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