code wiki / _hdl_build / nx_galx_viewadd_lib.nx
nx_galx_viewadd_lib.nx source
↩ module page · 77 lines · 2946 B
1// nx_galx_viewadd_lib.nx -- prepend a cid to the gallery's VIEW index. ONE implementation.
2//
3// This is a library, not a copy: nx_galx_viewadd (the CLI) and nx_gen_ingest (the pipeline) both
4// call it. Two writers of a FIXED-WIDTH file that disagreed by one byte would shift every record
5// after the insertion point and scramble 226,576 images -- and it would look like the gallery had
6// been shuffled, not like a write bug.
7// ★ WHEN TWO CALLERS MUST AGREE ON A BYTE LAYOUT, THEY MUST SHARE THE CODE, NOT THE COMMENT.
8//
9// Format (measured): 70-byte records = 69-char cid + '\n', NEWEST-FIRST, so a new gen PREPENDS.
10// Returns 1 = added, 0 = already present, negative = refused/error.
11// license_tier: ORIGINAL
12
13import "nx_syscalls.nx"
14const NXV_MAGIC_1024: i64 = 1024
15
16const NXV_REC: i64 = 70
17const NXV_CIDLEN: i64 = 69
18
19const NXV_ADDED: i64 = 1
20const NXV_PRESENT: i64 = 0
21const NXV_EREAD: i64 = 0 - 1
22const NXV_ECORRUPT:i64 = 0 - 2 // file size not a multiple of the record
23const NXV_EBADCID: i64 = 0 - 3 // cid not exactly 69 chars
24const NXV_EWRITE: i64 = 0 - 4
25
26func _nxv_len(s: *u8) -> i64 {
27 var n: i64 = 0
28 while s[n] != (0 as u8) { n = n + 1 }
29 return n
30}
31
32func nx_galx_view_present(buf: *u8, n: i64, cid: *u8) -> i64 {
33 var r: i64 = 0
34 while r * NXV_REC < n {
35 let at: i64 = r * NXV_REC
36 var i: i64 = 0
37 var same: i64 = 1
38 while i < NXV_CIDLEN {
39 if buf[at + i] != cid[i] { same = 0; i = NXV_CIDLEN } else { i = i + 1 }
40 }
41 if same == 1 { return 1 }
42 r = r + 1
43 }
44 return 0
45}
46
47func nx_galx_view_prepend(path: *u8, cid: *u8) -> i64 {
48 // A cid of the wrong length is refused BEFORE any write. In a fixed-width file a short record
49 // does not corrupt one row, it corrupts every row after it.
50 if _nxv_len(cid) != NXV_CIDLEN { return NXV_EBADCID }
51
52 let sp: *i64 = sys_mmap(16) as *i64
53 let buf: *u8 = sys_read_file(path, sp)
54 if (buf as i64) == 0 { return NXV_EREAD }
55 let n: i64 = sp[0]
56 if n - (n / NXV_REC) * NXV_REC != 0 { return NXV_ECORRUPT }
57 if nx_galx_view_present(buf, n, cid) == 1 { return NXV_PRESENT }
58
59 // temp + rename: a crash mid-write must never leave the gallery reading a half file.
60 let tmp: *u8 = sys_mmap(NXV_MAGIC_1024)
61 var t: i64 = 0
62 while path[t] != (0 as u8) { tmp[t] = path[t]; t = t + 1 }
63 tmp[t] = 0x2E; tmp[t+1] = 0x6E; tmp[t+2] = 0x65; tmp[t+3] = 0x77; tmp[t+4] = 0 // ".new"
64
65 let rec: *u8 = sys_mmap(128)
66 var i: i64 = 0
67 while i < NXV_CIDLEN { rec[i] = cid[i]; i = i + 1 }
68 rec[NXV_CIDLEN] = 10 as u8
69
70 let fd: i64 = sys_openat_wr(tmp, 0x1a4)
71 if fd < 0 { return NXV_EWRITE }
72 if sys_write(fd, rec, NXV_REC) != NXV_REC { sys_close(fd); return NXV_EWRITE }
73 if sys_write(fd, buf, n) != n { sys_close(fd); return NXV_EWRITE }
74 sys_close(fd)
75 if sys_renameat(tmp, path) != 0 { return NXV_EWRITE }
76 return NXV_ADDED
77}