diff options
Diffstat (limited to 'extract.cc')
-rw-r--r-- | extract.cc | 75 |
1 files changed, 27 insertions, 48 deletions
@@ -44,7 +44,6 @@ namespace { Resizable_buffer grbuf( initial_line_length ); -int gretval = 0; bool has_lz_ext; // global var for archive_read void skip_warn( const bool reset = false ) // avoid duplicate warnings @@ -118,16 +117,14 @@ int archive_read( const int infd, uint8_t * const buf, const int size, if( !islz && !istar && !iseof ) // corrupt or invalid format { show_error( "This does not look like a POSIX tar archive." ); - if( has_lz_ext ) islz = true; - if( verbosity >= 2 && !islz && rd == size ) - std::fprintf( stderr, "ustar chksum = %07o\n", ustar_chksum( buf ) ); + if( has_lz_ext && rd >= min_member_size ) islz = true; if( !islz ) return 1; } if( !islz ) // uncompressed { if( rd == size ) return 0; fatal = true; return 2; } decoder = LZ_decompress_open(); // compressed if( !decoder || LZ_decompress_errno( decoder ) != LZ_ok ) - { show_error( "Not enough memory." ); + { show_error( mem_msg ); LZ_decompress_close( decoder ); fatal = true; return 2; } if( LZ_decompress_write( decoder, buf, rd ) != rd ) internal_error( "library error (LZ_decompress_write)." ); @@ -154,7 +151,7 @@ int archive_read( const int infd, uint8_t * const buf, const int size, { if( LZ_decompress_sync_to_member( decoder ) < 0 ) internal_error( "library error (LZ_decompress_sync_to_member)." ); - skip_warn(); gretval = 2; return 1; + skip_warn(); set_error_status( 2 ); return 1; } if( rd == 0 && LZ_decompress_finished( decoder ) == 1 ) { LZ_decompress_close( decoder ); @@ -271,8 +268,8 @@ void format_member_name( const Extended & extended, const Tar_header header, 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 ); + if( (int)rbuf.size() > len + offset || !rbuf.resize( len + offset + 1 ) ) + break; } } else @@ -458,25 +455,6 @@ int extract_member( const int infd, const Extended & extended, } // end namespace -// Removes any amount of leading "./" and '/' strings. -const char * remove_leading_slash( const char * const filename ) - { - static bool first_post = true; - const char * p = filename; - - while( *p == '/' || ( *p == '.' && p[1] == '/' ) ) ++p; - if( p != filename && first_post ) - { - first_post = false; - std::string msg( "Removing leading '" ); - msg.append( filename, p - filename ); - msg += "' from member names."; - show_error( msg.c_str() ); - } - if( *p == 0 ) p = "."; - return p; - } - // return true if dir is a parent directory of name bool compare_prefix_dir( const char * const dir, const char * const name ) @@ -587,19 +565,21 @@ int decode( const std::string & archive_name, const Arg_parser & parser, { show_file_error( dir, "Error changing working directory", errno ); return 1; } } - if( !code ) name_pending[i] = true; + if( !code && parser.argument( i ).size() ) name_pending[i] = true; } - if( listing && num_workers > 0 ) // multi-threaded --list + // multi-threaded --list is faster even with 1 thread and 1 file in archive + if( listing && num_workers > 0 ) { - const Lzip_index lzip_index( infd, true, false ); + const Lzip_index lzip_index( infd, true, false ); // only regular files const long members = lzip_index.members(); - if( lzip_index.retval() == 0 && ( members >= 3 || - ( members >= 2 && lzip_index.dblock( members - 1 ).size() > 1024 ) ) ) - { //show_file_error( archive_name.c_str(), "Is compressed seekable" ); - return list_lz( parser, name_pending, lzip_index, filenames, - debug_level, infd, std::min( (long)num_workers, members ), - missing_crc, permissive ); } + if( lzip_index.retval() == 0 && members >= 2 ) // one file + eof + { + // show_file_error( archive_name.c_str(), "Is compressed seekable" ); + return list_lz( parser, name_pending, lzip_index, filenames, debug_level, + infd, std::min( (long)num_workers, members ), + missing_crc, permissive ); + } lseek( infd, 0, SEEK_SET ); } @@ -619,7 +599,9 @@ int decode( const std::string & archive_name, const Arg_parser & parser, if( ret != 0 || !verify_ustar_chksum( header ) ) { if( ret == 0 && block_is_zero( header, header_size ) ) break; // EOF - skip_warn(); gretval = 2; continue; + if( verbosity >= 2 ) + std::fprintf( stderr, "ustar chksum = %07o\n", ustar_chksum( header ) ); + skip_warn(); set_error_status( 2 ); continue; } skip_warn( true ); // reset warning @@ -632,7 +614,7 @@ int decode( const std::string & archive_name, const Arg_parser & parser, Extended dummy; // global headers are parsed and ignored if( !parse_records( infd, dummy, header, true ) ) { show_error( "Error in global extended records. Skipping to next header." ); - gretval = 2; } + set_error_status( 2 ); } continue; } if( typeflag == tf_extended ) @@ -642,7 +624,7 @@ int decode( const std::string & archive_name, const Arg_parser & parser, /*" Use --permissive.", 0, true*/ ); return 2; } if( !parse_records( infd, extended, header, permissive ) ) { show_error( "Error in extended records. Skipping to next header." ); - extended.reset(); gretval = 2; } + extended.reset(); set_error_status( 2 ); } else if( !extended.crc_present() && missing_crc ) { show_error( "Missing CRC in extended records.", 0, true ); return 2; } prev_extended = true; @@ -674,17 +656,17 @@ 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_dotslash( stored_name ) ); } const char * const filename = extended.path().c_str(); bool skip = filenames > 0; if( skip ) for( int i = 0; i < parser.arguments(); ++i ) - if( parser.code( i ) == 0 ) + if( !parser.code( i ) && parser.argument( i ).size() ) { const char * const name = - remove_leading_slash( parser.argument( i ).c_str() ); + remove_leading_dotslash( parser.argument( i ).c_str() ); if( compare_prefix_dir( name, filename ) || compare_tslash( name, filename ) ) { skip = false; name_pending[i] = false; break; } @@ -705,13 +687,10 @@ int decode( const std::string & archive_name, const Arg_parser & parser, } for( int i = 0; i < parser.arguments(); ++i ) - if( parser.code( i ) == 0 && name_pending[i] ) + if( !parser.code( i ) && parser.argument( i ).size() && name_pending[i] ) { show_file_error( parser.argument( i ).c_str(), "Not found in archive." ); - if( gretval < 1 ) gretval = 1; + set_error_status( 1 ); } - if( !retval && gretval ) - { show_error( "Exiting with failure status due to previous errors." ); - retval = gretval; } - return retval; + return final_exit_status( retval ); } |