From 29867477a1c50b8cbea6212b8dd649a052778bf0 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2019 10:59:10 +0200 Subject: Adding upstream version 0.15. Signed-off-by: Daniel Baumann --- extract.cc | 172 +++++++++++++++++++++++++++++++------------------------------ 1 file changed, 87 insertions(+), 85 deletions(-) (limited to 'extract.cc') diff --git a/extract.cc b/extract.cc index 7d4b3ae..bd2b624 100644 --- a/extract.cc +++ b/extract.cc @@ -91,8 +91,8 @@ bool make_path( const std::string & name ) // Return value: 0 = OK, 1 = damaged member, 2 = fatal error. // If sizep and error, return in *sizep the number of bytes read. // The first 6 bytes of the archive must be intact for islz to be meaningful. -int archive_read( const int infd, uint8_t * const buf, const int size, - int * const sizep = 0 ) +int archive_read( const char * const archive_namep, const int infd, + uint8_t * const buf, const int size, int * const sizep = 0 ) { static LZ_Decoder * decoder = 0; static bool at_eof = false; @@ -109,7 +109,8 @@ int archive_read( const int infd, uint8_t * const buf, const int size, const int rd = readblock( infd, buf, size ); if( sizep ) *sizep = rd; if( rd != size && errno ) - { show_error( "Error reading archive", errno ); fatal = true; return 2; } + { show_file_error( archive_namep, "Error reading archive", errno ); + fatal = true; return 2; } const Lzip_header & header = (*(const Lzip_header *)buf); bool islz = ( rd >= min_member_size && header.verify_magic() && header.verify_version() && @@ -119,7 +120,7 @@ int archive_read( const int infd, uint8_t * const buf, const int size, ( !islz && !istar && rd == size && block_is_zero( buf, size ) ); if( !islz && !istar && !iseof ) // corrupt or invalid format { - show_error( "This does not look like a POSIX tar archive." ); + show_file_error( archive_namep, posix_msg ); if( archive_has_lz_ext && rd >= min_member_size ) islz = true; if( !islz ) return 1; } @@ -132,10 +133,10 @@ int archive_read( const int infd, uint8_t * const buf, const int size, LZ_decompress_close( decoder ); fatal = true; return 2; } if( LZ_decompress_write( decoder, buf, rd ) != rd ) internal_error( "library error (LZ_decompress_write)." ); - const int res = archive_read( infd, buf, size, sizep ); + const int res = archive_read( archive_namep, infd, buf, size, sizep ); if( res != 0 ) { if( res == 2 ) fatal = true; return res; } if( verify_ustar_chksum( buf ) || block_is_zero( buf, size ) ) return 0; - show_error( "This does not look like a POSIX tar.lz archive." ); + show_file_error( archive_namep, posix_lz_msg ); fatal = true; return 2; } @@ -143,7 +144,7 @@ int archive_read( const int infd, uint8_t * const buf, const int size, { const int rd = readblock( infd, buf, size ); if( rd == size ) return 0; if( sizep ) *sizep = rd; - show_error( "Archive ends unexpectedly." ); fatal = true; return 2; + show_file_error( archive_namep, end_msg ); fatal = true; return 2; } const int ibuf_size = 16384; uint8_t ibuf[ibuf_size]; @@ -159,11 +160,8 @@ int archive_read( const int infd, uint8_t * const buf, const int size, } if( rd == 0 && LZ_decompress_finished( decoder ) == 1 ) { LZ_decompress_close( decoder ); - show_error( "Archive ends unexpectedly." ); fatal = true; return 2; } + show_file_error( archive_namep, end_msg ); fatal = true; return 2; } sz += rd; if( sizep ) *sizep = sz; - if( sz == size && LZ_decompress_finished( decoder ) == 1 && - LZ_decompress_close( decoder ) < 0 ) - { show_error( "LZ_decompress_close failed." ); fatal = true; return 2; } if( sz < size && !at_eof && LZ_decompress_write_size( decoder ) > 0 ) { const int rsize = std::min( ibuf_size, LZ_decompress_write_size( decoder ) ); @@ -174,8 +172,8 @@ int archive_read( const int infd, uint8_t * const buf, const int size, { at_eof = true; LZ_decompress_finish( decoder ); if( errno ) - { show_error( "Error reading archive", errno ); fatal = true; - return 2; } + { show_file_error( archive_namep, "Error reading archive", errno ); + fatal = true; return 2; } } } } @@ -292,7 +290,6 @@ bool format_member_name( const Extended & extended, const Tar_header header, return true; } -namespace { bool show_member_name( const Extended & extended, const Tar_header header, const int vlevel, Resizable_buffer & rbuf ) @@ -307,22 +304,23 @@ bool show_member_name( const Extended & extended, const Tar_header header, return true; } +namespace { -int skip_member( const int infd, const Extended & extended ) +int skip_member( const char * const archive_namep, const int infd, + const Extended & extended ) { - unsigned long long rest = extended.file_size(); + long long rest = extended.file_size(); const int rem = rest % header_size; - const int padding = rem ? header_size - rem : 0; - if( archive_is_uncompressed_seekable && - lseek( infd, rest + padding, SEEK_CUR ) > 0 ) return 0; - const unsigned bufsize = 32 * header_size; + if( rem ) rest += header_size - rem; // padding + if( archive_is_uncompressed_seekable && lseek( infd, rest, SEEK_CUR ) > 0 ) + return 0; + const int bufsize = 32 * header_size; uint8_t buf[bufsize]; while( rest > 0 ) { - const int rsize = ( rest >= bufsize ) ? bufsize : rest + padding; - const int ret = archive_read( infd, buf, rsize ); + const int rsize = ( rest >= bufsize ) ? bufsize : rest; + const int ret = archive_read( archive_namep, infd, buf, rsize ); if( ret != 0 ) { if( ret == 2 ) return 2; else break; } - if( rest < bufsize ) break; rest -= rsize; } return 0; @@ -336,11 +334,12 @@ void show_file_diff( const char * const filename, const char * const msg ) } -int compare_member( const int infd1, const Extended & extended, - const Tar_header header, const bool ignore_ids ) +int compare_member( const char * const archive_namep, const int infd1, + const Extended & extended, const Tar_header header, + const bool ignore_ids ) { if( !show_member_name( extended, header, 1, grbuf ) ) return 1; - unsigned long long rest = extended.file_size(); + long long rest = extended.file_size(); const char * const filename = extended.path().c_str(); const Typeflag typeflag = (Typeflag)header[typeflag_o]; bool diff = false, size_differs = false, type_differs = true; @@ -386,7 +385,7 @@ int compare_member( const int infd1, const Extended & extended, { show_file_diff( filename, "Mod time differs" ); diff = true; } } if( ( typeflag == tf_regular || typeflag == tf_hiperf ) && - (off_t)rest != st.st_size ) // don't compare contents + rest != st.st_size ) // don't compare contents { show_file_diff( filename, "Size differs" ); size_differs = true; } if( ( typeflag == tf_chardev || typeflag == tf_blockdev ) && ( parse_octal( header + devmajor_o, devmajor_l ) != @@ -412,24 +411,26 @@ int compare_member( const int infd1, const Extended & extended, } if( diff || size_differs || type_differs ) { diff = false; set_error_status( 1 ); } - if( rest == 0 ) return 0; + if( rest <= 0 ) return 0; if( ( typeflag != tf_regular && typeflag != tf_hiperf ) || - size_differs || type_differs ) return skip_member( infd1, extended ); + size_differs || type_differs ) + return skip_member( archive_namep, infd1, extended ); // else compare file contents const int rem = rest % header_size; const int padding = rem ? header_size - rem : 0; - const unsigned bufsize = 32 * header_size; + const int bufsize = 32 * header_size; uint8_t buf1[bufsize]; uint8_t buf2[bufsize]; const int infd2 = open_instream( filename ); if( infd2 < 0 ) - { set_error_status( 1 ); return skip_member( infd1, extended ); } + { set_error_status( 1 ); + return skip_member( archive_namep, infd1, extended ); } int retval = 0; while( rest > 0 ) { const int rsize1 = ( rest >= bufsize ) ? bufsize : rest + padding; const int rsize2 = ( rest >= bufsize ) ? bufsize : rest; - const int ret = archive_read( infd1, buf1, rsize1 ); + const int ret = archive_read( archive_namep, infd1, buf1, rsize1 ); if( ret != 0 ) { if( ret == 2 ) retval = 2; diff = true; break; } if( !diff ) { @@ -456,11 +457,11 @@ int compare_member( const int infd1, const Extended & extended, } -int list_member( const int infd, const Extended & extended, - const Tar_header header ) +int list_member( const char * const archive_namep, const int infd, + const Extended & extended, const Tar_header header ) { if( !show_member_name( extended, header, 0, grbuf ) ) return 1; - return skip_member( infd, extended ); + return skip_member( archive_namep, infd, extended ); } @@ -472,14 +473,15 @@ bool contains_dotdot( const char * const filename ) } -int extract_member( const int infd, const Extended & extended, - const Tar_header header, const bool keep_damaged ) +int extract_member( const char * const archive_namep, const int infd, + const Extended & extended, const Tar_header header, + const bool keep_damaged ) { const char * const filename = extended.path().c_str(); if( contains_dotdot( filename ) ) { show_file_error( filename, "Contains a '..' component, skipping." ); - return skip_member( infd, extended ); + return skip_member( archive_namep, infd, extended ); } const mode_t mode = parse_octal( header + mode_o, mode_l ); // 12 bits const time_t mtime = parse_octal( header + mtime_o, mtime_l ); // 33 bits @@ -557,22 +559,22 @@ int extract_member( const int infd, const Extended & extended, return 2; } - const unsigned bufsize = 32 * header_size; + const int bufsize = 32 * header_size; uint8_t buf[bufsize]; - unsigned long long rest = extended.file_size(); + long long rest = extended.file_size(); const int rem = rest % header_size; const int padding = rem ? header_size - rem : 0; while( rest > 0 ) { const int rsize = ( rest >= bufsize ) ? bufsize : rest + padding; int rd; - const int ret = archive_read( infd, buf, rsize, &rd ); + const int ret = archive_read( archive_namep, infd, buf, rsize, &rd ); if( ret != 0 ) { if( outfd >= 0 ) { if( keep_damaged ) - { writeblock( outfd, buf, std::min( rest, (unsigned long long)rd ) ); + { writeblock( outfd, buf, std::min( rest, (long long)rd ) ); close( outfd ); } else { close( outfd ); std::remove( filename ); } } @@ -620,16 +622,16 @@ bool compare_tslash( const char * const name1, const char * const name2 ) namespace { -bool parse_records( const int infd, Extended & extended, - const Tar_header header, Resizable_buffer & rbuf, - const bool permissive ) +bool parse_records( const char * const archive_namep, const int infd, + Extended & extended, const Tar_header header, + Resizable_buffer & rbuf, const bool permissive ) { - const unsigned long long edsize = parse_octal( header + size_o, size_l ); - const unsigned long long bufsize = round_up( edsize ); - if( edsize == 0 || edsize >= 1ULL << 33 || bufsize == 0 || bufsize >= INT_MAX ) + const long long edsize = parse_octal( header + size_o, size_l ); + const long long bufsize = round_up( edsize ); + if( edsize <= 0 || edsize >= 1LL << 33 || bufsize >= INT_MAX ) return false; // overflow or no extended data if( !rbuf.resize( bufsize ) ) return false; // extended records buffer - return ( archive_read( infd, (uint8_t *)rbuf(), bufsize ) == 0 && + return ( archive_read( archive_namep, infd, (uint8_t *)rbuf(), bufsize ) == 0 && extended.parse( rbuf(), edsize, permissive ) ); } @@ -690,8 +692,10 @@ int decode( const std::string & archive_name, const Arg_parser & parser, const bool keep_damaged, const bool missing_crc, const bool permissive ) { - const int infd = archive_name.size() ? - open_instream( archive_name ) : STDIN_FILENO; + const bool from_stdin = archive_name.empty(); + const char * const archive_namep = + from_stdin ? "(stdin)" : archive_name.c_str(); + const int infd = from_stdin ? STDIN_FILENO : open_instream( archive_name ); if( infd < 0 ) return 1; // Execute -C options and mark filenames to be compared, extracted or listed. @@ -719,9 +723,10 @@ int decode( const std::string & archive_name, const Arg_parser & parser, const long members = lzip_index.members(); 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 ), + // show_file_error( archive_namep, "Is compressed seekable" ); + return list_lz( archive_namep, parser, name_pending, lzip_index, + filenames, debug_level, infd, + std::min( (long)num_workers, members ), missing_crc, permissive ); } if( lseek( infd, 0, SEEK_SET ) == 0 && lzip_index.retval() != 0 && @@ -733,19 +738,18 @@ int decode( const std::string & archive_name, const Arg_parser & parser, Extended extended; // metadata from extended records int retval = 0; bool prev_extended = false; // prev header was extended - while( true ) // process one tar member per iteration + while( true ) // process one tar header per iteration { Tar_header header; - const int ret = archive_read( infd, header, header_size ); - if( ret == 2 ) return 2; + const int ret = archive_read( archive_namep, infd, header, header_size ); + if( ret == 2 ) { retval = 2; break; } if( ret != 0 || !verify_ustar_chksum( header ) ) { if( ret == 0 && block_is_zero( header, header_size ) ) { - if( !prev_extended ) break; // EOF - show_file_error( archive_name.c_str(), - "Format violation: extended header followed by EOF blocks." ); - return 2; + if( !prev_extended || permissive ) break; // EOF + show_file_error( archive_namep, fv_msg1 ); + retval = 2; break; } if( skip_warn() && verbosity >= 2 ) std::fprintf( stderr, "ustar chksum = %07o\n", ustar_chksum( header ) ); @@ -756,13 +760,11 @@ int decode( const std::string & archive_name, const Arg_parser & parser, const Typeflag typeflag = (Typeflag)header[typeflag_o]; if( typeflag == tf_global ) { - if( prev_extended ) - { show_file_error( archive_name.c_str(), - "Format violation: extended header followed by global header." ); - return 2; } + if( prev_extended && !permissive ) + { show_file_error( archive_namep, fv_msg2 ); retval = 2; break; } Extended dummy; // global headers are parsed and ignored - if( !parse_records( infd, dummy, header, grbuf, true ) ) - { show_file_error( archive_name.c_str(), + if( !parse_records( archive_namep, infd, dummy, header, grbuf, true ) ) + { show_file_error( archive_namep, "Error in global extended records. Skipping to next header." ); set_error_status( 2 ); } continue; @@ -770,16 +772,14 @@ int decode( const std::string & archive_name, const Arg_parser & parser, if( typeflag == tf_extended ) { if( prev_extended && !permissive ) - { show_file_error( archive_name.c_str(), - "Format violation: consecutive extended headers found." - /*" Use --permissive.", 0, true*/ ); return 2; } - if( !parse_records( infd, extended, header, grbuf, permissive ) ) - { show_file_error( archive_name.c_str(), + { show_file_error( archive_namep, fv_msg3 ); retval = 2; break; } + if( !parse_records( archive_namep, infd, extended, header, grbuf, + permissive ) ) + { show_file_error( archive_namep, "Error in extended records. Skipping to next header." ); extended.reset(); set_error_status( 2 ); } else if( !extended.crc_present() && missing_crc ) - { show_file_error( archive_name.c_str(), - "Missing CRC in extended records." ); return 2; } + { show_file_error( archive_namep, mcrc_msg ); retval = 2; break; } prev_extended = true; continue; } @@ -787,23 +787,25 @@ int decode( const std::string & archive_name, const Arg_parser & parser, extended.fill_from_ustar( header ); // copy metadata from header - const bool skip = check_skip_filename( parser, name_pending, - extended.path().c_str(), filenames ); - if( skip ) - retval = skip_member( infd, extended ); + if( check_skip_filename( parser, name_pending, extended.path().c_str(), + filenames ) ) + retval = skip_member( archive_namep, infd, extended ); else if( program_mode == m_list ) - retval = list_member( infd, extended, header ); + retval = list_member( archive_namep, infd, extended, header ); else if( program_mode == m_diff ) - retval = compare_member( infd, extended, header, ignore_ids ); - else - retval = extract_member( infd, extended, header, keep_damaged ); + retval = compare_member( archive_namep, infd, extended, header, ignore_ids ); + else retval = extract_member( archive_namep, infd, extended, header, + keep_damaged ); extended.reset(); if( retval ) - { show_error( "Error is not recoverable: exiting now." ); - return retval; } + { show_error( "Error is not recoverable: exiting now." ); break; } } - for( int i = 0; i < parser.arguments(); ++i ) + if( close( infd ) != 0 && !retval ) + { show_file_error( archive_namep, "Error closing archive", errno ); + retval = 1; } + + if( retval == 0 ) for( int i = 0; i < parser.arguments(); ++i ) if( !parser.code( i ) && parser.argument( i ).size() && name_pending[i] ) { show_file_error( parser.argument( i ).c_str(), "Not found in archive." ); -- cgit v1.2.3