]> Dogcows Code - chaz/tar/blobdiff - src/list.c
Started merging with cpio into paxutils.
[chaz/tar] / src / list.c
index 5b06e80ecb9b7a27115fb5e5154934d25170918c..0e5e205f9a4f43feb8a7fa052c4a7509c733335a 100644 (file)
@@ -1,7 +1,7 @@
 /* List a tar archive, with support routines for reading a tar archive.
 
    Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
-   2001, 2003 Free Software Foundation, Inc.
+   2001, 2003, 2004 Free Software Foundation, Inc.
 
    Written by John Gilmore, on 1985-08-26.
 
@@ -22,7 +22,7 @@
 /* Define to non-zero for forcing old ctime format instead of ISO format.  */
 #undef USE_OLD_CTIME
 
-#include "system.h"
+#include <system.h>
 #include <quotearg.h>
 
 #include "common.h"
@@ -73,9 +73,12 @@ read_and (void (*do_something) (void))
   name_gather ();
   open_archive (ACCESS_READ);
 
-  while (1)
+  do
     {
       prev_status = status;
+      tar_stat_destroy (&current_stat_info);
+      xheader_destroy (&extended_header);
+
       status = read_header (false);
       switch (status)
        {
@@ -89,12 +92,17 @@ read_and (void (*do_something) (void))
             Ensure incoming names are null terminated.  */
 
          if (! name_match (current_stat_info.file_name)
-             || (newer_mtime_option != TYPE_MINIMUM (time_t)
+             || (NEWER_OPTION_INITIALIZED (newer_mtime_option)
                  /* FIXME: We get mtime now, and again later; this causes
                     duplicate diagnostics if header.mtime is bogus.  */
                  && ((current_stat_info.stat.st_mtime
-                      = TIME_FROM_HEADER (current_header->header.mtime))
-                     < newer_mtime_option))
+                      = TIME_FROM_HEADER (current_header->header.mtime)),
+#ifdef ST_MTIM_NSEC
+                     /* FIXME: Grab fractional time stamps from
+                        extended header.  */
+                     current_stat_info.stat.st_mtim.ST_MTIM_NSEC = 0,
+#endif
+                     OLDER_STAT_TIME (current_stat_info.stat, m)))
              || excluded_name (current_stat_info.file_name))
            {
              switch (current_header->header.typeflag)
@@ -110,10 +118,12 @@ read_and (void (*do_something) (void))
                           quotearg_colon (current_stat_info.file_name)));
                  /* Fall through.  */
                default:
+                 decode_header (current_header,
+                                &current_stat_info, &current_format, 0);
                  skip_member ();
                  continue;
                }
-             }
+           }
 
          (*do_something) ();
          continue;
@@ -127,10 +137,20 @@ read_and (void (*do_something) (void))
            }
 
          set_next_block_after (current_header);
+
+         if (!ignore_zeros_option)
+           {
+             char buf[UINTMAX_STRSIZE_BOUND];
+
+             status = read_header (false);
+             if (status == HEADER_ZERO_BLOCK)
+               break;
+             WARN ((0, 0, _("A lone zero block at %s"),
+                    STRINGIFY_BIGINT (current_block_ordinal (), buf)));
+             break;
+           }
          status = prev_status;
-         if (ignore_zeros_option)
-           continue;
-         break;
+         continue;
 
        case HEADER_END_OF_FILE:
          if (block_number_option)
@@ -153,6 +173,15 @@ read_and (void (*do_something) (void))
 
            case HEADER_ZERO_BLOCK:
            case HEADER_SUCCESS:
+             if (block_number_option)
+               {
+                 char buf[UINTMAX_STRSIZE_BOUND];
+                 off_t block_ordinal = current_block_ordinal ();
+                 block_ordinal -= recent_long_name_blocks;
+                 block_ordinal -= recent_long_link_blocks;
+                 fprintf (stdlis, _("block %s: "),
+                          STRINGIFY_BIGINT (block_ordinal, buf));
+               }
              ERROR ((0, 0, _("Skipping to next header")));
              break;
 
@@ -168,6 +197,7 @@ read_and (void (*do_something) (void))
        }
       break;
     }
+  while (!all_names_found (&current_stat_info));
 
   close_archive ();
   names_notfound ();           /* print names not found */
@@ -181,7 +211,7 @@ list_archive (void)
 
   decode_header (current_header, &current_stat_info, &current_format, 0);
   if (verbose_option)
-    print_header (-1);
+    print_header (&current_stat_info, -1);
 
   if (incremental_option && current_header->header.typeflag == GNUTYPE_DUMPDIR)
     {
@@ -342,7 +372,7 @@ read_header (bool raw_extended_headers)
                xalloc_die ();
 
              header_copy = xmalloc (size + 1);
-             
+
              if (header->header.typeflag == GNUTYPE_LONGNAME)
                {
                  if (next_long_name)
@@ -357,7 +387,7 @@ read_header (bool raw_extended_headers)
                  next_long_link = header_copy;
                  next_long_link_blocks = size / BLOCKSIZE;
                }
-             
+
              set_next_block_after (header);
              *header_copy = *header;
              bp = header_copy->buffer + BLOCKSIZE;
@@ -373,7 +403,7 @@ read_header (bool raw_extended_headers)
                  written = available_space_after (data_block);
                  if (written > size)
                    written = size;
-                 
+
                  memcpy (bp, data_block->buffer, written);
                  bp += written;
                  set_next_block_after ((union block *)
@@ -382,10 +412,14 @@ read_header (bool raw_extended_headers)
 
              *bp = '\0';
            }
-         else if (header->header.typeflag == XHDTYPE
-                  || header->header.typeflag == XGLTYPE)
+         else if (header->header.typeflag == XHDTYPE)
            xheader_read (header, OFF_FROM_HEADER (header->header.size));
-      
+         else if (header->header.typeflag == XGLTYPE)
+           {
+             xheader_read (header, OFF_FROM_HEADER (header->header.size));
+             xheader_decode_global ();
+           }
+
          /* Loop!  */
 
        }
@@ -485,8 +519,10 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
          && ISOCTAL (header->star_header.ctime[0])
          && header->star_header.ctime[11] == ' ')
        format = STAR_FORMAT;
-      else
+      else if (extended_header.size)
        format = POSIX_FORMAT;
+      else
+       format = USTAR_FORMAT;
     }
   else if (strcmp (header->header.magic, OLDGNU_MAGIC) == 0)
     format = OLDGNU_FORMAT;
@@ -500,7 +536,10 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
   assign_string (&stat_info->gname, header->header.gname);
   stat_info->devmajor = MAJOR_FROM_HEADER (header->header.devmajor);
   stat_info->devminor = MINOR_FROM_HEADER (header->header.devminor);
-  
+
+  stat_info->stat.st_atime = start_time;
+  stat_info->stat.st_ctime = start_time;
+
   if (format == OLDGNU_FORMAT && incremental_option)
     {
       stat_info->stat.st_atime = TIME_FROM_HEADER (header->oldgnu_header.atime);
@@ -536,12 +575,13 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
              || !gname_to_gid (header->header.gname, &stat_info->stat.st_gid))
            stat_info->stat.st_gid = GID_FROM_HEADER (header->header.gid);
        }
-      
+
       switch (header->header.typeflag)
        {
        case BLKTYPE:
        case CHRTYPE:
-         stat_info->stat.st_rdev = makedev (stat_info->devmajor, stat_info->devminor);
+         stat_info->stat.st_rdev = makedev (stat_info->devmajor,
+                                            stat_info->devminor);
          break;
 
        default:
@@ -549,8 +589,16 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
        }
     }
 
-  if (extended_header.size)
-    xheader_decode (stat_info);
+  stat_info->archive_file_size = stat_info->stat.st_size;
+  xheader_decode (stat_info);
+
+  if (sparse_member_p (stat_info))
+    {
+      sparse_fixup_header (stat_info);
+      stat_info->is_sparse = true;
+    }
+  else
+    stat_info->is_sparse = false;
 }
 
 /* Convert buffer at WHERE0 of size DIGS from external format to
@@ -877,7 +925,7 @@ tartime (time_t t)
 #else
   /* Use ISO 8610 format.  See:
      http://www.cl.cam.ac.uk/~mgk25/iso-time.html  */
-  struct tm *tm = localtime (&t);
+  struct tm *tm = utc_option ? gmtime (&t) : localtime (&t);
   if (tm)
     {
       sprintf (buffer, "%04ld-%02d-%02d %02d:%02d:%02d",
@@ -926,12 +974,12 @@ static int ugswidth = UGSWIDTH;   /* maximum width encountered so far */
 #endif
 
 void
-print_header (off_t block_ordinal)
+print_header (struct tar_stat_info *st, off_t block_ordinal)
 {
   char modes[11];
   char const *time_stamp;
-  char *temp_name = current_stat_info.orig_file_name ? current_stat_info.orig_file_name : current_stat_info.file_name;
-  
+  char *temp_name = st->orig_file_name ? st->orig_file_name : st->file_name;
+
   /* These hold formatted ints.  */
   char uform[UINTMAX_STRSIZE_BOUND], gform[UINTMAX_STRSIZE_BOUND];
   char *user, *group;
@@ -1014,17 +1062,17 @@ print_header (off_t block_ordinal)
          break;
        }
 
-      decode_mode (current_stat_info.stat.st_mode, modes + 1);
+      decode_mode (st->stat.st_mode, modes + 1);
 
       /* Time stamp.  */
 
-      time_stamp = tartime (current_stat_info.stat.st_mtime);
+      time_stamp = tartime (st->stat.st_mtime);
 
       /* User and group names.  */
 
-      if (current_stat_info.uname && current_format != V7_FORMAT
+      if (st->uname && current_format != V7_FORMAT
          && !numeric_owner_option)
-       user = current_stat_info.uname;
+       user = st->uname;
       else
        {
          /* Try parsing it as an unsigned integer first, and as a
@@ -1044,9 +1092,9 @@ print_header (off_t block_ordinal)
            }
        }
 
-      if (current_stat_info.gname && current_format != V7_FORMAT
+      if (st->gname && current_format != V7_FORMAT
          && !numeric_owner_option)
-       group = current_stat_info.gname;
+       group = st->gname;
       else
        {
          /* Try parsing it as an unsigned integer first, and as a
@@ -1073,20 +1121,15 @@ print_header (off_t block_ordinal)
        case CHRTYPE:
        case BLKTYPE:
          strcpy (size,
-                 STRINGIFY_BIGINT (major (current_stat_info.stat.st_rdev), uintbuf));
+                 STRINGIFY_BIGINT (major (st->stat.st_rdev), uintbuf));
          strcat (size, ",");
          strcat (size,
-                 STRINGIFY_BIGINT (minor (current_stat_info.stat.st_rdev), uintbuf));
-         break;
-       case GNUTYPE_SPARSE:
-         strcpy (size,
-                 STRINGIFY_BIGINT
-                 (UINTMAX_FROM_HEADER (current_header
-                                       ->oldgnu_header.realsize),
-                  uintbuf));
+                 STRINGIFY_BIGINT (minor (st->stat.st_rdev), uintbuf));
          break;
+
        default:
-         strcpy (size, STRINGIFY_BIGINT (current_stat_info.stat.st_size, uintbuf));
+         /* st->stat.st_size keeps stored file size */
+         strcpy (size, STRINGIFY_BIGINT (st->stat.st_size, uintbuf));
          break;
        }
 
@@ -1104,11 +1147,11 @@ print_header (off_t block_ordinal)
       switch (current_header->header.typeflag)
        {
        case SYMTYPE:
-         fprintf (stdlis, " -> %s\n", quotearg (current_stat_info.link_name));
+         fprintf (stdlis, " -> %s\n", quotearg (st->link_name));
          break;
 
        case LNKTYPE:
-         fprintf (stdlis, _(" link to %s\n"), quotearg (current_stat_info.link_name));
+         fprintf (stdlis, _(" link to %s\n"), quotearg (st->link_name));
          break;
 
        default:
@@ -1163,7 +1206,7 @@ print_header (off_t block_ordinal)
 
 /* Print a similar line when we make a directory automatically.  */
 void
-print_for_mkdir (char *pathname, int length, mode_t mode)
+print_for_mkdir (char *dirname, int length, mode_t mode)
 {
   char modes[11];
 
@@ -1182,7 +1225,7 @@ print_for_mkdir (char *pathname, int length, mode_t mode)
        }
 
       fprintf (stdlis, "%s %*s %.*s\n", modes, ugswidth + DATEWIDTH,
-              _("Creating directory:"), length, quotearg (pathname));
+              _("Creating directory:"), length, quotearg (dirname));
     }
 }
 
@@ -1198,6 +1241,19 @@ skip_file (off_t size)
       save_sizeleft = size;
     }
 
+  if (seekable_archive)
+    {
+      off_t nblk = seek_archive (size);
+      if (nblk >= 0)
+       {
+         size -= nblk * BLOCKSIZE;
+         if (multi_volume_option) /* Argh.. */
+           save_sizeleft -= nblk * BLOCKSIZE;
+       }
+      else
+       seekable_archive = false;
+    }
+  
   while (size > 0)
     {
       x = find_next_block ();
@@ -1211,27 +1267,18 @@ skip_file (off_t size)
     }
 }
 
-/* Skip the current member in the archive.  */
+/* Skip the current member in the archive.
+   NOTE: Current header must be decoded before calling this function. */
 void
 skip_member (void)
 {
   char save_typeflag = current_header->header.typeflag;
   set_next_block_after (current_header);
+  
+  assign_string (&save_name, current_stat_info.file_name);
 
-  if (current_format == OLDGNU_FORMAT
-      && current_header->oldgnu_header.isextended)
-    {
-      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);
-    }
-
-  if (save_typeflag != DIRTYPE)
+  if (current_stat_info.is_sparse)
+    sparse_skip_file (&current_stat_info);
+  else if (save_typeflag != DIRTYPE)
     skip_file (current_stat_info.stat.st_size);
 }
This page took 0.038291 seconds and 4 git commands to generate.