summaryrefslogtreecommitdiffstats
path: root/create.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2019-04-13 08:59:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2019-04-13 08:59:14 +0000
commitbab86e3bc6fcc2b148d2a58247e27c765b2b1471 (patch)
treea21a640ddd20d20c6d01cfe1f13b5494722fcb1c /create.cc
parentReleasing debian version 0.14-1. (diff)
downloadtarlz-bab86e3bc6fcc2b148d2a58247e27c765b2b1471.tar.xz
tarlz-bab86e3bc6fcc2b148d2a58247e27c765b2b1471.zip
Merging upstream version 0.15.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'create.cc')
-rw-r--r--create.cc130
1 files changed, 66 insertions, 64 deletions
diff --git a/create.cc b/create.cc
index f70b99f..b8fc336 100644
--- a/create.cc
+++ b/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 );
}