summaryrefslogtreecommitdiff
path: root/gnome-2-24/monitor/hal/ghalvolume.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnome-2-24/monitor/hal/ghalvolume.c')
-rw-r--r--gnome-2-24/monitor/hal/ghalvolume.c1068
1 files changed, 1068 insertions, 0 deletions
diff --git a/gnome-2-24/monitor/hal/ghalvolume.c b/gnome-2-24/monitor/hal/ghalvolume.c
new file mode 100644
index 00000000..12579887
--- /dev/null
+++ b/gnome-2-24/monitor/hal/ghalvolume.c
@@ -0,0 +1,1068 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2007 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., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, 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 <gio/gio.h>
+
+#include "ghaldrive.h"
+#include "ghalvolume.h"
+#include "ghalmount.h"
+
+#include "hal-utils.h"
+
+/* Protects all fields of GHalDrive that can change */
+G_LOCK_DEFINE_STATIC(hal_volume);
+
+struct _GHalVolume {
+ GObject parent;
+
+ GVolumeMonitor *volume_monitor; /* owned by volume monitor */
+ GHalMount *mount; /* owned by volume monitor */
+ GHalDrive *drive; /* owned by volume monitor */
+
+ char *device_path;
+ char *mount_path;
+ char *uuid;
+ HalDevice *device;
+ HalDevice *drive_device;
+
+ /* set on creation if we won't create a GHalMount object ourselves
+ * and instead except to adopt one, with the given mount root,
+ * via adopt_orphan_mount()
+ */
+ GFile *foreign_mount_root;
+ GMount *foreign_mount;
+ gboolean is_mountable;
+ gboolean ignore_automount;
+
+ char *name;
+ char *icon;
+ char *icon_fallback;
+};
+
+static void g_hal_volume_volume_iface_init (GVolumeIface *iface);
+
+G_DEFINE_TYPE_EXTENDED (GHalVolume, g_hal_volume, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME,
+ g_hal_volume_volume_iface_init))
+
+static void
+g_hal_volume_finalize (GObject *object)
+{
+ GHalVolume *volume;
+
+ volume = G_HAL_VOLUME (object);
+
+ if (volume->mount != NULL)
+ g_hal_mount_unset_volume (volume->mount, volume);
+
+ if (volume->drive != NULL)
+ g_hal_drive_unset_volume (volume->drive, volume);
+
+ g_free (volume->mount_path);
+ g_free (volume->device_path);
+ g_free (volume->uuid);
+ if (volume->device != NULL)
+ g_object_unref (volume->device);
+ if (volume->drive_device != NULL)
+ g_object_unref (volume->drive_device);
+
+ if (volume->foreign_mount_root != NULL)
+ g_object_unref (volume->foreign_mount_root);
+
+ if (volume->foreign_mount != NULL)
+ g_object_unref (volume->foreign_mount);
+
+ if (volume->volume_monitor != NULL)
+ g_object_remove_weak_pointer (G_OBJECT (volume->volume_monitor), (gpointer) &(volume->volume_monitor));
+
+ g_free (volume->name);
+ g_free (volume->icon);
+ g_free (volume->icon_fallback);
+
+ if (G_OBJECT_CLASS (g_hal_volume_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_hal_volume_parent_class)->finalize) (object);
+}
+
+static void
+g_hal_volume_class_init (GHalVolumeClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = g_hal_volume_finalize;
+}
+
+static void
+g_hal_volume_init (GHalVolume *hal_volume)
+{
+}
+
+static gboolean
+changed_in_idle (gpointer data)
+{
+ GHalVolume *volume = data;
+
+ g_signal_emit_by_name (volume, "changed");
+ if (volume->volume_monitor != NULL)
+ g_signal_emit_by_name (volume->volume_monitor, "volume_changed", volume);
+ g_object_unref (volume);
+
+ return FALSE;
+}
+
+#define KILOBYTE_FACTOR 1000.0
+#define MEGABYTE_FACTOR (1000.0 * 1000.0)
+#define GIGABYTE_FACTOR (1000.0 * 1000.0 * 1000.0)
+
+/**
+ * format_size_for_display:
+ * @size: a number of octects
+ *
+ * Format a human readable string that can conveys how much storage a
+ * user-visible drive or piece of media can hold.
+ *
+ * As a matter of policy, we want this string to resemble what's on
+ * the packaging of the drive/media. Since all manufacturers use
+ * powers of 10, g_format_size_for_display() is not suitable here.
+ *
+ * TODO: we probably want to round to nearest power of two if @size is
+ * "close" (e.g. within 5%) - this is to avoid e.g. 63.4G when the
+ * packaging says "64G drive". We could also use per-drive or
+ * per-media quirks to make a better guess.
+ *
+ * Returns: A human readable string, caller must free it using
+ * g_free().
+ **/
+static char *
+format_size_for_display (guint64 size)
+{
+ char *str;
+ gdouble displayed_size;
+
+ if (size < MEGABYTE_FACTOR)
+ {
+ displayed_size = (double) size / KILOBYTE_FACTOR;
+ str = g_strdup_printf (_("%.1f kB"), displayed_size);
+ }
+ else if (size < GIGABYTE_FACTOR)
+ {
+ displayed_size = (double) size / MEGABYTE_FACTOR;
+ str = g_strdup_printf (_("%.1f MB"), displayed_size);
+ }
+ else
+ {
+ displayed_size = (double) size / GIGABYTE_FACTOR;
+ str = g_strdup_printf (_("%.1f GB"), displayed_size);
+ }
+
+ return str;
+}
+
+static void
+do_update_from_hal (GHalVolume *mv)
+{
+ const char *drive_type;
+ const char *drive_bus;
+ gboolean drive_uses_removable_media;
+ const char *volume_fs_label;
+ guint64 volume_size;
+ gboolean volume_is_disc;
+ gboolean volume_disc_has_audio;
+ gboolean volume_disc_has_data;
+ const char *volume_disc_type;
+ gboolean volume_disc_is_blank;
+ const char *volume_fsusage;
+ const char *volume_fstype;
+ HalDevice *volume;
+ HalDevice *drive;
+ char *name;
+ char *size;
+ gboolean is_crypto;
+ gboolean is_crypto_cleartext;
+
+ volume = mv->device;
+ drive = mv->drive_device;
+
+ drive_type = hal_device_get_property_string (drive, "storage.drive_type");
+ drive_bus = hal_device_get_property_string (drive, "storage.bus");
+ drive_uses_removable_media = hal_device_get_property_bool (drive, "storage.removable");
+ volume_fs_label = hal_device_get_property_string (volume, "volume.label");
+ volume_size = hal_device_get_property_uint64 (volume, "volume.size");
+ volume_is_disc = hal_device_get_property_bool (volume, "volume.is_disc");
+ volume_disc_has_audio = hal_device_get_property_bool (volume, "volume.disc.has_audio");
+ volume_disc_has_data = hal_device_get_property_bool (volume, "volume.disc.has_data");
+ volume_disc_is_blank = hal_device_get_property_bool (volume, "volume.disc.is_blank");
+ volume_disc_type = hal_device_get_property_string (volume, "volume.disc.type");
+ volume_fsusage = hal_device_get_property_string (volume, "volume.fsusage");
+ volume_fstype = hal_device_get_property_string (volume, "volume.fstype");
+
+ is_crypto = FALSE;
+ is_crypto_cleartext = FALSE;
+ if (strcmp (hal_device_get_property_string (volume, "volume.fsusage"), "crypto") == 0)
+ is_crypto = TRUE;
+ if (strlen (hal_device_get_property_string (volume, "volume.crypto_luks.clear.backing_volume")) > 0)
+ is_crypto_cleartext = TRUE;
+
+ if (volume_is_disc && volume_disc_has_audio && mv->foreign_mount_root != NULL)
+ name = g_strdup (_("Audio Disc"));
+ else
+ {
+ if (strcmp (volume_fsusage, "crypto") == 0 && strcmp (volume_fstype, "crypto_LUKS") == 0)
+ {
+ size = format_size_for_display (volume_size);
+ /* Translators: %s is the size of the volume (e.g. 512 MB) */
+ name = g_strdup_printf (_("%s Encrypted Data"), size);
+ g_free (size);
+ }
+ else
+ {
+ if (volume_fs_label != NULL && strlen (volume_fs_label) > 0)
+ name = g_strdup (volume_fs_label);
+ else if (volume_is_disc)
+ {
+ if (volume_disc_has_audio)
+ {
+ if (volume_disc_has_data)
+ name = g_strdup (_("Mixed Audio/Data Disc"));
+ else
+ name = g_strdup (_("Audio Disc"));
+ }
+ else
+ name = g_strdup (get_disc_name (volume_disc_type, volume_disc_is_blank));
+ }
+ else
+ {
+ size = format_size_for_display (volume_size);
+ /* Translators: %s is the size of the volume (e.g. 512 MB) */
+ name = g_strdup_printf (_("%s Media"), size);
+ g_free (size);
+ }
+ }
+ }
+
+ mv->name = name;
+ mv->icon = _drive_get_icon (drive); /* use the drive icon since we're unmounted */
+
+ if (is_crypto || is_crypto_cleartext)
+ {
+ mv->icon_fallback = mv->icon;
+ mv->icon = g_strdup ("drive-encrypted");
+ }
+
+ if (hal_device_get_property_bool (volume, "volume.is_mounted"))
+ mv->mount_path = g_strdup (hal_device_get_property_string (volume, "volume.mount_point"));
+ else
+ mv->mount_path = NULL;
+
+ g_object_set_data_full (G_OBJECT (mv),
+ "hal-storage-device-capabilities",
+ dupv_and_uniqify (hal_device_get_property_strlist (mv->drive_device, "info.capabilities")),
+ (GDestroyNotify) g_strfreev);
+
+ if (volume_disc_type != NULL && strlen (volume_disc_type) == 0)
+ volume_disc_type = NULL;
+ g_object_set_data_full (G_OBJECT (mv),
+ "hal-volume.disc.type",
+ g_strdup (volume_disc_type),
+ (GDestroyNotify) g_free);
+}
+
+static void
+update_from_hal (GHalVolume *mv, gboolean emit_changed)
+{
+ char *old_name;
+ char *old_icon;
+ char *old_mount_path;
+
+ G_LOCK (hal_volume);
+
+ old_name = g_strdup (mv->name);
+ old_icon = g_strdup (mv->icon);
+ old_mount_path = g_strdup (mv->mount_path);
+
+ g_free (mv->name);
+ g_free (mv->icon);
+ g_free (mv->mount_path);
+ do_update_from_hal (mv);
+
+ if (emit_changed)
+ {
+ gboolean mount_path_changed;
+
+ if ((old_mount_path == NULL && mv->mount_path != NULL) ||
+ (old_mount_path != NULL && mv->mount_path == NULL) ||
+ (old_mount_path != NULL && mv->mount_path != NULL && strcmp (old_mount_path, mv->mount_path) != 0))
+ mount_path_changed = TRUE;
+ else
+ mount_path_changed = FALSE;
+
+ if (mount_path_changed ||
+ (old_name == NULL ||
+ old_icon == NULL ||
+ strcmp (old_name, mv->name) != 0 ||
+ strcmp (old_icon, mv->icon) != 0))
+ g_idle_add (changed_in_idle, g_object_ref (mv));
+ }
+ g_free (old_name);
+ g_free (old_icon);
+ g_free (old_mount_path);
+
+ G_UNLOCK (hal_volume);
+}
+
+static void
+hal_changed (HalDevice *device, const char *key, gpointer user_data)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (user_data);
+
+ /*g_warning ("hal modifying %s (property %s changed)", hal_volume->device_path, key);*/
+ update_from_hal (hal_volume, TRUE);
+}
+
+static void
+compute_uuid (GHalVolume *volume)
+{
+ const char *fs_uuid;
+ const char *fs_label;
+
+ /* use the FS uuid before falling back to the FS label */
+
+ fs_uuid = hal_device_get_property_string (volume->device, "volume.uuid");
+ fs_label = hal_device_get_property_string (volume->device, "volume.label");
+
+ if (strlen (fs_uuid) == 0)
+ {
+ if (strlen (fs_label) == 0)
+ volume->uuid = NULL;
+ else
+ volume->uuid = g_strdup (fs_label);
+ }
+ else
+ volume->uuid = g_strdup (fs_uuid);
+}
+
+GHalVolume *
+g_hal_volume_new (GVolumeMonitor *volume_monitor,
+ HalDevice *device,
+ HalPool *pool,
+ GFile *foreign_mount_root,
+ gboolean is_mountable,
+ GHalDrive *drive)
+{
+ GHalVolume *volume;
+ HalDevice *drive_device;
+ const char *storage_udi;
+ const char *device_path;
+ gboolean ignore_automount;
+
+ ignore_automount = FALSE;
+
+ if (hal_device_has_capability (device, "block"))
+ {
+ storage_udi = hal_device_get_property_string (device, "block.storage_device");
+ if (storage_udi == NULL)
+ return NULL;
+
+ drive_device = hal_pool_get_device_by_udi (pool, storage_udi);
+ if (drive_device == NULL)
+ return NULL;
+
+ device_path = hal_device_get_property_string (device, "block.device");
+ }
+ else
+ {
+ return NULL;
+ }
+
+ if (drive_device &&
+ hal_device_has_property (drive_device, "storage.automount_enabled_hint") &&
+ !hal_device_get_property_bool (drive_device, "storage.automount_enabled_hint"))
+ ignore_automount = TRUE;
+
+ volume = g_object_new (G_TYPE_HAL_VOLUME, NULL);
+ volume->volume_monitor = volume_monitor;
+ g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(volume->volume_monitor));
+ volume->mount_path = NULL;
+ volume->device_path = g_strdup (device_path);
+ volume->device = g_object_ref (device);
+ volume->drive_device = g_object_ref (drive_device);
+ volume->foreign_mount_root = foreign_mount_root != NULL ? g_object_ref (foreign_mount_root) : NULL;
+ volume->is_mountable = is_mountable;
+ volume->ignore_automount = ignore_automount || ! hal_device_is_recently_plugged_in (device);
+
+ g_signal_connect_object (device, "hal_property_changed", (GCallback) hal_changed, volume, 0);
+ g_signal_connect_object (drive_device, "hal_property_changed", (GCallback) hal_changed, volume, 0);
+
+ compute_uuid (volume);
+ update_from_hal (volume, FALSE);
+
+ /* need to do this last */
+ volume->drive = drive;
+ if (drive != NULL)
+ g_hal_drive_set_volume (drive, volume);
+
+ return volume;
+}
+
+/**
+ * g_hal_volume_removed:
+ * @volume:
+ *
+ **/
+void
+g_hal_volume_removed (GHalVolume *volume)
+{
+
+ G_LOCK (hal_volume);
+
+ if (volume->mount != NULL)
+ {
+ g_hal_mount_unset_volume (volume->mount, volume);
+ volume->mount = NULL;
+ }
+
+ if (volume->drive != NULL)
+ {
+ g_hal_drive_unset_volume (volume->drive, volume);
+ volume->drive = NULL;
+ }
+
+ G_UNLOCK (hal_volume);
+}
+
+void
+g_hal_volume_set_mount (GHalVolume *volume,
+ GHalMount *mount)
+{
+ G_LOCK (hal_volume);
+ if (volume->mount != mount)
+ {
+
+ if (volume->mount != NULL)
+ g_hal_mount_unset_volume (volume->mount, volume);
+
+ volume->mount = mount;
+
+ g_idle_add (changed_in_idle, g_object_ref (volume));
+ }
+ G_UNLOCK (hal_volume);
+}
+
+void
+g_hal_volume_unset_mount (GHalVolume *volume,
+ GHalMount *mount)
+{
+ G_LOCK (hal_volume);
+ if (volume->mount == mount)
+ {
+ volume->mount = NULL;
+ g_idle_add (changed_in_idle, g_object_ref (volume));
+ }
+ G_UNLOCK (hal_volume);
+}
+
+void
+g_hal_volume_set_drive (GHalVolume *volume,
+ GHalDrive *drive)
+{
+ G_LOCK (hal_volume);
+ if (volume->drive != drive)
+ {
+ if (volume->drive != NULL)
+ g_hal_drive_unset_volume (volume->drive, volume);
+
+ volume->drive = drive;
+
+ g_idle_add (changed_in_idle, g_object_ref (volume));
+ }
+ G_UNLOCK (hal_volume);
+}
+
+void
+g_hal_volume_unset_drive (GHalVolume *volume,
+ GHalDrive *drive)
+{
+ G_LOCK (hal_volume);
+ if (volume->drive == drive)
+ {
+ volume->drive = NULL;
+ g_idle_add (changed_in_idle, g_object_ref (volume));
+ }
+ G_UNLOCK (hal_volume);
+}
+
+static GIcon *
+g_hal_volume_get_icon (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ GIcon *icon;
+ const char *name;
+ const char *fallback;
+
+ G_LOCK (hal_volume);
+ name = hal_volume->icon;
+
+ if (hal_volume->icon_fallback)
+ fallback = hal_volume->icon_fallback;
+ else /* if no custom fallbacks are set, use the icon to create them */
+ fallback = name;
+
+ icon = get_themed_icon_with_fallbacks (name, fallback);
+ G_UNLOCK (hal_volume);
+ return icon;
+}
+
+static char *
+g_hal_volume_get_name (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ char *name;
+
+ G_LOCK (hal_volume);
+ name = g_strdup (hal_volume->name);
+ G_UNLOCK (hal_volume);
+
+ return name;
+}
+
+static char *
+g_hal_volume_get_uuid (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ char *uuid;
+
+ G_LOCK (hal_volume);
+ uuid = g_strdup (hal_volume->uuid);
+ G_UNLOCK (hal_volume);
+
+ return uuid;
+}
+
+static gboolean
+g_hal_volume_can_mount (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = hal_volume->is_mountable;
+ G_UNLOCK (hal_volume);
+
+ return res;
+}
+
+static gboolean
+g_hal_volume_can_eject (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = FALSE;
+ if (hal_volume->drive != NULL)
+ res = g_drive_can_eject (G_DRIVE (hal_volume->drive));
+ G_UNLOCK (hal_volume);
+
+ return res;
+}
+
+static gboolean
+g_hal_volume_should_automount (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = ! (hal_volume->ignore_automount);
+ G_UNLOCK (hal_volume);
+
+ return res;
+}
+
+static GDrive *
+g_hal_volume_get_drive (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ GDrive *drive;
+
+ G_LOCK (hal_volume);
+ drive = NULL;
+ if (hal_volume->drive != NULL)
+ drive = g_object_ref (hal_volume->drive);
+ G_UNLOCK (hal_volume);
+
+ return drive;
+}
+
+static GMount *
+g_hal_volume_get_mount (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ GMount *mount;
+
+ G_LOCK (hal_volume);
+ mount = NULL;
+ if (hal_volume->foreign_mount != NULL)
+ mount = g_object_ref (hal_volume->foreign_mount);
+ else if (hal_volume->mount != NULL)
+ mount = g_object_ref (hal_volume->mount);
+ G_UNLOCK (hal_volume);
+
+ return mount;
+}
+
+gboolean
+g_hal_volume_has_mount_path (GHalVolume *volume,
+ const char *mount_path)
+{
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = FALSE;
+ if (volume->mount_path != NULL)
+ res = strcmp (volume->mount_path, mount_path) == 0;
+ G_UNLOCK (hal_volume);
+
+ return res;
+}
+
+gboolean
+g_hal_volume_has_device_path (GHalVolume *volume,
+ const char *device_path)
+{
+ gboolean res;
+
+ res = FALSE;
+ G_LOCK (hal_volume);
+ if (volume->device_path != NULL)
+ res = strcmp (volume->device_path, device_path) == 0;
+ G_UNLOCK (hal_volume);
+ return res;
+}
+
+gboolean
+g_hal_volume_has_udi (GHalVolume *volume,
+ const char *udi)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = FALSE;
+ if (hal_volume->device != NULL)
+ res = strcmp (hal_device_get_udi (hal_volume->device), udi) == 0;
+ G_UNLOCK (hal_volume);
+ return res;
+}
+
+gboolean
+g_hal_volume_has_uuid (GHalVolume *volume,
+ const char *uuid)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = FALSE;
+ if (hal_volume->uuid != NULL)
+ res = strcmp (hal_volume->uuid, uuid) == 0;
+ G_UNLOCK (hal_volume);
+
+ return res;
+}
+
+static void
+foreign_mount_unmounted (GMount *mount, gpointer user_data)
+{
+ GHalVolume *volume = G_HAL_VOLUME (user_data);
+ gboolean check;
+
+ G_LOCK (hal_volume);
+ check = volume->foreign_mount == mount;
+ G_UNLOCK (hal_volume);
+ if (check)
+ g_hal_volume_adopt_foreign_mount (volume, NULL);
+}
+
+void
+g_hal_volume_adopt_foreign_mount (GHalVolume *volume, GMount *foreign_mount)
+{
+ G_LOCK (hal_volume);
+ if (volume->foreign_mount != NULL)
+ g_object_unref (volume->foreign_mount);
+
+ if (foreign_mount != NULL)
+ {
+ volume->foreign_mount = g_object_ref (foreign_mount);
+ g_signal_connect_object (foreign_mount, "unmounted", (GCallback) foreign_mount_unmounted, volume, 0);
+ }
+ else
+ volume->foreign_mount = NULL;
+
+ g_idle_add (changed_in_idle, g_object_ref (volume));
+ G_UNLOCK (hal_volume);
+}
+
+gboolean
+g_hal_volume_has_foreign_mount_root (GHalVolume *volume,
+ GFile *mount_root)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = FALSE;
+ if (hal_volume->foreign_mount_root != NULL)
+ res = g_file_equal (hal_volume->foreign_mount_root, mount_root);
+ G_UNLOCK (hal_volume);
+
+ return res;
+}
+
+
+typedef struct {
+ GObject *object;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+ GCancellable *cancellable;
+} SpawnOp;
+
+static void
+spawn_cb (GPid pid, gint status, gpointer user_data)
+{
+ SpawnOp *data = user_data;
+ GSimpleAsyncResult *simple;
+
+ /* ensure that the #GHalMount corrosponding to the #GHalVolume we've
+ * mounted is made available before returning to the user
+ */
+ g_hal_volume_monitor_force_update (G_HAL_VOLUME_MONITOR (G_HAL_VOLUME (data->object)->volume_monitor));
+
+ if (WEXITSTATUS (status) != 0)
+ {
+ GError *error;
+ error = g_error_new_literal (G_IO_ERROR,
+ G_IO_ERROR_FAILED_HANDLED,
+ "You are not supposed to show G_IO_ERROR_FAILED_HANDLED in the UI");
+ simple = g_simple_async_result_new_from_error (data->object,
+ data->callback,
+ data->user_data,
+ error);
+ g_error_free (error);
+ }
+ else
+ {
+ simple = g_simple_async_result_new (data->object,
+ data->callback,
+ data->user_data,
+ NULL);
+ }
+
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ g_object_unref (data->object);
+ g_free (data);
+}
+
+static void
+spawn_do (GVolume *volume,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ char **argv)
+{
+ SpawnOp *data;
+ GPid child_pid;
+ GError *error;
+
+ data = g_new0 (SpawnOp, 1);
+ data->object = g_object_ref (volume);
+ data->callback = callback;
+ data->user_data = user_data;
+ data->cancellable = cancellable;
+
+ error = NULL;
+ if (!g_spawn_async (NULL, /* working dir */
+ argv,
+ NULL, /* envp */
+ G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH,
+ NULL, /* child_setup */
+ NULL, /* user_data for child_setup */
+ &child_pid,
+ &error))
+ {
+ g_simple_async_report_gerror_in_idle (data->object,
+ data->callback,
+ data->user_data,
+ error);
+ g_object_unref (data->object);
+ g_error_free (error);
+ g_free (data);
+ return;
+ }
+
+ g_child_watch_add (child_pid, spawn_cb, data);
+}
+
+typedef struct
+{
+ GHalVolume *enclosing_volume;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} ForeignMountOp;
+
+static void
+mount_foreign_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ ForeignMountOp *data = user_data;
+ data->callback (G_OBJECT (data->enclosing_volume), res, data->user_data);
+ g_object_unref (data->enclosing_volume);
+ g_free (data);
+}
+
+static void
+g_hal_volume_mount (GVolume *volume,
+ GMountMountFlags flags,
+ GMountOperation *mount_operation,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+
+ /*g_warning ("hal_volume_mount (can_mount=%d foreign=%p device_path=%s)",
+ g_hal_volume_can_mount (volume),
+ hal_volume->foreign_mount_root,
+ hal_volume->device_path);*/
+
+ G_LOCK (hal_volume);
+ if (hal_volume->foreign_mount_root != NULL)
+ {
+ ForeignMountOp *data;
+
+ data = g_new0 (ForeignMountOp, 1);
+ data->enclosing_volume = g_object_ref (hal_volume);
+ data->callback = callback;
+ data->user_data = user_data;
+
+ g_file_mount_enclosing_volume (hal_volume->foreign_mount_root,
+ 0,
+ mount_operation,
+ cancellable,
+ mount_foreign_callback,
+ data);
+ }
+ else
+ {
+ char *argv[] = {"gnome-mount", "-b", "-d", NULL, NULL, NULL};
+ argv[3] = hal_volume->device_path;
+ /* ask for no dialogs if mount_operation is NULL */
+ if (mount_operation == NULL)
+ argv[4] = "-n";
+ spawn_do (volume, cancellable, callback, user_data, argv);
+ }
+ G_UNLOCK (hal_volume);
+}
+
+static gboolean
+g_hal_volume_mount_finish (GVolume *volume,
+ GAsyncResult *result,
+ GError **error)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = TRUE;
+
+ if (hal_volume->foreign_mount_root != NULL)
+ res = g_file_mount_enclosing_volume_finish (hal_volume->foreign_mount_root, result, error);
+
+ G_UNLOCK (hal_volume);
+
+ return res;
+}
+
+typedef struct {
+ GObject *object;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} EjectWrapperOp;
+
+static void
+eject_wrapper_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ EjectWrapperOp *data = user_data;
+ data->callback (data->object, res, data->user_data);
+ g_object_unref (data->object);
+ g_free (data);
+}
+
+static void
+g_hal_volume_eject (GVolume *volume,
+ GMountUnmountFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ GHalDrive *drive;
+
+ /*g_warning ("hal_volume_eject");*/
+
+ drive = NULL;
+ G_LOCK (hal_volume);
+ if (hal_volume->drive != NULL)
+ drive = g_object_ref (hal_volume->drive);
+ G_UNLOCK (hal_volume);
+
+ if (drive != NULL)
+ {
+ EjectWrapperOp *data;
+ data = g_new0 (EjectWrapperOp, 1);
+ data->object = g_object_ref (volume);
+ data->callback = callback;
+ data->user_data = user_data;
+ g_drive_eject (G_DRIVE (drive), flags, cancellable, eject_wrapper_callback, data);
+ g_object_unref (drive);
+ }
+}
+
+static gboolean
+g_hal_volume_eject_finish (GVolume *volume,
+ GAsyncResult *result,
+ GError **error)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ gboolean res;
+
+ G_LOCK (hal_volume);
+ res = TRUE;
+ if (hal_volume->drive != NULL)
+ res = g_drive_eject_finish (G_DRIVE (hal_volume->drive), result, error);
+ G_UNLOCK (hal_volume);
+ return res;
+}
+
+static char *
+g_hal_volume_get_identifier (GVolume *volume,
+ const char *kind)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ char *id;
+
+ G_LOCK (hal_volume);
+ id = NULL;
+ if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_HAL_UDI) == 0)
+ id = g_strdup (hal_device_get_udi (hal_volume->device));
+ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0)
+ id = g_strdup (hal_volume->device_path);
+ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_LABEL) == 0)
+ id = g_strdup (hal_device_get_property_string (hal_volume->device, "volume.label"));
+ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UUID) == 0)
+ id = g_strdup (hal_device_get_property_string (hal_volume->device, "volume.uuid"));
+ G_UNLOCK (hal_volume);
+
+ return id;
+}
+
+static char **
+g_hal_volume_enumerate_identifiers (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ GPtrArray *res;
+ const char *label, *uuid;
+
+ G_LOCK (hal_volume);
+
+ res = g_ptr_array_new ();
+
+ g_ptr_array_add (res,
+ g_strdup (G_VOLUME_IDENTIFIER_KIND_HAL_UDI));
+
+ if (hal_volume->device_path && *hal_volume->device_path != 0)
+ g_ptr_array_add (res,
+ g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE));
+
+ label = hal_device_get_property_string (hal_volume->device, "volume.label");
+ uuid = hal_device_get_property_string (hal_volume->device, "volume.uuid");
+
+ if (label && *label != 0)
+ g_ptr_array_add (res,
+ g_strdup (G_VOLUME_IDENTIFIER_KIND_LABEL));
+
+ if (uuid && *uuid != 0)
+ g_ptr_array_add (res,
+ g_strdup (G_VOLUME_IDENTIFIER_KIND_UUID));
+
+ /* Null-terminate */
+ g_ptr_array_add (res, NULL);
+
+ G_UNLOCK (hal_volume);
+
+ return (char **)g_ptr_array_free (res, FALSE);
+}
+
+static GFile *
+g_hal_volume_get_activation_root (GVolume *volume)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ GFile *root = NULL;
+
+ G_LOCK (hal_volume);
+ if (hal_volume->foreign_mount_root != NULL)
+ root = g_object_ref (hal_volume->foreign_mount_root);
+ G_UNLOCK (hal_volume);
+
+ return root;
+}
+
+static void
+g_hal_volume_volume_iface_init (GVolumeIface *iface)
+{
+ iface->get_name = g_hal_volume_get_name;
+ iface->get_icon = g_hal_volume_get_icon;
+ iface->get_uuid = g_hal_volume_get_uuid;
+ iface->get_drive = g_hal_volume_get_drive;
+ iface->get_mount = g_hal_volume_get_mount;
+ iface->can_mount = g_hal_volume_can_mount;
+ iface->can_eject = g_hal_volume_can_eject;
+ iface->should_automount = g_hal_volume_should_automount;
+ iface->mount_fn = g_hal_volume_mount;
+ iface->mount_finish = g_hal_volume_mount_finish;
+ iface->eject = g_hal_volume_eject;
+ iface->eject_finish = g_hal_volume_eject_finish;
+ iface->get_identifier = g_hal_volume_get_identifier;
+ iface->enumerate_identifiers = g_hal_volume_enumerate_identifiers;
+ iface->get_activation_root = g_hal_volume_get_activation_root;
+}