diff options
Diffstat (limited to '')
-rw-r--r-- | repair.cc | 186 |
1 files changed, 181 insertions, 5 deletions
@@ -1,5 +1,5 @@ /* Lziprecover - Data recovery tool for the lzip format - Copyright (C) 2009-2014 Antonio Diaz Diaz. + Copyright (C) 2009-2015 Antonio Diaz Diaz. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -29,9 +29,12 @@ #include <sys/stat.h> #include "lzip.h" -#include "file_index.h" #include "mtester.h" +#include "block.h" +#include "file_index.h" + +namespace { int seek_write( const int fd, const uint8_t * const buf, const int size, const long long pos ) @@ -41,6 +44,8 @@ int seek_write( const int fd, const uint8_t * const buf, const int size, return 0; } +} // end namespace + int repair_file( const std::string & input_filename, const std::string & output_filename, const int verbosity, @@ -80,13 +85,13 @@ int repair_file( const std::string & input_filename, cleanup_and_fail( output_filename, outfd, 1 ); long pos = failure_pos; bool done = false; - while( pos >= File_header::size && pos > failure_pos - 40000 && !done ) + while( pos >= File_header::size && pos > failure_pos - 50000 && !done ) { - const long min_pos = std::max( (long)File_header::size, pos - 1000 ); + const long min_pos = std::max( (long)File_header::size, pos - 100 ); const LZ_mtester * master = prepare_master( mbuffer, msize, min_pos - 16 ); if( !master ) cleanup_and_fail( output_filename, outfd, 1 ); - for( ; pos >= min_pos && !done ; --pos ) + for( ; pos >= min_pos && !done; --pos ) { if( verbosity >= 1 ) { @@ -141,3 +146,174 @@ int repair_file( const std::string & input_filename, std::fputs( "Copy of input file repaired successfully.\n", stdout ); return 0; } + + +int debug_delay( const std::string & input_filename, Block range, + const int verbosity ) + { + struct stat in_stats; + const int infd = open_instream( input_filename.c_str(), &in_stats, true, true ); + if( infd < 0 ) return 1; + + Pretty_print pp( input_filename, verbosity ); + const File_index file_index( infd ); + if( file_index.retval() != 0 ) + { pp( file_index.error().c_str() ); return file_index.retval(); } + + if( range.end() > file_index.file_end() ) + range.size( std::max( 0LL, file_index.file_end() - range.pos() ) ); + if( range.size() <= 0 ) + { if( verbosity >= 0 ) pp( "Nothing to do." ); return 0; } + + for( long i = 0; i < file_index.members(); ++i ) + { + const Block & mb = file_index.mblock( i ); + if( !range.overlaps( mb ) ) continue; + const long long mpos = file_index.mblock( i ).pos(); + const long long msize = file_index.mblock( i ).size(); + if( verbosity >= 1 ) // damaged member found + { + std::printf( "Finding max delay in member %ld of %ld (member pos = %llu)\n", + i + 1, (long)file_index.members(), mpos ); + std::fflush( stdout ); + } + uint8_t * const mbuffer = read_member( infd, mpos, msize ); + if( !mbuffer ) + { show_error( "Can't read member." ); return 1; } + long pos = std::max( range.pos() - mpos, File_header::size + 1LL ); + const long end = std::min( range.end() - mpos, msize ); + long max_delay = 0; + while( pos < end ) + { + const LZ_mtester * master = prepare_master( mbuffer, msize, pos - 16 ); + if( !master ) + { show_error( "Can't prepare master." ); return 1; } + const long partial_end = std::min( pos + 100, end ); + for( ; pos < partial_end; ++pos ) + { + if( verbosity >= 1 ) + { + std::printf( "Delays in position %llu \r", mpos + pos ); + std::fflush( stdout ); + } + int value = -1; + for( int j = 0; j < 256; ++j ) + { + ++mbuffer[pos]; + if( j == 255 ) break; + long failure_pos; + if( test_member_rest( *master, &failure_pos ) ) continue; + const long delay = failure_pos - pos; + if( delay > max_delay ) { max_delay = delay; value = mbuffer[pos]; } + } + if( value >= 0 && verbosity >= 0 ) + { + std::printf( "New max delay %lu at position %llu (0x%02X)\n", + max_delay, mpos + pos, value ); + std::fflush( stdout ); + } + if( pos + max_delay >= msize ) { pos = end; break; } + } + delete master; + } + delete[] mbuffer; + if( verbosity >= 1 ) std::fputs( "\n", stdout ); + } + + if( verbosity >= 1 ) std::fputs( "Done.\n", stdout ); + return 0; + } + + +int debug_repair( const std::string & input_filename, const long long bad_pos, + const int verbosity, const uint8_t bad_value ) + { + struct stat in_stats; + const int infd = open_instream( input_filename.c_str(), &in_stats, true, true ); + if( infd < 0 ) return 1; + + Pretty_print pp( input_filename, verbosity ); + const File_index file_index( infd ); + if( file_index.retval() != 0 ) + { pp( file_index.error().c_str() ); return file_index.retval(); } + + long idx = 0; + for( ; idx < file_index.members(); ++idx ) + if( file_index.mblock( idx ).includes( bad_pos ) ) break; + if( idx >= file_index.members() ) + { if( verbosity >= 0 ) pp( "Nothing to do." ); return 0; } + + const long long mpos = file_index.mblock( idx ).pos(); + const long long msize = file_index.mblock( idx ).size(); + { + long long failure_pos = 0; + if( !safe_seek( infd, mpos ) ) + { show_error( "Can't seek to member." ); return 1; } + if( !try_decompress_member( infd, msize, &failure_pos ) ) + { + if( verbosity >= 0 ) + std::printf( "Member %ld of %ld already damaged (failure pos = %llu)\n", + idx + 1, (long)file_index.members(), mpos + failure_pos ); + return 1; + } + } + uint8_t * const mbuffer = read_member( infd, mpos, msize ); + if( !mbuffer ) + { show_error( "Can't read member." ); return 1; } + const uint8_t good_value = mbuffer[bad_pos]; + mbuffer[bad_pos] = bad_value; + long failure_pos = 0; + { + const LZ_mtester * master = prepare_master( mbuffer, msize, 0 ); + if( !master ) + { show_error( "Can't prepare master." ); return 1; } + if( test_member_rest( *master, &failure_pos ) ) + { + if( verbosity >= 1 ) + std::fputs( "Member decompressed with no errors.\n", stdout ); + return 0; + } + if( verbosity >= 1 ) + { + std::printf( "Test repairing member %ld of %ld\n" + " (damage pos = %llu (0x%02X->0x%02X), failure pos = %llu)\n", + idx + 1, (long)file_index.members(), mpos + bad_pos, + good_value, bad_value, mpos + failure_pos ); + std::fflush( stdout ); + } + } + long pos = failure_pos; + bool done = false; + while( pos >= File_header::size && pos > failure_pos - 50000 && !done ) + { + const long min_pos = std::max( (long)File_header::size, pos - 100 ); + const LZ_mtester * master = prepare_master( mbuffer, msize, min_pos - 16 ); + if( !master ) + { show_error( "Can't prepare master." ); return 1; } + for( ; pos >= min_pos && !done; --pos ) + { + if( verbosity >= 1 ) + { + std::printf( "Trying position %llu \r", mpos + pos ); + std::fflush( stdout ); + } + for( int j = 0; j < 256; ++j ) + { + ++mbuffer[pos]; + if( j == 255 ) break; + if( test_member_rest( *master ) ) { done = true; break; } + } + } + delete master; + } + delete[] mbuffer; + if( verbosity >= 1 ) std::fputs( "\n", stdout ); + if( !done ) + { + show_error( "Can't repair input file. There is a bug somewhere." ); + return 3; + } + if( verbosity >= 1 ) + std::fputs( "Member repaired successfully.\n", stdout ); + return 0; + } |