diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2019-04-13 08:59:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2019-04-13 08:59:10 +0000 |
commit | 29867477a1c50b8cbea6212b8dd649a052778bf0 (patch) | |
tree | 070208b9f3add6d1757dc9281b7c8d113eb2768d /create.cc | |
parent | Adding upstream version 0.14. (diff) | |
download | tarlz-29867477a1c50b8cbea6212b8dd649a052778bf0.tar.xz tarlz-29867477a1c50b8cbea6212b8dd649a052778bf0.zip |
Adding upstream version 0.15.upstream/0.15
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'create.cc')
-rw-r--r-- | create.cc | 130 |
1 files changed, 66 insertions, 64 deletions
@@ -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 ); } |