1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)tar.c 5.17 (Berkeley) 04/08/91"; 16 #endif /* not lint */ 17 18 /* 19 * Tape Archival Program 20 */ 21 #include <sys/param.h> 22 #include <sys/stat.h> 23 #include <sys/ioctl.h> 24 #include <sys/mtio.h> 25 #include <sys/time.h> 26 #include <dirent.h> 27 #include <fcntl.h> 28 #include <signal.h> 29 #include <errno.h> 30 #include <fcntl.h> 31 #include <unistd.h> 32 #include <stdio.h> 33 #include <string.h> 34 #include <stdlib.h> 35 #include "pathnames.h" 36 37 #define TBLOCK 512 38 #define NBLOCK 20 39 #define NAMSIZ 100 40 41 #define writetape(b) writetbuf(b, 1) 42 #define min(a,b) ((a) < (b) ? (a) : (b)) 43 #define max(a,b) ((a) > (b) ? (a) : (b)) 44 45 union hblock { 46 char dummy[TBLOCK]; 47 struct header { 48 char name[NAMSIZ]; 49 char mode[8]; 50 char uid[8]; 51 char gid[8]; 52 char size[12]; 53 char mtime[12]; 54 char chksum[8]; 55 char linkflag; 56 char linkname[NAMSIZ]; 57 } dbuf; 58 }; 59 60 struct linkbuf { 61 ino_t inum; 62 dev_t devnum; 63 int count; 64 char pathname[NAMSIZ]; 65 struct linkbuf *nextp; 66 }; 67 68 union hblock dblock; 69 union hblock *tbuf; 70 struct linkbuf *ihead; 71 struct stat stbuf; 72 73 int rflag; 74 int sflag; 75 int xflag; 76 int vflag; 77 int tflag; 78 int cflag; 79 int mflag; 80 int fflag; 81 int iflag; 82 int oflag; 83 int pflag; 84 int wflag; 85 int hflag; 86 int Bflag; 87 int Fflag; 88 89 int mt; 90 int term; 91 int chksum; 92 int recno; 93 int first; 94 int prtlinkerr; 95 int freemem = 1; 96 int nblock = 0; 97 void onintr(), onquit(), onhup(); 98 #ifdef notdef 99 void onterm(); 100 #endif 101 102 daddr_t low; 103 daddr_t high; 104 daddr_t bsrch(); 105 106 FILE *vfile = stdout; 107 FILE *tfile; 108 char tname[] = _PATH_TMP; 109 char *usefile; 110 char magtape[] = _PATH_MAGTAPE; 111 char *cwd(); 112 char *getmem(); 113 114 extern int errno; 115 116 main(argc, argv) 117 int argc; 118 char **argv; 119 { 120 char *cp; 121 122 if (argc < 2) 123 usage(); 124 125 tfile = NULL; 126 usefile = magtape; 127 argv[argc] = 0; 128 argv++; 129 for (cp = *argv++; *cp; cp++) 130 switch(*cp) { 131 132 case 'f': 133 if (*argv == 0) { 134 fprintf(stderr, 135 "tar: tapefile must be specified with 'f' option\n"); 136 usage(); 137 } 138 usefile = *argv++; 139 fflag++; 140 break; 141 142 case 'c': 143 cflag++; 144 rflag++; 145 break; 146 147 case 'o': 148 oflag++; 149 break; 150 151 case 'p': 152 pflag++; 153 break; 154 155 case 'u': 156 (void)mktemp(tname); 157 if ((tfile = fopen(tname, "w")) == NULL) { 158 fprintf(stderr, 159 "tar: cannot create temporary file (%s)\n", 160 tname); 161 done(1); 162 } 163 fprintf(tfile, "!!!!!/!/!/!/!/!/!/! 000\n"); 164 /*FALL THRU*/ 165 166 case 'r': 167 rflag++; 168 break; 169 170 case 's': 171 sflag++; 172 break; 173 174 case 'v': 175 vflag++; 176 break; 177 178 case 'w': 179 wflag++; 180 break; 181 182 case 'x': 183 xflag++; 184 break; 185 186 case 't': 187 tflag++; 188 break; 189 190 case 'm': 191 mflag++; 192 break; 193 194 case '-': 195 break; 196 197 case '0': 198 case '1': 199 case '4': 200 case '5': 201 case '7': 202 case '8': 203 magtape[8] = *cp; 204 usefile = magtape; 205 break; 206 207 case 'b': 208 if (*argv == 0) { 209 fprintf(stderr, 210 "tar: blocksize must be specified with 'b' option\n"); 211 usage(); 212 } 213 nblock = atoi(*argv); 214 if (nblock <= 0) { 215 fprintf(stderr, 216 "tar: invalid blocksize \"%s\"\n", *argv); 217 done(1); 218 } 219 argv++; 220 break; 221 222 case 'l': 223 prtlinkerr++; 224 break; 225 226 case 'h': 227 hflag++; 228 break; 229 230 case 'i': 231 iflag++; 232 break; 233 234 case 'B': 235 Bflag++; 236 break; 237 238 case 'F': 239 Fflag++; 240 break; 241 242 default: 243 fprintf(stderr, "tar: %c: unknown option\n", *cp); 244 usage(); 245 } 246 247 if (!rflag && !xflag && !tflag) 248 usage(); 249 if (rflag) { 250 if (cflag && tfile != NULL) 251 usage(); 252 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 253 (void) signal(SIGINT, onintr); 254 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 255 (void) signal(SIGHUP, onhup); 256 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) 257 (void) signal(SIGQUIT, onquit); 258 #ifdef notdef 259 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) 260 (void) signal(SIGTERM, onterm); 261 #endif 262 mt = openmt(usefile, 1); 263 dorep(argv); 264 done(0); 265 } 266 mt = openmt(usefile, 0); 267 if (xflag) 268 doxtract(argv); 269 else 270 dotable(argv); 271 done(0); 272 } 273 274 usage() 275 { 276 fprintf(stderr, 277 "tar: usage: tar -{txru}[cvfblmhopwBi] [tapefile] [blocksize] file1 file2...\n"); 278 done(1); 279 } 280 281 int 282 openmt(tape, writing) 283 char *tape; 284 int writing; 285 { 286 if (strcmp(tape, "-") == 0) { 287 /* 288 * Read from standard input or write to standard output. 289 */ 290 if (writing) { 291 if (cflag == 0) { 292 fprintf(stderr, 293 "tar: can only create standard output archives\n"); 294 done(1); 295 } 296 vfile = stderr; 297 setlinebuf(vfile); 298 mt = dup(1); 299 } else { 300 mt = dup(0); 301 Bflag++; 302 } 303 } else { 304 /* 305 * Use file or tape on local machine. 306 */ 307 if (writing) { 308 if (cflag) 309 mt = open(tape, O_RDWR|O_CREAT|O_TRUNC, 0666); 310 else 311 mt = open(tape, O_RDWR); 312 } else 313 mt = open(tape, O_RDONLY); 314 if (mt < 0) { 315 fprintf(stderr, "tar: %s: %s\n", tape, strerror(errno)); 316 done(1); 317 } 318 } 319 return(mt); 320 } 321 322 dorep(argv) 323 char *argv[]; 324 { 325 register char *cp, *cp2; 326 char *parent, *wdir; 327 328 if (!cflag) { 329 getdir(); 330 do { 331 passtape(); 332 if (term) 333 done(0); 334 getdir(); 335 } while (!endtape()); 336 backtape(); 337 if (tfile != NULL) { 338 char buf[200]; 339 340 (void)sprintf(buf, 341 "sort +0 -1 +1nr %s -o %s; awk '$1 != prev {print; prev=$1}' %s >%sX; mv %sX %s", 342 tname, tname, tname, tname, tname, tname); 343 fflush(tfile); 344 system(buf); 345 freopen(tname, "r", tfile); 346 fstat(fileno(tfile), &stbuf); 347 high = stbuf.st_size; 348 } 349 } 350 351 wdir = cwd(); 352 while (*argv && ! term) { 353 cp2 = *argv; 354 if (!strcmp(cp2, "-C") && argv[1]) { 355 argv++; 356 if (chdir(*argv) < 0) { 357 fprintf(stderr, 358 "tar: can't change directories to %s: %s\n", 359 *argv, strerror(errno)); 360 } else { 361 free(wdir); 362 wdir = cwd(); 363 } 364 argv++; 365 continue; 366 } 367 parent = wdir; 368 for (cp = *argv; *cp; cp++) 369 if (*cp == '/') 370 cp2 = cp; 371 if (cp2 != *argv) { 372 *cp2 = '\0'; 373 if (chdir(*argv) < 0) { 374 fprintf(stderr, 375 "tar: can't change directories to %s: %s\n", 376 *argv, strerror(errno)); 377 continue; 378 } 379 parent = cwd(); 380 *cp2 = '/'; 381 cp2++; 382 } 383 putfile(*argv++, cp2, parent); 384 if (chdir(wdir) < 0) 385 fprintf(stderr, "tar: cannot change back?: %s: %s\n", 386 wdir, strerror(errno)); 387 } 388 putempty(); 389 putempty(); 390 flushtape(); 391 if (prtlinkerr == 0) 392 return; 393 for (; ihead != NULL; ihead = ihead->nextp) { 394 if (ihead->count == 0) 395 continue; 396 fprintf(stderr, "tar: missing links to %s\n", ihead->pathname); 397 } 398 } 399 400 endtape() 401 { 402 return (dblock.dbuf.name[0] == '\0'); 403 } 404 405 getdir() 406 { 407 register struct stat *sp; 408 int i; 409 410 top: 411 readtape((char *)&dblock); 412 if (dblock.dbuf.name[0] == '\0') 413 return; 414 sp = &stbuf; 415 sscanf(dblock.dbuf.mode, "%o", &i); 416 sp->st_mode = i; 417 sscanf(dblock.dbuf.uid, "%o", &i); 418 sp->st_uid = i; 419 sscanf(dblock.dbuf.gid, "%o", &i); 420 sp->st_gid = i; 421 sscanf(dblock.dbuf.size, "%lo", &sp->st_size); 422 sscanf(dblock.dbuf.mtime, "%lo", &sp->st_mtime); 423 sscanf(dblock.dbuf.chksum, "%o", &chksum); 424 if (chksum != (i = checksum())) { 425 fprintf(stderr, "tar: directory checksum error (%d != %d)\n", 426 chksum, i); 427 if (iflag) 428 goto top; 429 done(2); 430 } 431 /* strip off leading "/" if present */ 432 if (sflag && dblock.dbuf.name[0] == '/') { 433 register char *cp1, *cp2; 434 for (cp1 = cp2 = dblock.dbuf.name; *cp2 && *cp2 == '/'; ++cp2); 435 if (!*cp2) 436 goto top; 437 while (*cp1++ = *cp2++); 438 } 439 if (tfile != NULL) 440 fprintf(tfile, "%s %s\n", dblock.dbuf.name, dblock.dbuf.mtime); 441 } 442 443 passtape() 444 { 445 long blocks; 446 char *bufp; 447 448 if (dblock.dbuf.linkflag == '1') 449 return; 450 blocks = stbuf.st_size; 451 blocks += TBLOCK-1; 452 blocks /= TBLOCK; 453 454 while (blocks-- > 0) 455 (void) readtbuf(&bufp, TBLOCK); 456 } 457 458 putfile(longname, shortname, parent) 459 char *longname; 460 char *shortname; 461 char *parent; 462 { 463 int infile = 0; 464 long blocks; 465 char buf[TBLOCK]; 466 char *bigbuf; 467 register char *cp; 468 struct dirent *dp; 469 DIR *dirp; 470 register int i; 471 long l; 472 char newparent[NAMSIZ+64]; 473 int maxread; 474 int hint; /* amount to write to get "in sync" */ 475 476 if (!hflag) 477 i = lstat(shortname, &stbuf); 478 else 479 i = stat(shortname, &stbuf); 480 if (i < 0) { 481 fprintf(stderr, "tar: %s: %s\n", longname, strerror(errno)); 482 return; 483 } 484 if (tfile != NULL && checkupdate(longname) == 0) 485 return; 486 if (checkw('r', longname) == 0) 487 return; 488 if (Fflag && checkf(shortname, stbuf.st_mode, Fflag) == 0) 489 return; 490 491 switch (stbuf.st_mode & S_IFMT) { 492 case S_IFDIR: 493 for (i = 0, cp = buf; *cp++ = longname[i++];) 494 ; 495 *--cp = '/'; 496 *++cp = 0 ; 497 if (!oflag) { 498 if ((cp - buf) >= NAMSIZ) { 499 fprintf(stderr, "tar: %s: file name too long\n", 500 longname); 501 return; 502 } 503 stbuf.st_size = 0; 504 tomodes(&stbuf); 505 strcpy(dblock.dbuf.name,buf); 506 (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 507 (void) writetape((char *)&dblock); 508 } 509 (void)sprintf(newparent, "%s/%s", parent, shortname); 510 if (chdir(shortname) < 0) { 511 fprintf(stderr, "tar: chdir %s: %s\n", 512 shortname, strerror(errno)); 513 return; 514 } 515 if ((dirp = opendir(".")) == NULL) { 516 fprintf(stderr, "tar: %s: directory read error\n", 517 longname); 518 if (chdir(parent) < 0) { 519 fprintf(stderr, 520 "tar: cannot change back?: %s: %s\n", 521 parent, strerror(errno)); 522 } 523 return; 524 } 525 while ((dp = readdir(dirp)) != NULL && !term) { 526 if (!strcmp(".", dp->d_name) || 527 !strcmp("..", dp->d_name)) 528 continue; 529 strcpy(cp, dp->d_name); 530 l = telldir(dirp); 531 closedir(dirp); 532 putfile(buf, cp, newparent); 533 dirp = opendir("."); 534 seekdir(dirp, l); 535 } 536 closedir(dirp); 537 if (chdir(parent) < 0) { 538 fprintf(stderr, 539 "tar: cannot change back?: %s: %s\n", 540 parent, strerror(errno)); 541 } 542 break; 543 544 case S_IFLNK: 545 tomodes(&stbuf); 546 if (strlen(longname) >= NAMSIZ) { 547 fprintf(stderr, "tar: %s: file name too long\n", 548 longname); 549 return; 550 } 551 strcpy(dblock.dbuf.name, longname); 552 if (stbuf.st_size + 1 >= NAMSIZ) { 553 fprintf(stderr, "tar: %s: symbolic link too long\n", 554 longname); 555 return; 556 } 557 i = readlink(shortname, dblock.dbuf.linkname, NAMSIZ - 1); 558 if (i < 0) { 559 fprintf(stderr, 560 "tar: can't read symbolic link %s: %s\n", 561 longname, strerror(errno)); 562 return; 563 } 564 dblock.dbuf.linkname[i] = '\0'; 565 dblock.dbuf.linkflag = '2'; 566 if (vflag) 567 fprintf(vfile, "a %s symbolic link to %s\n", 568 longname, dblock.dbuf.linkname); 569 (void)sprintf(dblock.dbuf.size, "%11lo", 0L); 570 (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 571 (void) writetape((char *)&dblock); 572 break; 573 574 case S_IFREG: 575 if ((infile = open(shortname, 0)) < 0) { 576 fprintf(stderr, "tar: %s: %s\n", 577 longname, strerror(errno)); 578 return; 579 } 580 tomodes(&stbuf); 581 if (strlen(longname) >= NAMSIZ) { 582 fprintf(stderr, "tar: %s: file name too long\n", 583 longname); 584 close(infile); 585 return; 586 } 587 strcpy(dblock.dbuf.name, longname); 588 if (stbuf.st_nlink > 1) { 589 struct linkbuf *lp; 590 int found = 0; 591 592 for (lp = ihead; lp != NULL; lp = lp->nextp) 593 if (lp->inum == stbuf.st_ino && 594 lp->devnum == stbuf.st_dev) { 595 found++; 596 break; 597 } 598 if (found) { 599 strcpy(dblock.dbuf.linkname, lp->pathname); 600 dblock.dbuf.linkflag = '1'; 601 (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 602 (void) writetape( (char *) &dblock); 603 if (vflag) 604 fprintf(vfile, "a %s link to %s\n", 605 longname, lp->pathname); 606 lp->count--; 607 close(infile); 608 return; 609 } 610 lp = (struct linkbuf *) getmem(sizeof(*lp)); 611 if (lp != NULL) { 612 lp->nextp = ihead; 613 ihead = lp; 614 lp->inum = stbuf.st_ino; 615 lp->devnum = stbuf.st_dev; 616 lp->count = stbuf.st_nlink - 1; 617 strcpy(lp->pathname, longname); 618 } 619 } 620 blocks = (stbuf.st_size + (TBLOCK-1)) / TBLOCK; 621 if (vflag) 622 fprintf(vfile, "a %s %ld blocks\n", longname, blocks); 623 (void)sprintf(dblock.dbuf.chksum, "%6o", checksum()); 624 hint = writetape((char *)&dblock); 625 maxread = max(stbuf.st_blksize, (nblock * TBLOCK)); 626 if ((bigbuf = malloc((unsigned)maxread)) == 0) { 627 maxread = TBLOCK; 628 bigbuf = buf; 629 } 630 631 while ((i = read(infile, bigbuf, min((hint*TBLOCK), maxread))) > 0 632 && blocks > 0) { 633 register int nblks; 634 635 nblks = ((i-1)/TBLOCK)+1; 636 if (nblks > blocks) 637 nblks = blocks; 638 hint = writetbuf(bigbuf, nblks); 639 blocks -= nblks; 640 } 641 close(infile); 642 if (bigbuf != buf) 643 free(bigbuf); 644 if (i < 0) { 645 fprintf(stderr, "tar: Read error on %s: %s\n", 646 longname, strerror(errno)); 647 } else if (blocks != 0 || i != 0) 648 fprintf(stderr, "tar: %s: file changed size\n", 649 longname); 650 while (--blocks >= 0) 651 putempty(); 652 break; 653 654 default: 655 fprintf(stderr, "tar: %s is not a file. Not dumped\n", 656 longname); 657 break; 658 } 659 } 660 661 doxtract(argv) 662 char *argv[]; 663 { 664 long blocks, bytes; 665 int ofile, i; 666 667 for (;;) { 668 if ((i = wantit(argv)) == 0) 669 continue; 670 if (i == -1) 671 break; /* end of tape */ 672 if (checkw('x', dblock.dbuf.name) == 0) { 673 passtape(); 674 continue; 675 } 676 if (Fflag) { 677 char *s; 678 679 if ((s = rindex(dblock.dbuf.name, '/')) == 0) 680 s = dblock.dbuf.name; 681 else 682 s++; 683 if (checkf(s, stbuf.st_mode, Fflag) == 0) { 684 passtape(); 685 continue; 686 } 687 } 688 if (checkdir(dblock.dbuf.name)) { /* have a directory */ 689 if (mflag == 0) 690 dodirtimes(&dblock); 691 continue; 692 } 693 if (dblock.dbuf.linkflag == '2') { /* symlink */ 694 /* 695 * only unlink non directories or empty 696 * directories 697 */ 698 if (rmdir(dblock.dbuf.name) < 0) { 699 if (errno == ENOTDIR) 700 unlink(dblock.dbuf.name); 701 } 702 if (symlink(dblock.dbuf.linkname, dblock.dbuf.name)<0) { 703 fprintf(stderr, 704 "tar: %s: symbolic link failed: %s\n", 705 dblock.dbuf.name, strerror(errno)); 706 continue; 707 } 708 if (vflag) 709 fprintf(vfile, "x %s symbolic link to %s\n", 710 dblock.dbuf.name, dblock.dbuf.linkname); 711 #ifdef notdef 712 /* ignore alien orders */ 713 chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 714 if (mflag == 0) 715 setimes(dblock.dbuf.name, stbuf.st_mtime); 716 if (pflag) 717 chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 718 #endif 719 continue; 720 } 721 if (dblock.dbuf.linkflag == '1') { /* regular link */ 722 /* 723 * only unlink non directories or empty 724 * directories 725 */ 726 if (rmdir(dblock.dbuf.name) < 0) { 727 if (errno == ENOTDIR) 728 unlink(dblock.dbuf.name); 729 } 730 if (link(dblock.dbuf.linkname, dblock.dbuf.name) < 0) { 731 fprintf(stderr, 732 "tar: can't link %s to %s: %s\n", 733 dblock.dbuf.name, dblock.dbuf.linkname, 734 strerror(errno)); 735 continue; 736 } 737 if (vflag) 738 fprintf(vfile, "%s linked to %s\n", 739 dblock.dbuf.name, dblock.dbuf.linkname); 740 continue; 741 } 742 if ((ofile = creat(dblock.dbuf.name,stbuf.st_mode&0xfff)) < 0) { 743 fprintf(stderr, "tar: can't create %s: %s\n", 744 dblock.dbuf.name, strerror(errno)); 745 passtape(); 746 continue; 747 } 748 chown(dblock.dbuf.name, stbuf.st_uid, stbuf.st_gid); 749 blocks = ((bytes = stbuf.st_size) + TBLOCK-1)/TBLOCK; 750 if (vflag) 751 fprintf(vfile, "x %s, %ld bytes, %ld tape blocks\n", 752 dblock.dbuf.name, bytes, blocks); 753 for (; blocks > 0;) { 754 register int nread; 755 char *bufp; 756 register int nwant; 757 758 nwant = NBLOCK*TBLOCK; 759 if (nwant > (blocks*TBLOCK)) 760 nwant = (blocks*TBLOCK); 761 nread = readtbuf(&bufp, nwant); 762 if (write(ofile, bufp, (int)min(nread, bytes)) < 0) { 763 fprintf(stderr, 764 "tar: %s: HELP - extract write error: %s\n", 765 dblock.dbuf.name, strerror(errno)); 766 done(2); 767 } 768 bytes -= nread; 769 blocks -= (((nread-1)/TBLOCK)+1); 770 } 771 close(ofile); 772 if (mflag == 0) 773 setimes(dblock.dbuf.name, stbuf.st_mtime); 774 if (pflag) 775 chmod(dblock.dbuf.name, stbuf.st_mode & 07777); 776 } 777 if (mflag == 0) { 778 dblock.dbuf.name[0] = '\0'; /* process the whole stack */ 779 dodirtimes(&dblock); 780 } 781 } 782 783 dotable(argv) 784 char *argv[]; 785 { 786 register int i; 787 788 for (;;) { 789 if ((i = wantit(argv)) == 0) 790 continue; 791 if (i == -1) 792 break; /* end of tape */ 793 if (vflag) 794 longt(&stbuf); 795 printf("%s", dblock.dbuf.name); 796 if (dblock.dbuf.linkflag == '1') 797 printf(" linked to %s", dblock.dbuf.linkname); 798 if (dblock.dbuf.linkflag == '2') 799 printf(" symbolic link to %s", dblock.dbuf.linkname); 800 printf("\n"); 801 passtape(); 802 } 803 } 804 805 putempty() 806 { 807 char buf[TBLOCK]; 808 809 bzero(buf, sizeof (buf)); 810 (void) writetape(buf); 811 } 812 813 longt(st) 814 register struct stat *st; 815 { 816 register char *cp; 817 char *ctime(); 818 819 pmode(st); 820 printf("%3u/%1u", st->st_uid, st->st_gid); 821 printf("%7ld", st->st_size); 822 cp = ctime(&st->st_mtime); 823 printf(" %-12.12s %-4.4s ", cp+4, cp+20); 824 } 825 826 #define SUID 04000 827 #define SGID 02000 828 #define ROWN 0400 829 #define WOWN 0200 830 #define XOWN 0100 831 #define RGRP 040 832 #define WGRP 020 833 #define XGRP 010 834 #define ROTH 04 835 #define WOTH 02 836 #define XOTH 01 837 #define STXT 01000 838 int m1[] = { 1, ROWN, 'r', '-' }; 839 int m2[] = { 1, WOWN, 'w', '-' }; 840 int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; 841 int m4[] = { 1, RGRP, 'r', '-' }; 842 int m5[] = { 1, WGRP, 'w', '-' }; 843 int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; 844 int m7[] = { 1, ROTH, 'r', '-' }; 845 int m8[] = { 1, WOTH, 'w', '-' }; 846 int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; 847 848 int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9}; 849 850 pmode(st) 851 register struct stat *st; 852 { 853 register int **mp; 854 855 for (mp = &m[0]; mp < &m[9];) 856 selectbits(*mp++, st); 857 } 858 859 selectbits(pairp, st) 860 int *pairp; 861 struct stat *st; 862 { 863 register int n, *ap; 864 865 ap = pairp; 866 n = *ap++; 867 while (--n>=0 && (st->st_mode&*ap++)==0) 868 ap++; 869 putchar(*ap); 870 } 871 872 /* 873 * Make all directories needed by `name'. If `name' is itself 874 * a directory on the tar tape (indicated by a trailing '/'), 875 * return 1; else 0. 876 */ 877 checkdir(name) 878 register char *name; 879 { 880 register char *cp; 881 882 /* 883 * Quick check for existence of directory. 884 */ 885 if ((cp = rindex(name, '/')) == 0) 886 return (0); 887 *cp = '\0'; 888 if (access(name, F_OK) == 0) { /* already exists */ 889 *cp = '/'; 890 return (cp[1] == '\0'); /* return (lastchar == '/') */ 891 } 892 *cp = '/'; 893 894 /* 895 * No luck, try to make all directories in path. 896 */ 897 for (cp = name; *cp; cp++) { 898 if (*cp != '/') 899 continue; 900 *cp = '\0'; 901 if (access(name, F_OK) < 0) { 902 if (mkdir(name, 0777) < 0) { 903 fprintf(stderr, "tar: mkdir: %s: %s\n", 904 name, strerror(errno)); 905 *cp = '/'; 906 return (0); 907 } 908 chown(name, stbuf.st_uid, stbuf.st_gid); 909 if (pflag && cp[1] == '\0') /* dir on the tape */ 910 chmod(name, stbuf.st_mode & 07777); 911 } 912 *cp = '/'; 913 } 914 return (cp[-1]=='/'); 915 } 916 917 void 918 onintr() 919 { 920 (void) signal(SIGINT, SIG_IGN); 921 term++; 922 } 923 924 void 925 onquit() 926 { 927 (void) signal(SIGQUIT, SIG_IGN); 928 term++; 929 } 930 931 void 932 onhup() 933 { 934 (void) signal(SIGHUP, SIG_IGN); 935 term++; 936 } 937 938 #ifdef notdef 939 void 940 onterm() 941 { 942 (void) signal(SIGTERM, SIG_IGN); 943 term++; 944 } 945 #endif 946 947 tomodes(sp) 948 register struct stat *sp; 949 { 950 register char *cp; 951 952 for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 953 *cp = '\0'; 954 (void)sprintf(dblock.dbuf.mode, "%6o ", sp->st_mode & 07777); 955 (void)sprintf(dblock.dbuf.uid, "%6o ", sp->st_uid); 956 (void)sprintf(dblock.dbuf.gid, "%6o ", sp->st_gid); 957 (void)sprintf(dblock.dbuf.size, "%11lo ", sp->st_size); 958 (void)sprintf(dblock.dbuf.mtime, "%11lo ", sp->st_mtime); 959 } 960 961 checksum() 962 { 963 register i; 964 register char *cp; 965 966 for (cp = dblock.dbuf.chksum; 967 cp < &dblock.dbuf.chksum[sizeof(dblock.dbuf.chksum)]; cp++) 968 *cp = ' '; 969 i = 0; 970 for (cp = dblock.dummy; cp < &dblock.dummy[TBLOCK]; cp++) 971 i += *cp; 972 return (i); 973 } 974 975 checkw(c, name) 976 char *name; 977 { 978 if (!wflag) 979 return (1); 980 printf("%c ", c); 981 if (vflag) 982 longt(&stbuf); 983 printf("%s: ", name); 984 return (response() == 'y'); 985 } 986 987 response() 988 { 989 char c; 990 991 c = getchar(); 992 if (c != '\n') 993 while (getchar() != '\n') 994 ; 995 else 996 c = 'n'; 997 return (c); 998 } 999 1000 checkf(name, mode, howmuch) 1001 char *name; 1002 int mode, howmuch; 1003 { 1004 int l; 1005 1006 if ((mode & S_IFMT) == S_IFDIR){ 1007 if ((strcmp(name, "SCCS")==0) || (strcmp(name, "RCS")==0)) 1008 return(0); 1009 return(1); 1010 } 1011 if ((l = strlen(name)) < 3) 1012 return (1); 1013 if (howmuch > 1 && name[l-2] == '.' && name[l-1] == 'o') 1014 return (0); 1015 if (strcmp(name, "core") == 0 || 1016 strcmp(name, "errs") == 0 || 1017 (howmuch > 1 && strcmp(name, "a.out") == 0)) 1018 return (0); 1019 /* SHOULD CHECK IF IT IS EXECUTABLE */ 1020 return (1); 1021 } 1022 1023 /* Is the current file a new file, or the newest one of the same name? */ 1024 checkupdate(arg) 1025 char *arg; 1026 { 1027 char name[100]; 1028 long mtime; 1029 daddr_t seekp; 1030 daddr_t lookup(); 1031 1032 rewind(tfile); 1033 for (;;) { 1034 if ((seekp = lookup(arg)) < 0) 1035 return (1); 1036 fseek(tfile, seekp, 0); 1037 fscanf(tfile, "%s %lo", name, &mtime); 1038 return (stbuf.st_mtime > mtime); 1039 } 1040 } 1041 1042 done(n) 1043 { 1044 unlink(tname); 1045 exit(n); 1046 } 1047 1048 /* 1049 * Do we want the next entry on the tape, i.e. is it selected? If 1050 * not, skip over the entire entry. Return -1 if reached end of tape. 1051 */ 1052 wantit(argv) 1053 char *argv[]; 1054 { 1055 register char **cp; 1056 1057 getdir(); 1058 if (endtape()) 1059 return (-1); 1060 if (*argv == 0) 1061 return (1); 1062 for (cp = argv; *cp; cp++) 1063 if (prefix(*cp, dblock.dbuf.name)) 1064 return (1); 1065 passtape(); 1066 return (0); 1067 } 1068 1069 /* 1070 * Does s2 begin with the string s1, on a directory boundary? 1071 */ 1072 prefix(s1, s2) 1073 register char *s1, *s2; 1074 { 1075 while (*s1) 1076 if (*s1++ != *s2++) 1077 return (0); 1078 if (*s2) 1079 return (*s2 == '/'); 1080 return (1); 1081 } 1082 1083 #define N 200 1084 int njab; 1085 1086 daddr_t 1087 lookup(s) 1088 char *s; 1089 { 1090 register i; 1091 daddr_t a; 1092 1093 for(i=0; s[i]; i++) 1094 if (s[i] == ' ') 1095 break; 1096 a = bsrch(s, i, low, high); 1097 return (a); 1098 } 1099 1100 daddr_t 1101 bsrch(s, n, l, h) 1102 daddr_t l, h; 1103 char *s; 1104 { 1105 register i, j; 1106 char b[N]; 1107 daddr_t m, m1; 1108 1109 njab = 0; 1110 1111 loop: 1112 if (l >= h) 1113 return ((daddr_t) -1); 1114 m = l + (h-l)/2 - N/2; 1115 if (m < l) 1116 m = l; 1117 fseek(tfile, m, 0); 1118 fread(b, 1, N, tfile); 1119 njab++; 1120 for(i=0; i<N; i++) { 1121 if (b[i] == '\n') 1122 break; 1123 m++; 1124 } 1125 if (m >= h) 1126 return ((daddr_t) -1); 1127 m1 = m; 1128 j = i; 1129 for(i++; i<N; i++) { 1130 m1++; 1131 if (b[i] == '\n') 1132 break; 1133 } 1134 i = cmp(b+j, s, n); 1135 if (i < 0) { 1136 h = m; 1137 goto loop; 1138 } 1139 if (i > 0) { 1140 l = m1; 1141 goto loop; 1142 } 1143 return (m); 1144 } 1145 1146 cmp(b, s, n) 1147 char *b, *s; 1148 { 1149 register i; 1150 1151 if (b[0] != '\n') 1152 exit(2); 1153 for(i=0; i<n; i++) { 1154 if (b[i+1] > s[i]) 1155 return (-1); 1156 if (b[i+1] < s[i]) 1157 return (1); 1158 } 1159 return (b[i+1] == ' '? 0 : -1); 1160 } 1161 1162 readtape(buffer) 1163 char *buffer; 1164 { 1165 char *bufp; 1166 1167 if (first == 0) 1168 getbuf(); 1169 (void) readtbuf(&bufp, TBLOCK); 1170 bcopy(bufp, buffer, TBLOCK); 1171 return(TBLOCK); 1172 } 1173 1174 readtbuf(bufpp, size) 1175 char **bufpp; 1176 int size; 1177 { 1178 register int i; 1179 1180 if (recno >= nblock || first == 0) { 1181 if ((i = bread(mt, (char *)tbuf, TBLOCK*nblock)) < 0) 1182 mterr("read", i, 3); 1183 if (first == 0) { 1184 if ((i % TBLOCK) != 0) { 1185 fprintf(stderr, "tar: tape blocksize error\n"); 1186 done(3); 1187 } 1188 i /= TBLOCK; 1189 if (i != nblock) { 1190 fprintf(stderr, "tar: blocksize = %d\n", i); 1191 nblock = i; 1192 } 1193 first = 1; 1194 } 1195 recno = 0; 1196 } 1197 if (size > ((nblock-recno)*TBLOCK)) 1198 size = (nblock-recno)*TBLOCK; 1199 *bufpp = (char *)&tbuf[recno]; 1200 recno += (size/TBLOCK); 1201 return (size); 1202 } 1203 1204 writetbuf(buffer, n) 1205 register char *buffer; 1206 register int n; 1207 { 1208 int i; 1209 1210 if (first == 0) { 1211 getbuf(); 1212 first = 1; 1213 } 1214 if (recno >= nblock) { 1215 i = write(mt, (char *)tbuf, TBLOCK*nblock); 1216 if (i != TBLOCK*nblock) 1217 mterr("write", i, 2); 1218 recno = 0; 1219 } 1220 1221 /* 1222 * Special case: We have an empty tape buffer, and the 1223 * users data size is >= the tape block size: Avoid 1224 * the bcopy and dma direct to tape. BIG WIN. Add the 1225 * residual to the tape buffer. 1226 */ 1227 while (recno == 0 && n >= nblock) { 1228 i = write(mt, buffer, TBLOCK*nblock); 1229 if (i != TBLOCK*nblock) 1230 mterr("write", i, 2); 1231 n -= nblock; 1232 buffer += (nblock * TBLOCK); 1233 } 1234 1235 while (n-- > 0) { 1236 bcopy(buffer, (char *)&tbuf[recno++], TBLOCK); 1237 buffer += TBLOCK; 1238 if (recno >= nblock) { 1239 i = write(mt, (char *)tbuf, TBLOCK*nblock); 1240 if (i != TBLOCK*nblock) 1241 mterr("write", i, 2); 1242 recno = 0; 1243 } 1244 } 1245 1246 /* Tell the user how much to write to get in sync */ 1247 return (nblock - recno); 1248 } 1249 1250 backtape() 1251 { 1252 static int mtdev = 1; 1253 static struct mtop mtop = {MTBSR, 1}; 1254 struct mtget mtget; 1255 1256 if (mtdev == 1) 1257 mtdev = ioctl(mt, MTIOCGET, (char *)&mtget); 1258 if (mtdev == 0) { 1259 if (ioctl(mt, MTIOCTOP, (char *)&mtop) < 0) { 1260 fprintf(stderr, "tar: tape backspace error: %s\n", 1261 strerror(errno)); 1262 done(4); 1263 } 1264 } else 1265 (void)lseek(mt, (daddr_t) -TBLOCK*nblock, 1); 1266 recno--; 1267 } 1268 1269 flushtape() 1270 { 1271 int i; 1272 1273 i = write(mt, (char *)tbuf, TBLOCK*nblock); 1274 if (i != TBLOCK*nblock) 1275 mterr("write", i, 2); 1276 } 1277 1278 mterr(operation, i, exitcode) 1279 char *operation; 1280 int i; 1281 { 1282 fprintf(stderr, "tar: tape %s error: %s\n", 1283 operation, i < 0 ? strerror(errno) : "unexpected EOF"); 1284 done(exitcode); 1285 } 1286 1287 bread(fd, buf, size) 1288 int fd; 1289 char *buf; 1290 int size; 1291 { 1292 int count; 1293 static int lastread = 0; 1294 1295 if (!Bflag) 1296 return (read(fd, buf, size)); 1297 1298 for (count = 0; count < size; count += lastread) { 1299 lastread = read(fd, buf, size - count); 1300 if (lastread <= 0) { 1301 if (count > 0) 1302 return (count); 1303 return (lastread); 1304 } 1305 buf += lastread; 1306 } 1307 return (count); 1308 } 1309 1310 char * 1311 cwd() 1312 { 1313 char *p; 1314 1315 p = getcwd((char *)NULL, 0); 1316 if (p == NULL) { 1317 (void)fprintf(stderr, "tar: %s\n", strerror(errno)); 1318 exit(1); 1319 } 1320 return (p); 1321 } 1322 1323 getbuf() 1324 { 1325 1326 if (nblock == 0) { 1327 fstat(mt, &stbuf); 1328 if ((stbuf.st_mode & S_IFMT) == S_IFCHR) 1329 nblock = NBLOCK; 1330 else { 1331 nblock = stbuf.st_blksize / TBLOCK; 1332 if (nblock == 0) 1333 nblock = NBLOCK; 1334 } 1335 } 1336 tbuf = (union hblock *)malloc((unsigned)nblock*TBLOCK); 1337 if (tbuf == NULL) { 1338 fprintf(stderr, "tar: blocksize %d too big, can't get memory\n", 1339 nblock); 1340 done(1); 1341 } 1342 } 1343 1344 /* 1345 * Save this directory and its mtime on the stack, popping and setting 1346 * the mtimes of any stacked dirs which aren't parents of this one. 1347 * A null directory causes the entire stack to be unwound and set. 1348 * 1349 * Since all the elements of the directory "stack" share a common 1350 * prefix, we can make do with one string. We keep only the current 1351 * directory path, with an associated array of mtime's, one for each 1352 * '/' in the path. A negative mtime means no mtime. The mtime's are 1353 * offset by one (first index 1, not 0) because calling this with a null 1354 * directory causes mtime[0] to be set. 1355 * 1356 * This stack algorithm is not guaranteed to work for tapes created 1357 * with the 'r' option, but the vast majority of tapes with 1358 * directories are not. This avoids saving every directory record on 1359 * the tape and setting all the times at the end. 1360 */ 1361 char dirstack[NAMSIZ]; 1362 #define NTIM (NAMSIZ/2+1) /* a/b/c/d/... */ 1363 time_t mtime[NTIM]; 1364 1365 dodirtimes(hp) 1366 union hblock *hp; 1367 { 1368 register char *p = dirstack; 1369 register char *q = hp->dbuf.name; 1370 register int ndir = 0; 1371 char *savp; 1372 int savndir; 1373 1374 /* Find common prefix */ 1375 while (*p == *q && *p) { 1376 if (*p++ == '/') 1377 ++ndir; 1378 q++; 1379 } 1380 1381 savp = p; 1382 savndir = ndir; 1383 while (*p) { 1384 /* 1385 * Not a child: unwind the stack, setting the times. 1386 * The order we do this doesn't matter, so we go "forward." 1387 */ 1388 if (*p++ == '/') 1389 if (mtime[++ndir] >= 0) { 1390 *--p = '\0'; /* zap the slash */ 1391 setimes(dirstack, mtime[ndir]); 1392 *p++ = '/'; 1393 } 1394 } 1395 p = savp; 1396 ndir = savndir; 1397 1398 /* Push this one on the "stack" */ 1399 while (*p = *q++) /* append the rest of the new dir */ 1400 if (*p++ == '/') 1401 mtime[++ndir] = -1; 1402 mtime[ndir] = stbuf.st_mtime; /* overwrite the last one */ 1403 } 1404 1405 setimes(path, mt) 1406 char *path; 1407 time_t mt; 1408 { 1409 struct timeval tv[2]; 1410 1411 tv[0].tv_sec = time((time_t *) 0); 1412 tv[1].tv_sec = mt; 1413 tv[0].tv_usec = tv[1].tv_usec = 0; 1414 if (utimes(path, tv) < 0) 1415 fprintf(stderr, "tar: can't set time on %s: %s\n", 1416 path, strerror(errno)); 1417 } 1418 1419 char * 1420 getmem(size) 1421 { 1422 char *p = malloc((unsigned) size); 1423 1424 if (p == NULL && freemem) { 1425 fprintf(stderr, 1426 "tar: out of memory, link and directory modtime info lost\n"); 1427 freemem = 0; 1428 } 1429 return (p); 1430 } 1431