[file-roller/gnome-3-8] libarchive: restore the folders modification time correctly



commit 4bf8552f8e60c8d4ec65e360451c6998198052db
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Wed Sep 4 12:02:11 2013 +0200

    libarchive: restore the folders modification time correctly
    
    when honoring the skip_older and overwrite flags ignore the
    directories created during the extraction process.
    
    [bug #697756]

 src/fr-archive-libarchive.c |   24 +++++++++++++--
 src/gio-utils.c             |   70 +++++++++++++++++++++++++++++++++++++++++++
 src/gio-utils.h             |    5 +++
 3 files changed, 96 insertions(+), 3 deletions(-)
---
diff --git a/src/fr-archive-libarchive.c b/src/fr-archive-libarchive.c
index 3b73c48..37e3008 100644
--- a/src/fr-archive-libarchive.c
+++ b/src/fr-archive-libarchive.c
@@ -33,6 +33,7 @@
 #include "file-utils.h"
 #include "fr-error.h"
 #include "fr-archive-libarchive.h"
+#include "gio-utils.h"
 #include "glib-utils.h"
 #include "typedefs.h"
 
@@ -547,6 +548,7 @@ extract_archive_thread (GSimpleAsyncResult *result,
        LoadData             *load_data;
        GHashTable           *checked_folders;
        GHashTable           *created_folders;
+       GHashTable           *folders_created_during_extraction;
        struct archive       *a;
        struct archive_entry *entry;
        int                   r;
@@ -556,6 +558,7 @@ extract_archive_thread (GSimpleAsyncResult *result,
 
        checked_folders = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, 
NULL);
        created_folders = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, 
g_object_unref);
+       folders_created_during_extraction = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, 
g_object_unref, NULL);
        fr_archive_progress_set_total_files (load_data->archive, extract_data->n_files_to_extract);
 
        a = archive_read_new ();
@@ -590,11 +593,14 @@ extract_archive_thread (GSimpleAsyncResult *result,
                        archive_read_data_skip (a);
                        continue;
                }
+
                file = g_file_get_child (extract_data->destination, relative_path);
 
                /* honor the skip_older and overwrite options */
 
-               if (extract_data->skip_older || ! extract_data->overwrite) {
+               if ((g_hash_table_lookup (folders_created_during_extraction, file) == NULL)
+                   && (extract_data->skip_older || ! extract_data->overwrite))
+               {
                        GFileInfo *info;
 
                        info = g_file_query_info (file,
@@ -652,7 +658,18 @@ extract_archive_thread (GSimpleAsyncResult *result,
                    && (g_hash_table_lookup (checked_folders, parent) == NULL)
                    && ! g_file_query_exists (parent, cancellable))
                {
-                       if (g_file_make_directory_with_parents (parent, cancellable, &load_data->error)) {
+                       if (! _g_file_make_directory_with_parents (parent,
+                                                                  folders_created_during_extraction,
+                                                                  cancellable,
+                                                                  &local_error))
+                       {
+                               if (! g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
+                                       load_data->error = local_error;
+                               else
+                                       g_clear_error (&local_error);
+                       }
+
+                       if (load_data->error == NULL) {
                                GFile *grandparent;
 
                                grandparent = g_object_ref (parent);
@@ -736,7 +753,7 @@ extract_archive_thread (GSimpleAsyncResult *result,
                                                load_data->error = g_error_copy (local_error);
                                        g_error_free (local_error);
                                }
-                               else {
+                               if (load_data->error == NULL) {
                                        GFileInfo *info;
 
                                        info = _g_file_info_create_from_entry (entry, extract_data);
@@ -803,6 +820,7 @@ extract_archive_thread (GSimpleAsyncResult *result,
        if (load_data->error != NULL)
                g_simple_async_result_set_from_error (result, load_data->error);
 
+       g_hash_table_unref (folders_created_during_extraction);
        g_hash_table_unref (created_folders);
        g_hash_table_unref (checked_folders);
        archive_read_free (a);
diff --git a/src/gio-utils.c b/src/gio-utils.c
index 9d9f708..b317694 100644
--- a/src/gio-utils.c
+++ b/src/gio-utils.c
@@ -1483,3 +1483,73 @@ _g_file_load_buffer_finish (GFile         *file,
 
        return TRUE;
 }
+
+
+static gboolean
+_g_file_make_directory_and_add_to_created_folders (GFile         *file,
+                                                  GHashTable    *created_folders,
+                                                  GCancellable  *cancellable,
+                                                  GError       **error)
+{
+       gboolean result;
+
+       result = g_file_make_directory (file, cancellable, error);
+       if (result && (g_hash_table_lookup (created_folders, file) == NULL))
+               g_hash_table_insert (created_folders, g_object_ref (file), GINT_TO_POINTER (1));
+
+       return result;
+}
+
+
+gboolean
+_g_file_make_directory_with_parents (GFile         *file,
+                                    GHashTable    *created_folders,
+                                    GCancellable  *cancellable,
+                                    GError       **error)
+{
+       GError *local_error = NULL;
+       GFile  *work_file = NULL;
+       GList  *list = NULL, *l;
+
+       g_return_val_if_fail (G_IS_FILE (file), FALSE);
+
+       _g_file_make_directory_and_add_to_created_folders (file, created_folders, cancellable, &local_error);
+       if ((local_error == NULL) || (local_error->code != G_IO_ERROR_NOT_FOUND)) {
+               if (local_error != NULL)
+                       g_propagate_error (error, local_error);
+               return local_error == NULL;
+       }
+
+       work_file = g_object_ref (file);
+       while ((local_error != NULL) && (local_error->code == G_IO_ERROR_NOT_FOUND)) {
+               GFile *parent_file;
+
+               parent_file = g_file_get_parent (work_file);
+               if (parent_file == NULL)
+                       break;
+
+               g_clear_error (&local_error);
+               _g_file_make_directory_and_add_to_created_folders (parent_file, created_folders, cancellable, 
&local_error);
+
+               g_object_unref (work_file);
+               work_file = g_object_ref (parent_file);
+
+               if ((local_error != NULL) && (local_error->code == G_IO_ERROR_NOT_FOUND))
+                       list = g_list_prepend (list, parent_file);  /* Transfer ownership of ref */
+               else
+                       g_object_unref (parent_file);
+       }
+
+       for (l = list; (local_error == NULL) && (l != NULL); l = l->next)
+               _g_file_make_directory_and_add_to_created_folders ((GFile *) l->data, created_folders, 
cancellable, &local_error);
+
+       _g_object_unref (work_file);
+       _g_object_list_unref (list);
+
+       if (local_error != NULL) {
+               g_propagate_error (error, local_error);
+               return FALSE;
+       }
+
+       return _g_file_make_directory_and_add_to_created_folders (file, created_folders, cancellable, error);
+}
diff --git a/src/gio-utils.h b/src/gio-utils.h
index f784c41..0d7dd3c 100644
--- a/src/gio-utils.h
+++ b/src/gio-utils.h
@@ -177,5 +177,10 @@ gboolean _g_file_load_buffer_finish  (GFile                 *file,
                                      char                 **buffer,
                                      gsize                 *buffer_size,
                                      GError               **error);
+gboolean _g_file_make_directory_with_parents
+                                    (GFile                 *file,
+                                     GHashTable            *created_folders,
+                                     GCancellable          *cancellable,
+                                     GError               **error);
 
 #endif /* _GIO_UTILS_H */


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