code wiki / (root) / nx_pushback_lib.nx

nx_pushback_lib.nx source

↩ module page · 408 lines · 19890 B

1// nx_pushback_lib.nx -- COMMUNITY PUSH-BACK WITH LICENCE, PROVENANCE AND THE REFEREE GRADE ATTACHED (/compare/modding MD23 2// pushback_publish, 2026-09-06). Our own models go back to the communities as ONE bundle per community target: the sovereign 3// mod manifest (nx_mod_manifest_lib, MD18) copied byte-for-byte, the package archived by the estate's own 7z writer 4// (nx_sevenz_lib sz_write_copy, MD29), the content id, magnet, download url and index row from the ONE transport addresser 5// (nx_dist_publish), and a publish row carrying the licence row, the member count, the manifest and archive digests and the 6// referee grade. Every door this lib composes is fail-closed and it adds no second ruler: the manifest must VERIFY against 7// the files as they are (mm_verify), the package licence is re-read from the ONE rights table (a hand-edited id is refused 8// LICENCE-UNKNOWN), every journaled member is re-asked from the ONE asset journal at publish time (a rip whose licence class 9// is unknown is refused PROVENANCE by name -- the rung's own words), the community's redistribution floor is applied to the 10// package and to every journaled member, and an UNGRADED package never publishes (the operator's law: presence is not 11// completion; a push-back without a referee grade is a poorly-done cut shipped to strangers). The community targets are DATA 12// (knowledge/modding_communities.conf); the same manifest bytes land in every bundle, which is the invariant the gate proves. 13// license_tier: ORIGINAL No hw writes (Rule 26). 14import "nx_syscalls.nx" 15import "nx_mod_manifest_lib.nx" 16import "nx_sevenz_lib.nx" 17import "nx_dist_publish.nx" 18 19const PB_CONF_DEFAULT: *u8 = "knowledge/modding_communities.conf" 20const PB_GRADE_DEFAULT_NAME: *u8 = "referee.grade" 21const PB_OUTDIR_DEFAULT_NAME: *u8 = "pushback" 22const PB_TAG: *u8 = "community" 23const PB_GRADE_TAG: *u8 = "grade" 24const PB_KIND_DIST_S: *u8 = "dist" 25const PB_KIND_APIDESC_S: *u8 = "api-desc" 26const PB_MANIFEST_EXT: *u8 = ".nxmod" 27const PB_ARCHIVE_EXT: *u8 = ".7z" 28const PB_INDEX_FILE: *u8 = "index.row" 29const PB_ROW_FILE: *u8 = "publish.row" 30const PB_TRANSPORT_DIST: *u8 = "dist-index" 31const PB_TRANSPORT_DESC: *u8 = "descriptor-awaiting-keyed-door" 32const PB_DASH_S: *u8 = "-" 33const PB_SEP: i64 = 124 34const PB_NL: i64 = 10 35const PB_HASH: i64 = 35 36const PB_DASH: i64 = 45 37const PB_SLASH: i64 = 47 38const PB_DIR_MODE: i64 = 493 39const PB_FILE_MODE: i64 = 420 40const PB_PATH_CAP: i64 = 1024 41const PB_ROW_CAP: i64 = 8192 42const PB_ARCHIVE_SLACK: i64 = 4096 43const PB_PER_MEMBER_SLACK: i64 = 512 44const PB_PERMIL_MAX: i64 = 1000 45const PB_MAX_COMMUNITIES: i64 = 64 46const PB_MAX_IDS: i64 = 64 47// community table slots (one row = PB_C_SLOTS i64s) 48const PB_C_ID: i64 = 0 49const PB_C_KIND: i64 = 1 50const PB_C_ENDPOINT: i64 = 2 51const PB_C_MINREDIST: i64 = 3 52const PB_C_NOTE: i64 = 4 53const PB_C_SLOTS: i64 = 6 54const PB_KIND_UNKNOWN: i64 = 0 55const PB_KIND_DIST: i64 = 1 56const PB_KIND_APIDESC: i64 = 2 57// results, every one NAMED by pb_err_name 58const PB_OK: i64 = 0 59const PB_ERR_CONF_UNREADABLE: i64 = 0 - 1 60const PB_ERR_NO_SUCH_COMMUNITY: i64 = 0 - 2 61const PB_ERR_MANIFEST_UNREADABLE: i64 = 0 - 3 62const PB_ERR_MANIFEST_REFUSED: i64 = 0 - 4 63const PB_ERR_LICENCE_UNKNOWN: i64 = 0 - 5 64const PB_ERR_NON_REDISTRIBUTABLE: i64 = 0 - 6 65const PB_ERR_PROVENANCE: i64 = 0 - 7 66const PB_ERR_UNGRADED: i64 = 0 - 8 67const PB_ERR_OUT_UNWRITABLE: i64 = 0 - 9 68const PB_ERR_ARCHIVE: i64 = 0 - 10 69const PB_ERR_MEMBER_UNREADABLE: i64 = 0 - 11 70const PB_ERR_TABLE_UNREADABLE: i64 = 0 - 12 71const PB_ERR_KIND_UNKNOWN: i64 = 0 - 13 72// per-community result slots 73const PB_R_RC: i64 = 0 74const PB_R_KIND: i64 = 1 75const PB_R_ARCHIVE_BYTES: i64 = 2 76const PB_R_CID: i64 = 3 // *u8 65 77const PB_R_MANIFEST_SHA: i64 = 4 // *u8 65, hashed from the WRITTEN copy 78const PB_R_OUTDIR: i64 = 5 // *u8 the bundle directory 79const PB_R_MEMBER_IDX: i64 = 6 // the member that refused, or -1 80const PB_R_REASON: i64 = 7 // the pv reason, the mm verdict, or the redist level that fell below the floor 81const PB_R_N: i64 = 8 82// referee grade slots 83const PB_G_PERMIL: i64 = 0 84const PB_G_JUDGE: i64 = 1 85const PB_G_DATE: i64 = 2 86const PB_G_N: i64 = 4 87// request summary slots 88const PB_S_REQUESTED: i64 = 0 89const PB_S_PUBLISHED: i64 = 1 90const PB_S_REFUSED: i64 = 2 91const PB_S_IDENTICAL: i64 = 3 92const PB_S_RC: i64 = 4 93const PB_S_CONF_ROWS: i64 = 5 94const PB_S_MEMBERS: i64 = 6 95const PB_S_PERMIL: i64 = 7 96const PB_S_N: i64 = 8 97 98func pb_write_file(path: *u8, b: *u8, n: i64) -> i64 { 99 let fd: i64 = sys_openat_wr(path, PB_FILE_MODE) 100 if fd < 0 { return 0 - 1 } 101 var done: i64 = 0 102 while done < n { let k: i64 = sys_write(fd, b + done, n - done); if k <= 0 { break } done = done + k } 103 sys_close(fd) 104 return done 105} 106func pb_sep(row: *u8, o: i64) -> i64 { row[o] = PB_SEP as u8; return o + 1 } 107func pb_kind_code(s: *u8) -> i64 { 108 if mm_streq(s, PB_KIND_DIST_S) == 1 { return PB_KIND_DIST } 109 if mm_streq(s, PB_KIND_APIDESC_S) == 1 { return PB_KIND_APIDESC } 110 return PB_KIND_UNKNOWN 111} 112func pb_kind_name(k: i64) -> *u8 { 113 if k == PB_KIND_DIST { return PB_KIND_DIST_S } 114 if k == PB_KIND_APIDESC { return PB_KIND_APIDESC_S } 115 return "unknown" as *u8 116} 117func pb_transport_name(k: i64) -> *u8 { 118 if k == PB_KIND_DIST { return PB_TRANSPORT_DIST } 119 return PB_TRANSPORT_DESC 120} 121func pb_err_name(rc: i64) -> *u8 { 122 if rc == PB_OK { return "OK" as *u8 } 123 if rc == PB_ERR_CONF_UNREADABLE { return "CONF-UNREADABLE" as *u8 } 124 if rc == PB_ERR_NO_SUCH_COMMUNITY { return "NO-SUCH-COMMUNITY" as *u8 } 125 if rc == PB_ERR_MANIFEST_UNREADABLE { return "MANIFEST-UNREADABLE" as *u8 } 126 if rc == PB_ERR_MANIFEST_REFUSED { return "MANIFEST-REFUSED" as *u8 } 127 if rc == PB_ERR_LICENCE_UNKNOWN { return "LICENCE-UNKNOWN" as *u8 } 128 if rc == PB_ERR_NON_REDISTRIBUTABLE { return "NON-REDISTRIBUTABLE" as *u8 } 129 if rc == PB_ERR_PROVENANCE { return "PROVENANCE" as *u8 } 130 if rc == PB_ERR_UNGRADED { return "UNGRADED" as *u8 } 131 if rc == PB_ERR_OUT_UNWRITABLE { return "OUT-UNWRITABLE" as *u8 } 132 if rc == PB_ERR_ARCHIVE { return "ARCHIVE" as *u8 } 133 if rc == PB_ERR_MEMBER_UNREADABLE { return "MEMBER-UNREADABLE" as *u8 } 134 if rc == PB_ERR_TABLE_UNREADABLE { return "RIGHTS-TABLE-UNREADABLE" as *u8 } 135 if rc == PB_ERR_KIND_UNKNOWN { return "KIND-UNKNOWN" as *u8 } 136 return "UNKNOWN-RC" as *u8 137} 138// ---- the community table: community|id|kind|endpoint|minredist|note ---- 139func pb_conf_load(path: *u8, tbl: *i64, cap: i64) -> i64 { 140 let lp: *i64 = sys_mmap(16) as *i64 141 let b: *u8 = sys_read_file(path, lp) 142 if (b as i64) == 0 { return PB_ERR_CONF_UNREADABLE } 143 let n: i64 = lp[0] 144 let offs: *i64 = sys_mmap(8 * MM_MAX_FIELDS) as *i64 145 let lens: *i64 = sys_mmap(8 * MM_MAX_FIELDS) as *i64 146 var rows: i64 = 0 147 var p: i64 = 0 148 while p < n { 149 var e: i64 = p 150 while e < n { if (b[e] as i64) == PB_NL { break } e = e + 1 } 151 if e > p { if (b[p] as i64) != PB_HASH { 152 let nf: i64 = mm_fields(b, p, e, offs, lens) 153 if nf >= 5 { if mm_is(b, offs[0], lens[0], PB_TAG) == 1 { if rows < cap { 154 let base: i64 = rows * PB_C_SLOTS 155 tbl[base + PB_C_ID] = (mm_dup(b + offs[1], lens[1])) as i64 156 tbl[base + PB_C_KIND] = (mm_dup(b + offs[2], lens[2])) as i64 157 tbl[base + PB_C_ENDPOINT] = (mm_dup(b + offs[3], lens[3])) as i64 158 tbl[base + PB_C_MINREDIST] = mm_atoi(b + offs[4], lens[4]) 159 var note: i64 = PB_DASH_S as i64 160 if nf >= 6 { note = (mm_dup(b + offs[5], lens[5])) as i64 } 161 tbl[base + PB_C_NOTE] = note 162 rows = rows + 1 163 } } } 164 } } 165 p = e + 1 166 } 167 return rows 168} 169func pb_find(tbl: *i64, n: i64, id: *u8) -> i64 { 170 var i: i64 = 0 171 while i < n { if mm_streq(tbl[i * PB_C_SLOTS + PB_C_ID] as *u8, id) == 1 { return i } i = i + 1 } 172 return 0 - 1 173} 174// ---- the referee grade: a file whose first grade row reads grade|<permil>|<judge>|<date> ---- 175func pb_grade_read(path: *u8, g: *i64) -> i64 { 176 g[PB_G_PERMIL] = 0 - 1 177 g[PB_G_JUDGE] = PB_DASH_S as i64 178 g[PB_G_DATE] = PB_DASH_S as i64 179 if (path as i64) == 0 { return PB_ERR_UNGRADED } 180 if path[0] == (0 as u8) { return PB_ERR_UNGRADED } 181 let lp: *i64 = sys_mmap(16) as *i64 182 let b: *u8 = sys_read_file(path, lp) 183 if (b as i64) == 0 { return PB_ERR_UNGRADED } 184 let n: i64 = lp[0] 185 let offs: *i64 = sys_mmap(8 * MM_MAX_FIELDS) as *i64 186 let lens: *i64 = sys_mmap(8 * MM_MAX_FIELDS) as *i64 187 var p: i64 = 0 188 while p < n { 189 var e: i64 = p 190 while e < n { if (b[e] as i64) == PB_NL { break } e = e + 1 } 191 if e > p { if (b[p] as i64) != PB_HASH { 192 let nf: i64 = mm_fields(b, p, e, offs, lens) 193 if nf >= 4 { if mm_is(b, offs[0], lens[0], PB_GRADE_TAG) == 1 { 194 let permil: i64 = mm_atoi(b + offs[1], lens[1]) 195 if permil < 0 { return PB_ERR_UNGRADED } 196 if permil > PB_PERMIL_MAX { return PB_ERR_UNGRADED } 197 g[PB_G_PERMIL] = permil 198 g[PB_G_JUDGE] = (mm_dup(b + offs[2], lens[2])) as i64 199 g[PB_G_DATE] = (mm_dup(b + offs[3], lens[3])) as i64 200 return PB_OK 201 } } 202 } } 203 p = e + 1 204 } 205 return PB_ERR_UNGRADED 206} 207// ---- ONE community: verify, licence floor, provenance floor, then the bundle ---- 208func pb_publish_one(root: *u8, mb: *u8, mn: i64, m: *i64, crow: *i64, outdir: *u8, g: *i64, jrnl: *u8, r: *i64) -> i64 { 209 var q: i64 = 0 210 while q < PB_R_N { r[q] = 0; q = q + 1 } 211 r[PB_R_MEMBER_IDX] = 0 - 1 212 r[PB_R_KIND] = pb_kind_code(crow[PB_C_KIND] as *u8) 213 r[PB_R_CID] = (sys_mmap(MM_SHA_HEX + 1)) as i64 214 r[PB_R_MANIFEST_SHA] = (sys_mmap(MM_SHA_HEX + 1)) as i64 215 r[PB_R_OUTDIR] = (sys_mmap(PB_PATH_CAP)) as i64 216 if r[PB_R_KIND] == PB_KIND_UNKNOWN { r[PB_R_RC] = PB_ERR_KIND_UNKNOWN; return PB_ERR_KIND_UNKNOWN } 217 if g[PB_G_PERMIL] < 0 { r[PB_R_RC] = PB_ERR_UNGRADED; return PB_ERR_UNGRADED } 218 // 1. the manifest must verify against the files as they ARE (tampered, missing and forged refuse here) 219 let rv: *i64 = sys_mmap(8 * MM_R_N) as *i64 220 let v: i64 = mm_verify(m, root, rv) 221 if v != MM_V_ACCEPT { r[PB_R_REASON] = v; r[PB_R_RC] = PB_ERR_MANIFEST_REFUSED; return PB_ERR_MANIFEST_REFUSED } 222 // 2. the package licence, re-read from the ONE rights table, against the community's floor 223 let lic: *u8 = m[MM_M_LIC] as *u8 224 let ctx: *i64 = lg_ctx() 225 if ctx[3] < 0 { r[PB_R_RC] = PB_ERR_TABLE_UNREADABLE; return PB_ERR_TABLE_UNREADABLE } 226 let li: i64 = lg_find_license(ctx, lic) 227 if li < 0 { r[PB_R_RC] = PB_ERR_LICENCE_UNKNOWN; return PB_ERR_LICENCE_UNKNOWN } 228 var redist: i64 = lg_lic_redist(ctx, li) 229 if lg_lic_verified(ctx, li) == LG_UNVERIFIED { if redist > LG_COND { redist = LG_COND } } 230 let minr: i64 = crow[PB_C_MINREDIST] 231 r[PB_R_REASON] = redist 232 if redist < minr { r[PB_R_RC] = PB_ERR_NON_REDISTRIBUTABLE; return PB_ERR_NON_REDISTRIBUTABLE } 233 // 3. every member's provenance, LIVE from the journal at publish time (the manifest's prov rows are a snapshot) 234 let nc: i64 = m[MM_M_NCONTENT] 235 let shas: *i64 = m[MM_M_SHAS] as *i64 236 let paths: *i64 = m[MM_M_PATHS] as *i64 237 let res: *i64 = sys_mmap(8 * PV_RES_N) as *i64 238 var i: i64 = 0 239 while i < nc { 240 pv_verdict(jrnl, shas[i] as *u8, res) 241 let reason: i64 = res[PV_RES_REASON] 242 var bad: i64 = 0 243 if reason == PV_R_UNKNOWN_LIC { bad = 1 } 244 if reason == PV_R_NON_REDIST { bad = 1 } 245 if reason == PV_R_TABLE_UNREADABLE { bad = 1 } 246 if bad == 1 { r[PB_R_MEMBER_IDX] = i; r[PB_R_REASON] = reason; r[PB_R_RC] = PB_ERR_PROVENANCE; return PB_ERR_PROVENANCE } 247 var journaled: i64 = 1 248 if reason == PV_R_NO_ROW { journaled = 0 } 249 if reason == PV_R_NO_JOURNAL { journaled = 0 } 250 if journaled == 1 { if res[PV_RES_REDIST] < minr { 251 r[PB_R_MEMBER_IDX] = i; r[PB_R_REASON] = res[PV_RES_REDIST]; r[PB_R_RC] = PB_ERR_NON_REDISTRIBUTABLE; return PB_ERR_NON_REDISTRIBUTABLE 252 } } 253 i = i + 1 254 } 255 // 4. the bundle directory and the byte-identical manifest copy 256 sys_mkdir(outdir, PB_DIR_MODE) 257 let cdir: *u8 = r[PB_R_OUTDIR] as *u8 258 mm_join_path(outdir, crow[PB_C_ID] as *u8, cdir) 259 sys_mkdir(cdir, PB_DIR_MODE) 260 let stem: *u8 = sys_mmap(PB_PATH_CAP) 261 var so: i64 = mm_cat(stem, 0, m[MM_M_NAME] as *u8) 262 stem[so] = PB_DASH as u8 263 so = so + 1 264 so = mm_cat(stem, so, m[MM_M_VERSION] as *u8) 265 stem[so] = 0 as u8 266 let mname: *u8 = sys_mmap(PB_PATH_CAP) 267 var mo: i64 = mm_cat(mname, 0, stem) 268 mo = mm_cat(mname, mo, PB_MANIFEST_EXT) 269 mname[mo] = 0 as u8 270 let aname: *u8 = sys_mmap(PB_PATH_CAP) 271 var ao: i64 = mm_cat(aname, 0, stem) 272 ao = mm_cat(aname, ao, PB_ARCHIVE_EXT) 273 aname[ao] = 0 as u8 274 let mcopy: *u8 = sys_mmap(PB_PATH_CAP) 275 mm_join_path(cdir, mname, mcopy) 276 if pb_write_file(mcopy, mb, mn) != mn { r[PB_R_RC] = PB_ERR_OUT_UNWRITABLE; return PB_ERR_OUT_UNWRITABLE } 277 if pv_hash_file(mcopy, r[PB_R_MANIFEST_SHA] as *u8) != mn { r[PB_R_RC] = PB_ERR_OUT_UNWRITABLE; return PB_ERR_OUT_UNWRITABLE } 278 // 5. the archive: the manifest first, then every member, through the estate's own 7z writer 279 let nf: i64 = nc + 1 280 let names: *i64 = sys_mmap(8 * (nf + 1)) as *i64 281 let datas: *i64 = sys_mmap(8 * (nf + 1)) as *i64 282 let lens: *i64 = sys_mmap(8 * (nf + 1)) as *i64 283 names[0] = mname as i64 284 datas[0] = mb as i64 285 lens[0] = mn 286 var total: i64 = mn 287 i = 0 288 while i < nc { 289 let full: *u8 = sys_mmap(PB_PATH_CAP * 2) 290 mm_join_path(root, paths[i] as *u8, full) 291 let lp: *i64 = sys_mmap(16) as *i64 292 let d: *u8 = sys_read_file(full, lp) 293 if (d as i64) == 0 { r[PB_R_MEMBER_IDX] = i; r[PB_R_RC] = PB_ERR_MEMBER_UNREADABLE; return PB_ERR_MEMBER_UNREADABLE } 294 names[i + 1] = paths[i] 295 datas[i + 1] = d as i64 296 lens[i + 1] = lp[0] 297 total = total + lp[0] 298 i = i + 1 299 } 300 let acap: i64 = total + PB_ARCHIVE_SLACK + nf * (PB_PER_MEMBER_SLACK + PB_PATH_CAP) 301 let arch: *u8 = sys_mmap(acap) 302 let an: i64 = sz_write_copy(names, datas, lens, nf, arch, acap) 303 if an <= 0 { r[PB_R_REASON] = an; r[PB_R_RC] = PB_ERR_ARCHIVE; return PB_ERR_ARCHIVE } 304 let apath: *u8 = sys_mmap(PB_PATH_CAP) 305 mm_join_path(cdir, aname, apath) 306 if pb_write_file(apath, arch, an) != an { r[PB_R_RC] = PB_ERR_OUT_UNWRITABLE; return PB_ERR_OUT_UNWRITABLE } 307 r[PB_R_ARCHIVE_BYTES] = an 308 // 6. content id, magnet, download url and the index row: the ONE transport addresser (nx_dist_publish) 309 let cid: *u8 = r[PB_R_CID] as *u8 310 let cb: i64 = dp_content_id(apath, cid) 311 if cb != an { r[PB_R_REASON] = cb; r[PB_R_RC] = PB_ERR_OUT_UNWRITABLE; return PB_ERR_OUT_UNWRITABLE } 312 let magnet: *u8 = sys_mmap(PB_ROW_CAP) 313 dp_magnet(cid, aname, magnet) 314 let url: *u8 = sys_mmap(PB_ROW_CAP) 315 dp_dl_url(cid, aname, url) 316 let row: *u8 = sys_mmap(PB_ROW_CAP) 317 var ro: i64 = dp_index_row(aname, cid, an, magnet, url, row) 318 row[ro] = PB_NL as u8 319 ro = ro + 1 320 let ipath: *u8 = sys_mmap(PB_PATH_CAP) 321 mm_join_path(cdir, PB_INDEX_FILE, ipath) 322 if pb_write_file(ipath, row, ro) != ro { r[PB_R_RC] = PB_ERR_OUT_UNWRITABLE; return PB_ERR_OUT_UNWRITABLE } 323 // 7. the publish row: what went, under which licence, with which referee grade, by which transport 324 var po: i64 = mm_cat(row, 0, "pushback|" as *u8) 325 po = mm_cat(row, po, crow[PB_C_ID] as *u8); po = pb_sep(row, po) 326 po = mm_cat(row, po, crow[PB_C_KIND] as *u8); po = pb_sep(row, po) 327 po = mm_cat(row, po, crow[PB_C_ENDPOINT] as *u8); po = pb_sep(row, po) 328 po = mm_cat(row, po, m[MM_M_NAME] as *u8); po = pb_sep(row, po) 329 po = mm_cat(row, po, m[MM_M_VERSION] as *u8); po = pb_sep(row, po) 330 po = mm_cat(row, po, lic); po = pb_sep(row, po) 331 po = mm_putd(row, po, redist); po = pb_sep(row, po) 332 po = mm_putd(row, po, nc); po = pb_sep(row, po) 333 po = mm_cat(row, po, r[PB_R_MANIFEST_SHA] as *u8); po = pb_sep(row, po) 334 po = mm_cat(row, po, cid); po = pb_sep(row, po) 335 po = mm_putd(row, po, an); po = pb_sep(row, po) 336 po = mm_putd(row, po, g[PB_G_PERMIL]); po = pb_sep(row, po) 337 po = mm_cat(row, po, g[PB_G_JUDGE] as *u8); po = pb_sep(row, po) 338 po = mm_cat(row, po, g[PB_G_DATE] as *u8); po = pb_sep(row, po) 339 po = mm_cat(row, po, pb_transport_name(r[PB_R_KIND])) 340 row[po] = PB_NL as u8 341 po = po + 1 342 let rpath: *u8 = sys_mmap(PB_PATH_CAP) 343 mm_join_path(cdir, PB_ROW_FILE, rpath) 344 if pb_write_file(rpath, row, po) != po { r[PB_R_RC] = PB_ERR_OUT_UNWRITABLE; return PB_ERR_OUT_UNWRITABLE } 345 r[PB_R_RC] = PB_OK 346 return PB_OK 347} 348// ---- the request: N communities from one manifest; rows carries PB_R_N slots per requested community ---- 349// returns the published count, or a NAMED negative rc when the request refuses before any community is tried 350func pb_publish(root: *u8, mpath: *u8, ids_csv: *u8, outdir: *u8, gradepath: *u8, confpath: *u8, jrnl: *u8, sum: *i64, rows: *i64) -> i64 { 351 var q: i64 = 0 352 while q < PB_S_N { sum[q] = 0; q = q + 1 } 353 sum[PB_S_PERMIL] = 0 - 1 354 var conf: *u8 = confpath 355 if (conf as i64) == 0 { conf = PB_CONF_DEFAULT } 356 if conf[0] == (0 as u8) { conf = PB_CONF_DEFAULT } 357 let tbl: *i64 = sys_mmap(8 * PB_C_SLOTS * PB_MAX_COMMUNITIES) as *i64 358 let nconf: i64 = pb_conf_load(conf, tbl, PB_MAX_COMMUNITIES) 359 if nconf < 0 { sum[PB_S_RC] = PB_ERR_CONF_UNREADABLE; return PB_ERR_CONF_UNREADABLE } 360 sum[PB_S_CONF_ROWS] = nconf 361 let lp: *i64 = sys_mmap(16) as *i64 362 let mb: *u8 = sys_read_file(mpath, lp) 363 if (mb as i64) == 0 { sum[PB_S_RC] = PB_ERR_MANIFEST_UNREADABLE; return PB_ERR_MANIFEST_UNREADABLE } 364 let m: *i64 = sys_mmap(8 * MM_M_N_SLOTS) as *i64 365 if mm_parse(mb, lp[0], m) != MM_OK { sum[PB_S_RC] = PB_ERR_MANIFEST_UNREADABLE; return PB_ERR_MANIFEST_UNREADABLE } 366 sum[PB_S_MEMBERS] = m[MM_M_NCONTENT] 367 let g: *i64 = sys_mmap(8 * PB_G_N) as *i64 368 pb_grade_read(gradepath, g) 369 sum[PB_S_PERMIL] = g[PB_G_PERMIL] 370 let parts: *i64 = sys_mmap(8 * PB_MAX_IDS) as *i64 371 let k: i64 = mm_split_csv(ids_csv, parts, PB_MAX_IDS) 372 sum[PB_S_REQUESTED] = k 373 var published: i64 = 0 374 var refused: i64 = 0 375 var identical: i64 = 1 376 var first: *u8 = 0 as *u8 377 var j: i64 = 0 378 while j < k { 379 let r: *i64 = ((rows as i64) + j * PB_R_N * 8) as *i64 380 var w: i64 = 0 381 while w < PB_R_N { r[w] = 0; w = w + 1 } 382 r[PB_R_MEMBER_IDX] = 0 - 1 383 let idx: i64 = pb_find(tbl, nconf, parts[j] as *u8) 384 if idx < 0 { r[PB_R_RC] = PB_ERR_NO_SUCH_COMMUNITY; refused = refused + 1 } 385 else { 386 let rc: i64 = pb_publish_one(root, mb, lp[0], m, ((tbl as i64) + idx * PB_C_SLOTS * 8) as *i64, outdir, g, jrnl, r) 387 if rc == PB_OK { 388 published = published + 1 389 if (first as i64) == 0 { first = r[PB_R_MANIFEST_SHA] as *u8 } 390 else { if mm_streq(first, r[PB_R_MANIFEST_SHA] as *u8) == 0 { identical = 0 } } 391 } else { 392 refused = refused + 1 393 if sum[PB_S_RC] == 0 { sum[PB_S_RC] = rc } 394 } 395 } 396 j = j + 1 397 } 398 sum[PB_S_PUBLISHED] = published 399 sum[PB_S_REFUSED] = refused 400 if published == 0 { identical = 0 } 401 sum[PB_S_IDENTICAL] = identical 402 return published 403} 404// THE CONTRACT SYMBOL the board watches (modding MD23): a thin name over pb_publish so the watch flips only when the real 405// entry exists and the command reaches it 406func pushback_publish(root: *u8, mpath: *u8, ids_csv: *u8, outdir: *u8, gradepath: *u8, confpath: *u8, jrnl: *u8, sum: *i64, rows: *i64) -> i64 { 407 return pb_publish(root, mpath, ids_csv, outdir, gradepath, confpath, jrnl, sum, rows) 408}