summaryrefslogtreecommitdiffstats
path: root/extract.cc
diff options
context:
space:
mode:
Diffstat (limited to 'extract.cc')
-rw-r--r--extract.cc203
1 files changed, 3 insertions, 200 deletions
diff --git a/extract.cc b/extract.cc
index bd2b624..a1f019e 100644
--- a/extract.cc
+++ b/extract.cc
@@ -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,