summaryrefslogtreecommitdiffstats
path: root/tarlz.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--tarlz.h136
1 files changed, 108 insertions, 28 deletions
diff --git a/tarlz.h b/tarlz.h
index 19c913a..2da81dd 100644
--- a/tarlz.h
+++ b/tarlz.h
@@ -57,7 +57,7 @@ inline void init_tar_header( Tar_header header ) // set magic and version
}
inline void print_octal( uint8_t * const buf, int size, unsigned long long num )
- { while( --size >= 0 ) { buf[size] = '0' + ( num % 8 ); num /= 8; } }
+ { while( --size >= 0 ) { buf[size] = num % 8 + '0'; num /= 8; } }
// Round "size" to the next multiple of header size (512).
@@ -70,6 +70,14 @@ inline unsigned long long round_up( const unsigned long long size )
}
+inline int decimal_digits( unsigned long long value )
+ {
+ int digits = 1;
+ while( value >= 10 ) { value /= 10; ++digits; }
+ return digits;
+ }
+
+
inline bool dotdot_at_i( const char * const filename, const int i )
{
return ( filename[i] == '.' && filename[i+1] == '.' &&
@@ -119,12 +127,45 @@ public:
};
-class Extended // stores metadata from/for extended records
+inline bool uid_in_ustar_range( const long long uid ) // also for gid
+ { return uid >= 0 && uid < 1 << 21; }
+
+inline bool time_in_ustar_range( const long long seconds )
+ { return seconds >= 0 && seconds < 1LL << 33; }
+
+
+/* The sign of the seconds field applies to the whole time value.
+ A nanoseconds value out of range means an invalid time. */
+class Etime // time since (or before) the epoch
+ {
+ long long sec_;
+ int nsec_; // range [0, 999_999_999]
+
+public:
+ Etime() : sec_( 0 ), nsec_( -1 ) {}
+ void reset() { sec_ = 0; nsec_ = -1; }
+ void set( const long long s ) { sec_ = s; nsec_ = 0; }
+ long long sec() const { return sec_; }
+ int nsec() const { return nsec_; }
+ bool isvalid() const { return nsec_ >= 0 && nsec_ <= 999999999; }
+ bool out_of_ustar_range() const
+ { return isvalid() && !time_in_ustar_range( sec_ ); }
+
+ unsigned decimal_size() const;
+ unsigned print( char * const buf ) const;
+ bool parse( const char * const ptr, const char ** const tailp,
+ const long long size );
+ };
+
+
+class Extended // stores metadata from/for extended records
{
static std::vector< std::string > unknown_keywords; // already diagnosed
std::string linkpath_; // these are the real metadata
std::string path_;
long long file_size_; // >= 0 && <= max_file_size
+ long long uid_, gid_; // may not fit in unsigned int
+ Etime atime_, mtime_;
// cached sizes; if full_size_ < 0 they must be recalculated
mutable long long edsize_; // extended data size
@@ -133,6 +174,10 @@ class Extended // stores metadata from/for extended records
mutable long long linkpath_recsize_;
mutable long long path_recsize_;
mutable int file_size_recsize_;
+ mutable int uid_recsize_;
+ mutable int gid_recsize_;
+ mutable int atime_recsize_;
+ mutable int mtime_recsize_;
// true if CRC present in parsed or formatted records
mutable bool crc_present_;
@@ -143,29 +188,47 @@ class Extended // stores metadata from/for extended records
public:
static const std::string crc_record;
+ std::string removed_prefix;
Extended()
- : file_size_( 0 ), edsize_( 0 ), padded_edsize_( 0 ), full_size_( 0 ),
- linkpath_recsize_( 0 ), path_recsize_( 0 ), file_size_recsize_( 0 ),
+ : file_size_( 0 ), uid_( -1 ), gid_( -1 ), edsize_( 0 ),
+ padded_edsize_( 0 ), full_size_( 0 ), linkpath_recsize_( 0 ),
+ path_recsize_( 0 ), file_size_recsize_( 0 ), uid_recsize_( 0 ),
+ gid_recsize_( 0 ), atime_recsize_( 0 ), mtime_recsize_( 0 ),
crc_present_( false ) {}
void reset()
- { linkpath_.clear(); path_.clear(); file_size_ = 0; edsize_ = 0;
- padded_edsize_ = 0; full_size_ = 0; linkpath_recsize_ = 0;
- path_recsize_ = 0; file_size_recsize_ = 0; crc_present_ = false; }
+ { linkpath_.clear(); path_.clear(); file_size_ = 0; uid_ = -1; gid_ = -1;
+ atime_.reset(); mtime_.reset(); edsize_ = 0; padded_edsize_ = 0;
+ full_size_ = 0; linkpath_recsize_ = 0; path_recsize_ = 0;
+ file_size_recsize_ = 0; uid_recsize_ = 0; gid_recsize_ = 0;
+ atime_recsize_ = 0; mtime_recsize_ = 0; crc_present_ = false;
+ removed_prefix.clear(); }
bool empty() const
- { return linkpath_.empty() && path_.empty() && file_size_ == 0; }
+ { return linkpath_.empty() && path_.empty() && file_size_ == 0 &&
+ uid_ < 0 && gid_ < 0 &&
+ !atime_.out_of_ustar_range() && !mtime_.out_of_ustar_range(); }
const std::string & linkpath() const { return linkpath_; }
const std::string & path() const { return path_; }
long long file_size() const { return file_size_; }
long long get_file_size_and_reset( const Tar_header header );
+ long long get_uid() const { return uid_; }
+ long long get_gid() const { return gid_; }
+ const Etime & atime() const { return atime_; }
+ const Etime & mtime() const { return mtime_; }
void linkpath( const char * const lp ) { linkpath_ = lp; full_size_ = -1; }
void path( const char * const p ) { path_ = p; full_size_ = -1; }
void file_size( const long long fs ) { full_size_ = -1;
file_size_ = ( fs >= 0 && fs <= max_file_size ) ? fs : 0; }
+ bool set_uid( const long long id )
+ { if( id >= 0 ) { uid_ = id; full_size_ = -1; } return id >= 0; }
+ bool set_gid( const long long id )
+ { if( id >= 0 ) { gid_ = id; full_size_ = -1; } return id >= 0; }
+ void set_atime( const long long s ) { atime_.set( s ); full_size_ = -1; }
+ void set_mtime( const long long s ) { mtime_.set( s ); full_size_ = -1; }
long long full_size() const
{ if( full_size_ < 0 ) calculate_sizes(); return full_size_; }
@@ -269,10 +332,10 @@ const uint8_t lzip_magic[4] = { 0x4C, 0x5A, 0x49, 0x50 }; // "LZIP"
struct Lzip_header
{
- uint8_t data[6]; // 0-3 magic bytes
+ enum { size = 6 };
+ uint8_t data[size]; // 0-3 magic bytes
// 4 version
// 5 coded dictionary size
- enum { size = 6 };
bool verify_magic() const
{ return ( std::memcmp( data, lzip_magic, 4 ) == 0 ); }
@@ -283,6 +346,7 @@ struct Lzip_header
if( data[i] != lzip_magic[i] ) return false;
return ( sz > 0 );
}
+
bool verify_corrupt() const // detect corrupt header
{
int matches = 0;
@@ -310,10 +374,10 @@ struct Lzip_header
struct Lzip_trailer
{
- uint8_t data[20]; // 0-3 CRC32 of the uncompressed data
+ enum { size = 20 };
+ uint8_t data[size]; // 0-3 CRC32 of the uncompressed data
// 4-11 size of the uncompressed data
// 12-19 member size including header and trailer
- enum { size = 20 };
unsigned data_crc() const
{
@@ -356,12 +420,15 @@ enum Program_mode { m_none, m_append, m_compress, m_concatenate, m_create,
m_delete, m_diff, m_extract, m_list };
enum Solidity { no_solid, bsolid, dsolid, asolid, solid };
class Arg_parser;
+
struct Cl_options // command line options
{
const Arg_parser & parser;
std::string archive_name;
std::string output_filename;
long long mtime;
+ long long uid;
+ long long gid;
Program_mode program_mode;
Solidity solidity;
int data_size;
@@ -370,29 +437,28 @@ struct Cl_options // command line options
int num_files;
int num_workers; // start this many worker threads
int out_slots;
- int owner;
- int group;
bool dereference;
bool filenames_given;
bool ignore_ids;
+ bool ignore_overflow;
bool keep_damaged;
bool missing_crc;
+ bool mtime_set;
bool permissive;
bool preserve_permissions;
bool warn_newer;
Cl_options( const Arg_parser & ap )
- : parser( ap ), mtime( -1 ), program_mode( m_none ), solidity( bsolid ),
- data_size( 0 ), debug_level( 0 ), level( 6 ), num_files( 0 ),
- num_workers( -1 ), out_slots( 64 ), owner( -1 ), group( -1 ),
- dereference( false ), filenames_given( false ), ignore_ids( false ),
- keep_damaged( false ), missing_crc( false ), permissive( false ),
- preserve_permissions( false ), warn_newer( false ) {}
+ : parser( ap ), mtime( 0 ), uid( -1 ), gid( -1 ), program_mode( m_none ),
+ solidity( bsolid ), data_size( 0 ), debug_level( 0 ), level( 6 ),
+ num_files( 0 ), num_workers( -1 ), out_slots( 64 ), dereference( false ),
+ filenames_given( false ), ignore_ids( false ), ignore_overflow( false ),
+ keep_damaged( false ), missing_crc( false ), mtime_set( false ),
+ permissive( false ), preserve_permissions( false ), warn_newer( false ) {}
bool to_stdout() const { return output_filename == "-"; }
};
-
inline void set_retval( int & retval, const int new_val )
{ if( retval < new_val ) retval = new_val; }
@@ -403,15 +469,23 @@ const char * const trailing_msg = "Trailing data not allowed.";
const char * const bad_hdr_msg = "Corrupt or invalid tar header.";
const char * const gblrec_msg = "Error in global extended records.";
const char * const extrec_msg = "Error in extended records.";
-const char * const mcrc_msg = "Missing CRC in extended records.";
+const char * const miscrc_msg = "Missing CRC in extended records.";
+const char * const misrec_msg = "Missing extended records.";
+const char * const longrec_msg = "Extended records are too long.";
const char * const end_msg = "Archive ends unexpectedly.";
const char * const mem_msg = "Not enough memory.";
const char * const mem_msg2 = "Not enough memory. Try a lower compression level.";
-const char * const fv_msg1 = "Format violation: extended header followed by EOF blocks.";
+const char * const fv_msg1 = "Format violation: extended header followed by EOA blocks.";
const char * const fv_msg2 = "Format violation: extended header followed by global header.";
const char * const fv_msg3 = "Format violation: consecutive extended headers found.";
const char * const posix_msg = "This does not look like a POSIX tar archive.";
const char * const posix_lz_msg = "This does not look like a POSIX tar.lz archive.";
+const char * const eclosa_msg = "Error closing archive";
+const char * const eclosf_msg = "Error closing file";
+const char * const nfound_msg = "Not found in archive.";
+const char * const seek_msg = "Seek error";
+const char * const werr_msg = "Write error";
+const char * const chdir_msg = "Error changing working directory";
// defined in common.cc
void xinit_mutex( pthread_mutex_t * const mutex );
@@ -441,15 +515,17 @@ mode_t get_umask();
bool make_path( const std::string & name );
// defined in compress.cc
-int compress( Cl_options & cl_opts );
+int compress( const Cl_options & cl_opts );
// defined in create.cc
bool copy_file( const int infd, const int outfd, const long long max_size = -1 );
bool writeblock_wrapper( const int outfd, const uint8_t * const buffer,
const int size );
-bool write_eof_records( const int outfd, const bool compressed );
+bool write_eoa_records( const int outfd, const bool compressed );
const char * remove_leading_dotslash( const char * const filename,
- const bool dotdot = false );
+ std::string * const removed_prefixp, const bool dotdot = false );
+bool print_removed_prefix( const std::string & prefix,
+ std::string * const msgp = 0 );
bool fill_headers( const char * const filename, Extended & extended,
Tar_header header, long long & file_size, const int flag );
bool block_is_full( const long long extended_size,
@@ -462,11 +538,10 @@ unsigned ustar_chksum( const Tar_header header );
bool verify_ustar_chksum( const Tar_header header );
bool has_lz_ext( const std::string & name );
int concatenate( const Cl_options & cl_opts );
-int encode( Cl_options & cl_opts );
+int encode( const Cl_options & cl_opts );
// defined in create_lz.cc
int encode_lz( const Cl_options & cl_opts, const char * const archive_namep,
- const int dictionary_size, const int match_len_limit,
const int outfd );
// defined in decode.cc
@@ -522,8 +597,13 @@ int open_outstream( const std::string & name, const bool create = true,
void exit_fail_mt( const int retval = 1 ); // terminate the program
void show_error( const char * const msg, const int errcode = 0,
const bool help = false );
+bool format_error( Resizable_buffer & rbuf, const int errcode,
+ const char * const format, ... );
+void print_error( const int errcode, const char * const format, ... );
void format_file_error( std::string & estr, const char * const filename,
const char * const msg, const int errcode = 0 );
+bool format_file_error( Resizable_buffer & rbuf, const char * const filename,
+ const char * const msg, const int errcode = 0 );
void show_file_error( const char * const filename, const char * const msg,
const int errcode = 0 );
void internal_error( const char * const msg );