1
0
Fork 0

Merging upstream version 0.15.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-17 21:13:41 +01:00
parent edd0dce1fe
commit b3a2ab2af7
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
51 changed files with 1255 additions and 507 deletions

130
create.cc
View file

@ -92,37 +92,6 @@ bool option_C_after_relative_filename( const Arg_parser & parser )
}
// infd and outfd can refer to the same file if copying to a lower file
// position or if source and destination blocks don't overlap.
// max_size < 0 means no size limit.
bool copy_file( const int infd, const int outfd, const long long max_size = -1 )
{
const int buffer_size = 65536;
// remaining number of bytes to copy
long long rest = ( ( max_size >= 0 ) ? max_size : buffer_size );
long long copied_size = 0;
uint8_t * const buffer = new uint8_t[buffer_size];
bool error = false;
while( rest > 0 )
{
const int size = std::min( (long long)buffer_size, rest );
if( max_size >= 0 ) rest -= size;
const int rd = readblock( infd, buffer, size );
if( rd != size && errno )
{ show_error( "Error reading input file", errno ); error = true; break; }
if( rd > 0 )
{
if( !writeblock_wrapper( outfd, buffer, rd ) ) { error = true; break; }
copied_size += rd;
}
if( rd < size ) break; // EOF
}
delete[] buffer;
return ( !error && ( max_size < 0 || copied_size == max_size ) );
}
/* Check archive type. Return position of EOF blocks or -1 if failure.
If remove_eof, leave fd file pos at beginning of the EOF blocks.
Else, leave fd file pos at 0. */
@ -185,12 +154,12 @@ long long check_uncompressed_appendable( const int fd, const bool remove_eof )
struct stat st; // fd must be regular
if( fstat( fd, &st ) != 0 || !S_ISREG( st.st_mode ) ) return -1;
if( lseek( fd, 0, SEEK_SET ) != 0 ) return -1;
if( st.st_size == 0 ) return 0; // append to empty archive
if( st.st_size <= 0 ) return 0; // append to empty archive
long long eof_pos = 0;
Extended extended; // metadata from extended records
Resizable_buffer rbuf; // extended records buffer
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 rd = readblock( fd, header, header_size );
@ -202,12 +171,12 @@ long long check_uncompressed_appendable( const int fd, const bool remove_eof )
if( typeflag == tf_extended || typeflag == tf_global )
{
if( prev_extended ) return -1;
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 >= 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 -1; // overflow or no extended data
if( !rbuf.resize( bufsize ) ) return -1;
if( readblock( fd, (uint8_t *)rbuf(), bufsize ) != (int)bufsize )
if( readblock( fd, (uint8_t *)rbuf(), bufsize ) != bufsize )
return -1;
if( typeflag == tf_extended )
{ if( !extended.parse( rbuf(), edsize, false ) ) return -1;
@ -303,8 +272,8 @@ bool store_name( const char * const filename, Extended & extended,
int add_member( const char * const filename, const struct stat *,
const int flag, struct FTW * )
{
if( Exclude::excluded( filename ) ) return 0; // skip excluded
unsigned long long file_size = 0;
if( Exclude::excluded( filename ) ) return 0; // skip excluded files
long long file_size;
Extended extended; // metadata for extended records
Tar_header header;
if( !fill_headers( filename, extended, header, file_size, flag ) ) return 0;
@ -319,12 +288,12 @@ int add_member( const char * const filename, const struct stat *,
return 1;
if( file_size )
{
enum { bufsize = 32 * header_size };
const long long bufsize = 32 * header_size;
uint8_t buf[bufsize];
unsigned long long rest = file_size;
long long rest = file_size;
while( rest > 0 )
{
int size = std::min( rest, (unsigned long long)bufsize );
int size = std::min( rest, bufsize );
const int rd = readblock( infd, buf, size );
rest -= rd;
if( rd != size )
@ -354,6 +323,37 @@ int add_member( const char * const filename, const struct stat *,
} // end namespace
// infd and outfd can refer to the same file if copying to a lower file
// position or if source and destination blocks don't overlap.
// max_size < 0 means no size limit.
bool copy_file( const int infd, const int outfd, const long long max_size )
{
const long long buffer_size = 65536;
// remaining number of bytes to copy
long long rest = ( ( max_size >= 0 ) ? max_size : buffer_size );
long long copied_size = 0;
uint8_t * const buffer = new uint8_t[buffer_size];
bool error = false;
while( rest > 0 )
{
const int size = std::min( buffer_size, rest );
if( max_size >= 0 ) rest -= size;
const int rd = readblock( infd, buffer, size );
if( rd != size && errno )
{ show_error( "Error reading input file", errno ); error = true; break; }
if( rd > 0 )
{
if( !writeblock_wrapper( outfd, buffer, rd ) ) { error = true; break; }
copied_size += rd;
}
if( rd < size ) break; // EOF
}
delete[] buffer;
return ( !error && ( max_size < 0 || copied_size == max_size ) );
}
bool writeblock_wrapper( const int outfd, const uint8_t * const buffer,
const int size )
{
@ -417,8 +417,7 @@ const char * remove_leading_dotslash( const char * const filename,
bool fill_headers( const char * const filename, Extended & extended,
Tar_header header, unsigned long long & file_size,
const int flag )
Tar_header header, long long & file_size, const int flag )
{
struct stat st;
if( hstat( filename, &st ) != 0 )
@ -447,7 +446,7 @@ bool fill_headers( const char * const filename, Extended & extended,
set_error_status( 1 ); return false; }
print_octal( header + mtime_o, mtime_l - 1, mtime );
Typeflag typeflag;
if( S_ISREG( mode ) ) { typeflag = tf_regular; file_size = st.st_size; }
if( S_ISREG( mode ) ) typeflag = tf_regular;
else if( S_ISDIR( mode ) )
{
typeflag = tf_directory;
@ -508,7 +507,9 @@ bool fill_headers( const char * const filename, Extended & extended,
std::strncpy( (char *)header + gname_o, gr->gr_name, gname_l - 1 );
/* else { show_file_error( filename, "Can't read group name from database", errno );
set_error_status( 1 ); } */ // numerical only
if( file_size >= 1ULL << 33 )
file_size = ( typeflag == tf_regular && st.st_size > 0 &&
st.st_size <= max_file_size ) ? st.st_size : 0;
if( file_size >= 1LL << 33 )
{ extended.file_size( file_size ); force_extended_name = true; }
else print_octal( header + size_o, size_l - 1, file_size );
store_name( filename, extended, header, force_extended_name );
@ -521,7 +522,7 @@ bool block_is_full( const Extended & extended,
const unsigned long long file_size,
unsigned long long & partial_data_size )
{
const unsigned long long member_size =
const unsigned long long member_size = // may overflow 'long long'
header_size + extended.full_size() + round_up( file_size );
const unsigned long long target_size = cl_data_size;
if( partial_data_size >= target_size ||
@ -574,18 +575,18 @@ bool has_lz_ext( const std::string & name )
}
int concatenate( std::string archive_name, const Arg_parser & parser,
int concatenate( const std::string & archive_name, const Arg_parser & parser,
const int filenames )
{
if( !filenames )
{ if( verbosity >= 1 ) show_error( "Nothing to concatenate." ); return 0; }
const bool to_stdout = archive_name.empty();
archive_namep = to_stdout ? "(stdout)" : archive_name.c_str();
const int outfd =
to_stdout ? STDOUT_FILENO : open_outstream( archive_name, false );
if( outfd < 0 ) return 1;
if( to_stdout ) archive_name = "(stdout)";
else if( !file_is_the_archive.init( outfd ) )
{ show_file_error( archive_name.c_str(), "Can't stat", errno ); return 1; }
if( !to_stdout && !file_is_the_archive.init( outfd ) )
{ show_file_error( archive_namep, "Can't stat", errno ); return 1; }
int compressed; // tri-state bool
if( to_stdout ) compressed = -1; // unknown
else
@ -598,7 +599,7 @@ int concatenate( std::string archive_name, const Arg_parser & parser,
pos = check_uncompressed_appendable( outfd, true );
if( pos > 0 ) compressed = false;
else if( pos < 0 )
{ show_file_error( archive_name.c_str(), compressed ?
{ show_file_error( archive_namep, compressed ?
"This does not look like an appendable tar.lz archive." :
"This does not look like an appendable tar archive." );
return 2; }
@ -612,7 +613,7 @@ int concatenate( std::string archive_name, const Arg_parser & parser,
if( parser.code( i ) ) continue; // skip options
if( parser.argument( i ).empty() ) continue; // skip empty names
const char * const filename = parser.argument( i ).c_str();
if( Exclude::excluded( filename ) ) continue; // skip excluded
if( Exclude::excluded( filename ) ) continue; // skip excluded files
const int infd = open_instream( filename );
if( infd < 0 ) { retval = 1; break; }
struct stat st;
@ -644,7 +645,7 @@ int concatenate( std::string archive_name, const Arg_parser & parser,
if( eof_pending && !write_eof_records( outfd, compressed ) && !retval )
retval = 1;
if( close( outfd ) != 0 && !retval )
{ show_file_error( archive_name.c_str(), "Error closing archive", errno );
{ show_file_error( archive_namep, "Error closing archive", errno );
retval = 1; }
return retval;
}
@ -673,21 +674,23 @@ int encode( const std::string & archive_name, const Arg_parser & parser,
{ 3 << 23, 132 }, // -8
{ 1 << 25, 273 } }; // -9
const bool compressed = ( level >= 0 && level <= 9 );
const bool to_stdout = archive_name.empty();
archive_namep = to_stdout ? "(stdout)" : archive_name.c_str();
if( archive_name.size() && !compressed && has_lz_ext( archive_name ) )
{ show_file_error( archive_name.c_str(),
if( !to_stdout && !compressed && has_lz_ext( archive_name ) )
{ show_file_error( archive_namep,
"Uncompressed mode incompatible with .lz extension." ); return 2; }
if( !filenames )
{
if( !append && archive_name.size() ) // create archive
if( !append && !to_stdout ) // create archive
{ show_error( "Cowardly refusing to create an empty archive.", 0, true );
return 1; }
else // create/append to stdout or append to archive
{ if( verbosity >= 1 ) show_error( "Nothing to append." ); return 0; }
}
if( archive_name.empty() ) // create/append to stdout
if( to_stdout ) // create/append to stdout
goutfd = STDOUT_FILENO;
else if( !append ) // create archive
{ if( ( goutfd = open_outstream( archive_name ) ) < 0 ) return 1; }
@ -695,14 +698,13 @@ int encode( const std::string & archive_name, const Arg_parser & parser,
{
if( ( goutfd = open_outstream( archive_name, false ) ) < 0 ) return 1;
if( compressed && check_appendable( goutfd, true ) < 0 )
{ show_file_error( archive_name.c_str(),
{ show_file_error( archive_namep,
"This does not look like an appendable tar.lz archive." ); return 2; }
if( !compressed && check_uncompressed_appendable( goutfd, true ) < 0 )
{ show_file_error( archive_name.c_str(),
{ show_file_error( archive_namep,
"This does not look like an appendable tar archive." ); return 2; }
}
archive_namep = archive_name.size() ? archive_name.c_str() : "(stdout)";
if( !file_is_the_archive.init( goutfd ) )
{ show_file_error( archive_namep, "Can't stat", errno ); return 1; }
@ -720,7 +722,7 @@ int encode( const std::string & archive_name, const Arg_parser & parser,
!option_C_after_relative_filename( parser ) )
{
// show_file_error( archive_namep, "Multi-threaded --create" );
return encode_lz( parser, dictionary_size,
return encode_lz( archive_namep, parser, dictionary_size,
option_mapping[level].match_len_limit, num_workers,
goutfd, out_slots, debug_level, dereference );
}
@ -752,7 +754,7 @@ int encode( const std::string & archive_name, const Arg_parser & parser,
while( len > 1 && arg[len-1] == '/' ) --len;
if( len < arg.size() )
{ deslashed.assign( arg, 0, len ); filename = deslashed.c_str(); }
if( Exclude::excluded( filename ) ) continue; // skip excluded
if( Exclude::excluded( filename ) ) continue; // skip excluded files
struct stat st;
if( lstat( filename, &st ) != 0 ) // filename from command line
{ show_file_error( filename, "Can't stat input file", errno );
@ -778,7 +780,7 @@ int encode( const std::string & archive_name, const Arg_parser & parser,
if( encoder && LZ_compress_close( encoder ) < 0 )
{ show_error( "LZ_compress_close failed." ); retval = 1; }
if( close( goutfd ) != 0 && !retval )
{ show_file_error( archive_name.c_str(), "Error closing archive", errno );
{ show_file_error( archive_namep, "Error closing archive", errno );
retval = 1; }
return final_exit_status( retval );
}