diff options
Diffstat (limited to 'repair.cc')
-rw-r--r-- | repair.cc | 88 |
1 files changed, 45 insertions, 43 deletions
@@ -20,6 +20,7 @@ #include <cerrno> #include <climits> #include <cstdio> +#include <cstdlib> #include <cstring> #include <string> #include <vector> @@ -29,15 +30,7 @@ #include "lzip.h" #include "file_index.h" - - -int seek_read( const int fd, uint8_t * const buf, const int size, - const long long pos ) - { - if( lseek( fd, pos, SEEK_SET ) == pos ) - return readblock( fd, buf, size ); - return 0; - } +#include "mtester.h" int seek_write( const int fd, const uint8_t * const buf, const int size, @@ -63,7 +56,7 @@ int repair_file( const std::string & input_filename, { pp( file_index.error().c_str() ); return file_index.retval(); } int outfd = -1; - for( int i = 0; i < file_index.members(); ++i ) + for( long i = 0; i < file_index.members(); ++i ) { const long long mpos = file_index.mblock( i ).pos(); const long long msize = file_index.mblock( i ).size(); @@ -76,50 +69,59 @@ int repair_file( const std::string & input_filename, { show_error( "Can't repair error in input file." ); cleanup_and_fail( output_filename, outfd, 2 ); } - if( outfd < 0 ) // first damaged member found + if( verbosity >= 1 ) // damaged member found { - if( !safe_seek( infd, 0 ) ) return 1; - outfd = open_outstream_rw( output_filename, force ); - if( outfd < 0 ) { close( infd ); return 1; } - if( !copy_file( infd, outfd ) ) // copy whole file - cleanup_and_fail( output_filename, outfd, 1 ); - } - - if( verbosity >= 1 ) - { - std::printf( "Repairing member %d\n", i + 1 ); + std::printf( "Repairing member %ld (failure pos = %llu)\n", + i + 1, mpos + failure_pos ); std::fflush( stdout ); } - const long long min_pos = - std::max( (long long)File_header::size, failure_pos - 1000 ); + uint8_t * const mbuffer = read_member( infd, mpos, msize ); + if( !mbuffer ) + cleanup_and_fail( output_filename, outfd, 1 ); + long pos = failure_pos; bool done = false; - for( long long pos = failure_pos; pos >= min_pos && !done ; --pos ) + while( pos >= File_header::size && pos > failure_pos - 20000 && !done ) { - if( verbosity >= 1 ) - { - std::printf( "Trying position %llu \r", mpos + pos ); - std::fflush( stdout ); - } - uint8_t byte; - if( seek_read( outfd, &byte, 1, mpos + pos ) != 1 ) - { show_error( "Error reading output file", errno ); - cleanup_and_fail( output_filename, outfd, 1 ); } - for( int i = 0; i < 256; ++i ) + const long min_pos = std::max( (long)File_header::size, pos - 1000 ); + 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 ) { - ++byte; - if( seek_write( outfd, &byte, 1, mpos + pos ) != 1 || - lseek( outfd, mpos, SEEK_SET ) < 0 ) - { show_error( "Error writing output file", errno ); - cleanup_and_fail( output_filename, outfd, 1 ); } - if( i == 255 ) break; - if( try_decompress_member( outfd, msize ) ) - { done = true; break; } + 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; + if( outfd < 0 ) // first damaged member repaired + { + if( !safe_seek( infd, 0 ) ) return 1; + outfd = open_outstream_rw( output_filename, force ); + if( outfd < 0 ) { close( infd ); return 1; } + if( !copy_file( infd, outfd ) ) // copy whole file + cleanup_and_fail( output_filename, outfd, 1 ); + } + if( seek_write( outfd, mbuffer + pos, 1, mpos + pos ) != 1 ) + { show_error( "Error writing output file", errno ); + cleanup_and_fail( output_filename, outfd, 1 ); } + break; + } + } } + delete master; } + delete[] mbuffer; if( verbosity >= 1 ) std::printf( "\n" ); if( !done ) { - show_error( "Error is larger than 1 byte. Can't repair input file." ); + show_error( "Can't repair input file. Error is probably larger than 1 byte." ); cleanup_and_fail( output_filename, outfd, 2 ); } } |