commit eed3b5cce2c17a139bfa333cdd3c7c9f634f848c Author: CentOS Sources Date: Tue Nov 8 01:43:54 2022 -0500 import gvfs-1.36.2-14.el8 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7d60f6d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/gvfs-1.36.2.tar.xz diff --git a/.gvfs.metadata b/.gvfs.metadata new file mode 100644 index 0000000..1ed6813 --- /dev/null +++ b/.gvfs.metadata @@ -0,0 +1 @@ +fb5fe05f0661da8c88f5fa41014bcd526ad39993 SOURCES/gvfs-1.36.2.tar.xz diff --git a/SOURCES/admin-Add-query_info_on_read-write-functionality.patch b/SOURCES/admin-Add-query_info_on_read-write-functionality.patch new file mode 100644 index 0000000..b0a27e7 --- /dev/null +++ b/SOURCES/admin-Add-query_info_on_read-write-functionality.patch @@ -0,0 +1,127 @@ +From 5cd76d627f4d1982b6e77a0e271ef9301732d09e Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Thu, 23 May 2019 10:24:36 +0200 +Subject: [PATCH] admin: Add query_info_on_read/write functionality + +Admin backend doesn't implement query_info_on_read/write which might +potentially lead to some race conditions which aren't really wanted +especially in case of admin backend. Let's add this missing functionality. +--- + daemon/gvfsbackendadmin.c | 79 +++++++++++++++++++++++++++++++++------ + 1 file changed, 67 insertions(+), 12 deletions(-) + +diff --git a/daemon/gvfsbackendadmin.c b/daemon/gvfsbackendadmin.c +index 65a979e7..23d16f16 100644 +--- a/daemon/gvfsbackendadmin.c ++++ b/daemon/gvfsbackendadmin.c +@@ -42,6 +42,8 @@ + #include "gvfsjobopenforwrite.h" + #include "gvfsjobqueryattributes.h" + #include "gvfsjobqueryinfo.h" ++#include "gvfsjobqueryinforead.h" ++#include "gvfsjobqueryinfowrite.h" + #include "gvfsjobread.h" + #include "gvfsjobseekread.h" + #include "gvfsjobseekwrite.h" +@@ -155,6 +157,19 @@ complete_job (GVfsJob *job, + g_vfs_job_succeeded (job); + } + ++static void ++fix_file_info (GFileInfo *info) ++{ ++ /* Override read/write flags, since the above call will use access() ++ * to determine permissions, which does not honor our privileged ++ * capabilities. ++ */ ++ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ, TRUE); ++ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, TRUE); ++ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, TRUE); ++ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, TRUE); ++} ++ + static void + do_query_info (GVfsBackend *backend, + GVfsJobQueryInfo *query_info_job, +@@ -180,19 +195,57 @@ do_query_info (GVfsBackend *backend, + if (error != NULL) + goto out; + +- /* Override read/write flags, since the above call will use access() +- * to determine permissions, which does not honor our privileged +- * capabilities. +- */ +- g_file_info_set_attribute_boolean (real_info, +- G_FILE_ATTRIBUTE_ACCESS_CAN_READ, TRUE); +- g_file_info_set_attribute_boolean (real_info, +- G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, TRUE); +- g_file_info_set_attribute_boolean (real_info, +- G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, TRUE); +- g_file_info_set_attribute_boolean (real_info, +- G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, TRUE); ++ fix_file_info (real_info); ++ g_file_info_copy_into (real_info, info); ++ g_object_unref (real_info); ++ ++ out: ++ complete_job (job, error); ++} ++ ++static void ++do_query_info_on_read (GVfsBackend *backend, ++ GVfsJobQueryInfoRead *query_info_job, ++ GVfsBackendHandle handle, ++ GFileInfo *info, ++ GFileAttributeMatcher *matcher) ++{ ++ GVfsJob *job = G_VFS_JOB (query_info_job); ++ GFileInputStream *stream = handle; ++ GError *error = NULL; ++ GFileInfo *real_info; ++ ++ real_info = g_file_input_stream_query_info (stream, query_info_job->attributes, ++ job->cancellable, &error); ++ if (error != NULL) ++ goto out; ++ ++ fix_file_info (real_info); ++ g_file_info_copy_into (real_info, info); ++ g_object_unref (real_info); ++ ++ out: ++ complete_job (job, error); ++} ++ ++static void ++do_query_info_on_write (GVfsBackend *backend, ++ GVfsJobQueryInfoWrite *query_info_job, ++ GVfsBackendHandle handle, ++ GFileInfo *info, ++ GFileAttributeMatcher *matcher) ++{ ++ GVfsJob *job = G_VFS_JOB (query_info_job); ++ GFileOutputStream *stream = handle; ++ GError *error = NULL; ++ GFileInfo *real_info; ++ ++ real_info = g_file_output_stream_query_info (stream, query_info_job->attributes, ++ job->cancellable, &error); ++ if (error != NULL) ++ goto out; + ++ fix_file_info (real_info); + g_file_info_copy_into (real_info, info); + g_object_unref (real_info); + +@@ -868,6 +921,8 @@ g_vfs_backend_admin_class_init (GVfsBackendAdminClass * klass) + backend_class->mount = do_mount; + backend_class->open_for_read = do_open_for_read; + backend_class->query_info = do_query_info; ++ backend_class->query_info_on_read = do_query_info_on_read; ++ backend_class->query_info_on_write = do_query_info_on_write; + backend_class->read = do_read; + backend_class->create = do_create; + backend_class->append_to = do_append_to; +-- +2.23.0 + diff --git a/SOURCES/admin-Ensure-correct-ownership-when-moving-to-file-u.patch b/SOURCES/admin-Ensure-correct-ownership-when-moving-to-file-u.patch new file mode 100644 index 0000000..f5e483a --- /dev/null +++ b/SOURCES/admin-Ensure-correct-ownership-when-moving-to-file-u.patch @@ -0,0 +1,80 @@ +From d5dfd823c94045488aef8727c553f1e0f7666b90 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Fri, 24 May 2019 09:43:43 +0200 +Subject: [PATCH] admin: Ensure correct ownership when moving to file:// uri + +User and group is not restored properly when moving (or copying with +G_FILE_COPY_ALL_METADATA) from admin:// to file://, because it is handled +by GIO fallback code, which doesn't run with root permissions. Let's +handle this case with pull method to ensure correct ownership. +--- + daemon/gvfsbackendadmin.c | 46 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 46 insertions(+) + +diff --git a/daemon/gvfsbackendadmin.c b/daemon/gvfsbackendadmin.c +index 32b51b1a..9a7e8295 100644 +--- a/daemon/gvfsbackendadmin.c ++++ b/daemon/gvfsbackendadmin.c +@@ -807,6 +807,51 @@ do_move (GVfsBackend *backend, + complete_job (job, error); + } + ++static void ++do_pull (GVfsBackend *backend, ++ GVfsJobPull *pull_job, ++ const char *source, ++ const char *local_path, ++ GFileCopyFlags flags, ++ gboolean remove_source, ++ GFileProgressCallback progress_callback, ++ gpointer progress_callback_data) ++{ ++ GVfsBackendAdmin *self = G_VFS_BACKEND_ADMIN (backend); ++ GVfsJob *job = G_VFS_JOB (pull_job); ++ GError *error = NULL; ++ GFile *src_file, *dst_file; ++ ++ /* Pull method is necessary when user/group needs to be restored, return ++ * G_IO_ERROR_NOT_SUPPORTED in other cases to proceed with the fallback code. ++ */ ++ if (!(flags & G_FILE_COPY_ALL_METADATA)) ++ { ++ g_vfs_job_failed_literal (G_VFS_JOB (job), G_IO_ERROR, ++ G_IO_ERROR_NOT_SUPPORTED, ++ _("Operation not supported")); ++ return; ++ } ++ ++ if (!check_permission (self, job)) ++ return; ++ ++ src_file = g_file_new_for_path (source); ++ dst_file = g_file_new_for_path (local_path); ++ ++ if (remove_source) ++ g_file_move (src_file, dst_file, flags, job->cancellable, ++ progress_callback, progress_callback_data, &error); ++ else ++ g_file_copy (src_file, dst_file, flags, job->cancellable, ++ progress_callback, progress_callback_data, &error); ++ ++ g_object_unref (src_file); ++ g_object_unref (dst_file); ++ ++ complete_job (job, error); ++} ++ + static void + do_query_settable_attributes (GVfsBackend *backend, + GVfsJobQueryAttributes *query_job, +@@ -927,6 +972,7 @@ g_vfs_backend_admin_class_init (GVfsBackendAdminClass * klass) + backend_class->set_attribute = do_set_attribute; + backend_class->delete = do_delete; + backend_class->move = do_move; ++ backend_class->pull = do_pull; + backend_class->query_settable_attributes = do_query_settable_attributes; + backend_class->query_writable_namespaces = do_query_writable_namespaces; + } +-- +2.23.0 + diff --git a/SOURCES/admin-Prevent-access-if-any-authentication-agent-isn.patch b/SOURCES/admin-Prevent-access-if-any-authentication-agent-isn.patch new file mode 100644 index 0000000..63b0c74 --- /dev/null +++ b/SOURCES/admin-Prevent-access-if-any-authentication-agent-isn.patch @@ -0,0 +1,42 @@ +From d8d0c8c40049cfd824b2b90d0cd47914052b9811 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Wed, 2 Jan 2019 17:13:27 +0100 +Subject: [PATCH] admin: Prevent access if any authentication agent isn't + available + +The backend currently allows to access and modify files without prompting +for password if any polkit authentication agent isn't available. This seems +isn't usually problem, because polkit agents are integral parts of +graphical environments / linux distributions. The agents can't be simply +disabled without root permissions and are automatically respawned. However, +this might be a problem in some non-standard cases. + +This affects only users which belong to wheel group (i.e. those who are +already allowed to use sudo). It doesn't allow privilege escalation for +users, who don't belong to that group. + +Let's return permission denied error also when the subject can't be +authorized by any polkit agent to prevent this behavior. + +Closes: https://gitlab.gnome.org/GNOME/gvfs/issues/355 +--- + daemon/gvfsbackendadmin.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/daemon/gvfsbackendadmin.c b/daemon/gvfsbackendadmin.c +index ec0f2392..0f849008 100644 +--- a/daemon/gvfsbackendadmin.c ++++ b/daemon/gvfsbackendadmin.c +@@ -130,8 +130,7 @@ check_permission (GVfsBackendAdmin *self, + return FALSE; + } + +- is_authorized = polkit_authorization_result_get_is_authorized (result) || +- polkit_authorization_result_get_is_challenge (result); ++ is_authorized = polkit_authorization_result_get_is_authorized (result); + + g_object_unref (result); + +-- +2.20.1 + diff --git a/SOURCES/admin-Use-fsuid-to-ensure-correct-file-ownership.patch b/SOURCES/admin-Use-fsuid-to-ensure-correct-file-ownership.patch new file mode 100644 index 0000000..a911d1d --- /dev/null +++ b/SOURCES/admin-Use-fsuid-to-ensure-correct-file-ownership.patch @@ -0,0 +1,87 @@ +From d7d362995aa0cb8905c8d5c2a2a4c305d2ffff80 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Thu, 23 May 2019 10:33:30 +0200 +Subject: [PATCH] admin: Use fsuid to ensure correct file ownership + +Files created over admin backend should be owned by root, but they are +owned by the user itself. This is because the daemon drops the uid to +make dbus connection work. Use fsuid and euid to fix this issue. + +Closes: https://gitlab.gnome.org/GNOME/gvfs/issues/21 +--- + daemon/gvfsbackendadmin.c | 29 +++++++---------------------- + 1 file changed, 7 insertions(+), 22 deletions(-) + +diff --git a/daemon/gvfsbackendadmin.c b/daemon/gvfsbackendadmin.c +index a74d09cf..32b51b1a 100644 +--- a/daemon/gvfsbackendadmin.c ++++ b/daemon/gvfsbackendadmin.c +@@ -157,19 +157,6 @@ complete_job (GVfsJob *job, + g_vfs_job_succeeded (job); + } + +-static void +-fix_file_info (GFileInfo *info) +-{ +- /* Override read/write flags, since the above call will use access() +- * to determine permissions, which does not honor our privileged +- * capabilities. +- */ +- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ, TRUE); +- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, TRUE); +- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, TRUE); +- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, TRUE); +-} +- + static void + do_query_info (GVfsBackend *backend, + GVfsJobQueryInfo *query_info_job, +@@ -195,7 +182,6 @@ do_query_info (GVfsBackend *backend, + if (error != NULL) + goto out; + +- fix_file_info (real_info); + g_file_info_copy_into (real_info, info); + g_object_unref (real_info); + +@@ -220,7 +206,6 @@ do_query_info_on_read (GVfsBackend *backend, + if (error != NULL) + goto out; + +- fix_file_info (real_info); + g_file_info_copy_into (real_info, info); + g_object_unref (real_info); + +@@ -245,7 +230,6 @@ do_query_info_on_write (GVfsBackend *backend, + if (error != NULL) + goto out; + +- fix_file_info (real_info); + g_file_info_copy_into (real_info, info); + g_object_unref (real_info); + +@@ -977,14 +961,15 @@ acquire_caps (uid_t uid) + struct __user_cap_header_struct hdr; + struct __user_cap_data_struct data; + +- /* Tell kernel not clear capabilities when dropping root */ +- if (prctl (PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) +- g_error ("prctl(PR_SET_KEEPCAPS) failed"); +- +- /* Drop root uid, but retain the required permitted caps */ +- if (setuid (uid) < 0) ++ /* Set euid to user to make dbus work */ ++ if (seteuid (uid) < 0) + g_error ("unable to drop privs"); + ++ /* Set fsuid to still behave like root when working with files */ ++ setfsuid (0); ++ if (setfsuid (-1) != 0) ++ g_error ("setfsuid failed"); ++ + memset (&hdr, 0, sizeof(hdr)); + hdr.version = _LINUX_CAPABILITY_VERSION; + +-- +2.23.0 + diff --git a/SOURCES/daemon-Handle-lockdown-option-to-disable-writing.patch b/SOURCES/daemon-Handle-lockdown-option-to-disable-writing.patch new file mode 100644 index 0000000..211c3ba --- /dev/null +++ b/SOURCES/daemon-Handle-lockdown-option-to-disable-writing.patch @@ -0,0 +1,385 @@ +From af4d0d88604af7c196e461a743f2d1e81239d76a Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Tue, 14 May 2019 09:31:37 +0200 +Subject: [PATCH 2/3] daemon: Handle lockdown option to disable writing + +Handle the new mount-removable-storage-devices-as-read-only option of +org.gnome.desktop.lockdown schema and present AFC, MTP, GPhoto2 devices +as read-only if enabled. +--- + daemon/gvfsbackend.c | 62 ++++++++++++++++++++++++++++++++-- + daemon/gvfsbackend.h | 6 ++++ + daemon/gvfsbackendafc.c | 2 ++ + daemon/gvfsbackendgphoto2.c | 1 + + daemon/gvfsbackendmtp.c | 1 + + daemon/gvfsjobcopy.c | 7 ++++ + daemon/gvfsjobdelete.c | 7 ++++ + daemon/gvfsjobmakedirectory.c | 7 ++++ + daemon/gvfsjobmakesymlink.c | 7 ++++ + daemon/gvfsjobmove.c | 7 ++++ + daemon/gvfsjobopenforwrite.c | 7 ++++ + daemon/gvfsjobpush.c | 7 ++++ + daemon/gvfsjobqueryfsinfo.c | 11 ++---- + daemon/gvfsjobsetattribute.c | 7 ++++ + daemon/gvfsjobsetdisplayname.c | 7 ++++ + daemon/gvfsjobtrash.c | 7 ++++ + 16 files changed, 143 insertions(+), 10 deletions(-) + +diff --git a/daemon/gvfsbackend.c b/daemon/gvfsbackend.c +index 4fd3455c..599733ef 100644 +--- a/daemon/gvfsbackend.c ++++ b/daemon/gvfsbackend.c +@@ -80,6 +80,9 @@ struct _GVfsBackendPrivate + char *default_location; + GMountSpec *mount_spec; + gboolean block_requests; ++ ++ GSettings *lockdown_settings; ++ gboolean readonly_lockdown; + }; + + +@@ -155,7 +158,9 @@ g_vfs_backend_finalize (GObject *object) + g_free (backend->priv->default_location); + if (backend->priv->mount_spec) + g_mount_spec_unref (backend->priv->mount_spec); +- ++ ++ g_clear_object (&backend->priv->lockdown_settings); ++ + if (G_OBJECT_CLASS (g_vfs_backend_parent_class)->finalize) + (*G_OBJECT_CLASS (g_vfs_backend_parent_class)->finalize) (object); + } +@@ -587,7 +592,29 @@ g_vfs_backend_add_auto_info (GVfsBackend *backend, + g_file_attribute_matcher_matches (matcher, + G_FILE_ATTRIBUTE_THUMBNAILING_FAILED))) + get_thumbnail_attributes (uri, info); +- ++ ++ if (backend->priv->readonly_lockdown) ++ { ++ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, FALSE); ++ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, FALSE); ++ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE); ++ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE); ++ } ++} ++ ++void ++g_vfs_backend_add_auto_fs_info (GVfsBackend *backend, ++ GFileAttributeMatcher *matcher, ++ GFileInfo *info) ++{ ++ const char *type; ++ ++ type = g_vfs_backend_get_backend_type (backend); ++ if (type) ++ g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_GVFS_BACKEND, type); ++ ++ if (backend->priv->readonly_lockdown) ++ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE); + } + + void +@@ -1047,3 +1074,34 @@ g_vfs_backend_force_unmount (GVfsBackend *backend) + (GAsyncReadyCallback) forced_unregister_mount_callback, + NULL); + } ++ ++static void ++lockdown_settings_changed (GSettings *settings, ++ gchar *key, ++ gpointer user_data) ++{ ++ GVfsBackend *backend = G_VFS_BACKEND (user_data); ++ ++ backend->priv->readonly_lockdown = g_settings_get_boolean (settings, ++ "mount-removable-storage-devices-as-read-only"); ++} ++ ++ ++void ++g_vfs_backend_handle_readonly_lockdown (GVfsBackend *backend) ++{ ++ backend->priv->lockdown_settings = g_settings_new ("org.gnome.desktop.lockdown"); ++ backend->priv->readonly_lockdown = g_settings_get_boolean (backend->priv->lockdown_settings, ++ "mount-removable-storage-devices-as-read-only"); ++ g_signal_connect_object (backend->priv->lockdown_settings, ++ "changed", ++ G_CALLBACK (lockdown_settings_changed), ++ backend, ++ 0); ++} ++ ++gboolean ++g_vfs_backend_get_readonly_lockdown (GVfsBackend *backend) ++{ ++ return backend->priv->readonly_lockdown; ++} +diff --git a/daemon/gvfsbackend.h b/daemon/gvfsbackend.h +index 9c7476cf..431dd290 100644 +--- a/daemon/gvfsbackend.h ++++ b/daemon/gvfsbackend.h +@@ -516,6 +516,9 @@ void g_vfs_backend_add_auto_info (GVfsBackend + GFileAttributeMatcher *matcher, + GFileInfo *info, + const char *uri); ++void g_vfs_backend_add_auto_fs_info (GVfsBackend *backend, ++ GFileAttributeMatcher *matcher, ++ GFileInfo *info); + + void g_vfs_backend_set_block_requests (GVfsBackend *backend, + gboolean value); +@@ -534,6 +537,9 @@ gboolean g_vfs_backend_invocation_first_handler (GVfsDBusMount *object, + GDBusMethodInvocation *invocation, + GVfsBackend *backend); + ++void g_vfs_backend_handle_readonly_lockdown (GVfsBackend *backend); ++gboolean g_vfs_backend_get_readonly_lockdown (GVfsBackend *backend); ++ + G_END_DECLS + + #endif /* __G_VFS_BACKEND_H__ */ +diff --git a/daemon/gvfsbackendafc.c b/daemon/gvfsbackendafc.c +index b6e6a106..ce68aa45 100644 +--- a/daemon/gvfsbackendafc.c ++++ b/daemon/gvfsbackendafc.c +@@ -2760,6 +2760,8 @@ g_vfs_backend_afc_init (GVfsBackendAfc *self) + } + + g_mutex_init (&self->apps_lock); ++ ++ g_vfs_backend_handle_readonly_lockdown (G_VFS_BACKEND (self)); + } + + static void +diff --git a/daemon/gvfsbackendgphoto2.c b/daemon/gvfsbackendgphoto2.c +index 51e9a3bd..7e50194a 100644 +--- a/daemon/gvfsbackendgphoto2.c ++++ b/daemon/gvfsbackendgphoto2.c +@@ -614,6 +614,7 @@ g_vfs_backend_gphoto2_init (GVfsBackendGphoto2 *gphoto2_backend) + g_mutex_init (&gphoto2_backend->lock); + + g_vfs_backend_set_display_name (backend, "gphoto2"); ++ g_vfs_backend_handle_readonly_lockdown (G_VFS_BACKEND (backend)); + + mount_spec = g_mount_spec_new ("gphoto2"); + g_vfs_backend_set_mount_spec (backend, mount_spec); +diff --git a/daemon/gvfsbackendmtp.c b/daemon/gvfsbackendmtp.c +index e3a25ef2..c4f1e855 100644 +--- a/daemon/gvfsbackendmtp.c ++++ b/daemon/gvfsbackendmtp.c +@@ -379,6 +379,7 @@ g_vfs_backend_mtp_init (GVfsBackendMtp *backend) + g_mutex_init (&backend->mutex); + g_vfs_backend_set_display_name (G_VFS_BACKEND (backend), "mtp"); + g_vfs_backend_set_icon_name (G_VFS_BACKEND (backend), "multimedia-player"); ++ g_vfs_backend_handle_readonly_lockdown (G_VFS_BACKEND (backend)); + + mount_spec = g_mount_spec_new ("mtp"); + g_vfs_backend_set_mount_spec (G_VFS_BACKEND (backend), mount_spec); +diff --git a/daemon/gvfsjobcopy.c b/daemon/gvfsjobcopy.c +index 785d7480..cf33da56 100644 +--- a/daemon/gvfsjobcopy.c ++++ b/daemon/gvfsjobcopy.c +@@ -141,6 +141,13 @@ try (GVfsJob *job) + GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend); + gboolean res; + ++ if (g_vfs_backend_get_readonly_lockdown (op_job->backend)) ++ { ++ g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, ++ _("Filesystem is read-only")); ++ return TRUE; ++ } ++ + if (class->try_copy == NULL) + return FALSE; + +diff --git a/daemon/gvfsjobdelete.c b/daemon/gvfsjobdelete.c +index 92892f15..8d5e5b8e 100644 +--- a/daemon/gvfsjobdelete.c ++++ b/daemon/gvfsjobdelete.c +@@ -120,6 +120,13 @@ try (GVfsJob *job) + GVfsJobDelete *op_job = G_VFS_JOB_DELETE (job); + GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend); + ++ if (g_vfs_backend_get_readonly_lockdown (op_job->backend)) ++ { ++ g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, ++ _("Filesystem is read-only")); ++ return TRUE; ++ } ++ + if (class->try_delete == NULL) + return FALSE; + +diff --git a/daemon/gvfsjobmakedirectory.c b/daemon/gvfsjobmakedirectory.c +index 98bb28d5..56a9c42a 100644 +--- a/daemon/gvfsjobmakedirectory.c ++++ b/daemon/gvfsjobmakedirectory.c +@@ -120,6 +120,13 @@ try (GVfsJob *job) + GVfsJobMakeDirectory *op_job = G_VFS_JOB_MAKE_DIRECTORY (job); + GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend); + ++ if (g_vfs_backend_get_readonly_lockdown (op_job->backend)) ++ { ++ g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, ++ _("Filesystem is read-only")); ++ return TRUE; ++ } ++ + if (class->try_make_directory == NULL) + return FALSE; + +diff --git a/daemon/gvfsjobmakesymlink.c b/daemon/gvfsjobmakesymlink.c +index 2c55e26b..2684b6fd 100644 +--- a/daemon/gvfsjobmakesymlink.c ++++ b/daemon/gvfsjobmakesymlink.c +@@ -124,6 +124,13 @@ try (GVfsJob *job) + GVfsJobMakeSymlink *op_job = G_VFS_JOB_MAKE_SYMLINK (job); + GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend); + ++ if (g_vfs_backend_get_readonly_lockdown (op_job->backend)) ++ { ++ g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, ++ _("Filesystem is read-only")); ++ return TRUE; ++ } ++ + if (class->try_make_symlink == NULL) + return FALSE; + +diff --git a/daemon/gvfsjobmove.c b/daemon/gvfsjobmove.c +index cc4ad220..5903d17a 100644 +--- a/daemon/gvfsjobmove.c ++++ b/daemon/gvfsjobmove.c +@@ -141,6 +141,13 @@ try (GVfsJob *job) + GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend); + gboolean res; + ++ if (g_vfs_backend_get_readonly_lockdown (op_job->backend)) ++ { ++ g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, ++ _("Filesystem is read-only")); ++ return TRUE; ++ } ++ + if (class->try_move == NULL) + return FALSE; + +diff --git a/daemon/gvfsjobopenforwrite.c b/daemon/gvfsjobopenforwrite.c +index 68eae532..60ce64f9 100644 +--- a/daemon/gvfsjobopenforwrite.c ++++ b/daemon/gvfsjobopenforwrite.c +@@ -230,6 +230,13 @@ try (GVfsJob *job) + GVfsJobOpenForWrite *op_job = G_VFS_JOB_OPEN_FOR_WRITE (job); + GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend); + ++ if (g_vfs_backend_get_readonly_lockdown (op_job->backend)) ++ { ++ g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, ++ _("Filesystem is read-only")); ++ return TRUE; ++ } ++ + if (op_job->mode == OPEN_FOR_WRITE_CREATE) + { + if (class->try_create == NULL) +diff --git a/daemon/gvfsjobpush.c b/daemon/gvfsjobpush.c +index d7e48d86..a8df73a8 100644 +--- a/daemon/gvfsjobpush.c ++++ b/daemon/gvfsjobpush.c +@@ -146,6 +146,13 @@ try (GVfsJob *job) + GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend); + gboolean res; + ++ if (g_vfs_backend_get_readonly_lockdown (op_job->backend)) ++ { ++ g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, ++ _("Filesystem is read-only")); ++ return TRUE; ++ } ++ + if (class->try_push == NULL) + return FALSE; + +diff --git a/daemon/gvfsjobqueryfsinfo.c b/daemon/gvfsjobqueryfsinfo.c +index 898052ea..3363311a 100644 +--- a/daemon/gvfsjobqueryfsinfo.c ++++ b/daemon/gvfsjobqueryfsinfo.c +@@ -147,15 +147,10 @@ create_reply (GVfsJob *job, + GDBusMethodInvocation *invocation) + { + GVfsJobQueryFsInfo *op_job = G_VFS_JOB_QUERY_FS_INFO (job); +- const char *type; +- +- type = g_vfs_backend_get_backend_type (op_job->backend); +- +- if (type) +- g_file_info_set_attribute_string (op_job->file_info, +- G_FILE_ATTRIBUTE_GVFS_BACKEND, +- type); + ++ g_vfs_backend_add_auto_fs_info (op_job->backend, ++ op_job->attribute_matcher, ++ op_job->file_info); + g_file_info_set_attribute_mask (op_job->file_info, + op_job->attribute_matcher); + +diff --git a/daemon/gvfsjobsetattribute.c b/daemon/gvfsjobsetattribute.c +index 1efe7c94..ac7618a4 100644 +--- a/daemon/gvfsjobsetattribute.c ++++ b/daemon/gvfsjobsetattribute.c +@@ -146,6 +146,13 @@ try (GVfsJob *job) + GVfsJobSetAttribute *op_job = G_VFS_JOB_SET_ATTRIBUTE (job); + GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend); + ++ if (g_vfs_backend_get_readonly_lockdown (op_job->backend)) ++ { ++ g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, ++ _("Filesystem is read-only")); ++ return TRUE; ++ } ++ + if (class->try_set_attribute == NULL) + return FALSE; + +diff --git a/daemon/gvfsjobsetdisplayname.c b/daemon/gvfsjobsetdisplayname.c +index badb10dd..e12ae879 100644 +--- a/daemon/gvfsjobsetdisplayname.c ++++ b/daemon/gvfsjobsetdisplayname.c +@@ -124,6 +124,13 @@ try (GVfsJob *job) + GVfsJobSetDisplayName *op_job = G_VFS_JOB_SET_DISPLAY_NAME (job); + GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend); + ++ if (g_vfs_backend_get_readonly_lockdown (op_job->backend)) ++ { ++ g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, ++ _("Filesystem is read-only")); ++ return TRUE; ++ } ++ + if (class->try_set_display_name == NULL) + return FALSE; + +diff --git a/daemon/gvfsjobtrash.c b/daemon/gvfsjobtrash.c +index 1738f8a2..5234ebf8 100644 +--- a/daemon/gvfsjobtrash.c ++++ b/daemon/gvfsjobtrash.c +@@ -119,6 +119,13 @@ try (GVfsJob *job) + GVfsJobTrash *op_job = G_VFS_JOB_TRASH (job); + GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend); + ++ if (g_vfs_backend_get_readonly_lockdown (op_job->backend)) ++ { ++ g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, ++ _("Filesystem is read-only")); ++ return TRUE; ++ } ++ + if (class->try_trash == NULL) + return FALSE; + +-- +2.21.0 + diff --git a/SOURCES/daemon-Prevent-spawning-new-daemons-if-outgoing-oper.patch b/SOURCES/daemon-Prevent-spawning-new-daemons-if-outgoing-oper.patch new file mode 100644 index 0000000..305c7e5 --- /dev/null +++ b/SOURCES/daemon-Prevent-spawning-new-daemons-if-outgoing-oper.patch @@ -0,0 +1,99 @@ +From 396216f71abf6907efd1383ca0d1a597918cd83d Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Thu, 11 Oct 2018 17:47:59 +0200 +Subject: [PATCH] daemon: Prevent spawning new daemons if outgoing operation + exists + +A new daemon is always spawned if MountLocation method (or LookupMount for +automounted) is called and the respective mount isn't registered yet. This +is not usually an issue, because the redundant daemons are consequently +terminated. However, this is a problem if mount operations hang for some reason. +This may happen e.g. with trash backend due to stale NFS mounts. Consequently, +new and new daemons are spawned which may lead to system failures due to lack +of system resources. See the following downstream bug report: +https://bugzilla.redhat.com/show_bug.cgi?id=1632960 + +Let's fix that behavior simply by preventing spawning of new daemons if +respective outgoing mount operations exist. + +https://gitlab.gnome.org/GNOME/gvfs/merge_requests/19 +--- + daemon/mount.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/daemon/mount.c b/daemon/mount.c +index e242666d..33cae597 100644 +--- a/daemon/mount.c ++++ b/daemon/mount.c +@@ -73,6 +73,7 @@ typedef void (*MountCallback) (VfsMountable *mountable, + + static GList *mountables = NULL; + static GList *mounts = NULL; ++static GList *ongoing = NULL; + + static gboolean fuse_available; + +@@ -253,6 +254,7 @@ typedef struct { + char *obj_path; + gboolean spawned; + GVfsDBusSpawner *spawner; ++ GList *pending; /* MountData */ + } MountData; + + static void spawn_mount (MountData *data); +@@ -264,6 +266,7 @@ mount_data_free (MountData *data) + g_mount_spec_unref (data->mount_spec); + g_free (data->obj_path); + g_clear_object (&data->spawner); ++ g_list_free_full (data->pending, (GDestroyNotify) mount_data_free); + + g_free (data); + } +@@ -271,7 +274,17 @@ mount_data_free (MountData *data) + static void + mount_finish (MountData *data, GError *error) + { ++ GList *l; ++ ++ ongoing = g_list_remove (ongoing, data); ++ + data->callback (data->mountable, error, data->user_data); ++ for (l = data->pending; l != NULL; l = l->next) ++ { ++ MountData *pending_data = l->data; ++ pending_data->callback (pending_data->mountable, error, pending_data->user_data); ++ } ++ + mount_data_free (data); + } + +@@ -493,6 +506,7 @@ mountable_mount (VfsMountable *mountable, + gpointer user_data) + { + MountData *data; ++ GList *l; + + data = g_new0 (MountData, 1); + data->automount = automount; +@@ -502,6 +516,18 @@ mountable_mount (VfsMountable *mountable, + data->callback = callback; + data->user_data = user_data; + ++ for (l = ongoing; l != NULL; l = l->next) ++ { ++ MountData *ongoing_data = l->data; ++ if (g_mount_spec_equal (ongoing_data->mount_spec, mount_spec)) ++ { ++ ongoing_data->pending = g_list_append (ongoing_data->pending, data); ++ return; ++ } ++ } ++ ++ ongoing = g_list_append (ongoing, data); ++ + if (mountable->dbus_name == NULL) + spawn_mount (data); + else +-- +2.20.1 + diff --git a/SOURCES/goa-Add-support-for-certificate-prompts.patch b/SOURCES/goa-Add-support-for-certificate-prompts.patch new file mode 100644 index 0000000..fef2e61 --- /dev/null +++ b/SOURCES/goa-Add-support-for-certificate-prompts.patch @@ -0,0 +1,164 @@ +From bbc95d6716ac491489f059c68a6dd258e38aee79 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Mon, 25 Nov 2019 16:53:31 +0100 +Subject: [PATCH] goa: Add support for certificate prompts + +Since commit f5ee590e, it is not possible to access Nextcloud/ownCloud +shares with self-signed (or invalid) certificates. This is because +the mount operation is handled by GOA volume monitor and the prompt +to accept certificate is not shown. Let's update the volume monitor +to handle just passwords and show the prompt to the client. + +Fixes: https://gitlab.gnome.org/GNOME/gvfs/issues/251 +--- + monitor/goa/goavolume.c | 98 ++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 96 insertions(+), 2 deletions(-) + +diff --git a/monitor/goa/goavolume.c b/monitor/goa/goavolume.c +index c077dd94..5e9097c6 100644 +--- a/monitor/goa/goavolume.c ++++ b/monitor/goa/goavolume.c +@@ -64,6 +64,7 @@ G_DEFINE_TYPE_EXTENDED (GVfsGoaVolume, g_vfs_goa_volume, G_TYPE_OBJECT, 0, + typedef struct + { + GMountOperation *mount_operation; ++ GMountOperation *mount_operation_orig; + gchar *passwd; + } MountOp; + +@@ -72,6 +73,13 @@ mount_op_free (MountOp *data) + { + g_clear_object (&data->mount_operation); + g_free (data->passwd); ++ ++ if (data->mount_operation_orig != NULL) ++ { ++ g_signal_handlers_disconnect_by_data (data->mount_operation_orig, data); ++ g_object_unref (data->mount_operation_orig); ++ } ++ + g_slice_free (MountOp, data); + } + +@@ -97,6 +105,88 @@ account_attention_needed_cb (GObject *_object, GParamSpec *pspec, gpointer user_ + + /* ---------------------------------------------------------------------------------------------------- */ + ++GType g_vfs_goa_mount_operation_get_type (void) G_GNUC_CONST; ++ ++typedef struct ++{ ++ GMountOperation parent_instance; ++} GVfsGoaMountOperation; ++ ++typedef struct ++{ ++ GMountOperationClass parent_class; ++} GVfsGoaMountOperationClass; ++ ++static GMountOperation * ++g_vfs_goa_mount_operation_new (void) ++{ ++ return G_MOUNT_OPERATION (g_object_new (g_vfs_goa_mount_operation_get_type (), NULL)); ++} ++ ++G_DEFINE_TYPE (GVfsGoaMountOperation, g_vfs_goa_mount_operation, G_TYPE_MOUNT_OPERATION) ++ ++static void ++g_vfs_goa_mount_operation_init (GVfsGoaMountOperation *mount_operation) ++{ ++} ++ ++static void ++g_vfs_goa_mount_operation_ask_question (GMountOperation *op, ++ const char *message, ++ const char *choices[]) ++{ ++ /* This is needed to prevent G_MOUNT_OPERATION_UNHANDLED reply in idle. */ ++} ++ ++static void ++g_vfs_goa_mount_operation_class_init (GVfsGoaMountOperationClass *klass) ++{ ++ GMountOperationClass *mount_op_class; ++ ++ mount_op_class = G_MOUNT_OPERATION_CLASS (klass); ++ mount_op_class->ask_question = g_vfs_goa_mount_operation_ask_question; ++} ++ ++/* ---------------------------------------------------------------------------------------------------- */ ++ ++static void ++ask_question_reply_cb (GMountOperation *op, ++ GMountOperationResult result, ++ gpointer user_data) ++{ ++ MountOp *data = g_task_get_task_data (user_data); ++ ++ g_mount_operation_set_choice (data->mount_operation, ++ g_mount_operation_get_choice (op)); ++ g_mount_operation_reply (data->mount_operation, result); ++} ++ ++static void ++mount_operation_ask_question_cb (GMountOperation *op, ++ gchar *message, ++ GStrv choices, ++ gpointer user_data) ++{ ++ MountOp *data = g_task_get_task_data (user_data); ++ ++ if (data->mount_operation_orig != NULL) ++ { ++ g_signal_connect (data->mount_operation_orig, ++ "reply", ++ G_CALLBACK (ask_question_reply_cb), ++ user_data); ++ g_signal_emit_by_name (data->mount_operation_orig, ++ "ask-question", ++ message, ++ choices); ++ } ++ else ++ { ++ g_mount_operation_reply (data->mount_operation, ++ G_MOUNT_OPERATION_UNHANDLED); ++ } ++} ++ + static void + mount_operation_ask_password_cb (GMountOperation *op, + gchar *message, +@@ -412,7 +502,7 @@ g_vfs_goa_volume_get_uuid (GVolume *_self) + static void + g_vfs_goa_volume_mount (GVolume *_self, + GMountMountFlags flags, +- GMountOperation *mount_operation, ++ GMountOperation *mount_operation_orig, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +@@ -423,6 +513,9 @@ g_vfs_goa_volume_mount (GVolume *_self, + GoaAccount *account; + + data = g_slice_new0 (MountOp); ++ if (mount_operation_orig != NULL) ++ data->mount_operation_orig = g_object_ref (mount_operation_orig); ++ + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_source_tag (task, g_vfs_goa_volume_mount); + g_task_set_task_data (task, data, (GDestroyNotify) mount_op_free); +@@ -431,8 +524,9 @@ g_vfs_goa_volume_mount (GVolume *_self, + * monitor because it is set up to emit MountOpAskPassword on + * ask-password. + */ +- data->mount_operation = g_mount_operation_new (); ++ data->mount_operation = g_vfs_goa_mount_operation_new (); + g_signal_connect (data->mount_operation, "ask-password", G_CALLBACK (mount_operation_ask_password_cb), task); ++ g_signal_connect (data->mount_operation, "ask-question", G_CALLBACK (mount_operation_ask_question_cb), task); + + account = goa_object_peek_account (self->object); + goa_account_call_ensure_credentials (account, cancellable, ensure_credentials_cb, task); +-- +2.28.0 + diff --git a/SOURCES/google-performance-fixes.patch b/SOURCES/google-performance-fixes.patch new file mode 100644 index 0000000..3225c59 --- /dev/null +++ b/SOURCES/google-performance-fixes.patch @@ -0,0 +1,2724 @@ +From ea26e6ddefca9b5f75f3d7485e420729bc038852 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Tue, 5 Jun 2018 13:04:15 +0200 +Subject: [PATCH 01/14] google: Do not create .desktop files for native files + +Currently, .desktop file with a link to the original location is provided, +when a native file is opened because Google doesn't provide its proprietary +formats and GLocalFile doesn't know G_FILE_TYPE_SHORTCUT. It is a bit +tricky and confusing, among other because the .desktop files aren't +automatically converted back to native files when writing. + +What is worse, Nautilus has dropped support for .desktop files recently, +so you see "There was an error launching the application." instead of the +requested file. It doesn't make more sense to provide this .desktop files, +so let's remove this fallback and return error instead. + +https://gitlab.gnome.org/GNOME/nautilus/issues/448 +--- + daemon/gvfsbackendgoogle.c | 68 ++++++++------------------------------ + 1 file changed, 13 insertions(+), 55 deletions(-) + +diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c +index 23bd8f58..7bea4bff 100644 +--- a/daemon/gvfsbackendgoogle.c ++++ b/daemon/gvfsbackendgoogle.c +@@ -907,7 +907,6 @@ build_file_info (GVfsBackendGoogle *self, + gchar *escaped_name = NULL; + gchar *content_type = NULL; + gchar *copy_name = NULL; +- gchar *generated_copy_name = NULL; + gint64 atime; + gint64 ctime; + gint64 mtime; +@@ -1025,21 +1024,7 @@ build_file_info (GVfsBackendGoogle *self, + g_file_info_set_display_name (info, title); + g_file_info_set_edit_name (info, title); + +- generated_copy_name = generate_copy_name (self, entry); +- +- /* While copying remote Drive content to local storage, we want to +- * create Link-type desktop files because GLocalFile doesn't know +- * about shortcuts. That might change in future. +- */ +- if (file_type == G_FILE_TYPE_SHORTCUT) +- { +- copy_name = g_strconcat (generated_copy_name, ".desktop", NULL); +- } +- else +- { +- copy_name = generated_copy_name; +- generated_copy_name = NULL; +- } ++ copy_name = generate_copy_name (self, entry); + + /* Sanitize copy-name by replacing slashes with dashes. This is + * what nautilus does (for desktop files). +@@ -1097,7 +1082,6 @@ build_file_info (GVfsBackendGoogle *self, + + out: + g_free (copy_name); +- g_free (generated_copy_name); + g_free (escaped_name); + g_free (content_type); + g_list_free (links); +@@ -2249,6 +2233,8 @@ g_vfs_backend_google_open_for_read (GVfsBackend *_self, + GError *error; + gchar *content_type = NULL; + gchar *entry_path = NULL; ++ GDataAuthorizationDomain *auth_domain; ++ const gchar *uri; + + g_rec_mutex_lock (&self->mutex); + g_debug ("+ open_for_read: %s\n", filename); +@@ -2278,47 +2264,19 @@ g_vfs_backend_google_open_for_read (GVfsBackend *_self, + goto out; + } + +- /* While copying remote Drive content to local storage, we want to +- * create Link-type desktop files because GLocalFile doesn't know +- * about shortcuts. That might change in future. +- */ +- if (g_str_has_prefix (content_type, CONTENT_TYPE_PREFIX_GOOGLE)) ++ if (is_native_file (entry)) + { +- GDataLink *alternate; +- GKeyFile *file; +- const gchar *title; +- const gchar *uri; +- gchar *data; +- gsize length; +- +- file = g_key_file_new (); +- +- title = gdata_entry_get_title (entry); +- g_key_file_set_string (file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, title); +- g_key_file_set_string (file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TYPE, "Link"); +- +- alternate = gdata_entry_look_up_link (entry, GDATA_LINK_ALTERNATE); +- uri = gdata_link_get_uri (alternate); +- g_key_file_set_string (file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_URL, uri); +- +- data = g_key_file_to_data (file, &length, NULL); +- stream = g_memory_input_stream_new_from_data (data, (gssize) length, g_free); +- +- g_key_file_free (file); ++ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_REGULAR_FILE, _("File is not a regular file")); ++ goto out; + } +- else +- { +- GDataAuthorizationDomain *auth_domain; +- const gchar *uri; + +- auth_domain = gdata_documents_service_get_primary_authorization_domain (); +- uri = gdata_entry_get_content_uri (entry); +- stream = gdata_download_stream_new (GDATA_SERVICE (self->service), auth_domain, uri, cancellable); +- if (stream == NULL) +- { +- g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED, _("Error getting data from file")); +- goto out; +- } ++ auth_domain = gdata_documents_service_get_primary_authorization_domain (); ++ uri = gdata_entry_get_content_uri (entry); ++ stream = gdata_download_stream_new (GDATA_SERVICE (self->service), auth_domain, uri, cancellable); ++ if (stream == NULL) ++ { ++ g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_FAILED, _("Error getting data from file")); ++ goto out; + } + + g_object_set_data_full (G_OBJECT (stream), "g-vfs-backend-google-entry", g_object_ref (entry), g_object_unref); +-- +2.36.1 + + +From fec7d2162966c3574226564b62c6dd252bf4706f Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Mon, 23 Jul 2018 13:39:33 +0200 +Subject: [PATCH 02/14] google: Drop the (GDestroyNotify) cast + +"warning: function called through a non-compatible type" is printed +by GCC 8 because of (GDestroyNotfiy) cast in g_clear_pointer, see for +more info: https://gitlab.gnome.org/GNOME/glib/issues/1425. Let's +drop the (GDestroyNotify) cast in order to prevent those warnings. +The cast was not needed anyway. +--- + daemon/gvfsbackendgoogle.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c +index 7bea4bff..2e96cca4 100644 +--- a/daemon/gvfsbackendgoogle.c ++++ b/daemon/gvfsbackendgoogle.c +@@ -2866,8 +2866,8 @@ g_vfs_backend_google_dispose (GObject *_self) + g_clear_object (&self->service); + g_clear_object (&self->root); + g_clear_object (&self->client); +- g_clear_pointer (&self->entries, (GDestroyNotify) g_hash_table_unref); +- g_clear_pointer (&self->dir_entries, (GDestroyNotify) g_hash_table_unref); ++ g_clear_pointer (&self->entries, g_hash_table_unref); ++ g_clear_pointer (&self->dir_entries, g_hash_table_unref); + + G_OBJECT_CLASS (g_vfs_backend_google_parent_class)->dispose (_self); + } +-- +2.36.1 + + +From 2d5fc426acb1bff385258d860ec97ff30242285d Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Wed, 1 Aug 2018 13:43:16 +0200 +Subject: [PATCH 03/14] google: Move debug prints before releasing entry + +Debug output contains mess because id and title are const gchar * +and are released together with GDataEntry on previous line. Let's +just swap the lines. +--- + daemon/gvfsbackendgoogle.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c +index 2e96cca4..e157458b 100644 +--- a/daemon/gvfsbackendgoogle.c ++++ b/daemon/gvfsbackendgoogle.c +@@ -510,13 +510,13 @@ remove_entry (GVfsBackendGoogle *self, + parent_id = get_parent_id (self, entry); + + k = dir_entries_key_new (id, parent_id); +- g_hash_table_remove (self->dir_entries, k); + g_debug (" remove_entry: Removed (%s, %s) -> %p\n", id, parent_id, entry); ++ g_hash_table_remove (self->dir_entries, k); + dir_entries_key_free (k); + + k = dir_entries_key_new (title, parent_id); +- g_hash_table_remove (self->dir_entries, k); + g_debug (" remove_entry: Removed (%s, %s) -> %p\n", title, parent_id, entry); ++ g_hash_table_remove (self->dir_entries, k); + dir_entries_key_free (k); + + for (l = self->dir_collisions; l != NULL; l = l->next) +-- +2.36.1 + + +From b3f8db69522fdbdc965219e403da6e8e60997907 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Wed, 1 Aug 2018 13:44:59 +0200 +Subject: [PATCH 04/14] google: Remove also dir_collisions entries + +dir_collisions are not properly invalidated if removed entry is on this list. +Let's remove the entry also from this list. +--- + daemon/gvfsbackendgoogle.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c +index e157458b..e9eaec1f 100644 +--- a/daemon/gvfsbackendgoogle.c ++++ b/daemon/gvfsbackendgoogle.c +@@ -519,6 +519,13 @@ remove_entry (GVfsBackendGoogle *self, + g_hash_table_remove (self->dir_entries, k); + dir_entries_key_free (k); + ++ l = g_list_find (self->dir_collisions, entry); ++ if (l != NULL) ++ { ++ self->dir_collisions = g_list_remove_link (self->dir_collisions, l); ++ g_object_unref (entry); ++ } ++ + for (l = self->dir_collisions; l != NULL; l = l->next) + { + GDataEntry *colliding_entry = GDATA_ENTRY (l->data); +-- +2.36.1 + + +From ab007b1f3215a30c3ef49492cf22e6ef1383b0fd Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Tue, 31 Jul 2018 18:43:44 +0200 +Subject: [PATCH 05/14] google: Ignore entries without parents + +Entries without parents are not shown on the web and there isn't any +reason to list them here. Such entries belongs to some web services +and we have no control over them. +--- + daemon/gvfsbackendgoogle.c | 18 +----------------- + 1 file changed, 1 insertion(+), 17 deletions(-) + +diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c +index e9eaec1f..897df61f 100644 +--- a/daemon/gvfsbackendgoogle.c ++++ b/daemon/gvfsbackendgoogle.c +@@ -347,14 +347,6 @@ get_parent_id (GVfsBackendGoogle *self, + } + } + +- if (ret_val == NULL) +- { +- const gchar *root_id; +- +- root_id = gdata_entry_get_id (self->root); +- ret_val = g_strdup (root_id); +- } +- + g_list_free (links); + return ret_val; + } +@@ -903,10 +895,8 @@ build_file_info (GVfsBackendGoogle *self, + { + GFileType file_type; + GList *authors; +- GList *links; + gboolean is_folder = FALSE; + gboolean is_root = FALSE; +- gboolean has_parent = FALSE; + const gchar *etag; + const gchar *id; + const gchar *name; +@@ -925,9 +915,6 @@ build_file_info (GVfsBackendGoogle *self, + if (entry == self->root) + is_root = TRUE; + +- links = gdata_entry_look_up_links (entry, GDATA_LINK_PARENT); +- has_parent = (links != NULL); +- + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, !is_root); + + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, is_folder); +@@ -936,9 +923,7 @@ build_file_info (GVfsBackendGoogle *self, + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_STANDARD_IS_VOLATILE, is_symlink); + + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE); +- g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, !is_root && has_parent); +- +- g_file_info_set_is_hidden (info, !has_parent); ++ g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, !is_root); + + if (is_folder) + { +@@ -1091,7 +1076,6 @@ build_file_info (GVfsBackendGoogle *self, + g_free (copy_name); + g_free (escaped_name); + g_free (content_type); +- g_list_free (links); + } + + /* ---------------------------------------------------------------------------------------------------- */ +-- +2.36.1 + + +From 631f794a4a660f49be9d30744e5c66a1f60da4de Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Tue, 31 Jul 2018 19:08:39 +0200 +Subject: [PATCH 06/14] google: Add support for files with multiple parents + +One entry can have multiple parents. You can create such entry on +the web in a pretty simple way, e.g. Ctrl + Drag&Drop. Such entries +are currently shown only on one place in the backend. Also the backend +rely on get_parent_id() and get_entry_path() functions which are tottaly +wrong. Let's introduce get_parent_ids() and resolve entry_path only +from given filename. +--- + daemon/gvfsbackendgoogle.c | 388 ++++++++++++++++--------------------- + 1 file changed, 168 insertions(+), 220 deletions(-) + +diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c +index 897df61f..7f812448 100644 +--- a/daemon/gvfsbackendgoogle.c ++++ b/daemon/gvfsbackendgoogle.c +@@ -99,11 +99,13 @@ typedef struct + GDataEntry *document; + GDataUploadStream *stream; + gchar *filename; ++ gchar *entry_path; + } WriteHandle; + + static GDataEntry *resolve_dir (GVfsBackendGoogle *self, + const gchar *filename, + gchar **out_basename, ++ gchar **out_path, + GError **error); + + /* ---------------------------------------------------------------------------------------------------- */ +@@ -160,7 +162,7 @@ entries_in_folder_equal (gconstpointer a, gconstpointer b) + /* ---------------------------------------------------------------------------------------------------- */ + + static WriteHandle * +-write_handle_new (GDataEntry *document, GDataUploadStream *stream, const gchar *filename) ++write_handle_new (GDataEntry *document, GDataUploadStream *stream, const gchar *filename, const gchar *entry_path) + { + WriteHandle *handle; + +@@ -177,6 +179,7 @@ write_handle_new (GDataEntry *document, GDataUploadStream *stream, const gchar * + } + + handle->filename = g_strdup (filename); ++ handle->entry_path = g_strdup (entry_path); + + return handle; + } +@@ -192,6 +195,7 @@ write_handle_free (gpointer data) + g_clear_object (&handle->document); + g_clear_object (&handle->stream); + g_free (handle->filename); ++ g_free (handle->entry_path); + g_slice_free (WriteHandle, handle); + } + +@@ -313,13 +317,13 @@ get_content_type_from_entry (GDataEntry *entry) + + /* ---------------------------------------------------------------------------------------------------- */ + +-static gchar * +-get_parent_id (GVfsBackendGoogle *self, +- GDataEntry *entry) ++static GList * ++get_parent_ids (GVfsBackendGoogle *self, ++ GDataEntry *entry) + { + GList *l; + GList *links = NULL; +- gchar *ret_val = NULL; ++ GList *ids = NULL; + + links = gdata_entry_look_up_links (entry, GDATA_LINK_PARENT); + for (l = links; l != NULL; l = l->next) +@@ -341,68 +345,13 @@ get_parent_id (GVfsBackendGoogle *self, + id = uri + uri_prefix_len; + if (id[0] != '\0') + { +- ret_val = g_strdup (uri + uri_prefix_len); +- break; ++ ids = g_list_prepend (ids, g_strdup (id)); + } + } + } + + g_list_free (links); +- return ret_val; +-} +- +-static gchar * +-get_entry_path (GVfsBackendGoogle *self, GDataEntry *entry) +-{ +- GString *path = NULL; +- const gchar *base_id; +- const gchar *root_id; +- gchar *id = NULL; +- gchar *ret_val = NULL; +- +- if (entry == self->root) +- { +- ret_val = g_strdup ("/"); +- goto out; +- } +- +- base_id = gdata_entry_get_id (entry); +- path = g_string_new (base_id); +- g_string_prepend_c (path, '/'); +- +- id = get_parent_id (self, entry); +- root_id = gdata_entry_get_id (self->root); +- +- while (id != NULL) +- { +- GDataEntry *parent_entry; +- +- /* The root folder itself has an ID, so path can become +- * /root/folder1/folder2/file. Instead, we want it to be +- * /folder1/folder2/file. +- */ +- +- if (g_strcmp0 (id, root_id) == 0) +- break; +- +- parent_entry = g_hash_table_lookup (self->entries, id); +- if (parent_entry == NULL) +- goto out; +- +- g_string_prepend (path, id); +- g_string_prepend_c (path, '/'); +- +- g_free (id); +- id = get_parent_id (self, parent_entry); +- } +- +- ret_val = g_strdup (path->str); +- +- out: +- g_free (id); +- if (path != NULL) +- g_string_free (path, TRUE); +- return ret_val; ++ return ids; + } + + /* ---------------------------------------------------------------------------------------------------- */ +@@ -418,62 +367,66 @@ insert_entry_full (GVfsBackendGoogle *self, + const gchar *id; + const gchar *old_id; + const gchar *title; +- gchar *parent_id; ++ GList *parent_ids, *l; + + id = gdata_entry_get_id (entry); + title = gdata_entry_get_title (entry); + + g_hash_table_insert (self->entries, g_strdup (id), g_object_ref (entry)); + +- parent_id = get_parent_id (self, entry); ++ parent_ids = get_parent_ids (self, entry); ++ for (l = parent_ids; l != NULL; l = l->next) ++ { ++ gchar *parent_id = l->data; + +- k = dir_entries_key_new (id, parent_id); +- g_hash_table_insert (self->dir_entries, k, g_object_ref (entry)); +- g_debug (" insert_entry: Inserted (%s, %s) -> %p\n", id, parent_id, entry); ++ k = dir_entries_key_new (id, parent_id); ++ g_hash_table_insert (self->dir_entries, k, g_object_ref (entry)); ++ g_debug (" insert_entry: Inserted (%s, %s) -> %p\n", id, parent_id, entry); + +- k = dir_entries_key_new (title, parent_id); +- old_entry = g_hash_table_lookup (self->dir_entries, k); +- if (old_entry != NULL) +- { +- old_id = gdata_entry_get_id (old_entry); +- if (g_strcmp0 (old_id, title) == 0) +- { +- insert_title = FALSE; +- } +- else ++ k = dir_entries_key_new (title, parent_id); ++ old_entry = g_hash_table_lookup (self->dir_entries, k); ++ if (old_entry != NULL) + { +- /* If the collision is not due to the title matching the ID +- * of an earlier GDataEntry, then it is due to duplicate +- * titles. +- */ +- if (g_strcmp0 (old_id, id) < 0) +- insert_title = FALSE; ++ old_id = gdata_entry_get_id (old_entry); ++ if (g_strcmp0 (old_id, title) == 0) ++ { ++ insert_title = FALSE; ++ } ++ else ++ { ++ /* If the collision is not due to the title matching the ID ++ * of an earlier GDataEntry, then it is due to duplicate ++ * titles. ++ */ ++ if (g_strcmp0 (old_id, id) < 0) ++ insert_title = FALSE; ++ } + } +- } + +- if (insert_title) +- { +- if (old_entry != NULL && track_dir_collisions) ++ if (insert_title) + { +- self->dir_collisions = g_list_prepend (self->dir_collisions, g_object_ref (old_entry)); +- g_debug (" insert_entry: Ejected (%s, %s, %s) -> %p\n", old_id, title, parent_id, old_entry); +- } ++ if (old_entry != NULL && track_dir_collisions) ++ { ++ self->dir_collisions = g_list_prepend (self->dir_collisions, g_object_ref (old_entry)); ++ g_debug (" insert_entry: Ejected (%s, %s, %s) -> %p\n", old_id, title, parent_id, old_entry); ++ } + +- g_hash_table_insert (self->dir_entries, k, g_object_ref (entry)); +- g_debug (" insert_entry: Inserted (%s, %s) -> %p\n", title, parent_id, entry); +- } +- else +- { +- if (track_dir_collisions) +- { +- self->dir_collisions = g_list_prepend (self->dir_collisions, g_object_ref (entry)); +- g_debug (" insert_entry: Skipped (%s, %s, %s) -> %p\n", id, title, parent_id, entry); ++ g_hash_table_insert (self->dir_entries, k, g_object_ref (entry)); ++ g_debug (" insert_entry: Inserted (%s, %s) -> %p\n", title, parent_id, entry); + } ++ else ++ { ++ if (track_dir_collisions) ++ { ++ self->dir_collisions = g_list_prepend (self->dir_collisions, g_object_ref (entry)); ++ g_debug (" insert_entry: Skipped (%s, %s, %s) -> %p\n", id, title, parent_id, entry); ++ } + +- dir_entries_key_free (k); ++ dir_entries_key_free (k); ++ } + } ++ g_list_free_full (parent_ids, g_free); + +- g_free (parent_id); + return insert_title; + } + +@@ -492,47 +445,50 @@ remove_entry (GVfsBackendGoogle *self, + GList *l; + const gchar *id; + const gchar *title; +- gchar *parent_id; ++ GList *parent_ids, *ll; + + id = gdata_entry_get_id (entry); + title = gdata_entry_get_title (entry); + + g_hash_table_remove (self->entries, id); + +- parent_id = get_parent_id (self, entry); +- +- k = dir_entries_key_new (id, parent_id); +- g_debug (" remove_entry: Removed (%s, %s) -> %p\n", id, parent_id, entry); +- g_hash_table_remove (self->dir_entries, k); +- dir_entries_key_free (k); +- +- k = dir_entries_key_new (title, parent_id); +- g_debug (" remove_entry: Removed (%s, %s) -> %p\n", title, parent_id, entry); +- g_hash_table_remove (self->dir_entries, k); +- dir_entries_key_free (k); +- +- l = g_list_find (self->dir_collisions, entry); +- if (l != NULL) ++ parent_ids = get_parent_ids (self, entry); ++ for (ll = parent_ids; ll != NULL; ll = ll->next) + { +- self->dir_collisions = g_list_remove_link (self->dir_collisions, l); +- g_object_unref (entry); +- } ++ gchar *parent_id = ll->data; + +- for (l = self->dir_collisions; l != NULL; l = l->next) +- { +- GDataEntry *colliding_entry = GDATA_ENTRY (l->data); ++ k = dir_entries_key_new (id, parent_id); ++ g_debug (" remove_entry: Removed (%s, %s) -> %p\n", id, parent_id, entry); ++ g_hash_table_remove (self->dir_entries, k); ++ dir_entries_key_free (k); ++ ++ k = dir_entries_key_new (title, parent_id); ++ g_debug (" remove_entry: Removed (%s, %s) -> %p\n", title, parent_id, entry); ++ g_hash_table_remove (self->dir_entries, k); ++ dir_entries_key_free (k); + +- if (insert_entry_full (self, colliding_entry, FALSE)) ++ l = g_list_find (self->dir_collisions, entry); ++ if (l != NULL) + { + self->dir_collisions = g_list_remove_link (self->dir_collisions, l); +- g_debug (" remove_entry: Restored %p\n", colliding_entry); +- g_list_free (l); +- g_object_unref (colliding_entry); +- break; ++ g_object_unref (entry); + } +- } + +- g_free (parent_id); ++ for (l = self->dir_collisions; l != NULL; l = l->next) ++ { ++ GDataEntry *colliding_entry = GDATA_ENTRY (l->data); ++ ++ if (insert_entry_full (self, colliding_entry, FALSE)) ++ { ++ self->dir_collisions = g_list_remove_link (self->dir_collisions, l); ++ g_debug (" remove_entry: Restored %p\n", colliding_entry); ++ g_list_free (l); ++ g_object_unref (colliding_entry); ++ break; ++ } ++ } ++ } ++ g_list_free_full (parent_ids, g_free); + } + + static void +@@ -617,6 +573,7 @@ resolve_child (GVfsBackendGoogle *self, + static GDataEntry * + resolve (GVfsBackendGoogle *self, + const gchar *filename, ++ gchar **out_path, + GError **error) + { + GDataEntry *parent; +@@ -627,11 +584,15 @@ resolve (GVfsBackendGoogle *self, + if (g_strcmp0 (filename, "/") == 0) + { + ret_val = self->root; ++ ++ if (out_path != NULL) ++ *out_path = g_strdup ("/"); ++ + goto out; + } + + local_error = NULL; +- parent = resolve_dir (self, filename, &basename, &local_error); ++ parent = resolve_dir (self, filename, &basename, out_path, &local_error); + if (local_error != NULL) + { + g_propagate_error (error, local_error); +@@ -645,6 +606,14 @@ resolve (GVfsBackendGoogle *self, + goto out; + } + ++ if (out_path != NULL) ++ { ++ gchar *tmp; ++ tmp = g_build_path ("/", *out_path, gdata_entry_get_id (ret_val), NULL); ++ g_free (*out_path); ++ *out_path = tmp; ++ } ++ + out: + g_free (basename); + return ret_val; +@@ -654,6 +623,7 @@ static GDataEntry * + resolve_dir (GVfsBackendGoogle *self, + const gchar *filename, + gchar **out_basename, ++ gchar **out_path, + GError **error) + { + GDataEntry *parent; +@@ -666,7 +636,7 @@ resolve_dir (GVfsBackendGoogle *self, + parent_path = g_path_get_dirname (filename); + + local_error = NULL; +- parent = resolve (self, parent_path, &local_error); ++ parent = resolve (self, parent_path, out_path, &local_error); + if (local_error != NULL) + { + g_propagate_error (error, local_error); +@@ -699,12 +669,13 @@ static GDataEntry * + resolve_and_rebuild (GVfsBackendGoogle *self, + const gchar *filename, + GCancellable *cancellable, ++ gchar **out_path, + GError **error) + { + GDataEntry *entry; + GDataEntry *ret_val = NULL; + +- entry = resolve (self, filename, NULL); ++ entry = resolve (self, filename, out_path, NULL); + if (entry == NULL) + { + GError *local_error; +@@ -718,7 +689,7 @@ resolve_and_rebuild (GVfsBackendGoogle *self, + } + + local_error = NULL; +- entry = resolve (self, filename, &local_error); ++ entry = resolve (self, filename, out_path, &local_error); + if (local_error != NULL) + { + g_propagate_error (error, local_error); +@@ -737,6 +708,7 @@ resolve_dir_and_rebuild (GVfsBackendGoogle *self, + const gchar *filename, + GCancellable *cancellable, + gchar **out_basename, ++ gchar **out_path, + GError **error) + { + GDataEntry *parent; +@@ -745,7 +717,7 @@ resolve_dir_and_rebuild (GVfsBackendGoogle *self, + gchar *basename = NULL; + + local_error = NULL; +- parent = resolve_dir (self, filename, &basename, &local_error); ++ parent = resolve_dir (self, filename, &basename, out_path, &local_error); + if (local_error != NULL) + { + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY)) +@@ -767,7 +739,7 @@ resolve_dir_and_rebuild (GVfsBackendGoogle *self, + } + + local_error = NULL; +- parent = resolve_dir (self, filename, &basename, &local_error); ++ parent = resolve_dir (self, filename, &basename, out_path, &local_error); + if (local_error != NULL) + { + g_propagate_error (error, local_error); +@@ -819,13 +791,12 @@ get_extension_offset (const char *title) + } + + static gchar * +-generate_copy_name (GVfsBackendGoogle *self, GDataEntry *entry) ++generate_copy_name (GVfsBackendGoogle *self, GDataEntry *entry, const gchar *entry_path) + { + GDataEntry *existing_entry; + GDataEntry *parent; + const gchar *id; + const gchar *title; +- gchar *entry_path = NULL; + gchar *extension = NULL; + gchar *extension_offset; + gchar *ret_val = NULL; +@@ -833,11 +804,7 @@ generate_copy_name (GVfsBackendGoogle *self, GDataEntry *entry) + + title = gdata_entry_get_title (entry); + +- entry_path = get_entry_path (self, entry); +- if (entry_path == NULL) +- goto out; +- +- parent = resolve_dir (self, entry_path, NULL, NULL); ++ parent = resolve_dir (self, entry_path, NULL, NULL, NULL); + if (parent == NULL) + goto out; + +@@ -859,7 +826,6 @@ generate_copy_name (GVfsBackendGoogle *self, GDataEntry *entry) + out: + if (ret_val == NULL) + ret_val = g_strdup (title); +- g_free (entry_path); + g_free (extension); + g_free (title_without_extension); + return ret_val; +@@ -890,7 +856,7 @@ build_file_info (GVfsBackendGoogle *self, + GFileAttributeMatcher *matcher, + gboolean is_symlink, + const gchar *symlink_name, +- const gchar *symlink_target, ++ const gchar *entry_path, + GError **error) + { + GFileType file_type; +@@ -968,7 +934,7 @@ build_file_info (GVfsBackendGoogle *self, + file_type = G_FILE_TYPE_SYMBOLIC_LINK; + } + +- g_file_info_set_symlink_target (info, symlink_target); ++ g_file_info_set_symlink_target (info, entry_path); + } + + if (content_type != NULL) +@@ -1016,7 +982,7 @@ build_file_info (GVfsBackendGoogle *self, + g_file_info_set_display_name (info, title); + g_file_info_set_edit_name (info, title); + +- copy_name = generate_copy_name (self, entry); ++ copy_name = generate_copy_name (self, entry, entry_path); + + /* Sanitize copy-name by replacing slashes with dashes. This is + * what nautilus does (for desktop files). +@@ -1116,6 +1082,7 @@ g_vfs_backend_google_copy (GVfsBackend *_self, + gchar *destination_basename = NULL; + gchar *entry_path = NULL; + goffset size; ++ gchar *parent_path = NULL; + + g_rec_mutex_lock (&self->mutex); + g_debug ("+ copy: %s -> %s, %d\n", source, destination, flags); +@@ -1130,12 +1097,12 @@ g_vfs_backend_google_copy (GVfsBackend *_self, + goto out; + } + +- source_entry = resolve (self, source, NULL); ++ source_entry = resolve (self, source, NULL, NULL); + if (source_entry == NULL) + needs_rebuild = TRUE; + + error = NULL; +- destination_parent = resolve_dir (self, destination, &destination_basename, &error); ++ destination_parent = resolve_dir (self, destination, &destination_basename, &parent_path, &error); + if (error != NULL) + { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY)) +@@ -1158,7 +1125,7 @@ g_vfs_backend_google_copy (GVfsBackend *_self, + } + + error = NULL; +- source_entry = resolve (self, source, &error); ++ source_entry = resolve (self, source, NULL, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -1172,7 +1139,7 @@ g_vfs_backend_google_copy (GVfsBackend *_self, + destination_basename = NULL; + + error = NULL; +- destination_parent = resolve_dir (self, destination, &destination_basename, &error); ++ destination_parent = resolve_dir (self, destination, &destination_basename, &parent_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -1258,7 +1225,7 @@ g_vfs_backend_google_copy (GVfsBackend *_self, + goto out; + } + +- entry_path = get_entry_path (self, GDATA_ENTRY (new_entry)); ++ entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (new_entry)), NULL); + g_debug (" new entry path: %s\n", entry_path); + + insert_entry (self, GDATA_ENTRY (new_entry)); +@@ -1277,6 +1244,7 @@ g_vfs_backend_google_copy (GVfsBackend *_self, + g_clear_object (&new_entry); + g_free (destination_basename); + g_free (entry_path); ++ g_free (parent_path); + g_debug ("- copy\n"); + g_rec_mutex_unlock (&self->mutex); + } +@@ -1306,7 +1274,7 @@ g_vfs_backend_google_create_dir_monitor (GVfsBackend *_self, + } + + error = NULL; +- entry = resolve_and_rebuild (self, filename, cancellable, &error); ++ entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -1314,7 +1282,6 @@ g_vfs_backend_google_create_dir_monitor (GVfsBackend *_self, + goto out; + } + +- entry_path = get_entry_path (self, entry); + g_debug (" entry path: %s\n", entry_path); + + if (!GDATA_IS_DOCUMENTS_FOLDER (entry)) +@@ -1356,7 +1323,7 @@ g_vfs_backend_google_delete (GVfsBackend *_self, + g_debug ("+ delete: %s\n", filename); + + error = NULL; +- entry = resolve_and_rebuild (self, filename, cancellable, &error); ++ entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -1364,7 +1331,6 @@ g_vfs_backend_google_delete (GVfsBackend *_self, + goto out; + } + +- entry_path = get_entry_path (self, entry); + g_debug (" entry path: %s\n", entry_path); + + if (entry == self->root) +@@ -1420,7 +1386,8 @@ g_vfs_backend_google_enumerate (GVfsBackend *_self, + GDataEntry *entry; + GError *error; + GHashTableIter iter; +- gchar *entry_path = NULL; ++ char *parent_path; ++ char *id; + + g_rec_mutex_lock (&self->mutex); + g_debug ("+ enumerate: %s\n", filename); +@@ -1447,7 +1414,7 @@ g_vfs_backend_google_enumerate (GVfsBackend *_self, + } + + error = NULL; +- entry = resolve (self, filename, &error); ++ entry = resolve (self, filename, &parent_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -1455,9 +1422,6 @@ g_vfs_backend_google_enumerate (GVfsBackend *_self, + goto out; + } + +- entry_path = get_entry_path (self, entry); +- g_debug (" entry path: %s\n", entry_path); +- + if (!GDATA_IS_DOCUMENTS_FOLDER (entry)) + { + g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY,_("The file is not a directory")); +@@ -1466,39 +1430,37 @@ g_vfs_backend_google_enumerate (GVfsBackend *_self, + + g_vfs_job_succeeded (G_VFS_JOB (job)); + ++ /* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */ ++ id = g_strdup (gdata_entry_get_id (entry)); ++ + g_hash_table_iter_init (&iter, self->entries); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry)) + { +- gchar *path; ++ DirEntriesKey *k; + +- path = get_entry_path (self, entry); +- g_debug (" found entry: %s\n", path); +- if (path != NULL) ++ k = dir_entries_key_new (gdata_entry_get_id (entry), id); ++ if (g_hash_table_contains (self->dir_entries, k)) + { +- gchar *parent_path; +- +- parent_path = g_path_get_dirname (path); +- if (g_strcmp0 (entry_path, parent_path) == 0) +- { +- GFileInfo *info; +- +- info = g_file_info_new (); +- build_file_info (self, entry, flags, info, matcher, FALSE, NULL, NULL, NULL); +- g_vfs_job_enumerate_add_info (job, info); +- g_object_unref (info); +- } +- +- g_free (parent_path); ++ GFileInfo *info; ++ gchar *entry_path; ++ ++ info = g_file_info_new (); ++ entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (entry)), NULL); ++ build_file_info (self, entry, flags, info, matcher, FALSE, NULL, entry_path, NULL); ++ g_vfs_job_enumerate_add_info (job, info); ++ g_object_unref (info); ++ g_free (entry_path); + } + +- g_free (path); ++ dir_entries_key_free (k); + } + + g_vfs_job_enumerate_done (job); + + out: +- g_free (entry_path); + g_debug ("- enumerate\n"); ++ g_free (parent_path); ++ g_free (id); + g_rec_mutex_unlock (&self->mutex); + } + +@@ -1532,7 +1494,7 @@ g_vfs_backend_google_make_directory (GVfsBackend *_self, + } + + error = NULL; +- parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &error); ++ parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &parent_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -1540,7 +1502,6 @@ g_vfs_backend_google_make_directory (GVfsBackend *_self, + goto out; + } + +- parent_path = get_entry_path (self, parent); + g_debug (" parent path: %s\n", parent_path); + + summary_entry = g_hash_table_lookup (self->entries, basename); +@@ -1574,7 +1535,7 @@ g_vfs_backend_google_make_directory (GVfsBackend *_self, + goto out; + } + +- entry_path = get_entry_path (self, GDATA_ENTRY (new_folder)); ++ entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (new_folder)), NULL); + g_debug (" new entry path: %s\n", entry_path); + + insert_entry (self, GDATA_ENTRY (new_folder)); +@@ -1744,6 +1705,7 @@ g_vfs_backend_google_push (GVfsBackend *_self, + const gchar *title; + gchar *destination_basename = NULL; + gchar *entry_path = NULL; ++ gchar *parent_path = NULL; + goffset size; + + g_rec_mutex_lock (&self->mutex); +@@ -1777,7 +1739,7 @@ g_vfs_backend_google_push (GVfsBackend *_self, + } + + error = NULL; +- destination_parent = resolve_dir_and_rebuild (self, destination, cancellable, &destination_basename, &error); ++ destination_parent = resolve_dir_and_rebuild (self, destination, cancellable, &destination_basename, &parent_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -1922,7 +1884,7 @@ g_vfs_backend_google_push (GVfsBackend *_self, + goto out; + } + +- entry_path = get_entry_path (self, GDATA_ENTRY (new_document)); ++ entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (new_document)), NULL); + g_debug (" new entry path: %s\n", entry_path); + + if (needs_overwrite) +@@ -1960,6 +1922,7 @@ g_vfs_backend_google_push (GVfsBackend *_self, + g_clear_object (&ostream); + g_free (destination_basename); + g_free (entry_path); ++ g_free (parent_path); + g_debug ("- push\n"); + g_rec_mutex_unlock (&self->mutex); + } +@@ -2065,7 +2028,7 @@ g_vfs_backend_google_query_info (GVfsBackend *_self, + g_debug ("+ query_info: %s, %d\n", filename, flags); + + error = NULL; +- entry = resolve_and_rebuild (self, filename, cancellable, &error); ++ entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -2073,7 +2036,6 @@ g_vfs_backend_google_query_info (GVfsBackend *_self, + goto out; + } + +- entry_path = get_entry_path (self, entry); + if (g_strcmp0 (entry_path, filename) != 0) /* volatile */ + { + is_symlink = TRUE; +@@ -2122,8 +2084,8 @@ g_vfs_backend_google_query_info_on_read (GVfsBackend *_self, + + entry = g_object_get_data (G_OBJECT (stream), "g-vfs-backend-google-entry"); + filename = g_object_get_data (G_OBJECT (stream), "g-vfs-backend-google-filename"); ++ entry_path = g_object_get_data (G_OBJECT (stream), "g-vfs-backend-google-entry-path"); + +- entry_path = get_entry_path (self, entry); + if (g_strcmp0 (entry_path, filename) != 0) /* volatile */ + { + is_symlink = TRUE; +@@ -2152,7 +2114,6 @@ g_vfs_backend_google_query_info_on_read (GVfsBackend *_self, + g_vfs_job_succeeded (G_VFS_JOB (job)); + + out: +- g_free (entry_path); + g_free (symlink_name); + g_debug ("- query_info_on_read\n"); + } +@@ -2170,19 +2131,17 @@ g_vfs_backend_google_query_info_on_write (GVfsBackend *_self, + GError *error; + WriteHandle *wh = (WriteHandle *) handle; + gboolean is_symlink = FALSE; +- gchar *entry_path = NULL; + gchar *symlink_name = NULL; + + g_debug ("+ query_info_on_write: %p\n", handle); + +- entry_path = get_entry_path (self, wh->document); +- if (g_strcmp0 (entry_path, wh->filename) != 0) /* volatile */ ++ if (g_strcmp0 (wh->entry_path, wh->filename) != 0) /* volatile */ + { + is_symlink = TRUE; + symlink_name = g_path_get_basename (wh->filename); + } + +- g_debug (" entry path: %s (%d)\n", entry_path, is_symlink); ++ g_debug (" entry path: %s (%d)\n", wh->entry_path, is_symlink); + + error = NULL; + build_file_info (self, +@@ -2192,7 +2151,7 @@ g_vfs_backend_google_query_info_on_write (GVfsBackend *_self, + matcher, + is_symlink, + symlink_name, +- entry_path, ++ wh->entry_path, + &error); + if (error != NULL) + { +@@ -2204,7 +2163,6 @@ g_vfs_backend_google_query_info_on_write (GVfsBackend *_self, + g_vfs_job_succeeded (G_VFS_JOB (job)); + + out: +- g_free (entry_path); + g_free (symlink_name); + g_debug ("- query_info_on_write\n"); + return TRUE; +@@ -2231,7 +2189,7 @@ g_vfs_backend_google_open_for_read (GVfsBackend *_self, + g_debug ("+ open_for_read: %s\n", filename); + + error = NULL; +- entry = resolve_and_rebuild (self, filename, cancellable, &error); ++ entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -2239,7 +2197,6 @@ g_vfs_backend_google_open_for_read (GVfsBackend *_self, + goto out; + } + +- entry_path = get_entry_path (self, entry); + g_debug (" entry path: %s\n", entry_path); + + if (GDATA_IS_DOCUMENTS_FOLDER (entry)) +@@ -2272,6 +2229,7 @@ g_vfs_backend_google_open_for_read (GVfsBackend *_self, + + g_object_set_data_full (G_OBJECT (stream), "g-vfs-backend-google-entry", g_object_ref (entry), g_object_unref); + g_object_set_data_full (G_OBJECT (stream), "g-vfs-backend-google-filename", g_strdup (filename), g_free); ++ g_object_set_data_full (G_OBJECT (stream), "g-vfs-backend-google-entry-path", g_strdup (entry_path), g_free); + g_vfs_job_open_for_read_set_handle (job, stream); + g_vfs_job_open_for_read_set_can_seek (job, TRUE); + g_vfs_job_succeeded (G_VFS_JOB (job)); +@@ -2419,7 +2377,7 @@ g_vfs_backend_google_set_display_name (GVfsBackend *_self, + g_debug ("+ set_display_name: %s, %s\n", filename, display_name); + + error = NULL; +- entry = resolve_and_rebuild (self, filename, cancellable, &error); ++ entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -2427,7 +2385,6 @@ g_vfs_backend_google_set_display_name (GVfsBackend *_self, + goto out; + } + +- entry_path = get_entry_path (self, entry); + g_debug (" entry path: %s\n", entry_path); + + if (entry == self->root) +@@ -2492,7 +2449,7 @@ g_vfs_backend_google_create (GVfsBackend *_self, + } + + error = NULL; +- parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &error); ++ parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &parent_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -2500,7 +2457,6 @@ g_vfs_backend_google_create (GVfsBackend *_self, + goto out; + } + +- parent_path = get_entry_path (self, parent); + g_debug (" parent path: %s\n", parent_path); + + existing_entry = resolve_child (self, parent, basename); +@@ -2538,13 +2494,13 @@ g_vfs_backend_google_create (GVfsBackend *_self, + goto out; + } + +- entry_path = get_entry_path (self, GDATA_ENTRY (new_document)); ++ entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (new_document)), NULL); + g_debug (" new entry path: %s\n", entry_path); + + insert_entry (self, GDATA_ENTRY (new_document)); + g_hash_table_foreach (self->monitors, emit_create_event, entry_path); + +- handle = write_handle_new (GDATA_ENTRY (new_document), NULL, filename); ++ handle = write_handle_new (GDATA_ENTRY (new_document), NULL, filename, entry_path); + g_vfs_job_open_for_write_set_handle (job, handle); + g_vfs_job_succeeded (G_VFS_JOB (job)); + +@@ -2602,7 +2558,7 @@ g_vfs_backend_google_replace (GVfsBackend *_self, + } + + error = NULL; +- parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &error); ++ parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &parent_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -2610,7 +2566,6 @@ g_vfs_backend_google_replace (GVfsBackend *_self, + goto out; + } + +- parent_path = get_entry_path (self, parent); + g_debug (" parent path: %s\n", parent_path); + + existing_entry = resolve_child (self, parent, basename); +@@ -2639,7 +2594,7 @@ g_vfs_backend_google_replace (GVfsBackend *_self, + { + const gchar *title; + +- entry_path = get_entry_path (self, existing_entry); ++ entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (existing_entry), NULL); + g_debug (" existing entry path: %s\n", entry_path); + + title = gdata_entry_get_title (existing_entry); +@@ -2660,7 +2615,7 @@ g_vfs_backend_google_replace (GVfsBackend *_self, + goto out; + } + +- handle = write_handle_new (NULL, stream, filename); ++ handle = write_handle_new (NULL, stream, filename, entry_path); + } + else + { +@@ -2681,13 +2636,13 @@ g_vfs_backend_google_replace (GVfsBackend *_self, + goto out; + } + +- entry_path = get_entry_path (self, GDATA_ENTRY (new_document)); ++ entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (new_document)), NULL); + g_debug (" new entry path: %s\n", entry_path); + + insert_entry (self, GDATA_ENTRY (new_document)); + g_hash_table_foreach (self->monitors, emit_create_event, entry_path); + +- handle = write_handle_new (GDATA_ENTRY (new_document), NULL, filename); ++ handle = write_handle_new (GDATA_ENTRY (new_document), NULL, filename, entry_path); + } + + g_vfs_job_open_for_write_set_handle (job, handle); +@@ -2718,7 +2673,6 @@ g_vfs_backend_google_write (GVfsBackend *_self, + GCancellable *cancellable = G_VFS_JOB (job)->cancellable; + GError *error; + WriteHandle *wh = (WriteHandle *) handle; +- gchar *entry_path = NULL; + gssize nwrite; + + g_debug ("+ write: %p\n", handle); +@@ -2751,9 +2705,7 @@ g_vfs_backend_google_write (GVfsBackend *_self, + } + + g_debug (" writing to stream: %p\n", wh->stream); +- +- entry_path = get_entry_path (self, wh->document); +- g_debug (" entry path: %s\n", entry_path); ++ g_debug (" entry path: %s\n", wh->entry_path); + + error = NULL; + nwrite = g_output_stream_write (G_OUTPUT_STREAM (wh->stream), +@@ -2768,12 +2720,11 @@ g_vfs_backend_google_write (GVfsBackend *_self, + goto out; + } + +- g_hash_table_foreach (self->monitors, emit_changed_event, entry_path); ++ g_hash_table_foreach (self->monitors, emit_changed_event, wh->entry_path); + g_vfs_job_write_set_written_size (job, (gsize) nwrite); + g_vfs_job_succeeded (G_VFS_JOB (job)); + + out: +- g_free (entry_path); + g_debug ("- write\n"); + } + +@@ -2789,7 +2740,6 @@ g_vfs_backend_google_close_write (GVfsBackend *_self, + GDataDocumentsDocument *new_document = NULL; + GError *error; + WriteHandle *wh = (WriteHandle *) handle; +- gchar *entry_path = NULL; + + g_debug ("+ close_write: %p\n", handle); + +@@ -2820,18 +2770,16 @@ g_vfs_backend_google_close_write (GVfsBackend *_self, + goto out; + } + +- entry_path = get_entry_path (self, GDATA_ENTRY (new_document)); +- g_debug (" new entry path: %s\n", entry_path); ++ g_debug (" new entry path: %s\n", wh->entry_path); + + remove_entry (self, wh->document); + insert_entry (self, GDATA_ENTRY (new_document)); +- g_hash_table_foreach (self->monitors, emit_changes_done_event, entry_path); ++ g_hash_table_foreach (self->monitors, emit_changes_done_event, wh->entry_path); + g_vfs_job_succeeded (G_VFS_JOB (job)); + + out: + g_clear_object (&new_document); + write_handle_free (wh); +- g_free (entry_path); + g_debug ("- close_write\n"); + } + +-- +2.36.1 + + +From 77610a76ae671ec340d100791043f7b3de4bbaf4 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Wed, 1 Aug 2018 11:21:45 +0200 +Subject: [PATCH 07/14] google: Remove file just from concrete parent + +Files with multiple parents are currently removed from all parents. +This is unexpected and may cause data loss, because it is not obvious +that it is one file. Let's remove the file just from requested folder. +--- + daemon/gvfsbackendgoogle.c | 37 +++++++++++++++++++++++++++++++++---- + 1 file changed, 33 insertions(+), 4 deletions(-) + +diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c +index 7f812448..45a48079 100644 +--- a/daemon/gvfsbackendgoogle.c ++++ b/daemon/gvfsbackendgoogle.c +@@ -1314,10 +1314,12 @@ g_vfs_backend_google_delete (GVfsBackend *_self, + { + GVfsBackendGoogle *self = G_VFS_BACKEND_GOOGLE (_self); + GCancellable *cancellable = G_VFS_JOB (job)->cancellable; +- GDataAuthorizationDomain *auth_domain; + GDataEntry *entry; ++ GDataEntry *parent; ++ GDataDocumentsEntry *new_entry = NULL; + GError *error; + gchar *entry_path = NULL; ++ GList *parent_ids; + + g_rec_mutex_lock (&self->mutex); + g_debug ("+ delete: %s\n", filename); +@@ -1331,6 +1333,14 @@ g_vfs_backend_google_delete (GVfsBackend *_self, + goto out; + } + ++ parent = resolve_dir (self, filename, cancellable, NULL, NULL, &error); ++ if (error != NULL) ++ { ++ g_vfs_job_failed_from_error (G_VFS_JOB (job), error); ++ g_error_free (error); ++ goto out; ++ } ++ + g_debug (" entry path: %s\n", entry_path); + + if (entry == self->root) +@@ -1339,10 +1349,26 @@ g_vfs_backend_google_delete (GVfsBackend *_self, + goto out; + } + +- auth_domain = gdata_documents_service_get_primary_authorization_domain (); ++ /* It has to be removed before the actual call to properly invalidate dir entries. */ ++ g_object_ref (entry); ++ remove_entry (self, entry); + + error = NULL; +- gdata_service_delete_entry (GDATA_SERVICE (self->service), auth_domain, entry, cancellable, &error); ++ ++ /* 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) ++ { ++ new_entry = gdata_documents_service_remove_entry_from_folder (self->service, GDATA_DOCUMENTS_ENTRY (entry), GDATA_DOCUMENTS_FOLDER (parent), cancellable, &error); ++ } ++ else ++ { ++ GDataAuthorizationDomain *auth_domain; ++ ++ auth_domain = gdata_documents_service_get_primary_authorization_domain (); ++ gdata_service_delete_entry (GDATA_SERVICE (self->service), auth_domain, entry, cancellable, &error); ++ } ++ + if (error != NULL) + { + sanitize_error (&error); +@@ -1351,11 +1377,14 @@ g_vfs_backend_google_delete (GVfsBackend *_self, + goto out; + } + +- remove_entry (self, entry); ++ if (new_entry) ++ 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)); + + out: ++ g_object_unref (entry); ++ g_clear_object (&new_entry); + g_free (entry_path); + g_debug ("- delete\n"); + g_rec_mutex_unlock (&self->mutex); +-- +2.36.1 + + +From 454e38f9a96505ea5ecaa6a95a8658d58caf24a1 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Mon, 30 Jul 2018 16:42:31 +0200 +Subject: [PATCH 08/14] google: Rework cache for better performance + +The backend is totally unusable if you have too many files on your +Drive. This happens because the backend preloads the whole Drive's +metadata. Let's build the cache incrementaly per folders. + +As a result, the backend works smoothly regardless of the total +number of Drive files, because the total number of transmitted data +is significantly reduced. On the other hand, more requests is done +to Drive, but the Drive quotas seem big enough. +--- + daemon/gvfsbackendgoogle.c | 404 +++++++++++++++---------------------- + 1 file changed, 166 insertions(+), 238 deletions(-) + +diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c +index 45a48079..bf50fef6 100644 +--- a/daemon/gvfsbackendgoogle.c ++++ b/daemon/gvfsbackendgoogle.c +@@ -55,15 +55,13 @@ struct _GVfsBackendGoogle + GVfsBackend parent; + GDataDocumentsService *service; + GDataEntry *root; +- GHashTable *entries; +- GHashTable *dir_entries; ++ GHashTable *entries; /* gchar *entry_id -> GDataEntry */ ++ GHashTable *dir_entries; /* DirEntriesKey -> GDataEntry */ + GHashTable *monitors; + GList *dir_collisions; + GRecMutex mutex; /* guards cache */ + GoaClient *client; +- gboolean entries_stale; + gchar *account_identity; +- guint entries_stale_timeout; + }; + + struct _GVfsBackendGoogleClass +@@ -104,6 +102,7 @@ typedef struct + + static GDataEntry *resolve_dir (GVfsBackendGoogle *self, + const gchar *filename, ++ GCancellable *cancellable, + gchar **out_basename, + gchar **out_path, + GError **error); +@@ -434,12 +433,19 @@ static void + insert_entry (GVfsBackendGoogle *self, + GDataEntry *entry) + { ++ gint64 *timestamp; ++ ++ timestamp = g_new (gint64, 1); ++ *timestamp = g_get_real_time (); ++ g_object_set_data_full (G_OBJECT (entry), "timestamp", timestamp, g_free); ++ + insert_entry_full (self, entry, TRUE); + } + + static void +-remove_entry (GVfsBackendGoogle *self, +- GDataEntry *entry) ++remove_entry_full (GVfsBackendGoogle *self, ++ GDataEntry *entry, ++ gboolean restore_dir_collisions) + { + DirEntriesKey *k; + GList *l; +@@ -474,17 +480,20 @@ remove_entry (GVfsBackendGoogle *self, + g_object_unref (entry); + } + +- for (l = self->dir_collisions; l != NULL; l = l->next) ++ if (restore_dir_collisions) + { +- GDataEntry *colliding_entry = GDATA_ENTRY (l->data); +- +- if (insert_entry_full (self, colliding_entry, FALSE)) ++ for (l = self->dir_collisions; l != NULL; l = l->next) + { +- self->dir_collisions = g_list_remove_link (self->dir_collisions, l); +- g_debug (" remove_entry: Restored %p\n", colliding_entry); +- g_list_free (l); +- g_object_unref (colliding_entry); +- break; ++ GDataEntry *colliding_entry = GDATA_ENTRY (l->data); ++ ++ if (insert_entry_full (self, colliding_entry, FALSE)) ++ { ++ self->dir_collisions = g_list_remove_link (self->dir_collisions, l); ++ g_debug (" remove_entry: Restored %p\n", colliding_entry); ++ g_list_free (l); ++ g_object_unref (colliding_entry); ++ break; ++ } + } + } + } +@@ -492,16 +501,85 @@ remove_entry (GVfsBackendGoogle *self, + } + + static void +-rebuild_entries (GVfsBackendGoogle *self, +- GCancellable *cancellable, +- GError **error) ++remove_entry (GVfsBackendGoogle *self, ++ GDataEntry *entry) ++{ ++ remove_entry_full (self, entry, TRUE); ++} ++ ++static void ++remove_dir (GVfsBackendGoogle *self, ++ GDataEntry *parent) ++{ ++ GHashTableIter iter; ++ GDataEntry *entry; ++ gchar *parent_id; ++ GList *l; ++ ++ /* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */ ++ parent_id = g_strdup (gdata_entry_get_id (parent)); ++ ++ g_hash_table_iter_init (&iter, self->entries); ++ while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry)) ++ { ++ DirEntriesKey *k; ++ ++ k = dir_entries_key_new (gdata_entry_get_id (entry), parent_id); ++ if (g_hash_table_contains (self->dir_entries, k)) ++ { ++ g_object_ref (entry); ++ g_hash_table_iter_remove (&iter); ++ remove_entry_full (self, entry, FALSE); ++ g_object_unref (entry); ++ } ++ ++ dir_entries_key_free (k); ++ } ++ ++ for (l = self->dir_collisions; l != NULL; l = l->next) ++ { ++ GDataEntry *colliding_entry = GDATA_ENTRY (l->data); ++ ++ if (insert_entry_full (self, colliding_entry, FALSE)) ++ { ++ self->dir_collisions = g_list_remove_link (self->dir_collisions, l); ++ g_debug (" remove_entry: Restored %p\n", colliding_entry); ++ g_list_free (l); ++ g_object_unref (colliding_entry); ++ break; ++ } ++ } ++ ++ g_free (parent_id); ++} ++ ++static gboolean ++is_entry_valid (GDataEntry *entry) ++{ ++ gint64 *timestamp; ++ ++ timestamp = g_object_get_data (G_OBJECT (entry), "timestamp"); ++ return (g_get_real_time () - *timestamp < REBUILD_ENTRIES_TIMEOUT * G_USEC_PER_SEC); ++} ++ ++static void ++rebuild_dir (GVfsBackendGoogle *self, ++ GDataEntry *parent, ++ GCancellable *cancellable, ++ GError **error) + { + GDataDocumentsFeed *feed = NULL; + GDataDocumentsQuery *query = NULL; + gboolean succeeded_once = FALSE; ++ gchar *search; ++ const gchar *parent_id; ++ ++ parent_id = gdata_entry_get_id (parent); + +- query = gdata_documents_query_new_with_limits (NULL, 1, MAX_RESULTS); ++ search = g_strdup_printf ("'%s' in parents", parent_id); ++ query = gdata_documents_query_new_with_limits (search, 1, MAX_RESULTS); + gdata_documents_query_set_show_folders (query, TRUE); ++ g_free (search); + + while (TRUE) + { +@@ -515,18 +593,13 @@ rebuild_entries (GVfsBackendGoogle *self, + { + sanitize_error (&local_error); + g_propagate_error (error, local_error); +- self->entries_stale = TRUE; + + goto out; + } + + if (!succeeded_once) + { +- g_hash_table_remove_all (self->entries); +- g_hash_table_remove_all (self->dir_entries); +- +- g_list_free_full (self->dir_collisions, g_object_unref); +- self->dir_collisions = NULL; ++ remove_dir (self, parent); + + succeeded_once = TRUE; + } +@@ -545,8 +618,6 @@ rebuild_entries (GVfsBackendGoogle *self, + g_clear_object (&feed); + } + +- self->entries_stale = FALSE; +- + out: + g_clear_object (&feed); + g_clear_object (&query); +@@ -555,24 +626,48 @@ rebuild_entries (GVfsBackendGoogle *self, + /* ---------------------------------------------------------------------------------------------------- */ + + static GDataEntry * +-resolve_child (GVfsBackendGoogle *self, +- GDataEntry *parent, +- const gchar *basename) ++resolve_child (GVfsBackendGoogle *self, ++ GDataEntry *parent, ++ const gchar *basename, ++ GCancellable *cancellable, ++ GError **error) + { + DirEntriesKey *k; + GDataEntry *entry; + const gchar *parent_id; ++ GError *local_error = NULL; + + parent_id = gdata_entry_get_id (parent); + k = dir_entries_key_new (basename, parent_id); + entry = g_hash_table_lookup (self->dir_entries, k); ++ // TODO: Rebuild only if dir listing is not valid ++ if (entry == NULL || !is_entry_valid (entry)) ++ { ++ rebuild_dir (self, parent, cancellable, &local_error); ++ if (local_error != NULL) ++ { ++ g_propagate_error (error, local_error); ++ goto out; ++ } ++ ++ entry = g_hash_table_lookup (self->dir_entries, k); ++ if (entry == NULL) ++ { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory")); ++ goto out; ++ } ++ } ++ ++ out: + dir_entries_key_free (k); ++ + return entry; + } + + static GDataEntry * + resolve (GVfsBackendGoogle *self, + const gchar *filename, ++ GCancellable *cancellable, + gchar **out_path, + GError **error) + { +@@ -581,6 +676,8 @@ resolve (GVfsBackendGoogle *self, + GError *local_error; + gchar *basename = NULL; + ++ g_assert (filename && filename[0] == '/'); ++ + if (g_strcmp0 (filename, "/") == 0) + { + ret_val = self->root; +@@ -592,17 +689,17 @@ resolve (GVfsBackendGoogle *self, + } + + local_error = NULL; +- parent = resolve_dir (self, filename, &basename, out_path, &local_error); ++ parent = resolve_dir (self, filename, cancellable, &basename, out_path, &local_error); + if (local_error != NULL) + { + g_propagate_error (error, local_error); + goto out; + } + +- ret_val = resolve_child (self, parent, basename); ++ ret_val = resolve_child (self, parent, basename, cancellable, &local_error); + if (ret_val == NULL) + { +- g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory")); ++ g_propagate_error (error, local_error); + goto out; + } + +@@ -622,6 +719,7 @@ resolve (GVfsBackendGoogle *self, + static GDataEntry * + resolve_dir (GVfsBackendGoogle *self, + const gchar *filename, ++ GCancellable *cancellable, + gchar **out_basename, + gchar **out_path, + GError **error) +@@ -636,7 +734,7 @@ resolve_dir (GVfsBackendGoogle *self, + parent_path = g_path_get_dirname (filename); + + local_error = NULL; +- parent = resolve (self, parent_path, out_path, &local_error); ++ parent = resolve (self, parent_path, cancellable, out_path, &local_error); + if (local_error != NULL) + { + g_propagate_error (error, local_error); +@@ -665,103 +763,6 @@ resolve_dir (GVfsBackendGoogle *self, + + /* ---------------------------------------------------------------------------------------------------- */ + +-static GDataEntry * +-resolve_and_rebuild (GVfsBackendGoogle *self, +- const gchar *filename, +- GCancellable *cancellable, +- gchar **out_path, +- GError **error) +-{ +- GDataEntry *entry; +- GDataEntry *ret_val = NULL; +- +- entry = resolve (self, filename, out_path, NULL); +- if (entry == NULL) +- { +- GError *local_error; +- +- local_error = NULL; +- rebuild_entries (self, cancellable, &local_error); +- if (local_error != NULL) +- { +- g_propagate_error (error, local_error); +- goto out; +- } +- +- local_error = NULL; +- entry = resolve (self, filename, out_path, &local_error); +- if (local_error != NULL) +- { +- g_propagate_error (error, local_error); +- goto out; +- } +- } +- +- ret_val = entry; +- +- out: +- return ret_val; +-} +- +-static GDataEntry * +-resolve_dir_and_rebuild (GVfsBackendGoogle *self, +- const gchar *filename, +- GCancellable *cancellable, +- gchar **out_basename, +- gchar **out_path, +- GError **error) +-{ +- GDataEntry *parent; +- GDataEntry *ret_val = NULL; +- GError *local_error; +- gchar *basename = NULL; +- +- local_error = NULL; +- parent = resolve_dir (self, filename, &basename, out_path, &local_error); +- if (local_error != NULL) +- { +- if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY)) +- { +- g_propagate_error (error, local_error); +- goto out; +- } +- else +- { +- g_error_free (local_error); +- } +- +- local_error = NULL; +- rebuild_entries (self, cancellable, &local_error); +- if (local_error != NULL) +- { +- g_propagate_error (error, local_error); +- goto out; +- } +- +- local_error = NULL; +- parent = resolve_dir (self, filename, &basename, out_path, &local_error); +- if (local_error != NULL) +- { +- g_propagate_error (error, local_error); +- goto out; +- } +- } +- +- if (out_basename != NULL) +- { +- *out_basename = basename; +- basename = NULL; +- } +- +- ret_val = parent; +- +- out: +- g_free (basename); +- return ret_val; +-} +- +-/* ---------------------------------------------------------------------------------------------------- */ +- + static char * + get_extension_offset (const char *title) + { +@@ -804,11 +805,11 @@ generate_copy_name (GVfsBackendGoogle *self, GDataEntry *entry, const gchar *ent + + title = gdata_entry_get_title (entry); + +- parent = resolve_dir (self, entry_path, NULL, NULL, NULL); ++ parent = resolve_dir (self, entry_path, NULL, NULL, NULL, NULL); + if (parent == NULL) + goto out; + +- existing_entry = resolve_child (self, parent, title); ++ existing_entry = resolve_child (self, parent, title, NULL, NULL); + if (existing_entry == entry) + goto out; + +@@ -1074,8 +1075,6 @@ g_vfs_backend_google_copy (GVfsBackend *_self, + GDataEntry *source_entry; + GError *error; + GType source_entry_type; +- gboolean needs_rebuild = FALSE; +- gboolean destination_not_directory = FALSE; + const gchar *etag; + const gchar *id; + const gchar *summary; +@@ -1097,56 +1096,21 @@ g_vfs_backend_google_copy (GVfsBackend *_self, + goto out; + } + +- source_entry = resolve (self, source, NULL, NULL); +- if (source_entry == NULL) +- needs_rebuild = TRUE; +- + error = NULL; +- destination_parent = resolve_dir (self, destination, &destination_basename, &parent_path, &error); ++ source_entry = resolve (self, source, cancellable, NULL, &error); + if (error != NULL) + { +- if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY)) +- destination_not_directory = TRUE; +- else +- needs_rebuild = TRUE; +- ++ g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_error_free (error); ++ goto out; + } + +- if (needs_rebuild) ++ destination_parent = resolve_dir (self, destination, cancellable, &destination_basename, &parent_path, &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; +- } +- +- error = NULL; +- source_entry = resolve (self, source, NULL, &error); +- if (error != NULL) +- { +- g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +- g_error_free (error); +- goto out; +- } +- +- if (!destination_not_directory) +- { +- g_free (destination_basename); +- destination_basename = NULL; +- +- error = NULL; +- destination_parent = resolve_dir (self, destination, &destination_basename, &parent_path, &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; + } + + etag = gdata_entry_get_etag (source_entry); +@@ -1165,13 +1129,7 @@ g_vfs_backend_google_copy (GVfsBackend *_self, + goto out; + } + +- if (destination_not_directory) +- { +- g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY, _("The file is not a directory")); +- goto out; +- } +- +- existing_entry = resolve_child (self, destination_parent, destination_basename); ++ existing_entry = resolve_child (self, destination_parent, destination_basename, cancellable, NULL); + if (existing_entry != NULL) + { + if (flags & G_FILE_COPY_OVERWRITE) +@@ -1274,7 +1232,7 @@ g_vfs_backend_google_create_dir_monitor (GVfsBackend *_self, + } + + error = NULL; +- entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error); ++ entry = resolve (self, filename, cancellable, &entry_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -1325,7 +1283,7 @@ g_vfs_backend_google_delete (GVfsBackend *_self, + g_debug ("+ delete: %s\n", filename); + + error = NULL; +- entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error); ++ entry = resolve (self, filename, cancellable, &entry_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -1392,17 +1350,6 @@ g_vfs_backend_google_delete (GVfsBackend *_self, + + /* ---------------------------------------------------------------------------------------------------- */ + +-static gboolean +-rebuild_entries_timeout_cb (gpointer user_data) +-{ +- GVfsBackendGoogle *self = G_VFS_BACKEND_GOOGLE (user_data); +- +- self->entries_stale = TRUE; +- self->entries_stale_timeout = 0; +- +- return G_SOURCE_REMOVE; +-} +- + static void + g_vfs_backend_google_enumerate (GVfsBackend *_self, + GVfsJobEnumerate *job, +@@ -1421,29 +1368,8 @@ g_vfs_backend_google_enumerate (GVfsBackend *_self, + g_rec_mutex_lock (&self->mutex); + g_debug ("+ enumerate: %s\n", filename); + +- if (self->entries_stale_timeout == 0) +- { +- self->entries_stale_timeout = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT, +- REBUILD_ENTRIES_TIMEOUT, +- rebuild_entries_timeout_cb, +- g_object_ref (self), +- g_object_unref); +- } +- +- if (self->entries_stale) +- { +- 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; +- } +- } +- + error = NULL; +- entry = resolve (self, filename, &parent_path, &error); ++ entry = resolve (self, filename, cancellable, &parent_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -1457,6 +1383,15 @@ g_vfs_backend_google_enumerate (GVfsBackend *_self, + goto out; + } + ++ // TODO: Rebuild only if dir listing is not valid ++ rebuild_dir (self, entry, 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_succeeded (G_VFS_JOB (job)); + + /* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */ +@@ -1523,7 +1458,7 @@ g_vfs_backend_google_make_directory (GVfsBackend *_self, + } + + error = NULL; +- parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &parent_path, &error); ++ parent = resolve_dir (self, filename, cancellable, &basename, &parent_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -1539,7 +1474,7 @@ g_vfs_backend_google_make_directory (GVfsBackend *_self, + else + summary = gdata_entry_get_summary (summary_entry); + +- existing_entry = resolve_child (self, parent, basename); ++ existing_entry = resolve_child (self, parent, basename, cancellable, NULL); + if (existing_entry != NULL) + { + g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR, G_IO_ERROR_EXISTS, _("Target file already exists")); +@@ -1768,7 +1703,7 @@ g_vfs_backend_google_push (GVfsBackend *_self, + } + + error = NULL; +- destination_parent = resolve_dir_and_rebuild (self, destination, cancellable, &destination_basename, &parent_path, &error); ++ destination_parent = resolve_dir (self, destination, cancellable, &destination_basename, &parent_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -1776,7 +1711,7 @@ g_vfs_backend_google_push (GVfsBackend *_self, + goto out; + } + +- existing_entry = resolve_child (self, destination_parent, destination_basename); ++ existing_entry = resolve_child (self, destination_parent, destination_basename, cancellable, NULL); + if (existing_entry != NULL) + { + if (flags & G_FILE_COPY_OVERWRITE) +@@ -2057,7 +1992,7 @@ g_vfs_backend_google_query_info (GVfsBackend *_self, + g_debug ("+ query_info: %s, %d\n", filename, flags); + + error = NULL; +- entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error); ++ entry = resolve (self, filename, cancellable, &entry_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -2218,7 +2153,7 @@ g_vfs_backend_google_open_for_read (GVfsBackend *_self, + g_debug ("+ open_for_read: %s\n", filename); + + error = NULL; +- entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error); ++ entry = resolve (self, filename, cancellable, &entry_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -2406,7 +2341,7 @@ g_vfs_backend_google_set_display_name (GVfsBackend *_self, + g_debug ("+ set_display_name: %s, %s\n", filename, display_name); + + error = NULL; +- entry = resolve_and_rebuild (self, filename, cancellable, &entry_path, &error); ++ entry = resolve (self, filename, cancellable, &entry_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -2478,7 +2413,7 @@ g_vfs_backend_google_create (GVfsBackend *_self, + } + + error = NULL; +- parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &parent_path, &error); ++ parent = resolve_dir (self, filename, cancellable, &basename, &parent_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -2488,7 +2423,7 @@ g_vfs_backend_google_create (GVfsBackend *_self, + + g_debug (" parent path: %s\n", parent_path); + +- existing_entry = resolve_child (self, parent, basename); ++ existing_entry = resolve_child (self, parent, basename, cancellable, NULL); + if (existing_entry != NULL) + { + if (flags & G_FILE_CREATE_REPLACE_DESTINATION) +@@ -2587,7 +2522,7 @@ g_vfs_backend_google_replace (GVfsBackend *_self, + } + + error = NULL; +- parent = resolve_dir_and_rebuild (self, filename, cancellable, &basename, &parent_path, &error); ++ parent = resolve_dir (self, filename, cancellable, &basename, &parent_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -2597,7 +2532,7 @@ g_vfs_backend_google_replace (GVfsBackend *_self, + + g_debug (" parent path: %s\n", parent_path); + +- existing_entry = resolve_child (self, parent, basename); ++ existing_entry = resolve_child (self, parent, basename, cancellable, NULL); + if (existing_entry != NULL) + { + if (GDATA_IS_DOCUMENTS_FOLDER (existing_entry)) +@@ -2819,12 +2754,6 @@ g_vfs_backend_google_dispose (GObject *_self) + { + GVfsBackendGoogle *self = G_VFS_BACKEND_GOOGLE (_self); + +- if (self->entries_stale_timeout != 0) +- { +- g_source_remove (self->entries_stale_timeout); +- self->entries_stale_timeout = 0; +- } +- + if (self->dir_collisions != NULL) + { + g_list_free_full (self->dir_collisions, g_object_unref); +@@ -2896,5 +2825,4 @@ g_vfs_backend_google_init (GVfsBackendGoogle *self) + g_object_unref); + self->monitors = g_hash_table_new (NULL, NULL); + g_rec_mutex_init (&self->mutex); +- self->entries_stale = TRUE; + } +-- +2.36.1 + + +From 8c8bc7a8c37bbf1493b14cd76b21b077136e3260 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Thu, 16 Aug 2018 15:00:52 +0200 +Subject: [PATCH 09/14] google: Use cache for enumeration also + +The reworked cache hasn't been used for enumeration results and also +for missing files checks, which always caused rebuilding cache. Let's +save timestamps also for enumerations and use it to prevent redundant +cache rebuilds. +--- + daemon/gvfsbackendgoogle.c | 62 ++++++++++++++++++++++++++++---------- + 1 file changed, 46 insertions(+), 16 deletions(-) + +diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c +index bf50fef6..4eb8dbfe 100644 +--- a/daemon/gvfsbackendgoogle.c ++++ b/daemon/gvfsbackendgoogle.c +@@ -57,6 +57,7 @@ struct _GVfsBackendGoogle + GDataEntry *root; + GHashTable *entries; /* gchar *entry_id -> GDataEntry */ + GHashTable *dir_entries; /* DirEntriesKey -> GDataEntry */ ++ GHashTable *dir_timestamps; /* gchar *entry_id -> gint64 *timestamp */ + GHashTable *monitors; + GList *dir_collisions; + GRecMutex mutex; /* guards cache */ +@@ -463,6 +464,8 @@ remove_entry_full (GVfsBackendGoogle *self, + { + gchar *parent_id = ll->data; + ++ g_hash_table_remove (self->dir_timestamps, parent_id); ++ + k = dir_entries_key_new (id, parent_id); + g_debug (" remove_entry: Removed (%s, %s) -> %p\n", id, parent_id, entry); + g_hash_table_remove (self->dir_entries, k); +@@ -519,6 +522,8 @@ remove_dir (GVfsBackendGoogle *self, + /* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */ + parent_id = g_strdup (gdata_entry_get_id (parent)); + ++ g_hash_table_remove (self->dir_timestamps, parent_id); ++ + g_hash_table_iter_init (&iter, self->entries); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry)) + { +@@ -562,6 +567,18 @@ is_entry_valid (GDataEntry *entry) + return (g_get_real_time () - *timestamp < REBUILD_ENTRIES_TIMEOUT * G_USEC_PER_SEC); + } + ++static gboolean ++is_dir_listing_valid (GVfsBackendGoogle *self, GDataEntry *parent) ++{ ++ gint64 *timestamp; ++ ++ timestamp = g_hash_table_lookup (self->dir_timestamps, gdata_entry_get_id (parent)); ++ if (timestamp != NULL) ++ return (g_get_real_time () - *timestamp < REBUILD_ENTRIES_TIMEOUT * G_USEC_PER_SEC); ++ ++ return FALSE; ++} ++ + static void + rebuild_dir (GVfsBackendGoogle *self, + GDataEntry *parent, +@@ -572,9 +589,10 @@ rebuild_dir (GVfsBackendGoogle *self, + GDataDocumentsQuery *query = NULL; + gboolean succeeded_once = FALSE; + gchar *search; +- const gchar *parent_id; ++ gchar *parent_id; + +- parent_id = gdata_entry_get_id (parent); ++ /* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */ ++ parent_id = g_strdup (gdata_entry_get_id (parent)); + + search = g_strdup_printf ("'%s' in parents", parent_id); + query = gdata_documents_query_new_with_limits (search, 1, MAX_RESULTS); +@@ -599,8 +617,14 @@ rebuild_dir (GVfsBackendGoogle *self, + + if (!succeeded_once) + { ++ gint64 *timestamp; ++ + remove_dir (self, parent); + ++ timestamp = g_new (gint64, 1); ++ *timestamp = g_get_real_time (); ++ g_hash_table_insert (self->dir_timestamps, g_strdup (parent_id), timestamp); ++ + succeeded_once = TRUE; + } + +@@ -621,6 +645,7 @@ rebuild_dir (GVfsBackendGoogle *self, + out: + g_clear_object (&feed); + g_clear_object (&query); ++ g_free (parent_id); + } + + /* ---------------------------------------------------------------------------------------------------- */ +@@ -640,8 +665,8 @@ resolve_child (GVfsBackendGoogle *self, + parent_id = gdata_entry_get_id (parent); + k = dir_entries_key_new (basename, parent_id); + entry = g_hash_table_lookup (self->dir_entries, k); +- // TODO: Rebuild only if dir listing is not valid +- if (entry == NULL || !is_entry_valid (entry)) ++ if ((entry == NULL && !is_dir_listing_valid (self, parent)) || ++ (entry != NULL && !is_entry_valid (entry))) + { + rebuild_dir (self, parent, cancellable, &local_error); + if (local_error != NULL) +@@ -651,11 +676,12 @@ resolve_child (GVfsBackendGoogle *self, + } + + entry = g_hash_table_lookup (self->dir_entries, k); +- if (entry == NULL) +- { +- g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory")); +- goto out; +- } ++ } ++ ++ if (entry == NULL) ++ { ++ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("No such file or directory")); ++ goto out; + } + + out: +@@ -1363,7 +1389,7 @@ g_vfs_backend_google_enumerate (GVfsBackend *_self, + GError *error; + GHashTableIter iter; + char *parent_path; +- char *id; ++ char *id = NULL; + + g_rec_mutex_lock (&self->mutex); + g_debug ("+ enumerate: %s\n", filename); +@@ -1383,13 +1409,15 @@ g_vfs_backend_google_enumerate (GVfsBackend *_self, + goto out; + } + +- // TODO: Rebuild only if dir listing is not valid +- rebuild_dir (self, entry, cancellable, &error); +- if (error != NULL) ++ if (!is_dir_listing_valid (self, entry)) + { +- g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +- g_error_free (error); +- goto out; ++ rebuild_dir (self, entry, 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_succeeded (G_VFS_JOB (job)); +@@ -2765,6 +2793,7 @@ g_vfs_backend_google_dispose (GObject *_self) + g_clear_object (&self->client); + g_clear_pointer (&self->entries, g_hash_table_unref); + g_clear_pointer (&self->dir_entries, g_hash_table_unref); ++ g_clear_pointer (&self->dir_timestamps, g_hash_table_unref); + + G_OBJECT_CLASS (g_vfs_backend_google_parent_class)->dispose (_self); + } +@@ -2823,6 +2852,7 @@ g_vfs_backend_google_init (GVfsBackendGoogle *self) + entries_in_folder_equal, + dir_entries_key_free, + g_object_unref); ++ self->dir_timestamps = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + self->monitors = g_hash_table_new (NULL, NULL); + g_rec_mutex_init (&self->mutex); + } +-- +2.36.1 + + +From 79e1878e1a43e32c0dbce585ea377d0222f85f27 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Wed, 1 Aug 2018 16:17:42 +0200 +Subject: [PATCH 10/14] google: Handle child of volatile also as volatile + +Files in volatile folder should be also marked as volatile. + +Volatile handling is a bit simplified as a part of this patch also. +--- + daemon/gvfsbackendgoogle.c | 58 +++++++++++++------------------------- + 1 file changed, 19 insertions(+), 39 deletions(-) + +diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c +index 4eb8dbfe..3823cfe4 100644 +--- a/daemon/gvfsbackendgoogle.c ++++ b/daemon/gvfsbackendgoogle.c +@@ -881,8 +881,7 @@ build_file_info (GVfsBackendGoogle *self, + GFileQueryInfoFlags flags, + GFileInfo *info, + GFileAttributeMatcher *matcher, +- gboolean is_symlink, +- const gchar *symlink_name, ++ const gchar *filename, + const gchar *entry_path, + GError **error) + { +@@ -890,6 +889,7 @@ build_file_info (GVfsBackendGoogle *self, + GList *authors; + gboolean is_folder = FALSE; + gboolean is_root = FALSE; ++ gboolean is_symlink = FALSE; + const gchar *etag; + const gchar *id; + const gchar *name; +@@ -897,6 +897,7 @@ build_file_info (GVfsBackendGoogle *self, + gchar *escaped_name = NULL; + gchar *content_type = NULL; + gchar *copy_name = NULL; ++ gchar *symlink_name = NULL; + gint64 atime; + gint64 ctime; + gint64 mtime; +@@ -908,6 +909,12 @@ build_file_info (GVfsBackendGoogle *self, + if (entry == self->root) + is_root = TRUE; + ++ if (filename != NULL && g_strcmp0 (entry_path, filename) != 0) /* volatile */ ++ { ++ is_symlink = TRUE; ++ symlink_name = g_path_get_basename (filename); ++ } ++ + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME, !is_root); + + g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE, is_folder); +@@ -1066,6 +1073,7 @@ build_file_info (GVfsBackendGoogle *self, + } + + out: ++ g_free (symlink_name); + g_free (copy_name); + g_free (escaped_name); + g_free (content_type); +@@ -1435,10 +1443,12 @@ g_vfs_backend_google_enumerate (GVfsBackend *_self, + { + GFileInfo *info; + gchar *entry_path; ++ gchar *child_filename; + + info = g_file_info_new (); + entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (entry)), NULL); +- build_file_info (self, entry, flags, info, matcher, FALSE, NULL, entry_path, NULL); ++ child_filename = g_build_filename (filename, gdata_entry_get_id (GDATA_ENTRY (entry)), NULL); ++ build_file_info (self, entry, flags, info, matcher, child_filename, entry_path, NULL); + g_vfs_job_enumerate_add_info (job, info); + g_object_unref (info); + g_free (entry_path); +@@ -2012,9 +2022,7 @@ g_vfs_backend_google_query_info (GVfsBackend *_self, + GCancellable *cancellable = G_VFS_JOB (job)->cancellable; + GDataEntry *entry; + GError *error; +- gboolean is_symlink = FALSE; + gchar *entry_path = NULL; +- gchar *symlink_name = NULL; + + g_rec_mutex_lock (&self->mutex); + g_debug ("+ query_info: %s, %d\n", filename, flags); +@@ -2028,16 +2036,10 @@ g_vfs_backend_google_query_info (GVfsBackend *_self, + goto out; + } + +- if (g_strcmp0 (entry_path, filename) != 0) /* volatile */ +- { +- is_symlink = TRUE; +- symlink_name = g_path_get_basename (filename); +- } +- +- g_debug (" entry path: %s (%d)\n", entry_path, is_symlink); ++ g_debug (" entry path: %s\n", entry_path); + + error = NULL; +- build_file_info (self, entry, flags, info, matcher, is_symlink, symlink_name, entry_path, &error); ++ build_file_info (self, entry, flags, info, matcher, filename, entry_path, &error); + if (error != NULL) + { + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); +@@ -2049,7 +2051,6 @@ g_vfs_backend_google_query_info (GVfsBackend *_self, + + out: + g_free (entry_path); +- g_free (symlink_name); + g_debug ("- query_info\n"); + g_rec_mutex_unlock (&self->mutex); + } +@@ -2067,10 +2068,8 @@ g_vfs_backend_google_query_info_on_read (GVfsBackend *_self, + GDataEntry *entry; + GError *error; + GInputStream *stream = G_INPUT_STREAM (handle); +- gboolean is_symlink = FALSE; + const gchar *filename; + gchar *entry_path = NULL; +- gchar *symlink_name = NULL; + + g_debug ("+ query_info_on_read: %p\n", handle); + +@@ -2078,13 +2077,7 @@ g_vfs_backend_google_query_info_on_read (GVfsBackend *_self, + filename = g_object_get_data (G_OBJECT (stream), "g-vfs-backend-google-filename"); + entry_path = g_object_get_data (G_OBJECT (stream), "g-vfs-backend-google-entry-path"); + +- if (g_strcmp0 (entry_path, filename) != 0) /* volatile */ +- { +- is_symlink = TRUE; +- symlink_name = g_path_get_basename (filename); +- } +- +- g_debug (" entry path: %s (%d)\n", entry_path, is_symlink); ++ g_debug (" entry path: %s\n", entry_path); + + error = NULL; + build_file_info (self, +@@ -2092,8 +2085,7 @@ g_vfs_backend_google_query_info_on_read (GVfsBackend *_self, + G_FILE_QUERY_INFO_NONE, + info, + matcher, +- is_symlink, +- symlink_name, ++ filename, + entry_path, + &error); + if (error != NULL) +@@ -2106,7 +2098,6 @@ g_vfs_backend_google_query_info_on_read (GVfsBackend *_self, + g_vfs_job_succeeded (G_VFS_JOB (job)); + + out: +- g_free (symlink_name); + g_debug ("- query_info_on_read\n"); + } + +@@ -2122,18 +2113,9 @@ g_vfs_backend_google_query_info_on_write (GVfsBackend *_self, + GVfsBackendGoogle *self = G_VFS_BACKEND_GOOGLE (_self); + GError *error; + WriteHandle *wh = (WriteHandle *) handle; +- gboolean is_symlink = FALSE; +- gchar *symlink_name = NULL; + + g_debug ("+ query_info_on_write: %p\n", handle); +- +- if (g_strcmp0 (wh->entry_path, wh->filename) != 0) /* volatile */ +- { +- is_symlink = TRUE; +- symlink_name = g_path_get_basename (wh->filename); +- } +- +- g_debug (" entry path: %s (%d)\n", wh->entry_path, is_symlink); ++ g_debug (" entry path: %s\n", wh->entry_path); + + error = NULL; + build_file_info (self, +@@ -2141,8 +2123,7 @@ g_vfs_backend_google_query_info_on_write (GVfsBackend *_self, + G_FILE_QUERY_INFO_NONE, + info, + matcher, +- is_symlink, +- symlink_name, ++ wh->filename, + wh->entry_path, + &error); + if (error != NULL) +@@ -2155,7 +2136,6 @@ g_vfs_backend_google_query_info_on_write (GVfsBackend *_self, + g_vfs_job_succeeded (G_VFS_JOB (job)); + + out: +- g_free (symlink_name); + g_debug ("- query_info_on_write\n"); + return TRUE; + } +-- +2.36.1 + + +From 46444e0aacd07a152e3d7958dcc263195cb69433 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Fri, 12 Jul 2019 10:35:47 +0200 +Subject: [PATCH 11/14] google: Do not enumerate volatile entries if title + matches id + +Currently, the volatile entry is enumerated if its title matches id +of another entry. But we don't want to enumerate volatile entries +to not confuse our clients. Let's add simple check to prevent this. +--- + daemon/gvfsbackendgoogle.c | 23 +++++++++++++++++++---- + 1 file changed, 19 insertions(+), 4 deletions(-) + +diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c +index 3823cfe4..60d6142f 100644 +--- a/daemon/gvfsbackendgoogle.c ++++ b/daemon/gvfsbackendgoogle.c +@@ -1437,23 +1437,38 @@ g_vfs_backend_google_enumerate (GVfsBackend *_self, + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry)) + { + DirEntriesKey *k; ++ GDataEntry *child; ++ gchar *child_id; + +- k = dir_entries_key_new (gdata_entry_get_id (entry), id); +- if (g_hash_table_contains (self->dir_entries, k)) ++ /* g_strdup() is necessary to prevent segfault because gdata_entry_get_id() calls g_free() */ ++ child_id = g_strdup (gdata_entry_get_id (entry)); ++ ++ k = dir_entries_key_new (child_id, id); ++ if ((child = g_hash_table_lookup (self->dir_entries, k)) != NULL) + { + GFileInfo *info; + gchar *entry_path; + gchar *child_filename; + ++ /* Be sure that we are not matching title of volatile file */ ++ if (g_strcmp0 (child_id, gdata_entry_get_id (child)) != 0) ++ { ++ g_debug ("Skipping %s as it is volatile path for %s\n", child_id, gdata_entry_get_id (child)); ++ g_free (child_id); ++ dir_entries_key_free (k); ++ continue; ++ } ++ + info = g_file_info_new (); +- entry_path = g_build_path ("/", parent_path, gdata_entry_get_id (GDATA_ENTRY (entry)), NULL); +- child_filename = g_build_filename (filename, gdata_entry_get_id (GDATA_ENTRY (entry)), NULL); ++ entry_path = g_build_path ("/", parent_path, child_id, NULL); ++ child_filename = g_build_filename (filename, child_id, NULL); + build_file_info (self, entry, flags, info, matcher, child_filename, entry_path, NULL); + g_vfs_job_enumerate_add_info (job, info); + g_object_unref (info); + g_free (entry_path); + } + ++ g_free (child_id); + dir_entries_key_free (k); + } + +-- +2.36.1 + + +From 7a6419a1a8702516f82002c4a003eb6468ac5e7b Mon Sep 17 00:00:00 2001 +From: Mayank Sharma +Date: Thu, 18 Jul 2019 01:18:43 +0530 +Subject: [PATCH 12/14] google: Fix issue with stale entries remaining after + rename operation + +Currently, whenever we perform a rename operation, we set the `entry`'s +title to new display name, but at the time of removal of this entry from +cache, we still use the newer title. Hence, each time rename is done, a +single stale entry remains. This commit fixes the issue by reverting +back the title to the original display name of `entry` and then +performing a removal from cache. + +Fixes: https://gitlab.gnome.org/GNOME/gvfs/issues/410 +--- + daemon/gvfsbackendgoogle.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c +index 60d6142f..1147e8f1 100644 +--- a/daemon/gvfsbackendgoogle.c ++++ b/daemon/gvfsbackendgoogle.c +@@ -2380,6 +2380,11 @@ g_vfs_backend_google_set_display_name (GVfsBackend *_self, + goto out; + } + ++ /* The internal ref count has to be increased before removing the entry since ++ * remove_entry_full calls g_object_unref(). */ ++ g_object_ref (entry); ++ remove_entry (self, entry); ++ + gdata_entry_set_title (entry, display_name); + auth_domain = gdata_documents_service_get_primary_authorization_domain (); + +@@ -2390,14 +2395,15 @@ g_vfs_backend_google_set_display_name (GVfsBackend *_self, + sanitize_error (&error); + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_error_free (error); ++ g_object_unref (entry); + goto out; + } + +- remove_entry (self, entry); + insert_entry (self, new_entry); + g_hash_table_foreach (self->monitors, emit_attribute_changed_event, entry_path); + g_vfs_job_set_display_name_set_new_path (job, entry_path); + g_vfs_job_succeeded (G_VFS_JOB (job)); ++ g_object_unref (entry); + + out: + g_clear_object (&new_entry); +-- +2.36.1 + + +From 00d1e161f47adedf2f05d3574beb05d06c76b4c0 Mon Sep 17 00:00:00 2001 +From: Mayank Sharma +Date: Tue, 23 Jul 2019 09:51:41 +0530 +Subject: [PATCH 13/14] google: Fix crashes when deleting if the file isn't + found + +Currently in delete operation, if the entry gets resolved but parent +resolution fails, the jump to `out` label (while handling error) will +cause the existing entry's ref_count to decrease by 1 (since `out` +label calls g_object_unref on entry). + +We fix the issue by removing g_object_unref from `out` label and +suitably unreffing the entry. +--- + daemon/gvfsbackendgoogle.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c +index 1147e8f1..230b89eb 100644 +--- a/daemon/gvfsbackendgoogle.c ++++ b/daemon/gvfsbackendgoogle.c +@@ -1366,6 +1366,7 @@ g_vfs_backend_google_delete (GVfsBackend *_self, + sanitize_error (&error); + g_vfs_job_failed_from_error (G_VFS_JOB (job), error); + g_error_free (error); ++ g_object_unref (entry); + goto out; + } + +@@ -1373,9 +1374,9 @@ g_vfs_backend_google_delete (GVfsBackend *_self, + 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)); ++ g_object_unref (entry); + + out: +- g_object_unref (entry); + g_clear_object (&new_entry); + g_free (entry_path); + g_debug ("- delete\n"); +-- +2.36.1 + + +From d842aa6c729866343d7a3b0514a6574c01be30ed Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Fri, 29 Jan 2021 14:06:16 +0100 +Subject: [PATCH 14/14] google: Increase number of results in batches for + better performance + +Currently, only 50 results are returned in one batch, which means that +multiple network requests are needed for folders with a lot files, which +makes it slow. I am not sure there was some reason for this limitation +earlier (e.g. before the cache rework), however, I don't see any +rationals for it currently. Let's increase this to its maximum for +better performance. +--- + daemon/gvfsbackendgoogle.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c +index 230b89eb..f97c038c 100644 +--- a/daemon/gvfsbackendgoogle.c ++++ b/daemon/gvfsbackendgoogle.c +@@ -79,8 +79,6 @@ G_DEFINE_TYPE(GVfsBackendGoogle, g_vfs_backend_google, G_VFS_TYPE_BACKEND) + + #define CONTENT_TYPE_PREFIX_GOOGLE "application/vnd.google-apps" + +-#define MAX_RESULTS 50 +- + #define REBUILD_ENTRIES_TIMEOUT 60 /* s */ + + #define URI_PREFIX "https://www.googleapis.com/drive/v2/files/" +@@ -595,7 +593,7 @@ rebuild_dir (GVfsBackendGoogle *self, + parent_id = g_strdup (gdata_entry_get_id (parent)); + + search = g_strdup_printf ("'%s' in parents", parent_id); +- query = gdata_documents_query_new_with_limits (search, 1, MAX_RESULTS); ++ query = gdata_documents_query_new_with_limits (search, 1, G_MAXUINT); + gdata_documents_query_set_show_folders (query, TRUE); + g_free (search); + +-- +2.36.1 + diff --git a/SOURCES/gvfsdaemon-Check-that-the-connecting-client-is-the-s.patch b/SOURCES/gvfsdaemon-Check-that-the-connecting-client-is-the-s.patch new file mode 100644 index 0000000..cebad56 --- /dev/null +++ b/SOURCES/gvfsdaemon-Check-that-the-connecting-client-is-the-s.patch @@ -0,0 +1,92 @@ +From e3808a1b4042761055b1d975333a8243d67b8bfe Mon Sep 17 00:00:00 2001 +From: Simon McVittie +Date: Wed, 5 Jun 2019 13:33:38 +0100 +Subject: [PATCH] gvfsdaemon: Check that the connecting client is the same user + +Otherwise, an attacker who learns the abstract socket address from +netstat(8) or similar could connect to it and issue D-Bus method +calls. + +Signed-off-by: Simon McVittie +--- + daemon/gvfsdaemon.c | 36 +++++++++++++++++++++++++++++++++++- + 1 file changed, 35 insertions(+), 1 deletion(-) + +diff --git a/daemon/gvfsdaemon.c b/daemon/gvfsdaemon.c +index 406d4f8e..be148a7b 100644 +--- a/daemon/gvfsdaemon.c ++++ b/daemon/gvfsdaemon.c +@@ -79,6 +79,7 @@ struct _GVfsDaemon + + gint mount_counter; + ++ GDBusAuthObserver *auth_observer; + GDBusConnection *conn; + GVfsDBusDaemon *daemon_skeleton; + GVfsDBusMountable *mountable_skeleton; +@@ -171,6 +172,8 @@ g_vfs_daemon_finalize (GObject *object) + } + if (daemon->conn != NULL) + g_object_unref (daemon->conn); ++ if (daemon->auth_observer != NULL) ++ g_object_unref (daemon->auth_observer); + + g_hash_table_destroy (daemon->registered_paths); + g_hash_table_destroy (daemon->client_connections); +@@ -236,6 +239,35 @@ name_vanished_handler (GDBusConnection *connection, + daemon->lost_main_daemon = TRUE; + } + ++/* ++ * Authentication observer signal handler that authorizes connections ++ * from the same uid as this process. This matches the behaviour of a ++ * libdbus DBusServer/DBusConnection when no DBusAllowUnixUserFunction ++ * has been set, but is not the default in GDBus. ++ */ ++static gboolean ++authorize_authenticated_peer_cb (GDBusAuthObserver *observer, ++ G_GNUC_UNUSED GIOStream *stream, ++ GCredentials *credentials, ++ G_GNUC_UNUSED gpointer user_data) ++{ ++ gboolean authorized = FALSE; ++ ++ if (credentials != NULL) ++ { ++ GCredentials *own_credentials; ++ ++ own_credentials = g_credentials_new (); ++ ++ if (g_credentials_is_same_user (credentials, own_credentials, NULL)) ++ authorized = TRUE; ++ ++ g_object_unref (own_credentials); ++ } ++ ++ return authorized; ++} ++ + static void + g_vfs_daemon_init (GVfsDaemon *daemon) + { +@@ -265,6 +297,8 @@ g_vfs_daemon_init (GVfsDaemon *daemon) + + daemon->conn = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); + g_assert (daemon->conn != NULL); ++ daemon->auth_observer = g_dbus_auth_observer_new (); ++ g_signal_connect (daemon->auth_observer, "authorize-authenticated-peer", G_CALLBACK (authorize_authenticated_peer_cb), NULL); + + daemon->daemon_skeleton = gvfs_dbus_daemon_skeleton_new (); + g_signal_connect (daemon->daemon_skeleton, "handle-get-connection", G_CALLBACK (handle_get_connection), daemon); +@@ -876,7 +910,7 @@ handle_get_connection (GVfsDBusDaemon *object, + server = g_dbus_server_new_sync (address1, + G_DBUS_SERVER_FLAGS_NONE, + guid, +- NULL, /* GDBusAuthObserver */ ++ daemon->auth_observer, + NULL, /* GCancellable */ + &error); + g_free (guid); +-- +2.21.0 + diff --git a/SOURCES/smb-Ignore-EINVAL-for-kerberos-login.patch b/SOURCES/smb-Ignore-EINVAL-for-kerberos-login.patch new file mode 100644 index 0000000..aa42bd9 --- /dev/null +++ b/SOURCES/smb-Ignore-EINVAL-for-kerberos-login.patch @@ -0,0 +1,43 @@ +diff --git a/daemon/gvfsbackendsmb.c b/daemon/gvfsbackendsmb.c +index 33d1a209..776b67bc 100644 +--- a/daemon/gvfsbackendsmb.c ++++ b/daemon/gvfsbackendsmb.c +@@ -513,7 +513,13 @@ do_mount (GVfsBackend *backend, + if (res == 0) + break; + +- if (op_backend->mount_cancelled || (errsv != EACCES && errsv != EPERM)) ++ if (errsv == EINVAL && op_backend->mount_try == 0 && op_backend->user == NULL) ++ { ++ /* EINVAL is "expected" when kerberos/ccache is misconfigured, see: ++ * https://gitlab.gnome.org/GNOME/gvfs/-/issues/611 ++ */ ++ } ++ else if (op_backend->mount_cancelled || (errsv != EACCES && errsv != EPERM)) + { + g_debug ("do_mount - (errno != EPERM && errno != EACCES), cancelled = %d, breaking\n", op_backend->mount_cancelled); + break; +diff --git a/daemon/gvfsbackendsmbbrowse.c b/daemon/gvfsbackendsmbbrowse.c +index 57bae9db..7e8facfb 100644 +--- a/daemon/gvfsbackendsmbbrowse.c ++++ b/daemon/gvfsbackendsmbbrowse.c +@@ -967,8 +967,14 @@ do_mount (GVfsBackend *backend, + uri, op_backend->mount_try, dir, op_backend->mount_cancelled, + errsv, g_strerror (errsv)); + +- if (dir == NULL && +- (op_backend->mount_cancelled || (errsv != EPERM && errsv != EACCES))) ++ if (errsv == EINVAL && op_backend->mount_try == 0 && op_backend->user == NULL) ++ { ++ /* EINVAL is "expected" when kerberos is misconfigured, see: ++ * https://gitlab.gnome.org/GNOME/gvfs/-/issues/611 ++ */ ++ } ++ else if (dir == NULL && ++ (op_backend->mount_cancelled || (errsv != EPERM && errsv != EACCES))) + { + g_debug ("do_mount - (errno != EPERM && errno != EACCES), cancelled = %d, breaking\n", op_backend->mount_cancelled); + break; +-- +2.35.1 + diff --git a/SOURCES/smb-Improve-enumeration-performance.patch b/SOURCES/smb-Improve-enumeration-performance.patch new file mode 100644 index 0000000..9019b0a --- /dev/null +++ b/SOURCES/smb-Improve-enumeration-performance.patch @@ -0,0 +1,115 @@ +diff --git a/configure.ac b/configure.ac +index daeee728..689667e5 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -551,6 +551,11 @@ if test "x$enable_samba" != "xno"; then + AC_DEFINE(HAVE_SMBC_SETOPTIONPROTOCOLS, 1, [Define to 1 if smbc_setOptionProtocols() is available]), + [] + ) ++ ++ AC_CHECK_LIB(smbclient, smbc_readdirplus2, ++ AC_DEFINE(HAVE_SMBC_READDIRPLUS2, 1, [Define to 1 if smbc_readdirplus2() is available]), ++ [] ++ ) + fi + fi + +diff --git a/daemon/gvfsbackendsmb.c b/daemon/gvfsbackendsmb.c +index 9571fa0d..ce151648 100644 +--- a/daemon/gvfsbackendsmb.c ++++ b/daemon/gvfsbackendsmb.c +@@ -1738,25 +1738,34 @@ do_enumerate (GVfsBackend *backend, + GFileQueryInfoFlags flags) + { + GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend); +- struct stat st; +- int res; ++ struct stat st = { 0 }; + GError *error; + SMBCFILE *dir; +- char dirents[1024*4]; +- struct smbc_dirent *dirp; + GFileInfo *info; + GString *uri; +- int uri_start_len; + smbc_opendir_fn smbc_opendir; ++ smbc_closedir_fn smbc_closedir; ++#ifndef HAVE_SMBC_READDIRPLUS2 ++ int res; ++ char dirents[1024*4]; ++ struct smbc_dirent *dirp; ++ int uri_start_len; + smbc_getdents_fn smbc_getdents; + smbc_stat_fn smbc_stat; +- smbc_closedir_fn smbc_closedir; ++#else ++ smbc_readdirplus2_fn smbc_readdirplus2; ++ const struct libsmb_file_info *exstat; ++#endif + + uri = create_smb_uri_string (op_backend->server, op_backend->port, op_backend->share, filename); + + smbc_opendir = smbc_getFunctionOpendir (op_backend->smb_context); ++#ifndef HAVE_SMBC_READDIRPLUS2 + smbc_getdents = smbc_getFunctionGetdents (op_backend->smb_context); + smbc_stat = smbc_getFunctionStat (op_backend->smb_context); ++#else ++ smbc_readdirplus2 = smbc_getFunctionReaddirPlus2 (op_backend->smb_context); ++#endif + smbc_closedir = smbc_getFunctionClosedir (op_backend->smb_context); + + dir = smbc_opendir (op_backend->smb_context, uri->str); +@@ -1776,6 +1785,8 @@ do_enumerate (GVfsBackend *backend, + + if (uri->str[uri->len - 1] != '/') + g_string_append_c (uri, '/'); ++ ++#ifndef HAVE_SMBC_READDIRPLUS2 + uri_start_len = uri->len; + + while (TRUE) +@@ -1827,9 +1838,27 @@ do_enumerate (GVfsBackend *backend, + dirp = (struct smbc_dirent *) (((char *)dirp) + dirlen); + res -= dirlen; + } ++ } ++#else ++ while ((exstat = smbc_readdirplus2 (op_backend->smb_context, dir, &st)) != NULL) ++ { ++ if ((S_ISREG (st.st_mode) || ++ S_ISDIR (st.st_mode) || ++ S_ISLNK (st.st_mode)) && ++ g_strcmp0 (exstat->name, ".") != 0 && ++ g_strcmp0 (exstat->name, "..") != 0) ++ { ++ info = g_file_info_new (); ++ set_info_from_stat (op_backend, info, &st, exstat->name, matcher); ++ g_vfs_job_enumerate_add_info (job, info); ++ g_object_unref (info); ++ } ++ ++ memset (&st, 0, sizeof (struct stat)); + } +- +- res = smbc_closedir (op_backend->smb_context, dir); ++#endif ++ ++ smbc_closedir (op_backend->smb_context, dir); + + g_vfs_job_enumerate_done (job); + +diff --git a/meson.build b/meson.build +index 6ae768d9..d3f59457 100644 +--- a/meson.build ++++ b/meson.build +@@ -418,6 +418,7 @@ if enable_samba + smbclient_dep = dependency('smbclient') + + config_h.set('HAVE_SMBC_SETOPTIONPROTOCOLS', cc.has_function('smbc_setOptionProtocols', dependencies: smbclient_dep)) ++ config_h.set('HAVE_SMBC_READDIRPLUS2', cc.has_function('smbc_readdirplus2', dependencies: smbclient_dep)) + endif + + # *** Check for libarchive *** +-- +2.26.2 + diff --git a/SOURCES/smb-Rework-anonymous-handling-to-avoid-EINVAL.patch b/SOURCES/smb-Rework-anonymous-handling-to-avoid-EINVAL.patch new file mode 100644 index 0000000..3486aa7 --- /dev/null +++ b/SOURCES/smb-Rework-anonymous-handling-to-avoid-EINVAL.patch @@ -0,0 +1,57 @@ +diff --git a/daemon/gvfsbackendsmb.c b/daemon/gvfsbackendsmb.c +index 776b67bc..a1e3eacd 100644 +--- a/daemon/gvfsbackendsmb.c ++++ b/daemon/gvfsbackendsmb.c +@@ -80,7 +80,6 @@ struct _GVfsBackendSmb + int mount_try; + gboolean mount_try_again; + gboolean mount_cancelled; +- gboolean use_anonymous; + + gboolean password_in_keyring; + GPasswordSave password_save; +@@ -215,13 +214,6 @@ auth_callback (SMBCCTX *context, + backend->mount_try_again = TRUE; + g_debug ("auth_callback - kerberos pass\n"); + } +- else if (backend->use_anonymous) +- { +- /* Try again if anonymous login fails */ +- backend->use_anonymous = FALSE; +- backend->mount_try_again = TRUE; +- g_debug ("auth_callback - anonymous login pass\n"); +- } + else + { + gboolean in_keyring = FALSE; +@@ -304,10 +296,13 @@ auth_callback (SMBCCTX *context, + /* Try again if this fails */ + backend->mount_try_again = TRUE; + ++ smbc_setOptionNoAutoAnonymousLogin (backend->smb_context, ++ !anonymous); ++ + if (anonymous) + { +- backend->use_anonymous = TRUE; + backend->password_save = FALSE; ++ g_debug ("auth_callback - anonymous enabled\n"); + } + else + { +@@ -535,12 +530,6 @@ do_mount (GVfsBackend *backend, + smbc_setOptionFallbackAfterKerberos (op_backend->smb_context, 1); + } + +- /* If the AskPassword reply requested anonymous login, enable the +- * anonymous fallback and try again. +- */ +- smbc_setOptionNoAutoAnonymousLogin (op_backend->smb_context, +- !op_backend->use_anonymous); +- + op_backend->mount_try ++; + } + while (op_backend->mount_try_again); +-- +2.36.0 + diff --git a/SOURCES/smb-Use-O_RDWR-to-fix-fstat-when-writing.patch b/SOURCES/smb-Use-O_RDWR-to-fix-fstat-when-writing.patch new file mode 100644 index 0000000..2142250 --- /dev/null +++ b/SOURCES/smb-Use-O_RDWR-to-fix-fstat-when-writing.patch @@ -0,0 +1,67 @@ +From 3f6f906c7c7b28dc30edb98200b6e13e1a513bb4 Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Wed, 9 May 2018 12:54:59 +0200 +Subject: [PATCH] smb: Use O_RDWR to fix fstat when writing + +fstat fails with EINVAL on Windows servers if O_WRONLY is used to open +(though it works properly on SAMBA servers). O_RDWR is needed to make +it work. This causes issues when copying files over gvfsd-fuse among +others. + +https://bugzilla.gnome.org/show_bug.cgi?id=795805 +--- + daemon/gvfsbackendsmb.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/daemon/gvfsbackendsmb.c b/daemon/gvfsbackendsmb.c +index d4944197..9571fa0d 100644 +--- a/daemon/gvfsbackendsmb.c ++++ b/daemon/gvfsbackendsmb.c +@@ -808,7 +808,7 @@ do_create (GVfsBackend *backend, + smbc_open = smbc_getFunctionOpen (op_backend->smb_context); + errno = 0; + file = smbc_open (op_backend->smb_context, uri, +- O_CREAT|O_WRONLY|O_EXCL, 0666); ++ O_CREAT|O_RDWR|O_EXCL, 0666); + g_free (uri); + + if (file == NULL) +@@ -850,7 +850,7 @@ do_append_to (GVfsBackend *backend, + smbc_open = smbc_getFunctionOpen (op_backend->smb_context); + errno = 0; + file = smbc_open (op_backend->smb_context, uri, +- O_CREAT|O_WRONLY|O_APPEND, 0666); ++ O_CREAT|O_RDWR|O_APPEND, 0666); + g_free (uri); + + if (file == NULL) +@@ -916,7 +916,7 @@ open_tmpfile (GVfsBackendSmb *backend, + smbc_open = smbc_getFunctionOpen (backend->smb_context); + errno = 0; + file = smbc_open (backend->smb_context, tmp_uri, +- O_CREAT|O_WRONLY|O_EXCL, 0666); ++ O_CREAT|O_RDWR|O_EXCL, 0666); + } while (file == NULL && errno == EEXIST); + + g_free (dir_uri); +@@ -1040,7 +1040,7 @@ do_replace (GVfsBackend *backend, + + errno = 0; + file = smbc_open (op_backend->smb_context, uri, +- O_CREAT|O_WRONLY|O_EXCL, 0); ++ O_CREAT|O_RDWR|O_EXCL, 0); + if (file == NULL && errno != EEXIST) + { + int errsv = fixup_open_errno (errno); +@@ -1110,7 +1110,7 @@ do_replace (GVfsBackend *backend, + + errno = 0; + file = smbc_open (op_backend->smb_context, uri, +- O_CREAT|O_WRONLY|O_TRUNC, 0); ++ O_CREAT|O_RDWR|O_TRUNC, 0); + if (file == NULL) + { + int errsv = fixup_open_errno (errno); +-- +2.35.3 + diff --git a/SOURCES/smbbrowse-Force-NT1-protocol-version-for-workgroup-s.patch b/SOURCES/smbbrowse-Force-NT1-protocol-version-for-workgroup-s.patch new file mode 100644 index 0000000..4bf9934 --- /dev/null +++ b/SOURCES/smbbrowse-Force-NT1-protocol-version-for-workgroup-s.patch @@ -0,0 +1,89 @@ +diff --git a/configure.ac b/configure.ac +index 3b5836ff..daeee728 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -546,6 +546,11 @@ if test "x$enable_samba" != "xno"; then + if test "x$msg_samba" = "xyes"; then + PKG_CHECK_MODULES([SAMBA], [smbclient]) + AC_DEFINE([HAVE_SAMBA], 1, [Define to 1 if you have the samba libraries]) ++ ++ AC_CHECK_LIB(smbclient, smbc_setOptionProtocols, ++ AC_DEFINE(HAVE_SMBC_SETOPTIONPROTOCOLS, 1, [Define to 1 if smbc_setOptionProtocols() is available]), ++ [] ++ ) + fi + fi + +diff --git a/daemon/gvfsbackendsmbbrowse.c b/daemon/gvfsbackendsmbbrowse.c +index f08d2988..3b11883e 100644 +--- a/daemon/gvfsbackendsmbbrowse.c ++++ b/daemon/gvfsbackendsmbbrowse.c +@@ -45,6 +45,7 @@ + #include "gvfskeyring.h" + #include "gmounttracker.h" + #include "gvfsbackendsmbprivate.h" ++#include "gvfsutils.h" + + #include + +@@ -847,6 +848,47 @@ do_mount (GVfsBackend *backend, + else + op_backend->server = g_strdup (op_backend->mounted_server); + ++#ifdef HAVE_SMBC_SETOPTIONPROTOCOLS ++ /* Force NT1 protocol version if server can't be resolved (i.e. is not ++ * hostname, nor IP address). This is needed for workgroup support, because ++ * "client max protocol" has been changed from NT1 to SMB3 in recent samba ++ * versions. ++ */ ++ ++ if (op_backend->server != NULL) ++ { ++ GResolver *resolver; ++ GList *addresses; ++ GError *error = NULL; ++ gchar *server; ++ ++ resolver = g_resolver_get_default (); ++ ++ /* IPv6 server includes brackets in GMountSpec, GResolver doesn't */ ++ if (gvfs_is_ipv6 (op_backend->server)) ++ server = g_strndup (op_backend->server + 1, strlen (op_backend->server) - 2); ++ else ++ server = g_strdup (op_backend->server); ++ ++ addresses = g_resolver_lookup_by_name (resolver, server, NULL, &error); ++ if (addresses == NULL) ++ { ++ if (error != NULL) ++ { ++ g_debug ("%s\n", error->message); ++ g_error_free (error); ++ } ++ ++ g_debug ("Forcing NT1 protocol version\n"); ++ smbc_setOptionProtocols (smb_context, "NT1", "NT1"); ++ } ++ ++ g_resolver_free_addresses (addresses); ++ g_object_unref (resolver); ++ g_free (server); ++ } ++#endif ++ + icon = NULL; + symbolic_icon = NULL; + if (op_backend->server == NULL) +diff --git a/meson.build b/meson.build +index 34600188..3a876172 100644 +--- a/meson.build ++++ b/meson.build +@@ -416,6 +416,8 @@ config_h.set10('HAVE_LIBUSB', enable_libusb) + enable_samba = get_option('smb') + if enable_samba + smbclient_dep = dependency('smbclient') ++ ++ config_h.set('HAVE_SMBC_SETOPTIONPROTOCOLS', cc.has_function('smbc_setOptionProtocols', dependencies: smbclient_dep)) + endif + + # *** Check for libarchive *** diff --git a/SOURCES/udisks2-Fix-crashes-caused-by-missing-source-tag.patch b/SOURCES/udisks2-Fix-crashes-caused-by-missing-source-tag.patch new file mode 100644 index 0000000..07c0c97 --- /dev/null +++ b/SOURCES/udisks2-Fix-crashes-caused-by-missing-source-tag.patch @@ -0,0 +1,29 @@ +From 38831e4ea149a0b4731d123c63d8b493d30ad0be Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Sat, 26 May 2018 08:16:02 +0200 +Subject: [PATCH] udisks2: Fix crashes caused by missing source tag + +GAsyncReadyCallback is never called from g_drive_stop, because +source_tag is not set, but checked. This obviously causes issues +for client applications. Add missing source_tag. + +Closes: https://gitlab.gnome.org/GNOME/gvfs/issues/1 +--- + monitor/udisks2/gvfsudisks2drive.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/monitor/udisks2/gvfsudisks2drive.c b/monitor/udisks2/gvfsudisks2drive.c +index 52e9b75e..87656688 100644 +--- a/monitor/udisks2/gvfsudisks2drive.c ++++ b/monitor/udisks2/gvfsudisks2drive.c +@@ -915,6 +915,7 @@ gvfs_udisks2_drive_stop (GDrive *_drive, + GTask *task; + + task = g_task_new (drive, cancellable, callback, user_data); ++ g_task_set_source_tag (task, gvfs_udisks2_drive_stop); + + /* This information is needed in GVfsDdisks2Volume when apps have + * open files on the device ... we need to know if the button should +-- +2.23.0 + diff --git a/SOURCES/udisks2-Handle-lockdown-option-to-disable-writing.patch b/SOURCES/udisks2-Handle-lockdown-option-to-disable-writing.patch new file mode 100644 index 0000000..deb4da3 --- /dev/null +++ b/SOURCES/udisks2-Handle-lockdown-option-to-disable-writing.patch @@ -0,0 +1,128 @@ +From 9fdd59cfda93b508e76770146a8295d0a26b175d Mon Sep 17 00:00:00 2001 +From: Ondrej Holy +Date: Tue, 14 May 2019 08:46:48 +0200 +Subject: [PATCH 1/3] udisks2: Handle lockdown option to disable writing + +Handle the new mount-removable-storage-devices-as-read-only option of +org.gnome.desktop.lockdown schema and mount removable devices as read-only +if enabled. +--- + monitor/udisks2/gvfsudisks2volume.c | 8 +++++ + monitor/udisks2/gvfsudisks2volumemonitor.c | 34 ++++++++++++++++++++++ + monitor/udisks2/gvfsudisks2volumemonitor.h | 1 + + 3 files changed, 43 insertions(+) + +diff --git a/monitor/udisks2/gvfsudisks2volume.c b/monitor/udisks2/gvfsudisks2volume.c +index a509b5dd..b2545058 100644 +--- a/monitor/udisks2/gvfsudisks2volume.c ++++ b/monitor/udisks2/gvfsudisks2volume.c +@@ -1093,6 +1093,7 @@ do_mount (GTask *task) + { + MountData *data = g_task_get_task_data (task); + GVariantBuilder builder; ++ GVfsUDisks2Volume *volume = g_task_get_source_object (task); + + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + if (data->mount_operation == NULL) +@@ -1101,6 +1102,13 @@ do_mount (GTask *task) + "{sv}", + "auth.no_user_interaction", g_variant_new_boolean (TRUE)); + } ++ if (gvfs_udisks2_volume_monitor_get_readonly_lockdown (volume->monitor)) ++ { ++ g_variant_builder_add (&builder, ++ "{sv}", ++ "options", g_variant_new_string ("ro")); ++ ++ } + udisks_filesystem_call_mount (data->filesystem_to_mount, + g_variant_builder_end (&builder), + g_task_get_cancellable (task), +diff --git a/monitor/udisks2/gvfsudisks2volumemonitor.c b/monitor/udisks2/gvfsudisks2volumemonitor.c +index 0a5ce96e..37c81fcf 100644 +--- a/monitor/udisks2/gvfsudisks2volumemonitor.c ++++ b/monitor/udisks2/gvfsudisks2volumemonitor.c +@@ -65,6 +65,9 @@ struct _GVfsUDisks2VolumeMonitor + /* we keep volumes/mounts for blank and audio discs separate to handle e.g. mixed discs properly */ + GList *disc_volumes; + GList *disc_mounts; ++ ++ GSettings *lockdown_settings; ++ gboolean readonly_lockdown; + }; + + static UDisksClient *get_udisks_client_sync (GError **error); +@@ -140,6 +143,8 @@ gvfs_udisks2_volume_monitor_finalize (GObject *object) + g_list_free_full (monitor->disc_volumes, g_object_unref); + g_list_free_full (monitor->disc_mounts, g_object_unref); + ++ g_clear_object (&monitor->lockdown_settings); ++ + G_OBJECT_CLASS (gvfs_udisks2_volume_monitor_parent_class)->finalize (object); + } + +@@ -304,6 +309,17 @@ gvfs_udisks2_volume_monitor_constructor (GType type, + return ret; + } + ++static void ++lockdown_settings_changed (GSettings *settings, ++ gchar *key, ++ gpointer user_data) ++{ ++ GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (user_data); ++ ++ monitor->readonly_lockdown = g_settings_get_boolean (settings, ++ "mount-removable-storage-devices-as-read-only"); ++} ++ + static void + gvfs_udisks2_volume_monitor_init (GVfsUDisks2VolumeMonitor *monitor) + { +@@ -325,6 +341,15 @@ gvfs_udisks2_volume_monitor_init (GVfsUDisks2VolumeMonitor *monitor) + G_CALLBACK (mountpoints_changed), + monitor); + ++ monitor->lockdown_settings = g_settings_new ("org.gnome.desktop.lockdown"); ++ monitor->readonly_lockdown = g_settings_get_boolean (monitor->lockdown_settings, ++ "mount-removable-storage-devices-as-read-only"); ++ g_signal_connect_object (monitor->lockdown_settings, ++ "changed", ++ G_CALLBACK (lockdown_settings_changed), ++ monitor, ++ 0); ++ + update_all (monitor, FALSE, TRUE); + } + +@@ -388,6 +413,15 @@ gvfs_udisks2_volume_monitor_get_gudev_client (GVfsUDisks2VolumeMonitor *monitor) + + /* ---------------------------------------------------------------------------------------------------- */ + ++gboolean ++gvfs_udisks2_volume_monitor_get_readonly_lockdown (GVfsUDisks2VolumeMonitor *monitor) ++{ ++ g_return_val_if_fail (GVFS_IS_UDISKS2_VOLUME_MONITOR (monitor), FALSE); ++ return monitor->readonly_lockdown; ++} ++ ++/* ---------------------------------------------------------------------------------------------------- */ ++ + void + gvfs_udisks2_volume_monitor_update (GVfsUDisks2VolumeMonitor *monitor) + { +diff --git a/monitor/udisks2/gvfsudisks2volumemonitor.h b/monitor/udisks2/gvfsudisks2volumemonitor.h +index 7f0215dc..751a0236 100644 +--- a/monitor/udisks2/gvfsudisks2volumemonitor.h ++++ b/monitor/udisks2/gvfsudisks2volumemonitor.h +@@ -49,6 +49,7 @@ GVolumeMonitor *gvfs_udisks2_volume_monitor_new (void); + UDisksClient *gvfs_udisks2_volume_monitor_get_udisks_client (GVfsUDisks2VolumeMonitor *monitor); + void gvfs_udisks2_volume_monitor_update (GVfsUDisks2VolumeMonitor *monitor); + GUdevClient *gvfs_udisks2_volume_monitor_get_gudev_client (GVfsUDisks2VolumeMonitor *monitor); ++gboolean gvfs_udisks2_volume_monitor_get_readonly_lockdown (GVfsUDisks2VolumeMonitor *monitor); + + G_END_DECLS + +-- +2.21.0 + diff --git a/SPECS/gvfs.spec b/SPECS/gvfs.spec new file mode 100644 index 0000000..c727337 --- /dev/null +++ b/SPECS/gvfs.spec @@ -0,0 +1,1636 @@ +%define _unpackaged_files_terminate_build 0 + +%global avahi_version 0.6 +%global fuse_version 2.8.0 +%global gettext_version 0.19.4 +%global glib2_version 2.51.0 +%global goa_version 3.17.1 +%global gsettings_desktop_schemas_version 3.28.1-2 +%global gudev_version 147 +%global libarchive_version 3.0.22 +%global libcdio_paranoia_version 0.78.2 +%global libgcrypt_version 1.2.2 +%global libgdata_version 0.17.9 +%global libgphoto2_version 2.5.0 +%global libimobiledevice_version 1.2 +%global libmtp_version 1.1.12 +%global libnfs_version 1.9.8 +%global libplist_version 0.15 +%global libsmbclient_version 3.4.0 +%global libsoup_version 2.42.0 +%global libusb_version 1.0.21 +%global systemd_version 206 +%global talloc_version 1.3.0 +%global udisks2_version 1.97 + +Name: gvfs +Version: 1.36.2 +Release: 14%{?dist} +Summary: Backends for the gio framework in GLib + +License: GPLv3 and LGPLv2+ and BSD and MPLv2.0 +URL: https://wiki.gnome.org/Projects/gvfs +Source0: https://download.gnome.org/sources/gvfs/1.36/gvfs-%{version}.tar.xz + +# https://bugzilla.redhat.com/show_bug.cgi?id=1673888 +Patch0: admin-Prevent-access-if-any-authentication-agent-isn.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=1662193 +Patch1: udisks2-Handle-lockdown-option-to-disable-writing.patch +Patch2: daemon-Handle-lockdown-option-to-disable-writing.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=1729885 +Patch3: gvfsdaemon-Check-that-the-connecting-client-is-the-s.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=1739117 +Patch4: daemon-Prevent-spawning-new-daemons-if-outgoing-oper.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=1739116 +Patch5: smbbrowse-Force-NT1-protocol-version-for-workgroup-s.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=1754506 +Patch6: admin-Add-query_info_on_read-write-functionality.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=1752926 +Patch7: admin-Use-fsuid-to-ensure-correct-file-ownership.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=1753972 +Patch8: admin-Ensure-correct-ownership-when-moving-to-file-u.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=1759075 +Patch9: udisks2-Fix-crashes-caused-by-missing-source-tag.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=1569868 +Patch10: smb-Improve-enumeration-performance.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=1889411 +Patch11: goa-Add-support-for-certificate-prompts.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=2095712 +Patch12: smb-Ignore-EINVAL-for-kerberos-login.patch +Patch13: smb-Rework-anonymous-handling-to-avoid-EINVAL.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=2080478 +Patch14: smb-Use-O_RDWR-to-fix-fstat-when-writing.patch + +# https://bugzilla.redhat.com/show_bug.cgi?id=2083481 +Patch15: google-performance-fixes.patch + +BuildRequires: pkgconfig +BuildRequires: pkgconfig(glib-2.0) >= %{glib2_version} +BuildRequires: pkgconfig(dbus-glib-1) +BuildRequires: pkgconfig(gcr-3) +BuildRequires: /usr/bin/ssh +BuildRequires: pkgconfig(libcdio_paranoia) >= %{libcdio_paranoia_version} +BuildRequires: pkgconfig(gudev-1.0) >= %{gudev_version} +BuildRequires: pkgconfig(libsoup-2.4) >= %{libsoup_version} +BuildRequires: pkgconfig(avahi-client) >= %{avahi_version} +BuildRequires: pkgconfig(avahi-glib) >= %{avahi_version} +BuildRequires: pkgconfig(libsecret-1) +BuildRequires: gettext-devel >= %{gettext_version} +BuildRequires: pkgconfig(udisks2) >= %{udisks2_version} +%if ! 0%{?rhel} +BuildRequires: pkgconfig(libbluray) +%endif +BuildRequires: systemd-devel >= %{systemd_version} +BuildRequires: pkgconfig(libxslt) +BuildRequires: docbook-style-xsl +BuildRequires: pkgconfig(polkit-gobject-1) +BuildRequires: pkgconfig(libcap) + +BuildRequires: automake autoconf +BuildRequires: libtool + +Requires: %{name}-client%{?_isa} = %{version}-%{release} +Requires: glib2%{?_isa} >= %{glib2_version} +Requires: udisks2 >= %{udisks2_version} +Requires: gsettings-desktop-schemas >= %{gsettings_desktop_schemas_version} + +# for file triggers +Requires(post): desktop-file-utils >= 0.22-6 +Requires(postun): desktop-file-utils >= 0.22-6 + +Obsoletes: gnome-mount <= 0.8 +Obsoletes: gnome-mount-nautilus-properties <= 0.8 +Obsoletes: gvfs-obexftp < 1.17.91-2 + +%description +The gvfs package provides backend implementations for the gio +framework in GLib. It includes ftp, sftp, cifs. + + +%package client +Summary: Client modules of backends for the gio framework in GLib +Conflicts: %{name} < 1.25.2-2 + +%description client +The gvfs package provides client modules of backend implementations for the gio +framework in GLib. + + +%package devel +Summary: Development files for gvfs +Requires: %{name}-client%{?_isa} = %{version}-%{release} + +%description devel +The gvfs-devel package contains headers and other files that are +required to develop applications using gvfs. + + +%package fuse +Summary: FUSE support for gvfs +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: %{name}-client%{?_isa} = %{version}-%{release} +BuildRequires: pkgconfig(fuse) >= %{fuse_version} +Requires: fuse >= %{fuse_version} + +%description fuse +This package provides support for applications not using gio +to access the gvfs filesystems. + + +%package smb +Summary: Windows fileshare support for gvfs +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: %{name}-client%{?_isa} = %{version}-%{release} +BuildRequires: libsmbclient-devel >= %{libsmbclient_version} +BuildRequires: pkgconfig(talloc) >= %{talloc_version} + +%description smb +This package provides support for reading and writing files on windows +shares (SMB) to applications using gvfs. + + +%package archive +Summary: Archiving support for gvfs +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: %{name}-client%{?_isa} = %{version}-%{release} +BuildRequires: pkgconfig(libarchive) >= %{libarchive_version} + +%description archive +This package provides support for accessing files inside Zip and Tar archives, +as well as ISO images, to applications using gvfs. + + +%package gphoto2 +Summary: gphoto2 support for gvfs +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: %{name}-client%{?_isa} = %{version}-%{release} +BuildRequires: pkgconfig(libgphoto2) >= %{libgphoto2_version} +BuildRequires: libexif-devel + +%description gphoto2 +This package provides support for reading and writing files on +PTP based cameras (Picture Transfer Protocol) and MTP based +media players (Media Transfer Protocol) to applications using gvfs. + + +%ifnarch s390 s390x +%package afc +Summary: AFC support for gvfs +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: %{name}-client%{?_isa} = %{version}-%{release} +Requires: usbmuxd +BuildRequires: pkgconfig(libimobiledevice-1.0) >= %{libimobiledevice_version} +BuildRequires: pkgconfig(libplist) >= %{libplist_version} + +%description afc +This package provides support for reading files on mobile devices +including phones and music players to applications using gvfs. +%endif + + +%package afp +Summary: AFP support for gvfs +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: %{name}-client%{?_isa} = %{version}-%{release} +BuildRequires: libgcrypt-devel >= %{libgcrypt_version} +# this should ensure having this new subpackage installed on upgrade from older versions +Obsoletes: %{name} < 1.9.4-1 + +%description afp +This package provides support for reading and writing files on +Mac OS X and original Mac OS network shares via Apple Filing Protocol +to applications using gvfs. + + +%package mtp +Summary: MTP support for gvfs +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: %{name}-client%{?_isa} = %{version}-%{release} +BuildRequires: pkgconfig(libmtp) >= %{libmtp_version} +BuildRequires: pkgconfig(libusb-1.0) >= %{libusb_version} + +%description mtp +This package provides support for reading and writing files on +MTP based devices (Media Transfer Protocol) to applications using gvfs. + + +%if ! 0%{?rhel} +%package nfs +Summary: NFS support for gvfs +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: %{name}-client%{?_isa} = %{version}-%{release} +BuildRequires: pkgconfig(libnfs) >= %{libnfs_version} + +%description nfs +This package provides support for reading and writing files on +NFS network shares (Network File System) to applications using gvfs. +%endif + + +%package goa +Summary: GOA support for gvfs +Requires: %{name}%{?_isa} = %{version}-%{release} +Requires: %{name}-client%{?_isa} = %{version}-%{release} +BuildRequires: pkgconfig(goa-1.0) >= %{goa_version} +BuildRequires: pkgconfig(libgdata) >= %{libgdata_version} +Requires: libgdata%{?_isa} >= %{libgdata_version} + +%description goa +This package provides seamless integration with gnome-online-accounts +file services. + +%package tests +Summary: Tests for the gvfs package +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description tests +The gvfs-tests package contains tests that can be used to verify +the functionality of the installed gvfs package. + +%prep +%autosetup -p1 + +autoreconf -fi + +%build +%configure \ + --disable-gdu \ + --enable-udisks2 \ + --enable-keyring \ + --enable-installed-tests \ +%if 0%{?rhel} + --disable-nfs \ + --disable-bluray \ +%endif + %{nil} +make %{?_smp_mflags} V=1 + +%install +%make_install + +rm $RPM_BUILD_ROOT%{_libdir}/gvfs/*.la +rm $RPM_BUILD_ROOT%{_libdir}/gio/modules/*.la + +# trashlib is GPLv3, include the license +cp -p daemon/trashlib/COPYING COPYING.GPL3 + +%find_lang gvfs + +%post +# Reload .mount files: +killall -USR1 gvfsd >&/dev/null || : + +# Reload .mount files when single subpackage is installed: +%post smb +killall -USR1 gvfsd >&/dev/null || : +%post gphoto2 +killall -USR1 gvfsd >&/dev/null || : +%post mtp +killall -USR1 gvfsd >&/dev/null || : +%post goa +killall -USR1 gvfsd >&/dev/null || : +%ifnarch s390 s390x +%post afc +killall -USR1 gvfsd >&/dev/null || : +%endif + +%post archive +killall -USR1 gvfsd >&/dev/null || : +%if ! 0%{?rhel} +%post nfs +killall -USR1 gvfsd >&/dev/null || : +%endif +%post afp +killall -USR1 gvfsd >&/dev/null || : + + +%files +%dir %{_datadir}/gvfs +%dir %{_datadir}/gvfs/mounts +%{_datadir}/gvfs/mounts/admin.mount +%{_datadir}/gvfs/mounts/sftp.mount +%{_datadir}/gvfs/mounts/trash.mount +%{_datadir}/gvfs/mounts/cdda.mount +%{_datadir}/gvfs/mounts/computer.mount +%{_datadir}/gvfs/mounts/dav.mount +%{_datadir}/gvfs/mounts/dav+sd.mount +%{_datadir}/gvfs/mounts/http.mount +%{_datadir}/gvfs/mounts/localtest.mount +%{_datadir}/gvfs/mounts/burn.mount +%{_datadir}/gvfs/mounts/dns-sd.mount +%{_datadir}/gvfs/mounts/network.mount +%{_datadir}/gvfs/mounts/ftp.mount +%{_datadir}/gvfs/mounts/ftps.mount +%{_datadir}/gvfs/mounts/recent.mount +%{_datadir}/dbus-1/services/org.gtk.vfs.Daemon.service +%{_datadir}/dbus-1/services/org.gtk.vfs.Metadata.service +%{_datadir}/dbus-1/services/org.gtk.vfs.UDisks2VolumeMonitor.service +%dir %{_datadir}/gvfs/remote-volume-monitors +%{_datadir}/gvfs/remote-volume-monitors/udisks2.monitor +%{_datadir}/GConf/gsettings/*.convert +%{_datadir}/glib-2.0/schemas/*.xml +%{_datadir}/polkit-1/actions/org.gtk.vfs.file-operations.policy +%{_datadir}/polkit-1/rules.d/org.gtk.vfs.file-operations.rules +%{_libdir}/gvfs/libgvfsdaemon.so +%{_libexecdir}/gvfsd +%{_libexecdir}/gvfsd-admin +%{_libexecdir}/gvfsd-ftp +%{_libexecdir}/gvfsd-sftp +%{_libexecdir}/gvfsd-trash +%{_libexecdir}/gvfsd-cdda +%{_libexecdir}/gvfsd-computer +%{_libexecdir}/gvfsd-dav +%{_libexecdir}/gvfsd-http +%{_libexecdir}/gvfsd-localtest +%{_libexecdir}/gvfsd-burn +%{_libexecdir}/gvfsd-dnssd +%{_libexecdir}/gvfsd-network +%{_libexecdir}/gvfsd-metadata +%{_libexecdir}/gvfs-udisks2-volume-monitor +%{_libexecdir}/gvfsd-recent +%{_mandir}/man1/gvfsd.1* +%{_mandir}/man1/gvfsd-metadata.1* +%if ! 0%{?flatpak} +%{_userunitdir}/gvfs-daemon.service +%{_userunitdir}/gvfs-metadata.service +%{_userunitdir}/gvfs-udisks2-volume-monitor.service +%endif + +%files client -f gvfs.lang +%{!?_licensedir:%global license %%doc} +%license COPYING COPYING.GPL3 +%doc AUTHORS NEWS README +%dir %{_libdir}/gvfs +%{_libdir}/gvfs/libgvfscommon.so +%{_libdir}/gio/modules/libgioremote-volume-monitor.so +%{_libdir}/gio/modules/libgvfsdbus.so +%{_mandir}/man7/gvfs.7* + +%files devel +%dir %{_includedir}/gvfs-client +%dir %{_includedir}/gvfs-client/gvfs +%{_includedir}/gvfs-client/gvfs/gvfsurimapper.h +%{_includedir}/gvfs-client/gvfs/gvfsuriutils.h + + +%files fuse +%{_libexecdir}/gvfsd-fuse +%{_mandir}/man1/gvfsd-fuse.1* +%if ! 0%{?flatpak} +%{_tmpfilesdir}/gvfsd-fuse-tmpfiles.conf +%endif + +%files smb +%{_libexecdir}/gvfsd-smb +%{_libexecdir}/gvfsd-smb-browse +%{_datadir}/gvfs/mounts/smb-browse.mount +%{_datadir}/gvfs/mounts/smb.mount + + +%files archive +%{_libexecdir}/gvfsd-archive +%{_datadir}/gvfs/mounts/archive.mount + + +%files gphoto2 +%{_libexecdir}/gvfsd-gphoto2 +%{_datadir}/gvfs/mounts/gphoto2.mount +%{_libexecdir}/gvfs-gphoto2-volume-monitor +%{_datadir}/dbus-1/services/org.gtk.vfs.GPhoto2VolumeMonitor.service +%{_datadir}/gvfs/remote-volume-monitors/gphoto2.monitor +%if ! 0%{?flatpak} +%{_userunitdir}/gvfs-gphoto2-volume-monitor.service +%endif + +%ifnarch s390 s390x +%files afc +%{_libexecdir}/gvfsd-afc +%{_datadir}/gvfs/mounts/afc.mount +%{_libexecdir}/gvfs-afc-volume-monitor +%{_datadir}/dbus-1/services/org.gtk.vfs.AfcVolumeMonitor.service +%{_datadir}/gvfs/remote-volume-monitors/afc.monitor +%if ! 0%{?flatpak} +%{_userunitdir}/gvfs-afc-volume-monitor.service +%endif +%endif + +%files afp +%{_libexecdir}/gvfsd-afp +%{_libexecdir}/gvfsd-afp-browse +%{_datadir}/gvfs/mounts/afp.mount +%{_datadir}/gvfs/mounts/afp-browse.mount + +%files mtp +%{_libexecdir}/gvfsd-mtp +%{_datadir}/gvfs/mounts/mtp.mount +%{_libexecdir}/gvfs-mtp-volume-monitor +%{_datadir}/dbus-1/services/org.gtk.vfs.MTPVolumeMonitor.service +%{_datadir}/gvfs/remote-volume-monitors/mtp.monitor +%if ! 0%{?flatpak} +%{_userunitdir}/gvfs-mtp-volume-monitor.service +%endif + +%if ! 0%{?rhel} +%files nfs +%{_libexecdir}/gvfsd-nfs +# for privileged ports +%caps(cap_net_bind_service=ep) %{_libexecdir}/gvfsd-nfs +%{_datadir}/gvfs/mounts/nfs.mount +%endif + +%files goa +%{_libexecdir}/gvfs-goa-volume-monitor +%{_datadir}/dbus-1/services/org.gtk.vfs.GoaVolumeMonitor.service +%{_datadir}/gvfs/remote-volume-monitors/goa.monitor +%{_datadir}/gvfs/mounts/google.mount +%{_libexecdir}/gvfsd-google +%if ! 0%{?flatpak} +%{_userunitdir}/gvfs-goa-volume-monitor.service +%endif + +%files tests +%dir %{_libexecdir}/installed-tests +%{_libexecdir}/installed-tests/gvfs +%{_datadir}/installed-tests + +%changelog +* Thu Jun 16 2022 Ondrej Holy - 1.36.2-14 +- Backport performance fixes for Google backend (#2083481) + +* Tue Jun 14 2022 Ondrej Holy - 1.36.2-13 +- Use O_RDWR to fix fstat when writing on SMB share (#2080478) + +* Tue Jun 14 2022 Ondrej Holy - 1.36.2-12 +- Ignore EINVAL for kerberos login to fix SMB mounting (#2095712) + +* Tue Nov 03 2020 Ondrej Holy - 1.36.2-11 +- Add support for certificates prompts for GOA mounts (rhbz#1889411) + +* Wed Aug 05 2020 Ondrej Holy - 1.36.2-10 +- Fix libusb(x) requirements (rhbz#1866332) + +* Wed Jun 17 2020 Ondrej Holy - 1.36.2-9 +- Improve enumeration performance of smb backend (rhbz#1569868) + +* Tue Oct 8 2019 Ondrej Holy - 1.36.2-8 +- Fix udisks2 volume monitor crashes when stopping drive (rhbz#1759075) + +* Thu Sep 19 2019 Ondrej Holy - 1.36.2-7 +- Remove libbluray support (#1747972) +- CVE-2019-12448: Add query_info_on_read/write functionality (rhbz#1754506) +- CVE-2019-12447: Use fsuid to ensure correct file ownership (rhbz#1752926) +- CVE-2019-12449: Ensure correct ownership when moving to file:// uri (rhbz#1753972) + +* Fri Aug 09 2019 Ondrej Holy - 1.36.2-6 +- Prevent spawning new daemons if outgoing operation exists (#1739117) +- Force NT1 protocol version for workgroup support (#1739116) + +* Thu Aug 08 2019 Ondrej Holy - 1.36.2-5 +- CVE-2019-12795 Check that the connecting client is the same user (#1729885) + +* Thu May 16 2019 Ondrej Holy - 1.36.2-4 +- Handle lockdown option to disable writing (#1662193) + +* Mon Apr 01 2019 Ondrej Holy - 1.36.2-3 +- CVE-2019-3827: Prevent access if any authentication agent isn't available (#1673888) + +* Fri Dec 14 2018 Ray Strode - 1.36.2-2 +- rebuild + +* Tue Jun 12 2018 Ondrej Holy - 1.36.2-1 +- Update to 1.36.2 +- Remove mount-archive.desktop helper +- Remove obsolete gvfs utils +- Disable nfs support + +* Mon Apr 09 2018 Kalev Lember - 1.36.1-1 +- Update to 1.36.1 + +* Mon Mar 12 2018 Kalev Lember - 1.36.0-1 +- Update to 1.36.0 + +* Mon Mar 05 2018 Kalev Lember - 1.35.92-1 +- Update to 1.35.92 + +* Wed Feb 28 2018 Ondrej Holy - 1.35.91-1 +- Update to 1.35.91 + +* Wed Feb 07 2018 Fedora Release Engineering - 1.35.90-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Mon Feb 05 2018 Kalev Lember - 1.35.90-1 +- Update to 1.35.90 +- Drop ldconfig scriptlets + +* Thu Jan 25 2018 Adrian Reber - 1.35.3-2 +- Rebuilt for libcdio-2.0.0 + +* Tue Dec 19 2017 Ondrej Holy - 1.35.3-1 +- Update to 1.35.3 + +* Thu Nov 02 2017 Kalev Lember - 1.35.1-1 +- Update to 1.35.1 + +* Fri Oct 06 2017 Kalev Lember - 1.34.1-1 +- Update to 1.34.1 + +* Mon Sep 11 2017 Kalev Lember - 1.34.0-1 +- Update to 1.34.0 + +* Tue Sep 05 2017 Kalev Lember - 1.33.92-1 +- Update to 1.33.92 + +* Mon Aug 28 2017 Kalev Lember - 1.33.91-1 +- Update to 1.33.91 + +* Wed Aug 09 2017 Ondrej Holy - 1.33.90-1 +- Update to 1.33.90 + +* Wed Aug 02 2017 Fedora Release Engineering - 1.33.3-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 1.33.3-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Mon Jul 24 2017 Ondrej Holy - 1.33.3-3 +- gdaemonfileenumerator: Fix crashes in synchronous enumerator code (rhbz#1472819) + +* Wed Jul 19 2017 Ondrej Holy - 1.33.3-2 +- goa: Fix password-based authentication (rhbz#1461066) + +* Sun Jun 25 2017 Kalev Lember - 1.33.3-1 +- Update to 1.33.3 + +* Wed May 10 2017 Ondrej Holy - 1.33.1-1 +- Update to 1.33.1 +- Drop gtk+ dependency + +* Tue Apr 11 2017 Kalev Lember - 1.32.1-1 +- Update to 1.32.1 + +* Tue Mar 21 2017 Kalev Lember - 1.32.0-1 +- Update to 1.32.0 + +* Fri Mar 17 2017 Kalev Lember - 1.31.92-2 +- Rebuilt for libbluray soname bump + +* Thu Mar 16 2017 Kalev Lember - 1.31.92-1 +- Update to 1.31.92 + +* Tue Feb 28 2017 Richard Hughes - 1.31.91-1 +- Update to 1.31.91 + +* Tue Feb 14 2017 Richard Hughes - 1.31.90-1 +- Update to 1.31.90 + +* Fri Feb 10 2017 Fedora Release Engineering - 1.31.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Mon Nov 28 2016 Ray Strode - 1.31.2-1 +- Update to 1.31.2 + Related: https://bugzilla.gnome.org/show_bug.cgi?id=768707 + +* Mon Nov 14 2016 Adrian Reber - 1.31.1-2 +- Rebuilt for libcdio-0.94 + +* Sun Oct 30 2016 Kalev Lember - 1.31.1-1 +- Update to 1.31.1 + +* Mon Oct 17 2016 Ondrej Holy - 1.30.1.1-1 +- Update to 1.30.1.1 + +* Wed Oct 12 2016 Kalev Lember - 1.30.1-1 +- Update to 1.30.1 + +* Mon Sep 19 2016 Kalev Lember - 1.30.0-1 +- Update to 1.30.0 + +* Tue Sep 13 2016 Kalev Lember - 1.29.92-1 +- Update to 1.29.92 + +* Tue Aug 30 2016 Kalev Lember - 1.29.91-1 +- Update to 1.29.91 + +* Fri Aug 12 2016 Kalev Lember - 1.29.90-1 +- Update to 1.29.90 + +* Mon Jul 18 2016 Richard Hughes - 1.29.4-1 +- Update to 1.29.4 + +* Wed Jun 22 2016 Richard Hughes - 1.29.3-1 +- Update to 1.29.3 + +* Tue May 03 2016 Kalev Lember - 1.29.1-1 +- Update to 1.29.1 + +* Wed Apr 13 2016 Kalev Lember - 1.28.1-1 +- Update to 1.28.1 + +* Tue Mar 22 2016 Kalev Lember - 1.28.0-1 +- Update to 1.28.0 + +* Mon Mar 14 2016 Richard Hughes - 1.27.92-1 +- Update to 1.27.92 + +* Tue Mar 01 2016 Richard Hughes - 1.27.91-1 +- Update to 1.27.91 + +* Tue Feb 16 2016 Richard Hughes - 1.27.90-1 +- Update to 1.27.90 + +* Wed Feb 03 2016 Fedora Release Engineering - 1.27.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Wed Jan 20 2016 Kalev Lember - 1.27.4-1 +- Update to 1.27.4 + +* Mon Dec 14 2015 Kalev Lember - 1.27.3-1 +- Update to 1.27.3 + +* Tue Nov 10 2015 Kalev Lember - 1.26.2-1 +- Update to 1.26.2 + +* Fri Oct 23 2015 poma - 1.26.1.1-3 +- Accept XDG_RUNTIME_DIR/bus as a valid D-Bus session/user bus + +* Fri Oct 23 2015 Ondrej Holy - 1.26.1.1-2 +- google: Fail in-fs copy/move if it leads to display name loss + +* Thu Oct 15 2015 Kalev Lember - 1.26.1.1-1 +- Update to 1.26.1.1 + +* Thu Oct 15 2015 Kalev Lember - 1.26.1-2 +- file monitor: Fix invalid read + +* Mon Oct 12 2015 Kalev Lember - 1.26.1-1 +- Update to 1.26.1 + +* Mon Sep 21 2015 Kalev Lember - 1.26.0-1 +- Update to 1.26.0 + +* Wed Sep 16 2015 Ondrej Holy - 1.25.92-3 +- Move Google Drive backend into the goa subpackage + +* Mon Sep 14 2015 Kalev Lember - 1.25.92-2 +- Build Google Drive backend + +* Mon Sep 14 2015 Kalev Lember - 1.25.92-1 +- Update to 1.25.92 + +* Tue Sep 01 2015 Kalev Lember - 1.25.91-1 +- Update to 1.25.91 + +* Thu Aug 20 2015 Ondrej Holy - 1.25.90-3 +- Add NFS backend + +* Thu Aug 20 2015 Ondrej Holy - 1.25.90-2 +- Rely on file triggers for schemas and desktop files + +* Mon Aug 17 2015 Kalev Lember - 1.25.90-1 +- Update to 1.25.90 +- Use make_install macro + +* Fri Jul 24 2015 Ondrej Holy - 1.25.4.1-1 +- Update to 1.25.4.1 + +* Fri Jul 24 2015 Ondrej Holy - 1.25.4-1 +- Update to 1.25.4 + +* Tue Jun 30 2015 Kalev Lember - 1.25.3-1 +- Update to 1.25.3 + +* Wed Jun 17 2015 Fedora Release Engineering - 1.25.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Mon Jun 8 2015 Ondrej Holy - 1.25.2-2 +- Move client libs into the own subpackage +- Move gvfs tools into the own subpackage +- Move gvfsd-fuse-tmpfiles.conf into fuse subpackage +- Remove obsoleted expat-devel dependency +- Remove obsoleted Group tags +- Fix bogus dates + +* Sun May 31 2015 Kalev Lember - 1.25.2-1 +- Update to 1.25.2 + +* Fri May 01 2015 Kalev Lember - 1.25.1-1 +- Update to 1.25.1 + +* Tue Apr 14 2015 Kalev Lember - 1.24.1-1 +- Update to 1.24.1 + +* Mon Mar 23 2015 Kalev Lember - 1.24.0-1 +- Update to 1.24.0 + +* Mon Mar 16 2015 Kalev Lember - 1.23.92-1 +- Update to 1.23.92 + +* Sat Feb 21 2015 Till Maas - 1.23.90-2 +- Rebuilt for Fedora 23 Change + https://fedoraproject.org/wiki/Changes/Harden_all_packages_with_position-independent_code + +* Fri Feb 13 2015 Richard Hughes - 1.23.90-1 +- Update to 1.23.90 + +* Wed Feb 11 2015 Peter Robinson 1.23.4-5 +- Rebuild (libimobiledevice) +- Use %%license + +* Wed Jan 21 2015 Peter Robinson 1.23.4-4 +- Rebuild (libgpohoto2) + +* Tue Jan 20 2015 Richard Hughes - 1.23.4-1 +- Update to 1.23.4 + +* Fri Dec 19 2014 Richard Hughes - 1.23.3-1 +- Update to 1.23.3 + +* Tue Nov 25 2014 Kalev Lember - 1.23.2-1 +- Update to 1.23.2 + +* Wed Nov 12 2014 Vadim Rutkovsky - 1.22.2-3 +- Build installed tests + +* Tue Nov 11 2014 Adrian Reber - 1.22.2-2 +- Rebuilt for libcdio-0.93 + +* Mon Nov 10 2014 Kalev Lember - 1.22.2-1 +- Update to 1.22.2 + +* Wed Oct 15 2014 Peter Robinson 1.22.1-2 +- Rebuild for libimobiledevice 1.1.6 + +* Mon Oct 13 2014 Kalev Lember - 1.22.1-1 +- Update to 1.22.1 + +* Sun Sep 21 2014 Kalev Lember - 1.22.0-1 +- Update to 1.22.0 + +* Mon Sep 15 2014 Kalev Lember - 1.21.92-1 +- Update to 1.21.92 + +* Sat Aug 30 2014 Kalev Lember - 1.21.91-1 +- Update to 1.21.91 + +* Sat Aug 16 2014 Kalev Lember - 1.21.90-1 +- Update to 1.21.90 + +* Sat Aug 16 2014 Fedora Release Engineering - 1.21.4-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Fri Jul 18 2014 Kalev Lember - 1.21.4-1 +- Update to 1.21.4 + +* Tue Jun 24 2014 Richard Hughes - 1.21.3-1 +- Update to 1.21.3 + +* Sat Jun 07 2014 Fedora Release Engineering - 1.21.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Sat May 24 2014 Kalev Lember - 1.21.2-1 +- Update to 1.21.2 + +* Mon May 5 2014 Peter Robinson 1.21.1-2 +- Rebuild for libimobiledevice 1.1.6 + +* Mon Apr 28 2014 Richard Hughes - 1.21.1-1 +- Update to 1.21.1 + +* Fri Apr 11 2014 Richard Hughes - 1.20.1-1 +- Update to 1.20.1 + +* Fri Mar 21 2014 Kalev Lember - 1.20.0-1 +- Update to 1.20.0 + +* Tue Feb 18 2014 Richard Hughes - 1.19.90-1 +- Update to 1.19.90 + +* Thu Feb 06 2014 Ondrej Holy - 1.19.5-2 +- Fix license field + +* Mon Feb 03 2014 Richard Hughes - 1.19.5-1 +- Update to 1.19.5 + +* Tue Jan 28 2014 Dan Horák - 1.19.4-2 +- fix the BR: libarchive-devel condition for recent rpmbuild + +* Mon Jan 13 2014 Richard Hughes - 1.19.4-1 +- Update to 1.19.4 + +* Tue Dec 17 2013 Richard Hughes - 1.19.3-1 +- Update to 1.19.3 + +* Mon Dec 16 2013 Adrian Reber - 1.19.2-2 +- Rebuilt for libcdio-0.92 + +* Mon Nov 18 2013 Richard Hughes - 1.19.2-1 +- Update to 1.19.2 + +* Tue Oct 29 2013 Richard Hughes - 1.19.1-1 +- Update to 1.19.1 + +* Thu Oct 3 2013 Ondrej Holy - 1.18.2-1 +- Update to 1.18.2 + +* Thu Sep 26 2013 Kalev Lember - 1.18.1-1 +- Update to 1.18.1 + +* Thu Sep 26 2013 Rex Dieter 1.18.0-2 +- add explicit avahi build deps, move autofoo to %%prep + +* Wed Sep 25 2013 Kalev Lember - 1.18.0-1 +- Update to 1.18.0 + +* Wed Sep 18 2013 Kalev Lember - 1.17.91-3 +- Obsolete the removed obexftp subpackage + +* Wed Sep 18 2013 Matthias Clasen - 1.17.91-2 +- Drop obexftp subpackage + +* Tue Sep 03 2013 Kalev Lember - 1.17.91-1 +- Update to 1.17.91 + +* Thu Aug 22 2013 Kalev Lember - 1.17.90-1 +- Update to 1.17.90 + +* Fri Aug 09 2013 Kalev Lember - 1.17.3-1 +- Update to 1.17.3 + +* Sat Aug 03 2013 Fedora Release Engineering - 1.17.2-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild + +* Thu Jun 20 2013 Bastien Nocera 1.17.2-2 +- Fix gvfs-afc crashes due to new libimobiledevice (#951731) + +* Fri Jun 14 2013 Kalev Lember - 1.17.2-1 +- Update to 1.17.2 + +* Sun Jun 02 2013 Kalev Lember - 1.17.1-1 +- Update to 1.17.1 + +* Wed May 22 2013 Kalev Lember - 1.17.0-2 +- gvfs-archive: Add the update-desktop-database rpm scriptlets (#954214) + +* Sat May 04 2013 Kalev Lember - 1.17.0-1 +- Update to 1.17.0 + +* Tue Apr 16 2013 Richard Hughes - 1.16.1-1 +- Update to 1.16.1 + +* Thu Mar 28 2013 Tomas Bzatek - 1.16.0-1 +- Update to 1.16.0 + +* Wed Mar 20 2013 Peter Robinson 1.15.4-2 +- Rebuild for new libimobiledevice + +* Mon Mar 04 2013 Richard Hughes - 1.15.4-1 +- Update to 1.15.4 + +* Wed Feb 6 2013 Tomas Bzatek - 1.15.3-2 +- Install systemd tmpfiles.d exclusion file for gvfs-fuse (#902743) + +* Tue Feb 5 2013 Tomas Bzatek - 1.15.3-1 +- Update to 1.15.3 + +* Tue Jan 15 2013 Tomas Bzatek - 1.15.2-1 +- Update to 1.15.2 + +* Mon Jan 07 2013 Adrian Reber - 1.15.1-3 +- Rebuilt for libcdio-0.90 + +* Wed Dec 19 2012 Tomas Bzatek - 1.15.1-2 +- Rebuilt for new udisks + +* Tue Dec 18 2012 Tomas Bzatek - 1.15.1-1 +- Update to 1.15.1 + +* Fri Dec 7 2012 Tomas Bzatek - 1.15.0-3 +- Enable verbose build messages +- Remove deprecated Encoding key from mount-archive.desktop + +* Tue Nov 6 2012 Tomas Bzatek - 1.15.0-2 +- Clarify licensing +- Explicitly disable HAL + +* Mon Oct 29 2012 Tomas Bzatek - 1.15.0-1 +- Update to 1.15.0 + +* Tue Sep 25 2012 Tomas Bzatek - 1.14.0-1 +- Update to 1.14.0 + +* Tue Sep 18 2012 Matthias Clasen - 1.13.9-1 +- Update to 1.13.9 + +* Wed Sep 5 2012 Tomas Bzatek - 1.13.8-1 +- Update to 1.13.8 + +* Wed Aug 29 2012 Tomas Bzatek - 1.13.7-3 +- Bring archive mounter back + +* Mon Aug 27 2012 Cosimo Cecchi - 1.13.7-2 +- Make sure keyring integration is enabled + +* Tue Aug 21 2012 Richard Hughes - 1.13.7-1 +- Update to 1.13.7 + +* Tue Aug 07 2012 Richard Hughes - 1.13.4-1 +- Update to 1.13.4 + +* Tue Aug 7 2012 Jindrich Novy - 1.13.3-4 +- add BR: docbook-style-xsl so that gvfs actually builds + +* Sun Aug 5 2012 Jindrich Novy - 1.13.3-3 +- add patch to fix gvfs build against libgphoto2 (inspired by SUSE) + +* Fri Jul 27 2012 Fedora Release Engineering - 1.13.3-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Mon Jul 16 2012 Tomas Bzatek - 1.13.3-1 +- Update to 1.13.3 + +* Mon Jul 16 2012 Nils Philippsen - 1.13.2-2 +- rebuild for new libgphoto2 + +* Tue Jun 26 2012 Tomas Bzatek - 1.13.2-1 +- Update to 1.13.2 + +* Mon Jun 4 2012 Tomas Bzatek - 1.13.1-1 +- Update to 1.13.1 + +* Wed May 2 2012 Tomas Bzatek - 1.13.0-1 +- Update to 1.13.0 + +* Fri Apr 27 2012 Tomas Bzatek - 1.12.2-1 +- Update to 1.12.2 +- Backport multiseat patches from master + +* Tue Apr 24 2012 Kalev Lember - 1.12.1-3 +- Silence rpm scriptlet output + +* Wed Apr 18 2012 Kalev Lember - 1.12.1-2 +- Rebuild again for new libimobiledevice and usbmuxd + +* Tue Apr 17 2012 Tomas Bzatek - 1.12.1-1 +- Update to 1.12.1 + +* Thu Apr 12 2012 Peter Robinson - 1.12.0-2 +- Rebuild for new libimobiledevice and usbmuxd + +* Mon Mar 26 2012 Tomas Bzatek - 1.12.0-1 +- Update to 1.12.0 + +* Tue Mar 20 2012 Tomas Bzatek - 1.11.5-1 +- Update to 1.11.5 + +* Fri Feb 24 2012 Tomas Bzatek - 1.11.4-1 +- Update to 1.11.4 + +* Tue Feb 7 2012 Tomas Bzatek - 1.11.3-1 +- Update to 1.11.3 + +* Fri Feb 3 2012 Tomas Bzatek - 1.11.3-0.4.20120120 +- Exclude the obexftp package from s390 builds + +* Wed Jan 25 2012 Tomas Bzatek - 1.11.3-0.3.20120120 +- Rebuilt for new libarchive + +* Tue Jan 24 2012 Tomas Bzatek - 1.11.3-0.2.20120120 +- Add udisks2 runtime Requires + +* Fri Jan 20 2012 Matthias Clasen - 1.11.3-0.1.20120120-1 +- Prelease that works with udisks2 + +* Wed Jan 18 2012 Tomas Bzatek - 1.11.2-1 +- Update to 1.11.2 + +* Fri Jan 13 2012 Fedora Release Engineering - 1.11.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Tue Dec 20 2011 Matthias Clasen - 1.11.1-1 +- Update to 1.11.1 + +* Tue Dec 13 2011 Tomas Bzatek - 1.11.0-5 +- Rebuilt for new libbluray + +* Sun Nov 20 2011 Adrian Reber - 1.11.0-4 +- Rebuild for libcdio-0.83 + +* Wed Nov 16 2011 Adam Jackson 1.11.0-3 +- Rebuild for new libarchive + +* Wed Oct 26 2011 Fedora Release Engineering - 1.11.0-2 +- Rebuilt for glibc bug#747377 + +* Wed Oct 26 2011 Tomas Bzatek - 1.11.0-1 +- Update to 1.11.0 + +* Mon Oct 17 2011 Tomas Bzatek - 1.10.1-1 +- Update to 1.10.1 + +* Tue Sep 27 2011 Ray - 1.10.0-1 +- Update to 1.10.0 + +* Mon Sep 5 2011 Matthias Clasen - 1.9.5-1 +- Update to 1.9.5 + +* Tue Aug 30 2011 Tomas Bzatek - 1.9.4-1 +- Update to 1.9.4 +- New AFP backend in separate subpackage + +* Tue Aug 16 2011 Matthias Clasen - 1.9.3-1 +- Update to 1.9.3 +- Drop obsolete patches +- Clean up spec a bit + +* Wed Jul 27 2011 Tomas Bzatek - 1.9.2-1 +- Update to 1.9.2 +- Enable real statfs calls in the fuse daemon + +* Wed Jun 15 2011 Tomas Bzatek - 1.9.1-1 +- Update to 1.9.1 + +* Mon May 09 2011 Tomas Bzatek - 1.9.0-1 +- Update to 1.9.0 + +* Sat May 07 2011 Christopher Aillon - 1.8.1-2 +- Update gsettings scriptlet + +* Tue Apr 26 2011 Tomas Bzatek - 1.8.1-1 +- Update to 1.8.1 + +* Fri Apr 22 2011 Tomas Bzatek - 1.8.0-3 +- Build without HAL -> expect obexftp breakage. + +* Mon Apr 18 2011 Tomas Bzatek - 1.8.0-2 +- Fix threadsafety of closing channels +- Fix d-bus messages leaks +- Fix /dev symlink checks in gdu volume monitor + +* Mon Apr 4 2011 Matthias Clasen - 1.8.0-1 +- Update to 1.8.0 + +* Mon Mar 21 2011 Matthias Clasen - 1.7.3-1 +- Update to 1.7.3 + +* Wed Feb 09 2011 Fedora Release Engineering - 1.7.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Tue Feb 1 2011 Tomas Bzatek - 1.7.2-1 +- Update to 1.7.2 + +* Sun Dec 26 2010 Bastien Nocera 1.7.1-1 +- Update to 1.7.1 + +* Thu Dec 2 2010 Tomas Bzatek - 1.7.0-1 +- Update to 1.7.0 + +* Mon Nov 1 2010 Matthias Clasen - 1.6.5-1 +- Update to 1.6.5 +- Drop upstreamed patches + +* Mon Nov 1 2010 Tomas Bzatek - 1.6.4-4 +- Use correct "usb:" address for GPhoto mounts with gudev (#642836) + +* Wed Oct 13 2010 Tomas Bzatek - 1.6.4-3 +- FUSE: Add O_TRUNC support for open() + +* Mon Oct 4 2010 Tomas Bzatek - 1.6.4-2 +- Fix sftp poll timeout + +* Wed Sep 29 2010 Matthias Clasen - 1.6.4-1 +- Update to 1.6.4 + +* Wed Sep 8 2010 Tomas Bzatek - 1.6.3-3 +- Fix smb daemons deadlock due to GConf initialization + +* Mon Jul 12 2010 Dan Horák - 1.6.3-2 +- s390(x) machines can't connect mobile phones or players + +* Mon Jul 12 2010 Matthias Clasen - 1.6.3-1 +- Update to 1.6.3 + +* Thu May 27 2010 Tomas Bzatek - 1.6.2-1 +- Update to 1.6.2 + +* Tue May 4 2010 Tomas Bzatek - 1.6.1-3 +- Fix Nautilus 100% CPU after trashing a file with an emblem (#584784) + +* Mon Apr 26 2010 Tomas Bzatek - 1.6.1-2 +- Explicitly require minimal glib2 version (#585912) + +* Mon Apr 26 2010 Tomas Bzatek - 1.6.1-1 +- Update to 1.6.1 + +* Mon Apr 19 2010 Matthias Clasen - 1.6.0-2 +- Use update-gio-modules + +* Mon Mar 29 2010 Tomas Bzatek - 1.6.0-1 +- Update to 1.6.0 + +* Mon Mar 22 2010 Bastien Nocera 1.5.5-3 +- Fix build with new libimobiledevice +- Don't mount both gphoto and AFC mounts on AFC devices + +* Sun Mar 21 2010 Peter Robinson 1.5.5-2 +- Rebuild for new stable libimobiledevice + +* Mon Mar 8 2010 Tomas Bzatek - 1.5.5-1 +- Update to 1.5.5 + +* Thu Feb 25 2010 Matthias Clasen - 1.5.4-2 +- Re-add missing service files + +* Mon Feb 22 2010 Matthias Clasen - 1.5.4-1 +- Update to 1.5.4 + +* Mon Feb 15 2010 Tomas Bzatek - 1.5.3-2 +- sftp: fix crash on unmount + +* Tue Feb 9 2010 Tomas Bzatek - 1.5.3-1 +- Update to 1.5.3 + +* Mon Feb 8 2010 Tomas Bzatek - 1.5.2-5 +- ftp: backport several PASV/EPSV fixes from master (#542205, #555033) + +* Fri Feb 5 2010 Tomas Bzatek - 1.5.2-4 +- AFC: Use new libimobiledevice library + +* Tue Jan 26 2010 Tomas Bzatek - 1.5.2-3 +- Fix AFC build against new libiphone + +* Mon Jan 25 2010 Matthias Clasen - 1.5.2-2 +- Update the GIO module cache + +* Mon Jan 25 2010 Tomas Bzatek - 1.5.2-1 +- Update to 1.5.2 + +* Fri Jan 22 2010 Adrian Reber - 1.5.1-6 +- Rebuild for libcdio-0.82 + +* Mon Jan 18 2010 Tomas Bzatek - 1.5.1-5 +- Avoid crash on race to mount gvfstrash (#555337) +- Nuke HAL volume monitor + +* Tue Jan 12 2010 Tomas Bzatek - 1.5.1-4 +- Don't leak mount job operation (#552842) +- Recognize gphoto2 cameras which don't implement get storageinfo (#552856) +- ObexFTP: Use a private D-Bus connection for obex-data-server (#539347) + +* Tue Dec 15 2009 Tomas Bzatek - 1.5.1-3 +- Rebuilt against new libiphone + +* Mon Nov 30 2009 Tomas Bzatek - 1.5.1-2 +- Metadata fixes +- SMB: Fix free space calculation for older samba servers +- fuse: Fix setting timestamps + +* Wed Nov 18 2009 Tomas Bzatek - 1.5.1-1 +- Update to 1.5.1 +- AFC: temporarily disable setting file modification times + +* Thu Nov 12 2009 Matthias Clasen 1.4.1-6 +- Add obsoletes for gnome-mount + +* Thu Nov 12 2009 Bastien Nocera 1.4.1-5 +- Add obsoletes for gnome-vfs2-obexftp + +* Tue Nov 10 2009 Tomas Bzatek - 1.4.1-4 +- SMB: Support querying filesystem size and free space + +* Tue Nov 3 2009 Tomas Bzatek - 1.4.1-3 +- gdu-volume-monitor: don't crash on NULL devices (#529982) + +* Mon Nov 2 2009 Tomas Bzatek - 1.4.1-2 +- Reload .mount files when single package is installed + +* Tue Oct 20 2009 Tomas Bzatek - 1.4.1-1 +- Update to 1.4.1 + +* Fri Oct 16 2009 Tomas Bzatek - 1.4.0-7 +- HTTP: Support g_file_input_stream_query_info() +- HTTP: Use libsoup header parsing function +- Set correct MIME type for MTP music players + +* Wed Oct 14 2009 Bastien Nocera 1.4.0-6 +- Fix crasher in ObexFTP (#528181) + +* Fri Oct 9 2009 Tomas Bzatek - 1.4.0-5 +- Don't always overwrite on trash restore +- Separate "Safely Remove Drive" from "Eject" +- Don't advertise can_poll for drives not using removable media +- Disallow mounting empty drives +- Disallow ejecting empty drives +- Silently drop eject error messages when detaching drive + +* Thu Oct 8 2009 Tomas Bzatek - 1.4.0-4 +- Fix Nautilus not displaying friendly icons for SSH-connected system (#526892) +- Actually apply the logical partitions patch + +* Thu Oct 1 2009 Matthias Clasen - 1.4.0-3 +- Consider logical partitions when deciding if a drive should be ignored + +* Tue Sep 29 2009 Matthias Clasen - 1.4.0-2 +- Fix the lack of icons in the http backend + +* Mon Sep 21 2009 Tomas Bzatek - 1.4.0-1 +- Update to 1.4.0 + +* Thu Sep 17 2009 Peter Lemenkov - 1.3.6-2 +- Rebuilt with new fuse + +* Mon Sep 7 2009 Tomas Bzatek - 1.3.6-1 +- Update to 1.3.6 + +* Wed Aug 26 2009 Matthias Clasen - 1.3.5-2 +- Don't mount interactively during login + +* Mon Aug 24 2009 Matthias Clasen - 1.3.5-1 +- Update to 1.3.5 + +* Mon Aug 17 2009 Tomas Bzatek - 1.3.4-7 +- Fix Nautilus can't create "untitled folder" on sftp mounts (#512611) + +* Fri Aug 14 2009 Bastien Nocera 1.3.4-6 +- Update AFC patch + +* Thu Aug 13 2009 Tomas Bzatek - 1.3.4-5 +- More complete fix for DAV mount path prefix issues + +* Tue Aug 11 2009 Bastien Nocera 1.3.4-4 +- Fix crash on startup for the afc volume monitor + +* Tue Aug 11 2009 Bastien Nocera 1.3.4-3 +- libgudev-devel is required for the gphoto2 monitor + +* Tue Aug 11 2009 Bastien Nocera 1.3.4-2 +- Add AFC backend + +* Mon Aug 10 2009 Matthias Clasen - 1.3.4-1 +- Update to 1.3.4 + +* Fri Aug 7 2009 Tomas Bzatek - 1.3.3-3 +- Fix bad mount prefix stripping (part of #509612) +- Fix gvfsd-sftp segfault when asking a question +- Enable tar+xz in the archive mounter + +* Tue Aug 4 2009 Tomas Bzatek - 1.3.3-2 +- Fix gedit crashed with SEGV in strlen() +- Fix SMB protocol not handled when opening from a bookmark (#509832) + +* Wed Jul 29 2009 Matthias Clasen - 1.3.3-1 +- Update to 1.3.3 + +* Mon Jul 27 2009 Matthias Clasen - 1.3.2-3 +- Rebuild + +* Fri Jul 24 2009 Fedora Release Engineering - 1.3.2-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Mon Jul 13 2009 Matthias Clasen - 1.3.2-1 +- Update to 1.3.2 +- Drop upstreamed patches + +* Mon Jun 22 2009 Tomas Bzatek - 1.3.1-2 +- Bump version requirements +- Backport FTP and Computer backend patches from master + +* Mon Jun 15 2009 Matthias Clasen - 1.3.1-1 +- Update to 1.3.1 +- Drop obsolete patches + +* Fri Jun 12 2009 Tomas Bzatek - 1.2.3-3 +- Move bash-completion out of profile.d (#466883) + +* Mon Jun 8 2009 Tomas Bzatek - 1.2.3-2 +- SFTP: Increase timeout (#504339) + +* Mon May 18 2009 Tomas Bzatek - 1.2.3-1 +- Update to 1.2.3 +- Prevent deadlocks in dnssd resolver (#497631) + +* Tue May 12 2009 Tomas Bzatek - 1.2.2-5 +- Require separate libtalloc to fix libsmbclient +- Ref the infos in next_files_finish (gnome #582195) +- FTP: parse file sizes > 4GB correctly (#499286) +- CDDA: allow query well-formed filenames only (#499266) + +* Sat May 02 2009 David Zeuthen - 1.2.2-4 +- Don't show drives that are supposed to be hidden (#498649) +- Only automount if media or drive was just inserted - this fixes + a problem with spurious automounts when partitioning/formatting + +* Wed Apr 15 2009 David Zeuthen - 1.2.2-3 +- Sync with the gdu-volume-monitor branch + +* Mon Apr 13 2009 Alexander Larsson - 1.2.2-2 +- Add ssh-auth-sock patch from svn + +* Mon Apr 13 2009 Matthias Clasen - 1.2.2-1 +- Update to 1.2.2 +- Allow eject even on non-ejectable devices + +* Sat Apr 11 2009 David Zeuthen - 1.2.1-5 +- Don't show drives in computer:/// if media is available but + no volumes are recognized (#495152) + +* Sat Apr 11 2009 Matthias Clasen - 1.2.1-4 +- No need for bash completion to be executable + +* Thu Apr 9 2009 David Zeuthen - 1.2.1-3 +- Clean up gdu patches and bump BR for gdu to 0.3 +- Avoiding showing volume for ignored mounts (#495033) + +* Thu Apr 9 2009 David Zeuthen - 1.2.1-2 +- Avoid automounting device-mapper devices and similar (#494144) + +* Thu Apr 2 2009 Matthias Clasen - 1.2.1-1 +- Update to 1.2.1 + +* Wed Mar 18 2009 David Zeuthen - 1.2.0-2 +- GNOME #575728 - crash in Open Folder: mounting a crypto volume + +* Mon Mar 16 2009 Tomas Bzatek - 1.2.0-1 +- Update to 1.2.0 + +* Wed Mar 11 2009 Tomas Bzatek - 1.1.8-2 +- Fix 100% cpu usage when connecting to a ssh key and denying key access +- Fix monitors leak + +* Tue Mar 10 2009 Tomas Bzatek - 1.1.8-1 +- Update to 1.1.8 + +* Mon Mar 9 2009 Tomas Bzatek - 1.1.7-5 +- Expose device file attribute for all items in computer:// + +* Fri Mar 6 2009 Tomas Bzatek - 1.1.7-4 +- Fix volume lists not filled correctly + +* Wed Mar 4 2009 David Zeuthen - 1.1.7-3 +- Update GVfs gdu patch to fix mount detection confusion (#488399) + +* Mon Mar 2 2009 Matthias Clasen - 1.1.7-2 +- Port to DeviceKit-disks + +* Mon Mar 2 2009 Tomas Bzatek - 1.1.7-1 +- Update to 1.1.7 + +* Tue Feb 24 2009 Fedora Release Engineering - 1.1.6-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Mon Feb 16 2009 Tomas Bzatek - 1.1.6-1 +- Update to 1.1.6 + +* Mon Feb 2 2009 Tomas Bzatek - 1.1.5-1 +- Update to 1.1.5 + +* Wed Jan 28 2009 - Bastien Nocera - 1.1.4-2 +- ObexFTP write support + +* Tue Jan 20 2009 Tomas Bzatek - 1.1.4-1 +- Update to 1.1.4 + +* Tue Jan 13 2009 Adrian Reber - 1.1.3-4 +- Rebuild for libcdio-0.81 + +* Mon Jan 12 2009 Matthias Clasen - 1.1.3-3 +- Fix dav+sd.mount + +* Fri Jan 9 2009 Matthias Clasen - 1.1.3-2 +- Support moving files in the burn backend + +* Tue Jan 6 2009 Tomas Bzatek - 1.1.3-1 +- Update to 1.1.3 + +* Wed Dec 17 2008 Tomas Bzatek - 1.1.2-2 +- Update the smb-browse auth patch + +* Tue Dec 16 2008 Matthias Clasen - 1.1.2-1 +- Update to 1.1.2 + +* Fri Dec 12 2008 Tomas Bzatek - 1.1.1-5 +- FTP: Fix PASV connections + +* Tue Dec 9 2008 Tomas Bzatek - 1.1.1-4 +- Add support for .tar.lzma archives in archive mounter + +* Fri Dec 5 2008 Tomas Bzatek - 1.1.1-3 +- Added experimental smb-browse auth patch + +* Wed Dec 3 2008 Matthias Clasen - 1.1.1-2 +- Update file lists to include the dav+sd backend + +* Tue Dec 2 2008 Tomas Bzatek - 1.1.1-1 +- Update to 1.1.1 + +* Mon Dec 1 2008 Tomas Bzatek - 1.0.3-1 +- Update to 1.0.3 + +* Fri Nov 7 2008 Tomas Bzatek - 1.0.2-4 +- SMB: timestamp setting support (#461505) + +* Tue Nov 4 2008 Tomas Bzatek - 1.0.2-3 +- Return an empty array on success when no content type + matches (#468946) + +* Fri Oct 24 2008 Alexander Larsson - 1.0.2-2 +- Don't return generic fallback icons for files, + as this means custom mimetypes don't work (from svn) + +* Mon Oct 20 2008 Tomas Bzatek - 1.0.2-1 +- Update to 1.0.2 + +* Tue Oct 7 2008 Tomas Bzatek - 1.0.1-5 +- Don't make warnings fatal (resolves #465693) + +* Wed Oct 1 2008 David Zeuthen - 1.0.1-4 +- Add patch for reverse mapping FUSE paths (bgo #530654) + +* Mon Sep 29 2008 Matthias Clasen - 1.0.1-3 +- Fix mounting + +* Mon Sep 29 2008 - Bastien Nocera - 1.0.1-2 +- Update obexftp patch from upstream + +* Wed Sep 24 2008 Matthias Clasen - 1.0.1-1 +- Update to 1.0.1 + +* Mon Sep 22 2008 Matthias Clasen - 1.0.0-2 +- Update to 1.0.0 + +* Fri Sep 19 2008 - Bastien Nocera - 0.99.8-6 +- Update patch for missing file + +* Fri Sep 19 2008 - Bastien Nocera - 0.99.8-5 +- Updated patch, fixed deadlock whilst mounting + +* Wed Sep 17 2008 Tomas Bzatek - 0.99.8-4 +- Actually apply the kerberos patch + +* Tue Sep 16 2008 Tomas Bzatek - 0.99.8-3 +- SMB: Fix kerberos authentication + +* Mon Sep 15 2008 Matthias Clasen - 0.99.8-2 +- Update to 0.99.8 + +* Mon Sep 15 2008 - Bastien Nocera - 0.99.7.1-4 +- Update for BlueZ and obex-data-server D-Bus API changes + +* Thu Sep 11 2008 Matthias Clasen - 0.99.7.1-3 +- Rebuild + +* Tue Sep 09 2008 - Bastien Nocera - 0.99.7.1-2 +- Somebody made the build system be obnoxious and point out my + errors in obvious ways + +* Tue Sep 09 2008 - Bastien Nocera - 0.99.7.1-1 +- Update to 0.99.7.1 + +* Tue Sep 2 2008 Tomas Bzatek - 0.99.6-1 +- Update to 0.99.6 + +* Thu Aug 28 2008 Matthias Clasen - 0.99.5-3 +- Add a comma + +* Wed Aug 27 2008 - Bastien Nocera - 0.99.5-2 +- Update some descriptions + +* Wed Aug 20 2008 Tomas Bzatek - 0.99.5-1 +- Update to 0.99.5 + +* Mon Aug 4 2008 Matthias Clasen - 0.99.4-1 +- Update to 0.99.4 + +* Sun Jul 27 2008 Matthias Clasen - 0.99.3-2 +- Use standard icon names + +* Wed Jul 23 2008 Matthias Clasen - 0.99.3-1 +- Update to 0.99.3 + +* Tue Jul 22 2008 Tomas Bzatek - 0.99.2-1 +- Update to 0.99.2 +- Split out backends to separate packages + +* Tue Jun 24 2008 Tomas Bzatek - 0.99.1-3 +- gvfsd-trash: Skip autofs mounts + +* Thu Jun 12 2008 Tomas Bzatek - 0.99.1-2 +- Fix transfer of whole directories from FTP (#448560) + +* Tue Jun 3 2008 Matthias Clasen - 0.99.1-1 +- Update to 0.99.1 + +* Tue May 27 2008 Tomas Bzatek - 0.2.4-1 +- Update to 0.2.4 + +* Thu Apr 24 2008 Matthias Clasen - 0.2.3-10 +- Add application/zip to the supported mime types for the archive + backend (launchpad #211697) + +* Sat Apr 19 2008 David Zeuthen - 0.2.3-9 +- Ensure archive mounts are read-only and turn on thumbnailing on them +- Update fuse threading patch + +* Fri Apr 18 2008 Matthias Clasen - 0.2.3-8 +- Fix thread-safety issues in gvfs-fuse-daemon +- Prevent dbus from shutting us down unexpectedly + +* Thu Apr 17 2008 David Zeuthen - 0.2.3-7 +- Put X-Gnome-Vfs-System=gio into mount-archarive.desktop (See #442835) + +* Wed Apr 16 2008 Matthias Clasen - 0.2.3-6 +- Reenable gphoto automounting +- Support unmounting all mounts for a scheme + +* Wed Apr 16 2008 Matthias Clasen - 0.2.3-5 +- Fix hangs when unmounting gphoto mounts + +* Wed Apr 16 2008 David Zeuthen - 0.2.3-4 +- Only show mounts in /media and inside $HOME (#442189) + +* Mon Apr 14 2008 Matthias Clasen - 0.2.3-3 +- Fix a bug that causes application crashes (#441084) + +* Fri Apr 11 2008 Matthias Clasen - 0.2.3-2 +- Fix a crash of the fuse daemon on 64bit + +* Mon Apr 7 2008 Matthias Clasen - 0.2.3-1 +- Update to 0.2.3 + +* Fri Mar 28 2008 Tomas Bzatek - 0.2.2-1 +- Update to 0.2.2 + +* Tue Mar 25 2008 Tomas Bzatek - 0.2.1-4 +- Moved fuse stuff to a dedicated package + +* Thu Mar 20 2008 Alexander Larsson - 0.2.1-3 +- Add patch with simple archive backend UI integration + +* Wed Mar 19 2008 Tomas Bzatek - 0.2.1-2 +- Added libarchive dependency for archive backend +- Require new libsmbclient in order to get smb backend working again + +* Tue Mar 18 2008 Tomas Bzatek - 0.2.1-1 +- Update to 0.2.1 (archive backend temporarily disabled) + +* Mon Mar 17 2008 Matthias Clasen - 0.2.0.1-2 +- Silence %%post + +* Mon Mar 10 2008 Matthias Clasen - 0.2.0.1-1 +- Update to 0.2.0.1 + +* Thu Mar 6 2008 Tomas Bzatek - 0.1.11-2 +- Add patch that fixes a deadlock when foreign volume is removed + +* Tue Mar 4 2008 Matthias Clasen - 0.1.11-1 +- Update to 0.1.11 + +* Tue Mar 04 2008 Tomas Bzatek - 0.1.10-1 +- Update to 0.1.10 + +* Mon Feb 25 2008 Alexander Larsson - 0.1.8-1 +- Update to 0.1.8 + +* Thu Feb 14 2008 Alexander Larsson - 0.1.7-3 +- Add patch that fixes a smb bug that can cause short reads when copying files + +* Tue Feb 12 2008 Alexander Larsson - 0.1.7-2 +- Fix double free in hal volume monitor +- Ensure gconf module is built by adding build dep + +* Mon Feb 11 2008 Matthias Clasen - 0.1.7-1 +- Update to 0.1.7 + +* Tue Jan 29 2008 Matthias Clasen - 0.1.6-1 +- Update to 0.1.6 + +* Mon Jan 28 2008 Matthias Clasen - 0.1.5-1 +- Update to 0.1.5 +- Reenable http/dav + +* Mon Jan 21 2008 Alexander Larsson - 0.1.4-2 +- Remove the http/dav stuff for now, as we don't have the latest libsoup + +* Mon Jan 21 2008 Alexander Larsson - 0.1.4-1 +- Update to 0.1.4 +- Send USR1 in post to reload config + +* Mon Jan 14 2008 Matthias Clasen 0.1.2-1 +- Update to 0.1.2 + +* Tue Jan 8 2008 Matthias Clasen 0.1.1-1 +- Update to 0.1.1 + +* Thu Dec 20 2007 Matthias Clasen 0.1.0-1 +- Initial packaging