]> Dogcows Code - chaz/tar/blobdiff - src/list.c
(tar_checksum): New function
[chaz/tar] / src / list.c
index 3166e686c1ca43970807805f75da15a87204a004..0d96e8bb67eaef9d9e4ab05552e57c771838b1da 100644 (file)
@@ -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"
@@ -118,6 +118,8 @@ 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;
                }
@@ -264,6 +266,61 @@ list_archive (void)
     assign_string (&save_name, 0);
 }
 
+/* Check header checksum */
+/* 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
+   on the PDP-11, but it's signed on the Next and Sun.  It looks like the
+   sources to BSD tar were never changed to compute the checksum
+   correctly, so both the Sun and Next add the bytes of the header as
+   signed chars.  This doesn't cause a problem until you get a file with
+   a name containing characters with the high bit set.  So tar_checksum
+   computes two checksums -- signed and unsigned.  */
+
+enum read_header
+tar_checksum (union block *header)
+{
+  size_t i;
+  int unsigned_sum = 0;                /* the POSIX one :-) */
+  int signed_sum = 0;          /* the Sun one :-( */
+  int recorded_sum;
+  uintmax_t parsed_sum;
+  char *p;
+  
+  p = header->buffer;
+  for (i = sizeof *header; i-- != 0;)
+    {
+      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 -= (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;
+
+  parsed_sum = from_header (header->header.chksum,
+                           sizeof header->header.chksum, 0,
+                           (uintmax_t) 0,
+                           (uintmax_t) TYPE_MAXIMUM (int));
+  if (parsed_sum == (uintmax_t) -1)
+    return HEADER_FAILURE;
+
+  recorded_sum = parsed_sum;
+  
+  if (unsigned_sum != recorded_sum && signed_sum != recorded_sum)
+    return HEADER_FAILURE;
+
+  return HEADER_SUCCESS;
+}
+
 /* 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_info.stat.st_size.
@@ -277,23 +334,9 @@ list_archive (void)
    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
-   on the PDP-11, but it's signed on the Next and Sun.  It looks like the
-   sources to BSD tar were never changed to compute the checksum
-   correctly, so both the Sun and Next add the bytes of the header as
-   signed chars.  This doesn't cause a problem until you get a file with
-   a name containing characters with the high bit set.  So read_header
-   computes two checksums -- signed and unsigned.  */
-
 enum read_header
 read_header (bool raw_extended_headers)
 {
-  size_t i;
-  int unsigned_sum;            /* the POSIX one :-) */
-  int signed_sum;              /* the Sun one :-( */
-  int recorded_sum;
-  uintmax_t parsed_sum;
   char *p;
   union block *header;
   union block *header_copy;
@@ -307,44 +350,15 @@ read_header (bool raw_extended_headers)
 
   while (1)
     {
+      enum read_header status;
+      
       header = find_next_block ();
       current_header = header;
       if (!header)
        return HEADER_END_OF_FILE;
 
-      unsigned_sum = 0;
-      signed_sum = 0;
-      p = header->buffer;
-      for (i = sizeof *header; i-- != 0;)
-       {
-         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 -= (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;
-
-      parsed_sum = from_header (header->header.chksum,
-                               sizeof header->header.chksum, 0,
-                               (uintmax_t) 0,
-                               (uintmax_t) TYPE_MAXIMUM (int));
-      if (parsed_sum == (uintmax_t) -1)
-       return HEADER_FAILURE;
-
-      recorded_sum = parsed_sum;
-
-      if (unsigned_sum != recorded_sum && signed_sum != recorded_sum)
-       return HEADER_FAILURE;
+      if ((status = tar_checksum (header)) != HEADER_SUCCESS)
+       return status;
 
       /* Good block.  Decode file size and return.  */
 
@@ -530,8 +544,10 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
 
   stat_info->stat.st_mode = MODE_FROM_HEADER (header->header.mode);
   stat_info->stat.st_mtime = TIME_FROM_HEADER (header->header.mtime);
-  assign_string (&stat_info->uname, header->header.uname);
-  assign_string (&stat_info->gname, header->header.gname);
+  assign_string (&stat_info->uname,
+                header->header.uname[0] ? header->header.uname : NULL);
+  assign_string (&stat_info->gname,
+                header->header.gname[0] ? header->header.gname : NULL);
   stat_info->devmajor = MAJOR_FROM_HEADER (header->header.devmajor);
   stat_info->devminor = MINOR_FROM_HEADER (header->header.devminor);
 
@@ -595,6 +611,8 @@ decode_header (union block *header, struct tar_stat_info *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
@@ -1263,16 +1281,17 @@ 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 (sparse_member_p (&current_stat_info))
+  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.02553 seconds and 4 git commands to generate.