summaryrefslogtreecommitdiffstats
path: root/create.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--create.cc142
1 files changed, 71 insertions, 71 deletions
diff --git a/create.cc b/create.cc
index 93cd9fc..94654ed 100644
--- a/create.cc
+++ b/create.cc
@@ -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;