APLawrence.com -  Resources for Unix and Linux Systems, Bloggers and the self-employed

How to rescue a damaged tar file

Another way to do this is to download demo versions of one of the Supertars


From: "David Serrano (Hue-Bond)" <responder_solo_en_el_grupo@yahoo.es>
Newsgroups: comp.os.linux.misc,comp.unix.admin,comp.unix.shell
Subject: Re: rescue damaged tar file
Date: Thu, 2 Feb 2006 22:47:50 +0000 (UTC)
Message-ID: <slrndu530m.1ss.responder_solo_en_el_grupo@genus.hue-bond.info>
References: <u64pdnebu.fsf@trollope.org>
X-Message-Flag: Visit http://www.debian.org/
X-MSMail-Priority: High
Mail-Copies-To: nobody

Michael Powe, dom20051225@20:53:25(CET):
>

Maybe I'm a bit late but anyway...




> This archive has bad data about 1/3 to 1/2 way through it.  I'm trying
> to find a way to get at the data below the damaged part.

> I used the gzip recovery kit to unpack the file.  This worked and gave
> me the 2.5 GB uncompressed file.  However, tar will only unpack up to
> the damaged part, and even with --ignore-failed-read, blows up.

I was once in the same problem and found a Perl script in the web that made
my day. Let's reproduce a session:

$ tar cf bin.tar /bin/
tar: Removing leading `/' from member names
tar: Removing leading `/' from hard link targets
$ ll bin.tar
-rw------- 1 hue hue 2836480 20060202:233334+0100 bin.tar
$ dd if=/dev/urandom of=bin.tar bs=1k seek=1k count=300 conv=notrunc
300+0 records in
300+0 records out
307200 bytes (307 kB) copied, 0,101178 seconds, 3,0 MB/s
$ tar tf bin.tar
bin/
bin/bash
bin/rbash
bin/sh
bin/cat
bin/chgrp
bin/chmod
bin/chown
bin/cp
bin/date
bin/dd
bin/df
bin/dir
tar: Skipping to next header
tar: Archive contains obsolescent base-64 headers
tar: Error exit delayed from previous errors
$ perl ~hue/lang/perl/find_tar_headers.pl bin.tar
bin.tar:0:bin/:0
bin.tar:512:bin/bash:2467624
bin.tar:685056:bin/rbash:0
bin.tar:685568:bin/sh:0
bin.tar:686080:bin/cat:40550
bin.tar:703488:bin/chgrp:100664
bin.tar:737280:bin/chmod:73560
bin.tar:768512:bin/chown:105250
bin.tar:804864:bin/cp:153524
bin.tar:860672:bin/date:126274
bin.tar:905728:bin/dd:113410
bin.tar:945152:bin/df:103344
bin.tar:980480:bin/dir:226110
bin.tar:1368064:bin/vdir:226110
bin.tar:1445888:bin/sleep:33104
bin.tar:1460736:bin/stty:110140
[...]
$ _

We can see that the offset of the next tar header is that of vdir, at
1368064. In order to make dd fast, we obtain offset in Kb:



$ bc
[...]
scale=4
1368064/1024
1336.0000
$ dd if=bin.tar of=bin-tail.tar bs=1k skip=1336
1434+0 records in
1434+0 records out
1468416 bytes (1,5 MB) copied, 0,017176 seconds, 85,5 MB/s
$ file bin-tail.tar
bin-tail.tar: POSIX tar archive
$ tar xf bin.tar
tar: Skipping to next header
tar: Archive contains obsolescent base-64 headers
tar: Error exit delayed from previous errors
$ tar xf bin-tail.tar
$ rm -f bin/dir   ## probably corrupted

And now we have everything recoverable:

$ ls bin|wc -l
83
$ ls /bin/|wc -l
95
$ _

This is find_tar_headers.pl:

-----------------------------
#!/usr/bin/perl -w
use strict;

# 99.9% of all credits for this script go 
# to Tore Skjellnes <torsk@elkraft.ntnu.no>
# who is the originator.

my $tarfile;
my $c;
my $hit;
my $header;

# if you don't get any results, outcomment the line below and
# decomment the line below the it and retry
my @src = (ord('u'),ord('s'),ord('t'),ord('a'),ord('r'),ord(" "), ord(" "),0);
#my @src = (ord('u'),ord('s'),ord('t'),ord('a'),ord('r'),0,ord('0'),ord('0'));

die "No tar file given on command line" if $#ARGV != 0;

$tarfile = $ARGV[0];

open(IN,$tarfile) or die "Could not open `$tarfile': $!";

$hit = 0;
 $| = 1;
seek(IN,257,0) or die "Could not seek forward 257 characters in `$tarfile': $!";
while (read(IN,$c,1) == 1)
{
    ($hit = 0, next) unless (ord($c) == $src[$hit]);
    $hit = $hit + 1;
    ( print "hit: $hit", next ) unless $hit > $#src;

    
    # we have a probable header at (pos - 265)!
    my $pos = tell(IN) - 265;
    seek(IN,$pos,0)
	or (warn "Could not seek to position $pos in `$tarfile': $!", next);

    (read(IN,$header,512) == 512)
	or (warn "Could not read 512 byte header at position $pos in `$tarfile': $!", seek(IN,$pos+265,0),next);

    my ($name, $mode, $uid, $gid, $size, $mtime, $chksum, $typeflag,
	$linkname, $magic, $version, $uname, $gname,
	$devmajor, $devminor, $prefix)
	= unpack ("Z100a8a8a8Z12a12a8a1a100a6a2a32a32a8a8Z155", $header);
    $size = int $size;
    printf("%s:%s:%s:%s\n",$tarfile,$pos,$name,$size);

    $hit = 0;
}

close(IN) or warn "Error closing `$tarfile': $!";
-----------------------------

Good luck.


-- 
 David Serrano
 

Got something to add? Send me email.





(OLDER)    <- More Stuff -> (NEWER)    (NEWEST)   

Printer Friendly Version

-> -> This does not look like a tar archive, skipping



Increase ad revenue 50-250% with Ezoic

Kerio Samepage


Have you tried Searching this site?

Support Rates

This is a Unix/Linux resource website. It contains technical articles about Unix, Linux and general computing related subjects, opinion, news, help files, how-to's, tutorials and more.

Contact us





I wanted to learn how to swim, so Google showed me how to turn on the water at the sink and let me splash it around a bit. They then dragged me into a helicopter, flew way out into the ocean and dumped me out. (Tony Lawrence)





This post tagged: