1implement Wrap; 2 3include "sys.m"; 4 sys : Sys; 5include "draw.m"; 6include "bufio.m"; 7 bufio : Bufio; 8 Iobuf : import bufio; 9include "keyring.m"; 10 keyring : Keyring; 11include "sh.m"; 12include "arch.m"; 13 arch : Arch; 14include "wrap.m"; 15include "archfs.m"; 16 17archpid := -1; 18gzfd: ref Sys->FD; 19gzfile: string; 20 21init(bio: Bufio) 22{ 23 sys = load Sys Sys->PATH; 24 if(bio == nil) 25 bufio = load Bufio Bufio->PATH; 26 else 27 bufio = bio; 28 keyring = load Keyring Keyring->PATH; 29 arch = load Arch Arch->PATH; 30 arch->init(bufio); 31} 32 33end() 34{ 35 if(gzfile != nil) 36 sys->remove(gzfile); 37 if (archpid > 0){ 38 fd := sys->open("#p/" + string archpid + "/ctl", sys->OWRITE); 39 if (fd != nil) 40 sys->fprint(fd, "killgrp"); 41 } 42} 43 44archfs(f : string, mtpt : string, all : int, c : chan of int) 45{ 46 sys->pctl(Sys->NEWPGRP, nil); 47 cmd := "/dis/install/archfs.dis"; 48 m := load Archfs Archfs->PATH; 49 if(m == nil) { 50 c <-= -1; 51 return; 52 } 53 ch := chan of int; 54 if (all) 55 spawn m->initc(cmd :: "-m" :: mtpt :: f :: nil, ch); 56 else 57 spawn m->initc(cmd :: "-s" :: "-m" :: mtpt :: f :: "/wrap" :: nil, ch); 58 pid := <- ch; 59 c <-= pid; 60} 61 62mountarch(f : string, mtpt : string, all : int) : int 63{ 64 c := chan of int; 65 spawn archfs(f, mtpt, all, c); 66 pid := <- c; 67 if (pid < 0) { 68 if(pid == -1) 69 sys->fprint(sys->fildes(2), "fatal: cannot run archfs\n"); 70 # else probably not an archive file 71 return -1; 72 } 73 archpid = pid; 74 return 0; 75} 76 77openmount(f : string, d : string) : ref Wrapped 78{ 79 if (f == nil) { 80 p := d+"/wrap"; 81 f = getfirstdir(p); 82 if (f == nil) 83 return nil; 84 } 85 w := ref Wrapped; 86 w.name = f; 87 w.root = d; 88 # p := d + "/wrap/" + f; 89 p := pathcat(d, pathcat("wrap", f)); 90 (w.u, w.nu, w.tfull) = openupdate(p); 91 if (w.nu < 0) { 92 closewrap(w); 93 return nil; 94 } 95 return w; 96} 97 98closewrap(w : ref Wrapped) 99{ 100 w = nil; 101} 102 103openwraphdr(f : string, d : string, argl : list of string, all : int) : ref Wrapped 104{ 105 argl = nil; 106 (ok, dir) := sys->stat(f); 107 if (ok < 0 || dir.mode & Sys->DMDIR) 108 return openwrap(f, d, all); 109 (nf, fd) := arch->openarchgz(f); 110 if (nf != nil) { 111 gzfile = nf; 112 f = nf; 113 gzfd = fd; 114 } 115 return openwrap(f, "/mnt/wrap", all); 116} 117 118openwrap(f : string, d : string, all : int) : ref Wrapped 119{ 120 if (d == nil) 121 d = "/"; 122 if((w := openmount(f, d)) != nil) 123 return w; # don't mess about if /wrap/ structure exists 124 (ok, dir) := sys->stat(f); 125 if (ok < 0) 126 return nil; 127 # accept root/ or root/wrap/pkgname 128 if (dir.mode & Sys->DMDIR) { 129 d = f; 130 if ((i := strstr(f, "/wrap/")) >= 0) { 131 f = f[i+6:]; 132 d = d[0:i+6]; 133 } 134 else 135 f = nil; 136 return openmount(f, d); 137 } 138 (ok, dir) = sys->stat(f); 139 if (ok < 0 || dir.mode & Sys->DMDIR) 140 return openmount(f, d); # ? 141 if (mountarch(f, d, all) < 0) 142 return nil; 143 return openmount(nil, d); 144} 145 146getfirstdir(d : string) : string 147{ 148 if ((fd := sys->open(d, Sys->OREAD)) == nil) 149 return nil; 150 for(;;){ 151 (n, dir) := sys->dirread(fd); 152 if(n <= 0) 153 break; 154 for(i:=0; i<n; i++) 155 if(dir[i].mode & Sys->DMDIR) 156 return dir[i].name; 157 } 158 return nil; 159} 160 161NONE : con 0; 162 163sniffdir(base : string, elem : string) : (int, int) 164{ 165 # t := int elem; 166 t := string2now(elem, 0); 167 if (t == 0) 168 return (NONE, 0); 169 # buf := sys->sprint("%ud", t); 170 # if (buf != elem) 171 # return (NONE, 0); 172 rv := NONE; 173 p := base + "/" + elem + "/package"; 174 (ok, nil) := sys->stat(p); 175 if (ok >= 0) 176 rv |= FULL; 177 p = base + "/" + elem + "/update"; 178 (ok, nil) = sys->stat(p); 179 if (ok >= 0) 180 rv |= UPD; 181 return (rv, t); 182} 183 184openupdate(d : string) : (array of Update, int, int) 185{ 186 u : array of Update; 187 188 if ((fd := sys->open(d, Sys->OREAD)) == nil) 189 return (nil, -1, 0); 190 # 191 # We are looking to find the most recent full 192 # package; anything before that is irrelevant. 193 # Also figure out the most recent package update. 194 # Non-package updates before that are irrelevant. 195 # If there are no packages installed, 196 # grab all the updates we can find. 197 # 198 tbase := -1; 199 tfull := -1; 200 nu := 0; 201 for(;;){ 202 (n, dir) := sys->dirread(fd); 203 if(n <= 0) 204 break; 205 for(i := 0; i < n; i++){ 206 (k, t) := sniffdir(d, dir[i].name); 207 case (k) { 208 FULL => 209 nu++; 210 if (t > tfull) 211 tfull = t; 212 if (t > tbase) 213 tbase = t; 214 FULL|UPD => 215 nu++; 216 if (t > tfull) 217 tfull = t; 218 UPD => 219 nu++; 220 } 221 } 222 } 223 if (nu == 0) 224 return (nil, -1, 0); 225 u = nil; 226 nu = 0; 227 if ((fd = sys->open(d, Sys->OREAD)) == nil) 228 return (nil, -1, 0); 229 for(;;){ 230 (n, dir) := sys->dirread(fd); 231 if(n <= 0) 232 break; 233 for(i := 0; i < n; i++){ 234 (k, t) := sniffdir(d, dir[i].name); 235 if (k == 0) 236 continue; 237 if (t < tbase) 238 continue; 239 if (t < tfull && k == UPD) 240 continue; 241 if (nu%8 == 0) { 242 newu := array[nu+8] of Update; 243 newu[0:] = u[0:nu]; 244 u = newu; 245 } 246 u[nu].typ = k; 247 if (readupdate(u, nu, d, dir[i].name) != nil) 248 nu++; 249 } 250 } 251 if (nu == 0) 252 return (nil, -1, 0); 253 qsort(u, nu); 254 return (u, nu, tfull); 255} 256 257readupdate(u : array of Update, ui : int, base : string, elem : string) : array of Update 258{ 259 # u[ui].dir = base + "/" + elem; 260 u[ui].dir = pathcat(base, elem); 261 p := u[ui].dir + "/desc"; 262 u[ui].desc = readfile(p); 263 # u[ui].time = int elem; 264 u[ui].time = string2now(elem, 0); 265 p = u[ui].dir + "/md5sum"; 266 u[ui].bmd5 = bufio->open(p, Bufio->OREAD); 267 p = u[ui].dir + "/update"; 268 q := readfile(p); 269 if (q != nil) 270 u[ui].utime = int q; 271 else 272 u[ui].utime = 0; 273 if (u[ui].bmd5 == nil) 274 return nil; 275 return u; 276} 277 278readfile(s : string) : string 279{ 280 (ok, d) := sys->stat(s); 281 if (ok < 0) 282 return nil; 283 buf := array[int d.length] of byte; 284 if ((fd := sys->open(s, Sys->OREAD)) == nil || sys->read(fd, buf, int d.length) != int d.length) 285 return nil; 286 s = string buf; 287 ls := len s; 288 if (s[ls-1] == '\n') 289 s = s[0:ls-1]; 290 return s; 291} 292 293hex(c : int) : int 294{ 295 if (c >= '0' && c <= '9') 296 return c-'0'; 297 if (c >= 'a' && c <= 'f') 298 return c-'a'+10; 299 if (c >= 'A' && c <= 'F') 300 return c-'A'+10; 301 return -1; 302} 303 304getfileinfo(w : ref Wrapped, f : string, rdigest : array of byte, wdigest : array of byte, ardigest: array of byte) : (int, int) 305{ 306 p : string; 307 308 if (w == nil) 309 return (-1, 0); 310 digest := array[keyring->MD5dlen] of { * => byte 0 }; 311 for (i := w.nu-1; i >= 0; i--){ 312 if ((p = bsearch(w.u[i].bmd5, f)) == nil) 313 continue; 314 if (p == nil) 315 continue; 316 k := 0; 317 while (k < len p && p[k] != ' ') 318 k++; 319 if (k == len p) 320 continue; 321 q := p[k+1:]; 322 if (q == nil) 323 continue; 324 if (len q != 2*Keyring->MD5dlen+1) 325 continue; 326 for (j := 0; j < Keyring->MD5dlen; j++) { 327 a := hex(q[2*j]); 328 b := hex(q[2*j+1]); 329 if (a < 0 || b < 0) 330 break; 331 digest[j] = byte ((a<<4)|b); 332 } 333 if(j != Keyring->MD5dlen) 334 continue; 335 if(rdigest == nil || memcmp(rdigest, digest, keyring->MD5dlen) == 0 || (ardigest != nil && memcmp(ardigest, digest, keyring->MD5dlen) == 0)) 336 break; 337 else 338 return (-1, 0); # NEW 339 } 340 if(i < 0) 341 return (-1, 0); 342 if(wdigest != nil) 343 wdigest[0:] = rdigest; 344 return (0, w.u[i].time); 345 346 347} 348 349bsearch(b : ref Bufio->Iobuf, p : string) : string 350{ 351 if (b == nil) 352 return nil; 353 lo := 0; 354 b.seek(big 0, Bufio->SEEKEND); 355 hi := int b.offset(); 356 l := len p; 357 while (lo < hi) { 358 m := (lo+hi)/2; 359 b.seek(big m, Bufio->SEEKSTART); 360 b.gets('\n'); 361 if (int b.offset() == hi) { 362 bgetbackc(b); 363 m = int b.offset(); 364 while (m-- > lo) { 365 if (bgetbackc(b) == '\n') { 366 b.getc(); 367 break; 368 } 369 } 370 } 371 s := b.gets('\n'); 372 if (len s >= l+1 && s[0:l] == p && (s[l] == ' ' || s[l] == '\n')) 373 return s; 374 if (s < p) 375 lo = int b.offset(); 376 else 377 hi = int b.offset()-len s; 378 } 379 return nil; 380} 381 382bgetbackc(b : ref Bufio->Iobuf) : int 383{ 384 m := int b.offset(); 385 b.seek(big (m-1), Bufio->SEEKSTART); 386 c := b.getc(); 387 b.ungetc(); 388 return c; 389} 390 391strstr(s : string, p : string) : int 392{ 393 lp := len p; 394 ls := len s; 395 for (i := 0; i < ls-lp; i++) 396 if (s[i:i+lp] == p) 397 return i; 398 return -1; 399} 400 401qsort(a : array of Update, n : int) 402{ 403 i, j : int; 404 t : Update; 405 406 while(n > 1) { 407 i = n>>1; 408 t = a[0]; a[0] = a[i]; a[i] = t; 409 i = 0; 410 j = n; 411 for(;;) { 412 do 413 i++; 414 while(i < n && a[i].time < a[0].time); 415 do 416 j--; 417 while(j > 0 && a[j].time > a[0].time); 418 if(j < i) 419 break; 420 t = a[i]; a[i] = a[j]; a[j] = t; 421 } 422 t = a[0]; a[0] = a[j]; a[j] = t; 423 n = n-j-1; 424 if(j >= n) { 425 qsort(a, j); 426 a = a[j+1:]; 427 } else { 428 qsort(a[j+1:], n); 429 n = j; 430 } 431 } 432} 433 434md5file(file : string, digest : array of byte) : int 435{ 436 (ok, d) := sys->stat(file); 437 if (ok < 0) 438 return -1; 439 if (d.mode & Sys->DMDIR) 440 return 0; 441 bio := bufio->open(file, Bufio->OREAD); 442 if (bio == nil) 443 return -1; 444 # return md5sum(bio, digest, d.length); 445 buff := array[Sys->ATOMICIO] of byte; 446 ds := keyring->md5(nil, 0, nil, nil); 447 while ((n := bio.read(buff, len buff)) > 0) 448 keyring->md5(buff, n, nil, ds); 449 keyring->md5(nil, 0, digest, ds); 450 bio = nil; 451 return 0; 452} 453 454md5sum(b : ref Iobuf, digest : array of byte, leng : int) : int 455{ 456 ds := keyring->md5(nil, 0, nil, nil); 457 buff := array[Sys->ATOMICIO] of byte; 458 while (leng > 0) { 459 if (leng > len buff) 460 n := len buff; 461 else 462 n = leng; 463 if ((n = b.read(buff, n)) <= 0) 464 return -1; 465 keyring->md5(buff, n, nil, ds); 466 leng -= n; 467 } 468 keyring->md5(nil, 0, digest, ds); 469 return 0; 470} 471 472md5conv(d : array of byte) : string 473{ 474 s : string = nil; 475 476 for (i := 0; i < keyring->MD5dlen; i++) 477 s += sys->sprint("%.2ux", int d[i]); 478 return s; 479} 480 481zd : Sys->Dir; 482 483newd(time : int, uid : string, gid : string) : ref Sys->Dir 484{ 485 d := ref Sys->Dir; 486 *d = zd; 487 d.uid = uid; 488 d.gid = gid; 489 d.mtime = time; 490 return d; 491} 492 493putwrapfile(b : ref Iobuf, name : string, time : int, elem : string, file : string, uid : string, gid : string) 494{ 495 d := newd(time, uid, gid); 496 d.mode = 8r444; 497 (ok, dir) := sys->stat(file); 498 if (ok < 0) 499 sys->fprint(sys->fildes(2), "cannot stat %s: %r", file); 500 d.length = dir.length; 501 # s := "/wrap/"+name+"/"+sys->sprint("%ud", time)+"/"+elem; 502 s := "/wrap/"+name+"/"+now2string(time, 0)+"/"+elem; 503 arch->puthdr(b, s, d); 504 arch->putfile(b, file, int d.length); 505} 506 507putwrap(b : ref Iobuf, name : string, time : int, desc : string, utime : int, pkg : int, uid : string, gid : string) 508{ 509 if (!(utime || pkg)) 510 sys->fprint(sys->fildes(2), "bad precondition in putwrap()"); 511 d := newd(time, uid, gid); 512 d.mode = Sys->DMDIR|8r775; 513 s := "/wrap"; 514 arch->puthdr(b, s, d); 515 s += "/"+name; 516 arch->puthdr(b, s, d); 517 # s += "/"+sys->sprint("%ud", time); 518 s += "/"+now2string(time, 0); 519 arch->puthdr(b, s, d); 520 d.mode = 8r444; 521 s += "/"; 522 dir := s; 523 if (utime) { 524 s = dir+"update"; 525 d.length = big 23; 526 arch->puthdr(b, s, d); 527 arch->putstring(b, sys->sprint("%22ud\n", utime)); 528 } 529 if (pkg) { 530 s = dir+"package"; 531 d.length = big 0; 532 arch->puthdr(b, s, d); 533 } 534 if (desc != nil) { 535 s = dir+"desc"; 536 d.length = big (len desc+1); 537 d.mode = 8r444; 538 arch->puthdr(b, s, d); 539 arch->putstring(b, desc+"\n"); 540 } 541} 542 543memcmp(b1, b2 : array of byte, n : int) : int 544{ 545 for (i := 0; i < n; i++) 546 if (b1[i] < b2[i]) 547 return -1; 548 else if (b1[i] > b2[i]) 549 return 1; 550 return 0; 551} 552 553strprefix(s: string, pre: string): int 554{ 555 return len s >= (l := len pre) && s[0:l] == pre; 556} 557 558match(s: string, pre: list of string): int 559{ 560 if(pre == nil || s == "/wrap" || strprefix(s, "/wrap/")) 561 return 1; 562 for( ; pre != nil; pre = tl pre) 563 if(strprefix(s, hd pre)) 564 return 1; 565 return 0; 566} 567 568notmatch(s: string, pre: list of string): int 569{ 570 if(pre == nil || s == "/wrap" || strprefix(s, "/wrap/")) 571 return 1; 572 for( ; pre != nil; pre = tl pre) 573 if(strprefix(s, hd pre)) 574 return 0; 575 return 1; 576} 577 578pathcat(s : string, t : string) : string 579{ 580 if (s == nil) return t; 581 if (t == nil) return s; 582 slashs := s[len s - 1] == '/'; 583 slasht := t[0] == '/'; 584 if (slashs && slasht) 585 return s + t[1:]; 586 if (!slashs && !slasht) 587 return s + "/" + t; 588 return s + t; 589} 590 591md5filea(file : string, digest : array of byte) : int 592{ 593 n, n0: int; 594 595 (ok, d) := sys->stat(file); 596 if (ok < 0) 597 return -1; 598 if (d.mode & Sys->DMDIR) 599 return 0; 600 bio := bufio->open(file, Bufio->OREAD); 601 if (bio == nil) 602 return -1; 603 buff := array[Sys->ATOMICIO] of byte; 604 m := len buff; 605 ds := keyring->md5(nil, 0, nil, nil); 606 r := 0; 607 while(1){ 608 if(r){ 609 if((n = bio.read(buff[1:], m-1)) <= 0) 610 break; 611 n++; 612 } 613 else{ 614 if ((n = bio.read(buff, m)) <= 0) 615 break; 616 } 617 (n0, r) = remcr(buff, n); 618 if(r){ 619 keyring->md5(buff, n0-1, nil, ds); 620 buff[0] = byte '\r'; 621 } 622 else 623 keyring->md5(buff, n0, nil, ds); 624 } 625 if(r) 626 keyring->md5(buff, 1, nil, ds); 627 keyring->md5(nil, 0, digest, ds); 628 bio = nil; 629 return 0; 630} 631 632remcr(b: array of byte, n: int): (int, int) 633{ 634 if(n == 0) 635 return (0, 0); 636 for(i := 0; i < n; ){ 637 if(b[i] == byte '\r' && i+1 < n && b[i+1] == byte '\n') 638 b[i:] = b[i+1:n--]; 639 else 640 i++; 641 } 642 return (n, b[n-1] == byte '\r'); 643} 644 645TEN2EIGHT: con 100000000; 646 647now2string(n: int, flag: int): string 648{ 649 if(flag == 0) 650 return sys->sprint("%ud", n); 651 if(n < 0) 652 return nil; 653 q := n/TEN2EIGHT; 654 s := "0" + string (n-TEN2EIGHT*q); 655 while(len s < 9) 656 s = "0" + s; 657 if(q <= 9) 658 s[0] = '0' + q - 0; 659 else if(q <= 21) 660 s[0] = 'A' + q - 10; 661 else 662 return nil; 663 return s; 664} 665 666string2now(s: string, flag: int): int 667{ 668 if(flag == 0 && s[0] != 'A') 669 return int s; 670 if(len s != 9) 671 return 0; 672 r := int s[1: ]; 673 c := s[0]; 674 if(c >= '0' && c <= '9') 675 q := c - '0' + 0; 676 else if(c >= 'A' && c <= 'L') 677 q = c - 'A' + 10; 678 else 679 return 0; 680 n := TEN2EIGHT*q + r; 681 if(n < 0) 682 return 0; 683 return n; 684} 685