diff options
Diffstat (limited to '')
-rw-r--r-- | tarlz.h | 136 |
1 files changed, 108 insertions, 28 deletions
@@ -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 ); |