1
0
Fork 0

Merging upstream version 0.11.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-17 21:12:14 +01:00
parent 3b818501c2
commit 5db1949a73
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
18 changed files with 1504 additions and 654 deletions

View file

@ -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 );
}