summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMayank Sharma <mayank8019@gmail.com>2019-04-29 09:40:54 +0530
committerOndrej Holy <oholy@redhat.com>2019-05-09 07:12:11 +0000
commitbc8ac1055355a82bc32819569d048d1495793584 (patch)
tree376a2809197cc9abceb9fabe3e50df8decc789a6
parent38d1902e3f02b3f80aa5feccda9d3ac550a1efdc (diff)
downloadgvfs-bc8ac1055355a82bc32819569d048d1495793584.tar.gz
google: Support deleting shared Google Drive files
`g_file_delete ()` currently fails for shared files with "Permission denied" error (if they have a different owner and only one parent folder). This is because `gdata_service_delete_entry ()` can't be used for files, which have a different owner. `gdata_documents_service_remove_entry_from_folder ()` has to be used instead in this case (as well as for cases when the files have multiple parents). This fix depends on https://gitlab.gnome.org/GNOME/libgdata/merge_requests/5, which fixes `gdata_documents_service_remove_entry_from_folder ()` implementation to make it work for files with only one parent. Fixes: https://gitlab.gnome.org/GNOME/gvfs/issues/265
-rw-r--r--daemon/gvfsbackendgoogle.c80
1 files changed, 75 insertions, 5 deletions
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
index dfb35503..e60ad510 100644
--- a/daemon/gvfsbackendgoogle.c
+++ b/daemon/gvfsbackendgoogle.c
@@ -357,6 +357,55 @@ get_parent_ids (GVfsBackendGoogle *self,
/* ---------------------------------------------------------------------------------------------------- */
static gboolean
+is_owner (GVfsBackendGoogle *self,
+ GDataEntry *entry,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GDataFeed *acl_feed;
+ GDataAccessRule *rule;
+ GList *l;
+ GError *local_error = NULL;
+ gboolean ret_val = FALSE;
+
+ acl_feed = gdata_access_handler_get_rules (GDATA_ACCESS_HANDLER (GDATA_DOCUMENTS_ENTRY (entry)),
+ GDATA_SERVICE (self->service),
+ cancellable,
+ NULL,
+ NULL,
+ &local_error);
+
+ if (local_error != NULL)
+ {
+ sanitize_error (&local_error);
+ g_propagate_error (error, local_error);
+
+ goto out;
+ }
+
+ for (l = gdata_feed_get_entries (acl_feed); l != NULL; l = l->next)
+ {
+ const gchar *scope_value, *scope_type, *role;
+ rule = GDATA_ACCESS_RULE (l->data);
+ role = gdata_access_rule_get_role (rule);
+ gdata_access_rule_get_scope (rule, &scope_type, &scope_value);
+
+ if (g_strcmp0 (scope_value, self->account_identity) == 0 &&
+ g_strcmp0 (role, GDATA_DOCUMENTS_ACCESS_ROLE_OWNER) == 0)
+ {
+ ret_val = TRUE;
+ goto out;
+ }
+ }
+
+ out:
+ g_clear_object (&acl_feed);
+ return ret_val;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
insert_entry_full (GVfsBackendGoogle *self,
GDataEntry *entry,
gboolean track_dir_collisions)
@@ -1304,6 +1353,8 @@ g_vfs_backend_google_delete (GVfsBackend *_self,
GError *error;
gchar *entry_path = NULL;
GList *parent_ids;
+ gboolean owner = FALSE;
+ guint parent_ids_len;
g_rec_mutex_lock (&self->mutex);
g_debug ("+ delete: %s\n", filename);
@@ -1339,11 +1390,26 @@ g_vfs_backend_google_delete (GVfsBackend *_self,
error = NULL;
- /* gdata_documents_service_remove_entry_from_folder seems doesn't work for one parent. */
- parent_ids = get_parent_ids (self, entry);
- if (g_list_length (parent_ids) > 1)
+ owner = is_owner (self, GDATA_ENTRY (entry), cancellable, &error);
+ if (error != NULL)
{
- new_entry = gdata_documents_service_remove_entry_from_folder (self->service, GDATA_DOCUMENTS_ENTRY (entry), GDATA_DOCUMENTS_FOLDER (parent), cancellable, &error);
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+ g_error_free (error);
+ goto out;
+ }
+
+ parent_ids = get_parent_ids (self, entry);
+ parent_ids_len = g_list_length (parent_ids);
+ if (parent_ids_len > 1 || !owner)
+ {
+ /* gdata_documents_service_remove_entry_from_folder () returns the
+ * updated entry variable provided as argument with an increased ref.
+ * The ref count after the next line shall be 2. */
+ new_entry = gdata_documents_service_remove_entry_from_folder (self->service,
+ GDATA_DOCUMENTS_ENTRY (entry),
+ GDATA_DOCUMENTS_FOLDER (parent),
+ cancellable,
+ &error);
}
else
{
@@ -1361,7 +1427,11 @@ g_vfs_backend_google_delete (GVfsBackend *_self,
goto out;
}
- if (new_entry)
+ /* In case of files owned by somebody else, the new entry is returned
+ * even if it had just one parent before the operation. The backend
+ * doesn't care about entries without parents (i.e. entries with
+ * parent_ids_len = 1), so let's ignore it. */
+ if (new_entry && parent_ids_len > 1)
insert_entry (self, GDATA_ENTRY (new_entry));
g_hash_table_foreach (self->monitors, emit_delete_event, entry_path);
g_vfs_job_succeeded (G_VFS_JOB (job));