code wiki / (root) / nx_filecopy.nx

nx_filecopy.nx source

↩ module page · 168 lines · 9197 B

1// nx_filecopy.nx -- A COPY THAT PROVES IT COPIED (2026-08-07; STREAMING 2026-08-13). 2// 3// WHY IT EXISTS: `nx_gate_dry_apply` produces a migration candidate and `nx_gate_migrate verify` proves 4// it judge-equivalent (exit code, verdict and the whole PASS/FAIL vector identical) -- and then the 5// migration cannot be APPLIED, because nothing in the estate moves bytes from one path to another. 6// `nx_filehash cmp` can tell you two files match; no organ can MAKE them match. A capability search over 7// 938 tools returned no copier. So a proven-safe automated migration path was blocked on the most 8// ordinary primitive there is. 9// *AN AUTOMATED PATH THAT CANNOT APPLY ITS OWN RESULT IS A DEMONSTRATION, NOT A TOOL.* 10// 11// The alternative was round-tripping the candidate through JSON via read+write, and this codebase has 12// already banked that chunked JSON re-assembly is NOT byte-faithful. A silent one-byte corruption in a 13// GATE would be the mutation-class defect the estate has been bitten by twice. 14// 15// SO IT VERIFIES BY CONSTRUCTION: after writing, it RE-READS the destination and compares every byte to 16// the source. A copy that did not land, landed short, or landed altered REPORTS FAILURE and exits 17// non-zero. **AN UNVERIFIED COPY IS INDISTINGUISHABLE FROM A SUCCESSFUL ONE UNTIL SOMETHING DOWNSTREAM 18// BREAKS** -- which for a gate means a silently weakened guard, the worst possible failure mode. 19// 20// 2026-08-13 STREAMING FIX (debt 1786597688): v1 read the WHOLE source into one 8MiB buffer and treated 21// that read as the file -- so any source >8MiB was SILENTLY TRUNCATED and then "verified=1" against its 22// own truncation (it verified what it copied, not the source; caught when an 8.8MB model banked as an 23// 8,388,608-byte corrupt copy). Now: the 8MiB buffer is a CHUNK, the copy streams to source EOF, and the 24// verify re-reads BOTH files in aligned chunks to EOF and requires identical totals. The buffer can 25// never again masquerade as the population. 26// 27// OVERWRITE IS EXPLICIT. Clobbering an existing destination requires the literal 3rd arg `overwrite`, 28// because for a migration the clobber IS the intent and for everything else it is an accident. 29// 30// nx_filecopy <src> <dst> [overwrite] 31// exit 0 copied+verified | 1 verify FAILED | 2 io error | 3 usage/refused 32// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 33import "nx_syscalls.nx" 34 35const FC_CAP: i64 = 8388608 // CHUNK size, not a file-size cap -- both copy and verify stream to EOF 36 37func fcp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 38func fce(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(2,s,n); return 0 } 39func fcn(v: i64) -> i64 { 40 var m: i64 = v 41 if m < 0 { fcp("-" as *u8); m = 0 - m } 42 let t: *u8 = sys_mmap(32) 43 var k: i64 = 0 44 if m == 0 { t[0] = 48 as u8; k = 1 } 45 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 46 let b: *u8 = sys_mmap(32) 47 var i: i64 = 0 48 while i < k { b[i] = t[k-1-i]; i = i + 1 } 49 sys_write(1, b, k) 50 return 0 51} 52func fc_exists(p: *u8) -> i64 { let fd: i64 = sys_openat_rd(p); if fd < 0 { return 0 } sys_close(fd); return 1 } 53func fc_streq(a: *u8, b: *u8) -> i64 { 54 var i: i64 = 0 55 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 56 if b[i] != (0 as u8) { return 0 } 57 return 1 58} 59// fill buf with up to cap bytes from fd; returns bytes read (0 = EOF) 60func fc_chunk(fd: i64, buf: *u8, cap: i64) -> i64 { 61 var n: i64 = 0 62 var r: i64 = 1 63 while r > 0 { 64 r = sys_read(fd, ((buf as i64) + n) as *u8, cap - n) 65 if r > 0 { n = n + r } 66 if n >= cap { r = 0 } 67 } 68 return n 69} 70 71func main(argc: i64, argv: *i64) -> i64 { 72 if argc < 3 { fce("usage: nx_filecopy <src> <dst> [overwrite]\n" as *u8); sys_exit(3); return 3 } 73 let src: *u8 = argv[1] as *u8 74 let dst: *u8 = argv[2] as *u8 75 if fc_streq(src, dst) == 1 { fce("nx_filecopy: REFUSED src == dst\n" as *u8); sys_exit(3); return 3 } 76 var over: i64 = 0 77 if argc >= 4 { let o: *u8 = argv[3] as *u8; if o[0] == (111 as u8) { over = 1 } } 78 if fc_exists(dst) == 1 { if over == 0 { fce("nx_filecopy: REFUSED destination exists; pass `overwrite` to replace it deliberately\n" as *u8); sys_exit(3); return 3 } } 79 80 let sbuf: *u8 = sys_mmap(FC_CAP) 81 let dbuf: *u8 = sys_mmap(FC_CAP) 82 let sfd: i64 = sys_openat_rd(src) 83 if sfd < 0 { fce("nx_filecopy: cannot read src\n" as *u8); sys_exit(2); return 2 } 84 // read the FIRST chunk before touching dst, so an empty source refuses without clobbering anything. 85 // A ZERO-BYTE SOURCE IS REFUSED: copying nothing over a real file is the silent-truncation shape 86 // that an "it succeeded" message would completely hide. 87 var chunk: i64 = fc_chunk(sfd, sbuf, FC_CAP) 88 if chunk == 0 { sys_close(sfd); fce("nx_filecopy: REFUSED empty source (copying 0 bytes over a destination is silent truncation)\n" as *u8); sys_exit(3); return 3 } 89 let fd: i64 = sys_openat_wr(dst, 0x1a4) 90 if fd < 0 { sys_close(sfd); fce("nx_filecopy: cannot open dst for write\n" as *u8); sys_exit(2); return 2 } 91 var total: i64 = 0 92 var more: i64 = 1 93 while more == 1 { 94 var w: i64 = 0 95 var werr: i64 = 0 96 while w < chunk { 97 let r: i64 = sys_write(fd, ((sbuf as i64) + w) as *u8, chunk - w) 98 if r <= 0 { werr = 1; w = chunk } else { w = w + r } 99 } 100 if werr == 1 { more = 0; total = 0 - 1 } else { 101 total = total + chunk 102 chunk = fc_chunk(sfd, sbuf, FC_CAP) 103 if chunk == 0 { more = 0 } 104 } 105 } 106 sys_close(sfd) 107 sys_close(fd) 108 if total < 0 { fce("nx_filecopy: write failed mid-copy; treat the destination as CORRUPT\n" as *u8); sys_exit(2); return 2 } 109 110 // VERIFY BY RE-READING BOTH FILES TO EOF in aligned chunks. The write returning a byte count proves 111 // the syscall accepted it, not that the bytes are on disk and correct -- and an artifact check that 112 // only asks "did the call succeed" is the defect this whole session kept finding. 113 let vs: i64 = sys_openat_rd(src) 114 let vd: i64 = sys_openat_rd(dst) 115 var ok: i64 = 1 116 if vs < 0 { ok = 0 } 117 if vd < 0 { ok = 0 } 118 var vtotal: i64 = 0 119 var going: i64 = ok 120 while going == 1 { 121 let a: i64 = fc_chunk(vs, sbuf, FC_CAP) 122 let b2: i64 = fc_chunk(vd, dbuf, FC_CAP) 123 if a != b2 { ok = 0; going = 0 } else { 124 if a == 0 { going = 0 } else { 125 var i: i64 = 0 126 while i < a { if sbuf[i] != dbuf[i] { ok = 0; i = a; going = 0 } else { i = i + 1 } } 127 vtotal = vtotal + a 128 } 129 } 130 } 131 if vs >= 0 { sys_close(vs) } 132 if vd >= 0 { sys_close(vd) } 133 if vtotal != total { ok = 0 } 134 135 if ok == 1 { 136 // ---- PRESERVE THE SOURCE MODE (2026-08-14) ------------------------------------------------ 137 // ★★★★★★A BYTE-FOR-BYTE VERIFY IS STRUCTURALLY BLIND TO THE EXECUTE BIT, SO THIS ORGAN COULD 138 // REPORT verified=1 ON A COPY THAT CANNOT RUN. It opened the destination 0644 unconditionally, 139 // so copying ANY executable produced a byte-perfect INERT artifact -- and the failure is silent 140 // and total: a fork of it yields ZERO bytes, which reads exactly like a bug in the organ being 141 // tested rather than in the copy. 142 // MEASURED THE SAME DAY: four binaries installed into _offc/ with this tool were byte-identical 143 // to their promoted originals and unrunnable; a sibling seat independently measured the same 144 // shape from the other side (a byte-identical _offc artifact without +x read as FRESH to 145 // nx_offc_install, so it never reinstalled, and every gate forking it got nothing). 146 // ★THE FIX IS TO COPY WHAT A COPY MEANS: mode is part of the file, not decoration. Preserving the 147 // SOURCE's mode is also the least surprising contract -- a copier that silently downgrades 148 // permissions is a defect generator no byte check can catch. 149 // st_mode is a u32 at offset 24 of struct stat; only the low 12 permission bits are applied. 150 let sb: *u8 = sys_mmap(160) 151 var mode_applied: i64 = 0 - 1 152 if sys_fstatat(src, sb) >= 0 { 153 let m: i64 = ((sb[24] as i64) + ((sb[25] as i64) << 8)) & 4095 154 if m > 0 { nx_chmod(dst, m); mode_applied = m } 155 } 156 fcp("NX-FILECOPY OK bytes=" as *u8); fcn(total) 157 fcp(" verified=1 (destination re-read and compared byte-for-byte)" as *u8) 158 // ANNOUNCE IT: a mode that was NOT applied must be visible, or the next reader inherits exactly 159 // the silent-inert-artifact defect this line exists to close. 160 if mode_applied >= 0 { fcp(" mode_preserved=" as *u8); fcn(mode_applied) } else { fcp(" mode_preserved=UNKNOWN (could not stat src; destination keeps the default 0644 and may be INERT if it is an executable)" as *u8) } 161 fcp("\n" as *u8) 162 return 0 163 } 164 fce("NX-FILECOPY VERIFY-FAILED src_bytes=" as *u8) 165 fce(" -- destination does NOT match source; treat the destination as CORRUPT\n" as *u8) 166 sys_exit(1) 167 return 1 168}