summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2009-06-30 23:19:01 -0400
committerAlexander Larsson <alexl@redhat.com>2009-07-08 13:53:04 +0200
commit8af5a5581e11d9c07e8ba3a17eb2cc93b5c70631 (patch)
tree47206e3fdc7532a97deacb836ec5c79042661421 /common
parentc33e26d3914e0659d4a317fda7fe9acbb6269dc9 (diff)
downloadgvfs-8af5a5581e11d9c07e8ba3a17eb2cc93b5c70631.tar.gz
Bug 587484 – Interaction when unmounting mounts and misc fixes
- Port everything to use _with_operation() variants of unmount/eject methods - Add support for g_file_poll_mountable() - new job class: GVfsJobPollMountable - Pass mount operation for unmount/eject ops on GDaemonFile and GDaemonMount - receive in the appropriate GVfsJob classes - also pass unmount flags where it was missing - port all backends to use this - Teach GMountSource and GMountOperationDBus about the new GMountOperation::show-processes signal - also provide new API - g_mount_source_is_dummy() - e.g. when the client didn't passed NULL for the GMountOperation - g_mount_source_abort() - to send the ::abort signal to the client-side GMountOperation - make the client-side of GMountSource return ::reply with NOT_HANDLED when we do an abort - Refactor the mount operation handling in GProxyVolumeMonitor - Pass mount operation for unmount/ejects in GProxyVolumeMonitor - Pass the process id of the actual reader/writer in OpenForRead and OpenForWrite daemon methods - add some private API for making the FUSE client set the pid of the POSIX client (otherwise it looks like the FUSE client is blocking) and pass the right pid. This is because the FUSE client is basically impersonating the POSIX processes. - Make the process id mentioned above available in appropriate GVfsJob classes - GVfsJobOpenForRead - GVfsJobOpenForWrite - GVfsChannel - Provide API to get a list of all blocking clients, e.g. an array of GPid - g_vfs_daemon_get_blocking_processes() - Provide convenience API to easily doing the right thing on unmount; e.g. interact with the user about blocking processes - see the gphoto2 backend for example usage - g_vfs_backend_has_blocking_processes() - g_vfs_backend_unmount_with_operation() and g_vfs_backend_unmount_with_operation_finish() - Only the gphoto2 backend supports ::show-processes right now. Support for other backends will be added shortly. - Implement support for ::show-processes in the GDU volume monitor - right now we don't support "Unmount Anyway" since it requires ABI changes in libgdu.so - this will be changed as soon as there's a new gnome-disk-utility release
Diffstat (limited to 'common')
-rw-r--r--common/gmountoperationdbus.c89
-rw-r--r--common/gmountsource.c254
-rw-r--r--common/gmountsource.h25
-rw-r--r--common/gvfsdaemonprotocol.h2
4 files changed, 366 insertions, 4 deletions
diff --git a/common/gmountoperationdbus.c b/common/gmountoperationdbus.c
index b8ac4f7d..9122042e 100644
--- a/common/gmountoperationdbus.c
+++ b/common/gmountoperationdbus.c
@@ -51,6 +51,8 @@ static void mount_op_ask_password (GMountOperationDBus *op_d
DBusMessage *message);
static void mount_op_ask_question (GMountOperationDBus *op_dbus,
DBusMessage *message);
+static void mount_op_show_processes (GMountOperationDBus *op_dbus,
+ DBusMessage *message);
static void mount_op_aborted (GMountOperationDBus *op_dbus,
DBusMessage *message);
@@ -135,6 +137,10 @@ mount_op_message_function (DBusConnection *connection,
mount_op_ask_question (op_dbus, message);
else if (dbus_message_is_method_call (message,
G_VFS_DBUS_MOUNT_OPERATION_INTERFACE,
+ G_VFS_DBUS_MOUNT_OPERATION_OP_SHOW_PROCESSES))
+ mount_op_show_processes (op_dbus, message);
+ else if (dbus_message_is_method_call (message,
+ G_VFS_DBUS_MOUNT_OPERATION_INTERFACE,
G_VFS_DBUS_MOUNT_OPERATION_OP_ABORTED))
mount_op_aborted (op_dbus, message);
else
@@ -320,8 +326,91 @@ mount_op_ask_question (GMountOperationDBus *op_dbus,
}
static void
+show_processes_reply (GMountOperation *op,
+ GMountOperationResult result,
+ gpointer data)
+{
+ DBusMessage *reply = data;
+ guint32 choice;
+ dbus_bool_t handled, abort_dbus;
+ GMountOperationDBus *op_dbus;
+
+ op_dbus = g_object_get_data (G_OBJECT (op), "dbus-op");
+
+ handled = (result != G_MOUNT_OPERATION_UNHANDLED);
+ abort_dbus = (result == G_MOUNT_OPERATION_ABORTED);
+
+ choice = g_mount_operation_get_choice (op);
+
+ _g_dbus_message_append_args (reply,
+ DBUS_TYPE_BOOLEAN, &handled,
+ DBUS_TYPE_BOOLEAN, &abort_dbus,
+ DBUS_TYPE_UINT32, &choice,
+ 0);
+
+ mount_op_send_reply (op_dbus, reply);
+}
+
+static void
+mount_op_show_processes (GMountOperationDBus *op_dbus,
+ DBusMessage *message)
+{
+ const char *message_string;
+ char **choices;
+ int num_choices;
+ gint32 **process_pids;
+ int num_process_pids;
+ DBusMessage *reply;
+ DBusError error;
+ DBusMessageIter iter;
+ GArray *processes;
+
+ reply = NULL;
+
+ dbus_message_iter_init (message, &iter);
+ dbus_error_init (&error);
+ if (!_g_dbus_message_iter_get_args (&iter,
+ &error,
+ DBUS_TYPE_STRING, &message_string,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+ &choices, &num_choices,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_INT32,
+ &process_pids, &num_process_pids,
+ 0))
+ {
+ reply = dbus_message_new_error (message, error.name, error.message);
+ if (reply == NULL)
+ _g_dbus_oom ();
+ if (!dbus_connection_send (op_dbus->connection, reply, NULL))
+ _g_dbus_oom ();
+ dbus_message_unref (reply);
+ dbus_error_free (&error);
+ return;
+ }
+
+ processes = g_array_sized_new (FALSE, FALSE, sizeof (GPid), num_process_pids);
+ g_array_append_vals (processes, process_pids, num_process_pids);
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ _g_dbus_oom ();
+
+ g_signal_connect (op_dbus->op, "reply", (GCallback)show_processes_reply, reply);
+
+ g_signal_emit_by_name (op_dbus->op, "show_processes",
+ message_string,
+ processes,
+ choices);
+
+ dbus_free_string_array (choices);
+ g_array_unref (processes);
+}
+
+static void
mount_op_aborted (GMountOperationDBus *op_dbus,
DBusMessage *message)
{
+ /* also emit reply to make the all DBus ops return */
+ g_mount_operation_reply (op_dbus->op, G_MOUNT_OPERATION_UNHANDLED);
g_signal_emit_by_name (op_dbus->op, "aborted");
}
diff --git a/common/gmountsource.c b/common/gmountsource.c
index ac705fad..5ee964ea 100644
--- a/common/gmountsource.c
+++ b/common/gmountsource.c
@@ -699,12 +699,241 @@ op_ask_question (GMountOperation *op,
return TRUE;
}
+typedef struct ShowProcessesData ShowProcessesData;
+
+struct ShowProcessesData {
+
+ /* results: */
+ gboolean aborted;
+ guint32 choice;
+};
+
+/* the callback from dbus -> main thread */
+static void
+show_processes_reply (DBusMessage *reply,
+ GError *error,
+ gpointer _data)
+{
+ GSimpleAsyncResult *result;
+ ShowProcessesData *data;
+ dbus_bool_t handled, aborted;
+ guint32 choice;
+ DBusMessageIter iter;
+
+ result = G_SIMPLE_ASYNC_RESULT (_data);
+ handled = TRUE;
+
+ data = g_new0 (ShowProcessesData, 1);
+ g_simple_async_result_set_op_res_gpointer (result, data, g_free);
+
+ if (reply == NULL)
+ {
+ data->aborted = TRUE;
+ }
+ else
+ {
+ dbus_message_iter_init (reply, &iter);
+ if (!_g_dbus_message_iter_get_args (&iter, NULL,
+ DBUS_TYPE_BOOLEAN, &handled,
+ DBUS_TYPE_BOOLEAN, &aborted,
+ DBUS_TYPE_UINT32, &choice,
+ 0))
+ data->aborted = TRUE;
+ else
+ {
+ data->aborted = aborted;
+ data->choice = choice;
+ }
+ }
+
+ if (handled == FALSE)
+ {
+ g_simple_async_result_set_error (result, G_IO_ERROR, G_IO_ERROR_FAILED, "Internal Error");
+ }
+
+ g_simple_async_result_complete (result);
+}
+
+void
+g_mount_source_show_processes_async (GMountSource *source,
+ const char *message_string,
+ GArray *processes,
+ const char **choices,
+ gint n_choices,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+ DBusMessage *message;
+
+ /* If no dbus id specified, reply that we weren't handled */
+ if (source->dbus_id[0] == 0)
+ {
+ g_simple_async_report_error_in_idle (G_OBJECT (source),
+ callback,
+ user_data,
+ G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Internal Error");
+ return;
+ }
+
+ result = g_simple_async_result_new (G_OBJECT (source), callback, user_data,
+ g_mount_source_show_processes_async);
+
+ if (message_string == NULL)
+ message_string = "";
+
+ message = dbus_message_new_method_call (source->dbus_id,
+ source->obj_path,
+ G_VFS_DBUS_MOUNT_OPERATION_INTERFACE,
+ G_VFS_DBUS_MOUNT_OPERATION_OP_SHOW_PROCESSES);
+
+ _g_dbus_message_append_args (message,
+ DBUS_TYPE_STRING, &message_string,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+ &choices, n_choices,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_INT32,
+ &processes->data, processes->len,
+ 0);
+
+ /* 30 minute timeout */
+ _g_dbus_connection_call_async (NULL, message, 1000 * 60 * 30,
+ show_processes_reply, result);
+ dbus_message_unref (message);
+}
+
+gboolean
+g_mount_source_show_processes_finish (GMountSource *source,
+ GAsyncResult *result,
+ gboolean *aborted,
+ gint *choice_out)
+{
+ ShowProcessesData *data, def= { FALSE, };
+ GSimpleAsyncResult *simple;
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+
+ if (g_simple_async_result_propagate_error (simple, NULL))
+ data = &def;
+ else
+ data = (ShowProcessesData *) g_simple_async_result_get_op_res_gpointer (simple);
+
+ if (aborted)
+ *aborted = data->aborted;
+
+ if (choice_out)
+ *choice_out = data->choice;
+
+ return data != &def;
+}
+
+gboolean
+g_mount_source_show_processes (GMountSource *source,
+ const char *message,
+ GArray *processes,
+ const char **choices,
+ gint n_choices,
+ gboolean *aborted_out,
+ gint *choice_out)
+{
+ gint choice;
+ gboolean handled, aborted;
+ AskSyncData data = {NULL};
+
+ data.mutex = g_mutex_new ();
+ data.cond = g_cond_new ();
+
+ g_mutex_lock (data.mutex);
+
+ g_mount_source_show_processes_async (source,
+ message,
+ processes,
+ choices,
+ n_choices,
+ ask_reply_sync,
+ &data);
+
+ g_cond_wait (data.cond, data.mutex);
+ g_mutex_unlock (data.mutex);
+
+ g_cond_free (data.cond);
+ g_mutex_free (data.mutex);
+
+ handled = g_mount_source_show_processes_finish (source,
+ data.result,
+ &aborted,
+ &choice);
+
+ g_object_unref (data.result);
+
+ if (aborted_out)
+ *aborted_out = aborted;
+
+ if (choice_out)
+ *choice_out = choice;
+
+ return handled;
+}
+
+static void
+op_show_processes_reply (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GMountOperationResult result;
+ GMountOperation *op;
+ GMountSource *source;
+ gboolean handled, aborted;
+ gint choice;
+
+ source = G_MOUNT_SOURCE (source_object);
+ op = G_MOUNT_OPERATION (user_data);
+
+ handled = g_mount_source_show_processes_finish (source,
+ res,
+ &aborted,
+ &choice);
+
+ if (!handled)
+ result = G_MOUNT_OPERATION_UNHANDLED;
+ else if (aborted)
+ result = G_MOUNT_OPERATION_ABORTED;
+ else
+ {
+ result = G_MOUNT_OPERATION_HANDLED;
+ g_mount_operation_set_choice (op, choice);
+ }
+
+ g_mount_operation_reply (op, result);
+ g_object_unref (op);
+}
+
static gboolean
-op_aborted (GMountOperation *op,
- GMountSource *source)
+op_show_processes (GMountOperation *op,
+ const char *message,
+ GArray *processes,
+ const char **choices,
+ GMountSource *mount_source)
+{
+ g_mount_source_show_processes_async (mount_source,
+ message,
+ processes,
+ choices,
+ g_strv_length ((gchar **) choices),
+ op_show_processes_reply,
+ g_object_ref (op));
+ g_signal_stop_emission_by_name (op, "show_processes");
+ return TRUE;
+}
+
+gboolean
+g_mount_source_abort (GMountSource *source)
{
DBusMessage *message;
DBusConnection *connection;
+ gboolean ret;
+
+ ret = FALSE;
/* If no dbus id specified, reply that we weren't handled */
if (source->dbus_id[0] == 0)
@@ -713,7 +942,7 @@ op_aborted (GMountOperation *op,
connection = dbus_bus_get (DBUS_BUS_SESSION, NULL);
if (connection == NULL)
goto out;
-
+
message = dbus_message_new_method_call (source->dbus_id,
source->obj_path,
G_VFS_DBUS_MOUNT_OPERATION_INTERFACE,
@@ -725,8 +954,24 @@ op_aborted (GMountOperation *op,
dbus_message_unref (message);
}
+ ret = TRUE;
+
out:
- return TRUE;
+ return ret;
+}
+
+static void
+op_aborted (GMountOperation *op,
+ GMountSource *source)
+{
+ g_mount_source_abort (source);
+}
+
+gboolean
+g_mount_source_is_dummy (GMountSource *source)
+{
+ g_return_val_if_fail (G_IS_MOUNT_SOURCE (source), TRUE);
+ return source->dbus_id[0] == 0;
}
@@ -742,6 +987,7 @@ g_mount_source_get_operation (GMountSource *mount_source)
g_signal_connect (op, "ask_password", (GCallback)op_ask_password, mount_source);
g_signal_connect (op, "ask_question", (GCallback)op_ask_question, mount_source);
+ g_signal_connect (op, "show_processes", (GCallback)op_show_processes, mount_source);
g_signal_connect (op, "aborted", (GCallback)op_aborted, mount_source);
return op;
diff --git a/common/gmountsource.h b/common/gmountsource.h
index e4298357..1f973a10 100644
--- a/common/gmountsource.h
+++ b/common/gmountsource.h
@@ -104,6 +104,31 @@ gboolean g_mount_source_ask_question_finish (GMountSource
gboolean *aborted,
gint *choice_out);
+gboolean g_mount_source_show_processes (GMountSource *mount_source,
+ const char *message,
+ GArray *processes,
+ const char **choices,
+ gint n_choices,
+ gboolean *aborted,
+ gint *choice_out);
+
+void g_mount_source_show_processes_async (GMountSource *mount_source,
+ const char *message,
+ GArray *processes,
+ const char **choices,
+ gint n_choices,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean g_mount_source_show_processes_finish (GMountSource *source,
+ GAsyncResult *result,
+ gboolean *aborted,
+ gint *choice_out);
+
+gboolean g_mount_source_abort (GMountSource *source);
+
+gboolean g_mount_source_is_dummy (GMountSource *source);
+
const char * g_mount_source_get_dbus_id (GMountSource *mount_source);
const char * g_mount_source_get_obj_path (GMountSource *mount_source);
diff --git a/common/gvfsdaemonprotocol.h b/common/gvfsdaemonprotocol.h
index 77658549..98779f72 100644
--- a/common/gvfsdaemonprotocol.h
+++ b/common/gvfsdaemonprotocol.h
@@ -39,6 +39,7 @@ G_BEGIN_DECLS
#define G_VFS_DBUS_MOUNT_OP_EJECT_MOUNTABLE "EjectMountable"
#define G_VFS_DBUS_MOUNT_OP_START_MOUNTABLE "StartMountable"
#define G_VFS_DBUS_MOUNT_OP_STOP_MOUNTABLE "StopMountable"
+#define G_VFS_DBUS_MOUNT_OP_POLL_MOUNTABLE "PollMountable"
#define G_VFS_DBUS_MOUNT_OP_SET_DISPLAY_NAME "SetDisplayName"
#define G_VFS_DBUS_MOUNT_OP_DELETE "Delete"
#define G_VFS_DBUS_MOUNT_OP_TRASH "Trash"
@@ -75,6 +76,7 @@ G_BEGIN_DECLS
#define G_VFS_DBUS_MOUNT_OPERATION_INTERFACE "org.gtk.vfs.MountOperation"
#define G_VFS_DBUS_MOUNT_OPERATION_OP_ASK_PASSWORD "askPassword"
#define G_VFS_DBUS_MOUNT_OPERATION_OP_ASK_QUESTION "askQuestion"
+#define G_VFS_DBUS_MOUNT_OPERATION_OP_SHOW_PROCESSES "showProcesses"
#define G_VFS_DBUS_MOUNT_OPERATION_OP_ABORTED "aborted"
/* Implemented by the spawner of a process, the spawned process sends the