ADR-073 — FAT16 mkdir (directory create depth)
- Status: Accepted (FAT16 root mkdir mile Verified when the serial / tests pass; Track A / app hosting still Planned for Linux/POSIX claims; Track N untouched)
- Date: 2026-09-16
Context
ADR-028 landed virtio-blk + FAT16 read. ADR-050 deepened write / small create. ADR-056 deepened root listing. ADR-057 deepened root file delete. ADR-064 deepened multi-cluster file grow. Docs “new vs extend” prefer deepening the known small FS (FAT16) behind the thin VFS (ADR-027).
Sponsor train mile (2) is honest FAT16 directory create (mkdir): allocate a root dirent with ATTR_DIR, allocate an empty directory cluster, write . / .., update the parent (root). Fail-closed serial + #[test_case].
Not POSIX mkdir / mkdirat. Not a nested path tree (thin-VFS path grammar stays flat /name). Not exFAT / FAT32. Not recursive rm. Do not implement thin TCP (sponsor mile 3) in this PR.
Hypotheses
| ID | Option | Notes |
|---|---|---|
| H1 (chosen) | Kernel + thin VFS vfs::mkdir creates a FAT16 root directory. Serial fat: mkdir / keep fat: ok. Probe creates /fdir, confirms dirent + ./.. cluster, refuses second create (Exists). No new SVC this mile. | Deepens ADR-028/050/056/057/064. Same flat path grammar. |
| H2 (rejected) | Claim POSIX mkdir / mkdirat or a Linux mkdir ABI. | Forbidden honesty. |
| H3 (rejected) | New SVC / libctos wrapper this PR. | Delete/readdir/grow miles used existing VFS; mkdir is a kernel/VFS depth probe; EL0 SVC can follow later. |
| H4 (rejected) | Nested subdirectory trees, LFN, recursive rm, or exFAT. | Out of scope; follow-ups. |
| H5 (rejected) | Thin TCP / Track N mile 3 in this PR. | Separate sponsor mile; out of scope. |
Decision
fat::mkdir/vfs::mkdir. Allocate a free cluster (EOC), zero it, write.(self cluster) and..(parent = FAT16 root → cluster 0), allocate a free root dirent withATTR_DIR+ size 0. Name collision with a file or directory →FsError::Exists(fail-closed). Missing mount / bad path → fail-closed.- Probe after grow. Create
/fdir(leftover empty dir:rmdir_emptythen recreate). Confirmhas_dir, refuseopenas a file (Missing), confirm./..bytes, secondmkdir→Exists. Serialfat: mkdir. Keepfat: ok/ write / readdir / delete / grow / A9 / net markers. - No new SVC numbers. Public ABI stays as today (FS 19–23, net 24–26). Not a POSIX product claim. EL0/
libctosmkdir is an explicit follow-up. - Fail-closed smoke. Grep
fat: mkdir/ keepfat: ok/ grow / delete / net / samples.#[test_case]covers mkdir + exists/bad-path + create-on-dir-name refuse. - Honesty. Say “the guest created a FAT16 root directory through the thin VFS” only when serial / tests pass. Do not say: POSIX
mkdir, directory trees, exFAT/FAT32, “supports FAT,” EL0 isolated, PAN, taken SError, Linux, containers, TCP. - NFR-10 text revised in place (ID unchanged). Threat-model v1.48. Do not mint NFR-15+.
Consequences
- Code:
src/fat.rs(mkdir / dot entries / probe),src/vfs.rs(vfs::mkdir),scripts/qemu-smoke.shgreps. - Docs: this ADR, filesystem overview/stance, honesty ledger, roadmap note, threat-model v1.48, SUMMARY, light fr-nfr NFR-10 note.
- Follow-ups: EL0
fs_mkdirSVC + sample → ADR-075. Nested dirs + emptyrmdir→ ADR-077. Recursive rm (non-goal unless sponsored) remains open. Thin TCP closed in ADR-074.