1
0
Fork 0

Adding upstream version 0.24.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-17 21:27:02 +01:00
parent 9a8733dd3b
commit 4f5d0de2b2
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
33 changed files with 905 additions and 882 deletions

102
decode.cc
View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2022 Antonio Diaz Diaz.
Copyright (C) 2013-2023 Antonio Diaz Diaz.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -21,7 +21,7 @@
#include <cctype>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <stdint.h> // for lzlib.h
#include <unistd.h>
#include <utime.h>
@ -246,9 +246,37 @@ void format_file_diff( std::string & ostr, const char * const filename,
{ if( verbosity >= 0 )
{ ostr += filename; ostr += ": "; ostr += msg; ostr += '\n'; } }
bool option_C_present( const Arg_parser & parser )
{
for( int i = 0; i < parser.arguments(); ++i )
if( parser.code( i ) == 'C' ) return true;
return false;
}
bool option_C_after_filename( const Arg_parser & parser )
{
for( int i = 0; i < parser.arguments(); ++i )
if( nonempty_arg( parser, i ) )
while( ++i < parser.arguments() )
if( parser.code( i ) == 'C' ) return true;
return false;
}
} // end namespace
mode_t get_umask()
{
static mode_t mask = 0; // read once, cache the result
static bool first_call = true;
if( first_call ) { first_call = false; mask = umask( 0 ); umask( mask );
mask &= S_IRWXU | S_IRWXG | S_IRWXO; }
return mask;
}
bool compare_file_type( std::string & estr, std::string & ostr,
const Cl_options & cl_opts,
const Extended & extended, const Tar_header header )
@ -380,32 +408,37 @@ int decode( const Cl_options & cl_opts )
const Archive_descriptor ad( cl_opts.archive_name );
if( ad.infd < 0 ) return 1;
// Execute -C options and mark filenames to be compared, extracted or listed.
// name_pending is of type char instead of bool to allow concurrent update.
std::vector< char > name_pending( cl_opts.parser.arguments(), false );
for( int i = 0; i < cl_opts.parser.arguments(); ++i )
{
const int code = cl_opts.parser.code( i );
if( code == 'C' && cl_opts.program_mode != m_list )
const bool c_present = option_C_present( cl_opts.parser ) &&
cl_opts.program_mode != m_list;
const bool c_after_name = c_present &&
option_C_after_filename( cl_opts.parser );
// save current working directory for sequential decoding
const int chdir_fd = c_after_name ? open( ".", O_RDONLY | O_DIRECTORY ) : -1;
if( c_after_name && chdir_fd < 0 )
{ show_error( "Can't save current working directory", errno ); return 1; }
if( c_present && !c_after_name ) // execute all -C options
for( int i = 0; i < cl_opts.parser.arguments(); ++i )
{
if( cl_opts.parser.code( i ) != 'C' ) continue;
const char * const dir = cl_opts.parser.argument( i ).c_str();
if( chdir( dir ) != 0 )
{ show_file_error( dir, chdir_msg, errno ); return 1; }
}
if( !code && cl_opts.parser.argument( i ).size() &&
/* Mark filenames to be compared, extracted or listed.
name_pending is of type char instead of bool to allow concurrent update. */
std::vector< char > name_pending( cl_opts.parser.arguments(), false );
for( int i = 0; i < cl_opts.parser.arguments(); ++i )
if( nonempty_arg( cl_opts.parser, i ) && // skip opts, empty names
!Exclude::excluded( cl_opts.parser.argument( i ).c_str() ) )
name_pending[i] = true;
}
// multi-threaded --list is faster even with 1 thread and 1 file in archive
// but multi-threaded --diff and --extract probably need at least 2 of each
if( ( cl_opts.program_mode == m_diff || cl_opts.program_mode == m_list ||
cl_opts.program_mode == m_extract ) && cl_opts.num_workers > 0 &&
ad.indexed && ad.lzip_index.members() >= 2 ) // one file + EOA
{
// show_file_error( ad.namep, "Is compressed seekable" );
/* multi-threaded --list is faster even with 1 thread and 1 file in archive
but multi-threaded --diff and --extract probably need at least 2 of each.
CWD is not per-thread; multi-threaded decode can't be used if a
-C option appears after a file name in the command line. */
if( cl_opts.num_workers > 0 && !c_after_name && ad.indexed &&
ad.lzip_index.members() >= 2 ) // 2 lzip members may be 1 file + EOA
return decode_lz( cl_opts, ad, name_pending );
}
Archive_reader ar( ad ); // serial reader
Extended extended; // metadata from extended records
@ -416,7 +449,7 @@ int decode( const Cl_options & cl_opts )
Tar_header header;
const int ret = ar.read( header, header_size );
if( ret != 0 ) { read_error( ar ); if( ar.fatal() ) { retval = ret; break; } }
if( ret != 0 || !verify_ustar_chksum( header ) ) // error or EOA
if( ret != 0 || !check_ustar_chksum( header ) ) // error or EOA
{
if( ret == 0 && block_is_zero( header, header_size ) ) // EOA
{
@ -461,20 +494,23 @@ int decode( const Cl_options & cl_opts )
extended.fill_from_ustar( header ); // copy metadata from header
// members without name are skipped except when listing
if( check_skip_filename( cl_opts, name_pending, extended.path().c_str() ) )
retval = skip_member( ar, extended, typeflag );
else
{
print_removed_prefix( extended.removed_prefix );
if( cl_opts.program_mode == m_list )
retval = list_member( ar, extended, header );
else if( extended.path().empty() )
retval = skip_member( ar, extended, typeflag );
else if( cl_opts.program_mode == m_diff )
retval = compare_member( cl_opts, ar, extended, header );
else retval = extract_member( cl_opts, ar, extended, header );
try {
// members without name are skipped except when listing
if( check_skip_filename( cl_opts, name_pending, extended.path().c_str(),
chdir_fd ) ) retval = skip_member( ar, extended, typeflag );
else
{
print_removed_prefix( extended.removed_prefix );
if( cl_opts.program_mode == m_list )
retval = list_member( ar, extended, header );
else if( extended.path().empty() )
retval = skip_member( ar, extended, typeflag );
else if( cl_opts.program_mode == m_diff )
retval = compare_member( cl_opts, ar, extended, header );
else retval = extract_member( cl_opts, ar, extended, header );
}
}
catch( Chdir_error & ) { retval = 1; }
extended.reset();
if( retval )
{ show_error( "Error is not recoverable: exiting now." ); break; }