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