home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Tools / Tapes / tarx.shar / tarx.c < prev   
Encoding:
C/C++ Source or Header  |  1998-03-03  |  5.7 KB  |  299 lines

  1. /*
  2.  * tarx - manipulate damaged tar tapes heuristically
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <string.h>
  7.  
  8. #define NAMSIZ 100        /* why isn't there a tar.h??? */
  9. #define    FLAG    (NAMSIZ+8+8+8+12+12+8)    /* offset of is-a-link flag */
  10. struct matches {
  11.     int offset;
  12.     char value;
  13. } matches[] = {            /* pattern-match table for header blocks */
  14.     NAMSIZ+6,    ' ',
  15.     NAMSIZ+7,    '\0',
  16.     NAMSIZ+8+6,    ' ',
  17.     NAMSIZ+8+7,    '\0',
  18.     NAMSIZ+16+6,    ' ',
  19.     NAMSIZ+16+7,    '\0',
  20.     NAMSIZ+24+11,    ' ',
  21.     NAMSIZ+36+11,    ' ',
  22.     NAMSIZ+48+6,    '\0',
  23.     0,        0,
  24. };
  25.  
  26. #ifndef MAXBLOCK
  27. #define    MAXBLOCK    400    /* SGI makes blocky tapes */
  28. #endif
  29. int maxblock = MAXBLOCK;
  30. #define    BLOCK    512
  31.  
  32. char *buf;            /* -> malloced buffer */
  33. int nleft = 0;            /* number of blocks left in buffer */
  34. int whichnow;            /* index in buffer of current block */
  35.  
  36. int nbad = 0;            /* number of consecutive bad reads */
  37. int badlimit = 3;        /* limit on consecutive bads */
  38. int neof = 0;            /* number of consecutive EOF marks */
  39. int eoflimit = 2;        /* limit on consecutive eofs */
  40.  
  41. int opened = 0;            /* are we writing a file? */
  42. int f;                /* the file descriptor, if any */
  43. long fsize;            /* number of bytes not yet written to file */
  44.  
  45. char op = 'x';            /* what operation is being done? */
  46.  
  47. #define    STREQ(a, b)    (*(a) == *(b) && strcmp((a), (b)) == 0)
  48.  
  49. #ifndef lint
  50. static char RCSid[] = "$Header$";
  51. #endif
  52.  
  53. int debug = 0;
  54. char *progname;
  55.  
  56. extern void exit();
  57. #ifdef UTZOOERR
  58. extern char *mkprogname();
  59. #else
  60. #define    mkprogname(a)    (a)
  61. #endif
  62.  
  63. /*
  64.  - main - parse arguments and handle options
  65.  */
  66. main(argc, argv)
  67. int argc;
  68. char *argv[];
  69. {
  70.     int c;
  71.     int errflg = 0;
  72.     register char *block;
  73.     extern char *readblock();
  74.     extern char *malloc();
  75.     extern int optind;
  76.     extern char *optarg;
  77.  
  78.     progname = mkprogname(argv[0]);
  79.  
  80.     while ((c = getopt(argc, argv, "tb:e:E:d")) != EOF)
  81.         switch (c) {
  82.         case 't':    /* just list files */
  83.             op = 't';
  84.             break;
  85.         case 'b':    /* set blocking factor */
  86.             maxblock = atoi(optarg);
  87.             break;
  88.         case 'e':    /* set error limit */
  89.             badlimit = atoi(optarg);
  90.             break;
  91.         case 'E':    /* set eof limit */
  92.             eoflimit = atoi(optarg);
  93.             break;
  94.         case 'd':    /* Debugging. */
  95.             debug++;
  96.             break;
  97.         case '?':
  98.         default:
  99.             errflg++;
  100.             break;
  101.         }
  102.     if (errflg) {
  103.         fprintf(stderr, "usage: %s ", progname);
  104.         fprintf(stderr, "[-t] [-b blockf] [-e errs] [-E eofs] [name] ...\n");
  105.         exit(2);
  106.     }
  107.  
  108.     buf = malloc(maxblock*BLOCK);
  109.     if (buf == NULL) {
  110.         fprintf(stderr, "%s: cannot allocate buffer of %d blocks\n",
  111.                             progname, maxblock);
  112.         exit(1);
  113.     }
  114.  
  115.     for(;;) {
  116.         block = readblock(0);
  117.  
  118.         if (block != NULL)
  119.             doblock(block, argc - optind, &argv[optind]);
  120.     }
  121.     /* NOTREACHED */
  122. }
  123.  
  124. /*
  125.  - readblock - read in a block and deal with error/eof
  126.  */
  127. char *
  128. readblock(desc)
  129. int desc;
  130. {
  131.     register int count;
  132.     extern int errno;
  133.     extern int sys_nerr;
  134.     extern char *sys_errlist[];
  135.  
  136.     if (nleft > 0) {
  137.         whichnow++;
  138.         nleft--;
  139.         return(buf+whichnow*BLOCK);
  140.     }
  141.  
  142.     count = read(desc, buf, maxblock*BLOCK);
  143.     if (count != 0 && neof > 0)
  144.         printf("---! %d EOF(s)\n", neof);    /* delayed EOF count */
  145.     if (count <= 0 || count%BLOCK != 0) {
  146.         if (count == 0)
  147.             neof++;
  148.         else if (count > 0) {
  149.             printf("---! bad block size (%d) - treated as bad\n", count);
  150.             nbad++;
  151.         } else {
  152.             if (errno >= 0 && errno < sys_nerr)
  153.                 printf("---! error (%s)\n", sys_errlist[errno]);
  154.             else
  155.                 printf("---! error %d\n", errno);
  156.             nbad++;
  157.         }
  158.         if (nbad >= badlimit)
  159.             exit(1);
  160.         if (neof >= eoflimit)
  161.             exit(0);
  162.         return(NULL);
  163.     }
  164.  
  165.     /* successful read */
  166.     nbad = 0;
  167.     neof = 0;
  168.     whichnow = 0;
  169.     nleft = count/BLOCK - 1;    /* -1 for one we're about to return */
  170.     return(buf);
  171. }
  172.  
  173. /*
  174.  - doblock - process a block
  175.  */
  176. doblock(block, argc, argv)
  177. char *block;
  178. int argc;
  179. char **argv;
  180. {
  181.     register int count;
  182.     register int tar = istar(block);
  183.     register int ret;
  184.  
  185.     if (!tar && !opened)
  186.         return;
  187.  
  188.     if (!tar && opened) {
  189.         count = (fsize > BLOCK) ? BLOCK : (int)fsize;
  190.         ret = write(f, block, count);
  191.         if (ret < 0)
  192.             printf("---! write error in file!\n");
  193.         fsize -= count;
  194.         if (fsize <= 0) {
  195.             opened = 0;
  196.             close(f);
  197.             printf("--- done\n");
  198.         }
  199.         return;
  200.     }
  201.     /* it's a tar header block */
  202.  
  203.     if (op == 't') {
  204.         printf("%s\n", block);
  205.         return;
  206.     }
  207.     /* op == 'x' */
  208.  
  209.     if (opened) {
  210.         printf("---! premature end\n");
  211.         close(f);
  212.         opened = 0;
  213.     }
  214.  
  215.     if (!match(block, argc, argv))
  216.         return;        /* this file is not of interest */
  217.  
  218.     switch (block[FLAG]) {
  219.     case '0':
  220.     case '\0':
  221.         f = creat(block, 0666);
  222.         if (f < 0)
  223.             printf("---! unable to create `%s'\n", block);
  224.         else {
  225.             opened = 1;
  226.             ret = sscanf(block+NAMSIZ+24, "%lo", &fsize);
  227.             if (ret != 1) {
  228.                 printf("---! can't read size of `%s'", block);
  229.                 close(f);
  230.                 opened = 0;
  231.             } else {
  232.                 printf("--- reading %s %ld\n", block, fsize);
  233.                 if (fsize <= 0) {
  234.                     close(f);
  235.                     opened = 0;
  236.                     printf("--- done\n");
  237.                 }
  238.             }
  239.         }
  240.         break;
  241.     case '1':
  242.         f = link(block+FLAG+1, block);
  243.         if (f < 0)
  244.             printf("---! unable to link %s to %s\n", block+FLAG+1, block);
  245.         else
  246.             printf("--- link %s to %s\n", block+FLAG+1, block);
  247.         break;
  248.     case '2':
  249.         f = symlink(block+FLAG+1, block);
  250.         if (f < 0)
  251.             printf("---! unable to symlink %s to %s\n", block+FLAG+1, block);
  252.         else
  253.             printf("--- symlink %s to %s\n", block+FLAG+1, block);
  254.         break;
  255.     default:
  256.         printf("---! unknown flag value %c\n", block[FLAG]);
  257.         break;
  258.     }
  259. }
  260.  
  261. /*
  262.  - match - does this string match one of the arguments?
  263.  */
  264. int
  265. match(s, argc, argv)
  266. char *s;
  267. int argc;
  268. char **argv;
  269. {
  270.     register int i;
  271.     register int len;
  272.  
  273.     if (argc == 0)
  274.         return(1);
  275.  
  276.     for (i = 0; i < argc; i++) {
  277.         len = strlen(argv[i]);
  278.         if (strncmp(s, argv[i], len) == 0 &&
  279.                     (s[len] == '/' || s[len] == '\0'))
  280.             return(1);
  281.     }
  282.     return(0);
  283. }
  284.  
  285. /*
  286.  - istar - is this plausibly a tar header block?
  287.  */
  288. int
  289. istar(block)
  290. register char *block;
  291. {
  292.     register int loop;
  293.  
  294.     for (loop = 0; matches[loop].offset != 0; loop++)
  295.         if (block[matches[loop].offset] != matches[loop].value)
  296.             return(0);
  297.     return(1);
  298. }
  299.