[gvfs/wip/rishi/goa: 4/4] Drive continued ...



commit 4ce3516d3395060f2a3c4dc3ebb961ae6e89bdba
Author: Debarshi Ray <debarshir gnome org>
Date:   Thu Jun 25 14:09:40 2015 +0200

    Drive continued ...
    
    refactor find_root
    implement escaping/unescaping of ids

 daemon/gvfsbackendgoogle.c |  612 +++++++++++++++++++++++++++++++++++---------
 1 files changed, 497 insertions(+), 115 deletions(-)
---
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
index 26072a1..c9363d4 100644
--- a/daemon/gvfsbackendgoogle.c
+++ b/daemon/gvfsbackendgoogle.c
@@ -82,6 +82,186 @@ G_DEFINE_TYPE(GVfsBackendGoogle, g_vfs_backend_google, G_VFS_TYPE_BACKEND)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+static gchar *
+escape_id (const gchar *id)
+{
+  return g_strconcat ("_", id, NULL);
+}
+
+static gchar *
+escape_filename (const gchar *filename)
+{
+  GString *escaped_filename;
+  gboolean separator_added = FALSE;
+  gchar *basename = NULL;
+  gchar *dirname = NULL;
+  gsize len;
+
+  len = strlen (filename);
+  escaped_filename = g_string_sized_new (len);
+  basename = g_path_get_basename (filename);
+  dirname = g_path_get_dirname (filename);
+
+  while (g_strcmp0 (basename, dirname) != 0)
+    {
+      gchar *escaped_basename;
+      gchar *tmp = NULL;
+
+      escaped_basename = escape_id (basename);
+      g_string_prepend (escaped_filename, escaped_basename);
+      g_string_prepend_c (escaped_filename, G_DIR_SEPARATOR);
+      separator_added = TRUE;
+      g_free (escaped_basename);
+
+      g_free (basename);
+      basename = g_path_get_basename (dirname);
+
+      tmp = dirname;
+      dirname = g_path_get_dirname (dirname);
+      g_free (tmp);
+    }
+
+  if (!separator_added)
+    g_string_prepend_c (escaped_filename, G_DIR_SEPARATOR);
+
+  g_free (basename);
+  g_free (dirname);
+  return g_string_free (escaped_filename, FALSE);
+}
+
+/* Takes a filename as supplied by the application and returns a value
+ * that is either:
+ * (a) guaranteed to be made up of persistent, server-defined IDs, or
+ * (b) can be used to look-up such a persistent filename through the
+ *     lookaside cache
+ */
+static gchar *
+unescape_filename (GVfsBackendGoogle *self,
+                   const gchar       *filename,
+                   gboolean          *out_is_volatile)
+{
+  GString *unescaped_filename;
+  gboolean is_volatile;
+  gboolean separator_added = FALSE;
+  gchar *basename = NULL;
+  gchar *dirname = NULL;
+  gsize len;
+
+  /* If a path is in the lookaside cache then it is volatile, even if
+   * it looks like /_id10/_id2, and we don't perform the usual
+   * unescaping operation. See the copy job for an explanation.
+   */
+  if (g_hash_table_lookup (self->lookaside, filename) != NULL)
+    {
+      is_volatile = TRUE;
+      unescaped_filename = g_string_new (filename);
+      goto out;
+    }
+  else
+    {
+      is_volatile = FALSE;
+    }
+
+  len = strlen (filename);
+  unescaped_filename = g_string_sized_new (len);
+  basename = g_path_get_basename (filename);
+  dirname = g_path_get_dirname (filename);
+
+  while (g_strcmp0 (basename, dirname) != 0)
+    {
+      const gchar *unescaped_basename;
+      gchar *tmp = NULL;
+
+      if (g_str_has_prefix (basename, "_") && !g_str_has_prefix (basename, "__"))
+        {
+          unescaped_basename = basename + 1;
+        }
+      else
+        {
+          unescaped_basename = basename;
+          is_volatile = TRUE;
+        }
+
+      g_string_prepend (unescaped_filename, unescaped_basename);
+      g_string_prepend_c (unescaped_filename, G_DIR_SEPARATOR);
+      separator_added = TRUE;
+
+      g_free (basename);
+      basename = g_path_get_basename (dirname);
+
+      tmp = dirname;
+      dirname = g_path_get_dirname (dirname);
+      g_free (tmp);
+    }
+
+  if (!separator_added)
+    g_string_prepend_c (unescaped_filename, G_DIR_SEPARATOR);
+
+ out:
+  if (out_is_volatile != NULL)
+    *out_is_volatile = is_volatile;
+  g_free (basename);
+  g_free (dirname);
+  return g_string_free (unescaped_filename, FALSE);
+}
+
+/* Specifically meant for differentiating between /_id1/_id2 and
+ * /_id1/foo when creating a file or directory, and unescaping the
+ * dirname.
+ */
+static gchar *
+unescape_basename_and_map_dirname (GVfsBackendGoogle *self,
+                                   const gchar       *filename,
+                                   gboolean          *out_is_volatile)
+{
+  gboolean is_volatile;
+  gboolean is_dirname_volatile;
+  const gchar *unescaped_basename;
+  gchar *basename = NULL;
+  gchar *dirname = NULL;
+  gchar *ret_val = NULL;
+  gchar *unescaped_dirname = NULL;
+
+  basename = g_path_get_basename (filename);
+  if (g_str_has_prefix (basename, "_") && !g_str_has_prefix (basename, "__"))
+    {
+      unescaped_basename = basename + 1;
+      is_volatile = FALSE;
+    }
+  else
+    {
+      unescaped_basename = basename;
+      is_volatile = TRUE;
+    }
+
+  dirname = g_path_get_dirname (filename);
+  unescaped_dirname = unescape_filename (self, dirname, &is_dirname_volatile);
+  if (is_dirname_volatile)
+    {
+      const gchar *real_dirname;
+
+      real_dirname = g_hash_table_lookup (self->lookaside, unescaped_dirname);
+      if (real_dirname == NULL)
+        goto out;
+
+      g_free (unescaped_dirname);
+      unescaped_dirname = g_strdup (real_dirname);
+    }
+
+  ret_val = g_build_filename (unescaped_dirname, unescaped_basename);
+
+  if (out_is_volatile != NULL)
+    *out_is_volatile = is_volatile;
+
+ out:
+  g_free (unescaped_dirname);
+  g_free (dirname);
+  g_free (basename);
+  return ret_val;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static void
 emit_event_internal (GVfsMonitor       *monitor,
                      const gchar       *filename,
@@ -91,7 +271,13 @@ emit_event_internal (GVfsMonitor       *monitor,
 
   monitored_path = g_object_get_data (G_OBJECT (monitor), "g-vfs-backend-google-path");
   if (g_str_has_prefix (filename, monitored_path))
-    g_vfs_monitor_emit_event (monitor, event, filename, NULL);
+    {
+      gchar *escaped_filename = NULL;
+
+      escaped_filename = escape_filename (filename);
+      g_vfs_monitor_emit_event (monitor, event, escaped_filename, NULL);
+      g_free (escaped_filename);
+    }
 }
 
 static void
@@ -185,6 +371,7 @@ build_file_info (GVfsBackendGoogle      *self,
   const gchar *id;
   const gchar *name;
   const gchar *title;
+  gchar *escaped_name = NULL;
   gchar *content_type = NULL;
   gchar *copy_name = NULL;
   gint64 atime;
@@ -223,15 +410,18 @@ build_file_info (GVfsBackendGoogle      *self,
     {
       const gchar *mount_identity;
       const gchar *type;
+      gchar *escaped_filename = NULL;
       gchar *target_uri = NULL;
 
       file_type = G_FILE_TYPE_SYMBOLIC_LINK;
 
       type = g_mount_spec_get (spec, "type");
       mount_identity = g_mount_spec_get (spec, "goa-identity");
-      target_uri = g_strdup_printf ("%s://%s%s", type, mount_identity, filename);
+      escaped_filename = escape_filename (filename);
+      target_uri = g_strdup_printf ("%s://%s%s", type, mount_identity, escaped_filename);
       g_file_info_set_symlink_target (info, target_uri);
       g_free (target_uri);
+      g_free (escaped_filename);
     }
 
   if (content_type != NULL)
@@ -258,10 +448,18 @@ build_file_info (GVfsBackendGoogle      *self,
   if (is_root)
     goto out;
 
+  id = gdata_entry_get_id (entry);
+  g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILE, id);
+
   if (is_symlink)
-    name = symlink_name;
+    {
+      name = symlink_name;
+    }
   else
-    name = gdata_entry_get_id (entry);
+    {
+      escaped_name = escape_id (id);
+      name = escaped_name;
+    }
 
   g_file_info_set_name (info, name);
 
@@ -289,22 +487,19 @@ build_file_info (GVfsBackendGoogle      *self,
   if (authors != NULL)
     {
       GDataAuthor *author = GDATA_AUTHOR (authors->data);
+      const gchar *author_name;
       const gchar *email_address;
-      const gchar *name;
+
+      author_name = gdata_author_get_name (author);
+      g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER_REAL, author_name);
 
       email_address = gdata_author_get_email_address (author);
       g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER, email_address);
-
-      name = gdata_author_get_name (author);
-      g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER_REAL, name);
     }
 
   etag = gdata_entry_get_etag (entry);
   g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ETAG_VALUE, etag);
 
-  id = gdata_entry_get_id (entry);
-  g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILE, id);
-
   if (!is_folder)
     {
       const gchar *thumbnail_uri;
@@ -322,11 +517,32 @@ build_file_info (GVfsBackendGoogle      *self,
 
  out:
   g_free (copy_name);
+  g_free (escaped_name);
   g_free (content_type);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+static void
+find_root (GVfsBackendGoogle *self, GCancellable *cancellable, GError **error)
+{
+  GDataAuthorizationDomain *auth_domain;
+
+  if (self->root != NULL)
+    return;
+
+  auth_domain = gdata_documents_service_get_primary_authorization_domain ();
+  self->root = gdata_service_query_single_entry (GDATA_SERVICE (self->service),
+                                                 auth_domain,
+                                                 "root",
+                                                 NULL,
+                                                 GDATA_TYPE_DOCUMENTS_FOLDER,
+                                                 cancellable,
+                                                 error);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static gchar *
 get_parent_id (GDataEntry *entry)
 {
@@ -370,7 +586,7 @@ get_entry_path (GVfsBackendGoogle *self, GDataEntry *entry)
 
   base_id = gdata_entry_get_id (entry);
   path = g_string_new (base_id);
-  path = g_string_prepend_c (path, '/');
+  g_string_prepend_c (path, '/');
 
   id = get_parent_id (entry);
   root_id = gdata_entry_get_id (self->root);
@@ -391,8 +607,8 @@ get_entry_path (GVfsBackendGoogle *self, GDataEntry *entry)
       if (parent_entry == NULL)
         goto out;
 
-      path = g_string_prepend (path, id);
-      path = g_string_prepend_c (path, '/');
+      g_string_prepend (path, id);
+      g_string_prepend_c (path, '/');
 
       g_free (id);
       id = get_parent_id (parent_entry);
@@ -455,25 +671,12 @@ rebuild_entries (GVfsBackendGoogle  *self,
   GError *local_error;
   gboolean succeeded_once = FALSE;
 
-  if (self->root == NULL)
+  local_error = NULL;
+  find_root (self, cancellable, &local_error);
+  if (local_error != NULL)
     {
-      GDataAuthorizationDomain *auth_domain;
-
-      auth_domain = gdata_documents_service_get_primary_authorization_domain ();
-
-      local_error = NULL;
-      self->root = gdata_service_query_single_entry (GDATA_SERVICE (self->service),
-                                                     auth_domain,
-                                                     "root",
-                                                     NULL,
-                                                     GDATA_TYPE_DOCUMENTS_FOLDER,
-                                                     cancellable,
-                                                     &local_error);
-      if (local_error != NULL)
-        {
-          g_propagate_error (error, local_error);
-          goto out;
-        }
+      g_propagate_error (error, local_error);
+      goto out;
     }
 
   query = gdata_documents_query_new_with_limits (NULL, 1, MAX_RESULTS);
@@ -601,6 +804,7 @@ g_vfs_backend_google_copy (GVfsBackend           *_self,
   GError *error;
   gboolean is_folder;
   gboolean is_root;
+  gboolean is_volatile_source;
   const gchar *id;
   const gchar *real_destination_parent_path;
   const gchar *real_parent_path;
@@ -609,27 +813,54 @@ g_vfs_backend_google_copy (GVfsBackend           *_self,
   gchar *destination_parent_path = NULL;
   gchar *path = NULL;
   gchar *source_id = NULL;
+  gchar *unescaped_destination = NULL;
+  gchar *unescaped_source = NULL;
+
+  /* The destination is always volatile. Even in the best case, it
+   * will look like /_id1/_id2 -> /_id10/_id2, whereas in reality it
+   * will be /_id1/_id2 -> /_id10/_id20. This will confuse our
+   * escaping logic when /_id10/_id2 is passed to a any subsequent
+   * job, and make it think that it is a non-volatile path. Hence, we
+   * add /_id10/_id2 to the lookaside cache at the end of the
+   * copy so that subsequent jobs can recognize it as a volatile path.
+   */
 
   g_rec_mutex_lock (&self->mutex);
-  g_debug ("+ copy: %s -> %s\n", source, destination);
+  unescaped_destination = unescape_filename (self, destination, NULL);
+  unescaped_source = unescape_filename (self, source, &is_volatile_source);
+  g_debug ("+ copy: %s (%s, %d) -> %s (%s, 1)\n",
+           source,
+           unescaped_source,
+           is_volatile_source,
+           destination,
+           unescaped_destination);
+  source = unescaped_source;
 
-  real_source = g_hash_table_lookup (self->lookaside, source);
-  if (real_source != NULL)
-    source = real_source;
-
-  source_id = g_path_get_basename (source);
-  source_entry = g_hash_table_lookup (self->entries, source_id);
-  is_folder_or_root (source, source_entry, &is_folder, NULL);
-  if (is_folder)
+  error = NULL;
+  find_root (self, cancellable, &error);
+  if (error != NULL)
     {
-      g_vfs_job_failed (G_VFS_JOB (job),
-                        G_IO_ERROR,
-                        G_IO_ERROR_WOULD_RECURSE,
-                        _("Can't recursively copy directory"));
+      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+      g_error_free (error);
       goto out;
     }
 
-  destination_parent_path = g_path_get_dirname (destination);
+  if (is_volatile_source)
+    {
+      real_source = g_hash_table_lookup (self->lookaside, source);
+      if (real_source == NULL)
+        {
+          g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or 
directory"));
+          goto out;
+        }
+
+      source = real_source;
+    }
+
+  source_id = g_path_get_basename (source);
+  source_entry = g_hash_table_lookup (self->entries, source_id);
+
+  destination_parent_path = g_path_get_dirname (unescaped_destination);
   real_destination_parent_path = g_hash_table_lookup (self->lookaside, destination_parent_path);
   if (real_destination_parent_path != NULL)
     {
@@ -646,27 +877,38 @@ g_vfs_backend_google_copy (GVfsBackend           *_self,
     {
       destination_parent_id = g_path_get_basename (destination_parent_path);
       destination_parent = g_hash_table_lookup (self->entries, destination_parent_id);
+    }
 
-      if (destination_parent == NULL)
+  if (source_entry == NULL || destination_parent == NULL)
+    {
+      error = NULL;
+      rebuild_entries (self, cancellable, &error);
+      if (error != NULL)
         {
-          error = NULL;
-          rebuild_entries (self, cancellable, &error);
-          if (error != NULL)
-            {
-              g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
-              g_error_free (error);
-              goto out;
-            }
-
-          destination_parent = g_hash_table_lookup (self->entries, destination_parent_id);
-          if (destination_parent == NULL)
-            {
-              g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or 
directory"));
-              goto out;
-            }
+          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+          g_error_free (error);
+          goto out;
         }
     }
 
+  source_entry = g_hash_table_lookup (self->entries, source_id);
+  is_folder_or_root (source, source_entry, &is_folder, NULL);
+  if (is_folder)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job),
+                        G_IO_ERROR,
+                        G_IO_ERROR_WOULD_RECURSE,
+                        _("Can't recursively copy directory"));
+      goto out;
+    }
+
+  destination_parent = g_hash_table_lookup (self->entries, destination_parent_id);
+  if (source_entry == NULL || destination_parent == NULL)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory"));
+      goto out;
+    }
+
   error = NULL;
   new_entry = gdata_documents_service_add_entry_to_folder (self->service,
                                                            GDATA_DOCUMENTS_ENTRY (source_entry),
@@ -686,6 +928,7 @@ g_vfs_backend_google_copy (GVfsBackend           *_self,
   path = get_entry_path (self, GDATA_ENTRY (new_entry));
   if (path != NULL)
     {
+      g_debug ("  insert lookaside: %s -> %s\n", destination, path);
       g_hash_table_insert (self->lookaside, g_strdup (destination), g_strdup (path));
       g_hash_table_foreach (self->monitors, emit_create_event, (gpointer) path);
     }
@@ -700,6 +943,8 @@ g_vfs_backend_google_copy (GVfsBackend           *_self,
   g_free (destination_parent_id);
   g_free (destination_parent_path);
   g_free (source_id);
+  g_free (unescaped_source);
+  g_free (unescaped_destination);
   g_debug ("- copy\n");
   g_rec_mutex_unlock (&self->mutex);
 }
@@ -719,9 +964,28 @@ g_vfs_backend_google_create_dir_monitor (GVfsBackend          *_self,
   GVfsMonitor *monitor = NULL;
   gboolean is_folder;
   gboolean is_root;
+  gboolean is_volatile;
   gchar *id = NULL;
+  gchar *unescaped_filename = NULL;
 
   g_rec_mutex_lock (&self->mutex);
+  unescaped_filename = unescape_filename (self, filename, &is_volatile);
+  g_debug ("+ create_dir_monitor: %s (%s, %d)\n", filename, unescaped_filename, is_volatile);
+  filename = unescaped_filename;
+
+  if (is_volatile)
+    {
+      const gchar *real_filename;
+
+      real_filename = g_hash_table_lookup (self->lookaside, filename);
+      if (real_filename == NULL)
+        {
+          g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or 
directory"));
+          goto out;
+        }
+
+      filename = real_filename;
+    }
 
   id = g_path_get_basename (filename);
   entry = g_hash_table_lookup (self->entries, id);
@@ -763,6 +1027,8 @@ g_vfs_backend_google_create_dir_monitor (GVfsBackend          *_self,
  out:
   g_clear_object (&monitor);
   g_free (id);
+  g_free (unescaped_filename);
+  g_debug ("- create_dir_monitor\n");
   g_rec_mutex_unlock (&self->mutex);
   return TRUE;
 }
@@ -780,16 +1046,29 @@ g_vfs_backend_google_delete (GVfsBackend   *_self,
   GDataEntry *entry;
   GError *error;
   gboolean is_root;
-  const gchar *real_filename;
+  gboolean is_volatile;
   gchar *path = NULL;
   gchar *id = NULL;
+  gchar *unescaped_filename = NULL;
 
   g_rec_mutex_lock (&self->mutex);
-  g_debug ("+ delete: %s\n", filename);
+  unescaped_filename = unescape_filename (self, filename, &is_volatile);
+  g_debug ("+ delete: %s (%s, %d)\n", filename, unescaped_filename, is_volatile);
+  filename = unescaped_filename;
 
-  real_filename = g_hash_table_lookup (self->lookaside, filename);
-  if (real_filename != NULL)
-    filename = real_filename;
+  if (is_volatile)
+    {
+      const gchar *real_filename;
+
+      real_filename = g_hash_table_lookup (self->lookaside, filename);
+      if (real_filename == NULL)
+        {
+          g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or 
directory"));
+          goto out;
+        }
+
+      filename = real_filename;
+    }
 
   is_folder_or_root (filename, NULL, NULL, &is_root);
   if (is_root)
@@ -845,6 +1124,7 @@ g_vfs_backend_google_delete (GVfsBackend   *_self,
  out:
   g_free (path);
   g_free (id);
+  g_free (unescaped_filename);
   g_debug ("- delete\n");
   g_rec_mutex_unlock (&self->mutex);
 }
@@ -874,9 +1154,27 @@ g_vfs_backend_google_enumerate (GVfsBackend           *_self,
   GDataEntry *entry;
   GError *error;
   GHashTableIter iter;
+  gboolean is_volatile;
+  gchar *unescaped_filename = NULL;
 
   g_rec_mutex_lock (&self->mutex);
-  g_debug ("+ enumerate: %s\n", filename);
+  unescaped_filename = unescape_filename (self, filename, &is_volatile);
+  g_debug ("+ enumerate: %s (%s, %d)\n", filename, unescaped_filename, is_volatile);
+  filename = unescaped_filename;
+
+  if (is_volatile)
+    {
+      const gchar *real_filename;
+
+      real_filename = g_hash_table_lookup (self->lookaside, filename);
+      if (real_filename == NULL)
+        {
+          g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or 
directory"));
+          goto out;
+        }
+
+      filename = real_filename;
+    }
 
   if (self->entries_stale_timeout == 0)
     {
@@ -933,6 +1231,7 @@ g_vfs_backend_google_enumerate (GVfsBackend           *_self,
   g_vfs_job_enumerate_done (job);
 
  out:
+  g_free (unescaped_filename);
   g_debug ("- enumerate\n");
   g_rec_mutex_unlock (&self->mutex);
 }
@@ -949,19 +1248,31 @@ g_vfs_backend_google_make_directory (GVfsBackend          *_self,
   GDataDocumentsEntry *new_entry = NULL;
   GDataDocumentsFolder *folder = NULL;
   GDataDocumentsFolder *parent;
+  GDataEntry *source_entry = NULL;
   GError *error;
+  gboolean is_display_name;
   gboolean is_root;
+  gboolean needs_rebuild = FALSE;
   const gchar *id;
   const gchar *real_parent_path;
   gchar *parent_id = NULL;
   gchar *parent_path = NULL;
   gchar *path = NULL;
+  gchar *source_id = NULL;
   gchar *title = NULL;
+  gchar *unescaped_filename = NULL;
 
   g_rec_mutex_lock (&self->mutex);
-  g_debug ("+ make_directory: %s\n", filename);
+  unescaped_filename = unescape_basename_and_map_dirname (self, filename, &is_display_name);
+  g_debug ("+ make_directory: %s (%s, %d)\n", filename, unescaped_filename, is_display_name);
 
-  is_folder_or_root (filename, NULL, NULL, &is_root);
+  if (unescaped_filename == NULL)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory"));
+      goto out;
+    }
+
+  is_folder_or_root (unescaped_filename, NULL, NULL, &is_root);
   if (is_root)
     {
       g_vfs_job_failed (G_VFS_JOB (job),
@@ -971,14 +1282,23 @@ g_vfs_backend_google_make_directory (GVfsBackend          *_self,
       goto out;
     }
 
-  parent_path = g_path_get_dirname (filename);
-  real_parent_path = g_hash_table_lookup (self->lookaside, parent_path);
-  if (real_parent_path != NULL)
+  error = NULL;
+  find_root (self, cancellable, &error);
+  if (error != NULL)
     {
-      g_free (parent_path);
-      parent_path = g_strdup (real_parent_path);
+      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+      g_error_free (error);
+      goto out;
     }
 
+  parent_path = g_path_get_dirname (unescaped_filename);
+  /* real_parent_path = g_hash_table_lookup (self->lookaside, parent_path); */
+  /* if (real_parent_path != NULL) */
+  /*   { */
+  /*     g_free (parent_path); */
+  /*     parent_path = g_strdup (real_parent_path); */
+  /*   } */
+
   is_folder_or_root (parent_path, NULL, NULL, &is_root);
   if (is_root)
     {
@@ -988,29 +1308,54 @@ g_vfs_backend_google_make_directory (GVfsBackend          *_self,
     {
       parent_id = g_path_get_basename (parent_path);
       parent = g_hash_table_lookup (self->entries, parent_id);
-
       if (parent == NULL)
+        needs_rebuild = TRUE;
+    }
+
+  if (is_display_name)
+    {
+      title = g_path_get_basename (unescaped_filename);
+    }
+  else
+    {
+      source_id = g_path_get_basename (unescaped_filename);
+      source_entry = g_hash_table_lookup (self->entries, source_id);
+      if (source_entry == NULL)
+        needs_rebuild = TRUE;
+    }
+
+  if (needs_rebuild)
+    {
+      error = NULL;
+      rebuild_entries (self, cancellable, &error);
+      if (error != NULL)
         {
-          error = NULL;
-          rebuild_entries (self, cancellable, &error);
-          if (error != NULL)
-            {
-              g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
-              g_error_free (error);
-              goto out;
-            }
+          g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+          g_error_free (error);
+          goto out;
+        }
+    }
 
-          parent = g_hash_table_lookup (self->entries, parent_id);
-          if (parent == NULL)
-            {
-              g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or 
directory"));
-              goto out;
-            }
+  parent = g_hash_table_lookup (self->entries, parent_id);
+  if (parent == NULL)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory"));
+      goto out;
+    }
+
+  if (!is_display_name)
+    {
+      source_entry = g_hash_table_lookup (self->entries, source_id);
+      if (source_entry == NULL)
+        {
+          g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or 
directory"));
+          goto out;
         }
+
+      title = g_strdup (gdata_entry_get_title (source_entry));
     }
 
   folder = gdata_documents_folder_new (NULL);
-  title = g_path_get_basename (filename);
   gdata_entry_set_title (GDATA_ENTRY (folder), title);
 
   error = NULL;
@@ -1030,6 +1375,7 @@ g_vfs_backend_google_make_directory (GVfsBackend          *_self,
   g_hash_table_insert (self->entries, g_strdup (id), g_object_ref (new_entry));
 
   path = get_entry_path (self, GDATA_ENTRY (new_entry));
+  g_debug ("  insert lookaside: %s -> %s\n", filename, path);
   g_hash_table_insert (self->lookaside, g_strdup (filename), g_strdup (path));
 
   self->entries_stale = TRUE;
@@ -1040,10 +1386,12 @@ g_vfs_backend_google_make_directory (GVfsBackend          *_self,
  out:
   g_clear_object (&new_entry);
   g_clear_object (&folder);
+  g_free (source_id);
   g_free (parent_id);
   g_free (parent_path);
   g_free (path);
   g_free (title);
+  g_free (unescaped_filename);
   g_debug ("- make_directory\n");
   g_rec_mutex_unlock (&self->mutex);
 }
@@ -1147,16 +1495,29 @@ g_vfs_backend_google_open_for_read (GVfsBackend        *_self,
   GError *error;
   gboolean is_folder;
   gboolean is_root;
-  const gchar *real_filename;
+  gboolean is_volatile;
   gchar *content_type = NULL;
   gchar *id = NULL;
+  gchar *unescaped_filename = NULL;
 
   g_rec_mutex_lock (&self->mutex);
-  g_debug ("+ open_for_read: %s\n", filename);
+  unescaped_filename = unescape_filename (self, filename, &is_volatile);
+  g_debug ("+ open_for_read: %s (%s, %d)\n", filename, unescaped_filename, is_volatile);
+  filename = unescaped_filename;
+
+  if (is_volatile)
+    {
+      const gchar *real_filename;
+
+      real_filename = g_hash_table_lookup (self->lookaside, filename);
+      if (real_filename == NULL)
+        {
+          g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or 
directory"));
+          goto out;
+        }
 
-  real_filename = g_hash_table_lookup (self->lookaside, filename);
-  if (real_filename != NULL)
-    filename = real_filename;
+      filename = real_filename;
+    }
 
   id = g_path_get_basename (filename);
   entry = g_hash_table_lookup (self->entries, id);
@@ -1244,6 +1605,7 @@ g_vfs_backend_google_open_for_read (GVfsBackend        *_self,
  out:
   g_free (content_type);
   g_free (id);
+  g_free (unescaped_filename);
   g_debug ("- open_for_read\n");
   g_rec_mutex_unlock (&self->mutex);
 }
@@ -1428,6 +1790,7 @@ g_vfs_backend_google_push (GVfsBackend           *_self,
   g_hash_table_insert (self->entries, g_strdup (id), g_object_ref (new_document));
 
   path = get_entry_path (self, GDATA_ENTRY (new_document));
+  g_debug ("  insert lookaside: %s -> %s\n", destination, path);
   g_hash_table_insert (self->lookaside, g_strdup (destination), g_strdup (path));
 
   self->entries_stale = TRUE;
@@ -1492,16 +1855,27 @@ g_vfs_backend_google_query_info (GVfsBackend           *_self,
   GError *error;
   gboolean is_root;
   gboolean is_symlink = FALSE;
-  const gchar *real_filename;
+  gboolean is_volatile;
   gchar *id = NULL;
   gchar *symlink_name = NULL;
+  gchar *unescaped_filename = NULL;
 
   g_rec_mutex_lock (&self->mutex);
-  g_debug ("+ query_info: %s, %d\n", filename, flags);
+  unescaped_filename = unescape_filename (self, filename, &is_volatile);
+  g_debug ("+ query_info: %s (%s, %d), %d\n", filename, unescaped_filename, is_volatile, flags);
+  filename = unescaped_filename;
 
-  real_filename = g_hash_table_lookup (self->lookaside, filename);
-  if (real_filename != NULL)
+  if (is_volatile)
     {
+      const gchar *real_filename;
+
+      real_filename = g_hash_table_lookup (self->lookaside, filename);
+      if (real_filename == NULL)
+        {
+          g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or 
directory"));
+          goto out;
+        }
+
       filename = real_filename;
       if ((flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) != 0)
         {
@@ -1542,6 +1916,7 @@ g_vfs_backend_google_query_info (GVfsBackend           *_self,
  out:
   g_free (id);
   g_free (symlink_name);
+  g_free (unescaped_filename);
   g_debug ("- query_info\n");
   g_rec_mutex_unlock (&self->mutex);
 }
@@ -1636,19 +2011,31 @@ g_vfs_backend_google_set_display_name (GVfsBackend           *_self,
   GDataEntry *new_entry = NULL;
   GError *error;
   gboolean is_root;
+  gboolean is_volatile;
   const gchar *new_id;
-  const gchar *real_filename;
   gchar *id = NULL;
-  gchar *path = NULL;
+  gchar *unescaped_filename = NULL;
 
   g_rec_mutex_lock (&self->mutex);
-  g_debug ("+ set_display_name: %s, %s\n", filename, display_name);
+  unescaped_filename = unescape_filename (self, filename, &is_volatile);
+  g_debug ("+ set_display_name: %s (%s, %d), %s\n", filename, unescaped_filename, is_volatile, display_name);
 
-  real_filename = g_hash_table_lookup (self->lookaside, filename);
-  if (real_filename != NULL)
-    filename = real_filename;
+  if (is_volatile)
+    {
+      const gchar *real_filename;
 
-  is_folder_or_root (filename, NULL, NULL, &is_root);
+      real_filename = g_hash_table_lookup (self->lookaside, unescaped_filename);
+      if (real_filename == NULL)
+        {
+          g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or 
directory"));
+          goto out;
+        }
+
+      g_free (unescaped_filename);
+      unescaped_filename = g_strdup (real_filename);
+    }
+
+  is_folder_or_root (unescaped_filename, NULL, NULL, &is_root);
   if (is_root)
     {
       g_vfs_job_failed (G_VFS_JOB (job),
@@ -1658,7 +2045,7 @@ g_vfs_backend_google_set_display_name (GVfsBackend           *_self,
       goto out;
     }
 
-  id = g_path_get_basename (filename);
+  id = g_path_get_basename (unescaped_filename);
   entry = g_hash_table_lookup (self->entries, id);
 
   if (entry == NULL)
@@ -1681,7 +2068,6 @@ g_vfs_backend_google_set_display_name (GVfsBackend           *_self,
     }
 
   gdata_entry_set_title (entry, display_name);
-
   auth_domain = gdata_documents_service_get_primary_authorization_domain ();
 
   error = NULL;
@@ -1698,17 +2084,13 @@ g_vfs_backend_google_set_display_name (GVfsBackend           *_self,
   new_id = gdata_entry_get_id (new_entry);
   g_hash_table_insert (self->entries, g_strdup (new_id), g_object_ref (new_entry));
 
-  path = get_entry_path (self, new_entry);
-  g_vfs_job_set_display_name_set_new_path (job, path);
-
-  g_warn_if_fail (g_strcmp0 (filename, path) == 0);
-
+  g_vfs_job_set_display_name_set_new_path (job, filename);
   g_vfs_job_succeeded (G_VFS_JOB (job));
 
  out:
   g_clear_object (&new_entry);
   g_free (id);
-  g_free (path);
+  g_free (unescaped_filename);
   g_debug ("- set_display_name\n");
   g_rec_mutex_unlock (&self->mutex);
 }


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