]> Dogcows Code - chaz/tar/blobdiff - src/buffer.c
(name_gather, addname): Use offsetof when computing sizes for
[chaz/tar] / src / buffer.c
index 09738b3898f145497a1eb567bab6257c7f6792e3..e531061d7036ee48e35f674d15fb9e8fdbf69c06 100644 (file)
@@ -1,5 +1,8 @@
 /* Buffer management for tar.
-   Copyright 1988, 92, 93, 94, 96, 97, 1999 Free Software Foundation, Inc.
+
+   Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001 Free
+   Software Foundation, Inc.
+
    Written by John Gilmore, on 1985-08-25.
 
    This program is free software; you can redistribute it and/or modify it
    with this program; if not, write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
-/* Enable GNU extensions in fnmatch.h.  */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-#endif
-
 #include "system.h"
 
 #include <signal.h>
-#include <time.h>
-#ifndef time
-time_t time ();
-#endif
 
 #if MSDOS
 # include <process.h>
@@ -76,7 +70,7 @@ FILE *stdlis;
 
 static void backspace_output PARAMS ((void));
 static int new_volume PARAMS ((enum access_mode));
-static void archive_write_error PARAMS ((ssize_t));
+static void archive_write_error PARAMS ((ssize_t)) __attribute__ ((noreturn));
 static void archive_read_error PARAMS ((void));
 
 #if !MSDOS
@@ -161,20 +155,14 @@ print_total_written (void)
            : "?"));
 }
 
-/*--------------------------------------------------------.
-| Compute and return the block ordinal at current_block.  |
-`--------------------------------------------------------*/
-
+/* Compute and return the block ordinal at current_block.  */
 off_t
 current_block_ordinal (void)
 {
   return record_start_block + (current_block - record_start);
 }
 
-/*------------------------------------------------------------------.
-| If the EOF flag is set, reset it, as well as current_block, etc.  |
-`------------------------------------------------------------------*/
-
+/* If the EOF flag is set, reset it, as well as current_block, etc.  */
 void
 reset_eof (void)
 {
@@ -187,12 +175,9 @@ reset_eof (void)
     }
 }
 
-/*-------------------------------------------------------------------------.
-| Return the location of the next available input or output block.        |
-| Return zero for EOF.  Once we have returned zero, we just keep returning |
-| it, to avoid accidentally going on to the next file on the tape.        |
-`-------------------------------------------------------------------------*/
-
+/* Return the location of the next available input or output block.
+   Return zero for EOF.  Once we have returned zero, we just keep returning
+   it, to avoid accidentally going on to the next file on the tape.  */
 union block *
 find_next_block (void)
 {
@@ -210,12 +195,8 @@ find_next_block (void)
   return current_block;
 }
 
-/*------------------------------------------------------.
-| Indicate that we have used all blocks up thru BLOCK.  |
-|                                                      |
-| FIXME: should the arg have an off-by-1?              |
-`------------------------------------------------------*/
-
+/* Indicate that we have used all blocks up thru BLOCK.
+   FIXME: should the arg have an off-by-1?  */
 void
 set_next_block_after (union block *block)
 {
@@ -230,40 +211,28 @@ set_next_block_after (union block *block)
     abort ();
 }
 
-/*------------------------------------------------------------------------.
-| Return the number of bytes comprising the space between POINTER through |
-| the end of the current buffer of blocks.  This space is available for          |
-| filling with data, or taking data from.  POINTER is usually (but not   |
-| always) the result previous find_next_block call.                      |
-`------------------------------------------------------------------------*/
-
+/* Return the number of bytes comprising the space between POINTER
+   through the end of the current buffer of blocks.  This space is
+   available for filling with data, or taking data from.  POINTER is
+   usually (but not always) the result previous find_next_block call.  */
 size_t
 available_space_after (union block *pointer)
 {
   return record_end->buffer - pointer->buffer;
 }
 
-/*------------------------------------------------------------------.
-| Close file having descriptor FD, and abort if close unsuccessful. |
-`------------------------------------------------------------------*/
-
+/* Close file having descriptor FD, and abort if close unsuccessful.  */
 static void
 xclose (int fd)
 {
-  if (close (fd) < 0)
-    {
-      int e = errno;
-      FATAL_ERROR ((0, e, _("Cannot close file #%d"), fd));
-    }
+  if (close (fd) != 0)
+    close_error (_("(pipe)"));
 }
 
-/*-----------------------------------------------------------------------.
-| Duplicate file descriptor FROM into becoming INTO, or else, issue     |
-| MESSAGE.  INTO is closed first and has to be the next available slot.         |
-`-----------------------------------------------------------------------*/
-
+/* Duplicate file descriptor FROM into becoming INTO.
+   INTO is closed first and has to be the next available slot.  */
 static void
-xdup2 (int from, int into, const char *message)
+xdup2 (int from, int into)
 {
   if (from != into)
     {
@@ -272,13 +241,17 @@ xdup2 (int from, int into, const char *message)
       if (status != 0 && errno != EBADF)
        {
          int e = errno;
-         FATAL_ERROR ((0, e, _("Cannot close file descriptor")));
+         FATAL_ERROR ((0, e, _("Cannot close")));
        }
       status = dup (from);
       if (status != into)
        {
-         int e = status < 0 ? errno : 0;
-         FATAL_ERROR ((0, e, _("Cannot properly duplicate %s"), message));
+         if (status < 0)
+           {
+             int e = errno;
+             FATAL_ERROR ((0, e, _("Cannot dup")));
+           }
+         abort ();
        }
       xclose (from);
     }
@@ -286,20 +259,14 @@ xdup2 (int from, int into, const char *message)
 
 #if MSDOS
 
-/*-------------------------------------------------------.
-| Set ARCHIVE for writing, then compressing an archive.         |
-`-------------------------------------------------------*/
-
+/* Set ARCHIVE for writing, then compressing an archive.  */
 static void
 child_open_for_compress (void)
 {
   FATAL_ERROR ((0, 0, _("Cannot use compressed or remote archives")));
 }
 
-/*---------------------------------------------------------.
-| Set ARCHIVE for uncompressing, then reading an archive.  |
-`---------------------------------------------------------*/
-
+/* Set ARCHIVE for uncompressing, then reading an archive.  */
 static void
 child_open_for_uncompress (void)
 {
@@ -308,11 +275,8 @@ child_open_for_uncompress (void)
 
 #else /* not MSDOS */
 
-/*---------------------------------------------------------------------.
-| Return nonzero if NAME is the name of a regular file, or if the file |
-| does not exist (so it would be created as a regular file).          |
-`---------------------------------------------------------------------*/
-
+/* Return nonzero if NAME is the name of a regular file, or if the file
+   does not exist (so it would be created as a regular file).  */
 static int
 is_regular_file (const char *name)
 {
@@ -342,16 +306,14 @@ write_archive_buffer (void)
   return written ? written : status;
 }
 
-/*-------------------------------------------------------.
-| Set ARCHIVE for writing, then compressing an archive.         |
-`-------------------------------------------------------*/
-
+/* Set ARCHIVE for writing, then compressing an archive.  */
 static void
 child_open_for_compress (void)
 {
   int parent_pipe[2];
   int child_pipe[2];
   pid_t grandchild_pid;
+  int wait_status;
 
   xpipe (parent_pipe);
   child_pid = xfork ();
@@ -369,7 +331,7 @@ child_open_for_compress (void)
 
   program_name = _("tar (child)");
 
-  xdup2 (parent_pipe[PREAD], STDIN_FILENO, _("(child) Pipe to stdin"));
+  xdup2 (parent_pipe[PREAD], STDIN_FILENO);
   xclose (parent_pipe[PWRITE]);
 
   /* Check if we need a grandchild tar.  This happens only if either:
@@ -397,7 +359,7 @@ child_open_for_compress (void)
          errno = saved_errno;
          open_fatal (archive_name_array[0]);
        }
-      xdup2 (archive, STDOUT_FILENO, _("Archive to stdout"));
+      xdup2 (archive, STDOUT_FILENO);
       execlp (use_compress_program_option, use_compress_program_option,
              (char *) 0);
       exec_fatal (use_compress_program_option);
@@ -408,25 +370,24 @@ child_open_for_compress (void)
   xpipe (child_pipe);
   grandchild_pid = xfork ();
 
-  if (grandchild_pid > 0)
+  if (grandchild_pid == 0)
     {
-      /* The child tar is still here!  Launch the compressor.  */
+      /* The newborn grandchild tar is here!  Launch the compressor.  */
 
-      xdup2 (child_pipe[PWRITE], STDOUT_FILENO,
-            _("((child)) Pipe to stdout"));
+      program_name = _("tar (grandchild)");
+
+      xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
       xclose (child_pipe[PREAD]);
       execlp (use_compress_program_option, use_compress_program_option,
              (char *) 0);
       exec_fatal (use_compress_program_option);
     }
 
-  /* The new born grandchild tar is here!  */
-
-  program_name = _("tar (grandchild)");
+  /* The child tar is still here!  */
 
   /* Prepare for reblocking the data from the compressor into the archive.  */
 
-  xdup2 (child_pipe[PREAD], STDIN_FILENO, _("(grandchild) Pipe to stdin"));
+  xdup2 (child_pipe[PREAD], STDIN_FILENO);
   xclose (child_pipe[PWRITE]);
 
   if (strcmp (archive_name_array[0], "-") == 0)
@@ -486,25 +447,41 @@ child_open_for_compress (void)
 
       status = write_archive_buffer ();
       if (status != record_size)
-       archive_write_error (status);
+       archive_write_error (status);
     }
 
 #if 0
   close_archive ();
 #endif
+
+  /* Propagate any failure of the grandchild back to the parent.  */
+
+  while (waitpid (grandchild_pid, &wait_status, 0) == -1)
+    if (errno != EINTR)
+      {
+       waitpid_error (use_compress_program_option);
+       break;
+      }
+
+  if (WIFSIGNALED (wait_status))
+    {
+      kill (child_pid, WTERMSIG (wait_status));
+      exit_status = TAREXIT_FAILURE;
+    }
+  else if (WEXITSTATUS (wait_status) != 0)
+    exit_status = WEXITSTATUS (wait_status);
+
   exit (exit_status);
 }
 
-/*---------------------------------------------------------.
-| Set ARCHIVE for uncompressing, then reading an archive.  |
-`---------------------------------------------------------*/
-
+/* Set ARCHIVE for uncompressing, then reading an archive.  */
 static void
 child_open_for_uncompress (void)
 {
   int parent_pipe[2];
   int child_pipe[2];
   pid_t grandchild_pid;
+  int wait_status;
 
   xpipe (parent_pipe);
   child_pid = xfork ();
@@ -519,11 +496,11 @@ child_open_for_uncompress (void)
       return;
     }
 
-  /* The new born child tar is here!  */
+  /* The newborn child tar is here!  */
 
   program_name = _("tar (child)");
 
-  xdup2 (parent_pipe[PWRITE], STDOUT_FILENO, _("(child) Pipe to stdout"));
+  xdup2 (parent_pipe[PWRITE], STDOUT_FILENO);
   xclose (parent_pipe[PREAD]);
 
   /* Check if we need a grandchild tar.  This happens only if either:
@@ -541,7 +518,7 @@ child_open_for_uncompress (void)
       archive = open (archive_name_array[0], O_RDONLY | O_BINARY, MODE_RW);
       if (archive < 0)
        open_fatal (archive_name_array[0]);
-      xdup2 (archive, STDIN_FILENO, _("Archive to stdin"));
+      xdup2 (archive, STDIN_FILENO);
       execlp (use_compress_program_option, use_compress_program_option,
              "-d", (char *) 0);
       exec_fatal (use_compress_program_option);
@@ -552,24 +529,25 @@ child_open_for_uncompress (void)
   xpipe (child_pipe);
   grandchild_pid = xfork ();
 
-  if (grandchild_pid > 0)
+  if (grandchild_pid == 0)
     {
-      /* The child tar is still here!  Launch the uncompressor.  */
+      /* The newborn grandchild tar is here!  Launch the uncompressor.  */
+
+      program_name = _("tar (grandchild)");
 
-      xdup2 (child_pipe[PREAD], STDIN_FILENO, _("((child)) Pipe to stdin"));
+      xdup2 (child_pipe[PREAD], STDIN_FILENO);
       xclose (child_pipe[PWRITE]);
       execlp (use_compress_program_option, use_compress_program_option,
              "-d", (char *) 0);
       exec_fatal (use_compress_program_option);
     }
 
-  /* The new born grandchild tar is here!  */
-
-  program_name = _("tar (grandchild)");
+  /* The child tar is still here!  */
 
-  /* Prepare for unblocking the data from the archive into the uncompressor.  */
+  /* Prepare for unblocking the data from the archive into the
+     uncompressor.  */
 
-  xdup2 (child_pipe[PWRITE], STDOUT_FILENO, _("(grandchild) Pipe to stdout"));
+  xdup2 (child_pipe[PWRITE], STDOUT_FILENO);
   xclose (child_pipe[PREAD]);
 
   if (strcmp (archive_name_array[0], "-") == 0)
@@ -605,42 +583,53 @@ child_open_for_uncompress (void)
       while (maximum)
        {
          count = maximum < BLOCKSIZE ? maximum : BLOCKSIZE;
-         status = full_write (STDOUT_FILENO, cursor, count);
-         if (status < 0)
+         if (full_write (STDOUT_FILENO, cursor, count) != count)
            write_error (use_compress_program_option);
-
-         if (status != count)
-           {
-             ERROR ((0, 0, _("Write to compression program short %lu bytes"),
-                     (unsigned long) (count - status)));
-             count = status;
-           }
-
          cursor += count;
          maximum -= count;
        }
     }
 
+  xclose (STDOUT_FILENO);
 #if 0
   close_archive ();
 #endif
+
+  /* Propagate any failure of the grandchild back to the parent.  */
+
+  while (waitpid (grandchild_pid, &wait_status, 0) == -1)
+    if (errno != EINTR)
+      {
+       waitpid_error (use_compress_program_option);
+       break;
+      }
+
+  if (WIFSIGNALED (wait_status))
+    {
+      kill (child_pid, WTERMSIG (wait_status));
+      exit_status = TAREXIT_FAILURE;
+    }
+  else if (WEXITSTATUS (wait_status) != 0)
+    exit_status = WEXITSTATUS (wait_status);
+
   exit (exit_status);
 }
 
 #endif /* not MSDOS */
 
-/*--------------------------------------------------------------------------.
-| Check the LABEL block against the volume label, seen as a globbing       |
-| pattern.  Return true if the pattern matches.  In case of failure, retry  |
-| matching a volume sequence number before giving up in multi-volume mode.  |
-`--------------------------------------------------------------------------*/
-
+/* Check the LABEL block against the volume label, seen as a globbing
+   pattern.  Return true if the pattern matches.  In case of failure,
+   retry matching a volume sequence number before giving up in
+   multi-volume mode.  */
 static int
 check_label_pattern (union block *label)
 {
   char *string;
   int result;
 
+  if (! memchr (label->header.name, '\0', sizeof label->header.name))
+    return 0;
+
   if (fnmatch (volume_label_option, label->header.name, 0) == 0)
     return 1;
 
@@ -656,11 +645,8 @@ check_label_pattern (union block *label)
   return result;
 }
 
-/*------------------------------------------------------------------------.
-| Open an archive file.  The argument specifies whether we are reading or |
-| writing, or both.                                                      |
-`------------------------------------------------------------------------*/
-
+/* Open an archive file.  The argument specifies whether we are
+   reading or writing, or both.  */
 void
 open_archive (enum access_mode wanted_access)
 {
@@ -676,18 +662,8 @@ open_archive (enum access_mode wanted_access)
 
   current_file_name = 0;
   current_link_name = 0;
-
-  /* FIXME: According to POSIX.1, PATH_MAX may well not be a compile-time
-     constant, and the value from sysconf (_SC_PATH_MAX) may well not be any
-     size that is reasonable to allocate a buffer.  In the GNU system, there
-     is no fixed limit.  The only correct thing to do is to use dynamic
-     allocation.  (Roland McGrath)  */
-
-  if (!real_s_name)
-    real_s_name = xmalloc (PATH_MAX);
-  /* FIXME: real_s_name is never freed.  */
-
   save_name = 0;
+  real_s_name = 0;
 
   if (multi_volume_option)
     {
@@ -808,8 +784,8 @@ open_archive (enum access_mode wanted_access)
        || (! _isrmt (archive)
           && S_ISCHR (archive_stat.st_mode)
           && stat (dev_null, &dev_null_stat) == 0
-          && S_ISCHR (dev_null_stat.st_mode)
-          && archive_stat.st_rdev == dev_null_stat.st_rdev));
+          && archive_stat.st_dev == dev_null_stat.st_dev
+          && archive_stat.st_ino == dev_null_stat.st_ino));
   }
 
   if (!_isrmt (archive) && S_ISREG (archive_stat.st_mode))
@@ -870,10 +846,7 @@ open_archive (enum access_mode wanted_access)
     }
 }
 
-/*--------------------------------------.
-| Perform a write to flush the buffer.  |
-`--------------------------------------*/
-
+/* Perform a write to flush the buffer.  */
 void
 flush_write (void)
 {
@@ -906,17 +879,17 @@ flush_write (void)
 
          if (!save_name)
            {
-             real_s_name[0] = '\0';
+             assign_string (&real_s_name, 0);
              real_s_totsize = 0;
              real_s_sizeleft = 0;
              return;
            }
 
          cursor = save_name + FILESYSTEM_PREFIX_LEN (save_name);
-         while (*cursor == '/')
+         while (ISSLASH (*cursor))
            cursor++;
 
-         strcpy (real_s_name, cursor);
+         assign_string (&real_s_name, cursor);
          real_s_totsize = save_totsize;
          real_s_sizeleft = save_sizeleft;
        }
@@ -938,12 +911,12 @@ flush_write (void)
     prev_written += bytes_written;
   bytes_written = 0;
 
-  if (volume_label_option && real_s_name[0])
+  if (volume_label_option && real_s_name)
     {
       copy_back = 2;
       record_start -= 2;
     }
-  else if (volume_label_option || real_s_name[0])
+  else if (volume_label_option || real_s_name)
     {
       copy_back = 1;
       record_start--;
@@ -961,7 +934,7 @@ flush_write (void)
       finish_header (record_start);
     }
 
-  if (real_s_name[0])
+  if (real_s_name)
     {
       int tmp;
 
@@ -977,7 +950,7 @@ flush_write (void)
       strcpy (record_start->header.name, real_s_name);
       record_start->header.typeflag = GNUTYPE_MULTIVOL;
       OFF_TO_CHARS (real_s_sizeleft, record_start->header.size);
-      OFF_TO_CHARS (real_s_totsize - real_s_sizeleft, 
+      OFF_TO_CHARS (real_s_totsize - real_s_sizeleft,
                    record_start->oldgnu_header.offset);
       tmp = verbose_option;
       verbose_option = 0;
@@ -1005,15 +978,15 @@ flush_write (void)
       if (real_s_sizeleft >= copy_back * BLOCKSIZE)
        real_s_sizeleft -= copy_back * BLOCKSIZE;
       else if ((real_s_sizeleft + BLOCKSIZE - 1) / BLOCKSIZE <= copy_back)
-       real_s_name[0] = '\0';
+       assign_string (&real_s_name, 0);
       else
        {
          char *cursor = save_name + FILESYSTEM_PREFIX_LEN (save_name);
 
-         while (*cursor == '/')
+         while (ISSLASH (*cursor))
            cursor++;
 
-         strcpy (real_s_name, cursor);
+         assign_string (&real_s_name, cursor);
          real_s_sizeleft = save_sizeleft;
          real_s_totsize = save_totsize;
        }
@@ -1021,38 +994,26 @@ flush_write (void)
     }
 }
 
-/*---------------------------------------------------------------------.
-| Handle write errors on the archive.  Write errors are always fatal.  |
-| Hitting the end of a volume does not cause a write error unless the  |
-| write was the first record of the volume.                           |
-`---------------------------------------------------------------------*/
-
+/* Handle write errors on the archive.  Write errors are always fatal.
+   Hitting the end of a volume does not cause a write error unless the
+   write was the first record of the volume.  */
 static void
 archive_write_error (ssize_t status)
 {
-  int saved_errno = errno;
-
   /* It might be useful to know how much was written before the error
      occurred.  */
   if (totals_option)
-    print_total_written ();
-
-  if (status < 0)
     {
-      errno = saved_errno;
-      write_fatal (*archive_name_cursor);
+      int e = errno;
+      print_total_written ();
+      errno = e;
     }
-  else
-    FATAL_ERROR ((0, 0, _("Only wrote %lu of %lu bytes to %s"),
-                 (unsigned long) status, (unsigned long) record_size,
-                 quote (*archive_name_cursor)));
-}
 
-/*-------------------------------------------------------------------.
-| Handle read errors on the archive.  If the read should be retried, |
-| returns to the caller.                                            |
-`-------------------------------------------------------------------*/
+  write_fatal_details (*archive_name_cursor, status, record_size);
+}
 
+/* Handle read errors on the archive.  If the read should be retried,
+   return to the caller.  */
 static void
 archive_read_error (void)
 {
@@ -1069,10 +1030,7 @@ archive_read_error (void)
   return;
 }
 
-/*-------------------------------------.
-| Perform a read to flush the buffer.  |
-`-------------------------------------*/
-
+/* Perform a read to flush the buffer.  */
 void
 flush_read (void)
 {
@@ -1102,16 +1060,16 @@ flush_read (void)
        {
          char *cursor = save_name + FILESYSTEM_PREFIX_LEN (save_name);
 
-         while (*cursor == '/')
+         while (ISSLASH (*cursor))
            cursor++;
 
-         strcpy (real_s_name, cursor);
+         assign_string (&real_s_name, cursor);
          real_s_sizeleft = save_sizeleft;
          real_s_totsize = save_totsize;
        }
       else
        {
-         real_s_name[0] = '\0';
+         assign_string (&real_s_name, 0);
          real_s_totsize = 0;
          real_s_sizeleft = 0;
        }
@@ -1178,7 +1136,7 @@ flush_read (void)
       else if (volume_label_option)
        WARN ((0, 0, _("WARNING: No volume header")));
 
-      if (real_s_name[0])
+      if (real_s_name)
        {
          uintmax_t s1, s2;
          if (cursor->header.typeflag != GNUTYPE_MULTIVOL
@@ -1197,7 +1155,7 @@ flush_read (void)
              char totsizebuf[UINTMAX_STRSIZE_BOUND];
              char s1buf[UINTMAX_STRSIZE_BOUND];
              char s2buf[UINTMAX_STRSIZE_BOUND];
-             
+
              WARN ((0, 0, _("%s is the wrong size (%s != %s + %s)"),
                     quote (cursor->header.name),
                     STRINGIFY_BIGINT (save_totsize, totsizebuf),
@@ -1230,22 +1188,25 @@ flush_read (void)
   more = record_start->buffer + status;
   left = record_size - status;
 
-  while (left % BLOCKSIZE != 0)
+  while (left % BLOCKSIZE != 0
+        || (left && status && read_full_records_option))
     {
-      while ((status = rmtread (archive, more, left)) < 0)
-       archive_read_error ();
+      if (status)
+       while ((status = rmtread (archive, more, left)) < 0)
+         archive_read_error ();
 
       if (status == 0)
        {
-         ERROR ((0, 0, _("%d garbage bytes ignored at end of archive"),
-                 (int) ((record_size - left) % BLOCKSIZE)));
+         if (left % BLOCKSIZE != 0)
+           ERROR ((0, 0, _("%d garbage bytes ignored at end of archive"),
+                   (int) ((record_size - left) % BLOCKSIZE)));
          break;
        }
 
       if (! read_full_records_option)
        FATAL_ERROR ((0, 0, _("Unaligned block (%lu bytes) in archive"),
                      (unsigned long) (record_size - left)));
-         
+
       /* User warned us about this.  Fix up.  */
 
       left -= status;
@@ -1263,10 +1224,7 @@ flush_read (void)
   record_end = record_start + (record_size - left) / BLOCKSIZE;
 }
 
-/*-----------------------------------------------.
-| Flush the current buffer to/from the archive.         |
-`-----------------------------------------------*/
-
+/*  Flush the current buffer to/from the archive.  */
 void
 flush_archive (void)
 {
@@ -1281,14 +1239,8 @@ flush_archive (void)
 
       if (file_to_switch_to >= 0)
        {
-         int status = rmtclose (archive);
-
-         if (status < 0)
-           {
-             int e = errno;
-             WARN ((0, e, _("WARNING: %s: close (%d, %d)"),
-                    quotearg_colon (*archive_name_cursor), archive, status));
-           }
+         if (rmtclose (archive) != 0)
+           close_warn (*archive_name_cursor);
 
          archive = file_to_switch_to;
        }
@@ -1311,12 +1263,9 @@ flush_archive (void)
     }
 }
 
-/*-------------------------------------------------------------------------.
-| Backspace the archive descriptor by one record worth.  If its a tape,           |
-| MTIOCTOP will work.  If its something else, we try to seek on it.  If we |
-| can't seek, we lose!                                                    |
-`-------------------------------------------------------------------------*/
-
+/* Backspace the archive descriptor by one record worth.  If it's a
+   tape, MTIOCTOP will work.  If it's something else, try to seek on
+   it.  If we can't seek, we lose!  */
 static void
 backspace_output (void)
 {
@@ -1339,6 +1288,8 @@ backspace_output (void)
     /* Seek back to the beginning of this record and start writing there.  */
 
     position -= record_size;
+    if (position < 0)
+      position = 0;
     if (rmtlseek (archive, position, SEEK_SET) != position)
       {
        /* Lseek failed.  Try a different method.  */
@@ -1355,10 +1306,7 @@ backspace_output (void)
   }
 }
 
-/*-------------------------.
-| Close the archive file.  |
-`-------------------------*/
-
+/* Close the archive file.  */
 void
 close_archive (void)
 {
@@ -1379,30 +1327,11 @@ close_archive (void)
       continue;
 #endif
 
-  if (! _isrmt (archive) && subcommand_option == DELETE_SUBCOMMAND)
-    {
-#if MSDOS
-      int status = write (archive, "", 0);
-#else
-      off_t pos = lseek (archive, (off_t) 0, SEEK_CUR);
-      int status = pos < 0 ? -1 : ftruncate (archive, pos);
-#endif
-      if (status != 0)
-       truncate_warn (*archive_name_cursor);
-    }
   if (verify_option)
     verify_volume ();
 
-  {
-    int status = rmtclose (archive);
-
-    if (status < 0)
-      {
-       int e = errno;
-       WARN ((0, e, _("WARNING: %s: close (%d, %d)"),
-              quotearg_colon (*archive_name_cursor), archive, status));
-      }
-  }
+  if (rmtclose (archive) != 0)
+    close_warn (*archive_name_cursor);
 
 #if !MSDOS
 
@@ -1418,23 +1347,11 @@ close_archive (void)
          }
 
       if (WIFSIGNALED (wait_status))
-       {
-         /* SIGPIPE is OK, everything else is a problem.  */
-         
-         if (WTERMSIG (wait_status) != SIGPIPE)
-           ERROR ((0, 0, _("Child died with signal %d"),
-                   WTERMSIG (wait_status)));
-       }
-      else
-       {
-         /* Child voluntarily terminated -- but why?  /bin/sh returns
-            SIGPIPE + 128 if its child, then do nothing.  */
-             
-         if (WEXITSTATUS (wait_status)
-             && WEXITSTATUS (wait_status) != (SIGPIPE + 128))
-           ERROR ((0, 0, _("Child returned status %d"),
-                   WEXITSTATUS (wait_status)));
-       }
+       ERROR ((0, 0, _("Child died with signal %d"),
+               WTERMSIG (wait_status)));
+      else if (WEXITSTATUS (wait_status) != 0)
+       ERROR ((0, 0, _("Child returned status %d"),
+               WEXITSTATUS (wait_status)));
     }
 #endif /* !MSDOS */
 
@@ -1444,13 +1361,12 @@ close_archive (void)
     free (current_link_name);
   if (save_name)
     free (save_name);
+  if (real_s_name)
+    free (real_s_name);
   free (multi_volume_option ? record_start - 2 : record_start);
 }
 
-/*------------------------------------------------.
-| Called to initialize the global volume number.  |
-`------------------------------------------------*/
-
+/* Called to initialize the global volume number.  */
 void
 init_volume_number (void)
 {
@@ -1458,7 +1374,10 @@ init_volume_number (void)
 
   if (file)
     {
-      fscanf (file, "%d", &global_volno);
+      if (fscanf (file, "%d", &global_volno) != 1
+         || global_volno < 0)
+       FATAL_ERROR ((0, 0, _("%s: contains invalid volume number"),
+                     quotearg_colon (volno_file_option)));
       if (ferror (file))
        read_error (volno_file_option);
       if (fclose (file) != 0)
@@ -1468,10 +1387,7 @@ init_volume_number (void)
     open_error (volno_file_option);
 }
 
-/*-------------------------------------------------------.
-| Called to write out the closing global volume number.         |
-`-------------------------------------------------------*/
-
+/* Called to write out the closing global volume number.  */
 void
 closeout_volume_number (void)
 {
@@ -1489,19 +1405,14 @@ closeout_volume_number (void)
     open_error (volno_file_option);
 }
 
-/*-----------------------------------------------------------------------.
-| We've hit the end of the old volume.  Close it and open the next one.         |
-| Return nonzero on success.                                            |
-`-----------------------------------------------------------------------*/
-
+/* We've hit the end of the old volume.  Close it and open the next one.
+   Return nonzero on success.  */
 static int
 new_volume (enum access_mode access)
 {
   static FILE *read_file;
   static int looped;
 
-  int status;
-
   if (!read_file && !info_script_option)
     /* FIXME: if fopen is used, it will never be closed.  */
     read_file = archive == STDIN_FILENO ? fopen (TTY_NAME, "r") : stdin;
@@ -1511,14 +1422,12 @@ new_volume (enum access_mode access)
   if (verify_option)
     verify_volume ();
 
-  if (status = rmtclose (archive), status < 0)
-    {
-      int e = errno;
-      WARN ((0, e, _("WARNING: %s: close (%d, %d)"),
-            quotearg_colon (*archive_name_cursor), archive, status));
-    }
+  if (rmtclose (archive) != 0)
+    close_warn (*archive_name_cursor);
 
   global_volno++;
+  if (global_volno < 0)
+    FATAL_ERROR ((0, 0, _("Volume number overflow")));
   volno++;
   archive_name_cursor++;
   if (archive_name_cursor == archive_name_array + archive_names)
@@ -1536,7 +1445,8 @@ new_volume (enum access_mode access)
        {
          if (volno_file_option)
            closeout_volume_number ();
-         system (info_script_option);
+         if (system (info_script_option) != 0)
+           FATAL_ERROR ((0, 0, _("`%s' command failed"), info_script_option));
        }
       else
        while (1)
This page took 0.04714 seconds and 4 git commands to generate.