The last three hazards of contract review 2026-07-28-D, closed together
because they are one invariant: no name the store *invents* beneath a root
may be reached through a link or resolve to an object of the wrong type. The
flags and descriptor checks are the safety property, so the mechanics go in
the `sys.rs` funnel where the next author looking for how this crate opens
files will find them.
Refusal semantics differ per name, because the names mean different things.
`write_fenced` adopts and empties an existing regular `.tmp` — that is
residue from an interrupted attempt at this exact write, and reusing the name
is how a retry works — which is why the open and the truncation had to be
separated: no flag combination truncates only regular files, so the type
check needs the descriptor first and `O_TRUNC` cannot be in the open.
`read_format` keeps three answers apart: absent stays `Io(NotFound)` because
startup states 1 and 3 depend on it, non-regular is `UnrecognizedLayout`, and
a corrupt regular marker keeps its decode error. `initialize_root` leaves the
caller's root and ancestors alone, adopts existing directories beneath it, and
classifies every planned entry before creating any missing one so a refusal
cannot half-extend the tree it refused.
Directory fences now go to descriptors already validated rather than
re-resolving the name, which would hand the fence to whatever the name
resolves to now instead of what was checked. The fence sequence is otherwise
identical on purpose: `engine.rs` asserts the count exactly.
Each protection was reverted independently and the witnesses observed:
- `write_fenced` — a 4096-byte file outside the root truncated and
rewritten through a live link, a file created outside the root through a
dangling one, and a fifo at the name blocking the open for the full
ten-second deadline: an unbounded startup hang from one `mkfifo`.
- `read_format` — a foreign `FORMAT` read in full, its `shard_count` and
`root_uuid` returned as this root's, so every file in the tree would then
be validated against a marker the store never wrote. Same hang on the
read side.
- `initialize_root` — returned `Ok(FormatMarker)`, reporting a working
store with its shard tree built outside the root. The preflight has its
own witness: `shards/00/active` left behind by a refusal that named
`shards/00/segments`.
The witnesses sit on the `segment` entry points. `StoreEngine::open`'s
classifier refuses a redirected root before any of this is reached, so a test
entering that way passes whether or not the protection exists — and
`RecoverySession::open`, `drive.rs` and `store-bench` all arrive without it.
Disclosed: the device-node residual now covers `FORMAT.tmp` too — one
`O_NONBLOCK` open before the `fstat` refuses it, still gated behind `mknod`
privilege inside a configured root. `rename_noreplace` needed no change;
`RENAME_NOREPLACE` fails `EEXIST` on an occupied target whether or not it is
a link.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XKzM69CHmBuDcA3qN1jFdh