/* Define to non-zero for forcing old ctime format instead of ISO format. */
#undef USE_OLD_CTIME
-#include "system.h"
+#include <system.h>
#include <quotearg.h>
#include "common.h"
quotearg_colon (current_stat_info.file_name)));
/* Fall through. */
default:
+ decode_header (current_header,
+ ¤t_stat_info, ¤t_format, 0);
skip_member ();
continue;
}
assign_string (&save_name, 0);
}
+/* Check header checksum */
+/* The standard BSD tar sources create the checksum by adding up the
+ bytes in the header as type char. I think the type char was unsigned
+ on the PDP-11, but it's signed on the Next and Sun. It looks like the
+ sources to BSD tar were never changed to compute the checksum
+ correctly, so both the Sun and Next add the bytes of the header as
+ signed chars. This doesn't cause a problem until you get a file with
+ a name containing characters with the high bit set. So tar_checksum
+ computes two checksums -- signed and unsigned. */
+
+enum read_header
+tar_checksum (union block *header)
+{
+ size_t i;
+ int unsigned_sum = 0; /* the POSIX one :-) */
+ int signed_sum = 0; /* the Sun one :-( */
+ int recorded_sum;
+ uintmax_t parsed_sum;
+ char *p;
+
+ p = header->buffer;
+ for (i = sizeof *header; i-- != 0;)
+ {
+ unsigned_sum += (unsigned char) *p;
+ signed_sum += (signed char) (*p++);
+ }
+
+ if (unsigned_sum == 0)
+ return HEADER_ZERO_BLOCK;
+
+ /* Adjust checksum to count the "chksum" field as blanks. */
+
+ for (i = sizeof header->header.chksum; i-- != 0;)
+ {
+ unsigned_sum -= (unsigned char) header->header.chksum[i];
+ signed_sum -= (signed char) (header->header.chksum[i]);
+ }
+ unsigned_sum += ' ' * sizeof header->header.chksum;
+ signed_sum += ' ' * sizeof header->header.chksum;
+
+ parsed_sum = from_header (header->header.chksum,
+ sizeof header->header.chksum, 0,
+ (uintmax_t) 0,
+ (uintmax_t) TYPE_MAXIMUM (int));
+ if (parsed_sum == (uintmax_t) -1)
+ return HEADER_FAILURE;
+
+ recorded_sum = parsed_sum;
+
+ if (unsigned_sum != recorded_sum && signed_sum != recorded_sum)
+ return HEADER_FAILURE;
+
+ return HEADER_SUCCESS;
+}
+
/* Read a block that's supposed to be a header block. Return its
address in "current_header", and if it is good, the file's size in
current_stat_info.stat.st_size.
You must always set_next_block_after(current_header) to skip past
the header which this routine reads. */
-/* The standard BSD tar sources create the checksum by adding up the
- bytes in the header as type char. I think the type char was unsigned
- on the PDP-11, but it's signed on the Next and Sun. It looks like the
- sources to BSD tar were never changed to compute the checksum
- correctly, so both the Sun and Next add the bytes of the header as
- signed chars. This doesn't cause a problem until you get a file with
- a name containing characters with the high bit set. So read_header
- computes two checksums -- signed and unsigned. */
-
enum read_header
read_header (bool raw_extended_headers)
{
- size_t i;
- int unsigned_sum; /* the POSIX one :-) */
- int signed_sum; /* the Sun one :-( */
- int recorded_sum;
- uintmax_t parsed_sum;
char *p;
union block *header;
union block *header_copy;
while (1)
{
+ enum read_header status;
+
header = find_next_block ();
current_header = header;
if (!header)
return HEADER_END_OF_FILE;
- unsigned_sum = 0;
- signed_sum = 0;
- p = header->buffer;
- for (i = sizeof *header; i-- != 0;)
- {
- unsigned_sum += (unsigned char) *p;
- signed_sum += (signed char) (*p++);
- }
-
- if (unsigned_sum == 0)
- return HEADER_ZERO_BLOCK;
-
- /* Adjust checksum to count the "chksum" field as blanks. */
-
- for (i = sizeof header->header.chksum; i-- != 0;)
- {
- unsigned_sum -= (unsigned char) header->header.chksum[i];
- signed_sum -= (signed char) (header->header.chksum[i]);
- }
- unsigned_sum += ' ' * sizeof header->header.chksum;
- signed_sum += ' ' * sizeof header->header.chksum;
-
- parsed_sum = from_header (header->header.chksum,
- sizeof header->header.chksum, 0,
- (uintmax_t) 0,
- (uintmax_t) TYPE_MAXIMUM (int));
- if (parsed_sum == (uintmax_t) -1)
- return HEADER_FAILURE;
-
- recorded_sum = parsed_sum;
-
- if (unsigned_sum != recorded_sum && signed_sum != recorded_sum)
- return HEADER_FAILURE;
+ if ((status = tar_checksum (header)) != HEADER_SUCCESS)
+ return status;
/* Good block. Decode file size and return. */
stat_info->stat.st_mode = MODE_FROM_HEADER (header->header.mode);
stat_info->stat.st_mtime = TIME_FROM_HEADER (header->header.mtime);
- assign_string (&stat_info->uname, header->header.uname);
- assign_string (&stat_info->gname, header->header.gname);
+ assign_string (&stat_info->uname,
+ header->header.uname[0] ? header->header.uname : NULL);
+ assign_string (&stat_info->gname,
+ header->header.gname[0] ? header->header.gname : NULL);
stat_info->devmajor = MAJOR_FROM_HEADER (header->header.devmajor);
stat_info->devminor = MINOR_FROM_HEADER (header->header.devminor);
sparse_fixup_header (stat_info);
stat_info->is_sparse = true;
}
+ else
+ stat_info->is_sparse = false;
}
/* Convert buffer at WHERE0 of size DIGS from external format to
/* Print a similar line when we make a directory automatically. */
void
-print_for_mkdir (char *pathname, int length, mode_t mode)
+print_for_mkdir (char *dirname, int length, mode_t mode)
{
char modes[11];
}
fprintf (stdlis, "%s %*s %.*s\n", modes, ugswidth + DATEWIDTH,
- _("Creating directory:"), length, quotearg (pathname));
+ _("Creating directory:"), length, quotearg (dirname));
}
}
save_sizeleft = size;
}
+ if (seekable_archive)
+ {
+ off_t nblk = seek_archive (size);
+ if (nblk >= 0)
+ {
+ size -= nblk * BLOCKSIZE;
+ if (multi_volume_option) /* Argh.. */
+ save_sizeleft -= nblk * BLOCKSIZE;
+ }
+ else
+ seekable_archive = false;
+ }
+
while (size > 0)
{
x = find_next_block ();
}
}
-/* Skip the current member in the archive. */
+/* Skip the current member in the archive.
+ NOTE: Current header must be decoded before calling this function. */
void
skip_member (void)
{
char save_typeflag = current_header->header.typeflag;
set_next_block_after (current_header);
-
+
assign_string (&save_name, current_stat_info.file_name);
- if (sparse_member_p (¤t_stat_info))
+ if (current_stat_info.is_sparse)
sparse_skip_file (¤t_stat_info);
else if (save_typeflag != DIRTYPE)
skip_file (current_stat_info.stat.st_size);