home *** CD-ROM | disk | FTP | other *** search
- /*
- * tarx - manipulate damaged tar tapes heuristically
- */
-
- #include <stdio.h>
- #include <string.h>
-
- #define NAMSIZ 100 /* why isn't there a tar.h??? */
- #define FLAG (NAMSIZ+8+8+8+12+12+8) /* offset of is-a-link flag */
- struct matches {
- int offset;
- char value;
- } matches[] = { /* pattern-match table for header blocks */
- NAMSIZ+6, ' ',
- NAMSIZ+7, '\0',
- NAMSIZ+8+6, ' ',
- NAMSIZ+8+7, '\0',
- NAMSIZ+16+6, ' ',
- NAMSIZ+16+7, '\0',
- NAMSIZ+24+11, ' ',
- NAMSIZ+36+11, ' ',
- NAMSIZ+48+6, '\0',
- 0, 0,
- };
-
- #ifndef MAXBLOCK
- #define MAXBLOCK 400 /* SGI makes blocky tapes */
- #endif
- int maxblock = MAXBLOCK;
- #define BLOCK 512
-
- char *buf; /* -> malloced buffer */
- int nleft = 0; /* number of blocks left in buffer */
- int whichnow; /* index in buffer of current block */
-
- int nbad = 0; /* number of consecutive bad reads */
- int badlimit = 3; /* limit on consecutive bads */
- int neof = 0; /* number of consecutive EOF marks */
- int eoflimit = 2; /* limit on consecutive eofs */
-
- int opened = 0; /* are we writing a file? */
- int f; /* the file descriptor, if any */
- long fsize; /* number of bytes not yet written to file */
-
- char op = 'x'; /* what operation is being done? */
-
- #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
-
- #ifndef lint
- static char RCSid[] = "$Header$";
- #endif
-
- int debug = 0;
- char *progname;
-
- extern void exit();
- #ifdef UTZOOERR
- extern char *mkprogname();
- #else
- #define mkprogname(a) (a)
- #endif
-
- /*
- - main - parse arguments and handle options
- */
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int c;
- int errflg = 0;
- register char *block;
- extern char *readblock();
- extern char *malloc();
- extern int optind;
- extern char *optarg;
-
- progname = mkprogname(argv[0]);
-
- while ((c = getopt(argc, argv, "tb:e:E:d")) != EOF)
- switch (c) {
- case 't': /* just list files */
- op = 't';
- break;
- case 'b': /* set blocking factor */
- maxblock = atoi(optarg);
- break;
- case 'e': /* set error limit */
- badlimit = atoi(optarg);
- break;
- case 'E': /* set eof limit */
- eoflimit = atoi(optarg);
- break;
- case 'd': /* Debugging. */
- debug++;
- break;
- case '?':
- default:
- errflg++;
- break;
- }
- if (errflg) {
- fprintf(stderr, "usage: %s ", progname);
- fprintf(stderr, "[-t] [-b blockf] [-e errs] [-E eofs] [name] ...\n");
- exit(2);
- }
-
- buf = malloc(maxblock*BLOCK);
- if (buf == NULL) {
- fprintf(stderr, "%s: cannot allocate buffer of %d blocks\n",
- progname, maxblock);
- exit(1);
- }
-
- for(;;) {
- block = readblock(0);
-
- if (block != NULL)
- doblock(block, argc - optind, &argv[optind]);
- }
- /* NOTREACHED */
- }
-
- /*
- - readblock - read in a block and deal with error/eof
- */
- char *
- readblock(desc)
- int desc;
- {
- register int count;
- extern int errno;
- extern int sys_nerr;
- extern char *sys_errlist[];
-
- if (nleft > 0) {
- whichnow++;
- nleft--;
- return(buf+whichnow*BLOCK);
- }
-
- count = read(desc, buf, maxblock*BLOCK);
- if (count != 0 && neof > 0)
- printf("---! %d EOF(s)\n", neof); /* delayed EOF count */
- if (count <= 0 || count%BLOCK != 0) {
- if (count == 0)
- neof++;
- else if (count > 0) {
- printf("---! bad block size (%d) - treated as bad\n", count);
- nbad++;
- } else {
- if (errno >= 0 && errno < sys_nerr)
- printf("---! error (%s)\n", sys_errlist[errno]);
- else
- printf("---! error %d\n", errno);
- nbad++;
- }
- if (nbad >= badlimit)
- exit(1);
- if (neof >= eoflimit)
- exit(0);
- return(NULL);
- }
-
- /* successful read */
- nbad = 0;
- neof = 0;
- whichnow = 0;
- nleft = count/BLOCK - 1; /* -1 for one we're about to return */
- return(buf);
- }
-
- /*
- - doblock - process a block
- */
- doblock(block, argc, argv)
- char *block;
- int argc;
- char **argv;
- {
- register int count;
- register int tar = istar(block);
- register int ret;
-
- if (!tar && !opened)
- return;
-
- if (!tar && opened) {
- count = (fsize > BLOCK) ? BLOCK : (int)fsize;
- ret = write(f, block, count);
- if (ret < 0)
- printf("---! write error in file!\n");
- fsize -= count;
- if (fsize <= 0) {
- opened = 0;
- close(f);
- printf("--- done\n");
- }
- return;
- }
- /* it's a tar header block */
-
- if (op == 't') {
- printf("%s\n", block);
- return;
- }
- /* op == 'x' */
-
- if (opened) {
- printf("---! premature end\n");
- close(f);
- opened = 0;
- }
-
- if (!match(block, argc, argv))
- return; /* this file is not of interest */
-
- switch (block[FLAG]) {
- case '0':
- case '\0':
- f = creat(block, 0666);
- if (f < 0)
- printf("---! unable to create `%s'\n", block);
- else {
- opened = 1;
- ret = sscanf(block+NAMSIZ+24, "%lo", &fsize);
- if (ret != 1) {
- printf("---! can't read size of `%s'", block);
- close(f);
- opened = 0;
- } else {
- printf("--- reading %s %ld\n", block, fsize);
- if (fsize <= 0) {
- close(f);
- opened = 0;
- printf("--- done\n");
- }
- }
- }
- break;
- case '1':
- f = link(block+FLAG+1, block);
- if (f < 0)
- printf("---! unable to link %s to %s\n", block+FLAG+1, block);
- else
- printf("--- link %s to %s\n", block+FLAG+1, block);
- break;
- case '2':
- f = symlink(block+FLAG+1, block);
- if (f < 0)
- printf("---! unable to symlink %s to %s\n", block+FLAG+1, block);
- else
- printf("--- symlink %s to %s\n", block+FLAG+1, block);
- break;
- default:
- printf("---! unknown flag value %c\n", block[FLAG]);
- break;
- }
- }
-
- /*
- - match - does this string match one of the arguments?
- */
- int
- match(s, argc, argv)
- char *s;
- int argc;
- char **argv;
- {
- register int i;
- register int len;
-
- if (argc == 0)
- return(1);
-
- for (i = 0; i < argc; i++) {
- len = strlen(argv[i]);
- if (strncmp(s, argv[i], len) == 0 &&
- (s[len] == '/' || s[len] == '\0'))
- return(1);
- }
- return(0);
- }
-
- /*
- - istar - is this plausibly a tar header block?
- */
- int
- istar(block)
- register char *block;
- {
- register int loop;
-
- for (loop = 0; matches[loop].offset != 0; loop++)
- if (block[matches[loop].offset] != matches[loop].value)
- return(0);
- return(1);
- }
-