code wiki / _hdl_build / nx_dr_tree.nx

nx_dr_tree.nx source

↩ module page · 82 lines · 4865 B

1// nx_dr_tree.nx -- CAP-DR-TREE: recursive + STREAMING archive of a whole directory tree to a separate drive (for 2// large content: galx, reference, search-data, wiki). Walks src (getdents64), mirrors the structure under dest 3// (mkdir), streams each file in 1 MiB chunks (NO size cap -> handles multi-GB media) and size-verifies the copy. 4// Additive-safe (reads src, writes only dest). Composes nx_lsdir's getdents primitives. argv: [1]=src-dir [2]=dest-dir. 5// license_tier: ORIGINAL 6import "nx_syscalls.nx" 7const K_MAGIC_1048576: i64 = 1048576 8const K_MAGIC_3900: i64 = 3900 9const K_MAGIC_131072: i64 = 131072 10const K_MAGIC_4096: i64 = 4096 11 12func tr_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 13func tr_wn(v: i64) -> i64 { var t: i64=v; if t<0{sys_write(1,"-" as *u8,1);t=0-t} let tm:*u8=sys_mmap(24); var k:i64=0; if t==0{tm[0]=48 as u8;k=1} while t>0{tm[k]=(48+(t%10)) as u8;t=t/10;k=k+1} let b:*u8=sys_mmap(24); var j:i64=0; while j<k{b[j]=tm[k-1-j];j=j+1} sys_write(1,b,k); return 0 } 14 15// end size of a file via SEEK_END. 16func tr_size(path: *u8) -> i64 { let fd: i64=sys_openat_rd(path); if fd<0 { return 0-1 } let s: i64=sys_lseek(fd,0,2); sys_close(fd); return s } 17// streaming copy src->dest (any size), then size-verify. Returns bytes, -1 read-fail, -2 write-fail, -3 size-mismatch. 18func tr_copy(src: *u8, dest: *u8) -> i64 { 19 let sfd: i64 = sys_openat_rd(src); if sfd < 0 { return 0 - 1 } 20 let dfd: i64 = sys_openat_wr(dest, 0x1a4); if dfd < 0 { sys_close(sfd); return 0 - 2 } 21 let buf: *u8 = sys_mmap(K_MAGIC_1048576); var total: i64 = 0; var go: i64 = 1 22 while go == 1 { let nr: i64 = sys_read(sfd, buf, K_MAGIC_1048576); if nr <= 0 { go = 0 } else { sys_write(dfd, buf, nr); total = total + nr } } 23 sys_close(sfd); sys_close(dfd) 24 if tr_size(dest) != total { return 0 - 3 } 25 return total 26} 27// append "/name" to buf at base_n (NOT NUL-terminated); returns the new length. 28func tr_join(buf: *u8, base_n: i64, name: *u8) -> i64 { 29 buf[base_n] = 47 as u8; var o: i64 = base_n + 1; var i: i64 = 0 30 while name[i] != (0 as u8) { buf[o] = name[i]; o = o + 1; i = i + 1 } 31 return o 32} 33func tr_isdotdot(nm: *u8) -> i64 { 34 if nm[0] == (46 as u8) { if nm[1] == (0 as u8) { return 1 } if nm[1] == (46 as u8) { if nm[2] == (0 as u8) { return 1 } } } 35 return 0 36} 37// recursively archive src[0..src_n) -> dst[0..dst_n). st[0]=files st[1]=dirs st[2]=bytes st[3]=failed 38func tr_walk(src: *u8, src_n: i64, dst: *u8, dst_n: i64, st: *i64) -> i64 { 39 if src_n > K_MAGIC_3900 { return 0 } // path-depth guard (buffer safety) 40 src[src_n] = 0 as u8; dst[dst_n] = 0 as u8 41 sys_mkdir(dst, 0x1ed) 42 let fd: i64 = sys_openat_rd(src); if fd < 0 { return 0 } 43 let dbuf: *u8 = sys_mmap(K_MAGIC_131072) 44 var go: i64 = 1 45 while go == 1 { 46 let nr: i64 = sys_getdents64(fd, dbuf, K_MAGIC_131072) 47 if nr <= 0 { go = 0 } else { 48 var off: i64 = 0 49 while off < nr { 50 let rec: *u8 = (dbuf as i64 + off) as *u8 51 let ty: i64 = dirent_type(rec) 52 let nm: *u8 = dirent_name(rec) 53 if tr_isdotdot(nm) == 0 { 54 let cs: i64 = tr_join(src, src_n, nm) 55 let cd: i64 = tr_join(dst, dst_n, nm) 56 if ty == 4 { st[1] = st[1] + 1; tr_walk(src, cs, dst, cd, st) } 57 else { 58 src[cs] = 0 as u8; dst[cd] = 0 as u8 59 let n: i64 = tr_copy(src, dst) 60 if n < 0 { st[3] = st[3] + 1 } else { st[0] = st[0] + 1; st[2] = st[2] + n } 61 } 62 } 63 off = off + dirent_reclen(rec) 64 } 65 } 66 } 67 sys_close(fd) 68 return 0 69} 70 71func main(argc: i64, argv: *i64) -> i64 { 72 if argc < 3 { tr_w("usage: nx_dr_tree <src-dir> <dest-dir>\n" as *u8); sys_exit(2); return 2 } 73 let src: *u8 = sys_mmap(K_MAGIC_4096); let dst: *u8 = sys_mmap(K_MAGIC_4096) 74 var sn: i64 = 0; var i: i64 = 0; let a1: *u8 = argv[1] as *u8; while a1[i]!=(0 as u8){src[sn]=a1[i];sn=sn+1;i=i+1} 75 var dn: i64 = 0; i = 0; let a2: *u8 = argv[2] as *u8; while a2[i]!=(0 as u8){dst[dn]=a2[i];dn=dn+1;i=i+1} 76 tr_w("=== nx_dr_tree: recursive+streaming archive ===\n src: " as *u8); tr_w(a1); tr_w("\n dst: " as *u8); tr_w(a2); tr_w("\n" as *u8) 77 let st: *i64 = sys_mmap(64) as *i64; st[0]=0; st[1]=0; st[2]=0; st[3]=0 78 tr_walk(src, sn, dst, dn, st) 79 tr_w(" ---- files=" as *u8); tr_wn(st[0]); tr_w(" dirs=" as *u8); tr_wn(st[1]); tr_w(" bytes=" as *u8); tr_wn(st[2]); tr_w(" failed=" as *u8); tr_wn(st[3]); tr_w("\n" as *u8) 80 if st[3] == 0 { tr_w("=== TREE ARCHIVE OK (mirrored + size-verified on a separate device) ===\n" as *u8); sys_exit(0); return 0 } 81 tr_w("=== TREE ARCHIVE had FAILURES ===\n" as *u8); sys_exit(1); return 1 82}