diff options
author | Mayank Sharma <mayank8019@gmail.com> | 2019-04-29 09:40:54 +0530 |
---|---|---|
committer | Ondrej Holy <oholy@redhat.com> | 2019-05-09 07:12:11 +0000 |
commit | bc8ac1055355a82bc32819569d048d1495793584 (patch) | |
tree | 376a2809197cc9abceb9fabe3e50df8decc789a6 | |
parent | 38d1902e3f02b3f80aa5feccda9d3ac550a1efdc (diff) | |
download | gvfs-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.c | 80 |
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)); |