1
0
Fork 0

Adding upstream version 0.22.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-17 21:16:46 +01:00
parent cc1b855cb3
commit 22f7f3575c
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
30 changed files with 307 additions and 182 deletions

154
main.cc
View file

@ -1,5 +1,5 @@
/* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2021 Antonio Diaz Diaz.
Copyright (C) 2013-2022 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
@ -56,7 +56,7 @@ const char * const program_name = "tarlz";
namespace {
const char * const program_year = "2021";
const char * const program_year = "2022";
const char * invocation_name = program_name; // default value
@ -146,17 +146,44 @@ void show_version()
}
int check_lzlib_ver() // <major>.<minor> or <major>.<minor>[a-z.-]*
{
#if defined LZ_API_VERSION && LZ_API_VERSION >= 1012
const unsigned char * p = (unsigned char *)LZ_version_string;
unsigned major = 0, minor = 0;
while( major < 100000 && isdigit( *p ) )
{ major *= 10; major += *p - '0'; ++p; }
if( *p == '.' ) ++p;
else
out: { show_error( "Invalid LZ_version_string in lzlib.h" ); return 2; }
while( minor < 100 && isdigit( *p ) )
{ minor *= 10; minor += *p - '0'; ++p; }
if( *p && *p != '-' && *p != '.' && !std::islower( *p ) ) goto out;
const unsigned version = major * 1000 + minor;
if( LZ_API_VERSION != version )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Version mismatch in lzlib.h: "
"LZ_API_VERSION = %u, should be %u.\n",
program_name, LZ_API_VERSION, version );
return 2;
}
#endif
return 0;
}
int check_lib()
{
bool warning = false;
int retval = check_lzlib_ver();
if( std::strcmp( LZ_version_string, LZ_version() ) != 0 )
{ warning = true;
{ set_retval( retval, 1 );
if( verbosity >= 0 )
std::printf( "warning: LZ_version_string != LZ_version() (%s vs %s)\n",
LZ_version_string, LZ_version() ); }
#if defined LZ_API_VERSION && LZ_API_VERSION >= 1012
if( LZ_API_VERSION != LZ_api_version() )
{ warning = true;
{ set_retval( retval, 1 );
if( verbosity >= 0 )
std::printf( "warning: LZ_API_VERSION != LZ_api_version() (%u vs %u)\n",
LZ_API_VERSION, LZ_api_version() ); }
@ -173,20 +200,54 @@ int check_lib()
"Using an unknown LZ_API_VERSION\n", LZ_API_VERSION );
#endif
}
return warning;
return retval;
}
unsigned long long getnum( const char * const ptr,
// separate large numbers >= 100_000 in groups of 3 digits using '_'
const char * format_num3( unsigned long long num )
{
const char * const si_prefix = "kMGTPEZY";
const char * const binary_prefix = "KMGTPEZY";
enum { buffers = 8, bufsize = 4 * sizeof (long long) };
static char buffer[buffers][bufsize]; // circle of static buffers for printf
static int current = 0;
char * const buf = buffer[current++]; current %= buffers;
char * p = buf + bufsize - 1; // fill the buffer backwards
*p = 0; // terminator
char prefix = 0; // try binary first, then si
for( int i = 0; i < 8 && num >= 1024 && num % 1024 == 0; ++i )
{ num /= 1024; prefix = binary_prefix[i]; }
if( prefix ) *(--p) = 'i';
else
for( int i = 0; i < 8 && num >= 1000 && num % 1000 == 0; ++i )
{ num /= 1000; prefix = si_prefix[i]; }
if( prefix ) *(--p) = prefix;
const bool split = num >= 100000;
for( int i = 0; ; )
{
*(--p) = num % 10 + '0'; num /= 10; if( num == 0 ) break;
if( split && ++i >= 3 ) { i = 0; *(--p) = '_'; }
}
return p;
}
unsigned long long getnum( const char * const arg,
const char * const option_name,
const unsigned long long llimit,
const unsigned long long ulimit )
{
char * tail;
errno = 0;
unsigned long long result = strtoull( ptr, &tail, 0 );
if( tail == ptr )
unsigned long long result = strtoull( arg, &tail, 0 );
if( tail == arg )
{
show_error( "Bad or missing numerical argument.", 0, true );
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Bad or missing numerical argument in "
"option '%s'.\n", program_name, option_name );
std::exit( 1 );
}
@ -208,7 +269,9 @@ unsigned long long getnum( const char * const ptr,
}
if( exponent <= 0 )
{
show_error( "Bad multiplier in numerical argument.", 0, true );
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Bad multiplier in numerical argument of "
"option '%s'.\n", program_name, option_name );
std::exit( 1 );
}
for( int i = 0; i < exponent; ++i )
@ -220,7 +283,10 @@ unsigned long long getnum( const char * const ptr,
if( !errno && ( result < llimit || result > ulimit ) ) errno = ERANGE;
if( errno )
{
show_error( "Numerical argument out of limits." );
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Numerical argument out of limits [%s,%s] "
"in option '%s'.\n", program_name, format_num3( llimit ),
format_num3( ulimit ), option_name );
std::exit( 1 );
}
return result;
@ -249,10 +315,10 @@ void set_mode( Program_mode & program_mode, const Program_mode new_mode )
}
void set_mtime( long long & mtime, const char * arg )
void set_mtime( long long & mtime, const char * arg, const char * const pn )
{
if( *arg == '@' )
{ mtime = getnum( arg + 1, 0, ( 1ULL << 33 ) - 1 ); return; }
{ mtime = getnum( arg + 1, pn, 0, ( 1ULL << 33 ) - 1 ); return; }
else if( *arg == '.' || *arg == '/' )
{
struct stat st;
@ -276,22 +342,22 @@ void set_mtime( long long & mtime, const char * arg )
}
void set_owner( int & owner, const char * const arg )
void set_owner( int & owner, const char * const arg, const char * const pn )
{
const struct passwd * const pw = getpwnam( arg );
if( pw ) owner = pw->pw_uid;
else if( std::isdigit( (unsigned char)arg[0] ) )
owner = getnum( arg, 0, INT_MAX );
owner = getnum( arg, pn, 0, INT_MAX );
else if( std::strcmp( arg, "root" ) == 0 ) owner = 0;
else { show_file_error( arg, "Invalid owner" ); std::exit( 1 ); }
}
void set_group( int & group, const char * const arg )
void set_group( int & group, const char * const arg, const char * const pn )
{
const struct group * const gr = getgrnam( arg );
if( gr ) group = gr->gr_gid;
else if( std::isdigit( (unsigned char)arg[0] ) )
group = getnum( arg, 0, INT_MAX );
group = getnum( arg, pn, 0, INT_MAX );
else if( std::strcmp( arg, "root" ) == 0 ) group = 0;
else { show_file_error( arg, "Invalid group" ); std::exit( 1 ); }
}
@ -308,7 +374,12 @@ int open_instream( const std::string & name )
{
const int infd = open( name.c_str(), O_RDONLY | O_BINARY );
if( infd < 0 )
show_file_error( name.c_str(), "Can't open for reading", errno );
{ show_file_error( name.c_str(), "Can't open for reading", errno );
return -1; }
struct stat st; // infd must not be a directory
if( fstat( infd, &st ) == 0 && S_ISDIR( st.st_mode ) )
{ show_file_error( name.c_str(), "Is a directory." );
close( infd ); return -1; }
return infd;
}
@ -460,6 +531,9 @@ int main( const int argc, const char * const argv[] )
if( max_workers < 1 || max_workers > INT_MAX / (int)sizeof (pthread_t) )
max_workers = INT_MAX / sizeof (pthread_t);
const char * f_pn = 0;
const char * o_pn = 0;
const char * z_pn = 0;
for( int argind = 0; argind < parser.arguments(); ++argind )
{
const int code = parser.code( argind );
@ -470,6 +544,7 @@ int main( const int argc, const char * const argv[] )
if( parser.argument( argind ) != "-" ) cl_opts.filenames_given = true;
++cl_opts.num_files; continue;
}
const char * const pn = parser.parsed_name( argind ).c_str();
const std::string & sarg = parser.argument( argind );
const char * const arg = sarg.c_str();
switch( code )
@ -478,16 +553,16 @@ int main( const int argc, const char * const argv[] )
case '5': case '6': case '7': case '8': case '9':
cl_opts.level = code - '0'; break;
case 'A': set_mode( cl_opts.program_mode, m_concatenate ); break;
case 'B': cl_opts.data_size = getnum( arg, min_data_size, max_data_size );
break;
case 'B': cl_opts.data_size =
getnum( arg, pn, min_data_size, max_data_size ); break;
case 'c': set_mode( cl_opts.program_mode, m_create ); break;
case 'C': break; // skip chdir
case 'd': set_mode( cl_opts.program_mode, m_diff ); break;
case 'f': set_archive_name( cl_opts.archive_name, sarg ); break;
case 'f': set_archive_name( cl_opts.archive_name, sarg ); f_pn = pn; break;
case 'h': cl_opts.dereference = true; break;
case 'H': break; // ignore format
case 'n': cl_opts.num_workers = getnum( arg, 0, max_workers ); break;
case 'o': cl_opts.output_filename = sarg; break;
case 'n': cl_opts.num_workers = getnum( arg, pn, 0, max_workers ); break;
case 'o': cl_opts.output_filename = sarg; o_pn = pn; break;
case 'p': cl_opts.preserve_permissions = true; break;
case 'q': verbosity = -1; break;
case 'r': set_mode( cl_opts.program_mode, m_append ); break;
@ -495,25 +570,25 @@ int main( const int argc, const char * const argv[] )
case 'v': if( verbosity < 4 ) ++verbosity; break;
case 'V': show_version(); return 0;
case 'x': set_mode( cl_opts.program_mode, m_extract ); break;
case 'z': set_mode( cl_opts.program_mode, m_compress ); break;
case opt_ano: set_owner( cl_opts.owner, "root" );
set_group( cl_opts.group, "root" ); break;
case 'z': set_mode( cl_opts.program_mode, m_compress ); z_pn = pn; break;
case opt_ano: set_owner( cl_opts.owner, "root", pn );
set_group( cl_opts.group, "root", pn ); break;
case opt_aso: cl_opts.solidity = asolid; break;
case opt_bso: cl_opts.solidity = bsolid; break;
case opt_crc: cl_opts.missing_crc = true; break;
case opt_chk: return check_lib();
case opt_dbg: cl_opts.debug_level = getnum( arg, 0, 3 ); break;
case opt_dbg: cl_opts.debug_level = getnum( arg, pn, 0, 3 ); break;
case opt_del: set_mode( cl_opts.program_mode, m_delete ); break;
case opt_dso: cl_opts.solidity = dsolid; break;
case opt_exc: Exclude::add_pattern( sarg ); break;
case opt_grp: set_group( cl_opts.group, arg ); break;
case opt_grp: set_group( cl_opts.group, arg, pn ); break;
case opt_hlp: show_help( num_online ); return 0;
case opt_id: cl_opts.ignore_ids = true; break;
case opt_kd: cl_opts.keep_damaged = true; break;
case opt_mti: set_mtime( cl_opts.mtime, arg ); break;
case opt_mti: set_mtime( cl_opts.mtime, arg, pn ); break;
case opt_nso: cl_opts.solidity = no_solid; break;
case opt_out: cl_opts.out_slots = getnum( arg, 1, 1024 ); break;
case opt_own: set_owner( cl_opts.owner, arg ); break;
case opt_out: cl_opts.out_slots = getnum( arg, pn, 1, 1024 ); break;
case opt_own: set_owner( cl_opts.owner, arg, pn ); break;
case opt_per: cl_opts.permissive = true; break;
case opt_sol: cl_opts.solidity = solid; break;
case opt_un: cl_opts.level = -1; break;
@ -522,6 +597,21 @@ int main( const int argc, const char * const argv[] )
}
} // end process options
if( cl_opts.program_mode != m_compress && cl_opts.output_filename.size() )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Option '%s' can only be used with "
"'-z, --compress'.\n", program_name, o_pn );
return 1;
}
if( cl_opts.program_mode == m_compress && f_pn )
{
if( verbosity >= 0 )
std::fprintf( stderr, "%s: Option '%s' can't be used with '%s'.\n",
program_name, f_pn, z_pn );
return 1;
}
#if !defined LZ_API_VERSION || LZ_API_VERSION < 1012 // compile-time test
#error "lzlib 1.12 or newer needed."
#endif