|
|
1.1 ! root 1: /* ! 2: * Tape archive ! 3: * tar [0-7bcflmrtuvwx]+ [blocks] [archive] pathname* ! 4: */ ! 5: ! 6: #include <stdio.h> ! 7: #include <sys/types.h> ! 8: #include <errno.h> ! 9: #include <canon.h> ! 10: #include <sys/stat.h> ! 11: #include <sys/dir.h> ! 12: ! 13: #define S_PERM 07777 /* should be in stat.h */ ! 14: ! 15: /* Possible actions for do_checksum_error(). */ ! 16: #define CLEAR 0 /* Print all pending messages. */ ! 17: #define ADD 1 /* Add another pending message. */ ! 18: ! 19: #define MAXBLK 20 ! 20: #define roundup(n, r) (((n)+(r)-1)/(r)) ! 21: ! 22: typedef struct dirhd_t { ! 23: dev_t t_dev; ! 24: ino_t t_ino; ! 25: unsigned short t_nlink, ! 26: t_mode, ! 27: t_uid, ! 28: t_gid; ! 29: fsize_t t_size; ! 30: time_t t_mtime; ! 31: char *t_name; ! 32: struct dirhd_t *t_cont[]; ! 33: } dirhd_t; ! 34: ! 35: typedef union tarhd_t { ! 36: struct { ! 37: char th_name[100], ! 38: th_mode[8], ! 39: th_uid[8], ! 40: th_gid[8], ! 41: th_size[12], ! 42: th_mtime[12], ! 43: th_check[8], ! 44: th_islink, ! 45: th_link[100], ! 46: th_pad[255]; ! 47: } th_info; ! 48: char th_data[BUFSIZ]; ! 49: } tarhd_t; ! 50: ! 51: typedef unsigned short flag_t; /* fastest type for machine */ ! 52: ! 53: flag_t linkmsg = 0, /* message if not all links found */ ! 54: modtime = 1, /* restore modtimes */ ! 55: verbose = 0; ! 56: unixbug = 0; /* avoid bug in U**X tar */ ! 57: FILE *whether = (FILE *)NULL, /* ask about each file */ ! 58: *tarfile; ! 59: char tapedev[10] = '\0'; ! 60: char *archive = &tapedev[0]; ! 61: unsigned short blocking = 1; /* blocking factor */ ! 62: time_t oldtime[2], /* for utime */ ! 63: recently, /* set to 6 months ago for tv key */ ! 64: time(); ! 65: ! 66: dirhd_t *newdirhd(), ! 67: *update(), ! 68: *research(); ! 69: tarhd_t *readhdr(), ! 70: *readblk(), ! 71: *writeblk(); ! 72: char *havelink(); ! 73: long getoctl(); ! 74: extern char *malloc(); ! 75: extern char *ctime(); ! 76: ! 77: main(argc, argv) ! 78: int argc; ! 79: char *argv[]; ! 80: { ! 81: char *key, ! 82: unit = '\0', ! 83: function = 0, ! 84: deffunc, ! 85: prefix[101] = '\0'; ! 86: unsigned short arg = 2; ! 87: dirhd_t *args; ! 88: ! 89: if (argc < 2) { ! 90: fprintf(stderr, ! 91: "Usage: %s [crtux][0-7bflmvw] [blocks] [archive] pathname*\n", ! 92: argv[0]); ! 93: exit(-1); ! 94: } ! 95: for (key = argv[1]; *key != '\0'; key++) switch (*key) { ! 96: case '0': ! 97: case '1': ! 98: case '2': ! 99: case '3': ! 100: case '4': ! 101: case '5': ! 102: case '6': ! 103: case '7': ! 104: unit = *key; ! 105: deffunc = 't'; ! 106: continue; ! 107: case 'b': ! 108: if (argc <= arg) ! 109: fatal("missing blocking factor"); ! 110: else if ((blocking = atoi(argv[arg++])) <= 0 ! 111: || blocking > MAXBLK) ! 112: fatal("illegal blocking factor"); ! 113: deffunc = 'r'; ! 114: continue; ! 115: case 'f': ! 116: if (argc <= arg) ! 117: fatal("missing archive name"); ! 118: else ! 119: archive = argv[arg++]; ! 120: deffunc = 't'; ! 121: continue; ! 122: case 'l': ! 123: linkmsg = 1; ! 124: deffunc = 'r'; ! 125: continue; ! 126: case 'm': ! 127: modtime = 0; ! 128: deffunc = 'x'; ! 129: continue; ! 130: case 'v': ! 131: verbose = 1; ! 132: deffunc = 't'; ! 133: continue; ! 134: case 'U': ! 135: unixbug = 1; ! 136: deffunc = 't'; ! 137: continue; ! 138: case 'w': ! 139: whether = fopen("/dev/tty", "r+w"); ! 140: deffunc = 'x'; ! 141: continue; ! 142: case 'c': ! 143: case 'r': ! 144: case 't': ! 145: case 'u': ! 146: case 'x': ! 147: if (function) ! 148: fatal("keys c, r, t, u, x are mutually exclusive"); ! 149: else ! 150: function = *key; ! 151: continue; ! 152: default: ! 153: fatal("illegal key '%c'", *key); ! 154: } ! 155: if (!function) ! 156: function = deffunc; ! 157: oldtime[0] = time((time_t *)0); ! 158: if (verbose && function=='t') ! 159: recently = oldtime[0] - 6*((time_t)30*24*60*60); ! 160: ! 161: /* construct descriptors for args given */ ! 162: ! 163: args = (dirhd_t *) malloc(sizeof (dirhd_t) ! 164: + (argc-arg)*sizeof (dirhd_t *)); ! 165: if (args == NULL) ! 166: fatal("out of memory"); ! 167: args->t_mode = S_IFDIR; ! 168: args->t_nlink = 0; ! 169: for (; arg < argc; arg++) { ! 170: dirhd_t *argp; ! 171: ! 172: if ((argp = newdirhd(argv[arg], strlen(argv[arg]))) == NULL) ! 173: fprintf(stderr, "Tar: %s: out of memory\n", argv[arg]); ! 174: else ! 175: args->t_cont[args->t_nlink++] = argp; ! 176: } ! 177: ! 178: /* open archive file */ ! 179: ! 180: if (*archive == '\0') ! 181: sprintf(archive, "/dev/%smt%c", blocking==1 ? "" : "r", unit); ! 182: if (function=='t' || function=='x') ! 183: if (strcmp(archive, "-")==0) ! 184: tarfile = stdin; ! 185: else ! 186: tarfile = fopen(archive, "r"); ! 187: else if (function=='c') ! 188: if (strcmp(archive, "-")==0) ! 189: tarfile = stdout; ! 190: else ! 191: tarfile = fopen(archive, "w"); ! 192: else ! 193: tarfile = fopen(archive, "r+w"); ! 194: if (tarfile==NULL) { ! 195: exit(perror("Tar: 1: %s", archive)); ! 196: } ! 197: setbuf(tarfile, NULL); ! 198: ! 199: /* perform required function */ ! 200: ! 201: switch (function) { ! 202: case 't': ! 203: table(args); ! 204: break; ! 205: case 'x': ! 206: extract(args); ! 207: break; ! 208: case 'r': ! 209: while (readblk() != NULL) ! 210: ; ! 211: goto doappend; ! 212: case 'u': ! 213: if ((args = update(prefix, args, readhdr())) == NULL) ! 214: break; ! 215: case 'c': ! 216: doappend: ! 217: append(prefix, args); ! 218: flushtar(); ! 219: } ! 220: /* Flush any remaining checksum messages. */ ! 221: do_checksum_error(NULL, CLEAR); ! 222: ! 223: exit(errno); ! 224: } ! 225: ! 226: fatal(args) ! 227: char *args; ! 228: { ! 229: /* Flush any remaining checksum messages. */ ! 230: do_checksum_error(NULL, CLEAR); ! 231: ! 232: fprintf(stderr, "tar: %r\n", &args); ! 233: exit(-1); ! 234: } ! 235: ! 236: dirhd_t * ! 237: newdirhd(name, len) ! 238: register char *name; ! 239: unsigned short len; ! 240: { ! 241: register dirhd_t *dp; ! 242: ! 243: if ((dp = (dirhd_t *) malloc(sizeof (dirhd_t))) != NULL ! 244: && (dp->t_name = malloc(len+1)) == NULL) { ! 245: free(dp); ! 246: dp = NULL; ! 247: } ! 248: if (dp != NULL) { ! 249: dp->t_nlink = 0; ! 250: strncpy(dp->t_name, name, len); ! 251: dp->t_name[len] = '\0'; ! 252: } ! 253: return (dp); ! 254: } ! 255: int ! 256: perror(args) ! 257: char *args; ! 258: { ! 259: register int err; ! 260: ! 261: if ((err=errno) >= sys_nerr) ! 262: fprintf(stderr, "%r: Bad error number\n", &args); ! 263: else if (err) ! 264: fprintf(stderr, "%r: %s\n", &args, sys_errlist[err]); ! 265: return (err); ! 266: } ! 267: ! 268: table(args) ! 269: register dirhd_t *args; ! 270: { ! 271: register tarhd_t *header; ! 272: ! 273: for (; (header = readhdr()) != NULL; skipfile(header)) { ! 274: if (argcont(args, header->th_info.th_name, 0) < 0) ! 275: continue; ! 276: if (verbose) { ! 277: register unsigned short mode = getoct(header->th_info.th_mode); ! 278: unsigned short uid = getoct(header->th_info.th_uid), ! 279: gid = getoct(header->th_info.th_gid); ! 280: fsize_t size = getoctl(header->th_info.th_size); ! 281: time_t mtime = getoctl(header->th_info.th_mtime); ! 282: char *timestr = ctime(&mtime); ! 283: ! 284: if (header->th_info.th_name[strnlen(header->th_info.th_name, 100)-1] ! 285: == '/') ! 286: putchar('d'); ! 287: else ! 288: putchar('-'); ! 289: printf("%c%c%c", ! 290: mode&S_IREAD ? 'r' : '-', ! 291: mode&S_IWRITE ? 'w' : '-', ! 292: mode&S_ISUID ? 's' : ! 293: mode&S_IEXEC ? 'x' : '-'); ! 294: printf("%c%c%c", ! 295: mode&S_IREAD>>3 ? 'r' : '-', ! 296: mode&S_IWRITE>>3 ? 'w' : '-', ! 297: mode&S_ISGID ? 's' : ! 298: mode&S_IEXEC>>3 ? 'x' : '-'); ! 299: printf("%c%c%c", ! 300: mode&S_IREAD>>6 ? 'r' : '-', ! 301: mode&S_IWRITE>>6 ? 'w' : '-', ! 302: mode&S_ISVTX ? 't' : ! 303: mode&S_IEXEC>>6 ? 'x' : '-'); ! 304: printf("%3d %3d %6ld %.11s%.5s ", ! 305: gid, ! 306: uid, ! 307: size, ! 308: timestr, ! 309: mtime > recently ? timestr+11 : timestr+19); ! 310: } ! 311: printf("%.100s", header->th_info.th_name); ! 312: if (header->th_info.th_islink) ! 313: if (verbose) ! 314: printf("\n%33s link to %s\n", "", ! 315: header->th_info.th_link); ! 316: else ! 317: printf(" link to %s\n", header->th_info.th_link); ! 318: else ! 319: putchar('\n'); ! 320: } ! 321: } ! 322: ! 323: extract(args) ! 324: register dirhd_t *args; ! 325: { ! 326: register tarhd_t *header; ! 327: short skipping = 0; ! 328: ! 329: while ((header = readhdr()) != NULL) { ! 330: register char name[101]; ! 331: unsigned short namelen = strnlen(header->th_info.th_name, 100), ! 332: mode, ! 333: uid, ! 334: gid; ! 335: ! 336: if (!skipping || contains(name, header->th_info.th_name) >= 0) { ! 337: strncpy(name, header->th_info.th_name, namelen); ! 338: name[namelen--] = '\0'; ! 339: if ((skipping = argcont(args, name, 0)) >= 0) ! 340: skipping = disallow('x', name); ! 341: } ! 342: switch (skipping) { ! 343: case -1: ! 344: skipping = 0; ! 345: case 1: ! 346: skipfile(header); ! 347: continue; ! 348: } ! 349: if (verbose) ! 350: printf("x %s\n", name); ! 351: mode = getoct(header->th_info.th_mode); ! 352: uid = getoct(header->th_info.th_uid); ! 353: gid = getoct(header->th_info.th_gid); ! 354: oldtime[1] = getoctl(header->th_info.th_mtime); ! 355: if (name[namelen] == '/') { ! 356: name[namelen] = '\0'; ! 357: makepath(name); ! 358: chmod(name, mode); ! 359: name[namelen] = '/'; ! 360: } else if (header->th_info.th_islink == '\0') { ! 361: int fd = recreate(name, mode); ! 362: fsize_t size = getoctl(header->th_info.th_size); ! 363: ! 364: for (; size > 0; size -= sizeof (tarhd_t)) { ! 365: int my_size; ! 366: ! 367: /* Handle unexpected EOF - mods by [email protected] */ ! 368: if ((header = readblk()) == NULL) { ! 369: fprintf(stderr, ! 370: "Unexpected end of the file %s\n", ! 371: name); ! 372: break; ! 373: } ! 374: if (size > sizeof(tarhd_t)) ! 375: my_size = sizeof(tarhd_t); ! 376: else ! 377: my_size = (int) size; ! 378: if (fd >= 0 && (write(fd, header->th_data, ! 379: my_size) != my_size)) ! 380: ! 381: perror("Tar: 2: %s", name); ! 382: } ! 383: if (fd >= 0) ! 384: close(fd); ! 385: } else { ! 386: struct stat statbuf; ! 387: flag_t xlink = 1; ! 388: ! 389: if (stat(header->th_info.th_link, &statbuf) < 0) ! 390: close(recreate(header->th_info.th_link, mode)); ! 391: else if (havelink(statbuf.st_dev, statbuf.st_ino, 0) ! 392: != NULL) ! 393: xlink = 0; ! 394: if (xlink) ! 395: fprintf(stderr, "Tar: Must extract %s\n", ! 396: header->th_info.th_link); ! 397: unlink(name); ! 398: mkparent(name); ! 399: if (link(header->th_info.th_link, name) < 0) ! 400: fprintf(stderr, "Tar: Can't link %s to %s\n", ! 401: name, header->th_info.th_link); ! 402: } ! 403: if (modtime) ! 404: utime(name, oldtime); ! 405: chown(name, uid, gid); ! 406: } ! 407: } ! 408: ! 409: dirhd_t * ! 410: update(name, args, header) ! 411: char *name; ! 412: register dirhd_t *args; ! 413: tarhd_t *header; ! 414: { ! 415: unsigned short namelen = strlen(name); ! 416: flag_t donedir = 0; ! 417: ! 418: if (header == NULL) ! 419: return (args); ! 420: if (args->t_nlink == 0 && (args = research(name, args)) == NULL) ! 421: return (NULL); ! 422: do switch (args->t_mode&S_IFMT) { ! 423: register short arg; ! 424: register dirhd_t *argp; ! 425: ! 426: case S_IFREG: ! 427: if (args->t_mtime <= getoctl(header->th_info.th_mtime)) ! 428: args->t_nlink = 0; ! 429: skipfile(header); ! 430: continue; ! 431: case S_IFDIR: ! 432: if (namelen != 0 && !donedir) { ! 433: name[namelen] = '/'; ! 434: donedir++; ! 435: } ! 436: if ((arg = argcont(args, header->th_info.th_name+namelen+donedir, -1)) ! 437: >= 0) { ! 438: strcpy(name+namelen+donedir, ! 439: (argp=args->t_cont[arg])->t_name); ! 440: if ((args->t_cont[arg] = update(name, argp, header)) ! 441: == NULL) ! 442: args->t_cont[arg] ! 443: = args->t_cont[--args->t_nlink]; ! 444: } else ! 445: skipfile(header); ! 446: name[namelen+donedir] = '\0'; ! 447: } while ((header=readhdr()) != NULL ! 448: && contains(name, header->th_info.th_name)); ! 449: if (header != NULL) ! 450: ungetblk(); ! 451: if (args->t_nlink == 0) { ! 452: if (namelen != 0) ! 453: free(args->t_name); ! 454: free((char *) args); ! 455: return (NULL); ! 456: } else ! 457: return (args); ! 458: } ! 459: ! 460: append(name, args) ! 461: char *name; ! 462: register dirhd_t *args; ! 463: { ! 464: unsigned short namelen; ! 465: register unsigned short arg; ! 466: register dirhd_t *argp; ! 467: ! 468: if ((namelen = strlen(name)) != 0 && disallow('a', name)) ! 469: return; ! 470: if (args->t_nlink == 0 && (args = research(name, args)) == NULL) ! 471: return; ! 472: switch (args->t_mode&S_IFMT) { ! 473: case S_IFDIR: ! 474: if (namelen != 0) { ! 475: name[namelen++] = '/'; name[namelen] = '\0'; ! 476: writehdr(name, args, ""); ! 477: } ! 478: for (arg = 0; arg < args->t_nlink; arg++) { ! 479: strcpy(name+namelen, (argp=args->t_cont[arg])->t_name); ! 480: append(name, argp); ! 481: } ! 482: break; ! 483: case S_IFREG: ! 484: if (args->t_nlink != 1) { ! 485: char *link; ! 486: ! 487: if ((link=havelink(args->t_dev, ! 488: args->t_ino, 1))!=NULL) { ! 489: writehdr(name, args, link); ! 490: break; ! 491: } else { ! 492: filelink(args->t_dev, ! 493: args->t_ino, ! 494: args->t_nlink, ! 495: name); ! 496: } ! 497: } ! 498: writehdr(name, args, ""); ! 499: writefil(name, args->t_size); ! 500: } ! 501: if (namelen != 0) ! 502: free(args->t_name); ! 503: free((char *) args); ! 504: } ! 505: ! 506: dirhd_t * ! 507: research(name, args) ! 508: char *name; ! 509: register dirhd_t *args; ! 510: { ! 511: unsigned short namelen; ! 512: register short nfile; ! 513: int fd; ! 514: struct stat statbuf; ! 515: ! 516: if ((namelen = strlen(name)) == 0) ! 517: name = "."; ! 518: if (stat(name, &statbuf) < 0) { ! 519: perror("Tar: 3: %s", name); ! 520: return (args); ! 521: } ! 522: args->t_dev = statbuf.st_dev; ! 523: args->t_ino = statbuf.st_ino; ! 524: args->t_nlink = statbuf.st_nlink; ! 525: args->t_uid = statbuf.st_uid; ! 526: args->t_gid = statbuf.st_gid; ! 527: args->t_mtime = statbuf.st_mtime; ! 528: switch ((args->t_mode = statbuf.st_mode)&S_IFMT) { ! 529: case S_IFREG: ! 530: args->t_size = statbuf.st_size; ! 531: return (args); ! 532: default: ! 533: args->t_size = 0; ! 534: return (args); ! 535: case S_IFDIR: ! 536: args->t_size = 0; ! 537: } ! 538: if ((nfile = (short) (statbuf.st_size/sizeof (struct direct))) > 2) { ! 539: args = (dirhd_t *) realloc((char *)args, ! 540: sizeof (dirhd_t) + (nfile-2)*sizeof (dirhd_t *)); ! 541: if (args == NULL) { ! 542: fprintf(stderr, "Tar: %s: out of memory\n", name); ! 543: return (NULL); ! 544: } ! 545: } ! 546: args->t_nlink = 0; ! 547: if ((fd = open(name, 0)) < 0) { ! 548: perror("Tar: 4: %s", name); ! 549: return (args); ! 550: } ! 551: for (; nfile > 0; --nfile) { ! 552: struct direct dir_ent; ! 553: unsigned short arglen; ! 554: dirhd_t *argp; ! 555: ! 556: switch (read(fd, (char *)&dir_ent, sizeof (struct direct))) { ! 557: case -1: ! 558: perror("Tar: 5: %s", name); ! 559: case 0: ! 560: break; ! 561: default: ! 562: if (dir_ent.d_ino == 0 ! 563: || strcmp(dir_ent.d_name, ".") == 0 ! 564: || strcmp(dir_ent.d_name, "..") == 0) ! 565: continue; ! 566: else if ((arglen=strnlen(dir_ent.d_name, DIRSIZ)) ! 567: + namelen > 99) ! 568: fprintf(stderr, ! 569: "Tar: %s/%.*s: name too long\n", ! 570: name, DIRSIZ, dir_ent.d_name); ! 571: else if ((argp = newdirhd(dir_ent.d_name, arglen)) ! 572: == NULL) ! 573: fprintf(stderr, ! 574: "Tar: %s/%.*s: out of memory\n", ! 575: name, DIRSIZ, dir_ent.d_name); ! 576: else ! 577: args->t_cont[args->t_nlink++] = argp; ! 578: continue; ! 579: } ! 580: break; ! 581: } ! 582: close(fd); ! 583: return (args); ! 584: } ! 585: ! 586: int ! 587: argcont(args, name, ret) ! 588: register dirhd_t *args; ! 589: char *name; ! 590: int ret; ! 591: { ! 592: register unsigned short arg; ! 593: ! 594: if (args->t_nlink == 0) ! 595: return (ret); ! 596: else for (arg = 0; arg < args->t_nlink; arg++) ! 597: if (contains(args->t_cont[arg]->t_name, name)) ! 598: return (arg); ! 599: return (-1); ! 600: } ! 601: ! 602: int ! 603: strnlen(str, maxlen) ! 604: register char *str; ! 605: register unsigned short maxlen; ! 606: { ! 607: register unsigned short len = 0; ! 608: ! 609: while (maxlen && *str++ != '\0') { ! 610: --maxlen; ++len; ! 611: } ! 612: return (len); ! 613: } ! 614: ! 615: /* ! 616: * Create file system paths ! 617: */ ! 618: ! 619: int ! 620: makepath(pathname) ! 621: char *pathname; ! 622: { ! 623: struct stat statbuf; ! 624: register int err; ! 625: ! 626: if (stat(pathname, &statbuf) == 0) ! 627: if ((statbuf.st_mode&S_IFMT) == S_IFDIR) ! 628: return (0); ! 629: else ! 630: errno = ENOTDIR; ! 631: else if (errno == ENOENT) { ! 632: errno = 0; ! 633: if ((err=mkparent(pathname)) != 0) ! 634: return err; ! 635: return mkdir(pathname); ! 636: } ! 637: return (perror("Tar: 6: %s", pathname)); ! 638: } ! 639: ! 640: int ! 641: mkparent(pathname) ! 642: register char *pathname; ! 643: { ! 644: register char *pathend = &pathname[strlen(pathname)]; ! 645: ! 646: while (pathend > pathname && *--pathend != '/') ! 647: ; ! 648: if (pathend > pathname) { ! 649: *pathend = '\0'; ! 650: errno = makepath(pathname); ! 651: *pathend = '/'; ! 652: } else ! 653: errno = 0; ! 654: return (errno); ! 655: } ! 656: ! 657: mkdir(pathname) ! 658: char *pathname; ! 659: { ! 660: int status; ! 661: ! 662: switch(fork()) { ! 663: case -1: ! 664: break; ! 665: case 0: ! 666: close(2); ! 667: execl("/bin/mkdir", "mkdir", pathname, NULL); ! 668: exit(errno); ! 669: default: ! 670: wait(&status); ! 671: errno = status>>8; ! 672: } ! 673: return (perror("Tar: 7: %s", pathname)); ! 674: } ! 675: ! 676: int ! 677: recreate(pathname, mode) ! 678: char *pathname; ! 679: unsigned short mode; ! 680: { ! 681: int fd; ! 682: ! 683: if ((fd = create(pathname, mode)) < 0 ! 684: && (errno != ENOENT ! 685: || mkparent(pathname) == 0 && (fd = create(pathname, mode)) < 0)) ! 686: perror("Tar: 8: %s", pathname); ! 687: errno = 0; ! 688: return (fd); ! 689: } ! 690: ! 691: int ! 692: create(pathname, mode) ! 693: char *pathname; ! 694: unsigned short mode; ! 695: { ! 696: int fd; ! 697: ! 698: unlink(pathname); ! 699: if ((fd = creat(pathname, mode)) >= 0) { ! 700: struct stat statbuf; ! 701: ! 702: fstat(fd, &statbuf); ! 703: filelink(statbuf.st_dev, statbuf.st_ino, ! 704: statbuf.st_nlink, pathname); ! 705: } ! 706: return (fd); ! 707: } ! 708: ! 709: /* ! 710: * Ask about current action ! 711: */ ! 712: ! 713: int ! 714: disallow(function, pathname) ! 715: char function, ! 716: *pathname; ! 717: { ! 718: while (whether) { ! 719: register int c1, ! 720: c; ! 721: ! 722: fprintf(whether, "%c %s? ", function, pathname); ! 723: for (c1=c=getc(whether); c!=EOF && c!='\n'; c=getc(whether)) ! 724: ; ! 725: switch (c1) { ! 726: case EOF: ! 727: case 'x': ! 728: if (function == 'a') ! 729: flushtar(); ! 730: exit(errno); ! 731: case '\n': ! 732: case 'n': ! 733: case 'N': ! 734: return (1); ! 735: case 'y': ! 736: case 'Y': ! 737: return (0); ! 738: } ! 739: } ! 740: return (0); ! 741: } ! 742: ! 743: /* ! 744: * High level I/O routines ! 745: */ ! 746: ! 747: tarhd_t * ! 748: readhdr() ! 749: { ! 750: register tarhd_t *header; ! 751: ! 752: while ((header = readblk()) != NULL) { ! 753: if (header->th_info.th_name[0] == '\0') ! 754: if (unixbug) { ! 755: ungetblk(); ! 756: return (NULL); ! 757: } else ! 758: continue; ! 759: else { ! 760: int check = getoct(header->th_info.th_check); ! 761: ! 762: strncpy(header->th_info.th_check, " ", ! 763: sizeof(header->th_info.th_check)); ! 764: if (checksum(header->th_data, sizeof(tarhd_t)) != check){ ! 765: do_checksum_error(header->th_info.th_name, ADD); ! 766: } else { ! 767: do_checksum_error(NULL, CLEAR); ! 768: break; ! 769: } ! 770: } ! 771: } ! 772: /* We shouldn't have to check EVERY header, but if we do it here ! 773: * it gets done for every routine. ! 774: * Newer tar programs use the first eight bytes of the ! 775: * pad field as magic to indicate the type of archive. ! 776: * With old tar archives, these eight characters should be ! 777: * NUL. We'll only check the first one. ! 778: */ ! 779: /* Check to see if this is a v7 style tar archive. */ ! 780: if ((char)0 != header->th_info.th_pad[0]) { ! 781: fatal("%.8s archive, not v7 archive.", ! 782: header->th_info.th_pad); ! 783: ! 784: } ! 785: return (header); ! 786: } ! 787: ! 788: skipfile(header) ! 789: tarhd_t *header; ! 790: { ! 791: register fsize_t size; ! 792: ! 793: if (header->th_info.th_islink) ! 794: return; ! 795: for (size = getoctl(header->th_info.th_size); ! 796: size > 0 && readblk() != NULL; ! 797: size -= sizeof (tarhd_t)) ! 798: ; ! 799: } ! 800: ! 801: writehdr(name, args, link) ! 802: char *name; ! 803: register dirhd_t *args; ! 804: char *link; ! 805: { ! 806: register tarhd_t *header = writeblk(); ! 807: ! 808: if (verbose) ! 809: fprintf(stderr, "a %s", name); ! 810: strncpy(header->th_info.th_name, name, sizeof(header->th_info.th_name)); ! 811: putoct(header->th_info.th_mode, args->t_mode&S_PERM); ! 812: putoct(header->th_info.th_uid, args->t_uid); ! 813: putoct(header->th_info.th_gid, args->t_gid); ! 814: putoctl(header->th_info.th_size, args->t_size); ! 815: putoctl(header->th_info.th_mtime, args->t_mtime); ! 816: strncpy(header->th_info.th_check, " ", sizeof(header->th_info.th_check)); ! 817: if (*link == '\0') { ! 818: header->th_info.th_islink = 0; ! 819: if (verbose) ! 820: if (args->t_size == 0) ! 821: putc('\n', stderr); ! 822: else ! 823: fprintf(stderr, " %ld block%s\n", ! 824: roundup(args->t_size, BUFSIZ), ! 825: args->t_size <= BUFSIZ ? "" : "s"); ! 826: } else { ! 827: header->th_info.th_islink = '1'; ! 828: if (verbose) ! 829: fprintf(stderr, " link to %s\n", link); ! 830: } ! 831: strncpy(header->th_info.th_link, link, sizeof(header->th_info.th_link)); ! 832: strncpy(header->th_info.th_pad, "", sizeof(header->th_info.th_pad)); ! 833: putoct(header->th_info.th_check, checksum(header->th_data, sizeof(tarhd_t))); ! 834: } ! 835: ! 836: writefil(name, size) ! 837: char *name; ! 838: register fsize_t size; ! 839: { ! 840: int fd; ! 841: register tarhd_t *header; ! 842: ! 843: if ((fd = open(name, 0)) < 0) { ! 844: perror("Tar: 9: %s", name); ! 845: } ! 846: for (; size > 0; size -= sizeof (tarhd_t)) { ! 847: header = writeblk(); ! 848: if (fd >= 0) ! 849: read(fd, header->th_data, sizeof (tarhd_t)); ! 850: else ! 851: strncpy(header->th_data, "", sizeof (tarhd_t)); ! 852: } ! 853: if (fd >= 0) ! 854: close(fd); ! 855: } ! 856: ! 857: /* ! 858: * Tape I/O, with record blocking if specified ! 859: */ ! 860: ! 861: tarhd_t buffer[MAXBLK], ! 862: *current = &buffer[0]; ! 863: ! 864: tarhd_t * ! 865: readblk() ! 866: { ! 867: static unsigned short blocks = 0; ! 868: ! 869: if (feof(tarfile)) ! 870: return (NULL); ! 871: if (current == &buffer[blocks]) { ! 872: current = &buffer[0]; ! 873: blocks = fread((char *) buffer, ! 874: sizeof (tarhd_t), MAXBLK, tarfile); ! 875: if (ferror(tarfile)) { ! 876: exit(perror("Tar: 10: %s", archive)); ! 877: } else if (feof(tarfile)) { ! 878: /* This is a hack. We should actually find ! 879: * out why returning NULL is not good enough. ! 880: * ! 881: * Really a pain without a symbolic debugger! ! 882: */ ! 883: exit(0); ! 884: } ! 885: } ! 886: return (current++); ! 887: } ! 888: ! 889: ungetblk() ! 890: { ! 891: --current; ! 892: } ! 893: ! 894: tarhd_t * ! 895: writeblk() ! 896: { ! 897: if (current == &buffer[blocking]) { ! 898: current = &buffer[0]; ! 899: fwrite((char *)buffer, sizeof (tarhd_t), blocking, tarfile); ! 900: if (ferror(tarfile) || feof(tarfile)) { ! 901: exit(perror("Tar: 11: %s", archive)); ! 902: } ! 903: } ! 904: return (current++); ! 905: } ! 906: ! 907: flushtar() ! 908: { ! 909: register tarhd_t *header; ! 910: ! 911: while ((header=writeblk()) != &buffer[0]) ! 912: strncpy(header->th_data, "", sizeof (tarhd_t)); ! 913: if (linkmsg) ! 914: misslink(); ! 915: } ! 916: ! 917: /* ! 918: * Keep track of files by ino in hash table ! 919: */ ! 920: ! 921: typedef struct link_t { ! 922: dev_t t_dev; ! 923: ino_t t_ino; ! 924: unsigned short t_nlink; ! 925: struct link_t *t_next; ! 926: char t_link[]; ! 927: } link_t; ! 928: ! 929: #define NHASH 64 ! 930: ! 931: link_t *linklist[NHASH]; ! 932: ! 933: filelink(dev, ino, nlink, link) ! 934: dev_t dev; ! 935: ino_t ino; ! 936: unsigned short nlink; ! 937: char *link; ! 938: { ! 939: unsigned short id = ino%NHASH; ! 940: register link_t *lp; ! 941: ! 942: lp = (link_t *) malloc(sizeof (link_t) + strlen(link) + 1); ! 943: if (lp == NULL) ! 944: fprintf(stderr, "Tar: %s: note: link info lost\n", link); ! 945: else { ! 946: lp->t_next = linklist[id]; ! 947: linklist[id] = lp; ! 948: lp->t_dev = dev; ! 949: lp->t_ino = ino; ! 950: lp->t_nlink = nlink; ! 951: strcpy(lp->t_link, link); ! 952: } ! 953: } ! 954: ! 955: char * ! 956: havelink(dev, ino, flag) ! 957: dev_t dev; ! 958: ino_t ino; ! 959: flag_t flag; ! 960: { ! 961: register link_t *lp; ! 962: ! 963: for (lp = linklist[ino%NHASH]; lp != NULL; lp = lp->t_next) { ! 964: if (lp->t_ino == ino && lp->t_dev == dev) { ! 965: if (flag) ! 966: --lp->t_nlink; ! 967: return (lp->t_link); ! 968: } ! 969: } ! 970: return (NULL); ! 971: } ! 972: ! 973: misslink() ! 974: { ! 975: unsigned short ino; ! 976: ! 977: for (ino = 0; ino < NHASH; ino++) { ! 978: register link_t *lp; ! 979: ! 980: for (lp = linklist[ino]; lp != NULL; lp=lp->t_next) { ! 981: register short nlink; ! 982: ! 983: if (nlink = lp->t_nlink - 1) ! 984: fprintf(stderr, ! 985: "Tar: missed %d link%s to %s\n", ! 986: nlink, nlink==1 ? "" : "s", ! 987: lp->t_link); ! 988: } ! 989: } ! 990: } ! 991: ! 992: /* ! 993: * Read unsigned octal numbers ! 994: */ ! 995: ! 996: int ! 997: getoct(cp) ! 998: register char *cp; ! 999: { ! 1000: register int val = 0; ! 1001: register char c; ! 1002: ! 1003: while (*cp == ' ') ! 1004: cp++; ! 1005: while ((c = *cp++ - '0') >= 0 && c <= 7) ! 1006: val = val<<3 | c; ! 1007: return (val); ! 1008: } ! 1009: ! 1010: long ! 1011: getoctl(cp) ! 1012: register char *cp; ! 1013: { ! 1014: register long val = 0; ! 1015: register char c; ! 1016: ! 1017: while (*cp==' ') ! 1018: cp++; ! 1019: while ((c = *cp++ - '0') >= 0 && c <= 7) ! 1020: val = val<<3 | c; ! 1021: return (val); ! 1022: } ! 1023: ! 1024: /* ! 1025: * Write unsigned octal numbers ! 1026: * in fixed format ! 1027: */ ! 1028: ! 1029: putoct(str, val) ! 1030: char *str; ! 1031: unsigned short val; ! 1032: { ! 1033: register char *cp; ! 1034: ! 1035: *(cp = &str[7]) = '\0'; ! 1036: *--cp = ' '; ! 1037: *--cp = (val&07) + '0'; ! 1038: while (cp != str) ! 1039: *--cp = (val>>=3) ? (val&07) + '0' : ' '; ! 1040: } ! 1041: ! 1042: putoctl(str, val) ! 1043: char *str; ! 1044: register unsigned long val; ! 1045: { ! 1046: register char *cp; ! 1047: ! 1048: *(cp = &str[11]) = ' '; ! 1049: *--cp = (val&07) + '0'; ! 1050: while (cp != str) ! 1051: *--cp = (val>>=3) ? (val&07) + '0' : ' '; ! 1052: } ! 1053: ! 1054: /* ! 1055: * Compute checksum of string ! 1056: */ ! 1057: int ! 1058: checksum(str, len) ! 1059: register char *str; ! 1060: register int len; ! 1061: { ! 1062: register int check = 0; ! 1063: ! 1064: if (len) do ! 1065: check += *str++; ! 1066: while (--len); ! 1067: return (check); ! 1068: } ! 1069: ! 1070: /* ! 1071: * Return -1 if dname is a directory prefix of fname ! 1072: * 0 if no match ! 1073: * 1 if complete match ! 1074: */ ! 1075: int ! 1076: contains(dname, fname) ! 1077: register char *dname, ! 1078: *fname; ! 1079: { ! 1080: if (*dname=='\0') ! 1081: return (-1); ! 1082: while (*dname!='\0') ! 1083: if (*dname++ != *fname++) ! 1084: return (0); ! 1085: if (*fname=='\0') ! 1086: return (1); ! 1087: else if (*fname=='/' || *--fname=='/') ! 1088: return (-1); ! 1089: else ! 1090: return (0); ! 1091: } ! 1092: ! 1093: /* Handle the processing of a checksum error. ! 1094: * This is special because sometimes end of archive will look like ! 1095: * a lot of checksum errors. ! 1096: */ ! 1097: int ! 1098: do_checksum_error(name, action) ! 1099: char *name; ! 1100: int action; ! 1101: { ! 1102: #define MSG_SIZE (100 + sizeof("Tar: %.100s: bad checksum\n") + 1) ! 1103: #define MAX_CHECKERR 5 /* Give up after 5 consecutive checksum errors. */ ! 1104: ! 1105: static error_count = 0; /* Number of checksums we've seen. */ ! 1106: static char *msg_list = NULL; /* Error message we've queued. */ ! 1107: char tmp_buf[MSG_SIZE]; /* Someplace to build new errors. */ ! 1108: ! 1109: ! 1110: switch (action) { ! 1111: case ADD: ! 1112: /* If there have been too many checksum errors, or if ! 1113: * we can't allocate more memory for more error messages, ! 1114: * throw away the existing messages, and look for another ! 1115: * valid block. ! 1116: */ ! 1117: if (++error_count > MAX_CHECKERR || ! 1118: (msg_list = (char *)realloc(msg_list, ! 1119: strlen(msg_list) + MSG_SIZE +1)) == ! 1120: NULL) { ! 1121: fprintf(stderr, ! 1122: "Tar: %s: This doesn't look like a tar archive.\n", ! 1123: archive); ! 1124: free(msg_list); ! 1125: msg_list = 0; ! 1126: error_count = 0; ! 1127: fprintf(stderr, "Tar: Scanning for next file.\n"); ! 1128: scan_for_next(); ! 1129: } ! 1130: ! 1131: sprintf(tmp_buf, "Tar: %.100s: bad checksum\n", ! 1132: name); ! 1133: strcat(msg_list, tmp_buf); ! 1134: break; ! 1135: case CLEAR: ! 1136: if (NULL != msg_list) { ! 1137: fprintf(stderr, "%s", msg_list); ! 1138: free(msg_list); ! 1139: msg_list = NULL; ! 1140: } ! 1141: error_count = 0; ! 1142: break; ! 1143: } /* switch (action) */ ! 1144: } /* do_checksum_error() */ ! 1145: ! 1146: /* Find the next valid block. */ ! 1147: int ! 1148: scan_for_next() ! 1149: { ! 1150: int check; ! 1151: tarhd_t *header; ! 1152: ! 1153: while ( (header = readblk()) != NULL ) { ! 1154: check = getoct(header->th_info.th_check); ! 1155: ! 1156: strncpy(header->th_info.th_check, " ", ! 1157: sizeof(header->th_info.th_check)); ! 1158: if (checksum(header->th_data, sizeof(tarhd_t)) == check){ ! 1159: /* Found a good header! */ ! 1160: ungetblk(); ! 1161: return; ! 1162: } ! 1163: } /* while (more blocks to read) */ ! 1164: /* If we got here, it means we ran out of things to read. */ ! 1165: fatal("no more valid blocks"); ! 1166: ! 1167: } /* scan_for_next() */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.