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}