github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/pack/ar.c (about) 1 // Inferno utils/iar/ar.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/iar/ar.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 /* 32 * ar - portable (ascii) format version 33 */ 34 35 /* protect a couple of our names */ 36 #define select your_select 37 #define rcmd your_rcmd 38 39 #include <u.h> 40 #include <libc.h> 41 #include <bio.h> 42 #include <mach.h> 43 #include "../../libmach/obj.h" 44 #include <ar.h> 45 46 #undef select 47 #undef rcmd 48 49 /* 50 * The algorithm uses up to 3 temp files. The "pivot member" is the 51 * archive member specified by and a, b, or i option. The temp files are 52 * astart - contains existing members up to and including the pivot member. 53 * amiddle - contains new files moved or inserted behind the pivot. 54 * aend - contains the existing members that follow the pivot member. 55 * When all members have been processed, function 'install' streams the 56 * temp files, in order, back into the archive. 57 */ 58 59 typedef struct Arsymref 60 { 61 char *name; 62 char *file; 63 int type; 64 int len; 65 vlong offset; 66 struct Arsymref *next; 67 } Arsymref; 68 69 typedef struct Armember /* Temp file entry - one per archive member */ 70 { 71 struct Armember *next; 72 struct ar_hdr hdr; 73 long size; 74 long date; 75 void *member; 76 } Armember; 77 78 typedef struct Arfile /* Temp file control block - one per tempfile */ 79 { 80 char *fname; /* paging file name */ 81 vlong size; 82 Armember *head; /* head of member chain */ 83 Armember *tail; /* tail of member chain */ 84 Arsymref *sym; /* head of defined symbol chain */ 85 } Arfile; 86 87 typedef struct Hashchain 88 { 89 char *name; 90 char *file; 91 struct Hashchain *next; 92 } Hashchain; 93 94 #define NHASH 1024 95 96 /* 97 * macro to portably read/write archive header. 98 * 'cmd' is read/write/Bread/Bwrite, etc. 99 */ 100 #define HEADER_IO(cmd, f, h) cmd(f, h.name, sizeof(h.name)) != sizeof(h.name)\ 101 || cmd(f, h.date, sizeof(h.date)) != sizeof(h.date)\ 102 || cmd(f, h.uid, sizeof(h.uid)) != sizeof(h.uid)\ 103 || cmd(f, h.gid, sizeof(h.gid)) != sizeof(h.gid)\ 104 || cmd(f, h.mode, sizeof(h.mode)) != sizeof(h.mode)\ 105 || cmd(f, h.size, sizeof(h.size)) != sizeof(h.size)\ 106 || cmd(f, h.fmag, sizeof(h.fmag)) != sizeof(h.fmag) 107 108 /* constants and flags */ 109 char *man = "mrxtdpq"; 110 char *opt = "uvnbailogS"; 111 char artemp[] = "/tmp/vXXXXX"; 112 char movtemp[] = "/tmp/v1XXXXX"; 113 char tailtemp[] = "/tmp/v2XXXXX"; 114 char symdef[] = "__.GOSYMDEF"; 115 char pkgdef[] = "__.PKGDEF"; 116 117 int aflag; /* command line flags */ 118 int bflag; 119 int cflag; 120 int gflag; 121 int oflag; 122 int uflag; 123 int vflag; 124 int Pflag; /* remove leading file prefix */ 125 int Sflag; /* force mark Go package as safe */ 126 127 int errors; 128 129 Arfile *astart, *amiddle, *aend; /* Temp file control block pointers */ 130 int allobj = 1; /* set when all members are object files of the same type */ 131 int symdefsize; /* size of symdef file */ 132 char *pkgstmt; /* string "package foo" */ 133 char *objhdr; /* string "go object darwin 386 release.2010-01-01 2345+" */ 134 int dupfound; /* flag for duplicate symbol */ 135 Hashchain *hash[NHASH]; /* hash table of text symbols */ 136 137 #define ARNAMESIZE sizeof(astart->tail->hdr.name) 138 139 char poname[ARNAMESIZE+1]; /* name of pivot member */ 140 char *file; /* current file or member being worked on */ 141 Biobuf bout; 142 Biobuf bar; 143 char *prefix; 144 int pkgdefsafe; /* was __.PKGDEF marked safe? */ 145 146 void arcopy(Biobuf*, Arfile*, Armember*); 147 int arcreate(char*); 148 void arfree(Arfile*); 149 void arinsert(Arfile*, Armember*); 150 void *armalloc(int); 151 char *arstrdup(char*); 152 void armove(Biobuf*, Arfile*, Armember*); 153 void arread(Biobuf*, Armember*); 154 void arstream(int, Arfile*); 155 int arwrite(int, Armember*); 156 int bamatch(char*, char*); 157 int duplicate(char*, char**); 158 Armember *getdir(Biobuf*); 159 void getpkgdef(char**, int*); 160 void install(char*, Arfile*, Arfile*, Arfile*, int); 161 void loadpkgdata(char*, int); 162 void longt(Armember*); 163 int match(int, char**); 164 void mesg(int, char*); 165 Arfile *newtempfile(char*); 166 Armember *newmember(void); 167 void objsym(Sym*, void*); 168 int openar(char*, int, int); 169 void pmode(long); 170 void rl(int); 171 void scanobj(Biobuf*, Arfile*, long); 172 void scanpkg(Biobuf*, long); 173 void select(int*, long); 174 void setcom(void(*)(char*, int, char**)); 175 void skip(Biobuf*, vlong); 176 void checksafe(Biobuf*, vlong); 177 int symcomp(void*, void*); 178 void trim(char*, char*, int); 179 void usage(void); 180 void wrerr(void); 181 void wrsym(Biobuf*, long, Arsymref*); 182 int arread_cutprefix(Biobuf*, Armember*); 183 184 void rcmd(char*, int, char**); /* command processing */ 185 void dcmd(char*, int, char**); 186 void xcmd(char*, int, char**); 187 void tcmd(char*, int, char**); 188 void pcmd(char*, int, char**); 189 void mcmd(char*, int, char**); 190 void qcmd(char*, int, char**); 191 void (*comfun)(char*, int, char**); 192 193 void 194 main(int argc, char *argv[]) 195 { 196 char *cp; 197 198 Binit(&bout, 1, OWRITE); 199 if(argc < 3) 200 usage(); 201 for (cp = argv[1]; *cp; cp++) { 202 switch(*cp) { 203 case 'a': aflag = 1; break; 204 case 'b': bflag = 1; break; 205 case 'c': cflag = 1; break; 206 case 'd': setcom(dcmd); break; 207 case 'g': gflag = 1; break; 208 case 'i': bflag = 1; break; 209 case 'l': 210 strcpy(artemp, "vXXXXX"); 211 strcpy(movtemp, "v1XXXXX"); 212 strcpy(tailtemp, "v2XXXXX"); 213 break; 214 case 'm': setcom(mcmd); break; 215 case 'o': oflag = 1; break; 216 case 'p': setcom(pcmd); break; 217 case 'q': setcom(qcmd); break; 218 case 'r': setcom(rcmd); break; 219 case 't': setcom(tcmd); break; 220 case 'u': uflag = 1; break; 221 case 'v': vflag = 1; break; 222 case 'x': setcom(xcmd); break; 223 case 'S': Sflag = 1; break; 224 case 'P': Pflag = 1; break; 225 default: 226 fprint(2, "pack: bad option `%c'\n", *cp); 227 exits("error"); 228 } 229 } 230 if (aflag && bflag) { 231 fprint(2, "pack: only one of 'a' and 'b' can be specified\n"); 232 usage(); 233 } 234 if(aflag || bflag) { 235 trim(argv[2], poname, sizeof(poname)); 236 argv++; 237 argc--; 238 if(argc < 3) 239 usage(); 240 } 241 if(Pflag) { 242 if(argc < 4) { 243 fprint(2, "pack: P flag requires prefix argument\n"); 244 usage(); 245 } 246 prefix = argv[2]; 247 argv++; 248 argc--; 249 } 250 if(comfun == 0) { 251 if(uflag == 0) { 252 fprint(2, "pack: one of [%s] must be specified\n", man); 253 usage(); 254 } 255 setcom(rcmd); 256 } 257 cp = argv[2]; 258 argc -= 3; 259 argv += 3; 260 (*comfun)(cp, argc, argv); /* do the command */ 261 if(errors && cflag) 262 remove(cp); 263 cp = 0; 264 while (argc--) { 265 if (*argv) { 266 fprint(2, "pack: %s not found\n", *argv); 267 cp = "error"; 268 } 269 argv++; 270 } 271 if (errors) 272 cp = "error"; 273 exits(cp); 274 } 275 /* 276 * select a command 277 */ 278 void 279 setcom(void (*fun)(char *, int, char**)) 280 { 281 282 if(comfun != 0) { 283 fprint(2, "pack: only one of [%s] allowed\n", man); 284 usage(); 285 } 286 comfun = fun; 287 } 288 /* 289 * perform the 'r' and 'u' commands 290 */ 291 void 292 rcmd(char *arname, int count, char **files) 293 { 294 int fd; 295 int i; 296 Arfile *ap; 297 Armember *bp; 298 Dir *d; 299 Biobuf *bfile; 300 301 fd = openar(arname, ORDWR, 1); 302 if (fd >= 0) { 303 Binit(&bar, fd, OREAD); 304 Bseek(&bar,seek(fd,0,1), 1); 305 } 306 astart = newtempfile(artemp); 307 ap = astart; 308 aend = 0; 309 for(i = 0; fd >= 0; i++) { 310 bp = getdir(&bar); 311 if (!bp) 312 break; 313 if (bamatch(file, poname)) { /* check for pivot */ 314 aend = newtempfile(tailtemp); 315 ap = aend; 316 } 317 /* pitch symdef file */ 318 if (i == 0 && strcmp(file, symdef) == 0) { 319 skip(&bar, bp->size); 320 continue; 321 } 322 /* pitch pkgdef file but remember whether it was marked safe */ 323 if (gflag && strcmp(file, pkgdef) == 0) { 324 checksafe(&bar, bp->size); 325 continue; 326 } 327 /* 328 * the plan 9 ar treats count == 0 as equivalent 329 * to listing all the archive's files on the command line: 330 * it will try to open every file name in the archive 331 * and copy that file into the archive if it exists. 332 * for go we disable that behavior, because we use 333 * r with no files to make changes to the archive itself, 334 * using the S or P flags. 335 */ 336 if (!match(count, files)) { 337 scanobj(&bar, ap, bp->size); 338 arcopy(&bar, ap, bp); 339 continue; 340 } 341 bfile = Bopen(file, OREAD); 342 if (!bfile) { 343 if (count != 0) { 344 fprint(2, "pack: cannot open %s\n", file); 345 errors++; 346 } 347 scanobj(&bar, ap, bp->size); 348 arcopy(&bar, ap, bp); 349 continue; 350 } 351 d = dirfstat(Bfildes(bfile)); 352 if(d == nil) 353 fprint(2, "pack: cannot stat %s: %r\n", file); 354 if (uflag && (d==nil || d->mtime <= bp->date)) { 355 scanobj(&bar, ap, bp->size); 356 arcopy(&bar, ap, bp); 357 Bterm(bfile); 358 free(d); 359 continue; 360 } 361 mesg('r', file); 362 skip(&bar, bp->size); 363 scanobj(bfile, ap, d->length); 364 free(d); 365 armove(bfile, ap, bp); 366 Bterm(bfile); 367 } 368 if(fd >= 0) 369 close(fd); 370 /* copy in remaining files named on command line */ 371 for (i = 0; i < count; i++) { 372 file = files[i]; 373 if(file == 0) 374 continue; 375 files[i] = 0; 376 bfile = Bopen(file, OREAD); 377 if (!bfile) { 378 fprint(2, "pack: cannot open %s\n", file); 379 errors++; 380 } else { 381 mesg('a', file); 382 d = dirfstat(Bfildes(bfile)); 383 if (d == nil) 384 fprint(2, "can't stat %s\n", file); 385 else { 386 scanobj(bfile, astart, d->length); 387 armove(bfile, astart, newmember()); 388 free(d); 389 } 390 Bterm(bfile); 391 } 392 } 393 if(fd < 0 && !cflag) 394 install(arname, astart, 0, aend, 1); /* issue 'creating' msg */ 395 else 396 install(arname, astart, 0, aend, 0); 397 } 398 399 void 400 dcmd(char *arname, int count, char **files) 401 { 402 Armember *bp; 403 int fd, i; 404 405 if (!count) 406 return; 407 fd = openar(arname, ORDWR, 0); 408 Binit(&bar, fd, OREAD); 409 Bseek(&bar,seek(fd,0,1), 1); 410 astart = newtempfile(artemp); 411 for (i = 0; bp = getdir(&bar); i++) { 412 if(match(count, files)) { 413 mesg('d', file); 414 skip(&bar, bp->size); 415 if (strcmp(file, symdef) == 0) 416 allobj = 0; 417 } else if (i == 0 && strcmp(file, symdef) == 0) { 418 skip(&bar, bp->size); 419 } else if (gflag && strcmp(file, pkgdef) == 0) { 420 skip(&bar, bp->size); 421 } else { 422 scanobj(&bar, astart, bp->size); 423 arcopy(&bar, astart, bp); 424 } 425 } 426 close(fd); 427 install(arname, astart, 0, 0, 0); 428 } 429 430 void 431 xcmd(char *arname, int count, char **files) 432 { 433 int fd, f, mode, i; 434 Armember *bp; 435 Dir dx; 436 437 fd = openar(arname, OREAD, 0); 438 Binit(&bar, fd, OREAD); 439 Bseek(&bar,seek(fd,0,1), 1); 440 i = 0; 441 while (bp = getdir(&bar)) { 442 if(count == 0 || match(count, files)) { 443 mode = strtoul(bp->hdr.mode, 0, 8) & 0777; 444 f = create(file, OWRITE, mode); 445 if(f < 0) { 446 fprint(2, "pack: %s cannot create\n", file); 447 skip(&bar, bp->size); 448 } else { 449 mesg('x', file); 450 arcopy(&bar, 0, bp); 451 if (write(f, bp->member, bp->size) < 0) 452 wrerr(); 453 if(oflag && bp->date != 0) { 454 nulldir(&dx); 455 dx.atime = bp->date; 456 dx.mtime = bp->date; 457 if(dirwstat(file, &dx) < 0) 458 perror(file); 459 } 460 free(bp->member); 461 close(f); 462 } 463 free(bp); 464 if (count && ++i >= count) 465 break; 466 } else { 467 skip(&bar, bp->size); 468 free(bp); 469 } 470 } 471 close(fd); 472 } 473 void 474 pcmd(char *arname, int count, char **files) 475 { 476 int fd; 477 Armember *bp; 478 479 fd = openar(arname, OREAD, 0); 480 Binit(&bar, fd, OREAD); 481 Bseek(&bar,seek(fd,0,1), 1); 482 while(bp = getdir(&bar)) { 483 if(count == 0 || match(count, files)) { 484 if(vflag) 485 print("\n<%s>\n\n", file); 486 arcopy(&bar, 0, bp); 487 if (write(1, bp->member, bp->size) < 0) 488 wrerr(); 489 } else 490 skip(&bar, bp->size); 491 free(bp); 492 } 493 close(fd); 494 } 495 void 496 mcmd(char *arname, int count, char **files) 497 { 498 int fd, i; 499 Arfile *ap; 500 Armember *bp; 501 502 if (count == 0) 503 return; 504 fd = openar(arname, ORDWR, 0); 505 Binit(&bar, fd, OREAD); 506 Bseek(&bar,seek(fd,0,1), 1); 507 astart = newtempfile(artemp); 508 amiddle = newtempfile(movtemp); 509 aend = 0; 510 ap = astart; 511 for (i = 0; bp = getdir(&bar); i++) { 512 if (bamatch(file, poname)) { 513 aend = newtempfile(tailtemp); 514 ap = aend; 515 } 516 if(match(count, files)) { 517 mesg('m', file); 518 scanobj(&bar, amiddle, bp->size); 519 arcopy(&bar, amiddle, bp); 520 } else if (ap == astart && i == 0 && strcmp(file, symdef) == 0) { 521 /* 522 * pitch the symdef file if it is at the beginning 523 * of the archive and we aren't inserting in front 524 * of it (ap == astart). 525 */ 526 skip(&bar, bp->size); 527 } else if (ap == astart && gflag && strcmp(file, pkgdef) == 0) { 528 /* 529 * pitch the pkgdef file if we aren't inserting in front 530 * of it (ap == astart). 531 */ 532 skip(&bar, bp->size); 533 } else { 534 scanobj(&bar, ap, bp->size); 535 arcopy(&bar, ap, bp); 536 } 537 } 538 close(fd); 539 if (poname[0] && aend == 0) 540 fprint(2, "pack: %s not found - files moved to end.\n", poname); 541 install(arname, astart, amiddle, aend, 0); 542 } 543 void 544 tcmd(char *arname, int count, char **files) 545 { 546 int fd; 547 Armember *bp; 548 char name[ARNAMESIZE+1]; 549 550 fd = openar(arname, OREAD, 0); 551 Binit(&bar, fd, OREAD); 552 Bseek(&bar,seek(fd,0,1), 1); 553 while(bp = getdir(&bar)) { 554 if(count == 0 || match(count, files)) { 555 if(vflag) 556 longt(bp); 557 trim(file, name, ARNAMESIZE); 558 Bprint(&bout, "%s\n", name); 559 } 560 skip(&bar, bp->size); 561 free(bp); 562 } 563 close(fd); 564 } 565 void 566 qcmd(char *arname, int count, char **files) 567 { 568 int fd, i; 569 Armember *bp; 570 Biobuf *bfile; 571 572 if(aflag || bflag) { 573 fprint(2, "pack: abi not allowed with q\n"); 574 exits("error"); 575 } 576 fd = openar(arname, ORDWR, 1); 577 if (fd < 0) { 578 if(!cflag) 579 fprint(2, "pack: creating %s\n", arname); 580 fd = arcreate(arname); 581 } 582 Binit(&bar, fd, OREAD); 583 Bseek(&bar,seek(fd,0,1), 1); 584 /* leave note group behind when writing archive; i.e. sidestep interrupts */ 585 rfork(RFNOTEG); 586 Bseek(&bar, 0, 2); 587 bp = newmember(); 588 for(i=0; i<count && files[i]; i++) { 589 file = files[i]; 590 files[i] = 0; 591 bfile = Bopen(file, OREAD); 592 if(!bfile) { 593 fprint(2, "pack: cannot open %s\n", file); 594 errors++; 595 } else { 596 mesg('q', file); 597 armove(bfile, 0, bp); 598 if (!arwrite(fd, bp)) 599 wrerr(); 600 free(bp->member); 601 bp->member = 0; 602 Bterm(bfile); 603 } 604 } 605 free(bp); 606 close(fd); 607 } 608 609 /* 610 * does the object header line p match the last one we saw? 611 * update *lastp if it gets more specific. 612 */ 613 int 614 matchhdr(char *p, char **lastp) 615 { 616 int n; 617 char *last; 618 619 // no information? 620 last = *lastp; 621 if(last == nil) { 622 *lastp = strdup(p); 623 return 1; 624 } 625 626 // identical match? 627 if(strcmp(last, p) == 0) 628 return 1; 629 630 // last has extra fields 631 n = strlen(p); 632 if(n < strlen(last) && last[n] == ' ') 633 return 1; 634 635 // p has extra fields - save in last 636 n = strlen(last); 637 if(n < strlen(p) && p[n] == ' ') { 638 free(last); 639 *lastp = strdup(p); 640 return 1; 641 } 642 643 return 0; 644 } 645 646 /* 647 * extract the symbol references from an object file 648 */ 649 void 650 scanobj(Biobuf *b, Arfile *ap, long size) 651 { 652 int obj, goobject; 653 vlong offset, offset1; 654 Dir *d; 655 static int lastobj = -1; 656 uchar buf[4]; 657 char *p; 658 659 if (!allobj) /* non-object file encountered */ 660 return; 661 offset = Boffset(b); 662 obj = objtype(b, 0); 663 if (obj < 0) { /* not an object file */ 664 /* maybe a foreign object file */ 665 Bseek(b, offset, 0); 666 memset(buf, 0, sizeof buf); 667 Bread(b, buf, 4); 668 669 /* maybe a foreign object file? that's okay */ 670 if((buf[0] == 0x7F && buf[1] == 'E' && buf[2] == 'L' && buf[3] == 'F') || // ELF 671 (buf[0] == 0x4c && buf[1] == 0x01 || buf[0] == 0x64 && buf[1] == 0x86) || // Windows PE 672 (buf[0] == 0xFE && buf[1] == 0xED && buf[2] == 0xFA && (buf[3]&~1) == 0xCE) || // Mach-O big-endian 673 (buf[3] == 0xFE && buf[2] == 0xED && buf[1] == 0xFA && (buf[0]&~1) == 0xCE)) { // Mach-O little-endian 674 Bseek(b, offset, 0); 675 return; 676 } 677 678 if (!gflag || strcmp(file, pkgdef) != 0) { /* don't clear allobj if it's pkg defs */ 679 fprint(2, "pack: non-object file %s\n", file); 680 errors++; 681 allobj = 0; 682 } 683 d = dirfstat(Bfildes(b)); 684 if (d != nil && d->length == 0) { 685 fprint(2, "pack: zero length file %s\n", file); 686 errors++; 687 } 688 free(d); 689 Bseek(b, offset, 0); 690 return; 691 } 692 693 goobject = 1; 694 offset1 = Boffset(b); 695 Bseek(b, offset, 0); 696 p = Brdstr(b, '\n', 1); 697 698 // After the go object header comes the Go metadata, 699 // followed by ! on a line by itself. If this is not a Go object, 700 // the ! comes immediately. Catch that so we can avoid 701 // the call to scanpkg below, since scanpkg assumes that the 702 // Go metadata is present. 703 if(Bgetc(b) == '!') 704 goobject = 0; 705 706 Bseek(b, offset1, 0); 707 if(p == nil || strncmp(p, "go object ", 10) != 0) { 708 fprint(2, "pack: malformed object file %s\n", file); 709 errors++; 710 Bseek(b, offset, 0); 711 free(p); 712 return; 713 } 714 715 if (!matchhdr(p, &objhdr)) { 716 fprint(2, "pack: inconsistent object file %s: [%s] vs [%s]\n", file, p, objhdr); 717 errors++; 718 allobj = 0; 719 free(p); 720 return; 721 } 722 free(p); 723 724 // Old check. Should be impossible since objhdrs match, but keep the check anyway. 725 if (lastobj >= 0 && obj != lastobj) { 726 fprint(2, "pack: inconsistent object file %s\n", file); 727 errors++; 728 allobj = 0; 729 return; 730 } 731 lastobj = obj; 732 733 if (!readar(b, obj, offset+size, 0)) { 734 fprint(2, "pack: invalid symbol reference in file %s\n", file); 735 errors++; 736 allobj = 0; 737 Bseek(b, offset, 0); 738 return; 739 } 740 Bseek(b, offset, 0); 741 objtraverse(objsym, ap); 742 if (gflag && goobject) { 743 scanpkg(b, size); 744 Bseek(b, offset, 0); 745 } 746 } 747 748 /* 749 * does line contain substring (length-limited) 750 */ 751 int 752 strstrn(char *line, int len, char *sub) 753 { 754 int i; 755 int sublen; 756 757 sublen = strlen(sub); 758 for (i = 0; i < len - sublen; i++) 759 if (memcmp(line+i, sub, sublen) == 0) 760 return 1; 761 return 0; 762 } 763 764 /* 765 * package import data 766 */ 767 int safe = 1; 768 char* pkgname; 769 char* importblock; 770 771 void 772 getpkgdef(char **datap, int *lenp) 773 { 774 char *tag, *hdr; 775 776 if(pkgname == nil) { 777 pkgname = "__emptyarchive__"; 778 importblock = ""; 779 } 780 781 tag = ""; 782 if(safe || Sflag) 783 tag = "safe"; 784 785 hdr = "empty archive"; 786 if(objhdr != nil) 787 hdr = objhdr; 788 789 *datap = smprint("%s\nimport\n$$\npackage %s %s\n%s\n$$\n", hdr, pkgname, tag, importblock); 790 *lenp = strlen(*datap); 791 } 792 793 /* 794 * extract the package definition data from an object file. 795 * there can be only one. 796 */ 797 void 798 scanpkg(Biobuf *b, long size) 799 { 800 long n; 801 int c; 802 long start, end, pkgsize; 803 char *data, *line, pkgbuf[1024], *pkg; 804 int first; 805 806 /* 807 * scan until $$ 808 */ 809 for (n=0; n<size; ) { 810 c = Bgetc(b); 811 if(c == Beof) 812 break; 813 n++; 814 if(c != '$') 815 continue; 816 c = Bgetc(b); 817 if(c == Beof) 818 break; 819 n++; 820 if(c != '$') 821 continue; 822 goto foundstart; 823 } 824 // fprint(2, "pack: warning: no package import section in %s\n", file); 825 if(b != &bar || !pkgdefsafe) 826 safe = 0; // non-Go file (C or assembly) 827 return; 828 829 foundstart: 830 /* found $$; skip rest of line */ 831 while((c = Bgetc(b)) != '\n') 832 if(c == Beof) 833 goto bad; 834 835 /* how big is it? */ 836 first = 1; 837 start = end = 0; 838 for (n=0; n<size; n+=Blinelen(b)) { 839 line = Brdstr(b, '\n', 0); 840 if (line == nil) 841 goto bad; 842 if (first && strstrn(line, Blinelen(b), "package ")) { 843 if (Blinelen(b) > sizeof(pkgbuf)-1) 844 goto bad; 845 memmove(pkgbuf, line, Blinelen(b)); 846 pkgbuf[Blinelen(b)] = '\0'; 847 pkg = pkgbuf; 848 while(*pkg == ' ' || *pkg == '\t') 849 pkg++; 850 if(strncmp(pkg, "package ", 8) != 0) 851 goto bad; 852 pkg += 8; 853 data = pkg; 854 while(*pkg != ' ' && *pkg != '\n' && *pkg != '\0') 855 pkg++; 856 pkgname = armalloc(pkg - data + 1); 857 memmove(pkgname, data, pkg - data); 858 pkgname[pkg-data] = '\0'; 859 if(strcmp(pkg, " safe\n") != 0 && (b != &bar || !pkgdefsafe)) 860 safe = 0; 861 start = Boffset(b); // after package statement 862 first = 0; 863 free(line); 864 continue; 865 } 866 if(line[0] == '$' && line[1] == '$') { 867 free(line); 868 goto foundend; 869 } 870 end = Boffset(b); // before closing $$ 871 free(line); 872 } 873 bad: 874 fprint(2, "pack: bad package import section in %s\n", file); 875 errors++; 876 return; 877 878 foundend: 879 if (start == 0) 880 return; 881 if (end == 0) 882 goto bad; 883 if(importblock != nil) { 884 fprint(2, "pack: multiple Go object files\n"); 885 errors++; 886 return; 887 } 888 pkgsize = end-start; 889 data = armalloc(end - start + 1); 890 Bseek(b, start, 0); 891 if (Bread(b, data, pkgsize) != pkgsize) { 892 fprint(2, "pack: error reading package import section in %s\n", file); 893 errors++; 894 return; 895 } 896 data[end-start] = '\0'; 897 importblock = data; 898 } 899 900 /* 901 * add text and data symbols to the symbol list 902 */ 903 void 904 objsym(Sym *s, void *p) 905 { 906 int n; 907 Arsymref *as; 908 Arfile *ap; 909 char *ofile; 910 911 if (s->type != 'T' && s->type != 'D') 912 return; 913 ap = (Arfile*)p; 914 as = armalloc(sizeof(Arsymref)); 915 as->offset = ap->size; 916 as->name = arstrdup(s->name); 917 as->file = arstrdup(file); 918 if(s->type == 'T' && duplicate(as->name, &ofile)) { 919 dupfound = 1; 920 fprint(2, "duplicate text symbol: %s and %s: %s\n", as->file, ofile, as->name); 921 errors++; 922 free(as->name); 923 free(as); 924 return; 925 } 926 as->type = s->type; 927 n = strlen(s->name); 928 symdefsize += 4+(n+1)+1; 929 as->len = n; 930 as->next = ap->sym; 931 ap->sym = as; 932 } 933 934 /* 935 * Check the symbol table for duplicate text symbols 936 */ 937 int 938 hashstr(char *name) 939 { 940 int h; 941 char *cp; 942 943 h = 0; 944 for(cp = name; *cp; h += *cp++) 945 h *= 1119; 946 947 // the code used to say 948 // if(h < 0) 949 // h = ~h; 950 // but on gcc 4.3 with -O2 on some systems, 951 // the if(h < 0) gets compiled away as not possible. 952 // use a mask instead, leaving plenty of bits but 953 // definitely not the sign bit. 954 955 return h & 0xfffffff; 956 } 957 958 int 959 duplicate(char *name, char **ofile) 960 { 961 Hashchain *p; 962 int h; 963 964 h = hashstr(name) % NHASH; 965 966 for(p = hash[h]; p; p = p->next) 967 if(strcmp(p->name, name) == 0) { 968 *ofile = p->file; 969 return 1; 970 } 971 p = armalloc(sizeof(Hashchain)); 972 p->next = hash[h]; 973 p->name = name; 974 p->file = file; 975 hash[h] = p; 976 *ofile = nil; 977 return 0; 978 } 979 980 /* 981 * open an archive and validate its header 982 */ 983 int 984 openar(char *arname, int mode, int errok) 985 { 986 int fd; 987 char mbuf[SARMAG]; 988 989 fd = open(arname, mode); 990 if(fd >= 0){ 991 if(read(fd, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) { 992 fprint(2, "pack: %s not in archive format\n", arname); 993 exits("error"); 994 } 995 }else if(!errok){ 996 fprint(2, "pack: cannot open %s: %r\n", arname); 997 exits("error"); 998 } 999 return fd; 1000 } 1001 1002 /* 1003 * create an archive and set its header 1004 */ 1005 int 1006 arcreate(char *arname) 1007 { 1008 int fd; 1009 1010 fd = create(arname, OWRITE, 0664); 1011 if(fd < 0){ 1012 fprint(2, "pack: cannot create %s: %r\n", arname); 1013 exits("error"); 1014 } 1015 if(write(fd, ARMAG, SARMAG) != SARMAG) 1016 wrerr(); 1017 return fd; 1018 } 1019 1020 /* 1021 * error handling 1022 */ 1023 void 1024 wrerr(void) 1025 { 1026 perror("pack: write error"); 1027 exits("error"); 1028 } 1029 1030 void 1031 rderr(void) 1032 { 1033 perror("pack: read error"); 1034 exits("error"); 1035 } 1036 1037 void 1038 phaseerr(int offset) 1039 { 1040 fprint(2, "pack: phase error at offset %d\n", offset); 1041 exits("error"); 1042 } 1043 1044 void 1045 usage(void) 1046 { 1047 fprint(2, "usage: pack [%s][%s][P prefix] archive files ...\n", opt, man); 1048 exits("error"); 1049 } 1050 1051 /* 1052 * read the header for the next archive member 1053 */ 1054 Armember * 1055 getdir(Biobuf *b) 1056 { 1057 Armember *bp; 1058 char *cp; 1059 static char name[ARNAMESIZE+1]; 1060 1061 bp = newmember(); 1062 if(HEADER_IO(Bread, b, bp->hdr)) { 1063 free(bp); 1064 return 0; 1065 } 1066 if(strncmp(bp->hdr.fmag, ARFMAG, sizeof(bp->hdr.fmag))) 1067 phaseerr(Boffset(b)); 1068 strncpy(name, bp->hdr.name, sizeof(bp->hdr.name)); 1069 cp = name+sizeof(name)-1; 1070 while(*--cp==' ') 1071 ; 1072 cp[1] = '\0'; 1073 file = arstrdup(name); 1074 bp->date = strtol(bp->hdr.date, 0, 0); 1075 bp->size = strtol(bp->hdr.size, 0, 0); 1076 return bp; 1077 } 1078 1079 /* 1080 * Copy the file referenced by fd to the temp file 1081 */ 1082 void 1083 armove(Biobuf *b, Arfile *ap, Armember *bp) 1084 { 1085 char *cp; 1086 Dir *d; 1087 vlong n; 1088 1089 d = dirfstat(Bfildes(b)); 1090 if (d == nil) { 1091 fprint(2, "pack: cannot stat %s\n", file); 1092 return; 1093 } 1094 1095 trim(file, bp->hdr.name, sizeof(bp->hdr.name)); 1096 for (cp = strchr(bp->hdr.name, 0); /* blank pad on right */ 1097 cp < bp->hdr.name+sizeof(bp->hdr.name); cp++) 1098 *cp = ' '; 1099 sprint(bp->hdr.date, "%-12ld", 0L); // was d->mtime but removed for idempotent builds 1100 sprint(bp->hdr.uid, "%-6d", 0); 1101 sprint(bp->hdr.gid, "%-6d", 0); 1102 sprint(bp->hdr.mode, "%-8lo", d->mode); 1103 sprint(bp->hdr.size, "%-10lld", d->length); 1104 strncpy(bp->hdr.fmag, ARFMAG, 2); 1105 bp->size = d->length; 1106 arread(b, bp); 1107 n = bp->size; 1108 if (n&1) 1109 n++; 1110 if (ap) { 1111 arinsert(ap, bp); 1112 ap->size += n+SAR_HDR; 1113 } 1114 free(d); 1115 } 1116 1117 /* 1118 * Copy the archive member at the current offset into the temp file. 1119 */ 1120 void 1121 arcopy(Biobuf *b, Arfile *ap, Armember *bp) 1122 { 1123 long n; 1124 1125 arread(b, bp); 1126 n = bp->size; 1127 if (n & 01) 1128 n++; 1129 if (ap) { 1130 arinsert(ap, bp); 1131 ap->size += n+SAR_HDR; 1132 } 1133 } 1134 1135 /* 1136 * Skip an archive member 1137 */ 1138 void 1139 skip(Biobuf *bp, vlong len) 1140 { 1141 if (len & 01) 1142 len++; 1143 Bseek(bp, len, 1); 1144 } 1145 1146 void 1147 checksafe(Biobuf *bp, vlong len) 1148 { 1149 char *p; 1150 vlong end; 1151 1152 if (len & 01) 1153 len++; 1154 end = Boffset(bp) + len; 1155 1156 p = Brdline(bp, '\n'); 1157 if(p == nil || strncmp(p, "go object ", 10) != 0) 1158 goto done; 1159 for(;;) { 1160 p = Brdline(bp, '\n'); 1161 if(p == nil || Boffset(bp) >= end) 1162 goto done; 1163 if(strncmp(p, "$$\n", 3) == 0) 1164 break; 1165 } 1166 p = Brdline(bp, '\n'); 1167 if(p == nil || Boffset(bp) > end) 1168 goto done; 1169 if(Blinelen(bp) > 8+6 && strncmp(p, "package ", 8) == 0 && strncmp(p+Blinelen(bp)-6, " safe\n", 6) == 0) 1170 pkgdefsafe = 1; 1171 1172 done: 1173 Bseek(bp, end, 0); 1174 } 1175 1176 /* 1177 * Stream the three temp files to an archive 1178 */ 1179 void 1180 install(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend, int createflag) 1181 { 1182 int fd; 1183 1184 if(allobj && dupfound) { 1185 fprint(2, "%s not changed\n", arname); 1186 return; 1187 } 1188 /* leave note group behind when copying back; i.e. sidestep interrupts */ 1189 rfork(RFNOTEG); 1190 1191 if(createflag) 1192 fprint(2, "pack: creating %s\n", arname); 1193 fd = arcreate(arname); 1194 1195 if(allobj) 1196 rl(fd); 1197 1198 if (astart) { 1199 arstream(fd, astart); 1200 arfree(astart); 1201 } 1202 if (amiddle) { 1203 arstream(fd, amiddle); 1204 arfree(amiddle); 1205 } 1206 if (aend) { 1207 arstream(fd, aend); 1208 arfree(aend); 1209 } 1210 close(fd); 1211 } 1212 1213 void 1214 rl(int fd) 1215 { 1216 Biobuf b; 1217 char *cp; 1218 struct ar_hdr a; 1219 long len; 1220 int headlen; 1221 char *pkgdefdata; 1222 int pkgdefsize; 1223 1224 pkgdefdata = nil; 1225 pkgdefsize = 0; 1226 1227 Binit(&b, fd, OWRITE); 1228 Bseek(&b,seek(fd,0,1), 0); 1229 1230 len = symdefsize; 1231 if(len&01) 1232 len++; 1233 sprint(a.date, "%-12ld", 0L); // time(0) 1234 sprint(a.uid, "%-6d", 0); 1235 sprint(a.gid, "%-6d", 0); 1236 sprint(a.mode, "%-8lo", 0644L); 1237 sprint(a.size, "%-10ld", len); 1238 strncpy(a.fmag, ARFMAG, 2); 1239 strcpy(a.name, symdef); 1240 for (cp = strchr(a.name, 0); /* blank pad on right */ 1241 cp < a.name+sizeof(a.name); cp++) 1242 *cp = ' '; 1243 if(HEADER_IO(Bwrite, &b, a)) 1244 wrerr(); 1245 1246 headlen = Boffset(&b); 1247 len += headlen; 1248 if (gflag) { 1249 getpkgdef(&pkgdefdata, &pkgdefsize); 1250 len += SAR_HDR + pkgdefsize; 1251 if (len & 1) 1252 len++; 1253 } 1254 if (astart) { 1255 wrsym(&b, len, astart->sym); 1256 len += astart->size; 1257 } 1258 if(amiddle) { 1259 wrsym(&b, len, amiddle->sym); 1260 len += amiddle->size; 1261 } 1262 if(aend) 1263 wrsym(&b, len, aend->sym); 1264 1265 if(symdefsize&0x01) 1266 Bputc(&b, 0); 1267 1268 if (gflag) { 1269 len = pkgdefsize; 1270 sprint(a.date, "%-12ld", 0L); // time(0) 1271 sprint(a.uid, "%-6d", 0); 1272 sprint(a.gid, "%-6d", 0); 1273 sprint(a.mode, "%-8lo", 0644L); 1274 sprint(a.size, "%-10ld", (len + 1) & ~1); 1275 strncpy(a.fmag, ARFMAG, 2); 1276 strcpy(a.name, pkgdef); 1277 for (cp = strchr(a.name, 0); /* blank pad on right */ 1278 cp < a.name+sizeof(a.name); cp++) 1279 *cp = ' '; 1280 if(HEADER_IO(Bwrite, &b, a)) 1281 wrerr(); 1282 1283 if (Bwrite(&b, pkgdefdata, pkgdefsize) != pkgdefsize) 1284 wrerr(); 1285 if(len&0x01) 1286 Bputc(&b, 0); 1287 } 1288 Bterm(&b); 1289 } 1290 1291 /* 1292 * Write the defined symbols to the symdef file 1293 */ 1294 void 1295 wrsym(Biobuf *bp, long offset, Arsymref *as) 1296 { 1297 int off; 1298 1299 while(as) { 1300 Bputc(bp, as->type); 1301 off = as->offset+offset; 1302 Bputc(bp, off); 1303 Bputc(bp, off>>8); 1304 Bputc(bp, off>>16); 1305 Bputc(bp, off>>24); 1306 if (Bwrite(bp, as->name, as->len+1) != as->len+1) 1307 wrerr(); 1308 as = as->next; 1309 } 1310 } 1311 1312 /* 1313 * Check if the archive member matches an entry on the command line. 1314 */ 1315 int 1316 match(int count, char **files) 1317 { 1318 int i; 1319 char name[ARNAMESIZE+1]; 1320 1321 for(i=0; i<count; i++) { 1322 if(files[i] == 0) 1323 continue; 1324 trim(files[i], name, ARNAMESIZE); 1325 if(strncmp(name, file, ARNAMESIZE) == 0) { 1326 file = files[i]; 1327 files[i] = 0; 1328 return 1; 1329 } 1330 } 1331 return 0; 1332 } 1333 1334 /* 1335 * compare the current member to the name of the pivot member 1336 */ 1337 int 1338 bamatch(char *file, char *pivot) 1339 { 1340 static int state = 0; 1341 1342 switch(state) 1343 { 1344 case 0: /* looking for position file */ 1345 if (aflag) { 1346 if (strncmp(file, pivot, ARNAMESIZE) == 0) 1347 state = 1; 1348 } else if (bflag) { 1349 if (strncmp(file, pivot, ARNAMESIZE) == 0) { 1350 state = 2; /* found */ 1351 return 1; 1352 } 1353 } 1354 break; 1355 case 1: /* found - after previous file */ 1356 state = 2; 1357 return 1; 1358 case 2: /* already found position file */ 1359 break; 1360 } 1361 return 0; 1362 } 1363 1364 /* 1365 * output a message, if 'v' option was specified 1366 */ 1367 void 1368 mesg(int c, char *file) 1369 { 1370 1371 if(vflag) 1372 Bprint(&bout, "%c - %s\n", c, file); 1373 } 1374 1375 /* 1376 * isolate file name by stripping leading directories and trailing slashes 1377 */ 1378 void 1379 trim(char *s, char *buf, int n) 1380 { 1381 char *p, *q; 1382 1383 for(;;) { 1384 p = strrchr(s, '/'); 1385 q = strrchr(s, '\\'); 1386 if (q > p) 1387 p = q; 1388 if (!p) { /* no (back)slash in name */ 1389 strncpy(buf, s, n); 1390 return; 1391 } 1392 if (p[1] != 0) { /* p+1 is first char of file name */ 1393 strncpy(buf, p+1, n); 1394 return; 1395 } 1396 *p = 0; /* strip trailing (back)slash */ 1397 } 1398 } 1399 1400 /* 1401 * utilities for printing long form of 't' command 1402 */ 1403 #define SUID 04000 1404 #define SGID 02000 1405 #define ROWN 0400 1406 #define WOWN 0200 1407 #define XOWN 0100 1408 #define RGRP 040 1409 #define WGRP 020 1410 #define XGRP 010 1411 #define ROTH 04 1412 #define WOTH 02 1413 #define XOTH 01 1414 #define STXT 01000 1415 1416 void 1417 longt(Armember *bp) 1418 { 1419 char *cp; 1420 1421 pmode(strtoul(bp->hdr.mode, 0, 8)); 1422 Bprint(&bout, "%3ld/%1ld", strtol(bp->hdr.uid, 0, 0), strtol(bp->hdr.gid, 0, 0)); 1423 Bprint(&bout, "%7ld", bp->size); 1424 cp = ctime(bp->date); 1425 Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24); 1426 } 1427 1428 int m1[] = { 1, ROWN, 'r', '-' }; 1429 int m2[] = { 1, WOWN, 'w', '-' }; 1430 int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 1431 int m4[] = { 1, RGRP, 'r', '-' }; 1432 int m5[] = { 1, WGRP, 'w', '-' }; 1433 int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 1434 int m7[] = { 1, ROTH, 'r', '-' }; 1435 int m8[] = { 1, WOTH, 'w', '-' }; 1436 int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 1437 1438 int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 1439 1440 void 1441 pmode(long mode) 1442 { 1443 int **mp; 1444 1445 for(mp = &m[0]; mp < &m[9];) 1446 select(*mp++, mode); 1447 } 1448 1449 void 1450 select(int *ap, long mode) 1451 { 1452 int n; 1453 1454 n = *ap++; 1455 while(--n>=0 && (mode&*ap++)==0) 1456 ap++; 1457 Bputc(&bout, *ap); 1458 } 1459 1460 /* 1461 * Temp file I/O subsystem. We attempt to cache all three temp files in 1462 * core. When we run out of memory we spill to disk. 1463 * The I/O model assumes that temp files: 1464 * 1) are only written on the end 1465 * 2) are only read from the beginning 1466 * 3) are only read after all writing is complete. 1467 * The architecture uses one control block per temp file. Each control 1468 * block anchors a chain of buffers, each containing an archive member. 1469 */ 1470 Arfile * 1471 newtempfile(char *name) /* allocate a file control block */ 1472 { 1473 Arfile *ap; 1474 1475 ap = armalloc(sizeof(Arfile)); 1476 ap->fname = name; 1477 return ap; 1478 } 1479 1480 Armember * 1481 newmember(void) /* allocate a member buffer */ 1482 { 1483 return armalloc(sizeof(Armember)); 1484 } 1485 1486 void 1487 arread(Biobuf *b, Armember *bp) /* read an image into a member buffer */ 1488 { 1489 int i; 1490 vlong off; 1491 1492 bp->member = armalloc(bp->size); 1493 1494 // If P flag is set, let arread_cutprefix try. 1495 // If it succeeds, we're done. If not, fall back 1496 // to a direct copy. 1497 off = Boffset(b); 1498 if(Pflag && arread_cutprefix(b, bp)) 1499 return; 1500 Bseek(b, off, 0); 1501 1502 i = Bread(b, bp->member, bp->size); 1503 if (i < 0) { 1504 free(bp->member); 1505 bp->member = 0; 1506 rderr(); 1507 } 1508 if(bp->size&1) 1509 Bgetc(b); 1510 } 1511 1512 /* 1513 * insert a member buffer into the member chain 1514 */ 1515 void 1516 arinsert(Arfile *ap, Armember *bp) 1517 { 1518 bp->next = 0; 1519 if (!ap->tail) 1520 ap->head = bp; 1521 else 1522 ap->tail->next = bp; 1523 ap->tail = bp; 1524 } 1525 1526 /* 1527 * stream the members in a temp file to the file referenced by 'fd'. 1528 */ 1529 void 1530 arstream(int fd, Arfile *ap) 1531 { 1532 Armember *bp; 1533 1534 /* dump the in-core buffers */ 1535 for (bp = ap->head; bp; bp = bp->next) { 1536 if (!arwrite(fd, bp)) 1537 wrerr(); 1538 } 1539 } 1540 1541 /* 1542 * write a member to 'fd'. 1543 */ 1544 int 1545 arwrite(int fd, Armember *bp) 1546 { 1547 int len; 1548 1549 if(HEADER_IO(write, fd, bp->hdr)) 1550 return 0; 1551 len = bp->size; 1552 if (len & 01) 1553 len++; 1554 if (write(fd, bp->member, len) != len) 1555 return 0; 1556 return 1; 1557 } 1558 1559 void 1560 arfree(Arfile *ap) /* free a member buffer */ 1561 { 1562 Armember *bp, *next; 1563 1564 for (bp = ap->head; bp; bp = next) { 1565 next = bp->next; 1566 if (bp->member) 1567 free(bp->member); 1568 free(bp); 1569 } 1570 free(ap); 1571 } 1572 1573 /* 1574 * allocate space for a control block or member buffer. if the malloc 1575 * fails we try to reclaim space by spilling previously allocated 1576 * member buffers. 1577 */ 1578 void * 1579 armalloc(int n) 1580 { 1581 char *cp; 1582 1583 // bump so that arwrite can do the same 1584 if(n&1) 1585 n++; 1586 1587 cp = malloc(n); 1588 if (cp) { 1589 memset(cp, 0, n); 1590 return cp; 1591 } 1592 fprint(2, "pack: out of memory\n"); 1593 exits("malloc"); 1594 return 0; 1595 } 1596 1597 char * 1598 arstrdup(char *s) 1599 { 1600 char *t; 1601 1602 t = armalloc(strlen(s) + 1); 1603 strcpy(t, s); 1604 return t; 1605 } 1606 1607 1608 /* 1609 * Parts of libmach we're not supposed 1610 * to look at but need for arread_cutprefix. 1611 */ 1612 extern int _read5(Biobuf*, Prog*); 1613 extern int _read6(Biobuf*, Prog*); 1614 extern int _read8(Biobuf*, Prog*); 1615 int (*reader[256])(Biobuf*, Prog*) = { 1616 [ObjArm] = _read5, 1617 [ObjAmd64] = _read6, 1618 [Obj386] = _read8, 1619 }; 1620 1621 /* 1622 * copy b into bp->member but rewrite object 1623 * during copy to drop prefix from all file names. 1624 * return 1 if b was recognized as an object file 1625 * and copied successfully, 0 otherwise. 1626 */ 1627 int 1628 arread_cutprefix(Biobuf *b, Armember *bp) 1629 { 1630 vlong offset, o, end; 1631 int n, t; 1632 int (*rd)(Biobuf*, Prog*); 1633 char *w, *inprefix; 1634 Prog p; 1635 1636 offset = Boffset(b); 1637 end = offset + bp->size; 1638 t = objtype(b, nil); 1639 if(t < 0) 1640 return 0; 1641 if((rd = reader[t]) == nil) 1642 return 0; 1643 1644 // copy header 1645 w = bp->member; 1646 n = Boffset(b) - offset; 1647 Bseek(b, -n, 1); 1648 if(Bread(b, w, n) != n) 1649 return 0; 1650 offset += n; 1651 w += n; 1652 1653 // read object file one pseudo-instruction at a time, 1654 // eliding the file name instructions that refer to 1655 // the prefix. 1656 memset(&p, 0, sizeof p); 1657 inprefix = nil; 1658 while(Boffset(b) < end && rd(b, &p)) { 1659 if(p.kind == aName && p.type == UNKNOWN && p.sym == 1 && p.id[0] == '<') { 1660 // part of a file path. 1661 // we'll keep continuing (skipping the copy) 1662 // around the loop until either we get to a 1663 // name piece that should be kept or we see 1664 // the whole prefix. 1665 1666 if(inprefix == nil && prefix[0] == '/' && p.id[1] == '/' && p.id[2] == '\0') { 1667 // leading / 1668 inprefix = prefix+1; 1669 } else if(inprefix != nil) { 1670 // handle subsequent elements 1671 n = strlen(p.id+1); 1672 if(strncmp(p.id+1, inprefix, n) == 0 && (inprefix[n] == '/' || inprefix[n] == '\0')) { 1673 inprefix += n; 1674 if(inprefix[0] == '/') 1675 inprefix++; 1676 } 1677 } 1678 1679 if(inprefix && inprefix[0] == '\0') { 1680 // reached end of prefix. 1681 // if we another path element follows, 1682 // nudge the offset to skip over the prefix we saw. 1683 // if not, leave offset alone, to emit the whole name. 1684 // additional name elements will not be skipped 1685 // because inprefix is now nil and we won't see another 1686 // leading / in this name. 1687 inprefix = nil; 1688 o = Boffset(b); 1689 if(o < end && rd(b, &p) && p.kind == aName && p.type == UNKNOWN && p.sym == 1 && p.id[0] == '<') { 1690 // print("skip %lld-%lld\n", offset, o); 1691 offset = o; 1692 } 1693 } 1694 } else { 1695 // didn't find the whole prefix. 1696 // give up and let it emit the entire name. 1697 inprefix = nil; 1698 } 1699 1700 // copy instructions 1701 if(!inprefix) { 1702 n = Boffset(b) - offset; 1703 Bseek(b, -n, 1); 1704 if(Bread(b, w, n) != n) 1705 return 0; 1706 offset += n; 1707 w += n; 1708 } 1709 } 1710 bp->size = w - (char*)bp->member; 1711 sprint(bp->hdr.size, "%-10lld", (vlong)bp->size); 1712 strncpy(bp->hdr.fmag, ARFMAG, 2); 1713 Bseek(b, end, 0); 1714 if(Boffset(b)&1) 1715 Bgetc(b); 1716 return 1; 1717 }