[file-roller] Bring back support for file caching when gvfs-fuse-daemon is not available
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [file-roller] Bring back support for file caching when gvfs-fuse-daemon is not available
- Date: Sat, 15 May 2010 10:33:56 +0000 (UTC)
commit 33c21fc3647af32de5a9c9d49e33765a526910f5
Author: Tomas Bzatek <tbzatek redhat com>
Date: Wed May 12 13:54:29 2010 +0200
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.
src/fr-archive.c | 595 +++++++++++++++++++++++++++++++++++++++++++++++++-----
src/fr-archive.h | 2 +
src/fr-window.c | 8 +-
src/gio-utils.c | 155 +++++++++------
src/gio-utils.h | 2 +-
5 files changed, 642 insertions(+), 120 deletions(-)
---
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,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]