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