diff options
Diffstat (limited to 'trunk/monitor/hal/ghalmount.c')
-rw-r--r-- | trunk/monitor/hal/ghalmount.c | 1132 |
1 files changed, 1132 insertions, 0 deletions
diff --git a/trunk/monitor/hal/ghalmount.c b/trunk/monitor/hal/ghalmount.c new file mode 100644 index 00000000..2c84f4b4 --- /dev/null +++ b/trunk/monitor/hal/ghalmount.c @@ -0,0 +1,1132 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* 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 <gvfsmountinfo.h> + +#include "ghalvolumemonitor.h" +#include "ghalmount.h" +#include "ghalvolume.h" + +#include "hal-utils.h" + +struct _GHalMount { + GObject parent; + + GVolumeMonitor *volume_monitor; /* owned by volume monitor */ + GHalVolume *volume; /* owned by volume monitor */ + + char *name; + GIcon *icon; + char *device_path; + char *mount_path; + + char *uuid; + + char *override_name; + GIcon *override_icon; + GFile *override_root; + gboolean cannot_unmount; + + HalDevice *device; + HalDevice *drive_device; + + GIcon *autorun_icon; + gboolean searched_for_autorun; + + gchar *xdg_volume_info_name; + GIcon *xdg_volume_info_icon; + gboolean searched_for_xdg_volume_info; +}; + +static GFile *get_root (GHalMount *hal_mount); + +static void update_from_hal (GHalMount *m, gboolean emit_changed); + +static void g_hal_mount_mount_iface_init (GMountIface *iface); + +G_DEFINE_TYPE_EXTENDED (GHalMount, g_hal_mount, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (G_TYPE_MOUNT, + g_hal_mount_mount_iface_init)) + +static void +g_hal_mount_finalize (GObject *object) +{ + GHalMount *mount; + + mount = G_HAL_MOUNT (object); + + if (mount->volume != NULL) + g_hal_volume_unset_mount (mount->volume, mount); + + g_free (mount->device_path); + g_free (mount->mount_path); + g_free (mount->uuid); + + if (mount->device != NULL) + g_object_unref (mount->device); + if (mount->drive_device != NULL) + g_object_unref (mount->drive_device); + + g_free (mount->name); + if (mount->icon != NULL) + g_object_unref (mount->icon); + + g_free (mount->override_name); + if (mount->override_icon != NULL) + g_object_unref (mount->override_icon); + + if (mount->override_root != NULL) + g_object_unref (mount->override_root); + + if (mount->autorun_icon != NULL) + g_object_unref (mount->autorun_icon); + + g_free (mount->xdg_volume_info_name); + if (mount->xdg_volume_info_icon != NULL) + g_object_unref (mount->xdg_volume_info_icon); + + if (mount->volume_monitor != NULL) + g_object_remove_weak_pointer (G_OBJECT (mount->volume_monitor), (gpointer) &(mount->volume_monitor)); + + if (G_OBJECT_CLASS (g_hal_mount_parent_class)->finalize) + (*G_OBJECT_CLASS (g_hal_mount_parent_class)->finalize) (object); +} + +static void +g_hal_mount_class_init (GHalMountClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = g_hal_mount_finalize; +} + +static void +g_hal_mount_init (GHalMount *hal_mount) +{ +} + +static void +emit_mount_changed (GHalMount *mount) +{ + g_signal_emit_by_name (mount, "changed"); + if (mount->volume_monitor != NULL) + g_signal_emit_by_name (mount->volume_monitor, "mount_changed", mount); +} + +#define KILOBYTE_FACTOR 1000.0 +#define MEGABYTE_FACTOR (1000.0 * 1000.0) +#define GIGABYTE_FACTOR (1000.0 * 1000.0 * 1000.0) + +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 +got_autorun_info_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GHalMount *mount = G_HAL_MOUNT (user_data); + + mount->autorun_icon = g_vfs_mount_info_query_autorun_info_finish (G_FILE (source_object), + res, + NULL); + + update_from_hal (mount, TRUE); + + g_object_unref (mount); +} + +static void +got_xdg_volume_info_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GHalMount *mount = G_HAL_MOUNT (user_data); + + mount->xdg_volume_info_icon = g_vfs_mount_info_query_xdg_volume_info_finish (G_FILE (source_object), + res, + &(mount->xdg_volume_info_name), + NULL); + update_from_hal (mount, TRUE); + + g_object_unref (mount); +} + +static void +do_update_from_hal (GHalMount *m) +{ + HalDevice *volume; + HalDevice *drive; + char *name; + const char *icon_name; + const char *icon_name_fallback; + 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; + gboolean is_audio_player; + const char *icon_from_hal; + const char *volume_icon_from_hal; + const char *name_from_hal; + const char *volume_name_from_hal; + gboolean is_crypto; + gboolean is_crypto_cleartext; + + volume = m->device; + drive = m->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"); + is_audio_player = hal_device_has_capability (drive, "portable_audio_player"); + icon_from_hal = hal_device_get_property_string (drive, "storage.icon.drive"); + volume_icon_from_hal = hal_device_get_property_string (volume, "storage.icon.volume"); + name_from_hal = hal_device_get_property_string (drive, "info.desktop.name"); + volume_name_from_hal = hal_device_get_property_string (volume, "info.desktop.name"); + + 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; + + /*g_warning ("drive_type='%s'", drive_type); */ + /*g_warning ("drive_bus='%s'", drive_bus); */ + /*g_warning ("drive_uses_removable_media=%d", drive_uses_removable_media); */ + + icon_name_fallback = NULL; + + if (strlen (volume_icon_from_hal) > 0) + icon_name = volume_icon_from_hal; + else if (strlen (icon_from_hal) > 0) + icon_name = icon_from_hal; + else if (is_audio_player) + icon_name = "multimedia-player"; + else if (strcmp (drive_type, "disk") == 0) + { + if (strcmp (drive_bus, "ide") == 0) + icon_name = "drive-harddisk-ata"; + else if (strcmp (drive_bus, "scsi") == 0) + icon_name = "drive-harddisk-scsi"; + else if (strcmp (drive_bus, "ieee1394") == 0) + icon_name = "drive-harddisk-ieee1394"; + else if (strcmp (drive_bus, "usb") == 0) + icon_name = "drive-harddisk-usb"; + else + icon_name = "drive-harddisk"; + } + else if (strcmp (drive_type, "cdrom") == 0) + icon_name = get_disc_icon (volume_disc_type); + else if (strcmp (drive_type, "floppy") == 0) + icon_name = "media-floppy"; + else if (strcmp (drive_type, "tape") == 0) + icon_name = "media-tape"; + else if (strcmp (drive_type, "compact_flash") == 0) + icon_name = "media-flash-cf"; + else if (strcmp (drive_type, "memory_stick") == 0) + icon_name = "media-flash-ms"; + else if (strcmp (drive_type, "smart_media") == 0) + icon_name = "media-flash-sm"; + else if (strcmp (drive_type, "sd_mmc") == 0) + icon_name = "media-flash-sd"; + else + icon_name = "drive-harddisk"; + + /* Create default fallbacks for the icon_name by default + * with get_themed_icon_with_fallbacks () */ + icon_name_fallback = icon_name; + + /* Note: we are not chaning the default fallbacks + * so we get all the fallbacks if the media-encrytped + * icon is not there */ + if (is_crypto || is_crypto_cleartext) + icon_name = "media-encrypted"; + + if (strlen (volume_name_from_hal) > 0) + name = g_strdup (volume_name_from_hal); + else if (strlen (name_from_hal) > 0) + name = g_strdup (name_from_hal); + 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 + { + char *size; + + size = format_size_for_display (volume_size); + /* Translators: %s is the size of the mount (e.g. 512 MB) */ + name = g_strdup_printf (_("%s Media"), size); + g_free (size); + } + + /* order of preference : xdg, override, probed */ + if (m->xdg_volume_info_name != NULL) + { + m->name = g_strdup (m->xdg_volume_info_name); + g_free (name); + } + else if (m->override_name != NULL) + { + m->name = g_strdup (m->override_name); + g_free (name); + } + else + m->name = name; + + /* order of preference: xdg, autorun, override, probed */ + if (m->xdg_volume_info_icon != NULL) + m->icon = g_object_ref (m->xdg_volume_info_icon); + else if (m->autorun_icon != NULL) + m->icon = g_object_ref (m->autorun_icon); + else if (m->override_icon != NULL) + m->icon = g_object_ref (m->override_icon); + else + m->icon = get_themed_icon_with_fallbacks (icon_name, + icon_name_fallback); + + /* search for .xdg-volume-info */ + if (!m->searched_for_xdg_volume_info) + { + GFile *root; + root = get_root (m); + m->searched_for_xdg_volume_info = TRUE; + g_vfs_mount_info_query_xdg_volume_info (root, + NULL, + got_xdg_volume_info_cb, + g_object_ref (m)); + g_object_unref (root); + } + + /* search for autorun.inf */ + if (!m->searched_for_autorun) + { + GFile *root; + root = get_root (m); + m->searched_for_autorun = TRUE; + g_vfs_mount_info_query_autorun_info (root, + NULL, + got_autorun_info_cb, + g_object_ref (m)); + g_object_unref (root); + } +} + + +static void +update_from_hal (GHalMount *m, gboolean emit_changed) +{ + char *old_name; + GIcon *old_icon; + + old_name = g_strdup (m->name); + old_icon = m->icon != NULL ? g_object_ref (m->icon) : NULL; + + g_free (m->name); + if (m->icon != NULL) + g_object_unref (m->icon); + do_update_from_hal (m); + + if (emit_changed) + { + if (old_name == NULL || + old_icon == NULL || + strcmp (old_name, m->name) != 0 || + (! g_icon_equal (old_icon, m->icon))) + emit_mount_changed (m); + } + g_free (old_name); + if (old_icon != NULL) + g_object_unref (old_icon); +} + +static void +hal_changed (HalDevice *device, const char *key, gpointer user_data) +{ + GHalMount *hal_mount = G_HAL_MOUNT (user_data); + + /*g_warning ("mounthal modifying %s (property %s changed)", hal_mount->device_path, key); */ + update_from_hal (hal_mount, TRUE); +} + +static void +compute_uuid (GHalMount *mount) +{ + 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 (mount->device, "volume.uuid"); + fs_label = hal_device_get_property_string (mount->device, "volume.label"); + + if (strlen (fs_uuid) == 0) + { + if (strlen (fs_label) == 0) + mount->uuid = NULL; + else + mount->uuid = g_strdup (fs_label); + } + else + mount->uuid = g_strdup (fs_uuid); +} + + +GHalMount * +g_hal_mount_new_for_hal_device (GVolumeMonitor *volume_monitor, + HalDevice *device, + GFile *override_root, + const char *override_name, + GIcon *override_icon, + gboolean cannot_unmount, + HalPool *pool, + GHalVolume *volume) +{ + HalDevice *drive_device; + const char *storage_udi; + GHalMount *mount; + + storage_udi = hal_device_get_property_string (device, "block.storage_device"); + if (storage_udi == NULL) + goto fail; + + /* g_warning ("storage_udi = %s", storage_udi); */ + + drive_device = hal_pool_get_device_by_udi (pool, storage_udi); + if (drive_device == NULL) + goto fail; + + /* g_warning ("drive_device = %p", drive_device); */ + + mount = g_object_new (G_TYPE_HAL_MOUNT, NULL); + mount->volume_monitor = volume_monitor; + g_object_add_weak_pointer (G_OBJECT (mount->volume_monitor), (gpointer) &(mount->volume_monitor)); + mount->device_path = g_strdup (hal_device_get_property_string (device, "block.device")); + mount->mount_path = g_strdup ("/"); + mount->device = g_object_ref (device); + mount->drive_device = g_object_ref (drive_device); + mount->override_root = override_root != NULL ? g_object_ref (override_root) : NULL; + mount->override_icon = override_icon != NULL ? g_object_ref (override_icon) : NULL; + mount->override_name = g_strdup (override_name); + mount->cannot_unmount = cannot_unmount; + + g_signal_connect_object (device, "hal_property_changed", (GCallback) hal_changed, mount, 0); + g_signal_connect_object (drive_device, "hal_property_changed", (GCallback) hal_changed, mount, 0); + + compute_uuid (mount); + update_from_hal (mount, FALSE); + + /* need to do this last */ + mount->volume = volume; + if (volume != NULL) + g_hal_volume_set_mount (volume, mount); + + return mount; + + fail: + return NULL; +} + +void +g_hal_mount_override_name (GHalMount *mount, const char *name) +{ + g_free (mount->override_name); + + if (name != NULL) + mount->override_name = g_strdup (name); + else + mount->override_name = NULL; + + update_from_hal (mount, TRUE); +} + +void +g_hal_mount_override_icon (GHalMount *mount, GIcon *icon) +{ + if (mount->override_icon != NULL) + g_object_unref (mount->override_icon); + + if (icon != NULL) + mount->override_icon = g_object_ref (icon); + else + mount->override_icon = NULL; + + update_from_hal (mount, TRUE); +} + +GHalMount * +g_hal_mount_new (GVolumeMonitor *volume_monitor, + GUnixMountEntry *mount_entry, + HalPool *pool, + GHalVolume *volume) +{ + HalDevice *device; + HalDevice *drive_device; + const char *storage_udi; + GHalMount *mount; + + /* If no volume for mount - Ignore internal things */ + if (volume == NULL && !g_unix_mount_guess_should_display (mount_entry)) + return NULL; + + mount = g_object_new (G_TYPE_HAL_MOUNT, NULL); + mount->volume_monitor = volume_monitor; + g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(mount->volume_monitor)); + mount->device_path = g_strdup (g_unix_mount_get_device_path (mount_entry)); + mount->mount_path = g_strdup (g_unix_mount_get_mount_path (mount_entry)); + mount->device = NULL; + mount->drive_device = NULL; + mount->uuid = NULL; + + if (pool != NULL) + { + device = hal_pool_get_device_by_capability_and_string (pool, + "volume", + "block.device", + mount->device_path); + /* g_warning ("device = %p for %s", device, mount->device_path); */ + if (device != NULL) + { + /* g_warning ("udi = %s", hal_device_get_udi (device)); */ + + storage_udi = hal_device_get_property_string (device, "block.storage_device"); + if (storage_udi == NULL) + goto not_hal; + + /* g_warning ("storage_udi = %s", storage_udi); */ + + drive_device = hal_pool_get_device_by_udi (pool, storage_udi); + if (drive_device == NULL) + goto not_hal; + + /* g_warning ("drive_device = %p", drive_device); */ + + mount->device = g_object_ref (device); + mount->drive_device = g_object_ref (drive_device); + + g_signal_connect_object (device, "hal_property_changed", (GCallback) hal_changed, mount, 0); + g_signal_connect_object (drive_device, "hal_property_changed", (GCallback) hal_changed, mount, 0); + + compute_uuid (mount); + update_from_hal (mount, FALSE); + + goto was_hal; + } + } + + not_hal: + + if (volume != NULL) + { + g_object_unref (mount); + return NULL; + } + + mount->name = g_unix_mount_guess_name (mount_entry); + mount->icon = g_unix_mount_guess_icon (mount_entry); + + was_hal: + + /* need to do this last */ + mount->volume = volume; + if (volume != NULL) + g_hal_volume_set_mount (volume, mount); + + return mount; +} + +void +g_hal_mount_unmounted (GHalMount *mount) +{ + if (mount->volume != NULL) + { + g_hal_volume_unset_mount (mount->volume, mount); + mount->volume = NULL; + emit_mount_changed (mount); + } +} + +void +g_hal_mount_unset_volume (GHalMount *mount, + GHalVolume *volume) +{ + if (mount->volume == volume) + { + mount->volume = NULL; + emit_mount_changed (mount); + } +} + +static GFile * +get_root (GHalMount *hal_mount) +{ + if (hal_mount->override_root != NULL) + return g_object_ref (hal_mount->override_root); + else + return g_file_new_for_path (hal_mount->mount_path); +} + +static GFile * +g_hal_mount_get_root (GMount *mount) +{ + GHalMount *hal_mount = G_HAL_MOUNT (mount); + + return get_root (hal_mount); +} + +static GIcon * +g_hal_mount_get_icon (GMount *mount) +{ + GHalMount *hal_mount = G_HAL_MOUNT (mount); + + return g_object_ref (hal_mount->icon); +} + +static char * +g_hal_mount_get_uuid (GMount *mount) +{ + GHalMount *hal_mount = G_HAL_MOUNT (mount); + + return g_strdup (hal_mount->uuid); +} + +static char * +g_hal_mount_get_name (GMount *mount) +{ + GHalMount *hal_mount = G_HAL_MOUNT (mount); + + return g_strdup (hal_mount->name); +} + +gboolean +g_hal_mount_has_uuid (GHalMount *mount, + const char *uuid) +{ + gboolean res; + + res = FALSE; + if (mount->uuid != NULL) + res = strcmp (mount->uuid, uuid) == 0; + + return res; +} + +gboolean +g_hal_mount_has_mount_path (GHalMount *mount, + const char *mount_path) +{ + return strcmp (mount->mount_path, mount_path) == 0; +} + +gboolean +g_hal_mount_has_udi (GHalMount *mount, + const char *udi) +{ + gboolean res; + + res = FALSE; + if (mount->device != NULL) + res = strcmp (hal_device_get_udi (mount->device), udi) == 0; + + return res; +} + +static GDrive * +g_hal_mount_get_drive (GMount *mount) +{ + GHalMount *hal_mount = G_HAL_MOUNT (mount); + GDrive *drive; + + drive = NULL; + if (hal_mount->volume != NULL) + drive = g_volume_get_drive (G_VOLUME (hal_mount->volume)); + + return drive; +} + +static GVolume * +g_hal_mount_get_volume (GMount *mount) +{ + GHalMount *hal_mount = G_HAL_MOUNT (mount); + GVolume *volume; + + volume = NULL; + if (hal_mount->volume) + volume = G_VOLUME (g_object_ref (hal_mount->volume)); + + return volume; +} + +static gboolean +g_hal_mount_can_unmount (GMount *mount) +{ + GHalMount *hal_mount = G_HAL_MOUNT (mount); + gboolean res; + + res = TRUE; + if (hal_mount->cannot_unmount) + res = FALSE; + + return res; +} + +static gboolean +g_hal_mount_can_eject (GMount *mount) +{ + GHalMount *hal_mount = G_HAL_MOUNT (mount); + GDrive *drive; + gboolean can_eject; + + can_eject = FALSE; + if (hal_mount->volume != NULL) + { + drive = g_volume_get_drive (G_VOLUME (hal_mount->volume)); + if (drive != NULL) + can_eject = g_drive_can_eject (drive); + } + + return can_eject; +} + +typedef struct { + GObject *object; + GAsyncReadyCallback callback; + gpointer user_data; + GCancellable *cancellable; + int error_fd; + GIOChannel *error_channel; + guint error_channel_source_id; + GString *error_string; + gboolean using_legacy; +} UnmountOp; + +static void +unmount_cb (GPid pid, gint status, gpointer user_data) +{ + UnmountOp *data = user_data; + GSimpleAsyncResult *simple; + + if (WEXITSTATUS (status) != 0) + { + if (data->using_legacy) + { + GError *error; + error = g_error_new_literal (G_IO_ERROR, + G_IO_ERROR_FAILED, + data->error_string->str); + simple = g_simple_async_result_new_from_error (data->object, + data->callback, + data->user_data, + error); + g_error_free (error); + } + else + { + 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_source_remove (data->error_channel_source_id); + g_io_channel_unref (data->error_channel); + g_string_free (data->error_string, TRUE); + close (data->error_fd); + g_spawn_close_pid (pid); + + g_object_unref (data->object); + g_free (data); +} + +static gboolean +unmount_read_error (GIOChannel *channel, + GIOCondition condition, + gpointer user_data) +{ + char *str; + gsize str_len; + UnmountOp *data = user_data; + + g_io_channel_read_to_end (channel, &str, &str_len, NULL); + g_string_append (data->error_string, str); + g_free (str); + return TRUE; +} + +static void +unmount_do (GMount *mount, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data, + char **argv, + gboolean using_legacy) +{ + UnmountOp *data; + GPid child_pid; + GError *error; + + data = g_new0 (UnmountOp, 1); + data->object = g_object_ref (mount); + data->callback = callback; + data->user_data = user_data; + data->cancellable = cancellable; + data->using_legacy = using_legacy; + + error = NULL; + if (!g_spawn_async_with_pipes (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, + NULL, /* standard_input */ + NULL, /* standard_output */ + &(data->error_fd), + &error)) + { + GSimpleAsyncResult *simple; + simple = g_simple_async_result_new_from_error (data->object, + data->callback, + data->user_data, + error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + g_error_free (error); + g_free (data); + return; + } + data->error_string = g_string_new (""); + data->error_channel = g_io_channel_unix_new (data->error_fd); + data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, unmount_read_error, data); + g_child_watch_add (child_pid, unmount_cb, data); +} + + +static void +g_hal_mount_unmount (GMount *mount, + GMountUnmountFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GHalMount *hal_mount = G_HAL_MOUNT (mount); + char *argv[] = {"gnome-mount", "-u", "-b", "-d", NULL, NULL}; + gboolean using_legacy = FALSE; + char *d, *m; + + d = g_strdup (hal_mount->device_path); + m = g_strdup (hal_mount->mount_path); + + if (hal_mount->device != NULL) + argv[4] = d; + else + { + using_legacy = TRUE; + argv[0] = "umount"; + argv[1] = m; + argv[2] = NULL; + } + + unmount_do (mount, cancellable, callback, user_data, argv, using_legacy); + g_free (d); + g_free (m); +} + +static gboolean +g_hal_mount_unmount_finish (GMount *mount, + GAsyncResult *result, + GError **error) +{ + return TRUE; +} + +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_mount_eject (GMount *mount, + GMountUnmountFlags flags, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GHalMount *hal_mount = G_HAL_MOUNT (mount); + GDrive *drive; + + drive = NULL; + if (hal_mount->volume != NULL) + drive = g_volume_get_drive (G_VOLUME (hal_mount->volume)); + + if (drive != NULL) + { + EjectWrapperOp *data; + data = g_new0 (EjectWrapperOp, 1); + data->object = g_object_ref (mount); + data->callback = callback; + data->user_data = user_data; + g_drive_eject (drive, flags, cancellable, eject_wrapper_callback, data); + g_object_unref (drive); + } +} + +static gboolean +g_hal_mount_eject_finish (GMount *mount, + GAsyncResult *result, + GError **error) +{ + GHalMount *hal_mount = G_HAL_MOUNT (mount); + GDrive *drive; + gboolean res; + + res = TRUE; + + drive = NULL; + if (hal_mount->volume != NULL) + drive = g_volume_get_drive (G_VOLUME (hal_mount->volume)); + + if (drive != NULL) + { + res = g_drive_eject_finish (drive, result, error); + g_object_unref (drive); + } + return res; +} + +/* TODO: handle force_rescan */ +static char ** +g_hal_mount_guess_content_type_sync (GMount *mount, + gboolean force_rescan, + GCancellable *cancellable, + GError **error) +{ + GHalMount *hal_mount = G_HAL_MOUNT (mount); + const char *disc_type; + char **x_content_types; + GFile *root; + GPtrArray *p; + char **result; + int n; + char **caps; + char *uri; + + p = g_ptr_array_new (); + + root = get_root (hal_mount); + uri = g_file_get_uri (root); + if (g_str_has_prefix (uri, "burn://")) + { + /* doesn't make sense to probe burn:/// - look at the disc type instead */ + if (hal_mount->device != NULL) + { + disc_type = hal_device_get_property_string (hal_mount->device, "volume.disc.type"); + if (disc_type != NULL) + { + if (g_str_has_prefix (disc_type, "dvd")) + g_ptr_array_add (p, g_strdup ("x-content/blank-dvd")); + else if (g_str_has_prefix (disc_type, "hddvd")) + g_ptr_array_add (p, g_strdup ("x-content/blank-hddvd")); + else if (g_str_has_prefix (disc_type, "bd")) + g_ptr_array_add (p, g_strdup ("x-content/blank-bd")); + else + g_ptr_array_add (p, g_strdup ("x-content/blank-cd")); /* assume CD */ + } + } + } + else + { + /* sniff content type */ + x_content_types = g_content_type_guess_for_tree (root); + if (x_content_types != NULL) + { + for (n = 0; x_content_types[n] != NULL; n++) + g_ptr_array_add (p, g_strdup (x_content_types[n])); + g_strfreev (x_content_types); + } + } + g_object_unref (root); + g_free (uri); + + /* also add content types from hal capabilities */ + if (hal_mount->drive_device != NULL) + { + caps = dupv_and_uniqify (hal_device_get_property_strlist (hal_mount->drive_device, "info.capabilities")); + if (caps != NULL) + { + for (n = 0; caps[n] != NULL; n++) + { + if (strcmp (caps[n], "portable_audio_player") == 0) + g_ptr_array_add (p, g_strdup ("x-content/audio-player")); + } + g_strfreev (caps); + } + } + + if (p->len == 0) + { + result = NULL; + g_ptr_array_free (p, TRUE); + } + else + { + g_ptr_array_add (p, NULL); + result = (char **) g_ptr_array_free (p, FALSE); + } + + return result; +} + +/* since we're an out-of-process volume monitor we'll just do this sync */ +static void +g_hal_mount_guess_content_type (GMount *mount, + gboolean force_rescan, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + + /* TODO: handle force_rescan */ + simple = g_simple_async_result_new (G_OBJECT (mount), + callback, + user_data, + NULL); + g_simple_async_result_complete (simple); + g_object_unref (simple); +} + +static char ** +g_hal_mount_guess_content_type_finish (GMount *mount, + GAsyncResult *result, + GError **error) +{ + /* TODO: handle force_rescan */ + return g_hal_mount_guess_content_type_sync (mount, FALSE, NULL, error); +} + +static void +g_hal_mount_mount_iface_init (GMountIface *iface) +{ + iface->get_root = g_hal_mount_get_root; + iface->get_name = g_hal_mount_get_name; + iface->get_icon = g_hal_mount_get_icon; + iface->get_uuid = g_hal_mount_get_uuid; + iface->get_drive = g_hal_mount_get_drive; + iface->get_volume = g_hal_mount_get_volume; + iface->can_unmount = g_hal_mount_can_unmount; + iface->can_eject = g_hal_mount_can_eject; + iface->unmount = g_hal_mount_unmount; + iface->unmount_finish = g_hal_mount_unmount_finish; + iface->eject = g_hal_mount_eject; + iface->eject_finish = g_hal_mount_eject_finish; + iface->guess_content_type = g_hal_mount_guess_content_type; + iface->guess_content_type_finish = g_hal_mount_guess_content_type_finish; + iface->guess_content_type_sync = g_hal_mount_guess_content_type_sync; +} |