fs-sim Playground

Run file system commands in your browser. One per line, then Run.

mount · mkdir · create · ls · cd · read · write · delete · resize · defrag

No file tree yet

Mount a disk and create dirs or files, then run. Your folder structure will show here.

How it works

This playground models a minimal UNIX-style file system. When you mount a disk, the system creates a superblock, 126 inodes, and a block bitmap. You create files and directories, list them, change directory, and read or write file data one block at a time. The explanations below describe how each part works in full detail.

  1. The superblock and disk layout. When you run mount with a disk name, the file system is initialized in memory. The heart of the layout is the superblock: a small structure that holds a 128-bit free-block bitmap and an array of 126 inodes. The bitmap records which of the 127 data blocks (numbered 1 through 127) are currently in use; block 0 is not used for file data. This design matches a real on-disk layout where the superblock sits at the start of the disk and describes the rest of the volume.
  2. What an inode stores. Every file and directory is represented by one inode. Each inode has four fields. The name is at most 5 characters (matching the C library). The used_size byte is used in a packed way: the high bit indicates whether the inode is in use, and the low 7 bits store the size in blocks (for a file) or 0 (for a directory). The start_block is the first data block number for file content (directories do not use blocks). The dir_parent byte is also packed: the high bit is set if this inode is a directory, and the low 7 bits hold the inode index of the parent directory. So a single byte encodes both “is this a directory?” and “who is my parent?”.
  3. Directories and the root. A directory is an inode whose size is 0 and whose dir_parent has the directory bit set. Directories do not allocate data blocks; they only exist as inodes that other entries point to. The root directory is special: it is not a real inode in the array. It is represented by the reserved index 127. When you mount, the current directory is set to this root. When you run ls, the listing always shows "." and ".." first: "." is the current directory (with the number of its children), and ".." is the parent (with the number of its children). Then every file and subdirectory in the current directory is listed by name, with either a size in KB (files) or a child count (directories).
  4. Lookup and navigation. The file system does not support full pathnames like /home/user/file. Lookup is done only by name in the current directory. The cd command changes the current directory: cd name moves into the directory name in the current directory, and cd .. moves to the parent. There is no notion of an absolute path; you navigate step by step. Every other command (create, delete, read, write, etc.) looks up names in the current directory only.
  5. Reading and writing file data. File contents are stored in blocks. Each block is 1024 bytes. The system maintains a single buffer of 1024 bytes. You put data into the buffer with the buffer command (e.g. buffer Hello world). You then write that buffer into a specific block of a file (e.g. write myfile 0 writes to block 0 of myfile). Similarly, read myfile 0 loads block 0 of myfile into the buffer (in this in-memory demo the buffer is not filled with real block data, but the operation is recorded). Block indices are 0-based and must be less than the file’s size in blocks. So a file of size 3 has blocks 0, 1, and 2.
  6. Block allocation and first-fit. When you create a file with a positive size, the system must allocate that many contiguous data blocks. It uses first-fit: it scans the block bitmap from block 1 onward and takes the first run of free blocks that is long enough. Those bits are marked used in the bitmap, and the file’s inode stores the starting block number and size. When you delete a file (or a directory tree), the blocks that were used are marked free again. Directories never allocate blocks; only files do.
  7. Resize and defrag. resize name new_size changes the number of blocks allocated to a file. If you shrink the file, the blocks no longer needed are freed in the bitmap. If you grow the file, the system first checks whether the blocks immediately after the current end of the file are free; if so, it extends in place. If not (or if the new size would exceed the disk), it finds a new contiguous region with first-fit, marks the old blocks free, marks the new blocks used, and updates the inode’s start block. defrag compacts all files: it scans blocks in order and moves each file’s data (in the bitmap and inode) so that files sit in a contiguous block of low block numbers with no gaps. That can free space at the end and reduce fragmentation for future first-fit allocations.

About

This playground runs the fs-sim file system: a UNIX-like file system on a 128 KB virtual disk with 1 KB blocks. The first block is the superblock (a 128-bit free-space list and 126 inodes); the remaining 127 blocks hold file data. You mount a disk, then create files and directories, ls to list, cd to change the current working directory, and read / write by block index using a 1 KB buffer. Files are stored in contiguous blocks (first-fit allocation); resize and defrag update layout and the bitmap. The same layout, inodes, and commands are what the library provides, whether you use it here or from your own program.