code wiki / (root) / nx_torrent_clean.nx

nx_torrent_clean.nx source

↩ module page · 113 lines · 6753 B

1// nx_torrent_clean.nx -- SOVEREIGN disk purge of leftover torrent folders. A folder is DELETED only 2// if it is NOT in the live torrents.idx (so the operator's real/active downloads are always kept) AND 3// its control is not "active" (defensive). Reports every action. Frees the dead/removed/duplicate/test 4// clutter the doctor surfaced. Uses raw unlinkat/rmdir (nx_syscalls has no wrapper). Run: nx_torrent_clean 5import "nx_syscalls.nx" 6const K_MAGIC_2048: i64 = 2048 7const K_MAGIC_65536: i64 = 65536 8const K_MAGIC_1024: i64 = 1024 9 10const DBUF: i64 = 65536 11const O: *u8 = "/mnt/c/Users/elder/Downloads/nishi-torrents" as *u8 12const IDX: *u8 = "/mnt/c/Users/elder/Downloads/nishi-torrents/torrents.idx" as *u8 13 14func cl_p(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 15func cl_n(v: i64) -> i64 { let t: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m} var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} let b: *u8=sys_mmap(28); var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 16func cl_len(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 17func cl_cat(dst: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){dst[off+i]=s[i];i=i+1} return off+cl_len(s) } 18// raw unlinkat: file (flags=0) / dir (flags=0x200 AT_REMOVEDIR). x86_64 nr 263. returns 0 on success. 19func cl_unlink(path: *u8) -> i64 { return __syscall(263, AT_FDCWD, path as i64, 0, 0, 0, 0) } 20func cl_rmdir(path: *u8) -> i64 { return __syscall(263, AT_FDCWD, path as i64, 0x200, 0, 0, 0) } 21func cl_read(path: *u8, buf: *u8, cap: i64) -> i64 { 22 let fd: i64 = sys_openat_rd(path); if fd<0 { return 0-1 } 23 var off: i64=0; var go: i64=1 24 while go==1 { if off>=cap {go=0} else { let r: i64=sys_read(fd, ((buf as i64)+off) as *u8, cap-off); if r<=0 {go=0} else {off=off+r} } } 25 sys_close(fd); return off 26} 27// is `name` (len nl) a whole line in the idx buffer? (the keep-list) 28func cl_idx_has(idx: *u8, n: i64, name: *u8, nl: i64) -> i64 { 29 var i: i64 = 0 30 while i < n { 31 var ls: i64 = 0; if i==0 {ls=1} else { if (idx[i-1] as i64)==10 {ls=1} } 32 if ls==1 { 33 var m: i64=1; var j: i64=0 34 while j<nl { if i+j>=n {m=0;j=nl} else { if idx[i+j]!=name[j] {m=0;j=nl} else {j=j+1} } } 35 if m==1 { let e: i64=i+nl; var term: i64=0; if e>=n {term=1} else { if (idx[e] as i64)==10 {term=1} } if term==1 { return 1 } } 36 } 37 i=i+1 38 } 39 return 0 40} 41// flat-delete a torrent folder: unlink its files, then rmdir. returns 1 if the dir was removed. 42func cl_rmtree_flat(dir: *u8) -> i64 { 43 let fd: i64 = sys_openat_rd(dir); if fd<0 { return 0 } 44 let gbuf: *u8 = sys_mmap(DBUF); let child: *u8 = sys_mmap(K_MAGIC_2048); let dlen: i64 = cl_len(dir) 45 var nested: i64 = 0; var go: i64 = 1 46 while go == 1 { 47 let n: i64 = sys_getdents64(fd, gbuf, DBUF) 48 if n <= 0 { go = 0 } else { 49 var off: i64 = 0 50 while off < n { 51 let rec: *u8 = ((gbuf as i64) + off) as *u8 52 let reclen: i64 = dirent_reclen(rec) 53 let typ: i64 = dirent_type(rec) 54 let name: *u8 = dirent_name(rec) 55 if name[0]!=(46 as u8) { 56 var co: i64=0; while co<dlen {child[co]=dir[co];co=co+1} child[co]=47 as u8; co=co+1 57 var ni: i64=0; while name[ni]!=(0 as u8){child[co]=name[ni];co=co+1;ni=ni+1} child[co]=0 as u8 58 if typ == DT_DIR { nested = 1 } else { cl_unlink(child) } 59 } 60 if reclen <= 0 { off = n } else { off = off + reclen } 61 } 62 } 63 } 64 sys_close(fd) 65 if nested == 1 { return 0 } // a nested subdir remains (multi-file extract) -> leave the folder 66 if cl_rmdir(dir) == 0 { return 1 } 67 return 0 68} 69 70func main() -> i64 { 71 let idx: *u8 = sys_mmap(K_MAGIC_65536); let idxn: i64 = cl_read(IDX, idx, K_MAGIC_65536) 72 let fd: i64 = sys_openat_rd(O); if fd<0 { cl_p("CLEAN FAIL: no outdir\n" as *u8); sys_exit(1); return 1 } 73 let gbuf: *u8 = sys_mmap(DBUF); let sub: *u8 = sys_mmap(K_MAGIC_1024); let probe: *u8 = sys_mmap(K_MAGIC_1024); let ctl: *u8 = sys_mmap(64) 74 var kept: i64=0; var deleted: i64=0; var skipped: i64=0 75 cl_p("=== NISHI TORRENT CLEAN (folders NOT in the live index, control!=active) ===\n" as *u8) 76 var go: i64 = 1 77 while go == 1 { 78 let n: i64 = sys_getdents64(fd, gbuf, DBUF) 79 if n <= 0 { go = 0 } else { 80 var off: i64 = 0 81 while off < n { 82 let rec: *u8 = ((gbuf as i64) + off) as *u8 83 let reclen: i64 = dirent_reclen(rec) 84 let name: *u8 = dirent_name(rec) 85 if name[0]!=(46 as u8) { 86 var so: i64=cl_cat(sub,0,O); sub[so]=47 as u8; so=so+1; var ni: i64=0; while name[ni]!=(0 as u8){sub[so]=name[ni];so=so+1;ni=ni+1} sub[so]=0 as u8 87 // is this a torrent folder? (has download.status) 88 var po: i64=cl_cat(probe,0,sub); po=cl_cat(probe,po,"/download.status" as *u8); probe[po]=0 as u8 89 let stfd: i64 = sys_openat_rd(probe) 90 if stfd >= 0 { 91 sys_close(stfd) 92 let nl: i64 = cl_len(name) 93 if cl_idx_has(idx, idxn, name, nl) == 1 { kept = kept + 1; cl_p(" KEEP " as *u8); cl_p(name); cl_p(" (in index)\n" as *u8) } 94 else { 95 var cp: i64=cl_cat(probe,0,sub); cp=cl_cat(probe,cp,"/download.control" as *u8); probe[cp]=0 as u8 96 let cn: i64 = cl_read(probe, ctl, 63) 97 var active: i64 = 0; if cn>0 { let c0: i64=ctl[0] as i64; if c0==97 { active=1 } if c0==112 { active=1 } } // 'a'ctive or 'p'aused -> defensive skip 98 if active == 1 { skipped = skipped + 1; cl_p(" SKIP " as *u8); cl_p(name); cl_p(" (control=active/paused, not in index)\n" as *u8) } 99 else { 100 if cl_rmtree_flat(sub) == 1 { deleted = deleted + 1; cl_p(" DELETE " as *u8); cl_p(name); cl_p("\n" as *u8) } 101 else { skipped = skipped + 1; cl_p(" SKIP " as *u8); cl_p(name); cl_p(" (nested files remain)\n" as *u8) } 102 } 103 } 104 } 105 } 106 if reclen <= 0 { off = n } else { off = off + reclen } 107 } 108 } 109 } 110 sys_close(fd) 111 cl_p("--- summary --- kept=" as *u8); cl_n(kept); cl_p(" deleted=" as *u8); cl_n(deleted); cl_p(" skipped=" as *u8); cl_n(skipped); cl_p("\n" as *u8) 112 sys_exit(0); return 0 113}