[gvfs/wip/rishi/goa: 7/8] Introduce dir_entries and fix a bug in copy
- From: Debarshi Ray <debarshir src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gvfs/wip/rishi/goa: 7/8] Introduce dir_entries and fix a bug in copy
- Date: Mon, 31 Aug 2015 19:02:55 +0000 (UTC)
commit 1104ade401cf1afe2c4cd1adadb1cfc3b61c25b1
Author: Debarshi Ray <debarshir gnome org>
Date: Thu Aug 27 20:28:50 2015 +0200
Introduce dir_entries and fix a bug in copy
daemon/gvfsbackendgoogle.c | 327 +++++++++++++++++++++++++++++++++++++-------
1 files changed, 275 insertions(+), 52 deletions(-)
---
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
index a5ca53e..0e6c89c 100644
--- a/daemon/gvfsbackendgoogle.c
+++ b/daemon/gvfsbackendgoogle.c
@@ -55,6 +55,7 @@ struct _GVfsBackendGoogle
GDataDocumentsService *service;
GDataEntry *root;
GHashTable *entries;
+ GHashTable *dir_entries;
GHashTable *lookaside;
GHashTable *monitors;
GRecMutex mutex;
@@ -86,6 +87,69 @@ G_DEFINE_TYPE(GVfsBackendGoogle, g_vfs_backend_google, G_VFS_TYPE_BACKEND)
/* ---------------------------------------------------------------------------------------------------- */
+typedef struct
+{
+ gchar *title_or_id;
+ gchar *parent_id;
+} DirEntriesKey;
+
+static GDataEntry *resolve_dir (GVfsBackendGoogle *self,
+ const gchar *filename,
+ gchar **out_basename);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+DirEntriesKey *
+dir_entries_key_new (const gchar *title_or_id, const gchar *parent_id)
+{
+ DirEntriesKey *k;
+
+ k = g_slice_new (DirEntriesKey);
+ k->title_or_id = g_strdup (title_or_id);
+ k->parent_id = g_strdup (parent_id);
+ return k;
+}
+
+static void
+dir_entries_key_free (gpointer data)
+{
+ DirEntriesKey *k = (DirEntriesKey *) data;
+
+ if (k == NULL)
+ return;
+
+ g_free (k->title_or_id);
+ g_free (k->parent_id);
+ g_slice_free (DirEntriesKey, k);
+}
+
+guint
+entries_in_folder_hash (gconstpointer key)
+{
+ DirEntriesKey *k = (DirEntriesKey *) key;
+ guint hash1;
+ guint hash2;
+
+ hash1 = g_str_hash (k->title_or_id);
+ hash2 = g_str_hash (k->parent_id);
+ return hash1 ^ hash2;
+}
+
+gboolean
+entries_in_folder_equal (gconstpointer a, gconstpointer b)
+{
+ DirEntriesKey *k_a = (DirEntriesKey *) a;
+ DirEntriesKey *k_b = (DirEntriesKey *) b;
+
+ if (g_strcmp0 (k_a->title_or_id, k_b->title_or_id) == 0 &&
+ g_strcmp0 (k_a->parent_id, k_b->parent_id) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
insert_lookaside (GVfsBackendGoogle *self,
const gchar *parent_id,
@@ -397,15 +461,16 @@ emit_delete_event (gpointer monitor,
/* ---------------------------------------------------------------------------------------------------- */
static void
-is_folder_or_root (const gchar *filename,
- GDataEntry *entry,
- gboolean *out_is_folder,
- gboolean *out_is_root)
+is_folder_or_root (GVfsBackendGoogle *self,
+ const gchar *filename,
+ GDataEntry *entry,
+ gboolean *out_is_folder,
+ gboolean *out_is_root)
{
gboolean is_folder = FALSE;
gboolean is_root = FALSE;
- if (g_strcmp0 (filename, "/") == 0 && entry == NULL)
+ if (g_strcmp0 (filename, "/") == 0 && (entry == NULL || entry == self->root))
{
is_folder = TRUE;
is_root = TRUE;
@@ -475,7 +540,7 @@ build_file_info (GVfsBackendGoogle *self,
gint64 mtime;
gsize i;
- is_folder_or_root (filename, entry, &is_folder, &is_root);
+ is_folder_or_root (self, filename, entry, &is_folder, &is_root);
if (entry == NULL && !is_root)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory"));
@@ -745,6 +810,86 @@ get_parent_basename (const gchar *filename)
/* ---------------------------------------------------------------------------------------------------- */
static void
+insert_entry (GVfsBackendGoogle *self,
+ GDataEntry *entry)
+{
+ DirEntriesKey *k;
+ GDataEntry *old_entry;
+ gboolean insert_title = TRUE;
+ const gchar *id;
+ const gchar *title;
+ gchar *parent_id;
+
+ id = gdata_entry_get_id (entry);
+ g_hash_table_insert (self->entries, g_strdup (id), g_object_ref (entry));
+
+ parent_id = get_parent_id (entry);
+ if (parent_id == NULL)
+ return;
+
+ k = dir_entries_key_new (id, parent_id);
+ g_hash_table_insert (self->dir_entries, k, g_object_ref (entry));
+
+ title = gdata_entry_get_title (entry);
+ k = dir_entries_key_new (title, parent_id);
+ old_entry = g_hash_table_lookup (self->dir_entries, k);
+ if (old_entry != NULL)
+ {
+ const gchar *old_id;
+
+ old_id = gdata_entry_get_id (old_entry);
+ if (g_strcmp0 (old_id, title) == 0)
+ {
+ insert_title = FALSE;
+ }
+ else
+ {
+ /* If the collision is not due to the title matching the ID
+ * of an earlier GDataEntry, then it is due to duplicate
+ * titles.
+ */
+ if (g_strcmp0 (old_id, id) < 0)
+ insert_title = FALSE;
+ }
+ }
+
+ if (insert_title)
+ g_hash_table_insert (self->dir_entries, k, g_object_ref (entry));
+ else
+ dir_entries_key_free (k);
+
+ g_free (parent_id);
+}
+
+static void
+remove_entry (GVfsBackendGoogle *self,
+ GDataEntry *entry)
+{
+ DirEntriesKey *k;
+ const gchar *id;
+ const gchar *title;
+ gchar *parent_id;
+
+ id = gdata_entry_get_id (entry);
+ g_hash_table_remove (self->entries, id);
+
+ parent_id = get_parent_id (entry);
+ if (parent_id == NULL)
+ return;
+
+ k = dir_entries_key_new (id, parent_id);
+ g_hash_table_remove (self->dir_entries, k);
+ dir_entries_key_free (k);
+
+ title = gdata_entry_get_title (entry);
+ k = dir_entries_key_new (title, parent_id);
+ g_hash_table_remove (self->dir_entries, k);
+ dir_entries_key_free (k);
+
+ g_free (parent_id);
+}
+
+static void
rebuild_entries (GVfsBackendGoogle *self,
GCancellable *cancellable,
GError **error)
@@ -782,6 +927,7 @@ rebuild_entries (GVfsBackendGoogle *self,
if (!succeeded_once)
{
g_hash_table_remove_all (self->entries);
+ g_hash_table_remove_all (self->dir_entries);
succeeded_once = TRUE;
}
@@ -792,10 +938,7 @@ rebuild_entries (GVfsBackendGoogle *self,
for (l = entries; l != NULL; l = l->next)
{
GDataEntry *entry = GDATA_ENTRY (l->data);
- const gchar *id;
-
- id = gdata_entry_get_id (entry);
- g_hash_table_insert (self->entries, g_strdup (id), g_object_ref (entry));
+ insert_entry (self, entry);
}
gdata_query_next_page (GDATA_QUERY (query));
@@ -811,6 +954,89 @@ rebuild_entries (GVfsBackendGoogle *self,
/* ---------------------------------------------------------------------------------------------------- */
+static GDataEntry *
+resolve_child (GVfsBackendGoogle *self,
+ GDataEntry *parent,
+ const gchar *basename)
+{
+ DirEntriesKey *k;
+ GDataEntry *entry;
+ const gchar *parent_id;
+
+ parent_id = gdata_entry_get_id (parent);
+ k = dir_entries_key_new (basename, parent_id);
+ entry = g_hash_table_lookup (self->dir_entries, k);
+ dir_entries_key_free (k);
+ return entry;
+}
+
+static GDataEntry *
+resolve (GVfsBackendGoogle *self,
+ const gchar *filename,
+ GError **error)
+{
+ GDataEntry *parent;
+ GDataEntry *ret_val = NULL;
+ gchar *basename = NULL;
+
+ if (g_strcmp0 (filename, "/") == 0)
+ {
+ ret_val = self->root;
+ goto out;
+ }
+
+ parent = resolve_dir (self, filename, &basename);
+ if (parent == NULL)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY, _("The file is not a directory"));
+ goto out;
+ }
+
+ ret_val = resolve_child (self, parent, basename);
+ if (ret_val == NULL)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory"));
+ goto out;
+ }
+
+ out:
+ g_free (basename);
+ return ret_val;
+}
+
+static GDataEntry *
+resolve_dir (GVfsBackendGoogle *self,
+ const gchar *filename,
+ gchar **out_basename)
+{
+ GDataEntry *parent;
+ gboolean is_folder;
+ gchar *basename = NULL;
+ gchar *parent_path = NULL;
+
+ basename = g_path_get_basename (filename);
+ if (out_basename != NULL)
+ {
+ *out_basename = basename;
+ basename = NULL;
+ }
+
+ parent_path = g_path_get_dirname (filename);
+ parent = resolve (self, parent_path, NULL);
+ if (parent != NULL)
+ {
+ is_folder_or_root (self, parent_path, parent, &is_folder, NULL);
+ if (!is_folder)
+ parent = NULL;
+ }
+
+ g_free (basename);
+ g_free (parent_path);
+ return parent;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
remove_monitor_weak_ref (gpointer monitor,
gpointer unused,
@@ -834,14 +1060,13 @@ create_document (GVfsBackendGoogle *self,
GDataDocumentsFolder *parent;
GError *local_error;
gboolean is_root;
- const gchar *id;
gchar *parent_id = NULL;
gchar *parent_path = NULL;
gchar *path = NULL;
gchar *title = NULL;
parent_path = g_path_get_dirname (unescaped_filename);
- is_folder_or_root (parent_path, NULL, NULL, &is_root);
+ is_folder_or_root (self, parent_path, NULL, NULL, &is_root);
if (is_root)
{
parent = GDATA_DOCUMENTS_FOLDER (self->root);
@@ -881,8 +1106,7 @@ create_document (GVfsBackendGoogle *self,
if (local_error != NULL)
goto out;
- id = gdata_entry_get_id (GDATA_ENTRY (new_document));
- g_hash_table_insert (self->entries, g_strdup (id), g_object_ref (new_document));
+ insert_entry (self, GDATA_ENTRY (new_document));
path = get_entry_path (self, GDATA_ENTRY (new_document));
if (path != NULL)
@@ -924,9 +1148,8 @@ g_vfs_backend_google_copy (GVfsBackend *_self,
GDataEntry *source_entry;
GError *error;
gboolean is_folder;
- gboolean is_root;
+ gboolean destination_is_root;
gboolean is_volatile_source;
- const gchar *id;
const gchar *real_destination_parent_path;
const gchar *real_parent_path;
const gchar *real_source;
@@ -996,8 +1219,8 @@ g_vfs_backend_google_copy (GVfsBackend *_self,
destination_parent_path = g_strdup (real_destination_parent_path);
}
- is_folder_or_root (destination_parent_path, NULL, NULL, &is_root);
- if (is_root)
+ is_folder_or_root (self, destination_parent_path, NULL, NULL, &destination_is_root);
+ if (destination_is_root)
{
destination_parent = GDATA_DOCUMENTS_FOLDER (self->root);
}
@@ -1020,7 +1243,17 @@ g_vfs_backend_google_copy (GVfsBackend *_self,
}
source_entry = g_hash_table_lookup (self->entries, source_id);
- is_folder_or_root (source, source_entry, &is_folder, NULL);
+
+ if (!destination_is_root && destination_parent == NULL)
+ destination_parent = g_hash_table_lookup (self->entries, destination_parent_id);
+
+ if (source_entry == NULL || destination_parent == NULL)
+ {
+ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory"));
+ goto out;
+ }
+
+ is_folder_or_root (self, source, source_entry, &is_folder, NULL);
if (is_folder)
{
g_vfs_job_failed (G_VFS_JOB (job),
@@ -1030,13 +1263,6 @@ g_vfs_backend_google_copy (GVfsBackend *_self,
goto out;
}
- destination_parent = g_hash_table_lookup (self->entries, destination_parent_id);
- if (source_entry == NULL || destination_parent == NULL)
- {
- g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory"));
- goto out;
- }
-
error = NULL;
new_entry = gdata_documents_service_add_entry_to_folder (self->service,
GDATA_DOCUMENTS_ENTRY (source_entry),
@@ -1050,8 +1276,7 @@ g_vfs_backend_google_copy (GVfsBackend *_self,
goto out;
}
- id = gdata_entry_get_id (GDATA_ENTRY (new_entry));
- g_hash_table_insert (self->entries, g_strdup (id), g_object_ref (new_entry));
+ insert_entry (self, GDATA_ENTRY (new_entry));
path = get_entry_path (self, GDATA_ENTRY (new_entry));
if (path != NULL)
@@ -1123,7 +1348,7 @@ g_vfs_backend_google_create_dir_monitor (GVfsBackend *_self,
id = g_path_get_basename (filename);
entry = g_hash_table_lookup (self->entries, id);
- is_folder_or_root (filename, entry, NULL, &is_root);
+ is_folder_or_root (self, filename, entry, NULL, &is_root);
if (entry == NULL && !is_root)
{
@@ -1144,7 +1369,7 @@ g_vfs_backend_google_create_dir_monitor (GVfsBackend *_self,
}
}
- is_folder_or_root (filename, entry, &is_folder, NULL);
+ is_folder_or_root (self, filename, entry, &is_folder, NULL);
if (!is_folder)
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY, _("The file is not a
directory"));
@@ -1204,7 +1429,7 @@ g_vfs_backend_google_delete (GVfsBackend *_self,
filename = real_filename;
}
- is_folder_or_root (filename, NULL, NULL, &is_root);
+ is_folder_or_root (self, filename, NULL, NULL, &is_root);
if (is_root)
{
g_vfs_job_failed (G_VFS_JOB (job),
@@ -1248,7 +1473,7 @@ g_vfs_backend_google_delete (GVfsBackend *_self,
goto out;
}
- g_hash_table_remove (self->entries, id);
+ remove_entry (self, entry);
if (path != NULL)
g_hash_table_foreach (self->monitors, emit_delete_event, (gpointer) path);
@@ -1384,7 +1609,6 @@ g_vfs_backend_google_make_directory (GVfsBackend *_self,
gboolean is_display_name;
gboolean is_root;
gboolean needs_rebuild = FALSE;
- const gchar *id;
const gchar *real_parent_path;
gchar *parent_id = NULL;
gchar *parent_path = NULL;
@@ -1403,7 +1627,7 @@ g_vfs_backend_google_make_directory (GVfsBackend *_self,
goto out;
}
- is_folder_or_root (unescaped_filename, NULL, NULL, &is_root);
+ is_folder_or_root (self, unescaped_filename, NULL, NULL, &is_root);
if (is_root)
{
g_vfs_job_failed (G_VFS_JOB (job),
@@ -1414,7 +1638,7 @@ g_vfs_backend_google_make_directory (GVfsBackend *_self,
}
parent_path = g_path_get_dirname (unescaped_filename);
- is_folder_or_root (parent_path, NULL, NULL, &is_root);
+ is_folder_or_root (self, parent_path, NULL, NULL, &is_root);
if (is_root)
{
parent = GDATA_DOCUMENTS_FOLDER (self->root);
@@ -1489,8 +1713,7 @@ g_vfs_backend_google_make_directory (GVfsBackend *_self,
goto out;
}
- id = gdata_entry_get_id (GDATA_ENTRY (new_entry));
- g_hash_table_insert (self->entries, g_strdup (id), g_object_ref (new_entry));
+ insert_entry (self, GDATA_ENTRY (new_entry));
path = get_entry_path (self, GDATA_ENTRY (new_entry));
if (path != NULL)
@@ -1672,7 +1895,6 @@ g_vfs_backend_google_push (GVfsBackend *_self,
gboolean is_root;
gboolean needs_overwrite = FALSE;
const gchar *content_type;
- const gchar *id;
const gchar *title;
gchar *basename = NULL;
gchar *parent_id = NULL;
@@ -1827,7 +2049,7 @@ g_vfs_backend_google_push (GVfsBackend *_self,
{
parent_path = g_path_get_dirname (unescaped_destination);
- is_folder_or_root (parent_path, NULL, NULL, &is_root);
+ is_folder_or_root (self, parent_path, NULL, NULL, &is_root);
if (!is_root)
{
parent_id = g_path_get_basename (parent_path);
@@ -1899,8 +2121,7 @@ g_vfs_backend_google_push (GVfsBackend *_self,
goto out;
}
- id = gdata_entry_get_id (GDATA_ENTRY (new_document));
- g_hash_table_insert (self->entries, g_strdup (id), g_object_ref (new_document));
+ insert_entry (self, GDATA_ENTRY (new_document));
path = get_entry_path (self, GDATA_ENTRY (new_document));
if (path != NULL)
@@ -2016,7 +2237,7 @@ g_vfs_backend_google_query_info (GVfsBackend *_self,
id = g_path_get_basename (filename);
entry = g_hash_table_lookup (self->entries, id);
- is_folder_or_root (filename, entry, NULL, &is_root);
+ is_folder_or_root (self, filename, entry, NULL, &is_root);
if (entry == NULL && !is_root)
{
@@ -2175,7 +2396,7 @@ g_vfs_backend_google_open_for_read (GVfsBackend *_self,
id = g_path_get_basename (filename);
entry = g_hash_table_lookup (self->entries, id);
- is_folder_or_root (filename, entry, NULL, &is_root);
+ is_folder_or_root (self, filename, entry, NULL, &is_root);
if (is_root)
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY, _("Can't open directory"));
@@ -2201,7 +2422,7 @@ g_vfs_backend_google_open_for_read (GVfsBackend *_self,
}
}
- is_folder_or_root (filename, entry, &is_folder, NULL);
+ is_folder_or_root (self, filename, entry, &is_folder, NULL);
if (is_folder)
{
g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY, _("Can't open directory"));
@@ -2404,7 +2625,6 @@ g_vfs_backend_google_set_display_name (GVfsBackend *_self,
GError *error;
gboolean is_root;
gboolean is_volatile;
- const gchar *new_id;
gchar *escaped_filename = NULL;
gchar *id = NULL;
gchar *unescaped_filename = NULL;
@@ -2428,7 +2648,7 @@ g_vfs_backend_google_set_display_name (GVfsBackend *_self,
filename = real_filename;
}
- is_folder_or_root (filename, NULL, NULL, &is_root);
+ is_folder_or_root (self, filename, NULL, NULL, &is_root);
if (is_root)
{
g_vfs_job_failed (G_VFS_JOB (job),
@@ -2472,10 +2692,8 @@ g_vfs_backend_google_set_display_name (GVfsBackend *_self,
goto out;
}
- g_hash_table_remove (self->entries, id);
-
- new_id = gdata_entry_get_id (new_entry);
- g_hash_table_insert (self->entries, g_strdup (new_id), g_object_ref (new_entry));
+ remove_entry (self, entry);
+ insert_entry (self, new_entry);
g_hash_table_foreach (self->monitors, emit_attribute_changed_event, (gpointer) filename);
@@ -2522,7 +2740,7 @@ g_vfs_backend_google_create (GVfsBackend *_self,
goto out;
}
- is_folder_or_root (unescaped_filename, NULL, NULL, &is_root);
+ is_folder_or_root (self, unescaped_filename, NULL, NULL, &is_root);
if (is_root)
{
g_vfs_job_failed (G_VFS_JOB (job),
@@ -2581,7 +2799,7 @@ g_vfs_backend_google_replace (GVfsBackend *_self,
goto out;
}
- is_folder_or_root (unescaped_filename, NULL, NULL, &is_root);
+ is_folder_or_root (self, unescaped_filename, NULL, NULL, &is_root);
if (is_root)
{
g_vfs_job_failed (G_VFS_JOB (job),
@@ -2826,6 +3044,7 @@ g_vfs_backend_google_dispose (GObject *_self)
g_clear_object (&self->root);
g_clear_object (&self->client);
g_clear_pointer (&self->entries, (GDestroyNotify) g_hash_table_unref);
+ g_clear_pointer (&self->dir_entries, (GDestroyNotify) g_hash_table_unref);
G_OBJECT_CLASS (g_vfs_backend_google_parent_class)->dispose (_self);
}
@@ -2884,6 +3103,10 @@ g_vfs_backend_google_init (GVfsBackendGoogle *self)
g_vfs_backend_set_prefered_filename_encoding (G_VFS_BACKEND (self), "google-drive");
self->entries = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+ self->dir_entries = g_hash_table_new_full (entries_in_folder_hash,
+ entries_in_folder_equal,
+ dir_entries_key_free,
+ g_object_unref);
self->lookaside = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
self->monitors = g_hash_table_new (NULL, NULL);
g_rec_mutex_init (&self->mutex);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]