summaryrefslogtreecommitdiff
path: root/monitor/gdu/ggdudrive.c
diff options
context:
space:
mode:
Diffstat (limited to 'monitor/gdu/ggdudrive.c')
-rw-r--r--monitor/gdu/ggdudrive.c1244
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), &degraded);
-
- 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), &degraded))
- 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;
-}