rpms/file-roller/devel file-roller-2.31.0-gvfs-fuse.patch, NONE, 1.1 file-roller.spec, 1.179, 1.180

Tomas Bzatek tbzatek at fedoraproject.org
Mon May 17 14:47:48 UTC 2010


Author: tbzatek

Update of /cvs/extras/rpms/file-roller/devel
In directory cvs01.phx2.fedoraproject.org:/tmp/cvs-serv23534

Modified Files:
	file-roller.spec 
Added Files:
	file-roller-2.31.0-gvfs-fuse.patch 
Log Message:
* Mon May 17 2010 Tomas Bzatek <tbzatek at redhat.com> 2.30.1.1-3
- Fix archive handling on remote GIO mounts without running fuse daemon (#527045, #518510)


file-roller-2.31.0-gvfs-fuse.patch:
 fr-archive.c |  595 +++++++++++++++++++++++++++++++++++++++++++++++++++++------
 fr-archive.h |    2 
 fr-window.c  |    8 
 gio-utils.c  |  155 +++++++++------
 gio-utils.h  |    3 
 5 files changed, 642 insertions(+), 121 deletions(-)

--- NEW FILE file-roller-2.31.0-gvfs-fuse.patch ---
>From 33c21fc3647af32de5a9c9d49e33765a526910f5 Mon Sep 17 00:00:00 2001
From: Tomas Bzatek <tbzatek at redhat.com>
Date: Wed, 12 May 2010 11:54:29 +0000
Subject: Bring back support for file caching when gvfs-fuse-daemon is not available

The commit 73fa5d77a60861cd35c6f3425d27c88061af081c introduced trouble
when user was trying to work with archives on remote GIO mounts and
not having the fuse daemon running. This led to segfaults and error messages.

Please see bug #617769 for details.
---
diff --git a/src/fr-archive.c b/src/fr-archive.c
index e4a1259..adf9976 100644
--- a/src/fr-archive.c
+++ b/src/fr-archive.c
@@ -114,16 +114,51 @@ struct _FrArchivePrivData {
 	FakeLoadFunc         add_is_stoppable_func;         /* Returns whether the add operation is
 							     * stoppable. */
 	gpointer             add_is_stoppable_data;
-  	GCancellable        *cancellable;
+	GCancellable        *cancellable;
 	char                *temp_dir;
 	gboolean             continue_adding_dropped_items;
 	DroppedItemsData    *dropped_items_data;
 
+	char                *temp_extraction_dir;
 	char                *extraction_destination;
+	gboolean             remote_extraction;
 	gboolean             extract_here;
 };
 
 
+typedef struct {
+	FrArchive      *archive;
+	char           *uri;
+	FrAction        action;
+	GList          *file_list;
+	char           *base_uri;
+	char           *dest_dir;
+	gboolean        update;
+	char           *tmp_dir;
+	guint           source_id;
+	char           *password;
+	gboolean        encrypt_header;
+	FrCompression   compression;
+	guint           volume_size;
+} XferData;
+
+
+static void
+xfer_data_free (XferData *data)
+{
+	if (data == NULL)
+		return;
+
+	g_free (data->uri);
+	g_free (data->password);
+	path_list_free (data->file_list);
+	g_free (data->base_uri);
+	g_free (data->dest_dir);
+	g_free (data->tmp_dir);
+	g_free (data);
+}
+
+
 #define MAX_CHUNK_LEN (NCARGS * 2 / 3) /* Max command line length */
 #define UNKNOWN_TYPE "application/octet-stream"
 #define SAME_FS (FALSE)
@@ -322,6 +357,8 @@ static void
 fr_archive_init (FrArchive *archive)
 {
 	archive->file = NULL;
+	archive->local_copy = NULL;
+	archive->is_remote = FALSE;
 	archive->command = NULL;
 	archive->is_compressed_file = FALSE;
 	archive->can_create_compressed_file = FALSE;
@@ -333,6 +370,7 @@ fr_archive_init (FrArchive *archive)
 	archive->priv->add_is_stoppable_data = NULL;
 
 	archive->priv->extraction_destination = NULL;
+	archive->priv->temp_extraction_dir = NULL;
 	archive->priv->cancellable = g_cancellable_new ();
 
 	archive->process = fr_process_new ();
@@ -350,18 +388,73 @@ fr_archive_new (void)
 }
 
 
+static GFile *
+get_local_copy_for_file (GFile *remote_file)
+{
+	char  *temp_dir;
+	GFile *local_copy = NULL;
+
+	temp_dir = get_temp_work_dir (NULL);
+	if (temp_dir != NULL) {
+		char  *archive_name;
+		char  *local_path;
+
+		archive_name = g_file_get_basename (remote_file);
+		local_path = g_build_filename (temp_dir, archive_name, NULL);
+		local_copy = g_file_new_for_path (local_path);
+
+		g_free (local_path);
+		g_free (archive_name);
+	}
+	g_free (temp_dir);
+
+	return local_copy;
+}
+
+
 static void
 fr_archive_set_uri (FrArchive  *archive,
 		    const char *uri)
 {
+	if ((archive->local_copy != NULL) && archive->is_remote) {
+		GFile  *temp_folder;
+		GError *err = NULL;
+
+		g_file_delete (archive->local_copy, NULL, &err);
+		if (err != NULL) {
+			g_warning ("Failed to delete the local copy: %s", err->message);
+			g_clear_error (&err);
+		}
+
+		temp_folder = g_file_get_parent (archive->local_copy);
+		g_file_delete (temp_folder, NULL, &err);
+		if (err != NULL) {
+			g_warning ("Failed to delete temp folder: %s", err->message);
+			g_clear_error (&err);
+		}
+
+		g_object_unref (temp_folder);
+	}
+
 	if (archive->file != NULL) {
 		g_object_unref (archive->file);
 		archive->file = NULL;
 	}
+	if (archive->local_copy != NULL) {
+		g_object_unref (archive->local_copy);
+		archive->local_copy = NULL;
+	}
 	archive->content_type = NULL;
 
-	if (uri != NULL)
-		archive->file = g_file_new_for_uri (uri);
+	if (uri == NULL)
+		return;
+
+	archive->file = g_file_new_for_uri (uri);
+	archive->is_remote = ! g_file_has_uri_scheme (archive->file, "file");
+	if (archive->is_remote)
+		archive->local_copy = get_local_copy_for_file (archive->file);
+	else
+		archive->local_copy = g_file_dup (archive->file);
 }
 
 
@@ -395,6 +488,7 @@ fr_archive_finalize (GObject *object)
 		dropped_items_data_free (archive->priv->dropped_items_data);
 		archive->priv->dropped_items_data = NULL;
 	}
+	g_free (archive->priv->temp_extraction_dir);
 	g_free (archive->priv->extraction_destination);
 	g_free (archive->priv);
 
@@ -501,7 +595,7 @@ create_command_from_type (FrArchive     *archive,
 	if (command_type == 0)
 		return FALSE;
 
-	filename = g_file_get_path (archive->file);
+	filename = g_file_get_path (archive->local_copy);
 	archive->command = FR_COMMAND (g_object_new (command_type,
 					             "process", archive->process,
 					             "filename", filename,
@@ -588,6 +682,79 @@ action_started (FrCommand *command,
 }
 
 
+/* -- copy_to_remote_location -- */
+
+
+static void
+fr_archive_copy_done (FrArchive *archive,
+		      FrAction   action,
+		      GError    *error)
+{
+	FrProcErrorType  error_type = FR_PROC_ERROR_NONE;
+	const char      *error_details = NULL;
+
+	if (error != NULL) {
+		error_type = (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) ? FR_PROC_ERROR_STOPPED : FR_PROC_ERROR_GENERIC);
+		error_details = error->message;
+	}
+	fr_archive_action_completed (archive, action, error_type, error_details);
+}
+
+
+static void
+copy_to_remote_location_done (GError   *error,
+			      gpointer  user_data)
+{
+	XferData *xfer_data = user_data;
+
+	fr_archive_copy_done (xfer_data->archive, xfer_data->action, error);
+	xfer_data_free (xfer_data);
+}
+
+
+static void
+copy_to_remote_location_progress (goffset   current_file,
+                                  goffset   total_files,
+                                  GFile    *source,
+                                  GFile    *destination,
+                                  goffset   current_num_bytes,
+                                  goffset   total_num_bytes,
+                                  gpointer  user_data)
+{
+	XferData *xfer_data = user_data;
+
+	g_signal_emit (G_OBJECT (xfer_data->archive),
+		       fr_archive_signals[PROGRESS],
+		       0,
+		       (double) current_num_bytes / total_num_bytes);
+}
+
+
+static void
+copy_to_remote_location (FrArchive  *archive,
+			 FrAction    action)
+{
+	XferData *xfer_data;
+
+	xfer_data = g_new0 (XferData, 1);
+	xfer_data->archive = archive;
+	xfer_data->action = action;
+
+	g_copy_file_async (archive->local_copy,
+			   archive->file,
+			   G_FILE_COPY_OVERWRITE,
+			   G_PRIORITY_DEFAULT,
+			   archive->priv->cancellable,
+			   copy_to_remote_location_progress,
+			   xfer_data,
+			   copy_to_remote_location_done,
+			   xfer_data);
+}
+
+
+/* -- copy_extracted_files_to_destination -- */
+
+
 static void
 move_here (FrArchive *archive)
 {
@@ -656,6 +823,61 @@ move_here (FrArchive *archive)
 }
 
 
+static void
+copy_extracted_files_done (GError   *error,
+			   gpointer  user_data)
+{
+	FrArchive *archive = user_data;
+
+	remove_local_directory (archive->priv->temp_extraction_dir);
+	g_free (archive->priv->temp_extraction_dir);
+	archive->priv->temp_extraction_dir = NULL;
+
+	fr_archive_action_completed (archive,
+				     FR_ACTION_COPYING_FILES_TO_REMOTE,
+				     FR_PROC_ERROR_NONE,
+				     NULL);
+
+	if ((error == NULL) && (archive->priv->extract_here))
+		move_here (archive);
+
+	fr_archive_copy_done (archive, FR_ACTION_EXTRACTING_FILES, error);
+}
+
+
+static void
+copy_extracted_files_progress (goffset   current_file,
+                               goffset   total_files,
+                               GFile    *source,
+                               GFile    *destination,
+                               goffset   current_num_bytes,
+                               goffset   total_num_bytes,
+                               gpointer  user_data)
+{
+	FrArchive *archive = user_data;
+
+	g_signal_emit (G_OBJECT (archive),
+		       fr_archive_signals[PROGRESS],
+		       0,
+		       (double) current_file / (total_files + 1));
+}
+
+
+static void
+copy_extracted_files_to_destination (FrArchive *archive)
+{
+	g_directory_copy_async (archive->priv->temp_extraction_dir,
+				archive->priv->extraction_destination,
+				G_FILE_COPY_OVERWRITE,
+				G_PRIORITY_DEFAULT,
+				archive->priv->cancellable,
+				copy_extracted_files_progress,
+				archive,
+				copy_extracted_files_done,
+				archive);
+}
+
+
 static void add_dropped_items (DroppedItemsData *data);
 
 
@@ -672,6 +894,11 @@ fr_archive_change_name (FrArchive  *archive,
 	g_object_unref (archive->file);
 	archive->file = g_file_get_child (parent, name);
 	g_object_unref (parent);
+
+	parent = g_file_get_parent (archive->local_copy);
+	g_object_unref (archive->local_copy);
+	archive->local_copy = g_file_get_child (parent, name);
+	g_object_unref (parent);
 }
 
 
@@ -686,6 +913,15 @@ action_performed (FrCommand   *command,
 #endif
 
 	switch (action) {
+	case FR_ACTION_DELETING_FILES:
+		if (error->type == FR_PROC_ERROR_NONE) {
+			if (! g_file_has_uri_scheme (archive->file, "file")) {
+				copy_to_remote_location (archive, action);
+				return;
+			}
+		}
+		break;
+
 	case FR_ACTION_ADDING_FILES:
 		if (error->type == FR_PROC_ERROR_NONE) {
 			fr_archive_remove_temp_work_dir (archive);
@@ -701,15 +937,33 @@ action_performed (FrCommand   *command,
 			 * original name */
 			if (archive->command->multi_volume)
 				fr_archive_change_name (archive, archive->command->filename);
+			if (! g_file_has_uri_scheme (archive->file, "file")) {
+				copy_to_remote_location (archive, action);
+				return;
+			}
 		}
 		break;
 
 	case FR_ACTION_EXTRACTING_FILES:
 		if (error->type == FR_PROC_ERROR_NONE) {
-			if (archive->priv->extract_here)
+			if (archive->priv->remote_extraction) {
+				copy_extracted_files_to_destination (archive);
+				return;
+			}
+			else if (archive->priv->extract_here)
 				move_here (archive);
 		}
 		else {
+			/* if an error occurred during extraction remove the
+			 * temp extraction dir, if used. */
+			g_print ("action_performed: ERROR!\n");
+
+			if ((archive->priv->remote_extraction) && (archive->priv->temp_extraction_dir != NULL)) {
+				remove_local_directory (archive->priv->temp_extraction_dir);
+				g_free (archive->priv->temp_extraction_dir);
+				archive->priv->temp_extraction_dir = NULL;
+			}
+
 			if (archive->priv->extract_here)
 				remove_directory (archive->priv->extraction_destination);
 		}
@@ -817,7 +1071,7 @@ fr_archive_create (FrArchive  *archive,
 
 	tmp_command = archive->command;
 
-	mime_type = get_mime_type_from_filename (archive->file);
+	mime_type = get_mime_type_from_filename (archive->local_copy);
 	if (! create_command_to_create_archive (archive, mime_type)) {
 		archive->command = tmp_command;
 		return FALSE;
@@ -878,11 +1132,11 @@ load_local_archive (FrArchive  *archive,
 
 	tmp_command = archive->command;
 
-	mime_type = get_mime_type_from_filename (archive->file);
+	mime_type = get_mime_type_from_filename (archive->local_copy);
 	if (! create_command_to_load_archive (archive, mime_type)) {
-		mime_type = get_mime_type_from_content (archive->file);
+		mime_type = get_mime_type_from_content (archive->local_copy);
 		if (! create_command_to_load_archive (archive, mime_type)) {
-			mime_type = get_mime_type_from_magic_numbers (archive->file);
+			mime_type = get_mime_type_from_magic_numbers (archive->local_copy);
 			if (! create_command_to_load_archive (archive, mime_type)) {
 				archive->command = tmp_command;
 				archive->content_type = mime_type;
@@ -921,6 +1175,86 @@ load_local_archive (FrArchive  *archive,
 }
 
 
+static void
+copy_remote_file_done (GError   *error,
+		       gpointer  user_data)
+{
+	XferData *xfer_data = user_data;
+
+	if (error != NULL)
+		fr_archive_copy_done (xfer_data->archive, FR_ACTION_LOADING_ARCHIVE, error);
+	else
+		load_local_archive (xfer_data->archive, xfer_data->password);
+	xfer_data_free (xfer_data);
+}
+
+
+static void
+copy_remote_file_progress (goffset   current_file,
+                           goffset   total_files,
+                           GFile    *source,
+                           GFile    *destination,
+                           goffset   current_num_bytes,
+                           goffset   total_num_bytes,
+                           gpointer  user_data)
+{
+	XferData *xfer_data = user_data;
+
+	g_signal_emit (G_OBJECT (xfer_data->archive),
+		       fr_archive_signals[PROGRESS],
+		       0,
+		       (double) current_num_bytes / total_num_bytes);
+}
+
+
+static gboolean
+copy_remote_file_done_cb (gpointer user_data)
+{
+	XferData *xfer_data = user_data;
+
+	g_source_remove (xfer_data->source_id);
+	copy_remote_file_done (NULL, xfer_data);
+	return FALSE;
+}
+
+
+static void
+copy_remote_file (FrArchive  *archive,
+		  const char *password)
+{
+	XferData *xfer_data;
+
+	if (! g_file_query_exists (archive->file, NULL)) {
+		GError *error;
+		error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("The file doesn't exist"));
+		fr_archive_copy_done (archive, FR_ACTION_LOADING_ARCHIVE, error);
+		g_error_free (error);
+		return;
+	}
+
+	xfer_data = g_new0 (XferData, 1);
+	xfer_data->archive = archive;
+	xfer_data->uri = g_file_get_uri (archive->file);
+	if (password != NULL)
+		xfer_data->password = g_strdup (password);
+
+	if (! archive->is_remote) {
+		xfer_data->source_id = g_idle_add (copy_remote_file_done_cb, xfer_data);
+		return;
+	}
+
+	g_copy_file_async (archive->file,
+			   archive->local_copy,
+			   G_FILE_COPY_OVERWRITE,
+			   G_PRIORITY_DEFAULT,
+			   archive->priv->cancellable,
+			   copy_remote_file_progress,
+			   xfer_data,
+			   copy_remote_file_done,
+			   xfer_data);
+}
+
+
 gboolean
 fr_archive_load (FrArchive  *archive,
 		 const char *uri,
@@ -934,7 +1268,7 @@ fr_archive_load (FrArchive  *archive,
 		       FR_ACTION_LOADING_ARCHIVE);
 
 	fr_archive_set_uri (archive, uri);
-	load_local_archive (archive, password);
+	copy_remote_file (archive, password);
 
 	return TRUE;
 }
@@ -953,7 +1287,7 @@ fr_archive_load_local (FrArchive  *archive,
 		       FR_ACTION_LOADING_ARCHIVE);
 
 	fr_archive_set_uri (archive, uri);
-	load_local_archive (archive, password);
+	copy_remote_file (archive, password);
 
 	return TRUE;
 }
@@ -1120,18 +1454,12 @@ convert_to_local_file_list (GList *file_list)
 	GList *scan;
 
 	for (scan = file_list; scan; scan = scan->next) {
-		GFile *file;
-		char  *uri = scan->data;
-		char  *local_filename;
-
-		file = g_file_new_for_uri (uri);
-		local_filename = g_file_get_path (file);
-		if (local_filename == NULL)
-			local_filename = g_strdup (uri);
+		char *uri = scan->data;
+		char *local_filename;
+
+		local_filename = g_uri_unescape_string (uri, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH);
 		if (local_filename != NULL)
 			local_file_list = g_list_prepend (local_file_list, local_filename);
-
-		g_object_unref (file);
 	}
 
 	return local_file_list;
@@ -1446,6 +1774,145 @@ fr_archive_add_local_files (FrArchive     *archive,
 }
 
 
+static void
+copy_remote_files_done (GError   *error,
+			gpointer  user_data)
+{
+	XferData *xfer_data = user_data;
+
+	fr_archive_copy_done (xfer_data->archive, FR_ACTION_COPYING_FILES_FROM_REMOTE, error);
+
+	if (error == NULL)
+		fr_archive_add_local_files (xfer_data->archive,
+					    xfer_data->file_list,
+					    xfer_data->tmp_dir,
+					    xfer_data->dest_dir,
+					    FALSE,
+					    xfer_data->password,
+					    xfer_data->encrypt_header,
+					    xfer_data->compression,
+					    xfer_data->volume_size);
+	xfer_data_free (xfer_data);
+}
+
+
+static void
+copy_remote_files_progress (goffset   current_file,
+                            goffset   total_files,
+                            GFile    *source,
+                            GFile    *destination,
+                            goffset   current_num_bytes,
+                            goffset   total_num_bytes,
+                            gpointer  user_data)
+{
+	XferData *xfer_data = user_data;
+
+	g_signal_emit (G_OBJECT (xfer_data->archive),
+		       fr_archive_signals[PROGRESS],
+		       0,
+		       (double) current_file / (total_files + 1));
+}
+
+
+static void
+copy_remote_files (FrArchive     *archive,
+		   GList         *file_list,
+		   const char    *base_uri,
+		   const char    *dest_dir,
+		   gboolean       update,
+		   const char    *password,
+		   gboolean       encrypt_header,
+		   FrCompression  compression,
+		   guint          volume_size,
+		   const char    *tmp_dir)
+{
+	GList      *sources = NULL, *destinations = NULL;
+	GHashTable *created_folders;
+	GList      *scan;
+	XferData   *xfer_data;
+
+	created_folders = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
+	for (scan = file_list; scan; scan = scan->next) {
+		char  *partial_filename = scan->data;
+		char  *local_uri;
+		char  *local_folder_uri;
+		char  *remote_uri;
+
+		local_uri = g_strconcat ("file://", tmp_dir, "/", partial_filename, NULL);
+		local_folder_uri = remove_level_from_path (local_uri);
+		if (g_hash_table_lookup (created_folders, local_folder_uri) == NULL) {
+			GError *error = NULL;
+			if (! ensure_dir_exists (local_folder_uri, 0755, &error)) {
+				g_free (local_folder_uri);
+				g_free (local_uri);
+				gio_file_list_free (sources);
+				gio_file_list_free (destinations);
+				g_hash_table_destroy (created_folders);
+
+				fr_archive_action_completed (archive,
+							     FR_ACTION_COPYING_FILES_FROM_REMOTE,
+							     FR_PROC_ERROR_GENERIC,
+							     error->message);
+				g_clear_error (&error);
+				return;
+			}
+
+			g_hash_table_insert (created_folders, local_folder_uri, GINT_TO_POINTER (1));
+		}
+		else
+			g_free (local_folder_uri);
+
+		remote_uri = g_strconcat (base_uri, "/", partial_filename, NULL);
+		sources = g_list_append (sources, g_file_new_for_uri (remote_uri));
+		g_free (remote_uri);
+
+		destinations = g_list_append (destinations, g_file_new_for_uri (local_uri));
+		g_free (local_uri);
+	}
+	g_hash_table_destroy (created_folders);
+
+	xfer_data = g_new0 (XferData, 1);
+	xfer_data->archive = archive;
+	xfer_data->file_list = path_list_dup (file_list);
+	xfer_data->base_uri = g_strdup (base_uri);
+	xfer_data->dest_dir = g_strdup (dest_dir);
+	xfer_data->update = update;
+	xfer_data->dest_dir = g_strdup (dest_dir);
+	xfer_data->password = g_strdup (password);
+	xfer_data->encrypt_header = encrypt_header;
+	xfer_data->compression = compression;
+	xfer_data->volume_size = volume_size;
+	xfer_data->tmp_dir = g_strdup (tmp_dir);
+
+	g_signal_emit (G_OBJECT (archive),
+		       fr_archive_signals[START],
+		       0,
+		       FR_ACTION_COPYING_FILES_FROM_REMOTE);
+
+	g_copy_files_async (sources,
+			    destinations,
+			    G_FILE_COPY_OVERWRITE,
+			    G_PRIORITY_DEFAULT,
+			    archive->priv->cancellable,
+			    copy_remote_files_progress,
+			    xfer_data,
+			    copy_remote_files_done,
+			    xfer_data);
+
+	gio_file_list_free (sources);
+	gio_file_list_free (destinations);
+}
+
+
+static char *
+fr_archive_get_temp_work_dir (FrArchive *archive)
+{
+	fr_archive_remove_temp_work_dir (archive);
+	archive->priv->temp_dir = get_temp_work_dir (NULL);
+	return archive->priv->temp_dir;
+}
+
+
 void
 fr_archive_add_files (FrArchive     *archive,
 		      GList         *file_list,
@@ -1457,23 +1924,30 @@ fr_archive_add_files (FrArchive     *archive,
 		      FrCompression  compression,
 		      guint          volume_size)
 {
-	GFile *file;
-	char  *local_dir;
-
-	file = g_file_new_for_uri (base_dir);
-	local_dir = g_file_get_path (file);
-	fr_archive_add_local_files (archive,
-				    file_list,
-				    local_dir,
-				    dest_dir,
-				    update,
-				    password,
-				    encrypt_header,
-				    compression,
-				    volume_size);
-
-	g_free (local_dir);
-	g_object_unref (file);
+	if (uri_is_local (base_dir)) {
+		char *local_dir = g_filename_from_uri (base_dir, NULL, NULL);
+		fr_archive_add_local_files (archive,
+					    file_list,
+					    local_dir,
+					    dest_dir,
+					    update,
+					    password,
+					    encrypt_header,
+					    compression,
+					    volume_size);
+		g_free (local_dir);
+	}
+	else
+		copy_remote_files (archive,
+				   file_list,
+				   base_dir,
+				   dest_dir,
+				   update,
+				   password,
+				   encrypt_header,
+				   compression,
+				   volume_size,
+				   fr_archive_get_temp_work_dir (archive));
 }
 
 
@@ -2675,25 +3149,38 @@ fr_archive_extract (FrArchive  *archive,
 		    gboolean    junk_paths,
 		    const char *password)
 {
-	GFile *file;
-	char  *local_destination;
-
 	g_free (archive->priv->extraction_destination);
 	archive->priv->extraction_destination = g_strdup (destination);
 
-	file = g_file_new_for_uri (destination);
-	local_destination = g_file_get_path (file);
-	fr_archive_extract_to_local (archive,
-				     file_list,
-				     local_destination,
-				     base_dir,
-				     skip_older,
-				     overwrite,
-				     junk_paths,
-				     password);
-
-	g_free (local_destination);
-	g_object_unref (file);
+	g_free (archive->priv->temp_extraction_dir);
+	archive->priv->temp_extraction_dir = NULL;
+
+	archive->priv->remote_extraction = ! uri_is_local (destination);
+	if (archive->priv->remote_extraction) {
+		archive->priv->temp_extraction_dir = get_temp_work_dir (NULL);
+		fr_archive_extract_to_local (archive,
+					     file_list,
+					     archive->priv->temp_extraction_dir,
+					     base_dir,
+					     skip_older,
+					     overwrite,
+					     junk_paths,
+					     password);
+	}
+	else {
+		char *local_destination;
+
+		local_destination = g_filename_from_uri (destination, NULL, NULL);
+		fr_archive_extract_to_local (archive,
+					     file_list,
+					     local_destination,
+					     base_dir,
+					     skip_older,
+					     overwrite,
+					     junk_paths,
+					     password);
+		g_free (local_destination);
+	}
 }
 
 
diff --git a/src/fr-archive.h b/src/fr-archive.h
index 2c485a2..530e49e 100644
--- a/src/fr-archive.h
+++ b/src/fr-archive.h
@@ -44,6 +44,8 @@ struct _FrArchive {
 	GObject  __parent;
 
 	GFile       *file;
+	GFile       *local_copy;
+	gboolean     is_remote;
 	const char  *content_type;
 	FrCommand   *command;
 	FrProcess   *process;
diff --git a/src/fr-window.c b/src/fr-window.c
index 8eeb833..d8fb08e 100644
--- a/src/fr-window.c
+++ b/src/fr-window.c
@@ -4226,14 +4226,14 @@ get_selection_data_from_clipboard_data (FrWindow        *window,
 		      			FrClipboardData *data)
 {
 	GString *list;
-	char    *archive_uri;
+	char    *local_filename;
 	GList   *scan;
 
 	list = g_string_new (NULL);
 
-	archive_uri = g_file_get_uri (window->archive->file);
-	g_string_append (list, archive_uri);
-	g_free (archive_uri);
+	local_filename = g_file_get_uri (window->archive->local_copy);
+	g_string_append (list, local_filename);
+	g_free (local_filename);
 
 	g_string_append (list, "\r\n");
 	if (window->priv->password != NULL)
diff --git a/src/gio-utils.c b/src/gio-utils.c
index f94e94f..7886b2e 100644
--- a/src/gio-utils.c
+++ b/src/gio-utils.c
@@ -127,7 +127,7 @@ filter_empty (Filter *filter)
 
 
 typedef struct {
-	char                 *base_directory;
+	GFile                *base_directory;
 	gboolean              recursive;
 	gboolean              follow_links;
 	StartDirCallback      start_dir_func;
@@ -153,7 +153,8 @@ for_each_child_data_free (ForEachChildData *fec)
 	if (fec == NULL)
 		return;
 
-	g_free (fec->base_directory);
+	if (fec->base_directory != NULL)
+		g_object_unref (fec->base_directory);
 	if (fec->current != NULL)
 		g_object_unref (fec->current);
 	if (fec->already_visited)
@@ -172,7 +173,7 @@ for_each_child_done_cb (gpointer user_data)
 	g_source_remove (fec->source_id);
 	if (fec->current != NULL) {
 		g_object_unref (fec->current);
-		 fec->current = NULL;
+		fec->current = NULL;
 	}
 	if (fec->done_func)
 		fec->done_func (fec->error, fec->user_data);
@@ -212,8 +213,8 @@ for_each_child_start (ForEachChildData *fec)
 
 
 static void
-for_each_child_set_current (ForEachChildData *fec,
-			    const char       *directory)
+for_each_child_set_current_uri (ForEachChildData *fec,
+				const char       *directory)
 {
 	if (fec->current != NULL)
 		g_object_unref (fec->current);
@@ -222,6 +223,15 @@ for_each_child_set_current (ForEachChildData *fec,
 
 
 static void
+for_each_child_set_current (ForEachChildData *fec,
+			    GFile            *directory)
+{
+	if (fec->current != NULL)
+		g_object_unref (fec->current);
+	fec->current = g_file_dup (directory);
+}
+
+static void
 for_each_child_start_next_sub_directory (ForEachChildData *fec)
 {
 	char *sub_directory = NULL;
@@ -236,7 +246,7 @@ for_each_child_start_next_sub_directory (ForEachChildData *fec)
 	}
 
 	if (sub_directory != NULL) {
-		for_each_child_set_current (fec, sub_directory);
+		for_each_child_set_current_uri (fec, sub_directory);
 		for_each_child_start (fec);
 	}
 	else
@@ -276,7 +286,6 @@ for_each_child_next_files_ready (GObject      *source_object,
 {
 	ForEachChildData *fec = user_data;
 	GList            *children, *scan;
-	char             *current_directory;
 
 	children = g_file_enumerator_next_files_finish (fec->enumerator,
                                                         result,
@@ -291,16 +300,16 @@ for_each_child_next_files_ready (GObject      *source_object,
 		return;
 	}
 
-	current_directory = g_file_get_uri (fec->current);
 	for (scan = children; scan; scan = scan->next) {
 		GFileInfo *child_info = scan->data;
-		char      *name, *uri;
+		GFile     *f;
+		char      *uri;
 
-		name = g_uri_escape_string (g_file_info_get_name (child_info), G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT, FALSE);
-		uri = g_strconcat (current_directory, "/", name, NULL);
+		f = g_file_get_child (fec->current, g_file_info_get_name (child_info));
+		uri = g_file_get_uri (f);
 
 		if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY) {
-			/* avoid to visit a directory more than ones */
+			/* avoid to visit a directory more than once */
 
 			if (g_hash_table_lookup (fec->already_visited, uri) == NULL) {
 				char *sub_directory;
@@ -314,9 +323,8 @@ for_each_child_next_files_ready (GObject      *source_object,
 		fec->for_each_file_func (uri, child_info, fec->user_data);
 
 		g_free (uri);
-		g_free (name);
+		g_object_unref (f);
 	}
-	g_free (current_directory);
 
 	g_file_enumerator_next_files_async (fec->enumerator,
                                             N_FILES_PER_REQUEST,
@@ -404,7 +412,7 @@ for_each_child_start_current (ForEachChildData *fec)
  * Each callback uses the same @user_data additional parameter.
  */
 void
-g_directory_foreach_child (const char           *directory,
+g_directory_foreach_child (GFile                *directory,
 			   gboolean              recursive,
 			   gboolean              follow_links,
 			   GCancellable         *cancellable,
@@ -419,7 +427,7 @@ g_directory_foreach_child (const char           *directory,
 
 	fec = g_new0 (ForEachChildData, 1);
 
-	fec->base_directory = g_strdup (directory);
+	fec->base_directory = g_object_ref (directory);
 	fec->recursive = recursive;
 	fec->follow_links = follow_links;
 	fec->cancellable = cancellable;
@@ -443,8 +451,8 @@ g_directory_foreach_child (const char           *directory,
 typedef struct {
 	GList             *files;
 	GList             *dirs;
-	char              *directory;
-	char              *base_dir;
+	GFile             *directory;
+	GFile             *base_dir;
 	GCancellable      *cancellable;
 	ListReadyCallback  done_func;
 	gpointer           done_data;
@@ -469,8 +477,10 @@ get_file_list_data_free (GetFileListData *gfl)
 	path_list_free (gfl->files);
 	path_list_free (gfl->dirs);
 	path_list_free (gfl->to_visit);
-	g_free (gfl->directory);
-	g_free (gfl->base_dir);
+	if (gfl->directory != NULL)
+		g_object_unref (gfl->directory);
+	if (gfl->base_dir != NULL)
+		g_object_unref (gfl->base_dir);
 	g_free (gfl);
 }
 
@@ -479,27 +489,25 @@ get_file_list_data_free (GetFileListData *gfl)
 
 
 static GList*
-get_relative_file_list (GList      *rel_list,
-			GList      *file_list,
-			const char *base_dir)
+get_relative_file_list (GList *rel_list,
+			GList *file_list,
+			GFile *base_dir)
 {
 	GList *scan;
-	int    base_len;
 
 	if (base_dir == NULL)
 		return NULL;
 
-	base_len = 0;
-	if (strcmp (base_dir, "/") != 0)
-		base_len = strlen (base_dir);
-
 	for (scan = file_list; scan; scan = scan->next) {
-		char *full_path = scan->data;
-
-		if (path_in_path (base_dir, full_path)) {
-			char *rel_path = g_uri_unescape_string (full_path + base_len + 1, NULL);
-			rel_list = g_list_prepend (rel_list, rel_path);
-		}
+		char  *full_path = scan->data;
+		GFile *f;
+		char  *relative_path;
+
+		f = g_file_new_for_commandline_arg (full_path);
+		relative_path = g_file_get_relative_path (base_dir, f);
+		if (relative_path != NULL)
+			rel_list = g_list_prepend (rel_list, relative_path);
+		g_object_unref (f);
 	}
 
 	return rel_list;
@@ -565,6 +573,7 @@ get_file_list_done (GError   *error,
 	GetFileListData *gfl = user_data;
 	GHashTable      *h_dirs;
 	GList           *scan;
+	char            *uri;
 
 	gfl->files = g_list_reverse (gfl->files);
 	gfl->dirs = g_list_reverse (gfl->dirs);
@@ -582,7 +591,7 @@ get_file_list_done (GError   *error,
 	if (gfl->base_dir != NULL) {
 		char *dir;
 
-		dir = g_strdup (gfl->base_dir);
+		dir = g_file_get_uri (gfl->base_dir);
 		gfl->dirs = g_list_prepend (gfl->dirs, dir);
 		g_hash_table_insert (h_dirs, dir, GINT_TO_POINTER (1));
 	}
@@ -594,11 +603,13 @@ get_file_list_done (GError   *error,
 	for (scan = gfl->dirs; scan; scan = scan->next)
 		g_hash_table_insert (h_dirs, (char*)scan->data, GINT_TO_POINTER (1));
 
-	gfl->dirs = g_list_concat (gfl->dirs, get_dir_list_from_file_list (h_dirs, gfl->base_dir, gfl->files, FALSE));
+	uri = g_file_get_uri (gfl->base_dir);
+	gfl->dirs = g_list_concat (gfl->dirs, get_dir_list_from_file_list (h_dirs, uri, gfl->files, FALSE));
 
 	if (filter_empty (gfl->include_filter))
-		gfl->dirs = g_list_concat (gfl->dirs, get_dir_list_from_file_list (h_dirs, gfl->base_dir, gfl->dirs, TRUE));
+		gfl->dirs = g_list_concat (gfl->dirs, get_dir_list_from_file_list (h_dirs, uri, gfl->dirs, TRUE));
 
+	g_free (uri);
 	/**/
 
 	if (error == NULL) {
@@ -680,8 +691,8 @@ g_directory_list_async (const char        *directory,
 	FilterOptions    filter_options;
 
 	gfl = g_new0 (GetFileListData, 1);
-	gfl->directory = g_strdup (directory);
-	gfl->base_dir = g_strdup (base_dir);
+	gfl->directory = g_file_new_for_commandline_arg (directory);
+	gfl->base_dir = g_file_new_for_commandline_arg (base_dir);
 	gfl->done_func = done_func;
 	gfl->done_data = done_data;
 
@@ -696,7 +707,7 @@ g_directory_list_async (const char        *directory,
 	gfl->exclude_filter = filter_new (exclude_files, ignorecase ? FILTER_IGNORECASE : FILTER_DEFAULT);
 	gfl->exclude_folders_filter = filter_new (exclude_folders, ignorecase ? FILTER_IGNORECASE : FILTER_DEFAULT);
 
-	g_directory_foreach_child (directory,
+	g_directory_foreach_child (gfl->directory,
 				   recursive,
 				   follow_links,
 				   cancellable,
@@ -756,7 +767,9 @@ static void
 get_items_for_current_dir (GetFileListData *gfl)
 {
 	const char *directory_name;
+	GFile      *directory_file;
 	char       *directory_uri;
+	char       *base_dir_uri;
 
 	if (gfl->current_dir == NULL) {
 		if (gfl->done_func) {
@@ -770,19 +783,20 @@ get_items_for_current_dir (GetFileListData *gfl)
 	}
 
 	directory_name = file_name_from_path ((char*) gfl->current_dir->data);
-	if (strcmp (gfl->base_dir, "/") == 0)
-		directory_uri = g_strconcat (gfl->base_dir, directory_name, NULL);
-	else
-		directory_uri = g_strconcat (gfl->base_dir, "/", directory_name, NULL);
+	directory_file = g_file_get_child (gfl->base_dir, directory_name);
+	directory_uri = g_file_get_uri (directory_file);
+	base_dir_uri = g_file_get_uri (gfl->base_dir);
 
 	g_directory_list_all_async (directory_uri,
-			   	    gfl->base_dir,
+				    base_dir_uri,
 				    TRUE,
 				    gfl->cancellable,
-			   	    get_items_for_current_dir_done,
-			   	    gfl);
+				    get_items_for_current_dir_done,
+				    gfl);
 
 	g_free (directory_uri);
+	g_free (base_dir_uri);
+	g_object_unref (directory_file);
 }
 
 
@@ -800,7 +814,7 @@ g_list_items_async (GList             *items,
 	g_return_if_fail (base_dir != NULL);
 
 	gfl = g_new0 (GetFileListData, 1);
-	gfl->base_dir = g_strdup (base_dir);
+	gfl->base_dir = g_file_new_for_commandline_arg (base_dir);
 	gfl->cancellable = cancellable;
 	gfl->done_func = done_func;
 	gfl->done_data = done_data;
@@ -916,6 +930,19 @@ g_copy_files_ready_cb (GObject      *source_object,
 	GError        *error = NULL;
 
 	if (! g_file_copy_finish (source, result, &error)) {
+		/* source and target are directories, ignore the error */
+		if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_MERGE))
+			g_clear_error (&error);
+		/* source is directory, create target directory */
+		if (g_error_matches (error, G_IO_ERROR,  G_IO_ERROR_WOULD_RECURSE)) {
+			g_clear_error (&error);
+			g_file_make_directory ((GFile*) cfd->destination->data,
+					       cfd->cancellable,
+					       &error);
+		}
+	}
+
+	if (error) {
 		if (cfd->callback)
 			cfd->callback (error, cfd->user_data);
 		g_clear_error (&error);
@@ -1123,8 +1150,8 @@ child_data_free (ChildData *child)
 
 
 typedef struct {
-	char                  *source;
-	char                  *destination;
+	GFile                 *source;
+	GFile                 *destination;
 	GFileCopyFlags         flags;
 	int                    io_priority;
 	GCancellable          *cancellable;
@@ -1149,8 +1176,10 @@ directory_copy_data_free (DirectoryCopyData *dcd)
 	if (dcd == NULL)
 		return;
 
-	g_free (dcd->source);
-	g_free (dcd->destination);
+	if (dcd->source != NULL)
+		g_object_unref (dcd->source);
+	if (dcd->destination != NULL)
+		g_object_unref (dcd->destination);
 	if (dcd->current_source != NULL) {
 		g_object_unref (dcd->current_source);
 		dcd->current_source = NULL;
@@ -1161,7 +1190,6 @@ directory_copy_data_free (DirectoryCopyData *dcd)
 	}
 	g_list_foreach (dcd->to_copy, (GFunc) child_data_free, NULL);
 	g_list_free (dcd->to_copy);
-	g_object_unref (dcd->cancellable);
 	g_free (dcd);
 }
 
@@ -1187,15 +1215,19 @@ static GFile *
 get_destination_for_uri (DirectoryCopyData *dcd,
 		         const char        *uri)
 {
-	char  *destination_uri;
+	GFile *f_uri;
 	GFile *destination_file;
+	char  *relative_path;
 
-	if (strlen (uri) <=  strlen (dcd->source))
-		return NULL;
+	f_uri = g_file_new_for_uri (uri);
+	relative_path = g_file_get_relative_path (dcd->source, f_uri);
+	if (relative_path != NULL)
+		destination_file = g_file_resolve_relative_path (dcd->destination, relative_path);
+	else
+		destination_file = g_file_dup (dcd->destination);
 
-	destination_uri = g_strconcat (dcd->destination, "/", uri + strlen (dcd->source) + 1, NULL);
-	destination_file = g_file_new_for_uri (destination_uri);
-	g_free (destination_uri);
+	g_free (relative_path);
+	g_object_unref (f_uri);
 
 	return destination_file;
 }
@@ -1417,9 +1449,10 @@ g_directory_copy_async (const char            *source,
 {
 	DirectoryCopyData *dcd;
 
+	/* Creating GFile objects here will save us lot of effort in path construction */
 	dcd = g_new0 (DirectoryCopyData, 1);
-	dcd->source = g_strdup (source);
-	dcd->destination = g_strdup (destination);
+	dcd->source = g_file_new_for_commandline_arg (source);
+	dcd->destination = g_file_new_for_commandline_arg (destination);
 	dcd->flags = flags;
 	dcd->io_priority = io_priority;
 	dcd->cancellable = cancellable;
diff --git a/src/gio-utils.h b/src/gio-utils.h
index 4cd0a49..7dfe306 100644
--- a/src/gio-utils.h
+++ b/src/gio-utils.h
@@ -58,7 +58,7 @@ typedef void (*CopyDoneCallback)     (GError      *error,
 
 /* asynchronous recursive list functions */
 
-void   g_directory_foreach_child     (const char            *directory,
+void   g_directory_foreach_child     (GFile                 *directory,
 				      gboolean               recursive,
 				      gboolean               follow_links,
 				      GCancellable          *cancellable,
--
cgit v0.8.3.1


Index: file-roller.spec
===================================================================
RCS file: /cvs/extras/rpms/file-roller/devel/file-roller.spec,v
retrieving revision 1.179
retrieving revision 1.180
diff -u -p -r1.179 -r1.180
--- file-roller.spec	6 May 2010 02:19:06 -0000	1.179
+++ file-roller.spec	17 May 2010 14:47:48 -0000	1.180
@@ -11,7 +11,7 @@
 Summary:	Tool for viewing and creating archives
 Name:		file-roller
 Version:	2.30.1.1
-Release: 	2%{?dist}
+Release: 	3%{?dist}
 License:	GPLv2+
 Group:		Applications/Archiving
 URL:		http://download.gnome.org/sources/file-roller/
@@ -43,6 +43,10 @@ Conflicts: nautilus < 2.2.0
 # https://bugzilla.gnome.org/show_bug.cgi?id=617840
 Patch0: tar7z.patch
 
+# from master
+# http://bugzilla.gnome.org/show_bug.cgi?id=617769
+Patch1: file-roller-2.31.0-gvfs-fuse.patch
+
 %description
 File Roller is an application for creating and viewing archives files,
 such as tar or zip files.
@@ -50,6 +54,7 @@ such as tar or zip files.
 %prep
 %setup -q
 %patch0 -p1 -b .tarz7
+%patch1 -p1 -b .gvfs-fuse
 
 %build
 %configure 	--disable-scrollkeeper 		\
@@ -111,6 +116,9 @@ gtk-update-icon-cache %{_datadir}/icons/
 %{_datadir}/icons/hicolor/scalable/apps/file-roller.svg
 
 %changelog
+* Mon May 17 2010 Tomas Bzatek <tbzatek at redhat.com> 2.30.1.1-3
+- Fix archive handling on remote GIO mounts without running fuse daemon (#527045, #518510)
+
 * Wed May  5 2010 Matthias Clasen <mclasen at redhat.com> 2.30.1.1-2
 - Don't crash when creating .tar.7z archives
 



More information about the scm-commits mailing list