]> Dogcows Code - chaz/tar/blobdiff - src/buffer.c
Allocate one more byte than the size would indicate, since we're
[chaz/tar] / src / buffer.c
index b59efb2808c41af4b5a21343d60070aa7ba57e37..949505c0b912ceb1b3d52fdf3907571c1994adb9 100644 (file)
@@ -1,5 +1,8 @@
 /* Buffer management for tar.
-   Copyright 1988, 92, 93, 94, 96, 97, 99, 2000 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
 #include "system.h"
 
 #include <signal.h>
-#include <time.h>
-#ifndef time
-time_t time ();
-#endif
 
 #if MSDOS
 # include <process.h>
@@ -53,14 +52,16 @@ time_t time ();
 static tarlong prev_written;   /* bytes written on previous volumes */
 static tarlong bytes_written;  /* bytes written on this volume */
 
-/* FIXME: The following four variables should ideally be static to this
-   module.  However, this cannot be done yet, as update.c uses the first
-   three a lot, and compare.c uses the fourth.  The cleanup continues!  */
+/* FIXME: The following variables should ideally be static to this
+   module.  However, this cannot be done yet.  The cleanup continues!  */
 
 union block *record_start;     /* start of record of archive */
 union block *record_end;       /* last+1 block of archive record */
 union block *current_block;    /* current block of archive */
 enum access_mode access_mode;  /* how do we handle the archive */
+off_t records_read;            /* number of records read from this archive */
+off_t records_written;         /* likewise, for records written */
+
 static struct stat archive_stat; /* stat block for archive file */
 
 static off_t record_start_block; /* block ordinal at record_start */
@@ -118,7 +119,7 @@ off_t save_totsize;         /* total size of file we are writing, only
 off_t save_sizeleft;           /* where we are in the file we are writing,
                                   only valid if save_name is nonzero */
 
-int write_archive_to_stdout;
+bool write_archive_to_stdout;
 
 /* Used by flush_read and flush_write to store the real info about saved
    names.  */
@@ -300,7 +301,9 @@ write_archive_buffer (void)
     {
       written += status;
       if (written == record_size
-         || _isrmt (archive) || ! S_ISFIFO (archive_stat.st_mode))
+         || _isrmt (archive)
+         || ! (S_ISFIFO (archive_stat.st_mode)
+               || S_ISSOCK (archive_stat.st_mode)))
        break;
     }
 
@@ -448,7 +451,7 @@ child_open_for_compress (void)
 
       status = write_archive_buffer ();
       if (status != record_size)
-       archive_write_error (status);
+       archive_write_error (status);
     }
 
 #if 0
@@ -463,7 +466,7 @@ child_open_for_compress (void)
        waitpid_error (use_compress_program_option);
        break;
       }
-  
+
   if (WIFSIGNALED (wait_status))
     {
       kill (child_pid, WTERMSIG (wait_status));
@@ -584,17 +587,8 @@ 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;
        }
@@ -613,7 +607,7 @@ child_open_for_uncompress (void)
        waitpid_error (use_compress_program_option);
        break;
       }
-  
+
   if (WIFSIGNALED (wait_status))
     {
       kill (child_pid, WTERMSIG (wait_status));
@@ -637,6 +631,9 @@ 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;
 
@@ -811,8 +808,10 @@ open_archive (enum access_mode wanted_access)
 
   switch (wanted_access)
     {
-    case ACCESS_READ:
     case ACCESS_UPDATE:
+      records_written = 0;
+    case ACCESS_READ:
+      records_read = 0;
       record_end = record_start; /* set up for 1st record = # 0 */
       find_next_block ();      /* read it in, check for EOF */
 
@@ -831,6 +830,7 @@ open_archive (enum access_mode wanted_access)
       break;
 
     case ACCESS_WRITE:
+      records_written = 0;
       if (volume_label_option)
        {
          memset (record_start, 0, BLOCKSIZE);
@@ -876,7 +876,10 @@ flush_write (void)
     archive_write_error (status);
 
   if (status > 0)
-    bytes_written += status;
+    {
+      records_written++;
+      bytes_written += status;
+    }
 
   if (status == record_size)
     {
@@ -893,7 +896,7 @@ flush_write (void)
            }
 
          cursor = save_name + FILESYSTEM_PREFIX_LEN (save_name);
-         while (*cursor == '/')
+         while (ISSLASH (*cursor))
            cursor++;
 
          assign_string (&real_s_name, cursor);
@@ -957,7 +960,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;
@@ -990,7 +993,7 @@ flush_write (void)
        {
          char *cursor = save_name + FILESYSTEM_PREFIX_LEN (save_name);
 
-         while (*cursor == '/')
+         while (ISSLASH (*cursor))
            cursor++;
 
          assign_string (&real_s_name, cursor);
@@ -1067,7 +1070,7 @@ flush_read (void)
        {
          char *cursor = save_name + FILESYSTEM_PREFIX_LEN (save_name);
 
-         while (*cursor == '/')
+         while (ISSLASH (*cursor))
            cursor++;
 
          assign_string (&real_s_name, cursor);
@@ -1085,7 +1088,10 @@ flush_read (void)
  error_loop:
   status = rmtread (archive, record_start->buffer, record_size);
   if (status == record_size)
-    return;
+    {
+      records_read++;
+      return;
+    }
 
   if ((status == 0
        || (status < 0 && errno == ENOSPC)
@@ -1162,7 +1168,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),
@@ -1183,6 +1189,7 @@ flush_read (void)
          cursor++;
        }
       current_block = cursor;
+      records_read++;
       return;
     }
   else if (status < 0)
@@ -1195,7 +1202,8 @@ 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))
     {
       if (status)
        while ((status = rmtread (archive, more, left)) < 0)
@@ -1203,15 +1211,16 @@ flush_read (void)
 
       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;
@@ -1227,6 +1236,7 @@ flush_read (void)
           (unsigned long) ((record_size - left) / BLOCKSIZE)));
 
   record_end = record_start + (record_size - left) / BLOCKSIZE;
+  records_read++;
 }
 
 /*  Flush the current buffer to/from the archive.  */
@@ -1327,7 +1337,7 @@ close_archive (void)
 
   if (access_mode == ACCESS_READ
       && ! _isrmt (archive)
-      && S_ISFIFO (archive_stat.st_mode))
+      && (S_ISFIFO (archive_stat.st_mode) || S_ISSOCK (archive_stat.st_mode)))
     while (rmtread (archive, record_start->buffer, record_size) > 0)
       continue;
 #endif
@@ -1379,7 +1389,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)
@@ -1428,6 +1441,8 @@ new_volume (enum access_mode access)
     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)
@@ -1445,7 +1460,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.035447 seconds and 4 git commands to generate.