]> Dogcows Code - chaz/tar/blobdiff - src/compare.c
Use current_stat_info
[chaz/tar] / src / compare.c
index d4871c44350d9bb4d88c28390d75196f27775481..6124c95af343f35142041cb21123012eb9246bb1 100644 (file)
@@ -1,5 +1,8 @@
 /* Diff files from a tar archive.
-   Copyright (C) 1988, 92, 93, 94, 96, 97 Free Software Foundation, Inc.
+
+   Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
+   2003 Free Software Foundation, Inc.
+
    Written by John Gilmore, on 1987-04-30.
 
    This program is free software; you can redistribute it and/or modify it
 
    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
-   59 Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "system.h"
 
+#if HAVE_UTIME_H
+# include <utime.h>
+#else
+struct utimbuf
+  {
+    long actime;
+    long modtime;
+  };
+#endif
+
 #if HAVE_LINUX_FD_H
 # include <linux/fd.h>
 #endif
 
+#include <quotearg.h>
+
 #include "common.h"
 #include "rmt.h"
 
 #define MESSAGE_BUFFER_SIZE 100
 
 /* Nonzero if we are verifying at the moment.  */
-int now_verifying = 0;
+bool now_verifying;
 
 /* File descriptor for the file we are diffing.  */
 static int diff_handle;
 
 /* Area for reading file contents into.  */
-static char *diff_buffer = NULL;
-
-/*--------------------------------.
-| Initialize for a diff operation |
-`--------------------------------*/
+static char *diff_buffer;
 
+/* Initialize for a diff operation.  */
 void
 diff_init (void)
 {
-  diff_buffer = (char *) valloc ((unsigned) record_size);
+  diff_buffer = valloc (record_size);
   if (!diff_buffer)
-    FATAL_ERROR ((0, 0,
-                 _("Could not allocate memory for diff buffer of %d bytes"),
-                 record_size));
+    xalloc_die ();
 }
 
-/*------------------------------------------------------------------------.
-| Sigh about something that differs by writing a MESSAGE to stdlis, given |
-| MESSAGE is not NULL.  Also set the exit status if not already.          |
-`------------------------------------------------------------------------*/
-
+/* Sigh about something that differs by writing a MESSAGE to stdlis,
+   given MESSAGE is nonzero.  Also set the exit status if not already.  */
 static void
 report_difference (const char *message)
 {
   if (message)
-    fprintf (stdlis, "%s: %s\n", current_file_name, message);
+    fprintf (stdlis, "%s: %s\n", quotearg_colon (current_stat_info.file_name), message);
 
   if (exit_status == TAREXIT_SUCCESS)
     exit_status = TAREXIT_DIFFERS;
 }
 
-/*-----------------------------------------------------------------------.
-| Takes a buffer returned by read_and_process and does nothing with it.         |
-`-----------------------------------------------------------------------*/
-
-/* Yes, I know.  SIZE and DATA are unused in this function.  Some compilers
-   may even report it.  That's OK, just relax!  */
-
+/* Take a buffer returned by read_and_process and do nothing with it.  */
 static int
-process_noop (long size, char *data)
+process_noop (size_t size, char *data)
 {
+  /* Yes, I know.  SIZE and DATA are unused in this function.  Some
+     compilers may even report it.  That's OK, just relax!  */
   return 1;
 }
 
-/*---.
-| ?  |
-`---*/
-
 static int
-process_rawdata (long bytes, char *buffer)
+process_rawdata (size_t bytes, char *buffer)
 {
-  int status = read (diff_handle, diff_buffer, (size_t) bytes);
+  ssize_t status = safe_read (diff_handle, diff_buffer, bytes);
   char message[MESSAGE_BUFFER_SIZE];
 
   if (status != bytes)
     {
       if (status < 0)
        {
-         WARN ((0, errno, _("Cannot read %s"), current_file_name));
-         report_difference (NULL);
+         read_error (current_stat_info.file_name);
+         report_difference (0);
        }
       else
        {
-         sprintf (message, _("Could only read %d of %ld bytes"),
-                  status, bytes);
+         sprintf (message, _("Could only read %lu of %lu bytes"),
+                  (unsigned long) status, (unsigned long) bytes);
          report_difference (message);
        }
       return 0;
     }
 
-  if (memcmp (buffer, diff_buffer, (size_t) bytes))
+  if (memcmp (buffer, diff_buffer, bytes))
     {
-      report_difference (_("Data differs"));
+      report_difference (_("Contents differ"));
       return 0;
     }
 
   return 1;
 }
 
-/*---.
-| ?  |
-`---*/
-
 /* Directory contents, only for GNUTYPE_DUMPDIR.  */
 
 static char *dumpdir_cursor;
 
 static int
-process_dumpdir (long bytes, char *buffer)
+process_dumpdir (size_t bytes, char *buffer)
 {
-  if (memcmp (buffer, dumpdir_cursor, (size_t) bytes))
+  if (memcmp (buffer, dumpdir_cursor, bytes))
     {
-      report_difference (_("Data differs"));
+      report_difference (_("Contents differ"));
       return 0;
     }
 
@@ -135,28 +130,25 @@ process_dumpdir (long bytes, char *buffer)
   return 1;
 }
 
-/*------------------------------------------------------------------------.
-| Some other routine wants SIZE bytes in the archive.  For each chunk of  |
-| the archive, call PROCESSOR with the size of the chunk, and the address |
-| of the chunk it can work with.  The PROCESSOR should return nonzero for |
-| success.  It it return error once, continue skipping without calling    |
-| PROCESSOR anymore.                                                      |
-`------------------------------------------------------------------------*/
-
+/* Some other routine wants SIZE bytes in the archive.  For each chunk
+   of the archive, call PROCESSOR with the size of the chunk, and the
+   address of the chunk it can work with.  The PROCESSOR should return
+   nonzero for success.  It it return error once, continue skipping
+   without calling PROCESSOR anymore.  */
 static void
-read_and_process (long size, int (*processor) (long, char *))
+read_and_process (off_t size, int (*processor) (size_t, char *))
 {
   union block *data_block;
-  long data_size;
+  size_t data_size;
 
   if (multi_volume_option)
     save_sizeleft = size;
   while (size)
     {
       data_block = find_next_block ();
-      if (data_block == NULL)
+      if (! data_block)
        {
-         ERROR ((0, 0, _("Unexpected EOF on archive file")));
+         ERROR ((0, 0, _("Unexpected EOF in archive")));
          return;
        }
 
@@ -173,98 +165,9 @@ read_and_process (long size, int (*processor) (long, char *))
     }
 }
 
-/*---.
-| ?  |
-`---*/
-
-/* JK This routine should be used more often than it is ... look into
-   that.  Anyhow, what it does is translate the sparse information on the
-   header, and in any subsequent extended headers, into an array of
-   structures with true numbers, as opposed to character strings.  It
-   simply makes our life much easier, doing so many comparisong and such.
-   */
-
-static void
-fill_in_sparse_array (void)
-{
-  int counter;
-
-  /* Allocate space for our scratch space; it's initially 10 elements
-     long, but can change in this routine if necessary.  */
-
-  sp_array_size = 10;
-  sparsearray = (struct sp_array *) xmalloc (sp_array_size * sizeof (struct sp_array));
-
-  /* There are at most five of these structures in the header itself;
-     read these in first.  */
-
-  for (counter = 0; counter < SPARSES_IN_OLDGNU_HEADER; counter++)
-    {
-      /* Compare to 0, or use !(int)..., for Pyramid's dumb compiler.  */
-      if (current_header->oldgnu_header.sp[counter].numbytes == 0)
-       break;
-
-      sparsearray[counter].offset =
-       from_oct (1 + 12, current_header->oldgnu_header.sp[counter].offset);
-      sparsearray[counter].numbytes =
-       from_oct (1 + 12, current_header->oldgnu_header.sp[counter].numbytes);
-    }
-
-  /* If the header's extended, we gotta read in exhdr's till we're done.  */
-
-  if (current_header->oldgnu_header.isextended)
-    {
-      /* How far into the sparsearray we are `so far'.  */
-      static int so_far_ind = SPARSES_IN_OLDGNU_HEADER;
-      union block *exhdr;
-
-      while (1)
-       {
-         exhdr = find_next_block ();
-         for (counter = 0; counter < SPARSES_IN_SPARSE_HEADER; counter++)
-           {
-             if (counter + so_far_ind > sp_array_size - 1)
-               {
-                 /* We just ran out of room in our scratch area -
-                    realloc it.  */
-
-                 sp_array_size *= 2;
-                 sparsearray = (struct sp_array *)
-                   xrealloc (sparsearray,
-                             sp_array_size * sizeof (struct sp_array));
-               }
-
-             /* Convert the character strings into longs.  */
-
-             sparsearray[counter + so_far_ind].offset =
-               from_oct (1 + 12, exhdr->sparse_header.sp[counter].offset);
-             sparsearray[counter + so_far_ind].numbytes =
-               from_oct (1 + 12, exhdr->sparse_header.sp[counter].numbytes);
-           }
-
-         /* If this is the last extended header for this file, we can
-            stop.  */
-
-         if (!exhdr->sparse_header.isextended)
-           break;
-
-         so_far_ind += SPARSES_IN_SPARSE_HEADER;
-         set_next_block_after (exhdr);
-       }
-
-      /* Be sure to skip past the last one.  */
-
-      set_next_block_after (exhdr);
-    }
-}
-
-/*---.
-| ?  |
-`---*/
-
 /* JK Diff'ing a sparse file with its counterpart on the tar file is a
    bit of a different story than a normal file.  First, we must know what
-   areas of the file to skip through, i.e., we need to contruct a
+   areas of the file to skip through, i.e., we need to construct a
    sparsearray, which will hold all the information we need.  We must
    compare small amounts of data at a time as we find it.  */
 
@@ -273,56 +176,68 @@ fill_in_sparse_array (void)
    I'm not sure overall identical sparsity is verified.  */
 
 static void
-diff_sparse_files (int size_of_file)
+diff_sparse_files (void)
 {
-  int remaining_size = size_of_file;
-  char *buffer = (char *) xmalloc (BLOCKSIZE * sizeof (char));
-  int buffer_size = BLOCKSIZE;
-  union block *data_block = NULL;
+  off_t remaining_size = current_stat_info.stat.st_size;
+  char *buffer = xmalloc (BLOCKSIZE * sizeof (char));
+  size_t buffer_size = BLOCKSIZE;
+  union block *data_block = 0;
   int counter = 0;
   int different = 0;
 
-  fill_in_sparse_array ();
+  if (! fill_in_sparse_array ())
+    fatal_exit ();
 
   while (remaining_size > 0)
     {
-      int status;
-      long chunk_size;
+      ssize_t status;
+      size_t chunk_size;
+      off_t offset;
+
 #if 0
-      int amount_read = 0;
+      off_t amount_read = 0;
 #endif
 
       data_block = find_next_block ();
+      if (!data_block)
+       FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
       chunk_size = sparsearray[counter].numbytes;
       if (!chunk_size)
        break;
 
-      lseek (diff_handle, sparsearray[counter].offset, 0);
+      offset = sparsearray[counter].offset;
+      if (lseek (diff_handle, offset, SEEK_SET) < 0)
+       {
+         seek_error_details (current_stat_info.file_name, offset);
+         report_difference (0);
+       }
 
       /* Take care to not run out of room in our buffer.  */
 
       while (buffer_size < chunk_size)
        {
+         if (buffer_size * 2 < buffer_size)
+           xalloc_die ();
          buffer_size *= 2;
-         buffer = (char *) xrealloc (buffer, buffer_size * sizeof (char));
+         buffer = xrealloc (buffer, buffer_size * sizeof (char));
        }
 
       while (chunk_size > BLOCKSIZE)
        {
-         if (status = read (diff_handle, buffer, BLOCKSIZE),
+         if (status = safe_read (diff_handle, buffer, BLOCKSIZE),
              status != BLOCKSIZE)
            {
              if (status < 0)
                {
-                 WARN ((0, errno, _("Cannot read %s"), current_file_name));
-                 report_difference (NULL);
+                 read_error (current_stat_info.file_name);
+                 report_difference (0);
                }
              else
                {
                  char message[MESSAGE_BUFFER_SIZE];
 
-                 sprintf (message, _("Could only read %d of %ld bytes"),
-                          status, chunk_size);
+                 sprintf (message, _("Could only read %lu of %lu bytes"),
+                          (unsigned long) status, (unsigned long) chunk_size);
                  report_difference (message);
                }
              break;
@@ -338,27 +253,29 @@ diff_sparse_files (int size_of_file)
          remaining_size -= status;
          set_next_block_after (data_block);
          data_block = find_next_block ();
+         if (!data_block)
+           FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
        }
-      if (status = read (diff_handle, buffer, (size_t) chunk_size),
+      if (status = safe_read (diff_handle, buffer, chunk_size),
          status != chunk_size)
        {
          if (status < 0)
            {
-             WARN ((0, errno, _("Cannot read %s"), current_file_name));
-             report_difference (NULL);
+             read_error (current_stat_info.file_name);
+             report_difference (0);
            }
          else
            {
              char message[MESSAGE_BUFFER_SIZE];
 
-             sprintf (message, _("Could only read %d of %ld bytes"),
-                      status, chunk_size);
+             sprintf (message, _("Could only read %lu of %lu bytes"),
+                      (unsigned long) status, (unsigned long) chunk_size);
              report_difference (message);
            }
          break;
        }
 
-      if (memcmp (buffer, data_block->buffer, (size_t) chunk_size))
+      if (memcmp (buffer, data_block->buffer, chunk_size))
        {
          different = 1;
          break;
@@ -370,6 +287,8 @@ diff_sparse_files (int size_of_file)
          amount_read = 0;
          set_next_block_after (data_block);
          data_block = find_next_block ();
+         if (!data_block)
+           FATAL_ERROR ((0, 0, _("Unexpected EOF in archive")));
        }
 #endif
       set_next_block_after (data_block);
@@ -381,7 +300,7 @@ diff_sparse_files (int size_of_file)
   /* If the number of bytes read isn't the number of bytes supposedly in
      the file, they're different.  */
 
-  if (amount_read != size_of_file)
+  if (amount_read != current_stat_info.stat.st_size)
     different = 1;
 #endif
 
@@ -389,71 +308,56 @@ diff_sparse_files (int size_of_file)
   free (sparsearray);
 
   if (different)
-    report_difference (_("Data differs"));
+    report_difference (_("Contents differ"));
 }
 
-/*---------------------------------------------------------------------.
-| Call either stat or lstat over STAT_DATA, depending on --dereference |
-| (-h), for a file which should exist.  Diagnose any problem.  Return  |
-| nonzero for success, zero otherwise.                                |
-`---------------------------------------------------------------------*/
-
+/* Call either stat or lstat over STAT_DATA, depending on
+   --dereference (-h), for a file which should exist.  Diagnose any
+   problem.  Return nonzero for success, zero otherwise.  */
 static int
-get_stat_data (struct stat *stat_data)
+get_stat_data (char const *file_name, struct stat *stat_data)
 {
-  int status = (dereference_option
-               ? stat (current_file_name, stat_data)
-               : lstat (current_file_name, stat_data));
+  int status = deref_stat (dereference_option, file_name, stat_data);
 
-  if (status < 0)
+  if (status != 0)
     {
       if (errno == ENOENT)
-       report_difference (_("File does not exist"));
+       stat_warn (file_name);
       else
-       {
-         ERROR ((0, errno, _("Cannot stat file %s"), current_file_name));
-         report_difference (NULL);
-       }
-#if 0
-      skip_file ((long) current_stat.st_size);
-#endif
+       stat_error (file_name);
+      report_difference (0);
       return 0;
     }
 
   return 1;
 }
 
-/*----------------------------------.
-| Diff a file against the archive.  |
-`----------------------------------*/
-
+/* Diff a file against the archive.  */
 void
 diff_archive (void)
 {
   struct stat stat_data;
-  int name_length;
   int status;
-
-  errno = EPIPE;               /* FIXME: errno should be read-only */
-                               /* FIXME: remove perrors */
+  struct utimbuf restore_times;
 
   set_next_block_after (current_header);
-  decode_header (current_header, &current_stat, &current_format, 1);
+  decode_header (current_header, &current_stat_info, &current_format, 1);
 
-  /* Print the block from `current_header' and `current_stat'.  */
+  /* Print the block from current_header and current_stat_info.  */
 
   if (verbose_option)
     {
       if (now_verifying)
        fprintf (stdlis, _("Verify "));
-      print_header ();
+      print_header (-1);
     }
 
   switch (current_header->header.typeflag)
     {
     default:
-      WARN ((0, 0, _("Unknown file type '%c' for %s, diffed as normal file"),
-                current_header->header.typeflag, current_file_name));
+      ERROR ((0, 0, _("%s: Unknown file type '%c', diffed as normal file"),
+             quotearg_colon (current_stat_info.file_name),
+             current_header->header.typeflag));
       /* Fall through.  */
 
     case AREGTYPE:
@@ -463,92 +367,83 @@ diff_archive (void)
 
       /* Appears to be a file.  See if it's really a directory.  */
 
-      name_length = strlen (current_file_name) - 1;
-      if (current_file_name[name_length] == '/')
+      if (current_stat_info.had_trailing_slash)
        goto really_dir;
 
-      if (!get_stat_data (&stat_data))
+      if (!get_stat_data (current_stat_info.file_name, &stat_data))
        {
-         if (current_header->oldgnu_header.isextended)
-           skip_extended_headers ();
-         skip_file ((long) current_stat.st_size);
+         skip_member ();
          goto quit;
        }
 
       if (!S_ISREG (stat_data.st_mode))
        {
-         report_difference (_("Not a regular file"));
-         skip_file ((long) current_stat.st_size);
+         report_difference (_("File type differs"));
+         skip_member ();
          goto quit;
        }
 
-      stat_data.st_mode &= 07777;
-      if (stat_data.st_mode != current_stat.st_mode)
+      if ((current_stat_info.stat.st_mode & MODE_ALL) != (stat_data.st_mode & MODE_ALL))
        report_difference (_("Mode differs"));
 
 #if !MSDOS
       /* stat() in djgpp's C library gives a constant number of 42 as the
         uid and gid of a file.  So, comparing an FTP'ed archive just after
         unpack would fail on MSDOS.  */
-      if (stat_data.st_uid != current_stat.st_uid)
+      if (stat_data.st_uid != current_stat_info.stat.st_uid)
        report_difference (_("Uid differs"));
-      if (stat_data.st_gid != current_stat.st_gid)
+      if (stat_data.st_gid != current_stat_info.stat.st_gid)
        report_difference (_("Gid differs"));
 #endif
 
-      if (stat_data.st_mtime != current_stat.st_mtime)
+      if (stat_data.st_mtime != current_stat_info.stat.st_mtime)
        report_difference (_("Mod time differs"));
       if (current_header->header.typeflag != GNUTYPE_SPARSE &&
-         stat_data.st_size != current_stat.st_size)
+         stat_data.st_size != current_stat_info.stat.st_size)
        {
          report_difference (_("Size differs"));
-         skip_file ((long) current_stat.st_size);
+         skip_member ();
          goto quit;
        }
 
-      diff_handle = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY);
+      diff_handle = open (current_stat_info.file_name, O_RDONLY | O_BINARY);
 
-      if (diff_handle < 0 && !absolute_names_option)
-       {
-         char *tmpbuf = xmalloc (strlen (current_file_name) + 2);
-
-         *tmpbuf = '/';
-         strcpy (tmpbuf + 1, current_file_name);
-         diff_handle = open (tmpbuf, O_NDELAY | O_RDONLY);
-         free (tmpbuf);
-       }
       if (diff_handle < 0)
        {
-         ERROR ((0, errno, _("Cannot open %s"), current_file_name));
-         if (current_header->oldgnu_header.isextended)
-           skip_extended_headers ();
-         skip_file ((long) current_stat.st_size);
-         report_difference (NULL);
+         open_error (current_stat_info.file_name);
+         skip_member ();
+         report_difference (0);
          goto quit;
        }
 
+      restore_times.actime = stat_data.st_atime;
+      restore_times.modtime = stat_data.st_mtime;
+
       /* Need to treat sparse files completely differently here.  */
 
       if (current_header->header.typeflag == GNUTYPE_SPARSE)
-       diff_sparse_files (current_stat.st_size);
+       diff_sparse_files ();
       else
        {
          if (multi_volume_option)
            {
-             assign_string (&save_name, current_file_name);
-             save_totsize = current_stat.st_size;
+             assign_string (&save_name, current_stat_info.file_name);
+             save_totsize = current_stat_info.stat.st_size;
              /* save_sizeleft is set in read_and_process.  */
            }
 
-         read_and_process ((long) (current_stat.st_size), process_rawdata);
+         read_and_process (current_stat_info.stat.st_size, process_rawdata);
 
          if (multi_volume_option)
-           assign_string (&save_name, NULL);
+           assign_string (&save_name, 0);
        }
 
       status = close (diff_handle);
-      if (status < 0)
-       ERROR ((0, errno, _("Error while closing %s"), current_file_name));
+      if (status != 0)
+       close_error (current_stat_info.file_name);
+
+      if (atime_preserve_option)
+       utime (current_stat_info.file_name, &restore_times);
 
     quit:
       break;
@@ -556,33 +451,21 @@ diff_archive (void)
 #if !MSDOS
     case LNKTYPE:
       {
-       dev_t dev;
-       ino_t ino;
+       struct stat link_data;
 
-       if (!get_stat_data (&stat_data))
+       if (!get_stat_data (current_stat_info.file_name, &stat_data))
+         break;
+       if (!get_stat_data (current_stat_info.link_name, &link_data))
          break;
 
-       dev = stat_data.st_dev;
-       ino = stat_data.st_ino;
-       status = stat (current_link_name, &stat_data);
-       if (status < 0)
-         {
-           if (errno == ENOENT)
-             report_difference (_("Does not exist"));
-           else
-             {
-               WARN ((0, errno, _("Cannot stat file %s"), current_file_name));
-               report_difference (NULL);
-             }
-           break;
-         }
-
-       if (stat_data.st_dev != dev || stat_data.st_ino != ino)
+       if (stat_data.st_dev != link_data.st_dev
+           || stat_data.st_ino != link_data.st_ino)
          {
-           char *message = (char *)
-             xmalloc (MESSAGE_BUFFER_SIZE + strlen (current_link_name));
+           char *message =
+             xmalloc (MESSAGE_BUFFER_SIZE + 4 * strlen (current_stat_info.link_name));
 
-           sprintf (message, _("Not linked to %s"), current_link_name);
+           sprintf (message, _("Not linked to %s"),
+                    quote (current_stat_info.link_name));
            report_difference (message);
            free (message);
            break;
@@ -592,80 +475,61 @@ diff_archive (void)
       }
 #endif /* not MSDOS */
 
-#ifdef S_ISLNK
+#ifdef HAVE_READLINK
     case SYMTYPE:
       {
-       char linkbuf[NAME_FIELD_SIZE + 3]; /* FIXME: may be too short.  */
+       size_t len = strlen (current_stat_info.link_name);
+       char *linkbuf = alloca (len + 1);
 
-       status = readlink (current_file_name, linkbuf, (sizeof linkbuf) - 1);
+       status = readlink (current_stat_info.file_name, linkbuf, len + 1);
 
        if (status < 0)
          {
            if (errno == ENOENT)
-             report_difference (_("No such file or directory"));
+             readlink_warn (current_stat_info.file_name);
            else
-             {
-               WARN ((0, errno, _("Cannot read link %s"), current_file_name));
-               report_difference (NULL);
-             }
-           break;
+             readlink_error (current_stat_info.file_name);
+           report_difference (0);
          }
-
-       linkbuf[status] = '\0'; /* null-terminate it */
-       if (strncmp (current_link_name, linkbuf, (size_t) status) != 0)
+       else if (status != len
+                || strncmp (current_stat_info.link_name, linkbuf, len) != 0)
          report_difference (_("Symlink differs"));
 
        break;
       }
-#endif /* not S_ISLNK */
+#endif
 
-#ifdef S_IFCHR
     case CHRTYPE:
-      current_stat.st_mode |= S_IFCHR;
-      goto check_node;
-#endif /* not S_IFCHR */
-
-#ifdef S_IFBLK
-      /* If local system doesn't support block devices, use default case.  */
-
     case BLKTYPE:
-      current_stat.st_mode |= S_IFBLK;
-      goto check_node;
-#endif /* not S_IFBLK */
-
-#ifdef S_ISFIFO
-      /* If local system doesn't support FIFOs, use default case.  */
-
     case FIFOTYPE:
-# ifdef S_IFIFO
-      current_stat.st_mode |= S_IFIFO;
-# endif
-      current_stat.st_rdev = 0;        /* FIXME: do we need this? */
-      goto check_node;
-#endif /* S_ISFIFO */
-
-    check_node:
+
       /* FIXME: deal with umask.  */
 
-      if (!get_stat_data (&stat_data))
+      if (!get_stat_data (current_stat_info.file_name, &stat_data))
        break;
 
-      if (current_stat.st_rdev != stat_data.st_rdev)
+      if (current_header->header.typeflag == CHRTYPE
+         ? !S_ISCHR (stat_data.st_mode)
+         : current_header->header.typeflag == BLKTYPE
+         ? !S_ISBLK (stat_data.st_mode)
+         : /* current_header->header.typeflag == FIFOTYPE */
+         !S_ISFIFO (stat_data.st_mode))
        {
-         report_difference (_("Device numbers changed"));
+         report_difference (_("File type differs"));
          break;
        }
 
-      if (
-#ifdef S_IFMT
-         current_stat.st_mode != stat_data.st_mode
-#else
-         /* POSIX lossage.  */
-         (current_stat.st_mode & 07777) != (stat_data.st_mode & 07777)
-#endif
-         )
+      if ((current_header->header.typeflag == CHRTYPE
+          || current_header->header.typeflag == BLKTYPE)
+         && current_stat_info.stat.st_rdev != stat_data.st_rdev)
+       {
+         report_difference (_("Device number differs"));
+         break;
+       }
+
+      if ((current_stat_info.stat.st_mode & MODE_ALL) != (stat_data.st_mode & MODE_ALL))
        {
-         report_difference (_("Mode or device-type changed"));
+         report_difference (_("Mode differs"));
          break;
        }
 
@@ -673,49 +537,46 @@ diff_archive (void)
 
     case GNUTYPE_DUMPDIR:
       {
-       char *dumpdir_buffer = get_directory_contents (current_file_name, 0);
+       char *dumpdir_buffer = get_directory_contents (current_stat_info.file_name, 0);
 
        if (multi_volume_option)
          {
-           assign_string (&save_name, current_file_name);
-           save_totsize = current_stat.st_size;
+           assign_string (&save_name, current_stat_info.file_name);
+           save_totsize = current_stat_info.stat.st_size;
            /* save_sizeleft is set in read_and_process.  */
          }
 
        if (dumpdir_buffer)
          {
            dumpdir_cursor = dumpdir_buffer;
-           read_and_process ((long) (current_stat.st_size), process_dumpdir);
+           read_and_process (current_stat_info.stat.st_size, process_dumpdir);
            free (dumpdir_buffer);
          }
        else
-         read_and_process ((long) (current_stat.st_size), process_noop);
+         read_and_process (current_stat_info.stat.st_size, process_noop);
 
        if (multi_volume_option)
-         assign_string (&save_name, NULL);
+         assign_string (&save_name, 0);
        /* Fall through.  */
       }
 
     case DIRTYPE:
-      /* Check for trailing /.  */
-
-      name_length = strlen (current_file_name) - 1;
-
     really_dir:
-      while (name_length && current_file_name[name_length] == '/')
-       current_file_name[name_length--] = '\0';        /* zap / */
-
-      if (!get_stat_data (&stat_data))
+      if (!get_stat_data (current_stat_info.file_name, &stat_data))
        break;
 
       if (!S_ISDIR (stat_data.st_mode))
        {
-         report_difference (_("No longer a directory"));
+         report_difference (_("File type differs"));
+         break;
+       }
+
+      if ((current_stat_info.stat.st_mode & MODE_ALL) != (stat_data.st_mode & MODE_ALL))
+       {
+         report_difference (_("Mode differs"));
          break;
        }
 
-      if ((stat_data.st_mode & 07777) != (current_stat.st_mode & 07777))
-       report_difference (_("Mode differs"));
       break;
 
     case GNUTYPE_VOLHDR:
@@ -725,73 +586,65 @@ diff_archive (void)
       {
        off_t offset;
 
-       name_length = strlen (current_file_name) - 1;
-       if (current_file_name[name_length] == '/')
+       if (current_stat_info.had_trailing_slash)
          goto really_dir;
 
-       if (!get_stat_data (&stat_data))
+       if (!get_stat_data (current_stat_info.file_name, &stat_data))
          break;
 
        if (!S_ISREG (stat_data.st_mode))
          {
-           report_difference (_("Not a regular file"));
-           skip_file ((long) current_stat.st_size);
+           report_difference (_("File type differs"));
+           skip_member ();
            break;
          }
 
-       stat_data.st_mode &= 07777;
-       offset = from_oct (1 + 12, current_header->oldgnu_header.offset);
-       if (stat_data.st_size != current_stat.st_size + offset)
+       offset = OFF_FROM_HEADER (current_header->oldgnu_header.offset);
+       if (stat_data.st_size != current_stat_info.stat.st_size + offset)
          {
            report_difference (_("Size differs"));
-           skip_file ((long) current_stat.st_size);
+           skip_member ();
            break;
          }
 
-       diff_handle = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY);
+       diff_handle = open (current_stat_info.file_name, O_RDONLY | O_BINARY);
 
        if (diff_handle < 0)
          {
-           WARN ((0, errno, _("Cannot open file %s"), current_file_name));
-           report_difference (NULL);
-           skip_file ((long) current_stat.st_size);
+           open_error (current_stat_info.file_name);
+           report_difference (0);
+           skip_member ();
            break;
          }
 
-       status = lseek (diff_handle, offset, 0);
-       if (status != offset)
+       if (lseek (diff_handle, offset, SEEK_SET) < 0)
          {
-           WARN ((0, errno, _("Cannot seek to %ld in file %s"),
-                  offset, current_file_name));
-           report_difference (NULL);
+           seek_error_details (current_stat_info.file_name, offset);
+           report_difference (0);
            break;
          }
 
        if (multi_volume_option)
          {
-           assign_string (&save_name, current_file_name);
+           assign_string (&save_name, current_stat_info.file_name);
            save_totsize = stat_data.st_size;
            /* save_sizeleft is set in read_and_process.  */
          }
 
-       read_and_process ((long) (current_stat.st_size), process_rawdata);
+       read_and_process (current_stat_info.stat.st_size, process_rawdata);
 
        if (multi_volume_option)
-         assign_string (&save_name, NULL);
+         assign_string (&save_name, 0);
 
        status = close (diff_handle);
-       if (status < 0)
-         ERROR ((0, errno, _("Error while closing %s"), current_file_name));
+       if (status != 0)
+         close_error (current_stat_info.file_name);
 
        break;
       }
     }
 }
 
-/*---.
-| ?  |
-`---*/
-
 void
 verify_volume (void)
 {
@@ -829,12 +682,10 @@ verify_volume (void)
                status < 0))
          {
 #endif
-           if (rmtlseek (archive, 0L, 0) != 0)
+           if (rmtlseek (archive, (off_t) 0, SEEK_SET) != 0)
              {
                /* Lseek failed.  Try a different method.  */
-
-               WARN ((0, errno,
-                      _("Could not rewind archive file for verify")));
+               seek_warn (archive_name_array[0]);
                return;
              }
 #ifdef MTIOCTOP
@@ -849,17 +700,19 @@ verify_volume (void)
   flush_read ();
   while (1)
     {
-      enum read_header status = read_header ();
+      enum read_header status = read_header (0);
 
       if (status == HEADER_FAILURE)
        {
          int counter = 0;
 
-         while (status == HEADER_FAILURE);
+         do
            {
              counter++;
-             status = read_header ();
+             status = read_header (0);
            }
+         while (status == HEADER_FAILURE);
+
          ERROR ((0, 0,
                  _("VERIFY FAILURE: %d invalid header(s) detected"), counter));
        }
This page took 0.04749 seconds and 4 git commands to generate.