浏览代码

(hit_eof): Changed type to boolean
(read_full_records,reading_from_pipe): New variables
(check_compressed_archive,open_compressed_archive): New functions
(open_archive): Autodetect compressed archives and act accodingly.
Set reading_from_pipe. This fixes contraversial set of changes
introduced 2004-05-11,2004-03-22.

Sergey Poznyakoff 20 年之前
父节点
当前提交
4674867a23
共有 1 个文件被更改,包括 135 次插入16 次删除
  1. 135 16
      src/buffer.c

+ 135 - 16
src/buffer.c

@@ -67,11 +67,14 @@ static pid_t child_pid;
 static int read_error_count;
 static int read_error_count;
 
 
 /* Have we hit EOF yet?  */
 /* Have we hit EOF yet?  */
-static int hit_eof;
+static bool hit_eof;
 
 
 /* Checkpointing counter */
 /* Checkpointing counter */
 static int checkpoint;
 static int checkpoint;
 
 
+static bool read_full_records = false;
+static bool reading_from_pipe = false;
+
 /* We're reading, but we just read the last block and it's time to update.
 /* We're reading, but we just read the last block and it's time to update.
    Declared in update.c
    Declared in update.c
 
 
@@ -143,6 +146,104 @@ compute_duration ()
   set_start_time ();
   set_start_time ();
 }
 }
 
 
+
+/* Compression detection */
+
+enum compress_type {
+  ct_none,
+  ct_compress,
+  ct_gzip,
+  ct_bzip2
+};
+
+struct zip_magic
+{
+  enum compress_type type;
+  unsigned char *magic;
+  size_t length;
+  char *program;
+  char *option;
+};
+
+static struct zip_magic magic[] = {
+  { ct_none, },
+  { ct_compress, "\037\235", 2, "compress", "-Z" },
+  { ct_gzip,     "\037\213", 2, "gzip", "-z"  },
+  { ct_bzip2,    "BZh",      3, "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 FD is a compressed archive. FD is guaranteed to
+   represent a local file */
+enum compress_type 
+check_compressed_archive (int fd)
+{
+  struct zip_magic *p;
+  size_t status;
+  union block buf;
+  
+  status = read (fd, &buf, sizeof buf);
+  if (status != sizeof buf)
+    {
+      archive_read_error ();
+      FATAL_ERROR ((0, 0, _("Quitting now.")));
+    }
+
+  lseek (fd, 0, SEEK_SET); /* This will fail if fd==0, but that does not
+			      matter, since we do not handle compressed
+			      stdin anyway */
+  
+  if (tar_checksum (&buf) == HEADER_SUCCESS)
+    /* Probably a valid header */
+    return ct_none;
+
+  for (p = magic + 1; p < magic + NMAGIC; p++)
+    if (memcmp (buf.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 ()
+{
+  enum compress_type type;
+  int fd = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
+		    MODE_RW, rsh_command_option);
+  if (fd == -1 || _isrmt (fd))
+    return fd;
+  
+  type = check_compressed_archive (fd);
+  
+  if (type == ct_none)
+    {
+      if (rmtlseek (fd, (off_t) 0, SEEK_CUR) != 0)
+	{
+	  /* Archive may be not seekable. Reopen it. */
+	  rmtclose (fd);
+	  fd = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
+			MODE_RW, rsh_command_option);
+	}
+      return fd;
+    }
+
+  /* FD is not needed any more */
+  rmtclose (fd);
+
+  /* Open compressed archive */
+  use_compress_program_option = compress_program (type);
+  child_pid = sys_child_open_for_uncompress ();
+  read_full_records = reading_from_pipe = true;
+
+  return archive;
+}
 
 
 
 
 void
 void
@@ -178,7 +279,7 @@ reset_eof (void)
 {
 {
   if (hit_eof)
   if (hit_eof)
     {
     {
-      hit_eof = 0;
+      hit_eof = false;
       current_block = record_start;
       current_block = record_start;
       record_end = record_start + blocking_factor;
       record_end = record_start + blocking_factor;
       access_mode = ACCESS_WRITE;
       access_mode = ACCESS_WRITE;
@@ -198,7 +299,7 @@ find_next_block (void)
       flush_archive ();
       flush_archive ();
       if (current_block == record_end)
       if (current_block == record_end)
 	{
 	{
-	  hit_eof = 1;
+	  hit_eof = true;
 	  return 0;
 	  return 0;
 	}
 	}
     }
     }
@@ -304,12 +405,16 @@ open_archive (enum access_mode wanted_access)
   /* When updating the archive, we start with reading.  */
   /* When updating the archive, we start with reading.  */
   access_mode = wanted_access == ACCESS_UPDATE ? ACCESS_READ : wanted_access;
   access_mode = wanted_access == ACCESS_UPDATE ? ACCESS_READ : wanted_access;
 
 
+  read_full_records = read_full_records_option;
+  reading_from_pipe = false;
+  
   if (use_compress_program_option)
   if (use_compress_program_option)
     {
     {
       switch (wanted_access)
       switch (wanted_access)
 	{
 	{
 	case ACCESS_READ:
 	case ACCESS_READ:
 	  child_pid = sys_child_open_for_uncompress ();
 	  child_pid = sys_child_open_for_uncompress ();
+	  read_full_records = reading_from_pipe = true;
 	  break;
 	  break;
 
 
 	case ACCESS_WRITE:
 	case ACCESS_WRITE:
@@ -327,14 +432,24 @@ open_archive (enum access_mode wanted_access)
     }
     }
   else if (strcmp (archive_name_array[0], "-") == 0)
   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)
       if (verify_option)
 	FATAL_ERROR ((0, 0, _("Cannot verify stdin/stdout archive")));
 	FATAL_ERROR ((0, 0, _("Cannot verify stdin/stdout archive")));
 
 
       switch (wanted_access)
       switch (wanted_access)
 	{
 	{
 	case ACCESS_READ:
 	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;
 	  break;
 
 
 	case ACCESS_WRITE:
 	case ACCESS_WRITE:
@@ -356,8 +471,7 @@ open_archive (enum access_mode wanted_access)
     switch (wanted_access)
     switch (wanted_access)
       {
       {
       case ACCESS_READ:
       case ACCESS_READ:
-	archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY,
-			   MODE_RW, rsh_command_option);
+	archive = open_compressed_archive ();
 	break;
 	break;
 
 
       case ACCESS_WRITE:
       case ACCESS_WRITE:
@@ -544,9 +658,11 @@ flush_write (void)
 
 
       strncpy (record_start->header.name, real_s_name, NAME_FIELD_SIZE);
       strncpy (record_start->header.name, real_s_name, NAME_FIELD_SIZE);
       record_start->header.typeflag = GNUTYPE_MULTIVOL;
       record_start->header.typeflag = GNUTYPE_MULTIVOL;
+
       OFF_TO_CHARS (real_s_sizeleft, record_start->header.size);
       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);
 		    record_start->oldgnu_header.offset);
+      
       tmp = verbose_option;
       tmp = verbose_option;
       verbose_option = 0;
       verbose_option = 0;
       finish_header (&current_stat_info, record_start, -1);
       finish_header (&current_stat_info, record_start, -1);
@@ -630,7 +746,7 @@ short_read (size_t status)
   left = record_size - status;
   left = record_size - status;
 
 
   while (left % BLOCKSIZE != 0
   while (left % BLOCKSIZE != 0
-	 || (left && status && read_full_records_option))
+	 || (left && status && read_full_records))
     {
     {
       if (status)
       if (status)
 	while ((status = rmtread (archive, more, left)) == SAFE_READ_ERROR)
 	while ((status = rmtread (archive, more, left)) == SAFE_READ_ERROR)
@@ -638,15 +754,18 @@ short_read (size_t status)
 
 
       if (status == 0)
       if (status == 0)
 	{
 	{
-	  char buf[UINTMAX_STRSIZE_BOUND];
+	  if (!reading_from_pipe)
+	    {
+	      char buf[UINTMAX_STRSIZE_BOUND];
 
 
-	  WARN((0, 0, _("Read %s bytes from %s"),
-		STRINGIFY_BIGINT (record_size - left, buf),
-		*archive_name_cursor));
+	      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;
 	  unsigned long rest = record_size - left;
 
 
@@ -666,7 +785,7 @@ short_read (size_t status)
   /* FIXME: for size=0, multi-volume support.  On the first record, warn
   /* FIXME: for size=0, multi-volume support.  On the first record, warn
      about the problem.  */
      about the problem.  */
 
 
-  if (!read_full_records_option && verbose_option > 1
+  if (!read_full_records && verbose_option > 1
       && record_start_block == 0 && status != 0)
       && record_start_block == 0 && status != 0)
     {
     {
       unsigned long rsize = (record_size - left) / BLOCKSIZE;
       unsigned long rsize = (record_size - left) / BLOCKSIZE;
@@ -728,7 +847,7 @@ flush_read (void)
     }
     }
 
 
   /* The condition below used to include
   /* 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
      This is incorrect since even if new_volume() succeeds, the
      subsequent call to rmtread will overwrite the chunk of data
      subsequent call to rmtread will overwrite the chunk of data
      already read in the buffer, so the processing will fail */
      already read in the buffer, so the processing will fail */
@@ -1137,7 +1256,7 @@ new_volume (enum access_mode mode)
 
 
   if (strcmp (archive_name_cursor[0], "-") == 0)
   if (strcmp (archive_name_cursor[0], "-") == 0)
     {
     {
-      read_full_records_option = true;
+      read_full_records = true;
       archive = STDIN_FILENO;
       archive = STDIN_FILENO;
     }
     }
   else if (verify_option)
   else if (verify_option)