diff options
Diffstat (limited to '')
-rw-r--r-- | create.cc | 142 |
1 files changed, 71 insertions, 71 deletions
@@ -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; |