From 047b195c61a23dd3ec8b69dff43c1a21792ce4b6 Mon Sep 17 00:00:00 2001 From: Paolo Bacchilega Date: Wed, 04 Sep 2013 10:02:11 +0000 Subject: 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] --- 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 */ -- cgit v0.9.2 From 6c831b143dd08f3d6c3d1923ef5751222d21fc86 Mon Sep 17 00:00:00 2001 From: Paolo Bacchilega Date: Sat, 17 Aug 2013 10:16:19 +0000 Subject: libarchive: restore directory modification time when extrating [bug #697756] --- diff --git a/src/fr-archive-libarchive.c b/src/fr-archive-libarchive.c index 0817cf8..3b73c48 100644 --- a/src/fr-archive-libarchive.c +++ b/src/fr-archive-libarchive.c @@ -417,14 +417,11 @@ extract_data_get_extraction_requested (ExtractData *extract_data, } -static void -_g_file_set_attributes_from_entry (GFile *file, - struct archive_entry *entry, - ExtractData *extract_data, - GCancellable *cancellable) +static GFileInfo * +_g_file_info_create_from_entry (struct archive_entry *entry, + ExtractData *extract_data) { GFileInfo *info; - GError *error = NULL; info = g_file_info_new (); @@ -478,12 +475,66 @@ _g_file_set_attributes_from_entry (GFile *file, g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE, archive_entry_mode (entry)); - if (! g_file_set_attributes_from_info (file, info, 0, cancellable, &error)) { - g_warning ("%s", error->message); - g_error_free (error); - } + return info; +} + + +static gboolean +_g_file_set_attributes_from_info (GFile *file, + GFileInfo *info, + GCancellable *cancellable, + GError **error) +{ + return g_file_set_attributes_from_info (file, info, G_FILE_QUERY_INFO_NONE, cancellable, error); +} + + +static gboolean +_g_file_set_attributes_from_entry (GFile *file, + struct archive_entry *entry, + ExtractData *extract_data, + GCancellable *cancellable, + GError **error) +{ + GFileInfo *info; + gboolean result; + + info = _g_file_info_create_from_entry (entry, extract_data); + result = _g_file_set_attributes_from_info (file, info, cancellable, error); g_object_unref (info); + + return result; +} + + +static gboolean +restore_modification_time (GHashTable *created_folders, + GCancellable *cancellable, + GError **error) +{ + GHashTableIter iter; + gpointer key, value; + gboolean result = TRUE; + + g_hash_table_iter_init (&iter, created_folders); + while (result && g_hash_table_iter_next (&iter, &key, &value)) { + GFile *file = key; + GFileInfo *original_info = value; + GFileInfo *info; + + if (g_file_info_get_attribute_status (original_info, G_FILE_ATTRIBUTE_TIME_MODIFIED) != G_FILE_ATTRIBUTE_STATUS_SET) + continue; + + info = g_file_info_new (); + g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED, g_file_info_get_attribute_uint64 (original_info, G_FILE_ATTRIBUTE_TIME_MODIFIED)); + g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC, g_file_info_get_attribute_uint32 (original_info, G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC)); + result = _g_file_set_attributes_from_info (file, info, cancellable, error); + + g_object_unref (info); + } + + return result; } @@ -495,6 +546,7 @@ extract_archive_thread (GSimpleAsyncResult *result, ExtractData *extract_data; LoadData *load_data; GHashTable *checked_folders; + GHashTable *created_folders; struct archive *a; struct archive_entry *entry; int r; @@ -503,6 +555,7 @@ extract_archive_thread (GSimpleAsyncResult *result, load_data = LOAD_DATA (extract_data); 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); fr_archive_progress_set_total_files (load_data->archive, extract_data->n_files_to_extract); a = archive_read_new (); @@ -683,8 +736,15 @@ extract_archive_thread (GSimpleAsyncResult *result, load_data->error = g_error_copy (local_error); g_error_free (local_error); } - else - _g_file_set_attributes_from_entry (file, entry, extract_data, cancellable); + else { + GFileInfo *info; + + info = _g_file_info_create_from_entry (entry, extract_data); + _g_file_set_attributes_from_info (file, info, cancellable, &load_data->error); + g_hash_table_insert (created_folders, g_object_ref (file), g_object_ref (info)); + + g_object_unref (info); + } archive_read_data_skip (a); break; @@ -703,7 +763,7 @@ extract_archive_thread (GSimpleAsyncResult *result, if (r != ARCHIVE_EOF) load_data->error = g_error_new_literal (FR_ERROR, FR_ERROR_COMMAND_ERROR, archive_error_string (a)); else - _g_file_set_attributes_from_entry (file, entry, extract_data, cancellable); + _g_file_set_attributes_from_entry (file, entry, extract_data, cancellable, &load_data->error); break; case AE_IFLNK: @@ -733,6 +793,9 @@ extract_archive_thread (GSimpleAsyncResult *result, } } + if (load_data->error == NULL) + restore_modification_time (created_folders, cancellable, &load_data->error); + if ((load_data->error == NULL) && (r != ARCHIVE_EOF)) load_data->error = g_error_new_literal (FR_ERROR, FR_ERROR_COMMAND_ERROR, archive_error_string (a)); if (load_data->error == NULL) @@ -740,6 +803,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 (created_folders); g_hash_table_unref (checked_folders); archive_read_free (a); extract_data_free (extract_data); -- cgit v0.9.2