diff options
Diffstat (limited to 'extract.cc')
-rw-r--r-- | extract.cc | 203 |
1 files changed, 3 insertions, 200 deletions
@@ -32,9 +32,7 @@ #include <utime.h> #include <sys/stat.h> #include <sys/types.h> -#if defined(__GNU_LIBRARY__) #include <sys/sysmacros.h> // for major, minor, makedev -#endif #include <lzlib.h> #include "arg_parser.h" @@ -181,131 +179,6 @@ int archive_read( const char * const archive_namep, const int infd, } -enum { mode_string_size = 10, - group_string_size = 1 + uname_l + 1 + gname_l + 1 }; // 67 - -void format_mode_string( const Tar_header header, char buf[mode_string_size] ) - { - const Typeflag typeflag = (Typeflag)header[typeflag_o]; - - std::memcpy( buf, "----------", mode_string_size ); - switch( typeflag ) - { - case tf_regular: break; - case tf_link: buf[0] = 'h'; break; - case tf_symlink: buf[0] = 'l'; break; - case tf_chardev: buf[0] = 'c'; break; - case tf_blockdev: buf[0] = 'b'; break; - case tf_directory: buf[0] = 'd'; break; - case tf_fifo: buf[0] = 'p'; break; - case tf_hiperf: buf[0] = 'C'; break; - default: buf[0] = '?'; - } - const mode_t mode = parse_octal( header + mode_o, mode_l ); // 12 bits - const bool setuid = mode & S_ISUID; - const bool setgid = mode & S_ISGID; - const bool sticky = mode & S_ISVTX; - if( mode & S_IRUSR ) buf[1] = 'r'; - if( mode & S_IWUSR ) buf[2] = 'w'; - if( mode & S_IXUSR ) buf[3] = setuid ? 's' : 'x'; - else if( setuid ) buf[3] = 'S'; - if( mode & S_IRGRP ) buf[4] = 'r'; - if( mode & S_IWGRP ) buf[5] = 'w'; - if( mode & S_IXGRP ) buf[6] = setgid ? 's' : 'x'; - else if( setgid ) buf[6] = 'S'; - if( mode & S_IROTH ) buf[7] = 'r'; - if( mode & S_IWOTH ) buf[8] = 'w'; - if( mode & S_IXOTH ) buf[9] = sticky ? 't' : 'x'; - else if( sticky ) buf[9] = 'T'; - } - - -int format_user_group_string( const Tar_header header, - char buf[group_string_size] ) - { - int len; - if( header[uname_o] && header[gname_o] ) - len = snprintf( buf, group_string_size, - " %.32s/%.32s", header + uname_o, header + gname_o ); - else - { - const unsigned uid = parse_octal( header + uid_o, uid_l ); - const unsigned gid = parse_octal( header + gid_o, gid_l ); - len = snprintf( buf, group_string_size, " %u/%u", uid, gid ); - } - return len; - } - -} // end namespace - -bool block_is_zero( const uint8_t * const buf, const int size ) - { - for( int i = 0; i < size; ++i ) if( buf[i] != 0 ) return false; - return true; - } - - -bool format_member_name( const Extended & extended, const Tar_header header, - Resizable_buffer & rbuf, const bool long_format ) - { - if( long_format ) - { - format_mode_string( header, rbuf() ); - const int group_string_len = - format_user_group_string( header, rbuf() + mode_string_size ); - int offset = mode_string_size + group_string_len; - const time_t mtime = parse_octal( header + mtime_o, mtime_l ); // 33 bits - struct tm tms; - const struct tm * tm = localtime_r( &mtime, &tms ); - if( !tm ) - { time_t z = 0; tm = localtime_r( &z, &tms ); if( !tm ) tm = &tms; } - const Typeflag typeflag = (Typeflag)header[typeflag_o]; - const bool islink = ( typeflag == tf_link || typeflag == tf_symlink ); - const char * const link_string = !islink ? "" : - ( ( typeflag == tf_link ) ? " link to " : " -> " ); - if( typeflag == tf_chardev || typeflag == tf_blockdev ) - offset += snprintf( rbuf() + offset, rbuf.size() - offset, " %5u,%u", - (unsigned)parse_octal( header + devmajor_o, devmajor_l ), - (unsigned)parse_octal( header + devminor_o, devminor_l ) ); - else - offset += snprintf( rbuf() + offset, rbuf.size() - offset, " %9llu", - extended.file_size() ); - for( int i = 0; i < 2; ++i ) - { - const int len = snprintf( rbuf() + offset, rbuf.size() - offset, - " %4d-%02u-%02u %02u:%02u %s%s%s\n", - 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, extended.path().c_str(), - link_string, islink ? extended.linkpath().c_str() : "" ); - if( (int)rbuf.size() > len + offset ) break; - if( !rbuf.resize( len + offset + 1 ) ) return false; - } - } - else - { - if( rbuf.size() < extended.path().size() + 2 && - !rbuf.resize( extended.path().size() + 2 ) ) return false; - snprintf( rbuf(), rbuf.size(), "%s\n", extended.path().c_str() ); - } - return true; - } - - -bool show_member_name( const Extended & extended, const Tar_header header, - const int vlevel, Resizable_buffer & rbuf ) - { - if( verbosity >= vlevel ) - { - if( !format_member_name( extended, header, rbuf, verbosity > vlevel ) ) - { show_error( mem_msg ); return false; } - std::fputs( rbuf(), stdout ); - std::fflush( stdout ); - } - return true; - } - -namespace { - int skip_member( const char * const archive_namep, const int infd, const Extended & extended ) { @@ -498,7 +371,6 @@ int extract_member( const char * const archive_namep, const int infd, case tf_hiperf: outfd = open_outstream( filename ); if( outfd < 0 ) return 2; - chmod( filename, mode ); // ignore errors break; case tf_link: case tf_symlink: @@ -559,6 +431,9 @@ int extract_member( const char * const archive_namep, const int infd, return 2; } + if( typeflag == tf_regular || typeflag == tf_hiperf ) + fchmod( outfd, mode ); // ignore errors + const int bufsize = 32 * header_size; uint8_t buf[bufsize]; long long rest = extended.file_size(); @@ -597,30 +472,6 @@ int extract_member( const char * const archive_namep, const int infd, return 0; } -} // end namespace - - -// return true if dir is a parent directory of name -bool compare_prefix_dir( const char * const dir, const char * const name ) - { - int len = 0; - while( dir[len] && dir[len] == name[len] ) ++len; - return ( !dir[len] && len > 0 && ( dir[len-1] == '/' || name[len] == '/' ) ); - } - - -// compare two file names ignoring trailing slashes -bool compare_tslash( const char * const name1, const char * const name2 ) - { - const char * p = name1; - const char * q = name2; - while( *p && *p == *q ) { ++p; ++q; } - while( *p == '/' ) ++p; - while( *q == '/' ) ++q; - return ( !*p && !*q ); - } - -namespace { bool parse_records( const char * const archive_namep, const int infd, Extended & extended, const Tar_header header, @@ -638,54 +489,6 @@ bool parse_records( const char * const archive_namep, const int infd, } // end namespace -/* Returns the number of bytes really read. - If (returned value < size) and (errno == 0), means EOF was reached. -*/ -int readblock( const int fd, uint8_t * const buf, const int size ) - { - int sz = 0; - errno = 0; - while( sz < size ) - { - const int n = read( fd, buf + sz, size - sz ); - if( n > 0 ) sz += n; - else if( n == 0 ) break; // EOF - else if( errno != EINTR ) break; - errno = 0; - } - return sz; - } - - -/* Returns the number of bytes really written. - If (returned value < size), it is always an error. -*/ -int writeblock( const int fd, const uint8_t * const buf, const int size ) - { - int sz = 0; - errno = 0; - while( sz < size ) - { - const int n = write( fd, buf + sz, size - sz ); - if( n > 0 ) sz += n; - else if( n < 0 && errno != EINTR ) break; - errno = 0; - } - return sz; - } - - -unsigned long long parse_octal( const uint8_t * const ptr, const int size ) - { - unsigned long long result = 0; - int i = 0; - while( i < size && std::isspace( ptr[i] ) ) ++i; - for( ; i < size && ptr[i] >= '0' && ptr[i] <= '7'; ++i ) - { result <<= 3; result += ptr[i] - '0'; } - return result; - } - - int decode( const std::string & archive_name, const Arg_parser & parser, const int filenames, const int num_workers, const int debug_level, const Program_mode program_mode, const bool ignore_ids, |