implement Wrap; include "sys.m"; sys : Sys; include "draw.m"; include "bufio.m"; bufio : Bufio; Iobuf : import bufio; include "keyring.m"; keyring : Keyring; include "sh.m"; include "arch.m"; arch : Arch; include "wrap.m"; include "archfs.m"; archpid := -1; gzfd: ref Sys->FD; gzfile: string; init() { sys = load Sys Sys->PATH; bufio = load Bufio Bufio->PATH; keyring = load Keyring Keyring->PATH; bufio->init(); arch = load Arch Arch->PATH; arch->init(nil, nil); } end() { if(gzfile != nil) sys->remove(gzfile); if (archpid > 0){ fd := sys->open("#p/" + string archpid + "/ctl", sys->OWRITE); if (fd != nil) sys->fprint(fd, "killgrp"); } } archfs(f : string, mtpt : string, all : int, c : chan of int) { sys->pctl(Sys->NEWPGRP, nil); cmd := "/dis/install/archfs.dis"; m := load Archfs Archfs->PATH; if(m == nil) { c <-= -1; return; } ch := chan of int; if (all) spawn m->initc(cmd :: "-m" :: mtpt :: f :: nil, ch); else spawn m->initc(cmd :: "-s" :: "-m" :: mtpt :: f :: "/wrap" :: nil, ch); pid := <- ch; c <-= pid; } mountarch(f : string, mtpt : string, all : int) : int { c := chan of int; spawn archfs(f, mtpt, all, c); pid := <- c; if (pid < 0) { sys->fprint(sys->fildes(2), "fatal: cannot run archfs\n"); return -1; } archpid = pid; return 0; } openmount(f : string, d : string) : ref Wrapped { if (f == nil) { p := d+"/wrap"; f = getfirstdir(p); if (f == nil) return nil; } w := ref Wrapped; w.name = f; w.root = d; # p := d + "/wrap/" + f; p := pathcat(d, pathcat("wrap", f)); (w.u, w.nu, w.tfull) = openupdate(p); if (w.nu < 0) { closewrap(w); return nil; } return w; } closewrap(w : ref Wrapped) { } openwraphdr(f : string, d : string, argl : list of string, all : int) : ref Wrapped { (ok, dir) := sys->stat(f); if (ok < 0 || dir.mode & Sys->CHDIR) return openwrap(f, d, all); (nf, fd) := arch->openarchgz(f); if (nf != nil) { gzfile = nf; f = nf; gzfd = fd; } return openwrap(f, "/mnt/wrap", all); } openwrap(f : string, d : string, all : int) : ref Wrapped { if (d == nil) d = "/"; if((w := openmount(f, d)) != nil) return w; # don't mess about if /wrap/ structure exists (ok, dir) := sys->stat(f); if (ok < 0) return nil; # accept root/ or root/wrap/pkgname if (dir.mode & Sys->CHDIR) { d = f; if ((i := strstr(f, "/wrap/")) >= 0) { f = f[i+6:]; d = d[0:i+6]; } else f = nil; return openmount(f, d); } (ok, dir) = sys->stat(f); if (ok < 0 || dir.mode & Sys->CHDIR) return openmount(f, d); # ? if (mountarch(f, d, all) < 0) return nil; return openmount(nil, d); } getfirstdir(d : string) : string { if ((fd := sys->open(d, Sys->OREAD)) == nil) return nil; dir := array[1] of Sys->Dir; while (sys->dirread(fd, dir) > 0) { if (dir[0].mode & Sys->CHDIR) return dir[0].name; } return nil; } NONE : con 0; sniffdir(base : string, elem : string) : (int, int) { t := int elem; if (t == 0) return (NONE, 0); buf := sys->sprint("%ud", t); if (buf != elem) return (NONE, 0); rv := NONE; p := base + "/" + elem + "/package"; (ok, nil) := sys->stat(p); if (ok >= 0) rv |= FULL; p = base + "/" + elem + "/update"; (ok, nil) = sys->stat(p); if (ok >= 0) rv |= UPD; return (rv, t); } openupdate(d : string) : (array of Update, int, int) { u : array of Update; if ((fd := sys->open(d, Sys->OREAD)) == nil) return (nil, -1, 0); # # We are looking to find the most recent full # package; anything before that is irrelevant. # Also figure out the most recent package update. # Non-package updates before that are irrelevant. # If there are no packages installed, # grab all the updates we can find. # tbase := -1; tfull := -1; nu := 0; dir := array[1] of Sys->Dir; while (sys->dirread(fd, dir) > 0) { (k, t) := sniffdir(d, dir[0].name); case (k) { FULL => nu++; if (t > tfull) tfull = t; if (t > tbase) tbase = t; FULL|UPD => nu++; if (t > tfull) tfull = t; UPD => nu++; } } if (nu == 0) return (nil, -1, 0); u = nil; nu = 0; if ((fd = sys->open(d, Sys->OREAD)) == nil) return (nil, -1, 0); while (sys->dirread(fd, dir) > 0) { (k, t) := sniffdir(d, dir[0].name); if (k == 0) continue; if (t < tbase) continue; if (t < tfull && k == UPD) continue; if (nu%8 == 0) { newu := array[nu+8] of Update; newu[0:] = u[0:nu]; u = newu; } u[nu].typ = k; if (readupdate(u, nu, d, dir[0].name) != nil) nu++; } if (nu == 0) return (nil, -1, 0); qsort(u, nu); return (u, nu, tfull); } readupdate(u : array of Update, ui : int, base : string, elem : string) : array of Update { # u[ui].dir = base + "/" + elem; u[ui].dir = pathcat(base, elem); p := u[ui].dir + "/desc"; u[ui].desc = readfile(p); u[ui].time = int elem; p = u[ui].dir + "/md5sum"; u[ui].bmd5 = bufio->open(p, Bufio->OREAD); p = u[ui].dir + "/update"; q := readfile(p); if (q != nil) u[ui].utime = int q; else u[ui].utime = 0; if (u[ui].bmd5 == nil) return nil; return u; } readfile(s : string) : string { (ok, d) := sys->stat(s); if (ok < 0) return nil; buf := array[d.length] of byte; if ((fd := sys->open(s, Sys->OREAD)) == nil || (n := sys->read(fd, buf, d.length)) != d.length) return nil; s = string buf; ls := len s; if (s[ls-1] == '\n') s = s[0:ls-1]; return s; } hex(c : int) : int { if (c >= '0' && c <= '9') return c-'0'; if (c >= 'a' && c <= 'f') return c-'a'+10; if (c >= 'A' && c <= 'F') return c-'A'+10; return -1; } getfileinfo(w : ref Wrapped, f : string, rdigest : array of byte, wdigest : array of byte) : (int, int) { p : string; if (w == nil) return (-1, 0); digest := array[keyring->MD5dlen] of { * => byte 0 }; for (i := w.nu-1; i >= 0; i--){ if ((p = bsearch(w.u[i].bmd5, f)) == nil) continue; if (p == nil) continue; k := 0; while (k < len p && p[k] != ' ') k++; if (k == len p) continue; q := p[k+1:]; if (q == nil) continue; if (len q != 2*Keyring->MD5dlen+1) continue; for (j := 0; j < Keyring->MD5dlen; j++) { a := hex(q[2*j]); b := hex(q[2*j+1]); if (a < 0 || b < 0) break; digest[j] = byte ((a<<4)|b); } if(j != Keyring->MD5dlen) continue; if(rdigest == nil || memcmp(rdigest, digest, keyring->MD5dlen) == 0) break; } if(i < 0) return (-1, 0); if(wdigest != nil) wdigest[0:] = rdigest; return (0, w.u[i].time); } bsearch(b : ref Bufio->Iobuf, p : string) : string { if (b == nil) return nil; lo := 0; b.seek(0, Bufio->SEEKEND); hi := b.offset(); l := len p; while (lo < hi) { m := (lo+hi)/2; b.seek(m, Bufio->SEEKSTART); b.gets('\n'); if (b.offset() == hi) { bgetbackc(b); m = b.offset(); while (m-- > lo) { if (bgetbackc(b) == '\n') { b.getc(); break; } } } s := b.gets('\n'); if (len s >= l+1 && s[0:l] == p && (s[l] == ' ' || s[l] == '\n')) return s; if (s < p) lo = b.offset(); else hi = b.offset()-len s; } return nil; } bgetbackc(b : ref Bufio->Iobuf) : int { m := b.offset(); b.seek(m-1, Bufio->SEEKSTART); c := b.getc(); b.ungetc(); return c; } strstr(s : string, p : string) : int { lp := len p; ls := len s; for (i := 0; i < ls-lp; i++) if (s[i:i+lp] == p) return i; return -1; } qsort(a : array of Update, n : int) { i, j : int; t : Update; while(n > 1) { i = n>>1; t = a[0]; a[0] = a[i]; a[i] = t; i = 0; j = n; for(;;) { do i++; while(i < n && a[i].time < a[0].time); do j--; while(j > 0 && a[j].time > a[0].time); if(j < i) break; t = a[i]; a[i] = a[j]; a[j] = t; } t = a[0]; a[0] = a[j]; a[j] = t; n = n-j-1; if(j >= n) { qsort(a, j); a = a[j+1:]; } else { qsort(a[j+1:], n); n = j; } } } md5file(file : string, digest : array of byte) : int { (ok, d) := sys->stat(file); if (ok < 0) return -1; if (d.mode & Sys->CHDIR) return 0; bio := bufio->open(file, Bufio->OREAD); if (bio == nil) return -1; buff := array[Sys->ATOMICIO] of byte; ds := keyring->md5(nil, 0, nil, nil); while ((n := bio.read(buff, len buff)) > 0) keyring->md5(buff, n, nil, ds); keyring->md5(nil, 0, digest, ds); bio = nil; return 0; } md5sum(b : ref Iobuf, digest : array of byte, leng : int) : int { ds := keyring->md5(nil, 0, nil, nil); buff := array[Sys->ATOMICIO] of byte; while (leng > 0) { if (leng > len buff) n := len buff; else n = leng; if ((n = b.read(buff, n)) <= 0) return -1; keyring->md5(buff, n, nil, ds); leng -= n; } keyring->md5(nil, 0, digest, ds); return 0; } md5conv(d : array of byte) : string { s : string = nil; for (i := 0; i < keyring->MD5dlen; i++) s += sys->sprint("%.2ux", int d[i]); return s; } zd : Sys->Dir; newd(time : int, uid : string, gid : string) : ref Sys->Dir { d := ref Sys->Dir; *d = zd; d.uid = uid; d.gid = gid; d.mtime = time; return d; } putwrapfile(b : ref Iobuf, name : string, time : int, elem : string, file : string, uid : string, gid : string) { d := newd(time, uid, gid); d.mode = 8r444; (ok, dir) := sys->stat(file); if (ok < 0) sys->fprint(sys->fildes(2), "cannot stat %s: %r", file); d.length = dir.length; s := "/wrap/"+name+"/"+sys->sprint("%ud", time)+"/"+elem; arch->puthdr(b, s, d); arch->putfile(b, file, d.length); } putwrap(b : ref Iobuf, name : string, time : int, desc : string, utime : int, pkg : int, uid : string, gid : string) { if (!(utime || pkg)) sys->fprint(sys->fildes(2), "bad precondition in putwrap()"); d := newd(time, uid, gid); d.mode = Sys->CHDIR|8r775; s := "/wrap"; arch->puthdr(b, s, d); s += "/"+name; arch->puthdr(b, s, d); s += "/"+sys->sprint("%ud", time); arch->puthdr(b, s, d); d.mode = 8r444; s += "/"; dir := s; if (utime) { s = dir+"update"; d.length = 23; arch->puthdr(b, s, d); arch->putstring(b, sys->sprint("%22ud\n", utime)); } if (pkg) { s = dir+"package"; d.length = 0; arch->puthdr(b, s, d); } if (desc != nil) { s = dir+"desc"; d.length = len desc+1; d.mode = 8r444; arch->puthdr(b, s, d); arch->putstring(b, desc+"\n"); } } memcmp(b1, b2 : array of byte, n : int) : int { for (i := 0; i < n; i++) if (b1[i] < b2[i]) return -1; else if (b1[i] > b2[i]) return 1; return 0; } strprefix(s: string, pre: string): int { return len s >= (l := len pre) && s[0:l] == pre; } match(s: string, pre: list of string): int { if(pre == nil || s == "/wrap" || strprefix(s, "/wrap/")) return 1; for( ; pre != nil; pre = tl pre) if(strprefix(s, hd pre)) return 1; return 0; } pathcat(s : string, t : string) : string { if (s == nil) return t; if (t == nil) return s; slashs := s[len s - 1] == '/'; slasht := t[0] == '/'; if (slashs && slasht) return s + t[1:]; if (!slashs && !slasht) return s + "/" + t; return s + t; } # rmch(b: array of byte, n: int, c: byte): int # { # for(i := 0; i < n; ){ # if(b[i] == c) # b[i:] = b[i+1:n--]; # else # i++; # } # return n; # }