[comp.unix.questions] Damaged TAR tape

stevem@katmandu.Solbourne.COM (Stephen Matson) (02/14/90)

   OK, Ok, I know.

     I should have put the write protect on, but I did not. And I 
     should have made more backup tapes, but I did not.Now after
     I typed "tar -cvf" instead of "tar -xvf" I've lost some very
     valuable data. The tape went just long enough to erase the header
     and put an end of file marker at the start of the tape. I know
     the data I need is at the end, untouched ( I think). 

     Is there any way to recover the last half of the tape ?
--
	     E-mail == stevem@Solbourne.COM                   
  "FRODO LIVES"                                "COLORADO!!" 
--------------------------------------------------------------------------------
        	U.S. OUT OF NORTH AMERICA

danny@stubby.UUCP (Danny Tsen) (02/14/90)

In article <1990Feb13.171717.2902@Solbourne.COM>, stevem@katmandu.Solbourne.COM (Stephen Matson) writes:
> 
>      I typed "tar -cvf" instead of "tar -xvf" I've lost some very
> 
>      Is there any way to recover the last half of the tape ?
I have done this before that I used dd to dump the whole tape and used a 
binary editor to get rid of the junk stuff.  Hope this help you.

dave@csd4.csd.uwm.edu (David A Rasmussen) (02/19/90)

From article <145@stubby.UUCP>, by danny@stubby.UUCP (Danny Tsen):
> In article <1990Feb13.171717.2902@Solbourne.COM>, stevem@katmandu.Solbourne.COM (Stephen Matson) writes:
>> 
>>      I typed "tar -cvf" instead of "tar -xvf" I've lost some very
>> 
>>      Is there any way to recover the last half of the tape ?
> I have done this before that I used dd to dump the whole tape and used a 
> binary editor to get rid of the junk stuff.  Hope this help you.

Someone sent out a thing called badtar a long time ago. I think you put this
as a filter between dd and tar, not sure.


/* read tar tapes with bad blocks MWS */
#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
#define TBLOCK 512
#define NAMSIZ 100
#define TAPEBLOCK 10240

/* see tar (5) in the manual */
union hblock {
     char dummy[TBLOCK];
     struct header {
          char name[NAMSIZ];
          char mode[8];
          char uid[8];
          char gid[8];
          char size[12];
          char mtime[12];
          char chksum[8];
          char linkflag;
          char linkname[NAMSIZ];
     } dbuf;
};
char pad[TBLOCK];

/* check the check sum for the header block */
check_sum(c)
union hblock *c;
{
	int i,j;
	char *cp;
	cp = c->dummy;
	i = 0;
	for (j = 0; j < TBLOCK; j++) i += *cp++;
	for (j = 0; j < 8; j++) i -= c->dbuf.chksum[j];
	for (j = 0; j < 8; j++) i += ' ';
	return(i);
}

char buf[TAPEBLOCK];
char xbuf[TAPEBLOCK];
int bpos = TAPEBLOCK - TBLOCK, eot, bad, fd1;
FILE *logf;

/* get the next TBLOCK chars from the tape */
char *get_next()
{
	int res;
	if (bpos == TAPEBLOCK - TBLOCK) {
		bcopy(xbuf, buf,TAPEBLOCK);
		res = read(fd1,buf,TAPEBLOCK);
		if (res == 0) eot = 1;
		if (res < TAPEBLOCK) {
			bad = 1; 
			fprintf(logf, "***Bad block on tape!!\n");
		}
		else {
			if (bad) fprintf(logf, "***End of bad block(s) on tape\n");
			bad = 0;
		}
		bpos = 0;
	}
	else bpos += TBLOCK;
	return(&buf[bpos]);
}

main(argc, argv)
char **argv;
{
	int i, size, chksum, fblocks, eot_block;
	union hblock *hp;
	char tape[20];
	strcpy(tape, "/dev/rmt8"); /* default */
	logf = stderr;
	i = 1;
	
	/* get arguments */
	while (argc > i && argv[i][0] == '-') {
		switch (argv[i][1]) {
			case 'f' : 
				if (argc > i +1) {
					strcpy(tape,argv[++i]);
					}
				else {
					fprintf(stderr, "No tape drive name given\n");
					exit(10);
				}
				break;
			case 'l':
				if (argc > i + 1) {
					if ((logf = fopen(argv[++i], "w")) == NULL) {
						perror("Can't open log file\n");
						exit(11);
					}
				}
				else {
					fprintf(stderr, "No log file name given\n");
					exit(12);
				}
				break;
			default: 
				fprintf(stderr, "usage %s [-l logfile] [-f tape drive]\n",
				  argv[0]);
				exit(13);
		}
		i++;
	}
	
	/* first char cannot be a 0 */
	pad[0]  = 'x';
	
	/* don't quite know what the tape driver will return, so fill buffer
	   with non zero rubbish
	 */
	for (i = 0; i < TAPEBLOCK; i++) xbuf[i] = 'x';
	
	/* open the tape drive */
	if ((fd1 = open(tape, O_RDONLY,0)) < 0) {
		perror("can't open tape");
		exit(1);
	}
	while (1) {
		hp = (union hblock *) get_next();
		/* tar tests the first char to see if it is an end of tape (eot) block
		   or not. Can't see why it doesn't use tape marks. Maybe they weren't
		   invented when it was written?
	 	*/
	 	/* get a tar block */
		
		if (hp->dbuf.name[0] == '\0' && !bad && !fblocks) {
			/* skip possible eot block (there are two of them) */
			fprintf(logf, "***End of tape block\n");
			eot_block++;
			if (eot_block < 2) continue;
			eot = 1;
		}
		/* note if the last block read is bad there may be rubish
		  (old info from the last write at the end of it) this may cause
		  some of the last files which are extracted to be partially
		  overwritten. There is very little one can do about this
		  (except pray)
		*/
		
		/* end of tape ?? */
		if (eot) {
			if (fblocks) {
				fprintf(logf,"***Last file Truncated. File padded!!\n");
				while (fblocks--) write(1, pad, TBLOCK);
			}
			/* write two blank (eot) blocks */
			pad[0] = '\0';
			write(1, pad, TBLOCK);
			write(1, pad, TBLOCK);
			exit(1);
		}
		
		eot_block = 0;
		
		if (fblocks && !bad) { /* all ok in the middle of a file */
			write(1, hp, TBLOCK);
			fblocks--;
			continue;
		}
		
		/* have we got a header ?? */
		sscanf(hp->dbuf.size, "%lo", &size);
		sscanf(hp->dbuf.chksum, "%o", &chksum);
		if(check_sum(hp) == chksum && hp->dbuf.name[0] != '\0') {
		
			/* we have a header */
			if (fblocks) {
				fprintf(logf, "***Truncated!! File padded!!\n");
				while (fblocks--) write(1, pad, TBLOCK);
			}
			fblocks = (size%TBLOCK) ? size/TBLOCK + 1 : size/TBLOCK;
			fprintf(logf,"%s\n", hp->dbuf.name);
			write(1,hp,TBLOCK);
			continue;
		}
		
		/* not a header */
		if (fblocks == 0) {
			/* throw it away! */
			fprintf(logf, "***Deleted block!!\n");
			continue;
		}
		fblocks--;
		write(1,hp,TBLOCK);
	}
}



--
Internet:dave@uwm.edu, Uucp:uwm!dave, Bitnet:dave%uwm.edu@INTERBIT
Bellnet: +1 (414) 229-5133, USnail: CSD, P.O. Box 413, Milwaukee, WI  53201

gnu@hoptoad.uucp (John Gilmore) (02/28/90)

The pdtar I posted to comp.sources.unix a long time ago also handles
damaged tar tapes better than Unix tar.  Check the archives under 'pdtar'.
-- 
John Gilmore      {sun,pacbell,uunet,pyramid}!hoptoad!gnu      gnu@toad.com
Boycott the census!  The government that would invade Central America would
not hesitate to break into "their own" census database to violate your privacy.
            Maximum penalty for refusing to answer:  $100, no jail.