]> Dogcows Code - chaz/tar/commitdiff
(flush_write,flush_read): Change data type.
authorSergey Poznyakoff <gray@gnu.org.ua>
Fri, 11 Nov 2005 00:24:52 +0000 (00:24 +0000)
committerSergey Poznyakoff <gray@gnu.org.ua>
Fri, 11 Nov 2005 00:24:52 +0000 (00:24 +0000)
(flush_archive): Compute actual buffer fill level before calling
low level function.
(close_archive): Call flush_archive again if the first call
resulted in partially filled buffer.
(try_new_volume): Rewritten handling of initial headers.
(add_chunk_header): New function. Write an additional header
before the continuation chunk. The purpose of the header is to
allow third-party tars to extract the member.
(simple_flush_write): Take an argument.
(_gnu_flush_write): Correctly handle partially filled buffers.

src/buffer.c

index f5ebfb7eb5ebb1e571aaad8bddc615f0ab6c8ebf..f8fe2ea42dd172c48c87a20846d660fcc0ff3256 100644 (file)
@@ -84,6 +84,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;
@@ -674,6 +677,7 @@ _flush_read (void)
 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 +696,7 @@ flush_archive (void)
       break;
 
     case ACCESS_WRITE:
-      flush_write ();
+      flush_write_ptr (buffer_level);
       break;
 
     case ACCESS_UPDATE:
@@ -784,7 +788,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 ();
 
@@ -1021,13 +1029,26 @@ new_volume (enum access_mode mode)
 
   return true;
 }
-      
+
+static bool
+read_header0 ()
+{
+  enum read_header rc = read_header (false);
+
+  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;
 
   switch (subcommand_option)
     {
@@ -1051,49 +1072,51 @@ 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 XGLTYPE:
+      {
+       struct tar_stat_info dummy;
+       if (!read_header0 ())
+         return false;
+       tar_stat_init (&dummy);
+       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;
+      }
       
-    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 GNUTYPE_VOLHDR:
+      if (!read_header0 ())
+       return false;
+      assign_string (&volume_label, current_header->header.name);
+      set_next_block_after (header);
+      header = find_next_block ();
+      if (header->header.typeflag != GNUTYPE_MULTIVOL)
        break;
-      set_next_block_after (current_header);
-      goto again;
-
-    case HEADER_ZERO_BLOCK:
-    case HEADER_END_OF_FILE:
-    case HEADER_FAILURE:
-      current_block = block;
+      /* FALL THROUGH */
+      
+    case GNUTYPE_MULTIVOL:
+      if (!read_header0 ())
+       return false;
+      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)
@@ -1219,6 +1242,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);
+      free (st.orig_file_name);
+      if (!blk)
+       abort (); /* FIXME */
+      finish_header (&st, blk, block_ordinal);
+    }
+}
+
+
 /* Add a volume label to the current archive */
 static void
 write_volume_label (void)
@@ -1350,7 +1405,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;
 
@@ -1431,20 +1486,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);
@@ -1476,7 +1531,7 @@ _gnu_flush_write (void)
   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 ();
@@ -1487,7 +1542,10 @@ _gnu_flush_write (void)
   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)
     {
@@ -1505,18 +1563,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)
@@ -1533,3 +1603,4 @@ open_archive (enum access_mode wanted_access)
       break;
     }
 }
+
This page took 0.033763 seconds and 4 git commands to generate.