| 30 |
#define max(a, b) ((a) < (b) ? (b) : (a)) |
#define max(a, b) ((a) < (b) ? (b) : (a)) |
| 31 |
|
|
| 32 |
union block *current_header; /* points to current archive header */ |
union block *current_header; /* points to current archive header */ |
|
struct stat current_stat; /* stat struct corresponding */ |
|
| 33 |
enum archive_format current_format; /* recognized format */ |
enum archive_format current_format; /* recognized format */ |
| 34 |
union block *recent_long_name; /* recent long name header and contents */ |
union block *recent_long_name; /* recent long name header and contents */ |
| 35 |
union block *recent_long_link; /* likewise, for long link */ |
union block *recent_long_link; /* likewise, for long link */ |
| 87 |
/* Valid header. We should decode next field (mode) first. |
/* Valid header. We should decode next field (mode) first. |
| 88 |
Ensure incoming names are null terminated. */ |
Ensure incoming names are null terminated. */ |
| 89 |
|
|
| 90 |
if (! name_match (current_file_name) |
if (! name_match (current_stat_info.file_name) |
| 91 |
|| (newer_mtime_option != TYPE_MINIMUM (time_t) |
|| (newer_mtime_option != TYPE_MINIMUM (time_t) |
| 92 |
/* FIXME: We get mtime now, and again later; this causes |
/* FIXME: We get mtime now, and again later; this causes |
| 93 |
duplicate diagnostics if header.mtime is bogus. */ |
duplicate diagnostics if header.mtime is bogus. */ |
| 94 |
&& ((current_stat.st_mtime |
&& ((current_stat_info.stat.st_mtime |
| 95 |
= TIME_FROM_HEADER (current_header->header.mtime)) |
= TIME_FROM_HEADER (current_header->header.mtime)) |
| 96 |
< newer_mtime_option)) |
< newer_mtime_option)) |
| 97 |
|| excluded_name (current_file_name)) |
|| excluded_name (current_stat_info.file_name)) |
| 98 |
{ |
{ |
| 99 |
switch (current_header->header.typeflag) |
switch (current_header->header.typeflag) |
| 100 |
{ |
{ |
| 106 |
case DIRTYPE: |
case DIRTYPE: |
| 107 |
if (show_omitted_dirs_option) |
if (show_omitted_dirs_option) |
| 108 |
WARN ((0, 0, _("%s: Omitting"), |
WARN ((0, 0, _("%s: Omitting"), |
| 109 |
quotearg_colon (current_file_name))); |
quotearg_colon (current_stat_info.file_name))); |
| 110 |
/* Fall through. */ |
/* Fall through. */ |
| 111 |
default: |
default: |
| 112 |
skip_member (); |
skip_member (); |
| 178 |
if (verbose_option) |
if (verbose_option) |
| 179 |
{ |
{ |
| 180 |
if (verbose_option > 1) |
if (verbose_option > 1) |
| 181 |
decode_header (current_header, ¤t_stat, ¤t_format, 0); |
decode_header (current_header, ¤t_stat_info, ¤t_format, 0); |
| 182 |
print_header (-1); |
print_header (-1); |
| 183 |
} |
} |
| 184 |
|
|
| 191 |
set_next_block_after (current_header); |
set_next_block_after (current_header); |
| 192 |
if (multi_volume_option) |
if (multi_volume_option) |
| 193 |
{ |
{ |
| 194 |
assign_string (&save_name, current_file_name); |
assign_string (&save_name, current_stat_info.file_name); |
| 195 |
save_totsize = current_stat.st_size; |
save_totsize = current_stat_info.stat.st_size; |
| 196 |
} |
} |
| 197 |
for (size = current_stat.st_size; size > 0; size -= written) |
for (size = current_stat_info.stat.st_size; size > 0; size -= written) |
| 198 |
{ |
{ |
| 199 |
if (multi_volume_option) |
if (multi_volume_option) |
| 200 |
save_sizeleft = size; |
save_sizeleft = size; |
| 213 |
(data_block->buffer + written - 1)); |
(data_block->buffer + written - 1)); |
| 214 |
if (check != written) |
if (check != written) |
| 215 |
{ |
{ |
| 216 |
write_error_details (current_file_name, check, written); |
write_error_details (current_stat_info.file_name, check, written); |
| 217 |
skip_file (size - written); |
skip_file (size - written); |
| 218 |
break; |
break; |
| 219 |
} |
} |
| 227 |
} |
} |
| 228 |
|
|
| 229 |
if (multi_volume_option) |
if (multi_volume_option) |
| 230 |
assign_string (&save_name, current_file_name); |
assign_string (&save_name, current_stat_info.file_name); |
| 231 |
|
|
| 232 |
skip_member (); |
skip_member (); |
| 233 |
|
|
| 237 |
|
|
| 238 |
/* Read a block that's supposed to be a header block. Return its |
/* Read a block that's supposed to be a header block. Return its |
| 239 |
address in "current_header", and if it is good, the file's size in |
address in "current_header", and if it is good, the file's size in |
| 240 |
current_stat.st_size. |
current_stat_info.stat.st_size. |
| 241 |
|
|
| 242 |
Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a |
Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a |
| 243 |
block full of zeros (EOF marker). |
block full of zeros (EOF marker). |
| 319 |
|
|
| 320 |
/* Good block. Decode file size and return. */ |
/* Good block. Decode file size and return. */ |
| 321 |
|
|
| 322 |
|
if (header->header.typeflag == XHDTYPE |
| 323 |
|
|| header->header.typeflag == XGLTYPE) |
| 324 |
|
{ |
| 325 |
|
xheader_read (header, OFF_FROM_HEADER (header->header.size)); |
| 326 |
|
continue; |
| 327 |
|
} |
| 328 |
|
|
| 329 |
if (header->header.typeflag == LNKTYPE) |
if (header->header.typeflag == LNKTYPE) |
| 330 |
current_stat.st_size = 0; /* links 0 size on tape */ |
current_stat_info.stat.st_size = 0; /* links 0 size on tape */ |
| 331 |
else |
else |
| 332 |
current_stat.st_size = OFF_FROM_HEADER (header->header.size); |
current_stat_info.stat.st_size = OFF_FROM_HEADER (header->header.size); |
| 333 |
|
|
| 334 |
if (header->header.typeflag == GNUTYPE_LONGNAME |
if (header->header.typeflag == GNUTYPE_LONGNAME |
| 335 |
|| header->header.typeflag == GNUTYPE_LONGLINK) |
|| header->header.typeflag == GNUTYPE_LONGLINK) |
| 338 |
return HEADER_SUCCESS_EXTENDED; |
return HEADER_SUCCESS_EXTENDED; |
| 339 |
else |
else |
| 340 |
{ |
{ |
| 341 |
size_t name_size = current_stat.st_size; |
size_t name_size = current_stat_info.stat.st_size; |
| 342 |
size = name_size - name_size % BLOCKSIZE + 2 * BLOCKSIZE; |
size = name_size - name_size % BLOCKSIZE + 2 * BLOCKSIZE; |
| 343 |
if (name_size != current_stat.st_size || size < name_size) |
if (name_size != current_stat_info.stat.st_size || size < name_size) |
| 344 |
xalloc_die (); |
xalloc_die (); |
| 345 |
} |
} |
| 346 |
|
|
| 427 |
recent_long_name = 0; |
recent_long_name = 0; |
| 428 |
recent_long_name_blocks = 0; |
recent_long_name_blocks = 0; |
| 429 |
} |
} |
| 430 |
assign_string (&orig_file_name, name); |
assign_string (¤t_stat_info.orig_file_name, name); |
| 431 |
assign_string (¤t_file_name, name); |
assign_string (¤t_stat_info.file_name, name); |
| 432 |
current_trailing_slash = strip_trailing_slashes (current_file_name); |
current_stat_info.had_trailing_slash = strip_trailing_slashes (current_stat_info.file_name); |
| 433 |
|
|
| 434 |
if (recent_long_link) |
if (recent_long_link) |
| 435 |
free (recent_long_link); |
free (recent_long_link); |
| 448 |
recent_long_link = 0; |
recent_long_link = 0; |
| 449 |
recent_long_link_blocks = 0; |
recent_long_link_blocks = 0; |
| 450 |
} |
} |
| 451 |
assign_string (¤t_link_name, name); |
assign_string (¤t_stat_info.link_name, name); |
| 452 |
|
|
| 453 |
return HEADER_SUCCESS; |
return HEADER_SUCCESS; |
| 454 |
} |
} |
| 455 |
} |
} |
| 456 |
} |
} |
| 457 |
|
|
| 458 |
|
#define ISOCTAL(c) ((c)>='0'&&(c)<='7') |
| 459 |
|
|
| 460 |
/* Decode things from a file HEADER block into STAT_INFO, also setting |
/* Decode things from a file HEADER block into STAT_INFO, also setting |
| 461 |
*FORMAT_POINTER depending on the header block format. If |
*FORMAT_POINTER depending on the header block format. If |
| 462 |
DO_USER_GROUP, decode the user/group information (this is useful |
DO_USER_GROUP, decode the user/group information (this is useful |
| 471 |
should decode it without uid/gid before calling a routine, |
should decode it without uid/gid before calling a routine, |
| 472 |
e.g. print_header, that assumes decoded data. */ |
e.g. print_header, that assumes decoded data. */ |
| 473 |
void |
void |
| 474 |
decode_header (union block *header, struct stat *stat_info, |
decode_header (union block *header, struct tar_stat_info *stat_info, |
| 475 |
enum archive_format *format_pointer, int do_user_group) |
enum archive_format *format_pointer, int do_user_group) |
| 476 |
{ |
{ |
| 477 |
enum archive_format format; |
enum archive_format format; |
| 478 |
|
|
| 479 |
if (strcmp (header->header.magic, TMAGIC) == 0) |
if (strcmp (header->header.magic, TMAGIC) == 0) |
| 480 |
format = POSIX_FORMAT; |
{ |
| 481 |
|
if (header->star_header.prefix[130] == 0 |
| 482 |
|
&& ISOCTAL (header->star_header.atime[0]) |
| 483 |
|
&& header->star_header.atime[11] == ' ' |
| 484 |
|
&& ISOCTAL (header->star_header.ctime[0]) |
| 485 |
|
&& header->star_header.ctime[11] == ' ') |
| 486 |
|
format = STAR_FORMAT; |
| 487 |
|
else |
| 488 |
|
format = POSIX_FORMAT; |
| 489 |
|
} |
| 490 |
else if (strcmp (header->header.magic, OLDGNU_MAGIC) == 0) |
else if (strcmp (header->header.magic, OLDGNU_MAGIC) == 0) |
| 491 |
format = OLDGNU_FORMAT; |
format = OLDGNU_FORMAT; |
| 492 |
else |
else |
| 493 |
format = V7_FORMAT; |
format = V7_FORMAT; |
| 494 |
*format_pointer = format; |
*format_pointer = format; |
| 495 |
|
|
| 496 |
stat_info->st_mode = MODE_FROM_HEADER (header->header.mode); |
stat_info->stat.st_mode = MODE_FROM_HEADER (header->header.mode); |
| 497 |
stat_info->st_mtime = TIME_FROM_HEADER (header->header.mtime); |
stat_info->stat.st_mtime = TIME_FROM_HEADER (header->header.mtime); |
| 498 |
|
assign_string (&stat_info->uname, header->header.uname); |
| 499 |
|
assign_string (&stat_info->gname, header->header.gname); |
| 500 |
|
stat_info->devmajor = MAJOR_FROM_HEADER (header->header.devmajor); |
| 501 |
|
stat_info->devminor = MINOR_FROM_HEADER (header->header.devminor); |
| 502 |
|
|
| 503 |
if (format == OLDGNU_FORMAT && incremental_option) |
if (format == OLDGNU_FORMAT && incremental_option) |
| 504 |
{ |
{ |
| 505 |
stat_info->st_atime = TIME_FROM_HEADER (header->oldgnu_header.atime); |
stat_info->stat.st_atime = TIME_FROM_HEADER (header->oldgnu_header.atime); |
| 506 |
stat_info->st_ctime = TIME_FROM_HEADER (header->oldgnu_header.ctime); |
stat_info->stat.st_ctime = TIME_FROM_HEADER (header->oldgnu_header.ctime); |
| 507 |
} |
} |
| 508 |
|
|
| 509 |
if (format == V7_FORMAT) |
if (format == V7_FORMAT) |
| 510 |
{ |
{ |
| 511 |
stat_info->st_uid = UID_FROM_HEADER (header->header.uid); |
stat_info->stat.st_uid = UID_FROM_HEADER (header->header.uid); |
| 512 |
stat_info->st_gid = GID_FROM_HEADER (header->header.gid); |
stat_info->stat.st_gid = GID_FROM_HEADER (header->header.gid); |
| 513 |
stat_info->st_rdev = 0; |
stat_info->stat.st_rdev = 0; |
| 514 |
} |
} |
| 515 |
else |
else |
| 516 |
{ |
{ |
| 517 |
|
|
| 518 |
|
if (format == STAR_FORMAT) |
| 519 |
|
{ |
| 520 |
|
stat_info->stat.st_atime = TIME_FROM_HEADER (header->star_header.atime); |
| 521 |
|
stat_info->stat.st_ctime = TIME_FROM_HEADER (header->star_header.ctime); |
| 522 |
|
} |
| 523 |
|
|
| 524 |
if (do_user_group) |
if (do_user_group) |
| 525 |
{ |
{ |
| 526 |
/* FIXME: Decide if this should somewhat depend on -p. */ |
/* FIXME: Decide if this should somewhat depend on -p. */ |
| 527 |
|
|
| 528 |
if (numeric_owner_option |
if (numeric_owner_option |
| 529 |
|| !*header->header.uname |
|| !*header->header.uname |
| 530 |
|| !uname_to_uid (header->header.uname, &stat_info->st_uid)) |
|| !uname_to_uid (header->header.uname, &stat_info->stat.st_uid)) |
| 531 |
stat_info->st_uid = UID_FROM_HEADER (header->header.uid); |
stat_info->stat.st_uid = UID_FROM_HEADER (header->header.uid); |
| 532 |
|
|
| 533 |
if (numeric_owner_option |
if (numeric_owner_option |
| 534 |
|| !*header->header.gname |
|| !*header->header.gname |
| 535 |
|| !gname_to_gid (header->header.gname, &stat_info->st_gid)) |
|| !gname_to_gid (header->header.gname, &stat_info->stat.st_gid)) |
| 536 |
stat_info->st_gid = GID_FROM_HEADER (header->header.gid); |
stat_info->stat.st_gid = GID_FROM_HEADER (header->header.gid); |
| 537 |
} |
} |
| 538 |
|
|
| 539 |
switch (header->header.typeflag) |
switch (header->header.typeflag) |
| 540 |
{ |
{ |
| 541 |
case BLKTYPE: |
case BLKTYPE: |
|
stat_info->st_rdev |
|
|
= makedev (MAJOR_FROM_HEADER (header->header.devmajor), |
|
|
MINOR_FROM_HEADER (header->header.devminor)); |
|
|
break; |
|
|
|
|
| 542 |
case CHRTYPE: |
case CHRTYPE: |
| 543 |
stat_info->st_rdev |
stat_info->stat.st_rdev = makedev (stat_info->devmajor, stat_info->devminor); |
|
= makedev (MAJOR_FROM_HEADER (header->header.devmajor), |
|
|
MINOR_FROM_HEADER (header->header.devminor)); |
|
| 544 |
break; |
break; |
| 545 |
|
|
| 546 |
default: |
default: |
| 547 |
stat_info->st_rdev = 0; |
stat_info->stat.st_rdev = 0; |
| 548 |
} |
} |
| 549 |
} |
} |
| 550 |
|
|
| 551 |
|
if (extended_header.nblocks) |
| 552 |
|
xheader_decode (stat_info); |
| 553 |
} |
} |
| 554 |
|
|
| 555 |
/* Convert buffer at WHERE0 of size DIGS from external format to |
/* Convert buffer at WHERE0 of size DIGS from external format to |
| 748 |
*--value_string = '-'; |
*--value_string = '-'; |
| 749 |
if (minus_minval) |
if (minus_minval) |
| 750 |
*--minval_string = '-'; |
*--minval_string = '-'; |
| 751 |
ERROR ((0, 0, _("Archive value %s is out of %s range %s..%s"), |
ERROR ((0, 0, _("Archive value %s is out of %s range %s.%s"), |
| 752 |
value_string, type, |
value_string, type, |
| 753 |
minval_string, STRINGIFY_BIGINT (maxval, maxval_buf))); |
minval_string, STRINGIFY_BIGINT (maxval, maxval_buf))); |
| 754 |
} |
} |
| 910 |
|
|
| 911 |
|
|
| 912 |
/* FIXME: Note that print_header uses the globals HEAD, HSTAT, and |
/* FIXME: Note that print_header uses the globals HEAD, HSTAT, and |
| 913 |
HEAD_STANDARD, which must be set up in advance. Not very clean... */ |
HEAD_STANDARD, which must be set up in advance. Not very clean.. */ |
| 914 |
|
|
| 915 |
/* UGSWIDTH starts with 18, so with user and group names <= 8 chars, the |
/* UGSWIDTH starts with 18, so with user and group names <= 8 chars, the |
| 916 |
columns never shift during the listing. */ |
columns never shift during the listing. */ |
| 929 |
{ |
{ |
| 930 |
char modes[11]; |
char modes[11]; |
| 931 |
char const *time_stamp; |
char const *time_stamp; |
| 932 |
char *temp_name = orig_file_name ? orig_file_name : current_file_name; |
char *temp_name = current_stat_info.orig_file_name ? current_stat_info.orig_file_name : current_stat_info.file_name; |
| 933 |
|
|
| 934 |
/* These hold formatted ints. */ |
/* These hold formatted ints. */ |
| 935 |
char uform[UINTMAX_STRSIZE_BOUND], gform[UINTMAX_STRSIZE_BOUND]; |
char uform[UINTMAX_STRSIZE_BOUND], gform[UINTMAX_STRSIZE_BOUND]; |
| 1013 |
break; |
break; |
| 1014 |
} |
} |
| 1015 |
|
|
| 1016 |
decode_mode (current_stat.st_mode, modes + 1); |
decode_mode (current_stat_info.stat.st_mode, modes + 1); |
| 1017 |
|
|
| 1018 |
/* Time stamp. */ |
/* Time stamp. */ |
| 1019 |
|
|
| 1020 |
time_stamp = tartime (current_stat.st_mtime); |
time_stamp = tartime (current_stat_info.stat.st_mtime); |
| 1021 |
|
|
| 1022 |
/* User and group names. */ |
/* User and group names. */ |
| 1023 |
|
|
| 1072 |
case CHRTYPE: |
case CHRTYPE: |
| 1073 |
case BLKTYPE: |
case BLKTYPE: |
| 1074 |
strcpy (size, |
strcpy (size, |
| 1075 |
STRINGIFY_BIGINT (major (current_stat.st_rdev), uintbuf)); |
STRINGIFY_BIGINT (major (current_stat_info.stat.st_rdev), uintbuf)); |
| 1076 |
strcat (size, ","); |
strcat (size, ","); |
| 1077 |
strcat (size, |
strcat (size, |
| 1078 |
STRINGIFY_BIGINT (minor (current_stat.st_rdev), uintbuf)); |
STRINGIFY_BIGINT (minor (current_stat_info.stat.st_rdev), uintbuf)); |
| 1079 |
break; |
break; |
| 1080 |
case GNUTYPE_SPARSE: |
case GNUTYPE_SPARSE: |
| 1081 |
strcpy (size, |
strcpy (size, |
| 1085 |
uintbuf)); |
uintbuf)); |
| 1086 |
break; |
break; |
| 1087 |
default: |
default: |
| 1088 |
strcpy (size, STRINGIFY_BIGINT (current_stat.st_size, uintbuf)); |
strcpy (size, STRINGIFY_BIGINT (current_stat_info.stat.st_size, uintbuf)); |
| 1089 |
break; |
break; |
| 1090 |
} |
} |
| 1091 |
|
|
| 1103 |
switch (current_header->header.typeflag) |
switch (current_header->header.typeflag) |
| 1104 |
{ |
{ |
| 1105 |
case SYMTYPE: |
case SYMTYPE: |
| 1106 |
fprintf (stdlis, " -> %s\n", quotearg (current_link_name)); |
fprintf (stdlis, " -> %s\n", quotearg (current_stat_info.link_name)); |
| 1107 |
break; |
break; |
| 1108 |
|
|
| 1109 |
case LNKTYPE: |
case LNKTYPE: |
| 1110 |
fprintf (stdlis, _(" link to %s\n"), quotearg (current_link_name)); |
fprintf (stdlis, _(" link to %s\n"), quotearg (current_stat_info.link_name)); |
| 1111 |
break; |
break; |
| 1112 |
|
|
| 1113 |
default: |
default: |
| 1217 |
char save_typeflag = current_header->header.typeflag; |
char save_typeflag = current_header->header.typeflag; |
| 1218 |
set_next_block_after (current_header); |
set_next_block_after (current_header); |
| 1219 |
|
|
| 1220 |
if (current_header->oldgnu_header.isextended) |
if (current_format == OLDGNU_FORMAT |
| 1221 |
|
&& current_header->oldgnu_header.isextended) |
| 1222 |
{ |
{ |
| 1223 |
union block *exhdr; |
union block *exhdr; |
| 1224 |
do |
do |
| 1232 |
} |
} |
| 1233 |
|
|
| 1234 |
if (save_typeflag != DIRTYPE) |
if (save_typeflag != DIRTYPE) |
| 1235 |
skip_file (current_stat.st_size); |
skip_file (current_stat_info.stat.st_size); |
| 1236 |
} |
} |