summaryrefslogtreecommitdiffstats
path: root/extract.cc
diff options
context:
space:
mode:
Diffstat (limited to 'extract.cc')
-rw-r--r--extract.cc94
1 files changed, 54 insertions, 40 deletions
diff --git a/extract.cc b/extract.cc
index 04d974a..7d4b3ae 100644
--- a/extract.cc
+++ b/extract.cc
@@ -44,9 +44,9 @@
namespace {
-Resizable_buffer grbuf( initial_line_length );
+Resizable_buffer grbuf;
bool archive_is_uncompressed_seekable = false;
-bool has_lz_ext; // global var for archive_read
+bool archive_has_lz_ext; // local var for archive_read
bool skip_warn( const bool reset = false ) // avoid duplicate warnings
{
@@ -120,7 +120,7 @@ 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 && rd >= min_member_size ) islz = true;
+ if( archive_has_lz_ext && rd >= min_member_size ) islz = true;
if( !islz ) return 1;
}
if( !islz ) // uncompressed
@@ -247,7 +247,7 @@ bool block_is_zero( const uint8_t * const buf, const int size )
}
-void format_member_name( const Extended & extended, const Tar_header header,
+bool format_member_name( const Extended & extended, const Tar_header header,
Resizable_buffer & rbuf, const bool long_format )
{
if( long_format )
@@ -279,27 +279,32 @@ void format_member_name( const Extended & extended, const Tar_header header,
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 || !rbuf.resize( len + offset + 1 ) )
- break;
+ if( (int)rbuf.size() > len + offset ) break;
+ if( !rbuf.resize( len + offset + 1 ) ) return false;
}
}
else
{
- if( rbuf.size() < extended.path().size() + 2 )
- rbuf.resize( extended.path().size() + 2 );
+ if( rbuf.size() < extended.path().size() + 2 &&
+ !rbuf.resize( extended.path().size() + 2 ) ) return false;
snprintf( rbuf(), rbuf.size(), "%s\n", extended.path().c_str() );
}
+ return true;
}
namespace {
-void show_member_name( const Extended & extended, const Tar_header header,
+bool show_member_name( const Extended & extended, const Tar_header header,
const int vlevel, Resizable_buffer & rbuf )
{
- if( verbosity < vlevel ) return;
- format_member_name( extended, header, rbuf, verbosity > vlevel );
- std::fputs( rbuf(), stdout );
- std::fflush( stdout );
+ if( verbosity >= vlevel )
+ {
+ if( !format_member_name( extended, header, rbuf, verbosity > vlevel ) )
+ { show_error( mem_msg ); return false; }
+ std::fputs( rbuf(), stdout );
+ std::fflush( stdout );
+ }
+ return true;
}
@@ -326,20 +331,21 @@ int skip_member( const int infd, const Extended & extended )
void show_file_diff( const char * const filename, const char * const msg )
{
- if( verbosity >= 0 ) std::fprintf( stderr, "%s: %s\n", filename, msg );
+ if( verbosity >= 0 )
+ { std::printf( "%s: %s\n", filename, msg ); std::fflush( stdout ); }
}
int compare_member( const int infd1, const Extended & extended,
const Tar_header header, const bool ignore_ids )
{
- show_member_name( extended, header, 1, grbuf );
+ if( !show_member_name( extended, header, 1, grbuf ) ) return 1;
unsigned 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;
struct stat st;
- if( lstat( filename, &st ) != 0 )
+ if( hstat( filename, &st ) != 0 )
show_file_error( filename, "Warning: Can't stat", errno );
else if( ( typeflag == tf_regular || typeflag == tf_hiperf ) &&
!S_ISREG( st.st_mode ) )
@@ -453,7 +459,7 @@ int compare_member( const int infd1, const Extended & extended,
int list_member( const int infd, const Extended & extended,
const Tar_header header )
{
- show_member_name( extended, header, 0, grbuf );
+ if( !show_member_name( extended, header, 0, grbuf ) ) return 1;
return skip_member( infd, extended );
}
@@ -481,7 +487,7 @@ int extract_member( const int infd, const Extended & extended,
const bool islink = ( typeflag == tf_link || typeflag == tf_symlink );
int outfd = -1;
- show_member_name( extended, header, 1, grbuf );
+ if( !show_member_name( extended, header, 1, grbuf ) ) return 1;
std::remove( filename );
make_path( filename );
switch( typeflag )
@@ -615,17 +621,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, const bool permissive )
+ 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( bufsize == 0 || edsize == 0 || edsize >= 1ULL << 33 )
+ if( edsize == 0 || edsize >= 1ULL << 33 || bufsize == 0 || bufsize >= INT_MAX )
return false; // overflow or no extended data
- char * const buf = new char[bufsize]; // extended records buffer
- const bool ret = ( archive_read( infd, (uint8_t *)buf, bufsize ) == 0 &&
- extended.parse( buf, edsize, permissive ) );
- delete[] buf;
- return ret;
+ if( !rbuf.resize( bufsize ) ) return false; // extended records buffer
+ return ( archive_read( infd, (uint8_t *)rbuf(), bufsize ) == 0 &&
+ extended.parse( rbuf(), edsize, permissive ) );
}
} // end namespace
@@ -702,7 +707,9 @@ int decode( const std::string & archive_name, const Arg_parser & parser,
{ show_file_error( dir, "Error changing working directory", errno );
return 1; }
}
- if( !code && parser.argument( i ).size() ) name_pending[i] = true;
+ if( !code && parser.argument( i ).size() &&
+ !Exclude::excluded( parser.argument( i ).c_str() ) )
+ name_pending[i] = true;
}
// multi-threaded --list is faster even with 1 thread and 1 file in archive
@@ -722,11 +729,7 @@ int decode( const std::string & archive_name, const Arg_parser & parser,
archive_is_uncompressed_seekable = true; // unless compressed corrupt
}
- has_lz_ext = // global var for archive_read
- ( archive_name.size() > 3 &&
- archive_name.compare( archive_name.size() - 3, 3, ".lz" ) == 0 ) ||
- ( archive_name.size() > 4 &&
- archive_name.compare( archive_name.size() - 4, 4, ".tlz" ) == 0 );
+ archive_has_lz_ext = has_lz_ext( archive_name ); // var for archive_read
Extended extended; // metadata from extended records
int retval = 0;
bool prev_extended = false; // prev header was extended
@@ -737,35 +740,46 @@ int decode( const std::string & archive_name, const Arg_parser & parser,
if( ret == 2 ) return 2;
if( ret != 0 || !verify_ustar_chksum( header ) )
{
- if( ret == 0 && block_is_zero( header, header_size ) ) break; // EOF
+ 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( skip_warn() && verbosity >= 2 )
std::fprintf( stderr, "ustar chksum = %07o\n", ustar_chksum( header ) );
set_error_status( 2 ); continue;
}
- skip_warn( true ); // reset warning
+ skip_warn( true ); // reset warning
const Typeflag typeflag = (Typeflag)header[typeflag_o];
if( typeflag == tf_global )
{
if( prev_extended )
- { show_error( "Format violation: global header after extended header." );
+ { show_file_error( archive_name.c_str(),
+ "Format violation: extended header followed by global header." );
return 2; }
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." );
+ if( !parse_records( infd, dummy, header, grbuf, true ) )
+ { show_file_error( archive_name.c_str(),
+ "Error in global extended records. Skipping to next header." );
set_error_status( 2 ); }
continue;
}
if( typeflag == tf_extended )
{
if( prev_extended && !permissive )
- { show_error( "Format violation: consecutive extended headers found."
+ { 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, permissive ) )
- { show_error( "Error in extended records. Skipping to next header." );
+ if( !parse_records( infd, extended, header, grbuf, permissive ) )
+ { show_file_error( archive_name.c_str(),
+ "Error in extended records. Skipping to next header." );
extended.reset(); set_error_status( 2 ); }
else if( !extended.crc_present() && missing_crc )
- { show_error( "Missing CRC in extended records.", 0, true ); return 2; }
+ { show_file_error( archive_name.c_str(),
+ "Missing CRC in extended records." ); return 2; }
prev_extended = true;
continue;
}