code wiki / (root) / nx_bundle_ingest_cli_candidate_t144.nx

nx_bundle_ingest_cli_candidate_t144.nx source

↩ module page · 495 lines · 24052 B

1// nx_bundle_ingest.nx -- COMMUNITY BUNDLE TO A TYPED MANIFEST (/compare/modding MD1 bundle_ingest, 2026-09-06). Walks a ZIP or 2// a 7z by content type through nx_bundle_ingest_lib (the zip reader, the inflater and the ONE identify ruler are all 3// incumbents) or nx_sevenz_lib (the 7z container reader over nx_lzma_lib, MD29, same day -- filling the SAME record table, so 4// the texture binder and the partition run unchanged over both containers) and prints one MEMBER row per entry plus one 5// BUNDLE row whose partition sums to the entry count. Unknown members are rows, not omissions; a method or coder the walker 6// cannot open is a row that says so. 7// PROVENANCE (MD9, same day): the archive's own sha256 is the asset identity. With source=<url> the walk appends a row to the 8// provenance journal (licence=<id> names a rights-table row; absent, the licence is recorded as unknown, which is NOT a table 9// row and therefore REFUSES every export and publish door by construction); with or without it the verdict for that sha is 10// printed from nx_asset_prov_lib -- private use always allowed, the walk's own exit code unchanged. 11// usage: nx_bundle_ingest <bundle.zip|bundle.7z> [manifest.out] [source=<url>] [licence=<id>] [jrnl=<path>] 12// exits: 0 walked | 2 usage | 3 REFUSED (unreadable, not a zip or 7z, truncated, a record or the header refused, partition 13// does not sum) 14// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 15import "nx_syscalls.nx" 16import "nx_bundle_ingest_selected_candidate_t144.nx" 17import "nx_asset_prov_lib.nx" 18import "nx_sevenz_selected_candidate_t144.nx" 19import "nx_fsops_lib.nx" 20import "nx_atomic_rewrite.nx" 21import "json_emit.nx" 22 23const BIC_NAMES_HEADROOM: i64 = 4096 24const BIC_MODE_0644: i64 = 420 25const BIC_EXIT_USAGE: i64 = 2 26const BIC_EXIT_REFUSE: i64 = 3 27const BIC_OUTFD: i64 = 1 28const BIC_SRC_KEY: *u8 = "source=" 29const BIC_SRC_KEY_LEN: i64 = 7 30const BIC_LIC_KEY: *u8 = "licence=" 31const BIC_LIC_KEY_LEN: i64 = 8 32const BIC_JRNL_KEY: *u8 = "jrnl=" 33const BIC_JRNL_KEY_LEN: i64 = 5 34const BIC_LIC_DEFAULT: *u8 = "unknown" // deliberately NOT a rights-table row: the absence is the refusal 35const BIC_ORIGIN: *u8 = "nx_bundle_ingest" 36const BIC_ST_N: i64 = 8 37const BIC_CONTAINER_ZIP: i64 = 0 38const BIC_CONTAINER_7Z: i64 = 1 39 40func bic_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 41func bic_w(fd: i64, s: *u8) -> i64 { sys_write(fd, s, bic_len(s)); return 0 } 42func bic_wn(fd: i64, v: i64) -> i64 { 43 let t: *u8 = sys_mmap(32) 44 var m: i64 = v 45 var w: i64 = 0 46 if m < 0 { t[0] = 45 as u8; sys_write(fd, t, 1); m = 0 - m } 47 if m == 0 { t[0] = 48 as u8; sys_write(fd, t, 1); return 0 } 48 let d: *u8 = sys_mmap(32) 49 var k: i64 = 0 50 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 51 var j: i64 = 0 52 while j < k { t[w] = d[k - 1 - j]; w = w + 1; j = j + 1 } 53 sys_write(fd, t, w) 54 return 0 55} 56func bic_prefix(s: *u8, p: *u8, n: i64) -> i64 { var i: i64 = 0; while i < n { if s[i] != p[i] { return 0 } i = i + 1 } return 1 } 57func bic_is_kv(s: *u8) -> i64 { 58 if bic_prefix(s, BIC_SRC_KEY, BIC_SRC_KEY_LEN) == 1 { return 1 } 59 if bic_prefix(s, BIC_LIC_KEY, BIC_LIC_KEY_LEN) == 1 { return 1 } 60 if bic_prefix(s, BIC_JRNL_KEY, BIC_JRNL_KEY_LEN) == 1 { return 1 } 61 return 0 62} 63// trailing key=value args are a SCAN, so the positional contract (archive, manifest) is untouched 64func bic_arg(argc: i64, argv: *i64, key: *u8, klen: i64) -> *u8 { 65 var i: i64 = 2 66 while i < argc { 67 let a: *u8 = argv[i] as *u8 68 if bic_prefix(a, key, klen) == 1 { return a + klen } 69 i = i + 1 70 } 71 return 0 as *u8 72} 73func bic_container_name(c: i64) -> *u8 { if c == BIC_CONTAINER_7Z { return "7z" as *u8 } return "zip" as *u8 } 74// the method column: a zip row carries the zip method number, a 7z row the coder code -- named so the reader need not know 75func bic_method(fd: i64, container: i64, code: i64) -> i64 { 76 if container == BIC_CONTAINER_7Z { bic_w(fd, sz_coder_name(code)); return 0 } 77 bic_wn(fd, code) 78 return 0 79} 80 81func bic_row(fd: i64, tbl: *i64, names: *u8, i: i64, container: i64) -> i64 { 82 let r: *i64 = bi_rec(tbl, i) 83 bic_w(fd, "MEMBER idx=" as *u8); bic_wn(fd, i) 84 bic_w(fd, " name=" as *u8); sys_write(fd, names + r[BI_F_NAMEOFF], r[BI_F_NAMELEN]) 85 bic_w(fd, " method=" as *u8); bic_method(fd, container, r[BI_F_METHOD]) 86 bic_w(fd, " csize=" as *u8); bic_wn(fd, r[BI_F_CSIZE]) 87 bic_w(fd, " usize=" as *u8); bic_wn(fd, r[BI_F_USIZE]) 88 bic_w(fd, " magic=" as *u8); bic_w(fd, ap_name(r[BI_F_MAGIC])) 89 bic_w(fd, " category=" as *u8); bic_w(fd, ap_catname(r[BI_F_CAT])) 90 bic_w(fd, " claim=" as *u8); bic_w(fd, ap_name(r[BI_F_CLAIM])) 91 bic_w(fd, " verdict=" as *u8); bic_w(fd, bi_verdict_name(r[BI_F_VERDICT])) 92 bic_w(fd, " inflate=" as *u8); bic_w(fd, bi_inflate_name(r[BI_F_INFLATE])) 93 bic_w(fd, " bind=" as *u8); bic_w(fd, bi_bind_name(r[BI_F_BIND])) 94 bic_w(fd, " bound_to=" as *u8); bic_wn(fd, r[BI_F_BOUND_TO]) 95 bic_w(fd, "\n" as *u8) 96 return 0 97} 98 99func bic_summary(fd: i64, m: i64, p: *i64, sum: i64, verdict: *u8, container: i64, st: *i64) -> i64 { 100 // the incumbent's prefix is a CONTRACT its gate and every reader anchor on: members first, the container after it 101 bic_w(fd, "BUNDLE members=" as *u8); bic_wn(fd, m) 102 bic_w(fd, " container=" as *u8); bic_w(fd, bic_container_name(container)) 103 bic_w(fd, " model=" as *u8); bic_wn(fd, p[BI_P_MODEL]) 104 bic_w(fd, " material=" as *u8); bic_wn(fd, p[BI_P_MATERIAL]) 105 bic_w(fd, " texture=" as *u8); bic_wn(fd, p[BI_P_TEXTURE]) 106 bic_w(fd, " motion=" as *u8); bic_wn(fd, p[BI_P_MOTION]) 107 bic_w(fd, " audio=" as *u8); bic_wn(fd, p[BI_P_AUDIO]) 108 bic_w(fd, " video=" as *u8); bic_wn(fd, p[BI_P_VIDEO]) 109 bic_w(fd, " bundle=" as *u8); bic_wn(fd, p[BI_P_BUNDLE]) 110 bic_w(fd, " unknown=" as *u8); bic_wn(fd, p[BI_P_UNKNOWN]) 111 bic_w(fd, " sum=" as *u8); bic_wn(fd, sum) 112 bic_w(fd, " stored=" as *u8); bic_wn(fd, p[BI_P_STORED]) 113 bic_w(fd, " inflated=" as *u8); bic_wn(fd, p[BI_P_INFLATED]) 114 bic_w(fd, " failed=" as *u8); bic_wn(fd, p[BI_P_FAILED]) 115 bic_w(fd, " unsupported=" as *u8); bic_wn(fd, p[BI_P_UNSUPPORTED]) 116 bic_w(fd, " textures_bound=" as *u8); bic_wn(fd, p[BI_P_BOUND]) 117 bic_w(fd, " textures_unbound=" as *u8); bic_wn(fd, p[BI_P_UNBOUND]) 118 if container == BIC_CONTAINER_7Z { 119 bic_w(fd, " dirs=" as *u8); bic_wn(fd, st[0]) 120 bic_w(fd, " folders=" as *u8); bic_wn(fd, st[2]) 121 bic_w(fd, " encoded_header=" as *u8); bic_wn(fd, st[3]) 122 } 123 bic_w(fd, " verdict=" as *u8); bic_w(fd, verdict); bic_w(fd, "\n" as *u8) 124 return 0 125} 126 127// the provenance leg: identity is the archive's own sha; a row is appended only when the caller names where it came from 128func bic_provenance(argc: i64, argv: *i64, b: *u8, n: i64) -> i64 { 129 let sha: *u8 = sys_mmap(PV_SHA_HEX + 1) 130 pv_hash_bytes(b, n, sha) 131 let src: *u8 = bic_arg(argc, argv, BIC_SRC_KEY, BIC_SRC_KEY_LEN) 132 var lic: *u8 = bic_arg(argc, argv, BIC_LIC_KEY, BIC_LIC_KEY_LEN) 133 var jrnl: *u8 = bic_arg(argc, argv, BIC_JRNL_KEY, BIC_JRNL_KEY_LEN) 134 if (jrnl as i64) == 0 { jrnl = PV_JRNL_DEFAULT } 135 if (src as i64) != 0 { 136 if (lic as i64) == 0 { lic = BIC_LIC_DEFAULT } 137 let w: i64 = pv_row_write(jrnl, sha, src, lic, BIC_ORIGIN, pv_now()) 138 bic_w(BIC_OUTFD, "PROVENANCE-ROW sha=" as *u8); bic_w(BIC_OUTFD, sha) 139 bic_w(BIC_OUTFD, " source=" as *u8); bic_w(BIC_OUTFD, src) 140 bic_w(BIC_OUTFD, " lic=" as *u8); bic_w(BIC_OUTFD, lic) 141 bic_w(BIC_OUTFD, " row_bytes=" as *u8); bic_wn(BIC_OUTFD, w) 142 bic_w(BIC_OUTFD, " jrnl=" as *u8); bic_w(BIC_OUTFD, jrnl); bic_w(BIC_OUTFD, "\n" as *u8) 143 } else { 144 bic_w(BIC_OUTFD, "PROVENANCE-ROW sha=" as *u8); bic_w(BIC_OUTFD, sha) 145 bic_w(BIC_OUTFD, " NOT-WRITTEN (pass source=<url> [licence=<id>] to record where this bundle came from)\n" as *u8) 146 } 147 let res: *i64 = sys_mmap(8 * PV_RES_N) as *i64 148 let rc: i64 = pv_verdict(jrnl, sha, res) 149 pv_print(sha, rc, res) 150 return rc 151} 152 153 154// Additive ZIP selection API. Ordinary bundle.zip/7z CLI remains below unchanged. 155// Limits are explicit caller arguments; member names never become filesystem paths. 156const BIX_LOCK_SUFFIX: *u8 = ".nx-ingest-lock" 157const BIX_JSON_ROW_ROOM: i64 = 512 158const BIX_JSON_BASE_ROOM: i64 = 2048 159func bix_uint(s: *u8) -> i64 { 160 var i: i64 = 0; var v: i64 = 0 161 while s[i] != (0 as u8) { 162 let d: i64 = s[i] as i64 - 48 163 if d < 0 { return 0-1 }; if d > 9 { return 0-1 } 164 if v > (NX_ZIP_U32-1-d)/10 { return 0-1 } 165 v=v*10+d; i=i+1 166 } 167 if i == 0 { return 0-1 }; return v 168} 169func bix_lock(path: *u8) -> i64 { 170 if fsx_write_denied(path) == 1 { return 0-1 } 171 let n: i64 = bic_len(path) 172 let sn: i64 = bic_len(BIX_LOCK_SUFFIX) 173 if n+sn+FSX_TMP_ROOM >= FSX_PATH_CAP { return 0-1 } 174 let p: *u8 = sys_mmap(n+sn+1) 175 if (p as i64) <= 0 { return 0-1 } 176 var i: i64 = 0 177 while i < n { p[i]=path[i]; i=i+1 } 178 i=0; while i < sn { p[n+i]=BIX_LOCK_SUFFIX[i]; i=i+1 }; p[n+sn]=0 as u8 179 let fd: i64 = sys_openat_lock(p) 180 sys_munmap(p,n+sn+1) 181 if fd < 0 { return fd } 182 if sys_flock(fd,SYS_LOCK_EX | SYS_LOCK_NB) != 0 { sys_close(fd); return 0-1 } 183 return fd 184} 185func bix_same(path: *u8, data: *u8, n: i64) -> i64 { 186 let fd: i64 = sys_openat_rd(path) 187 if fd < 0 { return 0 } 188 let size: i64 = sys_lseek(fd,0,2) 189 sys_close(fd) 190 if size != n { return 0 } 191 if n == 0 { return 1 } 192 return ar_same_file(path,data,n) 193} 194func bix_store(path: *u8, data: *u8, n: i64) -> i64 { 195 let lockfd: i64 = bix_lock(path) 196 if lockfd < 0 { return 0-4 } 197 var rc: i64 = 0 198 let present: i64 = sys_openat_rd(path) 199 if present >= 0 { 200 sys_close(present) 201 if bix_same(path,data,n) != 1 { rc = 0-5 } 202 } else { 203 if present != (0-2) { sys_flock(lockfd,SYS_LOCK_UN); sys_close(lockfd); return 0-8 } 204 let linkbuf: *u8=sys_mmap(1) 205 if (linkbuf as i64) <= 0 { sys_flock(lockfd,SYS_LOCK_UN); sys_close(lockfd); return 0-8 } 206 let link_rc: i64=sys_readlinkat(path,linkbuf,1) 207 sys_munmap(linkbuf,1) 208 if link_rc >= 0 { sys_flock(lockfd,SYS_LOCK_UN); sys_close(lockfd); return 0-9 } 209 if link_rc != (0-2) { sys_flock(lockfd,SYS_LOCK_UN); sys_close(lockfd); return 0-8 } 210 if fsx_write(path,data,n) != n { rc = 0-6 } 211 else { 212 let fd: i64 = sys_openat_rd(path) 213 if fd < 0 { rc=0-7 } else { 214 if sys_fsync(fd) != 0 { rc=0-7 } 215 if sys_close(fd) != 0 { rc=0-7 } 216 } 217 if ar_syncdir_checked(path) != 0 { rc=0-7 } 218 if bix_same(path,data,n) != 1 { rc=0-7 } 219 } 220 } 221 sys_flock(lockfd,SYS_LOCK_UN); sys_close(lockfd) 222 return rc 223} 224func bix_key(w: *JsonWriter, key: *u8, value: *u8) -> i64 { 225 if json_emit_key(w,key,bic_len(key)) < 0 { return 0-1 } 226 return json_emit_string(w,value,bic_len(value)) 227} 228func bix_num(w: *JsonWriter, key: *u8, value: i64) -> i64 { 229 if json_emit_key(w,key,bic_len(key)) < 0 { return 0-1 } 230 if w.cap-w.pos < NXI_BUF+1 { return 0-1 } 231 if je_sep(w) < 0 { return 0-1 } 232 w.pos=nxi_buf(w.buf,w.pos,value) 233 return 0 234} 235func bix_row(w: *JsonWriter, r: *i64, names: *u8, idx: i64) -> i64 { 236 var rc: i64 = json_begin_object(w) 237 rc=rc | bix_num(w,"index",idx) 238 // Hex retains arbitrary archive-name bytes without pretending a charset or emitting invalid UTF-8. 239 let nl: i64 = r[BI_F_NAMELEN] 240 let hex: *u8 = sys_mmap(nl*2+1) 241 if (hex as i64) <= 0 { return 0-1 } 242 let digits: *u8 = "0123456789abcdef" 243 var i: i64 = 0 244 while i < nl { let b: i64 = names[r[BI_F_NAMEOFF]+i] as i64; hex[i*2]=digits[(b>>4)&15]; hex[i*2+1]=digits[b&15]; i=i+1 } 245 hex[nl*2]=0 as u8 246 rc=rc | bix_key(w,"name_bytes_hex",hex) 247 sys_munmap(hex,nl*2+1) 248 rc=rc | bix_num(w,"compressed_bytes",r[BI_F_CSIZE]) 249 rc=rc | bix_num(w,"declared_bytes",r[BI_F_USIZE]) 250 rc=rc | bix_num(w,"decoded_bytes",r[BI_F_DLEN]) 251 rc=rc | bix_num(w,"method",r[BI_F_METHOD]) 252 rc=rc | bix_num(w,"crc_expected",r[BI_F_CRC]) 253 rc=rc | bix_num(w,"crc_actual",r[BI_F_CRC_ACTUAL]) 254 rc=rc | bix_key(w,"integrity",bi_inflate_name(r[BI_F_INFLATE])) 255 rc=rc | json_end_object(w) 256 return rc 257} 258func bix_receipt(path: *u8, w: *JsonWriter) -> i64 { 259 if w.pos >= w.cap { return 0-1 } 260 w.buf[w.pos]=10 as u8 261 let n: i64=w.pos+1 262 if fsx_append(path,w.buf,n) < n { return 0-1 } 263 let fd: i64=sys_openat_rd(path) 264 if fd < 0 { return 0-1 } 265 let rc: i64=sys_fsync(fd) 266 let close_rc: i64=sys_close(fd) 267 if rc != 0 { return 0-1 }; if close_rc != 0 { return 0-1 } 268 if ar_syncdir_checked(path) != 0 { return 0-1 } 269 if sys_write(1,w.buf,n) != n { return 0-1 } 270 return 0 271} 272func bix_intent(receipt: *u8, archive: *u8, sha: *u8, output: *u8, member_sha: *u8) -> i64 { 273 let cap: i64=BIX_JSON_BASE_ROOM+6*(bic_len(archive)+bic_len(output)) 274 let buf: *u8=sys_mmap(cap) 275 let w: *JsonWriter=sys_mmap(40) as *JsonWriter 276 let prior: *u8=sys_mmap(JE_MAX_DEPTH+16) 277 if (buf as i64) <= 0 { return 0-1 }; if (w as i64) <= 0 { return 0-1 }; if (prior as i64) <= 0 { return 0-1 } 278 w.buf=buf; w.pos=0; w.cap=cap; w.depth=0; w.prior=prior 279 var rc: i64=json_begin_object(w) 280 rc=rc | bix_key(w,"schema","nishi.bundle.selection.v1") 281 rc=rc | bix_key(w,"state","validated-output-pending") 282 rc=rc | bix_key(w,"archive",archive) 283 rc=rc | bix_key(w,"archive_sha256",sha) 284 rc=rc | bix_key(w,"output",output) 285 rc=rc | bix_key(w,"selected_sha256",member_sha) 286 rc=rc | json_end_object(w) 287 if rc >= 0 { rc=bix_receipt(receipt,w) } 288 sys_munmap(prior,JE_MAX_DEPTH+16); sys_munmap(w as *u8,40); sys_munmap(buf,cap) 289 return rc 290} 291// Paths are caller-owned private intake paths. Detect existing inode aliases before any receipt append. 292const BIX_STAT_BYTES: i64 = 256 293const BIX_STAT_DEVICE_WORD: i64 = 0 294const BIX_STAT_INODE_WORD: i64 = 1 295func bix_alias(a: *u8, b: *u8) -> i64 { 296 if fsx_seq(a,b) == 1 { return 1 } 297 let sa: *i64=sys_mmap(BIX_STAT_BYTES) as *i64 298 let sb: *i64=sys_mmap(BIX_STAT_BYTES) as *i64 299 if (sa as i64) <= 0 { return 0-1 } 300 if (sb as i64) <= 0 { sys_munmap(sa as *u8,BIX_STAT_BYTES); return 0-1 } 301 let ra: i64=sys_fstatat(a,sa as *u8) 302 let rb: i64=sys_fstatat(b,sb as *u8) 303 var same: i64=0 304 if ra == 0 { if rb == 0 { 305 if sa[BIX_STAT_DEVICE_WORD] == sb[BIX_STAT_DEVICE_WORD] { if sa[BIX_STAT_INODE_WORD] == sb[BIX_STAT_INODE_WORD] { same=1 } } 306 } } 307 if ra != 0 { if ra != (0-2) { same=0-1 } } 308 if rb != 0 { if rb != (0-2) { same=0-1 } } 309 sys_munmap(sa as *u8,BIX_STAT_BYTES); sys_munmap(sb as *u8,BIX_STAT_BYTES) 310 return same 311} 312func bix_store_state(rc: i64) -> *u8 { 313 if rc == (0-4) { return "output-lock-refused" } 314 if rc == (0-5) { return "output-conflict" } 315 if rc == (0-6) { return "output-write-failed" } 316 if rc == (0-7) { return "output-durability-or-readback-uncertain" } 317 if rc == (0-8) { return "output-path-unreadable-or-uncertain" } 318 if rc == (0-9) { return "output-existing-symlink" } 319 return "extracted-verified" 320} 321func bix_main(argc: i64, argv: *i64) -> i64 { 322 let extracting: i64=fsx_seq(argv[1] as *u8,"extract") 323 if extracting == 1 { if argc != 9 { return 2 } } else { if argc != 5 { return 2 } } 324 let archive: *u8=argv[2] as *u8 325 var receipt: *u8=argv[3] as *u8 326 var max_archive: i64=bix_uint(argv[4] as *u8) 327 var max_member: i64=0 328 var output: *u8=0 as *u8 329 var selected_name: *u8=0 as *u8 330 if extracting == 1 { 331 selected_name=argv[3] as *u8; output=argv[4] as *u8; receipt=argv[5] as *u8 332 max_archive=bix_uint(argv[6] as *u8); max_member=bix_uint(argv[7] as *u8) 333 // Explicit expected archive identity binds selection to the caller's inspected input. 334 if bic_len(argv[8] as *u8) != PV_SHA_HEX { return 2 } 335 } 336 if max_archive <= 0 { return 2 }; if max_member < 0 { return 2 } 337 if fsx_denied(archive) == 1 { return 5 } 338 if fsx_write_denied(receipt) == 1 { return 5 } 339 if bix_alias(archive,receipt) != 0 { return 5 } 340 if extracting == 1 { if bix_alias(archive,output) != 0 { return 5 }; if bix_alias(receipt,output) != 0 { return 5 } } 341 let fd: i64=sys_openat_rd(archive) 342 if fd < 0 { return 3 } 343 let n: i64=sys_lseek(fd,0,2) 344 sys_close(fd) 345 if n <= 0 { return 3 }; if n > max_archive { return 3 } 346 let lp: *i64=sys_mmap(8) as *i64 347 if (lp as i64) <= 0 { return 4 } 348 let b: *u8=sys_read_file(archive,lp) 349 if (b as i64) <= 0 { return 3 }; if lp[0] != n { return 3 } 350 let sha: *u8=sys_mmap(PV_SHA_HEX+1) 351 if (sha as i64) <= 0 { return 4 } 352 pv_hash_bytes(b,n,sha) 353 if extracting == 1 { if fsx_seq(sha,argv[8] as *u8) != 1 { return 3 } } 354 let count: i64=bi_count(b,n) 355 if count < 0 { return 3 } 356 let eo: i64=nxzip_find_eocd(b,n) 357 let ncap: i64=nxzip_r32(b,eo+12)+count+1 358 let names: *u8=sys_mmap(ncap) 359 let tbl: *i64=sys_mmap((count+1)*BI_F_N*8) as *i64 360 let opts: *i64=sys_mmap(24) as *i64 361 if (names as i64) <= 0 { return 4 }; if (tbl as i64) <= 0 { return 4 }; if (opts as i64) <= 0 { return 4 } 362 opts[0]=count; opts[1]=0-2; opts[2]=max_member 363 let rows: i64=bi_walk_selected(b,n,tbl,names,ncap,opts) 364 if rows != count { return 3 } 365 var selected: i64=0-2 366 var state: *u8="inventory-complete" 367 var exit_code: i64=0 368 var selected_sha: *u8="" 369 if extracting == 1 { 370 var matches: i64=0; var i: i64=0 371 while i < count { let r: *i64=bi_rec(tbl,i); if r[BI_F_NAMELEN] == bic_len(selected_name) { if fsx_seq(names+r[BI_F_NAMEOFF],selected_name) == 1 { matches=matches+1; selected=i } }; i=i+1 } 372 if matches != 1 { state="selection-not-unique-or-absent"; exit_code=3 } 373 else { 374 opts[1]=selected 375 if bi_walk_selected(b,n,tbl,names,ncap,opts) != count { state="directory-refused"; exit_code=3 } 376 else { 377 let r: *i64=bi_rec(tbl,selected) 378 if r[BI_F_INFLATE] > BI_INF_OK { state=bi_inflate_name(r[BI_F_INFLATE]); exit_code=3 } 379 else { 380 selected_sha=sys_mmap(PV_SHA_HEX+1) 381 if (selected_sha as i64) <= 0 { return 4 } 382 pv_hash_bytes(r[BI_F_DATA] as *u8,r[BI_F_DLEN],selected_sha) 383 if bix_intent(receipt,archive,sha,output,selected_sha) != 0 { return 4 } 384 let stored: i64=bix_store(output,r[BI_F_DATA] as *u8,r[BI_F_DLEN]) 385 state=bix_store_state(stored) 386 if stored != 0 { exit_code=4 } 387 } 388 } 389 } 390 } 391 let cap: i64=ncap*2+(count+1)*BIX_JSON_ROW_ROOM+BIX_JSON_BASE_ROOM+(bic_len(archive)+bic_len(receipt))*6 392 let buf: *u8=sys_mmap(cap) 393 let w: *JsonWriter=sys_mmap(40) as *JsonWriter 394 if (buf as i64) <= 0 { return 4 }; if (w as i64) <= 0 { return 4 } 395 let prior: *u8=sys_mmap(JE_MAX_DEPTH+16) 396 if (prior as i64) <= 0 { return 4 } 397 w.buf=buf; w.pos=0; w.cap=cap; w.depth=0; w.prior=prior 398 var rc: i64=json_begin_object(w) 399 rc=rc | bix_key(w,"schema","nishi.bundle.selection.v1") 400 rc=rc | bix_key(w,"state",state) 401 rc=rc | bix_key(w,"archive",archive) 402 rc=rc | bix_key(w,"archive_sha256",sha) 403 rc=rc | bix_num(w,"archive_bytes",n) 404 rc=rc | bix_num(w,"members",count) 405 rc=rc | bix_num(w,"selected_index",selected) 406 rc=rc | bix_key(w,"selected_sha256",selected_sha) 407 if extracting == 1 { rc=rc | bix_key(w,"output",output) } 408 rc=rc | bix_num(w,"exit_code",exit_code) 409 rc=rc | json_emit_key(w,"entries",7) 410 rc=rc | json_begin_array(w) 411 var i: i64=0 412 while i < count { rc=rc | bix_row(w,bi_rec(tbl,i),names,i); i=i+1 } 413 rc=rc | json_end_array(w) 414 rc=rc | json_end_object(w) 415 if rc < 0 { return 4 } 416 if bix_receipt(receipt,w) != 0 { return 4 } 417 return exit_code 418} 419 420func bix_run(argc: i64, argv: *i64) -> i64 { 421 let rc: i64=bix_main(argc,argv) 422 if rc != 0 { 423 let buf: *u8=sys_mmap(256) 424 if (buf as i64) > 0 { 425 let w: *JsonWriter=sys_mmap(40) as *JsonWriter 426 let prior: *u8=sys_mmap(JE_MAX_DEPTH+16) 427 if (w as i64) > 0 { if (prior as i64) > 0 { 428 w.buf=buf; w.pos=0; w.cap=256; w.depth=0; w.prior=prior 429 json_begin_object(w); bix_key(w,"schema","nishi.bundle.selection.v1"); bix_key(w,"state","refused-or-incomplete"); bix_num(w,"exit_code",rc); json_end_object(w) 430 buf[w.pos]=10 as u8; sys_write(1,buf,w.pos+1) 431 } } 432 } 433 } 434 return rc 435} 436 437func main(argc: i64, argv: *i64) -> i64 { 438 if argc > 1 { 439 if fsx_seq(argv[1] as *u8,"inventory") == 1 { return bix_run(argc,argv) } 440 if fsx_seq(argv[1] as *u8,"extract") == 1 { return bix_run(argc,argv) } 441 } 442 if argc < 2 { bic_w(BIC_OUTFD, "usage: nx_bundle_ingest <bundle.zip|bundle.7z> [manifest.out] [source=<url>] [licence=<id>] [jrnl=<path>]\n" as *u8); return BIC_EXIT_USAGE } 443 let path: *u8 = argv[1] as *u8 444 let lp: *i64 = sys_mmap(16) as *i64 445 let b: *u8 = sys_read_file(path, lp) 446 if (b as i64) == 0 { bic_w(BIC_OUTFD, "BUNDLE-REFUSE unreadable: " as *u8); bic_w(BIC_OUTFD, path); bic_w(BIC_OUTFD, "\n" as *u8); return BIC_EXIT_REFUSE } 447 let n: i64 = lp[0] 448 // the container is decided by its MAGIC, never by the filename 449 var container: i64 = BIC_CONTAINER_ZIP 450 if sz_is_7z(b, n) == 1 { container = BIC_CONTAINER_7Z } 451 var total: i64 = 0 452 if container == BIC_CONTAINER_7Z { total = sz_count(b, n) } else { total = bi_count(b, n) } 453 if total < 0 { 454 if container == BIC_CONTAINER_7Z { bic_w(BIC_OUTFD, "BUNDLE-REFUSE 7z " as *u8); bic_w(BIC_OUTFD, sz_err_name(total)) } 455 else { bic_w(BIC_OUTFD, "BUNDLE-REFUSE no-EOCD not-a-zip-or-truncated" as *u8) } 456 bic_w(BIC_OUTFD, " bytes=" as *u8); bic_wn(BIC_OUTFD, n); bic_w(BIC_OUTFD, "\n" as *u8) 457 return BIC_EXIT_REFUSE 458 } 459 // the table and the name arena are sized from the container, never from a constant (UTF-16 names widen at most 2x) 460 let tbl: *i64 = sys_mmap(8 * BI_F_N * (total + 1)) as *i64 461 let ncap: i64 = n * 2 + BIC_NAMES_HEADROOM 462 let names: *u8 = sys_mmap(ncap) 463 let st: *i64 = sys_mmap(8 * BIC_ST_N) as *i64 464 var m: i64 = 0 465 if container == BIC_CONTAINER_7Z { m = sz_walk(b, n, tbl, total, names, ncap, st) } else { m = bi_walk(b, n, tbl, total, names, ncap) } 466 if m < 0 { 467 if container == BIC_CONTAINER_7Z { bic_w(BIC_OUTFD, "BUNDLE-REFUSE 7z walk " as *u8); bic_w(BIC_OUTFD, sz_err_name(m)); bic_w(BIC_OUTFD, "\n" as *u8) } 468 else { bic_w(BIC_OUTFD, "BUNDLE-REFUSE central-directory walk rc=" as *u8); bic_wn(BIC_OUTFD, m); bic_w(BIC_OUTFD, " (-1 no EOCD, -2 a record refused, -3 count exceeded the declared count)\n" as *u8) } 469 return BIC_EXIT_REFUSE 470 } 471 bi_bind_textures(tbl, m, names) 472 let p: *i64 = sys_mmap(8 * BI_P_N) as *i64 473 let sum: i64 = bi_partition(tbl, m, p) 474 var verdict: *u8 = "WALKED" as *u8 475 if sum != m { verdict = "REFUSED-partition-does-not-sum" as *u8 } 476 var i: i64 = 0 477 while i < m { bic_row(BIC_OUTFD, tbl, names, i, container); i = i + 1 } 478 bic_summary(BIC_OUTFD, m, p, sum, verdict, container, st) 479 var manifest: *u8 = 0 as *u8 480 if argc >= 3 { if bic_is_kv(argv[2] as *u8) == 0 { manifest = argv[2] as *u8 } } 481 if (manifest as i64) != 0 { 482 let fd: i64 = sys_openat_wr(manifest, BIC_MODE_0644) 483 if fd < 0 { bic_w(BIC_OUTFD, "BUNDLE-MANIFEST-UNWRITABLE " as *u8); bic_w(BIC_OUTFD, manifest); bic_w(BIC_OUTFD, "\n" as *u8) } 484 else { 485 i = 0 486 while i < m { bic_row(fd, tbl, names, i, container); i = i + 1 } 487 bic_summary(fd, m, p, sum, verdict, container, st) 488 sys_close(fd) 489 bic_w(BIC_OUTFD, "BUNDLE-MANIFEST wrote=" as *u8); bic_w(BIC_OUTFD, manifest); bic_w(BIC_OUTFD, "\n" as *u8) 490 } 491 } 492 bic_provenance(argc, argv, b, n) 493 if sum != m { return BIC_EXIT_REFUSE } 494 return 0 495}