diff options
Diffstat (limited to 'gnome-2-24/monitor/hal/ghalvolume.c')
-rw-r--r-- | gnome-2-24/monitor/hal/ghalvolume.c | 1068 |
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; +} |