Script for uncompressing image due to missing backup file

Discussion in 'Acronis True Image Product Line' started by gthornejr, Apr 2, 2005.

Thread Status:
Not open for further replies.
  1. gthornejr

    gthornejr Registered Member

    Joined:
    Apr 2, 2005
    Posts:
    2
    About a month ago, we unfortunately had a rare sequence of events that led to a file being missing from one of our incremental backups. One of the incremental files was a zero byte file, but the original full backup image file was intact. When I tried to mount the image, I got a corrupt image file error. The total image was compressed without a password. I really needed to get a text file from this backup, so I spent a few days tinkering with the image file.

    It turns out that Acronis uses zLib compression, which is freely available from http://www.info-zip.org/ and also comes as a Perl module. I was able to successfully uncompress the image and retrieve the text file that I needed using a hex editor. I am posting the Perl script here in case it will be helpful to someone else. I am not a Perl hacker by any means, so if anyone can clean up this code to make it work better please do. It does not exit gracefully once it finishes extracting the images but the resulting image seems to be a correct copy.

    You can download ActivePerl, a free version of Perl for Windows at http://www.activestate.com/

    Gary Thorne
    HAL Systems

    Code:
    # Paste this code into Notepad and save as unimage.pl
    # Run from a command line by typing "perl unimage.pl"
    # This Perl script takes a file as an argument and extracts the Acronis compressed images from it to standard out
    # Status information on each image location is printed to standard err
    # Resulting binary image file can be searched and extracted to a file with a hex editor such as WinHex
    # http://www.x-ways.net/
    
    use strict ;
    use warnings ;
    
    use Compress::Zlib ;	# this Perl module comes with recent distributions of ActiveState ActivePerl for Windows
    						# http://www.activestate.com/
    
    die "Usage: unimage input_file > image.bin\n"
        unless @ARGV ;
    
    my $file ;
    my $junk ;
    my $tempfile ;
    my $curchar ;
    my ($output, $status) ;
    
    foreach $file (@ARGV) {
        my $buffer ;
    	$tempfile = $file;
    
    	open(INFILE, "<", $tempfile) or die "Cannot open $tempfile: $!\n";
    	binmode INFILE;
    
    	my $input = '';
    	my $onechar = '';
    	my $firstrun = 1; # true
    	my $blankflag = 0;	# false
    	my $doneflag = 0;	# false
    	while (!eof(INFILE))
    	{
    		if ($firstrun)
    		{
    			seek INFILE, 12, 1; #	jump to first compressed image
    			$firstrun = 0;
    		}
    		else
    		{
    			# locate next image
    			$blankflag = 0;	# indicates blank character found
    			$doneflag = 0;	# indicates header found
    			while (!$doneflag and !eof(INFILE))
    			{
    				$onechar = getc(INFILE) ;	# look for start of zLib header
    				if ($blankflag == 0)
    				{
    					if (ord $onechar == 255)	# ascii value of 255 could be start of ending blanks
    					{
    						$blankflag = 1;
    					}
    				}
    				elsif ($blankflag < 24)	# we haven't seen 24 blanks yet
    				{
    					if (ord $onechar == 255)
    					{
    						$blankflag = $blankflag + 1;	# eat all blanks in a row until we get to 24
    					}
    					else
    					{
    						$blankflag = 0;
    					}
    				}
    				else
    				{
    					if (ord $onechar == 120)
    					{
    						$doneflag = 1;	# ascii value of 120 signals the end of this header
    					}
    					elsif (ord $onechar == 255)
    					{
    						$blankflag = $blankflag + 1;	# eat any remaining blanks
    					}
    					else
    					{
    						$blankflag = 0;	# this wasn't the end, so keep looking
    					}
    				}
    			}
    			seek INFILE, -1, 1;	# back up a byte to include zLib header
    		}
    		$input = '';
    		$output = '';
    		$status = 0;
    		print STDERR "\nImage pos = ", tell(INFILE), "\n";
    		my $x = inflateInit( -WindowBits => 15)
    		   or die "Cannot create a inflation stream\n" ;
    		while (read(INFILE, $input, 4096))	# read 4096 bytes at a time
    		{
    	      	($output, $status) = $x->inflate(\$input) ;	# decompress the stored image
    
    	      	print $output	# print decompressed image to stdout
    				if $status == Z_OK or $status == Z_STREAM_END ;
    
    			last if $status != Z_OK;
    		}
    		die "Need preset dictionary" if $status == Z_NEED_DICT;
    		die "Data stream corrupted" if $status == Z_DATA_ERROR;
    		die "Stream structure inconsistent" if $status == Z_STREAM_ERROR;
    		die "Not enough memory" if $status == Z_MEM_ERROR;
    		die "Not enough room in output buffer" if $status == Z_BUF_ERROR;
    		seek INFILE, -(length $input), 1; # back up to include zLib header
    	}
    	#die "inflation succeeded" if $status == Z_STREAM_END; # don't seem to get to end of stream with this code
    
    	close(INFILE);
    }
    
     
  2. Acronis Support

    Acronis Support Acronis Support Staff

    Joined:
    Apr 28, 2004
    Posts:
    25,885
    Hello Gary,

    Thank you for choosing Acronis True Image (http://www.acronis.com/homecomputing/products/trueimage/).

    Please note that Acronis does not provide any tool to restore or explore the image besides Acronis True Image wizards. We haven't tested your approach and cannot guarantee that it works for everyone. Please use it at your own risk.

    Thank you.
    --
    Ilya Toytman
     
  3. Menorcaman

    Menorcaman Retired Moderator

    Joined:
    Aug 19, 2004
    Posts:
    4,661
    Location:
    Menorca (Balearic Islands) Spain
    Hi Gary,

    All water under the bridge now I guess. However, was that text file included in the image prior to the 0 byte incremental file? If so, did you try mounting/exploring the image after deleting the 0 byte file and all the encrementals that were created after it?

    Regards
     
  4. gthornejr

    gthornejr Registered Member

    Joined:
    Apr 2, 2005
    Posts:
    2
    Hi Menorcaman,

    I actually incorrectly posted the scenario. The original full backup image was 0 byte, because the backup started running and ran out of space. Apparently if the backup quits unexpectedly there is no backup file available. The five incremental backups were fine, so I used the perl script to restore the data from that file. It happened to be a file that I used somewhat frequently, so it was on the incremental backups. I did contact support who gave me your suggestion, but I was not able to mount the files via Acronis individually or by removing the zero byte file. I even tried doing a new full backup and putting that file in the place of the corrupted full backup file, but that didn't work either. Needless to say, I was desparate and excited to get the data back. :)

    Gary
     
  5. Menorcaman

    Menorcaman Retired Moderator

    Joined:
    Aug 19, 2004
    Posts:
    4,661
    Location:
    Menorca (Balearic Islands) Spain
    Hi Gary,

    Thanks for taking the time to reply and for the clarification. Clearly, as it was the full image that was 0 bytes, all of the incrementals would have been left orphaned. As you found out, creating a new full image didn't help because none of those original incrementals would have been associated with it.

    Anyway, I can imagine how pleased you were that you managed to find a third-party solution for recovering your important data. Nice work!!

    Regards
     
Thread Status:
Not open for further replies.