]> Dogcows Code - chaz/tar/blobdiff - src/buffer.c
Update FSF postal mail address.
[chaz/tar] / src / buffer.c
index d7c6844c4fd9da9eb8873d94991334f6ad4397ce..2f6df622a0aa49ff35daf5fcfa023124c6a1752a 100644 (file)
@@ -1,7 +1,7 @@
 /* Buffer management for tar.
 
    Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
-   2003, 2004 Free Software Foundation, Inc.
+   2003, 2004, 2005 Free Software Foundation, Inc.
 
    Written by John Gilmore, on 1985-08-25.
 
@@ -17,9 +17,9 @@
 
    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 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 
-#include "system.h"
+#include <system.h>
 
 #include <signal.h>
 
@@ -28,7 +28,7 @@
 #include <quotearg.h>
 
 #include "common.h"
-#include "rmt.h"
+#include <rmt.h>
 
 /* Number of retries before giving up on read.  */
 #define        READ_ERROR_MAX 10
@@ -67,11 +67,13 @@ static pid_t child_pid;
 static int read_error_count;
 
 /* Have we hit EOF yet?  */
-static int hit_eof;
+static bool hit_eof;
 
 /* Checkpointing counter */
 static int checkpoint;
 
+static bool read_full_records = false;
+
 /* We're reading, but we just read the last block and it's time to update.
    Declared in update.c
 
@@ -115,32 +117,147 @@ clear_read_error_count (void)
   read_error_count = 0;
 }
 
+\f
+/* Time-related functions */
+
+double duration;
+
 void
-print_total_written (void)
+set_start_time ()
 {
-  tarlong written = prev_written + bytes_written;
-  char bytes[sizeof (tarlong) * CHAR_BIT];
-  char abbr[LONGEST_HUMAN_READABLE + 1];
-  char rate[LONGEST_HUMAN_READABLE + 1];
-  double seconds;
-  int human_opts = human_autoscale | human_base_1024 | human_SI | human_B;
+#if HAVE_CLOCK_GETTIME
+  if (clock_gettime (CLOCK_REALTIME, &start_timespec) != 0)
+#endif
+    start_time = time (0);
+}
 
+void
+compute_duration ()
+{
 #if HAVE_CLOCK_GETTIME
   struct timespec now;
   if (clock_gettime (CLOCK_REALTIME, &now) == 0)
-    seconds = ((now.tv_sec - start_timespec.tv_sec)
-              + (now.tv_nsec - start_timespec.tv_nsec) / 1e9);
+    duration += ((now.tv_sec - start_timespec.tv_sec)
+                + (now.tv_nsec - start_timespec.tv_nsec) / 1e9);
   else
 #endif
-    seconds = time (0) - start_time;
+    duration += time (NULL) - start_time;
+  set_start_time ();
+}
+
+\f
+/* Compression detection */
+
+enum compress_type {
+  ct_none,
+  ct_compress,
+  ct_gzip,
+  ct_bzip2
+};
+
+struct zip_magic
+{
+  enum compress_type type;
+  size_t length;
+  char *magic;
+  char *program;
+  char *option;
+};
+
+static struct zip_magic const magic[] = {
+  { ct_none, },
+  { ct_compress, 2, "\037\235", "compress", "-Z" },
+  { ct_gzip,     2, "\037\213", "gzip", "-z"  },
+  { ct_bzip2,    3, "BZh",      "bzip2", "-j" },
+};
+
+#define NMAGIC (sizeof(magic)/sizeof(magic[0]))
+
+#define compress_option(t) magic[t].option
+#define compress_program(t) magic[t].program
+
+/* Check if the file ARCHIVE is a compressed archive. */
+enum compress_type
+check_compressed_archive ()
+{
+  struct zip_magic const *p;
+  bool sfr;
+
+  /* Prepare global data needed for find_next_block: */
+  record_end = record_start; /* set up for 1st record = # 0 */
+  sfr = read_full_records;
+  read_full_records = true; /* Suppress fatal error on reading a partial
+                              record */
+  find_next_block ();
+
+  /* Restore global values */
+  read_full_records = sfr;
+
+  if (tar_checksum (record_start, true) == HEADER_SUCCESS)
+    /* Probably a valid header */
+    return ct_none;
+
+  for (p = magic + 1; p < magic + NMAGIC; p++)
+    if (memcmp (record_start->buffer, p->magic, p->length) == 0)
+      return p->type;
+
+  return ct_none;
+}
+
+/* Open an archive named archive_name_array[0]. Detect if it is
+   a compressed archive of known type and use corresponding decompression
+   program if so */
+int
+open_compressed_archive ()
+{
+  archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
+                    MODE_RW, rsh_command_option);
+  if (archive == -1)
+    return archive;
+
+  if (!multi_volume_option)
+    {
+      enum compress_type type = check_compressed_archive ();
+
+      if (type == ct_none)
+       return archive;
+
+      /* FD is not needed any more */
+      rmtclose (archive);
+
+      hit_eof = false; /* It might have been set by find_next_block in
+                         check_compressed_archive */
+
+      /* Open compressed archive */
+      use_compress_program_option = compress_program (type);
+      child_pid = sys_child_open_for_uncompress ();
+      read_full_records = true;
+    }
+
+  records_read = 0;
+  record_end = record_start; /* set up for 1st record = # 0 */
+
+  return archive;
+}
+\f
+
+void
+print_total_written (void)
+{
+  tarlong written = prev_written + bytes_written;
+  char bytes[sizeof (tarlong) * CHAR_BIT];
+  char abbr[LONGEST_HUMAN_READABLE + 1];
+  char rate[LONGEST_HUMAN_READABLE + 1];
+
+  int human_opts = human_autoscale | human_base_1024 | human_SI | human_B;
 
   sprintf (bytes, TARLONG_FORMAT, written);
 
   /* Amanda 2.4.1p1 looks for "Total bytes written: [0-9][0-9]*".  */
   fprintf (stderr, _("Total bytes written: %s (%s, %s/s)\n"), bytes,
           human_readable (written, abbr, human_opts, 1, 1),
-          (0 < seconds && written / seconds < (uintmax_t) -1
-           ? human_readable (written / seconds, rate, human_opts, 1, 1)
+          (0 < duration && written / duration < (uintmax_t) -1
+           ? human_readable (written / duration, rate, human_opts, 1, 1)
            : "?"));
 }
 
@@ -157,7 +274,7 @@ reset_eof (void)
 {
   if (hit_eof)
     {
-      hit_eof = 0;
+      hit_eof = false;
       current_block = record_start;
       record_end = record_start + blocking_factor;
       access_mode = ACCESS_WRITE;
@@ -177,7 +294,7 @@ find_next_block (void)
       flush_archive ();
       if (current_block == record_end)
        {
-         hit_eof = 1;
+         hit_eof = true;
          return 0;
        }
     }
@@ -283,12 +400,18 @@ open_archive (enum access_mode wanted_access)
   /* When updating the archive, we start with reading.  */
   access_mode = wanted_access == ACCESS_UPDATE ? ACCESS_READ : wanted_access;
 
+  read_full_records = read_full_records_option;
+
+  records_read = 0;
+
   if (use_compress_program_option)
     {
       switch (wanted_access)
        {
        case ACCESS_READ:
          child_pid = sys_child_open_for_uncompress ();
+         read_full_records = true;
+         record_end = record_start; /* set up for 1st record = # 0 */
          break;
 
        case ACCESS_WRITE:
@@ -306,14 +429,24 @@ open_archive (enum access_mode wanted_access)
     }
   else if (strcmp (archive_name_array[0], "-") == 0)
     {
-      read_full_records_option = true; /* could be a pipe, be safe */
+      read_full_records = true; /* could be a pipe, be safe */
       if (verify_option)
        FATAL_ERROR ((0, 0, _("Cannot verify stdin/stdout archive")));
 
       switch (wanted_access)
        {
        case ACCESS_READ:
-         archive = STDIN_FILENO;
+         {
+           enum compress_type type;
+
+           archive = STDIN_FILENO;
+
+           type = check_compressed_archive (archive);
+           if (type != ct_none)
+             FATAL_ERROR ((0, 0,
+                           _("Archive is compressed. Use %s option"),
+                           compress_option (type)));
+         }
          break;
 
        case ACCESS_WRITE:
@@ -335,8 +468,7 @@ open_archive (enum access_mode wanted_access)
     switch (wanted_access)
       {
       case ACCESS_READ:
-       archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
-                          MODE_RW, rsh_command_option);
+       archive = open_compressed_archive ();
        break;
 
       case ACCESS_WRITE:
@@ -374,9 +506,9 @@ open_archive (enum access_mode wanted_access)
     {
     case ACCESS_UPDATE:
       records_written = 0;
-    case ACCESS_READ:
-      records_read = 0;
       record_end = record_start; /* set up for 1st record = # 0 */
+
+    case ACCESS_READ:
       find_next_block ();      /* read it in, check for EOF */
 
       if (volume_label_option)
@@ -425,6 +557,10 @@ flush_write (void)
   ssize_t status;
 
   if (checkpoint_option && !(++checkpoint % 10))
+    /* TRANSLATORS: This is a ``checkpoint of write operation'',
+       *not* ``Writing a checkpoint''.
+       E.g. in Spanish ``Punto de comprobaci@'on de escritura'',
+       *not* ``Escribiendo un punto de comprobaci@'on'' */
     WARN ((0, 0, _("Write checkpoint %d"), checkpoint));
 
   if (tape_length_option && tape_length_option <= bytes_written)
@@ -511,10 +647,10 @@ flush_write (void)
        record_start++;
 
       if (strlen (real_s_name) > NAME_FIELD_SIZE)
-       FATAL_ERROR ((0, 0,
-                     _("%s: file name too long to be stored in a GNU multivolume header"),
+       WARN ((0, 0,
+             _("%s: file name too long to be stored in a GNU multivolume header, truncated"),
                      quotearg_colon (real_s_name)));
-      
+
       memset (record_start, 0, BLOCKSIZE);
 
       /* FIXME: Michael P Urban writes: [a long name file] is being written
@@ -523,9 +659,11 @@ flush_write (void)
 
       strncpy (record_start->header.name, real_s_name, NAME_FIELD_SIZE);
       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,
                    record_start->oldgnu_header.offset);
+
       tmp = verbose_option;
       verbose_option = 0;
       finish_header (&current_stat_info, record_start, -1);
@@ -609,23 +747,16 @@ short_read (size_t status)
   left = record_size - status;
 
   while (left % BLOCKSIZE != 0
-        || (left && status && read_full_records_option))
+        || (left && status && read_full_records))
     {
       if (status)
        while ((status = rmtread (archive, more, left)) == SAFE_READ_ERROR)
          archive_read_error ();
 
       if (status == 0)
-       {
-         char buf[UINTMAX_STRSIZE_BOUND];
-
-         WARN((0, 0, _("Read %s bytes from %s"),
-               STRINGIFY_BIGINT (record_size - left, buf),
-               *archive_name_cursor));
-         break;
-       }
+       break;
 
-      if (! read_full_records_option)
+      if (! read_full_records)
        {
          unsigned long rest = record_size - left;
 
@@ -645,7 +776,7 @@ short_read (size_t status)
   /* FIXME: for size=0, multi-volume support.  On the first record, warn
      about the problem.  */
 
-  if (!read_full_records_option && verbose_option > 1
+  if (!read_full_records && verbose_option > 1
       && record_start_block == 0 && status != 0)
     {
       unsigned long rsize = (record_size - left) / BLOCKSIZE;
@@ -667,6 +798,10 @@ flush_read (void)
   size_t status;               /* result from system call */
 
   if (checkpoint_option && !(++checkpoint % 10))
+    /* TRANSLATORS: This is a ``checkpoint of read operation'',
+       *not* ``Reading a checkpoint''.
+       E.g. in Spanish ``Punto de comprobaci@'on de lectura'',
+       *not* ``Leyendo un punto de comprobaci@'on'' */
     WARN ((0, 0, _("Read checkpoint %d"), checkpoint));
 
   /* Clear the count of errors.  This only applies to a single call to
@@ -707,7 +842,7 @@ flush_read (void)
     }
 
   /* The condition below used to include
-             || (status > 0 && !read_full_records_option)
+             || (status > 0 && !read_full_records)
      This is incorrect since even if new_volume() succeeds, the
      subsequent call to rmtread will overwrite the chunk of data
      already read in the buffer, so the processing will fail */
@@ -896,13 +1031,13 @@ seek_archive (off_t size)
   off_t offset;
   off_t nrec, nblk;
   off_t skipped = (blocking_factor - (current_block - record_start));
-  
+
   size -= skipped * BLOCKSIZE;
-  
+
   if (size < record_size)
     return 0;
   /* FIXME: flush? */
-  
+
   /* Compute number of records to skip */
   nrec = size / record_size;
   offset = rmtlseek (archive, nrec * record_size, SEEK_CUR);
@@ -921,7 +1056,7 @@ seek_archive (off_t size)
   records_read += nblk / blocking_factor;
   record_start_block = offset - blocking_factor;
   current_block = record_end;
+
   return nblk;
 }
 
@@ -934,6 +1069,7 @@ close_archive (void)
 
   sys_drain_input_pipe ();
 
+  compute_duration ();
   if (verify_option)
     verify_volume ();
 
@@ -1031,7 +1167,8 @@ new_volume (enum access_mode mode)
          if (volno_file_option)
            closeout_volume_number ();
          if (system (info_script_option) != 0)
-           FATAL_ERROR ((0, 0, _("`%s' command failed"), info_script_option));
+           FATAL_ERROR ((0, 0, _("%s command failed"),
+                         quote (info_script_option)));
        }
       else
        while (1)
@@ -1115,7 +1252,7 @@ new_volume (enum access_mode mode)
 
   if (strcmp (archive_name_cursor[0], "-") == 0)
     {
-      read_full_records_option = true;
+      read_full_records = true;
       archive = STDIN_FILENO;
     }
   else if (verify_option)
@@ -1154,4 +1291,3 @@ new_volume (enum access_mode mode)
 
   return true;
 }
-
This page took 0.032344 seconds and 4 git commands to generate.