]> Dogcows Code - chaz/tar/blobdiff - src/list.c
Use shorter message.
[chaz/tar] / src / list.c
index b118f887265468c9c1d9e15fb14cd30e47718dbc..7c7061a899722b88b5e3492f70b424e510a88850 100644 (file)
@@ -1,5 +1,5 @@
 /* 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,2001 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
 #include "system.h"
 #include <quotearg.h>
 
-#include <time.h>
-#ifndef time
-time_t time ();
-#endif
-
 #include "common.h"
 
 #define max(a, b) ((a) < (b) ? (b) : (a))
@@ -61,10 +56,7 @@ base64_init (void)
     base64_map[(int) base_64_digits[i]] = i;
 }
 
-/*-----------------------------------.
-| Main loop for reading an archive.  |
-`-----------------------------------*/
-
+/* Main loop for reading an archive.  */
 void
 read_and (void (*do_something) ())
 {
@@ -89,42 +81,32 @@ read_and (void (*do_something) ())
          /* 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)
+             switch (current_header->header.typeflag)
                {
-                 (*do_something) ();
+               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_member ();
                  continue;
                }
-             if (show_omitted_dirs_option
-                 && current_header->header.typeflag == DIRTYPE)
-               WARN ((0, 0, _("Omitting %s"), current_file_name));
-
-             /* 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 ();
-
-             /* Skip to the next header on the archive.  */
-
-             if (save_typeflag != DIRTYPE)
-               skip_file (current_stat.st_size);
-             continue;
-           }
+             }
 
          (*do_something) ();
          continue;
@@ -177,15 +159,11 @@ read_and (void (*do_something) ())
       break;
     }
 
-  apply_delayed_set_stat ();
   close_archive ();
   names_notfound ();           /* print names not found */
 }
 
-/*---------------------------------------------.
-| Print a header block, based on tar options.  |
-`---------------------------------------------*/
-
+/* Print a header block, based on tar options.  */
 void
 list_archive (void)
 {
@@ -217,7 +195,7 @@ list_archive (void)
          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);
@@ -229,9 +207,7 @@ list_archive (void)
                                (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;
            }
@@ -244,34 +220,24 @@ list_archive (void)
 
     }
 
-  /* Skip past the header in the archive, and past any extended headers.  */
-
-  set_next_block_after (current_header);
-  if (current_header->oldgnu_header.isextended)
-    skip_extended_headers ();
-
   if (multi_volume_option)
     assign_string (&save_name, current_file_name);
 
-  /* Skip to the next header on the archive.  */
-
-  skip_file (current_stat.st_size);
+  skip_member ();
 
   if (multi_volume_option)
     assign_string (&save_name, 0);
 }
 
-/*-----------------------------------------------------------------------.
-| 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.st_size.                                                  |
-|                                                                        |
-| Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a    |
-| block full of zeros (EOF marker).                                      |
-|                                                                        |
-| You must always set_next_block_after(current_header) to skip past the  |
-| header which this routine reads.                                       |
-`-----------------------------------------------------------------------*/
+/* 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.st_size.
+
+   Return 1 for success, 0 if the checksum is bad, EOF on eof, 2 for a
+   block full of zeros (EOF marker).
+
+   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
@@ -311,7 +277,7 @@ read_header (void)
       for (i = sizeof *header; i-- != 0;)
        {
          unsigned_sum += (unsigned char) *p;
-         signed_sum += signed_char (*p++);
+         signed_sum += (signed char) (*p++);
        }
 
       if (unsigned_sum == 0)
@@ -322,7 +288,7 @@ read_header (void)
       for (i = sizeof header->header.chksum; i-- != 0;)
        {
          unsigned_sum -= (unsigned char) header->header.chksum[i];
-         signed_sum -= signed_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;
@@ -358,7 +324,7 @@ read_header (void)
            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)
@@ -366,7 +332,7 @@ read_header (void)
              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);
@@ -384,8 +350,8 @@ read_header (void)
        }
       else
        {
-         char *name;
-         struct posix_header *h = &current_header->header;
+         char const *name;
+         struct posix_header const *h = &current_header->header;
          char namebuf[sizeof h->prefix + 1 + NAME_FIELD_SIZE + 1];
 
          name = next_long_name;
@@ -393,15 +359,19 @@ read_header (void)
            {
              /* Accept file names as specified by POSIX.1-1996
                  section 10.1.1.  */
-             int posix_header = strcmp (h->magic, TMAGIC) == 0;
              char *np = namebuf;
 
-             if (posix_header && h->prefix[0])
+             if (h->prefix[0] && strcmp (h->magic, TMAGIC) == 0)
                {
                  memcpy (np, h->prefix, sizeof h->prefix);
                  np[sizeof h->prefix] = '\0';
                  np += strlen (np);
                  *np++ = '/';
+
+                 /* Prevent later references to current_header from
+                    mistakenly treating this as an old GNU header.
+                    This assignment invalidates h->prefix.  */
+                 current_header->oldgnu_header.isextended = 0;
                }
              memcpy (np, h->name, sizeof h->name);
              np[sizeof h->name] = '\0';
@@ -433,22 +403,19 @@ read_header (void)
     }
 }
 
-/*-------------------------------------------------------------------------.
-| Decode things from a file HEADER block into STAT_INFO, also setting     |
-| *FORMAT_POINTER depending on the header block format.  If DO_USER_GROUP, |
-| decode the user/group information (this is useful for extraction, but           |
-| waste time when merely listing).                                        |
-|                                                                         |
-| read_header() has already decoded the checksum and length, so we don't.  |
-|                                                                         |
-| This routine should *not* be called twice for the same block, since the  |
-| two calls might use different DO_USER_GROUP values and thus might end up |
-| with different uid/gid for the two calls.  If anybody wants the uid/gid  |
-| they should decode it first, and other callers should decode it without  |
-| uid/gid before calling a routine, e.g. print_header, that assumes       |
-| decoded data.                                                                   |
-`-------------------------------------------------------------------------*/
+/* Decode things from a file HEADER block into STAT_INFO, also setting
+   *FORMAT_POINTER depending on the header block format.  If
+   DO_USER_GROUP, decode the user/group information (this is useful
+   for extraction, but waste time when merely listing).
 
+   read_header() has already decoded the checksum and length, so we don't.
+
+   This routine should *not* be called twice for the same block, since
+   the two calls might use different DO_USER_GROUP values and thus
+   might end up with different uid/gid for the two calls.  If anybody
+   wants the uid/gid they should decode it first, and other callers
+   should decode it without uid/gid before calling a routine,
+   e.g. print_header, that assumes decoded data.  */
 void
 decode_header (union block *header, struct stat *stat_info,
               enum archive_format *format_pointer, int do_user_group)
@@ -514,12 +481,10 @@ decode_header (union block *header, struct stat *stat_info,
     }
 }
 
-/*------------------------------------------------------------------------.
-| Convert buffer at WHERE0 of size DIGS from external format to uintmax_t.|
-| The data is of type TYPE.  The buffer must represent a value in the     |
-| range -MINUS_MINVAL through MAXVAL.  DIGS must be positive.            |
-`------------------------------------------------------------------------*/
-
+/* Convert buffer at WHERE0 of size DIGS from external format to
+   uintmax_t.  The data is of type TYPE.  The buffer must represent a
+   value in the range -MINUS_MINVAL through MAXVAL.  DIGS must be
+   positive.  */
 static uintmax_t
 from_header (char const *where0, size_t digs, char const *type,
             uintmax_t minus_minval, uintmax_t maxval)
@@ -631,9 +596,12 @@ from_header (char const *where0, size_t digs, char const *type,
            {
              if (value << LG_64 >> LG_64 != value)
                {
+                 char *string = alloca (digs + 1);
+                 memcpy (string, where0, digs);
+                 string[digs] = '\0';
                  ERROR ((0, 0,
-                         _("Archive signed base-64 string `%.*s' is out of %s range"),
-                         (int) digs, where0, type));
+                         _("Archive signed base-64 string %s is out of %s range"),
+                         quote (string), type));
                  return -1;
                }
              value = (value << LG_64) | dig;
@@ -683,14 +651,14 @@ from_header (char const *where0, size_t digs, char const *type,
          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));
        }
 
@@ -783,12 +751,9 @@ size_from_header (const char *p, size_t s)
 time_t
 time_from_header (const char *p, size_t s)
 {
-  time_t t = from_header (p, s, "time_t",
-                         - (uintmax_t) TYPE_MINIMUM (time_t),
-                         (uintmax_t) TYPE_MAXIMUM (time_t));
-  if (start_time < t && time (0) < t)
-    WARN ((0, 0, _("Archive contains future timestamp %s"), tartime (t)));
-  return t;
+  return from_header (p, s, "time_t",
+                     - (uintmax_t) TYPE_MINIMUM (time_t),
+                     (uintmax_t) TYPE_MAXIMUM (time_t));
 }
 
 uid_t
@@ -807,10 +772,8 @@ uintmax_from_header (const char *p, size_t s)
 }
 
 
-/*----------------------------------------------------------------------.
-| Format O as a null-terminated decimal string into BUF _backwards_;   |
-| return pointer to start of result.                                   |
-`----------------------------------------------------------------------*/
+/* Format O as a null-terminated decimal string into BUF _backwards_;
+   return pointer to start of result.  */
 char *
 stringify_uintmax_t_backwards (uintmax_t o, char *buf)
 {
@@ -836,8 +799,8 @@ tartime (time_t t)
   if (p)
     {
       char const *time_stamp = p + 4;
-      for (p += 16; p[4] != '\n'; p++)
-       p[0] = p[4];
+      for (p += 16; p[3] != '\n'; p++)
+       p[0] = p[3];
       p[0] = '\0';
       return time_stamp;
     }
@@ -867,42 +830,15 @@ tartime (time_t t)
   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.                     |
-`-------------------------------------------------------------------------*/
+/* Actually print it.
 
-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';
-}
+   Plain and fancy file header block logging.  Non-verbose just prints
+   the name, e.g. for "tar t" or "tar x".  This should just contain
+   file names, so it can be fed back into tar with xargs or the "-T"
+   option.  The verbose option can give a bunch of info, one line per
+   file.  I doubt anybody tries to parse its format, or if they do,
+   they shouldn't.  Unix tar is pretty random here anyway.  */
 
-/*-------------------------------------------------------------------------.
-| Actually print it.                                                      |
-|                                                                         |
-| Plain and fancy file header block logging.  Non-verbose just prints the  |
-| name, e.g. for "tar t" or "tar x".  This should just contain file names, |
-| so it can be fed back into tar with xargs or the "-T" option.  The      |
-| verbose option can give a bunch of info, one line per file.  I doubt    |
-| anybody tries to parse its format, or if they do, they shouldn't.  Unix  |
-| tar is pretty random here anyway.                                       |
-`-------------------------------------------------------------------------*/
 
 /* FIXME: Note that print_header uses the globals HEAD, HSTAT, and
    HEAD_STANDARD, which must be set up in advance.  Not very clean...  */
@@ -931,7 +867,6 @@ print_header (void)
                                /* holds formatted size or major,minor */
   char uintbuf[UINTMAX_STRSIZE_BOUND];
   int pad;
-  char *name;
 
   if (block_number_option)
     {
@@ -943,16 +878,7 @@ print_header (void)
   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
     {
@@ -1066,42 +992,26 @@ print_header (void)
       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:
-         fprintf (stdlis, _(" unknown file type `%c'\n"),
-                  current_header->header.typeflag);
+         {
+           char type_string[2];
+           type_string[0] = current_header->header.typeflag;
+           type_string[1] = '\0';
+           fprintf (stdlis, _(" unknown file type %s\n"),
+                    quote (type_string));
+         }
          break;
 
        case AREGTYPE:
@@ -1136,15 +1046,11 @@ print_header (void)
   fflush (stdlis);
 }
 
-/*--------------------------------------------------------------.
-| Print a similar line when we make a directory automatically.  |
-`--------------------------------------------------------------*/
-
+/* Print a similar line when we make a directory automatically.  */
 void
 print_for_mkdir (char *pathname, int length, mode_t mode)
 {
   char modes[11];
-  char *name;
 
   if (verbose_option > 1)
     {
@@ -1159,23 +1065,13 @@ print_for_mkdir (char *pathname, int length, mode_t mode)
          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));
     }
 }
 
-/*--------------------------------------------------------.
-| Skip over SIZE bytes of data in blocks in the archive.  |
-`--------------------------------------------------------*/
-
+/* Skip over SIZE bytes of data in blocks in the archive.  */
 void
 skip_file (off_t size)
 {
@@ -1191,7 +1087,7 @@ skip_file (off_t size)
     {
       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;
@@ -1200,21 +1096,26 @@ skip_file (off_t size)
     }
 }
 
-/*---.
-| ?  |
-`---*/
-
+/* Skip the current member in the archive.  */
 void
-skip_extended_headers (void)
+skip_member (void)
 {
-  union block *exhdr;
+  char save_typeflag = current_header->header.typeflag;
+  set_next_block_after (current_header);
 
-  do
+  if (current_header->oldgnu_header.isextended)
     {
-      exhdr = find_next_block ();
-      if (!exhdr)
-       FATAL_ERROR ((0, 0, _("Unexpected EOF on archive file")));
-      set_next_block_after (exhdr);
+      union block *exhdr;
+      do
+       {
+         exhdr = find_next_block ();
+         if (!exhdr)
+           FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
+         set_next_block_after (exhdr);
+       }
+      while (exhdr->sparse_header.isextended);
     }
-  while (exhdr->sparse_header.isextended);
+
+  if (save_typeflag != DIRTYPE)
+    skip_file (current_stat.st_size);
 }
This page took 0.034872 seconds and 4 git commands to generate.