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