exfat: the engine read path (S4 step 2)

mount + resolve + list + read over a BlockDevice, host-tested against a
RAM-backed image the tests build with formatExfat. mount reads the VBR,
loads the geometry, and scans the root for the Allocation Bitmap (0x81)
and Up-case Table (0x82); the up-case prefix is decompressed (0xFFFF
identity runs) into a bounded table so names fold correctly.

A directory is read as consecutive 32-byte entries via readChain, so a
File/Stream/Name SET that straddles a sector or cluster boundary
assembles cleanly; each set's checksum is validated before it counts as
a file. A stream's no_fat_chain flag picks contiguous-arithmetic vs
FAT-follow cluster walking. reads honor valid_data_length (allocated-
but-unwritten tail reads as zero) and clamp data_length to the vfs u32
offset surface.

Tests cover mount + up-case fold, listing (skipping the metadata
entries), case-insensitive resolve, and reads across a cluster boundary
on both a contiguous and a FAT-fragmented file. Wired via engine.zig
(which imports on-disk.zig) into the host-test aggregate. 12/12, bounds
green. Write path is step 3.
This commit is contained in:
Daniel Samson
2026-08-10 03:02:58 +01:00
parent 56bd2e7678
commit 62eb2a748a
2 changed files with 734 additions and 3 deletions
+4 -3
View File
@@ -422,9 +422,10 @@ pub fn build(b: *std.Build) void {
"system/boot-handoff.zig",
"system/abi.zig",
"system/initial-ramdisk.zig", // v2 path-named entries: find/basename/magic
// The exFAT engine's pure on-disk layer (S4), std-only, before its package
// exists — moves into the `exfat` package's own test step once that lands.
"system/services/exfat/on-disk.zig",
// The exFAT engine (S4), std-only, before its package exists — the
// engine imports on-disk.zig, so this one entry runs both files' tests.
// Moves into the `exfat` package's own test step once that lands (step 4).
"system/services/exfat/engine.zig",
}) |root| {
const mod_tests = b.addTest(.{
.root_module = b.createModule(.{