/* List a tar archive, with support routines for reading a tar archive.
- Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
- 2001 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
+ 2001, 2003 Free Software Foundation, Inc.
Written by John Gilmore, on 1985-08-26.
union block *current_header; /* points to current archive header */
struct stat current_stat; /* stat struct corresponding */
enum archive_format current_format; /* recognized format */
+union block *recent_long_name; /* recent long name header and contents */
+union block *recent_long_link; /* likewise, for long link */
+size_t recent_long_name_blocks; /* number of blocks in recent_long_name */
+size_t recent_long_link_blocks; /* likewise, for long link */
-static uintmax_t from_header PARAMS ((const char *, size_t, const char *,
- uintmax_t, uintmax_t));
+static uintmax_t from_header (const char *, size_t, const char *,
+ uintmax_t, uintmax_t);
/* Base 64 digits; see Internet RFC 2045 Table 1. */
static char const base_64_digits[64] =
/* Main loop for reading an archive. */
void
-read_and (void (*do_something) ())
+read_and (void (*do_something) (void))
{
enum read_header status = HEADER_STILL_UNREAD;
enum read_header prev_status;
while (1)
{
prev_status = status;
- status = read_header ();
+ status = read_header (0);
switch (status)
{
case HEADER_STILL_UNREAD:
case GNUTYPE_MULTIVOL:
case GNUTYPE_NAMES:
break;
-
+
case DIRTYPE:
if (show_omitted_dirs_option)
WARN ((0, 0, _("%s: Omitting"),
{
if (verbose_option > 1)
decode_header (current_header, ¤t_stat, ¤t_format, 0);
- print_header ();
+ print_header (-1);
}
if (incremental_option && current_header->header.typeflag == GNUTYPE_DUMPDIR)
Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a
block full of zeros (EOF marker).
+ If RAW_EXTENDED_HEADERS is nonzero, do not automagically fold the
+ GNU long name and link headers into later headers.
+
You must always set_next_block_after(current_header) to skip past
the header which this routine reads. */
computes two checksums -- signed and unsigned. */
enum read_header
-read_header (void)
+read_header (bool raw_extended_headers)
{
size_t i;
int unsigned_sum; /* the POSIX one :-) */
uintmax_t parsed_sum;
char *p;
union block *header;
- char **longp;
+ union block *header_copy;
char *bp;
union block *data_block;
size_t size, written;
- static char *next_long_name, *next_long_link;
+ union block *next_long_name = 0;
+ union block *next_long_link = 0;
+ size_t next_long_name_blocks;
+ size_t next_long_link_blocks;
while (1)
{
if (header->header.typeflag == GNUTYPE_LONGNAME
|| header->header.typeflag == GNUTYPE_LONGLINK)
{
- longp = ((header->header.typeflag == GNUTYPE_LONGNAME)
- ? &next_long_name
- : &next_long_link);
+ if (raw_extended_headers)
+ return HEADER_SUCCESS_EXTENDED;
+ else
+ {
+ size_t name_size = current_stat.st_size;
+ size = name_size - name_size % BLOCKSIZE + 2 * BLOCKSIZE;
+ if (name_size != current_stat.st_size || size < name_size)
+ xalloc_die ();
+ }
+
+ header_copy = xmalloc (size + 1);
+
+ if (header->header.typeflag == GNUTYPE_LONGNAME)
+ {
+ if (next_long_name)
+ free (next_long_name);
+ next_long_name = header_copy;
+ next_long_name_blocks = size / BLOCKSIZE;
+ }
+ else
+ {
+ if (next_long_link)
+ free (next_long_link);
+ next_long_link = header_copy;
+ next_long_link_blocks = size / BLOCKSIZE;
+ }
set_next_block_after (header);
- if (*longp)
- free (*longp);
- size = current_stat.st_size;
- if (size != current_stat.st_size)
- xalloc_die ();
- bp = *longp = xmalloc (size);
-
- for (; size > 0; size -= written)
+ *header_copy = *header;
+ bp = header_copy->buffer + BLOCKSIZE;
+
+ for (size -= BLOCKSIZE; size > 0; size -= written)
{
data_block = find_next_block ();
if (! data_block)
(data_block->buffer + written - 1));
}
+ *bp = '\0';
+
/* Loop! */
}
struct posix_header const *h = ¤t_header->header;
char namebuf[sizeof h->prefix + 1 + NAME_FIELD_SIZE + 1];
- name = next_long_name;
- if (! name)
+ if (recent_long_name)
+ free (recent_long_name);
+
+ if (next_long_name)
+ {
+ name = next_long_name->buffer + BLOCKSIZE;
+ recent_long_name = next_long_name;
+ recent_long_name_blocks = next_long_name_blocks;
+ }
+ else
{
/* Accept file names as specified by POSIX.1-1996
section 10.1.1. */
memcpy (np, h->name, sizeof h->name);
np[sizeof h->name] = '\0';
name = namebuf;
+ recent_long_name = 0;
+ recent_long_name_blocks = 0;
}
assign_string (¤t_file_name, name);
- if (next_long_name)
+ current_trailing_slash = strip_trailing_slashes (current_file_name);
+
+ if (recent_long_link)
+ free (recent_long_link);
+
+ if (next_long_link)
{
- free (next_long_name);
- next_long_name = 0;
+ name = next_long_link->buffer + BLOCKSIZE;
+ recent_long_link = next_long_link;
+ recent_long_link_blocks = next_long_link_blocks;
}
-
- name = next_long_link;
- if (! name)
+ else
{
memcpy (namebuf, h->linkname, sizeof h->linkname);
namebuf[sizeof h->linkname] = '\0';
name = namebuf;
+ recent_long_link = 0;
+ recent_long_link_blocks = 0;
}
assign_string (¤t_link_name, name);
- if (next_long_link)
- {
- free (next_long_link);
- next_long_link = 0;
- }
return HEADER_SUCCESS;
}
size_t
size_from_header (const char *p, size_t s)
{
- return from_header (p, s, "size_t", (uintmax_t) 0,
+ return from_header (p, s, "size_t", (uintmax_t) 0,
(uintmax_t) TYPE_MAXIMUM (size_t));
}
struct tm *tm = localtime (&t);
if (tm)
{
- sprintf (buffer, "%04d-%02d-%02d %02d:%02d:%02d",
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ sprintf (buffer, "%04ld-%02d-%02d %02d:%02d:%02d",
+ tm->tm_year + 1900L, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
return buffer;
}
#endif
void
-print_header (void)
+print_header (off_t block_ordinal)
{
char modes[11];
char const *time_stamp;
if (block_number_option)
{
char buf[UINTMAX_STRSIZE_BOUND];
+ if (block_ordinal < 0)
+ block_ordinal = current_block_ordinal ();
+ block_ordinal -= recent_long_name_blocks;
+ block_ordinal -= recent_long_link_blocks;
fprintf (stdlis, _("block %s: "),
- STRINGIFY_BIGINT (current_block_ordinal (), buf));
+ STRINGIFY_BIGINT (block_ordinal, buf));
}
if (verbose_option <= 1)
case GNUTYPE_LONGNAME:
case GNUTYPE_LONGLINK:
+ modes[0] = 'L';
ERROR ((0, 0, _("Visible longname error")));
break;
case GNUTYPE_SPARSE:
case REGTYPE:
case AREGTYPE:
- case LNKTYPE:
modes[0] = '-';
if (current_file_name[strlen (current_file_name) - 1] == '/')
modes[0] = 'd';
break;
+ case LNKTYPE:
+ modes[0] = 'h';
+ break;
case GNUTYPE_DUMPDIR:
modes[0] = 'd';
break;
putc ('\n', stdlis);
break;
+ case GNUTYPE_LONGLINK:
+ fprintf (stdlis, _("--Long Link--\n"));
+ break;
+
+ case GNUTYPE_LONGNAME:
+ fprintf (stdlis, _("--Long Name--\n"));
+ break;
+
case GNUTYPE_VOLHDR:
fprintf (stdlis, _("--Volume Header--\n"));
break;