Skip to content
Imtiaz Hossain

work / systems / vsfsck

VSFSck

A file-system consistency checker in C that validates and repairs superblocks, bitmaps, inodes, and data blocks in a 64-block virtual file system.

period

2025

status

coursework

image
64 blocks
4096 B each, 256 KiB total
inode size
256 B
blocks 3-7 inode table
checks
5 validators
superblock to bad blocks
magic
0xd34d
superblock signature

system architecture / interactive

vsfs.imgraw binarySuperblockmagic 0xd34dInode Bitmapvs inode tableData Bitmapvs referencesReport + Fixdup/bad blocks
fig. 00 / vsfsck / hover nodes to trace the data flow

What an fsck actually does

When a file system is interrupted mid-write, its on-disk metadata can disagree with itself: a bitmap says a block is free while an inode still points at it, or two inodes claim the same block. Tools like fsck walk the raw image and reconcile these stories. VSFSck implements that logic for the Very Simple File System (VSFS), a teaching file system with a fixed layout, operating directly on a binary vsfs.img.

The on-disk layout

The image is 64 blocks of 4096 bytes: block 0 is the superblock, block 1 the inode bitmap, block 2 the data bitmap, blocks 3-7 the inode table (256-byte inodes), and blocks 8-63 the data region. Everything the checker knows, it learns by seeking and reading structs out of this raw layout, there is no file API to lean on.

The five validators

  1. Superblock validation: magic number 0xd34d, block size 4096, total blocks 64, valid metadata pointers, and sane inode size and count.
  2. Data bitmap consistency: every block marked used must be referenced by a valid inode, and every block an inode references must be marked used, checked in both directions.
  3. Inode bitmap consistency: every set bit must correspond to an inode with link_count > 0 and deletion_time == 0.
  4. Duplicate block detection: no data block may be claimed by more than one inode.
  5. Bad block detection: every reference must land inside the valid data region (8-63).

What it taught

The interesting engineering is in the cross-checks: each rule requires holding two views of the file system (what the bitmaps claim versus what the inode table actually references) and reconciling them bit by bit. Off-by-one errors in block indexing corrupt everything downstream, so the code treats boundaries (the 8-63 data region, the five inode-table blocks) as named constants and validates against them everywhere. Debugging happened at the hex level with ghex, which is the honest way to learn what "the file system is just bytes" means.

stack

CFile SystemsBinary I/OBitmapsGCC