[comp.unix.misc] Recovering corrupted tar's

alk@neuro.med.umn.edu (Anthony L Kimball) (10/04/90)

So, anyone have a handy-dandy tool to patch a tar archive which
has had it's leading N blocks overwritten?  I do so hate to do this
by hand.

--alk

enag@ifi.uio.no (Erik Naggum) (10/05/90)

In article <4121@neuro.med.umn.edu> alk@neuro.med.umn.edu (Anthony L Kimball) writes:

   So, anyone have a handy-dandy tool to patch a tar archive which
   has had it's leading N blocks overwritten?  I do so hate to do this
   by hand.

The files occupying the first n blocks are lost, where n >= N.  The
problem is to find the value of n.

If you know N, you can scan from there for the tar file start block.
It contains the filename from byte 0 in the block, up to 100
characters, nul-padded, then some decimal numbers, with space and nul
characters interspersed, then a bunch of nul characters to pad out the
block.  This should suffice to describe the block if you look for it
in, e.g. od dumps or in an emacs buffer.  When you know the offset
into the file, you have the value of n.

Then it's a simple matter of doing:

	dd if=<broken-tar-file> skip=<n> | tar tvf -

Works like a charm.  It may take a while to find the first block of
the first complete file, though.  Searching programs shouldn't be that
hard to write, either, but I don't think anybody has done this, yet.

There is no redundancy in tar files, so if you lose a block, it's
gone.

Hope this helps.

--
[Erik Naggum]		Naggum Software; Gaustadalleen 21; 0371 OSLO; NORWAY
	I disclaim,	<erik@naggum.uu.no>, <enag@ifi.uio.no>
  therefore I post.	+47-295-8622, +47-256-7822, (fax) +47-260-4427

terry@geovision.uucp (Terry McGonigal) (10/06/90)

I've just posted a utility that I've used to recover broken tar's
a couple of times to `alt.sources'.  The utility, `badtar' by
Mike Williams (mike@erix.UUCP [untried]) appeared in c.s.u some time
in the last cople of years.  It's nothing fancy, but it does work.

FYI, If you are talking about a DEC TK[57]0 device here, it's a lost
cause as far as I can see...  Anybody know how to get these drives to
go past a software EOT marker?

Cheers,
--
Terry McGonigal    GeoVision Corp   {uunet,nrcaer!cognos}!geovision!terry
                   Ottawa On, Can   terry@gvc.com
                   613-722-9518
-- 
Terry McGonigal    GeoVision Corp   {uunet,nrcaer!cognos}!geovision!terry
                   Ottawa On, Can   terry@gvc.com
                   613-722-9518

jpr@jpradley.uucp (Jean-Pierre Radley) (10/14/90)

In article <ENAG.90Oct4231246@svarte.ifi.uio.no> enag@ifi.uio.no (Erik Naggum) writes:
>In article <4121@neuro.med.umn.edu> alk@neuro.med.umn.edu (Anthony L Kimball) writes:
>
>   So, anyone have a handy-dandy tool to patch a tar archive which
>   has had it's leading N blocks overwritten?  I do so hate to do this
>   by hand.
>
>The files occupying the first n blocks are lost, where n >= N.  The
>problem is to find the value of n.
> ......
>                                  Searching programs shouldn't be that
>hard to write, either, but I don't think anybody has done this, yet.


Well, this often helps:


/* tarskip.c
 * taken from volume 2, number 8 of Unix World.
 * Usage: tarskip pathname [tardevice] | tar xvfn -
 * The pathname argument is the first file you can
 * think of after the bad spot on the archive.
 */
#include <stdio.h>

#define TARBLKSZ 1024	/* Block size on YOUR tar disk */
#define TRUE	 1	/* Boolean true */
#define FALSE	 0	/* Boolean false */

/* Global variables */

FILE *fp, *efopen();	/* file pointer for tar device file */
char fd;		/* file descriptor for tar device file */
char buf[TARBLKSZ];	/* buffer for "tar blocks" */
char *progname;
char *tardev = "/dev/rfd0"; /* Substitute YOUR default device name !! */

main(argc, argv)
int argc;
char *argv[];
{
	char *pathname;
	int match = FALSE;		/*Initialize to zero */
	progname = argv[0];

/* Process command line arguments */

	if (argc == 1 || argc > 3) {	/* Correct # of args? */
	     error("Usage: %s pathname [tardevice] | tar xvfn -", progname); }
	pathname = argv[1];		/* The pattern string to search for */
	if (argc == 3)
		tardev= argv[2];	/* Use device other than default */
	
		fp= efopen(tardev,"r");	/* Open for reading */
		fd= fileno(fp);		/* File descriptor */

/* Find block containing desired pathname */

	do {	getblk(tardev);
		match = strncmp(pathname, buf, strlen(pathname));
	} while (match);

/* Then read and process disk blocks "forever" */

	while (TRUE) { write(1, buf, sizeof(buf));
		       getblk(tardev); }
}

getblk(device)		/* Read the next block into the buffer */
char *device;		/* The tar disk device name */
{
	int c, done, n;
begin:	n = (read(fd, buf, sizeof(buf)));	/* Read a block */

	if (n ==0) { 				/* End of disk */
		done = query("\nEnd of disk, read another (y/n)? ");
		if (!done) {			/* Not done */
			close(fd);		/* Close previous device */
			fprintf(stderr, "Insert next disk and");
			fprintf(stderr, " press <ENTER> when ready\n");
			while ((c=getchar()) != '\n' && c != EOF)
				; 		/* Wait for ENTER */
			fp= efopen(device,"r");	/* Open for reading */
			fd= fileno(fp);		/* File descriptor */
			goto begin; /* Get first block from next disk */
		} else				/* Done */
			exit (0);
	} else if (n < 0) {			/* Tape read error */
		done = query("\nRead error, ignore (y/n)? ");
		if (done) {
			close(fd);
			fprintf(stderr, "Goodbye ... \n");
			exit(2);
		}
	}
}

query(msg)		/* Display message and prompt for continuance */
char *msg;
{
	int c, c2;
	fprintf(stderr, "%s", msg);
	c = c2 = getchar();
	while (c2 != '\n' && c2 != EOF)
		c2 = getchar(); 	/* Ignore remaining input */
	if (c == 'y' || c == 'Y') 	/* First char was y or Y */
	return(0);		 	/* Not done */
	else
	return(1);		 	/* Done */
}

error(s1, s2)		/* print error message and die */
char	*s1, *s2;
{
	extern	int	errno, sys_nerr;
	extern	char	*sys_errlist[], *progname;

	if (progname)
		fprintf(stderr, "%s: ", progname);
	fprintf(stderr, s1, s2);
	if (errno >0 && errno < sys_nerr)
			fprintf(stderr, "	(%s)", sys_errlist[errno]);
	fprintf(stderr, "\n");
	exit(1);
}

FILE *efopen(file, mode)	/* fopen file, call error() & die if can't */
char *file, *mode;
{
	FILE	*f;
	extern char *progname;
	char	str[80], *s=str;

	if	((f = fopen(file,mode)) != (FILE *)0)
		return f;
	sprintf(s, "can't open file %s mode %s\n", file, mode);
	error(s);
}
-- 
 Jean-Pierre Radley          HIGH-Q	     jpr@jpradley	CIS: 72160,1341