1
0
Fork 0

Merging upstream version 0.17.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-17 21:15:18 +01:00
parent dc1796cdfc
commit 68f8c54f95
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
29 changed files with 2935 additions and 2272 deletions

142
create.cc
View file

@ -1,18 +1,18 @@
/* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2019 Antonio Diaz Diaz.
/* Tarlz - Archiver with multimember lzip compression
Copyright (C) 2013-2020 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
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
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
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _FILE_OFFSET_BITS 64
@ -30,7 +30,10 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#if !defined __FreeBSD__ && !defined __OpenBSD__ && !defined __NetBSD__ && \
!defined __DragonFly__ && !defined __APPLE__
#include <sys/sysmacros.h> // for major, minor
#endif
#include <ftw.h>
#include <grp.h>
#include <pwd.h>
@ -40,16 +43,10 @@
#include "tarlz.h"
const CRC32 crc32c( true );
int cl_owner = -1; // global vars needed by add_member
int cl_group = -1;
int cl_data_size = 0;
Solidity solidity = bsolid;
namespace {
LZ_Encoder * encoder = 0; // local vars needed by add_member
const Cl_options * gcl_opts = 0; // local vars needed by add_member
LZ_Encoder * encoder = 0;
const char * archive_namep = 0;
unsigned long long partial_data_size = 0; // size of current block
Resizable_buffer grbuf; // extended header + data
@ -82,8 +79,7 @@ public:
bool option_C_after_relative_filename( const Arg_parser & parser )
{
for( int i = 0; i < parser.arguments(); ++i )
if( !parser.code( i ) && parser.argument( i ).size() &&
parser.argument( i )[0] != '/' ) // relative_filename
if( nonempty_arg( parser, i ) && parser.argument( i )[0] != '/' )
while( ++i < parser.arguments() )
if( parser.code( i ) == 'C' ) return true;
return false;
@ -92,7 +88,8 @@ bool option_C_after_relative_filename( const Arg_parser & parser )
/* 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. */
Else, leave fd file pos at 0.
*/
long long check_appendable( const int fd, const bool remove_eof )
{
struct stat st; // fd must be regular
@ -146,7 +143,8 @@ long long check_appendable( const int fd, const bool remove_eof )
/* Skip all tar headers. 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. */
Else, leave fd file pos at 0.
*/
long long check_uncompressed_appendable( const int fd, const bool remove_eof )
{
struct stat st; // fd must be regular
@ -278,7 +276,7 @@ int add_member( const char * const filename, const struct stat *,
const int infd = file_size ? open_instream( filename ) : -1;
if( file_size && infd < 0 ) { set_error_status( 1 ); return 0; }
if( encoder && solidity == bsolid &&
if( encoder && gcl_opts->solidity == bsolid &&
block_is_full( extended, file_size, partial_data_size ) &&
!archive_write( 0, 0 ) ) return 1;
@ -313,7 +311,8 @@ int add_member( const char * const filename, const struct stat *,
if( close( infd ) != 0 )
{ show_file_error( filename, "Error closing file", errno ); return 1; }
}
if( encoder && solidity == no_solid && !archive_write( 0, 0 ) ) return 1;
if( encoder && gcl_opts->solidity == no_solid && !archive_write( 0, 0 ) )
return 1;
if( verbosity >= 1 ) std::fprintf( stderr, "%s\n", filename );
return 0;
}
@ -382,7 +381,8 @@ bool write_eof_records( const int outfd, const bool compressed )
/* Removes any amount of leading "./" and '/' strings from filename.
Optionally also removes prefixes containing a ".." component. */
Optionally also removes prefixes containing a ".." component.
*/
const char * remove_leading_dotslash( const char * const filename,
const bool dotdot )
{
@ -418,7 +418,7 @@ bool fill_headers( const char * const filename, Extended & extended,
Tar_header header, long long & file_size, const int flag )
{
struct stat st;
if( hstat( filename, &st ) != 0 )
if( hstat( filename, &st, gcl_opts->dereference ) != 0 )
{ show_file_error( filename, "Can't stat input file", errno );
set_error_status( 1 ); return false; }
if( file_is_the_archive( st ) )
@ -431,14 +431,15 @@ bool fill_headers( const char * const filename, Extended & extended,
print_octal( header + mode_o, mode_l - 1,
mode & ( S_ISUID | S_ISGID | S_ISVTX |
S_IRWXU | S_IRWXG | S_IRWXO ) );
const uid_t uid = ( cl_owner >= 0 ) ? (uid_t)cl_owner : st.st_uid;
const gid_t gid = ( cl_group >= 0 ) ? (gid_t)cl_group : st.st_gid;
const uid_t uid = (gcl_opts->owner >= 0) ? (uid_t)gcl_opts->owner : st.st_uid;
const gid_t gid = (gcl_opts->group >= 0) ? (gid_t)gcl_opts->group : st.st_gid;
if( uid >= 2 << 20 || gid >= 2 << 20 )
{ show_file_error( filename, "uid or gid is larger than 2_097_151." );
set_error_status( 1 ); return false; }
print_octal( header + uid_o, uid_l - 1, uid );
print_octal( header + gid_o, gid_l - 1, gid );
const unsigned long long mtime = (st.st_mtime >= 0) ? st.st_mtime : 0;
const unsigned long long mtime = ( gcl_opts->mtime >= 0 ) ? gcl_opts->mtime :
( ( st.st_mtime >= 0 ) ? st.st_mtime : 0 );
if( mtime >= 1ULL << 33 )
{ show_file_error( filename, "mtime is out of ustar range [0, 8_589_934_591]." );
set_error_status( 1 ); return false; }
@ -522,7 +523,7 @@ bool block_is_full( const Extended & extended,
{
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;
const unsigned long long target_size = gcl_opts->data_size;
if( partial_data_size >= target_size ||
( partial_data_size >= min_data_size &&
partial_data_size + member_size / 2 > target_size ) )
@ -573,15 +574,14 @@ bool has_lz_ext( const std::string & name )
}
int concatenate( const std::string & archive_name, const Arg_parser & parser,
const int filenames )
int concatenate( const Cl_options & cl_opts )
{
if( !filenames )
if( cl_opts.filenames <= 0 )
{ 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 bool to_stdout = cl_opts.archive_name.empty();
archive_namep = to_stdout ? "(stdout)" : cl_opts.archive_name.c_str();
const int outfd =
to_stdout ? STDOUT_FILENO : open_outstream( archive_name, false );
to_stdout ? STDOUT_FILENO : open_outstream( cl_opts.archive_name, false );
if( outfd < 0 ) return 1;
if( !to_stdout && !file_is_the_archive.init( outfd ) )
{ show_file_error( archive_namep, "Can't stat", errno ); return 1; }
@ -589,7 +589,7 @@ int concatenate( const std::string & archive_name, const Arg_parser & parser,
if( to_stdout ) compressed = -1; // unknown
else
{
compressed = has_lz_ext( archive_name ); // default value
compressed = has_lz_ext( cl_opts.archive_name ); // default value
long long pos = check_appendable( outfd, true );
if( pos > 0 ) compressed = true;
else if( pos < 0 )
@ -606,11 +606,10 @@ int concatenate( const std::string & archive_name, const Arg_parser & parser,
int retval = 0;
bool eof_pending = false;
for( int i = 0; i < parser.arguments(); ++i ) // copy archives
for( int i = 0; i < cl_opts.parser.arguments(); ++i ) // copy archives
{
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( !nonempty_arg( cl_opts.parser, i ) ) continue; // skip opts, empty names
const char * const filename = cl_opts.parser.argument( i ).c_str();
if( Exclude::excluded( filename ) ) continue; // skip excluded files
const int infd = open_instream( filename );
if( infd < 0 ) { retval = 1; break; }
@ -649,10 +648,7 @@ int concatenate( const std::string & archive_name, const Arg_parser & parser,
}
int encode( const std::string & archive_name, const Arg_parser & parser,
const int filenames, const int level, const int num_workers,
const int out_slots, const int debug_level, const bool append,
const bool dereference )
int encode( Cl_options & cl_opts )
{
struct Lzma_options
{
@ -671,15 +667,17 @@ int encode( const std::string & archive_name, const Arg_parser & parser,
{ 1 << 24, 68 }, // -7
{ 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();
const bool compressed = ( cl_opts.level >= 0 && cl_opts.level <= 9 );
const bool to_stdout = cl_opts.archive_name.empty();
archive_namep = to_stdout ? "(stdout)" : cl_opts.archive_name.c_str();
gcl_opts = &cl_opts;
if( !to_stdout && !compressed && has_lz_ext( archive_name ) )
if( !to_stdout && !compressed && has_lz_ext( cl_opts.archive_name ) )
{ show_file_error( archive_namep,
"Uncompressed mode incompatible with .lz extension." ); return 2; }
if( !filenames )
const bool append = cl_opts.program_mode == m_append;
if( cl_opts.filenames <= 0 )
{
if( !append && !to_stdout ) // create archive
{ show_error( "Cowardly refusing to create an empty archive.", 0, true );
@ -691,10 +689,11 @@ int encode( const std::string & archive_name, const Arg_parser & parser,
if( to_stdout ) // create/append to stdout
goutfd = STDOUT_FILENO;
else if( !append ) // create archive
{ if( ( goutfd = open_outstream( archive_name ) ) < 0 ) return 1; }
{ if( ( goutfd = open_outstream( cl_opts.archive_name ) ) < 0 ) return 1; }
else // append to archive
{
if( ( goutfd = open_outstream( archive_name, false ) ) < 0 ) return 1;
if( ( goutfd = open_outstream( cl_opts.archive_name, false ) ) < 0 )
return 1;
if( compressed && check_appendable( goutfd, true ) < 0 )
{ show_file_error( archive_namep,
"This does not look like an appendable tar.lz archive." ); return 2; }
@ -708,24 +707,24 @@ int encode( const std::string & archive_name, const Arg_parser & parser,
if( compressed )
{
const int dictionary_size = option_mapping[level].dictionary_size;
if( cl_data_size <= 0 )
const int dictionary_size = option_mapping[cl_opts.level].dictionary_size;
if( cl_opts.data_size <= 0 )
{
if( level == 0 ) cl_data_size = 1 << 20;
else cl_data_size = 2 * dictionary_size;
if( cl_opts.level == 0 ) cl_opts.data_size = 1 << 20;
else cl_opts.data_size = 2 * dictionary_size;
}
/* CWD is not per-thread; multi-threaded --create can't be used if a
-C option appears after a relative filename in the command line. */
if( solidity != asolid && solidity != solid && num_workers > 0 &&
!option_C_after_relative_filename( parser ) )
if( cl_opts.solidity != asolid && cl_opts.solidity != solid &&
cl_opts.num_workers > 0 &&
!option_C_after_relative_filename( cl_opts.parser ) )
{
// show_file_error( archive_namep, "Multi-threaded --create" );
return encode_lz( archive_namep, parser, dictionary_size,
option_mapping[level].match_len_limit, num_workers,
goutfd, out_slots, debug_level, dereference );
return encode_lz( cl_opts, archive_namep, dictionary_size,
option_mapping[cl_opts.level].match_len_limit, goutfd );
}
encoder = LZ_compress_open( dictionary_size,
option_mapping[level].match_len_limit, LLONG_MAX );
option_mapping[cl_opts.level].match_len_limit, LLONG_MAX );
if( !encoder || LZ_compress_errno( encoder ) != LZ_ok )
{
if( !encoder || LZ_compress_errno( encoder ) == LZ_mem_error )
@ -737,16 +736,16 @@ int encode( const std::string & archive_name, const Arg_parser & parser,
}
int retval = 0;
for( int i = 0; i < parser.arguments(); ++i ) // parse command line
for( int i = 0; i < cl_opts.parser.arguments(); ++i ) // parse command line
{
const int code = parser.code( i );
const std::string & arg = parser.argument( i );
const int code = cl_opts.parser.code( i );
const std::string & arg = cl_opts.parser.argument( i );
const char * filename = arg.c_str();
if( code == 'C' && chdir( filename ) != 0 )
{ show_file_error( filename, "Error changing working directory", errno );
retval = 1; break; }
if( code ) continue; // skip options
if( parser.argument( i ).empty() ) continue; // skip empty names
if( cl_opts.parser.argument( i ).empty() ) continue; // skip empty names
std::string deslashed; // arg without trailing slashes
unsigned len = arg.size();
while( len > 1 && arg[len-1] == '/' ) --len;
@ -758,9 +757,9 @@ int encode( const std::string & archive_name, const Arg_parser & parser,
{ show_file_error( filename, "Can't stat input file", errno );
set_error_status( 1 ); }
else if( ( retval = nftw( filename, add_member, 16,
dereference ? 0 : FTW_PHYS ) ) != 0 )
cl_opts.dereference ? 0 : FTW_PHYS ) ) != 0 )
break; // write error
else if( encoder && solidity == dsolid && !archive_write( 0, 0 ) )
else if( encoder && cl_opts.solidity == dsolid && !archive_write( 0, 0 ) )
{ retval = 1; break; }
}
@ -770,7 +769,8 @@ int encode( const std::string & archive_name, const Arg_parser & parser,
uint8_t buf[bufsize];
std::memset( buf, 0, bufsize );
if( encoder &&
( solidity == asolid || ( solidity == bsolid && partial_data_size ) ) &&
( cl_opts.solidity == asolid ||
( cl_opts.solidity == bsolid && partial_data_size ) ) &&
!archive_write( 0, 0 ) ) retval = 1; // flush encoder
else if( !archive_write( buf, bufsize ) ||
( encoder && !archive_write( 0, 0 ) ) ) retval = 1;