[gnome-photos] base-item, utils: Handle name collisions while exporting
- From: Debarshi Ray <debarshir src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-photos] base-item, utils: Handle name collisions while exporting
- Date: Fri, 11 Mar 2016 16:52:47 +0000 (UTC)
commit 99357b8fb787e89dcb4b0d3339754e4eb15d80b2
Author: Rafael Fonseca <r4f4rfs gmail com>
Date: Fri Feb 19 16:49:25 2016 +0100
base-item, utils: Handle name collisions while exporting
Before this, we would always replace the contents of the exported
file. Instead, we suffix a copy number to deal with name collisions.
https://bugzilla.gnome.org/show_bug.cgi?id=762318
src/photos-base-item.c | 36 +++++-----
src/photos-utils.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++
src/photos-utils.h | 13 ++++
3 files changed, 207 insertions(+), 18 deletions(-)
---
diff --git a/src/photos-base-item.c b/src/photos-base-item.c
index 6b145a7..726f9ba 100644
--- a/src/photos-base-item.c
+++ b/src/photos-base-item.c
@@ -133,6 +133,7 @@ typedef struct _PhotosBaseItemSaveData PhotosBaseItemSaveData;
struct _PhotosBaseItemSaveData
{
GFile *dir;
+ GFile *unique_file;
GeglBuffer *buffer;
gchar *type;
};
@@ -168,6 +169,7 @@ static void
photos_base_item_save_data_free (PhotosBaseItemSaveData *data)
{
g_clear_object (&data->dir);
+ g_clear_object (&data->unique_file);
g_clear_object (&data->buffer);
g_free (data->type);
g_slice_free (PhotosBaseItemSaveData, data);
@@ -1147,7 +1149,6 @@ photos_base_item_save_save_metadata (GObject *source_object, GAsyncResult *res,
{
PhotosBaseItem *self = PHOTOS_BASE_ITEM (source_object);
GError *error;
- GFile *file = NULL;
GTask *task = G_TASK (user_data);
PhotosBaseItemSaveData *data;
@@ -1160,11 +1161,9 @@ photos_base_item_save_save_metadata (GObject *source_object, GAsyncResult *res,
goto out;
}
- file = g_file_get_child (data->dir, self->priv->filename);
- g_task_return_pointer (task, g_object_ref (file), g_object_unref);
+ g_task_return_pointer (task, g_object_ref (data->unique_file), g_object_unref);
out:
- g_clear_object (&file);
g_object_unref (task);
}
@@ -1177,7 +1176,6 @@ photos_base_item_save_save_to_stream (GObject *source_object, GAsyncResult *res,
PhotosBaseItemSaveData *data;
GCancellable *cancellable;
GError *error = NULL;
- GFile *file = NULL;
self = PHOTOS_BASE_ITEM (g_task_get_source_object (task));
cancellable = g_task_get_cancellable (task);
@@ -1189,21 +1187,19 @@ photos_base_item_save_save_to_stream (GObject *source_object, GAsyncResult *res,
goto out;
}
- file = g_file_get_child (data->dir, self->priv->filename);
photos_base_item_save_metadata_async (self,
- file,
+ data->unique_file,
cancellable,
photos_base_item_save_save_metadata,
g_object_ref (task));
out:
- g_clear_object (&file);
g_object_unref (task);
}
static void
-photos_base_item_save_replace (GObject *source_object, GAsyncResult *res, gpointer user_data)
+photos_base_item_save_create (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
GTask *task = G_TASK (user_data);
GCancellable *cancellable;
@@ -1212,19 +1208,24 @@ photos_base_item_save_replace (GObject *source_object, GAsyncResult *res, gpoint
GeglNode *buffer_source;
GeglNode *graph = NULL;
GFile *file = G_FILE (source_object);
+ GFile *unique_file = NULL;
GFileOutputStream *stream = NULL;
PhotosBaseItemSaveData *data;
cancellable = g_task_get_cancellable (task);
data = (PhotosBaseItemSaveData *) g_task_get_task_data (task);
- stream = g_file_replace_finish (file, res, &error);
+ stream = photos_utils_file_create_finish (file, res, &unique_file, &error);
if (error != NULL)
{
g_task_return_error (task, error);
goto out;
}
+ g_assert_null (data->unique_file);
+ g_assert_true (G_IS_FILE (unique_file));
+ data->unique_file = g_object_ref (unique_file);
+
graph = gegl_node_new ();
buffer_source = gegl_node_new_child (graph, "operation", "gegl:buffer-source", "buffer", data->buffer,
NULL);
pixbuf = photos_utils_create_pixbuf_from_node (buffer_source);
@@ -1260,6 +1261,7 @@ photos_base_item_save_replace (GObject *source_object, GAsyncResult *res, gpoint
g_clear_object (&graph);
g_clear_object (&pixbuf);
g_clear_object (&stream);
+ g_clear_object (&unique_file);
g_object_unref (task);
}
@@ -1292,14 +1294,12 @@ photos_base_item_save_buffer_zoom (GObject *source_object, GAsyncResult *res, gp
data->buffer = g_object_ref (buffer_zoomed);
file = g_file_get_child (data->dir, self->priv->filename);
- g_file_replace_async (file,
- NULL,
- TRUE,
- G_FILE_CREATE_REPLACE_DESTINATION,
- G_PRIORITY_DEFAULT,
- cancellable,
- photos_base_item_save_replace,
- g_object_ref (task));
+ photos_utils_file_create_async (file,
+ G_FILE_CREATE_NONE,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ photos_base_item_save_create,
+ g_object_ref (task));
out:
g_clear_object (&buffer_zoomed);
diff --git a/src/photos-utils.c b/src/photos-utils.c
index e85ebd9..64827b7 100644
--- a/src/photos-utils.c
+++ b/src/photos-utils.c
@@ -68,6 +68,18 @@
static const gdouble EPSILON = 1e-5;
+typedef struct _PhotosUtilsFileCreateData PhotosUtilsFileCreateData;
+
+struct _PhotosUtilsFileCreateData
+{
+ GFile *dir;
+ GFileCreateFlags flags;
+ gchar *basename;
+ gchar *extension;
+ gint io_priority;
+ guint count;
+};
+
static void
photos_utils_put_pixel (guchar *p)
@@ -935,6 +947,170 @@ photos_utils_filename_strip_extension (const gchar *filename_with_extension)
}
+static void
+photos_utils_file_create_data_free (PhotosUtilsFileCreateData *data)
+{
+ g_object_unref (data->dir);
+ g_free (data->basename);
+ g_free (data->extension);
+ g_slice_free (PhotosUtilsFileCreateData, data);
+}
+
+
+static gchar *
+photos_utils_file_create_data_get_filename (PhotosUtilsFileCreateData *data)
+{
+ gchar *ret_val;
+
+ if (data->count > 0)
+ ret_val = g_strdup_printf ("%s(%u)%s", data->basename, data->count, data->extension);
+ else
+ ret_val = g_strdup_printf ("%s%s", data->basename, data->extension);
+
+ return ret_val;
+}
+
+
+static PhotosUtilsFileCreateData *
+photos_utils_file_create_data_new (GFile *file, GFileCreateFlags flags, gint io_priority)
+{
+ PhotosUtilsFileCreateData *data;
+ gchar *filename;
+
+ data = g_slice_new0 (PhotosUtilsFileCreateData);
+
+ filename = g_file_get_basename (file);
+ data->dir = g_file_get_parent (file);
+ data->basename = photos_utils_filename_strip_extension (filename);
+ data->extension = g_strdup (photos_utils_filename_get_extension_offset (filename));
+ data->count = 0;
+ data->flags = flags;
+ data->io_priority = io_priority;
+
+ g_free (filename);
+
+ return data;
+}
+
+
+static void
+photos_utils_file_create_create (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GCancellable *cancellable;
+ GError *error = NULL;
+ GFile *file = G_FILE (source_object);
+ GFile *unique_file = NULL;
+ GFileOutputStream *stream = NULL;
+ GTask *task = G_TASK (user_data);
+ PhotosUtilsFileCreateData *data;
+ gchar *filename = NULL;
+
+ cancellable = g_task_get_cancellable (task);
+ data = (PhotosUtilsFileCreateData *) g_task_get_task_data (task);
+
+ stream = g_file_create_finish (file, res, &error);
+ if (error != NULL)
+ {
+
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
+ {
+ g_task_return_error (task, error);
+ goto out;
+ }
+
+ if (data->count == G_MAXUINT)
+ {
+ g_task_return_new_error (task, PHOTOS_ERROR, 0, "Exceeded number of copies of a file");
+ goto out;
+ }
+
+ data->count++;
+
+ filename = photos_utils_file_create_data_get_filename (data);
+ unique_file = g_file_get_child (data->dir, filename);
+
+ g_file_create_async (unique_file,
+ data->flags,
+ data->io_priority,
+ cancellable,
+ photos_utils_file_create_create,
+ g_object_ref (task));
+
+ goto out;
+ }
+
+ g_task_return_pointer (task, g_object_ref (stream), g_object_unref);
+
+ out:
+ g_free (filename);
+ g_clear_object (&stream);
+ g_clear_object (&unique_file);
+ g_object_unref (task);
+}
+
+
+void
+photos_utils_file_create_async (GFile *file,
+ GFileCreateFlags flags,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ PhotosUtilsFileCreateData *data;
+
+ task = g_task_new (file, cancellable, callback, user_data);
+ g_task_set_source_tag (task, photos_utils_file_create_async);
+
+ data = photos_utils_file_create_data_new (file, flags, io_priority);
+ g_task_set_task_data (task, data, (GDestroyNotify) photos_utils_file_create_data_free);
+
+ g_file_create_async (file,
+ data->flags,
+ data->io_priority,
+ cancellable,
+ photos_utils_file_create_create,
+ g_object_ref (task));
+
+ g_object_unref (task);
+}
+
+
+GFileOutputStream *
+photos_utils_file_create_finish (GFile *file, GAsyncResult *res, GFile **out_unique_file, GError **error)
+{
+ GTask *task = G_TASK (res);
+ GFileOutputStream *ret_val = NULL;
+ PhotosUtilsFileCreateData *data;
+
+ g_return_val_if_fail (g_task_is_valid (res, file), NULL);
+ g_return_val_if_fail (g_task_get_source_tag (task) == photos_utils_file_create_async, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ data = (PhotosUtilsFileCreateData *) g_task_get_task_data (task);
+ g_return_val_if_fail (data != NULL, NULL);
+
+ ret_val = g_task_propagate_pointer (task, error);
+ if (ret_val == NULL)
+ goto out;
+
+ if (out_unique_file != NULL)
+ {
+ GFile *unique_file;
+ gchar *filename = NULL;
+
+ filename = photos_utils_file_create_data_get_filename (data);
+ unique_file = g_file_get_child (data->dir, filename);
+ *out_unique_file = unique_file;
+ g_free (filename);
+ }
+
+ out:
+ return ret_val;
+}
+
+
GQuark
photos_utils_flash_off_quark (void)
{
diff --git a/src/photos-utils.h b/src/photos-utils.h
index 86b8a90..b788e4d 100644
--- a/src/photos-utils.h
+++ b/src/photos-utils.h
@@ -121,6 +121,18 @@ gdouble photos_utils_eval_radial_line (gdouble crop_center_x
gdouble corner_y,
gdouble event_x);
+void photos_utils_file_create_async (GFile *file,
+ GFileCreateFlags flags,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GFileOutputStream *photos_utils_file_create_finish (GFile *file,
+ GAsyncResult *res,
+ GFile **out_unique_file,
+ GError **error);
+
gchar *photos_utils_filename_strip_extension (const gchar *filename_with_extension);
GQuark photos_utils_flash_off_quark (void);
@@ -129,6 +141,7 @@ GQuark photos_utils_flash_on_quark (void);
gchar *photos_utils_get_extension_from_mime_type (const gchar *mime_type);
+
gint photos_utils_get_icon_size (void);
gint photos_utils_get_icon_size_unscaled (void);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]