Utility: fcap
Utility: fcap - file-as-capability self-check
Status: Built. As-built reference.
Shape: shell built-in (see 0_conventions.md §2).
1. Purpose
fcap answers is a file really a capability? - it is the executable proof of the
file-as-capability model (§7.10, the P2 amendment; docs/persistence.md §7.2). In GodspeedOS
a file is not a path you have permission to, nor a handle the filesystem trusts you to use
honestly: opening a file mints a real, kernel-minted capability for it, and every read or
write is a validated invocation of that capability - the same unforgeable, non-escalating,
revocable machinery as any IPC-endpoint cap.
fcap is a diagnostic, not a file tool. It creates its own throwaway file, exercises every
property the capability model promises against it, prints one line per check, then deletes the
file. It never touches a file of yours and takes no path argument - so it is safe to run any
time as a "does the file-cap model still hold end-to-end?" probe.
2. Invocation
| Command | Meaning |
|---|---|
fcap | Run the self-check against an internal throwaway file. |
fcap help | Print usage. |
fcap version | Print the version (uniform across utilities). |
fcap reuse | Mint a file cap, restart fs, put a DIFFERENT file in the freed blocks, and prove the old cap reaches nothing (the stale-handle, confused-deputy question). Ends fcap reuse: ok - .... |
fcap gsreuse | The same restart question asked through the standard library (gs::fs / gs::cap). |
fcap takes no path - passing one is refused (fcap: takes no argument …). It uses its own
files in the shell's scratch folder (/system/scratch/shell/fcap-selftest, then fcap_append and fcap-gs) and removes them, so it is
leak-free and re-runnable. reuse and gsreuse are listed in fcap help and tab-complete;
both kill fs, and reuse uses /ru_old.txt and /ru_new.txt at the root.
3. Output
gsh> fcap
fcap: opened rw (file cap)
fcap: write via cap OK
fcap: read via cap OK
fcap: ro-cap write rejected by kernel (non-escalation)
fcap: fs refused write under read right (op<=right)
fcap: forged handle rejected
fcap: cap revoked after close
fcap: cap revoked after rename
fcap: opened append-only (file cap)
fcap: append-only writes moving FORWARD accepted
fcap: rewriting earlier bytes through an append-only cap DENIED
fcap: a later forward write still accepted after the refusal
fcap: gs::cap wrote and read the file THROUGH the capability
fcap: gs::cap non-escalation holds - a READ cap cannot write
fcap: gs::cap an append-only file carries WRITE alone, and closes
fcap: all file-capability checks passed
Each line is one verified property. Any FAIL line (and a non-zero result) means the
file-capability model is broken - a constitutional regression, not a cosmetic one.
4. What it verifies
The checks map one-to-one onto the §7.3 capability properties, applied to a file:
| Check | Property pinned |
|---|---|
| read / write through the cap | A file is a capability - operated by invoking it, not by naming a path the fs trusts (§7.10). |
| read-only cap's write rejected by the kernel | Non-escalation at the kernel layer - the cap lacks WRITE, so the invocation never reaches fs (CapInsufficientRights). |
fs refuses a write op sent under a read-validated badge | Non-escalation at the fs layer - op ≤ right; even a correctly-validated read cap can't smuggle a write (FS_DENIED). |
| fabricated handle rejected | Unforgeable - only the kernel mints valid caps; a made-up handle is not one. |
| cap stale after close | Revocable - closing the file revokes the resource (generation bump); the next use is stale. |
| cap stale after rename | Revocable on path rebinding - renaming revokes a still-open cap so it can never silently rebind to a different file later created at the old path (confused-deputy avoidance, §7.10). |
| append-only cap: forward writes accepted, rewriting earlier bytes denied | An append-only right is enforced by fs against the resource's own high-water mark, and a refused write does not break it. |
the same through gs::cap | The standard library speaks the same protocol, on the same tag counter. |
The unforgeable-badge detail: the right that authorises a file-cap invocation is carried to fs
in an unforgeable, kernel-set Message field, not in the client's payload - so a client
cannot fake a file-cap operation over its ordinary fs send cap.
5. Capabilities
- A narrow
SENDcap tofs(the shell already holds it forread/write/drives) -fcapmints and invokes file caps throughfs;fsenforces all disk authority. RESOURCE_MINTis not held by the shell - onlyfsmints delegated resource caps (§3.1, §7.10).fcapreceives the minted file cap fromfson open; it cannot mint its own.- Console output to print the per-check lines.
6. Non-goals
- Not a file editor or viewer.
fcapnever reads, writes, or deletes a file of yours - useread/write/deletefor that. It only touches its own throwaway file. - No options or paths. No flags (§
0_conventions.md); the self-check takes no argument, andreuse/gsreuseare its only words. It is a self-check, not a configurable tool.
7. Conformance
Conforms: own fcap help (usage with real examples per 0_conventions.md) and fcap version
(number + creator credit), listed by the shell's top-level help. Pinned end-to-end by
osdev test file-cap (§22 Test 14 - every line above is asserted), and run in-memory by the
shell's selfcheck suite. Hardware-proven on the HP T630 (§23.3). See 0_conventions.md §3,
CLAUDE.md §7.10 / §22 Test 14, and docs/persistence.md §7.2.