file-roller r2193 - in trunk: . src
- From: paobac svn gnome org
- To: svn-commits-list gnome org
- Subject: file-roller r2193 - in trunk: . src
- Date: Sat, 29 Mar 2008 10:08:26 +0000 (GMT)
Author: paobac
Date: Sat Mar 29 10:08:26 2008
New Revision: 2193
URL: http://svn.gnome.org/viewvc/file-roller?rev=2193&view=rev
Log:
2008-03-29 Paolo Bacchilega <paobac svn gnome org>
* src/gio-utils.h:
* src/gio-utils.c: new files
Started implementing asynchronous recursive copy functions using gio.
Moved gio functions in gio-utils.c
Added:
trunk/src/gio-utils.c
trunk/src/gio-utils.h
Modified:
trunk/ChangeLog
Added: trunk/src/gio-utils.c
==============================================================================
--- (empty file)
+++ trunk/src/gio-utils.c Sat Mar 29 10:08:26 2008
@@ -0,0 +1,1207 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * File-Roller
+ *
+ * Copyright (C) 2001, 2003, 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include "glib-utils.h"
+#include "file-utils.h"
+#include "gio-utils.h"
+
+
+#define N_FILES_PER_REQUEST 128
+
+
+/* -- filter -- */
+
+
+typedef enum {
+ FILTER_DEFAULT = 0,
+ FILTER_NODOTFILES = 1 << 1,
+ FILTER_IGNORECASE = 1 << 2,
+ FILTER_NOBACKUPFILES = 1 << 3
+} FilterOptions;
+
+
+typedef struct {
+ char *pattern;
+ char **patterns;
+ FilterOptions options;
+ GRegex **regexps;
+} Filter;
+
+
+static Filter *
+filter_new (const char *pattern,
+ FilterOptions options)
+{
+ Filter *filter;
+ GRegexCompileFlags flags;
+ int i;
+
+ filter = g_new0 (Filter, 1);
+
+ if (pattern != NULL) {
+ filter->pattern = g_strdup (pattern);
+ filter->patterns = search_util_get_patterns (pattern);
+ }
+
+ filter->options = options;
+ if (filter->options & FILTER_IGNORECASE)
+ flags = G_REGEX_CASELESS;
+ else
+ flags = 0;
+
+ if (pattern != NULL) {
+ filter->regexps = g_new0 (GRegex*, n_fields (filter->patterns) + 1);
+ for (i = 0; filter->patterns[i] != NULL; i++)
+ filter->regexps[i] = g_regex_new (filter->patterns[i],
+ flags,
+ G_REGEX_MATCH_NOTEMPTY,
+ NULL);
+ filter->regexps[i] = NULL;
+ }
+
+ return filter;
+}
+
+
+static void
+filter_destroy (Filter *filter)
+{
+ g_return_if_fail (filter != NULL);
+
+ g_free (filter->pattern);
+ if (filter->patterns != NULL)
+ g_strfreev (filter->patterns);
+ if (filter->regexps != NULL) {
+ int i;
+ for (i = 0; filter->regexps[i] != NULL; i++)
+ g_regex_unref (filter->regexps[i]);
+ g_free (filter->regexps);
+ }
+ g_free (filter);
+}
+
+
+static gboolean
+match_regexps (GRegex **regexps,
+ const char *string)
+{
+ gboolean matched;
+ int i;
+
+ if ((regexps == NULL) || (regexps[0] == NULL))
+ return TRUE;
+
+ if (string == NULL)
+ return FALSE;
+
+ matched = FALSE;
+ for (i = 0; regexps[i] != NULL; i++)
+ if (g_regex_match (regexps[i], string, 0, NULL)) {
+ matched = TRUE;
+ break;
+ }
+
+ return matched;
+}
+
+
+static gboolean
+filter_matches (Filter *filter,
+ const char *name)
+{
+ const char *file_name;
+ char *utf8_name;
+ gboolean matched;
+
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ file_name = file_name_from_path (name);
+
+ if ((filter->options & FILTER_NODOTFILES)
+ && ((file_name[0] == '.') || (strstr (file_name, "/.") != NULL)))
+ return FALSE;
+
+ if ((filter->options & FILTER_NOBACKUPFILES)
+ && (file_name[strlen (file_name) - 1] == '~'))
+ return FALSE;
+
+ if (filter->pattern == NULL)
+ return TRUE;
+
+ utf8_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
+ matched = match_regexps (filter->regexps, utf8_name);
+ g_free (utf8_name);
+
+ return matched;
+}
+
+
+static gboolean
+filter_empty (Filter *filter)
+{
+ return ((filter->pattern == NULL) || (strcmp (filter->pattern, "*") == 0))
+}
+
+
+/* -- g_directory_foreach_child -- */
+
+
+typedef struct {
+ char *base_directory;
+ gboolean recursive;
+ gboolean follow_links;
+ StartDirCallback start_dir_func;
+ ForEachChildCallback for_each_file_func;
+ ForEachDoneCallback done_func;
+ gpointer user_data;
+
+ /* private */
+
+ GFile *current;
+ GHashTable *already_visited;
+ GList *to_visit;
+ Filter *filter;
+ GCancellable *cancellable;
+ GFileEnumerator *enumerator;
+ GError *error;
+} ForEachChildData;
+
+
+static void
+for_each_child_data_free (ForEachChildData *fec)
+{
+ if (fec == NULL)
+ return;
+
+ g_free (fec->base_directory);
+ if (fec->current != NULL)
+ g_object_unref (fec->current);
+ if (fec->already_visited)
+ g_hash_table_destroy (fec->already_visited);
+ if (fec->to_visit != NULL)
+ path_list_free (fec->to_visit);
+ if (fec->filter)
+ filter_destroy (fec->filter);
+ if (fec->error != NULL)
+ g_error_free (fec->error);
+ g_free (fec);
+}
+
+
+static void for_each_child_start (ForEachChildData *fec, const char *directory);
+
+
+static void
+for_each_child_done (ForEachChildData *fec)
+{
+ if (fec->done_func)
+ fec->done_func (fec->error, fec->user_data);
+ for_each_child_data_free (fec);
+}
+
+
+static void
+for_each_child_next_files_ready (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ForEachChildData *fec = user_data;
+ GList *children, *scan;
+ char *current_directory;
+
+ children = g_file_enumerator_next_files_finish (fec->enumerator,
+ result,
+ &(fec->error));
+
+ if (children == NULL) {
+ if ((fec->error == NULL) && fec->recursive) {
+ char *sub_directory = NULL;
+
+ if (fec->to_visit != NULL) {
+ GList *tmp;
+
+ sub_directory = (char*) fec->to_visit->data;
+ tmp = fec->to_visit;
+ fec->to_visit = g_list_remove_link (fec->to_visit, tmp);
+ g_list_free (tmp);
+ }
+
+ if (sub_directory != NULL) {
+ for_each_child_start (fec, sub_directory);
+ return;
+ }
+ }
+ for_each_child_done (fec);
+ return;
+ }
+
+ current_directory = g_file_get_uri (fec->current);
+ for (scan = children; scan; scan = scan->next) {
+ GFileInfo *child_info = scan->data;
+ char *name, *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);
+
+ if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY) {
+ char *sub_directory;
+
+ /* avoid to visit a directory more than ones */
+
+ sub_directory = g_strdup (uri);
+ if (g_hash_table_lookup (fec->already_visited, sub_directory) == NULL) {
+ g_hash_table_insert (fec->already_visited, sub_directory, GINT_TO_POINTER (1));
+ fec->to_visit = g_list_append (fec->to_visit, sub_directory);
+ }
+ else
+ g_free (sub_directory);
+ }
+
+ fec->for_each_func (uri, child_info, fec->user_data);
+
+ g_free (uri);
+ g_free (name);
+ }
+ g_free (current_directory);
+
+ g_file_enumerator_next_files_async (fec->enumerator,
+ N_FILES_PER_REQUEST,
+ G_PRIORITY_DEFAULT,
+ fec->cancellable,
+ for_each_child_next_files_ready,
+ fec);
+}
+
+static void
+for_each_child_ready (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ForEachChildData *fec = user_data;
+
+ fec->enumerator = g_file_enumerate_children_finish (fec->current, result, &(fec->error));
+ if (fec->enumerator == NULL) {
+ for_each_child_done (fec);
+ return;
+ }
+
+ g_file_enumerator_next_files_async (fec->enumerator,
+ N_FILES_PER_REQUEST,
+ G_PRIORITY_DEFAULT,
+ fec->cancellable,
+ for_each_child_next_files_ready,
+ fec);
+}
+
+
+static void
+for_each_child_start (ForEachChildData *fec,
+ const char *directory)
+{
+ if (fec->start_dir_func != NULL)
+ if (! fec->start_dir_func (directory, &(fec->error), fec->user_data)) {
+ for_each_child_done (fec);
+ return;
+ }
+
+ if (fec->current != NULL)
+ g_object_unref (fec->current);
+ fec->current = g_file_new_for_uri (directory);
+
+ g_file_enumerate_children_async (fec->current,
+ "standard::name,standard::type",
+ fec->follow_links ? G_FILE_QUERY_INFO_NONE : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ G_PRIORITY_DEFAULT,
+ fec->cancellable,
+ for_each_child_ready,
+ fec);
+}
+
+
+void
+g_directory_foreach_child (const char *directory,
+ gboolean recursive,
+ gboolean follow_links,
+ GCancellable *cancellable,
+ StartDirCallback start_dir_func,
+ ForEachChildCallback for_each_file_func,
+ ForEachDoneCallback done_func,
+ gpointer user_data)
+{
+ ForEachChildData *fec;
+
+ g_return_if_fail (for_each_file_func != NULL);
+
+ fec = g_new0 (ForEachChildData, 1);
+
+ fec->base_directory = g_strdup (directory);
+ fec->recursive = recursive;
+ fec->follow_links = follow_links;
+ fev->cancellable = cancellable;
+ fec->start_dir_func = start_dir_func;
+ fec->for_file_each_func = for_each_file_func;
+ fec->done_func = done_func;
+ fec->user_data = user_data;
+ fec->already_visited = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ NULL);
+
+ for_each_child_start (fec, fec->base_directory);
+}
+
+
+/* -- get_file_list_data -- */
+
+
+typedef struct {
+ GList *files;
+ GList *dirs;
+ VisitDirHandle *handle;
+
+ char *directory;
+ char *base_dir;
+ VisitDirDoneFunc done_func;
+ gpointer done_data;
+
+ GList *to_visit;
+ GList *current_dir;
+
+ Filter *include_filter;
+ Filter *exclude_filter;
+ guint visit_timeout;
+} GetFileListData;
+
+
+static void
+get_file_list_data_free (GetFileListData *gfl)
+{
+ if (gfl == NULL)
+ return;
+
+ filter_destroy (gfl->include_filter);
+ filter_destroy (gfl->exclude_filter);
+ 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);
+ g_free (gfl);
+}
+
+
+/* -- g_directory_list_async -- */
+
+
+static GList*
+get_relative_file_list (GList *rel_list,
+ GList *file_list,
+ const char *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_strdup (full_path + base_len + 1);
+ rel_list = g_list_prepend (rel_list, rel_path);
+ }
+ }
+
+ return rel_list;
+}
+
+
+static GList*
+get_dir_list_from_file_list (GHashTable *h_dirs,
+ const char *base_dir,
+ GList *files,
+ gboolean is_dir_list)
+{
+ GList *scan;
+ GList *dir_list = NULL;
+ int base_dir_len = strlen (base_dir);
+
+ for (scan = files; scan; scan = scan->next) {
+ char *filename = scan->data;
+ char *dir_name;
+
+ if (is_dir_list)
+ dir_name = g_strdup (filename + base_dir_len + 1);
+ else
+ dir_name = remove_level_from_path (filename + base_dir_len + 1);
+
+ while ((dir_name != NULL) && (dir_name[0] != '\0') && (strcmp (dir_name, "/") != 0)) {
+ char *tmp;
+ char *dir;
+
+ /* avoid to insert duplicated folders */
+
+ dir = g_strconcat (base_dir, "/", dir_name, NULL);
+ if (g_hash_table_lookup (h_dirs, dir) == NULL) {
+ g_hash_table_insert (h_dirs, dir, GINT_TO_POINTER (1));
+ dir_list = g_list_prepend (dir_list, dir);
+ }
+ else
+ g_free (dir);
+
+ tmp = dir_name;
+ dir_name = remove_level_from_path (tmp);
+ g_free (tmp);
+ }
+
+ g_free (dir_name);
+ }
+
+ return dir_list;
+}
+
+
+static void
+get_file_list_done (GError *error,
+ gpointer user_data)
+{
+ GetFileListData *gfl = user_data;
+ GHashTable *h_dirs;
+ char *dir;
+
+ gfl->files = g_list_reverse (gfl->files);
+ gfl->dirs = g_list_reverse (gfl->dirs);
+
+ if (! filter_empty (gfl->include_filter) || (gfl->exclude_filter->pattern != NULL)) {
+ path_list_free (gfl->dirs);
+ gfl->dirs = NULL;
+ }
+
+ /* Always include the base directory, this way empty base
+ * directories are added to the archive as well. */
+
+ dir = g_strdup (gfl->base_dir);
+ gfl->dirs = g_list_prepend (gfl->dirs, dir);
+ g_hash_table_insert (h_dirs, dir, GINT_TO_POINTER (1));
+
+ /* Add all the parent directories in gfl->files/gfl->dirs to the
+ * gfl->dirs list, the hash table is used to avoid duplicated
+ * entries. */
+
+ h_dirs = g_hash_table_new (g_str_hash, g_str_equal);
+ 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));
+
+ 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));
+
+ /**/
+
+ if (error == NULL) {
+ GList *rel_files, *rel_dirs;
+
+ if (gfl->base_dir != NULL) {
+ rel_files = get_relative_file_list (NULL, gfl->files, gfl->base_dir);
+ rel_dirs = get_relative_file_list (NULL, gfl->dirs, gfl->base_dir);
+ }
+ else {
+ rel_files = gfl->files;
+ rel_dirs = gfl->dirs;
+ gfl->files = NULL;
+ gfl->dirs = NULL;
+ }
+
+ /* rel_files/rel_dirs must be deallocated in done_func */
+ gfl->done_func (rel_files, rel_dirs, NULL, gfl->done_data);
+ }
+ else
+ gfl->done_func (NULL, NULL, error, gfl->done_data);
+
+ g_hash_table_destroy (h_dirs);
+ get_file_list_data_free (gfl_data);
+}
+
+
+static void
+get_file_list_for_each_file (const char *uri,
+ GFileInfo *info,
+ gpointer user_data)
+{
+ GetFileListData *gfl = user_data;
+
+ switch (g_file_info_get_file_type (info)) {
+ case G_FILE_TYPE_DIRECTORY:
+ gfl->dirs = g_list_prepend (gfl->dirs, g_strdup (uri));
+ break;
+ case G_FILE_TYPE_DIRECTORY:
+ if (filter_matches (gfl->include_filter, uri))
+ if ((gfl->exclude_filter->pattern == NULL) || ! filter_matches (gfl->exclude_filter, uri))
+ gfl->files = g_list_prepend (gfl->files, g_strdup (uri));
+ break;
+ default:
+ break;
+ }
+}
+
+
+void
+g_directory_list_async (const char *directory,
+ const char *base_dir,
+ gboolean recursive,
+ gboolean follow_links,
+ gboolean no_backup_files,
+ gboolean no_dot_files,
+ const char *include_files,
+ const char *exclude_files,
+ gboolean ignorecase,
+ GCancellable *cancellable,
+ ListReadyCallback done_func,
+ gpointer done_data)
+{
+ GetFileListData *gfl;
+ FilterOptions filter_options;
+
+ gfl = g_new0 (GetFileListData, 1);
+ gfl->directory = get_uri_from_path (directory);
+ gfl->base_dir = g_strdup (base_dir);
+ gfl->done_func = done_func;
+ gfl->done_data = done_data;
+
+ filter_options = FILTER_DEFAULT;
+ if (no_backup_files)
+ filter_options |= FILTER_NOBACKUPFILES;
+ if (no_dot_files)
+ filter_options |= FILTER_NODOTFILES;
+ if (ignorecase)
+ filter_options |= FILTER_IGNORECASE;
+ gfl->include_filter = filter_new (include_files, filter_options);
+ gfl->exclude_filter = filter_new (exclude_files, ignorecase ? FILTER_IGNORECASE : FILTER_DEFAULT);
+
+ g_directory_foreach_child (directory,
+ recursive,
+ follow_links,
+ cancellable,
+ NULL,
+ get_file_list_for_each_file,
+ get_file_list_done,
+ gfl);
+}
+
+
+/* -- g_list_items_async -- */
+
+
+static void get_items_for_current_dir (GetFileListData *gfl);
+
+
+static gboolean
+get_items_for_next_dir_idle_cb (gpointer data)
+{
+ GetFileListData *gfl = data;
+
+ g_source_remove (gfl->visit_timeout);
+ gfl->visit_timeout = 0;
+
+ gfl->current_dir = g_list_next (gfl->current_dir);
+ get_items_for_current_dir (gfl);
+
+ return FALSE;
+}
+
+
+static void
+get_items_for_current_dir_done (GList *files,
+ GList *dirs,
+ GError *error,
+ gpointer data)
+{
+ GetFileListData *gfl = data;
+
+ if (error != NULL) {
+ if (gfl->done_func)
+ gfl->done_func (NULL, NULL, error, gfl->done_data);
+ path_list_free (files);
+ path_list_free (dirs);
+ get_file_list_data_free (gfl);
+ return;
+ }
+
+ gfl->files = g_list_concat (gfl->files, files);
+ gfl->dirs = g_list_concat (gfl->dirs, dirs);
+
+ gfl->visit_timeout = g_idle_add (get_items_for_next_dir_idle_cb, gfl);
+}
+
+
+static void
+get_items_for_current_dir (GetFileListData *gfl)
+{
+ const char *directory_name;
+ char *directory_uri;
+
+ if (gfl->current_dir == NULL) {
+ if (gfl->done_func) {
+ /* gfl->files/gfl->dirs must be deallocated in gfl->done_func */
+ gfl->done_func (gfl->files, gfl->dirs, NULL, gfl->done_data);
+ gfl->files = NULL;
+ gfl->dirs = NULL;
+ }
+ get_file_list_data_free (gfl);
+ return NULL;
+ }
+
+ 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);
+
+ g_directory_list_async (directory_uri,
+ gfl->base_dir,
+ TRUE,
+ gfl->cancellable,
+ get_items_for_current_dir_done,
+ gfl);
+
+ g_free (directory_uri);
+
+ return gfl->handle;
+}
+
+
+void
+g_list_items_async (GList *items,
+ const char *base_dir,
+ GCancellable *cancellable,
+ VisitDirDoneFunc done_func,
+ gpointer done_data)
+{
+ GetFileListData *gfl;
+ int base_len;
+ GList *scan;
+
+ g_return_val_if_fail (base_dir != NULL, NULL);
+
+ gfl = g_new0 (GetFileListData, 1);
+ gfl->base_dir = g_strdup (base_dir);
+ gfl->cancellable = cancellable;
+ gfl->done_func = done_func;
+ gfl->done_data = done_data;
+
+ base_len = 0;
+ if (strcmp (base_dir, "/") != 0)
+ base_len = strlen (base_dir);
+
+ for (scan = items; scan; scan = scan->next) {
+ char *path = scan->data;
+
+ /* FIXME: this is not async */
+ if (path_is_dir (path))
+ gfl->to_visit = g_list_prepend (gfl->to_visit, g_strdup (path));
+ else {
+ char *rel_path = g_strdup (path + base_len + 1);
+ gfl->files = g_list_prepend (gfl->files, rel_path);
+ }
+ }
+
+ get_items_for_current_dir (gfl);
+}
+
+
+/* -- g_copy_files_async -- */
+
+
+typedef struct {
+ GList *sources;
+ GList *destinations;
+ GFileCopyFlags flags;
+ int io_priority;
+ GCancellable *cancellable;
+ FilesProgressCallback progress_callback;
+ gpointer progress_callback_data;
+ FilesDoneCallback callback;
+ gpointer user_data;
+
+ GList *source;
+ GList *destination;
+ int n_file;
+ int tot_files;
+} CopyFilesData;
+
+
+static CopyFilesData*
+copy_files_data_new (GList *sources,
+ GList *destinations,
+ GFileCopyFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ FilesProgressCallback progress_callback,
+ gpointer progress_callback_data,
+ FilesDoneCallback callback,
+ gpointer user_data)
+{
+ CopyFilesData *cfd;
+
+ cfd = g_new0 (CopyFilesData, 1);
+ cfd->sources = gio_file_list_dup (sources);
+ cfd->destinations = gio_file_list_dup (destinations);
+ cfd->flags = flags;
+ cfd->io_priority = io_priority;
+ cfd->cancellable = cancellable;
+ cfd->progress_callback = progress_callback;
+ cfd->progress_callback_data = progress_callback_data;
+ cfd->callback = callback;
+ cfd->user_data = user_data;
+
+ cfd->source = cfd->sources;
+ cfd->destination = cfd->destinations;
+ cfd->n_file = 1;
+ cfd->tot_files = g_list_length (cfd->sources);
+
+ return cfd;
+}
+
+
+static void
+copy_files_data_free (CopyFilesData *cfd)
+{
+ if (cfd == NULL)
+ return;
+ gio_file_list_free (cfd->sources);
+ gio_file_list_free (cfd->destinations);
+ g_free (cfd);
+}
+
+
+static void g_copy_current_file (CopyFilesData *cfd);
+
+
+static void
+g_copy_next_file (CopyFilesData *cfd)
+{
+ cfd->source = g_list_next (cfd->source);
+ cfd->destination = g_list_next (cfd->destination);
+ cfd->n_file++;
+
+ g_copy_current_file (cfd);
+}
+
+
+static void
+g_copy_files_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ CopyFilesData *cfd = user_data;
+ GFile *source = cfd->source->data;
+ GError *error;
+
+ if (! g_file_copy_finish (source, result, &error)) {
+ if (cfd->callback)
+ cfd->callback (error, cfd->user_data);
+ g_clear_error (&error);
+ copy_files_data_free (cfd);
+ return;
+ }
+
+ g_copy_next_file (cfd);
+}
+
+
+static void
+g_copy_files_progess_cb (goffset current_num_bytes,
+ goffset total_num_bytes,
+ gpointer user_data)
+{
+ CopyFilesData *cfd = user_data;
+
+ if (cfd->progress_callback)
+ cfd->progress_callback (cfd->n_file,
+ cfd->tot_files,
+ (GFile*) cfd->source->data,
+ (GFile*) cfd->destination->data,
+ current_num_bytes,
+ total_num_bytes,
+ cfd->progress_callback_data);
+}
+
+
+static void
+g_copy_current_file (CopyFilesData *cfd)
+{
+ if ((cfd->source == NULL) || (cfd->destination == NULL)) {
+ if (cfd->callback)
+ cfd->callback (NULL, cfd->user_data);
+ copy_files_data_free (cfd);
+ return;
+ }
+
+ g_file_copy_async ((GFile*) cfd->source->data,
+ (GFile*) cfd->destination->data,
+ cfd->flags,
+ cfd->io_priority,
+ cfd->cancellable,
+ g_copy_files_progess_cb,
+ cfd,
+ g_copy_files_ready_cb,
+ cfd);
+}
+
+
+void
+g_copy_files_async (GList *sources,
+ GList *destinations,
+ GFileCopyFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ FilesProgressCallback progress_callback,
+ gpointer progress_callback_data,
+ FilesDoneCallback callback,
+ gpointer user_data)
+{
+ CopyFilesData *cfd;
+
+ cfd = copy_files_data_new (sources,
+ destinations,
+ flags,
+ io_priority,
+ cancellable,
+ progress_callback,
+ progress_callback_data,
+ callback,
+ user_data);
+ g_copy_current_file (cfd);
+}
+
+
+void
+g_copy_uris_async (GList *sources,
+ GList *destinations,
+ GFileCopyFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ FilesProgressCallback progress_callback,
+ gpointer progress_callback_data,
+ FilesDoneCallback callback,
+ gpointer user_data)
+{
+ GList *source_files, *destination_files;
+
+ source_files = gio_file_list_new_from_uri_list (sources);
+ destination_files = gio_file_list_new_from_uri_list (destinations);
+
+ g_copy_files_async (source_files,
+ destination_files,
+ flags,
+ io_priority,
+ cancellable,
+ progress_callback,
+ progress_callback_data,
+ callback,
+ user_data);
+
+ gio_file_list_free (source_files);
+ gio_file_list_free (destination_files);
+}
+
+
+/* -- g_directory_copy_async -- */
+
+
+typedef struct {
+ char *uri;
+ GFileType type;
+} ChildData;
+
+
+static ChildData*
+child_data_new (const char *uri,
+ GFileType type)
+{
+ ChildData *data;
+
+ data = g_new0 (ChildData, 1);
+ data->uri = g_strdup (uri);
+ data->type = type;
+
+ return data;
+}
+
+
+static void
+child_data_free (ChildData *child)
+{
+ if (child == NULL)
+ return;
+ g_free (child->uri);
+ g_free (child);
+}
+
+
+typedef struct {
+ GFile *source;
+ GFile *destination;
+ GFileCopyFlags flags;
+ int io_priority;
+ GCancellable *cancellable;
+ CopyProgressCallback progress_callback;
+ gpointer progress_callback_data;
+ CopyDoneCallback callback;
+ gpointer user_data;
+ GError *error;
+
+ char *source_uri;
+ char *destination_uri;
+ GList *to_copy;
+ GList *current;
+ GFile *current_source;
+ GFile *current_destination;
+ int n_file, tot_files;
+} DirectoryCopyData;
+
+
+static void
+directory_copy_data_free (DirectoryCopyData *dcd)
+{
+ if (dcd == NULL)
+ return;
+ g_object_unref (dcd->source);
+ g_object_unref (dcd->destination);
+ g_object_unref (dcd->cancellable);
+ g_free (dcd->source_uri);
+ g_free (dcd->destination_uri);
+ if (dcd->current_source != NULL) {
+ g_object_unref (dcd->current_source);
+ dcd->current_source = NULL;
+ }
+ if (dcd->current_destination != NULL) {
+ g_object_unref (dcd->current_destination);
+ dcd->current_destination = NULL;
+ }
+ g_list_foreach (dcd->to_copy, (GFunc) child_data_free, NULL);
+ g_list_free (dcd->to_copy);
+ g_free (dcd);
+}
+
+
+static void
+g_directory_copy_done (DirectoryCopyData *dcd,
+ GError *error)
+{
+ if (dcd->callback)
+ dcd->callback (error, dcd->user_data);
+ if (error != NULL)
+ g_clear_error (&error);
+ directory_copy_data_free (dcd);
+}
+
+
+static GFile *
+get_destination_for_uri (DirectoryCopyData *dcd,
+ const char *uri)
+{
+ char *uri;
+ GFile *file;
+
+ uri = g_strconcat (dcd->destination_uri, "/", uri + strlen (dcd->source_uri) + 1, NULL);
+ file = g_file_new_for_uri (uri);
+ g_free (uri);
+
+ return file;
+}
+
+
+static void g_directory_copy_current_child (DirectoryCopyData *dcd);
+
+
+static void
+g_directory_copy_child_done_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ DirectoryCopyData *dcd = user_data;
+
+ if (! g_file_copy_finish ((GFile*)source_object, result, &(dcd->error))) {
+ g_directory_copy_done (dcd, dcd->error);
+ return;
+ }
+
+ dcd->current = g_list_next (dcd->current);
+ dcd->n_file++;
+ g_directory_copy_current_child (dcd);
+}
+
+
+static void
+g_directory_copy_child_progess_cb (goffset current_num_bytes,
+ goffset total_num_bytes,
+ gpointer user_data)
+{
+ DirectoryCopyData *dcd = user_data;
+
+ if (dcd->progress_callback)
+ dcd->progress_callback (dcd->n_file,
+ dcd->tot_files,
+ dcd->current_source,
+ dcd->current_destination,
+ current_num_bytes,
+ total_num_bytes,
+ dcd->progress_callback_data);
+}
+
+
+static void
+g_directory_copy_current_child (DirectoryCopyData *dcd)
+{
+ ChildData *child;
+ GFile *source, *destination;
+
+ if (dcd->current == NULL) {
+ g_directory_copy_done (dcd, NULL);
+ return;
+ }
+
+ if (dcd->current_source != NULL) {
+ g_object_unref (dcd->current_source);
+ dcd->current_source = NULL;
+ }
+ if (dcd->current_destination != NULL) {
+ g_object_unref (dcd->current_destination);
+ dcd->current_destination = NULL;
+ }
+
+ child = dcd->current->data;
+ dcd->current_destination = get_destination_for_uri (dcd, child->uri);
+ switch (child->type) {
+ case G_FILE_TYPE_DIRECTORY:
+ /* FIXME: how to make a directory asynchronously ? */
+ if (! g_file_make_directory (destination, dcd->cancellable, &(dcd->error))) {
+ g_directory_copy_done (dcd, dcd->error);
+ return;
+ }
+ break;
+ case G_FILE_TYPE_REGULAR:
+ dcd->current_source = g_file_new_for_uri (child->uri);
+ g_file_copy_async (source,
+ destination,
+ dcd->flags,
+ dcd->io_priority,
+ dcd->cancellable,
+ g_directory_copy_child_progess_cb,
+ dcd,
+ g_directory_copy_child_done_cb,
+ dcd);
+ g_object_unref (source);
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void
+g_directory_copy_list_ready (GError *error,
+ gpointer user_data)
+{
+ DirectoryCopyData *dcd = user_data;
+
+ if (error != NULL) {
+ g_directory_copy_done (dcd, error);
+ return;
+ }
+
+ dcd->to_copy = g_list_reverse (dcd->to_copy);
+ dcd->current = dcd->to_copy;
+ dcd->n_file = 1;
+ g_directory_copy_current_child (dcd);
+}
+
+
+static void
+g_directory_copy_for_each_file (const char *uri,
+ GFileInfo *info,
+ gpointer user_data)
+{
+ dcd->to_copy = g_list_prepend (dcd->to_copy, child_data_new (uri, g_file_info_get_file_type (info)));
+ dcd->tot_files++;
+}
+
+
+static gboolean
+g_directory_copy_start_dir (const char *uri,
+ GError **error,
+ gpointer user_data)
+{
+ dcd->to_copy = g_list_prepend (dcd->to_copy, child_data_new (uri, G_FILE_TYPE_DIRECTORY));
+ return TRUE;
+}
+
+
+void
+g_directory_copy_async (GFile *source,
+ GFile *destination,
+ GFileCopyFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ FilesProgressCallback progress_callback,
+ gpointer progress_callback_data,
+ FilesDoneCallback callback,
+ gpointer user_data)
+{
+ DirectoryCopyData *dcd;
+
+ dcd = g_new0 (DirectoryCopyData, 1);
+ dcd->source = g_file_dup (source);
+ dcd->destination = g_file_dup (destination);
+ dcd->flags = flags;
+ dcd->io_priority = io_priority;
+ dcd->cancellable = cancellable;
+ dcd->progress_callback = progress_callback;
+ dcd->progress_callback_data = progress_callback_data;
+ dcd->callback = callback;
+ dcd->user_data = user_data;
+
+ dcd->source_uri = g_file_get_uri (dcd->source);
+ dcd->destination_uri = g_file_get_uri (dcd->destination);
+
+ dcd->to_copy = g_list_prepend (NULL, child_data_new (dcd->source_uri, G_FILE_TYPE_DIRECTORY));
+ dcd->n_nodes = 1;
+
+ for_each_children (dcd->source,
+ TRUE,
+ TRUE,
+ cancellable,
+ g_directory_copy_start_dir,
+ g_directory_copy_for_each_file,
+ g_directory_copy_list_ready,
+ dcd);
+}
+
Added: trunk/src/gio-utils.h
==============================================================================
--- (empty file)
+++ trunk/src/gio-utils.h Sat Mar 29 10:08:26 2008
@@ -0,0 +1,118 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * File-Roller
+ *
+ * Copyright (C) 2001, 2003, 2008 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GIO_UTILS_H
+#define _GIO_UTILS_H
+
+#include <glib.h>
+#include <gio/gio.h>
+
+/* callback types */
+
+typedef gboolean (*StartDirCallback) (const char *uri,
+ GError **error,
+ gpointer user_data);
+typedef void (*ForEachChildCallback) (const char *uri,
+ GFileInfo *info,
+ gpointer user_data);
+typedef void (*ForEachDoneCallback) (GError *error,
+ gpointer data);
+typedef void (*ListReadyCallback) (GList *files,
+ GList *dirs,
+ GError *error,
+ gpointer user_data);
+typedef void (*CopyProgressCallback) (goffset current_file,
+ goffset total_files,
+ GFile *source,
+ GFile *destination,
+ goffset current_num_bytes,
+ goffset total_num_bytes,
+ gpointer user_data);
+typedef void (*CopyDoneCallback) (GError *error,
+ gpointer user_data);
+
+/* asynchronous recursive list functions */
+
+void g_directory_foreach_child (const char *directory,
+ gboolean recursive,
+ gboolean follow_links,
+ GCancellable *cancellable,
+ StartDirCallback start_dir_func,
+ ForEachChildCallback for_each_file_func,
+ ForEachDoneCallback done_func,
+ gpointer user_data);
+void g_directory_list_async (const char *directory,
+ const char *base_dir,
+ gboolean recursive,
+ gboolean follow_links,
+ gboolean no_backup_files,
+ gboolean no_dot_files,
+ const char *include_files,
+ const char *exclude_files,
+ gboolean ignorecase,
+ GCancellable *cancellable,
+ ListReadyCallback done_func,
+ gpointer done_data);
+#define g_directory_list_all_async (directory, \
+ base_dir, \
+ recursive, \
+ cancellable, \
+ done_func, \
+ done_data) g_directory_list_async ((directory), (base_dir), (recursive), TRUE, FALSE, FALSE, NULL, NULL, FALSE, (cancellable), (done_func), (done_data))
+void g_list_items_async (GList *items,
+ const char *base_dir,
+ GCancellable *cancellable,
+ ListReadyCallback done_func,
+ gpointer done_data);
+
+/* asynchronous recursive copy functions */
+
+void g_copy_files_async (GList *sources,
+ GList *destinations,
+ GFileCopyFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ CopyProgressCallback progress_callback,
+ gpointer progress_callback_data,
+ CopyDoneCallback callback,
+ gpointer user_data);
+void g_copy_uris_async (GList *sources,
+ GList *destinations,
+ GFileCopyFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ CopyProgressCallback progress_callback,
+ gpointer progress_callback_data,
+ CopyDoneCallback callback,
+ gpointer user_data);
+void g_directory_copy_async (GFile *source,
+ GFile *destination,
+ GFileCopyFlags flags,
+ int io_priority,
+ GCancellable *cancellable,
+ CopyProgressCallback progress_callback,
+ gpointer progress_callback_data,
+ CopyDoneCallback callback,
+ gpointer user_data);
+
+#endif /* _GIO_UTILS_H */
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]