Adding upstream version 0.15.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
be936e5cc3
commit
5d67ab9e97
51 changed files with 1255 additions and 507 deletions
130
create.cc
130
create.cc
|
@ -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 );
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue