code wiki / (root) / nx_varcensus_candidate_t139.nx

nx_varcensus_candidate_t139.nx source

↩ module page · 1488 lines · 69333 B

1// nx_varcensus.nx -- THE VaM CORPUS CENSUS SURFACE (laptop-local lane, 2026-09-11). 2// 3// nx_varcensus names <file.var> one row per central-directory record (the package's own manifest) 4// nx_varcensus meta <file.var> meta.json's DIRECT top-level members: key, kind, size; short strings 5// nx_varcensus census <dir> <outdir> <rules.conf> EVERY .var under <dir>, recursively, into TSV reports + a summary 6// 7// WHY A SECOND CLI BESIDE nx_varfacts: nx_varfacts is the refcorpus WRITER (it imports nx_refcorpus for rc_put_row and the 8// NAS plane); this surface runs where the corpus lives (the laptop) and writes reports. Both consume the ONE walk in 9// nx_varfacts_lib (vf_cd_locate / vf_cd_entry / vf_member_data / vf_json_*): no second zip reader and no second JSON reader 10// exist here, and the classifier is DATA (nx_varcensus_lib rules). Legacy census/meta reads meta.json only. 11// Private member <file.var> <exact-member-name> <maxbytes> reads one selected member for bounded integrity/schema 12// measurements; member content is never emitted, interpreted as executable code, or published. 13// 14// THE CENSUS CONTRACT (each asserted, each printed with its sum): 15// packages walked = ok + no_eocd + zip64_eocd + window + short + read_fail + record_refused + unopenable 16// for the OK packages: members = sum over role classes = sum over format classes; meta parsed + absent + unreadable + 17// unparsed = ok packages; licence label rows sum to ok packages. A package that is not OK is named in unreadable.tsv. 18// A meta string longer than VC_SHOW_STR_MAX prints its LENGTH only in the meta verb -- free text is not needed to learn a 19// schema, and the bound is announced on every row it applies to (shown=0), never silent. 20// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 21import "nx_syscalls.nx" 22import "nx_varfacts_candidate_t139.nx" 23import "nx_varcensus_lib.nx" 24 25const VC_FD_OUT: i64 = 1 26const VC_FD_ERR: i64 = 2 27const VC_EXIT_OK: i64 = 0 28const VC_EXIT_IO: i64 = 1 29const VC_EXIT_USAGE: i64 = 2 30const VC_EXIT_MISMATCH: i64 = 3 31const VC_EXIT_REFUSED: i64 = 4 32const VC_SEEK_SET: i64 = 0 33const VC_SEEK_END: i64 = 2 34const VC_DEC: i64 = 10 35const VC_ASCII_0: i64 = 48 36const VC_ASCII_MINUS: i64 = 45 37const VC_PRINT_LO: i64 = 32 38const VC_DEL: i64 = 127 39const VC_QMARK: i64 = 63 40const VC_PAD: i64 = 16 41const VC_LINE_ROOM: i64 = 1024 42const VC_ST_N: i64 = 4 43const VC_ST_SIZE: i64 = 0 44const VC_ST_LOC: i64 = 1 45const VC_ST_WIN: i64 = 2 46const VC_ST_READFAIL: i64 = 9 47const VC_SHOW_STR_MAX: i64 = 80 48const VC_SHOW_ELEMS: i64 = 5 49const VC_MB_LEN: i64 = 0 50const VC_MB_STATE: i64 = 1 51const VC_MB_FOUND: i64 = 2 52const VC_MB_METHOD: i64 = 3 53const VC_MB_CSIZE: i64 = 4 54const VC_MB_USIZE: i64 = 5 55const VC_MB_CRC_EXPECTED: i64 = 6 56const VC_MB_CRC_ACTUAL: i64 = 7 57const VC_MB_N: i64 = 8 58const VC_MD_DUPLICATE: i64 = 6 59const VC_MD_LIMIT: i64 = 7 60const VC_MD_ENCRYPTED: i64 = 8 61const VC_META_NAME: *u8 = "meta.json" 62const VC_DEPS_KEY: *u8 = "dependencies" 63const VC_CONTENT_KEY: *u8 = "contentList" 64const VC_LIC_KEY: *u8 = "licenseType" 65const VC_CREATOR_KEY: *u8 = "creatorName" 66const VC_PACKAGE_KEY: *u8 = "packageName" 67const VC_PROGVER_KEY: *u8 = "programVersion" 68 69// census bounds that are OS or format facts, not tunables 70const VC_PATH_MAX: i64 = 4096 // Linux PATH_MAX: a longer path cannot be opened by name at all (counted, never skipped silently) 71const VC_DENT_BUF: i64 = 65536 // one getdents64 batch; the walk loops until the call returns 0 72const VC_NAME_BUF: i64 = 65536 // a ZIP member name length is a u16, so no member name is longer 73const VC_STAT_BUF: i64 = 144 74const VC_S_MODE: i64 = 24 75const VC_S_IFMT: i64 = 0xf000 76const VC_S_IFDIR: i64 = 0x4000 77const VC_S_IFREG: i64 = 0x8000 78const VC_DT_UNKNOWN: i64 = 0 79const VC_FLAG_UTF8: i64 = 2048 80const VC_LEGACY_LIC: i64 = 64 81const VC_NLETTERS: i64 = 26 82const VC_ASCII_UPPER_A: i64 = 65 83const VC_TAB: i64 = 9 84const VC_LF: i64 = 10 85const VC_SLASH: i64 = 47 86const VC_DOT: i64 = 46 87const VC_ROW_SEP: i64 = 44 88const VC_EQ: i64 = 61 89// package states: the partition of the packages walked 90const VC_P_OK: i64 = 0 91const VC_P_NOEOCD: i64 = 1 92const VC_P_ZIP64: i64 = 2 93const VC_P_WINDOW: i64 = 3 94const VC_P_SHORT: i64 = 4 95const VC_P_READFAIL: i64 = 5 96const VC_P_RECORD: i64 = 6 97const VC_P_UNOPENABLE: i64 = 7 98// a NO-EOCD package is split by what the file IS -- MEASURED 2026-09-11: the first census read 206 NO-EOCD rows and the first 99// 40 were all size=0. EMPTY is a zero-byte file; NO-EOCD-PK-HEAD carries a ZIP local header at byte 0 but no EOCD in its 100// tail window (an incomplete or damaged archive); NO-EOCD-OTHER-HEAD is not a ZIP at all. Plain NO-EOCD stays in the 101// partition and must read 0 once the split runs. 102const VC_P_EMPTY: i64 = 8 103const VC_P_NOEOCD_PK: i64 = 9 104const VC_P_NOEOCD_OTHER: i64 = 10 105const VC_P_N: i64 = 11 106const VC_HEAD_LEN: i64 = 4 107// meta states: the partition of the OK packages 108const VC_M_PARSED: i64 = 0 109const VC_M_ABSENT: i64 = 1 110const VC_M_UNREADABLE: i64 = 2 111const VC_M_UNPARSED: i64 = 3 112const VC_M_N: i64 = 4 113// walk stats 114const VC_W_DIRS: i64 = 0 115const VC_W_DIRS_UNREADABLE: i64 = 1 116const VC_W_VARS: i64 = 2 117const VC_W_VARS_TOP: i64 = 3 118const VC_W_OTHER_FILES: i64 = 4 119const VC_W_SYMLINKS: i64 = 5 120const VC_W_OTHER_TYPES: i64 = 6 121const VC_W_TOO_LONG: i64 = 7 122const VC_W_N: i64 = 8 123// licence reading agreement (legacy first-occurrence reader vs the depth-aware direct member) 124const VC_L_AGREE: i64 = 0 125const VC_L_DISAGREE: i64 = 1 126const VC_L_LEGACY_ONLY: i64 = 2 127const VC_L_DIRECT_ONLY: i64 = 3 128const VC_L_NEITHER: i64 = 4 129const VC_L_N: i64 = 5 130 131func vc_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 132func vc_streq(a: *u8, b: *u8) -> i64 { 133 var i: i64 = 0 134 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 135 if b[i] != (0 as u8) { return 0 } 136 return 1 137} 138func vc_wn(fd: i64, s: *u8, n: i64) -> i64 { 139 var done: i64 = 0 140 var run: i64 = 1 141 while run == 1 { 142 if done >= n { run = 0 } else { 143 let k: i64 = sys_write(fd, ((s as i64) + done) as *u8, n - done) 144 if k <= 0 { run = 0 } else { done = done + k } 145 } 146 } 147 return done 148} 149func vc_w(fd: i64, s: *u8) -> i64 { return vc_wn(fd, s, vc_slen(s)) } 150func vc_cat(b: *u8, o: i64, s: *u8) -> i64 { 151 var i: i64 = 0 152 while s[i] != (0 as u8) { b[o+i] = s[i]; i = i + 1 } 153 return o + i 154} 155func vc_catn(b: *u8, o: i64, v: i64) -> i64 { 156 var p: i64 = o 157 var m: i64 = v 158 if m < 0 { b[p] = VC_ASCII_MINUS as u8; p = p + 1; m = 0 - m } 159 if m == 0 { b[p] = VC_ASCII_0 as u8; return p + 1 } 160 let s: i64 = p 161 while m > 0 { b[p] = (VC_ASCII_0 + (m % VC_DEC)) as u8; m = m / VC_DEC; p = p + 1 } 162 var i: i64 = s 163 var j: i64 = p - 1 164 while i < j { let t: u8 = b[i]; b[i] = b[j]; b[j] = t; i = i + 1; j = j - 1 } 165 return p 166} 167// copy n bytes of src starting at s; control bytes and DEL become '?' so a name can never tear a row 168func vc_catb(b: *u8, o: i64, src: *u8, s: i64, n: i64) -> i64 { 169 var i: i64 = 0 170 while i < n { 171 let c: i64 = src[s+i] as i64 & 0xff 172 var ok: i64 = 1 173 if c < VC_PRINT_LO { ok = 0 } 174 if c == VC_DEL { ok = 0 } 175 if ok == 1 { b[o+i] = c as u8 } else { b[o+i] = VC_QMARK as u8 } 176 i = i + 1 177 } 178 return o + n 179} 180 181func vc_pread(fd: i64, off: i64, len: i64, buf: *u8) -> i64 { 182 if sys_lseek(fd, off, VC_SEEK_SET) != off { return 0 - 1 } 183 var got: i64 = 0 184 var run: i64 = 1 185 while run == 1 { 186 if got >= len { run = 0 } else { 187 let k: i64 = sys_read(fd, ((buf as i64) + got) as *u8, len - got) 188 if k <= 0 { run = 0 } else { got = got + k } 189 } 190 } 191 return got 192} 193 194func vc_state_name(s: i64) -> *u8 { 195 if s == VF_LOC_OK { return "OK" as *u8 } 196 if s == VF_LOC_NOEOCD { return "NO-EOCD" as *u8 } 197 if s == VF_LOC_ZIP64 { return "ZIP64" as *u8 } 198 if s == VF_LOC_WINDOW { return "WINDOW" as *u8 } 199 if s == VF_LOC_SHORT { return "SHORT" as *u8 } 200 if s == VC_ST_READFAIL { return "READ-FAIL" as *u8 } 201 return "UNNAMED" as *u8 202} 203func vc_pstate_name(s: i64) -> *u8 { 204 if s == VC_P_OK { return "OK" as *u8 } 205 if s == VC_P_NOEOCD { return "NO-EOCD" as *u8 } 206 if s == VC_P_ZIP64 { return "ZIP64-EOCD" as *u8 } 207 if s == VC_P_WINDOW { return "WINDOW" as *u8 } 208 if s == VC_P_SHORT { return "SHORT" as *u8 } 209 if s == VC_P_READFAIL { return "READ-FAIL" as *u8 } 210 if s == VC_P_RECORD { return "RECORD-REFUSED" as *u8 } 211 if s == VC_P_UNOPENABLE { return "UNOPENABLE" as *u8 } 212 if s == VC_P_EMPTY { return "EMPTY" as *u8 } 213 if s == VC_P_NOEOCD_PK { return "NO-EOCD-PK-HEAD" as *u8 } 214 if s == VC_P_NOEOCD_OTHER { return "NO-EOCD-OTHER-HEAD" as *u8 } 215 return "UNNAMED" as *u8 216} 217 218// does counter entry x rank before entry y? the higher count first, then the byte-smaller key 219func vc_rank_before(c: *i64, x: i64, y: i64) -> i64 { 220 let cx: i64 = vcl_counter_count(c, x) 221 let cy: i64 = vcl_counter_count(c, y) 222 if cx > cy { return 1 } 223 if cx < cy { return 0 } 224 if vc_cmp(vcl_counter_key(c, x), vcl_counter_key(c, y)) < 0 { return 1 } 225 return 0 226} 227// EVERY entry of a counter as TSV rows ranked by count (Shell sort of the entry indices): the whole table ranked, never a 228// top-N cut, so a reader taking the head of the file is reading a labelled head of a complete population 229func vc_counter_sorted_tsv(a: *i64, c: *i64) -> i64 { 230 let n: i64 = vcl_counter_n(c) 231 if n == 0 { return 0 } 232 let idx: *i64 = sys_mmap(n * 8) as *i64 233 var i: i64 = 0 234 while i < n { idx[i] = i; i = i + 1 } 235 var gap: i64 = n / 2 236 while gap > 0 { 237 var k: i64 = gap 238 while k < n { 239 let t: i64 = idx[k] 240 var j: i64 = k 241 var go: i64 = 1 242 while go == 1 { 243 if j < gap { go = 0 } else { 244 if vc_rank_before(c, t, idx[j - gap]) == 1 { idx[j] = idx[j - gap]; j = j - gap } else { go = 0 } 245 } 246 } 247 idx[j] = t 248 k = k + 1 249 } 250 gap = gap / 2 251 } 252 i = 0 253 while i < n { 254 vcl_appclean(a, vcl_counter_key(c, idx[i]), 0, vcl_counter_klen(c, idx[i])) 255 vcl_appc(a, VC_TAB) 256 vcl_appn(a, vcl_counter_count(c, idx[i])) 257 vcl_appc(a, VC_LF) 258 i = i + 1 259 } 260 sys_munmap(idx as *u8, n * 8) 261 return n 262} 263func vc_pstate_of(loc: i64) -> i64 { 264 if loc == VF_LOC_OK { return VC_P_OK } 265 if loc == VF_LOC_NOEOCD { return VC_P_NOEOCD } 266 if loc == VF_LOC_ZIP64 { return VC_P_ZIP64 } 267 if loc == VF_LOC_WINDOW { return VC_P_WINDOW } 268 if loc == VF_LOC_SHORT { return VC_P_SHORT } 269 return VC_P_READFAIL 270} 271func vc_md_name(s: i64) -> *u8 { 272 if s == VF_MD_STORED { return "STORED" as *u8 } 273 if s == VF_MD_INFLATED { return "INFLATED" as *u8 } 274 if s == VF_MD_UNSUPPORTED { return "UNSUPPORTED" as *u8 } 275 if s == VF_MD_SIZE_MISMATCH { return "SIZE-MISMATCH" as *u8 } 276 if s == VF_MD_CRC_MISMATCH { return "CRC-MISMATCH" as *u8 } 277 if s == VC_MD_DUPLICATE { return "DUPLICATE-MEMBER" as *u8 } 278 if s == VC_MD_LIMIT { return "MEMBER-LIMIT" as *u8 } 279 if s == VC_MD_ENCRYPTED { return "ENCRYPTED" as *u8 } 280 return "FAILED" as *u8 281} 282func vc_kind_name(k: i64) -> *u8 { 283 if k == VF_JK_STRING { return "string" as *u8 } 284 if k == VF_JK_OBJECT { return "object" as *u8 } 285 if k == VF_JK_ARRAY { return "array" as *u8 } 286 if k == VF_JK_SCALAR { return "scalar" as *u8 } 287 return "bad" as *u8 288} 289 290// THE WINDOW: read the EOCD window from the end; when the central directory starts before it, read exactly 291// [cd_abs, size) -- a window derived from the archive, never a guessed tail. st: size, locate state, window length. 292// Returns the mapping (release with sys_munmap(win, st[VC_ST_WIN] + VC_PAD)) or 0. 293func vc_window(fd: i64, size: i64, box: *i64, st: *i64) -> *u8 { 294 st[VC_ST_SIZE] = size 295 st[VC_ST_LOC] = VC_ST_READFAIL 296 st[VC_ST_WIN] = 0 297 let w0: i64 = vf_eocd_window(size) 298 if w0 <= 0 { st[VC_ST_LOC] = VF_LOC_NOEOCD; return 0 as *u8 } 299 let b0: *u8 = sys_mmap(w0 + VC_PAD) 300 if vc_pread(fd, size - w0, w0, b0) != w0 { sys_munmap(b0, w0 + VC_PAD); return 0 as *u8 } 301 let s0: i64 = vf_cd_locate(b0, w0, size, box) 302 st[VC_ST_LOC] = s0 303 st[VC_ST_WIN] = w0 304 if s0 != VF_LOC_WINDOW { return b0 } 305 let need: i64 = size - box[VF_L_CDABS] 306 sys_munmap(b0, w0 + VC_PAD) 307 st[VC_ST_WIN] = 0 308 if need <= w0 { st[VC_ST_LOC] = VF_LOC_SHORT; return 0 as *u8 } 309 if need > size { st[VC_ST_LOC] = VF_LOC_SHORT; return 0 as *u8 } 310 let b1: *u8 = sys_mmap(need + VC_PAD) 311 if vc_pread(fd, size - need, need, b1) != need { st[VC_ST_LOC] = VC_ST_READFAIL; sys_munmap(b1, need + VC_PAD); return 0 as *u8 } 312 st[VC_ST_LOC] = vf_cd_locate(b1, need, size, box) 313 st[VC_ST_WIN] = need 314 return b1 315} 316 317// meta.json of the package whose CD window is win. mbox: decoded length, vf_member_data state, found (1 found / 0 absent / 318// -1 unreadable), method. Returns the decoded bytes or 0. A member whose sizes could not be resolved (ZIP64 extra missing) 319// is UNREADABLE by name, never read at a 4 GiB size. 320// Single selected-member walk shared by meta and private measurement. No member bytes are emitted. 321func vc_member_read(fd: i64, size: i64, win: *u8, winn: i64, box: *i64, selected: *u8, maxbytes: i64, mbox: *i64) -> *u8 { 322 var i: i64 = 0 323 while i < VC_MB_N { mbox[i] = 0 - 1; i = i + 1 } 324 mbox[VC_MB_LEN] = 0 325 mbox[VC_MB_STATE] = VF_MD_FAILED 326 mbox[VC_MB_FOUND] = 0 327 let rec: *i64 = sys_mmap(VF_E_N * 8) as *i64 328 let chosen: *i64 = sys_mmap(VF_E_N * 8) as *i64 329 var off: i64 = box[VF_L_CD] 330 var k: i64 = 0 331 while k < box[VF_L_ENTRIES] { 332 if vf_cd_entry(win, winn, off, rec) != 1 { mbox[VC_MB_FOUND] = 0 - 1; return 0 as *u8 } 333 let ns: i64 = rec[VF_E_NAMEOFF] 334 if vf_span_is(win, ns, ns + rec[VF_E_NAMELEN], selected) == 1 { 335 if mbox[VC_MB_FOUND] == 1 { mbox[VC_MB_STATE] = VC_MD_DUPLICATE; return 0 as *u8 } 336 mbox[VC_MB_FOUND] = 1 337 i = 0 338 while i < VF_E_N { chosen[i] = rec[i]; i = i + 1 } 339 } 340 off = rec[VF_E_NEXT] 341 k = k + 1 342 } 343 if mbox[VC_MB_FOUND] != 1 { return 0 as *u8 } 344 let lho: i64 = chosen[VF_E_LHO] 345 let method: i64 = chosen[VF_E_METHOD] 346 let csize: i64 = chosen[VF_E_CSIZE] 347 let usize: i64 = chosen[VF_E_USIZE] 348 mbox[VC_MB_METHOD] = method 349 mbox[VC_MB_CSIZE] = csize 350 mbox[VC_MB_USIZE] = usize 351 mbox[VC_MB_CRC_EXPECTED] = chosen[VF_E_CRC] 352 if chosen[VF_E_Z64] == VF_Z64_UNRESOLVED { return 0 as *u8 } 353 if csize < 0 { return 0 as *u8 } 354 if usize < 0 { return 0 as *u8 } 355 if maxbytes > 0 { if csize > maxbytes { mbox[VC_MB_STATE] = VC_MD_LIMIT; return 0 as *u8 } if usize > maxbytes { mbox[VC_MB_STATE] = VC_MD_LIMIT; return 0 as *u8 } } 356 if (chosen[VF_E_FLAGS] & 1) != 0 { mbox[VC_MB_STATE] = VC_MD_ENCRYPTED; return 0 as *u8 } 357 if lho < 0 { return 0 as *u8 } 358 if lho > size - VF_LOCAL_LEN { return 0 as *u8 } 359 let hdr: *u8 = sys_mmap(VF_LOCAL_LEN + VC_PAD) 360 if vc_pread(fd, lho, VF_LOCAL_LEN, hdr) != VF_LOCAL_LEN { return 0 as *u8 } 361 if vf_u32(hdr, 0) != VF_SIG_LOCAL { return 0 as *u8 } 362 if vf_u16(hdr, 8) != method { return 0 as *u8 } 363 let fnl: i64 = vf_u16(hdr, VF_LOCAL_FNL) 364 if fnl != chosen[VF_E_NAMELEN] { return 0 as *u8 } 365 let nm: *u8 = sys_mmap(fnl + VC_PAD) 366 if vc_pread(fd, lho + VF_LOCAL_LEN, fnl, nm) != fnl { return 0 as *u8 } 367 if vf_span_is(nm, 0, fnl, selected) != 1 { return 0 as *u8 } 368 let doff: i64 = lho + VF_LOCAL_LEN + fnl + vf_u16(hdr, VF_LOCAL_EXL) 369 if doff > size { return 0 as *u8 } 370 if csize > size - doff { return 0 as *u8 } 371 let body: *u8 = sys_mmap(csize + VC_PAD) 372 if vc_pread(fd, doff, csize, body) != csize { sys_munmap(body, csize + VC_PAD); return 0 as *u8 } 373 let mdo: *i64 = sys_mmap(32) as *i64 374 let data: *u8 = vf_member_checked(body, csize, method, usize, chosen[VF_E_CRC], mdo) 375 mbox[VC_MB_LEN] = mdo[0] 376 mbox[VC_MB_STATE] = mdo[1] 377 mbox[VC_MB_CRC_ACTUAL] = mdo[3] 378 if mdo[1] == VF_MD_INFLATED { sys_munmap(body, csize + VC_PAD) } 379 return data 380} 381func vc_meta_read(fd: i64, size: i64, win: *u8, winn: i64, box: *i64, mbox: *i64) -> *u8 { 382 return vc_member_read(fd, size, win, winn, box, VC_META_NAME, 0, mbox) 383} 384 385func vc_names(path: *u8) -> i64 { 386 let fd: i64 = sys_openat_rd(path) 387 if fd < 0 { vc_w(VC_FD_OUT, "VARCENSUS-NAMES state=UNOPENABLE\n" as *u8); return VC_EXIT_IO } 388 let size: i64 = sys_lseek(fd, 0, VC_SEEK_END) 389 let box: *i64 = sys_mmap(VF_L_N * 8) as *i64 390 let st: *i64 = sys_mmap(VC_ST_N * 8) as *i64 391 let win: *u8 = vc_window(fd, size, box, st) 392 sys_close(fd) 393 let line: *u8 = sys_mmap(VF_U16_ALL + VC_LINE_ROOM) 394 if st[VC_ST_LOC] != VF_LOC_OK { 395 var o: i64 = vc_cat(line, 0, "VARCENSUS-NAMES state=" as *u8) 396 o = vc_cat(line, o, vc_state_name(st[VC_ST_LOC])) 397 o = vc_cat(line, o, " size=" as *u8) 398 o = vc_catn(line, o, size) 399 o = vc_cat(line, o, "\n" as *u8) 400 vc_wn(VC_FD_OUT, line, o) 401 return VC_EXIT_REFUSED 402 } 403 let rec: *i64 = sys_mmap(VF_E_N * 8) as *i64 404 let entries: i64 = box[VF_L_ENTRIES] 405 var off: i64 = box[VF_L_CD] 406 var k: i64 = 0 407 var usum: i64 = 0 408 var csum: i64 = 0 409 var z64r: i64 = 0 410 var z64u: i64 = 0 411 while k < entries { 412 if vf_cd_entry(win, st[VC_ST_WIN], off, rec) != 1 { 413 var o3: i64 = vc_cat(line, 0, "VARCENSUS-NAMES state=RECORD-REFUSED at=" as *u8) 414 o3 = vc_catn(line, o3, k) 415 o3 = vc_cat(line, o3, "\n" as *u8) 416 vc_wn(VC_FD_OUT, line, o3) 417 return VC_EXIT_REFUSED 418 } 419 var o2: i64 = vc_cat(line, 0, "M " as *u8) 420 o2 = vc_catn(line, o2, k) 421 o2 = vc_cat(line, o2, " m=" as *u8) 422 o2 = vc_catn(line, o2, rec[VF_E_METHOD]) 423 o2 = vc_cat(line, o2, " c=" as *u8) 424 o2 = vc_catn(line, o2, rec[VF_E_CSIZE]) 425 o2 = vc_cat(line, o2, " u=" as *u8) 426 o2 = vc_catn(line, o2, rec[VF_E_USIZE]) 427 o2 = vc_cat(line, o2, " f=" as *u8) 428 o2 = vc_catn(line, o2, rec[VF_E_FLAGS]) 429 o2 = vc_cat(line, o2, " z64=" as *u8) 430 o2 = vc_catn(line, o2, rec[VF_E_Z64]) 431 o2 = vc_cat(line, o2, " " as *u8) 432 o2 = vc_catb(line, o2, win, rec[VF_E_NAMEOFF], rec[VF_E_NAMELEN]) 433 o2 = vc_cat(line, o2, "\n" as *u8) 434 vc_wn(VC_FD_OUT, line, o2) 435 if rec[VF_E_Z64] == VF_Z64_RESOLVED { z64r = z64r + 1 } 436 if rec[VF_E_Z64] == VF_Z64_UNRESOLVED { z64u = z64u + 1 } else { 437 usum = usum + rec[VF_E_USIZE] 438 csum = csum + rec[VF_E_CSIZE] 439 } 440 off = rec[VF_E_NEXT] 441 k = k + 1 442 } 443 var o4: i64 = vc_cat(line, 0, "VARCENSUS-NAMES state=OK entries=" as *u8) 444 o4 = vc_catn(line, o4, entries) 445 o4 = vc_cat(line, o4, " size=" as *u8) 446 o4 = vc_catn(line, o4, size) 447 o4 = vc_cat(line, o4, " window=" as *u8) 448 o4 = vc_catn(line, o4, st[VC_ST_WIN]) 449 o4 = vc_cat(line, o4, " cd_abs=" as *u8) 450 o4 = vc_catn(line, o4, box[VF_L_CDABS]) 451 o4 = vc_cat(line, o4, " z64_resolved=" as *u8) 452 o4 = vc_catn(line, o4, z64r) 453 o4 = vc_cat(line, o4, " z64_unresolved=" as *u8) 454 o4 = vc_catn(line, o4, z64u) 455 o4 = vc_cat(line, o4, " usize_sum=" as *u8) 456 o4 = vc_catn(line, o4, usum) 457 o4 = vc_cat(line, o4, " csize_sum=" as *u8) 458 o4 = vc_catn(line, o4, csum) 459 o4 = vc_cat(line, o4, "\n" as *u8) 460 vc_wn(VC_FD_OUT, line, o4) 461 sys_munmap(win, st[VC_ST_WIN] + VC_PAD) 462 return VC_EXIT_OK 463} 464 465func vc_meta(path: *u8) -> i64 { 466 let fd: i64 = sys_openat_rd(path) 467 if fd < 0 { vc_w(VC_FD_OUT, "VARCENSUS-META state=UNOPENABLE\n" as *u8); return VC_EXIT_IO } 468 let size: i64 = sys_lseek(fd, 0, VC_SEEK_END) 469 let box: *i64 = sys_mmap(VF_L_N * 8) as *i64 470 let st: *i64 = sys_mmap(VC_ST_N * 8) as *i64 471 let win: *u8 = vc_window(fd, size, box, st) 472 let line: *u8 = sys_mmap(VF_U16_ALL + VC_LINE_ROOM) 473 if st[VC_ST_LOC] != VF_LOC_OK { 474 sys_close(fd) 475 var o: i64 = vc_cat(line, 0, "VARCENSUS-META window=" as *u8) 476 o = vc_cat(line, o, vc_state_name(st[VC_ST_LOC])) 477 o = vc_cat(line, o, "\n" as *u8) 478 vc_wn(VC_FD_OUT, line, o) 479 return VC_EXIT_REFUSED 480 } 481 let mbox: *i64 = sys_mmap(VC_MB_N * 8) as *i64 482 let data: *u8 = vc_meta_read(fd, size, win, st[VC_ST_WIN], box, mbox) 483 sys_close(fd) 484 let dn: i64 = mbox[VC_MB_LEN] 485 var o1: i64 = vc_cat(line, 0, "VARCENSUS-META found=" as *u8) 486 o1 = vc_catn(line, o1, mbox[VC_MB_FOUND]) 487 o1 = vc_cat(line, o1, " method=" as *u8) 488 o1 = vc_catn(line, o1, mbox[VC_MB_METHOD]) 489 o1 = vc_cat(line, o1, " md=" as *u8) 490 o1 = vc_cat(line, o1, vc_md_name(mbox[VC_MB_STATE])) 491 o1 = vc_cat(line, o1, " bytes=" as *u8) 492 o1 = vc_catn(line, o1, dn) 493 o1 = vc_cat(line, o1, "\n" as *u8) 494 vc_wn(VC_FD_OUT, line, o1) 495 if (data as i64) == 0 { return VC_EXIT_REFUSED } 496 let top: i64 = vf_json_skip(data, dn, 0) 497 if vf_json_kind(data, dn, top) != VF_JK_OBJECT { vc_w(VC_FD_OUT, "VARCENSUS-META json=NOT-OBJECT\n" as *u8); return VC_EXIT_REFUSED } 498 let end: i64 = vf_json_value_end(data, dn, top) 499 if end < 0 { vc_w(VC_FD_OUT, "VARCENSUS-META json=UNTERMINATED\n" as *u8); return VC_EXIT_REFUSED } 500 let mb: *i64 = sys_mmap(VF_JM_N * 8) as *i64 501 let db: *i64 = sys_mmap(VF_JM_N * 8) as *i64 502 let lenb: *i64 = sys_mmap(16) as *i64 503 var p: i64 = vf_json_skip(data, end, top + 1) 504 var members: i64 = 0 505 var run: i64 = 1 506 while run == 1 { 507 if p >= end - 1 { run = 0 } else { 508 let nx: i64 = vf_json_member(data, end, p, mb) 509 if nx < 0 { run = 0; vc_w(VC_FD_OUT, "VARCENSUS-META json=MALFORMED-MEMBER\n" as *u8) } else { 510 members = members + 1 511 let vs: i64 = mb[VF_JM_VS] 512 let ve: i64 = mb[VF_JM_VE] 513 let kind: i64 = vf_json_kind(data, dn, vs) 514 var o2: i64 = vc_cat(line, 0, "K " as *u8) 515 o2 = vc_catb(line, o2, data, mb[VF_JM_KS], mb[VF_JM_KE] - mb[VF_JM_KS]) 516 o2 = vc_cat(line, o2, " kind=" as *u8) 517 o2 = vc_cat(line, o2, vc_kind_name(kind)) 518 o2 = vc_cat(line, o2, " span=" as *u8) 519 o2 = vc_catn(line, o2, ve - vs) 520 if kind == VF_JK_STRING { 521 let sb: *u8 = sys_mmap(ve - vs + 1) 522 let sl: i64 = vf_json_decode(data, vs + 1, ve - 1, sb) 523 o2 = vc_cat(line, o2, " len=" as *u8) 524 o2 = vc_catn(line, o2, sl) 525 if sl >= 0 { if sl <= VC_SHOW_STR_MAX { o2 = vc_cat(line, o2, " value=" as *u8); o2 = vc_catb(line, o2, sb, 0, sl) } else { o2 = vc_cat(line, o2, " shown=0" as *u8) } } 526 } 527 if kind == VF_JK_ARRAY { 528 o2 = vc_cat(line, o2, " elems=" as *u8) 529 o2 = vc_catn(line, o2, vf_json_count_elems(data, dn, vs)) 530 } 531 if kind == VF_JK_OBJECT { 532 o2 = vc_cat(line, o2, " members=" as *u8) 533 o2 = vc_catn(line, o2, vf_json_count_members(data, dn, vs)) 534 } 535 if kind == VF_JK_SCALAR { 536 o2 = vc_cat(line, o2, " raw=" as *u8) 537 o2 = vc_catb(line, o2, data, vs, ve - vs) 538 } 539 o2 = vc_cat(line, o2, "\n" as *u8) 540 vc_wn(VC_FD_OUT, line, o2) 541 if kind == VF_JK_OBJECT { if vf_span_is(data, mb[VF_JM_KS], mb[VF_JM_KE], VC_DEPS_KEY) == 1 { 542 let dend: i64 = ve 543 var q: i64 = vf_json_skip(data, dend, vs + 1) 544 var drun: i64 = 1 545 while drun == 1 { 546 if q >= dend - 1 { drun = 0 } else { 547 let qn: i64 = vf_json_member(data, dend, q, db) 548 if qn < 0 { drun = 0 } else { 549 var o5: i64 = vc_cat(line, 0, " D " as *u8) 550 o5 = vc_catb(line, o5, data, db[VF_JM_KS], db[VF_JM_KE] - db[VF_JM_KS]) 551 let dk: i64 = vf_json_kind(data, dn, db[VF_JM_VS]) 552 o5 = vc_cat(line, o5, " kind=" as *u8) 553 o5 = vc_cat(line, o5, vc_kind_name(dk)) 554 if dk == VF_JK_OBJECT { 555 o5 = vc_cat(line, o5, " members=" as *u8) 556 o5 = vc_catn(line, o5, vf_json_count_members(data, dn, db[VF_JM_VS])) 557 let lic: *u8 = vf_json_get_str(data, dn, db[VF_JM_VS], VC_LIC_KEY, lenb) 558 if (lic as i64) != 0 { if lenb[0] <= VC_SHOW_STR_MAX { o5 = vc_cat(line, o5, " dep_licenseType=" as *u8); o5 = vc_catb(line, o5, lic, 0, lenb[0]) } } 559 } 560 o5 = vc_cat(line, o5, "\n" as *u8) 561 vc_wn(VC_FD_OUT, line, o5) 562 q = qn 563 } 564 } 565 } 566 } } 567 if kind == VF_JK_ARRAY { if vf_span_is(data, mb[VF_JM_KS], mb[VF_JM_KE], VC_CONTENT_KEY) == 1 { 568 let aend: i64 = ve 569 var r: i64 = vf_json_skip(data, aend, vs + 1) 570 var shown: i64 = 0 571 var arun: i64 = 1 572 while arun == 1 { 573 if r >= aend - 1 { arun = 0 } else { if shown >= VC_SHOW_ELEMS { arun = 0 } else { 574 let re: i64 = vf_json_value_end(data, aend, r) 575 if re < 0 { arun = 0 } else { 576 var o6: i64 = vc_cat(line, 0, " C " as *u8) 577 if vf_json_kind(data, dn, r) == VF_JK_STRING { 578 let cb: *u8 = sys_mmap(re - r + 1) 579 let cl: i64 = vf_json_decode(data, r + 1, re - 1, cb) 580 if cl >= 0 { o6 = vc_catb(line, o6, cb, 0, cl) } 581 } else { o6 = vc_cat(line, o6, "(non-string)" as *u8) } 582 o6 = vc_cat(line, o6, "\n" as *u8) 583 vc_wn(VC_FD_OUT, line, o6) 584 shown = shown + 1 585 var rq: i64 = vf_json_skip(data, aend, re) 586 if rq < aend { if (data[rq] as i64 & 0xff) == VF_J_COMMA { rq = vf_json_skip(data, aend, rq + 1) } } 587 if rq <= r { arun = 0 } else { r = rq } 588 } 589 } } 590 } 591 } } 592 p = nx 593 } 594 } 595 } 596 let legacy: *u8 = sys_mmap(VC_LEGACY_LIC) 597 let lr: i64 = vf_license(data, dn, 0, dn, legacy) 598 let dlen: *i64 = sys_mmap(16) as *i64 599 let dlic: *u8 = vf_json_get_str(data, dn, top, VC_LIC_KEY, dlen) 600 var o7: i64 = vc_cat(line, 0, "VARCENSUS-META members=" as *u8) 601 o7 = vc_catn(line, o7, members) 602 o7 = vc_cat(line, o7, " legacy_license=" as *u8) 603 if lr > 0 { o7 = vc_cat(line, o7, legacy) } else { o7 = vc_cat(line, o7, "unparsed" as *u8) } 604 o7 = vc_cat(line, o7, " direct_license=" as *u8) 605 if (dlic as i64) != 0 { if dlen[0] <= VC_SHOW_STR_MAX { o7 = vc_catb(line, o7, dlic, 0, dlen[0]) } } else { o7 = vc_cat(line, o7, "absent" as *u8) } 606 o7 = vc_cat(line, o7, "\n" as *u8) 607 vc_wn(VC_FD_OUT, line, o7) 608 return VC_EXIT_OK 609} 610 611// ---------------------------------------------------------------- census ---------------------------------------------------------------- 612 613func vc_cmp(a: *u8, b: *u8) -> i64 { 614 var i: i64 = 0 615 var run: i64 = 1 616 while run == 1 { 617 let ca: i64 = a[i] as i64 & 0xff 618 let cb: i64 = b[i] as i64 & 0xff 619 if ca != cb { if ca < cb { return 0 - 1 } return 1 } 620 if ca == 0 { run = 0 } else { i = i + 1 } 621 } 622 return 0 623} 624// Shell sort of the path offsets by the bytes of their paths: the report reads in one deterministic order on every run 625func vc_sort(paths: *i64, offs: *i64) -> i64 { 626 let n: i64 = vcl_vec_n(offs) 627 let v: *i64 = offs[VCL_A_PTR] as *i64 628 var gap: i64 = n / 2 629 while gap > 0 { 630 var i: i64 = gap 631 while i < n { 632 let t: i64 = v[i] 633 var j: i64 = i 634 var go: i64 = 1 635 while go == 1 { 636 if j < gap { go = 0 } else { 637 if vc_cmp(vcl_at(paths, v[j - gap]), vcl_at(paths, t)) > 0 { v[j] = v[j - gap]; j = j - gap } else { go = 0 } 638 } 639 } 640 v[j] = t 641 i = i + 1 642 } 643 gap = gap / 2 644 } 645 return n 646} 647 648// the lowercased extension of the basename of s[0..n): the bytes after its last dot, or "(none)" 649func vc_ext_key(s: *u8, n: i64, out: *u8) -> i64 { 650 var slash: i64 = 0 - 1 651 var dot: i64 = 0 - 1 652 var i: i64 = 0 653 while i < n { 654 let c: i64 = s[i] as i64 & 0xff 655 if c == VC_SLASH { slash = i; dot = 0 - 1 } 656 if c == VC_DOT { dot = i } 657 i = i + 1 658 } 659 if dot < 0 { return vc_cat(out, 0, "(none)" as *u8) } 660 if dot <= slash { return vc_cat(out, 0, "(none)" as *u8) } 661 var k: i64 = 0 662 var j: i64 = dot 663 while j < n { out[k] = vcl_lc(s[j] as i64 & 0xff) as u8; k = k + 1; j = j + 1 } 664 out[k] = 0 as u8 665 return k 666} 667// the first two path segments of a lowercased member name ("(root)" for a member with no slash): the residual worklist key 668func vc_prefix2_key(s: *u8, n: i64, out: *u8) -> i64 { 669 var first: i64 = 0 - 1 670 var second: i64 = 0 - 1 671 var i: i64 = 0 672 while i < n { 673 if (s[i] as i64 & 0xff) == VC_SLASH { if first < 0 { first = i } else { if second < 0 { second = i } } } 674 i = i + 1 675 } 676 if first < 0 { return vc_cat(out, 0, "(root)" as *u8) } 677 var e: i64 = n 678 if second >= 0 { e = second + 1 } 679 var k: i64 = 0 680 while k < e { out[k] = s[k]; k = k + 1 } 681 out[k] = 0 as u8 682 return k 683} 684 685// walk root recursively: every .var path (case-insensitive suffix) into paths/offs; other files counted by extension; 686// directories that cannot be opened, symlinks, other node types and over-long paths are COUNTED and named, never dropped 687func vc_walk(root: *u8, paths: *i64, offs: *i64, exts: *i64, ws: *i64, unread: *i64) -> i64 { 688 let dirs: *i64 = vcl_arena_new(VCL_ARENA_INIT) 689 let dq: *i64 = vcl_arena_new(VCL_ARENA_INIT) 690 let rl: i64 = vc_slen(root) 691 vcl_push(dq, vcl_put(dirs, root, 0, rl)) 692 vcl_push(dq, 0) 693 let cur: *u8 = sys_mmap(VC_PATH_MAX + VC_PAD) 694 let child: *u8 = sys_mmap(VC_PATH_MAX + VC_PAD) 695 let dbuf: *u8 = sys_mmap(VC_DENT_BUF + VC_PAD) 696 let stbuf: *u8 = sys_mmap(VC_STAT_BUF + VC_PAD) 697 let extb: *u8 = sys_mmap(VC_PATH_MAX + VC_PAD) 698 var qi: i64 = 0 699 while qi < vcl_vec_n(dq) / 2 { 700 let doff: i64 = vcl_vec_at(dq, qi * 2) 701 let depth: i64 = vcl_vec_at(dq, qi * 2 + 1) 702 let dp: *u8 = vcl_at(dirs, doff) 703 let cl: i64 = vc_slen(dp) 704 var ci: i64 = 0 705 while ci < cl { cur[ci] = dp[ci]; ci = ci + 1 } 706 cur[cl] = 0 as u8 707 let fd: i64 = sys_openat_directory(cur) 708 if fd < 0 { 709 ws[VC_W_DIRS_UNREADABLE] = ws[VC_W_DIRS_UNREADABLE] + 1 710 vcl_apps(unread, "DIR-UNREADABLE" as *u8) 711 vcl_appc(unread, VC_TAB) 712 vcl_appclean(unread, cur, 0, cl) 713 vcl_appc(unread, VC_TAB) 714 vcl_appn(unread, fd) 715 vcl_appc(unread, VC_LF) 716 } else { 717 ws[VC_W_DIRS] = ws[VC_W_DIRS] + 1 718 var run: i64 = 1 719 while run == 1 { 720 let nb: i64 = sys_getdents64(fd, dbuf, VC_DENT_BUF) 721 if nb <= 0 { run = 0 } else { 722 var off: i64 = 0 723 while off < nb { 724 let rec: *u8 = ((dbuf as i64) + off) as *u8 725 let reclen: i64 = dirent_reclen(rec) 726 if reclen <= 0 { off = nb } else { 727 let nm: *u8 = dirent_name(rec) 728 let nml: i64 = vc_slen(nm) 729 var dot: i64 = 0 730 if vc_streq(nm, "." as *u8) == 1 { dot = 1 } 731 if vc_streq(nm, ".." as *u8) == 1 { dot = 1 } 732 if dot == 0 { 733 var co: i64 = cl 734 var ci2: i64 = 0 735 while ci2 < cl { child[ci2] = cur[ci2]; ci2 = ci2 + 1 } 736 var need_slash: i64 = 1 737 if cl > 0 { if (cur[cl-1] as i64 & 0xff) == VC_SLASH { need_slash = 0 } } 738 if co + need_slash + nml >= VC_PATH_MAX { 739 ws[VC_W_TOO_LONG] = ws[VC_W_TOO_LONG] + 1 740 vcl_apps(unread, "PATH-TOO-LONG" as *u8) 741 vcl_appc(unread, VC_TAB) 742 vcl_appclean(unread, cur, 0, cl) 743 vcl_appc(unread, VC_LF) 744 } else { 745 if need_slash == 1 { child[co] = VC_SLASH as u8; co = co + 1 } 746 var cj: i64 = 0 747 while cj < nml { child[co + cj] = nm[cj]; cj = cj + 1 } 748 co = co + nml 749 child[co] = 0 as u8 750 var t: i64 = dirent_type(rec) 751 if t == VC_DT_UNKNOWN { 752 if sys_fstatat(child, stbuf) == 0 { 753 let mode: i64 = vf_u32(stbuf, VC_S_MODE) & VC_S_IFMT 754 if mode == VC_S_IFDIR { t = DT_DIR } 755 if mode == VC_S_IFREG { t = DT_REG } 756 } 757 } 758 if t == DT_DIR { 759 vcl_push(dq, vcl_put(dirs, child, 0, co)) 760 vcl_push(dq, depth + 1) 761 } else { 762 if t == DT_REG { 763 var isvar: i64 = 0 764 if nml >= 4 { 765 if (nm[nml-4] as i64 & 0xff) == VC_DOT { 766 if vcl_lc(nm[nml-3] as i64 & 0xff) == 118 { if vcl_lc(nm[nml-2] as i64 & 0xff) == 97 { if vcl_lc(nm[nml-1] as i64 & 0xff) == 114 { isvar = 1 } } } 767 } 768 } 769 if isvar == 1 { 770 vcl_push(offs, vcl_put(paths, child, 0, co)) 771 ws[VC_W_VARS] = ws[VC_W_VARS] + 1 772 if depth == 0 { ws[VC_W_VARS_TOP] = ws[VC_W_VARS_TOP] + 1 } 773 } else { 774 ws[VC_W_OTHER_FILES] = ws[VC_W_OTHER_FILES] + 1 775 let el: i64 = vc_ext_key(nm, nml, extb) 776 vcl_counter_add(exts, extb, 0, el, 1) 777 } 778 } else { 779 if t == DT_LNK { ws[VC_W_SYMLINKS] = ws[VC_W_SYMLINKS] + 1 } else { ws[VC_W_OTHER_TYPES] = ws[VC_W_OTHER_TYPES] + 1 } 780 } 781 } 782 } 783 } 784 off = off + reclen 785 } 786 } 787 } 788 } 789 sys_close(fd) 790 } 791 qi = qi + 1 792 } 793 return ws[VC_W_VARS] 794} 795 796func vc_write_out(dir: *u8, name: *u8, a: *i64, total: *i64) -> i64 { 797 let p: *u8 = sys_mmap(VC_PATH_MAX + VC_PAD) 798 let dl: i64 = vc_slen(dir) 799 if dl + vc_slen(name) + 2 >= VC_PATH_MAX { return 0 - 1 } 800 var o: i64 = vc_cat(p, 0, dir) 801 if o > 0 { if (p[o-1] as i64 & 0xff) != VC_SLASH { p[o] = VC_SLASH as u8; o = o + 1 } } 802 o = vc_cat(p, o, name) 803 p[o] = 0 as u8 804 let fd: i64 = sys_openat_wr(p, MODE_0644) 805 if fd < 0 { return 0 - 1 } 806 let w: i64 = vc_wn(fd, vcl_at(a, 0), vcl_used(a)) 807 sys_close(fd) 808 total[0] = total[0] + w 809 if w != vcl_used(a) { return 0 - 1 } 810 return w 811} 812 813func vc_kv(a: *i64, k: *u8, v: i64) -> i64 { 814 vcl_appc(a, 32) 815 vcl_apps(a, k) 816 vcl_appc(a, VC_EQ) 817 vcl_appn(a, v) 818 return 0 819} 820 821// decode the DIRECT string member key of the object at obj into out (caller sizes it >= n + 1); length or -1 822func vc_get_str(data: *u8, n: i64, obj: i64, key: *u8, jm: *i64, out: *u8) -> i64 { 823 out[0] = 0 as u8 824 let vs: i64 = vf_json_find(data, n, obj, key, jm) 825 if vs < 0 { return 0 - 1 } 826 if vf_json_kind(data, n, vs) != VF_JK_STRING { return 0 - 1 } 827 return vf_json_decode(data, vs + 1, jm[VF_JM_VE] - 1, out) 828} 829 830// append "name=count" for every class of an axis with a non-zero count, comma separated ("-" when none) 831func vc_app_counts(a: *i64, rs: *i64, axis: i64, counts: *i64, nclass: i64) -> i64 { 832 var first: i64 = 1 833 var c: i64 = 0 834 while c < nclass { 835 if counts[c] > 0 { 836 if first == 0 { vcl_appc(a, VC_ROW_SEP) } 837 vcl_apps(a, vcl_class_name(rs, axis, c)) 838 vcl_appc(a, VC_EQ) 839 vcl_appn(a, counts[c]) 840 first = 0 841 } 842 c = c + 1 843 } 844 if first == 1 { vcl_appc(a, VC_ASCII_MINUS) } 845 return 0 846} 847 848func vc_counter_tsv(a: *i64, c: *i64, prefix: *u8) -> i64 { 849 var i: i64 = 0 850 while i < vcl_counter_n(c) { 851 if vc_slen(prefix) > 0 { vcl_apps(a, prefix); vcl_appc(a, VC_TAB) } 852 vcl_appclean(a, vcl_counter_key(c, i), 0, vcl_counter_klen(c, i)) 853 vcl_appc(a, VC_TAB) 854 vcl_appn(a, vcl_counter_count(c, i)) 855 vcl_appc(a, VC_LF) 856 i = i + 1 857 } 858 return i 859} 860 861func vc_census(root: *u8, outdir: *u8, rulespath: *u8) -> i64 { 862 let rlen: *i64 = sys_mmap(16) as *i64 863 let rtext: *u8 = sys_read_file(rulespath, rlen) 864 if (rtext as i64) == 0 { vc_w(VC_FD_OUT, "VARCENSUS state=RULES-UNREADABLE\n" as *u8); return VC_EXIT_IO } 865 let rs: *i64 = vcl_rules_parse(rtext, rlen[0]) 866 let sm: *i64 = vcl_arena_new(VCL_ARENA_INIT) 867 if rs[VCL_RS_ERRORS] > 0 { 868 vcl_apps(sm, "VARCENSUS state=RULES-MALFORMED" as *u8) 869 vc_kv(sm, "errors" as *u8, rs[VCL_RS_ERRORS]) 870 vc_kv(sm, "first_line" as *u8, rs[VCL_RS_FIRST_ERR_LINE]) 871 vcl_appc(sm, VC_LF) 872 vc_wn(VC_FD_OUT, vcl_at(sm, 0), vcl_used(sm)) 873 return VC_EXIT_REFUSED 874 } 875 sys_mkdir(outdir, MODE_0755) 876 let nrole: i64 = vcl_nclasses(rs, VCL_AX_ROLE) 877 let nfmt: i64 = vcl_nclasses(rs, VCL_AX_FORMAT) 878 let tags: *i64 = rs[VCL_RS_TAGS] as *i64 879 let ntags: i64 = vcl_counter_n(tags) 880 let other_role: i64 = rs[VCL_RS_OTHER_ROLE] 881 let other_fmt: i64 = rs[VCL_RS_OTHER_FORMAT] 882 883 // ---- walk ---- 884 let paths: *i64 = vcl_arena_new(VCL_ARENA_INIT) 885 let offs: *i64 = vcl_arena_new(VCL_ARENA_INIT) 886 let exts: *i64 = vcl_counter_new() 887 let ws: *i64 = sys_mmap(VC_W_N * 8) as *i64 888 let ur: *i64 = vcl_arena_new(VCL_ARENA_INIT) 889 vcl_apps(ur, "state\tfile\tdetail\n" as *u8) 890 vc_walk(root, paths, offs, exts, ws, ur) 891 let npk: i64 = vc_sort(paths, offs) 892 let rootl: i64 = vc_slen(root) 893 894 // ---- outputs ---- 895 let pk: *i64 = vcl_arena_new(VCL_ARENA_INIT) 896 vcl_apps(pk, "file\tsize\tstate\tentries\tdirs\tz64_members\tz64_unresolved\tutf8_members\tmeta\tlicense\tcreator\tpackage\tprogram_version\tcontent_elems\tdeps_direct\tdeptags\trp_screen\tusize_sum\trole_counts\tformat_counts\n" as *u8) 897 let dpa: *i64 = vcl_arena_new(VCL_ARENA_INIT) 898 vcl_apps(dpa, "from\tto\tto_license\tdeptag\n" as *u8) 899 let rpa: *i64 = vcl_arena_new(VCL_ARENA_INIT) 900 vcl_apps(rpa, "file\treasons\tlicense\n" as *u8) 901 let labels: *i64 = vcl_counter_new() 902 let creators: *i64 = vcl_counter_new() 903 let targets: *i64 = vcl_counter_new() 904 let resrole: *i64 = vcl_counter_new() 905 let resfmt: *i64 = vcl_counter_new() 906 907 let role_members: *i64 = sys_mmap((nrole + 1) * 8) as *i64 908 let role_pkgs: *i64 = sys_mmap((nrole + 1) * 8) as *i64 909 let role_usize: *i64 = sys_mmap((nrole + 1) * 8) as *i64 910 let fmt_members: *i64 = sys_mmap((nfmt + 1) * 8) as *i64 911 let fmt_pkgs: *i64 = sys_mmap((nfmt + 1) * 8) as *i64 912 let fmt_usize: *i64 = sys_mmap((nfmt + 1) * 8) as *i64 913 let prole: *i64 = sys_mmap((nrole + 1) * 8) as *i64 914 let pfmt: *i64 = sys_mmap((nfmt + 1) * 8) as *i64 915 let pstates: *i64 = sys_mmap(VC_P_N * 8) as *i64 916 let mstates: *i64 = sys_mmap(VC_M_N * 8) as *i64 917 let lagree: *i64 = sys_mmap(VC_L_N * 8) as *i64 918 let tag_pkgs: *i64 = sys_mmap((ntags + 1) * 8) as *i64 919 let tag_edges: *i64 = sys_mmap((ntags + 1) * 8) as *i64 920 let ptag: *i64 = sys_mmap((ntags + 1) * 8) as *i64 921 let reason_pkgs: *i64 = sys_mmap(VC_NLETTERS * 8) as *i64 922 var t_members: i64 = 0 923 var t_dirs: i64 = 0 924 var t_z64: i64 = 0 925 var t_z64u: i64 = 0 926 var t_pkgs_z64: i64 = 0 927 var t_utf8: i64 = 0 928 var t_usize: i64 = 0 929 var t_edges: i64 = 0 930 var t_pkgs_deps: i64 = 0 931 var t_deps_malformed: i64 = 0 932 var t_flagged: i64 = 0 933 var t_role_sum: i64 = 0 934 var t_fmt_sum: i64 = 0 935 936 let box: *i64 = sys_mmap(VF_L_N * 8) as *i64 937 let st: *i64 = sys_mmap(VC_ST_N * 8) as *i64 938 let rec: *i64 = sys_mmap(VF_E_N * 8) as *i64 939 let namebuf: *u8 = sys_mmap(VC_NAME_BUF + VC_PAD) 940 let keyb: *u8 = sys_mmap(VC_NAME_BUF + VC_PAD) 941 let idlc: *u8 = sys_mmap(VC_PATH_MAX + VC_PAD) 942 let mbox: *i64 = sys_mmap(VC_MB_N * 8) as *i64 943 let jm: *i64 = sys_mmap(VF_JM_N * 8) as *i64 944 let jm2: *i64 = sys_mmap(VF_JM_N * 8) as *i64 945 let headb: *u8 = sys_mmap(VC_HEAD_LEN + VC_PAD) 946 let db: *i64 = sys_mmap(VF_JM_N * 8) as *i64 947 let legacy: *u8 = sys_mmap(VC_LEGACY_LIC) 948 949 var i: i64 = 0 950 while i < npk { 951 let path: *u8 = vcl_at(paths, vcl_vec_at(offs, i)) 952 let pl: i64 = vc_slen(path) 953 var rel: i64 = rootl 954 if rel < pl { if (path[rel] as i64 & 0xff) == VC_SLASH { rel = rel + 1 } } 955 // the package id: the relative path's basename without its 4-byte .var suffix 956 var bs: i64 = rel 957 var bi: i64 = rel 958 while bi < pl { if (path[bi] as i64 & 0xff) == VC_SLASH { bs = bi + 1 } bi = bi + 1 } 959 let idl: i64 = pl - 4 - bs 960 vcl_lower(((path as i64) + bs) as *u8, idl, idlc) 961 962 var state: i64 = VC_P_OK 963 var size: i64 = 0 - 1 964 var win: *u8 = 0 as *u8 965 let fd: i64 = sys_openat_rd(path) 966 if fd < 0 { state = VC_P_UNOPENABLE } else { 967 size = sys_lseek(fd, 0, VC_SEEK_END) 968 win = vc_window(fd, size, box, st) 969 state = vc_pstate_of(st[VC_ST_LOC]) 970 // split NO-EOCD by what the file IS: zero bytes, a ZIP local header with no EOCD, or not a ZIP at all 971 if state == VC_P_NOEOCD { 972 if size == 0 { state = VC_P_EMPTY } else { 973 state = VC_P_NOEOCD_OTHER 974 if size >= VC_HEAD_LEN { if vc_pread(fd, 0, VC_HEAD_LEN, headb) == VC_HEAD_LEN { if vf_u32(headb, 0) == VF_SIG_LOCAL { state = VC_P_NOEOCD_PK } } } 975 } 976 } 977 } 978 var c: i64 = 0 979 while c < nrole { prole[c] = 0; c = c + 1 } 980 c = 0 981 while c < nfmt { pfmt[c] = 0; c = c + 1 } 982 var p_entries: i64 = 0 983 var p_dirs: i64 = 0 984 var p_z64: i64 = 0 985 var p_z64u: i64 = 0 986 var p_utf8: i64 = 0 987 var p_usize: i64 = 0 988 if state == VC_P_OK { 989 p_entries = box[VF_L_ENTRIES] 990 var off: i64 = box[VF_L_CD] 991 var k: i64 = 0 992 var go: i64 = 1 993 while go == 1 { 994 if k >= p_entries { go = 0 } else { 995 if vf_cd_entry(win, st[VC_ST_WIN], off, rec) != 1 { state = VC_P_RECORD; go = 0 } else { 996 let nl: i64 = rec[VF_E_NAMELEN] 997 vcl_lower(((win as i64) + rec[VF_E_NAMEOFF]) as *u8, nl, namebuf) 998 if rec[VF_E_Z64] == VF_Z64_RESOLVED { p_z64 = p_z64 + 1 } 999 if (rec[VF_E_FLAGS] / VC_FLAG_UTF8) % 2 == 1 { p_utf8 = p_utf8 + 1 } 1000 if nl > 0 { if (namebuf[nl-1] as i64 & 0xff) == VC_SLASH { p_dirs = p_dirs + 1 } } 1001 let r: i64 = vcl_classify(rs, VCL_AX_ROLE, namebuf, nl) 1002 let f: i64 = vcl_classify(rs, VCL_AX_FORMAT, namebuf, nl) 1003 prole[r] = prole[r] + 1 1004 pfmt[f] = pfmt[f] + 1 1005 if rec[VF_E_Z64] == VF_Z64_UNRESOLVED { p_z64u = p_z64u + 1 } else { 1006 p_usize = p_usize + rec[VF_E_USIZE] 1007 role_usize[r] = role_usize[r] + rec[VF_E_USIZE] 1008 fmt_usize[f] = fmt_usize[f] + rec[VF_E_USIZE] 1009 } 1010 if r == other_role { let kl: i64 = vc_prefix2_key(namebuf, nl, keyb); vcl_counter_add(resrole, keyb, 0, kl, 1) } 1011 if f == other_fmt { let kl2: i64 = vc_ext_key(namebuf, nl, keyb); vcl_counter_add(resfmt, keyb, 0, kl2, 1) } 1012 off = rec[VF_E_NEXT] 1013 k = k + 1 1014 } 1015 } 1016 } 1017 } 1018 pstates[state] = pstates[state] + 1 1019 if state != VC_P_OK { 1020 vcl_apps(ur, vc_pstate_name(state)) 1021 vcl_appc(ur, VC_TAB) 1022 vcl_appclean(ur, path, rel, pl - rel) 1023 vcl_appc(ur, VC_TAB) 1024 vcl_apps(ur, "size=" as *u8) 1025 vcl_appn(ur, size) 1026 vcl_appc(ur, VC_LF) 1027 if (win as i64) != 0 { sys_munmap(win, st[VC_ST_WIN] + VC_PAD) } 1028 if fd >= 0 { sys_close(fd) } 1029 } else { 1030 // fold the package into the corpus only once its whole central directory read cleanly 1031 t_members = t_members + p_entries 1032 t_dirs = t_dirs + p_dirs 1033 t_z64 = t_z64 + p_z64 1034 t_z64u = t_z64u + p_z64u 1035 if p_z64 > 0 { t_pkgs_z64 = t_pkgs_z64 + 1 } 1036 t_utf8 = t_utf8 + p_utf8 1037 t_usize = t_usize + p_usize 1038 c = 0 1039 while c < nrole { role_members[c] = role_members[c] + prole[c]; if prole[c] > 0 { role_pkgs[c] = role_pkgs[c] + 1 } t_role_sum = t_role_sum + prole[c]; c = c + 1 } 1040 c = 0 1041 while c < nfmt { fmt_members[c] = fmt_members[c] + pfmt[c]; if pfmt[c] > 0 { fmt_pkgs[c] = fmt_pkgs[c] + 1 } t_fmt_sum = t_fmt_sum + pfmt[c]; c = c + 1 } 1042 1043 let data: *u8 = vc_meta_read(fd, size, win, st[VC_ST_WIN], box, mbox) 1044 sys_close(fd) 1045 let dn: i64 = mbox[VC_MB_LEN] 1046 var mstate: i64 = VC_M_ABSENT 1047 if mbox[VC_MB_FOUND] < 0 { mstate = VC_M_UNREADABLE } 1048 if mbox[VC_MB_FOUND] == 1 { if (data as i64) == 0 { mstate = VC_M_UNREADABLE } } 1049 var top: i64 = 0 - 1 1050 if (data as i64) != 0 { 1051 top = vf_json_skip(data, dn, 0) 1052 mstate = VC_M_UNPARSED 1053 if vf_json_kind(data, dn, top) == VF_JK_OBJECT { if vf_json_value_end(data, dn, top) >= 0 { mstate = VC_M_PARSED } } 1054 } 1055 mstates[mstate] = mstates[mstate] + 1 1056 var fbuf: *u8 = 0 as *u8 1057 var fcell: i64 = 0 1058 if mstate == VC_M_PARSED { fcell = dn + 1; fbuf = sys_mmap(fcell * 6 + VC_PAD) } 1059 let lb: *u8 = ((fbuf as i64) + 0) as *u8 1060 let cbuf: *u8 = ((fbuf as i64) + fcell) as *u8 1061 let pbuf: *u8 = ((fbuf as i64) + fcell * 2) as *u8 1062 let vbuf: *u8 = ((fbuf as i64) + fcell * 3) as *u8 1063 let kbuf: *u8 = ((fbuf as i64) + fcell * 4) as *u8 1064 let dlbuf: *u8 = ((fbuf as i64) + fcell * 5) as *u8 1065 var ll: i64 = 0 - 1 1066 var crl: i64 = 0 - 1 1067 var pnl: i64 = 0 - 1 1068 var pvl: i64 = 0 - 1 1069 var celems: i64 = 0 - 1 1070 var pdeps: i64 = 0 1071 c = 0 1072 while c < ntags { ptag[c] = 0; c = c + 1 } 1073 if mstate == VC_M_PARSED { 1074 ll = vc_get_str(data, dn, top, VC_LIC_KEY, jm, lb) 1075 crl = vc_get_str(data, dn, top, VC_CREATOR_KEY, jm, cbuf) 1076 pnl = vc_get_str(data, dn, top, VC_PACKAGE_KEY, jm, pbuf) 1077 pvl = vc_get_str(data, dn, top, VC_PROGVER_KEY, jm, vbuf) 1078 let cv: i64 = vf_json_find(data, dn, top, VC_CONTENT_KEY, jm) 1079 if cv >= 0 { celems = vf_json_count_elems(data, dn, cv) } 1080 // legacy first-occurrence licence reader against the depth-aware direct member: agreement MEASURED 1081 let lr: i64 = vf_license(data, dn, 0, dn, legacy) 1082 var li: i64 = VC_L_NEITHER 1083 if lr > 0 { if ll >= 0 { 1084 li = VC_L_DISAGREE 1085 if lr == ll { if vcl_eq(legacy, 0, lb, 0, ll) == 1 { li = VC_L_AGREE } } 1086 } else { li = VC_L_LEGACY_ONLY } } else { if ll >= 0 { li = VC_L_DIRECT_ONLY } } 1087 lagree[li] = lagree[li] + 1 1088 // direct dependency edges 1089 let dv: i64 = vf_json_find(data, dn, top, VC_DEPS_KEY, jm) 1090 if dv >= 0 { if vf_json_kind(data, dn, dv) == VF_JK_OBJECT { 1091 let dend: i64 = jm[VF_JM_VE] 1092 var q: i64 = vf_json_skip(data, dend, dv + 1) 1093 var drun: i64 = 1 1094 while drun == 1 { 1095 if q >= dend - 1 { drun = 0 } else { 1096 let qn: i64 = vf_json_member(data, dend, q, db) 1097 if qn < 0 { drun = 0; t_deps_malformed = t_deps_malformed + 1 } else { 1098 let kl3: i64 = vf_json_decode(data, db[VF_JM_KS], db[VF_JM_KE], kbuf) 1099 if kl3 >= 0 { 1100 pdeps = pdeps + 1 1101 vcl_lower(kbuf, kl3, keyb) 1102 let tg: i64 = vcl_deptag(rs, keyb, kl3) 1103 var dll: i64 = 0 - 1 1104 if vf_json_kind(data, dn, db[VF_JM_VS]) == VF_JK_OBJECT { dll = vc_get_str(data, dn, db[VF_JM_VS], VC_LIC_KEY, jm2, dlbuf) } 1105 vcl_appclean(dpa, path, bs, idl) 1106 vcl_appc(dpa, VC_TAB) 1107 vcl_appclean(dpa, kbuf, 0, kl3) 1108 vcl_appc(dpa, VC_TAB) 1109 if dll >= 0 { vcl_appclean(dpa, dlbuf, 0, dll) } else { vcl_appc(dpa, VC_ASCII_MINUS) } 1110 vcl_appc(dpa, VC_TAB) 1111 if tg >= 0 { vcl_apps(dpa, vcl_counter_key(tags, tg)); ptag[tg] = 1; tag_edges[tg] = tag_edges[tg] + 1 } else { vcl_appc(dpa, VC_ASCII_MINUS) } 1112 vcl_appc(dpa, VC_LF) 1113 vcl_counter_add(targets, keyb, 0, kl3, 1) 1114 t_edges = t_edges + 1 1115 } 1116 q = qn 1117 } 1118 } 1119 } 1120 } } 1121 } 1122 if pdeps > 0 { t_pkgs_deps = t_pkgs_deps + 1 } 1123 c = 0 1124 while c < ntags { if ptag[c] == 1 { tag_pkgs[c] = tag_pkgs[c] + 1 } c = c + 1 } 1125 // the licence label partition (every OK package lands in exactly one row) 1126 if mstate == VC_M_PARSED { 1127 if ll > 0 { vcl_counter_add(labels, lb, 0, ll, 1) } else { if ll == 0 { vcl_counter_add(labels, "(empty)" as *u8, 0, 7, 1) } else { vcl_counter_add(labels, "(no-licenseType)" as *u8, 0, 16, 1) } } 1128 if crl > 0 { vcl_counter_add(creators, cbuf, 0, crl, 1) } else { vcl_counter_add(creators, "(no-creatorName)" as *u8, 0, 16, 1) } 1129 } else { 1130 if mstate == VC_M_ABSENT { vcl_counter_add(labels, "(meta-absent)" as *u8, 0, 13, 1) } 1131 if mstate == VC_M_UNREADABLE { vcl_counter_add(labels, "(meta-unreadable)" as *u8, 0, 17, 1) } 1132 if mstate == VC_M_UNPARSED { vcl_counter_add(labels, "(meta-unparsed)" as *u8, 0, 15, 1) } 1133 } 1134 // the real-person screen: reasons from role classes and the package id, never adjudicated here 1135 let mask: i64 = vcl_screen(rs, prole, idlc, idl) 1136 if mask != 0 { 1137 t_flagged = t_flagged + 1 1138 var m: i64 = mask 1139 var bit: i64 = 0 1140 while bit < VC_NLETTERS { if m % 2 == 1 { reason_pkgs[bit] = reason_pkgs[bit] + 1 } m = m / 2; bit = bit + 1 } 1141 vcl_appclean(rpa, path, rel, pl - rel) 1142 vcl_appc(rpa, VC_TAB) 1143 vcl_app_reasons(rpa, mask) 1144 vcl_appc(rpa, VC_TAB) 1145 if ll > 0 { vcl_appclean(rpa, lb, 0, ll) } else { vcl_appc(rpa, VC_ASCII_MINUS) } 1146 vcl_appc(rpa, VC_LF) 1147 } 1148 // the package row 1149 vcl_appclean(pk, path, rel, pl - rel) 1150 vcl_appc(pk, VC_TAB) 1151 vcl_appn(pk, size) 1152 vcl_appc(pk, VC_TAB) 1153 vcl_apps(pk, "OK" as *u8) 1154 vcl_appc(pk, VC_TAB) 1155 vcl_appn(pk, p_entries) 1156 vcl_appc(pk, VC_TAB) 1157 vcl_appn(pk, p_dirs) 1158 vcl_appc(pk, VC_TAB) 1159 vcl_appn(pk, p_z64) 1160 vcl_appc(pk, VC_TAB) 1161 vcl_appn(pk, p_z64u) 1162 vcl_appc(pk, VC_TAB) 1163 vcl_appn(pk, p_utf8) 1164 vcl_appc(pk, VC_TAB) 1165 if mstate == VC_M_PARSED { vcl_apps(pk, "parsed" as *u8) } 1166 if mstate == VC_M_ABSENT { vcl_apps(pk, "absent" as *u8) } 1167 if mstate == VC_M_UNREADABLE { vcl_apps(pk, "unreadable" as *u8) } 1168 if mstate == VC_M_UNPARSED { vcl_apps(pk, "unparsed" as *u8) } 1169 vcl_appc(pk, VC_TAB) 1170 if ll > 0 { vcl_appclean(pk, lb, 0, ll) } else { vcl_appc(pk, VC_ASCII_MINUS) } 1171 vcl_appc(pk, VC_TAB) 1172 if crl > 0 { vcl_appclean(pk, cbuf, 0, crl) } else { vcl_appc(pk, VC_ASCII_MINUS) } 1173 vcl_appc(pk, VC_TAB) 1174 if pnl > 0 { vcl_appclean(pk, pbuf, 0, pnl) } else { vcl_appc(pk, VC_ASCII_MINUS) } 1175 vcl_appc(pk, VC_TAB) 1176 if pvl > 0 { vcl_appclean(pk, vbuf, 0, pvl) } else { vcl_appc(pk, VC_ASCII_MINUS) } 1177 vcl_appc(pk, VC_TAB) 1178 vcl_appn(pk, celems) 1179 vcl_appc(pk, VC_TAB) 1180 vcl_appn(pk, pdeps) 1181 vcl_appc(pk, VC_TAB) 1182 var tfirst: i64 = 1 1183 c = 0 1184 while c < ntags { if ptag[c] == 1 { if tfirst == 0 { vcl_appc(pk, VC_ROW_SEP) } vcl_apps(pk, vcl_counter_key(tags, c)); tfirst = 0 } c = c + 1 } 1185 if tfirst == 1 { vcl_appc(pk, VC_ASCII_MINUS) } 1186 vcl_appc(pk, VC_TAB) 1187 vcl_app_reasons(pk, mask) 1188 vcl_appc(pk, VC_TAB) 1189 vcl_appn(pk, p_usize) 1190 vcl_appc(pk, VC_TAB) 1191 vc_app_counts(pk, rs, VCL_AX_ROLE, prole, nrole) 1192 vcl_appc(pk, VC_TAB) 1193 vc_app_counts(pk, rs, VCL_AX_FORMAT, pfmt, nfmt) 1194 vcl_appc(pk, VC_LF) 1195 if fcell > 0 { sys_munmap(fbuf, fcell * 6 + VC_PAD) } 1196 sys_munmap(win, st[VC_ST_WIN] + VC_PAD) 1197 } 1198 i = i + 1 1199 } 1200 1201 // ---- aggregate tables ---- 1202 let cls: *i64 = vcl_arena_new(VCL_ARENA_INIT) 1203 vcl_apps(cls, "axis\tclass\tmembers\tpackages\tusize_sum\n" as *u8) 1204 c = 0 1205 while c < nrole { 1206 vcl_apps(cls, "role\t" as *u8); vcl_apps(cls, vcl_class_name(rs, VCL_AX_ROLE, c)); vcl_appc(cls, VC_TAB) 1207 vcl_appn(cls, role_members[c]); vcl_appc(cls, VC_TAB); vcl_appn(cls, role_pkgs[c]); vcl_appc(cls, VC_TAB); vcl_appn(cls, role_usize[c]); vcl_appc(cls, VC_LF) 1208 c = c + 1 1209 } 1210 c = 0 1211 while c < nfmt { 1212 vcl_apps(cls, "format\t" as *u8); vcl_apps(cls, vcl_class_name(rs, VCL_AX_FORMAT, c)); vcl_appc(cls, VC_TAB) 1213 vcl_appn(cls, fmt_members[c]); vcl_appc(cls, VC_TAB); vcl_appn(cls, fmt_pkgs[c]); vcl_appc(cls, VC_TAB); vcl_appn(cls, fmt_usize[c]); vcl_appc(cls, VC_LF) 1214 c = c + 1 1215 } 1216 let lba: *i64 = vcl_arena_new(VCL_ARENA_INIT) 1217 vcl_apps(lba, "label\tpackages\n" as *u8) 1218 vc_counter_sorted_tsv(lba, labels) 1219 let cra: *i64 = vcl_arena_new(VCL_ARENA_INIT) 1220 vcl_apps(cra, "creator\tpackages\n" as *u8) 1221 vc_counter_sorted_tsv(cra, creators) 1222 let tga: *i64 = vcl_arena_new(VCL_ARENA_INIT) 1223 vcl_apps(tga, "dependency_lowercased\tedges\n" as *u8) 1224 vc_counter_sorted_tsv(tga, targets) 1225 let rsa: *i64 = vcl_arena_new(VCL_ARENA_INIT) 1226 vcl_apps(rsa, "axis\tkey\tmembers\n" as *u8) 1227 vc_counter_tsv(rsa, resrole, "role-other" as *u8) 1228 vc_counter_tsv(rsa, resfmt, "format-other" as *u8) 1229 let wxa: *i64 = vcl_arena_new(VCL_ARENA_INIT) 1230 vcl_apps(wxa, "extension\tfiles\n" as *u8) 1231 vc_counter_tsv(wxa, exts, "" as *u8) 1232 1233 // ---- the reconciliations ---- 1234 var psum: i64 = 0 1235 c = 0 1236 while c < VC_P_N { psum = psum + pstates[c]; c = c + 1 } 1237 var msum: i64 = 0 1238 c = 0 1239 while c < VC_M_N { msum = msum + mstates[c]; c = c + 1 } 1240 var lsum: i64 = 0 1241 c = 0 1242 while c < vcl_counter_n(labels) { lsum = lsum + vcl_counter_count(labels, c); c = c + 1 } 1243 var ok_pk: i64 = 1 1244 if psum != npk { ok_pk = 0 } 1245 if npk != ws[VC_W_VARS] { ok_pk = 0 } 1246 var ok_role: i64 = 0 1247 if t_role_sum == t_members { ok_role = 1 } 1248 var ok_fmt: i64 = 0 1249 if t_fmt_sum == t_members { ok_fmt = 1 } 1250 var ok_meta: i64 = 0 1251 if msum == pstates[VC_P_OK] { ok_meta = 1 } 1252 var ok_lab: i64 = 0 1253 if lsum == pstates[VC_P_OK] { ok_lab = 1 } 1254 1255 vcl_apps(sm, "VARCENSUS-WALK" as *u8) 1256 vc_kv(sm, "dirs" as *u8, ws[VC_W_DIRS]) 1257 vc_kv(sm, "dirs_unreadable" as *u8, ws[VC_W_DIRS_UNREADABLE]) 1258 vc_kv(sm, "var_files" as *u8, ws[VC_W_VARS]) 1259 vc_kv(sm, "var_top_level" as *u8, ws[VC_W_VARS_TOP]) 1260 vc_kv(sm, "var_nested" as *u8, ws[VC_W_VARS] - ws[VC_W_VARS_TOP]) 1261 vc_kv(sm, "other_files" as *u8, ws[VC_W_OTHER_FILES]) 1262 vc_kv(sm, "symlinks" as *u8, ws[VC_W_SYMLINKS]) 1263 vc_kv(sm, "other_types" as *u8, ws[VC_W_OTHER_TYPES]) 1264 vc_kv(sm, "paths_too_long" as *u8, ws[VC_W_TOO_LONG]) 1265 vcl_appc(sm, VC_LF) 1266 vcl_apps(sm, "VARCENSUS-PACKAGES" as *u8) 1267 vc_kv(sm, "walked" as *u8, npk) 1268 c = 0 1269 while c < VC_P_N { 1270 vcl_appc(sm, 32) 1271 vcl_apps(sm, vc_pstate_name(c)) 1272 vcl_appc(sm, VC_EQ) 1273 vcl_appn(sm, pstates[c]) 1274 c = c + 1 1275 } 1276 vc_kv(sm, "sum" as *u8, psum) 1277 vc_kv(sm, "reconciles" as *u8, ok_pk) 1278 vcl_appc(sm, VC_LF) 1279 vcl_apps(sm, "VARCENSUS-MEMBERS" as *u8) 1280 vc_kv(sm, "members" as *u8, t_members) 1281 vc_kv(sm, "dir_entries" as *u8, t_dirs) 1282 vc_kv(sm, "file_members" as *u8, t_members - t_dirs) 1283 vc_kv(sm, "z64_extra_members" as *u8, t_z64) 1284 vc_kv(sm, "z64_unresolved" as *u8, t_z64u) 1285 vc_kv(sm, "packages_with_z64_extra" as *u8, t_pkgs_z64) 1286 vc_kv(sm, "utf8_named_members" as *u8, t_utf8) 1287 vc_kv(sm, "usize_sum" as *u8, t_usize) 1288 vcl_appc(sm, VC_LF) 1289 vcl_apps(sm, "VARCENSUS-ROLE" as *u8) 1290 vc_kv(sm, "classes" as *u8, nrole) 1291 vc_kv(sm, "sum" as *u8, t_role_sum) 1292 vc_kv(sm, "other" as *u8, role_members[other_role]) 1293 vc_kv(sm, "reconciles" as *u8, ok_role) 1294 vcl_appc(sm, VC_LF) 1295 vcl_apps(sm, "VARCENSUS-FORMAT" as *u8) 1296 vc_kv(sm, "classes" as *u8, nfmt) 1297 vc_kv(sm, "sum" as *u8, t_fmt_sum) 1298 vc_kv(sm, "other" as *u8, fmt_members[other_fmt]) 1299 vc_kv(sm, "reconciles" as *u8, ok_fmt) 1300 vcl_appc(sm, VC_LF) 1301 vcl_apps(sm, "VARCENSUS-META" as *u8) 1302 vc_kv(sm, "parsed" as *u8, mstates[VC_M_PARSED]) 1303 vc_kv(sm, "absent" as *u8, mstates[VC_M_ABSENT]) 1304 vc_kv(sm, "unreadable" as *u8, mstates[VC_M_UNREADABLE]) 1305 vc_kv(sm, "unparsed" as *u8, mstates[VC_M_UNPARSED]) 1306 vc_kv(sm, "sum" as *u8, msum) 1307 vc_kv(sm, "reconciles" as *u8, ok_meta) 1308 vcl_appc(sm, VC_LF) 1309 vcl_apps(sm, "VARCENSUS-LICENSE" as *u8) 1310 vc_kv(sm, "distinct_labels" as *u8, vcl_counter_n(labels)) 1311 vc_kv(sm, "label_rows_sum" as *u8, lsum) 1312 vc_kv(sm, "reconciles" as *u8, ok_lab) 1313 vc_kv(sm, "legacy_agree" as *u8, lagree[VC_L_AGREE]) 1314 vc_kv(sm, "legacy_disagree" as *u8, lagree[VC_L_DISAGREE]) 1315 vc_kv(sm, "legacy_only" as *u8, lagree[VC_L_LEGACY_ONLY]) 1316 vc_kv(sm, "direct_only" as *u8, lagree[VC_L_DIRECT_ONLY]) 1317 vc_kv(sm, "neither" as *u8, lagree[VC_L_NEITHER]) 1318 vcl_appc(sm, VC_LF) 1319 vcl_apps(sm, "VARCENSUS-DEPS" as *u8) 1320 vc_kv(sm, "edges" as *u8, t_edges) 1321 vc_kv(sm, "distinct_targets" as *u8, vcl_counter_n(targets)) 1322 vc_kv(sm, "packages_with_deps" as *u8, t_pkgs_deps) 1323 vc_kv(sm, "malformed_dependency_objects" as *u8, t_deps_malformed) 1324 c = 0 1325 while c < ntags { 1326 vcl_appc(sm, 32); vcl_apps(sm, vcl_counter_key(tags, c)); vcl_apps(sm, "_packages=" as *u8); vcl_appn(sm, tag_pkgs[c]) 1327 vcl_appc(sm, 32); vcl_apps(sm, vcl_counter_key(tags, c)); vcl_apps(sm, "_edges=" as *u8); vcl_appn(sm, tag_edges[c]) 1328 c = c + 1 1329 } 1330 vcl_appc(sm, VC_LF) 1331 vcl_apps(sm, "VARCENSUS-CREATORS" as *u8) 1332 vc_kv(sm, "distinct" as *u8, vcl_counter_n(creators)) 1333 vcl_appc(sm, VC_LF) 1334 vcl_apps(sm, "VARCENSUS-SCREEN" as *u8) 1335 vc_kv(sm, "flagged" as *u8, t_flagged) 1336 c = 0 1337 while c < VC_NLETTERS { 1338 if reason_pkgs[c] > 0 { vcl_appc(sm, 32); vcl_appc(sm, VC_ASCII_UPPER_A + c); vcl_appc(sm, VC_EQ); vcl_appn(sm, reason_pkgs[c]) } 1339 c = c + 1 1340 } 1341 vcl_appc(sm, VC_LF) 1342 1343 let tot: *i64 = sys_mmap(16) as *i64 1344 tot[0] = 0 1345 var wfail: i64 = 0 1346 if vc_write_out(outdir, "packages.tsv" as *u8, pk, tot) < 0 { wfail = wfail + 1 } 1347 if vc_write_out(outdir, "deps.tsv" as *u8, dpa, tot) < 0 { wfail = wfail + 1 } 1348 if vc_write_out(outdir, "rpscreen.tsv" as *u8, rpa, tot) < 0 { wfail = wfail + 1 } 1349 if vc_write_out(outdir, "unreadable.tsv" as *u8, ur, tot) < 0 { wfail = wfail + 1 } 1350 if vc_write_out(outdir, "classes.tsv" as *u8, cls, tot) < 0 { wfail = wfail + 1 } 1351 if vc_write_out(outdir, "labels.tsv" as *u8, lba, tot) < 0 { wfail = wfail + 1 } 1352 if vc_write_out(outdir, "creators.tsv" as *u8, cra, tot) < 0 { wfail = wfail + 1 } 1353 if vc_write_out(outdir, "dep_targets.tsv" as *u8, tga, tot) < 0 { wfail = wfail + 1 } 1354 if vc_write_out(outdir, "residual.tsv" as *u8, rsa, tot) < 0 { wfail = wfail + 1 } 1355 if vc_write_out(outdir, "walk_extensions.tsv" as *u8, wxa, tot) < 0 { wfail = wfail + 1 } 1356 vcl_apps(sm, "VARCENSUS-OUT" as *u8) 1357 vc_kv(sm, "files" as *u8, 11) 1358 vc_kv(sm, "write_failures" as *u8, wfail) 1359 vc_kv(sm, "tsv_bytes" as *u8, tot[0]) 1360 vcl_appc(sm, VC_LF) 1361 var verdict_ok: i64 = 1 1362 if ok_pk == 0 { verdict_ok = 0 } 1363 if ok_role == 0 { verdict_ok = 0 } 1364 if ok_fmt == 0 { verdict_ok = 0 } 1365 if ok_meta == 0 { verdict_ok = 0 } 1366 if ok_lab == 0 { verdict_ok = 0 } 1367 if wfail > 0 { verdict_ok = 0 } 1368 if verdict_ok == 1 { vcl_apps(sm, "VARCENSUS verdict=RECONCILED\n" as *u8) } else { vcl_apps(sm, "VARCENSUS verdict=MISMATCH\n" as *u8) } 1369 vc_write_out(outdir, "summary.txt" as *u8, sm, tot) 1370 vc_wn(VC_FD_OUT, vcl_at(sm, 0), vcl_used(sm)) 1371 if verdict_ok == 1 { return VC_EXIT_OK } 1372 return VC_EXIT_MISMATCH 1373} 1374 1375// Reports source declarations, never claims runtime simulation from a preset flag. 1376func vc_member_measure(path: *u8, selected: *u8, maxbytes: i64) -> i64 { 1377 if maxbytes <= 0 { return VC_EXIT_USAGE } 1378 let fd: i64 = sys_openat_rd(path) 1379 if fd < 0 { vc_w(VC_FD_OUT, "VARCENSUS-MEMBER state=UNOPENABLE\n" as *u8); return VC_EXIT_IO } 1380 let size: i64 = sys_lseek(fd, 0, VC_SEEK_END) 1381 let box: *i64 = sys_mmap(VF_L_N * 8) as *i64 1382 let st: *i64 = sys_mmap(VC_ST_N * 8) as *i64 1383 let win: *u8 = vc_window(fd, size, box, st) 1384 if st[VC_ST_LOC] != VF_LOC_OK { sys_close(fd); vc_w(VC_FD_OUT, "VARCENSUS-MEMBER state=ARCHIVE-REFUSED\n" as *u8); return VC_EXIT_REFUSED } 1385 let mb: *i64 = sys_mmap(VC_MB_N * 8) as *i64 1386 let data: *u8 = vc_member_read(fd, size, win, st[VC_ST_WIN], box, selected, maxbytes, mb) 1387 sys_close(fd) 1388 let out: *i64 = vcl_arena_new(VCL_ARENA_INIT) 1389 vcl_apps(out, "VARCENSUS-MEMBER coverage=one-selected-member asset_payload_emitted=0 runtime_simulation=unknown\nmember=" as *u8) 1390 vcl_appclean(out, selected, 0, vc_slen(selected)) 1391 vcl_appc(out, VC_LF) 1392 vc_kv(out, "found" as *u8, mb[VC_MB_FOUND]) 1393 vc_kv(out, "state" as *u8, mb[VC_MB_STATE]) 1394 vcl_apps(out, " state_name=" as *u8) 1395 vcl_apps(out, vc_md_name(mb[VC_MB_STATE])) 1396 vc_kv(out, "method" as *u8, mb[VC_MB_METHOD]) 1397 vc_kv(out, "compressed_bytes" as *u8, mb[VC_MB_CSIZE]) 1398 vc_kv(out, "declared_bytes" as *u8, mb[VC_MB_USIZE]) 1399 vc_kv(out, "decoded_bytes" as *u8, mb[VC_MB_LEN]) 1400 vc_kv(out, "crc_expected" as *u8, mb[VC_MB_CRC_EXPECTED]) 1401 vc_kv(out, "crc_actual" as *u8, mb[VC_MB_CRC_ACTUAL]) 1402 vc_kv(out, "maxbytes" as *u8, maxbytes) 1403 vcl_appc(out, VC_LF) 1404 var inspected: i64 = 0 1405 var enabled: i64 = 0 1406 var disabled: i64 = 0 1407 var invalid: i64 = 0 1408 var missing: i64 = 0 1409 var schema: i64 = 0 1410 if (data as i64) != 0 { 1411 let n: i64 = mb[VC_MB_LEN] 1412 let jb: *i64 = sys_mmap(VF_JM_N * 8) as *i64 1413 let top: i64 = vf_json_skip(data, n, 0) 1414 if vf_json_kind(data, n, top) == VF_JK_OBJECT { 1415 let a: i64 = vf_json_find(data, n, top, "storables" as *u8, jb) 1416 if vf_json_kind(data, n, a) == VF_JK_ARRAY { 1417 let end: i64 = jb[VF_JM_VE] 1418 var p: i64 = vf_json_skip(data, n, a + 1) 1419 schema = 1 1420 while p < end - 1 { 1421 let ve: i64 = vf_json_value_end(data, n, p) 1422 if ve <= p { schema = 0; p = end } else { 1423 inspected = inspected + 1 1424 let flag: i64 = vf_json_find(data, n, p, "simEnabled" as *u8, jb) 1425 if flag < 0 { missing = missing + 1 } else { 1426 var fs: i64 = flag 1427 var fe: i64 = jb[VF_JM_VE] 1428 if vf_json_kind(data, n, flag) == VF_JK_STRING { fs = fs + 1; fe = fe - 1 } 1429 if vf_span_is(data, fs, fe, "true" as *u8) == 1 { enabled = enabled + 1 } else { 1430 if vf_span_is(data, fs, fe, "false" as *u8) == 1 { disabled = disabled + 1 } else { invalid = invalid + 1 } 1431 } 1432 } 1433 p = vf_json_skip(data, n, ve) 1434 if p < end - 1 { if (data[p] as i64) == VC_ROW_SEP { p = vf_json_skip(data, n, p + 1) } else { schema = 0; p = end } } 1435 } 1436 } 1437 } 1438 } 1439 } 1440 vc_kv(out, "storables_schema" as *u8, schema) 1441 vc_kv(out, "storables_inspected" as *u8, inspected) 1442 vc_kv(out, "sim_declared_true" as *u8, enabled) 1443 vc_kv(out, "sim_declared_false" as *u8, disabled) 1444 vc_kv(out, "sim_flag_invalid" as *u8, invalid) 1445 vc_kv(out, "storables_without_sim_flag" as *u8, missing) 1446 vcl_appc(out, VC_LF) 1447 vc_wn(VC_FD_OUT, vcl_at(out, 0), vcl_used(out)) 1448 if (data as i64) == 0 { return VC_EXIT_REFUSED } 1449 return VC_EXIT_OK 1450} 1451func vc_positive_limit(s: *u8) -> i64 { 1452 var n: i64 = 0 1453 var i: i64 = 0 1454 while s[i] != (0 as u8) { 1455 let d: i64 = s[i] as i64 - VC_ASCII_0 1456 if d < 0 { return 0 } 1457 if d >= VC_DEC { return 0 } 1458 if n > (0x7fffffffffffffff - d) / VC_DEC { return 0 } 1459 n = n * VC_DEC + d 1460 i = i + 1 1461 } 1462 return n 1463} 1464 1465func main(argc: i64, argv: *i64) -> i64 { 1466 if argc < 3 { 1467 vc_w(VC_FD_ERR, "usage: nx_varcensus names <file.var> | meta <file.var> | census <dir> <outdir> <rules.conf> | member <file.var> <name> <maxbytes>\n" as *u8) 1468 vc_w(VC_FD_ERR, " legacy verbs inspect manifest/meta.json; member reports bounded measurements only.\n" as *u8) 1469 sys_exit(VC_EXIT_USAGE) 1470 return VC_EXIT_USAGE 1471 } 1472 if vc_streq(argv[1] as *u8, "member" as *u8) == 1 { 1473 if argc != 5 { return VC_EXIT_USAGE } 1474 return vc_member_measure(argv[2] as *u8, argv[3] as *u8, vc_positive_limit(argv[4] as *u8)) 1475 } 1476 let verb: *u8 = argv[1] as *u8 1477 let arg: *u8 = argv[2] as *u8 1478 var rc: i64 = VC_EXIT_USAGE 1479 if vc_streq(verb, "names" as *u8) == 1 { rc = vc_names(arg) } else { 1480 if vc_streq(verb, "meta" as *u8) == 1 { rc = vc_meta(arg) } else { 1481 if vc_streq(verb, "census" as *u8) == 1 { 1482 if argc < 5 { vc_w(VC_FD_ERR, "census needs <dir> <outdir> <rules.conf>\n" as *u8) } else { rc = vc_census(arg, argv[3] as *u8, argv[4] as *u8) } 1483 } else { vc_w(VC_FD_ERR, "nx_varcensus: unknown verb\n" as *u8) } 1484 } 1485 } 1486 sys_exit(rc) 1487 return rc 1488}