1
0
Fork 0

Merging upstream version 0.21.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-17 21:16:04 +01:00
parent 337c761a4d
commit 0703aa798f
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
27 changed files with 961 additions and 324 deletions

View file

@ -19,14 +19,10 @@
#include <algorithm>
#include <cerrno>
#include <climits>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <pthread.h>
#include <stdint.h>
#include <stdint.h> // for lzlib.h
#include <unistd.h>
#include <sys/stat.h>
#if !defined __FreeBSD__ && !defined __OpenBSD__ && !defined __NetBSD__ && \
@ -38,8 +34,12 @@
#include <pwd.h>
#include <lzlib.h>
#include "arg_parser.h"
#include "tarlz.h"
#include "arg_parser.h"
#include "create.h"
Archive_attrs archive_attrs; // archive attributes at time of creation
namespace {
@ -52,28 +52,6 @@ Resizable_buffer grbuf; // extended header + data
int goutfd = -1;
int error_status = 0;
class File_is_the_archive
{
dev_t archive_dev;
ino_t archive_ino;
bool initialized;
public:
File_is_the_archive() : initialized( false ) {}
bool init( const int fd )
{
struct stat st;
if( fstat( fd, &st ) != 0 ) return false;
if( S_ISREG( st.st_mode ) )
{ archive_dev = st.st_dev; archive_ino = st.st_ino; initialized = true; }
return true;
}
bool operator()( const struct stat & st ) const
{
return initialized && archive_dev == st.st_dev && archive_ino == st.st_ino;
}
} file_is_the_archive;
bool option_C_after_relative_filename( const Arg_parser & parser )
{
@ -171,7 +149,7 @@ long long check_uncompressed_appendable( const int fd, const bool remove_eof )
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 ) != bufsize )
if( readblock( fd, rbuf.u8(), bufsize ) != bufsize )
return -1;
if( typeflag == tf_extended )
{ if( !extended.parse( rbuf(), edsize, false ) ) return -1;
@ -229,7 +207,7 @@ bool write_extended( const Extended & extended )
for( long long pos = 0; pos < ebsize; ) // write extended block to archive
{
int size = std::min( ebsize - pos, 1LL << 20 );
if( !archive_write( (const uint8_t *)grbuf() + pos, size ) ) return false;
if( !archive_write( grbuf.u8() + pos, size ) ) return false;
pos += size;
}
return true;
@ -276,8 +254,8 @@ int add_member( const char * const filename, const struct stat *,
if( file_size && infd < 0 ) { set_error_status( 1 ); return 0; }
if( encoder && gcl_opts->solidity == bsolid &&
block_is_full( extended, file_size, partial_data_size ) &&
!archive_write( 0, 0 ) ) return 1;
block_is_full( extended.full_size(), file_size, gcl_opts->data_size,
partial_data_size ) && !archive_write( 0, 0 ) ) return 1;
if( !write_extended( extended ) || !archive_write( header, header_size ) )
return 1;
@ -312,6 +290,9 @@ int add_member( const char * const filename, const struct stat *,
}
if( encoder && gcl_opts->solidity == no_solid && !archive_write( 0, 0 ) )
return 1;
if( gcl_opts->warn_newer && archive_attrs.is_newer( filename ) )
{ show_file_error( filename, "File is newer than the archive." );
set_error_status( 1 ); }
if( verbosity >= 1 ) std::fprintf( stderr, "%s\n", filename );
return 0;
}
@ -420,7 +401,7 @@ bool fill_headers( const char * const filename, Extended & extended,
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 ) )
if( archive_attrs.is_the_archive( st ) )
{ show_file_error( archive_namep, "File is the archive; not dumped." );
return false; }
init_tar_header( header );
@ -516,13 +497,13 @@ bool fill_headers( const char * const filename, Extended & extended,
}
bool block_is_full( const Extended & extended,
bool block_is_full( const long long extended_size,
const unsigned long long file_size,
const unsigned long long target_size,
unsigned long long & partial_data_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 = gcl_opts->data_size;
header_size + extended_size + round_up( file_size );
if( partial_data_size >= target_size ||
( partial_data_size >= min_data_size &&
partial_data_size + member_size / 2 > target_size ) )
@ -550,7 +531,7 @@ int final_exit_status( int retval, const bool show_msg )
return retval;
}
unsigned ustar_chksum( const uint8_t * const header )
unsigned ustar_chksum( const Tar_header header )
{
unsigned chksum = chksum_l * 0x20; // treat chksum field as spaces
for( int i = 0; i < chksum_o; ++i ) chksum += header[i];
@ -559,7 +540,7 @@ unsigned ustar_chksum( const uint8_t * const header )
}
bool verify_ustar_chksum( const uint8_t * const header )
bool verify_ustar_chksum( const Tar_header header )
{ return ( verify_ustar_magic( header ) &&
ustar_chksum( header ) == parse_octal( header + chksum_o, chksum_l ) ); }
@ -575,14 +556,14 @@ bool has_lz_ext( const std::string & name )
int concatenate( const Cl_options & cl_opts )
{
if( cl_opts.filenames <= 0 )
if( cl_opts.num_files <= 0 )
{ if( verbosity >= 1 ) show_error( "Nothing to concatenate." ); return 0; }
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( cl_opts.archive_name, false );
if( outfd < 0 ) return 1;
if( !to_stdout && !file_is_the_archive.init( outfd ) )
if( !to_stdout && !archive_attrs.init( outfd ) )
{ show_file_error( archive_namep, "Can't stat", errno ); return 1; }
int compressed; // tri-state bool
if( to_stdout ) compressed = -1; // unknown
@ -613,7 +594,7 @@ int concatenate( const Cl_options & cl_opts )
const int infd = open_instream( filename );
if( infd < 0 ) { retval = 1; break; }
struct stat st;
if( !to_stdout && fstat( infd, &st ) == 0 && file_is_the_archive( st ) )
if( !to_stdout && fstat( infd, &st ) == 0 && archive_attrs.is_the_archive( st ) )
{ show_file_error( filename, "File is the archive; not concatenated." );
close( infd ); continue; }
long long size;
@ -649,23 +630,6 @@ int concatenate( const Cl_options & cl_opts )
int encode( Cl_options & cl_opts )
{
struct Lzma_options
{
int dictionary_size; // 4 KiB .. 512 MiB
int match_len_limit; // 5 .. 273
};
const Lzma_options option_mapping[] =
{
{ 65535, 16 }, // -0
{ 1 << 20, 5 }, // -1
{ 3 << 19, 6 }, // -2
{ 1 << 21, 8 }, // -3
{ 3 << 20, 12 }, // -4
{ 1 << 22, 20 }, // -5
{ 1 << 23, 36 }, // -6
{ 1 << 24, 68 }, // -7
{ 3 << 23, 132 }, // -8
{ 1 << 25, 273 } }; // -9
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();
@ -676,7 +640,7 @@ int encode( Cl_options & cl_opts )
"Uncompressed mode incompatible with .lz extension." ); return 2; }
const bool append = cl_opts.program_mode == m_append;
if( cl_opts.filenames <= 0 )
if( cl_opts.num_files <= 0 )
{
if( !append && !to_stdout ) // create archive
{ show_error( "Cowardly refusing to create an empty archive.", 0, true );
@ -701,7 +665,7 @@ int encode( Cl_options & cl_opts )
"This does not look like an appendable tar archive." ); return 2; }
}
if( !file_is_the_archive.init( goutfd ) )
if( !archive_attrs.init( goutfd ) )
{ show_file_error( archive_namep, "Can't stat", errno ); return 1; }
if( compressed )