/* List a tar archive, with support routines for reading a tar archive.
- Copyright 1988,92,93,94,96,97,98,1999 Free Software Foundation, Inc.
+ Copyright 1988, 92,93,94,96,97,98,99, 2000 Free Software Foundation, Inc.
Written by John Gilmore, on 1985-08-26.
This program is free software; you can redistribute it and/or modify it
struct stat current_stat; /* stat struct corresponding */
enum archive_format current_format; /* recognized format */
-static char const *tartime PARAMS ((time_t));
static uintmax_t from_header PARAMS ((const char *, size_t, const char *,
uintmax_t, uintmax_t));
/* Valid header. We should decode next field (mode) first.
Ensure incoming names are null terminated. */
- if (!name_match (current_file_name)
+ if (! name_match (current_file_name)
|| (newer_mtime_option != TYPE_MINIMUM (time_t)
- /* FIXME: We get mtime now, and again later; this
- causes duplicate diagnostics if header.mtime is
- bogus. */
+ /* FIXME: We get mtime now, and again later; this causes
+ duplicate diagnostics if header.mtime is bogus. */
&& ((current_stat.st_mtime
= TIME_FROM_HEADER (current_header->header.mtime))
< newer_mtime_option))
|| excluded_name (current_file_name))
{
- char save_typeflag;
-
- if (current_header->header.typeflag == GNUTYPE_VOLHDR
- || current_header->header.typeflag == GNUTYPE_MULTIVOL
- || current_header->header.typeflag == GNUTYPE_NAMES)
+ char save_typeflag = current_header->header.typeflag;
+ switch (save_typeflag)
{
- (*do_something) ();
- continue;
- }
- if (show_omitted_dirs_option
- && current_header->header.typeflag == DIRTYPE)
- WARN ((0, 0, _("Omitting %s"), current_file_name));
+ case GNUTYPE_VOLHDR:
+ case GNUTYPE_MULTIVOL:
+ case GNUTYPE_NAMES:
+ break;
+
+ case DIRTYPE:
+ if (show_omitted_dirs_option)
+ WARN ((0, 0, _("%s: Omitting"),
+ quotearg_colon (current_file_name)));
+ /* Fall through. */
+ default:
- /* Skip past it in the archive. */
+ /* Skip past it in the archive. */
- save_typeflag = current_header->header.typeflag;
- set_next_block_after (current_header);
- if (current_header->oldgnu_header.isextended)
- skip_extended_headers ();
+ set_next_block_after (current_header);
+ if (current_header->oldgnu_header.isextended)
+ skip_extended_headers ();
- /* Skip to the next header on the archive. */
+ /* Skip to the next header on the archive. */
- if (save_typeflag != DIRTYPE)
- skip_file (current_stat.st_size);
- continue;
- }
+ if (save_typeflag != DIRTYPE)
+ skip_file (current_stat.st_size);
+ continue;
+ }
+ }
+ apply_nonancestor_delayed_set_stat (current_file_name);
(*do_something) ();
continue;
switch (prev_status)
{
case HEADER_STILL_UNREAD:
- WARN ((0, 0, _("This does not look like a tar archive")));
+ ERROR ((0, 0, _("This does not look like a tar archive")));
/* Fall through. */
case HEADER_ZERO_BLOCK:
case HEADER_SUCCESS:
- WARN ((0, 0, _("Skipping to next header")));
+ ERROR ((0, 0, _("Skipping to next header")));
break;
case HEADER_END_OF_FILE:
data_block = find_next_block ();
if (!data_block)
{
- ERROR ((0, 0, _("EOF in archive file")));
+ ERROR ((0, 0, _("Unexpected EOF in archive")));
break; /* FIXME: What happens, then? */
}
written = available_space_after (data_block);
if (written > size)
written = size;
- errno = 0; /* FIXME: errno should be read-only */
+ errno = 0;
check = fwrite (data_block->buffer, sizeof (char), written, stdlis);
set_next_block_after ((union block *)
(data_block->buffer + written - 1));
if (check != written)
{
- ERROR ((0, errno, _("Only wrote %lu of %lu bytes to file %s"),
- (unsigned long) check,
- (unsigned long) written, current_file_name));
+ write_error_details (current_file_name, check, written);
skip_file (size - written);
break;
}
free (*longp);
size = current_stat.st_size;
if (size != current_stat.st_size)
- FATAL_ERROR ((0, 0, _("Memory exhausted")));
+ xalloc_die ();
bp = *longp = xmalloc (size);
for (; size > 0; size -= written)
data_block = find_next_block ();
if (! data_block)
{
- ERROR ((0, 0, _("Unexpected EOF on archive file")));
+ ERROR ((0, 0, _("Unexpected EOF in archive")));
break;
}
written = available_space_after (data_block);
}
/* Parse the output of older, unportable tars, which generate
- negative values in two's complement octal. */
- if ((overflow || maxval < value) && '4' <= *where1)
+ negative values in two's complement octal. If the leading
+ nonzero digit is 1, we can't recover the original value
+ reliably; so do this only if the digit is 2 or more. This
+ catches the common case of 32-bit negative time stamps. */
+ if ((overflow || maxval < value) && '2' <= *where1)
{
/* Compute the negative of the input value, assuming two's
complement. */
- for (value = 0, where = where1, overflow = 0; ; )
+ int digit = (*where1 - '0') | 4;
+ overflow = 0;
+ value = 0;
+ where = where1;
+ for (;;)
{
- value += 7 - (*where++ - '0');
+ value += 7 - digit;
+ where++;
if (where == lim || ! ISODIGIT (*where))
break;
+ digit = *where - '0';
overflow |= value ^ (value << LG_8 >> LG_8);
value <<= LG_8;
}
if (!o)
{
o = clone_quoting_options (0);
- set_quoting_style (o, c_quoting_style);
+ set_quoting_style (o, locale_quoting_style);
}
while (where0 != lim && ! lim[-1])
lim--;
quotearg_buffer (buf, sizeof buf, where0, lim - where, o);
ERROR ((0, 0,
- _("Archive contains `%.*s' where numeric %s value expected"),
+ _("Archive contains %.*s where numeric %s value expected"),
(int) sizeof buf, buf, type));
}
/* Return a printable representation of T. The result points to
static storage that can be reused in the next call to this
function, to ctime, or to asctime. */
-static char const *
+char const *
tartime (time_t t)
{
static char buffer[max (UINTMAX_STRSIZE_BOUND + 1,
return p;
}
-/*-------------------------------------------------------------------------.
-| Decode MODE from its binary form in a stat structure, and encode it into |
-| a 9 characters string STRING, terminated with a NUL. |
-`-------------------------------------------------------------------------*/
-
-static void
-decode_mode (mode_t mode, char *string)
-{
- *string++ = mode & S_IRUSR ? 'r' : '-';
- *string++ = mode & S_IWUSR ? 'w' : '-';
- *string++ = (mode & S_ISUID
- ? (mode & S_IXUSR ? 's' : 'S')
- : (mode & S_IXUSR ? 'x' : '-'));
- *string++ = mode & S_IRGRP ? 'r' : '-';
- *string++ = mode & S_IWGRP ? 'w' : '-';
- *string++ = (mode & S_ISGID
- ? (mode & S_IXGRP ? 's' : 'S')
- : (mode & S_IXGRP ? 'x' : '-'));
- *string++ = mode & S_IROTH ? 'r' : '-';
- *string++ = mode & S_IWOTH ? 'w' : '-';
- *string++ = (mode & S_ISVTX
- ? (mode & S_IXOTH ? 't' : 'T')
- : (mode & S_IXOTH ? 'x' : '-'));
- *string = '\0';
-}
-
/*-------------------------------------------------------------------------.
| Actually print it. |
| |
/* holds formatted size or major,minor */
char uintbuf[UINTMAX_STRSIZE_BOUND];
int pad;
- char *name;
if (block_number_option)
{
if (verbose_option <= 1)
{
/* Just the fax, mam. */
-
- char *quoted_name = quote_copy_string (current_file_name);
-
- if (quoted_name)
- {
- fprintf (stdlis, "%s\n", quoted_name);
- free (quoted_name);
- }
- else
- fprintf (stdlis, "%s\n", current_file_name);
+ fprintf (stdlis, "%s\n", quotearg (current_file_name));
}
else
{
fprintf (stdlis, "%s %s/%s %*s%s %s",
modes, user, group, ugswidth - pad, "", size, time_stamp);
- name = quote_copy_string (current_file_name);
- if (name)
- {
- fprintf (stdlis, " %s", name);
- free (name);
- }
- else
- fprintf (stdlis, " %s", current_file_name);
+ fprintf (stdlis, " %s", quotearg (current_file_name));
switch (current_header->header.typeflag)
{
case SYMTYPE:
- name = quote_copy_string (current_link_name);
- if (name)
- {
- fprintf (stdlis, " -> %s\n", name);
- free (name);
- }
- else
- fprintf (stdlis, " -> %s\n", current_link_name);
+ fprintf (stdlis, " -> %s\n", quotearg (current_link_name));
break;
case LNKTYPE:
- name = quote_copy_string (current_link_name);
- if (name)
- {
- fprintf (stdlis, _(" link to %s\n"), name);
- free (name);
- }
- else
- fprintf (stdlis, _(" link to %s\n"), current_link_name);
+ fprintf (stdlis, _(" link to %s\n"), quotearg (current_link_name));
break;
default:
print_for_mkdir (char *pathname, int length, mode_t mode)
{
char modes[11];
- char *name;
if (verbose_option > 1)
{
fprintf (stdlis, _("block %s: "),
STRINGIFY_BIGINT (current_block_ordinal (), buf));
}
- name = quote_copy_string (pathname);
- if (name)
- {
- fprintf (stdlis, "%s %*s %.*s\n", modes, ugswidth + DATEWIDTH,
- _("Creating directory:"), length, name);
- free (name);
- }
- else
- fprintf (stdlis, "%s %*s %.*s\n", modes, ugswidth + DATEWIDTH,
- _("Creating directory:"), length, pathname);
+
+ fprintf (stdlis, "%s %*s %.*s\n", modes, ugswidth + DATEWIDTH,
+ _("Creating directory:"), length, quotearg (pathname));
}
}
{
x = find_next_block ();
if (! x)
- FATAL_ERROR ((0, 0, _("Unexpected EOF on archive file")));
+ FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
set_next_block_after (x);
size -= BLOCKSIZE;
{
exhdr = find_next_block ();
if (!exhdr)
- FATAL_ERROR ((0, 0, _("Unexpected EOF on archive file")));
+ FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
set_next_block_after (exhdr);
}
while (exhdr->sparse_header.isextended);