(tar_checksum): New function

This commit is contained in:
Sergey Poznyakoff
2004-11-26 19:09:26 +00:00
parent 4674867a23
commit b5db978830

View File

@@ -266,6 +266,61 @@ list_archive (void)
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.
@@ -279,23 +334,9 @@ list_archive (void)
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;
@@ -309,44 +350,15 @@ read_header (bool raw_extended_headers)
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. */