Filesystem Module (src/fs/)
April 28, 2026 · View on GitHub
Trait-based filesystem abstraction for browsing, compaction, resize, and validation of partition contents.
Architecture
filesystem.rs—Filesystemtrait andFilesystemErrorenum. The trait definesroot,list_directory,read_file,volume_label,fs_type,total_size,used_size, andlast_data_byte.entry.rs—FileEntryandEntryTypestructs representing files and directories within a partition.fat.rs— Complete FAT12/16/32 implementation: BPB parsing, directory browsing (with LFN and CP437 support), cluster chain traversal,CompactFatReaderfor smart backup compaction, and in-place resize/validation/BPB patching for restore.ntfs.rs— NTFS implementation: VBR parsing, MFT record parsing with fixup array handling, data run decoding, version detection (1.0–3.1), directory browsing via B+ tree index entries,CompactNtfsReaderfor bitmap-based compaction, and VBR patching resize.exfat.rs— exFAT implementation: VBR parsing, directory entry set parsing (File + Stream Extension + File Name entries), allocation bitmap reading,CompactExfatReaderfor compaction, and full resize with bitmap/FAT/VBR/checksum updates.mod.rs— Factory functions (open_filesystem,compact_partition_reader,effective_partition_size) that route by MBR partition type byte, plus re-exports. Type byte0x07is disambiguated by reading the OEM ID magic ("NTFS "vs"EXFAT ").
Supported Partition Types
| Type Byte(s) | Filesystem | Browsing | Compaction | Resize |
|---|---|---|---|---|
0x01 | FAT12 | Yes | Yes | Yes |
0x04, 0x06, 0x0E, 0x14, 0x16, 0x1E | FAT16 | Yes | Yes | Yes |
0x0B, 0x0C, 0x1B, 0x1C | FAT32 | Yes | Yes | Yes |
0x07 | NTFS | Yes | Yes | Yes (VBR patch) |
0x07 | exFAT | Yes | Yes | Yes (full bitmap resize) |
0x83 | ext2/3/4 | No (planned) | No | No |
How to Add a New Filesystem
-
Create
src/fs/myfs.rsimplementing theFilesystemtrait:root()— return the root directory entrylist_directory()— list entries in a directoryread_file()— read file contents (up tomax_bytes)volume_label(),fs_type(),total_size(),used_size()last_data_byte()— minimum bytes from partition start to capture all data (for smart trimming)
-
Optionally implement a
CompactMyfsReader(implementsRead) for defragmented streaming backup. -
Optionally implement
resize_myfs_in_place()andvalidate_myfs_integrity()for restore/VHD export with partition resizing. -
Register in
fs/mod.rs:- Add partition type byte matching in
open_filesystem() - Add matching in
compact_partition_reader()if compaction is supported - Add matching in
effective_partition_size()if trimming is supported
- Add partition type byte matching in
-
Add
pub mod myfs;tofs/mod.rs.
See fat.rs as the complete reference implementation showing all capabilities.
Compact reader sizing model
Compact readers return a CompactResult (fs/mod.rs) carrying three byte counts that look similar but mean different things. Reading or writing one without remembering the distinction will silently corrupt progress bars or backup metadata.
| Field | Meaning |
|---|---|
original_size | Partition size on the source disk (unchanged by compaction). |
compacted_size | Bytes the reader will emit downstream (the stream's actual length). |
data_size | Logical data bytes: allocated_blocks * block_size (+ HFS pre-alloc). |
Two reader styles produce different relations:
- Packed (FAT, NTFS, exFAT): boot region + FAT + only used clusters, contiguously. Stream is smaller than the original. Invariant:
data_size == compacted_size < original_size. - Layout-preserving (HFS, HFS+, ext, btrfs, ProDOS): full original byte layout, but free clusters are zero-filled in-memory rather than read from disk. Stream is the same length as the original. Invariant:
data_size < compacted_size == original_size.
In backup/mod.rs the orchestrator uses these as:
effective_sizes[i] = data_size— feeds the smart-sizing log line ("X MiB of data in N MiB partition").stream_sizes[i] = compacted_size— feeds the progress bar (matches actual bytes flowing through the compressor).total_display_bytes = sum(data_sizes)— total logical data across all partitions.total_stream_bytes = sum(stream_sizes)— total bytes written to the archive.
When adding a new compact reader, decide which style it is, stamp the result accordingly, and add a unit test asserting the invariant so future changes can't drift.