diff options
author | Daniel Baumann <mail@daniel-baumann.ch> | 2015-11-07 11:41:34 +0000 |
---|---|---|
committer | Daniel Baumann <mail@daniel-baumann.ch> | 2015-11-07 11:41:34 +0000 |
commit | 9babb5bc11dd99942f6077669fa806d83ef146ff (patch) | |
tree | 5f2af8fceb7f878989259f6b65c6483c52891ec9 /file_index.cc | |
parent | Adding upstream version 1.14. (diff) | |
download | lziprecover-9babb5bc11dd99942f6077669fa806d83ef146ff.tar.xz lziprecover-9babb5bc11dd99942f6077669fa806d83ef146ff.zip |
Adding upstream version 1.15~pre1.upstream/1.15_pre1
Signed-off-by: Daniel Baumann <mail@daniel-baumann.ch>
Diffstat (limited to 'file_index.cc')
-rw-r--r-- | file_index.cc | 136 |
1 files changed, 124 insertions, 12 deletions
diff --git a/file_index.cc b/file_index.cc index 41bee41..997003a 100644 --- a/file_index.cc +++ b/file_index.cc @@ -52,21 +52,32 @@ const char * format_num( unsigned long long num, } -File_index::File_index( const int infd ) : retval_( 0 ) +Block Block::split( const long long pos ) + { + if( pos_ < pos && end() > pos ) + { + const Block b( pos_, pos - pos_ ); + pos_ = pos; size_ -= b.size_; + return b; + } + return Block( 0, 0 ); + } + + +File_index::File_index( const int infd ) + : + isize( lseek( infd, 0, SEEK_END ) ), retval_( 0 ) { - const long long isize = lseek( infd, 0, SEEK_END ); if( isize < 0 ) { error_ = "Input file is not seekable :"; error_ += std::strerror( errno ); retval_ = 1; return; } + if( isize < min_member_size ) + { error_ = "Input file is too short."; retval_ = 2; return; } if( isize > INT64_MAX ) { error_ = "Input file is too long (2^63 bytes or more)."; retval_ = 2; return; } - long long pos = isize; // always points to a header or EOF - File_header header; - File_trailer trailer; - if( isize < min_member_size ) - { error_ = "Input file is too short."; retval_ = 2; return; } + File_header header; if( seek_read( infd, header.data, File_header::size, 0 ) != File_header::size ) { error_ = "Error reading member header :"; error_ += std::strerror( errno ); retval_ = 1; return; } @@ -77,10 +88,12 @@ File_index::File_index( const int infd ) : retval_( 0 ) { error_ = "Version "; error_ += format_num( header.version() ); error_ += "member format not supported."; retval_ = 2; return; } + long long pos = isize; // always points to a header or to EOF while( pos >= min_member_size ) { - if( seek_read( infd, trailer.data, File_trailer::size(), - pos - File_trailer::size() ) != File_trailer::size() ) + File_trailer trailer; + if( seek_read( infd, trailer.data, File_trailer::size, + pos - File_trailer::size ) != File_trailer::size ) { error_ = "Error reading member trailer :"; error_ += std::strerror( errno ); retval_ = 1; break; } const long long member_size = trailer.member_size(); @@ -105,14 +118,113 @@ File_index::File_index( const int infd ) : retval_( 0 ) if( member_vector.size() == 0 && isize - pos > File_header::size && seek_read( infd, header.data, File_header::size, pos ) == File_header::size && header.verify_magic() && header.verify_version() ) - { // last trailer is corrupt - error_ = "Member size in trailer is corrupt at pos "; - error_ += format_num( isize - 8 ); retval_ = 2; break; + { + error_ = "Last member in input file is truncated or corrupt."; + retval_ = 2; break; + } + pos -= member_size; + member_vector.push_back( Member( 0, trailer.data_size(), + pos, member_size ) ); + } + if( pos != 0 || member_vector.size() == 0 ) + { + member_vector.clear(); + if( retval_ == 0 ) { error_ = "Can't create file index."; retval_ = 2; } + return; + } + std::reverse( member_vector.begin(), member_vector.end() ); + for( unsigned i = 0; i < member_vector.size() - 1; ++i ) + { + const long long end = member_vector[i].dblock.end(); + if( end < 0 || end > INT64_MAX ) + { + member_vector.clear(); + error_ = "Data in input file is too long (2^63 bytes or more)."; + retval_ = 2; return; + } + member_vector[i+1].dblock.pos( end ); + } + } + + +// All files in 'infd_vector' must be at least 'fsize' bytes long. +File_index::File_index( const std::vector< int > & infd_vector, + const long long fsize ) + : + isize( fsize ), retval_( 0 ) + { + if( isize < 0 ) + { error_ = "Input file is not seekable :"; + error_ += std::strerror( errno ); retval_ = 1; return; } + if( isize < min_member_size ) + { error_ = "Input file is too short."; retval_ = 2; return; } + if( isize > INT64_MAX ) + { error_ = "Input file is too long (2^63 bytes or more)."; + retval_ = 2; return; } + + const int files = infd_vector.size(); + File_header header; + bool done = false; + for( int i = 0; i < files && !done; ++i ) + { + const int infd = infd_vector[i]; + if( seek_read( infd, header.data, File_header::size, 0 ) != File_header::size ) + { error_ = "Error reading member header :"; + error_ += std::strerror( errno ); retval_ = 1; return; } + if( header.verify_magic() && header.verify_version() ) done = true; + } + if( !done ) + { error_ = "Bad magic number (file not in lzip format)."; + retval_ = 2; return; } + + long long pos = isize; // always points to a header or to EOF + while( pos >= min_member_size ) + { + long long member_size; + File_trailer trailer; + done = false; + for( int it = 0; it < files && !done; ++it ) + { + const int tfd = infd_vector[it]; + if( seek_read( tfd, trailer.data, File_trailer::size, + pos - File_trailer::size ) != File_trailer::size ) + { error_ = "Error reading member trailer :"; + error_ += std::strerror( errno ); retval_ = 1; goto error; } + member_size = trailer.member_size(); + if( member_size >= min_member_size && member_size <= pos ) + for( int ih = 0; ih < files && !done; ++ih ) + { + const int hfd = infd_vector[ih]; + if( seek_read( hfd, header.data, File_header::size, + pos - member_size ) != File_header::size ) + { error_ = "Error reading member header :"; + error_ += std::strerror( errno ); retval_ = 1; goto error; } + if( header.verify_magic() && header.verify_version() ) done = true; + } + } + if( !done ) + { + if( member_vector.size() == 0 ) // maybe trailing garbage + { --pos; continue; } + error_ = "Member size in trailer may be corrupt at pos "; + error_ += format_num( pos - 8 ); retval_ = 2; break; } + if( member_vector.size() == 0 && isize - pos > File_header::size ) + for( int i = 0; i < files; ++i ) + { + const int infd = infd_vector[i]; + if( seek_read( infd, header.data, File_header::size, pos ) == File_header::size && + header.verify_magic() && header.verify_version() ) + { + error_ = "Last member in input file is truncated or corrupt."; + retval_ = 2; goto error; + } + } pos -= member_size; member_vector.push_back( Member( 0, trailer.data_size(), pos, member_size ) ); } +error: if( pos != 0 || member_vector.size() == 0 ) { member_vector.clear(); |