The file system simulator is designed around a rigid block-based structure where the disk is treated as an array of 128 blocks (1024 bytes each).
Consistency Checking (fsck)
Consistency checking is implemented directly within the mount process. Before a file system is successfully mounted, fsck iterates through the superblock to verify the six consistency rules. If any check fails, the mount is aborted, so never operate on a corrupted image.
Defragmentation Strategy
The defragmentation algorithm (fs_defrag) was chosen to minimize data movement.
- It scans the inode table to identify all files (not directories).
- It sorts these files based on their current
start_blockindex. - It iterates through the sorted list, reading the file data into a buffer and writing it to the disk starting immediately after the superblock.
- Finally, it reconstructs the free block bitmap to match the new compacted layout.
Recursive Deletion
The fs_delete function utilizes a helper function rmrf. This implements a recursive strategy: it first identifies children of the target node. If a child is a directory, it recurses, if it is a file, it frees the associated blocks. This ensures that deleting a directory leaves no orphaned inodes.
Command Parsing
The main function in fs.c uses a dispatch pattern. It reads input line-by-line using getline and tokenizes it using strtok. Specialized handler functions (handler_0args, handler_1args, handler_2args, handler_bargs) are used to validate argument counts and types before passing control to the filesystem logic.
disk.c
disk_open: Usesopen()to acquire a file descriptor for the emulated disk file.disk_close: Usesclose()to release the file descriptor.disk_bread,disk_bwrite,disk_sbwrite:- Use
lseek()to move the file offset to the specific block location. - Use
read()andwrite()respectively to transfer 1024-byte blocks between memory and the disk file.
- Use
fs_sim.c
fs_mount: Usesclose()to ensure file descriptors are not leaked if the mount fails due tofsckerrors.
fs.c
main:- Uses
fopen()andfclose()for handling the script input file.
- Uses
Testing was conducted using an automated Python-based test suite (test.py and test_valgrind.py) that implements both functional and memory safety verification.
Functional Testing (test.py)
The testing framework operates on a "black box" basis with state verification:
After execution, the script compares the binary disk files generated by the simulator against "expected" disk images. This ensures that even if the console output is correct, the actual bytes written to the emulated disk are accurate.
Memory Safety Testing (test_valgrind.py)
A separate test suite wraps the execution in Valgrind (--tool=memcheck --leak-check=yes).
- It parses the Valgrind log file to ensure "ERROR SUMMARY: 0 errors" is present.
- This verifies that there are no memory leaks or invalid read/write operations.