nx_fsops_write.nx
buildroot/runtime/nx_fsops_write.nx
about
nx_fsops_write.nx -- WRITE-CLASS CLI of the consolidated fs tool (tools-api name: nx_fs_write).
2026-07-30: `write` is now COMPARE-AND-SWAP gated (seq1379) -- see the block above fsw_usage.
Deliberately a SEPARATE binary from the read-only `nx_fs`: the exposure policy (knowledge/mcp/
exposure_policy.txt) grades reads broad and writes cap-gated, so the two live under different
capability grants. One shared library (nx_fsops_lib) -- no logic duplicated.
write <path> <content> -> ATOMIC full-file write (tmp+fsync+rename)
edit <path> <old> <new> [all] -> exact-string replace, UNIQUENESS contract (Claude-Edit semantic)
append <path> <row> -> APPEND-ONLY (one O_APPEND write under flock; row must end in '\n'):
the journal/board verb -- no anchor, no expect token, nothing rewritten
exit: 0 ok | 2 usage | 3 absent | 4 io | 5 DENIED | 6 NOMATCH | 7 AMBIGUOUS (surfaced in MCP _meta)
DENY BY CONSTRUCTION (rule 26 + 12): secret material, OS device/firmware namespace (nx_os_fs seam),
the tool allowlist, + fs_write_deny.conf extras. license_tier: ORIGINAL
dependencies 2 imports · 2 importers
imports: nx_fsops_lib.nxnx_apistack_idempotency.nx
imported by: nx_writer_bound_run_t293.nxnx_writer_payload_gate_t293.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 16 | const FSW_USAGE_RC: i64 = 2 |
| 17 | const FSW_ARG_VERB: i64 = 1 // argv slot of the verb |
| 18 | const FSW_ARG_PATH: i64 = 2 // argv slot of the path |
| 19 | const FSW_ARG_A: i64 = 3 // write: content | edit: old-string |
| 20 | const FSW_ARG_B: i64 = 4 // edit: new-string |
| 21 | const FSW_ARG_ALL: i64 = 5 // edit: optional literal "all" |
| 22 | const FSW_ARGC_WRITE: i64 = 4 // write path content |
| 23 | const FSW_ARGC_EDIT: i64 = 5 // edit path old new |
| 24 | const FSW_ARGC_EDITALL: i64 = 6 // edit path old new all |
| 36 | const FSW_RC_CLOBBER: i64 = 8 // distinct from ABSENT/DENIED/IO/NOMATCH/AMBIG so callers can branch on it |
| 37 | const FSW_ARG_EXPECT: i64 = 4 // write: optional expect token |
| 38 | const FSW_ARGC_WRITE_EXPECT: i64 = 5 |
| 81 | const FSW_FNV_OFF: i64 = 0xcbf29ce484222325 |
| 82 | const FSW_FNV_PRIME: i64 = 0x100000001b3 |
| 151 | const FSW_IDEM_LEDGER: *u8 = "knowledge/status/fswrite_idem.jrnl" as *u8 // CWD-relative like every status file |
| 152 | const FSW_IDEM_RESULT_CAP: i64 = 1024 |
| 153 | const FSW_KEY_MIN_CH: i64 = 33 // printable ASCII, no space: a key with a TAB or newline would corrupt the ledger row |
| 154 | const FSW_KEY_MAX_CH: i64 = 126 |
| 192 | const FSW_REQUEST_FIELDS:i64=8 |
| 193 | const FSW_LENGTH_BYTES:i64=8 |
| 194 | const FSW_REQUEST_HASH_BYTES:i64=32 |
| 195 | const FSW_REQUEST_HEX_BYTES:i64=64 |
| 196 | const FSW_RECONCILE_RC:i64=9 |
| 197 | const FSW_RECEIPT_RC:i64=10 |
| 320 | const FSW_DIR_MODE: i64 = 0x1ed // 0755 on any parent this creates -- same mode the rest of the tree uses |
| 321 | const FSW_RC_DENIED_SENTINEL: i64 = 2 // fsx_write's DENIED return; it prints its own reason, we must not double-report |
functions
| 54 | func fsw_argval(s: *u8) -> *u8 |
| 64 | func fsw_cur_size(path: *u8) -> i64 |
| 83 | func fsw_content_hash(path: *u8) -> i64 |
| 93 | func fsw_hex_of(v: i64, out: *u8) -> i64 |
| 100 | func fsw_hex_val(s: *u8) -> i64 called by 1: fsw_expect_val |
| 120 | func fsw_print_hash(path: *u8) -> i64 |
| 126 | func fsw_expect_val(ex: *u8, path: *u8, cur: i64) -> i64 |
| 133 | func fsw_atoi(s: *u8) -> i64 called by 1: fsw_expect_val |
| 155 | func fsw_prefix(s: *u8, p: *u8) -> i64 { var i: i64 = 0; while p[i] != (0 as u8) { if s[i] != p[i] { return 0 } i = i + 1 } return 1 } |
| 156 | func fsw_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; var oo: i64 = o; while s[i] != (0 as u8) { d[oo] = s[i]; oo = oo + 1; i = i + 1 } d[oo] = 0 as u8; return oo } called by 1: fsw_record_bound |
| 157 | func fsw_catn(d: *u8, o: i64, v: i64) -> i64 |
| 170 | func fsw_keyarg(argc: i64, argv: *i64, from: i64) -> *u8 |
| 179 | func fsw_key_ok(key: *u8) -> i64 called by 1: fsw_dispatch |
| 198 | func fsw_request_hash(argc:i64,argv:*i64,hex:*u8)->i64 |
| 245 | func fsw_evidence_decide(key:*u8,hex:*u8)->i64 |
| 272 | func fsw_record_bound(key:*u8,hex:*u8,verb:*u8,path:*u8)->i64 |
| 288 | func fsw_dispatch(argc:i64,argv:*i64)->i64 |
| 315 | func fsw_usage() -> i64 |
| 333 | func fsw_mkparents(path: *u8) -> i64 |
| 358 | func fsw_rc(r: i64) -> i64 called by 1: fsw_execute |
| 371 | func fsw_payload_failure(path: *u8, stage: *u8, raw: i64, code: i64, next: *u8, status: *i64) -> *u8 |
| 381 | func fsw_load_text(path:*u8,status:*i64)->*u8 |
| 396 | func fsw_load_region_text(path:*u8,region:*NxFileReadRegion,status:*i64)->*u8 |
| 433 | func main(argc:i64,argv:*i64)->i64 |
| 463 | func fsw_execute(argc: i64, argv: *i64) -> i64 called by 1: fsw_dispatch calls 15: fsw_usagefsx_seqfsw_prefixfsw_argvalfsw_cur_sizefsw_expect_val+9 |