This was a project to learn more about how file systems are implemented and managed on operating systems. Using a virtual disk and a custom shell, it runs a file system on the virtual disk to format, create, delete, mount, unmount, read, and write the files on the filesystem in the virtual disk.

"make simplefs" to create our file system. You can run it using "./simplefs <file_name> "
- file_name is a custom disk "image.x" on this project or using your own file by creating a blank file.
- If you do opt for your own file, you can create an empty file "touch <file_name>"
- nblocks is the amount of blocks for our disk.
$ help # Gives a list of commands
$ format # Run this first to format the filesystem
$ mount # Run this next to mount our filesystem
$ unmount # Unmounts the fs
$ debug # Metadata of the filesystem
$ create # Creates an inode which can be used to copy data into it or out of it
$ delete <inode> # Deletes an inode
$ getsize <inode> # Gets the size of data inside the inode
$ cat <inode> # View contents of the inode
$ copyin <file> <inode> # Copy contents of a file to an inode
$ copyout <inode> <file> # Copy inode contents to a file
$ quit/exitecho "HELLO WORLD\n" > hello.txt
touch myFileSystem 20
./simplefs
$ format
$ mount
$ create
Block num: 1
created inode 0
$ create
Block num: 1
created inode 1
$ copyin hello.txt 1
14 bytes copied
copied file hello.txt to inode 1
$ cat 1
HELLO WORLD\n
$disk.c and disk.h is the implementation of the disk. It opens a file for reading or writing. It truncates the file into block sizes to emulate our disk.
shell.c is a simple implementation of a shell. It does not utilize exec or fork to create a separate process for the shell but just runs in the current shell. It receives commands to run within the file system.
fs.c and fs.h are the implementation of our file system. It contains a superblock which acts as either the superblock, an inode, indirect block, or data block using union. The layout of the file system is
<superblock>|<direct_inodes>|<indirect_inodes>|<data_blocks>
fs_format() clears out the inode table, data table, and inits our superblock
fs_mount() allocates our superblock, inodes, and freemap which is used to find which blocks to clean up
fs_create() creates an inode within a data block to hold data
fs_delete() clears out the inode
fs_read() opens a data block to read using our inode number.
fs_write() opens data block to write using our inode number.
Through this project I've learned how file systems are implemented but also edge cases managed. For example what if we don't write the entirety of the inode? How do we deal with internal and external fragmentation? What if someone attempts to create more inodes than can be fit in a data block? How can we ensure that if someone writes beyond the size of an inode that we don't cause memory access problems?
While fragmentation is still a problem with this project, we've dealt with a few edge cases. First with writing > inode size, we cut off whatever was copied. Another thing is concatenating multiple inodes in order to copyout the contents to a file.