1 /* 2 * tar - `tape archiver', actually usable on any medium. 3 * POSIX "ustar" compliant when extracting, and by default when creating. 4 * this tar attempts to read and write multiple Tblock-byte blocks 5 * at once to and from the filesystem, and does not copy blocks 6 * around internally. 7 */ 8 9 #include <u.h> 10 #include <libc.h> 11 #include <fcall.h> /* for %M */ 12 #include <String.h> 13 14 /* 15 * modified versions of those in libc.h; scans only the first arg for 16 * keyletters and options. 17 */ 18 #define TARGBEGIN {\ 19 (argv0 || (argv0 = *argv)), argv++, argc--;\ 20 if (argv[0]) {\ 21 char *_args, *_argt;\ 22 Rune _argc;\ 23 _args = &argv[0][0];\ 24 _argc = 0;\ 25 while(*_args && (_args += chartorune(&_argc, _args)))\ 26 switch(_argc) 27 #define TARGEND SET(_argt); USED(_argt);USED(_argc);USED(_args); \ 28 argc--, argv++; } \ 29 USED(argv); USED(argc); } 30 #define TARGC() (_argc) 31 32 #define ROUNDUP(a, b) (((a) + (b) - 1)/(b)) 33 #define BYTES2TBLKS(bytes) ROUNDUP(bytes, Tblock) 34 35 typedef vlong Off; 36 typedef char *(*Refill)(int ar, char *bufs, int justhdr); 37 38 enum { Stdin, Stdout, Stderr }; 39 enum { Rd, Wr }; /* pipe fd-array indices */ 40 enum { Output, Input }; 41 enum { None, Toc, Xtract, Replace }; 42 enum { Alldata, Justnxthdr }; 43 enum { 44 Tblock = 512, 45 Nblock = 40, /* maximum blocksize */ 46 Dblock = 20, /* default blocksize */ 47 Namsiz = 100, 48 Maxpfx = 155, /* from POSIX */ 49 Maxname = Namsiz + 1 + Maxpfx, 50 DEBUG = 0, 51 }; 52 53 /* POSIX link flags */ 54 enum { 55 LF_PLAIN1 = '\0', 56 LF_PLAIN2 = '0', 57 LF_LINK = '1', 58 LF_SYMLINK1 = '2', 59 LF_SYMLINK2 = 's', 60 LF_CHR = '3', 61 LF_BLK = '4', 62 LF_DIR = '5', 63 LF_FIFO = '6', 64 LF_CONTIG = '7', 65 /* 'A' - 'Z' are reserved for custom implementations */ 66 }; 67 68 #define islink(lf) (isreallink(lf) || issymlink(lf)) 69 #define isreallink(lf) ((lf) == LF_LINK) 70 #define issymlink(lf) ((lf) == LF_SYMLINK1 || (lf) == LF_SYMLINK2) 71 72 typedef union { 73 uchar data[Tblock]; 74 struct { 75 char name[Namsiz]; 76 char mode[8]; 77 char uid[8]; 78 char gid[8]; 79 char size[12]; 80 char mtime[12]; 81 char chksum[8]; 82 char linkflag; 83 char linkname[Namsiz]; 84 85 /* rest are defined by POSIX's ustar format; see p1003.2b */ 86 char magic[6]; /* "ustar" */ 87 char version[2]; 88 char uname[32]; 89 char gname[32]; 90 char devmajor[8]; 91 char devminor[8]; 92 char prefix[Maxpfx]; /* if non-null, path= prefix "/" name */ 93 }; 94 } Hdr; 95 96 typedef struct { 97 char *comp; 98 char *decomp; 99 char *sfx[4]; 100 } Compress; 101 102 static Compress comps[] = { 103 "gzip", "gunzip", { ".tar.gz", ".tgz" }, /* default */ 104 "compress", "uncompress", { ".tar.Z", ".tz" }, 105 "bzip2", "bunzip2", { ".tar.bz", ".tbz", 106 ".tar.bz2",".tbz2" }, 107 }; 108 109 typedef struct { 110 int kid; 111 int fd; /* original fd */ 112 int rfd; /* replacement fd */ 113 int input; 114 int open; 115 } Pushstate; 116 117 #define OTHER(rdwr) (rdwr == Rd? Wr: Rd) 118 119 static int debug; 120 static int verb; 121 static int posix = 1; 122 static int docreate; 123 static int aruid; 124 static int argid; 125 static int relative = 1; 126 static int settime; 127 static int verbose; 128 static int docompress; 129 static int keepexisting; 130 static Off nexthdr; 131 132 static int nblock = Dblock; 133 static char *usefile; 134 static char origdir[Maxname*2]; 135 static Hdr *tpblk, *endblk; 136 static Hdr *curblk; 137 138 static void 139 usage(void) 140 { 141 fprint(2, "usage: %s {crtx}[PRTfgkmpuvz] [archive] file1 file2...\n", 142 argv0); 143 exits("usage"); 144 } 145 146 /* compression */ 147 148 static Compress * 149 compmethod(char *name) 150 { 151 int i, nmlen = strlen(name), sfxlen; 152 Compress *cp; 153 154 for (cp = comps; cp < comps + nelem(comps); cp++) 155 for (i = 0; i < nelem(cp->sfx) && cp->sfx[i]; i++) { 156 sfxlen = strlen(cp->sfx[i]); 157 if (nmlen > sfxlen && 158 strcmp(cp->sfx[i], name + nmlen - sfxlen) == 0) 159 return cp; 160 } 161 return docompress? comps: nil; 162 } 163 164 /* 165 * push a filter, cmd, onto fd. if input, it's an input descriptor. 166 * returns a descriptor to replace fd, or -1 on error. 167 */ 168 static int 169 push(int fd, char *cmd, int input, Pushstate *ps) 170 { 171 int nfd, pifds[2]; 172 String *s; 173 174 ps->open = 0; 175 ps->fd = fd; 176 ps->input = input; 177 if (fd < 0 || pipe(pifds) < 0) 178 return -1; 179 ps->kid = fork(); 180 switch (ps->kid) { 181 case -1: 182 return -1; 183 case 0: 184 if (input) 185 dup(pifds[Wr], Stdout); 186 else 187 dup(pifds[Rd], Stdin); 188 close(pifds[input? Rd: Wr]); 189 dup(fd, (input? Stdin: Stdout)); 190 s = s_new(); 191 if (cmd[0] != '/') 192 s_append(s, "/bin/"); 193 s_append(s, cmd); 194 execl(s_to_c(s), cmd, nil); 195 sysfatal("can't exec %s: %r", cmd); 196 default: 197 nfd = pifds[input? Rd: Wr]; 198 close(pifds[input? Wr: Rd]); 199 break; 200 } 201 ps->rfd = nfd; 202 ps->open = 1; 203 return nfd; 204 } 205 206 static char * 207 pushclose(Pushstate *ps) 208 { 209 Waitmsg *wm; 210 211 if (ps->fd < 0 || ps->rfd < 0 || !ps->open) 212 return "not open"; 213 close(ps->rfd); 214 ps->rfd = -1; 215 ps->open = 0; 216 while ((wm = wait()) != nil && wm->pid != ps->kid) 217 continue; 218 return wm? wm->msg: nil; 219 } 220 221 /* 222 * block-buffer management 223 */ 224 225 static void 226 initblks(void) 227 { 228 free(tpblk); 229 tpblk = malloc(Tblock * nblock); 230 assert(tpblk != nil); 231 endblk = tpblk + nblock; 232 } 233 234 /* 235 * (re)fill block buffers from archive. `justhdr' means we don't care 236 * about the data before the next header block. 237 */ 238 static char * 239 refill(int ar, char *bufs, int justhdr) 240 { 241 int i, n; 242 unsigned bytes = Tblock * nblock; 243 static int done, first = 1, seekable; 244 245 if (done) 246 return nil; 247 248 if (first) 249 seekable = seek(ar, 0, 1) >= 0; 250 /* try to size non-pipe input at first read */ 251 if (first && usefile) { 252 n = read(ar, bufs, bytes); 253 if (n <= 0) 254 sysfatal("error reading archive: %r"); 255 i = n; 256 if (i % Tblock != 0) { 257 fprint(2, "%s: archive block size (%d) error\n", 258 argv0, i); 259 exits("blocksize"); 260 } 261 i /= Tblock; 262 if (i != nblock) { 263 nblock = i; 264 fprint(2, "%s: blocking = %d\n", argv0, nblock); 265 endblk = (Hdr *)bufs + nblock; 266 bytes = n; 267 } 268 } else if (justhdr && seekable && nexthdr - seek(ar, 0, 1) >= bytes) { 269 /* optimisation for huge archive members on seekable media */ 270 if (seek(ar, bytes, 1) < 0) 271 sysfatal("can't seek on archive: %r"); 272 n = bytes; 273 } else 274 n = readn(ar, bufs, bytes); 275 first = 0; 276 277 if (n == 0) 278 sysfatal("unexpected EOF reading archive"); 279 else if (n < 0) 280 sysfatal("error reading archive: %r"); 281 else if (n%Tblock != 0) 282 sysfatal("partial block read from archive"); 283 if (n != bytes) { 284 done = 1; 285 memset(bufs + n, 0, bytes - n); 286 } 287 return bufs; 288 } 289 290 static Hdr * 291 getblk(int ar, Refill rfp, int justhdr) 292 { 293 if (curblk == nil || curblk >= endblk) { /* input block exhausted? */ 294 if (rfp != nil && (*rfp)(ar, (char *)tpblk, justhdr) == nil) 295 return nil; 296 curblk = tpblk; 297 } 298 return curblk++; 299 } 300 301 static Hdr * 302 getblkrd(int ar, int justhdr) 303 { 304 return getblk(ar, refill, justhdr); 305 } 306 307 static Hdr * 308 getblke(int ar) 309 { 310 return getblk(ar, nil, Alldata); 311 } 312 313 static Hdr * 314 getblkz(int ar) 315 { 316 Hdr *hp = getblke(ar); 317 318 if (hp != nil) 319 memset(hp->data, 0, Tblock); 320 return hp; 321 } 322 323 /* 324 * how many block buffers are available, starting at the address 325 * just returned by getblk*? 326 */ 327 static int 328 gothowmany(int max) 329 { 330 int n = endblk - (curblk - 1); 331 332 return n > max? max: n; 333 } 334 335 /* 336 * indicate that one is done with the last block obtained from getblke 337 * and it is now available to be written into the archive. 338 */ 339 static void 340 putlastblk(int ar) 341 { 342 unsigned bytes = Tblock * nblock; 343 344 /* if writing end-of-archive, aid compression (good hygiene too) */ 345 if (curblk < endblk) 346 memset(curblk, 0, (char *)endblk - (char *)curblk); 347 if (write(ar, tpblk, bytes) != bytes) 348 sysfatal("error writing archive: %r"); 349 } 350 351 static void 352 putblk(int ar) 353 { 354 if (curblk >= endblk) 355 putlastblk(ar); 356 } 357 358 static void 359 putbackblk(int ar) 360 { 361 curblk--; 362 USED(ar); 363 } 364 365 static void 366 putreadblks(int ar, int blks) 367 { 368 curblk += blks - 1; 369 USED(ar); 370 } 371 372 static void 373 putblkmany(int ar, int blks) 374 { 375 curblk += blks - 1; 376 putblk(ar); 377 } 378 379 /* 380 * common routines 381 */ 382 383 /* modifies hp->chksum */ 384 long 385 chksum(Hdr *hp) 386 { 387 int n = Tblock; 388 long i = 0; 389 uchar *cp = hp->data; 390 391 memset(hp->chksum, ' ', sizeof hp->chksum); 392 while (n-- > 0) 393 i += *cp++; 394 return i; 395 } 396 397 static int 398 isustar(Hdr *hp) 399 { 400 return strcmp(hp->magic, "ustar") == 0; 401 } 402 403 /* 404 * s is at most n bytes long, but need not be NUL-terminated. 405 * if shorter than n bytes, all bytes after the first NUL must also 406 * be NUL. 407 */ 408 static int 409 strnlen(char *s, int n) 410 { 411 return s[n - 1] != '\0'? n: strlen(s); 412 } 413 414 /* set fullname from header */ 415 static char * 416 name(Hdr *hp) 417 { 418 int pfxlen, namlen; 419 static char fullnamebuf[2 + Maxname + 1]; /* 2 at beginning for ./ on relative names */ 420 char *fullname; 421 422 fullname = fullnamebuf+2; 423 namlen = strnlen(hp->name, sizeof hp->name); 424 if (hp->prefix[0] == '\0' || !isustar(hp)) { /* old-style name? */ 425 memmove(fullname, hp->name, namlen); 426 fullname[namlen] = '\0'; 427 return fullname; 428 } 429 430 /* name is in two pieces */ 431 pfxlen = strnlen(hp->prefix, sizeof hp->prefix); 432 memmove(fullname, hp->prefix, pfxlen); 433 fullname[pfxlen] = '/'; 434 memmove(fullname + pfxlen + 1, hp->name, namlen); 435 fullname[pfxlen + 1 + namlen] = '\0'; 436 return fullname; 437 } 438 439 static int 440 isdir(Hdr *hp) 441 { 442 /* the mode test is ugly but sometimes necessary */ 443 return hp->linkflag == LF_DIR || 444 strrchr(name(hp), '\0')[-1] == '/' || 445 (strtoul(hp->mode, nil, 8)&0170000) == 040000; 446 } 447 448 static int 449 eotar(Hdr *hp) 450 { 451 return name(hp)[0] == '\0'; 452 } 453 454 Off 455 hdrsize(Hdr *hp) 456 { 457 Off bytes = strtoull(hp->size, nil, 8); 458 459 if(isdir(hp)) 460 bytes = 0; 461 return bytes; 462 } 463 464 static Hdr * 465 readhdr(int ar) 466 { 467 long hdrcksum; 468 Hdr *hp; 469 470 hp = getblkrd(ar, Alldata); 471 if (hp == nil) 472 sysfatal("unexpected EOF instead of archive header"); 473 if (eotar(hp)) /* end-of-archive block? */ 474 return nil; 475 hdrcksum = strtoul(hp->chksum, nil, 8); 476 if (chksum(hp) != hdrcksum) 477 sysfatal("bad archive header checksum: name %.64s...", 478 hp->name); 479 nexthdr += Tblock*(1 + BYTES2TBLKS(hdrsize(hp))); 480 return hp; 481 } 482 483 /* 484 * tar r[c] 485 */ 486 487 /* 488 * if name is longer than Namsiz bytes, try to split it at a slash and fit the 489 * pieces into hp->prefix and hp->name. 490 */ 491 static int 492 putfullname(Hdr *hp, char *name) 493 { 494 int namlen, pfxlen; 495 char *sl, *osl; 496 String *slname = nil; 497 498 if (isdir(hp)) { 499 slname = s_new(); 500 s_append(slname, name); 501 s_append(slname, "/"); /* posix requires this */ 502 name = s_to_c(slname); 503 } 504 505 namlen = strlen(name); 506 if (namlen <= Namsiz) { 507 strncpy(hp->name, name, Namsiz); 508 hp->prefix[0] = '\0'; /* ustar paranoia */ 509 return 0; 510 } 511 512 if (!posix || namlen > Maxname) { 513 fprint(2, "%s: name too long for tar header: %s\n", 514 argv0, name); 515 return -1; 516 } 517 /* 518 * try various splits until one results in pieces that fit into the 519 * appropriate fields of the header. look for slashes from right 520 * to left, in the hopes of putting the largest part of the name into 521 * hp->prefix, which is larger than hp->name. 522 */ 523 sl = strrchr(name, '/'); 524 while (sl != nil) { 525 pfxlen = sl - name; 526 if (pfxlen <= sizeof hp->prefix && namlen-1 - pfxlen <= Namsiz) 527 break; 528 osl = sl; 529 *osl = '\0'; 530 sl = strrchr(name, '/'); 531 *osl = '/'; 532 } 533 if (sl == nil) { 534 fprint(2, "%s: name can't be split to fit tar header: %s\n", 535 argv0, name); 536 return -1; 537 } 538 *sl = '\0'; 539 strncpy(hp->prefix, name, sizeof hp->prefix); 540 *sl++ = '/'; 541 strncpy(hp->name, sl, sizeof hp->name); 542 if (slname) 543 s_free(slname); 544 return 0; 545 } 546 547 static int 548 mkhdr(Hdr *hp, Dir *dir, char *file) 549 { 550 /* 551 * these fields run together, so we format them in order and don't use 552 * snprint. 553 */ 554 sprint(hp->mode, "%6lo ", dir->mode & 0777); 555 sprint(hp->uid, "%6o ", aruid); 556 sprint(hp->gid, "%6o ", argid); 557 /* 558 * files > 2 bytes can't be described 559 * (unless we resort to xustar or exustar formats). 560 */ 561 if (dir->length >= (Off)1<<33) { 562 fprint(2, "%s: %s: too large for tar header format\n", 563 argv0, file); 564 return -1; 565 } 566 sprint(hp->size, "%11lluo ", dir->length); 567 sprint(hp->mtime, "%11luo ", dir->mtime); 568 hp->linkflag = (dir->mode&DMDIR? LF_DIR: LF_PLAIN1); 569 putfullname(hp, file); 570 if (posix) { 571 strncpy(hp->magic, "ustar", sizeof hp->magic); 572 strncpy(hp->version, "00", sizeof hp->version); 573 strncpy(hp->uname, dir->uid, sizeof hp->uname); 574 strncpy(hp->gname, dir->gid, sizeof hp->gname); 575 } 576 sprint(hp->chksum, "%6luo", chksum(hp)); 577 return 0; 578 } 579 580 static void addtoar(int ar, char *file, char *shortf); 581 582 static void 583 addtreetoar(int ar, char *file, char *shortf, int fd) 584 { 585 int n; 586 Dir *dent, *dirents; 587 String *name = s_new(); 588 589 n = dirreadall(fd, &dirents); 590 close(fd); 591 if (n == 0) 592 return; 593 594 if (chdir(shortf) < 0) 595 sysfatal("chdir %s: %r", file); 596 if (DEBUG) 597 fprint(2, "chdir %s\t# %s\n", shortf, file); 598 599 for (dent = dirents; dent < dirents + n; dent++) { 600 s_reset(name); 601 s_append(name, file); 602 s_append(name, "/"); 603 s_append(name, dent->name); 604 addtoar(ar, s_to_c(name), dent->name); 605 } 606 s_free(name); 607 free(dirents); 608 609 if (chdir("..") < 0) 610 sysfatal("chdir %s/..: %r", file); 611 if (DEBUG) 612 fprint(2, "chdir ..\n"); 613 } 614 615 static void 616 addtoar(int ar, char *file, char *shortf) 617 { 618 int n, fd, isdir; 619 long bytes; 620 ulong blksleft, blksread; 621 Hdr *hbp; 622 Dir *dir; 623 624 fd = open(shortf, OREAD); 625 if (fd < 0) { 626 fprint(2, "%s: can't open %s: %r\n", argv0, file); 627 return; 628 } 629 dir = dirfstat(fd); 630 if (dir == nil) 631 sysfatal("can't fstat %s: %r", file); 632 633 hbp = getblkz(ar); 634 isdir = !!(dir->qid.type&QTDIR); 635 if (mkhdr(hbp, dir, file) < 0) { 636 putbackblk(ar); 637 free(dir); 638 close(fd); 639 return; 640 } 641 putblk(ar); 642 643 blksleft = BYTES2TBLKS(dir->length); 644 free(dir); 645 646 if (isdir) 647 addtreetoar(ar, file, shortf, fd); 648 else { 649 for (; blksleft > 0; blksleft -= blksread) { 650 hbp = getblke(ar); 651 blksread = gothowmany(blksleft); 652 bytes = blksread * Tblock; 653 n = readn(fd, hbp->data, bytes); 654 if (n < 0) 655 sysfatal("error reading %s: %r", file); 656 /* 657 * ignore EOF. zero any partial block to aid 658 * compression and emergency recovery of data. 659 */ 660 if (n < Tblock) 661 memset(hbp->data + n, 0, bytes - n); 662 putblkmany(ar, blksread); 663 } 664 close(fd); 665 if (verbose) 666 fprint(2, "%s\n", file); 667 } 668 } 669 670 static char * 671 replace(char **argv) 672 { 673 int i, ar; 674 ulong blksleft, blksread; 675 Off bytes; 676 Hdr *hp; 677 Compress *comp = nil; 678 Pushstate ps; 679 680 if (usefile && docreate) { 681 ar = create(usefile, OWRITE, 0666); 682 if (docompress) 683 comp = compmethod(usefile); 684 } else if (usefile) 685 ar = open(usefile, ORDWR); 686 else 687 ar = Stdout; 688 if (comp) 689 ar = push(ar, comp->comp, Output, &ps); 690 if (ar < 0) 691 sysfatal("can't open archive %s: %r", usefile); 692 693 if (usefile && !docreate) { 694 /* skip quickly to the end */ 695 while ((hp = readhdr(ar)) != nil) { 696 bytes = hdrsize(hp); 697 for (blksleft = BYTES2TBLKS(bytes); 698 blksleft > 0 && getblkrd(ar, Justnxthdr) != nil; 699 blksleft -= blksread) { 700 blksread = gothowmany(blksleft); 701 putreadblks(ar, blksread); 702 } 703 } 704 /* 705 * we have just read the end-of-archive Tblock. 706 * now seek back over the (big) archive block containing it, 707 * and back up curblk ptr over end-of-archive Tblock in memory. 708 */ 709 if (seek(ar, -Tblock*nblock, 1) < 0) 710 sysfatal("can't seek back over end-of-archive: %r"); 711 curblk--; 712 } 713 714 for (i = 0; argv[i] != nil; i++) 715 addtoar(ar, argv[i], argv[i]); 716 717 /* write end-of-archive marker */ 718 getblkz(ar); 719 putblk(ar); 720 getblkz(ar); 721 putlastblk(ar); 722 723 if (comp) 724 return pushclose(&ps); 725 if (ar > Stderr) 726 close(ar); 727 return nil; 728 } 729 730 /* 731 * tar [xt] 732 */ 733 734 /* is pfx a file-name prefix of name? */ 735 static int 736 prefix(char *name, char *pfx) 737 { 738 int pfxlen = strlen(pfx); 739 char clpfx[Maxname+1]; 740 741 if (pfxlen > Maxname) 742 return 0; 743 strcpy(clpfx, pfx); 744 cleanname(clpfx); 745 return strncmp(pfx, name, pfxlen) == 0 && 746 (name[pfxlen] == '\0' || name[pfxlen] == '/'); 747 } 748 749 static int 750 match(char *name, char **argv) 751 { 752 int i; 753 char clname[Maxname+1]; 754 755 if (argv[0] == nil) 756 return 1; 757 strcpy(clname, name); 758 cleanname(clname); 759 for (i = 0; argv[i] != nil; i++) 760 if (prefix(clname, argv[i])) 761 return 1; 762 return 0; 763 } 764 765 static int 766 makedir(char *s) 767 { 768 int f; 769 770 if (access(s, AEXIST) == 0) 771 return -1; 772 f = create(s, OREAD, DMDIR | 0777); 773 if (f >= 0) 774 close(f); 775 return f; 776 } 777 778 static void 779 mkpdirs(char *s) 780 { 781 int done = 0; 782 char *p = s; 783 784 while (!done && (p = strchr(p + 1, '/')) != nil) { 785 *p = '\0'; 786 done = (access(s, AEXIST) < 0 && makedir(s) < 0); 787 *p = '/'; 788 } 789 } 790 791 /* copy a file from the archive into the filesystem */ 792 /* fname is result of name(), so has two extra bytes at beginning */ 793 static void 794 extract1(int ar, Hdr *hp, char *fname) 795 { 796 int wrbytes, fd = -1, dir = 0; 797 long mtime = strtol(hp->mtime, nil, 8); 798 ulong mode = strtoul(hp->mode, nil, 8) & 0777; 799 Off bytes = strtoll(hp->size, nil, 8); /* for printing */ 800 ulong blksread, blksleft = BYTES2TBLKS(hdrsize(hp)); 801 Hdr *hbp; 802 803 if (isdir(hp)) { 804 mode |= DMDIR|0700; 805 dir = 1; 806 } 807 switch (hp->linkflag) { 808 case LF_LINK: 809 case LF_SYMLINK1: 810 case LF_SYMLINK2: 811 case LF_FIFO: 812 blksleft = 0; 813 break; 814 } 815 if (relative) { 816 if(fname[0] == '/') 817 *--fname = '.'; 818 else if(fname[0] == '#'){ 819 *--fname = '/'; 820 *--fname = '.'; 821 } 822 } 823 if (verb == Xtract) { 824 cleanname(fname); 825 switch (hp->linkflag) { 826 case LF_LINK: 827 case LF_SYMLINK1: 828 case LF_SYMLINK2: 829 fprint(2, "%s: can't make (sym)link %s\n", 830 argv0, fname); 831 break; 832 case LF_FIFO: 833 fprint(2, "%s: can't make fifo %s\n", argv0, fname); 834 break; 835 default: 836 if (!keepexisting || access(fname, AEXIST) < 0) { 837 int rw = (dir? OREAD: OWRITE); 838 839 fd = create(fname, rw, mode); 840 if (fd < 0) { 841 mkpdirs(fname); 842 fd = create(fname, rw, mode); 843 } 844 if (fd < 0 && 845 (!dir || access(fname, AEXIST) < 0)) 846 fprint(2, "%s: can't create %s: %r\n", 847 argv0, fname); 848 } 849 if (fd >= 0 && verbose) 850 fprint(2, "%s\n", fname); 851 break; 852 } 853 } else if (verbose) { 854 char *cp = ctime(mtime); 855 856 print("%M %8lld %-12.12s %-4.4s %s\n", 857 mode, bytes, cp+4, cp+24, fname); 858 } else 859 print("%s\n", fname); 860 861 for (; blksleft > 0; blksleft -= blksread) { 862 hbp = getblkrd(ar, (fd >= 0? Alldata: Justnxthdr)); 863 if (hbp == nil) 864 sysfatal("unexpected EOF on archive extracting %s", 865 fname); 866 blksread = gothowmany(blksleft); 867 wrbytes = Tblock*blksread; 868 if(wrbytes > bytes) 869 wrbytes = bytes; 870 if (fd >= 0 && write(fd, hbp->data, wrbytes) != wrbytes) 871 sysfatal("write error on %s: %r", fname); 872 putreadblks(ar, blksread); 873 bytes -= wrbytes; 874 } 875 if (fd >= 0) { 876 /* 877 * directories should be wstated after we're done 878 * creating files in them. 879 */ 880 if (settime) { 881 Dir nd; 882 883 nulldir(&nd); 884 nd.mtime = mtime; 885 if (isustar(hp)) 886 nd.gid = hp->gname; 887 dirfwstat(fd, &nd); 888 } 889 close(fd); 890 } 891 } 892 893 static void 894 skip(int ar, Hdr *hp, char *fname) 895 { 896 ulong blksleft, blksread; 897 Hdr *hbp; 898 899 for (blksleft = BYTES2TBLKS(hdrsize(hp)); blksleft > 0; 900 blksleft -= blksread) { 901 hbp = getblkrd(ar, Justnxthdr); 902 if (hbp == nil) 903 sysfatal("unexpected EOF on archive extracting %s", 904 fname); 905 blksread = gothowmany(blksleft); 906 putreadblks(ar, blksread); 907 } 908 } 909 910 static char * 911 extract(char **argv) 912 { 913 int ar; 914 char *longname; 915 Hdr *hp; 916 Compress *comp = nil; 917 Pushstate ps; 918 919 if (usefile) { 920 ar = open(usefile, OREAD); 921 comp = compmethod(usefile); 922 } else 923 ar = Stdin; 924 if (comp) 925 ar = push(ar, comp->decomp, Input, &ps); 926 if (ar < 0) 927 sysfatal("can't open archive %s: %r", usefile); 928 929 while ((hp = readhdr(ar)) != nil) { 930 longname = name(hp); 931 if (match(longname, argv)) 932 extract1(ar, hp, longname); 933 else 934 skip(ar, hp, longname); 935 } 936 937 if (comp) 938 return pushclose(&ps); 939 if (ar > Stderr) 940 close(ar); 941 return nil; 942 } 943 944 void 945 main(int argc, char *argv[]) 946 { 947 int errflg = 0; 948 char *ret = nil; 949 950 quotefmtinstall(); 951 fmtinstall('M', dirmodefmt); 952 953 TARGBEGIN { 954 case 'c': 955 docreate++; 956 verb = Replace; 957 break; 958 case 'f': 959 usefile = EARGF(usage()); 960 break; 961 case 'g': 962 argid = strtoul(EARGF(usage()), 0, 0); 963 break; 964 case 'k': 965 keepexisting++; 966 break; 967 case 'm': /* compatibility */ 968 settime = 0; 969 break; 970 case 'p': 971 posix++; 972 break; 973 case 'P': 974 posix = 0; 975 break; 976 case 'r': 977 verb = Replace; 978 break; 979 case 'R': 980 relative = 0; 981 break; 982 case 't': 983 verb = Toc; 984 break; 985 case 'T': 986 settime++; 987 break; 988 case 'u': 989 aruid = strtoul(EARGF(usage()), 0, 0); 990 break; 991 case 'v': 992 verbose++; 993 break; 994 case 'x': 995 verb = Xtract; 996 break; 997 case 'z': 998 docompress++; 999 break; 1000 case '-': 1001 break; 1002 default: 1003 fprint(2, "tar: unknown letter %C\n", TARGC()); 1004 errflg++; 1005 break; 1006 } TARGEND 1007 1008 if (argc < 0 || errflg) 1009 usage(); 1010 1011 initblks(); 1012 switch (verb) { 1013 case Toc: 1014 case Xtract: 1015 ret = extract(argv); 1016 break; 1017 case Replace: 1018 if (getwd(origdir, sizeof origdir) == nil) 1019 strcpy(origdir, "/tmp"); 1020 ret = replace(argv); 1021 chdir(origdir); /* for profiling */ 1022 break; 1023 default: 1024 usage(); 1025 break; 1026 } 1027 exits(ret); 1028 } 1029