summaryrefslogtreecommitdiffstats
path: root/common_decode.cc
diff options
context:
space:
mode:
Diffstat (limited to 'common_decode.cc')
-rw-r--r--common_decode.cc67
1 files changed, 38 insertions, 29 deletions
diff --git a/common_decode.cc b/common_decode.cc
index a030428..835687f 100644
--- a/common_decode.cc
+++ b/common_decode.cc
@@ -68,7 +68,8 @@ void format_mode_string( const Tar_header header, char buf[mode_string_size] )
}
-int format_user_group_string( const Tar_header header,
+int format_user_group_string( const Extended & extended,
+ const Tar_header header,
char buf[group_string_size] )
{
int len;
@@ -76,11 +77,8 @@ int format_user_group_string( const Tar_header header,
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 );
- }
+ len = snprintf( buf, group_string_size, " %llu/%llu",
+ extended.get_uid(), extended.get_gid() );
return len;
}
@@ -122,32 +120,41 @@ bool format_member_name( const Extended & extended, const Tar_header header,
{
format_mode_string( header, rbuf() );
const int group_string_len =
- format_user_group_string( header, rbuf() + mode_string_size );
+ format_user_group_string( extended, 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 time_t mtime = extended.mtime().sec();
+ struct tm t;
+ if( !localtime_r( &mtime, &t ) ) // if local time fails
+ { time_t z = 0; if( !gmtime_r( &z, &t ) ) // use the UTC epoch
+ { t.tm_year = 70; t.tm_mon = t.tm_hour = t.tm_min = 0; t.tm_mday = 1; } }
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 " : " -> " );
+ // print "user/group size" in a field of width 19 with 8 or more for size
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 ) );
+ {
+ const unsigned devmajor = parse_octal( header + devmajor_o, devmajor_l );
+ const unsigned devminor = parse_octal( header + devminor_o, devminor_l );
+ const int width = std::max( 1,
+ std::max( 8, 19 - group_string_len ) - 1 - decimal_digits( devminor ) );
+ offset += snprintf( rbuf() + offset, rbuf.size() - offset, " %*u,%u",
+ width, devmajor, devminor );
+ }
else
- offset += snprintf( rbuf() + offset, rbuf.size() - offset, " %9llu",
- extended.file_size() );
+ {
+ const int width = std::max( 8, 19 - group_string_len );
+ offset += snprintf( rbuf() + offset, rbuf.size() - offset, " %*llu",
+ width, extended.file_size() );
+ }
for( int i = 0; i < 2; ++i ) // resize rbuf if not large enough
{
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;
+ 1900 + t.tm_year, 1 + t.tm_mon, t.tm_mday, t.tm_hour,
+ t.tm_min, extended.path().c_str(), link_string,
+ islink ? extended.linkpath().c_str() : "" );
+ if( len + offset < (int)rbuf.size() ) break;
if( !rbuf.resize( len + offset + 1 ) ) return false;
}
}
@@ -180,16 +187,18 @@ bool check_skip_filename( const Cl_options & cl_opts,
const char * const filename )
{
if( Exclude::excluded( filename ) ) return true; // skip excluded files
- bool skip = cl_opts.num_files > 0;
- if( skip )
+ bool skip = cl_opts.num_files > 0; // if no files specified, skip nothing
+ if( skip ) // else skip all but the files (or trees) specified
for( int i = 0; i < cl_opts.parser.arguments(); ++i )
if( nonempty_arg( cl_opts.parser, i ) )
{
- const char * const name =
- remove_leading_dotslash( cl_opts.parser.argument( i ).c_str() );
+ std::string removed_prefix;
+ const char * const name = remove_leading_dotslash(
+ cl_opts.parser.argument( i ).c_str(), &removed_prefix );
if( compare_prefix_dir( name, filename ) ||
compare_tslash( name, filename ) )
- { skip = false; name_pending[i] = false; break; }
+ { print_removed_prefix( removed_prefix );
+ skip = false; name_pending[i] = false; break; }
}
return skip;
}
@@ -224,10 +233,10 @@ bool make_path( const std::string & name )
{
const std::string partial( name, 0, index );
struct stat st;
- if( stat( partial.c_str(), &st ) == 0 )
- { if( !S_ISDIR( st.st_mode ) ) return false; }
+ if( lstat( partial.c_str(), &st ) == 0 )
+ { if( !S_ISDIR( st.st_mode ) ) { errno = ENOTDIR; return false; } }
else if( mkdir( partial.c_str(), mode ) != 0 && errno != EEXIST )
- return false;
+ return false; // if EEXIST, another thread or process created the dir
}
}
return true;