For this assignment, you are expected to implement a unix-style mini file system. The whole structure of the file system will exist within the single file. You'll be storing and removing other files within this file system, which is just a file itself.
The structure of this file is as followings:
SuperBlock |
Bit Map |
Root Directory |
Inodes |
DATA Blocks |
The SuperBlock is the first block in the disk that contains global information about the file system. You can store in the superblock things like starting location of the first block of the bit map, the root directory, the total number of free blocks, the overall size of the file system and any other thing you consider useful for making the file system persistent.
The root directory maintains the mapping between file names and inode numbers (or pointers). And the inodes has information about the data blocks in the file.
For simplicity, you can assume:
Program usage
Note: The number and size of files is also limited by the number of inodes and the number of free blocks.
./userfs -reformat disk_size file_name
Should create a virtual disk with the file name and size specified as arguments.
./userfs file_name
Should retrieve the file system with the name of virtual disk specified as argument and attempt to recover the file system if there is any inconsistency.
Download the skeleton code userfs.tar and work upon it to export the following functions. First, you should create a file under the current directory. This file simulates the virtual disk based on which you will build your file system.
int u_import(char* linux_file, char* u_file)
:int u_export(char* u_file, char* linux_file)
:int u_quota()
:int u_del(char* u_file)
:int u_ls()
:int u_fschk()
:Your system should support persistence and crash recovery.
Persistence means that all data written to the disk will never disappear unless you call explicitly u_del()
to remove them.
Files should remain there after you quit the file system and restart it. You file system may be terminated illegally, e.g. ctrl-c is pressed. This may leave the system in an inconsistent state. You should be able to detect such inconsistent states and recover from them
when the file system restarts. While writing the u_import()
and u_export()
functions you should take care of the order of operations to maintain consistency in the file system.
Extra credits:
You can do anything that you think can make the file system more interesting. Here are just some of my suggestions:
u_creat
, u_open
, u_read
, u_write
, u_close
etc.
minifile_t u_creat(char *filename)
minifile_t u_open(char *filename, char *mode)
int u_read(minifile_t file, char *data, int maxlen)
int u_write(minifile_t file, char *data, int len)
int u_close(minifile_t)
int u_mkdir(char *dirname)
int u_rmdir(char *dirname)
int u_cd(char *path)
char **u_ls(char *path)
char *u_pwd()
A single gzipped tar file containing one directory with the following files:
Here is some optional food for thought:
What is the largest file you can create in your file system?
What is the largest number of files?
If we reduce the block size, we also reduce the size of the bit map and the root directory
How do the answers to the above questions change with a block size of 1024? 8192?
Some simple things we could do to elleviate this problem is use each bit in the bit map rather than using an entire unsigned long ( 4 bytes) to represent a "bit" and make the root level directory be variable sized (i.e. give it its own inode).
You may do this assignment individually or in groups of two. If you work alone, you should implement the program to run in Linux. If you work in a team, you should write a single program that can be compiled to run either on Linux or on Windows. In either case, you should write your code in C.
Man pages: stat (2), fstat, lseek, read (2), write (2)