[gnome-autoar/wip/razvan/extract-refactor2: 3/3] AutoarExtract: add signal for name conflicts
- From: Răzvan-Mihai Chițu <razvanchitu src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-autoar/wip/razvan/extract-refactor2: 3/3] AutoarExtract: add signal for name conflicts
- Date: Wed, 1 Jun 2016 11:36:18 +0000 (UTC)
commit eb33f6cd80a70dc6fd9c93751b211fd6ceda2cad
Author: Razvan Chitu <razvan ch95 gmail com>
Date: Sun May 29 13:13:01 2016 +0300
AutoarExtract: add signal for name conflicts
Extraction was previously done with overwrite as the default option for existing
files. A better solution would be to detect conflicts and notify the user
application, offering the possibility to change the destination of the extracted
file.
In order to fix this, add a signal for notifying conflicts. This signal gets
emitted before actually extracting a file.
gnome-autoar/autoar-extract.c | 122 +++++++++++++++++++++++++++++++++++++++--
tests/test-extract.c | 17 ++++++
2 files changed, 134 insertions(+), 5 deletions(-)
---
diff --git a/gnome-autoar/autoar-extract.c b/gnome-autoar/autoar-extract.c
index 36ffadd..d8df6ed 100644
--- a/gnome-autoar/autoar-extract.c
+++ b/gnome-autoar/autoar-extract.c
@@ -173,6 +173,7 @@ enum
SCANNED,
CONFIRM_DESTINATION,
PROGRESS,
+ CONFLICT,
CANCELLED,
COMPLETED,
AR_ERROR,
@@ -838,6 +839,31 @@ autoar_extract_signal_progress (AutoarExtract *arextract)
}
}
+static GFile*
+autoar_extract_signal_conflict (AutoarExtract *arextract, GFile *file)
+{
+ GFile *new_file = NULL;
+
+ autoar_common_g_signal_emit (arextract, arextract->priv->in_thread,
+ autoar_extract_signals[CONFLICT], 0,
+ file,
+ &new_file);
+
+ if (new_file) {
+ char *previous_path, *new_path;
+
+ previous_path = g_file_get_path (file);
+ new_path = g_file_get_path (new_file);
+
+ g_debug ("autoar_extract_signal_conflict: %s => %s", previous_path, new_path);
+
+ g_free (previous_path);
+ g_free (new_path);
+ }
+
+ return new_file;
+}
+
static inline void
autoar_extract_signal_cancelled (AutoarExtract *arextract)
{
@@ -958,6 +984,54 @@ autoar_extract_do_pattern_check (const char *path,
}
static void
+autoar_extract_solve_conflict (AutoarExtract *arextract,
+ mode_t extracted_filetype,
+ GFile **dest)
+{
+ GFileType file_type;
+ GFile *new_dest;
+ gboolean is_conflict = FALSE;
+
+ file_type = g_file_query_file_type (*dest,
+ G_FILE_QUERY_INFO_NONE,
+ NULL);
+ /* If there is no file with the given name, there will be no conflict */
+ if (file_type == G_FILE_TYPE_UNKNOWN) {
+ return;
+ }
+
+ switch (extracted_filetype) {
+ case AE_IFDIR:
+ break;
+ case AE_IFREG:
+ case AE_IFLNK:
+#if defined HAVE_MKFIFO || defined HAVE_MKNOD
+ case AE_IFIFO:
+#endif
+#ifdef HAVE_MKNOD
+ case AE_IFSOCK:
+ case AE_IFBLK:
+ case AE_IFCHR:
+#endif
+ is_conflict = TRUE;
+ break;
+ default:
+ break;
+ }
+
+ if (!is_conflict) {
+ return;
+ }
+
+ new_dest = autoar_extract_signal_conflict (arextract, *dest);
+
+ if (new_dest) {
+ g_clear_object (dest);
+ *dest = new_dest;
+ }
+}
+
+static void
autoar_extract_do_write_entry (AutoarExtract *arextract,
struct archive *a,
struct archive_entry *entry,
@@ -1098,6 +1172,7 @@ autoar_extract_do_write_entry (AutoarExtract *arextract,
g_debug ("autoar_extract_do_write_entry: writing");
r = 0;
+
switch (filetype = archive_entry_filetype (entry)) {
default:
case AE_IFREG:
@@ -1108,16 +1183,18 @@ autoar_extract_do_write_entry (AutoarExtract *arextract,
gint64 offset;
g_debug ("autoar_extract_do_write_entry: case REG");
+
ostream = (GOutputStream*)g_file_replace (dest,
NULL,
FALSE,
G_FILE_CREATE_NONE,
priv->cancellable,
&(priv->error));
- if (arextract->priv->error != NULL) {
+ if (priv->error != NULL) {
g_object_unref (info);
return;
}
+
if (ostream != NULL) {
/* Archive entry size may be zero if we use raw format. */
if (archive_entry_size(entry) > 0 || priv->use_raw_format) {
@@ -1159,17 +1236,28 @@ autoar_extract_do_write_entry (AutoarExtract *arextract,
GFileAndInfo fileandinfo;
g_debug ("autoar_extract_do_write_entry: case DIR");
+
g_file_make_directory_with_parents (dest, priv->cancellable, &(priv->error));
+
if (priv->error != NULL) {
- /* "File exists" is not a fatal error */
- if (priv->error->code == G_IO_ERROR_EXISTS) {
- g_error_free (priv->error);
- priv->error = NULL;
+ /* "File exists" is not a fatal error, as long as the existing file
+ * is a directory
+ */
+ GFileType file_type;
+
+ file_type = g_file_query_file_type (dest,
+ G_FILE_QUERY_INFO_NONE,
+ NULL);
+
+ if (g_error_matches (priv->error, G_IO_ERROR, G_IO_ERROR_EXISTS) &&
+ file_type == G_FILE_TYPE_DIRECTORY) {
+ g_clear_error (&priv->error);
} else {
g_object_unref (info);
return;
}
}
+
fileandinfo.file = g_object_ref (dest);
fileandinfo.info = g_object_ref (info);
g_array_append_val (priv->extracted_dir_list, fileandinfo);
@@ -1440,6 +1528,26 @@ autoar_extract_class_init (AutoarExtractClass *klass)
G_TYPE_UINT);
/**
+ * AutoarExtract::conflict:
+ * @arextract: the #AutoarExtract
+ * @file: the file that caused a conflict
+ *
+ * Returns: (transfer full): a new file to be used as target for extraction
+ *
+ * This signal is used to report and offer the possibility to solve name
+ * conflicts when extracting files.
+ **/
+ autoar_extract_signals[CONFLICT] =
+ g_signal_new ("conflict",
+ type,
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_OBJECT,
+ 1,
+ G_TYPE_FILE);
+
+/**
* AutoarExtract::cancelled:
* @arextract: the #AutoarExtract
*
@@ -2001,6 +2109,10 @@ autoar_extract_step_extract (AutoarExtract *arextract) {
autoar_extract_do_sanitize_pathname (hardlink, priv->destination_dir);
}
+ /* Attempt to solve any name conflict before doing any operations */
+ autoar_extract_solve_conflict (arextract, archive_entry_filetype (entry),
+ &extracted_filename);
+
autoar_extract_do_write_entry (arextract, a, entry,
extracted_filename, hardlink_filename);
diff --git a/tests/test-extract.c b/tests/test-extract.c
index 2603da7..b5f6192 100644
--- a/tests/test-extract.c
+++ b/tests/test-extract.c
@@ -53,6 +53,22 @@ my_handler_progress (AutoarExtract *arextract,
((double)(completed_files)) * 100 / autoar_extract_get_files (arextract));
}
+static GFile*
+my_handler_conflict (AutoarExtract *arextract,
+ GFile *file,
+ gpointer data)
+{
+ char *path;
+
+ path = g_file_get_path (file);
+
+ g_print ("Conflict on: %s\n", path);
+
+ g_free (path);
+
+ return NULL;
+}
+
static void
my_handler_error (AutoarExtract *arextract,
GError *error,
@@ -121,6 +137,7 @@ main (int argc,
g_signal_connect (arextract, "scanned", G_CALLBACK (my_handler_scanned), NULL);
g_signal_connect (arextract, "confirm-dest", G_CALLBACK (my_handler_confirm_dest), NULL);
g_signal_connect (arextract, "progress", G_CALLBACK (my_handler_progress), NULL);
+ g_signal_connect (arextract, "conflict", G_CALLBACK (my_handler_conflict), NULL);
g_signal_connect (arextract, "error", G_CALLBACK (my_handler_error), NULL);
g_signal_connect (arextract, "completed", G_CALLBACK (my_handler_completed), NULL);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]