Compare commits

...

No commits in common. "c8" and "c8-beta" have entirely different histories.
c8 ... c8-beta

31 changed files with 1 additions and 4693 deletions

View File

@ -1,43 +0,0 @@
From d1ab5870e828df259897598298c2ca66b587426a Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 29 Aug 2018 15:36:57 +0200
Subject: [PATCH] backend: Prevent usage of NULL
g_dbus_connection_get_peer_credentials may fail in some cases, see
the documentation, and thus we have to check the return value before
use in order to prevent warnings like the following:
g_credentials_get_unix_pid: assertion 'G_IS_CREDENTIALS (credentials)' failed
Print simply -1 if pid can't be obtained this way.
---
daemon/gvfsbackend.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/daemon/gvfsbackend.c b/daemon/gvfsbackend.c
index 673070fa..4fd3455c 100644
--- a/daemon/gvfsbackend.c
+++ b/daemon/gvfsbackend.c
@@ -609,14 +609,17 @@ g_vfs_backend_invocation_first_handler (GVfsDBusMount *object,
{
GDBusConnection *connection;
GCredentials *credentials;
+ pid_t pid = -1;
connection = g_dbus_method_invocation_get_connection (invocation);
credentials = g_dbus_connection_get_peer_credentials (connection);
+ if (credentials)
+ pid = g_credentials_get_unix_pid (credentials, NULL);
- g_debug ("backend_dbus_handler %s:%s (pid=%u)\n",
+ g_debug ("backend_dbus_handler %s:%s (pid=%ld)\n",
g_dbus_method_invocation_get_interface_name (invocation),
g_dbus_method_invocation_get_method_name (invocation),
- g_credentials_get_unix_pid (credentials, NULL));
+ (long)pid);
if (backend->priv->block_requests)
{
--
2.53.0

View File

@ -1,47 +0,0 @@
From 9e38c56f99372b2474a780ac0c7c7d9b38e490cf Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Mon, 11 May 2026 17:48:26 +0200
Subject: [PATCH] daemon: Add process name to debug handler log
Made-with: Cursor (Claude)
---
daemon/gvfsbackend.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/daemon/gvfsbackend.c b/daemon/gvfsbackend.c
index fa1389ea..7dfd5300 100644
--- a/daemon/gvfsbackend.c
+++ b/daemon/gvfsbackend.c
@@ -636,16 +636,25 @@ g_vfs_backend_invocation_first_handler (GVfsDBusMount *object,
GDBusConnection *connection;
GCredentials *credentials;
pid_t pid = -1;
+ g_autofree gchar *comm = NULL;
connection = g_dbus_method_invocation_get_connection (invocation);
credentials = g_dbus_connection_get_peer_credentials (connection);
if (credentials)
pid = g_credentials_get_unix_pid (credentials, NULL);
- g_debug ("backend_dbus_handler %s:%s (pid=%ld)\n",
- g_dbus_method_invocation_get_interface_name (invocation),
- g_dbus_method_invocation_get_method_name (invocation),
- (long)pid);
+ if (pid > 0)
+ {
+ g_autofree gchar *comm_path = g_strdup_printf ("/proc/%ld/comm", (long)pid);
+
+ if (g_file_get_contents (comm_path, &comm, NULL, NULL))
+ g_strstrip (comm);
+ }
+
+ g_debug ("backend_dbus_handler %s:%s (pid=%ld comm=%s)\n",
+ g_dbus_method_invocation_get_interface_name (invocation),
+ g_dbus_method_invocation_get_method_name (invocation),
+ (long)pid, comm ? comm : "");
if (backend->priv->block_requests)
{
--
2.53.0

View File

@ -1,94 +0,0 @@
From 1d4acb8d95612384f603aa5c0c8d20060010fbc7 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Thu, 1 Aug 2024 12:35:43 +0200
Subject: [PATCH] daemon: Add support for edit mode
Currently, it is impossible to open the output stream without truncating
the file or appending it. This is a problem for many POSIX applications
relying on our FUSE daemon. Let's add an edit mode that could be used for
this purpose.
Related: https://gitlab.gnome.org/GNOME/gvfs/-/issues/249
---
daemon/gvfsbackend.h | 8 ++++++++
daemon/gvfsjobopenforwrite.c | 23 +++++++++++++++++++++++
daemon/gvfsjobopenforwrite.h | 3 ++-
3 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/daemon/gvfsbackend.h b/daemon/gvfsbackend.h
index 9c7476cf..0f97cff6 100644
--- a/daemon/gvfsbackend.h
+++ b/daemon/gvfsbackend.h
@@ -211,6 +211,14 @@ struct _GVfsBackendClass
const char *etag,
gboolean make_backup,
GFileCreateFlags flags);
+ gboolean (*try_edit) (GVfsBackend *backend,
+ GVfsJobOpenForWrite *job,
+ const char *filename,
+ GFileCreateFlags flags);
+ void (*edit) (GVfsBackend *backend,
+ GVfsJobOpenForWrite *job,
+ const char *filename,
+ GFileCreateFlags flags);
void (*close_write) (GVfsBackend *backend,
GVfsJobCloseWrite *job,
GVfsBackendHandle handle);
diff --git a/daemon/gvfsjobopenforwrite.c b/daemon/gvfsjobopenforwrite.c
index 439b63c4..5b6e8033 100644
--- a/daemon/gvfsjobopenforwrite.c
+++ b/daemon/gvfsjobopenforwrite.c
@@ -220,6 +220,20 @@ run (GVfsJob *job)
op_job->make_backup,
op_job->flags);
}
+ else if (op_job->mode == OPEN_FOR_WRITE_EDIT)
+ {
+ if (class->edit == NULL)
+ {
+ g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+ return;
+ }
+
+ class->edit (op_job->backend,
+ op_job,
+ op_job->filename,
+ op_job->flags);
+ }
else
g_assert_not_reached (); /* Handled in try */
}
@@ -259,6 +273,15 @@ try (GVfsJob *job)
op_job->make_backup,
op_job->flags);
}
+ else if (op_job->mode == OPEN_FOR_WRITE_EDIT)
+ {
+ if (class->try_edit == NULL)
+ return FALSE;
+ return class->try_edit (op_job->backend,
+ op_job,
+ op_job->filename,
+ op_job->flags);
+ }
else
{
GError *error = NULL;
diff --git a/daemon/gvfsjobopenforwrite.h b/daemon/gvfsjobopenforwrite.h
index 141189f3..e070d0ea 100644
--- a/daemon/gvfsjobopenforwrite.h
+++ b/daemon/gvfsjobopenforwrite.h
@@ -41,7 +41,8 @@ typedef struct _GVfsJobOpenForWriteClass GVfsJobOpenForWriteClass;
typedef enum {
OPEN_FOR_WRITE_CREATE = 0,
OPEN_FOR_WRITE_APPEND = 1,
- OPEN_FOR_WRITE_REPLACE = 2
+ OPEN_FOR_WRITE_REPLACE = 2,
+ OPEN_FOR_WRITE_EDIT = 3
} GVfsJobOpenForWriteMode;
typedef enum {
--
2.46.2

View File

@ -1,39 +0,0 @@
From fabacfef29e24628f7a1a303be4b54cb006431bb Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Thu, 1 Aug 2024 12:40:15 +0200
Subject: [PATCH] fuse: Use edit mode instead of returning ENOTSUP
Currently, the FUSE daemon fails with the `ENOTSUP` error when opening
a file for writing without `O_APPEND` or `O_TRUNC`. This is a problem
for many POSIX applications. Let's try the newly added edit mode instead.
Fixes: https://gitlab.gnome.org/GNOME/gvfs/-/issues/249
---
client/gvfsfusedaemon.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/client/gvfsfusedaemon.c b/client/gvfsfusedaemon.c
index ff5641ae..9ec4e3d8 100644
--- a/client/gvfsfusedaemon.c
+++ b/client/gvfsfusedaemon.c
@@ -1003,6 +1003,8 @@ setup_input_stream (GFile *file, FileHandle *fh)
return result;
}
+#define _g_file_edit(file, flags, cancellable, error) g_file_append_to(file, flags | (1 << 15), cancellable, error)
+
static gint
setup_output_stream (GFile *file, FileHandle *fh, int flags)
{
@@ -1032,7 +1034,7 @@ setup_output_stream (GFile *file, FileHandle *fh, int flags)
else if (flags & O_APPEND)
fh->stream = g_file_append_to (file, 0, NULL, &error);
else
- result = -ENOTSUP;
+ fh->stream = _g_file_edit (file, 0, NULL, &error);
if (fh->stream)
fh->pos = g_seekable_tell (G_SEEKABLE (fh->stream));
}
--
2.46.2

View File

@ -1,52 +0,0 @@
From 5dd5f5b97bc753cdf32a04e3de4bddce651ceb9b Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Thu, 1 Aug 2024 12:39:49 +0200
Subject: [PATCH] gdaemonfile: Use edit mode when private edit flag is used
The newly added edit mode is meant only for private use by our FUSE
daemon. Let's add a new private flag for the append operation to enable
the edit mode.
---
client/gdaemonfile.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/client/gdaemonfile.c b/client/gdaemonfile.c
index 485698b2..d66d0934 100644
--- a/client/gdaemonfile.c
+++ b/client/gdaemonfile.c
@@ -57,6 +57,8 @@ G_DEFINE_TYPE_WITH_CODE (GDaemonFile, g_daemon_file, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_FILE,
g_daemon_file_file_iface_init))
+#define PRIVATE_EDIT_FLAG (1 << 15)
+
static void
g_daemon_file_finalize (GObject *object)
{
@@ -1198,7 +1200,10 @@ g_daemon_file_append_to (GFile *file,
GCancellable *cancellable,
GError **error)
{
- return file_open_write (file, 1, "", FALSE, flags, cancellable, error);
+ if (flags & PRIVATE_EDIT_FLAG)
+ return file_open_write (file, 3, "", FALSE, flags, cancellable, error);
+ else
+ return file_open_write (file, 1, "", FALSE, flags, cancellable, error);
}
static GFileOutputStream *
@@ -3130,7 +3135,10 @@ g_daemon_file_append_to_async (GFile *file,
g_task_set_source_tag (task, g_daemon_file_append_to_async);
g_task_set_priority (task, io_priority);
- file_open_write_async (file, task, 1, "", FALSE, flags);
+ if (flags & PRIVATE_EDIT_FLAG)
+ file_open_write_async (file, task, 3, "", FALSE, flags);
+ else
+ file_open_write_async (file, task, 1, "", FALSE, flags);
}
static GFileOutputStream *
--
2.46.2

View File

@ -1,36 +0,0 @@
From b17f15558194ab3025c8a5cb1a2767c54333f28e Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 13 Nov 2024 11:22:27 +0100
Subject: [PATCH] smb: Disable seek support when appening
The seek is currently enabled when appending. However, the libsmbclient
doesn't support O_APPEND flag property [1]. The offset is not reset after
seeking. Let's disable seek support when appending to deal with it. The
seek operation doesn't make sense when appening anyway.
[1] https://github.com/samba-team/samba/blob/e4e3f05/source3/libsmb/libsmb_file.c#L162-L183
---
daemon/gvfsbackendsmb.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/daemon/gvfsbackendsmb.c b/daemon/gvfsbackendsmb.c
index dafbb71c..c2075555 100644
--- a/daemon/gvfsbackendsmb.c
+++ b/daemon/gvfsbackendsmb.c
@@ -871,7 +871,12 @@ do_append_to (GVfsBackend *backend,
handle->file = file;
g_vfs_job_open_for_write_set_initial_offset (job, initial_offset);
- g_vfs_job_open_for_write_set_can_seek (job, TRUE);
+
+ /* The O_APPEND flag is not properly supported by the libsmbclient library
+ * when seeking. See:
+ * https://github.com/samba-team/samba/blob/e4e3f05/source3/libsmb/libsmb_file.c#L162-L183
+ */
+ g_vfs_job_open_for_write_set_can_seek (job, FALSE);
g_vfs_job_open_for_write_set_can_truncate (job, TRUE);
g_vfs_job_open_for_write_set_handle (job, handle);
g_vfs_job_succeeded (G_VFS_JOB (job));
--
2.46.2

View File

@ -1,54 +0,0 @@
From 885bcc18b65ebd6d3c5bac56994f9f631cb9d363 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 6 Nov 2024 14:58:18 +0100
Subject: [PATCH] smb: Fail when initial_offset can't be determined
Currently, when the initial_offset can't be determined, the seek and
truncate operations are disabled. Let's fail immediatelly instead to
simplify the code as a preparation for the follow-up changes. Just a
note tha this situation can't happen with the current libsmbclient
codebase.
---
daemon/gvfsbackendsmb.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/daemon/gvfsbackendsmb.c b/daemon/gvfsbackendsmb.c
index c1c2d5f0..dafbb71c 100644
--- a/daemon/gvfsbackendsmb.c
+++ b/daemon/gvfsbackendsmb.c
@@ -857,20 +857,22 @@ do_append_to (GVfsBackend *backend,
g_vfs_job_failed_from_errno (G_VFS_JOB (job), fixup_open_errno (errno));
else
{
- handle = g_new0 (SmbWriteHandle, 1);
- handle->file = file;
-
smbc_lseek = smbc_getFunctionLseek (op_backend->smb_context);
initial_offset = smbc_lseek (op_backend->smb_context, file,
0, SEEK_CUR);
if (initial_offset == (off_t) -1)
- g_vfs_job_open_for_write_set_can_seek (job, FALSE);
- else
- {
- g_vfs_job_open_for_write_set_initial_offset (job, initial_offset);
- g_vfs_job_open_for_write_set_can_seek (job, TRUE);
- g_vfs_job_open_for_write_set_can_truncate (job, TRUE);
- }
+ {
+ g_vfs_job_failed_from_errno (G_VFS_JOB (job),
+ fixup_open_errno (errno));
+ return;
+ }
+
+ handle = g_new0 (SmbWriteHandle, 1);
+ handle->file = file;
+
+ g_vfs_job_open_for_write_set_initial_offset (job, initial_offset);
+ g_vfs_job_open_for_write_set_can_seek (job, TRUE);
+ g_vfs_job_open_for_write_set_can_truncate (job, TRUE);
g_vfs_job_open_for_write_set_handle (job, handle);
g_vfs_job_succeeded (G_VFS_JOB (job));
}
--
2.46.2

View File

@ -1,85 +0,0 @@
From b4ff6ddb32296f43439b4be79c7864f7ae7d14f1 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 13 Nov 2024 11:34:19 +0100
Subject: [PATCH] smb: Fix offset after truncate when appending
The truncate operation is currently enabled when appending. However,
the libsmbclient doesn't support O_APPEND flag property [1]. The
offset is not reset after the truncate operation. This may lead to
data corruptions. Let's explicitely seek to the desired offset when
truncating to prevent this.
[1] https://github.com/samba-team/samba/blob/e4e3f05/source3/libsmb/libsmb_file.c#L162-L183
---
daemon/gvfsbackendsmb.c | 27 ++++++++++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/daemon/gvfsbackendsmb.c b/daemon/gvfsbackendsmb.c
index c2075555..f287264b 100644
--- a/daemon/gvfsbackendsmb.c
+++ b/daemon/gvfsbackendsmb.c
@@ -780,6 +780,7 @@ typedef struct {
char *uri;
char *tmp_uri;
char *backup_uri;
+ GVfsJobOpenForWriteMode mode;
} SmbWriteHandle;
static void
@@ -824,6 +825,7 @@ do_create (GVfsBackend *backend,
{
handle = g_new0 (SmbWriteHandle, 1);
handle->file = file;
+ handle->mode = job->mode;
g_vfs_job_open_for_write_set_can_seek (job, TRUE);
g_vfs_job_open_for_write_set_can_truncate (job, TRUE);
@@ -869,6 +871,7 @@ do_append_to (GVfsBackend *backend,
handle = g_new0 (SmbWriteHandle, 1);
handle->file = file;
+ handle->mode = job->mode;
g_vfs_job_open_for_write_set_initial_offset (job, initial_offset);
@@ -1141,6 +1144,7 @@ do_replace (GVfsBackend *backend,
handle->uri = uri;
handle->tmp_uri = tmp_uri;
handle->backup_uri = backup_uri;
+ handle->mode = job->mode;
g_vfs_job_open_for_write_set_can_seek (job, TRUE);
g_vfs_job_open_for_write_set_can_truncate (job, TRUE);
@@ -1229,9 +1233,26 @@ do_truncate (GVfsBackend *backend,
smbc_ftruncate = smbc_getFunctionFtruncate (op_backend->smb_context);
if (smbc_ftruncate (op_backend->smb_context, handle->file, size) == -1)
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), errno);
- else
- g_vfs_job_succeeded (G_VFS_JOB (job));
+ {
+ g_vfs_job_failed_from_errno (G_VFS_JOB (job), errno);
+ return;
+ }
+
+ if (handle->mode == OPEN_FOR_WRITE_APPEND)
+ {
+ smbc_lseek_fn smbc_lseek;
+ off_t res;
+
+ smbc_lseek = smbc_getFunctionLseek (op_backend->smb_context);
+ res = smbc_lseek (op_backend->smb_context, handle->file, size, SEEK_SET);
+ if (res == (off_t)-1)
+ {
+ g_vfs_job_failed_from_errno (G_VFS_JOB (job), errno);
+ return;
+ }
+ }
+
+ g_vfs_job_succeeded (G_VFS_JOB (job));
}
static void
--
2.46.2

View File

@ -1,177 +0,0 @@
From bcbf85cc1f9bd8c1cb673a5d7d3f9907d84e3caa Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 13 Nov 2024 11:52:28 +0100
Subject: [PATCH] smb: Implement support for edit mode
Implement support for the newly added edit mode in the SMB backend.
Related: https://gitlab.gnome.org/GNOME/gvfs/-/issues/249
---
daemon/gvfsbackendsmb.c | 109 +++++++++++++++++++---------------------
1 file changed, 53 insertions(+), 56 deletions(-)
diff --git a/daemon/gvfsbackendsmb.c b/daemon/gvfsbackendsmb.c
index f287264b..4fbdfd23 100644
--- a/daemon/gvfsbackendsmb.c
+++ b/daemon/gvfsbackendsmb.c
@@ -793,10 +793,11 @@ smb_write_handle_free (SmbWriteHandle *handle)
}
static void
-do_create (GVfsBackend *backend,
- GVfsJobOpenForWrite *job,
- const char *filename,
- GFileCreateFlags flags)
+open_for_write (GVfsBackend *backend,
+ GVfsJobOpenForWrite *job,
+ const char *filename,
+ GFileCreateFlags flags,
+ int open_flags)
{
GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
char *uri;
@@ -804,12 +805,12 @@ do_create (GVfsBackend *backend,
SmbWriteHandle *handle;
smbc_open_fn smbc_open;
int errsv;
+ off_t initial_offset = 0;
uri = create_smb_uri (op_backend->server, op_backend->port, op_backend->share, filename);
smbc_open = smbc_getFunctionOpen (op_backend->smb_context);
errno = 0;
- file = smbc_open (op_backend->smb_context, uri,
- O_CREAT|O_RDWR|O_EXCL, 0666);
+ file = smbc_open (op_backend->smb_context, uri, open_flags, 0666);
g_free (uri);
if (file == NULL)
@@ -817,48 +818,16 @@ do_create (GVfsBackend *backend,
errsv = fixup_open_errno (errno);
/* We guarantee EEXIST on create on existing dir */
- if (errsv == EISDIR)
+ if (job->mode == OPEN_FOR_WRITE_CREATE && errsv == EISDIR)
errsv = EEXIST;
g_vfs_job_failed_from_errno (G_VFS_JOB (job), errsv);
+ return;
}
- else
- {
- handle = g_new0 (SmbWriteHandle, 1);
- handle->file = file;
- handle->mode = job->mode;
-
- g_vfs_job_open_for_write_set_can_seek (job, TRUE);
- g_vfs_job_open_for_write_set_can_truncate (job, TRUE);
- g_vfs_job_open_for_write_set_handle (job, handle);
- g_vfs_job_succeeded (G_VFS_JOB (job));
- }
-}
-static void
-do_append_to (GVfsBackend *backend,
- GVfsJobOpenForWrite *job,
- const char *filename,
- GFileCreateFlags flags)
-{
- GVfsBackendSmb *op_backend = G_VFS_BACKEND_SMB (backend);
- char *uri;
- SMBCFILE *file;
- SmbWriteHandle *handle;
- off_t initial_offset;
- smbc_open_fn smbc_open;
- smbc_lseek_fn smbc_lseek;
-
- uri = create_smb_uri (op_backend->server, op_backend->port, op_backend->share, filename);
- smbc_open = smbc_getFunctionOpen (op_backend->smb_context);
- errno = 0;
- file = smbc_open (op_backend->smb_context, uri,
- O_CREAT|O_RDWR|O_APPEND, 0666);
- g_free (uri);
-
- if (file == NULL)
- g_vfs_job_failed_from_errno (G_VFS_JOB (job), fixup_open_errno (errno));
- else
+ if (job->mode == OPEN_FOR_WRITE_APPEND)
{
+ smbc_lseek_fn smbc_lseek;
+
smbc_lseek = smbc_getFunctionLseek (op_backend->smb_context);
initial_offset = smbc_lseek (op_backend->smb_context, file,
0, SEEK_CUR);
@@ -868,24 +837,51 @@ do_append_to (GVfsBackend *backend,
fixup_open_errno (errno));
return;
}
+ }
- handle = g_new0 (SmbWriteHandle, 1);
- handle->file = file;
- handle->mode = job->mode;
+ handle = g_new0 (SmbWriteHandle, 1);
+ handle->file = file;
+ handle->mode = job->mode;
- g_vfs_job_open_for_write_set_initial_offset (job, initial_offset);
+ g_vfs_job_open_for_write_set_initial_offset (job, initial_offset);
- /* The O_APPEND flag is not properly supported by the libsmbclient library
- * when seeking. See:
- * https://github.com/samba-team/samba/blob/e4e3f05/source3/libsmb/libsmb_file.c#L162-L183
- */
- g_vfs_job_open_for_write_set_can_seek (job, FALSE);
- g_vfs_job_open_for_write_set_can_truncate (job, TRUE);
- g_vfs_job_open_for_write_set_handle (job, handle);
- g_vfs_job_succeeded (G_VFS_JOB (job));
- }
+ /* The O_APPEND flag is not properly supported by the libsmbclient library
+ * when seeking. See:
+ * https://github.com/samba-team/samba/blob/e4e3f05/source3/libsmb/libsmb_file.c#L162-L183
+ */
+ g_vfs_job_open_for_write_set_can_seek (job,
+ job->mode != OPEN_FOR_WRITE_APPEND);
+ g_vfs_job_open_for_write_set_can_truncate (job, TRUE);
+ g_vfs_job_open_for_write_set_handle (job, handle);
+ g_vfs_job_succeeded (G_VFS_JOB (job));
}
+static void
+do_create (GVfsBackend *backend,
+ GVfsJobOpenForWrite *job,
+ const char *filename,
+ GFileCreateFlags flags)
+{
+ open_for_write (backend, job, filename, flags, O_CREAT|O_RDWR|O_EXCL);
+}
+
+static void
+do_append_to (GVfsBackend *backend,
+ GVfsJobOpenForWrite *job,
+ const char *filename,
+ GFileCreateFlags flags)
+{
+ open_for_write (backend, job, filename, flags, O_CREAT|O_RDWR|O_APPEND);
+}
+
+static void
+do_edit (GVfsBackend *backend,
+ GVfsJobOpenForWrite *job,
+ const char *filename,
+ GFileCreateFlags flags)
+{
+ open_for_write (backend, job, filename, flags, O_CREAT|O_RDWR);
+}
static char *
get_dir_from_uri (const char *uri)
@@ -2153,6 +2149,7 @@ g_vfs_backend_smb_class_init (GVfsBackendSmbClass *klass)
backend_class->close_read = do_close_read;
backend_class->create = do_create;
backend_class->append_to = do_append_to;
+ backend_class->edit = do_edit;
backend_class->replace = do_replace;
backend_class->write = do_write;
backend_class->seek_on_write = do_seek_on_write;
--
2.46.2

View File

@ -1,60 +0,0 @@
From 78cc4e391d4f9e6e17af83e980f9d819b7fd208e Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Tue, 2 Jun 2026 15:32:58 +0200
Subject: [PATCH] trash: Add debug prints for mounts handling
Backport of commit e0018263.
Adapted for older GLib API: `g_unix_mount_entry_get_device_path`/`get_mount_path`/`get_fs_type` replaced with `g_unix_mount_get_device_path`/`g_unix_mount_get_mount_path`/`g_unix_mount_get_fs_type`.
---
daemon/trashlib/trashwatcher.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/daemon/trashlib/trashwatcher.c b/daemon/trashlib/trashwatcher.c
index fe2ee44..c195234 100644
--- a/daemon/trashlib/trashwatcher.c
+++ b/daemon/trashlib/trashwatcher.c
@@ -245,12 +245,22 @@ trash_watcher_remount_do (TrashWatcher *watcher)
if (result < 0)
{
/* new entry. add it. */
+ g_debug ("trash_watcher_remount_do: insert %s %s %s\n",
+ g_unix_mount_get_device_path (new->data),
+ g_unix_mount_get_mount_path (new->data),
+ g_unix_mount_get_fs_type (new->data));
+
trash_mount_insert (watcher, &old, new->data);
new = new->next;
}
else if (result > 0)
{
/* old entry. remove it. */
+ g_debug ("trash_watcher_remount_do: remove %s %s %s\n",
+ g_unix_mount_get_device_path ((*old)->mount_entry),
+ g_unix_mount_get_mount_path ((*old)->mount_entry),
+ g_unix_mount_get_fs_type ((*old)->mount_entry));
+
trash_mount_remove (old);
}
else
@@ -271,6 +281,8 @@ trash_watcher_remount_timeout (gpointer user_data)
{
TrashWatcher *watcher = user_data;
+ g_debug ("trash_watcher_remount_timeout\n");
+
watcher->update_id = 0;
trash_watcher_remount_do (watcher);
@@ -281,6 +293,8 @@ trash_watcher_remount_timeout (gpointer user_data)
static void
trash_watcher_remount (TrashWatcher *watcher)
{
+ g_debug ("trash_watcher_remount\n");
+
if (watcher->update_id != 0)
return;
--
2.53.0

View File

@ -1,94 +0,0 @@
From 86805f19dbcb55a4ad6fa2a00670d00b927c9d47 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Thu, 19 Jan 2023 12:57:30 +0100
Subject: [PATCH] trash: Add is_root function
Let's make the code more readable using the is_root function instead
of char comparison.
---
daemon/gvfsbackendtrash.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
diff --git a/daemon/gvfsbackendtrash.c b/daemon/gvfsbackendtrash.c
index 9702b860..d7ec4f77 100644
--- a/daemon/gvfsbackendtrash.c
+++ b/daemon/gvfsbackendtrash.c
@@ -44,6 +44,12 @@ struct OPAQUE_TYPE__GVfsBackendTrash
G_DEFINE_TYPE (GVfsBackendTrash, g_vfs_backend_trash, G_VFS_TYPE_BACKEND);
+static gboolean
+is_root (const char *filename)
+{
+ return (filename[0] == '/' && filename[1] == '\0');
+}
+
static GVfsMonitor *
trash_backend_get_file_monitor (GVfsBackendTrash *backend,
gboolean create)
@@ -229,7 +235,7 @@ trash_backend_open_for_read (GVfsBackend *vfs_backend,
GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (vfs_backend);
GError *error = NULL;
- if (filename[1] == '\0')
+ if (is_root (filename))
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
_("Cant open directory"));
@@ -397,7 +403,7 @@ trash_backend_delete (GVfsBackend *vfs_backend,
GError *error = NULL;
g_debug ("before job: %d\n", G_OBJECT(job)->ref_count);
- if (filename[1] == '\0')
+ if (is_root (filename))
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
_("The trash folder may not be deleted"));
else
@@ -456,7 +462,7 @@ trash_backend_pull (GVfsBackend *vfs_backend,
GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (vfs_backend);
GError *error = NULL;
- if (source[1] == '\0')
+ if (is_root (source))
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("The trash folder may not be deleted"));
else
@@ -683,7 +689,7 @@ trash_backend_enumerate (GVfsBackend *vfs_backend,
trash_watcher_rescan (backend->watcher);
- if (filename[1])
+ if (!is_root (filename))
trash_backend_enumerate_non_root (backend, job, filename,
attribute_matcher, flags);
else
@@ -729,7 +735,7 @@ trash_backend_query_info (GVfsBackend *vfs_backend,
if (!backend->file_monitor && !backend->dir_monitor)
trash_watcher_rescan (backend->watcher);
- if (filename[1])
+ if (!is_root (filename))
{
GError *error = NULL;
gboolean is_toplevel;
@@ -832,7 +838,7 @@ trash_backend_create_dir_monitor (GVfsBackend *vfs_backend,
GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (vfs_backend);
GVfsMonitor *monitor;
- if (filename[1])
+ if (!is_root (filename))
monitor = g_vfs_monitor_new (vfs_backend);
else
monitor = trash_backend_get_dir_monitor (backend, TRUE);
@@ -853,7 +859,7 @@ trash_backend_create_file_monitor (GVfsBackend *vfs_backend,
GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (vfs_backend);
GVfsMonitor *monitor;
- if (filename[1])
+ if (!is_root (filename))
monitor = g_vfs_monitor_new (vfs_backend);
else
monitor = trash_backend_get_file_monitor (backend, TRUE);
--
2.53.0

View File

@ -1,64 +0,0 @@
From 1c2cc7c0b80e5fc3f59e8557232bb6ff8ebbab7a Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Fri, 12 Jul 2024 13:21:49 +0200
Subject: [PATCH] trash: Add support for x-gvfs-trash mount option
Currently, the trash functionality is disabled for system internal mounts.
That might be a problem in some cases. The `x-gvfs-notrash` mount option
allows disabling the trash functionality for certain mounts. Let's add
support for the `x-gvfs-trash` mount option to allow the opposite.
See: https://issues.redhat.com/browse/RHEL-46828
Related: https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4155
---
daemon/trashlib/trashwatcher.c | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/daemon/trashlib/trashwatcher.c b/daemon/trashlib/trashwatcher.c
index eec32d0b..707323cb 100644
--- a/daemon/trashlib/trashwatcher.c
+++ b/daemon/trashlib/trashwatcher.c
@@ -218,10 +218,6 @@ ignore_trash_mount (GUnixMountEntry *mount)
{
GUnixMountPoint *mount_point = NULL;
const gchar *mount_options;
- gboolean retval = TRUE;
-
- if (g_unix_mount_is_system_internal (mount))
- return TRUE;
mount_options = g_unix_mount_get_options (mount);
if (mount_options == NULL)
@@ -230,15 +226,23 @@ ignore_trash_mount (GUnixMountEntry *mount)
NULL);
if (mount_point != NULL)
mount_options = g_unix_mount_point_get_options (mount_point);
+
+ g_clear_pointer (&mount_point, g_unix_mount_point_free);
}
- if (mount_options == NULL ||
- strstr (mount_options, "x-gvfs-notrash") == NULL)
- retval = FALSE;
+ if (mount_options != NULL)
+ {
+ if (strstr (mount_options, "x-gvfs-trash") != NULL)
+ return FALSE;
- g_clear_pointer (&mount_point, g_unix_mount_point_free);
+ if (strstr (mount_options, "x-gvfs-notrash") != NULL)
+ return TRUE;
+ }
+
+ if (g_unix_mount_is_system_internal (mount))
+ return TRUE;
- return retval;
+ return FALSE;
}
static void
--
2.46.1

View File

@ -1,295 +0,0 @@
From 890b2a747bbcd9ed220fb217aba41b9ef0188ba1 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 7 Jun 2023 15:49:41 +0200
Subject: [PATCH] trash: Add worker thread
The previous commit makes the backend a bit more resilience of against
stale NFS mounts, but still a lot of I/O operations (e.g.
`trash_watcher_rescan`) run on the main thread and can easily block the
whole backend. This is especially problem for the `create_dir_monitor` and
`create_file_monitor` methods that doesn't have asynchronous variants.
This may cause hangs for nautilus, or file chooser dialog, but also for
the whole gnome-shell session (resp. desktop-icons extension). Let's add
a worker thread to ensure that the `create_dir_monitor` and
`create_file_monitor` methods response immediately.
Related: https://bugzilla.redhat.com/show_bug.cgi?id=2152538
---
daemon/gvfsbackendtrash.c | 156 ++++++++++++++++++++++++++++++++------
1 file changed, 131 insertions(+), 25 deletions(-)
diff --git a/daemon/gvfsbackendtrash.c b/daemon/gvfsbackendtrash.c
index b4d3d089..0966242a 100644
--- a/daemon/gvfsbackendtrash.c
+++ b/daemon/gvfsbackendtrash.c
@@ -36,6 +36,10 @@ struct OPAQUE_TYPE__GVfsBackendTrash
GVfsMonitor *file_monitor;
GVfsMonitor *dir_monitor;
+ GMainContext *worker_context;
+ GMainLoop *worker_loop;
+ GThread *worker_thread;
+
TrashWatcher *watcher;
TrashRoot *root;
@@ -44,6 +48,94 @@ struct OPAQUE_TYPE__GVfsBackendTrash
G_DEFINE_TYPE (GVfsBackendTrash, g_vfs_backend_trash, G_VFS_TYPE_BACKEND);
+typedef struct
+{
+ GSourceFunc source_func;
+ gpointer user_data;
+ GMutex mutex;
+ GCond cond;
+ gboolean completed;
+} ContextInvokeData;
+
+static gboolean
+source_func_wrapper (gpointer user_data)
+{
+ ContextInvokeData *data = user_data;
+
+ g_mutex_lock (&data->mutex);
+
+ while (data->source_func (data->user_data));
+ data->completed = TRUE;
+
+ g_cond_signal (&data->cond);
+ g_mutex_unlock (&data->mutex);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+trash_backend_worker_thread_queue_and_wait (GVfsBackendTrash *backend,
+ GSourceFunc source_func)
+{
+ ContextInvokeData data;
+
+ data.source_func = source_func;
+ data.user_data = backend;
+
+ g_mutex_init (&data.mutex);
+ g_cond_init (&data.cond);
+ data.completed = FALSE;
+
+ g_mutex_lock (&data.mutex);
+
+ g_main_context_invoke (backend->worker_context,
+ source_func_wrapper,
+ &data);
+
+ while (!data.completed)
+ {
+ g_cond_wait (&data.cond, &data.mutex);
+ }
+
+ g_mutex_unlock (&data.mutex);
+
+ g_mutex_clear (&data.mutex);
+ g_cond_clear (&data.cond);
+}
+
+static void
+trash_backend_worker_thread_queue (GVfsBackendTrash *backend,
+ GSourceFunc source_func)
+{
+ g_main_context_invoke (backend->worker_context, source_func, backend);
+}
+
+static gboolean
+watch_func (gpointer user_data)
+{
+ GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (user_data);
+
+ trash_watcher_watch (backend->watcher);
+
+ return G_SOURCE_REMOVE;
+}
+
+static gboolean
+rescan_func (gpointer user_data)
+{
+ GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (user_data);
+
+ trash_watcher_rescan (backend->watcher);
+
+ return G_SOURCE_REMOVE;
+}
+
+static gboolean
+ready_func (gpointer user_data)
+{
+ return G_SOURCE_REMOVE;
+}
+
static gboolean
is_root (const char *filename)
{
@@ -63,7 +155,7 @@ trash_backend_get_file_monitor (GVfsBackendTrash *backend,
* no possibility here for creating more than one new monitor.
*/
if (backend->dir_monitor == NULL)
- trash_watcher_watch (backend->watcher);
+ trash_backend_worker_thread_queue (backend, watch_func);
backend->file_monitor = g_vfs_monitor_new (G_VFS_BACKEND (backend));
}
@@ -84,7 +176,7 @@ trash_backend_get_dir_monitor (GVfsBackendTrash *backend,
* no possibility here for creating more than one new monitor.
*/
if (backend->file_monitor == NULL)
- trash_watcher_watch (backend->watcher);
+ trash_backend_worker_thread_queue (backend, watch_func);
backend->dir_monitor = g_vfs_monitor_new (G_VFS_BACKEND (backend));
}
@@ -164,7 +256,6 @@ trash_backend_item_count_changed (gpointer user_data)
}
}
-
static GFile *
trash_backend_get_file (GVfsBackendTrash *backend,
const char *filename,
@@ -177,6 +268,8 @@ trash_backend_get_file (GVfsBackendTrash *backend,
TrashItem *item;
GFile *file;
+ trash_backend_worker_thread_queue_and_wait (backend, rescan_func);
+
file = NULL;
filename++;
@@ -243,9 +336,6 @@ trash_backend_open_for_read (GVfsBackend *vfs_backend,
{
GFile *real;
- if (!backend->file_monitor && !backend->dir_monitor)
- trash_watcher_rescan (backend->watcher);
-
real = trash_backend_get_file (backend, filename, NULL, NULL, &error);
if (real)
@@ -404,9 +494,6 @@ trash_backend_delete (GVfsBackend *vfs_backend,
TrashItem *item;
GFile *real;
- if (!backend->file_monitor && !backend->dir_monitor)
- trash_watcher_rescan (backend->watcher);
-
real = trash_backend_get_file (backend, filename,
&item, &is_toplevel, &error);
@@ -461,9 +548,6 @@ trash_backend_pull (GVfsBackend *vfs_backend,
TrashItem *item;
GFile *real;
- if (!backend->file_monitor && !backend->dir_monitor)
- trash_watcher_rescan (backend->watcher);
-
real = trash_backend_get_file (backend, source, &item,
&is_toplevel, &error);
@@ -585,6 +669,8 @@ trash_backend_enumerate_root (GVfsBackendTrash *backend,
g_vfs_job_succeeded (G_VFS_JOB (job));
+ trash_backend_worker_thread_queue_and_wait (backend, rescan_func);
+
items = trash_root_get_items (backend->root);
for (node = items; node; node = node->next)
@@ -675,8 +761,6 @@ trash_backend_enumerate (GVfsBackend *vfs_backend,
g_assert (filename[0] == '/');
- trash_watcher_rescan (backend->watcher);
-
if (!is_root (filename))
trash_backend_enumerate_non_root (backend, job, filename,
attribute_matcher, flags);
@@ -684,6 +768,31 @@ trash_backend_enumerate (GVfsBackend *vfs_backend,
trash_backend_enumerate_root (backend, job, attribute_matcher, flags);
}
+static gpointer
+thread_func (gpointer user_data)
+{
+ GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (user_data);
+
+ g_main_context_push_thread_default (backend->worker_context);
+ backend->worker_loop = g_main_loop_new (backend->worker_context, FALSE);
+
+ backend->root = trash_root_new (trash_backend_item_created,
+ trash_backend_item_deleted,
+ trash_backend_item_count_changed,
+ backend);
+ backend->watcher = trash_watcher_new (backend->root);
+
+ g_main_loop_run (backend->worker_loop);
+
+ trash_watcher_free (backend->watcher);
+ trash_root_free (backend->root);
+
+ g_main_context_pop_thread_default (backend->worker_context);
+ g_main_loop_unref (backend->worker_loop);
+
+ return NULL;
+}
+
static void
trash_backend_mount (GVfsBackend *vfs_backend,
GVfsJobMount *job,
@@ -695,11 +804,12 @@ trash_backend_mount (GVfsBackend *vfs_backend,
backend->file_monitor = NULL;
backend->dir_monitor = NULL;
- backend->root = trash_root_new (trash_backend_item_created,
- trash_backend_item_deleted,
- trash_backend_item_count_changed,
- backend);
- backend->watcher = trash_watcher_new (backend->root);
+
+ backend->worker_context = g_main_context_new ();
+ backend->worker_thread = g_thread_new ("Trash Worker Thread",
+ thread_func,
+ backend);
+ trash_backend_worker_thread_queue_and_wait (backend, ready_func);
g_vfs_job_succeeded (G_VFS_JOB (job));
}
@@ -716,9 +826,6 @@ trash_backend_query_info (GVfsBackend *vfs_backend,
g_assert (filename[0] == '/');
- if (!backend->file_monitor && !backend->dir_monitor)
- trash_watcher_rescan (backend->watcher);
-
if (!is_root (filename))
{
GError *error = NULL;
@@ -762,6 +869,8 @@ trash_backend_query_info (GVfsBackend *vfs_backend,
GIcon *icon;
int n_items;
+ trash_backend_worker_thread_queue_and_wait (backend, rescan_func);
+
n_items = trash_root_get_n_items (backend->root);
g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
@@ -878,9 +987,6 @@ trash_backend_finalize (GObject *object)
if (backend->dir_monitor)
g_object_unref (backend->dir_monitor);
backend->dir_monitor = NULL;
-
- trash_watcher_free (backend->watcher);
- trash_root_free (backend->root);
}
static void
--
2.53.0

View File

@ -1,30 +0,0 @@
From f1cdb812f8fa6f06239183923f920025a05e0712 Mon Sep 17 00:00:00 2001
From: Maximiliano Sandoval <msandova@gnome.org>
Date: Fri, 10 Apr 2026 23:52:16 +0200
Subject: [PATCH] trash: Chain up finalize
Currently, `trash_backend_finalize()` only releases backend-specific
monitors. Without chaining up, parent `GObject` finalization is
skipped, which can leave parent-side teardown incomplete. Let's call
`g_vfs_backend_trash_parent_class->finalize()` at the end of
`trash_backned_finalize()`.
---
daemon/gvfsbackendtrash.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/daemon/gvfsbackendtrash.c b/daemon/gvfsbackendtrash.c
index 0966242a..1dcb44f0 100644
--- a/daemon/gvfsbackendtrash.c
+++ b/daemon/gvfsbackendtrash.c
@@ -987,6 +987,8 @@ trash_backend_finalize (GObject *object)
if (backend->dir_monitor)
g_object_unref (backend->dir_monitor);
backend->dir_monitor = NULL;
+
+ G_OBJECT_CLASS (g_vfs_backend_trash_parent_class)->finalize (object);
}
static void
--
2.53.0

View File

@ -1,84 +0,0 @@
From 5e34cc212b32e58fd7b6721d92548e983fecd991 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Tue, 2 Jun 2026 15:54:33 +0200
Subject: [PATCH] trash: Defer mount monitoring to active watchers only
Backport of commit b53d45db.
Adjusted context for target version.
---
daemon/trashlib/trashwatcher.c | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/daemon/trashlib/trashwatcher.c b/daemon/trashlib/trashwatcher.c
index bd658e1..3a1bc9f 100644
--- a/daemon/trashlib/trashwatcher.c
+++ b/daemon/trashlib/trashwatcher.c
@@ -139,6 +139,7 @@ struct OPAQUE_TYPE__TrashWatcher
TrashRoot *root;
GUnixMountMonitor *mount_monitor;
+ gulong mounts_changed_id;
GHashTable *mounts; /* mount_path -> TrashMount */
guint update_id;
@@ -339,8 +340,7 @@ trash_watcher_new (TrashRoot *root)
watcher->watching = FALSE;
watcher->update_id = 0;
watcher->mount_monitor = g_unix_mount_monitor_get ();
- g_signal_connect_swapped (watcher->mount_monitor, "mounts_changed",
- G_CALLBACK (trash_watcher_remount), watcher);
+ watcher->mounts_changed_id = 0;
user_datadir = g_file_new_for_path (g_get_user_data_dir ());
homedir_trashdir = g_file_get_child (user_datadir, "Trash/files");
@@ -378,9 +378,17 @@ trash_watcher_watch (TrashWatcher *watcher)
GHashTableIter iter;
gpointer value;
+ g_debug ("trash_watcher_watch\n");
+
if (watcher->watching)
return;
+ watcher->mounts_changed_id =
+ g_signal_connect_swapped (watcher->mount_monitor, "mounts_changed",
+ G_CALLBACK (trash_watcher_remount), watcher);
+
+ trash_watcher_remount_do (watcher);
+
if (watcher->homedir_type != TRASH_WATCHER_NO_WATCH)
trash_dir_watch (watcher->homedir_trashdir);
@@ -404,9 +412,17 @@ trash_watcher_unwatch (TrashWatcher *watcher)
GHashTableIter iter;
gpointer value;
+ g_debug ("trash_watcher_unwatch\n");
+
if (!watcher->watching)
return;
+ g_signal_handler_disconnect (watcher->mount_monitor,
+ watcher->mounts_changed_id);
+ watcher->mounts_changed_id = 0;
+
+ g_clear_handle_id (&watcher->update_id, g_source_remove);
+
if (watcher->homedir_type != TRASH_WATCHER_NO_WATCH)
trash_dir_unwatch (watcher->homedir_trashdir);
@@ -430,7 +446,9 @@ trash_watcher_rescan (TrashWatcher *watcher)
GHashTableIter iter;
gpointer value;
- if (watcher->update_id != 0)
+ if (!watcher->watching)
+ trash_watcher_remount_do (watcher);
+ else if (watcher->update_id != 0)
{
g_source_remove (watcher->update_id);
trash_watcher_remount_timeout (watcher);
--
2.53.0

View File

@ -1,57 +0,0 @@
From 85a789c800ef2773af6eb8884fef746d67d3cafe Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Fri, 20 Jan 2023 09:17:00 +0100
Subject: [PATCH] trash: Do not create monitors for non-root items
The `create_dir_monitor` and `create_file_monitor` methods never fail
currently. However, no events are emitted for non-root items. Let's
return the `G_IO_ERROR_NOT_SUPPORTED` error for non-root items instead.
---
daemon/gvfsbackendtrash.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/daemon/gvfsbackendtrash.c b/daemon/gvfsbackendtrash.c
index d7ec4f77..76c9e006 100644
--- a/daemon/gvfsbackendtrash.c
+++ b/daemon/gvfsbackendtrash.c
@@ -839,10 +839,15 @@ trash_backend_create_dir_monitor (GVfsBackend *vfs_backend,
GVfsMonitor *monitor;
if (!is_root (filename))
- monitor = g_vfs_monitor_new (vfs_backend);
- else
- monitor = trash_backend_get_dir_monitor (backend, TRUE);
+ {
+ g_vfs_job_failed (G_VFS_JOB (job),
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+ return TRUE;
+ }
+ monitor = trash_backend_get_dir_monitor (backend, TRUE);
g_vfs_job_create_monitor_set_monitor (job, monitor);
g_vfs_job_succeeded (G_VFS_JOB (job));
g_object_unref (monitor);
@@ -860,10 +865,15 @@ trash_backend_create_file_monitor (GVfsBackend *vfs_backend,
GVfsMonitor *monitor;
if (!is_root (filename))
- monitor = g_vfs_monitor_new (vfs_backend);
- else
- monitor = trash_backend_get_file_monitor (backend, TRUE);
+ {
+ g_vfs_job_failed (G_VFS_JOB (job),
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported"));
+ return TRUE;
+ }
+ monitor = trash_backend_get_file_monitor (backend, TRUE);
g_vfs_job_create_monitor_set_monitor (job, monitor);
g_vfs_job_succeeded (G_VFS_JOB (job));
g_object_unref (monitor);
--
2.53.0

View File

@ -1,119 +0,0 @@
From 181da9f0d10a9e75795db5bb138214a89382271f Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Fri, 21 Nov 2025 13:28:55 +0100
Subject: [PATCH] trash: Rate limit mount updates
Currently, the trash daemon processes every `mounts_changed` signal.
This leads to high CPU usage when many mount events occur in a short
timeframe. Let's rate limit mount processing to avoid high CPU usage
in this case. The timeout is randomly chosen within the interval
50-500 ms to better balance the load when multiple daemons are
running simultaneously.
Related: https://gitlab.gnome.org/GNOME/gvfs/-/issues/814
---
daemon/trashlib/trashwatcher.c | 39 ++++++++++++++++++++++++++++++++--
1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/daemon/trashlib/trashwatcher.c b/daemon/trashlib/trashwatcher.c
index 80a24d3d..664380c6 100644
--- a/daemon/trashlib/trashwatcher.c
+++ b/daemon/trashlib/trashwatcher.c
@@ -142,6 +142,7 @@ struct OPAQUE_TYPE__TrashWatcher
GUnixMountMonitor *mount_monitor;
TrashMount *mounts;
+ guint update_id;
TrashDir *homedir_trashdir;
WatchType homedir_type;
@@ -158,6 +159,8 @@ struct _TrashMount
TrashMount *next;
};
+#define UPDATE_TIMEOUT 100 /* ms */
+
static void
trash_mount_insert (TrashWatcher *watcher,
TrashMount ***mount_ptr_ptr,
@@ -247,7 +250,7 @@ ignore_trash_mount (GUnixMountEntry *mount)
}
static void
-trash_watcher_remount (TrashWatcher *watcher)
+trash_watcher_remount_do (TrashWatcher *watcher)
{
TrashMount **old;
GList *mounts;
@@ -298,6 +301,29 @@ trash_watcher_remount (TrashWatcher *watcher)
g_list_free (mounts);
}
+static gboolean
+trash_watcher_remount_timeout (gpointer user_data)
+{
+ TrashWatcher *watcher = user_data;
+
+ watcher->update_id = 0;
+
+ trash_watcher_remount_do (watcher);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+trash_watcher_remount (TrashWatcher *watcher)
+{
+ if (watcher->update_id != 0)
+ return;
+
+ watcher->update_id = g_timeout_add (UPDATE_TIMEOUT * g_random_double_range (0.5, 5),
+ trash_watcher_remount_timeout,
+ watcher);
+}
+
TrashWatcher *
trash_watcher_new (TrashRoot *root)
{
@@ -310,6 +336,7 @@ trash_watcher_new (TrashRoot *root)
watcher->root = root;
watcher->mounts = NULL;
watcher->watching = FALSE;
+ watcher->update_id = 0;
watcher->mount_monitor = g_unix_mount_monitor_get ();
g_signal_connect_swapped (watcher->mount_monitor, "mounts_changed",
G_CALLBACK (trash_watcher_remount), watcher);
@@ -328,7 +355,7 @@ trash_watcher_new (TrashRoot *root)
g_object_unref (homedir_trashdir);
g_object_unref (user_datadir);
- trash_watcher_remount (watcher);
+ trash_watcher_remount_do (watcher);
return watcher;
}
@@ -336,6 +363,8 @@ trash_watcher_new (TrashRoot *root)
void
trash_watcher_free (TrashWatcher *watcher)
{
+ g_clear_handle_id (&watcher->update_id, g_source_remove);
+
/* We just leak everything here, as this is not normally hit.
This used to be a g_assert_not_reached(), and that got hit when
mounting the trash backend failed due to the trash already being
@@ -387,6 +416,12 @@ trash_watcher_rescan (TrashWatcher *watcher)
{
TrashMount *mount;
+ if (watcher->update_id != 0)
+ {
+ g_source_remove (watcher->update_id);
+ trash_watcher_remount_timeout (watcher);
+ }
+
if (!watcher->watching || watcher->homedir_type != TRASH_WATCHER_TRUSTED)
trash_dir_rescan (watcher->homedir_trashdir);
--
2.53.0

View File

@ -1,88 +0,0 @@
From 68a056dd3764c795c5d9d5844e2cc3f20f9eaf1d Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Tue, 3 Feb 2026 16:47:50 +0100
Subject: [PATCH] trash: Rate limit size change notifications
Currently, the `attribute-changed` signal is emitted after every file
change. This can lead to higher CPU usage if too many changes occur
in a short time frame. To avoid this, let's limit the frequency of the
signal to a maximum of 100 ms.
Co-Authored-By: Claude <noreply@anthropic.com>
Related: https://gitlab.gnome.org/GNOME/gvfs/-/issues/814
---
daemon/trashlib/trashitem.c | 26 +++++++++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/daemon/trashlib/trashitem.c b/daemon/trashlib/trashitem.c
index a5b5b166..08dd8ad8 100644
--- a/daemon/trashlib/trashitem.c
+++ b/daemon/trashlib/trashitem.c
@@ -30,8 +30,12 @@ struct OPAQUE_TYPE__TrashRoot
GHashTable *item_table;
int old_size;
+
+ guint size_change_id;
};
+#define SIZE_CHANGE_TIMEOUT 100 /* ms */
+
struct OPAQUE_TYPE__TrashItem
{
TrashRoot *root;
@@ -283,6 +287,17 @@ trash_item_invoke_closure (NotifyClosure *closure)
g_slice_free (NotifyClosure, closure);
}
+static gboolean
+trash_root_size_change_timeout (gpointer user_data)
+{
+ TrashRoot *root = user_data;
+
+ root->size_change_id = 0;
+ root->size_change (root->user_data);
+
+ return G_SOURCE_REMOVE;
+}
+
void
trash_root_thaw (TrashRoot *root)
{
@@ -308,10 +323,13 @@ trash_root_thaw (TrashRoot *root)
size_changed = root->old_size != size;
root->old_size = size;
- g_rw_lock_writer_unlock (&root->lock);
+ /* Rate limit size_change notifications */
+ if (size_changed && root->size_change_id == 0)
+ root->size_change_id = g_timeout_add (SIZE_CHANGE_TIMEOUT,
+ trash_root_size_change_timeout,
+ root);
- if (size_changed)
- root->size_change (root->user_data);
+ g_rw_lock_writer_unlock (&root->lock);
}
static void
@@ -341,6 +359,7 @@ trash_root_new (trash_item_notify create,
root->item_table = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL, trash_item_removed);
root->old_size = 0;
+ root->size_change_id = 0;
return root;
}
@@ -348,6 +367,7 @@ trash_root_new (trash_item_notify create,
void
trash_root_free (TrashRoot *root)
{
+ g_clear_handle_id (&root->size_change_id, g_source_remove);
g_hash_table_destroy (root->item_table);
while (!g_queue_is_empty (root->notifications))
--
2.53.0

View File

@ -1,24 +0,0 @@
From f8504e445976830287dcb44a51514dc4c15fe528 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 7 Jun 2023 15:50:51 +0200
Subject: [PATCH] trash: Remove unused is_homedir property
---
daemon/trashlib/trashitem.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/daemon/trashlib/trashitem.c b/daemon/trashlib/trashitem.c
index 08912856..a5b5b166 100644
--- a/daemon/trashlib/trashitem.c
+++ b/daemon/trashlib/trashitem.c
@@ -29,7 +29,6 @@ struct OPAQUE_TYPE__TrashRoot
gpointer user_data;
GHashTable *item_table;
- gboolean is_homedir;
int old_size;
};
--
2.53.0

View File

@ -1,68 +0,0 @@
From 07f55a1dae9af0852fed9d774a6ab7d5a924d5e1 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Fri, 20 Jan 2023 15:43:10 +0100
Subject: [PATCH] trash: Remove unused ui_hook property
---
daemon/trashlib/trashdir.c | 11 -----------
daemon/trashlib/trashdir.h | 5 -----
2 files changed, 16 deletions(-)
diff --git a/daemon/trashlib/trashdir.c b/daemon/trashlib/trashdir.c
index 0d7d2b1b..707dff6c 100644
--- a/daemon/trashlib/trashdir.c
+++ b/daemon/trashlib/trashdir.c
@@ -373,8 +373,6 @@ trash_dir_rescan (TrashDir *dir)
trash_dir_empty (dir);
}
-static trash_dir_ui_hook ui_hook;
-
TrashDir *
trash_dir_new (TrashRoot *root,
gboolean watching,
@@ -411,20 +409,11 @@ trash_dir_new (TrashRoot *root,
else
dir->watch = NULL;
- if (ui_hook)
- ui_hook (dir, dir->directory);
-
g_free (rel);
return dir;
}
-void
-trash_dir_set_ui_hook (trash_dir_ui_hook _ui_hook)
-{
- ui_hook = _ui_hook;
-}
-
void
trash_dir_free (TrashDir *dir)
{
diff --git a/daemon/trashlib/trashdir.h b/daemon/trashlib/trashdir.h
index 5612f9ba..4c39d516 100644
--- a/daemon/trashlib/trashdir.h
+++ b/daemon/trashlib/trashdir.h
@@ -15,9 +15,6 @@
typedef struct OPAQUE_TYPE__TrashDir TrashDir;
-typedef void (*trash_dir_ui_hook) (TrashDir *dir,
- GFile *directory);
-
TrashDir *trash_dir_new (TrashRoot *root,
gboolean watching,
gboolean is_homedir,
@@ -31,6 +28,4 @@ void trash_dir_watch (TrashDir *dir);
void trash_dir_unwatch (TrashDir *dir);
void trash_dir_rescan (TrashDir *dir);
-void trash_dir_set_ui_hook (trash_dir_ui_hook ui_hook);
-
#endif /* _trashdir_h_ */
--
2.53.0

View File

@ -1,241 +0,0 @@
From 3889e4dec938a8023b8120545d4b53083b209dab Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Thu, 19 Jan 2023 12:12:52 +0100
Subject: [PATCH] trash: Run blocking methods on a thread pool
All jobs use `_try` methods currently. This is wrong as most of them can
block. This works quite ok except the case of stale NFS mounts that can
block the main loop forever. Let's run the jobs on a thread pool instead.
This reverts commit 01fe5a61 except for the `create_dir_monitor` and
`create_file_monitor` methods in order to avoid issues like
https://bugzilla.gnome.org/show_bug.cgi?id=723305.
---
daemon/gvfsbackendtrash.c | 68 ++++++++++++++-------------------------
1 file changed, 25 insertions(+), 43 deletions(-)
diff --git a/daemon/gvfsbackendtrash.c b/daemon/gvfsbackendtrash.c
index 76c9e006..b4d3d089 100644
--- a/daemon/gvfsbackendtrash.c
+++ b/daemon/gvfsbackendtrash.c
@@ -227,7 +227,7 @@ trash_backend_get_file (GVfsBackendTrash *backend,
}
/* ======================= method implementations ======================= */
-static gboolean
+static void
trash_backend_open_for_read (GVfsBackend *vfs_backend,
GVfsJobOpenForRead *job,
const char *filename)
@@ -261,18 +261,16 @@ trash_backend_open_for_read (GVfsBackend *vfs_backend,
g_vfs_job_open_for_read_set_can_seek (job, TRUE);
g_vfs_job_succeeded (G_VFS_JOB (job));
- return TRUE;
+ return;
}
}
}
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
g_error_free (error);
-
- return TRUE;
}
-static gboolean
+static void
trash_backend_read (GVfsBackend *backend,
GVfsJobRead *job,
GVfsBackendHandle handle,
@@ -290,16 +288,14 @@ trash_backend_read (GVfsBackend *backend,
g_vfs_job_read_set_size (job, bytes);
g_vfs_job_succeeded (G_VFS_JOB (job));
- return TRUE;
+ return;
}
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
g_error_free (error);
-
- return TRUE;
}
-static gboolean
+static void
trash_backend_seek_on_read (GVfsBackend *backend,
GVfsJobSeekRead *job,
GVfsBackendHandle handle,
@@ -313,13 +309,11 @@ trash_backend_seek_on_read (GVfsBackend *backend,
g_vfs_job_seek_read_set_offset (job, g_seekable_tell (handle));
g_vfs_job_succeeded (G_VFS_JOB (job));
- return TRUE;
+ return;
}
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
g_error_free (error);
-
- return TRUE;
}
static void
@@ -349,7 +343,7 @@ trash_backend_query_info_on_read (GVfsBackend *backend,
}
}
-static gboolean
+static void
trash_backend_close_read (GVfsBackend *backend,
GVfsJobCloseRead *job,
GVfsBackendHandle handle)
@@ -361,15 +355,13 @@ trash_backend_close_read (GVfsBackend *backend,
g_vfs_job_succeeded (G_VFS_JOB (job));
g_object_unref (handle);
- return TRUE;
+ return;
}
g_object_unref (handle);
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
g_error_free (error);
-
- return TRUE;
}
static gboolean
@@ -394,7 +386,7 @@ trash_backend_schedule_thaw (GVfsBackendTrash *backend)
backend);
}
-static gboolean
+static void
trash_backend_delete (GVfsBackend *vfs_backend,
GVfsJobDelete *job,
const char *filename)
@@ -435,7 +427,7 @@ trash_backend_delete (GVfsBackend *vfs_backend,
g_vfs_job_succeeded (G_VFS_JOB (job));
trash_item_unref (item);
- return TRUE;
+ return;
}
}
@@ -445,11 +437,9 @@ trash_backend_delete (GVfsBackend *vfs_backend,
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
g_error_free (error);
-
- return TRUE;
}
-static gboolean
+static void
trash_backend_pull (GVfsBackend *vfs_backend,
GVfsJobPull *job,
const gchar *source,
@@ -505,7 +495,7 @@ trash_backend_pull (GVfsBackend *vfs_backend,
trash_item_unref (item);
g_object_unref (real);
- return TRUE;
+ return;
}
}
@@ -517,8 +507,6 @@ trash_backend_pull (GVfsBackend *vfs_backend,
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
g_error_free (error);
-
- return TRUE;
}
static void
@@ -676,7 +664,7 @@ trash_backend_enumerate_non_root (GVfsBackendTrash *backend,
g_error_free (error);
}
-static gboolean
+static void
trash_backend_enumerate (GVfsBackend *vfs_backend,
GVfsJobEnumerate *job,
const char *filename,
@@ -694,11 +682,9 @@ trash_backend_enumerate (GVfsBackend *vfs_backend,
attribute_matcher, flags);
else
trash_backend_enumerate_root (backend, job, attribute_matcher, flags);
-
- return TRUE;
}
-static gboolean
+static void
trash_backend_mount (GVfsBackend *vfs_backend,
GVfsJobMount *job,
GMountSpec *mount_spec,
@@ -716,11 +702,9 @@ trash_backend_mount (GVfsBackend *vfs_backend,
backend->watcher = trash_watcher_new (backend->root);
g_vfs_job_succeeded (G_VFS_JOB (job));
-
- return TRUE;
}
-static gboolean
+static void
trash_backend_query_info (GVfsBackend *vfs_backend,
GVfsJobQueryInfo *job,
const char *filename,
@@ -764,7 +748,7 @@ trash_backend_query_info (GVfsBackend *vfs_backend,
trash_item_unref (item);
g_object_unref (real_info);
- return TRUE;
+ return;
}
trash_item_unref (item);
@@ -798,8 +782,6 @@ trash_backend_query_info (GVfsBackend *vfs_backend,
g_vfs_job_succeeded (G_VFS_JOB (job));
}
-
- return TRUE;
}
static gboolean
@@ -926,17 +908,17 @@ g_vfs_backend_trash_class_init (GVfsBackendTrashClass *class)
gobject_class->finalize = trash_backend_finalize;
- backend_class->try_mount = trash_backend_mount;
- backend_class->try_open_for_read = trash_backend_open_for_read;
- backend_class->try_read = trash_backend_read;
- backend_class->try_seek_on_read = trash_backend_seek_on_read;
+ backend_class->mount = trash_backend_mount;
+ backend_class->open_for_read = trash_backend_open_for_read;
+ backend_class->read = trash_backend_read;
+ backend_class->seek_on_read = trash_backend_seek_on_read;
backend_class->query_info_on_read = trash_backend_query_info_on_read;
- backend_class->try_close_read = trash_backend_close_read;
- backend_class->try_query_info = trash_backend_query_info;
+ backend_class->close_read = trash_backend_close_read;
+ backend_class->query_info = trash_backend_query_info;
backend_class->try_query_fs_info = trash_backend_query_fs_info;
- backend_class->try_enumerate = trash_backend_enumerate;
- backend_class->try_delete = trash_backend_delete;
- backend_class->try_pull = trash_backend_pull;
+ backend_class->enumerate = trash_backend_enumerate;
+ backend_class->delete = trash_backend_delete;
+ backend_class->pull = trash_backend_pull;
backend_class->try_create_dir_monitor = trash_backend_create_dir_monitor;
backend_class->try_create_file_monitor = trash_backend_create_file_monitor;
}
--
2.53.0

View File

@ -1,47 +0,0 @@
From 1ae1e68794a01b524d91c3da0addeca4d060b795 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Tue, 2 Jun 2026 15:54:37 +0200
Subject: [PATCH] trash: Skip mount table reparsing when unchanged
Backport of commit e1821cdc.
Adapted for older GLib API: `g_unix_mount_entries_get`/`g_unix_mount_entries_changed_since` replaced with `g_unix_mounts_get`/`g_unix_mounts_changed_since`.
---
daemon/trashlib/trashwatcher.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/daemon/trashlib/trashwatcher.c b/daemon/trashlib/trashwatcher.c
index e44ab06..59303f0 100644
--- a/daemon/trashlib/trashwatcher.c
+++ b/daemon/trashlib/trashwatcher.c
@@ -142,6 +142,7 @@ struct OPAQUE_TYPE__TrashWatcher
gulong mounts_changed_id;
GHashTable *mounts; /* mount_path -> TrashMount */
guint update_id;
+ guint64 last_mount_time;
TrashDir *homedir_trashdir;
WatchType homedir_type;
@@ -246,7 +247,10 @@ trash_watcher_remount_do (TrashWatcher *watcher)
gpointer key, value;
const char *mount_path;
- mounts = g_unix_mounts_get (NULL);
+ if (!g_unix_mounts_changed_since (watcher->last_mount_time))
+ return;
+
+ mounts = g_unix_mounts_get (&watcher->last_mount_time);
mount_paths = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
for (l = mounts; l != NULL; l = l->next)
@@ -339,6 +343,7 @@ trash_watcher_new (TrashRoot *root)
watcher->mounts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
watcher->watching = FALSE;
watcher->update_id = 0;
+ watcher->last_mount_time = 0;
watcher->mount_monitor = g_unix_mount_monitor_get ();
watcher->mounts_changed_id = 0;
--
2.53.0

View File

@ -1,280 +0,0 @@
From 0f166b6f4f3e38144c779b3e6b55d777c6637b0e Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 3 Jun 2026 08:37:56 +0200
Subject: [PATCH] trash: Use GHashTable for mount tracking
Backport of commit 64f8853f.
Adapted for older GLib API: `g_unix_mount_entry_*` replaced with `g_unix_mount_*`, `g_unix_mount_entries_get` replaced with `g_unix_mounts_get`.
---
daemon/trashlib/trashwatcher.c | 156 +++++++++++++++++----------------
1 file changed, 80 insertions(+), 76 deletions(-)
diff --git a/daemon/trashlib/trashwatcher.c b/daemon/trashlib/trashwatcher.c
index d8d6ef8..426f97f 100644
--- a/daemon/trashlib/trashwatcher.c
+++ b/daemon/trashlib/trashwatcher.c
@@ -139,7 +139,7 @@ struct OPAQUE_TYPE__TrashWatcher
TrashRoot *root;
GUnixMountMonitor *mount_monitor;
- TrashMount *mounts;
+ GHashTable *mounts; /* mount_path -> TrashMount */
guint update_id;
TrashDir *homedir_trashdir;
@@ -153,16 +153,13 @@ struct _TrashMount
GUnixMountEntry *mount_entry;
TrashDir *dirs[2];
WatchType type;
-
- TrashMount *next;
};
#define UPDATE_TIMEOUT 100 /* ms */
static void
-trash_mount_insert (TrashWatcher *watcher,
- TrashMount ***mount_ptr_ptr,
- GUnixMountEntry *mount_entry)
+trash_mount_insert (TrashWatcher *watcher,
+ GUnixMountEntry *mount_entry)
{
const char *mountpoint;
gboolean watching;
@@ -192,24 +189,15 @@ trash_mount_insert (TrashWatcher *watcher,
mount->dirs[1] = trash_dir_new (watcher->root, watching, FALSE, mountpoint,
".Trash-%d/files", (int) getuid ());
- mount->next = **mount_ptr_ptr;
-
- **mount_ptr_ptr = mount;
- *mount_ptr_ptr = &mount->next;
+ g_hash_table_insert (watcher->mounts, g_strdup (mountpoint), mount);
}
static void
-trash_mount_remove (TrashMount **mount_ptr)
+trash_mount_free (TrashMount *mount)
{
- TrashMount *mount = *mount_ptr;
-
- /* first, the dirs */
trash_dir_free (mount->dirs[0]);
trash_dir_free (mount->dirs[1]);
- /* detach from list */
- *mount_ptr = mount->next;
-
g_unix_mount_free (mount->mount_entry);
g_slice_free (TrashMount, mount);
}
@@ -249,63 +237,64 @@ ignore_trash_mount (GUnixMountEntry *mount)
static void
trash_watcher_remount_do (TrashWatcher *watcher)
{
- TrashMount **old;
+ GHashTable *mount_paths;
+ GHashTableIter iter;
GList *mounts;
- GList *new;
+ GList *l;
+ gpointer key, value;
+ const char *mount_path;
mounts = g_unix_mounts_get (NULL);
- mounts = g_list_sort (mounts, (GCompareFunc) g_unix_mount_compare);
+ mount_paths = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- old = &watcher->mounts;
- new = mounts;
-
- /* synchronise the two lists */
- while (*old || new)
+ for (l = mounts; l != NULL; l = l->next)
{
- int result;
+ g_autoptr(GUnixMountEntry) mount_entry = l->data;
- if (new && ignore_trash_mount (new->data))
+ if (ignore_trash_mount (mount_entry))
{
- g_unix_mount_free (new->data);
- new = new->next;
+ g_debug ("trash_watcher_remount_do: ignore %s %s %s\n",
+ g_unix_mount_get_device_path (mount_entry),
+ g_unix_mount_get_mount_path (mount_entry),
+ g_unix_mount_get_fs_type (mount_entry));
continue;
}
- if ((result = (new == NULL) - (*old == NULL)) == 0)
- result = g_unix_mount_compare (new->data, (*old)->mount_entry);
-
- if (result < 0)
+ mount_path = g_unix_mount_get_mount_path (mount_entry);
+ if (!g_hash_table_contains (watcher->mounts, mount_path))
{
- /* new entry. add it. */
g_debug ("trash_watcher_remount_do: insert %s %s %s\n",
- g_unix_mount_get_device_path (new->data),
- g_unix_mount_get_mount_path (new->data),
- g_unix_mount_get_fs_type (new->data));
+ g_unix_mount_get_device_path (mount_entry),
+ g_unix_mount_get_mount_path (mount_entry),
+ g_unix_mount_get_fs_type (mount_entry));
- trash_mount_insert (watcher, &old, new->data);
- new = new->next;
+ trash_mount_insert (watcher, g_steal_pointer (&mount_entry));
}
- else if (result > 0)
- {
- /* old entry. remove it. */
- g_debug ("trash_watcher_remount_do: remove %s %s %s\n",
- g_unix_mount_get_device_path ((*old)->mount_entry),
- g_unix_mount_get_mount_path ((*old)->mount_entry),
- g_unix_mount_get_fs_type ((*old)->mount_entry));
- trash_mount_remove (old);
- }
- else
+ g_hash_table_add (mount_paths, g_strdup (mount_path));
+ }
+
+ g_list_free (mounts);
+
+ g_hash_table_iter_init (&iter, watcher->mounts);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ TrashMount *mount = value;
+ mount_path = key;
+
+ if (!g_hash_table_contains (mount_paths, mount_path))
{
- /* match. no change. */
- g_unix_mount_free (new->data);
+ g_debug ("trash_watcher_remount_do: remove %s %s %s\n",
+ g_unix_mount_get_device_path (mount->mount_entry),
+ g_unix_mount_get_mount_path (mount->mount_entry),
+ g_unix_mount_get_fs_type (mount->mount_entry));
- old = &(*old)->next;
- new = new->next;
+ trash_mount_free (mount);
+ g_hash_table_iter_remove (&iter);
}
}
- g_list_free (mounts);
+ g_hash_table_destroy (mount_paths);
}
static gboolean
@@ -345,7 +334,7 @@ trash_watcher_new (TrashRoot *root)
watcher = g_slice_new (TrashWatcher);
watcher->root = root;
- watcher->mounts = NULL;
+ watcher->mounts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
watcher->watching = FALSE;
watcher->update_id = 0;
watcher->mount_monitor = g_unix_mount_monitor_get ();
@@ -385,19 +374,24 @@ trash_watcher_free (TrashWatcher *watcher)
void
trash_watcher_watch (TrashWatcher *watcher)
{
- TrashMount *mount;
+ GHashTableIter iter;
+ gpointer value;
g_assert (!watcher->watching);
if (watcher->homedir_type != TRASH_WATCHER_NO_WATCH)
trash_dir_watch (watcher->homedir_trashdir);
- for (mount = watcher->mounts; mount; mount = mount->next)
- if (mount->type != TRASH_WATCHER_NO_WATCH)
- {
- trash_dir_watch (mount->dirs[0]);
- trash_dir_watch (mount->dirs[1]);
- }
+ g_hash_table_iter_init (&iter, watcher->mounts);
+ while (g_hash_table_iter_next (&iter, NULL, &value))
+ {
+ TrashMount *mount = value;
+ if (mount->type != TRASH_WATCHER_NO_WATCH)
+ {
+ trash_dir_watch (mount->dirs[0]);
+ trash_dir_watch (mount->dirs[1]);
+ }
+ }
watcher->watching = TRUE;
}
@@ -405,19 +399,24 @@ trash_watcher_watch (TrashWatcher *watcher)
void
trash_watcher_unwatch (TrashWatcher *watcher)
{
- TrashMount *mount;
+ GHashTableIter iter;
+ gpointer value;
g_assert (watcher->watching);
if (watcher->homedir_type != TRASH_WATCHER_NO_WATCH)
trash_dir_unwatch (watcher->homedir_trashdir);
- for (mount = watcher->mounts; mount; mount = mount->next)
- if (mount->type != TRASH_WATCHER_NO_WATCH)
- {
- trash_dir_unwatch (mount->dirs[0]);
- trash_dir_unwatch (mount->dirs[1]);
- }
+ g_hash_table_iter_init (&iter, watcher->mounts);
+ while (g_hash_table_iter_next (&iter, NULL, &value))
+ {
+ TrashMount *mount = value;
+ if (mount->type != TRASH_WATCHER_NO_WATCH)
+ {
+ trash_dir_unwatch (mount->dirs[0]);
+ trash_dir_unwatch (mount->dirs[1]);
+ }
+ }
watcher->watching = FALSE;
}
@@ -425,7 +424,8 @@ trash_watcher_unwatch (TrashWatcher *watcher)
void
trash_watcher_rescan (TrashWatcher *watcher)
{
- TrashMount *mount;
+ GHashTableIter iter;
+ gpointer value;
if (watcher->update_id != 0)
{
@@ -436,10 +436,14 @@ trash_watcher_rescan (TrashWatcher *watcher)
if (!watcher->watching || watcher->homedir_type != TRASH_WATCHER_TRUSTED)
trash_dir_rescan (watcher->homedir_trashdir);
- for (mount = watcher->mounts; mount; mount = mount->next)
- if (!watcher->watching || mount->type != TRASH_WATCHER_TRUSTED)
- {
- trash_dir_rescan (mount->dirs[0]);
- trash_dir_rescan (mount->dirs[1]);
- }
+ g_hash_table_iter_init (&iter, watcher->mounts);
+ while (g_hash_table_iter_next (&iter, NULL, &value))
+ {
+ TrashMount *mount = value;
+ if (!watcher->watching || mount->type != TRASH_WATCHER_TRUSTED)
+ {
+ trash_dir_rescan (mount->dirs[0]);
+ trash_dir_rescan (mount->dirs[1]);
+ }
+ }
}
--
2.54.0

View File

@ -1,221 +0,0 @@
From 97d9831042ca1c5c13fdb6cd9bfb2e2fe77f94f8 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 3 Jun 2026 08:45:00 +0200
Subject: [PATCH] trash: Use GHashTable for trash directory items
Backport of commit 665ff6b8.
Adjusted context for target version.
---
daemon/trashlib/trashdir.c | 122 +++++++++++++++----------------------
1 file changed, 48 insertions(+), 74 deletions(-)
diff --git a/daemon/trashlib/trashdir.c b/daemon/trashlib/trashdir.c
index 23aa0d7..610f2c3 100644
--- a/daemon/trashlib/trashdir.c
+++ b/daemon/trashlib/trashdir.c
@@ -16,7 +16,7 @@
struct OPAQUE_TYPE__TrashDir
{
TrashRoot *root;
- GSList *items;
+ GHashTable *items; /* basename -> GFile */
GFile *directory;
GFile *topdir;
@@ -27,28 +27,6 @@ struct OPAQUE_TYPE__TrashDir
GFileMonitor *monitor;
};
-static gint
-compare_basename (gconstpointer a,
- gconstpointer b)
-{
- GFile *file_a, *file_b;
- char *name_a, *name_b;
- gint result;
-
- file_a = (GFile *) a;
- file_b = (GFile *) b;
-
- name_a = g_file_get_basename (file_a);
- name_b = g_file_get_basename (file_b);
-
- result = strcmp (name_a, name_b);
-
- g_free (name_a);
- g_free (name_b);
-
- return result;
-}
-
static void
trash_dir_query_mtime (TrashDir *dir, GTimeVal *mtime)
{
@@ -70,47 +48,36 @@ trash_dir_query_mtime (TrashDir *dir, GTimeVal *mtime)
}
static void
-trash_dir_set_files (TrashDir *dir,
- GSList *items)
+trash_dir_set_files (TrashDir *dir,
+ GHashTable *items)
{
- GSList **old, *new;
-
- items = g_slist_sort (items, (GCompareFunc) compare_basename);
- old = &dir->items;
- new = items;
+ GHashTableIter iter;
+ gpointer key, value;
- while (new || *old)
+ g_hash_table_iter_init (&iter, dir->items);
+ while (g_hash_table_iter_next (&iter, &key, &value))
{
- int result;
-
- if ((result = (new == NULL) - (*old == NULL)) == 0)
- result = compare_basename (new->data, (*old)->data);
-
- if (result < 0)
- {
- /* new entry. add it. */
- *old = g_slist_prepend (*old, new->data); /* take reference */
- old = &(*old)->next;
- trash_root_add_item (dir->root, new->data, dir->topdir, dir->is_homedir);
- new = new->next;
- }
- else if (result > 0)
+ if (!g_hash_table_contains (items, key))
{
/* old entry. remove it. */
- trash_root_remove_item (dir->root, (*old)->data, dir->is_homedir);
- g_object_unref ((*old)->data);
- *old = g_slist_delete_link (*old, *old);
+ trash_root_remove_item (dir->root, value, dir->is_homedir);
+ g_hash_table_iter_remove (&iter);
}
- else
+ }
+
+ g_hash_table_iter_init (&iter, items);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ if (!g_hash_table_contains (dir->items, key))
{
- /* match. no change. */
- old = &(*old)->next;
- g_object_unref (new->data);
- new = new->next;
+ /* new entry. add it. */
+ g_hash_table_iter_steal (&iter);
+ g_hash_table_insert (dir->items, key, value);
+ trash_root_add_item (dir->root, value, dir->topdir, dir->is_homedir);
}
}
- g_slist_free (items);
+ g_hash_table_unref (items);
trash_root_thaw (dir->root);
}
@@ -118,16 +85,23 @@ trash_dir_set_files (TrashDir *dir,
static void
trash_dir_empty (TrashDir *dir)
{
- trash_dir_set_files (dir, NULL);
+ GHashTable *empty;
+
+ empty = g_hash_table_new (g_str_hash, g_str_equal);
+ trash_dir_set_files (dir, empty);
}
static void
trash_dir_enumerate (TrashDir *dir)
{
GFileEnumerator *enumerator;
- GSList *files = NULL;
+ GHashTable *files = NULL;
trash_dir_query_mtime (dir, &dir->mtime);
+
+ files = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_object_unref);
+
enumerator = g_file_enumerate_children (dir->directory,
G_FILE_ATTRIBUTE_STANDARD_NAME,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
@@ -140,10 +113,11 @@ trash_dir_enumerate (TrashDir *dir)
while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)))
{
GFile *file;
+ const gchar *name;
- file = g_file_get_child (dir->directory,
- g_file_info_get_name (info));
- files = g_slist_prepend (files, file);
+ name = g_file_info_get_name (info);
+ file = g_file_get_child (dir->directory, name);
+ g_hash_table_insert (files, g_strdup (name), file);
g_object_unref (info);
}
@@ -165,24 +139,20 @@ trash_dir_changed (GFileMonitor *monitor,
if (event_type == G_FILE_MONITOR_EVENT_CREATED)
{
- dir->items = g_slist_insert_sorted (dir->items,
- g_object_ref (file),
- (GCompareFunc) compare_basename);
- trash_root_add_item (dir->root, file, dir->topdir, dir->is_homedir);
+ g_autofree gchar *name = g_file_get_basename (file);
+
+ if (!g_hash_table_contains (dir->items, name))
+ {
+ g_hash_table_insert (dir->items, g_steal_pointer (&name), g_object_ref (file));
+ trash_root_add_item (dir->root, file, dir->topdir, dir->is_homedir);
+ }
}
else if (event_type == G_FILE_MONITOR_EVENT_DELETED)
{
- GSList *node;
+ g_autofree char *name = g_file_get_basename (file);
- node = g_slist_find_custom (dir->items,
- file,
- (GCompareFunc) compare_basename);
- if (node)
- {
- g_object_unref (node->data);
- dir->items = g_slist_delete_link (dir->items, node);
- }
+ g_hash_table_remove (dir->items, name);
trash_root_remove_item (dir->root, file, dir->is_homedir);
}
@@ -386,7 +356,8 @@ trash_dir_new (TrashRoot *root,
dir = g_slice_new (TrashDir);
dir->root = root;
- dir->items = NULL;
+ dir->items = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_object_unref);
dir->topdir = g_file_new_for_path (mount_point);
dir->directory = g_file_get_child (dir->topdir, rel);
dir->monitor = NULL;
@@ -416,7 +387,9 @@ trash_dir_free (TrashDir *dir)
if (dir->monitor)
g_object_unref (dir->monitor);
- trash_dir_set_files (dir, NULL);
+ trash_dir_empty (dir);
+
+ g_hash_table_unref (dir->items);
g_object_unref (dir->directory);
g_object_unref (dir->topdir);
--
2.53.0

View File

@ -1,223 +0,0 @@
From b15490d80dc8044dd546c8f5fba171bacb92c49c Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Tue, 2 Jun 2026 15:54:17 +0200
Subject: [PATCH] trash: Use weak refs for monitor lifecycle
Backport of commit 1080ca11.
Adjusted context for target version.
---
daemon/gvfsbackendtrash.c | 119 ++++++++++++++++++++++-----------
daemon/trashlib/trashwatcher.c | 6 +-
2 files changed, 84 insertions(+), 41 deletions(-)
diff --git a/daemon/gvfsbackendtrash.c b/daemon/gvfsbackendtrash.c
index 1dcb44f..6d0af56 100644
--- a/daemon/gvfsbackendtrash.c
+++ b/daemon/gvfsbackendtrash.c
@@ -33,8 +33,8 @@ struct OPAQUE_TYPE__GVfsBackendTrash
{
GVfsBackend parent_instance;
- GVfsMonitor *file_monitor;
- GVfsMonitor *dir_monitor;
+ GWeakRef file_monitor;
+ GWeakRef dir_monitor;
GMainContext *worker_context;
GMainLoop *worker_loop;
@@ -111,15 +111,32 @@ trash_backend_worker_thread_queue (GVfsBackendTrash *backend,
}
static gboolean
-watch_func (gpointer user_data)
+sync_watch_state_func (gpointer user_data)
{
GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (user_data);
+ GVfsMonitor *file_monitor;
+ GVfsMonitor *dir_monitor;
- trash_watcher_watch (backend->watcher);
+ file_monitor = g_weak_ref_get (&backend->file_monitor);
+ dir_monitor = g_weak_ref_get (&backend->dir_monitor);
+
+ if (file_monitor != NULL || dir_monitor != NULL)
+ trash_watcher_watch (backend->watcher);
+ else
+ trash_watcher_unwatch (backend->watcher);
+
+ g_clear_object (&file_monitor);
+ g_clear_object (&dir_monitor);
return G_SOURCE_REMOVE;
}
+static void
+trash_backend_queue_watch_state_sync (GVfsBackendTrash *backend)
+{
+ trash_backend_worker_thread_queue (backend, sync_watch_state_func);
+}
+
static gboolean
rescan_func (gpointer user_data)
{
@@ -142,46 +159,62 @@ is_root (const char *filename)
return (filename[0] == '/' && filename[1] == '\0');
}
+static void
+trash_backend_file_monitor_destroyed (gpointer data,
+ GObject *where_the_object_was)
+{
+ GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (data);
+
+ trash_backend_queue_watch_state_sync (backend);
+}
+
+static void
+trash_backend_dir_monitor_destroyed (gpointer data,
+ GObject *where_the_object_was)
+{
+ GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (data);
+
+ trash_backend_queue_watch_state_sync (backend);
+}
+
static GVfsMonitor *
trash_backend_get_file_monitor (GVfsBackendTrash *backend,
gboolean create)
{
- if (backend->file_monitor == NULL && create == FALSE)
- return NULL;
+ GVfsMonitor *monitor;
- else if (backend->file_monitor == NULL)
- {
- /* 'create' is only ever set in the main thread, so we will have
- * no possibility here for creating more than one new monitor.
- */
- if (backend->dir_monitor == NULL)
- trash_backend_worker_thread_queue (backend, watch_func);
+ monitor = g_weak_ref_get (&backend->file_monitor);
+ if (monitor != NULL || create == FALSE)
+ return monitor;
- backend->file_monitor = g_vfs_monitor_new (G_VFS_BACKEND (backend));
- }
+ monitor = g_vfs_monitor_new (G_VFS_BACKEND (backend));
+ g_weak_ref_set (&backend->file_monitor, monitor);
+ g_object_weak_ref (G_OBJECT (monitor),
+ trash_backend_file_monitor_destroyed, backend);
+
+ trash_backend_queue_watch_state_sync (backend);
- return g_object_ref (backend->file_monitor);
+ return monitor;
}
static GVfsMonitor *
trash_backend_get_dir_monitor (GVfsBackendTrash *backend,
gboolean create)
{
- if (backend->dir_monitor == NULL && create == FALSE)
- return NULL;
+ GVfsMonitor *monitor;
- else if (backend->dir_monitor == NULL)
- {
- /* 'create' is only ever set in the main thread, so we will have
- * no possibility here for creating more than one new monitor.
- */
- if (backend->file_monitor == NULL)
- trash_backend_worker_thread_queue (backend, watch_func);
+ monitor = g_weak_ref_get (&backend->dir_monitor);
+ if (monitor != NULL || create == FALSE)
+ return monitor;
- backend->dir_monitor = g_vfs_monitor_new (G_VFS_BACKEND (backend));
- }
+ monitor = g_vfs_monitor_new (G_VFS_BACKEND (backend));
+ g_weak_ref_set (&backend->dir_monitor, monitor);
+ g_object_weak_ref (G_OBJECT (monitor),
+ trash_backend_dir_monitor_destroyed, backend);
+
+ trash_backend_queue_watch_state_sync (backend);
- return g_object_ref (backend->dir_monitor);
+ return monitor;
}
static void
@@ -802,8 +835,8 @@ trash_backend_mount (GVfsBackend *vfs_backend,
{
GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (vfs_backend);
- backend->file_monitor = NULL;
- backend->dir_monitor = NULL;
+ g_weak_ref_init (&backend->file_monitor, NULL);
+ g_weak_ref_init (&backend->dir_monitor, NULL);
backend->worker_context = g_main_context_new ();
backend->worker_thread = g_thread_new ("Trash Worker Thread",
@@ -976,17 +1009,25 @@ static void
trash_backend_finalize (GObject *object)
{
GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (object);
+ GVfsMonitor *monitor;
- /* get rid of these first to stop a flood of event notifications
- * from being emitted while we're tearing down the TrashWatcher
- */
- if (backend->file_monitor)
- g_object_unref (backend->file_monitor);
- backend->file_monitor = NULL;
+ monitor = g_weak_ref_get (&backend->file_monitor);
+ if (monitor != NULL)
+ {
+ g_object_weak_unref (G_OBJECT (monitor),
+ trash_backend_file_monitor_destroyed, backend);
+ g_object_unref (monitor);
+ }
+ g_weak_ref_clear (&backend->file_monitor);
- if (backend->dir_monitor)
- g_object_unref (backend->dir_monitor);
- backend->dir_monitor = NULL;
+ monitor = g_weak_ref_get (&backend->dir_monitor);
+ if (monitor != NULL)
+ {
+ g_object_weak_unref (G_OBJECT (monitor),
+ trash_backend_dir_monitor_destroyed, backend);
+ g_object_unref (monitor);
+ }
+ g_weak_ref_clear (&backend->dir_monitor);
G_OBJECT_CLASS (g_vfs_backend_trash_parent_class)->finalize (object);
}
diff --git a/daemon/trashlib/trashwatcher.c b/daemon/trashlib/trashwatcher.c
index 1888bed..bd658e1 100644
--- a/daemon/trashlib/trashwatcher.c
+++ b/daemon/trashlib/trashwatcher.c
@@ -378,7 +378,8 @@ trash_watcher_watch (TrashWatcher *watcher)
GHashTableIter iter;
gpointer value;
- g_assert (!watcher->watching);
+ if (watcher->watching)
+ return;
if (watcher->homedir_type != TRASH_WATCHER_NO_WATCH)
trash_dir_watch (watcher->homedir_trashdir);
@@ -403,7 +404,8 @@ trash_watcher_unwatch (TrashWatcher *watcher)
GHashTableIter iter;
gpointer value;
- g_assert (watcher->watching);
+ if (!watcher->watching)
+ return;
if (watcher->homedir_type != TRASH_WATCHER_NO_WATCH)
trash_dir_unwatch (watcher->homedir_trashdir);
--
2.53.0

View File

@ -1,109 +0,0 @@
From 14dc69defb82a789999ba43e5350438d9c7086a6 Mon Sep 17 00:00:00 2001
Date: Mon, 11 Mar 2024 10:20:51 +0100
Subject: [PATCH] udisks2: Do not schedule update if pending already
Currently, the udisks2 volume monitor updates everything for each
`/proc/mounts`, `/etc/fstab`, and udisks2 change. The update takes some
time. If too many changes happen in a short timeframe, the udisks2
volume monitor is not able to handle those events in a real-time. The
pending events can be processed for a long time. Many of those updates
are redundant though as the real changes were already reflected during
the previous updates. This causes a high CPU load among others. Let's
add small timeout that will allow to skip accumullated events.
Fixes: https://gitlab.gnome.org/GNOME/gvfs/-/issues/713
---
monitor/udisks2/gvfsudisks2volumemonitor.c | 35 +++++++++++++++++++---
1 file changed, 31 insertions(+), 4 deletions(-)
diff --git a/monitor/udisks2/gvfsudisks2volumemonitor.c b/monitor/udisks2/gvfsudisks2volumemonitor.c
index c8864aea8..540683b22 100644
--- a/monitor/udisks2/gvfsudisks2volumemonitor.c
+++ b/monitor/udisks2/gvfsudisks2volumemonitor.c
@@ -68,8 +68,12 @@ struct _GVfsUDisks2VolumeMonitor
GSettings *lockdown_settings;
gboolean readonly_lockdown;
+
+ gint update_id;
};
+#define UPDATE_TIMEOUT 100 /* ms */
+
static UDisksClient *get_udisks_client_sync (GError **error);
static void update_all (GVfsUDisks2VolumeMonitor *monitor,
@@ -148,6 +152,8 @@ gvfs_udisks2_volume_monitor_finalize (GObject *object)
g_clear_object (&monitor->lockdown_settings);
+ g_clear_handle_id (&monitor->update_id, g_source_remove);
+
G_OBJECT_CLASS (gvfs_udisks2_volume_monitor_parent_class)->finalize (object);
}
@@ -425,12 +431,33 @@ gvfs_udisks2_volume_monitor_get_readonly_lockdown (GVfsUDisks2VolumeMonitor *mon
/* ---------------------------------------------------------------------------------------------------- */
+static gboolean
+update_func (gpointer user_data)
+{
+ GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (user_data);
+
+ monitor->update_id = 0;
+
+ update_all (monitor, TRUE, FALSE);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+schedule_update (GVfsUDisks2VolumeMonitor *monitor)
+{
+ if (monitor->update_id != 0)
+ return;
+
+ monitor->update_id = g_timeout_add (UPDATE_TIMEOUT, update_func, monitor);
+}
+
void
gvfs_udisks2_volume_monitor_update (GVfsUDisks2VolumeMonitor *monitor)
{
g_return_if_fail (GVFS_IS_UDISKS2_VOLUME_MONITOR (monitor));
udisks_client_settle (monitor->client);
- update_all (monitor, TRUE, FALSE);
+ schedule_update (monitor);
}
/* ---------------------------------------------------------------------------------------------------- */
@@ -532,7 +559,7 @@ on_client_changed (UDisksClient *client,
gpointer user_data)
{
GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (user_data);
- update_all (monitor, TRUE, FALSE);
+ schedule_update (monitor);
}
static void
@@ -540,7 +567,7 @@ mountpoints_changed (GUnixMountMonitor *mount_monitor,
gpointer user_data)
{
GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (user_data);
- update_all (monitor, TRUE, FALSE);
+ schedule_update (monitor);
}
static void
@@ -548,7 +575,7 @@ mounts_changed (GUnixMountMonitor *mount_monitor,
gpointer user_data)
{
GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (user_data);
- update_all (monitor, TRUE, FALSE);
+ schedule_update (monitor);
}
/* ---------------------------------------------------------------------------------------------------- */
--
GitLab

View File

@ -1,39 +0,0 @@
From 45a5612574a54bf4648cedafa5b977efb48293c9 Mon Sep 17 00:00:00 2001
Date: Thu, 12 Sep 2024 13:27:04 +0200
Subject: [PATCH] udisks2: Run update synchronously for internal changes
The commit 14dc69de introduced performance improvement by skipping
accumulated mount, mount point and udisks2 client changes. That was
achieved by running the update with a small delay. But this logic was
mistakenly used for the `gvfs_udisks2_volume_monitor_update` function
also. This function expects the update to happen synchronously. This
leads to various issues e.g. `g_volume_get_mount` fails when called
immediately after `g_volume_mount`. Let's run the update synchronously
from the `gvfs_udisks2_volume_monitor_update` function to fix the
mentioned issues.
Fixes: https://gitlab.gnome.org/GNOME/gvfs/-/issues/762
---
monitor/udisks2/gvfsudisks2volumemonitor.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/monitor/udisks2/gvfsudisks2volumemonitor.c b/monitor/udisks2/gvfsudisks2volumemonitor.c
index 3a2015b29..f78f28d40 100644
--- a/monitor/udisks2/gvfsudisks2volumemonitor.c
+++ b/monitor/udisks2/gvfsudisks2volumemonitor.c
@@ -457,7 +457,11 @@ gvfs_udisks2_volume_monitor_update (GVfsUDisks2VolumeMonitor *monitor)
{
g_return_if_fail (GVFS_IS_UDISKS2_VOLUME_MONITOR (monitor));
udisks_client_settle (monitor->client);
- schedule_update (monitor);
+
+ if (monitor->update_id != 0)
+ g_source_remove (monitor->update_id);
+
+ update_func (monitor);
}
/* ---------------------------------------------------------------------------------------------------- */
--
GitLab

File diff suppressed because it is too large Load Diff

View File

@ -1,89 +0,0 @@
Adapted https://gitlab.gnome.org/GNOME/gvfs/-/merge_requests/290
diff --git a/monitor/udisks2/gvfsudisks2volumemonitor.c b/monitor/udisks2/gvfsudisks2volumemonitor.c
index 55feb07..f78f364 100644
--- a/monitor/udisks2/gvfsudisks2volumemonitor.c
+++ b/monitor/udisks2/gvfsudisks2volumemonitor.c
@@ -92,6 +92,7 @@ static void update_volumes (GVfsUDisks2VolumeMonitor *monitor,
GList **removed_volumes,
gboolean coldplug);
static void update_fstab_volumes (GVfsUDisks2VolumeMonitor *monitor,
+ GHashTable *mount_points_by_path, /* gchar *path ~> GUnixMountPoint * */
GList **added_volumes,
GList **removed_volumes,
gboolean coldplug);
@@ -749,7 +750,7 @@ update_all (GVfsUDisks2VolumeMonitor *monitor,
update_drives (monitor, &added_drives, &removed_drives, coldplug);
update_volumes (monitor, mount_entries, mount_points_by_path, &added_volumes, &removed_volumes, coldplug);
- update_fstab_volumes (monitor, &added_volumes, &removed_volumes, coldplug);
+ update_fstab_volumes (monitor, mount_points_by_path, &added_volumes, &removed_volumes, coldplug);
update_mounts (monitor, mount_entries, mount_points_by_path, &added_mounts, &removed_mounts, coldplug);
update_discs (monitor,
&added_volumes, &removed_volumes,
@@ -1619,16 +1620,9 @@ mount_point_has_device (GVfsUDisks2VolumeMonitor *monitor,
return ret;
}
-static void
-free_nonnull_unix_mount_point (gpointer ptr)
-{
- GUnixMountPoint *mount_point = ptr;
- if (mount_point != NULL)
- g_unix_mount_point_free (mount_point);
-}
-
static void
update_fstab_volumes (GVfsUDisks2VolumeMonitor *monitor,
+ GHashTable *mount_points_by_path, /* gchar *path ~> GUnixMountPoint * */
GList **added_volumes,
GList **removed_volumes,
gboolean coldplug)
@@ -1636,7 +1630,6 @@ update_fstab_volumes (GVfsUDisks2VolumeMonitor *monitor,
GHashTable *cur_mount_points; /* GUnixMountPoint * ~> GVfsUDisks2Volume * */
GHashTableIter iter;
gpointer key = NULL, value = NULL;
- GList *new_mount_points, *l;
GVfsUDisks2Volume *volume;
cur_mount_points = g_hash_table_new_full (gvfs_mount_point_hash, gvfs_mount_point_equal, NULL, g_object_unref);
@@ -1651,10 +1644,10 @@ update_fstab_volumes (GVfsUDisks2VolumeMonitor *monitor,
g_hash_table_insert (cur_mount_points, mount_point, g_object_ref (volume));
}
- new_mount_points = g_unix_mount_points_get (NULL);
- for (l = new_mount_points; l != NULL; l = g_list_next (l))
+ g_hash_table_iter_init (&iter, mount_points_by_path);
+ while (g_hash_table_iter_next (&iter, NULL, &value))
{
- GUnixMountPoint *mount_point = l->data;
+ GUnixMountPoint *mount_point = value;
/* use the mount points that we want to include */
if (should_include_mount_point (monitor, mount_point) &&
@@ -1666,7 +1659,7 @@ update_fstab_volumes (GVfsUDisks2VolumeMonitor *monitor,
{
volume = gvfs_udisks2_volume_new (monitor,
NULL, /* block */
- mount_point,
+ g_unix_mount_point_copy (mount_point), /* adopts the mount_point */
NULL, /* drive */
NULL, /* activation_root */
coldplug);
@@ -1683,7 +1676,6 @@ update_fstab_volumes (GVfsUDisks2VolumeMonitor *monitor,
g_hash_table_add (monitor->fstab_volumes, g_object_ref (volume));
*added_volumes = g_list_prepend (*added_volumes, g_steal_pointer (&volume));
- l->data = NULL;
}
}
}
@@ -1699,8 +1691,6 @@ update_fstab_volumes (GVfsUDisks2VolumeMonitor *monitor,
g_hash_table_remove (monitor->fstab_volumes, volume);
}
- g_list_free_full (new_mount_points, free_nonnull_unix_mount_point);
-
g_hash_table_unref (cur_mount_points);
}

View File

@ -1,37 +0,0 @@
From 3e3691a59b69aeafac4288e0599fca3eb4cb02f3 Mon Sep 17 00:00:00 2001
Date: Tue, 3 Feb 2026 19:15:32 +0100
Subject: [PATCH] udisks2: Fix memory corruption with duplicate mount paths
Calling g_hash_table_insert on a key that already exists in the table frees
the old value and the *new* key, thus leaving the old key pointing to free'd
memory. g_hash_table_replace instead frees the old value and key together
and inserts the new value and key into the table.
---
monitor/udisks2/gvfsudisks2volumemonitor.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/monitor/udisks2/gvfsudisks2volumemonitor.c b/monitor/udisks2/gvfsudisks2volumemonitor.c
index c57249e5..aa1ca7a3 100644
--- a/monitor/udisks2/gvfsudisks2volumemonitor.c
+++ b/monitor/udisks2/gvfsudisks2volumemonitor.c
@@ -730,7 +730,7 @@ update_all (GVfsUDisks2VolumeMonitor *monitor,
for (link = entries; link != NULL; link = g_list_next (link))
{
GUnixMountEntry *mount_entry = link->data;
- g_hash_table_insert (mount_entries, (gpointer) g_unix_mount_get_mount_path (mount_entry), mount_entry);
+ g_hash_table_replace (mount_entries, (gpointer) g_unix_mount_get_mount_path (mount_entry), mount_entry);
}
/* the mount_entries took ownership of the mount entry objects */
g_list_free (entries);
@@ -742,7 +742,7 @@ update_all (GVfsUDisks2VolumeMonitor *monitor,
for (link = points; link != NULL; link = g_list_next (link))
{
GUnixMountPoint *mount_point = link->data;
- g_hash_table_insert (mount_points_by_path, (gpointer) g_unix_mount_point_get_mount_path (mount_point), mount_point);
+ g_hash_table_replace (mount_points_by_path, (gpointer) g_unix_mount_point_get_mount_path (mount_point), mount_point);
}
/* the mount_points_by_path took ownership of the mount point objects */
g_list_free (points);
--
GitLab

View File

@ -25,7 +25,7 @@
Name: gvfs
Version: 1.36.2
Release: 21%{?dist}
Release: 16%{?dist}
Summary: Backends for the gio framework in GLib
License: GPLv3 and LGPLv2+ and BSD and MPLv2.0
@ -80,48 +80,6 @@ Patch15: google-performance-fixes.patch
Patch16: trash-Add-support-for-x-gvfs-notrash-option-to-ignor.patch
Patch17: trash-Sync-trash-dir-items-when-files-change.patch
# https://issues.redhat.com/browse/RHEL-52342
Patch18: trash-Add-support-for-x-gvfs-trash-mount-option.patch
# https://issues.redhat.com/browse/RHEL-45163
Patch19: daemon-Add-support-for-edit-mode.patch
Patch20: gdaemonfile-Use-edit-mode-when-private-edit-flag-is-.patch
Patch21: fuse-Use-edit-mode-instead-of-returning-ENOTSUP.patch
Patch22: smb-Fail-when-initial_offset-can-t-be-determined.patch
Patch23: smb-Disable-seek-support-when-appening.patch
Patch24: smb-Fix-offset-after-truncate-when-appending.patch
Patch25: smb-Implement-support-for-edit-mode.patch
# https://issues.redhat.com/browse/RHEL-76484
Patch26: udisks2-monitor-performance-202.patch
Patch27: udisks2-monitor-performance-230.patch
Patch28: udisks2-monitor-performance-273.patch
Patch29: udisks2-monitor-performance-290.patch
Patch30: udisks2-monitor-performance-297.patch
# Improve trash backend performance
# https://gitlab.gnome.org/GNOME/gvfs/-/merge_requests/287
# https://gitlab.gnome.org/GNOME/gvfs/-/merge_requests/175
# https://gitlab.gnome.org/GNOME/gvfs/-/merge_requests/169
# https://gitlab.gnome.org/GNOME/gvfs/-/merge_requests/11
Patch31: backend-Prevent-usage-of-NULL.patch
Patch32: trash-Add-is_root-function.patch
Patch33: trash-Remove-unused-ui_hook-property.patch
Patch34: trash-Remove-unused-is_homedir-property.patch
Patch35: trash-Do-not-create-monitors-for-non-root-items.patch
Patch36: trash-Run-blocking-methods-on-a-thread-pool.patch
Patch37: trash-Add-worker-thread.patch
Patch38: trash-Chain-up-finalize.patch
Patch39: trash-Rate-limit-mount-updates.patch
Patch40: trash-Add-debug-prints-for-mounts-handling.patch
Patch41: trash-Use-GHashTable-for-mount-tracking.patch
Patch42: trash-Use-GHashTable-for-trash-directory-items.patch
Patch43: trash-Rate-limit-size-change-notifications.patch
Patch44: trash-Use-weak-refs-for-monitor-lifecycle.patch
Patch45: trash-Defer-mount-monitoring-to-active-watchers-only.patch
Patch46: daemon-Add-process-name-to-debug-handler-log.patch
Patch47: trash-Skip-mount-table-reparsing-when-unchanged.patch
BuildRequires: pkgconfig
BuildRequires: pkgconfig(glib-2.0) >= %{glib2_version}
BuildRequires: pkgconfig(dbus-glib-1)
@ -512,22 +470,6 @@ killall -USR1 gvfsd >&/dev/null || :
%{_datadir}/installed-tests
%changelog
* Tue Jun 02 2026 Ondrej Holy <oholy@redhat.com> - 1.36.2-21
- Improve trash backend performance
Resolves: RHEL-127445
* Fri Feb 06 2026 Milan Crha <mcrha@redhat.com> - 1.36.2-20
- udisks2: Correct add to hash table for items which can clash in the monitor (RHEL-76484)
* Wed Jan 21 2026 Milan Crha <mcrha@redhat.com> - 1.36.2-19
- udisks2: Use hash table for quicker lookups in the monitor (RHEL-76484)
* Thu Feb 13 2025 Ondrej Holy <oholy@redhat.com> - 1.36.2-18
- Add edit mode support for smb backend (RHEL-45163)
* Thu Sep 26 2024 Ondrej Holy <oholy@redhat.com> - 1.36.2-17
- Add support for x-gvfs-trash mount option (RHEL-52342)
* Wed Dec 06 2023 Ondrej Holy <oholy@redhat.com> - 1.36.2-16
- Sync trash dir items when files change (RHEL-2824)