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