[gvfs] backend: Fix crashes when "Volume is busy" prompt is shown



commit 7c27d2b78f27455ee33012e6cbf49af9a98a20e6
Author: Ondrej Holy <oholy redhat com>
Date:   Thu Mar 15 11:26:29 2018 +0100

    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

 daemon/gvfsbackend.c |   53 +++++++++++++++++---------------------------------
 1 files changed, 18 insertions(+), 35 deletions(-)
---
diff --git a/daemon/gvfsbackend.c b/daemon/gvfsbackend.c
index b909603..a622f6e 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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]