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}