(read_and, list_archive): Simplify code.
(read_header): Fix computation of signed checksums on machines where char is unsigned. Do not consider a block to be zero unless all its bytes are zero, even the checksum bytes. Do not attempt to parse the checksum of a zero block. Fix memory leak with long names and links. (from_chars): Accommodate a buggy tar that outputs leading NUL if the previous field overflows. (skip_extended_headers): Don't assume find_next_block yields nonnull.
This commit is contained in:
130
src/list.c
130
src/list.c
@@ -55,7 +55,6 @@ read_and (void (*do_something) ())
|
||||
{
|
||||
enum read_header status = HEADER_STILL_UNREAD;
|
||||
enum read_header prev_status;
|
||||
char save_typeflag;
|
||||
|
||||
base64_init ();
|
||||
name_gather ();
|
||||
@@ -83,7 +82,7 @@ read_and (void (*do_something) ())
|
||||
|| current_stat.st_mtime < newer_mtime_option
|
||||
|| excluded_name (current_file_name))
|
||||
{
|
||||
int isextended = 0;
|
||||
char save_typeflag;
|
||||
|
||||
if (current_header->header.typeflag == GNUTYPE_VOLHDR
|
||||
|| current_header->header.typeflag == GNUTYPE_MULTIVOL
|
||||
@@ -98,28 +97,10 @@ read_and (void (*do_something) ())
|
||||
|
||||
/* Skip past it in the archive. */
|
||||
|
||||
if (current_header->oldgnu_header.isextended)
|
||||
isextended = 1;
|
||||
save_typeflag = current_header->header.typeflag;
|
||||
set_next_block_after (current_header);
|
||||
if (isextended)
|
||||
{
|
||||
#if 0
|
||||
union block *exhdr;
|
||||
|
||||
while (1)
|
||||
{
|
||||
exhdr = find_next_block ();
|
||||
if (!exhdr->sparse_header.isextended)
|
||||
{
|
||||
set_next_block_after (exhdr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
set_next_block_after (exhdr);
|
||||
#endif
|
||||
skip_extended_headers ();
|
||||
}
|
||||
if (current_header->oldgnu_header.isextended)
|
||||
skip_extended_headers ();
|
||||
|
||||
/* Skip to the next header on the archive. */
|
||||
|
||||
@@ -191,8 +172,6 @@ read_and (void (*do_something) ())
|
||||
void
|
||||
list_archive (void)
|
||||
{
|
||||
int isextended = 0; /* to remember if current_header is extended */
|
||||
|
||||
/* Print the header block. */
|
||||
|
||||
if (verbose_option)
|
||||
@@ -248,37 +227,11 @@ list_archive (void)
|
||||
|
||||
}
|
||||
|
||||
/* Check to see if we have an extended header to skip over also. */
|
||||
|
||||
if (current_header->oldgnu_header.isextended)
|
||||
isextended = 1;
|
||||
|
||||
/* Skip past the header in the archive. */
|
||||
/* Skip past the header in the archive, and past any extended headers. */
|
||||
|
||||
set_next_block_after (current_header);
|
||||
|
||||
/* If we needed to skip any extended headers, do so now, by reading
|
||||
extended headers and skipping past them in the archive. */
|
||||
|
||||
if (isextended)
|
||||
{
|
||||
#if 0
|
||||
union block *exhdr;
|
||||
|
||||
while (1)
|
||||
{
|
||||
exhdr = find_next_block ();
|
||||
|
||||
if (!exhdr->sparse_header.isextended)
|
||||
{
|
||||
set_next_block_after (exhdr);
|
||||
break;
|
||||
}
|
||||
set_next_block_after (exhdr);
|
||||
}
|
||||
#endif
|
||||
skip_extended_headers ();
|
||||
}
|
||||
if (current_header->oldgnu_header.isextended)
|
||||
skip_extended_headers ();
|
||||
|
||||
if (multi_volume_option)
|
||||
assign_string (&save_name, current_file_name);
|
||||
@@ -312,16 +265,13 @@ list_archive (void)
|
||||
a name containing characters with the high bit set. So read_header
|
||||
computes two checksums -- signed and unsigned. */
|
||||
|
||||
/* FIXME: The signed checksum computation is broken on machines where char's
|
||||
are unsigned. It's uneasy to handle all cases correctly... */
|
||||
|
||||
enum read_header
|
||||
read_header (void)
|
||||
{
|
||||
size_t i;
|
||||
long unsigned_sum; /* the POSIX one :-) */
|
||||
long signed_sum; /* the Sun one :-( */
|
||||
long recorded_sum;
|
||||
int unsigned_sum; /* the POSIX one :-) */
|
||||
int signed_sum; /* the Sun one :-( */
|
||||
int recorded_sum;
|
||||
uintmax_t parsed_sum;
|
||||
char *p;
|
||||
union block *header;
|
||||
@@ -338,43 +288,36 @@ read_header (void)
|
||||
if (!header)
|
||||
return HEADER_END_OF_FILE;
|
||||
|
||||
parsed_sum = from_chars (header->header.chksum,
|
||||
sizeof header->header.chksum,
|
||||
(char *) 0, (uintmax_t) 0,
|
||||
(uintmax_t) TYPE_MAXIMUM (long));
|
||||
if (parsed_sum == (uintmax_t) -1)
|
||||
return HEADER_FAILURE;
|
||||
|
||||
recorded_sum = parsed_sum;
|
||||
unsigned_sum = 0;
|
||||
signed_sum = 0;
|
||||
p = header->buffer;
|
||||
for (i = sizeof (*header); i-- != 0;)
|
||||
{
|
||||
/* We can't use unsigned char here because of old compilers,
|
||||
e.g. V7. */
|
||||
|
||||
unsigned_sum += 0xFF & *p;
|
||||
signed_sum += *p++;
|
||||
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 -= 0xFF & header->header.chksum[i];
|
||||
signed_sum -= header->header.chksum[i];
|
||||
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;
|
||||
|
||||
if (unsigned_sum == sizeof header->header.chksum * ' ')
|
||||
{
|
||||
/* This is a zeroed block...whole block is 0's except for the
|
||||
blanks we faked for the checksum field. */
|
||||
parsed_sum = from_chars (header->header.chksum,
|
||||
sizeof header->header.chksum,
|
||||
(char *) 0, (uintmax_t) 0,
|
||||
(uintmax_t) TYPE_MAXIMUM (int));
|
||||
if (parsed_sum == (uintmax_t) -1)
|
||||
return HEADER_FAILURE;
|
||||
|
||||
return HEADER_ZERO_BLOCK;
|
||||
}
|
||||
recorded_sum = parsed_sum;
|
||||
|
||||
if (unsigned_sum != recorded_sum && signed_sum != recorded_sum)
|
||||
return HEADER_FAILURE;
|
||||
@@ -448,6 +391,11 @@ read_header (void)
|
||||
name = namebuf;
|
||||
}
|
||||
assign_string (¤t_file_name, name);
|
||||
if (next_long_name)
|
||||
{
|
||||
free (next_long_name);
|
||||
next_long_name = 0;
|
||||
}
|
||||
|
||||
name = next_long_link;
|
||||
if (! name)
|
||||
@@ -457,8 +405,12 @@ read_header (void)
|
||||
name = namebuf;
|
||||
}
|
||||
assign_string (¤t_link_name, name);
|
||||
if (next_long_link)
|
||||
{
|
||||
free (next_long_link);
|
||||
next_long_link = 0;
|
||||
}
|
||||
|
||||
next_long_link = next_long_name = 0;
|
||||
return HEADER_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -560,17 +512,19 @@ from_chars (char const *where0, size_t digs, char const *type,
|
||||
char const *lim = where + digs;
|
||||
int negative = 0;
|
||||
|
||||
/* Accommodate older tars, which output leading spaces, and at least one
|
||||
buggy tar, which outputs leading NUL if the previous field overflows. */
|
||||
for (;;)
|
||||
{
|
||||
if (where == lim)
|
||||
{
|
||||
if (type)
|
||||
ERROR ((0, 0,
|
||||
_("Blanks in header where numeric %s value expected"),
|
||||
_("Empty header where numeric %s value expected"),
|
||||
type));
|
||||
return -1;
|
||||
}
|
||||
if (!ISSPACE ((unsigned char) *where))
|
||||
if (!ISSPACE ((unsigned char) *where) && *where)
|
||||
break;
|
||||
where++;
|
||||
}
|
||||
@@ -1123,14 +1077,12 @@ skip_extended_headers (void)
|
||||
{
|
||||
union block *exhdr;
|
||||
|
||||
while (1)
|
||||
do
|
||||
{
|
||||
exhdr = find_next_block ();
|
||||
if (!exhdr->sparse_header.isextended)
|
||||
{
|
||||
set_next_block_after (exhdr);
|
||||
break;
|
||||
}
|
||||
if (!exhdr)
|
||||
FATAL_ERROR ((0, 0, _("Unexpected EOF on archive file")));
|
||||
set_next_block_after (exhdr);
|
||||
}
|
||||
while (exhdr->sparse_header.isextended);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user