]> Dogcows Code - chaz/tar/blobdiff - src/buffer.c
(new_volume): Initialize current_block
[chaz/tar] / src / buffer.c
index 367a93a0796d75c9561646560f5b7deaf50a46ae..57b271527ba3d4c64dbad00d04ba92ed9cfb44c2 100644 (file)
@@ -1,7 +1,7 @@
 /* Buffer management for tar.
 
    Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
-   2003, 2004, 2005 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
    Written by John Gilmore, on 1985-08-25.
 
    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>
 
@@ -41,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
@@ -52,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 */
 
@@ -70,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;
 
@@ -84,6 +90,9 @@ extern bool time_to_start_writing;
 
 bool write_archive_to_stdout;
 
+void (*flush_write_ptr) (size_t);
+void (*flush_read_ptr) (void);
+
 \f
 char *volume_label;
 char *continued_file_name;
@@ -159,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
@@ -166,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
@@ -267,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)
@@ -363,10 +420,11 @@ xclose (int fd)
 static void
 init_buffer ()
 {
-  if (!record_buffer[record_index])
-    page_aligned_alloc (&record_buffer[record_index], record_size);
-      
-  record_start = record_buffer[record_index];
+  if (! record_buffer_aligned[record_index])
+    record_buffer_aligned[record_index] =
+      page_aligned_alloc (&record_buffer[record_index], record_size);
+
+  record_start = record_buffer_aligned[record_index];
   current_block = record_start;
   record_end = record_start + blocking_factor;
 }
@@ -378,15 +436,6 @@ _open_archive (enum access_mode wanted_access)
 {
   int backed_up_flag = 0;
 
-  if (index_file_name)
-    {
-      stdlis = fopen (index_file_name, "w");
-      if (! stdlis)
-       open_error (index_file_name);
-    }
-  else
-    stdlis = to_stdout_option ? stderr : stdout;
-
   if (record_size == 0)
     FATAL_ERROR ((0, 0, _("Invalid value for record_size")));
 
@@ -399,7 +448,7 @@ _open_archive (enum access_mode wanted_access)
 
   record_index = 0;
   init_buffer ();
-  
+
   /* When updating the archive, we start with reading.  */
   access_mode = wanted_access == ACCESS_UPDATE ? ACCESS_READ : wanted_access;
 
@@ -425,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)
     {
@@ -444,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"),
@@ -454,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;
        }
     }
@@ -485,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;
       }
 
@@ -507,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;
@@ -558,7 +628,7 @@ archive_write_error (ssize_t status)
   if (totals_option)
     {
       int e = errno;
-      print_total_written ();
+      print_total_stats ();
       errno = e;
     }
 
@@ -637,43 +707,11 @@ 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)
 {
+  size_t buffer_level = current_block->buffer - record_start->buffer;
   record_start_block += record_end - record_start;
   current_block = record_start;
   record_end = record_start + blocking_factor;
@@ -692,7 +730,7 @@ flush_archive (void)
       break;
 
     case ACCESS_WRITE:
-      flush_write ();
+      flush_write_ptr (buffer_level);
       break;
 
     case ACCESS_UPDATE:
@@ -784,7 +822,11 @@ void
 close_archive (void)
 {
   if (time_to_start_writing || access_mode == ACCESS_WRITE)
-    flush_archive ();
+    {
+      flush_archive ();
+      if (current_block > record_start)
+       flush_archive ();
+    }
 
   sys_drain_input_pipe ();
 
@@ -855,6 +897,107 @@ increase_volume_number ()
   volno++;
 }
 
+void
+change_tape_menu (FILE *read_file)
+{
+  char *input_buffer = NULL;
+  size_t size = 0;
+  bool stop = false;
+  
+  while (!stop)
+    {
+      fputc ('\007', stderr);
+      fprintf (stderr,
+              _("Prepare volume #%d for %s and hit return: "),
+              global_volno + 1, quote (*archive_name_cursor));
+      fflush (stderr);
+
+      if (getline (&input_buffer, &size, read_file) <= 0)
+       {
+         WARN ((0, 0, _("EOF where user reply was expected")));
+
+         if (subcommand_option != EXTRACT_SUBCOMMAND
+             && subcommand_option != LIST_SUBCOMMAND
+             && subcommand_option != DIFF_SUBCOMMAND)
+           WARN ((0, 0, _("WARNING: Archive is incomplete")));
+
+         fatal_exit ();
+       }
+
+      if (input_buffer[0] == '\n'
+         || input_buffer[0] == 'y'
+         || input_buffer[0] == 'Y')
+       break;
+
+      switch (input_buffer[0])
+       {
+       case '?':
+         {
+           fprintf (stderr, _("\
+ 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)
+              fprintf (stderr, _(" !             Spawn a subshell\n"));
+           fprintf (stderr, _(" ?             Print this list\n"));
+         }
+         break;
+
+       case 'q':
+         /* Quit.  */
+
+         WARN ((0, 0, _("No new volume; exiting.\n")));
+
+         if (subcommand_option != EXTRACT_SUBCOMMAND
+             && subcommand_option != LIST_SUBCOMMAND
+             && subcommand_option != DIFF_SUBCOMMAND)
+           WARN ((0, 0, _("WARNING: Archive is incomplete")));
+
+         fatal_exit ();
+
+       case 'n':
+         /* Get new file name.  */
+
+         {
+           char *name;
+           char *cursor;
+
+           for (name = input_buffer + 1;
+                *name == ' ' || *name == '\t';
+                name++)
+             ;
+
+           for (cursor = name; *cursor && *cursor != '\n'; cursor++)
+             ;
+           *cursor = '\0';
+
+           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;
+
+       case '!':
+         if (!restrict_option)
+           {
+             sys_spawn_shell ();
+             break;
+           }
+         /* FALL THROUGH */
+
+       default:
+         fprintf (stderr, _("Invalid input. Type ? for help.\n"));
+       }
+    }
+  free (input_buffer);
+}
+
 /* We've hit the end of the old volume.  Close it and open the next one.
    Return nonzero on success.
 */
@@ -863,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.  */
@@ -876,6 +1020,7 @@ 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);
@@ -886,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.  */
 
@@ -896,88 +1042,12 @@ new_volume (enum access_mode mode)
        {
          if (volno_file_option)
            closeout_volume_number ();
-         if (system (info_script_option) != 0)
+         if (sys_exec_info_script (archive_name_cursor, global_volno+1))
            FATAL_ERROR ((0, 0, _("%s command failed"),
                          quote (info_script_option)));
        }
       else
-       while (1)
-         {
-           char input_buffer[80];
-
-           fputc ('\007', stderr);
-           fprintf (stderr,
-                    _("Prepare volume #%d for %s and hit return: "),
-                    global_volno + 1, quote (*archive_name_cursor));
-           fflush (stderr);
-
-           if (fgets (input_buffer, sizeof input_buffer, read_file) == 0)
-             {
-               WARN ((0, 0, _("EOF where user reply was expected")));
-
-               if (subcommand_option != EXTRACT_SUBCOMMAND
-                   && subcommand_option != LIST_SUBCOMMAND
-                   && subcommand_option != DIFF_SUBCOMMAND)
-                 WARN ((0, 0, _("WARNING: Archive is incomplete")));
-
-               fatal_exit ();
-             }
-           if (input_buffer[0] == '\n'
-               || input_buffer[0] == 'y'
-               || input_buffer[0] == 'Y')
-             break;
-
-           switch (input_buffer[0])
-             {
-             case '?':
-               {
-                 /* FIXME: Might it be useful to disable the '!' command? */
-                 fprintf (stderr, _("\
- n [name]   Give a new file name for the next (and subsequent) volume(s)\n\
- q          Abort tar\n\
- !          Spawn a subshell\n\
- ?          Print this list\n"));
-               }
-               break;
-
-             case 'q':
-               /* Quit.  */
-
-               WARN ((0, 0, _("No new volume; exiting.\n")));
-
-               if (subcommand_option != EXTRACT_SUBCOMMAND
-                   && subcommand_option != LIST_SUBCOMMAND
-                   && subcommand_option != DIFF_SUBCOMMAND)
-                 WARN ((0, 0, _("WARNING: Archive is incomplete")));
-
-               fatal_exit ();
-
-             case 'n':
-               /* Get new file name.  */
-
-               {
-                 char *name = &input_buffer[1];
-                 char *cursor;
-
-                 for (name = input_buffer + 1;
-                      *name == ' ' || *name == '\t';
-                      name++)
-                   ;
-
-                 for (cursor = name; *cursor && *cursor != '\n'; cursor++)
-                   ;
-                 *cursor = '\0';
-
-                 /* FIXME: the following allocation is never reclaimed.  */
-                 *archive_name_cursor = xstrdup (name);
-               }
-               break;
-
-             case '!':
-               sys_spawn_shell ();
-               break;
-             }
-         }
+       change_tape_menu (read_file);
     }
 
   if (strcmp (archive_name_cursor[0], "-") == 0)
@@ -1014,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;
     }
 
@@ -1021,29 +1092,47 @@ new_volume (enum access_mode mode)
 
   return true;
 }
-      
+
+static bool
+read_header0 (struct tar_stat_info *info)
+{
+  enum read_header rc;
+
+  tar_stat_init (info);
+  rc = read_header_primitive (false, info);
+  if (rc == HEADER_SUCCESS)
+    {
+      set_next_block_after (current_header);
+      return true;
+    }
+  ERROR ((0, 0, _("This does not look like a tar archive")));
+  return false;
+}
+
 bool
 try_new_volume ()
 {
   size_t status;
-  enum read_header rc;
-  union block *block;
+  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 ();
@@ -1051,60 +1140,73 @@ try_new_volume ()
   if (status != record_size)
     short_read (status);
 
- again:
-  block = current_block;
-  rc = read_header (true);
-  switch (rc)
+  header = find_next_block ();
+  if (!header)
+    return false;
+
+  switch (header->header.typeflag)
     {
-    case HEADER_SUCCESS_EXTENDED:
-      if (current_header->header.typeflag == XGLTYPE)
-       {
-         struct tar_stat_info dummy;
-         xheader_read (current_header,
-                       OFF_FROM_HEADER (current_header->header.size));
-         xheader_decode_global ();
-         xheader_destroy (&extended_header);
-         tar_stat_init (&dummy);
-         xheader_decode (&dummy); /* decodes values from the global header */
-         tar_stat_destroy (&dummy);
-       }
-      break;
-      
-    case HEADER_SUCCESS:
-      if (current_header->header.typeflag == GNUTYPE_VOLHDR)
-       assign_string (&volume_label, current_header->header.name);
-      else if (current_header->header.typeflag == GNUTYPE_MULTIVOL)
-       {
-         assign_string (&continued_file_name, current_header->header.name);
-         continued_file_size =
-              UINTMAX_FROM_HEADER (current_header->header.size);
-         continued_file_offset =
-              UINTMAX_FROM_HEADER (current_header->oldgnu_header.offset);
-       }
-      else
+    case XGLTYPE:
+      {
+       if (!read_header0 (&dummy))
+         return false;
+       xheader_decode (&dummy); /* decodes values from the global header */
+       tar_stat_destroy (&dummy);
+       if (!real_s_name)
+         {
+           /* We have read the extended header of the first member in
+              this volume. Put it back, so next read_header works as
+              expected. */
+           current_block = record_start;
+         }
        break;
-      set_next_block_after (current_header);
-      goto again;
+      }
 
-    case HEADER_ZERO_BLOCK:
-    case HEADER_END_OF_FILE:
-    case HEADER_FAILURE:
-      current_block = block;
+    case GNUTYPE_VOLHDR:
+      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 ();
+      if (header->header.typeflag != GNUTYPE_MULTIVOL)
+       break;
+      /* FALL THROUGH */
+
+    case GNUTYPE_MULTIVOL:
+      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);
+      continued_file_offset =
+       UINTMAX_FROM_HEADER (current_header->oldgnu_header.offset);
       break;
 
     default:
-      abort ();
+      break;
     }
 
   if (real_s_name)
     {
       uintmax_t s;
-      if (continued_file_name 
-         && strcmp (continued_file_name, real_s_name))
+      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;
@@ -1122,7 +1224,7 @@ try_new_volume ()
                 STRINGIFY_BIGINT (continued_file_offset, s2buf)));
          return false;
        }
-      
+
       if (real_s_totsize - real_s_sizeleft != continued_file_offset)
        {
          WARN ((0, 0, _("This volume is out of sequence")));
@@ -1188,7 +1290,7 @@ _write_volume_label (const char *str)
   else
     {
       union block *label = find_next_block ();
-      
+
       memset (label, 0, BLOCKSIZE);
 
       strcpy (label->header.name, volume_label_option);
@@ -1219,6 +1321,38 @@ add_volume_label (void)
   free (s);
 }
 
+static void
+add_chunk_header ()
+{
+  if (archive_format == POSIX_FORMAT)
+    {
+      off_t block_ordinal;
+      union block *blk;
+      struct tar_stat_info st;
+      static size_t real_s_part_no; /* FIXME */
+
+      real_s_part_no++;
+      memset (&st, 0, sizeof st);
+      st.orig_file_name = st.file_name = real_s_name;
+      st.stat.st_mode = S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
+      st.stat.st_uid = getuid ();
+      st.stat.st_gid = getgid ();
+      st.orig_file_name = xheader_format_name (&st,
+                                              "%d/GNUFileParts.%p/%f.%n",
+                                              real_s_part_no);
+      st.file_name = st.orig_file_name;
+      st.archive_file_size = st.stat.st_size = real_s_sizeleft;
+
+      block_ordinal = current_block_ordinal ();
+      blk = start_header (&st);
+      if (!blk)
+       abort (); /* FIXME */
+      finish_header (&st, blk, block_ordinal);
+      free (st.orig_file_name);
+    }
+}
+
+
 /* Add a volume label to the current archive */
 static void
 write_volume_label (void)
@@ -1235,25 +1369,25 @@ gnu_add_multi_volume_header (void)
 {
   int tmp;
   union block *block = find_next_block ();
-  
+
   if (strlen (real_s_name) > NAME_FIELD_SIZE)
     WARN ((0, 0,
           _("%s: file name too long to be stored in a GNU multivolume header, truncated"),
           quotearg_colon (real_s_name)));
-  
+
   memset (block, 0, BLOCKSIZE);
-  
+
   /* FIXME: Michael P Urban writes: [a long name file] is being written
      when a new volume rolls around [...]  Looks like the wrong value is
      being preserved in real_s_name, though.  */
-  
+
   strncpy (block->header.name, real_s_name, NAME_FIELD_SIZE);
   block->header.typeflag = GNUTYPE_MULTIVOL;
-  
+
   OFF_TO_CHARS (real_s_sizeleft, block->header.size);
   OFF_TO_CHARS (real_s_totsize - real_s_sizeleft,
                block->oldgnu_header.offset);
-  
+
   tmp = verbose_option;
   verbose_option = 0;
   finish_header (&current_stat_info, block, -1);
@@ -1269,6 +1403,7 @@ add_multi_volume_header (void)
   if (archive_format == POSIX_FORMAT)
     {
       off_t d = real_s_totsize - real_s_sizeleft;
+      xheader_store ("GNU.volume.filename", NULL, real_s_name);
       xheader_store ("GNU.volume.size", NULL, &real_s_sizeleft);
       xheader_store ("GNU.volume.offset", NULL, &d);
     }
@@ -1308,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.  */
 
@@ -1328,7 +1458,7 @@ simple_flush_read (void)
       if (status != record_size)
        archive_write_error (status);
     }
-  
+
   for (;;)
     {
       status = rmtread (archive, record_start->buffer, record_size);
@@ -1349,7 +1479,7 @@ simple_flush_read (void)
 
 /* Simple flush write (no multi-volume or label extensions) */
 static void
-simple_flush_write (void)
+simple_flush_write (size_t level __attribute__((unused)))
 {
   ssize_t status;
 
@@ -1372,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.  */
 
@@ -1420,7 +1545,7 @@ _gnu_flush_read (void)
       else if (status == SAFE_READ_ERROR)
        {
          archive_read_error ();
-         continue; 
+         continue;
        }
       break;
     }
@@ -1430,20 +1555,20 @@ _gnu_flush_read (void)
 static void
 gnu_flush_read (void)
 {
-  flush_read = simple_flush_read; /* Avoid recursion */
+  flush_read_ptr = simple_flush_read; /* Avoid recursion */
   _gnu_flush_read ();
-  flush_read = gnu_flush_read; 
+  flush_read_ptr = gnu_flush_read;
 }
 
 static void
-_gnu_flush_write (void)
+_gnu_flush_write (size_t buffer_level)
 {
   ssize_t status;
   union block *header;
   char *copy_ptr;
   size_t copy_size;
   size_t bufsize;
-  
+
   status = _flush_write ();
   if (status != record_size && !multi_volume_option)
     archive_write_error (status);
@@ -1468,25 +1593,27 @@ _gnu_flush_write (void)
     return;
 
   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;
-  copy_size = record_size - status;
+  copy_size = buffer_level - status;
   /* Switch to the next buffer */
   record_index = !record_index;
   init_buffer ();
-  
+
   if (volume_label_option)
     add_volume_label ();
 
   if (real_s_name)
     add_multi_volume_header ();
 
-  header = write_extended (XGLTYPE, NULL, find_next_block ());
+  write_extended (true, NULL, find_next_block ());
+  if (real_s_name)
+    add_chunk_header ();
+  header = find_next_block ();
   bufsize = available_space_after (header);
   while (bufsize < copy_size)
     {
@@ -1504,18 +1631,30 @@ _gnu_flush_write (void)
 }
 
 static void
-gnu_flush_write (void)
+gnu_flush_write (size_t buffer_level)
 {
-  flush_write = simple_flush_write; /* Avoid recursion */
-  _gnu_flush_write ();
-  flush_write = gnu_flush_write; 
+  flush_write_ptr = simple_flush_write; /* Avoid recursion */
+  _gnu_flush_write (buffer_level);
+  flush_write_ptr = gnu_flush_write;
 }
-  
+
+void
+flush_read ()
+{
+  flush_read_ptr ();
+}
+
+void
+flush_write ()
+{
+  flush_write_ptr (record_size);
+}
+
 void
 open_archive (enum access_mode wanted_access)
 {
-  flush_read = gnu_flush_read;
-  flush_write = gnu_flush_write;
+  flush_read_ptr = gnu_flush_read;
+  flush_write_ptr = gnu_flush_write;
 
   _open_archive (wanted_access);
   switch (wanted_access)
@@ -1530,5 +1669,9 @@ open_archive (enum access_mode wanted_access)
       if (volume_label_option)
        write_volume_label ();
       break;
+
+    default:
+      break;
     }
+  set_volume_start_time ();
 }
This page took 0.047082 seconds and 4 git commands to generate.