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