[gnome-disk-utility] Add ensure_unused() method to "shut down" a whole device
- From: David Zeuthen <davidz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-disk-utility] Add ensure_unused() method to "shut down" a whole device
- Date: Wed, 7 Nov 2012 17:55:50 +0000 (UTC)
commit 4cec710ab7d90375ee42a7f921274934e27fb495
Author: David Zeuthen <zeuthen gmail com>
Date: Wed Nov 7 12:45:14 2012 -0500
Add ensure_unused() method to "shut down" a whole device
This is useful to avoid pointless error dialogs complaining e.g. that
there are mounted filesystems on the media being ejected or
formatted... so instead of presenting this such an error to the user,
this method will go ahead and unmount/lock all relevant
filesystems/LUKS devices for the device.
Many users expect this kind of behavior since they do not really keep
track of implementation details such as whether a device is mounted or
unlocked.
Upcoming commits will make use of this new infrastructure in several
places.
Signed-off-by: David Zeuthen <zeuthen gmail com>
src/disks/gduwindow.c | 263 +++++++++++++++++++++++++++++++++++++++++++++++++
src/disks/gduwindow.h | 10 ++
2 files changed, 273 insertions(+), 0 deletions(-)
---
diff --git a/src/disks/gduwindow.c b/src/disks/gduwindow.c
index 62350c5..cf197e5 100644
--- a/src/disks/gduwindow.c
+++ b/src/disks/gduwindow.c
@@ -4512,3 +4512,266 @@ on_ms_raid_menu_item_create_activated (GtkMenuItem *menu_item,
device_tree_selection_toolbar_select_done_toggle (window, FALSE);
g_list_free_full (selected_blocks, g_object_unref);
}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+ GduWindow *window;
+ UDisksObject *object;
+ GSimpleAsyncResult *simple;
+ GCancellable *cancellable; /* borrowed ref */
+} UnuseData;
+
+static void
+unuse_data_free (UnuseData *data)
+{
+ g_clear_object (&data->window);
+ g_clear_object (&data->object);
+ g_clear_object (&data->simple);
+ g_slice_free (UnuseData, data);
+}
+
+static void
+unuse_data_complete (UnuseData *data,
+ const gchar *error_message,
+ GError *error)
+{
+ if (error != NULL)
+ {
+ gdu_utils_show_error (GTK_WINDOW (data->window),
+ error_message,
+ error);
+ g_simple_async_result_take_error (data->simple, error);
+ }
+ g_simple_async_result_complete_in_idle (data->simple);
+ unuse_data_free (data);
+}
+
+static void unuse_data_iterate (UnuseData *data);
+
+static void
+unuse_unmount_cb (UDisksFilesystem *filesystem,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ UnuseData *data = user_data;
+ GError *error = NULL;
+
+ if (!udisks_filesystem_call_unmount_finish (filesystem,
+ res,
+ &error))
+ {
+ unuse_data_complete (data, _("Error unmounting filesystem"), error);
+ }
+ else
+ {
+ unuse_data_iterate (data);
+ }
+}
+
+static void
+unuse_lock_cb (UDisksEncrypted *encrypted,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ UnuseData *data = user_data;
+ GError *error = NULL;
+
+ if (!udisks_encrypted_call_lock_finish (encrypted,
+ res,
+ &error))
+ {
+ unuse_data_complete (data, _("Error locking device"), error);
+ }
+ else
+ {
+ unuse_data_iterate (data);
+ }
+}
+
+static void
+unuse_data_iterate (UnuseData *data)
+{
+ UDisksFilesystem *filesystem_to_unmount = NULL;
+ UDisksEncrypted *encrypted_to_lock = NULL;
+ UDisksBlock *block = NULL;
+ UDisksDrive *drive = NULL;
+ UDisksObject *block_object = NULL;
+ UDisksPartitionTable *partition_table = NULL;
+ GList *partitions = NULL;
+ GList *l;
+ GList *objects_to_check = NULL;
+
+ drive = udisks_object_get_drive (data->object);
+ if (drive != NULL)
+ {
+ block = udisks_client_get_block_for_drive (data->window->client,
+ drive,
+ FALSE /* get_physical */);
+ }
+ else
+ {
+ block = udisks_object_get_block (data->object);
+ }
+
+ if (block != NULL)
+ {
+ block_object = (UDisksObject *) g_dbus_interface_dup_object (G_DBUS_INTERFACE (block));
+ objects_to_check = g_list_prepend (objects_to_check, g_object_ref (block_object));
+ }
+
+ /* if we're a partitioned block device, add all partitions */
+ partition_table = udisks_object_get_partition_table (block_object);
+ if (partition_table != NULL)
+ {
+ partitions = udisks_client_get_partitions (data->window->client, partition_table);
+ for (l = partitions; l != NULL; l = l->next)
+ {
+ UDisksPartition *partition = UDISKS_PARTITION (l->data);
+ UDisksObject *partition_object;
+ partition_object = (UDisksObject *) g_dbus_interface_dup_object (G_DBUS_INTERFACE (partition));
+ if (partition_object != NULL)
+ objects_to_check = g_list_append (objects_to_check, partition_object);
+ }
+ }
+
+ /* Add LUKS objects */
+ for (l = objects_to_check; l != NULL; l = l->next)
+ {
+ UDisksObject *object = UDISKS_OBJECT (l->data);
+ UDisksBlock *block_for_object;
+ block_for_object = udisks_object_peek_block (object);
+ if (block_for_object != NULL)
+ {
+ UDisksBlock *cleartext;
+ cleartext = udisks_client_get_cleartext_block (data->window->client, block_for_object);
+ if (cleartext != NULL)
+ {
+ UDisksObject *cleartext_object;
+ cleartext_object = (UDisksObject *) g_dbus_interface_dup_object (G_DBUS_INTERFACE (cleartext));
+ if (cleartext_object != NULL)
+ objects_to_check = g_list_append (objects_to_check, cleartext_object);
+ g_object_unref (cleartext);
+ }
+ }
+ }
+
+ /* Check in reverse order, e.g. cleartext before LUKS, partitions before the main block device */
+ objects_to_check = g_list_reverse (objects_to_check);
+ for (l = objects_to_check; l != NULL; l = l->next)
+ {
+ UDisksObject *object = UDISKS_OBJECT (l->data);
+ UDisksBlock *block_for_object;
+ UDisksFilesystem *filesystem_for_object;
+ UDisksEncrypted *encrypted_for_object;
+
+ block_for_object = udisks_object_peek_block (object);
+
+ filesystem_for_object = udisks_object_peek_filesystem (object);
+ if (filesystem_for_object != NULL)
+ {
+ const gchar *const *mount_points = udisks_filesystem_get_mount_points (filesystem_for_object);
+ if (g_strv_length ((gchar **) mount_points) > 0)
+ {
+ filesystem_to_unmount = g_object_ref (filesystem_for_object);
+ goto victim_found;
+ }
+ }
+
+ encrypted_for_object = udisks_object_peek_encrypted (object);
+ if (encrypted_for_object != NULL)
+ {
+ UDisksBlock *cleartext;
+ cleartext = udisks_client_get_cleartext_block (data->window->client, block_for_object);
+ if (cleartext != NULL)
+ {
+ g_object_unref (cleartext);
+ encrypted_to_lock = g_object_ref (encrypted_for_object);
+ goto victim_found;
+ }
+ }
+ }
+
+ victim_found:
+
+ if (filesystem_to_unmount != NULL)
+ {
+ udisks_filesystem_call_unmount (filesystem_to_unmount,
+ g_variant_new ("a{sv}", NULL), /* options */
+ data->cancellable, /* cancellable */
+ (GAsyncReadyCallback) unuse_unmount_cb,
+ data);
+ }
+ else if (encrypted_to_lock != NULL)
+ {
+ udisks_encrypted_call_lock (encrypted_to_lock,
+ g_variant_new ("a{sv}", NULL), /* options */
+ data->cancellable, /* cancellable */
+ (GAsyncReadyCallback) unuse_lock_cb,
+ data);
+ }
+ else
+ {
+ /* nothing left to do, terminate without error */
+ unuse_data_complete (data, NULL, NULL);
+ }
+
+ g_clear_object (&partition_table);
+ g_list_free_full (partitions, g_object_unref);
+ g_list_free_full (objects_to_check, g_object_unref);
+ g_clear_object (&encrypted_to_lock);
+ g_clear_object (&filesystem_to_unmount);
+ g_clear_object (&block_object);
+ g_clear_object (&block);
+ g_clear_object (&drive);
+}
+
+void
+gdu_window_ensure_unused (GduWindow *window,
+ UDisksObject *object,
+ GAsyncReadyCallback callback,
+ GCancellable *cancellable,
+ gpointer user_data)
+{
+ UnuseData *data;
+
+ g_return_if_fail (GDU_IS_WINDOW (window));
+ g_return_if_fail (UDISKS_IS_OBJECT (object));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ data = g_slice_new0 (UnuseData);
+ data->window = g_object_ref (window);
+ data->object = g_object_ref (object);
+ data->cancellable = cancellable;
+ data->simple = g_simple_async_result_new (G_OBJECT (window),
+ callback,
+ user_data,
+ gdu_window_ensure_unused);
+ g_simple_async_result_set_check_cancellable (data->simple, cancellable);
+
+ unuse_data_iterate (data);
+}
+
+gboolean
+gdu_window_ensure_unused_finish (GduWindow *window,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ gboolean ret = FALSE;
+
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (res), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == gdu_window_ensure_unused);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ goto out;
+
+ ret = TRUE;
+
+ out:
+ return ret;
+}
+
diff --git a/src/disks/gduwindow.h b/src/disks/gduwindow.h
index a348014..a07ab0f 100644
--- a/src/disks/gduwindow.h
+++ b/src/disks/gduwindow.h
@@ -31,6 +31,16 @@ gboolean gdu_window_select_object (GduWindow *window,
void gdu_window_show_attach_disk_image (GduWindow *window);
+void gdu_window_ensure_unused (GduWindow *window,
+ UDisksObject *object,
+ GAsyncReadyCallback callback,
+ GCancellable *cancellable,
+ gpointer user_data);
+
+gboolean gdu_window_ensure_unused_finish (GduWindow *window,
+ GAsyncResult *res,
+ GError **error);
+
G_END_DECLS
#endif /* __GDU_WINDOW_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]