diff options
author | Ondrej Holy <oholy@redhat.com> | 2018-03-15 11:26:29 +0100 |
---|---|---|
committer | Ondrej Holy <oholy@redhat.com> | 2018-03-15 15:02:04 +0100 |
commit | 7c27d2b78f27455ee33012e6cbf49af9a98a20e6 (patch) | |
tree | 27ef676eda9410cbf2a3739535c4af1ba76c7474 | |
parent | 22e16dcd0cfd07e36439a946b4520a5825fb744e (diff) | |
download | gvfs-7c27d2b78f27455ee33012e6cbf49af9a98a20e6.tar.gz |
backend: Fix crashes when "Volume is busy" prompt is shown
Backend crashes in on_show_processes_reply callback if
g_vfs_backend_unmount_with_operation async call has been completed
over on_update_processes_timeout in the meantime and releases GTask
data (i.e. "Volume is busy" prompt is being shown and blocking
operations have been finished).
This patch simplify the handling. With this patch, the async call
is completed only from one place, on_show_processes_reply. If there
are no more processes, g_mount_source_abort is called from
on_update_processes_timeout only and the reply is handled by
on_show_processes_reply consequently. This prevents the crashes.
Just a note that client side ensures that on_show_processes_reply is
called only once.
https://bugzilla.gnome.org/show_bug.cgi?id=794113
-rw-r--r-- | daemon/gvfsbackend.c | 53 |
1 files changed, 18 insertions, 35 deletions
diff --git a/daemon/gvfsbackend.c b/daemon/gvfsbackend.c index b9096033..a622f6e3 100644 --- a/daemon/gvfsbackend.c +++ b/daemon/gvfsbackend.c @@ -832,32 +832,35 @@ typedef struct { GMountSource *mount_source; - gboolean ret; - gboolean aborted; - gint choice; - const gchar *message; const gchar *choices[3]; - gboolean completed; + gboolean no_more_processes; guint timeout_id; } UnmountWithOpData; static void -complete_unmount_with_op (GTask *task, gboolean no_more_processes) +on_show_processes_reply (GMountSource *mount_source, + GAsyncResult *res, + gpointer user_data) { + GTask *task = G_TASK (user_data); UnmountWithOpData *data = g_task_get_task_data (task); + gboolean ret, aborted; + gint choice; - g_source_remove (data->timeout_id); + if (data->timeout_id != 0) + g_source_remove (data->timeout_id); - if (!no_more_processes && !data->ret) + ret = g_mount_source_show_processes_finish (mount_source, res, &aborted, &choice); + if (!data->no_more_processes && !ret) { /* If the "show-processes" signal wasn't handled */ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_BUSY, _("File system is busy")); } - else if (!no_more_processes && (data->aborted || data->choice == 1)) + else if (!data->no_more_processes && (aborted || choice == 1)) { g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED_HANDLED, "GMountOperation aborted"); @@ -867,30 +870,9 @@ complete_unmount_with_op (GTask *task, gboolean no_more_processes) g_task_return_boolean (task, TRUE); } - data->completed = TRUE; g_object_unref (task); } -static void -on_show_processes_reply (GMountSource *mount_source, - GAsyncResult *res, - gpointer user_data) -{ - GTask *task = G_TASK (user_data); - UnmountWithOpData *data = g_task_get_task_data (task); - - /* Do nothing if we've handled this already */ - if (data->completed) - return; - - data->ret = g_mount_source_show_processes_finish (mount_source, - res, - &data->aborted, - &data->choice); - - complete_unmount_with_op (task, FALSE); -} - static gboolean on_update_processes_timeout (gpointer user_data) { @@ -902,9 +884,11 @@ on_update_processes_timeout (gpointer user_data) if (!g_vfs_daemon_has_blocking_processes (daemon)) { - /* no more processes, abort mount op */ g_mount_source_abort (data->mount_source); - complete_unmount_with_op (task, TRUE); + data->timeout_id = 0; + data->no_more_processes = TRUE; + + return G_SOURCE_REMOVE; } else { @@ -916,10 +900,9 @@ on_update_processes_timeout (gpointer user_data) (GAsyncReadyCallback) on_show_processes_reply, task); g_array_unref (processes); - } - /* keep timeout around */ - return TRUE; + return G_SOURCE_CONTINUE; + } } static void |