[gnome-photos/wip/rishi/collection: 47/54] glib: Add photos_glib_file_copy_async



commit 7e4d566fb79ccebf8eb123e535f06a165c59f4ed
Author: Debarshi Ray <debarshir gnome org>
Date:   Sun Feb 4 14:38:30 2018 +0100

    glib: Add photos_glib_file_copy_async
    
    It's meant to copy the source GFile to the destination GFile and handle
    name collisions in the process. If the destination already exists, it
    will try to suffix a copy number to generate a unique filename and
    proceed with that.
    
    A subsequent commit will use this to copy files while importing content
    from attached devices.
    
    https://gitlab.gnome.org/GNOME/gnome-photos/issues/29

 src/photos-glib.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/photos-glib.h |  10 +++
 2 files changed, 193 insertions(+)
---
diff --git a/src/photos-glib.c b/src/photos-glib.c
index f0c8b2ba..4b6e0f1a 100644
--- a/src/photos-glib.c
+++ b/src/photos-glib.c
@@ -29,8 +29,15 @@
 #include "photos-glib.h"
 
 
+typedef struct _PhotosGLibFileCopyData PhotosGLibFileCopyData;
 typedef struct _PhotosGLibFileCreateData PhotosGLibFileCreateData;
 
+struct _PhotosGLibFileCopyData
+{
+  GFileOutputStream *ostream;
+  gint io_priority;
+};
+
 struct _PhotosGLibFileCreateData
 {
   GFile *dir;
@@ -63,6 +70,182 @@ photos_glib_app_info_launch_uri (GAppInfo *appinfo,
 }
 
 
+static void
+photos_glib_file_copy_data_free (PhotosGLibFileCopyData *data)
+{
+  g_clear_object (&data->ostream);
+  g_slice_free (PhotosGLibFileCopyData, data);
+}
+
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (PhotosGLibFileCopyData, photos_glib_file_copy_data_free);
+
+
+static PhotosGLibFileCopyData *
+photos_glib_file_copy_data_new (gint io_priority)
+{
+  PhotosGLibFileCopyData *data;
+
+  data = g_slice_new0 (PhotosGLibFileCopyData);
+  data->io_priority = io_priority;
+  return data;
+}
+
+
+static void
+photos_glib_file_copy_splice (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+  GOutputStream *ostream = G_OUTPUT_STREAM (source_object);
+  g_autoptr (GTask) task = G_TASK (user_data);
+  PhotosGLibFileCopyData *data;
+
+  data = (PhotosGLibFileCopyData *) g_task_get_task_data (task);
+
+  g_assert_true (G_IS_FILE_OUTPUT_STREAM (ostream));
+  g_assert_true (G_FILE_OUTPUT_STREAM (ostream) == data->ostream);
+
+  {
+    g_autoptr (GError) error = NULL;
+
+    g_output_stream_splice_finish (ostream, res, &error);
+    if (error != NULL)
+      {
+        g_task_return_error (task, g_steal_pointer (&error));
+        goto out;
+      }
+  }
+
+  g_task_return_boolean (task, TRUE);
+
+ out:
+  return;
+}
+
+
+static void
+photos_glib_file_copy_read (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+  GCancellable *cancellable;
+  GFile *source = G_FILE (source_object);
+  g_autoptr (GFileInputStream) istream = NULL;
+  g_autoptr (GTask) task = G_TASK (user_data);
+  PhotosGLibFileCopyData *data;
+
+  cancellable = g_task_get_cancellable (task);
+  data = (PhotosGLibFileCopyData *) g_task_get_task_data (task);
+
+  {
+    g_autoptr (GError) error = NULL;
+
+    istream = g_file_read_finish (source, res, &error);
+    if (error != NULL)
+      {
+        g_task_return_error (task, g_steal_pointer (&error));
+        goto out;
+      }
+  }
+
+  g_output_stream_splice_async (G_OUTPUT_STREAM (data->ostream),
+                                G_INPUT_STREAM (istream),
+                                G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
+                                data->io_priority,
+                                cancellable,
+                                photos_glib_file_copy_splice,
+                                g_object_ref (task));
+
+ out:
+  return;
+}
+
+
+static void
+photos_glib_file_copy_create (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+  GCancellable *cancellable;
+  GFile *destination = G_FILE (source_object);
+  GFile *source;
+  g_autoptr (GFileOutputStream) ostream = NULL;
+  g_autoptr (GTask) task = G_TASK (user_data);
+  PhotosGLibFileCopyData *data;
+
+  cancellable = g_task_get_cancellable (task);
+  data = (PhotosGLibFileCopyData *) g_task_get_task_data (task);
+  source = G_FILE (g_task_get_source_object (task));
+
+  {
+    g_autoptr (GError) error = NULL;
+
+    ostream = photos_glib_file_create_finish (destination, res, NULL, &error);
+    if (error != NULL)
+      {
+        g_task_return_error (task, g_steal_pointer (&error));
+        goto out;
+      }
+  }
+
+  g_assert_null (data->ostream);
+  g_assert_true (G_IS_FILE_OUTPUT_STREAM (ostream));
+  data->ostream = g_object_ref (ostream);
+
+  g_file_read_async (source, data->io_priority, cancellable, photos_glib_file_copy_read, g_object_ref 
(task));
+
+ out:
+  return;
+}
+
+
+void
+photos_glib_file_copy_async (GFile *source,
+                             GFile *destination,
+                             GFileCopyFlags flags,
+                             gint io_priority,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+  GFileCreateFlags create_flags = G_FILE_CREATE_NONE;
+  g_autoptr (GTask) task = NULL;
+  g_autoptr (PhotosGLibFileCopyData) data = NULL;
+
+  g_return_if_fail (G_IS_FILE (source));
+  g_return_if_fail (G_IS_FILE (destination));
+  g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (source, cancellable, callback, user_data);
+  g_task_set_source_tag (task, photos_glib_file_copy_async);
+
+  data = photos_glib_file_copy_data_new (io_priority);
+  g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) photos_glib_file_copy_data_free);
+
+  if ((flags & G_FILE_COPY_OVERWRITE) != 0)
+    create_flags |= G_FILE_CREATE_REPLACE_DESTINATION;
+
+  photos_glib_file_create_async (destination,
+                                 create_flags,
+                                 io_priority,
+                                 cancellable,
+                                 photos_glib_file_copy_create,
+                                 g_object_ref (task));
+}
+
+
+gboolean
+photos_glib_file_copy_finish (GFile *file, GAsyncResult *res, GError **error)
+{
+  GTask *task;
+
+  g_return_val_if_fail (G_IS_FILE (file), FALSE);
+
+  g_return_val_if_fail (g_task_is_valid (res, file), FALSE);
+  task = G_TASK (res);
+
+  g_return_val_if_fail (g_task_get_source_tag (task) == photos_glib_file_copy_async, FALSE);
+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+  return g_task_propagate_boolean (task, error);
+}
+
+
 static gchar *
 photos_glib_filename_get_extension_offset (const gchar *filename)
 {
diff --git a/src/photos-glib.h b/src/photos-glib.h
index b122336b..57c339a0 100644
--- a/src/photos-glib.h
+++ b/src/photos-glib.h
@@ -32,6 +32,16 @@ gboolean              photos_glib_app_info_launch_uri            (GAppInfo *appi
                                                                   GAppLaunchContext *launch_context,
                                                                   GError **error);
 
+void                  photos_glib_file_copy_async                (GFile *source,
+                                                                  GFile *destination,
+                                                                  GFileCopyFlags flags,
+                                                                  gint io_priority,
+                                                                  GCancellable *cancellable,
+                                                                  GAsyncReadyCallback callback,
+                                                                  gpointer user_data);
+
+gboolean              photos_glib_file_copy_finish               (GFile *file, GAsyncResult *res, GError 
**error);
+
 void                  photos_glib_file_create_async              (GFile *file,
                                                                   GFileCreateFlags flags,
                                                                   gint io_priority,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]