home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume24 / tarx < prev    next >
Text File  |  1991-03-21  |  11KB  |  430 lines

  1. Subject:  v24i077:  Tool to salvage data from damaged tar tapes
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: d94d3357 5075df9b f91b5436 4bc6db49
  5.  
  6. Submitted-by: henry@zoo.toronto.edu
  7. Posting-number: Volume 24, Issue 77
  8. Archive-name: tarx
  9.  
  10. Tarx is a newer, cleaner, more versatile replacement for my old targ/tarl
  11. programs for salvaging information from damaged tar tapes.  It does a
  12. better job on various details and has been extensively tidied up.
  13.  
  14. It uses a simplistic pattern-matching approach to identify tar header
  15. blocks.  It will cheerfully persist despite all sorts of bad things about
  16. the archive (such as wrong checksums, read errors, and scraped-off
  17. magnetic surface...), up to a maximum of "errlimit" hard errors in a row
  18.  
  19. It can be used to list the files, and extract as much of them as is
  20. possible.
  21.  
  22. #! /bin/sh
  23. echo 'README':
  24. sed 's/^X//' >'README' <<'!'
  25. XTarx is a newer, cleaner, more versatile replacement for my old targ/tarl
  26. Xprograms for salvaging information from damaged tar tapes.  It does a
  27. Xbetter job on various details and has been extensively tidied up.
  28. X
  29. X                                         Henry Spencer at U of Toronto Zoology
  30. X                                          henry@zoo.toronto.edu   utzoo!henry
  31. !
  32. echo 'Makefile':
  33. sed 's/^X//' >'Makefile' <<'!'
  34. XCFLAGS = -O
  35. XLDFLAGS =
  36. X
  37. Xtarx:    tarx.o
  38. X    $(CC) $(LDFLAGS) tarx.o -o $@
  39. !
  40. echo 'tarx.1':
  41. sed 's/^X//' >'tarx.1' <<'!'
  42. X.TH TARX 1 "26 July 1990"
  43. X.BY Zoology
  44. X.SH NAME
  45. Xtarx \- recover files from damaged tar-format archives
  46. X.SH SYNOPSIS
  47. X\fBtarx\fR
  48. X[
  49. X.B \-t
  50. X]
  51. X[
  52. X.B \-b
  53. Xblockfactor
  54. X]
  55. X[
  56. X.B \-e
  57. Xerrlimit
  58. X] [
  59. X.B \-E
  60. Xeoflimit
  61. X]
  62. Xname ...
  63. X.SH DESCRIPTION
  64. X\fITarx\fR is used to list and recover files from a
  65. Xdamaged \fItar\fR(1) archive.
  66. XIt uses a simplistic pattern-matching
  67. Xapproach to identify \fItar\fR header blocks.
  68. XIt will cheerfully persist despite all sorts of bad things about the archive
  69. X(such as wrong checksums, read errors, and scraped-off magnetic surface...),
  70. Xup to a maximum of \fIerrlimit\fR (default 3) hard errors in a row
  71. Xor \fIeoflimit\fR (default 2) EOFs in a row.
  72. XSuch events are reported but don't terminate operations.
  73. XThe \fItar\fR archive is read from standard input.
  74. X.PP
  75. XWith the
  76. X.B \-t
  77. Xoption,
  78. X\fItarx\fR lists the file names it sees in the archive.
  79. X.PP
  80. XWithout the
  81. X.B \-t
  82. Xoption,
  83. X\fItarx\fR takes file or directory \fIname\fRs as arguments
  84. Xand attempts to extract them from the archive.
  85. X(If no \fIname\fRs are given, \fItarx\fR extracts everything it can find.)
  86. X\fITarx\fR is not willing to create directories, however,
  87. Xso these must be made manually beforehand if they do not already exist.
  88. XFiles are owned by the user, and have his default permissions.
  89. X.PP
  90. X.I Tarx
  91. Xallocates a read buffer of \fIblockfactor\fR*512 bytes,
  92. Xwhere the default \fIblockfactor\fR is 400 (to allow for the very large
  93. Xblocks sometimes found on cartridge tapes),
  94. Xand attempts a full-sized read each time.
  95. XIt copes properly with getting less than it expected, although it does
  96. Xinsist that the result be a multiple of 512 bytes.
  97. XWhen dealing with cranky tape drives or other special situations,
  98. Xor severely short of memory, or working on a 16-bit machine,
  99. Xit may be useful to specify a smaller \fIblockfactor\fR.
  100. X(Notably, on 16-bit machines 126 is often the maximum that will work.)
  101. XSpecifying a larger \fIblockfactor\fR may be necessary if tape blocks
  102. Xare truly enormous.
  103. X.SH EXAMPLE
  104. X``tarx \-t </dev/rmt0 >filelist'' lists all files on the tape
  105. Xmounted on /dev/rmt0 and places the results in ``filelist''.
  106. X.PP
  107. X``tarx joe/precious </dev/rmt0'' restores the file
  108. X``joe/precious'' from the tape mounted on /dev/rmt0.
  109. XThe directory ``joe'' must already exist.
  110. X.SH SEE ALSO
  111. Xtar(1)
  112. X.SH HISTORY
  113. XWritten by Henry Spencer, Univ. of Toronto Zoology,
  114. Xbased on older programs by the same author.
  115. XThis software is public domain.
  116. XOriginal manual page by Chris Robertson.
  117. X.SH BUGS
  118. X\fITarx\fR should be smarter about directories and permissions.
  119. X.PP
  120. XArguably should use the \fItar\fR header-block checksum,
  121. Xinstead of the slightly-arcane pattern matcher, to identify header blocks.
  122. X.PP
  123. XA \fItar\fR archive containing a file which is itself a \fItar\fR archive
  124. Xwill cause considerable confusion.
  125. !
  126. echo 'tarx.c':
  127. sed 's/^X//' >'tarx.c' <<'!'
  128. X/*
  129. X * tarx - manipulate damaged tar tapes heuristically
  130. X */
  131. X
  132. X#include <stdio.h>
  133. X#include <string.h>
  134. X
  135. X#define NAMSIZ 100        /* why isn't there a tar.h??? */
  136. X#define    FLAG    (NAMSIZ+8+8+8+12+12+8)    /* offset of is-a-link flag */
  137. Xstruct matches {
  138. X    int offset;
  139. X    char value;
  140. X} matches[] = {            /* pattern-match table for header blocks */
  141. X    NAMSIZ+6,    ' ',
  142. X    NAMSIZ+7,    '\0',
  143. X    NAMSIZ+8+6,    ' ',
  144. X    NAMSIZ+8+7,    '\0',
  145. X    NAMSIZ+16+6,    ' ',
  146. X    NAMSIZ+16+7,    '\0',
  147. X    NAMSIZ+24+11,    ' ',
  148. X    NAMSIZ+36+11,    ' ',
  149. X    NAMSIZ+48+6,    '\0',
  150. X    0,        0,
  151. X};
  152. X
  153. X#ifndef MAXBLOCK
  154. X#define    MAXBLOCK    400    /* SGI makes blocky tapes */
  155. X#endif
  156. Xint maxblock = MAXBLOCK;
  157. X#define    BLOCK    512
  158. X
  159. Xchar *buf;            /* -> malloced buffer */
  160. Xint nleft = 0;            /* number of blocks left in buffer */
  161. Xint whichnow;            /* index in buffer of current block */
  162. X
  163. Xint nbad = 0;            /* number of consecutive bad reads */
  164. Xint badlimit = 3;        /* limit on consecutive bads */
  165. Xint neof = 0;            /* number of consecutive EOF marks */
  166. Xint eoflimit = 2;        /* limit on consecutive eofs */
  167. X
  168. Xint opened = 0;            /* are we writing a file? */
  169. Xint f;                /* the file descriptor, if any */
  170. Xlong fsize;            /* number of bytes not yet written to file */
  171. X
  172. Xchar op = 'x';            /* what operation is being done? */
  173. X
  174. X#define    STREQ(a, b)    (*(a) == *(b) && strcmp((a), (b)) == 0)
  175. X
  176. X#ifndef lint
  177. Xstatic char RCSid[] = "$Header$";
  178. X#endif
  179. X
  180. Xint debug = 0;
  181. Xchar *progname;
  182. X
  183. Xextern void exit();
  184. X#ifdef UTZOOERR
  185. Xextern char *mkprogname();
  186. X#else
  187. X#define    mkprogname(a)    (a)
  188. X#endif
  189. X
  190. X/*
  191. X - main - parse arguments and handle options
  192. X */
  193. Xmain(argc, argv)
  194. Xint argc;
  195. Xchar *argv[];
  196. X{
  197. X    int c;
  198. X    int errflg = 0;
  199. X    register char *block;
  200. X    extern char *readblock();
  201. X    extern char *malloc();
  202. X    extern int optind;
  203. X    extern char *optarg;
  204. X
  205. X    progname = mkprogname(argv[0]);
  206. X
  207. X    while ((c = getopt(argc, argv, "tb:e:E:d")) != EOF)
  208. X        switch (c) {
  209. X        case 't':    /* just list files */
  210. X            op = 't';
  211. X            break;
  212. X        case 'b':    /* set blocking factor */
  213. X            maxblock = atoi(optarg);
  214. X            break;
  215. X        case 'e':    /* set error limit */
  216. X            badlimit = atoi(optarg);
  217. X            break;
  218. X        case 'E':    /* set eof limit */
  219. X            eoflimit = atoi(optarg);
  220. X            break;
  221. X        case 'd':    /* Debugging. */
  222. X            debug++;
  223. X            break;
  224. X        case '?':
  225. X        default:
  226. X            errflg++;
  227. X            break;
  228. X        }
  229. X    if (errflg) {
  230. X        fprintf(stderr, "usage: %s ", progname);
  231. X        fprintf(stderr, "[-t] [-b blockf] [-e errs] [-E eofs] [name] ...\n");
  232. X        exit(2);
  233. X    }
  234. X
  235. X    buf = malloc(maxblock*BLOCK);
  236. X    if (buf == NULL) {
  237. X        fprintf(stderr, "%s: cannot allocate buffer of %d blocks\n",
  238. X                            progname, maxblock);
  239. X        exit(1);
  240. X    }
  241. X
  242. X    for(;;) {
  243. X        block = readblock(0);
  244. X
  245. X        if (block != NULL)
  246. X            doblock(block, argc - optind, &argv[optind]);
  247. X    }
  248. X    /* NOTREACHED */
  249. X}
  250. X
  251. X/*
  252. X - readblock - read in a block and deal with error/eof
  253. X */
  254. Xchar *
  255. Xreadblock(desc)
  256. Xint desc;
  257. X{
  258. X    register int count;
  259. X    extern int errno;
  260. X    extern int sys_nerr;
  261. X    extern char *sys_errlist[];
  262. X
  263. X    if (nleft > 0) {
  264. X        whichnow++;
  265. X        nleft--;
  266. X        return(buf+whichnow*BLOCK);
  267. X    }
  268. X
  269. X    count = read(desc, buf, maxblock*BLOCK);
  270. X    if (count != 0 && neof > 0)
  271. X        printf("---! %d EOF(s)\n", neof);    /* delayed EOF count */
  272. X    if (count <= 0 || count%BLOCK != 0) {
  273. X        if (count == 0)
  274. X            neof++;
  275. X        else if (count > 0) {
  276. X            printf("---! bad block size (%d) - treated as bad\n", count);
  277. X            nbad++;
  278. X        } else {
  279. X            if (errno >= 0 && errno < sys_nerr)
  280. X                printf("---! error (%s)\n", sys_errlist[errno]);
  281. X            else
  282. X                printf("---! error %d\n", errno);
  283. X            nbad++;
  284. X        }
  285. X        if (nbad >= badlimit)
  286. X            exit(1);
  287. X        if (neof >= eoflimit)
  288. X            exit(0);
  289. X        return(NULL);
  290. X    }
  291. X
  292. X    /* successful read */
  293. X    nbad = 0;
  294. X    neof = 0;
  295. X    whichnow = 0;
  296. X    nleft = count/BLOCK - 1;    /* -1 for one we're about to return */
  297. X    return(buf);
  298. X}
  299. X
  300. X/*
  301. X - doblock - process a block
  302. X */
  303. Xdoblock(block, argc, argv)
  304. Xchar *block;
  305. Xint argc;
  306. Xchar **argv;
  307. X{
  308. X    register int count;
  309. X    register int tar = istar(block);
  310. X    register int ret;
  311. X
  312. X    if (!tar && !opened)
  313. X        return;
  314. X
  315. X    if (!tar && opened) {
  316. X        count = (fsize > BLOCK) ? BLOCK : (int)fsize;
  317. X        ret = write(f, block, count);
  318. X        if (ret < 0)
  319. X            printf("---! write error in file!\n");
  320. X        fsize -= count;
  321. X        if (fsize <= 0) {
  322. X            opened = 0;
  323. X            close(f);
  324. X            printf("--- done\n");
  325. X        }
  326. X        return;
  327. X    }
  328. X    /* it's a tar header block */
  329. X
  330. X    if (op == 't') {
  331. X        printf("%s\n", block);
  332. X        return;
  333. X    }
  334. X    /* op == 'x' */
  335. X
  336. X    if (opened) {
  337. X        printf("---! premature end\n");
  338. X        close(f);
  339. X        opened = 0;
  340. X    }
  341. X
  342. X    if (!match(block, argc, argv))
  343. X        return;        /* this file is not of interest */
  344. X
  345. X    switch (block[FLAG]) {
  346. X    case '0':
  347. X    case '\0':
  348. X        f = creat(block, 0666);
  349. X        if (f < 0)
  350. X            printf("---! unable to create `%s'\n", block);
  351. X        else {
  352. X            opened = 1;
  353. X            ret = sscanf(block+NAMSIZ+24, "%lo", &fsize);
  354. X            if (ret != 1) {
  355. X                printf("---! can't read size of `%s'", block);
  356. X                close(f);
  357. X                opened = 0;
  358. X            } else {
  359. X                printf("--- reading %s %ld\n", block, fsize);
  360. X                if (fsize <= 0) {
  361. X                    close(f);
  362. X                    opened = 0;
  363. X                    printf("--- done\n");
  364. X                }
  365. X            }
  366. X        }
  367. X        break;
  368. X    case '1':
  369. X        f = link(block+FLAG+1, block);
  370. X        if (f < 0)
  371. X            printf("---! unable to link %s to %s\n", block+FLAG+1, block);
  372. X        else
  373. X            printf("--- link %s to %s\n", block+FLAG+1, block);
  374. X        break;
  375. X    case '2':
  376. X        f = symlink(block+FLAG+1, block);
  377. X        if (f < 0)
  378. X            printf("---! unable to symlink %s to %s\n", block+FLAG+1, block);
  379. X        else
  380. X            printf("--- symlink %s to %s\n", block+FLAG+1, block);
  381. X        break;
  382. X    default:
  383. X        printf("---! unknown flag value %c\n", block[FLAG]);
  384. X        break;
  385. X    }
  386. X}
  387. X
  388. X/*
  389. X - match - does this string match one of the arguments?
  390. X */
  391. Xint
  392. Xmatch(s, argc, argv)
  393. Xchar *s;
  394. Xint argc;
  395. Xchar **argv;
  396. X{
  397. X    register int i;
  398. X    register int len;
  399. X
  400. X    if (argc == 0)
  401. X        return(1);
  402. X
  403. X    for (i = 0; i < argc; i++) {
  404. X        len = strlen(argv[i]);
  405. X        if (strncmp(s, argv[i], len) == 0 &&
  406. X                    (s[len] == '/' || s[len] == '\0'))
  407. X            return(1);
  408. X    }
  409. X    return(0);
  410. X}
  411. X
  412. X/*
  413. X - istar - is this plausibly a tar header block?
  414. X */
  415. Xint
  416. Xistar(block)
  417. Xregister char *block;
  418. X{
  419. X    register int loop;
  420. X
  421. X    for (loop = 0; matches[loop].offset != 0; loop++)
  422. X        if (block[matches[loop].offset] != matches[loop].value)
  423. X            return(0);
  424. X    return(1);
  425. X}
  426. !
  427. echo done
  428.  
  429. exit 0 # Just in case...
  430.