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