code wiki / _hdl_build / nx_cms_snapshot.nx

nx_cms_snapshot.nx source

↩ module page · 146 lines · 5508 B

1// nx_cms_snapshot.nx -- CMS W4: a binary-safe site SNAPSHOT/RESTORE archive (the UpdraftPlus class). 2// One file packs N named files length-prefixed so ANY bytes survive (newlines, high bytes, NULs): 3// "NXSNAP1\n" then per entry: "N"<namelen-dec>"\n"<name> "D"<datalen-dec>"\n"<data> then "END\n" 4// Restore is BYTE-EXACT (the additive-history law: a restore brings back exactly what was archived). 5// Zero interpretation of the payload -> images, binary stores, anything round-trips. Reusable. 6// license_tier: ORIGINAL 7import "nx_syscalls.nx" 8const K_MAGIC_8388608: i64 = 8388608 9const K_MAGIC_1024: i64 = 1024 10 11func snap_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 12func snap_emit_num(out: *u8, o: i64, v: i64) -> i64 { 13 let t: *u8 = sys_mmap(24) 14 var m: i64 = v 15 var k: i64 = 0 16 if m == 0 { t[0] = 48 as u8; k = 1 } 17 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 18 var p: i64 = o 19 var i: i64 = 0 20 while i < k { out[p] = t[k-1-i]; p = p + 1; i = i + 1 } 21 out[p] = 10 as u8 22 p = p + 1 23 return p 24} 25func snap_read_file(path: *u8, out: *u8, cap: i64) -> i64 { 26 let fd: i64 = sys_openat_rd(path) 27 if fd < 0 { return 0 - 1 } 28 var total: i64 = 0 29 var go: i64 = 1 30 while go == 1 { 31 let r: i64 = sys_read(fd, (out + total) as *u8, cap - total) 32 go = 0 33 if r > 0 { total = total + r; if total < cap { go = 1 } } 34 } 35 sys_close(fd) 36 return total 37} 38func snap_join(out: *u8, dir: *u8, name: *u8, nlen: i64) -> i64 { 39 var o: i64 = 0 40 var k: i64 = 0 41 while dir[k] != (0 as u8) { out[o] = dir[k]; o = o + 1; k = k + 1 } 42 out[o] = 47 as u8; o = o + 1 43 k = 0 44 while k < nlen { out[o] = name[k]; o = o + 1; k = k + 1 } 45 out[o] = 0 as u8 46 return o 47} 48 49// pack dir/<names[i]> for each present file into out. names = array of *u8 (i64 cells). Returns 50// archive length, or -1 on overflow. Missing files are skipped (a snapshot of what exists). 51func snap_pack(dir: *u8, names: *i64, nn: i64, out: *u8, cap: i64) -> i64 { 52 var o: i64 = 0 53 let mg: *u8 = "NXSNAP1\n" as *u8 54 var mi: i64 = 0 55 while mi < 8 { out[o] = mg[mi]; o = o + 1; mi = mi + 1 } 56 let buf: *u8 = sys_mmap(K_MAGIC_8388608) // 8MB per-file cap 57 let path: *u8 = sys_mmap(K_MAGIC_1024) 58 var i: i64 = 0 59 while i < nn { 60 let nm: *u8 = names[i] as *u8 61 let nlen: i64 = snap_slen(nm) 62 snap_join(path, dir, nm, nlen) 63 let dn: i64 = snap_read_file(path, buf, K_MAGIC_8388608) 64 if dn >= 0 { 65 if o + nlen + dn + 64 > cap { return 0 - 1 } 66 out[o] = 78 as u8; o = o + 1 // 'N' 67 o = snap_emit_num(out, o, nlen) 68 var k: i64 = 0 69 while k < nlen { out[o] = nm[k]; o = o + 1; k = k + 1 } 70 out[o] = 68 as u8; o = o + 1 // 'D' 71 o = snap_emit_num(out, o, dn) 72 var d: i64 = 0 73 while d < dn { out[o] = buf[d]; o = o + 1; d = d + 1 } 74 } 75 i = i + 1 76 } 77 out[o] = 69 as u8; o = o + 1 // 'E' 78 out[o] = 78 as u8; o = o + 1 // 'N' 79 out[o] = 68 as u8; o = o + 1 // 'D' 80 out[o] = 10 as u8; o = o + 1 81 return o 82} 83 84// parse a decimal number at arc[*pp] up to '\n'; advance *pp past the newline. -1 on malformed. 85func snap_num(arc: *u8, n: i64, pp: *i64) -> i64 { 86 var v: i64 = 0 87 var seen: i64 = 0 88 var p: i64 = pp[0] 89 var go: i64 = 1 90 while go == 1 { 91 go = 0 92 if p < n { 93 let c: i64 = arc[p] as i64 94 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); seen = seen + 1; p = p + 1; go = 1 } } 95 } 96 } 97 if seen == 0 { return 0 - 1 } 98 if p >= n { return 0 - 1 } 99 if (arc[p] as i64) != 10 { return 0 - 1 } 100 pp[0] = p + 1 101 return v 102} 103 104// unpack archive arc[0..n) into dir, writing each entry BYTE-EXACT. Returns file count, or -1. 105func snap_unpack(arc: *u8, n: i64, dir: *u8) -> i64 { 106 if n < 8 { return 0 - 1 } 107 let mg: *u8 = "NXSNAP1\n" as *u8 108 var mi: i64 = 0 109 while mi < 8 { if (arc[mi] as i64) != (mg[mi] as i64) { return 0 - 1 } mi = mi + 1 } 110 let pp: *i64 = sys_mmap(16) as *i64 111 pp[0] = 8 112 let name: *u8 = sys_mmap(K_MAGIC_1024) 113 let path: *u8 = sys_mmap(K_MAGIC_1024) 114 var count: i64 = 0 115 var go: i64 = 1 116 while go == 1 { 117 if pp[0] >= n { return 0 - 1 } 118 let tag: i64 = arc[pp[0]] as i64 119 if tag == 69 { go = 0 } // 'E' (END) 120 if tag == 78 { // 'N' entry 121 pp[0] = pp[0] + 1 122 let nlen: i64 = snap_num(arc, n, pp) 123 if nlen < 0 { return 0 - 1 } 124 if nlen > 1000 { return 0 - 1 } 125 var k: i64 = 0 126 while k < nlen { name[k] = arc[pp[0] + k]; k = k + 1 } 127 name[nlen] = 0 as u8 128 pp[0] = pp[0] + nlen 129 if pp[0] >= n { return 0 - 1 } 130 if (arc[pp[0]] as i64) != 68 { return 0 - 1 } // 'D' 131 pp[0] = pp[0] + 1 132 let dlen: i64 = snap_num(arc, n, pp) 133 if dlen < 0 { return 0 - 1 } 134 if pp[0] + dlen > n { return 0 - 1 } 135 snap_join(path, dir, name, nlen) 136 let fd: i64 = sys_openat_wr(path, 0x1a4) 137 if fd < 0 { return 0 - 1 } 138 sys_write(fd, ((arc as i64) + pp[0]) as *u8, dlen) 139 sys_close(fd) 140 pp[0] = pp[0] + dlen 141 count = count + 1 142 } 143 if tag != 69 { if tag != 78 { return 0 - 1 } } 144 } 145 return count 146}