diff options
Diffstat (limited to '')
-rw-r--r-- | extract.cc | 133 |
1 files changed, 29 insertions, 104 deletions
@@ -37,7 +37,6 @@ #include <lzlib.h> #include "arg_parser.h" -#include "lzip.h" #include "lzip_index.h" #include "tarlz.h" @@ -268,19 +267,19 @@ void format_member_name( const Extended & extended, const Tar_header header, for( int i = 0; i < 2; ++i ) { const int len = snprintf( rbuf() + offset, rbuf.size() - offset, - " %9llu %4d-%02u-%02u %02u:%02u %s%s%s\n", - extended.size, 1900 + tm->tm_year, 1 + tm->tm_mon, - tm->tm_mday, tm->tm_hour, tm->tm_min, extended.path.c_str(), - link_string, !islink ? "" : extended.linkpath.c_str() ); + " %9llu %4d-%02u-%02u %02u:%02u %s%s%s\n", + extended.file_size(), 1900 + tm->tm_year, 1 + tm->tm_mon, + tm->tm_mday, tm->tm_hour, tm->tm_min, extended.path().c_str(), + link_string, !islink ? "" : extended.linkpath().c_str() ); if( (int)rbuf.size() > len + offset ) break; else rbuf.resize( len + offset + 1 ); } } else { - if( rbuf.size() < extended.path.size() + 2 ) - rbuf.resize( extended.path.size() + 2 ); - snprintf( rbuf(), rbuf.size(), "%s\n", extended.path.c_str() ); + if( rbuf.size() < extended.path().size() + 2 ) + rbuf.resize( extended.path().size() + 2 ); + snprintf( rbuf(), rbuf.size(), "%s\n", extended.path().c_str() ); } } @@ -303,8 +302,8 @@ int list_member( const int infd, const Extended & extended, const unsigned bufsize = 32 * header_size; uint8_t buf[bufsize]; - unsigned long long rest = extended.size; - const int rem = extended.size % header_size; + unsigned long long rest = extended.file_size(); + const int rem = rest % header_size; const int padding = rem ? header_size - rem : 0; while( rest > 0 ) { @@ -331,7 +330,7 @@ bool contains_dotdot( const char * const filename ) int extract_member( const int infd, const Extended & extended, const Tar_header header, const bool keep_damaged ) { - const char * const filename = extended.path.c_str(); + const char * const filename = extended.path().c_str(); if( contains_dotdot( filename ) ) { show_file_error( filename, "Contains a '..' component, skipping." ); @@ -357,7 +356,7 @@ int extract_member( const int infd, const Extended & extended, case tf_link: case tf_symlink: { - const char * const linkname = extended.linkpath.c_str(); + const char * const linkname = extended.linkpath().c_str(); /* if( contains_dotdot( linkname ) ) { show_file_error( filename, @@ -421,8 +420,8 @@ int extract_member( const int infd, const Extended & extended, const unsigned bufsize = 32 * header_size; uint8_t buf[bufsize]; - unsigned long long rest = extended.size; - const int rem = extended.size % header_size; + unsigned long long rest = extended.file_size(); + const int rem = rest % header_size; const int padding = rem ? header_size - rem : 0; while( rest > 0 ) { @@ -501,42 +500,6 @@ bool compare_tslash( const char * const name1, const char * const name2 ) namespace { -unsigned long long parse_decimal( const char * const ptr, - const char ** const tailp, - const unsigned long long size ) - { - unsigned long long result = 0; - unsigned long long i = 0; - while( i < size && std::isspace( ptr[i] ) ) ++i; - if( !std::isdigit( (unsigned char)ptr[i] ) ) - { if( tailp ) *tailp = ptr; return 0; } - for( ; i < size && std::isdigit( (unsigned char)ptr[i] ); ++i ) - { - const unsigned long long prev = result; - result *= 10; result += ptr[i] - '0'; - if( result < prev || result > LLONG_MAX ) // overflow - { if( tailp ) *tailp = ptr; return 0; } - } - if( tailp ) *tailp = ptr + i; - return result; - } - - -uint32_t parse_record_crc( const char * const ptr ) - { - uint32_t crc = 0; - for( int i = 0; i < 8; ++i ) - { - crc <<= 4; - if( ptr[i] >= '0' && ptr[i] <= '9' ) crc += ptr[i] - '0'; - else if( ptr[i] >= 'A' && ptr[i] <= 'F' ) crc += ptr[i] + 10 - 'A'; - else if( ptr[i] >= 'a' && ptr[i] <= 'f' ) crc += ptr[i] + 10 - 'a'; - else { crc = 0; break; } // invalid digit in crc string - } - return crc; - } - - bool parse_records( const int infd, Extended & extended, const Tar_header header, const bool permissive ) { @@ -602,48 +565,6 @@ unsigned long long parse_octal( const uint8_t * const ptr, const int size ) } -bool Extended::parse( const char * const buf, const unsigned long long edsize, - const bool permissive ) - { - for( unsigned long long pos = 0; pos < edsize; ) // parse records - { - const char * tail; - const unsigned long long rsize = - parse_decimal( buf + pos, &tail, edsize - pos ); - if( rsize == 0 || rsize > edsize - pos || tail[0] != ' ' || - buf[pos+rsize-1] != '\n' ) return false; - ++tail; // point to keyword - // rest = length of (keyword + '=' + value) without the final newline - const unsigned long long rest = ( buf + ( pos + rsize - 1 ) ) - tail; - if( rest > 5 && std::memcmp( tail, "path=", 5 ) == 0 ) - { if( path.size() && !permissive ) return false; - path.assign( tail + 5, rest - 5 ); } - else if( rest > 9 && std::memcmp( tail, "linkpath=", 9 ) == 0 ) - { if( linkpath.size() && !permissive ) return false; - linkpath.assign( tail + 9, rest - 9 ); } - else if( rest > 5 && std::memcmp( tail, "size=", 5 ) == 0 ) - { - if( size != 0 && !permissive ) return false; - size = parse_decimal( tail + 5, &tail, rest - 5 ); - // parse error or size fits in ustar header - if( size < 1ULL << 33 || tail != buf + ( pos + rsize - 1 ) ) return false; - } - else if( rest > 10 && std::memcmp( tail, "GNU.crc32=", 10 ) == 0 ) - { - if( crc_present && !permissive ) return false; - if( rsize != 22 ) return false; - const uint32_t stored_crc = parse_record_crc( tail + 10 ); - const uint32_t computed_crc = - crc32c.windowed_crc( (const uint8_t *)buf, pos + rsize - 9, edsize ); - crc_present = true; - if( stored_crc != computed_crc ) return false; - } - pos += rsize; - } - return true; - } - - int decode( const std::string & archive_name, const Arg_parser & parser, const int filenames, const int num_workers, const int debug_level, const bool keep_damaged, const bool listing, const bool missing_crc, @@ -722,23 +643,27 @@ int decode( const std::string & archive_name, const Arg_parser & parser, if( !parse_records( infd, extended, header, permissive ) ) { show_error( "Error in extended records. Skipping to next header." ); extended.reset(); gretval = 2; } - else if( !extended.crc_present && missing_crc ) + else if( !extended.crc_present() && missing_crc ) { show_error( "Missing CRC in extended records.", 0, true ); return 2; } prev_extended = true; continue; } prev_extended = false; - if( extended.linkpath.empty() ) // copy linkpath from ustar header + if( extended.linkpath().empty() ) // copy linkpath from ustar header { - for( int i = 0; i < linkname_l && header[linkname_o+i]; ++i ) - extended.linkpath += header[linkname_o+i]; - while( extended.linkpath.size() > 1 && // trailing '/' - extended.linkpath[extended.linkpath.size()-1] == '/' ) - extended.linkpath.resize( extended.linkpath.size() - 1 ); + int len = 0; + while( len < linkname_l && header[linkname_o+len] ) ++len; + while( len > 1 && header[linkname_o+len-1] == '/' ) --len; // trailing '/' + if( len > 0 ) + { + const uint8_t c = header[linkname_o+len]; header[linkname_o+len] = 0; + extended.linkpath( (const char *)header + linkname_o ); + header[linkname_o+len] = c; + } } - if( extended.path.empty() ) // copy path from ustar header + if( extended.path().empty() ) // copy path from ustar header { char stored_name[prefix_l+1+name_l+1]; int len = 0; @@ -749,9 +674,9 @@ int decode( const std::string & archive_name, const Arg_parser & parser, { stored_name[len] = header[name_o+i]; ++len; } while( len > 0 && stored_name[len-1] == '/' ) --len; // trailing '/' stored_name[len] = 0; - extended.path = remove_leading_slash( stored_name ); + extended.path( remove_leading_slash( stored_name ) ); } - const char * const filename = extended.path.c_str(); + const char * const filename = extended.path().c_str(); bool skip = filenames > 0; if( skip ) @@ -765,9 +690,9 @@ int decode( const std::string & archive_name, const Arg_parser & parser, { skip = false; name_pending[i] = false; break; } } - if( extended.size == 0 && + if( extended.file_size() == 0 && ( typeflag == tf_regular || typeflag == tf_hiperf ) ) - extended.size = parse_octal( header + size_o, size_l ); + extended.file_size( parse_octal( header + size_o, size_l ) ); if( listing || skip ) retval = list_member( infd, extended, header, skip ); |