Blame SOURCES/google-performance-fixes.patch

0049b8
From ea26e6ddefca9b5f75f3d7485e420729bc038852 Mon Sep 17 00:00:00 2001
0049b8
From: Ondrej Holy <oholy@redhat.com>
0049b8
Date: Tue, 5 Jun 2018 13:04:15 +0200
0049b8
Subject: [PATCH 01/14] google: Do not create .desktop files for native files
0049b8
0049b8
Currently, .desktop file with a link to the original location is provided,
0049b8
when a native file is opened because Google doesn't provide its proprietary
0049b8
formats and GLocalFile doesn't know G_FILE_TYPE_SHORTCUT. It is a bit
0049b8
tricky and confusing, among other because the .desktop files aren't
0049b8
automatically converted back to native files when writing.
0049b8
0049b8
What is worse, Nautilus has dropped support for .desktop files recently,
0049b8
so you see "There was an error launching the application." instead of the
0049b8
requested file. It doesn't make more sense to provide this .desktop files,
0049b8
so let's remove this fallback and return error instead.
0049b8
0049b8
https://gitlab.gnome.org/GNOME/nautilus/issues/448
0049b8
---
0049b8
 daemon/gvfsbackendgoogle.c | 68 ++++++++------------------------------
0049b8
 1 file changed, 13 insertions(+), 55 deletions(-)
0049b8
0049b8
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
0049b8
index 23bd8f58..7bea4bff 100644
0049b8
--- a/daemon/gvfsbackendgoogle.c
0049b8
+++ b/daemon/gvfsbackendgoogle.c
0049b8
@@ -907,7 +907,6 @@ build_file_info (GVfsBackendGoogle      *self,
0049b8
   gchar *escaped_name = NULL;
0049b8
   gchar *content_type = NULL;
0049b8
   gchar *copy_name = NULL;
0049b8
-  gchar *generated_copy_name = NULL;
0049b8
   gint64 atime;
0049b8
   gint64 ctime;
0049b8
   gint64 mtime;
0049b8
@@ -1025,21 +1024,7 @@ build_file_info (GVfsBackendGoogle      *self,
0049b8
   g_file_info_set_display_name (info, title);
0049b8
   g_file_info_set_edit_name (info, title);
0049b8
 
0049b8
-  generated_copy_name = generate_copy_name (self, entry);
0049b8
-
0049b8
-  /* While copying remote Drive content to local storage, we want to
0049b8
-   * create Link-type desktop files because GLocalFile doesn't know
0049b8
-   * about shortcuts. That might change in future.
0049b8
-   */
0049b8
-  if (file_type == G_FILE_TYPE_SHORTCUT)
0049b8
-    {
0049b8
-      copy_name = g_strconcat (generated_copy_name, ".desktop", NULL);
0049b8
-    }
0049b8
-  else
0049b8
-    {
0049b8
-      copy_name = generated_copy_name;
0049b8
-      generated_copy_name = NULL;
0049b8
-    }
0049b8
+  copy_name = generate_copy_name (self, entry);
0049b8
 
0049b8
   /* Sanitize copy-name by replacing slashes with dashes. This is
0049b8
    * what nautilus does (for desktop files).
0049b8
@@ -1097,7 +1082,6 @@ build_file_info (GVfsBackendGoogle      *self,
0049b8
 
0049b8
  out:
0049b8
   g_free (copy_name);
0049b8
-  g_free (generated_copy_name);
0049b8
   g_free (escaped_name);
0049b8
   g_free (content_type);
0049b8
   g_list_free (links);
0049b8
@@ -2249,6 +2233,8 @@ g_vfs_backend_google_open_for_read (GVfsBackend        *_self,
0049b8
   GError *error;
0049b8
   gchar *content_type = NULL;
0049b8
   gchar *entry_path = NULL;
0049b8
+  GDataAuthorizationDomain *auth_domain;
0049b8
+  const gchar *uri;
0049b8
 
0049b8
   g_rec_mutex_lock (&self->mutex);
0049b8
   g_debug ("+ open_for_read: %s\n", filename);
0049b8
@@ -2278,47 +2264,19 @@ g_vfs_backend_google_open_for_read (GVfsBackend        *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  /* While copying remote Drive content to local storage, we want to
0049b8
-   * create Link-type desktop files because GLocalFile doesn't know
0049b8
-   * about shortcuts. That might change in future.
0049b8
-   */
0049b8
-  if (g_str_has_prefix (content_type, CONTENT_TYPE_PREFIX_GOOGLE))
0049b8
+  if (is_native_file (entry))
0049b8
     {
0049b8
-      GDataLink *alternate;
0049b8
-      GKeyFile *file;
0049b8
-      const gchar *title;
0049b8
-      const gchar *uri;
0049b8
-      gchar *data;
0049b8
-      gsize length;
0049b8
-
0049b8
-      file = g_key_file_new ();
0049b8
-
0049b8
-      title = gdata_entry_get_title (entry);
0049b8
-      g_key_file_set_string (file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, title);
0049b8
-      g_key_file_set_string (file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TYPE, "Link");
0049b8
-
0049b8
-      alternate = gdata_entry_look_up_link (entry, GDATA_LINK_ALTERNATE);
0049b8
-      uri = gdata_link_get_uri (alternate);
0049b8
-      g_key_file_set_string (file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_URL, uri);
0049b8
-
0049b8
-      data = g_key_file_to_data (file, &length, NULL);
0049b8
-      stream = g_memory_input_stream_new_from_data (data, (gssize) length, g_free);
0049b8
-
0049b8
-      g_key_file_free (file);
0049b8
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE, _("File is not a regular file"));
0049b8
+      goto out;
0049b8
     }
0049b8
-  else
0049b8
-    {
0049b8
-      GDataAuthorizationDomain *auth_domain;
0049b8
-      const gchar *uri;
0049b8
 
0049b8
-      auth_domain = gdata_documents_service_get_primary_authorization_domain ();
0049b8
-      uri = gdata_entry_get_content_uri (entry);
0049b8
-      stream = gdata_download_stream_new (GDATA_SERVICE (self->service), auth_domain, uri, cancellable);
0049b8
-      if (stream == NULL)
0049b8
-        {
0049b8
-          g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED, _("Error getting data from file"));
0049b8
-          goto out;
0049b8
-        }
0049b8
+  auth_domain = gdata_documents_service_get_primary_authorization_domain ();
0049b8
+  uri = gdata_entry_get_content_uri (entry);
0049b8
+  stream = gdata_download_stream_new (GDATA_SERVICE (self->service), auth_domain, uri, cancellable);
0049b8
+  if (stream == NULL)
0049b8
+    {
0049b8
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED, _("Error getting data from file"));
0049b8
+      goto out;
0049b8
     }
0049b8
 
0049b8
   g_object_set_data_full (G_OBJECT (stream), "g-vfs-backend-google-entry", g_object_ref (entry), g_object_unref);
0049b8
-- 
0049b8
2.36.1
0049b8
0049b8
0049b8
From fec7d2162966c3574226564b62c6dd252bf4706f Mon Sep 17 00:00:00 2001
0049b8
From: Ondrej Holy <oholy@redhat.com>
0049b8
Date: Mon, 23 Jul 2018 13:39:33 +0200
0049b8
Subject: [PATCH 02/14] google: Drop the (GDestroyNotify) cast
0049b8
0049b8
"warning: function called through a non-compatible type" is printed
0049b8
by GCC 8 because of (GDestroyNotfiy) cast in g_clear_pointer, see for
0049b8
more info: https://gitlab.gnome.org/GNOME/glib/issues/1425. Let's
0049b8
drop the (GDestroyNotify) cast in order to prevent those warnings.
0049b8
The cast was not needed anyway.
0049b8
---
0049b8
 daemon/gvfsbackendgoogle.c | 4 ++--
0049b8
 1 file changed, 2 insertions(+), 2 deletions(-)
0049b8
0049b8
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
0049b8
index 7bea4bff..2e96cca4 100644
0049b8
--- a/daemon/gvfsbackendgoogle.c
0049b8
+++ b/daemon/gvfsbackendgoogle.c
0049b8
@@ -2866,8 +2866,8 @@ g_vfs_backend_google_dispose (GObject *_self)
0049b8
   g_clear_object (&self->service);
0049b8
   g_clear_object (&self->root);
0049b8
   g_clear_object (&self->client);
0049b8
-  g_clear_pointer (&self->entries, (GDestroyNotify) g_hash_table_unref);
0049b8
-  g_clear_pointer (&self->dir_entries, (GDestroyNotify) g_hash_table_unref);
0049b8
+  g_clear_pointer (&self->entries, g_hash_table_unref);
0049b8
+  g_clear_pointer (&self->dir_entries, g_hash_table_unref);
0049b8
 
0049b8
   G_OBJECT_CLASS (g_vfs_backend_google_parent_class)->dispose (_self);
0049b8
 }
0049b8
-- 
0049b8
2.36.1
0049b8
0049b8
0049b8
From 2d5fc426acb1bff385258d860ec97ff30242285d Mon Sep 17 00:00:00 2001
0049b8
From: Ondrej Holy <oholy@redhat.com>
0049b8
Date: Wed, 1 Aug 2018 13:43:16 +0200
0049b8
Subject: [PATCH 03/14] google: Move debug prints before releasing entry
0049b8
0049b8
Debug output contains mess because id and title are const gchar *
0049b8
and are released together with GDataEntry on previous line. Let's
0049b8
just swap the lines.
0049b8
---
0049b8
 daemon/gvfsbackendgoogle.c | 4 ++--
0049b8
 1 file changed, 2 insertions(+), 2 deletions(-)
0049b8
0049b8
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
0049b8
index 2e96cca4..e157458b 100644
0049b8
--- a/daemon/gvfsbackendgoogle.c
0049b8
+++ b/daemon/gvfsbackendgoogle.c
0049b8
@@ -510,13 +510,13 @@ remove_entry (GVfsBackendGoogle *self,
0049b8
   parent_id = get_parent_id (self, entry);
0049b8
 
0049b8
   k = dir_entries_key_new (id, parent_id);
0049b8
-  g_hash_table_remove (self->dir_entries, k);
0049b8
   g_debug ("  remove_entry: Removed (%s, %s) -> %p\n", id, parent_id, entry);
0049b8
+  g_hash_table_remove (self->dir_entries, k);
0049b8
   dir_entries_key_free (k);
0049b8
 
0049b8
   k = dir_entries_key_new (title, parent_id);
0049b8
-  g_hash_table_remove (self->dir_entries, k);
0049b8
   g_debug ("  remove_entry: Removed (%s, %s) -> %p\n", title, parent_id, entry);
0049b8
+  g_hash_table_remove (self->dir_entries, k);
0049b8
   dir_entries_key_free (k);
0049b8
 
0049b8
   for (l = self->dir_collisions; l != NULL; l = l->next)
0049b8
-- 
0049b8
2.36.1
0049b8
0049b8
0049b8
From b3f8db69522fdbdc965219e403da6e8e60997907 Mon Sep 17 00:00:00 2001
0049b8
From: Ondrej Holy <oholy@redhat.com>
0049b8
Date: Wed, 1 Aug 2018 13:44:59 +0200
0049b8
Subject: [PATCH 04/14] google: Remove also dir_collisions entries
0049b8
0049b8
dir_collisions are not properly invalidated if removed entry is on this list.
0049b8
Let's remove the entry also from this list.
0049b8
---
0049b8
 daemon/gvfsbackendgoogle.c | 7 +++++++
0049b8
 1 file changed, 7 insertions(+)
0049b8
0049b8
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
0049b8
index e157458b..e9eaec1f 100644
0049b8
--- a/daemon/gvfsbackendgoogle.c
0049b8
+++ b/daemon/gvfsbackendgoogle.c
0049b8
@@ -519,6 +519,13 @@ remove_entry (GVfsBackendGoogle *self,
0049b8
   g_hash_table_remove (self->dir_entries, k);
0049b8
   dir_entries_key_free (k);
0049b8
 
0049b8
+  l = g_list_find (self->dir_collisions, entry);
0049b8
+  if (l != NULL)
0049b8
+    {
0049b8
+      self->dir_collisions = g_list_remove_link (self->dir_collisions, l);
0049b8
+      g_object_unref (entry);
0049b8
+    }
0049b8
+
0049b8
   for (l = self->dir_collisions; l != NULL; l = l->next)
0049b8
     {
0049b8
       GDataEntry *colliding_entry = GDATA_ENTRY (l->data);
0049b8
-- 
0049b8
2.36.1
0049b8
0049b8
0049b8
From ab007b1f3215a30c3ef49492cf22e6ef1383b0fd Mon Sep 17 00:00:00 2001
0049b8
From: Ondrej Holy <oholy@redhat.com>
0049b8
Date: Tue, 31 Jul 2018 18:43:44 +0200
0049b8
Subject: [PATCH 05/14] google: Ignore entries without parents
0049b8
0049b8
Entries without parents are not shown on the web and there isn't any
0049b8
reason to list them here. Such entries belongs to some web services
0049b8
and we have no control over them.
0049b8
---
0049b8
 daemon/gvfsbackendgoogle.c | 18 +-----------------
0049b8
 1 file changed, 1 insertion(+), 17 deletions(-)
0049b8
0049b8
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
0049b8
index e9eaec1f..897df61f 100644
0049b8
--- a/daemon/gvfsbackendgoogle.c
0049b8
+++ b/daemon/gvfsbackendgoogle.c
0049b8
@@ -347,14 +347,6 @@ get_parent_id (GVfsBackendGoogle *self,
0049b8
         }
0049b8
     }
0049b8
 
0049b8
-  if (ret_val == NULL)
0049b8
-    {
0049b8
-      const gchar *root_id;
0049b8
-
0049b8
-      root_id = gdata_entry_get_id (self->root);
0049b8
-      ret_val = g_strdup (root_id);
0049b8
-    }
0049b8
-
0049b8
   g_list_free (links);
0049b8
   return ret_val;
0049b8
 }
0049b8
@@ -903,10 +895,8 @@ build_file_info (GVfsBackendGoogle      *self,
0049b8
 {
0049b8
   GFileType file_type;
0049b8
   GList *authors;
0049b8
-  GList *links;
0049b8
   gboolean is_folder = FALSE;
0049b8
   gboolean is_root = FALSE;
0049b8
-  gboolean has_parent = FALSE;
0049b8
   const gchar *etag;
0049b8
   const gchar *id;
0049b8
   const gchar *name;
0049b8
@@ -925,9 +915,6 @@ build_file_info (GVfsBackendGoogle      *self,
0049b8
   if (entry == self->root)
0049b8
     is_root = TRUE;
0049b8
 
0049b8
-  links = gdata_entry_look_up_links (entry, GDATA_LINK_PARENT);
0049b8
-  has_parent = (links != NULL);
0049b8
-
0049b8
   g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, !is_root);
0049b8
 
0049b8
   g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, is_folder);
0049b8
@@ -936,9 +923,7 @@ build_file_info (GVfsBackendGoogle      *self,
0049b8
   g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_STANDARD_IS_VOLATILE, is_symlink);
0049b8
 
0049b8
   g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
0049b8
-  g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, !is_root && has_parent);
0049b8
-
0049b8
-  g_file_info_set_is_hidden (info, !has_parent);
0049b8
+  g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, !is_root);
0049b8
 
0049b8
   if (is_folder)
0049b8
     {
0049b8
@@ -1091,7 +1076,6 @@ build_file_info (GVfsBackendGoogle      *self,
0049b8
   g_free (copy_name);
0049b8
   g_free (escaped_name);
0049b8
   g_free (content_type);
0049b8
-  g_list_free (links);
0049b8
 }
0049b8
 
0049b8
 /* ---------------------------------------------------------------------------------------------------- */
0049b8
-- 
0049b8
2.36.1
0049b8
0049b8
0049b8
From 631f794a4a660f49be9d30744e5c66a1f60da4de Mon Sep 17 00:00:00 2001
0049b8
From: Ondrej Holy <oholy@redhat.com>
0049b8
Date: Tue, 31 Jul 2018 19:08:39 +0200
0049b8
Subject: [PATCH 06/14] google: Add support for files with multiple parents
0049b8
0049b8
One entry can have multiple parents. You can create such entry on
0049b8
the web in a pretty simple way, e.g. Ctrl + Drag&Drop. Such entries
0049b8
are currently shown only on one place in the backend. Also the backend
0049b8
rely on get_parent_id() and get_entry_path() functions which are tottaly
0049b8
wrong. Let's introduce get_parent_ids() and resolve entry_path only
0049b8
from given filename.
0049b8
---
0049b8
 daemon/gvfsbackendgoogle.c | 388 ++++++++++++++++---------------------
0049b8
 1 file changed, 168 insertions(+), 220 deletions(-)
0049b8
0049b8
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
0049b8
index 897df61f..7f812448 100644
0049b8
--- a/daemon/gvfsbackendgoogle.c
0049b8
+++ b/daemon/gvfsbackendgoogle.c
0049b8
@@ -99,11 +99,13 @@ typedef struct
0049b8
   GDataEntry *document;
0049b8
   GDataUploadStream *stream;
0049b8
   gchar *filename;
0049b8
+  gchar *entry_path;
0049b8
 } WriteHandle;
0049b8
 
0049b8
 static GDataEntry *resolve_dir (GVfsBackendGoogle  *self,
0049b8
                                 const gchar        *filename,
0049b8
                                 gchar             **out_basename,
0049b8
+                                gchar             **out_path,
0049b8
                                 GError            **error);
0049b8
 
0049b8
 /* ---------------------------------------------------------------------------------------------------- */
0049b8
@@ -160,7 +162,7 @@ entries_in_folder_equal (gconstpointer a, gconstpointer b)
0049b8
 /* ---------------------------------------------------------------------------------------------------- */
0049b8
 
0049b8
 static WriteHandle *
0049b8
-write_handle_new (GDataEntry *document, GDataUploadStream *stream, const gchar *filename)
0049b8
+write_handle_new (GDataEntry *document, GDataUploadStream *stream, const gchar *filename, const gchar *entry_path)
0049b8
 {
0049b8
   WriteHandle *handle;
0049b8
 
0049b8
@@ -177,6 +179,7 @@ write_handle_new (GDataEntry *document, GDataUploadStream *stream, const gchar *
0049b8
     }
0049b8
 
0049b8
   handle->filename = g_strdup (filename);
0049b8
+  handle->entry_path = g_strdup (entry_path);
0049b8
 
0049b8
   return handle;
0049b8
 }
0049b8
@@ -192,6 +195,7 @@ write_handle_free (gpointer data)
0049b8
   g_clear_object (&handle->document);
0049b8
   g_clear_object (&handle->stream);
0049b8
   g_free (handle->filename);
0049b8
+  g_free (handle->entry_path);
0049b8
   g_slice_free (WriteHandle, handle);
0049b8
 }
0049b8
 
0049b8
@@ -313,13 +317,13 @@ get_content_type_from_entry (GDataEntry *entry)
0049b8
 
0049b8
 /* ---------------------------------------------------------------------------------------------------- */
0049b8
 
0049b8
-static gchar *
0049b8
-get_parent_id (GVfsBackendGoogle *self,
0049b8
-               GDataEntry        *entry)
0049b8
+static GList *
0049b8
+get_parent_ids (GVfsBackendGoogle *self,
0049b8
+                GDataEntry        *entry)
0049b8
 {
0049b8
   GList *l;
0049b8
   GList *links = NULL;
0049b8
-  gchar *ret_val = NULL;
0049b8
+  GList *ids = NULL;
0049b8
 
0049b8
   links = gdata_entry_look_up_links (entry, GDATA_LINK_PARENT);
0049b8
   for (l = links; l != NULL; l = l->next)
0049b8
@@ -341,68 +345,13 @@ get_parent_id (GVfsBackendGoogle *self,
0049b8
           id = uri + uri_prefix_len;
0049b8
           if (id[0] != '\0')
0049b8
             {
0049b8
-              ret_val = g_strdup (uri + uri_prefix_len);
0049b8
-              break;
0049b8
+              ids = g_list_prepend (ids, g_strdup (id));
0049b8
             }
0049b8
         }
0049b8
     }
0049b8
 
0049b8
   g_list_free (links);
0049b8
-  return ret_val;
0049b8
-}
0049b8
-
0049b8
-static gchar *
0049b8
-get_entry_path (GVfsBackendGoogle *self, GDataEntry *entry)
0049b8
-{
0049b8
-  GString *path = NULL;
0049b8
-  const gchar *base_id;
0049b8
-  const gchar *root_id;
0049b8
-  gchar *id = NULL;
0049b8
-  gchar *ret_val = NULL;
0049b8
-
0049b8
-  if (entry == self->root)
0049b8
-    {
0049b8
-      ret_val = g_strdup ("/");
0049b8
-      goto out;
0049b8
-    }
0049b8
-
0049b8
-  base_id = gdata_entry_get_id (entry);
0049b8
-  path = g_string_new (base_id);
0049b8
-  g_string_prepend_c (path, '/');
0049b8
-
0049b8
-  id = get_parent_id (self, entry);
0049b8
-  root_id = gdata_entry_get_id (self->root);
0049b8
-
0049b8
-  while (id != NULL)
0049b8
-    {
0049b8
-      GDataEntry *parent_entry;
0049b8
-
0049b8
-      /* The root folder itself has an ID, so path can become
0049b8
-       * /root/folder1/folder2/file. Instead, we want it to be
0049b8
-       * /folder1/folder2/file.
0049b8
-       */
0049b8
-
0049b8
-      if (g_strcmp0 (id, root_id) == 0)
0049b8
-        break;
0049b8
-
0049b8
-      parent_entry = g_hash_table_lookup (self->entries, id);
0049b8
-      if (parent_entry == NULL)
0049b8
-        goto out;
0049b8
-
0049b8
-      g_string_prepend (path, id);
0049b8
-      g_string_prepend_c (path, '/');
0049b8
-
0049b8
-      g_free (id);
0049b8
-      id = get_parent_id (self, parent_entry);
0049b8
-    }
0049b8
-
0049b8
-  ret_val = g_strdup (path->str);
0049b8
-
0049b8
- out:
0049b8
-  g_free (id);
0049b8
-  if (path != NULL)
0049b8
-    g_string_free (path, TRUE);
0049b8
-  return ret_val;
0049b8
+  return ids;
0049b8
 }
0049b8
 
0049b8
 /* ---------------------------------------------------------------------------------------------------- */
0049b8
@@ -418,62 +367,66 @@ insert_entry_full (GVfsBackendGoogle *self,
0049b8
   const gchar *id;
0049b8
   const gchar *old_id;
0049b8
   const gchar *title;
0049b8
-  gchar *parent_id;
0049b8
+  GList *parent_ids, *l;
0049b8
 
0049b8
   id = gdata_entry_get_id (entry);
0049b8
   title = gdata_entry_get_title (entry);
0049b8
 
0049b8
   g_hash_table_insert (self->entries, g_strdup (id), g_object_ref (entry));
0049b8
 
0049b8
-  parent_id = get_parent_id (self, entry);
0049b8
+  parent_ids = get_parent_ids (self, entry);
0049b8
+  for (l = parent_ids; l != NULL; l = l->next)
0049b8
+    {
0049b8
+      gchar *parent_id = l->data;
0049b8
 
0049b8
-  k = dir_entries_key_new (id, parent_id);
0049b8
-  g_hash_table_insert (self->dir_entries, k, g_object_ref (entry));
0049b8
-  g_debug ("  insert_entry: Inserted (%s, %s) -> %p\n", id, parent_id, entry);
0049b8
+      k = dir_entries_key_new (id, parent_id);
0049b8
+      g_hash_table_insert (self->dir_entries, k, g_object_ref (entry));
0049b8
+      g_debug ("  insert_entry: Inserted (%s, %s) -> %p\n", id, parent_id, entry);
0049b8
 
0049b8
-  k = dir_entries_key_new (title, parent_id);
0049b8
-  old_entry = g_hash_table_lookup (self->dir_entries, k);
0049b8
-  if (old_entry != NULL)
0049b8
-    {
0049b8
-      old_id = gdata_entry_get_id (old_entry);
0049b8
-      if (g_strcmp0 (old_id, title) == 0)
0049b8
-        {
0049b8
-          insert_title = FALSE;
0049b8
-        }
0049b8
-      else
0049b8
+      k = dir_entries_key_new (title, parent_id);
0049b8
+      old_entry = g_hash_table_lookup (self->dir_entries, k);
0049b8
+      if (old_entry != NULL)
0049b8
         {
0049b8
-          /* If the collision is not due to the title matching the ID
0049b8
-           * of an earlier GDataEntry, then it is due to duplicate
0049b8
-           * titles.
0049b8
-           */
0049b8
-          if (g_strcmp0 (old_id, id) < 0)
0049b8
-            insert_title = FALSE;
0049b8
+          old_id = gdata_entry_get_id (old_entry);
0049b8
+          if (g_strcmp0 (old_id, title) == 0)
0049b8
+            {
0049b8
+              insert_title = FALSE;
0049b8
+            }
0049b8
+          else
0049b8
+            {
0049b8
+              /* If the collision is not due to the title matching the ID
0049b8
+               * of an earlier GDataEntry, then it is due to duplicate
0049b8
+               * titles.
0049b8
+               */
0049b8
+              if (g_strcmp0 (old_id, id) < 0)
0049b8
+                insert_title = FALSE;
0049b8
+            }
0049b8
         }
0049b8
-    }
0049b8
 
0049b8
-  if (insert_title)
0049b8
-    {
0049b8
-      if (old_entry != NULL && track_dir_collisions)
0049b8
+      if (insert_title)
0049b8
         {
0049b8
-          self->dir_collisions = g_list_prepend (self->dir_collisions, g_object_ref (old_entry));
0049b8
-          g_debug ("  insert_entry: Ejected (%s, %s, %s) -> %p\n", old_id, title, parent_id, old_entry);
0049b8
-        }
0049b8
+          if (old_entry != NULL && track_dir_collisions)
0049b8
+            {
0049b8
+              self->dir_collisions = g_list_prepend (self->dir_collisions, g_object_ref (old_entry));
0049b8
+              g_debug ("  insert_entry: Ejected (%s, %s, %s) -> %p\n", old_id, title, parent_id, old_entry);
0049b8
+            }
0049b8
 
0049b8
-      g_hash_table_insert (self->dir_entries, k, g_object_ref (entry));
0049b8
-      g_debug ("  insert_entry: Inserted (%s, %s) -> %p\n", title, parent_id, entry);
0049b8
-    }
0049b8
-  else
0049b8
-    {
0049b8
-      if (track_dir_collisions)
0049b8
-        {
0049b8
-          self->dir_collisions = g_list_prepend (self->dir_collisions, g_object_ref (entry));
0049b8
-          g_debug ("  insert_entry: Skipped (%s, %s, %s) -> %p\n", id, title, parent_id, entry);
0049b8
+          g_hash_table_insert (self->dir_entries, k, g_object_ref (entry));
0049b8
+          g_debug ("  insert_entry: Inserted (%s, %s) -> %p\n", title, parent_id, entry);
0049b8
         }
0049b8
+      else
0049b8
+        {
0049b8
+          if (track_dir_collisions)
0049b8
+            {
0049b8
+              self->dir_collisions = g_list_prepend (self->dir_collisions, g_object_ref (entry));
0049b8
+              g_debug ("  insert_entry: Skipped (%s, %s, %s) -> %p\n", id, title, parent_id, entry);
0049b8
+            }
0049b8
 
0049b8
-      dir_entries_key_free (k);
0049b8
+          dir_entries_key_free (k);
0049b8
+        }
0049b8
     }
0049b8
+  g_list_free_full (parent_ids, g_free);
0049b8
 
0049b8
-  g_free (parent_id);
0049b8
   return insert_title;
0049b8
 }
0049b8
 
0049b8
@@ -492,47 +445,50 @@ remove_entry (GVfsBackendGoogle *self,
0049b8
   GList *l;
0049b8
   const gchar *id;
0049b8
   const gchar *title;
0049b8
-  gchar *parent_id;
0049b8
+  GList *parent_ids, *ll;
0049b8
 
0049b8
   id = gdata_entry_get_id (entry);
0049b8
   title = gdata_entry_get_title (entry);
0049b8
 
0049b8
   g_hash_table_remove (self->entries, id);
0049b8
 
0049b8
-  parent_id = get_parent_id (self, entry);
0049b8
-
0049b8
-  k = dir_entries_key_new (id, parent_id);
0049b8
-  g_debug ("  remove_entry: Removed (%s, %s) -> %p\n", id, parent_id, entry);
0049b8
-  g_hash_table_remove (self->dir_entries, k);
0049b8
-  dir_entries_key_free (k);
0049b8
-
0049b8
-  k = dir_entries_key_new (title, parent_id);
0049b8
-  g_debug ("  remove_entry: Removed (%s, %s) -> %p\n", title, parent_id, entry);
0049b8
-  g_hash_table_remove (self->dir_entries, k);
0049b8
-  dir_entries_key_free (k);
0049b8
-
0049b8
-  l = g_list_find (self->dir_collisions, entry);
0049b8
-  if (l != NULL)
0049b8
+  parent_ids = get_parent_ids (self, entry);
0049b8
+  for (ll = parent_ids; ll != NULL; ll = ll->next)
0049b8
     {
0049b8
-      self->dir_collisions = g_list_remove_link (self->dir_collisions, l);
0049b8
-      g_object_unref (entry);
0049b8
-    }
0049b8
+      gchar *parent_id = ll->data;
0049b8
 
0049b8
-  for (l = self->dir_collisions; l != NULL; l = l->next)
0049b8
-    {
0049b8
-      GDataEntry *colliding_entry = GDATA_ENTRY (l->data);
0049b8
+      k = dir_entries_key_new (id, parent_id);
0049b8
+      g_debug ("  remove_entry: Removed (%s, %s) -> %p\n", id, parent_id, entry);
0049b8
+      g_hash_table_remove (self->dir_entries, k);
0049b8
+      dir_entries_key_free (k);
0049b8
+
0049b8
+      k = dir_entries_key_new (title, parent_id);
0049b8
+      g_debug ("  remove_entry: Removed (%s, %s) -> %p\n", title, parent_id, entry);
0049b8
+      g_hash_table_remove (self->dir_entries, k);
0049b8
+      dir_entries_key_free (k);
0049b8
 
0049b8
-      if (insert_entry_full (self, colliding_entry, FALSE))
0049b8
+      l = g_list_find (self->dir_collisions, entry);
0049b8
+      if (l != NULL)
0049b8
         {
0049b8
           self->dir_collisions = g_list_remove_link (self->dir_collisions, l);
0049b8
-          g_debug ("  remove_entry: Restored %p\n", colliding_entry);
0049b8
-          g_list_free (l);
0049b8
-          g_object_unref (colliding_entry);
0049b8
-          break;
0049b8
+          g_object_unref (entry);
0049b8
         }
0049b8
-    }
0049b8
 
0049b8
-  g_free (parent_id);
0049b8
+      for (l = self->dir_collisions; l != NULL; l = l->next)
0049b8
+        {
0049b8
+          GDataEntry *colliding_entry = GDATA_ENTRY (l->data);
0049b8
+
0049b8
+          if (insert_entry_full (self, colliding_entry, FALSE))
0049b8
+            {
0049b8
+              self->dir_collisions = g_list_remove_link (self->dir_collisions, l);
0049b8
+              g_debug ("  remove_entry: Restored %p\n", colliding_entry);
0049b8
+              g_list_free (l);
0049b8
+              g_object_unref (colliding_entry);
0049b8
+              break;
0049b8
+            }
0049b8
+        }
0049b8
+    }
0049b8
+  g_list_free_full (parent_ids, g_free);
0049b8
 }
0049b8
 
0049b8
 static void
0049b8
@@ -617,6 +573,7 @@ resolve_child (GVfsBackendGoogle *self,
0049b8
 static GDataEntry *
0049b8
 resolve (GVfsBackendGoogle  *self,
0049b8
          const gchar        *filename,
0049b8
+         gchar             **out_path,
0049b8
          GError            **error)
0049b8
 {
0049b8
   GDataEntry *parent;
0049b8
@@ -627,11 +584,15 @@ resolve (GVfsBackendGoogle  *self,
0049b8
   if (g_strcmp0 (filename, "/") == 0)
0049b8
     {
0049b8
       ret_val = self->root;
0049b8
+
0049b8
+      if (out_path != NULL)
0049b8
+        *out_path = g_strdup ("/");
0049b8
+
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
   local_error = NULL;
0049b8
-  parent = resolve_dir (self, filename, &basename, &local_error);
0049b8
+  parent = resolve_dir (self, filename, &basename, out_path, &local_error);
0049b8
   if (local_error != NULL)
0049b8
     {
0049b8
       g_propagate_error (error, local_error);
0049b8
@@ -645,6 +606,14 @@ resolve (GVfsBackendGoogle  *self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
+  if (out_path != NULL)
0049b8
+    {
0049b8
+      gchar *tmp;
0049b8
+      tmp = g_build_path ("/", *out_path, gdata_entry_get_id (ret_val), NULL);
0049b8
+      g_free (*out_path);
0049b8
+      *out_path = tmp;
0049b8
+    }
0049b8
+
0049b8
  out:
0049b8
   g_free (basename);
0049b8
   return ret_val;
0049b8
@@ -654,6 +623,7 @@ static GDataEntry *
0049b8
 resolve_dir (GVfsBackendGoogle  *self,
0049b8
              const gchar        *filename,
0049b8
              gchar             **out_basename,
0049b8
+             gchar             **out_path,
0049b8
              GError            **error)
0049b8
 {
0049b8
   GDataEntry *parent;
0049b8
@@ -666,7 +636,7 @@ resolve_dir (GVfsBackendGoogle  *self,
0049b8
   parent_path = g_path_get_dirname (filename);
0049b8
 
0049b8
   local_error = NULL;
0049b8
-  parent = resolve (self, parent_path, &local_error);
0049b8
+  parent = resolve (self, parent_path, out_path, &local_error);
0049b8
   if (local_error != NULL)
0049b8
     {
0049b8
       g_propagate_error (error, local_error);
0049b8
@@ -699,12 +669,13 @@ static GDataEntry *
0049b8
 resolve_and_rebuild (GVfsBackendGoogle  *self,
0049b8
                      const gchar        *filename,
0049b8
                      GCancellable       *cancellable,
0049b8
+                     gchar             **out_path,
0049b8
                      GError            **error)
0049b8
 {
0049b8
   GDataEntry *entry;
0049b8
   GDataEntry *ret_val = NULL;
0049b8
 
0049b8
-  entry = resolve (self, filename, NULL);
0049b8
+  entry = resolve (self, filename, out_path, NULL);
0049b8
   if (entry == NULL)
0049b8
     {
0049b8
       GError *local_error;
0049b8
@@ -718,7 +689,7 @@ resolve_and_rebuild (GVfsBackendGoogle  *self,
0049b8
         }
0049b8
 
0049b8
       local_error = NULL;
0049b8
-      entry = resolve (self, filename, &local_error);
0049b8
+      entry = resolve (self, filename, out_path, &local_error);
0049b8
       if (local_error != NULL)
0049b8
         {
0049b8
           g_propagate_error (error, local_error);
0049b8
@@ -737,6 +708,7 @@ resolve_dir_and_rebuild (GVfsBackendGoogle  *self,
0049b8
                          const gchar        *filename,
0049b8
                          GCancellable       *cancellable,
0049b8
                          gchar             **out_basename,
0049b8
+                         gchar             **out_path,
0049b8
                          GError            **error)
0049b8
 {
0049b8
   GDataEntry *parent;
0049b8
@@ -745,7 +717,7 @@ resolve_dir_and_rebuild (GVfsBackendGoogle  *self,
0049b8
   gchar *basename = NULL;
0049b8
 
0049b8
   local_error = NULL;
0049b8
-  parent = resolve_dir (self, filename, &basename, &local_error);
0049b8
+  parent = resolve_dir (self, filename, &basename, out_path, &local_error);
0049b8
   if (local_error != NULL)
0049b8
     {
0049b8
       if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY))
0049b8
@@ -767,7 +739,7 @@ resolve_dir_and_rebuild (GVfsBackendGoogle  *self,
0049b8
         }
0049b8
 
0049b8
       local_error = NULL;
0049b8
-      parent = resolve_dir (self, filename, &basename, &local_error);
0049b8
+      parent = resolve_dir (self, filename, &basename, out_path, &local_error);
0049b8
       if (local_error != NULL)
0049b8
         {
0049b8
           g_propagate_error (error, local_error);
0049b8
@@ -819,13 +791,12 @@ get_extension_offset (const char *title)
0049b8
 }
0049b8
 
0049b8
 static gchar *
0049b8
-generate_copy_name (GVfsBackendGoogle *self, GDataEntry *entry)
0049b8
+generate_copy_name (GVfsBackendGoogle *self, GDataEntry *entry, const gchar *entry_path)
0049b8
 {
0049b8
   GDataEntry *existing_entry;
0049b8
   GDataEntry *parent;
0049b8
   const gchar *id;
0049b8
   const gchar *title;
0049b8
-  gchar *entry_path = NULL;
0049b8
   gchar *extension = NULL;
0049b8
   gchar *extension_offset;
0049b8
   gchar *ret_val = NULL;
0049b8
@@ -833,11 +804,7 @@ generate_copy_name (GVfsBackendGoogle *self, GDataEntry *entry)
0049b8
 
0049b8
   title = gdata_entry_get_title (entry);
0049b8
 
0049b8
-  entry_path = get_entry_path (self, entry);
0049b8
-  if (entry_path == NULL)
0049b8
-    goto out;
0049b8
-
0049b8
-  parent = resolve_dir (self, entry_path, NULL, NULL);
0049b8
+  parent = resolve_dir (self, entry_path, NULL, NULL, NULL);
0049b8
   if (parent == NULL)
0049b8
     goto out;
0049b8
 
0049b8
@@ -859,7 +826,6 @@ generate_copy_name (GVfsBackendGoogle *self, GDataEntry *entry)
0049b8
  out:
0049b8
   if (ret_val == NULL)
0049b8
     ret_val = g_strdup (title);
0049b8
-  g_free (entry_path);
0049b8
   g_free (extension);
0049b8
   g_free (title_without_extension);
0049b8
   return ret_val;
0049b8
@@ -890,7 +856,7 @@ build_file_info (GVfsBackendGoogle      *self,
0049b8
                  GFileAttributeMatcher  *matcher,
0049b8
                  gboolean                is_symlink,
0049b8
                  const gchar            *symlink_name,
0049b8
-                 const gchar            *symlink_target,
0049b8
+                 const gchar            *entry_path,
0049b8
                  GError                **error)
0049b8
 {
0049b8
   GFileType file_type;
0049b8
@@ -968,7 +934,7 @@ build_file_info (GVfsBackendGoogle      *self,
0049b8
           file_type = G_FILE_TYPE_SYMBOLIC_LINK;
0049b8
         }
0049b8
 
0049b8
-      g_file_info_set_symlink_target (info, symlink_target);
0049b8
+      g_file_info_set_symlink_target (info, entry_path);
0049b8
     }
0049b8
 
0049b8
   if (content_type != NULL)
0049b8
@@ -1016,7 +982,7 @@ build_file_info (GVfsBackendGoogle      *self,
0049b8
   g_file_info_set_display_name (info, title);
0049b8
   g_file_info_set_edit_name (info, title);
0049b8
 
0049b8
-  copy_name = generate_copy_name (self, entry);
0049b8
+  copy_name = generate_copy_name (self, entry, entry_path);
0049b8
 
0049b8
   /* Sanitize copy-name by replacing slashes with dashes. This is
0049b8
    * what nautilus does (for desktop files).
0049b8
@@ -1116,6 +1082,7 @@ g_vfs_backend_google_copy (GVfsBackend           *_self,
0049b8
   gchar *destination_basename = NULL;
0049b8
   gchar *entry_path = NULL;
0049b8
   goffset size;
0049b8
+  gchar *parent_path = NULL;
0049b8
 
0049b8
   g_rec_mutex_lock (&self->mutex);
0049b8
   g_debug ("+ copy: %s -> %s, %d\n", source, destination, flags);
0049b8
@@ -1130,12 +1097,12 @@ g_vfs_backend_google_copy (GVfsBackend           *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  source_entry = resolve (self, source, NULL);
0049b8
+  source_entry = resolve (self, source, NULL, NULL);
0049b8
   if (source_entry == NULL)
0049b8
     needs_rebuild = TRUE;
0049b8
 
0049b8
   error = NULL;
0049b8
-  destination_parent = resolve_dir (self, destination, &destination_basename, &error);
0049b8
+  destination_parent = resolve_dir (self, destination, &destination_basename, &parent_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY))
0049b8
@@ -1158,7 +1125,7 @@ g_vfs_backend_google_copy (GVfsBackend           *_self,
0049b8
         }
0049b8
 
0049b8
       error = NULL;
0049b8
-      source_entry = resolve (self, source, &error);
0049b8
+      source_entry = resolve (self, source, NULL, &error);
0049b8
       if (error != NULL)
0049b8
         {
0049b8
           g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -1172,7 +1139,7 @@ g_vfs_backend_google_copy (GVfsBackend           *_self,
0049b8
           destination_basename = NULL;
0049b8
 
0049b8
           error = NULL;
0049b8
-          destination_parent = resolve_dir (self, destination, &destination_basename, &error);
0049b8
+          destination_parent = resolve_dir (self, destination, &destination_basename, &parent_path, &error);
0049b8
           if (error != NULL)
0049b8
             {
0049b8
               g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -1258,7 +1225,7 @@ g_vfs_backend_google_copy (GVfsBackend           *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  entry_path = get_entry_path (self, GDATA_ENTRY (new_entry));
0049b8
+  entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (new_entry)), NULL);
0049b8
   g_debug ("  new entry path: %s\n", entry_path);
0049b8
 
0049b8
   insert_entry (self, GDATA_ENTRY (new_entry));
0049b8
@@ -1277,6 +1244,7 @@ g_vfs_backend_google_copy (GVfsBackend           *_self,
0049b8
   g_clear_object (&new_entry);
0049b8
   g_free (destination_basename);
0049b8
   g_free (entry_path);
0049b8
+  g_free (parent_path);
0049b8
   g_debug ("- copy\n");
0049b8
   g_rec_mutex_unlock (&self->mutex);
0049b8
 }
0049b8
@@ -1306,7 +1274,7 @@ g_vfs_backend_google_create_dir_monitor (GVfsBackend          *_self,
0049b8
     }
0049b8
 
0049b8
   error = NULL;
0049b8
-  entry = resolve_and_rebuild (self, filename, cancellable, &error);
0049b8
+  entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -1314,7 +1282,6 @@ g_vfs_backend_google_create_dir_monitor (GVfsBackend          *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  entry_path = get_entry_path (self, entry);
0049b8
   g_debug ("  entry path: %s\n", entry_path);
0049b8
 
0049b8
   if (!GDATA_IS_DOCUMENTS_FOLDER (entry))
0049b8
@@ -1356,7 +1323,7 @@ g_vfs_backend_google_delete (GVfsBackend   *_self,
0049b8
   g_debug ("+ delete: %s\n", filename);
0049b8
 
0049b8
   error = NULL;
0049b8
-  entry = resolve_and_rebuild (self, filename, cancellable, &error);
0049b8
+  entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -1364,7 +1331,6 @@ g_vfs_backend_google_delete (GVfsBackend   *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  entry_path = get_entry_path (self, entry);
0049b8
   g_debug ("  entry path: %s\n", entry_path);
0049b8
 
0049b8
   if (entry == self->root)
0049b8
@@ -1420,7 +1386,8 @@ g_vfs_backend_google_enumerate (GVfsBackend           *_self,
0049b8
   GDataEntry *entry;
0049b8
   GError *error;
0049b8
   GHashTableIter iter;
0049b8
-  gchar *entry_path = NULL;
0049b8
+  char *parent_path;
0049b8
+  char *id;
0049b8
 
0049b8
   g_rec_mutex_lock (&self->mutex);
0049b8
   g_debug ("+ enumerate: %s\n", filename);
0049b8
@@ -1447,7 +1414,7 @@ g_vfs_backend_google_enumerate (GVfsBackend           *_self,
0049b8
     }
0049b8
 
0049b8
   error = NULL;
0049b8
-  entry = resolve (self, filename, &error);
0049b8
+  entry = resolve (self, filename, &parent_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -1455,9 +1422,6 @@ g_vfs_backend_google_enumerate (GVfsBackend           *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  entry_path = get_entry_path (self, entry);
0049b8
-  g_debug ("  entry path: %s\n", entry_path);
0049b8
-
0049b8
   if (!GDATA_IS_DOCUMENTS_FOLDER (entry))
0049b8
     {
0049b8
       g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY,_("The file is not a directory"));
0049b8
@@ -1466,39 +1430,37 @@ g_vfs_backend_google_enumerate (GVfsBackend           *_self,
0049b8
 
0049b8
   g_vfs_job_succeeded (G_VFS_JOB (job));
0049b8
 
0049b8
+  /* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
0049b8
+  id = g_strdup (gdata_entry_get_id (entry));
0049b8
+
0049b8
   g_hash_table_iter_init (&iter, self->entries);
0049b8
   while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry))
0049b8
     {
0049b8
-      gchar *path;
0049b8
+      DirEntriesKey *k;
0049b8
 
0049b8
-      path = get_entry_path (self, entry);
0049b8
-      g_debug ("  found entry: %s\n", path);
0049b8
-      if (path != NULL)
0049b8
+      k = dir_entries_key_new (gdata_entry_get_id (entry), id);
0049b8
+      if (g_hash_table_contains (self->dir_entries, k))
0049b8
         {
0049b8
-          gchar *parent_path;
0049b8
-
0049b8
-          parent_path = g_path_get_dirname (path);
0049b8
-          if (g_strcmp0 (entry_path, parent_path) == 0)
0049b8
-            {
0049b8
-              GFileInfo *info;
0049b8
-
0049b8
-              info = g_file_info_new ();
0049b8
-              build_file_info (self, entry, flags, info, matcher, FALSE, NULL, NULL, NULL);
0049b8
-              g_vfs_job_enumerate_add_info (job, info);
0049b8
-              g_object_unref (info);
0049b8
-            }
0049b8
-
0049b8
-          g_free (parent_path);
0049b8
+          GFileInfo *info;
0049b8
+          gchar *entry_path;
0049b8
+
0049b8
+          info = g_file_info_new ();
0049b8
+          entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (entry)), NULL);
0049b8
+          build_file_info (self, entry, flags, info, matcher, FALSE, NULL, entry_path, NULL);
0049b8
+          g_vfs_job_enumerate_add_info (job, info);
0049b8
+          g_object_unref (info);
0049b8
+          g_free (entry_path);
0049b8
         }
0049b8
 
0049b8
-      g_free (path);
0049b8
+      dir_entries_key_free (k);
0049b8
     }
0049b8
 
0049b8
   g_vfs_job_enumerate_done (job);
0049b8
 
0049b8
  out:
0049b8
-  g_free (entry_path);
0049b8
   g_debug ("- enumerate\n");
0049b8
+  g_free (parent_path);
0049b8
+  g_free (id);
0049b8
   g_rec_mutex_unlock (&self->mutex);
0049b8
 }
0049b8
 
0049b8
@@ -1532,7 +1494,7 @@ g_vfs_backend_google_make_directory (GVfsBackend          *_self,
0049b8
     }
0049b8
 
0049b8
   error = NULL;
0049b8
-  parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &error);
0049b8
+  parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &parent_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -1540,7 +1502,6 @@ g_vfs_backend_google_make_directory (GVfsBackend          *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  parent_path = get_entry_path (self, parent);
0049b8
   g_debug ("  parent path: %s\n", parent_path);
0049b8
 
0049b8
   summary_entry = g_hash_table_lookup (self->entries, basename);
0049b8
@@ -1574,7 +1535,7 @@ g_vfs_backend_google_make_directory (GVfsBackend          *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  entry_path = get_entry_path (self, GDATA_ENTRY (new_folder));
0049b8
+  entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (new_folder)), NULL);
0049b8
   g_debug ("  new entry path: %s\n", entry_path);
0049b8
 
0049b8
   insert_entry (self, GDATA_ENTRY (new_folder));
0049b8
@@ -1744,6 +1705,7 @@ g_vfs_backend_google_push (GVfsBackend           *_self,
0049b8
   const gchar *title;
0049b8
   gchar *destination_basename = NULL;
0049b8
   gchar *entry_path = NULL;
0049b8
+  gchar *parent_path = NULL;
0049b8
   goffset size;
0049b8
 
0049b8
   g_rec_mutex_lock (&self->mutex);
0049b8
@@ -1777,7 +1739,7 @@ g_vfs_backend_google_push (GVfsBackend           *_self,
0049b8
     }
0049b8
 
0049b8
   error = NULL;
0049b8
-  destination_parent = resolve_dir_and_rebuild (self, destination, cancellable, &destination_basename, &error);
0049b8
+  destination_parent = resolve_dir_and_rebuild (self, destination, cancellable, &destination_basename, &parent_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -1922,7 +1884,7 @@ g_vfs_backend_google_push (GVfsBackend           *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  entry_path = get_entry_path (self, GDATA_ENTRY (new_document));
0049b8
+  entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (new_document)), NULL);
0049b8
   g_debug ("  new entry path: %s\n", entry_path);
0049b8
 
0049b8
   if (needs_overwrite)
0049b8
@@ -1960,6 +1922,7 @@ g_vfs_backend_google_push (GVfsBackend           *_self,
0049b8
   g_clear_object (&ostream);
0049b8
   g_free (destination_basename);
0049b8
   g_free (entry_path);
0049b8
+  g_free (parent_path);
0049b8
   g_debug ("- push\n");
0049b8
   g_rec_mutex_unlock (&self->mutex);
0049b8
 }
0049b8
@@ -2065,7 +2028,7 @@ g_vfs_backend_google_query_info (GVfsBackend           *_self,
0049b8
   g_debug ("+ query_info: %s, %d\n", filename, flags);
0049b8
 
0049b8
   error = NULL;
0049b8
-  entry = resolve_and_rebuild (self, filename, cancellable, &error);
0049b8
+  entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -2073,7 +2036,6 @@ g_vfs_backend_google_query_info (GVfsBackend           *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  entry_path = get_entry_path (self, entry);
0049b8
   if (g_strcmp0 (entry_path, filename) != 0) /* volatile */
0049b8
     {
0049b8
       is_symlink = TRUE;
0049b8
@@ -2122,8 +2084,8 @@ g_vfs_backend_google_query_info_on_read (GVfsBackend           *_self,
0049b8
 
0049b8
   entry = g_object_get_data (G_OBJECT (stream), "g-vfs-backend-google-entry");
0049b8
   filename = g_object_get_data (G_OBJECT (stream), "g-vfs-backend-google-filename");
0049b8
+  entry_path = g_object_get_data (G_OBJECT (stream), "g-vfs-backend-google-entry-path");
0049b8
 
0049b8
-  entry_path = get_entry_path (self, entry);
0049b8
   if (g_strcmp0 (entry_path, filename) != 0) /* volatile */
0049b8
     {
0049b8
       is_symlink = TRUE;
0049b8
@@ -2152,7 +2114,6 @@ g_vfs_backend_google_query_info_on_read (GVfsBackend           *_self,
0049b8
   g_vfs_job_succeeded (G_VFS_JOB (job));
0049b8
 
0049b8
  out:
0049b8
-  g_free (entry_path);
0049b8
   g_free (symlink_name);
0049b8
   g_debug ("- query_info_on_read\n");
0049b8
 }
0049b8
@@ -2170,19 +2131,17 @@ g_vfs_backend_google_query_info_on_write (GVfsBackend           *_self,
0049b8
   GError *error;
0049b8
   WriteHandle *wh = (WriteHandle *) handle;
0049b8
   gboolean is_symlink = FALSE;
0049b8
-  gchar *entry_path = NULL;
0049b8
   gchar *symlink_name = NULL;
0049b8
 
0049b8
   g_debug ("+ query_info_on_write: %p\n", handle);
0049b8
 
0049b8
-  entry_path = get_entry_path (self, wh->document);
0049b8
-  if (g_strcmp0 (entry_path, wh->filename) != 0) /* volatile */
0049b8
+  if (g_strcmp0 (wh->entry_path, wh->filename) != 0) /* volatile */
0049b8
     {
0049b8
       is_symlink = TRUE;
0049b8
       symlink_name = g_path_get_basename (wh->filename);
0049b8
     }
0049b8
 
0049b8
-  g_debug ("  entry path: %s (%d)\n", entry_path, is_symlink);
0049b8
+  g_debug ("  entry path: %s (%d)\n", wh->entry_path, is_symlink);
0049b8
 
0049b8
   error = NULL;
0049b8
   build_file_info (self,
0049b8
@@ -2192,7 +2151,7 @@ g_vfs_backend_google_query_info_on_write (GVfsBackend           *_self,
0049b8
                    matcher,
0049b8
                    is_symlink,
0049b8
                    symlink_name,
0049b8
-                   entry_path,
0049b8
+                   wh->entry_path,
0049b8
                    &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
@@ -2204,7 +2163,6 @@ g_vfs_backend_google_query_info_on_write (GVfsBackend           *_self,
0049b8
   g_vfs_job_succeeded (G_VFS_JOB (job));
0049b8
 
0049b8
  out:
0049b8
-  g_free (entry_path);
0049b8
   g_free (symlink_name);
0049b8
   g_debug ("- query_info_on_write\n");
0049b8
   return TRUE;
0049b8
@@ -2231,7 +2189,7 @@ g_vfs_backend_google_open_for_read (GVfsBackend        *_self,
0049b8
   g_debug ("+ open_for_read: %s\n", filename);
0049b8
 
0049b8
   error = NULL;
0049b8
-  entry = resolve_and_rebuild (self, filename, cancellable, &error);
0049b8
+  entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -2239,7 +2197,6 @@ g_vfs_backend_google_open_for_read (GVfsBackend        *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  entry_path = get_entry_path (self, entry);
0049b8
   g_debug ("  entry path: %s\n", entry_path);
0049b8
 
0049b8
   if (GDATA_IS_DOCUMENTS_FOLDER (entry))
0049b8
@@ -2272,6 +2229,7 @@ g_vfs_backend_google_open_for_read (GVfsBackend        *_self,
0049b8
 
0049b8
   g_object_set_data_full (G_OBJECT (stream), "g-vfs-backend-google-entry", g_object_ref (entry), g_object_unref);
0049b8
   g_object_set_data_full (G_OBJECT (stream), "g-vfs-backend-google-filename", g_strdup (filename), g_free);
0049b8
+  g_object_set_data_full (G_OBJECT (stream), "g-vfs-backend-google-entry-path", g_strdup (entry_path), g_free);
0049b8
   g_vfs_job_open_for_read_set_handle (job, stream);
0049b8
   g_vfs_job_open_for_read_set_can_seek (job, TRUE);
0049b8
   g_vfs_job_succeeded (G_VFS_JOB (job));
0049b8
@@ -2419,7 +2377,7 @@ g_vfs_backend_google_set_display_name (GVfsBackend           *_self,
0049b8
   g_debug ("+ set_display_name: %s, %s\n", filename, display_name);
0049b8
 
0049b8
   error = NULL;
0049b8
-  entry = resolve_and_rebuild (self, filename, cancellable, &error);
0049b8
+  entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -2427,7 +2385,6 @@ g_vfs_backend_google_set_display_name (GVfsBackend           *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  entry_path = get_entry_path (self, entry);
0049b8
   g_debug ("  entry path: %s\n", entry_path);
0049b8
 
0049b8
   if (entry == self->root)
0049b8
@@ -2492,7 +2449,7 @@ g_vfs_backend_google_create (GVfsBackend         *_self,
0049b8
     }
0049b8
 
0049b8
   error = NULL;
0049b8
-  parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &error);
0049b8
+  parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &parent_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -2500,7 +2457,6 @@ g_vfs_backend_google_create (GVfsBackend         *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  parent_path = get_entry_path (self, parent);
0049b8
   g_debug ("  parent path: %s\n", parent_path);
0049b8
 
0049b8
   existing_entry = resolve_child (self, parent, basename);
0049b8
@@ -2538,13 +2494,13 @@ g_vfs_backend_google_create (GVfsBackend         *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  entry_path = get_entry_path (self, GDATA_ENTRY (new_document));
0049b8
+  entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (new_document)), NULL);
0049b8
   g_debug ("  new entry path: %s\n", entry_path);
0049b8
 
0049b8
   insert_entry (self, GDATA_ENTRY (new_document));
0049b8
   g_hash_table_foreach (self->monitors, emit_create_event, entry_path);
0049b8
 
0049b8
-  handle = write_handle_new (GDATA_ENTRY (new_document), NULL, filename);
0049b8
+  handle = write_handle_new (GDATA_ENTRY (new_document), NULL, filename, entry_path);
0049b8
   g_vfs_job_open_for_write_set_handle (job, handle);
0049b8
   g_vfs_job_succeeded (G_VFS_JOB (job));
0049b8
 
0049b8
@@ -2602,7 +2558,7 @@ g_vfs_backend_google_replace (GVfsBackend         *_self,
0049b8
     }
0049b8
 
0049b8
   error = NULL;
0049b8
-  parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &error);
0049b8
+  parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &parent_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -2610,7 +2566,6 @@ g_vfs_backend_google_replace (GVfsBackend         *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  parent_path = get_entry_path (self, parent);
0049b8
   g_debug ("  parent path: %s\n", parent_path);
0049b8
 
0049b8
   existing_entry = resolve_child (self, parent, basename);
0049b8
@@ -2639,7 +2594,7 @@ g_vfs_backend_google_replace (GVfsBackend         *_self,
0049b8
     {
0049b8
       const gchar *title;
0049b8
 
0049b8
-      entry_path = get_entry_path (self, existing_entry);
0049b8
+      entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (existing_entry), NULL);
0049b8
       g_debug ("  existing entry path: %s\n", entry_path);
0049b8
 
0049b8
       title = gdata_entry_get_title (existing_entry);
0049b8
@@ -2660,7 +2615,7 @@ g_vfs_backend_google_replace (GVfsBackend         *_self,
0049b8
           goto out;
0049b8
         }
0049b8
 
0049b8
-      handle = write_handle_new (NULL, stream, filename);
0049b8
+      handle = write_handle_new (NULL, stream, filename, entry_path);
0049b8
     }
0049b8
   else
0049b8
     {
0049b8
@@ -2681,13 +2636,13 @@ g_vfs_backend_google_replace (GVfsBackend         *_self,
0049b8
           goto out;
0049b8
         }
0049b8
 
0049b8
-      entry_path = get_entry_path (self, GDATA_ENTRY (new_document));
0049b8
+      entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (new_document)), NULL);
0049b8
       g_debug ("  new entry path: %s\n", entry_path);
0049b8
 
0049b8
       insert_entry (self, GDATA_ENTRY (new_document));
0049b8
       g_hash_table_foreach (self->monitors, emit_create_event, entry_path);
0049b8
 
0049b8
-      handle = write_handle_new (GDATA_ENTRY (new_document), NULL, filename);
0049b8
+      handle = write_handle_new (GDATA_ENTRY (new_document), NULL, filename, entry_path);
0049b8
     }
0049b8
 
0049b8
   g_vfs_job_open_for_write_set_handle (job, handle);
0049b8
@@ -2718,7 +2673,6 @@ g_vfs_backend_google_write (GVfsBackend       *_self,
0049b8
   GCancellable *cancellable = G_VFS_JOB (job)->cancellable;
0049b8
   GError *error;
0049b8
   WriteHandle *wh = (WriteHandle *) handle;
0049b8
-  gchar *entry_path = NULL;
0049b8
   gssize nwrite;
0049b8
 
0049b8
   g_debug ("+ write: %p\n", handle);
0049b8
@@ -2751,9 +2705,7 @@ g_vfs_backend_google_write (GVfsBackend       *_self,
0049b8
     }
0049b8
 
0049b8
   g_debug ("  writing to stream: %p\n", wh->stream);
0049b8
-
0049b8
-  entry_path = get_entry_path (self, wh->document);
0049b8
-  g_debug ("  entry path: %s\n", entry_path);
0049b8
+  g_debug ("  entry path: %s\n", wh->entry_path);
0049b8
 
0049b8
   error = NULL;
0049b8
   nwrite = g_output_stream_write (G_OUTPUT_STREAM (wh->stream),
0049b8
@@ -2768,12 +2720,11 @@ g_vfs_backend_google_write (GVfsBackend       *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  g_hash_table_foreach (self->monitors, emit_changed_event, entry_path);
0049b8
+  g_hash_table_foreach (self->monitors, emit_changed_event, wh->entry_path);
0049b8
   g_vfs_job_write_set_written_size (job, (gsize) nwrite);
0049b8
   g_vfs_job_succeeded (G_VFS_JOB (job));
0049b8
 
0049b8
  out:
0049b8
-  g_free (entry_path);
0049b8
   g_debug ("- write\n");
0049b8
 }
0049b8
 
0049b8
@@ -2789,7 +2740,6 @@ g_vfs_backend_google_close_write (GVfsBackend       *_self,
0049b8
   GDataDocumentsDocument *new_document = NULL;
0049b8
   GError *error;
0049b8
   WriteHandle *wh = (WriteHandle *) handle;
0049b8
-  gchar *entry_path = NULL;
0049b8
 
0049b8
   g_debug ("+ close_write: %p\n", handle);
0049b8
 
0049b8
@@ -2820,18 +2770,16 @@ g_vfs_backend_google_close_write (GVfsBackend       *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  entry_path = get_entry_path (self, GDATA_ENTRY (new_document));
0049b8
-  g_debug ("  new entry path: %s\n", entry_path);
0049b8
+  g_debug ("  new entry path: %s\n", wh->entry_path);
0049b8
 
0049b8
   remove_entry (self, wh->document);
0049b8
   insert_entry (self, GDATA_ENTRY (new_document));
0049b8
-  g_hash_table_foreach (self->monitors, emit_changes_done_event, entry_path);
0049b8
+  g_hash_table_foreach (self->monitors, emit_changes_done_event, wh->entry_path);
0049b8
   g_vfs_job_succeeded (G_VFS_JOB (job));
0049b8
 
0049b8
  out:
0049b8
   g_clear_object (&new_document);
0049b8
   write_handle_free (wh);
0049b8
-  g_free (entry_path);
0049b8
   g_debug ("- close_write\n");
0049b8
 }
0049b8
 
0049b8
-- 
0049b8
2.36.1
0049b8
0049b8
0049b8
From 77610a76ae671ec340d100791043f7b3de4bbaf4 Mon Sep 17 00:00:00 2001
0049b8
From: Ondrej Holy <oholy@redhat.com>
0049b8
Date: Wed, 1 Aug 2018 11:21:45 +0200
0049b8
Subject: [PATCH 07/14] google: Remove file just from concrete parent
0049b8
0049b8
Files with multiple parents are currently removed from all parents.
0049b8
This is unexpected and may cause data loss, because it is not obvious
0049b8
that it is one file. Let's remove the file just from requested folder.
0049b8
---
0049b8
 daemon/gvfsbackendgoogle.c | 37 +++++++++++++++++++++++++++++++++----
0049b8
 1 file changed, 33 insertions(+), 4 deletions(-)
0049b8
0049b8
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
0049b8
index 7f812448..45a48079 100644
0049b8
--- a/daemon/gvfsbackendgoogle.c
0049b8
+++ b/daemon/gvfsbackendgoogle.c
0049b8
@@ -1314,10 +1314,12 @@ g_vfs_backend_google_delete (GVfsBackend   *_self,
0049b8
 {
0049b8
   GVfsBackendGoogle *self = G_VFS_BACKEND_GOOGLE (_self);
0049b8
   GCancellable *cancellable = G_VFS_JOB (job)->cancellable;
0049b8
-  GDataAuthorizationDomain *auth_domain;
0049b8
   GDataEntry *entry;
0049b8
+  GDataEntry *parent;
0049b8
+  GDataDocumentsEntry *new_entry = NULL;
0049b8
   GError *error;
0049b8
   gchar *entry_path = NULL;
0049b8
+  GList *parent_ids;
0049b8
 
0049b8
   g_rec_mutex_lock (&self->mutex);
0049b8
   g_debug ("+ delete: %s\n", filename);
0049b8
@@ -1331,6 +1333,14 @@ g_vfs_backend_google_delete (GVfsBackend   *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
+  parent = resolve_dir (self, filename, cancellable, NULL, NULL, &error);
0049b8
+  if (error != NULL)
0049b8
+    {
0049b8
+      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
+      g_error_free (error);
0049b8
+      goto out;
0049b8
+    }
0049b8
+
0049b8
   g_debug ("  entry path: %s\n", entry_path);
0049b8
 
0049b8
   if (entry == self->root)
0049b8
@@ -1339,10 +1349,26 @@ g_vfs_backend_google_delete (GVfsBackend   *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  auth_domain = gdata_documents_service_get_primary_authorization_domain ();
0049b8
+  /* It has to be removed before the actual call to properly invalidate dir entries. */
0049b8
+  g_object_ref (entry);
0049b8
+  remove_entry (self, entry);
0049b8
 
0049b8
   error = NULL;
0049b8
-  gdata_service_delete_entry (GDATA_SERVICE (self->service), auth_domain, entry, cancellable, &error);
0049b8
+
0049b8
+  /* gdata_documents_service_remove_entry_from_folder seems doesn't work for one parent. */
0049b8
+  parent_ids = get_parent_ids (self, entry);
0049b8
+  if (g_list_length (parent_ids) > 1)
0049b8
+    {
0049b8
+      new_entry = gdata_documents_service_remove_entry_from_folder (self->service, GDATA_DOCUMENTS_ENTRY (entry), GDATA_DOCUMENTS_FOLDER (parent), cancellable, &error);
0049b8
+    }
0049b8
+  else
0049b8
+    {
0049b8
+      GDataAuthorizationDomain *auth_domain;
0049b8
+
0049b8
+      auth_domain = gdata_documents_service_get_primary_authorization_domain ();
0049b8
+      gdata_service_delete_entry (GDATA_SERVICE (self->service), auth_domain, entry, cancellable, &error);
0049b8
+    }
0049b8
+
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       sanitize_error (&error);
0049b8
@@ -1351,11 +1377,14 @@ g_vfs_backend_google_delete (GVfsBackend   *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  remove_entry (self, entry);
0049b8
+  if (new_entry)
0049b8
+    insert_entry (self, GDATA_ENTRY (new_entry));
0049b8
   g_hash_table_foreach (self->monitors, emit_delete_event, entry_path);
0049b8
   g_vfs_job_succeeded (G_VFS_JOB (job));
0049b8
 
0049b8
  out:
0049b8
+  g_object_unref (entry);
0049b8
+  g_clear_object (&new_entry);
0049b8
   g_free (entry_path);
0049b8
   g_debug ("- delete\n");
0049b8
   g_rec_mutex_unlock (&self->mutex);
0049b8
-- 
0049b8
2.36.1
0049b8
0049b8
0049b8
From 454e38f9a96505ea5ecaa6a95a8658d58caf24a1 Mon Sep 17 00:00:00 2001
0049b8
From: Ondrej Holy <oholy@redhat.com>
0049b8
Date: Mon, 30 Jul 2018 16:42:31 +0200
0049b8
Subject: [PATCH 08/14] google: Rework cache for better performance
0049b8
0049b8
The backend is totally unusable if you have too many files on your
0049b8
Drive. This happens because the backend preloads the whole Drive's
0049b8
metadata. Let's build the cache incrementaly per folders.
0049b8
0049b8
As a result, the backend works smoothly regardless of the total
0049b8
number of Drive files, because the total number of transmitted data
0049b8
is significantly reduced. On the other hand, more requests is done
0049b8
to Drive, but the Drive quotas seem big enough.
0049b8
---
0049b8
 daemon/gvfsbackendgoogle.c | 404 +++++++++++++++----------------------
0049b8
 1 file changed, 166 insertions(+), 238 deletions(-)
0049b8
0049b8
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
0049b8
index 45a48079..bf50fef6 100644
0049b8
--- a/daemon/gvfsbackendgoogle.c
0049b8
+++ b/daemon/gvfsbackendgoogle.c
0049b8
@@ -55,15 +55,13 @@ struct _GVfsBackendGoogle
0049b8
   GVfsBackend parent;
0049b8
   GDataDocumentsService *service;
0049b8
   GDataEntry *root;
0049b8
-  GHashTable *entries;
0049b8
-  GHashTable *dir_entries;
0049b8
+  GHashTable *entries; /* gchar *entry_id -> GDataEntry */
0049b8
+  GHashTable *dir_entries; /* DirEntriesKey -> GDataEntry */
0049b8
   GHashTable *monitors;
0049b8
   GList *dir_collisions;
0049b8
   GRecMutex mutex; /* guards cache */
0049b8
   GoaClient *client;
0049b8
-  gboolean entries_stale;
0049b8
   gchar *account_identity;
0049b8
-  guint entries_stale_timeout;
0049b8
 };
0049b8
 
0049b8
 struct _GVfsBackendGoogleClass
0049b8
@@ -104,6 +102,7 @@ typedef struct
0049b8
 
0049b8
 static GDataEntry *resolve_dir (GVfsBackendGoogle  *self,
0049b8
                                 const gchar        *filename,
0049b8
+                                GCancellable       *cancellable,
0049b8
                                 gchar             **out_basename,
0049b8
                                 gchar             **out_path,
0049b8
                                 GError            **error);
0049b8
@@ -434,12 +433,19 @@ static void
0049b8
 insert_entry (GVfsBackendGoogle *self,
0049b8
               GDataEntry        *entry)
0049b8
 {
0049b8
+  gint64 *timestamp;
0049b8
+
0049b8
+  timestamp = g_new (gint64, 1);
0049b8
+  *timestamp =  g_get_real_time ();
0049b8
+  g_object_set_data_full (G_OBJECT (entry), "timestamp", timestamp, g_free);
0049b8
+
0049b8
   insert_entry_full (self, entry, TRUE);
0049b8
 }
0049b8
 
0049b8
 static void
0049b8
-remove_entry (GVfsBackendGoogle *self,
0049b8
-              GDataEntry        *entry)
0049b8
+remove_entry_full (GVfsBackendGoogle *self,
0049b8
+                   GDataEntry        *entry,
0049b8
+                   gboolean           restore_dir_collisions)
0049b8
 {
0049b8
   DirEntriesKey *k;
0049b8
   GList *l;
0049b8
@@ -474,17 +480,20 @@ remove_entry (GVfsBackendGoogle *self,
0049b8
           g_object_unref (entry);
0049b8
         }
0049b8
 
0049b8
-      for (l = self->dir_collisions; l != NULL; l = l->next)
0049b8
+      if (restore_dir_collisions)
0049b8
         {
0049b8
-          GDataEntry *colliding_entry = GDATA_ENTRY (l->data);
0049b8
-
0049b8
-          if (insert_entry_full (self, colliding_entry, FALSE))
0049b8
+          for (l = self->dir_collisions; l != NULL; l = l->next)
0049b8
             {
0049b8
-              self->dir_collisions = g_list_remove_link (self->dir_collisions, l);
0049b8
-              g_debug ("  remove_entry: Restored %p\n", colliding_entry);
0049b8
-              g_list_free (l);
0049b8
-              g_object_unref (colliding_entry);
0049b8
-              break;
0049b8
+              GDataEntry *colliding_entry = GDATA_ENTRY (l->data);
0049b8
+
0049b8
+              if (insert_entry_full (self, colliding_entry, FALSE))
0049b8
+                {
0049b8
+                  self->dir_collisions = g_list_remove_link (self->dir_collisions, l);
0049b8
+                  g_debug ("  remove_entry: Restored %p\n", colliding_entry);
0049b8
+                  g_list_free (l);
0049b8
+                  g_object_unref (colliding_entry);
0049b8
+                  break;
0049b8
+                }
0049b8
             }
0049b8
         }
0049b8
     }
0049b8
@@ -492,16 +501,85 @@ remove_entry (GVfsBackendGoogle *self,
0049b8
 }
0049b8
 
0049b8
 static void
0049b8
-rebuild_entries (GVfsBackendGoogle  *self,
0049b8
-                 GCancellable       *cancellable,
0049b8
-                 GError            **error)
0049b8
+remove_entry (GVfsBackendGoogle *self,
0049b8
+              GDataEntry        *entry)
0049b8
+{
0049b8
+  remove_entry_full (self, entry, TRUE);
0049b8
+}
0049b8
+
0049b8
+static void
0049b8
+remove_dir (GVfsBackendGoogle *self,
0049b8
+            GDataEntry        *parent)
0049b8
+{
0049b8
+  GHashTableIter iter;
0049b8
+  GDataEntry *entry;
0049b8
+  gchar *parent_id;
0049b8
+  GList *l;
0049b8
+
0049b8
+  /* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
0049b8
+  parent_id = g_strdup (gdata_entry_get_id (parent));
0049b8
+
0049b8
+  g_hash_table_iter_init (&iter, self->entries);
0049b8
+  while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry))
0049b8
+    {
0049b8
+      DirEntriesKey *k;
0049b8
+
0049b8
+      k = dir_entries_key_new (gdata_entry_get_id (entry), parent_id);
0049b8
+      if (g_hash_table_contains (self->dir_entries, k))
0049b8
+        {
0049b8
+          g_object_ref (entry);
0049b8
+          g_hash_table_iter_remove (&iter);
0049b8
+          remove_entry_full (self, entry, FALSE);
0049b8
+          g_object_unref (entry);
0049b8
+        }
0049b8
+
0049b8
+      dir_entries_key_free (k);
0049b8
+    }
0049b8
+
0049b8
+  for (l = self->dir_collisions; l != NULL; l = l->next)
0049b8
+  {
0049b8
+    GDataEntry *colliding_entry = GDATA_ENTRY (l->data);
0049b8
+
0049b8
+    if (insert_entry_full (self, colliding_entry, FALSE))
0049b8
+      {
0049b8
+        self->dir_collisions = g_list_remove_link (self->dir_collisions, l);
0049b8
+        g_debug ("  remove_entry: Restored %p\n", colliding_entry);
0049b8
+        g_list_free (l);
0049b8
+        g_object_unref (colliding_entry);
0049b8
+        break;
0049b8
+      }
0049b8
+  }
0049b8
+
0049b8
+  g_free (parent_id);
0049b8
+}
0049b8
+
0049b8
+static gboolean
0049b8
+is_entry_valid (GDataEntry *entry)
0049b8
+{
0049b8
+  gint64 *timestamp;
0049b8
+
0049b8
+  timestamp = g_object_get_data (G_OBJECT (entry), "timestamp");
0049b8
+  return (g_get_real_time () - *timestamp < REBUILD_ENTRIES_TIMEOUT * G_USEC_PER_SEC);
0049b8
+}
0049b8
+
0049b8
+static void
0049b8
+rebuild_dir (GVfsBackendGoogle  *self,
0049b8
+             GDataEntry         *parent,
0049b8
+             GCancellable       *cancellable,
0049b8
+             GError            **error)
0049b8
 {
0049b8
   GDataDocumentsFeed *feed = NULL;
0049b8
   GDataDocumentsQuery *query = NULL;
0049b8
   gboolean succeeded_once = FALSE;
0049b8
+  gchar *search;
0049b8
+  const gchar *parent_id;
0049b8
+
0049b8
+  parent_id = gdata_entry_get_id (parent);
0049b8
 
0049b8
-  query = gdata_documents_query_new_with_limits (NULL, 1, MAX_RESULTS);
0049b8
+  search = g_strdup_printf ("'%s' in parents", parent_id);
0049b8
+  query = gdata_documents_query_new_with_limits (search, 1, MAX_RESULTS);
0049b8
   gdata_documents_query_set_show_folders (query, TRUE);
0049b8
+  g_free (search);
0049b8
 
0049b8
   while (TRUE)
0049b8
     {
0049b8
@@ -515,18 +593,13 @@ rebuild_entries (GVfsBackendGoogle  *self,
0049b8
         {
0049b8
           sanitize_error (&local_error);
0049b8
           g_propagate_error (error, local_error);
0049b8
-          self->entries_stale = TRUE;
0049b8
 
0049b8
           goto out;
0049b8
         }
0049b8
 
0049b8
       if (!succeeded_once)
0049b8
         {
0049b8
-          g_hash_table_remove_all (self->entries);
0049b8
-          g_hash_table_remove_all (self->dir_entries);
0049b8
-
0049b8
-          g_list_free_full (self->dir_collisions, g_object_unref);
0049b8
-          self->dir_collisions = NULL;
0049b8
+          remove_dir (self, parent);
0049b8
 
0049b8
           succeeded_once = TRUE;
0049b8
         }
0049b8
@@ -545,8 +618,6 @@ rebuild_entries (GVfsBackendGoogle  *self,
0049b8
       g_clear_object (&feed);
0049b8
     }
0049b8
 
0049b8
-  self->entries_stale = FALSE;
0049b8
-
0049b8
  out:
0049b8
   g_clear_object (&feed);
0049b8
   g_clear_object (&query);
0049b8
@@ -555,24 +626,48 @@ rebuild_entries (GVfsBackendGoogle  *self,
0049b8
 /* ---------------------------------------------------------------------------------------------------- */
0049b8
 
0049b8
 static GDataEntry *
0049b8
-resolve_child (GVfsBackendGoogle *self,
0049b8
-               GDataEntry        *parent,
0049b8
-               const gchar       *basename)
0049b8
+resolve_child (GVfsBackendGoogle  *self,
0049b8
+               GDataEntry         *parent,
0049b8
+               const gchar        *basename,
0049b8
+               GCancellable       *cancellable,
0049b8
+               GError            **error)
0049b8
 {
0049b8
   DirEntriesKey *k;
0049b8
   GDataEntry *entry;
0049b8
   const gchar *parent_id;
0049b8
+  GError *local_error = NULL;
0049b8
 
0049b8
   parent_id = gdata_entry_get_id (parent);
0049b8
   k = dir_entries_key_new (basename, parent_id);
0049b8
   entry = g_hash_table_lookup (self->dir_entries, k);
0049b8
+  // TODO: Rebuild only if dir listing is not valid
0049b8
+  if (entry == NULL || !is_entry_valid (entry))
0049b8
+    {
0049b8
+      rebuild_dir (self, parent, cancellable, &local_error);
0049b8
+      if (local_error != NULL)
0049b8
+        {
0049b8
+          g_propagate_error (error, local_error);
0049b8
+          goto out;
0049b8
+        }
0049b8
+
0049b8
+      entry = g_hash_table_lookup (self->dir_entries, k);
0049b8
+      if (entry == NULL)
0049b8
+        {
0049b8
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory"));
0049b8
+          goto out;
0049b8
+        }
0049b8
+    }
0049b8
+
0049b8
+ out:
0049b8
   dir_entries_key_free (k);
0049b8
+
0049b8
   return entry;
0049b8
 }
0049b8
 
0049b8
 static GDataEntry *
0049b8
 resolve (GVfsBackendGoogle  *self,
0049b8
          const gchar        *filename,
0049b8
+         GCancellable       *cancellable,
0049b8
          gchar             **out_path,
0049b8
          GError            **error)
0049b8
 {
0049b8
@@ -581,6 +676,8 @@ resolve (GVfsBackendGoogle  *self,
0049b8
   GError *local_error;
0049b8
   gchar *basename = NULL;
0049b8
 
0049b8
+  g_assert (filename && filename[0] == '/');
0049b8
+
0049b8
   if (g_strcmp0 (filename, "/") == 0)
0049b8
     {
0049b8
       ret_val = self->root;
0049b8
@@ -592,17 +689,17 @@ resolve (GVfsBackendGoogle  *self,
0049b8
     }
0049b8
 
0049b8
   local_error = NULL;
0049b8
-  parent = resolve_dir (self, filename, &basename, out_path, &local_error);
0049b8
+  parent = resolve_dir (self, filename, cancellable, &basename, out_path, &local_error);
0049b8
   if (local_error != NULL)
0049b8
     {
0049b8
       g_propagate_error (error, local_error);
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  ret_val = resolve_child (self, parent, basename);
0049b8
+  ret_val = resolve_child (self, parent, basename, cancellable, &local_error);
0049b8
   if (ret_val == NULL)
0049b8
     {
0049b8
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory"));
0049b8
+      g_propagate_error (error, local_error);
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
@@ -622,6 +719,7 @@ resolve (GVfsBackendGoogle  *self,
0049b8
 static GDataEntry *
0049b8
 resolve_dir (GVfsBackendGoogle  *self,
0049b8
              const gchar        *filename,
0049b8
+             GCancellable       *cancellable,
0049b8
              gchar             **out_basename,
0049b8
              gchar             **out_path,
0049b8
              GError            **error)
0049b8
@@ -636,7 +734,7 @@ resolve_dir (GVfsBackendGoogle  *self,
0049b8
   parent_path = g_path_get_dirname (filename);
0049b8
 
0049b8
   local_error = NULL;
0049b8
-  parent = resolve (self, parent_path, out_path, &local_error);
0049b8
+  parent = resolve (self, parent_path, cancellable, out_path, &local_error);
0049b8
   if (local_error != NULL)
0049b8
     {
0049b8
       g_propagate_error (error, local_error);
0049b8
@@ -665,103 +763,6 @@ resolve_dir (GVfsBackendGoogle  *self,
0049b8
 
0049b8
 /* ---------------------------------------------------------------------------------------------------- */
0049b8
 
0049b8
-static GDataEntry *
0049b8
-resolve_and_rebuild (GVfsBackendGoogle  *self,
0049b8
-                     const gchar        *filename,
0049b8
-                     GCancellable       *cancellable,
0049b8
-                     gchar             **out_path,
0049b8
-                     GError            **error)
0049b8
-{
0049b8
-  GDataEntry *entry;
0049b8
-  GDataEntry *ret_val = NULL;
0049b8
-
0049b8
-  entry = resolve (self, filename, out_path, NULL);
0049b8
-  if (entry == NULL)
0049b8
-    {
0049b8
-      GError *local_error;
0049b8
-
0049b8
-      local_error = NULL;
0049b8
-      rebuild_entries (self, cancellable, &local_error);
0049b8
-      if (local_error != NULL)
0049b8
-        {
0049b8
-          g_propagate_error (error, local_error);
0049b8
-          goto out;
0049b8
-        }
0049b8
-
0049b8
-      local_error = NULL;
0049b8
-      entry = resolve (self, filename, out_path, &local_error);
0049b8
-      if (local_error != NULL)
0049b8
-        {
0049b8
-          g_propagate_error (error, local_error);
0049b8
-          goto out;
0049b8
-        }
0049b8
-    }
0049b8
-
0049b8
-  ret_val = entry;
0049b8
-
0049b8
- out:
0049b8
-  return ret_val;
0049b8
-}
0049b8
-
0049b8
-static GDataEntry *
0049b8
-resolve_dir_and_rebuild (GVfsBackendGoogle  *self,
0049b8
-                         const gchar        *filename,
0049b8
-                         GCancellable       *cancellable,
0049b8
-                         gchar             **out_basename,
0049b8
-                         gchar             **out_path,
0049b8
-                         GError            **error)
0049b8
-{
0049b8
-  GDataEntry *parent;
0049b8
-  GDataEntry *ret_val = NULL;
0049b8
-  GError *local_error;
0049b8
-  gchar *basename = NULL;
0049b8
-
0049b8
-  local_error = NULL;
0049b8
-  parent = resolve_dir (self, filename, &basename, out_path, &local_error);
0049b8
-  if (local_error != NULL)
0049b8
-    {
0049b8
-      if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY))
0049b8
-        {
0049b8
-          g_propagate_error (error, local_error);
0049b8
-          goto out;
0049b8
-        }
0049b8
-      else
0049b8
-        {
0049b8
-          g_error_free (local_error);
0049b8
-        }
0049b8
-
0049b8
-      local_error = NULL;
0049b8
-      rebuild_entries (self, cancellable, &local_error);
0049b8
-      if (local_error != NULL)
0049b8
-        {
0049b8
-          g_propagate_error (error, local_error);
0049b8
-          goto out;
0049b8
-        }
0049b8
-
0049b8
-      local_error = NULL;
0049b8
-      parent = resolve_dir (self, filename, &basename, out_path, &local_error);
0049b8
-      if (local_error != NULL)
0049b8
-        {
0049b8
-          g_propagate_error (error, local_error);
0049b8
-          goto out;
0049b8
-        }
0049b8
-    }
0049b8
-
0049b8
-  if (out_basename != NULL)
0049b8
-    {
0049b8
-      *out_basename = basename;
0049b8
-      basename = NULL;
0049b8
-    }
0049b8
-
0049b8
-  ret_val = parent;
0049b8
-
0049b8
- out:
0049b8
-  g_free (basename);
0049b8
-  return ret_val;
0049b8
-}
0049b8
-
0049b8
-/* ---------------------------------------------------------------------------------------------------- */
0049b8
-
0049b8
 static char *
0049b8
 get_extension_offset (const char *title)
0049b8
 {
0049b8
@@ -804,11 +805,11 @@ generate_copy_name (GVfsBackendGoogle *self, GDataEntry *entry, const gchar *ent
0049b8
 
0049b8
   title = gdata_entry_get_title (entry);
0049b8
 
0049b8
-  parent = resolve_dir (self, entry_path, NULL, NULL, NULL);
0049b8
+  parent = resolve_dir (self, entry_path, NULL, NULL, NULL, NULL);
0049b8
   if (parent == NULL)
0049b8
     goto out;
0049b8
 
0049b8
-  existing_entry = resolve_child (self, parent, title);
0049b8
+  existing_entry = resolve_child (self, parent, title, NULL, NULL);
0049b8
   if (existing_entry == entry)
0049b8
     goto out;
0049b8
 
0049b8
@@ -1074,8 +1075,6 @@ g_vfs_backend_google_copy (GVfsBackend           *_self,
0049b8
   GDataEntry *source_entry;
0049b8
   GError *error;
0049b8
   GType source_entry_type;
0049b8
-  gboolean needs_rebuild = FALSE;
0049b8
-  gboolean destination_not_directory = FALSE;
0049b8
   const gchar *etag;
0049b8
   const gchar *id;
0049b8
   const gchar *summary;
0049b8
@@ -1097,56 +1096,21 @@ g_vfs_backend_google_copy (GVfsBackend           *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  source_entry = resolve (self, source, NULL, NULL);
0049b8
-  if (source_entry == NULL)
0049b8
-    needs_rebuild = TRUE;
0049b8
-
0049b8
   error = NULL;
0049b8
-  destination_parent = resolve_dir (self, destination, &destination_basename, &parent_path, &error);
0049b8
+  source_entry = resolve (self, source, cancellable, NULL, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
-      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY))
0049b8
-        destination_not_directory = TRUE;
0049b8
-      else
0049b8
-        needs_rebuild = TRUE;
0049b8
-
0049b8
+      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
       g_error_free (error);
0049b8
+      goto out;
0049b8
     }
0049b8
 
0049b8
-  if (needs_rebuild)
0049b8
+  destination_parent = resolve_dir (self, destination, cancellable, &destination_basename, &parent_path, &error);
0049b8
+  if (error != NULL)
0049b8
     {
0049b8
-      error = NULL;
0049b8
-      rebuild_entries (self, cancellable, &error);
0049b8
-      if (error != NULL)
0049b8
-        {
0049b8
-          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
-          g_error_free (error);
0049b8
-          goto out;
0049b8
-        }
0049b8
-
0049b8
-      error = NULL;
0049b8
-      source_entry = resolve (self, source, NULL, &error);
0049b8
-      if (error != NULL)
0049b8
-        {
0049b8
-          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
-          g_error_free (error);
0049b8
-          goto out;
0049b8
-        }
0049b8
-
0049b8
-      if (!destination_not_directory)
0049b8
-        {
0049b8
-          g_free (destination_basename);
0049b8
-          destination_basename = NULL;
0049b8
-
0049b8
-          error = NULL;
0049b8
-          destination_parent = resolve_dir (self, destination, &destination_basename, &parent_path, &error);
0049b8
-          if (error != NULL)
0049b8
-            {
0049b8
-              g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
-              g_error_free (error);
0049b8
-              goto out;
0049b8
-            }
0049b8
-        }
0049b8
+      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
+      g_error_free (error);
0049b8
+      goto out;
0049b8
     }
0049b8
 
0049b8
   etag = gdata_entry_get_etag (source_entry);
0049b8
@@ -1165,13 +1129,7 @@ g_vfs_backend_google_copy (GVfsBackend           *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  if (destination_not_directory)
0049b8
-    {
0049b8
-      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY, _("The file is not a directory"));
0049b8
-      goto out;
0049b8
-    }
0049b8
-
0049b8
-  existing_entry = resolve_child (self, destination_parent, destination_basename);
0049b8
+  existing_entry = resolve_child (self, destination_parent, destination_basename, cancellable, NULL);
0049b8
   if (existing_entry != NULL)
0049b8
     {
0049b8
       if (flags & G_FILE_COPY_OVERWRITE)
0049b8
@@ -1274,7 +1232,7 @@ g_vfs_backend_google_create_dir_monitor (GVfsBackend          *_self,
0049b8
     }
0049b8
 
0049b8
   error = NULL;
0049b8
-  entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error);
0049b8
+  entry = resolve (self, filename, cancellable, &entry_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -1325,7 +1283,7 @@ g_vfs_backend_google_delete (GVfsBackend   *_self,
0049b8
   g_debug ("+ delete: %s\n", filename);
0049b8
 
0049b8
   error = NULL;
0049b8
-  entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error);
0049b8
+  entry = resolve (self, filename, cancellable, &entry_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -1392,17 +1350,6 @@ g_vfs_backend_google_delete (GVfsBackend   *_self,
0049b8
 
0049b8
 /* ---------------------------------------------------------------------------------------------------- */
0049b8
 
0049b8
-static gboolean
0049b8
-rebuild_entries_timeout_cb (gpointer user_data)
0049b8
-{
0049b8
-  GVfsBackendGoogle *self = G_VFS_BACKEND_GOOGLE (user_data);
0049b8
-
0049b8
-  self->entries_stale = TRUE;
0049b8
-  self->entries_stale_timeout = 0;
0049b8
-
0049b8
-  return G_SOURCE_REMOVE;
0049b8
-}
0049b8
-
0049b8
 static void
0049b8
 g_vfs_backend_google_enumerate (GVfsBackend           *_self,
0049b8
                                 GVfsJobEnumerate      *job,
0049b8
@@ -1421,29 +1368,8 @@ g_vfs_backend_google_enumerate (GVfsBackend           *_self,
0049b8
   g_rec_mutex_lock (&self->mutex);
0049b8
   g_debug ("+ enumerate: %s\n", filename);
0049b8
 
0049b8
-  if (self->entries_stale_timeout == 0)
0049b8
-    {
0049b8
-      self->entries_stale_timeout = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
0049b8
-                                                                REBUILD_ENTRIES_TIMEOUT,
0049b8
-                                                                rebuild_entries_timeout_cb,
0049b8
-                                                                g_object_ref (self),
0049b8
-                                                                g_object_unref);
0049b8
-    }
0049b8
-
0049b8
-  if (self->entries_stale)
0049b8
-    {
0049b8
-      error = NULL;
0049b8
-      rebuild_entries (self, cancellable, &error);
0049b8
-      if (error != NULL)
0049b8
-        {
0049b8
-          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
-          g_error_free (error);
0049b8
-          goto out;
0049b8
-        }
0049b8
-    }
0049b8
-
0049b8
   error = NULL;
0049b8
-  entry = resolve (self, filename, &parent_path, &error);
0049b8
+  entry = resolve (self, filename, cancellable, &parent_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -1457,6 +1383,15 @@ g_vfs_backend_google_enumerate (GVfsBackend           *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
+  // TODO: Rebuild only if dir listing is not valid
0049b8
+  rebuild_dir (self, entry, cancellable, &error);
0049b8
+  if (error != NULL)
0049b8
+    {
0049b8
+      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
+      g_error_free (error);
0049b8
+      goto out;
0049b8
+    }
0049b8
+
0049b8
   g_vfs_job_succeeded (G_VFS_JOB (job));
0049b8
 
0049b8
   /* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
0049b8
@@ -1523,7 +1458,7 @@ g_vfs_backend_google_make_directory (GVfsBackend          *_self,
0049b8
     }
0049b8
 
0049b8
   error = NULL;
0049b8
-  parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &parent_path, &error);
0049b8
+  parent = resolve_dir (self, filename, cancellable, &basename, &parent_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -1539,7 +1474,7 @@ g_vfs_backend_google_make_directory (GVfsBackend          *_self,
0049b8
   else
0049b8
     summary = gdata_entry_get_summary (summary_entry);
0049b8
 
0049b8
-  existing_entry = resolve_child (self, parent, basename);
0049b8
+  existing_entry = resolve_child (self, parent, basename, cancellable, NULL);
0049b8
   if (existing_entry != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_EXISTS, _("Target file already exists"));
0049b8
@@ -1768,7 +1703,7 @@ g_vfs_backend_google_push (GVfsBackend           *_self,
0049b8
     }
0049b8
 
0049b8
   error = NULL;
0049b8
-  destination_parent = resolve_dir_and_rebuild (self, destination, cancellable, &destination_basename, &parent_path, &error);
0049b8
+  destination_parent = resolve_dir (self, destination, cancellable, &destination_basename, &parent_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -1776,7 +1711,7 @@ g_vfs_backend_google_push (GVfsBackend           *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  existing_entry = resolve_child (self, destination_parent, destination_basename);
0049b8
+  existing_entry = resolve_child (self, destination_parent, destination_basename, cancellable, NULL);
0049b8
   if (existing_entry != NULL)
0049b8
     {
0049b8
       if (flags & G_FILE_COPY_OVERWRITE)
0049b8
@@ -2057,7 +1992,7 @@ g_vfs_backend_google_query_info (GVfsBackend           *_self,
0049b8
   g_debug ("+ query_info: %s, %d\n", filename, flags);
0049b8
 
0049b8
   error = NULL;
0049b8
-  entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error);
0049b8
+  entry = resolve (self, filename, cancellable, &entry_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -2218,7 +2153,7 @@ g_vfs_backend_google_open_for_read (GVfsBackend        *_self,
0049b8
   g_debug ("+ open_for_read: %s\n", filename);
0049b8
 
0049b8
   error = NULL;
0049b8
-  entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error);
0049b8
+  entry = resolve (self, filename, cancellable, &entry_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -2406,7 +2341,7 @@ g_vfs_backend_google_set_display_name (GVfsBackend           *_self,
0049b8
   g_debug ("+ set_display_name: %s, %s\n", filename, display_name);
0049b8
 
0049b8
   error = NULL;
0049b8
-  entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error);
0049b8
+  entry = resolve (self, filename, cancellable, &entry_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -2478,7 +2413,7 @@ g_vfs_backend_google_create (GVfsBackend         *_self,
0049b8
     }
0049b8
 
0049b8
   error = NULL;
0049b8
-  parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &parent_path, &error);
0049b8
+  parent = resolve_dir (self, filename, cancellable, &basename, &parent_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -2488,7 +2423,7 @@ g_vfs_backend_google_create (GVfsBackend         *_self,
0049b8
 
0049b8
   g_debug ("  parent path: %s\n", parent_path);
0049b8
 
0049b8
-  existing_entry = resolve_child (self, parent, basename);
0049b8
+  existing_entry = resolve_child (self, parent, basename, cancellable, NULL);
0049b8
   if (existing_entry != NULL)
0049b8
     {
0049b8
       if (flags & G_FILE_CREATE_REPLACE_DESTINATION)
0049b8
@@ -2587,7 +2522,7 @@ g_vfs_backend_google_replace (GVfsBackend         *_self,
0049b8
     }
0049b8
 
0049b8
   error = NULL;
0049b8
-  parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &parent_path, &error);
0049b8
+  parent = resolve_dir (self, filename, cancellable, &basename, &parent_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -2597,7 +2532,7 @@ g_vfs_backend_google_replace (GVfsBackend         *_self,
0049b8
 
0049b8
   g_debug ("  parent path: %s\n", parent_path);
0049b8
 
0049b8
-  existing_entry = resolve_child (self, parent, basename);
0049b8
+  existing_entry = resolve_child (self, parent, basename, cancellable, NULL);
0049b8
   if (existing_entry != NULL)
0049b8
     {
0049b8
       if (GDATA_IS_DOCUMENTS_FOLDER (existing_entry))
0049b8
@@ -2819,12 +2754,6 @@ g_vfs_backend_google_dispose (GObject *_self)
0049b8
 {
0049b8
   GVfsBackendGoogle *self = G_VFS_BACKEND_GOOGLE (_self);
0049b8
 
0049b8
-  if (self->entries_stale_timeout != 0)
0049b8
-    {
0049b8
-      g_source_remove (self->entries_stale_timeout);
0049b8
-      self->entries_stale_timeout = 0;
0049b8
-    }
0049b8
-
0049b8
   if (self->dir_collisions != NULL)
0049b8
     {
0049b8
       g_list_free_full (self->dir_collisions, g_object_unref);
0049b8
@@ -2896,5 +2825,4 @@ g_vfs_backend_google_init (GVfsBackendGoogle *self)
0049b8
                                              g_object_unref);
0049b8
   self->monitors = g_hash_table_new (NULL, NULL);
0049b8
   g_rec_mutex_init (&self->mutex);
0049b8
-  self->entries_stale = TRUE;
0049b8
 }
0049b8
-- 
0049b8
2.36.1
0049b8
0049b8
0049b8
From 8c8bc7a8c37bbf1493b14cd76b21b077136e3260 Mon Sep 17 00:00:00 2001
0049b8
From: Ondrej Holy <oholy@redhat.com>
0049b8
Date: Thu, 16 Aug 2018 15:00:52 +0200
0049b8
Subject: [PATCH 09/14] google: Use cache for enumeration also
0049b8
0049b8
The reworked cache hasn't been used for enumeration results and also
0049b8
for missing files checks, which always caused rebuilding cache. Let's
0049b8
save timestamps also for enumerations and use it to prevent redundant
0049b8
cache rebuilds.
0049b8
---
0049b8
 daemon/gvfsbackendgoogle.c | 62 ++++++++++++++++++++++++++++----------
0049b8
 1 file changed, 46 insertions(+), 16 deletions(-)
0049b8
0049b8
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
0049b8
index bf50fef6..4eb8dbfe 100644
0049b8
--- a/daemon/gvfsbackendgoogle.c
0049b8
+++ b/daemon/gvfsbackendgoogle.c
0049b8
@@ -57,6 +57,7 @@ struct _GVfsBackendGoogle
0049b8
   GDataEntry *root;
0049b8
   GHashTable *entries; /* gchar *entry_id -> GDataEntry */
0049b8
   GHashTable *dir_entries; /* DirEntriesKey -> GDataEntry */
0049b8
+  GHashTable *dir_timestamps; /* gchar *entry_id -> gint64 *timestamp */
0049b8
   GHashTable *monitors;
0049b8
   GList *dir_collisions;
0049b8
   GRecMutex mutex; /* guards cache */
0049b8
@@ -463,6 +464,8 @@ remove_entry_full (GVfsBackendGoogle *self,
0049b8
     {
0049b8
       gchar *parent_id = ll->data;
0049b8
 
0049b8
+      g_hash_table_remove (self->dir_timestamps, parent_id);
0049b8
+
0049b8
       k = dir_entries_key_new (id, parent_id);
0049b8
       g_debug ("  remove_entry: Removed (%s, %s) -> %p\n", id, parent_id, entry);
0049b8
       g_hash_table_remove (self->dir_entries, k);
0049b8
@@ -519,6 +522,8 @@ remove_dir (GVfsBackendGoogle *self,
0049b8
   /* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
0049b8
   parent_id = g_strdup (gdata_entry_get_id (parent));
0049b8
 
0049b8
+  g_hash_table_remove (self->dir_timestamps, parent_id);
0049b8
+
0049b8
   g_hash_table_iter_init (&iter, self->entries);
0049b8
   while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry))
0049b8
     {
0049b8
@@ -562,6 +567,18 @@ is_entry_valid (GDataEntry *entry)
0049b8
   return (g_get_real_time () - *timestamp < REBUILD_ENTRIES_TIMEOUT * G_USEC_PER_SEC);
0049b8
 }
0049b8
 
0049b8
+static gboolean
0049b8
+is_dir_listing_valid (GVfsBackendGoogle *self, GDataEntry *parent)
0049b8
+{
0049b8
+  gint64 *timestamp;
0049b8
+
0049b8
+  timestamp = g_hash_table_lookup (self->dir_timestamps, gdata_entry_get_id (parent));
0049b8
+  if (timestamp != NULL)
0049b8
+    return (g_get_real_time () - *timestamp < REBUILD_ENTRIES_TIMEOUT * G_USEC_PER_SEC);
0049b8
+
0049b8
+  return FALSE;
0049b8
+}
0049b8
+
0049b8
 static void
0049b8
 rebuild_dir (GVfsBackendGoogle  *self,
0049b8
              GDataEntry         *parent,
0049b8
@@ -572,9 +589,10 @@ rebuild_dir (GVfsBackendGoogle  *self,
0049b8
   GDataDocumentsQuery *query = NULL;
0049b8
   gboolean succeeded_once = FALSE;
0049b8
   gchar *search;
0049b8
-  const gchar *parent_id;
0049b8
+  gchar *parent_id;
0049b8
 
0049b8
-  parent_id = gdata_entry_get_id (parent);
0049b8
+  /* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
0049b8
+  parent_id = g_strdup (gdata_entry_get_id (parent));
0049b8
 
0049b8
   search = g_strdup_printf ("'%s' in parents", parent_id);
0049b8
   query = gdata_documents_query_new_with_limits (search, 1, MAX_RESULTS);
0049b8
@@ -599,8 +617,14 @@ rebuild_dir (GVfsBackendGoogle  *self,
0049b8
 
0049b8
       if (!succeeded_once)
0049b8
         {
0049b8
+          gint64 *timestamp;
0049b8
+
0049b8
           remove_dir (self, parent);
0049b8
 
0049b8
+          timestamp = g_new (gint64, 1);
0049b8
+          *timestamp = g_get_real_time ();
0049b8
+          g_hash_table_insert (self->dir_timestamps, g_strdup (parent_id), timestamp);
0049b8
+
0049b8
           succeeded_once = TRUE;
0049b8
         }
0049b8
 
0049b8
@@ -621,6 +645,7 @@ rebuild_dir (GVfsBackendGoogle  *self,
0049b8
  out:
0049b8
   g_clear_object (&feed);
0049b8
   g_clear_object (&query);
0049b8
+  g_free (parent_id);
0049b8
 }
0049b8
 
0049b8
 /* ---------------------------------------------------------------------------------------------------- */
0049b8
@@ -640,8 +665,8 @@ resolve_child (GVfsBackendGoogle  *self,
0049b8
   parent_id = gdata_entry_get_id (parent);
0049b8
   k = dir_entries_key_new (basename, parent_id);
0049b8
   entry = g_hash_table_lookup (self->dir_entries, k);
0049b8
-  // TODO: Rebuild only if dir listing is not valid
0049b8
-  if (entry == NULL || !is_entry_valid (entry))
0049b8
+  if ((entry == NULL && !is_dir_listing_valid (self, parent)) ||
0049b8
+      (entry != NULL && !is_entry_valid (entry)))
0049b8
     {
0049b8
       rebuild_dir (self, parent, cancellable, &local_error);
0049b8
       if (local_error != NULL)
0049b8
@@ -651,11 +676,12 @@ resolve_child (GVfsBackendGoogle  *self,
0049b8
         }
0049b8
 
0049b8
       entry = g_hash_table_lookup (self->dir_entries, k);
0049b8
-      if (entry == NULL)
0049b8
-        {
0049b8
-          g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory"));
0049b8
-          goto out;
0049b8
-        }
0049b8
+    }
0049b8
+
0049b8
+  if (entry == NULL)
0049b8
+    {
0049b8
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory"));
0049b8
+      goto out;
0049b8
     }
0049b8
 
0049b8
  out:
0049b8
@@ -1363,7 +1389,7 @@ g_vfs_backend_google_enumerate (GVfsBackend           *_self,
0049b8
   GError *error;
0049b8
   GHashTableIter iter;
0049b8
   char *parent_path;
0049b8
-  char *id;
0049b8
+  char *id = NULL;
0049b8
 
0049b8
   g_rec_mutex_lock (&self->mutex);
0049b8
   g_debug ("+ enumerate: %s\n", filename);
0049b8
@@ -1383,13 +1409,15 @@ g_vfs_backend_google_enumerate (GVfsBackend           *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  // TODO: Rebuild only if dir listing is not valid
0049b8
-  rebuild_dir (self, entry, cancellable, &error);
0049b8
-  if (error != NULL)
0049b8
+  if (!is_dir_listing_valid (self, entry))
0049b8
     {
0049b8
-      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
-      g_error_free (error);
0049b8
-      goto out;
0049b8
+      rebuild_dir (self, entry, cancellable, &error);
0049b8
+      if (error != NULL)
0049b8
+        {
0049b8
+          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
+          g_error_free (error);
0049b8
+          goto out;
0049b8
+        }
0049b8
     }
0049b8
 
0049b8
   g_vfs_job_succeeded (G_VFS_JOB (job));
0049b8
@@ -2765,6 +2793,7 @@ g_vfs_backend_google_dispose (GObject *_self)
0049b8
   g_clear_object (&self->client);
0049b8
   g_clear_pointer (&self->entries, g_hash_table_unref);
0049b8
   g_clear_pointer (&self->dir_entries, g_hash_table_unref);
0049b8
+  g_clear_pointer (&self->dir_timestamps, g_hash_table_unref);
0049b8
 
0049b8
   G_OBJECT_CLASS (g_vfs_backend_google_parent_class)->dispose (_self);
0049b8
 }
0049b8
@@ -2823,6 +2852,7 @@ g_vfs_backend_google_init (GVfsBackendGoogle *self)
0049b8
                                              entries_in_folder_equal,
0049b8
                                              dir_entries_key_free,
0049b8
                                              g_object_unref);
0049b8
+  self->dir_timestamps = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
0049b8
   self->monitors = g_hash_table_new (NULL, NULL);
0049b8
   g_rec_mutex_init (&self->mutex);
0049b8
 }
0049b8
-- 
0049b8
2.36.1
0049b8
0049b8
0049b8
From 79e1878e1a43e32c0dbce585ea377d0222f85f27 Mon Sep 17 00:00:00 2001
0049b8
From: Ondrej Holy <oholy@redhat.com>
0049b8
Date: Wed, 1 Aug 2018 16:17:42 +0200
0049b8
Subject: [PATCH 10/14] google: Handle child of volatile also as volatile
0049b8
0049b8
Files in volatile folder should be also marked as volatile.
0049b8
0049b8
Volatile handling is a bit simplified as a part of this patch also.
0049b8
---
0049b8
 daemon/gvfsbackendgoogle.c | 58 +++++++++++++-------------------------
0049b8
 1 file changed, 19 insertions(+), 39 deletions(-)
0049b8
0049b8
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
0049b8
index 4eb8dbfe..3823cfe4 100644
0049b8
--- a/daemon/gvfsbackendgoogle.c
0049b8
+++ b/daemon/gvfsbackendgoogle.c
0049b8
@@ -881,8 +881,7 @@ build_file_info (GVfsBackendGoogle      *self,
0049b8
                  GFileQueryInfoFlags     flags,
0049b8
                  GFileInfo              *info,
0049b8
                  GFileAttributeMatcher  *matcher,
0049b8
-                 gboolean                is_symlink,
0049b8
-                 const gchar            *symlink_name,
0049b8
+                 const gchar            *filename,
0049b8
                  const gchar            *entry_path,
0049b8
                  GError                **error)
0049b8
 {
0049b8
@@ -890,6 +889,7 @@ build_file_info (GVfsBackendGoogle      *self,
0049b8
   GList *authors;
0049b8
   gboolean is_folder = FALSE;
0049b8
   gboolean is_root = FALSE;
0049b8
+  gboolean is_symlink = FALSE;
0049b8
   const gchar *etag;
0049b8
   const gchar *id;
0049b8
   const gchar *name;
0049b8
@@ -897,6 +897,7 @@ build_file_info (GVfsBackendGoogle      *self,
0049b8
   gchar *escaped_name = NULL;
0049b8
   gchar *content_type = NULL;
0049b8
   gchar *copy_name = NULL;
0049b8
+  gchar *symlink_name = NULL;
0049b8
   gint64 atime;
0049b8
   gint64 ctime;
0049b8
   gint64 mtime;
0049b8
@@ -908,6 +909,12 @@ build_file_info (GVfsBackendGoogle      *self,
0049b8
   if (entry == self->root)
0049b8
     is_root = TRUE;
0049b8
 
0049b8
+  if (filename != NULL && g_strcmp0 (entry_path, filename) != 0) /* volatile */
0049b8
+    {
0049b8
+      is_symlink = TRUE;
0049b8
+      symlink_name = g_path_get_basename (filename);
0049b8
+    }
0049b8
+
0049b8
   g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, !is_root);
0049b8
 
0049b8
   g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, is_folder);
0049b8
@@ -1066,6 +1073,7 @@ build_file_info (GVfsBackendGoogle      *self,
0049b8
     }
0049b8
 
0049b8
  out:
0049b8
+  g_free (symlink_name);
0049b8
   g_free (copy_name);
0049b8
   g_free (escaped_name);
0049b8
   g_free (content_type);
0049b8
@@ -1435,10 +1443,12 @@ g_vfs_backend_google_enumerate (GVfsBackend           *_self,
0049b8
         {
0049b8
           GFileInfo *info;
0049b8
           gchar *entry_path;
0049b8
+          gchar *child_filename;
0049b8
 
0049b8
           info = g_file_info_new ();
0049b8
           entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (entry)), NULL);
0049b8
-          build_file_info (self, entry, flags, info, matcher, FALSE, NULL, entry_path, NULL);
0049b8
+          child_filename = g_build_filename (filename, gdata_entry_get_id (GDATA_ENTRY (entry)), NULL);
0049b8
+          build_file_info (self, entry, flags, info, matcher, child_filename, entry_path, NULL);
0049b8
           g_vfs_job_enumerate_add_info (job, info);
0049b8
           g_object_unref (info);
0049b8
           g_free (entry_path);
0049b8
@@ -2012,9 +2022,7 @@ g_vfs_backend_google_query_info (GVfsBackend           *_self,
0049b8
   GCancellable *cancellable = G_VFS_JOB (job)->cancellable;
0049b8
   GDataEntry *entry;
0049b8
   GError *error;
0049b8
-  gboolean is_symlink = FALSE;
0049b8
   gchar *entry_path = NULL;
0049b8
-  gchar *symlink_name = NULL;
0049b8
 
0049b8
   g_rec_mutex_lock (&self->mutex);
0049b8
   g_debug ("+ query_info: %s, %d\n", filename, flags);
0049b8
@@ -2028,16 +2036,10 @@ g_vfs_backend_google_query_info (GVfsBackend           *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  if (g_strcmp0 (entry_path, filename) != 0) /* volatile */
0049b8
-    {
0049b8
-      is_symlink = TRUE;
0049b8
-      symlink_name = g_path_get_basename (filename);
0049b8
-    }
0049b8
-
0049b8
-  g_debug ("  entry path: %s (%d)\n", entry_path, is_symlink);
0049b8
+  g_debug ("  entry path: %s\n", entry_path);
0049b8
 
0049b8
   error = NULL;
0049b8
-  build_file_info (self, entry, flags, info, matcher, is_symlink, symlink_name, entry_path, &error);
0049b8
+  build_file_info (self, entry, flags, info, matcher, filename, entry_path, &error);
0049b8
   if (error != NULL)
0049b8
     {
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
@@ -2049,7 +2051,6 @@ g_vfs_backend_google_query_info (GVfsBackend           *_self,
0049b8
 
0049b8
  out:
0049b8
   g_free (entry_path);
0049b8
-  g_free (symlink_name);
0049b8
   g_debug ("- query_info\n");
0049b8
   g_rec_mutex_unlock (&self->mutex);
0049b8
 }
0049b8
@@ -2067,10 +2068,8 @@ g_vfs_backend_google_query_info_on_read (GVfsBackend           *_self,
0049b8
   GDataEntry *entry;
0049b8
   GError *error;
0049b8
   GInputStream *stream = G_INPUT_STREAM (handle);
0049b8
-  gboolean is_symlink = FALSE;
0049b8
   const gchar *filename;
0049b8
   gchar *entry_path = NULL;
0049b8
-  gchar *symlink_name = NULL;
0049b8
 
0049b8
   g_debug ("+ query_info_on_read: %p\n", handle);
0049b8
 
0049b8
@@ -2078,13 +2077,7 @@ g_vfs_backend_google_query_info_on_read (GVfsBackend           *_self,
0049b8
   filename = g_object_get_data (G_OBJECT (stream), "g-vfs-backend-google-filename");
0049b8
   entry_path = g_object_get_data (G_OBJECT (stream), "g-vfs-backend-google-entry-path");
0049b8
 
0049b8
-  if (g_strcmp0 (entry_path, filename) != 0) /* volatile */
0049b8
-    {
0049b8
-      is_symlink = TRUE;
0049b8
-      symlink_name = g_path_get_basename (filename);
0049b8
-    }
0049b8
-
0049b8
-  g_debug ("  entry path: %s (%d)\n", entry_path, is_symlink);
0049b8
+  g_debug ("  entry path: %s\n", entry_path);
0049b8
 
0049b8
   error = NULL;
0049b8
   build_file_info (self,
0049b8
@@ -2092,8 +2085,7 @@ g_vfs_backend_google_query_info_on_read (GVfsBackend           *_self,
0049b8
                    G_FILE_QUERY_INFO_NONE,
0049b8
                    info,
0049b8
                    matcher,
0049b8
-                   is_symlink,
0049b8
-                   symlink_name,
0049b8
+                   filename,
0049b8
                    entry_path,
0049b8
                    &error);
0049b8
   if (error != NULL)
0049b8
@@ -2106,7 +2098,6 @@ g_vfs_backend_google_query_info_on_read (GVfsBackend           *_self,
0049b8
   g_vfs_job_succeeded (G_VFS_JOB (job));
0049b8
 
0049b8
  out:
0049b8
-  g_free (symlink_name);
0049b8
   g_debug ("- query_info_on_read\n");
0049b8
 }
0049b8
 
0049b8
@@ -2122,18 +2113,9 @@ g_vfs_backend_google_query_info_on_write (GVfsBackend           *_self,
0049b8
   GVfsBackendGoogle *self = G_VFS_BACKEND_GOOGLE (_self);
0049b8
   GError *error;
0049b8
   WriteHandle *wh = (WriteHandle *) handle;
0049b8
-  gboolean is_symlink = FALSE;
0049b8
-  gchar *symlink_name = NULL;
0049b8
 
0049b8
   g_debug ("+ query_info_on_write: %p\n", handle);
0049b8
-
0049b8
-  if (g_strcmp0 (wh->entry_path, wh->filename) != 0) /* volatile */
0049b8
-    {
0049b8
-      is_symlink = TRUE;
0049b8
-      symlink_name = g_path_get_basename (wh->filename);
0049b8
-    }
0049b8
-
0049b8
-  g_debug ("  entry path: %s (%d)\n", wh->entry_path, is_symlink);
0049b8
+  g_debug ("  entry path: %s\n", wh->entry_path);
0049b8
 
0049b8
   error = NULL;
0049b8
   build_file_info (self,
0049b8
@@ -2141,8 +2123,7 @@ g_vfs_backend_google_query_info_on_write (GVfsBackend           *_self,
0049b8
                    G_FILE_QUERY_INFO_NONE,
0049b8
                    info,
0049b8
                    matcher,
0049b8
-                   is_symlink,
0049b8
-                   symlink_name,
0049b8
+                   wh->filename,
0049b8
                    wh->entry_path,
0049b8
                    &error);
0049b8
   if (error != NULL)
0049b8
@@ -2155,7 +2136,6 @@ g_vfs_backend_google_query_info_on_write (GVfsBackend           *_self,
0049b8
   g_vfs_job_succeeded (G_VFS_JOB (job));
0049b8
 
0049b8
  out:
0049b8
-  g_free (symlink_name);
0049b8
   g_debug ("- query_info_on_write\n");
0049b8
   return TRUE;
0049b8
 }
0049b8
-- 
0049b8
2.36.1
0049b8
0049b8
0049b8
From 46444e0aacd07a152e3d7958dcc263195cb69433 Mon Sep 17 00:00:00 2001
0049b8
From: Ondrej Holy <oholy@redhat.com>
0049b8
Date: Fri, 12 Jul 2019 10:35:47 +0200
0049b8
Subject: [PATCH 11/14] google: Do not enumerate volatile entries if title
0049b8
 matches id
0049b8
0049b8
Currently, the volatile entry is enumerated if its title matches id
0049b8
of another entry. But we don't want to enumerate volatile entries
0049b8
to not confuse our clients. Let's add simple check to prevent this.
0049b8
---
0049b8
 daemon/gvfsbackendgoogle.c | 23 +++++++++++++++++++----
0049b8
 1 file changed, 19 insertions(+), 4 deletions(-)
0049b8
0049b8
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
0049b8
index 3823cfe4..60d6142f 100644
0049b8
--- a/daemon/gvfsbackendgoogle.c
0049b8
+++ b/daemon/gvfsbackendgoogle.c
0049b8
@@ -1437,23 +1437,38 @@ g_vfs_backend_google_enumerate (GVfsBackend           *_self,
0049b8
   while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry))
0049b8
     {
0049b8
       DirEntriesKey *k;
0049b8
+      GDataEntry *child;
0049b8
+      gchar *child_id;
0049b8
 
0049b8
-      k = dir_entries_key_new (gdata_entry_get_id (entry), id);
0049b8
-      if (g_hash_table_contains (self->dir_entries, k))
0049b8
+      /* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */
0049b8
+      child_id = g_strdup (gdata_entry_get_id (entry));
0049b8
+
0049b8
+      k = dir_entries_key_new (child_id, id);
0049b8
+      if ((child = g_hash_table_lookup (self->dir_entries, k)) != NULL)
0049b8
         {
0049b8
           GFileInfo *info;
0049b8
           gchar *entry_path;
0049b8
           gchar *child_filename;
0049b8
 
0049b8
+          /* Be sure that we are not matching title of volatile file */
0049b8
+          if (g_strcmp0 (child_id, gdata_entry_get_id (child)) != 0)
0049b8
+            {
0049b8
+              g_debug ("Skipping %s as it is volatile path for %s\n", child_id, gdata_entry_get_id (child));
0049b8
+              g_free (child_id);
0049b8
+              dir_entries_key_free (k);
0049b8
+              continue;
0049b8
+            }
0049b8
+
0049b8
           info = g_file_info_new ();
0049b8
-          entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (entry)), NULL);
0049b8
-          child_filename = g_build_filename (filename, gdata_entry_get_id (GDATA_ENTRY (entry)), NULL);
0049b8
+          entry_path = g_build_path ("/", parent_path, child_id, NULL);
0049b8
+          child_filename = g_build_filename (filename, child_id, NULL);
0049b8
           build_file_info (self, entry, flags, info, matcher, child_filename, entry_path, NULL);
0049b8
           g_vfs_job_enumerate_add_info (job, info);
0049b8
           g_object_unref (info);
0049b8
           g_free (entry_path);
0049b8
         }
0049b8
 
0049b8
+      g_free (child_id);
0049b8
       dir_entries_key_free (k);
0049b8
     }
0049b8
 
0049b8
-- 
0049b8
2.36.1
0049b8
0049b8
0049b8
From 7a6419a1a8702516f82002c4a003eb6468ac5e7b Mon Sep 17 00:00:00 2001
0049b8
From: Mayank Sharma <mayank8019@gmail.com>
0049b8
Date: Thu, 18 Jul 2019 01:18:43 +0530
0049b8
Subject: [PATCH 12/14] google: Fix issue with stale entries remaining after
0049b8
 rename operation
0049b8
0049b8
Currently, whenever we perform a rename operation, we set the `entry`'s
0049b8
title to new display name, but at the time of removal of this entry from
0049b8
cache, we still use the newer title. Hence, each time rename is done, a
0049b8
single stale entry remains. This commit fixes the issue by reverting
0049b8
back the title to the original display name of `entry` and then
0049b8
performing a removal from cache.
0049b8
0049b8
Fixes: https://gitlab.gnome.org/GNOME/gvfs/issues/410
0049b8
---
0049b8
 daemon/gvfsbackendgoogle.c | 8 +++++++-
0049b8
 1 file changed, 7 insertions(+), 1 deletion(-)
0049b8
0049b8
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
0049b8
index 60d6142f..1147e8f1 100644
0049b8
--- a/daemon/gvfsbackendgoogle.c
0049b8
+++ b/daemon/gvfsbackendgoogle.c
0049b8
@@ -2380,6 +2380,11 @@ g_vfs_backend_google_set_display_name (GVfsBackend           *_self,
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
+  /* The internal ref count has to be increased before removing the entry since
0049b8
+   * remove_entry_full calls g_object_unref(). */
0049b8
+  g_object_ref (entry);
0049b8
+  remove_entry (self, entry);
0049b8
+
0049b8
   gdata_entry_set_title (entry, display_name);
0049b8
   auth_domain = gdata_documents_service_get_primary_authorization_domain ();
0049b8
 
0049b8
@@ -2390,14 +2395,15 @@ g_vfs_backend_google_set_display_name (GVfsBackend           *_self,
0049b8
       sanitize_error (&error);
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
       g_error_free (error);
0049b8
+      g_object_unref (entry);
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
-  remove_entry (self, entry);
0049b8
   insert_entry (self, new_entry);
0049b8
   g_hash_table_foreach (self->monitors, emit_attribute_changed_event, entry_path);
0049b8
   g_vfs_job_set_display_name_set_new_path (job, entry_path);
0049b8
   g_vfs_job_succeeded (G_VFS_JOB (job));
0049b8
+  g_object_unref (entry);
0049b8
 
0049b8
  out:
0049b8
   g_clear_object (&new_entry);
0049b8
-- 
0049b8
2.36.1
0049b8
0049b8
0049b8
From 00d1e161f47adedf2f05d3574beb05d06c76b4c0 Mon Sep 17 00:00:00 2001
0049b8
From: Mayank Sharma <mayank8019@gmail.com>
0049b8
Date: Tue, 23 Jul 2019 09:51:41 +0530
0049b8
Subject: [PATCH 13/14] google: Fix crashes when deleting if the file isn't
0049b8
 found
0049b8
0049b8
Currently in delete operation, if the entry gets resolved but parent
0049b8
resolution fails, the jump to `out` label (while handling error) will
0049b8
cause the existing entry's ref_count to decrease by 1 (since `out`
0049b8
label calls g_object_unref on entry).
0049b8
0049b8
We fix the issue by removing g_object_unref from `out` label and
0049b8
suitably unreffing the entry.
0049b8
---
0049b8
 daemon/gvfsbackendgoogle.c | 3 ++-
0049b8
 1 file changed, 2 insertions(+), 1 deletion(-)
0049b8
0049b8
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
0049b8
index 1147e8f1..230b89eb 100644
0049b8
--- a/daemon/gvfsbackendgoogle.c
0049b8
+++ b/daemon/gvfsbackendgoogle.c
0049b8
@@ -1366,6 +1366,7 @@ g_vfs_backend_google_delete (GVfsBackend   *_self,
0049b8
       sanitize_error (&error);
0049b8
       g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
0049b8
       g_error_free (error);
0049b8
+      g_object_unref (entry);
0049b8
       goto out;
0049b8
     }
0049b8
 
0049b8
@@ -1373,9 +1374,9 @@ g_vfs_backend_google_delete (GVfsBackend   *_self,
0049b8
     insert_entry (self, GDATA_ENTRY (new_entry));
0049b8
   g_hash_table_foreach (self->monitors, emit_delete_event, entry_path);
0049b8
   g_vfs_job_succeeded (G_VFS_JOB (job));
0049b8
+  g_object_unref (entry);
0049b8
 
0049b8
  out:
0049b8
-  g_object_unref (entry);
0049b8
   g_clear_object (&new_entry);
0049b8
   g_free (entry_path);
0049b8
   g_debug ("- delete\n");
0049b8
-- 
0049b8
2.36.1
0049b8
0049b8
0049b8
From d842aa6c729866343d7a3b0514a6574c01be30ed Mon Sep 17 00:00:00 2001
0049b8
From: Ondrej Holy <oholy@redhat.com>
0049b8
Date: Fri, 29 Jan 2021 14:06:16 +0100
0049b8
Subject: [PATCH 14/14] google: Increase number of results in batches for
0049b8
 better performance
0049b8
0049b8
Currently, only 50 results are returned in one batch, which means that
0049b8
multiple network requests are needed for folders with a lot files, which
0049b8
makes it slow. I am not sure there was some reason for this limitation
0049b8
earlier (e.g. before the cache rework), however, I don't see any
0049b8
rationals for it currently. Let's increase this to its maximum for
0049b8
better performance.
0049b8
---
0049b8
 daemon/gvfsbackendgoogle.c | 4 +---
0049b8
 1 file changed, 1 insertion(+), 3 deletions(-)
0049b8
0049b8
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
0049b8
index 230b89eb..f97c038c 100644
0049b8
--- a/daemon/gvfsbackendgoogle.c
0049b8
+++ b/daemon/gvfsbackendgoogle.c
0049b8
@@ -79,8 +79,6 @@ G_DEFINE_TYPE(GVfsBackendGoogle, g_vfs_backend_google, G_VFS_TYPE_BACKEND)
0049b8
 
0049b8
 #define CONTENT_TYPE_PREFIX_GOOGLE "application/vnd.google-apps"
0049b8
 
0049b8
-#define MAX_RESULTS 50
0049b8
-
0049b8
 #define REBUILD_ENTRIES_TIMEOUT 60 /* s */
0049b8
 
0049b8
 #define URI_PREFIX "https://www.googleapis.com/drive/v2/files/"
0049b8
@@ -595,7 +593,7 @@ rebuild_dir (GVfsBackendGoogle  *self,
0049b8
   parent_id = g_strdup (gdata_entry_get_id (parent));
0049b8
 
0049b8
   search = g_strdup_printf ("'%s' in parents", parent_id);
0049b8
-  query = gdata_documents_query_new_with_limits (search, 1, MAX_RESULTS);
0049b8
+  query = gdata_documents_query_new_with_limits (search, 1, G_MAXUINT);
0049b8
   gdata_documents_query_set_show_folders (query, TRUE);
0049b8
   g_free (search);
0049b8
 
0049b8
-- 
0049b8
2.36.1
0049b8