diff options
Diffstat (limited to 'monitor/gdu/ggdudrive.c')
-rw-r--r-- | monitor/gdu/ggdudrive.c | 1244 |
1 files changed, 0 insertions, 1244 deletions
diff --git a/monitor/gdu/ggdudrive.c b/monitor/gdu/ggdudrive.c deleted file mode 100644 index aafd26c0..00000000 --- a/monitor/gdu/ggdudrive.c +++ /dev/null @@ -1,1244 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* gvfs - extensions for gio - * - * Copyright (C) 2006-2009 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * Author: David Zeuthen <davidz@redhat.com> - */ - -#include <config.h> - -#include <string.h> -#include <sys/wait.h> -#include <unistd.h> - -#include <glib.h> -#include <glib/gi18n-lib.h> - -#include "ggduvolumemonitor.h" -#include "ggdudrive.h" -#include "ggduvolume.h" - -struct _GGduDrive { - GObject parent; - - GVolumeMonitor *volume_monitor; /* owned by volume monitor */ - GList *volumes; /* entries in list are owned by volume_monitor */ - - GduPresentable *presentable; - - /* the following members need to be set upon construction */ - GIcon *icon; - gchar *name; - gchar *device_file; - dev_t dev; - gboolean is_media_removable; - gboolean has_media; - gboolean can_eject; - gboolean can_poll_for_media; - gboolean is_media_check_automatic; - - GDriveStartStopType start_stop_type; - gboolean can_start; - gboolean can_start_degraded; - gboolean can_stop; -}; - -static void g_gdu_drive_drive_iface_init (GDriveIface *iface); - -G_DEFINE_TYPE_EXTENDED (GGduDrive, g_gdu_drive, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (G_TYPE_DRIVE, - g_gdu_drive_drive_iface_init)) - -static void presentable_changed (GduPresentable *presentable, - GGduDrive *drive); - -static void presentable_job_changed (GduPresentable *presentable, - GGduDrive *drive); - -static void -g_gdu_drive_finalize (GObject *object) -{ - GList *l; - GGduDrive *drive; - - drive = G_GDU_DRIVE (object); - - for (l = drive->volumes; l != NULL; l = l->next) - { - GGduVolume *volume = l->data; - g_gdu_volume_unset_drive (volume, drive); - } - - if (drive->presentable != NULL) - { - g_signal_handlers_disconnect_by_func (drive->presentable, presentable_changed, drive); - g_signal_handlers_disconnect_by_func (drive->presentable, presentable_job_changed, drive); - g_object_unref (drive->presentable); - } - - if (drive->icon != NULL) - g_object_unref (drive->icon); - g_free (drive->name); - g_free (drive->device_file); - - if (G_OBJECT_CLASS (g_gdu_drive_parent_class)->finalize) - (*G_OBJECT_CLASS (g_gdu_drive_parent_class)->finalize) (object); -} - -static void -g_gdu_drive_class_init (GGduDriveClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->finalize = g_gdu_drive_finalize; -} - -static void -g_gdu_drive_init (GGduDrive *gdu_drive) -{ -} - -static void -emit_changed (GGduDrive *drive) -{ - g_signal_emit_by_name (drive, "changed"); - g_signal_emit_by_name (drive->volume_monitor, "drive_changed", drive); -} - -static gboolean -update_drive (GGduDrive *drive) -{ - GduDevice *device; - gboolean changed; - GIcon *old_icon; - gchar *old_name; - gchar *old_device_file; - dev_t old_dev; - gboolean old_is_media_removable; - gboolean old_has_media; - gboolean old_can_eject; - gboolean old_can_start; - gboolean old_can_start_degraded; - gboolean old_can_stop; - gboolean old_start_stop_type; - gboolean old_is_media_check_automatic; - gboolean old_can_poll_for_media; - - /* save old values */ - old_is_media_removable = drive->is_media_removable; - old_has_media = drive->has_media; - old_can_eject = drive->can_eject; - old_can_start = drive->can_start; - old_can_start_degraded = drive->can_start_degraded; - old_can_stop = drive->can_stop; - old_start_stop_type = drive->start_stop_type; - old_can_poll_for_media = drive->can_poll_for_media; - old_is_media_check_automatic = drive->is_media_check_automatic; - - old_name = g_strdup (drive->name); - old_device_file = g_strdup (drive->device_file); - old_dev = drive->dev; - old_icon = drive->icon != NULL ? g_object_ref (drive->icon) : NULL; - - /* in with the new */ - device = gdu_presentable_get_device (drive->presentable); - - if (drive->icon != NULL) - g_object_unref (drive->icon); - drive->icon = gdu_presentable_get_icon (drive->presentable); - - g_free (drive->name); - if (_is_pc_floppy_drive (device)) - drive->name = g_strdup (_("Floppy Drive")); - else - drive->name = gdu_presentable_get_name (drive->presentable); - - /* It's perfectly fine to not have a GduDevice - for example, this is the case for non-running - * MD RAID arrays as well as LVM2 Volume Group "drives" - */ - if (device == NULL) - { - g_free (drive->device_file); - drive->dev = 0; - drive->device_file = NULL; - drive->is_media_removable = FALSE; - drive->has_media = TRUE; - drive->can_eject = FALSE; - drive->can_poll_for_media = FALSE; - } - else - { - g_free (drive->device_file); - drive->dev = gdu_device_get_dev (device); - drive->device_file = g_strdup (gdu_device_get_device_file (device)); - drive->is_media_removable = gdu_device_is_removable (device); - drive->has_media = gdu_device_is_media_available (device); - /* All drives with removable media are ejectable - * - * See http://bugzilla.gnome.org/show_bug.cgi?id=576587 for why we want this. - * - * See also below where we e.g. set can_eject to TRUE for non-removable drives. - */ - drive->can_eject = ((gdu_device_drive_get_is_media_ejectable (device) || gdu_device_is_removable (device)) && - gdu_device_is_media_available (device) && ! _is_pc_floppy_drive (device)) || - gdu_device_drive_get_requires_eject (device); - drive->is_media_check_automatic = gdu_device_is_media_change_detected (device); - drive->can_poll_for_media = gdu_device_is_removable (device); - } - - /* determine start/stop type */ - drive->can_stop = FALSE; - drive->can_start = FALSE; - drive->can_start_degraded = FALSE; - drive->start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN; - if (gdu_drive_is_activatable (GDU_DRIVE (drive->presentable))) - { - gboolean can_activate; - gboolean degraded; - - can_activate = gdu_drive_can_activate (GDU_DRIVE (drive->presentable), °raded); - - drive->can_stop = gdu_drive_can_deactivate (GDU_DRIVE (drive->presentable)); - drive->can_start = can_activate && !degraded; - drive->can_start_degraded = can_activate && degraded; - drive->start_stop_type = G_DRIVE_START_STOP_TYPE_MULTIDISK; - } - else if (device != NULL && gdu_device_drive_get_can_detach (device)) - { - /* Ideally, for non-ejectable devices (e.g. non-cdrom, non-zip) - * such as USB sticks we'd display "Eject" instead of "Shutdown" - * since it is more familiar and the common case. The way this - * should work is that after the Eject() method returns we call - * Detach() - see eject_cb() below. - * - * (Note that it's not enough to just call Detach() since some - * devices, such as the Kindle, only works with Eject(). So we - * call them both in order). - * - * We actually used to do this (and that's why eject_cb() still - * has this code) but some systems use internal USB devices for - * e.g. SD card readers. If we were to detach these then the - * user would have to power-cycle the system to get the device - * back. See http://bugs.freedesktop.org/show_bug.cgi?id=24343 - * for more details. - * - * In the future, if we know for sure that a port is external - * (like, from DMI data) we can go back to doing this. For now - * the user will get all the options... - */ - drive->can_stop = TRUE; - drive->can_start = FALSE; - drive->can_start_degraded = FALSE; - drive->start_stop_type = G_DRIVE_START_STOP_TYPE_SHUTDOWN; - } - - if (device != NULL) - g_object_unref (device); - - /* Never use empty/blank names (#582772) */ - if (drive->name == NULL || strlen (drive->name) == 0) - { - if (drive->device_file != NULL) - drive->name = g_strdup_printf (_("Unnamed Drive (%s)"), drive->device_file); - else - drive->name = g_strdup (_("Unnamed Drive")); - } - - /* compute whether something changed */ - changed = !((old_is_media_removable == drive->is_media_removable) && - (old_has_media == drive->has_media) && - (old_can_eject == drive->can_eject) && - (old_can_start == drive->can_start) && - (old_can_start_degraded == drive->can_start_degraded) && - (old_can_stop == drive->can_stop) && - (old_start_stop_type == drive->start_stop_type) && - (old_is_media_check_automatic == drive->is_media_check_automatic) && - (old_can_poll_for_media == drive->can_poll_for_media) && - (g_strcmp0 (old_name, drive->name) == 0) && - (g_strcmp0 (old_device_file, drive->device_file) == 0) && - (old_dev == drive->dev) && - g_icon_equal (old_icon, drive->icon) - ); - - /* free old values */ - g_free (old_name); - g_free (old_device_file); - if (old_icon != NULL) - g_object_unref (old_icon); - - /*g_debug ("in update_drive(); has_media=%d changed=%d", drive->has_media, changed);*/ - - return changed; -} - -static void -presentable_changed (GduPresentable *presentable, - GGduDrive *drive) -{ - /*g_debug ("drive: presentable_changed: %p: %s", drive, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ - if (update_drive (drive)) - emit_changed (drive); -} - -static void -presentable_job_changed (GduPresentable *presentable, - GGduDrive *drive) -{ - /*g_debug ("drive: presentable_job_changed: %p: %s", drive, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ - if (update_drive (drive)) - emit_changed (drive); -} - -GGduDrive * -g_gdu_drive_new (GVolumeMonitor *volume_monitor, - GduPresentable *presentable) -{ - GGduDrive *drive; - - drive = g_object_new (G_TYPE_GDU_DRIVE, NULL); - drive->volume_monitor = volume_monitor; - g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(drive->volume_monitor)); - - drive->presentable = g_object_ref (presentable); - - g_signal_connect (drive->presentable, "changed", G_CALLBACK (presentable_changed), drive); - g_signal_connect (drive->presentable, "job-changed", G_CALLBACK (presentable_job_changed), drive); - - update_drive (drive); - - return drive; -} - -void -g_gdu_drive_disconnected (GGduDrive *drive) -{ - GList *l, *volumes; - - volumes = drive->volumes; - drive->volumes = NULL; - - for (l = volumes; l != NULL; l = l->next) - { - GGduVolume *volume = l->data; - g_gdu_volume_unset_drive (volume, drive); - } - - g_list_free (volumes); -} - -void -g_gdu_drive_set_volume (GGduDrive *drive, - GGduVolume *volume) -{ - if (g_list_find (drive->volumes, volume) == NULL) - { - drive->volumes = g_list_prepend (drive->volumes, volume); - emit_changed (drive); - } -} - -void -g_gdu_drive_unset_volume (GGduDrive *drive, - GGduVolume *volume) -{ - GList *l; - - l = g_list_find (drive->volumes, volume); - if (l != NULL) - { - drive->volumes = g_list_delete_link (drive->volumes, l); - emit_changed (drive); - } -} - -static GIcon * -g_gdu_drive_get_icon (GDrive *_drive) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - return drive->icon != NULL ? g_object_ref (drive->icon) : NULL; -} - -static char * -g_gdu_drive_get_name (GDrive *_drive) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - return g_strdup (drive->name); -} - -static GList * -g_gdu_drive_get_volumes (GDrive *_drive) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - GList *l; - - l = g_list_copy (drive->volumes); - g_list_foreach (l, (GFunc) g_object_ref, NULL); - - return l; -} - -static gboolean -g_gdu_drive_has_volumes (GDrive *_drive) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - gboolean res; - - res = drive->volumes != NULL; - - return res; -} - -static gboolean -g_gdu_drive_is_media_removable (GDrive *_drive) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - return drive->is_media_removable; -} - -static gboolean -g_gdu_drive_has_media (GDrive *_drive) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - return drive->has_media; -} - -static gboolean -g_gdu_drive_is_media_check_automatic (GDrive *_drive) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - return drive->is_media_check_automatic; -} - -static gboolean -g_gdu_drive_can_eject (GDrive *_drive) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - return drive->can_eject; -} - -static gboolean -g_gdu_drive_can_poll_for_media (GDrive *_drive) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - return drive->can_poll_for_media; -} - -static gboolean -g_gdu_drive_can_start (GDrive *_drive) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - return drive->can_start; -} - -static gboolean -g_gdu_drive_can_start_degraded (GDrive *_drive) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - return drive->can_start_degraded; -} - -static gboolean -g_gdu_drive_can_stop (GDrive *_drive) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - return drive->can_stop; -} - -static GDriveStartStopType -g_gdu_drive_get_start_stop_type (GDrive *_drive) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - return drive->start_stop_type; -} - -/* ---------------------------------------------------------------------------------------------------- */ - -typedef void (*UnmountsMountsFunc) (GDrive *drive, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data, - gpointer on_all_unmounted_data); - -typedef struct { - GDrive *drive; - GAsyncReadyCallback callback; - gpointer user_data; - GMountOperation *mount_operation; - GCancellable *cancellable; - GMountUnmountFlags flags; - - GList *pending_mounts; - - UnmountsMountsFunc on_all_unmounted; - gpointer on_all_unmounted_data; -} UnmountMountsOp; - -static void -free_unmount_mounts_op (UnmountMountsOp *data) -{ - GList *l; - - for (l = data->pending_mounts; l != NULL; l = l->next) - { - GMount *mount = l->data; - g_object_unref (mount); - } - g_list_free (data->pending_mounts); -} - -static void -unmount_mounts_cb (GObject *source_object, - GAsyncResult *res, - gpointer user_data); - -static void -unmount_mounts_do (UnmountMountsOp *data) -{ - if (data->pending_mounts == NULL) - { - - /*g_warning ("all pending mounts done");*/ - data->on_all_unmounted (data->drive, - data->cancellable, - data->callback, - data->user_data, - data->on_all_unmounted_data); - - g_object_unref (data->drive); - g_free (data); - } - else - { - GMount *mount; - - mount = data->pending_mounts->data; - data->pending_mounts = g_list_remove (data->pending_mounts, mount); - - /*g_warning ("unmounting %p", mount);*/ - - g_mount_unmount_with_operation (mount, - data->flags, - data->mount_operation, - data->cancellable, - unmount_mounts_cb, - data); - } -} - -static void -unmount_mounts_cb (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - UnmountMountsOp *data = user_data; - GMount *mount = G_MOUNT (source_object); - GSimpleAsyncResult *simple; - GError *error = NULL; - - if (!g_mount_unmount_with_operation_finish (mount, res, &error)) - { - /* make the error dialog more targeted to the drive.. unless the user has already seen a dialog */ - if (error->code != G_IO_ERROR_FAILED_HANDLED) - { - g_error_free (error); - error = g_error_new (G_IO_ERROR, G_IO_ERROR_BUSY, - _("Failed to eject medium; one or more volumes on the medium are busy.")); - } - - /* unmount failed; need to fail the whole eject operation */ - simple = g_simple_async_result_new_from_error (G_OBJECT (data->drive), - data->callback, - data->user_data, - error); - g_error_free (error); - g_simple_async_result_complete (simple); - g_object_unref (simple); - - free_unmount_mounts_op (data); - } - else - { - - /*g_warning ("successfully unmounted %p", mount);*/ - - /* move on to the next mount.. */ - unmount_mounts_do (data); - } - - g_object_unref (mount); -} - -static void -unmount_mounts (GGduDrive *drive, - GMountUnmountFlags flags, - GMountOperation *mount_operation, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data, - UnmountsMountsFunc on_all_unmounted, - gpointer on_all_unmounted_data) -{ - GMount *mount; - UnmountMountsOp *data; - GList *l; - - data = g_new0 (UnmountMountsOp, 1); - data->drive = g_object_ref (drive); - data->mount_operation = mount_operation; - data->cancellable = cancellable; - data->callback = callback; - data->user_data = user_data; - data->flags = flags; - data->on_all_unmounted = on_all_unmounted; - data->on_all_unmounted_data = on_all_unmounted_data; - - for (l = drive->volumes; l != NULL; l = l->next) - { - GGduVolume *volume = l->data; - mount = g_volume_get_mount (G_VOLUME (volume)); - if (mount != NULL && g_mount_can_unmount (mount)) - data->pending_mounts = g_list_prepend (data->pending_mounts, g_object_ref (mount)); - } - - unmount_mounts_do (data); -} - -/* ---------------------------------------------------------------------------------------------------- */ - -static void -detach_after_eject_cb (GduDevice *device, - GError *error, - gpointer user_data) -{ - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data); - - /* Don't return an error here - this is because some devices, such as - * the Kindle, can do Eject() but not Detach() e.g. the STOP UNIT - * command or any other part of Detach() may fail. - */ - if (error != NULL) - { - g_warning ("Detach() after Eject() failed with: %s", error->message); - g_error_free (error); - } - - g_simple_async_result_complete (simple); - g_object_unref (simple); -} - -static void -eject_cb (GduDevice *device, - GError *error, - gpointer user_data) -{ - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data); - GGduDrive *drive; - gboolean drive_detachable; - - drive = G_GDU_DRIVE (g_async_result_get_source_object (G_ASYNC_RESULT (simple))); - drive_detachable = drive->can_stop == FALSE && drive->start_stop_type == G_DRIVE_START_STOP_TYPE_SHUTDOWN; - - if (error != NULL && error->code == G_IO_ERROR_FAILED && - drive_detachable && ! drive->has_media && drive->is_media_removable) - { - /* Silently drop the error if there's no media in drive and we're still trying to detach it (see below) */ - g_error_free (error); - error = NULL; - } - - if (error != NULL) - { - g_simple_async_result_set_from_error (simple, error); - g_simple_async_result_complete (simple); - g_object_unref (simple); - g_error_free (error); - goto out; - } - - if (drive_detachable) - { - /* If device is not ejectable but it is detachable and we don't support stop(), - * then also run Detach() after Eject() - see update_drive() for details for why... - */ - gdu_device_op_drive_detach (device, detach_after_eject_cb, simple); - } - else - { - /* otherwise we are done */ - g_simple_async_result_complete (simple); - g_object_unref (simple); - } - g_object_unref (drive); - - out: - ; -} - -static void -g_gdu_drive_eject_on_all_unmounted (GDrive *_drive, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data, - gpointer on_all_unmounted_data) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - GSimpleAsyncResult *simple; - GduDevice *device; - - device = gdu_presentable_get_device (drive->presentable); - if (device == NULL) - { - simple = g_simple_async_result_new_error (G_OBJECT (drive), - callback, - user_data, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Drive is activatable and not running"); - g_simple_async_result_complete_in_idle (simple); - g_object_unref (simple); - } - else - { - simple = g_simple_async_result_new (G_OBJECT (drive), - callback, - user_data, - NULL); - - gdu_device_op_drive_eject (device, eject_cb, simple); - } -} - -static void -g_gdu_drive_eject_with_operation (GDrive *_drive, - GMountUnmountFlags flags, - GMountOperation *mount_operation, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - - /* first we need to go through all the volumes and unmount their assoicated mounts (if any) */ - unmount_mounts (drive, - flags, - mount_operation, - cancellable, - callback, - user_data, - g_gdu_drive_eject_on_all_unmounted, - NULL); -} - -static gboolean -g_gdu_drive_eject_with_operation_finish (GDrive *drive, - GAsyncResult *result, - GError **error) -{ - return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); -} - -static void -g_gdu_drive_eject (GDrive *drive, - GMountUnmountFlags flags, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - g_gdu_drive_eject_with_operation (drive, flags, NULL, cancellable, callback, user_data); -} - -static gboolean -g_gdu_drive_eject_finish (GDrive *drive, - GAsyncResult *result, - GError **error) -{ - return g_gdu_drive_eject_with_operation_finish (drive, result, error); -} - -/* ---------------------------------------------------------------------------------------------------- */ - -static void -stop_cb (GduDevice *device, - GError *error, - gpointer user_data) -{ - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data); - - if (error != NULL) - { - g_simple_async_result_set_from_error (simple, error); - g_error_free (error); - } - - g_simple_async_result_complete (simple); - g_object_unref (simple); -} - -static void -drive_deactivate_cb (GduDrive *drive, - GError *error, - gpointer user_data) -{ - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data); - - if (error != NULL) - { - g_simple_async_result_set_from_error (simple, error); - g_error_free (error); - } - - g_simple_async_result_complete (simple); - g_object_unref (simple); -} - -static void -g_gdu_drive_stop_on_all_unmounted (GDrive *_drive, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data, - gpointer on_all_unmounted_data) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - GSimpleAsyncResult *simple; - GduDevice *device; - - simple = g_simple_async_result_new (G_OBJECT (drive), - callback, - user_data, - NULL); - - switch (drive->start_stop_type) - { - case G_DRIVE_START_STOP_TYPE_SHUTDOWN: - device = gdu_presentable_get_device (drive->presentable); - if (device == NULL) - { - g_simple_async_result_set_error (simple, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Cannot detach: drive has no GduDevice object"); - g_simple_async_result_complete_in_idle (simple); - g_object_unref (simple); - } - else - { - gdu_device_op_drive_detach (device, stop_cb, simple); - g_object_unref (device); - } - break; - - case G_DRIVE_START_STOP_TYPE_MULTIDISK: - gdu_drive_deactivate (GDU_DRIVE (drive->presentable), drive_deactivate_cb, simple); - break; - - default: - g_simple_async_result_set_error (simple, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "start_stop_type %d not supported", - drive->start_stop_type); - g_simple_async_result_complete_in_idle (simple); - g_object_unref (simple); - break; - } -} - -static void -g_gdu_drive_stop (GDrive *_drive, - GMountUnmountFlags flags, - GMountOperation *mount_operation, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - - /* first we need to go through all the volumes and unmount their assoicated mounts (if any) */ - unmount_mounts (drive, - flags, - mount_operation, - cancellable, - callback, - user_data, - g_gdu_drive_stop_on_all_unmounted, - NULL); -} - -static gboolean -g_gdu_drive_stop_finish (GDrive *drive, - GAsyncResult *result, - GError **error) -{ - return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); -} - -/* ---------------------------------------------------------------------------------------------------- */ - -static void -start_cb (GduDrive *drive, - gchar *assembled_drive_object_path, - GError *error, - gpointer user_data) -{ - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data); - - if (error != NULL) - { - g_simple_async_result_set_error (simple, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Failed activating drive: %s", - error->message); - g_error_free (error); - } - else - { - g_free (assembled_drive_object_path); - } - g_simple_async_result_complete (simple); - g_object_unref (simple); -} - -typedef struct -{ - GGduDrive *drive; - GSimpleAsyncResult *simple; - - GMountOperation *start_operation; - gulong start_operation_reply_handler_id; -} StartOpData; - -static void -start_operation_reply (GMountOperation *op, - GMountOperationResult result, - gpointer user_data) -{ - StartOpData *data = user_data; - gint choice; - - /* we got what we wanted; don't listen to any other signals from the start operation */ - if (data->start_operation_reply_handler_id != 0) - { - g_signal_handler_disconnect (data->start_operation, data->start_operation_reply_handler_id); - data->start_operation_reply_handler_id = 0; - } - - if (result != G_MOUNT_OPERATION_HANDLED) - { - if (result == G_MOUNT_OPERATION_ABORTED) - { - /* The user aborted the operation so consider it "handled" */ - g_simple_async_result_set_error (data->simple, - G_IO_ERROR, - G_IO_ERROR_FAILED_HANDLED, - "Start operation dialog aborted (user should never see this error since " - "it is G_IO_ERROR_FAILED_HANDLED)"); - } - else - { - g_simple_async_result_set_error (data->simple, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Expected G_MOUNT_OPERATION_HANDLED but got %d", result); - } - g_simple_async_result_complete (data->simple); - goto out; - } - - /* handle the user pressing cancel */ - choice = g_mount_operation_get_choice (data->start_operation); - if (choice == 1) - { - g_simple_async_result_set_error (data->simple, - G_IO_ERROR, - G_IO_ERROR_FAILED_HANDLED, - "User refused to start degraded array (user should never see this error since " - "it is G_IO_ERROR_FAILED_HANDLED)"); - g_simple_async_result_complete (data->simple); - goto out; - } - - gdu_drive_activate (GDU_DRIVE (data->drive->presentable), start_cb, g_object_ref (data->simple)); - - out: - g_object_unref (data->drive); - g_object_unref (data->start_operation); - g_object_unref (data->simple); - g_free (data); -} - -static void -g_gdu_drive_start (GDrive *_drive, - GDriveStartFlags flags, - GMountOperation *start_operation, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - GSimpleAsyncResult *simple; - gboolean degraded; - - /* TODO: handle GCancellable */ - - if (!gdu_drive_can_activate (GDU_DRIVE (drive->presentable), °raded)) - goto not_supported; - - if (start_operation == NULL && degraded) - goto refuse_degraded_without_confirmation; - - simple = g_simple_async_result_new (G_OBJECT (drive), - callback, - user_data, - NULL); - - if (degraded) - { - const gchar *message; - const gchar *choices[3]; - StartOpData *data; - - message = _("Start drive in degraded mode?\n" - "Starting a drive in degraded mode means that " - "the drive is no longer tolerant to failures. " - "Data on the drive may be irrevocably lost if a " - "component fails."); - - choices[0] = _("Start Anyway"); - choices[1] = _("Cancel"); - choices[2] = NULL; - - data = g_new0 (StartOpData, 1); - data->drive = g_object_ref (drive); - data->simple = simple; - data->start_operation = g_object_ref (start_operation); - data->start_operation_reply_handler_id = g_signal_connect (start_operation, - "reply", - G_CALLBACK (start_operation_reply), - data); - - g_signal_emit_by_name (start_operation, - "ask-question", - message, - choices); - } - else - { - gdu_drive_activate (GDU_DRIVE (drive->presentable), start_cb, simple); - } - - return; - - not_supported: - simple = g_simple_async_result_new_error (G_OBJECT (drive), - callback, - user_data, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - "Starting drive with start_stop_type %d is not supported", - drive->start_stop_type); - g_simple_async_result_complete_in_idle (simple); - g_object_unref (simple); - return; - - refuse_degraded_without_confirmation: - simple = g_simple_async_result_new_error (G_OBJECT (drive), - callback, - user_data, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Refusing to start degraded multidisk drive without user confirmation"); - g_simple_async_result_complete_in_idle (simple); - g_object_unref (simple); - -} - -static gboolean -g_gdu_drive_start_finish (GDrive *drive, - GAsyncResult *result, - GError **error) -{ - return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); -} - -/* ---------------------------------------------------------------------------------------------------- */ - -static void -poll_media_cb (GduDevice *device, - GError *error, - gpointer user_data) -{ - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data); - - if (error != NULL) - { - /* We could handle PolicyKit integration here but this action is allowed by default - * and this won't be needed when porting to PolicyKit 1.0 anyway - */ - g_simple_async_result_set_from_error (simple, error); - g_error_free (error); - } - - g_simple_async_result_complete (simple); - g_object_unref (simple); -} - -static void -g_gdu_drive_poll_for_media (GDrive *_drive, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - GSimpleAsyncResult *simple; - GduDevice *device; - - device = gdu_presentable_get_device (drive->presentable); - if (device == NULL) - { - simple = g_simple_async_result_new_error (G_OBJECT (drive), - callback, - user_data, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Device is not active"); - g_simple_async_result_complete_in_idle (simple); - g_object_unref (simple); - } - else - { - simple = g_simple_async_result_new (G_OBJECT (drive), - callback, - user_data, - NULL); - - gdu_device_op_drive_poll_media (device, poll_media_cb, simple); - g_object_unref (device); - } -} - -static gboolean -g_gdu_drive_poll_for_media_finish (GDrive *drive, - GAsyncResult *result, - GError **error) -{ - return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); -} - -/* ---------------------------------------------------------------------------------------------------- */ - -static char * -g_gdu_drive_get_identifier (GDrive *_drive, - const char *kind) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - gchar *id; - - id = NULL; - - if (drive->device_file != NULL) - { - if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0) - id = g_strdup (drive->device_file); - } - - return id; -} - -static char ** -g_gdu_drive_enumerate_identifiers (GDrive *_drive) -{ - GGduDrive *drive = G_GDU_DRIVE (_drive); - GPtrArray *p; - - p = g_ptr_array_new (); - if (drive->device_file != NULL) - g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE)); - g_ptr_array_add (p, NULL); - - return (gchar **) g_ptr_array_free (p, FALSE); -} - -/* ---------------------------------------------------------------------------------------------------- */ - -static void -g_gdu_drive_drive_iface_init (GDriveIface *iface) -{ - iface->get_name = g_gdu_drive_get_name; - iface->get_icon = g_gdu_drive_get_icon; - iface->has_volumes = g_gdu_drive_has_volumes; - iface->get_volumes = g_gdu_drive_get_volumes; - iface->is_media_removable = g_gdu_drive_is_media_removable; - iface->has_media = g_gdu_drive_has_media; - iface->is_media_check_automatic = g_gdu_drive_is_media_check_automatic; - iface->can_eject = g_gdu_drive_can_eject; - iface->can_poll_for_media = g_gdu_drive_can_poll_for_media; - iface->eject = g_gdu_drive_eject; - iface->eject_finish = g_gdu_drive_eject_finish; - iface->eject_with_operation = g_gdu_drive_eject_with_operation; - iface->eject_with_operation_finish = g_gdu_drive_eject_with_operation_finish; - iface->poll_for_media = g_gdu_drive_poll_for_media; - iface->poll_for_media_finish = g_gdu_drive_poll_for_media_finish; - iface->get_identifier = g_gdu_drive_get_identifier; - iface->enumerate_identifiers = g_gdu_drive_enumerate_identifiers; - - iface->get_start_stop_type = g_gdu_drive_get_start_stop_type; - iface->can_start = g_gdu_drive_can_start; - iface->can_start_degraded = g_gdu_drive_can_start_degraded; - iface->can_stop = g_gdu_drive_can_stop; - iface->start = g_gdu_drive_start; - iface->start_finish = g_gdu_drive_start_finish; - iface->stop = g_gdu_drive_stop; - iface->stop_finish = g_gdu_drive_stop_finish; -} - -gboolean -g_gdu_drive_has_dev (GGduDrive *drive, - dev_t dev) -{ - return drive->dev == dev; -} - -gboolean -g_gdu_drive_has_presentable (GGduDrive *drive, - GduPresentable *presentable) -{ - return g_strcmp0 (gdu_presentable_get_id (drive->presentable), gdu_presentable_get_id (presentable)) == 0; -} - -time_t -g_gdu_drive_get_time_of_last_media_insertion (GGduDrive *drive) -{ - GduDevice *device; - time_t ret; - - ret = 0; - device = gdu_presentable_get_device (drive->presentable); - if (device != NULL) { - ret = gdu_device_get_media_detection_time (device); - g_object_unref (device); - } - return ret; -} - -GduPresentable * -g_gdu_drive_get_presentable (GGduDrive *drive) -{ - return drive->presentable; -} |