]> Dogcows Code - chaz/tar/blobdiff - src/buffer.c
(new_volume): Initialize current_block
[chaz/tar] / src / buffer.c
index 1b36051e19c784f7e5588162c8f7b06a92ea2f3c..57b271527ba3d4c64dbad00d04ba92ed9cfb44c2 100644 (file)
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 
 #include <system.h>
+#include <system-ioctl.h>
 
 #include <signal.h>
 
 #include <closeout.h>
 #include <fnmatch.h>
+#include <getline.h>
 #include <human.h>
 #include <quotearg.h>
 
@@ -42,6 +44,7 @@
 static tarlong prev_written;   /* bytes written on previous volumes */
 static tarlong bytes_written;  /* bytes written on this volume */
 static void *record_buffer[2]; /* allocated memory */
+union block *record_buffer_aligned[2];
 static int record_index;
 
 /* FIXME: The following variables should ideally be static to this
@@ -53,6 +56,8 @@ 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 */
+extern off_t records_skipped;   /* number of records skipped at the start
+                                  of the archive, defined in delete.c */   
 
 static off_t record_start_block; /* block ordinal at record_start */
 
@@ -71,7 +76,7 @@ static int read_error_count;
 static bool hit_eof;
 
 /* Checkpointing counter */
-static int checkpoint;
+static unsigned checkpoint;
 
 static bool read_full_records = false;
 
@@ -163,6 +168,15 @@ void
 set_start_time ()
 {
   gettime (&start_time);
+  volume_start_time = start_time;
+  last_stat_time = start_time;
+}
+
+void
+set_volume_start_time ()
+{
+  gettime (&volume_start_time);
+  last_stat_time = volume_start_time;
 }
 
 void
@@ -170,9 +184,9 @@ compute_duration ()
 {
   struct timespec now;
   gettime (&now);
-  duration += ((now.tv_sec - start_time.tv_sec)
-              + (now.tv_nsec - start_time.tv_nsec) / 1e9);
-  set_start_time ();
+  duration += ((now.tv_sec - last_stat_time.tv_sec)
+              + (now.tv_nsec - last_stat_time.tv_nsec) / 1e9);
+  gettime (&last_stat_time);
 }
 
 \f
@@ -271,26 +285,65 @@ open_compressed_archive ()
 }
 \f
 
-void
-print_total_written (void)
+static void
+print_stats (FILE *fp, const char *text, tarlong numbytes)
 {
-  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);
+  sprintf (bytes, TARLONG_FORMAT, numbytes);
 
-  /* 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 < duration && written / duration < (uintmax_t) -1
-           ? human_readable (written / duration, rate, human_opts, 1, 1)
+  fprintf (fp, "%s: %s (%s, %s/s)\n",
+          text, bytes,
+          human_readable (numbytes, abbr, human_opts, 1, 1),
+          (0 < duration && numbytes / duration < (uintmax_t) -1
+           ? human_readable (numbytes / duration, rate, human_opts, 1, 1)
            : "?"));
 }
 
+void
+print_total_stats ()
+{
+  switch (subcommand_option)
+    {
+    case CREATE_SUBCOMMAND:
+    case CAT_SUBCOMMAND:
+    case UPDATE_SUBCOMMAND:
+    case APPEND_SUBCOMMAND:
+      /* Amanda 2.4.1p1 looks for "Total bytes written: [0-9][0-9]*".  */
+      print_stats (stderr, _("Total bytes written"),
+                  prev_written + bytes_written);
+      break;
+
+    case DELETE_SUBCOMMAND:
+      {
+       char buf[UINTMAX_STRSIZE_BOUND];
+       print_stats (stderr, _("Total bytes read"),
+                    records_read * record_size);
+       print_stats (stderr, _("Total bytes written"),
+                    prev_written + bytes_written);
+       fprintf (stderr, _("Total bytes deleted: %s\n"),
+                STRINGIFY_BIGINT ((records_read - records_skipped)
+                                   * record_size
+                                  - (prev_written + bytes_written), buf));
+      }
+      break;
+
+    case EXTRACT_SUBCOMMAND:
+    case LIST_SUBCOMMAND:
+    case DIFF_SUBCOMMAND:
+      print_stats (stderr, _("Total bytes read"),
+                  records_read * record_size);
+      break;
+
+    default:
+      abort ();
+    }
+}
+
 /* Compute and return the block ordinal at current_block.  */
 off_t
 current_block_ordinal (void)
@@ -367,10 +420,11 @@ xclose (int fd)
 static void
 init_buffer ()
 {
-  if (!record_buffer[record_index])
-    page_aligned_alloc (&record_buffer[record_index], record_size);
+  if (! record_buffer_aligned[record_index])
+    record_buffer_aligned[record_index] =
+      page_aligned_alloc (&record_buffer[record_index], record_size);
 
-  record_start = record_buffer[record_index];
+  record_start = record_buffer_aligned[record_index];
   current_block = record_start;
   record_end = record_start + blocking_factor;
 }
@@ -382,16 +436,6 @@ _open_archive (enum access_mode wanted_access)
 {
   int backed_up_flag = 0;
 
-  if (index_file_name)
-    {
-      stdlis = freopen (index_file_name, "w", stdout);
-      if (! stdlis)
-       open_error (index_file_name);
-      close_stdout_set_file_name (index_file_name);
-    }
-  else
-    stdlis = to_stdout_option ? stderr : stdout;
-
   if (record_size == 0)
     FATAL_ERROR ((0, 0, _("Invalid value for record_size")));
 
@@ -430,10 +474,6 @@ _open_archive (enum access_mode wanted_access)
          abort (); /* Should not happen */
          break;
        }
-
-      if (wanted_access == ACCESS_WRITE
-         && strcmp (archive_name_array[0], "-") == 0)
-       stdlis = stderr;
     }
   else if (strcmp (archive_name_array[0], "-") == 0)
     {
@@ -449,7 +489,7 @@ _open_archive (enum access_mode wanted_access)
 
            archive = STDIN_FILENO;
 
-           type = check_compressed_archive (archive);
+           type = check_compressed_archive ();
            if (type != ct_none)
              FATAL_ERROR ((0, 0,
                            _("Archive is compressed. Use %s option"),
@@ -459,13 +499,12 @@ _open_archive (enum access_mode wanted_access)
 
        case ACCESS_WRITE:
          archive = STDOUT_FILENO;
-         stdlis = stderr;
          break;
 
        case ACCESS_UPDATE:
          archive = STDIN_FILENO;
-         stdlis = stderr;
          write_archive_to_stdout = true;
+         record_end = record_start; /* set up for 1st record = # 0 */
          break;
        }
     }
@@ -490,8 +529,13 @@ _open_archive (enum access_mode wanted_access)
        break;
 
       case ACCESS_UPDATE:
-       archive = rmtopen (archive_name_array[0], O_RDWR | O_CREAT | O_BINARY,
+       archive = rmtopen (archive_name_array[0],
+                          O_RDWR | O_CREAT | O_BINARY,
                           MODE_RW, rsh_command_option);
+
+       if (check_compressed_archive () != ct_none)
+         FATAL_ERROR ((0, 0,
+                       _("Cannot update compressed archives")));
        break;
       }
 
@@ -512,33 +556,54 @@ _open_archive (enum access_mode wanted_access)
 
   switch (wanted_access)
     {
-    case ACCESS_UPDATE:
-      records_written = 0;
-      record_end = record_start; /* set up for 1st record = # 0 */
-
     case ACCESS_READ:
       find_next_block ();      /* read it in, check for EOF */
       break;
 
+    case ACCESS_UPDATE:
     case ACCESS_WRITE:
       records_written = 0;
       break;
     }
 }
 
+static void
+do_checkpoint (bool write)
+{
+  if (checkpoint_option && !(++checkpoint % checkpoint_option))
+    {
+      switch (checkpoint_style)
+       {
+       case checkpoint_dot:
+         fputc ('.', stdlis);
+         fflush (stdlis);
+         break;
+
+       case checkpoint_text:
+         if (write)
+           /* 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 %u"), checkpoint));
+         else
+           /* 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 %u"), checkpoint));
+         break;
+       }
+    }
+}  
+
 /* Perform a write to flush the buffer.  */
 ssize_t
 _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));
-
+  do_checkpoint (true);
   if (tape_length_option && tape_length_option <= bytes_written)
     {
       errno = ENOSPC;
@@ -563,7 +628,7 @@ archive_write_error (ssize_t status)
   if (totals_option)
     {
       int e = errno;
-      print_total_written ();
+      print_total_stats ();
       errno = e;
     }
 
@@ -642,39 +707,6 @@ short_read (size_t status)
   records_read++;
 }
 
-/* Perform a read to flush the buffer.  */
-size_t
-_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
-     flush_read.  */
-
-  read_error_count = 0;                /* clear error count */
-
-  if (write_archive_to_stdout && record_start_block != 0)
-    {
-      archive = STDOUT_FILENO;
-      status = sys_write_archive_buffer ();
-      archive = STDIN_FILENO;
-      if (status != record_size)
-       archive_write_error (status);
-    }
-
-  status = rmtread (archive, record_start->buffer, record_size);
-  if (status == record_size)
-    records_read++;
-  return status;
-}
-
 /*  Flush the current buffer to/from the archive.  */
 void
 flush_archive (void)
@@ -870,8 +902,9 @@ change_tape_menu (FILE *read_file)
 {
   char *input_buffer = NULL;
   size_t size = 0;
-
-  while (1)
+  bool stop = false;
+  
+  while (!stop)
     {
       fputc ('\007', stderr);
       fprintf (stderr,
@@ -901,7 +934,7 @@ change_tape_menu (FILE *read_file)
        case '?':
          {
            fprintf (stderr, _("\
- n [name]      Give a new file name for the next (and subsequent) volume(s)\n\
+ n name        Give a new file name for the next (and subsequent) volume(s)\n\
  q             Abort tar\n\
  y or newline  Continue operation\n"));
             if (!restrict_option)
@@ -938,8 +971,15 @@ change_tape_menu (FILE *read_file)
              ;
            *cursor = '\0';
 
-           /* FIXME: the following allocation is never reclaimed.  */
-           *archive_name_cursor = xstrdup (name);
+           if (name[0])
+             {
+               /* FIXME: the following allocation is never reclaimed.  */
+               *archive_name_cursor = xstrdup (name);
+               stop = true;
+             }
+           else
+             fprintf (stderr, "%s",
+                      _("File name not specified. Try again.\n"));
          }
          break;
 
@@ -966,6 +1006,7 @@ new_volume (enum access_mode mode)
 {
   static FILE *read_file;
   static int looped;
+  int prompt;
 
   if (!read_file && !info_script_option)
     /* FIXME: if fopen is used, it will never be closed.  */
@@ -979,7 +1020,8 @@ new_volume (enum access_mode mode)
   assign_string (&volume_label, NULL);
   assign_string (&continued_file_name, NULL);
   continued_file_size = continued_file_offset = 0;
-
+  current_block = record_start;
+  
   if (rmtclose (archive) != 0)
     close_warn (*archive_name_cursor);
 
@@ -989,9 +1031,10 @@ new_volume (enum access_mode mode)
       archive_name_cursor = archive_name_array;
       looped = 1;
     }
+  prompt = looped;
 
  tryagain:
-  if (looped)
+  if (prompt)
     {
       /* We have to prompt from now on.  */
 
@@ -1041,6 +1084,7 @@ new_volume (enum access_mode mode)
       open_warn (*archive_name_cursor);
       if (!verify_option && mode == ACCESS_WRITE && backup_option)
        undo_last_backup ();
+      prompt = 1;
       goto tryagain;
     }
 
@@ -1050,10 +1094,12 @@ new_volume (enum access_mode mode)
 }
 
 static bool
-read_header0 ()
+read_header0 (struct tar_stat_info *info)
 {
-  enum read_header rc = read_header (false);
+  enum read_header rc;
 
+  tar_stat_init (info);
+  rc = read_header_primitive (false, info);
   if (rc == HEADER_SUCCESS)
     {
       set_next_block_after (current_header);
@@ -1068,22 +1114,25 @@ try_new_volume ()
 {
   size_t status;
   union block *header;
-
+  struct tar_stat_info dummy;
+  int access;
+  
   switch (subcommand_option)
     {
     case APPEND_SUBCOMMAND:
     case CAT_SUBCOMMAND:
     case UPDATE_SUBCOMMAND:
-      if (!new_volume (ACCESS_UPDATE))
-       return true;
+      access = ACCESS_UPDATE;
       break;
 
     default:
-      if (!new_volume (ACCESS_READ))
-       return true;
+      access = ACCESS_READ;
       break;
     }
 
+  if (!new_volume (access))
+    return true;
+  
   while ((status = rmtread (archive, record_start->buffer, record_size))
         == SAFE_READ_ERROR)
     archive_read_error ();
@@ -1094,14 +1143,13 @@ try_new_volume ()
   header = find_next_block ();
   if (!header)
     return false;
+
   switch (header->header.typeflag)
     {
     case XGLTYPE:
       {
-       struct tar_stat_info dummy;
-       if (!read_header0 ())
+       if (!read_header0 (&dummy))
          return false;
-       tar_stat_init (&dummy);
        xheader_decode (&dummy); /* decodes values from the global header */
        tar_stat_destroy (&dummy);
        if (!real_s_name)
@@ -1115,8 +1163,9 @@ try_new_volume ()
       }
 
     case GNUTYPE_VOLHDR:
-      if (!read_header0 ())
+      if (!read_header0 (&dummy))
        return false;
+      tar_stat_destroy (&dummy);
       assign_string (&volume_label, current_header->header.name);
       set_next_block_after (header);
       header = find_next_block ();
@@ -1125,8 +1174,9 @@ try_new_volume ()
       /* FALL THROUGH */
 
     case GNUTYPE_MULTIVOL:
-      if (!read_header0 ())
+      if (!read_header0 (&dummy))
        return false;
+      tar_stat_destroy (&dummy);
       assign_string (&continued_file_name, current_header->header.name);
       continued_file_size =
        UINTMAX_FROM_HEADER (current_header->header.size);
@@ -1144,9 +1194,19 @@ try_new_volume ()
       if (!continued_file_name
          || strcmp (continued_file_name, real_s_name))
        {
-         WARN ((0, 0, _("%s is not continued on this volume"),
-                quote (real_s_name)));
-         return false;
+         if ((archive_format == GNU_FORMAT || archive_format == OLDGNU_FORMAT)
+             && strlen (real_s_name) >= NAME_FIELD_SIZE
+             && strncmp (continued_file_name, real_s_name,
+                         NAME_FIELD_SIZE) == 0)
+           WARN ((0, 0,
+ _("%s is possibly continued on this volume: header contains truncated name"),
+                  quote (real_s_name)));
+         else
+           {
+             WARN ((0, 0, _("%s is not continued on this volume"),
+                    quote (real_s_name)));
+             return false;
+           }
        }
 
       s = continued_file_size + continued_file_offset;
@@ -1285,10 +1345,10 @@ add_chunk_header ()
 
       block_ordinal = current_block_ordinal ();
       blk = start_header (&st);
-      free (st.orig_file_name);
       if (!blk)
        abort (); /* FIXME */
       finish_header (&st, blk, block_ordinal);
+      free (st.orig_file_name);
     }
 }
 
@@ -1383,13 +1443,8 @@ simple_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));
-
+  do_checkpoint (false);
+  
   /* Clear the count of errors.  This only applies to a single call to
      flush_read.  */
 
@@ -1447,13 +1502,8 @@ _gnu_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));
-
+  do_checkpoint (false);
+  
   /* Clear the count of errors.  This only applies to a single call to
      flush_read.  */
 
@@ -1545,8 +1595,7 @@ _gnu_flush_write (size_t buffer_level)
   xheader_destroy (&extended_header);
 
   increase_volume_number ();
-  if (totals_option)
-    prev_written += bytes_written;
+  prev_written += bytes_written;
   bytes_written = 0;
 
   copy_ptr = record_start->buffer + status;
@@ -1624,4 +1673,5 @@ open_archive (enum access_mode wanted_access)
     default:
       break;
     }
+  set_volume_start_time ();
 }
This page took 0.03466 seconds and 4 git commands to generate.