[gvfs] archive: fix reading files when size not set



commit 39ab8a0f6f673696941a681cf11d2fbbb17bdccf
Author: Ondrej Holy <oholy redhat com>
Date:   Fri Nov 1 13:28:18 2013 +0100

    archive: fix reading files when size not set
    
    File size can be unset in the archive therefor is set to zero.
    This breaks reading file content using fuse. Determine file size
    by reading data blocks to fix it.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=670534

 daemon/gvfsbackendarchive.c |   51 ++++++++++++++++++++++++++++++++++++++----
 1 files changed, 46 insertions(+), 5 deletions(-)
---
diff --git a/daemon/gvfsbackendarchive.c b/daemon/gvfsbackendarchive.c
index 664a41c..ad992f3 100644
--- a/daemon/gvfsbackendarchive.c
+++ b/daemon/gvfsbackendarchive.c
@@ -356,14 +356,48 @@ create_root_file (GVfsBackendArchive *ba)
   g_object_unref (icon);
 }
 
+/* Read archive entry data blocks to determine file size */
+static int64_t
+archive_entry_determine_size (GVfsArchive          *archive,
+                             struct archive_entry *entry)
+{
+  size_t read, size = 0;
+  int result;
+  const void *block;
+  int64_t offset;
+
+  do
+    {
+      result = archive_read_data_block (archive->archive, &block, &read, &offset);
+      if (result >= ARCHIVE_WARN && result <= ARCHIVE_OK)
+       {
+         if (result < ARCHIVE_OK) {
+           DEBUG ("archive_read_data_block: result = %d, error = '%s'\n", result, archive_error_string 
(archive->archive));
+           archive_set_error (archive->archive, ARCHIVE_OK, "No error");
+           archive_clear_error (archive->archive);
+         }
+
+         size += read;
+       }
+    }
+  while (result != ARCHIVE_FATAL && result != ARCHIVE_EOF);
+
+  if (result == ARCHIVE_FATAL)
+    gvfs_archive_set_error_from_errno (archive);
+
+  return size;
+}
+
 static void
-archive_file_set_info_from_entry (ArchiveFile *                file, 
+archive_file_set_info_from_entry (GVfsArchive *         archive,
+                                 ArchiveFile *         file,
                                  struct archive_entry *entry,
                                  guint64               entry_index)
 {
   GFileInfo *info = g_file_info_new ();
   GFileType type;
   mode_t mode;
+  int64_t size;
   file->info = info;
 
   DEBUG ("setting up %s (%s)\n", archive_entry_pathname (entry), file->name);
@@ -415,8 +449,15 @@ archive_file_set_info_from_entry (ArchiveFile *            file,
                                   file->name,
                                   type);
 
-  g_file_info_set_size (info,
-                       archive_entry_size (entry));
+  if (archive_entry_size_is_set (entry))
+    {
+      size = archive_entry_size (entry);
+    }
+  else
+    {
+      size = archive_entry_determine_size (archive, entry);
+    }
+  g_file_info_set_size (info, size);
 
   mode = archive_entry_perm (entry);
   g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ, TRUE);
@@ -503,12 +544,12 @@ create_file_tree (GVfsBackendArchive *ba, GVfsJob *job)
                                                          TRUE);
           /* Don't set info for root */
           if (file != ba->files)
-            archive_file_set_info_from_entry (file, entry, entry_index);
+            archive_file_set_info_from_entry (archive, file, entry, entry_index);
          archive_read_data_skip (archive->archive);
          entry_index++;
        }
     }
-  while (result != ARCHIVE_FATAL && result != ARCHIVE_EOF);
+  while (result != ARCHIVE_FATAL && result != ARCHIVE_EOF && !gvfs_archive_in_error (archive));
 
   if (result == ARCHIVE_FATAL)
     gvfs_archive_set_error_from_errno (archive);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]