diff --git a/gdu-0001-Bug-573826-gdu-volume-monitor.patch b/gdu-0001-Bug-573826-gdu-volume-monitor.patch new file mode 100644 index 0000000..6731f35 --- /dev/null +++ b/gdu-0001-Bug-573826-gdu-volume-monitor.patch @@ -0,0 +1,5250 @@ +From 9d51c0de20170731db25422e858fee0e44b1dbd1 Mon Sep 17 00:00:00 2001 +From: David Zeuthen +Date: Thu, 9 Apr 2009 19:01:18 -0400 +Subject: [PATCH 1/7] =?utf-8?q?Bug=20573826=20=E2=80=93=20gdu=20volume=20monitor?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit + +Add the GNOME Disk Utility based volume monitor, see + + http://bugzilla.gnome.org/show_bug.cgi?id=573826 + http://mail.gnome.org/archives/gvfs-list/2009-March/msg00002.html + +for details. +--- + configure.ac | 28 +- + monitor/Makefile.am | 4 + + monitor/gdu/Makefile.am | 53 + + monitor/gdu/gdu-volume-monitor-daemon.c | 46 + + monitor/gdu/gdu.monitor | 5 + + monitor/gdu/ggdudrive.c | 691 ++++++++++ + monitor/gdu/ggdudrive.h | 69 + + monitor/gdu/ggdumount.c | 958 +++++++++++++ + monitor/gdu/ggdumount.h | 64 + + monitor/gdu/ggduvolume.c | 1408 +++++++++++++++++++ + monitor/gdu/ggduvolume.h | 78 ++ + monitor/gdu/ggduvolumemonitor.c | 1432 ++++++++++++++++++++ + monitor/gdu/ggduvolumemonitor.h | 60 + + .../org.gtk.Private.GduVolumeMonitor.service.in | 3 + + monitor/gdu/polkit.c | 137 ++ + monitor/gdu/polkit.h | 44 + + 16 files changed, 5079 insertions(+), 1 deletions(-) + create mode 100644 monitor/gdu/Makefile.am + create mode 100644 monitor/gdu/gdu-volume-monitor-daemon.c + create mode 100644 monitor/gdu/gdu.monitor + create mode 100644 monitor/gdu/ggdudrive.c + create mode 100644 monitor/gdu/ggdudrive.h + create mode 100644 monitor/gdu/ggdumount.c + create mode 100644 monitor/gdu/ggdumount.h + create mode 100644 monitor/gdu/ggduvolume.c + create mode 100644 monitor/gdu/ggduvolume.h + create mode 100644 monitor/gdu/ggduvolumemonitor.c + create mode 100644 monitor/gdu/ggduvolumemonitor.h + create mode 100644 monitor/gdu/org.gtk.Private.GduVolumeMonitor.service.in + create mode 100644 monitor/gdu/polkit.c + create mode 100644 monitor/gdu/polkit.h + +diff --git a/configure.ac b/configure.ac +index 311127e..895309b 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -198,6 +198,30 @@ AC_SUBST(GCONF_CFLAGS) + + AM_CONDITIONAL(USE_GCONF, [test "$msg_gconf" = "yes"]) + ++dnl ************************************ ++dnl *** Check for gnome-disk-utility *** ++dnl ************************************ ++ ++AC_ARG_ENABLE(gdu, [ --disable-gdu build without GDU volume monitor]) ++msg_gdu=no ++GDU_LIBS= ++GDU_CFLAGS= ++GDU_REQUIRED=0.3 ++ ++if test "x$enable_gdu" != "xno"; then ++ PKG_CHECK_EXISTS([gdu >= $GDU_REQUIRED], msg_gdu=yes) ++ ++ if test "x$msg_gdu" == "xyes"; then ++ PKG_CHECK_MODULES([GDU],[gdu >= $GDU_REQUIRED]) ++ AC_DEFINE(HAVE_GDU, 1, [Define to 1 if gnome-disk-utility is available]) ++ fi ++fi ++ ++AC_SUBST(GDU_LIBS) ++AC_SUBST(GDU_CFLAGS) ++ ++AM_CONDITIONAL(USE_GDU, [test "$msg_gdu" = "yes"]) ++ + dnl ********************** + dnl *** Check for HAL *** + dnl ********************** +@@ -558,6 +582,7 @@ daemon/Makefile + monitor/Makefile + monitor/proxy/Makefile + monitor/hal/Makefile ++monitor/gdu/Makefile + monitor/gphoto2/Makefile + gconf/Makefile + programs/Makefile +@@ -579,7 +604,8 @@ echo " + archive support: $msg_archive + GConf support: $msg_gconf + DNS-SD support: $msg_avahi +- Use HAL for volume monitor: $msg_hal (with fast init path: $have_hal_fast_init) ++ Build HAL volume monitor: $msg_hal (with fast init path: $have_hal_fast_init) ++ Build GDU volume monitor: $msg_gdu + GNOME Keyring support: $msg_keyring + Bash-completion support: $msg_bash_completion + " +diff --git a/monitor/Makefile.am b/monitor/Makefile.am +index d4197d5..f68423e 100644 +--- a/monitor/Makefile.am ++++ b/monitor/Makefile.am +@@ -5,6 +5,10 @@ if USE_HAL + SUBDIRS += hal + endif + ++if USE_GDU ++SUBDIRS += gdu ++endif ++ + if USE_GPHOTO2 + SUBDIRS += gphoto2 + endif +diff --git a/monitor/gdu/Makefile.am b/monitor/gdu/Makefile.am +new file mode 100644 +index 0000000..10b80f3 +--- /dev/null ++++ b/monitor/gdu/Makefile.am +@@ -0,0 +1,53 @@ ++ ++NULL = ++ ++libexec_PROGRAMS = gvfs-gdu-volume-monitor ++ ++ ++gvfs_gdu_volume_monitor_SOURCES = \ ++ gdu-volume-monitor-daemon.c \ ++ ggdudrive.c ggdudrive.h \ ++ ggduvolume.c ggduvolume.h \ ++ ggdumount.c ggdumount.h \ ++ ggduvolumemonitor.c ggduvolumemonitor.h \ ++ polkit.c polkit.h \ ++ $(NULL) ++ ++gvfs_gdu_volume_monitor_CFLAGS = \ ++ -DG_LOG_DOMAIN=\"GVFS-Gdu\" \ ++ -I$(top_srcdir)/common \ ++ -I$(top_srcdir)/monitor/proxy \ ++ $(GLIB_CFLAGS) \ ++ $(GDU_CFLAGS) \ ++ $(DBUS_CFLAGS) \ ++ -DGIO_MODULE_DIR=\"$(GIO_MODULE_DIR)\" \ ++ -DGVFS_LOCALEDIR=\""$(localedir)"\" \ ++ -DG_DISABLE_DEPRECATED \ ++ -DGDU_API_IS_SUBJECT_TO_CHANGE \ ++ $(NULL) ++ ++gvfs_gdu_volume_monitor_LDFLAGS = \ ++ $(NULL) ++ ++gvfs_gdu_volume_monitor_LDADD = \ ++ $(GLIB_LIBS) \ ++ $(GDU_LIBS) \ ++ $(DBUS_LIBS) \ ++ $(top_builddir)/common/libgvfscommon.la \ ++ $(top_builddir)/monitor/proxy/libgvfsproxyvolumemonitordaemon-noin.la \ ++ $(NULL) ++ ++remote_volume_monitorsdir = $(datadir)/gvfs/remote-volume-monitors ++remote_volume_monitors_DATA = gdu.monitor ++ ++servicedir = $(datadir)/dbus-1/services ++service_in_files = org.gtk.Private.GduVolumeMonitor.service.in ++service_DATA = $(service_in_files:.service.in=.service) ++ ++$(service_DATA): $(service_in_files) Makefile ++ @sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ ++ ++clean-local: ++ rm -f *~ *.loT $(BUILT_SOURCES) $(service_DATA) ++ ++EXTRA_DIST = $(service_in_files) gdu.monitor +diff --git a/monitor/gdu/gdu-volume-monitor-daemon.c b/monitor/gdu/gdu-volume-monitor-daemon.c +new file mode 100644 +index 0000000..cdb4f84 +--- /dev/null ++++ b/monitor/gdu/gdu-volume-monitor-daemon.c +@@ -0,0 +1,46 @@ ++/* -*- 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., 59 Temple Place, Suite 330, ++ * Boston, MA 02111-1307, USA. ++ * ++ * Author: David Zeuthen ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "ggduvolumemonitor.h" ++ ++int ++main (int argc, char *argv[]) ++{ ++ g_vfs_proxy_volume_monitor_daemon_init (); ++ ++ g_set_application_name (_("GVfs GDU Volume Monitor")); ++ ++ return g_vfs_proxy_volume_monitor_daemon_main (argc, ++ argv, ++ "org.gtk.Private.GduVolumeMonitor", ++ G_TYPE_GDU_VOLUME_MONITOR); ++} +diff --git a/monitor/gdu/gdu.monitor b/monitor/gdu/gdu.monitor +new file mode 100644 +index 0000000..9a97695 +--- /dev/null ++++ b/monitor/gdu/gdu.monitor +@@ -0,0 +1,5 @@ ++[RemoteVolumeMonitor] ++Name=GProxyVolumeMonitorGdu ++DBusName=org.gtk.Private.GduVolumeMonitor ++IsNative=true ++NativePriority=3 +diff --git a/monitor/gdu/ggdudrive.c b/monitor/gdu/ggdudrive.c +new file mode 100644 +index 0000000..257a113 +--- /dev/null ++++ b/monitor/gdu/ggdudrive.c +@@ -0,0 +1,691 @@ ++/* -*- 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., 59 Temple Place, Suite 330, ++ * Boston, MA 02111-1307, USA. ++ * ++ * Author: David Zeuthen ++ */ ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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; ++ gboolean is_media_removable; ++ gboolean has_media; ++ gboolean can_eject; ++ gboolean can_poll_for_media; ++ gboolean is_media_check_automatic; ++ time_t time_of_last_media_insertion; ++}; ++ ++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; ++ gboolean old_is_media_removable; ++ gboolean old_has_media; ++ gboolean old_can_eject; ++ 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_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_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); ++ drive->name = gdu_presentable_get_name (drive->presentable); ++ ++ /* the GduDevice for an activatable drive (such as RAID) is NULL if the drive is not activated */ ++ if (device == NULL) ++ { ++ g_free (drive->device_file); ++ drive->device_file = NULL; ++ drive->is_media_removable = TRUE; ++ drive->has_media = TRUE; ++ drive->can_eject = FALSE; ++ } ++ else ++ { ++ g_free (drive->device_file); ++ 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); ++ drive->can_eject = gdu_device_drive_get_is_media_ejectable (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 = TRUE; ++ } ++ ++ if (device != NULL) ++ g_object_unref (device); ++ ++ if (drive->has_media != old_has_media) ++ drive->time_of_last_media_insertion = time (NULL); ++ ++ /* 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_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) && ++ 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); ++ ++ drive->time_of_last_media_insertion = time (NULL); ++ ++ 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 void ++eject_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_eject_do (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, ++ "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); ++ g_object_unref (device); ++ } ++} ++ ++typedef struct { ++ GDrive *drive; ++ GAsyncReadyCallback callback; ++ gpointer user_data; ++ GCancellable *cancellable; ++ GMountUnmountFlags flags; ++ ++ GList *pending_mounts; ++} 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 _eject_unmount_mounts (UnmountMountsOp *data); ++ ++static void ++_eject_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_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 media; one or more volumes on the media 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.. */ ++ _eject_unmount_mounts (data); ++ } ++ ++ g_object_unref (mount); ++} ++ ++static void ++_eject_unmount_mounts (UnmountMountsOp *data) ++{ ++ GMount *mount; ++ ++ if (data->pending_mounts == NULL) ++ { ++ ++ /*g_warning ("all pending mounts done; ejecting drive");*/ ++ ++ g_gdu_drive_eject_do (data->drive, ++ data->cancellable, ++ data->callback, ++ data->user_data); ++ ++ g_object_unref (data->drive); ++ g_free (data); ++ } ++ else ++ { ++ mount = data->pending_mounts->data; ++ data->pending_mounts = g_list_remove (data->pending_mounts, mount); ++ ++ /*g_warning ("unmounting %p", mount);*/ ++ ++ g_mount_unmount (mount, ++ data->flags, ++ data->cancellable, ++ _eject_unmount_mounts_cb, ++ data); ++ } ++} ++ ++static void ++g_gdu_drive_eject (GDrive *drive, ++ GMountUnmountFlags flags, ++ GCancellable *cancellable, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ GGduDrive *gdu_drive = G_GDU_DRIVE (drive); ++ UnmountMountsOp *data; ++ GList *l; ++ ++ /* first we need to go through all the volumes and unmount their assoicated mounts (if any) */ ++ ++ data = g_new0 (UnmountMountsOp, 1); ++ data->drive = g_object_ref (drive); ++ data->cancellable = cancellable; ++ data->callback = callback; ++ data->user_data = user_data; ++ data->flags = flags; ++ ++ for (l = gdu_drive->volumes; l != NULL; l = l->next) ++ { ++ GGduVolume *volume = l->data; ++ GMount *mount; ++ ++ 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)); ++ } ++ ++ _eject_unmount_mounts (data); ++} ++ ++static gboolean ++g_gdu_drive_eject_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->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; ++} ++ ++gboolean ++g_gdu_drive_has_device_file (GGduDrive *drive, ++ const gchar *device_file) ++{ ++ return g_strcmp0 (drive->device_file, device_file) == 0; ++} ++ ++gboolean ++g_gdu_drive_has_presentable (GGduDrive *drive, ++ GduPresentable *presentable) ++{ ++ return gdu_presentable_get_id (drive->presentable) == gdu_presentable_get_id (presentable); ++} ++ ++time_t ++g_gdu_drive_get_time_of_last_media_insertion (GGduDrive *drive) ++{ ++ return drive->time_of_last_media_insertion; ++} ++ ++GduPresentable * ++g_gdu_drive_get_presentable (GGduDrive *drive) ++{ ++ return drive->presentable; ++} +diff --git a/monitor/gdu/ggdudrive.h b/monitor/gdu/ggdudrive.h +new file mode 100644 +index 0000000..e182c29 +--- /dev/null ++++ b/monitor/gdu/ggdudrive.h +@@ -0,0 +1,69 @@ ++/* -*- 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., 59 Temple Place, Suite 330, ++ * Boston, MA 02111-1307, USA. ++ * ++ * Author: David Zeuthen ++ */ ++ ++#ifndef __G_GDU_DRIVE_H__ ++#define __G_GDU_DRIVE_H__ ++ ++#include ++#include ++ ++#include "ggduvolumemonitor.h" ++ ++G_BEGIN_DECLS ++ ++#define G_TYPE_GDU_DRIVE (g_gdu_drive_get_type ()) ++#define G_GDU_DRIVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_GDU_DRIVE, GGduDrive)) ++#define G_GDU_DRIVE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_GDU_DRIVE, GGduDriveClass)) ++#define G_IS_GDU_DRIVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_GDU_DRIVE)) ++#define G_IS_GDU_DRIVE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_GDU_DRIVE)) ++ ++typedef struct _GGduDriveClass GGduDriveClass; ++ ++struct _GGduDriveClass { ++ GObjectClass parent_class; ++}; ++ ++GType g_gdu_drive_get_type (void) G_GNUC_CONST; ++ ++GGduDrive *g_gdu_drive_new (GVolumeMonitor *volume_monitor, ++ GduPresentable *presentable); ++void g_gdu_drive_set_volume (GGduDrive *drive, ++ GGduVolume *volume); ++void g_gdu_drive_unset_volume (GGduDrive *drive, ++ GGduVolume *volume); ++void g_gdu_drive_disconnected (GGduDrive *drive); ++gboolean g_gdu_drive_has_device_file (GGduDrive *drive, ++ const gchar *device_file); ++time_t g_gdu_drive_get_time_of_last_media_insertion (GGduDrive *drive); ++ ++gboolean g_gdu_drive_has_presentable (GGduDrive *drive, ++ GduPresentable *presentable); ++ ++GduPresentable *g_gdu_drive_get_presentable (GGduDrive *drive); ++ ++ ++char * _drive_get_icon (GduDevice *d); ++ ++G_END_DECLS ++ ++#endif /* __G_GDU_DRIVE_H__ */ +diff --git a/monitor/gdu/ggdumount.c b/monitor/gdu/ggdumount.c +new file mode 100644 +index 0000000..27c22d9 +--- /dev/null ++++ b/monitor/gdu/ggdumount.c +@@ -0,0 +1,958 @@ ++/* -*- 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., 59 Temple Place, Suite 330, ++ * Boston, MA 02111-1307, USA. ++ * ++ * Author: David Zeuthen ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++#include "ggduvolumemonitor.h" ++#include "ggdumount.h" ++#include "ggduvolume.h" ++ ++struct _GGduMount ++{ ++ GObject parent; ++ ++ GVolumeMonitor *volume_monitor; /* owned by volume monitor */ ++ GGduVolume *volume; /* owned by volume monitor */ ++ ++ /* the following members need to be set upon construction */ ++ GFile *root; ++ GIcon *icon; ++ gchar *name; ++ gchar *uuid; ++ gchar *device_file; ++ gchar *mount_path; ++ gboolean can_unmount; ++ ++ gchar *mount_entry_name; ++ GIcon *mount_entry_icon; ++ ++ gboolean is_burn_mount; ++ ++ GIcon *autorun_icon; ++ gboolean searched_for_autorun; ++ ++ gchar *xdg_volume_info_name; ++ GIcon *xdg_volume_info_icon; ++ gboolean searched_for_xdg_volume_info; ++}; ++ ++static gboolean update_mount (GGduMount *mount); ++ ++static void g_gdu_mount_mount_iface_init (GMountIface *iface); ++ ++G_DEFINE_TYPE_EXTENDED (GGduMount, g_gdu_mount, G_TYPE_OBJECT, 0, ++ G_IMPLEMENT_INTERFACE (G_TYPE_MOUNT, ++ g_gdu_mount_mount_iface_init)) ++ ++static void ++volume_changed (GVolume *volume, ++ gpointer user_data); ++ ++static void ++g_gdu_mount_finalize (GObject *object) ++{ ++ GGduMount *mount; ++ ++ mount = G_GDU_MOUNT (object); ++ ++ if (mount->volume != NULL) ++ { ++ g_signal_handlers_disconnect_by_func (mount->volume, volume_changed, mount); ++ g_gdu_volume_unset_mount (mount->volume, mount); ++ } ++ ++ if (mount->root != NULL) ++ g_object_unref (mount->root); ++ if (mount->icon != NULL) ++ g_object_unref (mount->icon); ++ g_free (mount->name); ++ g_free (mount->uuid); ++ g_free (mount->device_file); ++ g_free (mount->mount_path); ++ ++ g_free (mount->mount_entry_name); ++ if (mount->mount_entry_icon != NULL) ++ g_object_unref (mount->mount_entry_icon); ++ ++ 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 (G_OBJECT_CLASS (g_gdu_mount_parent_class)->finalize) ++ (*G_OBJECT_CLASS (g_gdu_mount_parent_class)->finalize) (object); ++} ++ ++static void ++g_gdu_mount_class_init (GGduMountClass *klass) ++{ ++ GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ++ ++ gobject_class->finalize = g_gdu_mount_finalize; ++} ++ ++static void ++g_gdu_mount_init (GGduMount *mount) ++{ ++} ++ ++static void ++emit_changed (GGduMount *mount) ++{ ++ g_signal_emit_by_name (mount, "changed"); ++ g_signal_emit_by_name (mount->volume_monitor, "mount_changed", mount); ++} ++ ++static void ++got_autorun_info_cb (GObject *source_object, ++ GAsyncResult *res, ++ gpointer user_data) ++{ ++ GGduMount *mount = G_GDU_MOUNT (user_data); ++ ++ mount->autorun_icon = g_vfs_mount_info_query_autorun_info_finish (G_FILE (source_object), ++ res, ++ NULL); ++ ++ if (update_mount (mount)) ++ emit_changed (mount); ++ ++ g_object_unref (mount); ++} ++ ++static void ++got_xdg_volume_info_cb (GObject *source_object, ++ GAsyncResult *res, ++ gpointer user_data) ++{ ++ GGduMount *mount = G_GDU_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); ++ if (update_mount (mount)) ++ emit_changed (mount); ++ ++ g_object_unref (mount); ++} ++ ++static gboolean ++update_mount (GGduMount *mount) ++{ ++ gboolean changed; ++ gboolean old_can_unmount; ++ gchar *old_name; ++ GIcon *old_icon; ++ ++ /* save old values */ ++ old_can_unmount = mount->can_unmount; ++ old_name = g_strdup (mount->name); ++ old_icon = mount->icon != NULL ? g_object_ref (mount->icon) : NULL; ++ ++ /* in with the new */ ++ if (mount->volume != NULL) ++ { ++ mount->can_unmount = TRUE; ++ ++ if (mount->icon != NULL) ++ g_object_unref (mount->icon); ++ ++ /* order of preference: xdg, autorun, probed */ ++ if (mount->xdg_volume_info_icon != NULL) ++ mount->icon = g_object_ref (mount->xdg_volume_info_icon); ++ else if (mount->autorun_icon != NULL) ++ mount->icon = g_object_ref (mount->autorun_icon); ++ else ++ mount->icon = g_volume_get_icon (G_VOLUME (mount->volume)); ++ ++ g_free (mount->name); ++ ++ /* order of preference : xdg, probed */ ++ if (mount->xdg_volume_info_name != NULL) ++ mount->name = g_strdup (mount->xdg_volume_info_name); ++ else ++ mount->name = g_volume_get_name (G_VOLUME (mount->volume)); ++ } ++ else ++ { ++ mount->can_unmount = TRUE; ++ ++ if (mount->icon != NULL) ++ g_object_unref (mount->icon); ++ ++ /* order of preference: xdg, autorun, probed */ ++ if (mount->xdg_volume_info_icon != NULL) ++ mount->icon = g_object_ref (mount->xdg_volume_info_icon); ++ else if (mount->autorun_icon != NULL) ++ mount->icon = g_object_ref (mount->autorun_icon); ++ else ++ mount->icon = mount->mount_entry_icon != NULL ? g_object_ref (mount->mount_entry_icon) : NULL; ++ ++ g_free (mount->name); ++ ++ /* order of preference : xdg, probed */ ++ if (mount->xdg_volume_info_name != NULL) ++ mount->name = g_strdup (mount->xdg_volume_info_name); ++ else ++ mount->name = g_strdup (mount->mount_entry_name); ++ } ++ ++ /* compute whether something changed */ ++ changed = !((old_can_unmount == mount->can_unmount) && ++ (g_strcmp0 (old_name, mount->name) == 0) && ++ g_icon_equal (old_icon, mount->icon) ++ ); ++ ++ /* free old values */ ++ g_free (old_name); ++ if (old_icon != NULL) ++ g_object_unref (old_icon); ++ ++ /*g_debug ("in update_mount(), changed=%d", changed);*/ ++ ++ /* search for .xdg-volume-info */ ++ if (!mount->searched_for_xdg_volume_info) ++ { ++ mount->searched_for_xdg_volume_info = TRUE; ++ g_vfs_mount_info_query_xdg_volume_info (mount->root, ++ NULL, ++ got_xdg_volume_info_cb, ++ g_object_ref (mount)); ++ } ++ ++ /* search for autorun.inf */ ++ if (!mount->searched_for_autorun) ++ { ++ mount->searched_for_autorun = TRUE; ++ g_vfs_mount_info_query_autorun_info (mount->root, ++ NULL, ++ got_autorun_info_cb, ++ g_object_ref (mount)); ++ } ++ ++ return changed; ++} ++ ++static void ++volume_changed (GVolume *volume, ++ gpointer user_data) ++{ ++ GGduMount *mount = G_GDU_MOUNT (user_data); ++ ++ if (update_mount (mount)) ++ emit_changed (mount); ++} ++ ++GGduMount * ++g_gdu_mount_new (GVolumeMonitor *volume_monitor, ++ GUnixMountEntry *mount_entry, ++ GGduVolume *volume) ++{ ++ GGduMount *mount; ++ ++ mount = NULL; ++ ++ /* Ignore internal mounts unless there's a volume */ ++ if (volume == NULL && (mount_entry != NULL && !g_unix_mount_guess_should_display (mount_entry))) ++ goto out; ++ ++ mount = g_object_new (G_TYPE_GDU_MOUNT, NULL); ++ mount->volume_monitor = volume_monitor; ++ g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(mount->volume_monitor)); ++ ++ if (mount_entry != NULL) ++ { ++ /* No ref on GUnixMountEntry so save values for later use */ ++ mount->mount_entry_name = g_unix_mount_guess_name (mount_entry); ++ mount->mount_entry_icon = g_unix_mount_guess_icon (mount_entry); ++ mount->device_file = g_strdup (g_unix_mount_get_device_path (mount_entry)); ++ mount->mount_path = g_strdup (g_unix_mount_get_mount_path (mount_entry)); ++ mount->root = g_file_new_for_path (mount->mount_path); ++ } ++ else ++ { ++ /* burn:/// mount (the only mounts we support with mount_entry == NULL) */ ++ mount->device_file = NULL; ++ mount->mount_path = NULL; ++ mount->root = g_file_new_for_uri ("burn:///"); ++ mount->is_burn_mount = TRUE; ++ } ++ ++ /* need to set the volume only when the mount is fully constructed */ ++ mount->volume = volume; ++ if (mount->volume != NULL) ++ { ++ g_gdu_volume_set_mount (volume, mount); ++ /* this is for piggy backing on the name and icon of the associated volume */ ++ g_signal_connect (mount->volume, "changed", G_CALLBACK (volume_changed), mount); ++ } ++ ++ update_mount (mount); ++ ++ out: ++ ++ return mount; ++} ++ ++void ++g_gdu_mount_unmounted (GGduMount *mount) ++{ ++ if (mount->volume != NULL) ++ { ++ g_gdu_volume_unset_mount (mount->volume, mount); ++ g_signal_handlers_disconnect_by_func (mount->volume, volume_changed, mount); ++ mount->volume = NULL; ++ emit_changed (mount); ++ } ++} ++ ++void ++g_gdu_mount_unset_volume (GGduMount *mount, ++ GGduVolume *volume) ++{ ++ if (mount->volume == volume) ++ { ++ g_signal_handlers_disconnect_by_func (mount->volume, volume_changed, mount); ++ mount->volume = NULL; ++ emit_changed (mount); ++ } ++} ++ ++static GFile * ++g_gdu_mount_get_root (GMount *_mount) ++{ ++ GGduMount *mount = G_GDU_MOUNT (_mount); ++ return mount->root != NULL ? g_object_ref (mount->root) : NULL; ++} ++ ++static GIcon * ++g_gdu_mount_get_icon (GMount *_mount) ++{ ++ GGduMount *mount = G_GDU_MOUNT (_mount); ++ return mount->icon != NULL ? g_object_ref (mount->icon) : NULL; ++} ++ ++static gchar * ++g_gdu_mount_get_uuid (GMount *_mount) ++{ ++ GGduMount *mount = G_GDU_MOUNT (_mount); ++ return g_strdup (mount->uuid); ++} ++ ++static gchar * ++g_gdu_mount_get_name (GMount *_mount) ++{ ++ GGduMount *mount = G_GDU_MOUNT (_mount); ++ return g_strdup (mount->name); ++} ++ ++gboolean ++g_gdu_mount_has_uuid (GGduMount *_mount, ++ const gchar *uuid) ++{ ++ GGduMount *mount = G_GDU_MOUNT (_mount); ++ return g_strcmp0 (mount->uuid, uuid) == 0; ++} ++ ++gboolean ++g_gdu_mount_has_mount_path (GGduMount *_mount, ++ const gchar *mount_path) ++{ ++ GGduMount *mount = G_GDU_MOUNT (_mount); ++ return g_strcmp0 (mount->mount_path, mount_path) == 0; ++} ++ ++static GDrive * ++g_gdu_mount_get_drive (GMount *_mount) ++{ ++ GGduMount *mount = G_GDU_MOUNT (_mount); ++ GDrive *drive; ++ ++ drive = NULL; ++ if (mount->volume != NULL) ++ drive = g_volume_get_drive (G_VOLUME (mount->volume)); ++ ++ return drive; ++} ++ ++static GVolume * ++g_gdu_mount_get_volume (GMount *_mount) ++{ ++ GGduMount *mount = G_GDU_MOUNT (_mount); ++ GVolume *volume; ++ ++ volume = NULL; ++ if (mount->volume) ++ volume = G_VOLUME (g_object_ref (mount->volume)); ++ ++ return volume; ++} ++ ++static gboolean ++g_gdu_mount_can_unmount (GMount *_mount) ++{ ++ GGduMount *mount = G_GDU_MOUNT (_mount); ++ return mount->can_unmount; ++} ++ ++static gboolean ++g_gdu_mount_can_eject (GMount *_mount) ++{ ++ GGduMount *mount = G_GDU_MOUNT (_mount); ++ GDrive *drive; ++ gboolean can_eject; ++ ++ can_eject = FALSE; ++ if (mount->volume != NULL) ++ { ++ drive = g_volume_get_drive (G_VOLUME (mount->volume)); ++ if (drive != NULL) ++ can_eject = g_drive_can_eject (drive); ++ } ++ ++ return can_eject; ++} ++ ++/* ---------------------------------------------------------------------------------------------------- */ ++ ++typedef struct { ++ GMount *mount; ++ GAsyncReadyCallback callback; ++ gpointer user_data; ++ GCancellable *cancellable; ++ int error_fd; ++ GIOChannel *error_channel; ++ guint error_channel_source_id; ++ GString *error_string; ++} UnmountEjectOp; ++ ++static void ++eject_unmount_cb (GPid pid, gint status, gpointer user_data) ++{ ++ UnmountEjectOp *data = user_data; ++ GSimpleAsyncResult *simple; ++ ++ if (WEXITSTATUS (status) != 0) ++ { ++ 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 (G_OBJECT (data->mount), ++ data->callback, ++ data->user_data, ++ error); ++ g_error_free (error); ++ } ++ else ++ { ++ simple = g_simple_async_result_new (G_OBJECT (data->mount), ++ 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_free (data); ++} ++ ++static gboolean ++eject_unmount_read_error (GIOChannel *channel, ++ GIOCondition condition, ++ gpointer user_data) ++{ ++ UnmountEjectOp *data = user_data; ++ gchar buf[BUFSIZ]; ++ gsize bytes_read; ++ GError *error; ++ GIOStatus status; ++ ++ error = NULL; ++read: ++ status = g_io_channel_read_chars (channel, buf, sizeof (buf), &bytes_read, &error); ++ if (status == G_IO_STATUS_NORMAL) ++ { ++ g_string_append_len (data->error_string, buf, bytes_read); ++ if (bytes_read == sizeof (buf)) ++ goto read; ++ } ++ else if (status == G_IO_STATUS_EOF) ++ g_string_append_len (data->error_string, buf, bytes_read); ++ else if (status == G_IO_STATUS_ERROR) ++ { ++ if (data->error_string->len > 0) ++ g_string_append (data->error_string, "\n"); ++ ++ g_string_append (data->error_string, error->message); ++ g_error_free (error); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static void ++eject_unmount_do (GMount *mount, ++ GCancellable *cancellable, ++ GAsyncReadyCallback callback, ++ gpointer user_data, ++ char **argv) ++{ ++ UnmountEjectOp *data; ++ GPid child_pid; ++ GError *error; ++ ++ data = g_new0 (UnmountEjectOp, 1); ++ data->mount = mount; ++ data->callback = callback; ++ data->user_data = user_data; ++ data->cancellable = cancellable; ++ ++ 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)) { ++ g_assert (error != NULL); ++ goto handle_error; ++ } ++ ++ data->error_string = g_string_new (""); ++ ++ data->error_channel = g_io_channel_unix_new (data->error_fd); ++ g_io_channel_set_flags (data->error_channel, G_IO_FLAG_NONBLOCK, &error); ++ if (error != NULL) ++ goto handle_error; ++ ++ data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, eject_unmount_read_error, data); ++ g_child_watch_add (child_pid, eject_unmount_cb, data); ++ ++handle_error: ++ ++ if (error != NULL) ++ { ++ GSimpleAsyncResult *simple; ++ simple = g_simple_async_result_new_from_error (G_OBJECT (data->mount), ++ data->callback, ++ data->user_data, ++ error); ++ g_simple_async_result_complete (simple); ++ g_object_unref (simple); ++ ++ if (data->error_string != NULL) ++ g_string_free (data->error_string, TRUE); ++ ++ if (data->error_channel != NULL) ++ g_io_channel_unref (data->error_channel); ++ ++ g_error_free (error); ++ g_free (data); ++ } ++} ++ ++/* ---------------------------------------------------------------------------------------------------- */ ++static void ++luks_lock_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 ++unmount_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); ++ goto out; ++ } ++ ++ /* if volume is a cleartext LUKS block device, then also lock this one */ ++ if (gdu_device_is_luks_cleartext (device)) ++ { ++ const gchar *luks_cleartext_slave_object_path; ++ GduDevice *luks_cleartext_slave; ++ GduPool *pool; ++ ++ luks_cleartext_slave_object_path = gdu_device_luks_cleartext_get_slave (device); ++ if (luks_cleartext_slave_object_path == NULL) ++ { ++ g_simple_async_result_set_error (simple, ++ G_IO_ERROR, ++ G_IO_ERROR_FAILED, ++ "Cannot get LUKS cleartext slave"); ++ g_simple_async_result_complete (simple); ++ g_object_unref (simple); ++ goto out; ++ } ++ ++ pool = gdu_device_get_pool (device); ++ luks_cleartext_slave = gdu_pool_get_by_object_path (pool, luks_cleartext_slave_object_path); ++ g_object_unref (pool); ++ ++ if (luks_cleartext_slave == NULL) ++ { ++ g_simple_async_result_set_error (simple, ++ G_IO_ERROR, ++ G_IO_ERROR_FAILED, ++ "Cannot get LUKS cleartext slave"); ++ g_simple_async_result_complete (simple); ++ g_object_unref (simple); ++ goto out; ++ } ++ ++ gdu_device_op_luks_lock (luks_cleartext_slave, ++ luks_lock_cb, ++ simple); ++ ++ g_object_unref (luks_cleartext_slave); ++ goto out; ++ } ++ ++ g_simple_async_result_complete (simple); ++ g_object_unref (simple); ++ ++ out: ++ ; ++} ++ ++static void ++g_gdu_mount_unmount (GMount *_mount, ++ GMountUnmountFlags flags, ++ GCancellable *cancellable, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ GGduMount *mount = G_GDU_MOUNT (_mount); ++ GSimpleAsyncResult *simple; ++ ++ if (mount->volume == NULL) ++ { ++ gchar *argv[] = {"umount", NULL, NULL}; ++ ++ /* TODO: honor flags */ ++ ++ if (mount->mount_path != NULL) ++ argv[1] = mount->mount_path; ++ else ++ argv[1] = mount->device_file; ++ ++ eject_unmount_do (_mount, cancellable, callback, user_data, argv); ++ } ++ else ++ { ++ simple = g_simple_async_result_new (G_OBJECT (mount), ++ callback, ++ user_data, ++ NULL); ++ ++ if (mount->is_burn_mount) ++ { ++ /* burn mounts are really never mounted... */ ++ g_simple_async_result_complete (simple); ++ g_object_unref (simple); ++ } ++ else ++ { ++ GduDevice *device; ++ GduPresentable *volume; ++ ++ /* TODO: honor flags */ ++ ++ volume = g_gdu_volume_get_presentable_with_cleartext (mount->volume); ++ device = gdu_presentable_get_device (volume); ++ ++ gdu_device_op_filesystem_unmount (device, unmount_cb, simple); ++ ++ g_object_unref (device); ++ } ++ } ++} ++ ++static gboolean ++g_gdu_mount_unmount_finish (GMount *mount, ++ GAsyncResult *result, ++ GError **error) ++{ ++ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); ++} ++ ++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_gdu_mount_eject (GMount *mount, ++ GMountUnmountFlags flags, ++ GCancellable *cancellable, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ GGduMount *gdu_mount = G_GDU_MOUNT (mount); ++ GDrive *drive; ++ ++ drive = NULL; ++ if (gdu_mount->volume != NULL) ++ drive = g_volume_get_drive (G_VOLUME (gdu_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); ++ } ++ else ++ { ++ GSimpleAsyncResult *simple; ++ simple = g_simple_async_result_new_error (G_OBJECT (mount), ++ callback, ++ user_data, ++ G_IO_ERROR, ++ G_IO_ERROR_FAILED, ++ _("Operation not supported by backend")); ++ g_simple_async_result_complete (simple); ++ g_object_unref (simple); ++ } ++ ++} ++ ++static gboolean ++g_gdu_mount_eject_finish (GMount *_mount, ++ GAsyncResult *result, ++ GError **error) ++{ ++ GGduMount *mount = G_GDU_MOUNT (_mount); ++ GDrive *drive; ++ gboolean res; ++ ++ res = TRUE; ++ ++ drive = NULL; ++ if (mount->volume != NULL) ++ drive = g_volume_get_drive (G_VOLUME (mount->volume)); ++ ++ if (drive != NULL) ++ { ++ res = g_drive_eject_finish (drive, result, error); ++ g_object_unref (drive); ++ } ++ else ++ { ++ g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); ++ res = FALSE; ++ } ++ ++ return res; ++} ++ ++/* TODO: handle force_rescan */ ++static gchar ** ++g_gdu_mount_guess_content_type_sync (GMount *_mount, ++ gboolean force_rescan, ++ GCancellable *cancellable, ++ GError **error) ++{ ++ GGduMount *mount = G_GDU_MOUNT (_mount); ++ const gchar *disc_type; ++ char **x_content_types; ++ GPtrArray *p; ++ gchar **result; ++ GduDevice *device; ++ guint n; ++ ++ p = g_ptr_array_new (); ++ ++ device = NULL; ++ if (mount->volume != NULL) ++ { ++ GduPresentable *presentable; ++ presentable = g_gdu_volume_get_presentable_with_cleartext (mount->volume); ++ device = gdu_presentable_get_device (presentable); ++ } ++ ++ /* doesn't make sense to probe blank discs - look at the disc type instead */ ++ if (device != NULL && gdu_device_optical_disc_get_is_blank (device)) ++ { ++ disc_type = gdu_device_drive_get_media (device); ++ if (disc_type != NULL) ++ { ++ if (g_str_has_prefix (disc_type, "optical_dvd")) ++ g_ptr_array_add (p, g_strdup ("x-content/blank-dvd")); ++ else if (g_str_has_prefix (disc_type, "optical_hddvd")) ++ g_ptr_array_add (p, g_strdup ("x-content/blank-hddvd")); ++ else if (g_str_has_prefix (disc_type, "optical_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 (mount->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); ++ } ++ } ++ ++ 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); ++ } ++ ++ if (device != NULL) ++ g_object_unref (device); ++ ++ return result; ++} ++ ++/* since we're an out-of-process volume monitor we'll just do this sync */ ++static void ++g_gdu_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 gchar ** ++g_gdu_mount_guess_content_type_finish (GMount *mount, ++ GAsyncResult *result, ++ GError **error) ++{ ++ return g_gdu_mount_guess_content_type_sync (mount, FALSE, NULL, error); ++} ++ ++static void ++g_gdu_mount_mount_iface_init (GMountIface *iface) ++{ ++ iface->get_root = g_gdu_mount_get_root; ++ iface->get_name = g_gdu_mount_get_name; ++ iface->get_icon = g_gdu_mount_get_icon; ++ iface->get_uuid = g_gdu_mount_get_uuid; ++ iface->get_drive = g_gdu_mount_get_drive; ++ iface->get_volume = g_gdu_mount_get_volume; ++ iface->can_unmount = g_gdu_mount_can_unmount; ++ iface->can_eject = g_gdu_mount_can_eject; ++ iface->unmount = g_gdu_mount_unmount; ++ iface->unmount_finish = g_gdu_mount_unmount_finish; ++ iface->eject = g_gdu_mount_eject; ++ iface->eject_finish = g_gdu_mount_eject_finish; ++ iface->guess_content_type = g_gdu_mount_guess_content_type; ++ iface->guess_content_type_finish = g_gdu_mount_guess_content_type_finish; ++ iface->guess_content_type_sync = g_gdu_mount_guess_content_type_sync; ++} ++ ++gboolean ++g_gdu_mount_has_volume (GGduMount *mount, ++ GGduVolume *volume) ++{ ++ return mount->volume == volume; ++} +diff --git a/monitor/gdu/ggdumount.h b/monitor/gdu/ggdumount.h +new file mode 100644 +index 0000000..62a19d8 +--- /dev/null ++++ b/monitor/gdu/ggdumount.h +@@ -0,0 +1,64 @@ ++/* -*- 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., 59 Temple Place, Suite 330, ++ * Boston, MA 02111-1307, USA. ++ * ++ * Author: David Zeuthen ++ */ ++ ++#ifndef __G_GDU_MOUNT_H__ ++#define __G_GDU_MOUNT_H__ ++ ++#include ++#include ++ ++#include "ggduvolumemonitor.h" ++ ++G_BEGIN_DECLS ++ ++#define G_TYPE_GDU_MOUNT (g_gdu_mount_get_type ()) ++#define G_GDU_MOUNT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_GDU_MOUNT, GGduMount)) ++#define G_GDU_MOUNT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_GDU_MOUNT, GGduMountClass)) ++#define G_IS_GDU_MOUNT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_GDU_MOUNT)) ++#define G_IS_GDU_MOUNT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_GDU_MOUNT)) ++ ++typedef struct _GGduMountClass GGduMountClass; ++ ++struct _GGduMountClass { ++ GObjectClass parent_class; ++}; ++ ++GType g_gdu_mount_get_type (void) G_GNUC_CONST; ++ ++GGduMount * g_gdu_mount_new (GVolumeMonitor *volume_monitor, ++ GUnixMountEntry *mount_entry, ++ GGduVolume *volume); ++gboolean g_gdu_mount_has_mount_path (GGduMount *mount, ++ const gchar *mount_path); ++gboolean g_gdu_mount_has_uuid (GGduMount *mount, ++ const gchar *uuid); ++void g_gdu_mount_unset_volume (GGduMount *mount, ++ GGduVolume *volume); ++void g_gdu_mount_unmounted (GGduMount *mount); ++ ++gboolean g_gdu_mount_has_volume (GGduMount *mount, ++ GGduVolume *volume); ++ ++G_END_DECLS ++ ++#endif /* __G_GDU_MOUNT_H__ */ +diff --git a/monitor/gdu/ggduvolume.c b/monitor/gdu/ggduvolume.c +new file mode 100644 +index 0000000..b540325 +--- /dev/null ++++ b/monitor/gdu/ggduvolume.c +@@ -0,0 +1,1408 @@ ++/* -*- 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., 59 Temple Place, Suite 330, ++ * Boston, MA 02111-1307, USA. ++ * ++ * Author: David Zeuthen ++ */ ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "ggdudrive.h" ++#include "ggduvolume.h" ++#include "ggdumount.h" ++ ++#include "polkit.h" ++ ++typedef struct MountOpData MountOpData; ++ ++static void cancel_pending_mount_op (MountOpData *data); ++ ++struct _GGduVolume ++{ ++ GObject parent; ++ ++ GVolumeMonitor *volume_monitor; /* owned by volume monitor */ ++ GGduMount *mount; /* owned by volume monitor */ ++ GGduDrive *drive; /* owned by volume monitor */ ++ ++ GduVolume *gdu_volume; ++ ++ /* if the volume is encrypted, this is != NULL when unlocked */ ++ GduVolume *cleartext_gdu_volume; ++ ++ /* If a mount operation is in progress, then pending_mount_op is != NULL. This ++ * is used to cancel the operation to make possible authentication dialogs go ++ * away. ++ */ ++ MountOpData *pending_mount_op; ++ ++ /* the following members need to be set upon construction */ ++ GIcon *icon; ++ GFile *activation_root; ++ gchar *name; ++ gchar *device_file; ++ gchar *uuid; ++ gboolean can_mount; ++ gboolean should_automount; ++}; ++ ++static void g_gdu_volume_volume_iface_init (GVolumeIface *iface); ++ ++G_DEFINE_TYPE_EXTENDED (GGduVolume, g_gdu_volume, G_TYPE_OBJECT, 0, ++ G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME, ++ g_gdu_volume_volume_iface_init)) ++ ++static void gdu_volume_changed (GduPresentable *presentable, ++ GGduVolume *volume); ++static void gdu_volume_job_changed (GduPresentable *presentable, ++ GGduVolume *volume); ++ ++static void gdu_cleartext_volume_removed (GduPresentable *presentable, ++ GGduVolume *volume); ++static void gdu_cleartext_volume_changed (GduPresentable *presentable, ++ GGduVolume *volume); ++static void gdu_cleartext_volume_job_changed (GduPresentable *presentable, ++ GGduVolume *volume); ++ ++static void mount_with_mount_operation (MountOpData *data); ++ ++static void ++g_gdu_volume_finalize (GObject *object) ++{ ++ GGduVolume *volume; ++ ++ volume = G_GDU_VOLUME (object); ++ ++ if (volume->mount != NULL) ++ g_gdu_mount_unset_volume (volume->mount, volume); ++ ++ if (volume->drive != NULL) ++ g_gdu_drive_unset_volume (volume->drive, volume); ++ ++ if (volume->gdu_volume != NULL) ++ { ++ g_signal_handlers_disconnect_by_func (volume->gdu_volume, gdu_volume_changed, volume); ++ g_signal_handlers_disconnect_by_func (volume->gdu_volume, gdu_volume_job_changed, volume); ++ g_object_unref (volume->gdu_volume); ++ } ++ ++ if (volume->cleartext_gdu_volume != NULL) ++ { ++ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_removed, volume); ++ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_changed, volume); ++ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_job_changed, volume); ++ g_object_unref (volume->cleartext_gdu_volume); ++ } ++ ++ if (volume->icon != NULL) ++ g_object_unref (volume->icon); ++ if (volume->activation_root != NULL) ++ g_object_unref (volume->activation_root); ++ ++ g_free (volume->name); ++ g_free (volume->device_file); ++ g_free (volume->uuid); ++ ++ if (G_OBJECT_CLASS (g_gdu_volume_parent_class)->finalize) ++ (*G_OBJECT_CLASS (g_gdu_volume_parent_class)->finalize) (object); ++} ++ ++static void ++g_gdu_volume_class_init (GGduVolumeClass *klass) ++{ ++ GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ++ ++ gobject_class->finalize = g_gdu_volume_finalize; ++} ++ ++static void ++g_gdu_volume_init (GGduVolume *gdu_volume) ++{ ++} ++ ++static void ++emit_changed (GGduVolume *volume) ++{ ++ g_signal_emit_by_name (volume, "changed"); ++ g_signal_emit_by_name (volume->volume_monitor, "volume_changed", volume); ++} ++ ++static gboolean ++update_volume (GGduVolume *volume) ++{ ++ GduDevice *device; ++ GduPool *pool; ++ time_t now; ++ gboolean changed; ++ gboolean old_can_mount; ++ gboolean old_should_automount; ++ gchar *old_name; ++ gchar *old_device_file; ++ GIcon *old_icon; ++ gboolean keep_cleartext_volume; ++ ++ /* save old values */ ++ old_can_mount = volume->can_mount; ++ old_should_automount = volume->should_automount; ++ old_name = g_strdup (volume->name); ++ old_device_file = g_strdup (volume->device_file); ++ old_icon = volume->icon != NULL ? g_object_ref (volume->icon) : NULL; ++ ++ /* ---------------------------------------------------------------------------------------------------- */ ++ ++ /* in with the new */ ++ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); ++ pool = gdu_device_get_pool (device); ++ ++ keep_cleartext_volume = FALSE; ++ if (gdu_device_is_luks (device)) ++ { ++ const gchar *holder_objpath; ++ ++ holder_objpath = gdu_device_luks_get_holder (device); ++ if (holder_objpath != NULL && g_strcmp0 (holder_objpath, "/") != 0) ++ { ++ GduDevice *cleartext_device; ++ ++ cleartext_device = gdu_pool_get_by_object_path (pool, holder_objpath); ++ if (cleartext_device != NULL) ++ { ++ GduVolume *cleartext_gdu_volume; ++ ++ cleartext_gdu_volume = GDU_VOLUME (gdu_pool_get_volume_by_device (pool, cleartext_device)); ++ if (cleartext_gdu_volume != volume->cleartext_gdu_volume) ++ { ++ if (volume->cleartext_gdu_volume != NULL) ++ { ++ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_removed, volume); ++ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_changed, volume); ++ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_job_changed, volume); ++ g_object_unref (volume->cleartext_gdu_volume); ++ } ++ ++ volume->cleartext_gdu_volume = g_object_ref (cleartext_gdu_volume); ++ g_signal_connect (volume->cleartext_gdu_volume, "removed", G_CALLBACK (gdu_cleartext_volume_removed), volume); ++ g_signal_connect (volume->cleartext_gdu_volume, "changed", G_CALLBACK (gdu_cleartext_volume_changed), volume); ++ g_signal_connect (volume->cleartext_gdu_volume, "job-changed", G_CALLBACK (gdu_cleartext_volume_job_changed), volume); ++ } ++ g_object_unref (cleartext_gdu_volume); ++ ++ g_object_unref (cleartext_device); ++ ++ keep_cleartext_volume = TRUE; ++ } ++ } ++ } ++ ++ if (!keep_cleartext_volume) ++ { ++ if (volume->cleartext_gdu_volume != NULL) ++ { ++ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_removed, volume); ++ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_changed, volume); ++ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_job_changed, volume); ++ g_object_unref (volume->cleartext_gdu_volume); ++ volume->cleartext_gdu_volume = NULL; ++ } ++ } ++ ++ ++ /* Use data from cleartext LUKS volume if it is unlocked */ ++ if (volume->cleartext_gdu_volume != NULL) ++ { ++ GduDevice *luks_cleartext_volume_device; ++ ++ luks_cleartext_volume_device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); ++ ++ if (volume->icon != NULL) ++ g_object_unref (volume->icon); ++ volume->icon = gdu_presentable_get_icon (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); ++ ++ g_free (volume->name); ++ volume->name = gdu_presentable_get_name (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); ++ ++ g_free (volume->device_file); ++ volume->device_file = g_strdup (gdu_device_get_device_file (luks_cleartext_volume_device)); ++ ++ volume->can_mount = TRUE; ++ ++ volume->should_automount = FALSE; ++ ++ g_object_unref (luks_cleartext_volume_device); ++ } ++ else ++ { ++ gchar *activation_uri; ++ ++ if (volume->icon != NULL) ++ g_object_unref (volume->icon); ++ volume->icon = gdu_presentable_get_icon (GDU_PRESENTABLE (volume->gdu_volume)); ++ ++ g_free (volume->name); ++ volume->name = gdu_presentable_get_name (GDU_PRESENTABLE (volume->gdu_volume)); ++ ++ /* special case the name and icon for audio discs */ ++ activation_uri = volume->activation_root != NULL ? g_file_get_uri (volume->activation_root) : NULL; ++ if (activation_uri != NULL && g_str_has_prefix (activation_uri, "cdda://")) ++ { ++ if (volume->icon != NULL) ++ g_object_unref (volume->icon); ++ volume->icon = g_themed_icon_new_with_default_fallbacks ("media-optical-audio"); ++ g_free (volume->name); ++ volume->name = g_strdup (_("Audio Disc")); ++ } ++ ++ g_free (volume->device_file); ++ volume->device_file = g_strdup (gdu_device_get_device_file (device)); ++ ++ volume->can_mount = TRUE; ++ ++ /* If a volume (partition) appear _much later_ than when media was insertion it ++ * can only be because the media was repartitioned. We don't want to automount ++ * such volumes. ++ */ ++ volume->should_automount = TRUE; ++ if (volume->drive != NULL) ++ { ++ now = time (NULL); ++ if (now - g_gdu_drive_get_time_of_last_media_insertion (volume->drive) > 5) ++ volume->should_automount = FALSE; ++ } ++ ++ g_free (activation_uri); ++ } ++ ++ g_object_unref (pool); ++ g_object_unref (device); ++ ++ /* ---------------------------------------------------------------------------------------------------- */ ++ ++ /* compute whether something changed */ ++ changed = !((old_can_mount == volume->can_mount) && ++ (old_should_automount == volume->should_automount) && ++ (g_strcmp0 (old_name, volume->name) == 0) && ++ (g_strcmp0 (old_device_file, volume->device_file) == 0) && ++ g_icon_equal (old_icon, volume->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_volume(), changed=%d", changed);*/ ++ ++ return changed; ++} ++ ++static void ++gdu_volume_changed (GduPresentable *presentable, ++ GGduVolume *volume) ++{ ++ /*g_debug ("volume: presentable_changed: %p: %s", volume, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ ++ if (update_volume (volume)) ++ emit_changed (volume); ++} ++ ++static void ++gdu_volume_job_changed (GduPresentable *presentable, ++ GGduVolume *volume) ++{ ++ /*g_debug ("volume: presentable_job_changed %p: %s", volume, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ ++ if (update_volume (volume)) ++ emit_changed (volume); ++} ++ ++static void ++gdu_cleartext_volume_removed (GduPresentable *presentable, ++ GGduVolume *volume) ++{ ++ /*g_debug ("cleartext volume: presentable_removed: %p: %s", volume, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ ++ if (update_volume (volume)) ++ emit_changed (volume); ++} ++ ++static void ++gdu_cleartext_volume_changed (GduPresentable *presentable, ++ GGduVolume *volume) ++{ ++ /*g_debug ("cleartext volume: presentable_changed: %p: %s", volume, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ ++ if (update_volume (volume)) ++ emit_changed (volume); ++} ++ ++static void ++gdu_cleartext_volume_job_changed (GduPresentable *presentable, ++ GGduVolume *volume) ++{ ++ /*g_debug ("cleartext volume: presentable_job_changed %p: %s", volume, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ ++ if (update_volume (volume)) ++ emit_changed (volume); ++} ++ ++GGduVolume * ++g_gdu_volume_new (GVolumeMonitor *volume_monitor, ++ GduVolume *gdu_volume, ++ GGduDrive *drive, ++ GFile *activation_root) ++{ ++ GGduVolume *volume; ++ ++ volume = g_object_new (G_TYPE_GDU_VOLUME, NULL); ++ volume->volume_monitor = volume_monitor; ++ g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(volume->volume_monitor)); ++ ++ volume->gdu_volume = g_object_ref (gdu_volume); ++ volume->activation_root = activation_root != NULL ? g_object_ref (activation_root) : NULL; ++ ++ g_signal_connect (volume->gdu_volume, "changed", G_CALLBACK (gdu_volume_changed), volume); ++ g_signal_connect (volume->gdu_volume, "job-changed", G_CALLBACK (gdu_volume_job_changed), volume); ++ ++ volume->drive = drive; ++ if (drive != NULL) ++ g_gdu_drive_set_volume (drive, volume); ++ ++ update_volume (volume); ++ ++ return volume; ++} ++ ++void ++g_gdu_volume_removed (GGduVolume *volume) ++{ ++ if (volume->pending_mount_op != NULL) ++ cancel_pending_mount_op (volume->pending_mount_op); ++ ++ if (volume->mount != NULL) ++ { ++ g_gdu_mount_unset_volume (volume->mount, volume); ++ volume->mount = NULL; ++ } ++ ++ if (volume->drive != NULL) ++ { ++ g_gdu_drive_unset_volume (volume->drive, volume); ++ volume->drive = NULL; ++ } ++} ++ ++void ++g_gdu_volume_set_mount (GGduVolume *volume, ++ GGduMount *mount) ++{ ++ if (volume->mount != mount) ++ { ++ ++ if (volume->mount != NULL) ++ g_gdu_mount_unset_volume (volume->mount, volume); ++ ++ volume->mount = mount; ++ ++ emit_changed (volume); ++ } ++} ++ ++void ++g_gdu_volume_unset_mount (GGduVolume *volume, ++ GGduMount *mount) ++{ ++ if (volume->mount == mount) ++ { ++ volume->mount = NULL; ++ emit_changed (volume); ++ } ++} ++ ++void ++g_gdu_volume_set_drive (GGduVolume *volume, ++ GGduDrive *drive) ++{ ++ if (volume->drive != drive) ++ { ++ if (volume->drive != NULL) ++ g_gdu_drive_unset_volume (volume->drive, volume); ++ ++ volume->drive = drive; ++ ++ emit_changed (volume); ++ } ++} ++ ++void ++g_gdu_volume_unset_drive (GGduVolume *volume, ++ GGduDrive *drive) ++{ ++ if (volume->drive == drive) ++ { ++ volume->drive = NULL; ++ emit_changed (volume); ++ } ++} ++ ++static GIcon * ++g_gdu_volume_get_icon (GVolume *_volume) ++{ ++ GGduVolume *volume = G_GDU_VOLUME (_volume); ++ return volume->icon != NULL ? g_object_ref (volume->icon) : NULL; ++} ++ ++static char * ++g_gdu_volume_get_name (GVolume *_volume) ++{ ++ GGduVolume *volume = G_GDU_VOLUME (_volume); ++ return g_strdup (volume->name); ++} ++ ++static char * ++g_gdu_volume_get_uuid (GVolume *_volume) ++{ ++ GGduVolume *volume = G_GDU_VOLUME (_volume); ++ return g_strdup (volume->uuid); ++} ++ ++static gboolean ++g_gdu_volume_can_mount (GVolume *_volume) ++{ ++ GGduVolume *volume = G_GDU_VOLUME (_volume); ++ return volume->can_mount; ++} ++ ++static gboolean ++g_gdu_volume_can_eject (GVolume *_volume) ++{ ++ GGduVolume *volume = G_GDU_VOLUME (_volume); ++ gboolean can_eject; ++ ++ can_eject = FALSE; ++ if (volume->drive != NULL) ++ can_eject = g_drive_can_eject (G_DRIVE (volume->drive)); ++ ++ return can_eject; ++} ++ ++static gboolean ++g_gdu_volume_should_automount (GVolume *_volume) ++{ ++ GGduVolume *volume = G_GDU_VOLUME (_volume); ++ return volume->should_automount; ++} ++ ++static GDrive * ++g_gdu_volume_get_drive (GVolume *volume) ++{ ++ GGduVolume *gdu_volume = G_GDU_VOLUME (volume); ++ GDrive *drive; ++ ++ drive = NULL; ++ if (gdu_volume->drive != NULL) ++ drive = g_object_ref (gdu_volume->drive); ++ ++ return drive; ++} ++ ++static GMount * ++g_gdu_volume_get_mount (GVolume *volume) ++{ ++ GGduVolume *gdu_volume = G_GDU_VOLUME (volume); ++ GMount *mount; ++ ++ mount = NULL; ++ if (gdu_volume->mount != NULL) ++ mount = g_object_ref (gdu_volume->mount); ++ ++ return mount; ++} ++ ++/* ---------------------------------------------------------------------------------------------------- */ ++ ++struct MountOpData ++{ ++ GGduVolume *volume; ++ GduDevice *device_to_mount; ++ GSimpleAsyncResult *simple; ++ GCancellable *cancellable; ++ gulong cancelled_handler_id; ++ ++ GMountOperation *mount_operation; ++ gulong mount_operation_reply_handler_id; ++ ++ gboolean is_cancelled; ++}; ++ ++static void ++mount_op_data_unref (MountOpData *data) ++{ ++ g_object_unref (data->volume); ++ if (data->device_to_mount != NULL) ++ g_object_unref (data->device_to_mount); ++ g_object_unref (data->simple); ++ if (data->cancelled_handler_id != 0) ++ g_signal_handler_disconnect (data->cancellable, data->cancelled_handler_id); ++ if (data->cancellable != NULL) ++ g_object_unref (data->cancellable); ++ if (data->mount_operation_reply_handler_id != 0) ++ g_signal_handler_disconnect (data->mount_operation, data->mount_operation_reply_handler_id); ++ if (data->mount_operation != NULL) ++ g_object_unref (data->mount_operation); ++ g_free (data); ++} ++ ++static void ++cancel_pending_mount_op (MountOpData *data) ++{ ++ /* we are no longer pending */ ++ data->volume->pending_mount_op = NULL; ++ ++ data->is_cancelled = TRUE; ++ ++ /* send an ::aborted signal to make the dialog go away */ ++ if (data->mount_operation != NULL) ++ g_signal_emit_by_name (data->mount_operation, "aborted"); ++ ++ /* complete the operation (sends reply to caller) */ ++ g_simple_async_result_set_error (data->simple, ++ G_IO_ERROR, ++ G_IO_ERROR_FAILED_HANDLED, ++ "Operation was cancelled"); ++ g_simple_async_result_complete (data->simple); ++} ++ ++static void ++mount_cb (GduDevice *device, ++ gchar *mount_point, ++ GError *error, ++ gpointer user_data); ++ ++static void ++mount_obtain_authz_cb (GObject *source_object, ++ GAsyncResult *res, ++ gpointer user_data) ++{ ++ MountOpData *data = user_data; ++ gboolean obtained_authz; ++ GError *error; ++ ++ /* if we've already aborted due to device removal / cancellation, just bail out */ ++ if (data->is_cancelled) ++ goto bailout; ++ ++ error = NULL; ++ obtained_authz = _obtain_authz_finish (res, &error); ++ ++ if (!obtained_authz) ++ { ++ /* be quiet if the daemon is inhibited */ ++ if (error->code == GDU_ERROR_INHIBITED) ++ { ++ error->domain = G_IO_ERROR; ++ error->code = G_IO_ERROR_FAILED_HANDLED; ++ } ++ g_simple_async_result_set_from_error (data->simple, error); ++ g_simple_async_result_complete (data->simple); ++ } ++ else ++ { ++ /* got the authz, now try again */ ++ gdu_device_op_filesystem_mount (data->device_to_mount, mount_cb, data); ++ goto out; ++ } ++ ++ bailout: ++ data->volume->pending_mount_op = NULL; ++ mount_op_data_unref (data); ++ ++ out: ++ ; ++} ++ ++static void ++mount_cb (GduDevice *device, ++ gchar *mount_point, ++ GError *error, ++ gpointer user_data) ++{ ++ MountOpData *data = user_data; ++ ++ /* if we've already aborted due to device removal / cancellation, just bail out */ ++ if (data->is_cancelled) ++ goto bailout; ++ ++ if (error != NULL) ++ { ++ PolKitAction *pk_action; ++ PolKitResult pk_result; ++ ++ /* only attempt to show authentication dialog if we have a mount operation */ ++ if (data->mount_operation != NULL && gdu_error_check_polkit_not_authorized (error, ++ &pk_action, ++ &pk_result)) ++ { ++ if (pk_result != POLKIT_RESULT_NO && pk_result != POLKIT_RESULT_UNKNOWN) ++ { ++ const gchar *action_id; ++ /* try to obtain the authorization */ ++ polkit_action_get_action_id (pk_action, (char **) &action_id); ++ _obtain_authz (action_id, ++ data->cancellable, ++ mount_obtain_authz_cb, ++ data); ++ goto out; ++ } ++ else ++ { ++ g_simple_async_result_set_from_error (data->simple, error); ++ } ++ polkit_action_unref (pk_action); ++ } ++ else ++ { ++ /* be quiet if the daemon is inhibited */ ++ if (error->code == GDU_ERROR_INHIBITED) ++ { ++ error->domain = G_IO_ERROR; ++ error->code = G_IO_ERROR_FAILED_HANDLED; ++ } ++ g_simple_async_result_set_from_error (data->simple, error); ++ } ++ g_error_free (error); ++ } ++ else ++ { ++ g_free (mount_point); ++ } ++ ++ g_simple_async_result_complete (data->simple); ++ ++ bailout: ++ data->volume->pending_mount_op = NULL; ++ mount_op_data_unref (data); ++ ++ out: ++ ; ++} ++ ++static void ++mount_cleartext_device (MountOpData *data, ++ const gchar *object_path_of_cleartext_device) ++{ ++ GduPool *pool; ++ ++ /* if we've already aborted due to device removal / cancellation, just bail out */ ++ if (data->is_cancelled) ++ { ++ mount_op_data_unref (data); ++ goto bailout; ++ } ++ ++ pool = gdu_presentable_get_pool (GDU_PRESENTABLE (data->volume->gdu_volume)); ++ ++ data->device_to_mount = gdu_pool_get_by_object_path (pool, object_path_of_cleartext_device); ++ if (data->device_to_mount == NULL) ++ { ++ g_simple_async_result_set_error (data->simple, ++ G_IO_ERROR, ++ G_IO_ERROR_FAILED, ++ "Successfully unlocked encrypted volume but cleartext device does not exist"); ++ g_simple_async_result_complete (data->simple); ++ data->volume->pending_mount_op = NULL; ++ mount_op_data_unref (data); ++ } ++ else ++ { ++ gdu_device_op_filesystem_mount (data->device_to_mount, mount_cb, data); ++ } ++ ++ g_object_unref (pool); ++ ++ bailout: ++ ; ++} ++ ++static void ++unlock_from_keyring_cb (GduDevice *device, ++ char *object_path_of_cleartext_device, ++ GError *error, ++ gpointer user_data) ++{ ++ MountOpData *data = user_data; ++ ++ /* if we've already aborted due to device removal / cancellation, just bail out */ ++ if (data->is_cancelled) ++ { ++ mount_op_data_unref (data); ++ goto bailout; ++ } ++ ++ if (error != NULL) ++ { ++ /*g_debug ("keyring password didn't work: %s", error->message);*/ ++ ++ /* The password we retrieved from the keyring didn't work. So go ahead and prompt ++ * the user. ++ */ ++ mount_with_mount_operation (data); ++ ++ g_error_free (error); ++ } ++ else ++ { ++ mount_cleartext_device (data, object_path_of_cleartext_device); ++ g_free (object_path_of_cleartext_device); ++ } ++ ++ bailout: ++ ; ++} ++ ++static void ++unlock_cb (GduDevice *device, ++ gchar *object_path_of_cleartext_device, ++ GError *error, ++ gpointer user_data) ++{ ++ MountOpData *data = user_data; ++ ++ /* if we've already aborted due to device removal / cancellation, just bail out */ ++ if (data->is_cancelled) ++ { ++ mount_op_data_unref (data); ++ goto bailout; ++ } ++ ++ if (error != NULL) ++ { ++ /* be quiet if the daemon is inhibited */ ++ if (error->code == GDU_ERROR_INHIBITED) ++ { ++ error->domain = G_IO_ERROR; ++ error->code = G_IO_ERROR_FAILED_HANDLED; ++ } ++ g_simple_async_result_set_from_error (data->simple, error); ++ g_error_free (error); ++ g_simple_async_result_complete (data->simple); ++ data->volume->pending_mount_op = NULL; ++ mount_op_data_unref (data); ++ } ++ else ++ { ++ GPasswordSave password_save; ++ const gchar *password; ++ ++ password_save = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (device), "password-save")); ++ password = g_object_get_data (G_OBJECT (device), "password"); ++ ++ if (password != NULL) ++ { ++ switch (password_save) ++ { ++ case G_PASSWORD_SAVE_FOR_SESSION: ++ gdu_util_save_secret (device, password, TRUE); ++ break; ++ ++ case G_PASSWORD_SAVE_PERMANENTLY: ++ gdu_util_save_secret (device, password, FALSE); ++ break; ++ ++ default: ++ /* do nothing */ ++ break; ++ } ++ } ++ ++ /* now we have a cleartext device; update the GVolume details to show that */ ++ if (update_volume (data->volume)) ++ emit_changed (data->volume); ++ ++ mount_cleartext_device (data, object_path_of_cleartext_device); ++ g_free (object_path_of_cleartext_device); ++ } ++ ++ bailout: ++ ++ /* scrub the password */ ++ g_object_set_data (G_OBJECT (device), "password-save", NULL); ++ g_object_set_data (G_OBJECT (device), "password", NULL); ++} ++ ++static void ++scrub_n_free_string (char *password) ++{ ++ memset (password, '\0', strlen (password)); ++ g_free (password); ++} ++ ++static void ++mount_operation_reply (GMountOperation *mount_operation, ++ GMountOperationResult result, ++ gpointer user_data) ++{ ++ MountOpData *data = user_data; ++ GduDevice *device; ++ const gchar *password; ++ ++ /* if we've already aborted due to device removal, just bail out */ ++ if (data->is_cancelled) ++ { ++ mount_op_data_unref (data); ++ goto out; ++ } ++ ++ /* we got what we wanted; don't listen to any other signals from the mount operation */ ++ if (data->mount_operation_reply_handler_id != 0) ++ { ++ g_signal_handler_disconnect (data->mount_operation, data->mount_operation_reply_handler_id); ++ data->mount_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, ++ "Password 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_PERMISSION_DENIED, ++ "Expected G_MOUNT_OPERATION_HANDLED but got %d", result); ++ } ++ g_simple_async_result_complete (data->simple); ++ data->volume->pending_mount_op = NULL; ++ mount_op_data_unref (data); ++ goto out; ++ } ++ ++ password = g_mount_operation_get_password (mount_operation); ++ ++ device = gdu_presentable_get_device (GDU_PRESENTABLE (data->volume->gdu_volume)); ++ ++ g_object_set_data (G_OBJECT (device), ++ "password-save", ++ GINT_TO_POINTER (g_mount_operation_get_password_save (mount_operation))); ++ g_object_set_data_full (G_OBJECT (device), ++ "password", ++ g_strdup (password), ++ (GDestroyNotify) scrub_n_free_string); ++ ++ gdu_device_op_luks_unlock (device, password, unlock_cb, data); ++ ++ g_object_unref (device); ++ ++ out: ++ ; ++} ++ ++static void ++mount_with_mount_operation (MountOpData *data) ++{ ++ gchar *message; ++ gchar *drive_name; ++ GduPresentable *toplevel; ++ GduDevice *device; ++ ++ device = NULL; ++ drive_name = NULL; ++ message = NULL; ++ toplevel = NULL; ++ ++ /* if we've already aborted due to device removal, just bail out */ ++ if (data->is_cancelled) ++ { ++ mount_op_data_unref (data); ++ goto out; ++ } ++ ++ if (data->mount_operation == NULL) ++ { ++ g_simple_async_result_set_error (data->simple, ++ G_IO_ERROR, ++ G_IO_ERROR_FAILED, ++ "Password required to access the encrypted data"); ++ g_simple_async_result_complete (data->simple); ++ data->volume->pending_mount_op = NULL; ++ mount_op_data_unref (data); ++ goto out; ++ } ++ ++ device = gdu_presentable_get_device (GDU_PRESENTABLE (data->volume->gdu_volume)); ++ ++ toplevel = gdu_presentable_get_toplevel (GDU_PRESENTABLE (data->volume->gdu_volume)); ++ if (toplevel != NULL) ++ drive_name = gdu_presentable_get_name (toplevel); ++ ++ /* This is going to look ass until bug 573416 is fixed. Unfortunately ++ * the gtk+ maintain has stated "oh, I stopped using luks" but that's ++ * more of a gtk+ problem ;-) ++ */ ++ if (drive_name != NULL) ++ { ++ if (gdu_device_is_partition (device)) ++ { ++ message = g_strdup_printf (_("Enter a password to unlock the volume\n" ++ "The device \"%s\" contains encrypted data on partition %d."), ++ drive_name, ++ gdu_device_partition_get_number (device)); ++ } ++ else ++ { ++ message = g_strdup_printf (_("Enter a password to unlock the volume\n" ++ "The device \"%s\" contains encrypted data."), ++ drive_name); ++ } ++ } ++ else ++ { ++ message = g_strdup_printf (_("Enter a password to unlock the volume\n" ++ "The device %s contains encrypted data."), ++ gdu_device_get_device_file (device)); ++ } ++ ++ data->mount_operation_reply_handler_id = g_signal_connect (data->mount_operation, ++ "reply", ++ G_CALLBACK (mount_operation_reply), ++ data); ++ ++ g_signal_emit_by_name (data->mount_operation, ++ "ask-password", ++ message, ++ NULL, ++ NULL, ++ G_ASK_PASSWORD_NEED_PASSWORD | ++ G_ASK_PASSWORD_SAVING_SUPPORTED); ++ ++ out: ++ g_free (drive_name); ++ g_free (message); ++ if (device != NULL) ++ g_object_unref (device); ++ if (toplevel != NULL) ++ g_object_unref (toplevel); ++} ++ ++static void ++cancelled_cb (GCancellable *cancellable, ++ GGduVolume *volume) ++{ ++ if (volume->pending_mount_op != NULL) ++ { ++ cancel_pending_mount_op (volume->pending_mount_op); ++ } ++} ++ ++static void ++g_gdu_volume_mount (GVolume *_volume, ++ GMountMountFlags flags, ++ GMountOperation *mount_operation, ++ GCancellable *cancellable, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ GGduVolume *volume = G_GDU_VOLUME (_volume); ++ GSimpleAsyncResult *simple; ++ GduDevice *device; ++ GduPool *pool; ++ const gchar *usage; ++ const gchar *type; ++ MountOpData *data; ++ ++ pool = NULL; ++ device = NULL; ++ ++ if (volume->pending_mount_op != NULL) ++ { ++ simple = g_simple_async_result_new_error (G_OBJECT (volume), ++ callback, ++ user_data, ++ G_IO_ERROR, ++ G_IO_ERROR_FAILED, ++ "A mount operation is already pending"); ++ g_simple_async_result_complete (simple); ++ g_object_unref (simple); ++ goto out; ++ } ++ ++ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); ++ pool = gdu_device_get_pool (device); ++ ++ /* Makes no sense to mount ++ * ++ * - blank discs since these already have a burn:/// mount ++ * - other things that are already mounted ++ * ++ * Unfortunately Nautilus will try to do this anyway. For now, just return success for ++ * such requests. ++ */ ++ if (gdu_device_optical_disc_get_is_blank (device) || gdu_device_is_mounted (device)) ++ { ++ simple = g_simple_async_result_new (G_OBJECT (volume), ++ callback, ++ user_data, ++ g_gdu_volume_mount); ++ g_simple_async_result_complete (simple); ++ g_object_unref (simple); ++ goto out; ++ } ++ ++ data = g_new0 (MountOpData, 1); ++ ++ data->volume = g_object_ref (volume); ++ ++ data->simple = g_simple_async_result_new (G_OBJECT (volume), ++ callback, ++ user_data, ++ g_gdu_volume_mount); ++ ++ data->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL; ++ ++ data->mount_operation = mount_operation != NULL ? g_object_ref (mount_operation) : NULL; ++ ++ if (data->cancellable != NULL) ++ data->cancelled_handler_id = g_signal_connect (data->cancellable, "cancelled", G_CALLBACK (cancelled_cb), volume); ++ ++ volume->pending_mount_op = data; ++ ++ /* if the device is already unlocked, just attempt to mount it */ ++ if (volume->cleartext_gdu_volume != NULL) ++ { ++ GduDevice *luks_cleartext_volume_device; ++ const gchar *object_path_of_cleartext_device; ++ ++ luks_cleartext_volume_device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); ++ ++ object_path_of_cleartext_device = gdu_device_get_object_path (luks_cleartext_volume_device); ++ ++ mount_cleartext_device (data, object_path_of_cleartext_device); ++ ++ g_object_unref (luks_cleartext_volume_device); ++ goto out; ++ } ++ ++ usage = gdu_device_id_get_usage (device); ++ type = gdu_device_id_get_type (device); ++ if (g_strcmp0 (usage, "crypto") == 0 && g_strcmp0 (type, "crypto_LUKS") == 0) ++ { ++ gchar *password; ++ ++ /* if we have the secret in the keyring, try with that first */ ++ password = gdu_util_get_secret (device); ++ if (password != NULL) ++ { ++ gdu_device_op_luks_unlock (device, password, unlock_from_keyring_cb, data); ++ ++ scrub_n_free_string (password); ++ goto out; ++ } ++ ++ /* don't put up a password dialog if the daemon is inhibited */ ++ if (gdu_pool_is_daemon_inhibited (pool)) ++ { ++ g_simple_async_result_set_error (data->simple, ++ G_IO_ERROR, ++ G_IO_ERROR_FAILED_HANDLED, ++ "Daemon is currently inhibited"); ++ g_simple_async_result_complete (data->simple); ++ volume->pending_mount_op = NULL; ++ mount_op_data_unref (data); ++ goto out; ++ } ++ ++ mount_with_mount_operation (data); ++ } ++ else ++ { ++ data->device_to_mount = g_object_ref (device); ++ gdu_device_op_filesystem_mount (data->device_to_mount, mount_cb, data); ++ } ++ ++ out: ++ if (pool != NULL) ++ g_object_unref (pool); ++ if (device != NULL) ++ g_object_unref (device); ++} ++ ++static gboolean ++g_gdu_volume_mount_finish (GVolume *volume, ++ GAsyncResult *result, ++ GError **error) ++{ ++ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); ++ ++ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_gdu_volume_mount); ++ ++ return !g_simple_async_result_propagate_error (simple, error); ++} ++ ++/* ---------------------------------------------------------------------------------------------------- */ ++ ++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_gdu_volume_eject (GVolume *volume, ++ GMountUnmountFlags flags, ++ GCancellable *cancellable, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ GGduVolume *gdu_volume = G_GDU_VOLUME (volume); ++ GGduDrive *drive; ++ ++ drive = NULL; ++ if (gdu_volume->drive != NULL) ++ drive = g_object_ref (gdu_volume->drive); ++ ++ 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); ++ } ++ else ++ { ++ GSimpleAsyncResult *simple; ++ simple = g_simple_async_result_new_error (G_OBJECT (volume), ++ callback, ++ user_data, ++ G_IO_ERROR, ++ G_IO_ERROR_FAILED, ++ _("Operation not supported by backend")); ++ g_simple_async_result_complete (simple); ++ g_object_unref (simple); ++ } ++} ++ ++static gboolean ++g_gdu_volume_eject_finish (GVolume *volume, ++ GAsyncResult *result, ++ GError **error) ++{ ++ GGduVolume *gdu_volume = G_GDU_VOLUME (volume); ++ gboolean res; ++ ++ res = TRUE; ++ if (gdu_volume->drive != NULL) ++ { ++ res = g_drive_eject_finish (G_DRIVE (gdu_volume->drive), result, error); ++ } ++ else ++ { ++ g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); ++ res = FALSE; ++ } ++ ++ return res; ++} ++ ++static char * ++g_gdu_volume_get_identifier (GVolume *_volume, ++ const char *kind) ++{ ++ GGduVolume *volume = G_GDU_VOLUME (_volume); ++ GduDevice *device; ++ const gchar *label; ++ const gchar *uuid; ++ gchar *id; ++ ++ id = NULL; ++ ++ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); ++ ++ label = gdu_device_id_get_label (device); ++ uuid = gdu_device_id_get_uuid (device); ++ ++ g_object_unref (device); ++ ++ if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0) ++ id = g_strdup (volume->device_file); ++ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_LABEL) == 0) ++ id = strlen (label) > 0 ? g_strdup (label) : NULL; ++ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UUID) == 0) ++ id = strlen (uuid) > 0 ? g_strdup (uuid) : NULL; ++ ++ return id; ++} ++ ++static char ** ++g_gdu_volume_enumerate_identifiers (GVolume *_volume) ++{ ++ GGduVolume *volume = G_GDU_VOLUME (_volume); ++ GduDevice *device; ++ GPtrArray *p; ++ const gchar *label; ++ const gchar *uuid; ++ ++ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); ++ ++ label = gdu_device_id_get_label (device); ++ uuid = gdu_device_id_get_uuid (device); ++ ++ g_object_unref (device); ++ ++ p = g_ptr_array_new (); ++ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE)); ++ if (strlen (label) > 0) ++ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_LABEL)); ++ if (strlen (uuid) > 0) ++ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UUID)); ++ ++ g_ptr_array_add (p, NULL); ++ ++ return (gchar **) g_ptr_array_free (p, FALSE); ++} ++ ++static GFile * ++g_gdu_volume_get_activation_root (GVolume *_volume) ++{ ++ GGduVolume *volume = G_GDU_VOLUME (_volume); ++ return volume->activation_root != NULL ? g_object_ref (volume->activation_root) : NULL; ++} ++ ++static void ++g_gdu_volume_volume_iface_init (GVolumeIface *iface) ++{ ++ iface->get_name = g_gdu_volume_get_name; ++ iface->get_icon = g_gdu_volume_get_icon; ++ iface->get_uuid = g_gdu_volume_get_uuid; ++ iface->get_drive = g_gdu_volume_get_drive; ++ iface->get_mount = g_gdu_volume_get_mount; ++ iface->can_mount = g_gdu_volume_can_mount; ++ iface->can_eject = g_gdu_volume_can_eject; ++ iface->should_automount = g_gdu_volume_should_automount; ++ iface->mount_fn = g_gdu_volume_mount; ++ iface->mount_finish = g_gdu_volume_mount_finish; ++ iface->eject = g_gdu_volume_eject; ++ iface->eject_finish = g_gdu_volume_eject_finish; ++ iface->get_identifier = g_gdu_volume_get_identifier; ++ iface->enumerate_identifiers = g_gdu_volume_enumerate_identifiers; ++ iface->get_activation_root = g_gdu_volume_get_activation_root; ++} ++ ++gboolean ++g_gdu_volume_has_device_file (GGduVolume *volume, ++ const gchar *device_file) ++{ ++ const gchar *_device_file; ++ ++ _device_file = volume->device_file; ++ ++ if (volume->cleartext_gdu_volume != NULL) ++ { ++ GduDevice *luks_cleartext_volume_device; ++ luks_cleartext_volume_device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); ++ _device_file = gdu_device_get_device_file (luks_cleartext_volume_device); ++ g_object_unref (luks_cleartext_volume_device); ++ } ++ ++ return g_strcmp0 (_device_file, device_file) == 0; ++} ++ ++ ++gboolean ++g_gdu_volume_has_mount_path (GGduVolume *volume, ++ const char *mount_path) ++{ ++ GduDevice *device; ++ GduPresentable *presentable; ++ gboolean ret; ++ ++ ret = FALSE; ++ ++ presentable = g_gdu_volume_get_presentable_with_cleartext (volume); ++ if (presentable != NULL) ++ { ++ device = gdu_presentable_get_device (presentable); ++ if (device != NULL) ++ { ++ ret = g_strcmp0 (gdu_device_get_mount_path (device), mount_path) == 0; ++ g_object_unref (device); ++ } ++ } ++ ++ return ret; ++} ++ ++gboolean ++g_gdu_volume_has_uuid (GGduVolume *volume, ++ const char *uuid) ++{ ++ const gchar *_uuid; ++ ++ _uuid = volume->uuid; ++ ++ if (volume->cleartext_gdu_volume != NULL) ++ { ++ GduDevice *luks_cleartext_volume_device; ++ luks_cleartext_volume_device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); ++ _uuid = gdu_device_id_get_uuid (luks_cleartext_volume_device); ++ g_object_unref (luks_cleartext_volume_device); ++ } ++ ++ return g_strcmp0 (_uuid, uuid) == 0; ++} ++ ++GduPresentable * ++g_gdu_volume_get_presentable (GGduVolume *volume) ++{ ++ return GDU_PRESENTABLE (volume->gdu_volume); ++} ++ ++GduPresentable * ++g_gdu_volume_get_presentable_with_cleartext (GGduVolume *volume) ++{ ++ GduVolume *ret; ++ ++ ret = volume->cleartext_gdu_volume; ++ if (ret == NULL) ++ ret = volume->gdu_volume; ++ ++ return GDU_PRESENTABLE (ret); ++} +diff --git a/monitor/gdu/ggduvolume.h b/monitor/gdu/ggduvolume.h +new file mode 100644 +index 0000000..8fd7358 +--- /dev/null ++++ b/monitor/gdu/ggduvolume.h +@@ -0,0 +1,78 @@ ++/* -*- 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., 59 Temple Place, Suite 330, ++ * Boston, MA 02111-1307, USA. ++ * ++ * Author: David Zeuthen ++ */ ++ ++#ifndef __G_GDU_VOLUME_H__ ++#define __G_GDU_VOLUME_H__ ++ ++#include ++#include ++ ++#include "ggduvolumemonitor.h" ++ ++G_BEGIN_DECLS ++ ++#define G_TYPE_GDU_VOLUME (g_gdu_volume_get_type ()) ++#define G_GDU_VOLUME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_GDU_VOLUME, GGduVolume)) ++#define G_GDU_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_GDU_VOLUME, GGduVolumeClass)) ++#define G_IS_GDU_VOLUME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_GDU_VOLUME)) ++#define G_IS_GDU_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_GDU_VOLUME)) ++ ++typedef struct _GGduVolumeClass GGduVolumeClass; ++ ++struct _GGduVolumeClass { ++ GObjectClass parent_class; ++}; ++ ++GType g_gdu_volume_get_type (void) G_GNUC_CONST; ++ ++GGduVolume *g_gdu_volume_new (GVolumeMonitor *volume_monitor, ++ GduVolume *gdu_volume, ++ GGduDrive *drive, ++ GFile *activation_root); ++ ++void g_gdu_volume_set_mount (GGduVolume *volume, ++ GGduMount *mount); ++void g_gdu_volume_unset_mount (GGduVolume *volume, ++ GGduMount *mount); ++ ++void g_gdu_volume_set_drive (GGduVolume *volume, ++ GGduDrive *drive); ++void g_gdu_volume_unset_drive (GGduVolume *volume, ++ GGduDrive *drive); ++ ++void g_gdu_volume_removed (GGduVolume *volume); ++ ++gboolean g_gdu_volume_has_mount_path (GGduVolume *volume, ++ const char *mount_path); ++gboolean g_gdu_volume_has_uuid (GGduVolume *volume, ++ const char *uuid); ++gboolean g_gdu_volume_has_device_file (GGduVolume *volume, ++ const gchar *device_file); ++ ++GduPresentable *g_gdu_volume_get_presentable (GGduVolume *volume); ++ ++GduPresentable *g_gdu_volume_get_presentable_with_cleartext (GGduVolume *volume); ++ ++G_END_DECLS ++ ++#endif /* __G_GDU_VOLUME_H__ */ +diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c +new file mode 100644 +index 0000000..32604d0 +--- /dev/null ++++ b/monitor/gdu/ggduvolumemonitor.c +@@ -0,0 +1,1432 @@ ++/* -*- 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., 59 Temple Place, Suite 330, ++ * Boston, MA 02111-1307, USA. ++ * ++ * Author: David Zeuthen ++ */ ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "ggduvolumemonitor.h" ++#include "ggdumount.h" ++#include "ggduvolume.h" ++#include "ggdudrive.h" ++ ++static GGduVolumeMonitor *the_volume_monitor = NULL; ++ ++struct _GGduVolumeMonitor { ++ GNativeVolumeMonitor parent; ++ ++ GUnixMountMonitor *mount_monitor; ++ ++ GduPool *pool; ++ ++ GList *last_optical_disc_devices; ++ GList *last_mountpoints; ++ GList *last_mounts; ++ ++ GList *drives; ++ GList *volumes; ++ GList *mounts; ++ ++ /* we keep volumes/mounts for blank and audio discs separate to handle e.g. mixed discs properly */ ++ GList *disc_volumes; ++ GList *disc_mounts; ++ ++}; ++ ++static void mountpoints_changed (GUnixMountMonitor *mount_monitor, ++ gpointer user_data); ++static void mounts_changed (GUnixMountMonitor *mount_monitor, ++ gpointer user_data); ++ ++static void presentable_added (GduPool *pool, ++ GduPresentable *presentable, ++ gpointer user_data); ++static void presentable_removed (GduPool *pool, ++ GduPresentable *presentable, ++ gpointer user_data); ++ ++static void update_all (GGduVolumeMonitor *monitor, ++ gboolean emit_changes); ++ ++static void update_drives (GGduVolumeMonitor *monitor, ++ GList **added_drives, ++ GList **removed_drives); ++static void update_volumes (GGduVolumeMonitor *monitor, ++ GList **added_volumes, ++ GList **removed_volumes); ++static void update_mounts (GGduVolumeMonitor *monitor, ++ GList **added_mounts, ++ GList **removed_mounts); ++static void update_discs (GGduVolumeMonitor *monitor, ++ GList **added_volumes, ++ GList **removed_volumes, ++ GList **added_mounts, ++ GList **removed_mounts); ++ ++ ++G_DEFINE_TYPE (GGduVolumeMonitor, g_gdu_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR) ++ ++static void ++list_free (GList *objects) ++{ ++ g_list_foreach (objects, (GFunc)g_object_unref, NULL); ++ g_list_free (objects); ++} ++ ++static void ++g_gdu_volume_monitor_dispose (GObject *object) ++{ ++ GGduVolumeMonitor *monitor; ++ ++ monitor = G_GDU_VOLUME_MONITOR (object); ++ ++ the_volume_monitor = NULL; ++ ++ if (G_OBJECT_CLASS (g_gdu_volume_monitor_parent_class)->dispose) ++ (*G_OBJECT_CLASS (g_gdu_volume_monitor_parent_class)->dispose) (object); ++} ++ ++static void ++g_gdu_volume_monitor_finalize (GObject *object) ++{ ++ GGduVolumeMonitor *monitor; ++ ++ monitor = G_GDU_VOLUME_MONITOR (object); ++ ++ g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mountpoints_changed, monitor); ++ g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mounts_changed, monitor); ++ g_signal_handlers_disconnect_by_func (monitor->mount_monitor, presentable_added, monitor); ++ g_signal_handlers_disconnect_by_func (monitor->mount_monitor, presentable_removed, monitor); ++ ++ g_object_unref (monitor->mount_monitor); ++ ++ g_object_unref (monitor->pool); ++ ++ list_free (monitor->last_optical_disc_devices); ++ list_free (monitor->last_mountpoints); ++ g_list_foreach (monitor->last_mounts, ++ (GFunc)g_unix_mount_free, NULL); ++ g_list_free (monitor->last_mounts); ++ ++ list_free (monitor->drives); ++ list_free (monitor->volumes); ++ list_free (monitor->mounts); ++ ++ list_free (monitor->disc_volumes); ++ list_free (monitor->disc_mounts); ++ ++ if (G_OBJECT_CLASS (g_gdu_volume_monitor_parent_class)->finalize) ++ (*G_OBJECT_CLASS (g_gdu_volume_monitor_parent_class)->finalize) (object); ++} ++ ++static GList * ++get_mounts (GVolumeMonitor *volume_monitor) ++{ ++ GGduVolumeMonitor *monitor; ++ GList *l, *ll; ++ ++ monitor = G_GDU_VOLUME_MONITOR (volume_monitor); ++ ++ l = g_list_copy (monitor->mounts); ++ ll = g_list_copy (monitor->disc_mounts); ++ l = g_list_concat (l, ll); ++ ++ g_list_foreach (l, (GFunc)g_object_ref, NULL); ++ ++ return l; ++} ++ ++static GList * ++get_volumes (GVolumeMonitor *volume_monitor) ++{ ++ GGduVolumeMonitor *monitor; ++ GList *l, *ll; ++ ++ monitor = G_GDU_VOLUME_MONITOR (volume_monitor); ++ ++ l = g_list_copy (monitor->volumes); ++ ll = g_list_copy (monitor->disc_volumes); ++ l = g_list_concat (l, ll); ++ ++ g_list_foreach (l, (GFunc)g_object_ref, NULL); ++ ++ return l; ++} ++ ++static GList * ++get_connected_drives (GVolumeMonitor *volume_monitor) ++{ ++ GGduVolumeMonitor *monitor; ++ GList *l; ++ ++ monitor = G_GDU_VOLUME_MONITOR (volume_monitor); ++ ++ l = g_list_copy (monitor->drives); ++ g_list_foreach (l, (GFunc)g_object_ref, NULL); ++ ++ return l; ++} ++ ++static GVolume * ++get_volume_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid) ++{ ++ GGduVolumeMonitor *monitor; ++ GGduVolume *volume; ++ GList *l; ++ ++ monitor = G_GDU_VOLUME_MONITOR (volume_monitor); ++ ++ volume = NULL; ++ ++ for (l = monitor->volumes; l != NULL; l = l->next) ++ { ++ volume = l->data; ++ if (g_gdu_volume_has_uuid (volume, uuid)) ++ goto found; ++ } ++ ++ for (l = monitor->disc_volumes; l != NULL; l = l->next) ++ { ++ volume = l->data; ++ if (g_gdu_volume_has_uuid (volume, uuid)) ++ goto found; ++ } ++ ++ return NULL; ++ ++ found: ++ ++ g_object_ref (volume); ++ ++ return (GVolume *)volume; ++} ++ ++static GMount * ++get_mount_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid) ++{ ++ GGduVolumeMonitor *monitor; ++ GGduMount *mount; ++ GList *l; ++ ++ monitor = G_GDU_VOLUME_MONITOR (volume_monitor); ++ ++ mount = NULL; ++ ++ for (l = monitor->mounts; l != NULL; l = l->next) ++ { ++ mount = l->data; ++ if (g_gdu_mount_has_uuid (mount, uuid)) ++ goto found; ++ } ++ ++ for (l = monitor->disc_mounts; l != NULL; l = l->next) ++ { ++ mount = l->data; ++ if (g_gdu_mount_has_uuid (mount, uuid)) ++ goto found; ++ } ++ ++ return NULL; ++ ++ found: ++ ++ g_object_ref (mount); ++ ++ return (GMount *)mount; ++} ++ ++static GMount * ++get_mount_for_mount_path (const char *mount_path, ++ GCancellable *cancellable) ++{ ++ GMount *mount; ++ GGduMount *gdu_mount; ++ GGduVolumeMonitor *volume_monitor; ++ ++ if (the_volume_monitor == NULL) ++ { ++ /* Dammit, no monitor is set up.. so we have to create one, find ++ * what the user asks for and throw it away again. ++ * ++ * What a waste - especially considering that there's IO ++ * involved in doing this: connect to the system message bus; ++ * IPC to DeviceKit-disks etc etc ++ */ ++ volume_monitor = G_GDU_VOLUME_MONITOR (g_gdu_volume_monitor_new ()); ++ } ++ else ++ { ++ volume_monitor = g_object_ref (the_volume_monitor); ++ } ++ ++ mount = NULL; ++ ++ /* creation of the volume monitor might actually fail */ ++ if (volume_monitor != NULL) ++ { ++ GList *l; ++ ++ for (l = volume_monitor->mounts; l != NULL; l = l->next) ++ { ++ gdu_mount = l->data; ++ ++ if (g_gdu_mount_has_mount_path (gdu_mount, mount_path)) ++ { ++ mount = g_object_ref (gdu_mount); ++ break; ++ } ++ } ++ } ++ ++ g_object_unref (volume_monitor); ++ ++ return (GMount *) mount; ++} ++ ++static void ++mountpoints_changed (GUnixMountMonitor *mount_monitor, ++ gpointer user_data) ++{ ++ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); ++ ++ update_all (monitor, TRUE); ++} ++ ++static void ++mounts_changed (GUnixMountMonitor *mount_monitor, ++ gpointer user_data) ++{ ++ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); ++ ++ update_all (monitor, TRUE); ++} ++ ++static void ++presentable_added (GduPool *pool, ++ GduPresentable *presentable, ++ gpointer user_data) ++{ ++ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); ++ ++ /*g_debug ("presentable_added %p: %s", presentable, gdu_presentable_get_id (presentable));*/ ++ ++ update_all (monitor, TRUE); ++} ++ ++static void ++presentable_removed (GduPool *pool, ++ GduPresentable *presentable, ++ gpointer user_data) ++{ ++ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); ++ ++ /*g_debug ("presentable_removed %p: %s", presentable, gdu_presentable_get_id (presentable));*/ ++ ++ update_all (monitor, TRUE); ++} ++ ++static void ++presentable_changed (GduPool *pool, ++ GduPresentable *presentable, ++ gpointer user_data) ++{ ++ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); ++ ++ /*g_debug ("presentable_changed %p: %s", presentable, gdu_presentable_get_id (presentable));*/ ++ ++ update_all (monitor, TRUE); ++} ++ ++static void ++presentable_job_changed (GduPool *pool, ++ GduPresentable *presentable, ++ gpointer user_data) ++{ ++ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); ++ ++ /*g_debug ("presentable_job_changed %p: %s", presentable, gdu_presentable_get_id (presentable));*/ ++ ++ update_all (monitor, TRUE); ++} ++ ++static GObject * ++g_gdu_volume_monitor_constructor (GType type, ++ guint n_construct_properties, ++ GObjectConstructParam *construct_properties) ++{ ++ GObject *object; ++ GGduVolumeMonitor *monitor; ++ GGduVolumeMonitorClass *klass; ++ GObjectClass *parent_class; ++ ++ if (the_volume_monitor != NULL) ++ { ++ object = g_object_ref (the_volume_monitor); ++ return object; ++ } ++ ++ /*g_warning ("creating gdu vm");*/ ++ ++ object = NULL; ++ ++ /* Invoke parent constructor. */ ++ klass = G_GDU_VOLUME_MONITOR_CLASS (g_type_class_peek (G_TYPE_GDU_VOLUME_MONITOR)); ++ parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); ++ object = parent_class->constructor (type, ++ n_construct_properties, ++ construct_properties); ++ ++ monitor = G_GDU_VOLUME_MONITOR (object); ++ ++ monitor->mount_monitor = g_unix_mount_monitor_new (); ++ ++ g_signal_connect (monitor->mount_monitor, ++ "mounts_changed", ++ G_CALLBACK (mounts_changed), ++ monitor); ++ ++ g_signal_connect (monitor->mount_monitor, ++ "mountpoints_changed", ++ G_CALLBACK (mountpoints_changed), ++ monitor); ++ ++ monitor->pool = gdu_pool_new (); ++ ++ g_signal_connect (monitor->pool, ++ "presentable_added", ++ G_CALLBACK (presentable_added), ++ monitor); ++ ++ g_signal_connect (monitor->pool, ++ "presentable_removed", ++ G_CALLBACK (presentable_removed), ++ monitor); ++ ++ g_signal_connect (monitor->pool, ++ "presentable_changed", ++ G_CALLBACK (presentable_changed), ++ monitor); ++ ++ g_signal_connect (monitor->pool, ++ "presentable_job_changed", ++ G_CALLBACK (presentable_job_changed), ++ monitor); ++ ++ update_all (monitor, FALSE); ++ ++ the_volume_monitor = monitor; ++ ++ return object; ++} ++ ++static void ++g_gdu_volume_monitor_init (GGduVolumeMonitor *monitor) ++{ ++} ++ ++static gboolean ++is_supported (void) ++{ ++ /* TODO: return FALSE if DeviceKit-disks is not available */ ++ return TRUE; ++} ++ ++static void ++g_gdu_volume_monitor_class_init (GGduVolumeMonitorClass *klass) ++{ ++ GObjectClass *gobject_class = G_OBJECT_CLASS (klass); ++ GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS (klass); ++ GNativeVolumeMonitorClass *native_class = G_NATIVE_VOLUME_MONITOR_CLASS (klass); ++ ++ gobject_class->constructor = g_gdu_volume_monitor_constructor; ++ gobject_class->finalize = g_gdu_volume_monitor_finalize; ++ gobject_class->dispose = g_gdu_volume_monitor_dispose; ++ ++ monitor_class->get_mounts = get_mounts; ++ monitor_class->get_volumes = get_volumes; ++ monitor_class->get_connected_drives = get_connected_drives; ++ monitor_class->get_volume_for_uuid = get_volume_for_uuid; ++ monitor_class->get_mount_for_uuid = get_mount_for_uuid; ++ monitor_class->is_supported = is_supported; ++ ++ native_class->get_mount_for_mount_path = get_mount_for_mount_path; ++} ++ ++/** ++ * g_gdu_volume_monitor_new: ++ * ++ * Returns: a new #GVolumeMonitor. ++ **/ ++GVolumeMonitor * ++g_gdu_volume_monitor_new (void) ++{ ++ GGduVolumeMonitor *monitor; ++ ++ monitor = g_object_new (G_TYPE_GDU_VOLUME_MONITOR, NULL); ++ ++ return G_VOLUME_MONITOR (monitor); ++} ++ ++static void ++diff_sorted_lists (GList *list1, ++ GList *list2, ++ GCompareFunc compare, ++ GList **added, ++ GList **removed) ++{ ++ int order; ++ ++ *added = *removed = NULL; ++ ++ while (list1 != NULL && ++ list2 != NULL) ++ { ++ order = (*compare) (list1->data, list2->data); ++ if (order < 0) ++ { ++ *removed = g_list_prepend (*removed, list1->data); ++ list1 = list1->next; ++ } ++ else if (order > 0) ++ { ++ *added = g_list_prepend (*added, list2->data); ++ list2 = list2->next; ++ } ++ else ++ { /* same item */ ++ list1 = list1->next; ++ list2 = list2->next; ++ } ++ } ++ ++ while (list1 != NULL) ++ { ++ *removed = g_list_prepend (*removed, list1->data); ++ list1 = list1->next; ++ } ++ while (list2 != NULL) ++ { ++ *added = g_list_prepend (*added, list2->data); ++ list2 = list2->next; ++ } ++} ++ ++static GGduVolume * ++find_volume_for_mount_path (GGduVolumeMonitor *monitor, ++ const char *mount_path) ++{ ++ GList *l; ++ GGduVolume *found; ++ ++ found = NULL; ++ ++ for (l = monitor->volumes; l != NULL; l = l->next) ++ { ++ GGduVolume *volume = l->data; ++ ++ if (g_gdu_volume_has_mount_path (volume, mount_path)) ++ { ++ found = volume; ++ break; ++ } ++ } ++ ++ return found; ++} ++ ++static GGduMount * ++find_mount_by_mount_path (GGduVolumeMonitor *monitor, ++ const char *mount_path) ++{ ++ GList *l; ++ ++ for (l = monitor->mounts; l != NULL; l = l->next) ++ { ++ GGduMount *mount = l->data; ++ ++ if (g_gdu_mount_has_mount_path (mount, mount_path)) ++ return mount; ++ } ++ ++ return NULL; ++} ++ ++/* TODO: move to gio */ ++static gboolean ++_g_unix_mount_point_guess_should_display (GUnixMountPoint *mount_point) ++{ ++ const char *mount_path; ++ ++ mount_path = g_unix_mount_point_get_mount_path (mount_point); ++ ++ /* Never display internal mountpoints */ ++ if (g_unix_is_mount_path_system_internal (mount_path)) ++ return FALSE; ++ ++ /* Only display things in /media (which are generally user mountable) ++ and home dir (fuse stuff) */ ++ if (g_str_has_prefix (mount_path, "/media/")) ++ return TRUE; ++ ++ if (g_str_has_prefix (mount_path, g_get_home_dir ())) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++static GUnixMountPoint * ++get_mount_point_for_device (GduDevice *d, GList *fstab_mount_points) ++{ ++ GList *l; ++ const gchar *device_file; ++ const gchar *mount_path; ++ GUnixMountPoint *ret; ++ ++ ret = NULL; ++ ++ mount_path = gdu_device_get_mount_path (d); ++ ++ device_file = gdu_device_get_device_file (d); ++ ++ for (l = fstab_mount_points; l != NULL; l = l->next) ++ { ++ GUnixMountPoint *mount_point = l->data; ++ const gchar *device_file; ++ const gchar *fstab_mount_path; ++ ++ fstab_mount_path = g_unix_mount_point_get_mount_path (mount_point); ++ if (g_strcmp0 (mount_path, fstab_mount_path) == 0) ++ { ++ ret = mount_point; ++ goto out; ++ } ++ ++ device_file = g_unix_mount_point_get_device_path (mount_point); ++ if (g_str_has_prefix (device_file, "LABEL=")) ++ { ++ if (g_strcmp0 (device_file + 6, gdu_device_id_get_label (d)) == 0) ++ { ++ ret = mount_point; ++ goto out; ++ } ++ } ++ else if (g_str_has_prefix (device_file, "UUID=")) ++ { ++ if (g_ascii_strcasecmp (device_file + 5, gdu_device_id_get_uuid (d)) == 0) ++ { ++ ret = mount_point; ++ goto out; ++ } ++ } ++ else ++ { ++ char resolved_device_file[PATH_MAX]; ++ ++ /* handle symlinks such as /dev/disk/by-uuid/47C2-1994 */ ++ if (realpath (device_file, resolved_device_file) != NULL && ++ g_strcmp0 (resolved_device_file, device_file) == 0) ++ { ++ ret = mount_point; ++ goto out; ++ } ++ } ++ } ++ ++ out: ++ return ret; ++} ++ ++static gboolean ++should_mount_be_ignored (GduPool *pool, GduDevice *d) ++{ ++ gboolean ret; ++ const gchar *mount_path; ++ GUnixMountEntry *mount_entry; ++ ++ ret = FALSE; ++ ++ if (gdu_device_is_mounted (d)) ++ goto out; ++ ++ mount_path = gdu_device_get_mount_path (d); ++ if (mount_path == NULL || strlen (mount_path) == 0) ++ goto out; ++ ++ mount_entry = g_unix_mount_at (mount_path, NULL); ++ if (mount_entry != NULL) ++ { ++ if (!g_unix_mount_guess_should_display (mount_entry)) ++ { ++ ret = TRUE; ++ } ++ g_unix_mount_free (mount_entry); ++ } ++ ++ out: ++ return ret; ++} ++ ++static gboolean ++should_volume_be_ignored (GduPool *pool, GduVolume *volume, GList *fstab_mount_points) ++{ ++ GduDevice *device; ++ gboolean ret; ++ const gchar *usage; ++ const gchar *type; ++ ++ ret = TRUE; ++ device = NULL; ++ ++ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume)); ++ ++ usage = gdu_device_id_get_usage (device); ++ type = gdu_device_id_get_type (device); ++ ++ if (g_strcmp0 (usage, "filesystem") == 0) ++ { ++ GUnixMountPoint *mount_point; ++ ++ /* don't ignore volumes with a mountable filesystem unless ++ * ++ * - volume is referenced in /etc/fstab and deemed to be ignored ++ * ++ * - volume is mounted and should_mount_be_ignored() deems it should be ignored ++ * ++ * - volume is a cleartext LUKS device as the cryptotext LUKS volume will morph ++ * into the cleartext volume when unlocked (see ggduvolume.c) ++ */ ++ ++ if (gdu_device_is_luks_cleartext (device)) ++ goto out; ++ ++ mount_point = get_mount_point_for_device (device, fstab_mount_points); ++ if (mount_point != NULL && !_g_unix_mount_point_guess_should_display (mount_point)) ++ goto out; ++ ++ if (gdu_device_is_mounted (device)) ++ { ++ ret = should_mount_be_ignored (pool, device); ++ goto out; ++ } ++ ++ ret = FALSE; ++ ++ } ++ else if (g_strcmp0 (usage, "crypto") == 0 && g_strcmp0 (type, "crypto_LUKS") == 0) ++ { ++ /* don't ignore LUKS volumes */ ++ ret = FALSE; ++ } ++ ++ out: ++ ++ g_object_unref (device); ++ return ret; ++} ++ ++static gboolean ++should_drive_be_ignored (GduPool *pool, GduDrive *d, GList *fstab_mount_points) ++{ ++ GduDevice *device; ++ gboolean ret; ++ gboolean has_volumes; ++ gboolean all_volumes_are_ignored; ++ GList *enclosed; ++ GList *l; ++ ++ ret = FALSE; ++ device = NULL; ++ enclosed = NULL; ++ ++ device = gdu_presentable_get_device (GDU_PRESENTABLE (d)); ++ ++ /* the GduDevice for an activatable drive (such as RAID) is NULL if the drive is not ++ * activated; never ignore these ++ */ ++ if (device == NULL) ++ goto out; ++ ++ /* never ignore drives with removable media */ ++ if (gdu_device_is_removable (device)) ++ goto out; ++ ++ has_volumes = FALSE; ++ all_volumes_are_ignored = TRUE; ++ ++ /* never ignore a drive if it has volumes that we don't want to ignore */ ++ enclosed = gdu_pool_get_enclosed_presentables (pool, GDU_PRESENTABLE (d)); ++ for (l = enclosed; l != NULL; l = l->next) ++ { ++ GduPresentable *enclosed_presentable = GDU_PRESENTABLE (l->data); ++ ++ /* There might be other presentables that GduVolume objects; for example GduVolumeHole */ ++ if (GDU_IS_VOLUME (enclosed_presentable)) ++ { ++ GduVolume *volume = GDU_VOLUME (enclosed_presentable); ++ ++ has_volumes = TRUE; ++ ++ if (!should_volume_be_ignored (pool, volume, fstab_mount_points)) ++ { ++ all_volumes_are_ignored = FALSE; ++ break; ++ } ++ } ++ } ++ ++ ret = has_volumes && all_volumes_are_ignored; ++ ++ out: ++ g_list_foreach (enclosed, (GFunc) g_object_unref, NULL); ++ g_list_free (enclosed); ++ ++ if (device != NULL) ++ g_object_unref (device); ++ ++ return ret; ++} ++ ++static void ++list_emit (GGduVolumeMonitor *monitor, ++ const char *monitor_signal, ++ const char *object_signal, ++ GList *objects) ++{ ++ GList *l; ++ ++ for (l = objects; l != NULL; l = l->next) ++ { ++ g_signal_emit_by_name (monitor, monitor_signal, l->data); ++ if (object_signal) ++ g_signal_emit_by_name (l->data, object_signal); ++ } ++} ++ ++static void ++update_all (GGduVolumeMonitor *monitor, ++ gboolean emit_changes) ++{ ++ GList *added_drives, *removed_drives; ++ GList *added_volumes, *removed_volumes; ++ GList *added_mounts, *removed_mounts; ++ ++ added_drives = NULL; ++ removed_drives = NULL; ++ added_volumes = NULL; ++ removed_volumes = NULL; ++ added_mounts = NULL; ++ removed_mounts = NULL; ++ ++ update_drives (monitor, &added_drives, &removed_drives); ++ update_volumes (monitor, &added_volumes, &removed_volumes); ++ update_mounts (monitor, &added_mounts, &removed_mounts); ++ update_discs (monitor, ++ &added_volumes, &removed_volumes, ++ &added_mounts, &removed_mounts); ++ ++ if (emit_changes) ++ { ++ list_emit (monitor, ++ "drive_disconnected", NULL, ++ removed_drives); ++ list_emit (monitor, ++ "drive_connected", NULL, ++ added_drives); ++ ++ list_emit (monitor, ++ "volume_removed", "removed", ++ removed_volumes); ++ list_emit (monitor, ++ "volume_added", NULL, ++ added_volumes); ++ ++ list_emit (monitor, ++ "mount_removed", "unmounted", ++ removed_mounts); ++ list_emit (monitor, ++ "mount_added", NULL, ++ added_mounts); ++ } ++ ++ list_free (removed_drives); ++ list_free (added_drives); ++ list_free (removed_volumes); ++ list_free (added_volumes); ++ list_free (removed_mounts); ++ list_free (added_mounts); ++} ++ ++static GGduMount * ++find_disc_mount_for_volume (GGduVolumeMonitor *monitor, ++ GGduVolume *volume) ++{ ++ GList *l; ++ ++ for (l = monitor->disc_mounts; l != NULL; l = l->next) ++ { ++ GGduMount *mount = G_GDU_MOUNT (l->data); ++ ++ if (g_gdu_mount_has_volume (mount, volume)) ++ return mount; ++ } ++ ++ return NULL; ++} ++ ++static GGduVolume * ++find_disc_volume_for_device_file (GGduVolumeMonitor *monitor, ++ const gchar *device_file) ++{ ++ GList *l; ++ ++ for (l = monitor->disc_volumes; l != NULL; l = l->next) ++ { ++ GGduVolume *volume = G_GDU_VOLUME (l->data); ++ ++ if (g_gdu_volume_has_device_file (volume, device_file)) ++ return volume; ++ } ++ ++ return NULL; ++} ++ ++static GGduVolume * ++find_volume_for_device_file (GGduVolumeMonitor *monitor, ++ const gchar *device_file) ++{ ++ GList *l; ++ ++ for (l = monitor->volumes; l != NULL; l = l->next) ++ { ++ GGduVolume *volume = G_GDU_VOLUME (l->data); ++ ++ if (g_gdu_volume_has_device_file (volume, device_file)) ++ return volume; ++ } ++ ++ return NULL; ++} ++ ++static GGduDrive * ++find_drive_by_device_file (GGduVolumeMonitor *monitor, ++ const gchar *device_file) ++{ ++ GList *l; ++ ++ for (l = monitor->drives; l != NULL; l = l->next) ++ { ++ GGduDrive *drive = G_GDU_DRIVE (l->data); ++ ++ if (g_gdu_drive_has_device_file (drive, device_file)) ++ return drive; ++ } ++ ++ return NULL; ++} ++ ++static GGduDrive * ++find_drive_by_presentable (GGduVolumeMonitor *monitor, ++ GduPresentable *presentable) ++{ ++ GList *l; ++ ++ for (l = monitor->drives; l != NULL; l = l->next) ++ { ++ GGduDrive *drive = G_GDU_DRIVE (l->data); ++ ++ if (g_gdu_drive_has_presentable (drive, presentable)) ++ return drive; ++ } ++ ++ return NULL; ++} ++ ++static void ++update_drives (GGduVolumeMonitor *monitor, ++ GList **added_drives, ++ GList **removed_drives) ++{ ++ GList *cur_drives; ++ GList *new_drives; ++ GList *removed, *added; ++ GList *l, *ll; ++ GGduDrive *drive; ++ GList *fstab_mount_points; ++ ++ fstab_mount_points = g_unix_mount_points_get (NULL); ++ ++ cur_drives = NULL; ++ for (l = monitor->drives; l != NULL; l = l->next) ++ cur_drives = g_list_prepend (cur_drives, g_gdu_drive_get_presentable (G_GDU_DRIVE (l->data))); ++ ++ /* remove devices we want to ignore - we do it here so we get to reevaluate ++ * on the next update whether they should still be ignored ++ */ ++ new_drives = gdu_pool_get_presentables (monitor->pool); ++ for (l = new_drives; l != NULL; l = ll) ++ { ++ GduPresentable *p = GDU_PRESENTABLE (l->data); ++ ll = l->next; ++ if (!GDU_IS_DRIVE (p) || should_drive_be_ignored (monitor->pool, GDU_DRIVE (p), fstab_mount_points)) ++ { ++ g_object_unref (p); ++ new_drives = g_list_delete_link (new_drives, l); ++ } ++ } ++ ++ cur_drives = g_list_sort (cur_drives, (GCompareFunc) gdu_presentable_compare); ++ new_drives = g_list_sort (new_drives, (GCompareFunc) gdu_presentable_compare); ++ diff_sorted_lists (cur_drives, ++ new_drives, (GCompareFunc) gdu_presentable_compare, ++ &added, &removed); ++ ++ for (l = removed; l != NULL; l = l->next) ++ { ++ GduPresentable *p = GDU_PRESENTABLE (l->data); ++ GduDevice *d; ++ ++ d = gdu_presentable_get_device (p); ++ ++ drive = find_drive_by_presentable (monitor, p); ++ if (drive != NULL) ++ { ++ /*g_debug ("removing drive %s", gdu_presentable_get_id (p));*/ ++ g_gdu_drive_disconnected (drive); ++ monitor->drives = g_list_remove (monitor->drives, drive); ++ *removed_drives = g_list_prepend (*removed_drives, drive); ++ } ++ if (d != NULL) ++ g_object_unref (d); ++ } ++ ++ for (l = added; l != NULL; l = l->next) ++ { ++ GduPresentable *p = GDU_PRESENTABLE (l->data); ++ GduDevice *d; ++ ++ d = gdu_presentable_get_device (p); ++ ++ drive = find_drive_by_presentable (monitor, p); ++ if (drive == NULL) ++ { ++ /*g_debug ("adding drive %s", gdu_presentable_get_id (p));*/ ++ drive = g_gdu_drive_new (G_VOLUME_MONITOR (monitor), p); ++ if (drive != NULL) ++ { ++ monitor->drives = g_list_prepend (monitor->drives, drive); ++ *added_drives = g_list_prepend (*added_drives, g_object_ref (drive)); ++ } ++ } ++ if (d != NULL) ++ g_object_unref (d); ++ } ++ ++ g_list_free (added); ++ g_list_free (removed); ++ ++ g_list_free (cur_drives); ++ ++ g_list_foreach (new_drives, (GFunc) g_object_unref, NULL); ++ g_list_free (new_drives); ++ ++ g_list_foreach (fstab_mount_points, (GFunc) g_unix_mount_point_free, NULL); ++ g_list_free (fstab_mount_points); ++} ++ ++static void ++update_volumes (GGduVolumeMonitor *monitor, ++ GList **added_volumes, ++ GList **removed_volumes) ++{ ++ GList *cur_volumes; ++ GList *new_volumes; ++ GList *removed, *added; ++ GList *l, *ll; ++ GGduVolume *volume; ++ GGduDrive *drive; ++ GList *fstab_mount_points; ++ ++ fstab_mount_points = g_unix_mount_points_get (NULL); ++ ++ cur_volumes = NULL; ++ for (l = monitor->volumes; l != NULL; l = l->next) ++ cur_volumes = g_list_prepend (cur_volumes, g_gdu_volume_get_presentable (G_GDU_VOLUME (l->data))); ++ ++ /* remove devices we want to ignore - we do it here so we get to reevaluate ++ * on the next update whether they should still be ignored ++ */ ++ new_volumes = gdu_pool_get_presentables (monitor->pool); ++ for (l = new_volumes; l != NULL; l = ll) ++ { ++ GduPresentable *p = GDU_PRESENTABLE (l->data); ++ ll = l->next; ++ if (!GDU_IS_VOLUME (p) || should_volume_be_ignored (monitor->pool, GDU_VOLUME (p), fstab_mount_points)) ++ { ++ g_object_unref (p); ++ new_volumes = g_list_delete_link (new_volumes, l); ++ } ++ } ++ ++ cur_volumes = g_list_sort (cur_volumes, (GCompareFunc) gdu_presentable_compare); ++ new_volumes = g_list_sort (new_volumes, (GCompareFunc) gdu_presentable_compare); ++ diff_sorted_lists (cur_volumes, ++ new_volumes, (GCompareFunc) gdu_presentable_compare, ++ &added, &removed); ++ ++ for (l = removed; l != NULL; l = l->next) ++ { ++ GduPresentable *p = GDU_PRESENTABLE (l->data); ++ GduDevice *d; ++ ++ d = gdu_presentable_get_device (p); ++ ++ volume = find_volume_for_device_file (monitor, gdu_device_get_device_file (d)); ++ if (volume != NULL) ++ { ++ /*g_debug ("removing volume %s", gdu_device_get_device_file (d));*/ ++ g_gdu_volume_removed (volume); ++ monitor->volumes = g_list_remove (monitor->volumes, volume); ++ *removed_volumes = g_list_prepend (*removed_volumes, volume); ++ } ++ g_object_unref (d); ++ } ++ ++ for (l = added; l != NULL; l = l->next) ++ { ++ GduPresentable *p = GDU_PRESENTABLE (l->data); ++ GduDevice *d; ++ ++ d = gdu_presentable_get_device (p); ++ ++ volume = find_volume_for_device_file (monitor, gdu_device_get_device_file (d)); ++ if (volume == NULL) ++ { ++ GduPresentable *toplevel_presentable; ++ ++ toplevel_presentable = gdu_presentable_get_toplevel (p); ++ if (toplevel_presentable != NULL) ++ { ++ GduDevice *toplevel_device; ++ ++ toplevel_device = gdu_presentable_get_device (toplevel_presentable); ++ drive = find_drive_by_device_file (monitor, gdu_device_get_device_file (toplevel_device)); ++ /*g_debug ("adding volume %s (drive %s)", ++ gdu_device_get_device_file (d), ++ gdu_device_get_device_file (toplevel_device));*/ ++ g_object_unref (toplevel_device); ++ g_object_unref (toplevel_presentable); ++ } ++ else ++ { ++ drive = NULL; ++ /*g_debug ("adding volume %s (no drive)", gdu_device_get_device_file (d));*/ ++ } ++ ++ volume = g_gdu_volume_new (G_VOLUME_MONITOR (monitor), ++ GDU_VOLUME (p), ++ drive, ++ NULL); ++ if (volume != NULL) ++ { ++ monitor->volumes = g_list_prepend (monitor->volumes, volume); ++ *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume)); ++ } ++ } ++ ++ g_object_unref (d); ++ } ++ ++ g_list_free (added); ++ g_list_free (removed); ++ ++ g_list_foreach (new_volumes, (GFunc) g_object_unref, NULL); ++ g_list_free (new_volumes); ++ ++ g_list_free (cur_volumes); ++ ++ g_list_foreach (fstab_mount_points, (GFunc) g_unix_mount_point_free, NULL); ++ g_list_free (fstab_mount_points); ++} ++ ++static void ++update_mounts (GGduVolumeMonitor *monitor, ++ GList **added_mounts, ++ GList **removed_mounts) ++{ ++ GList *new_mounts; ++ GList *removed, *added; ++ GList *l, *ll; ++ GGduMount *mount; ++ GGduVolume *volume; ++ const char *device_file; ++ const char *mount_path; ++ ++ new_mounts = g_unix_mounts_get (NULL); ++ ++ /* remove mounts we want to ignore - we do it here so we get to reevaluate ++ * on the next update whether they should still be ignored ++ */ ++ for (l = new_mounts; l != NULL; l = ll) ++ { ++ GUnixMountEntry *mount_entry = l->data; ++ ll = l->next; ++ ++ /* keep in sync with should_mount_be_ignored() */ ++ if (!g_unix_mount_guess_should_display (mount_entry)) ++ { ++ g_unix_mount_free (mount_entry); ++ new_mounts = g_list_delete_link (new_mounts, l); ++ } ++ } ++ ++ new_mounts = g_list_sort (new_mounts, (GCompareFunc) g_unix_mount_compare); ++ ++ diff_sorted_lists (monitor->last_mounts, ++ new_mounts, (GCompareFunc) g_unix_mount_compare, ++ &added, &removed); ++ ++ for (l = removed; l != NULL; l = l->next) ++ { ++ GUnixMountEntry *mount_entry = l->data; ++ ++ mount = find_mount_by_mount_path (monitor, g_unix_mount_get_mount_path (mount_entry)); ++ if (mount) ++ { ++ /*g_debug ("removing mount %s", g_unix_mount_get_device_path (mount_entry));*/ ++ g_gdu_mount_unmounted (mount); ++ monitor->mounts = g_list_remove (monitor->mounts, mount); ++ ++ *removed_mounts = g_list_prepend (*removed_mounts, mount); ++ } ++ } ++ ++ for (l = added; l != NULL; l = l->next) ++ { ++ GUnixMountEntry *mount_entry = l->data; ++ ++ device_file = g_unix_mount_get_device_path (mount_entry); ++ mount_path = g_unix_mount_get_mount_path (mount_entry); ++ volume = find_volume_for_device_file (monitor, device_file); ++ if (volume == NULL) ++ volume = find_volume_for_mount_path (monitor, mount_path); ++ ++ /*g_debug ("adding mount %s (vol %p)", g_unix_mount_get_device_path (mount_entry), volume);*/ ++ mount = g_gdu_mount_new (G_VOLUME_MONITOR (monitor), mount_entry, volume); ++ if (mount) ++ { ++ monitor->mounts = g_list_prepend (monitor->mounts, mount); ++ *added_mounts = g_list_prepend (*added_mounts, g_object_ref (mount)); ++ } ++ } ++ ++ g_list_free (added); ++ g_list_free (removed); ++ g_list_foreach (monitor->last_mounts, ++ (GFunc)g_unix_mount_free, NULL); ++ g_list_free (monitor->last_mounts); ++ monitor->last_mounts = new_mounts; ++} ++ ++static void ++update_discs (GGduVolumeMonitor *monitor, ++ GList **added_volumes, ++ GList **removed_volumes, ++ GList **added_mounts, ++ GList **removed_mounts) ++{ ++ GList *cur_discs; ++ GList *new_discs; ++ GList *removed, *added; ++ GList *l, *ll; ++ GGduDrive *drive; ++ GGduVolume *volume; ++ GGduMount *mount; ++ ++ /* we also need to generate GVolume + GMount objects for ++ * ++ * - optical discs that have audio ++ * - optical discs that are blank ++ * ++ */ ++ ++ cur_discs = NULL; ++ for (l = monitor->disc_volumes; l != NULL; l = l->next) ++ cur_discs = g_list_prepend (cur_discs, g_gdu_volume_get_presentable (G_GDU_VOLUME (l->data))); ++ ++ new_discs = gdu_pool_get_presentables (monitor->pool); ++ for (l = new_discs; l != NULL; l = ll) ++ { ++ GduPresentable *p = GDU_PRESENTABLE (l->data); ++ GduDevice *d; ++ gboolean ignore; ++ ++ ll = l->next; ++ ignore = TRUE; ++ ++ /* filter out everything but discs that are blank or has audio */ ++ d = gdu_presentable_get_device (p); ++ if (GDU_IS_VOLUME (p) && d != NULL && gdu_device_is_optical_disc (d)) ++ { ++ if (gdu_device_optical_disc_get_num_audio_tracks (d) > 0 || gdu_device_optical_disc_get_is_blank (d)) ++ ignore = FALSE; ++ } ++ ++ if (ignore) ++ { ++ g_object_unref (p); ++ new_discs = g_list_delete_link (new_discs, l); ++ } ++ ++ if (d != NULL) ++ g_object_unref (d); ++ } ++ ++ cur_discs = g_list_sort (cur_discs, (GCompareFunc) gdu_presentable_compare); ++ new_discs = g_list_sort (new_discs, (GCompareFunc) gdu_presentable_compare); ++ diff_sorted_lists (cur_discs, new_discs, (GCompareFunc) gdu_presentable_compare, &added, &removed); ++ ++ for (l = removed; l != NULL; l = l->next) ++ { ++ GduPresentable *p = GDU_PRESENTABLE (l->data); ++ GduDevice *d; ++ ++ d = gdu_presentable_get_device (p); ++ ++ volume = find_disc_volume_for_device_file (monitor, gdu_device_get_device_file (d)); ++ mount = find_disc_mount_for_volume (monitor, volume); ++ ++ if (mount != NULL) ++ { ++ /*g_debug ("removing disc mount %s", gdu_device_get_device_file (d));*/ ++ g_gdu_mount_unmounted (mount); ++ monitor->disc_mounts = g_list_remove (monitor->disc_mounts, mount); ++ *removed_mounts = g_list_prepend (*removed_mounts, mount); ++ } ++ ++ if (volume != NULL) ++ { ++ /*g_debug ("removing disc volume %s", gdu_device_get_device_file (d));*/ ++ g_gdu_volume_removed (volume); ++ monitor->disc_volumes = g_list_remove (monitor->disc_volumes, volume); ++ *removed_volumes = g_list_prepend (*removed_volumes, volume); ++ } ++ ++ g_object_unref (d); ++ } ++ ++ for (l = added; l != NULL; l = l->next) ++ { ++ GduPresentable *p = GDU_PRESENTABLE (l->data); ++ GduDevice *d; ++ gboolean is_blank; ++ ++ d = gdu_presentable_get_device (p); ++ ++ is_blank = gdu_device_optical_disc_get_is_blank (d); ++ ++ volume = find_disc_volume_for_device_file (monitor, gdu_device_get_device_file (d)); ++ if (volume == NULL) ++ { ++ GduPresentable *toplevel_presentable; ++ ++ toplevel_presentable = gdu_presentable_get_toplevel (p); ++ if (toplevel_presentable != NULL) ++ { ++ GduDevice *toplevel_device; ++ ++ toplevel_device = gdu_presentable_get_device (toplevel_presentable); ++ drive = find_drive_by_device_file (monitor, gdu_device_get_device_file (toplevel_device)); ++ /*g_debug ("adding volume %s (drive %s)", ++ gdu_device_get_device_file (d), ++ gdu_device_get_device_file (toplevel_device));*/ ++ g_object_unref (toplevel_device); ++ g_object_unref (toplevel_presentable); ++ } ++ else ++ { ++ drive = NULL; ++ /*g_debug ("adding volume %s (no drive)", gdu_device_get_device_file (d));*/ ++ } ++ ++ mount = NULL; ++ if (is_blank) ++ { ++ volume = g_gdu_volume_new (G_VOLUME_MONITOR (monitor), ++ GDU_VOLUME (p), ++ drive, ++ NULL); ++ mount = g_gdu_mount_new (G_VOLUME_MONITOR (monitor), ++ NULL, ++ volume); ++ } ++ else ++ { ++ gchar *uri; ++ gchar *device_basename; ++ GFile *activation_root; ++ ++ /* the gvfsd-cdda backend uses URI's like these */ ++ device_basename = g_path_get_basename (gdu_device_get_device_file (d)); ++ uri = g_strdup_printf ("cdda://%s", device_basename); ++ activation_root = g_file_new_for_uri (uri); ++ g_free (device_basename); ++ g_free (uri); ++ ++ volume = g_gdu_volume_new (G_VOLUME_MONITOR (monitor), ++ GDU_VOLUME (p), ++ drive, ++ activation_root); ++ ++ g_object_unref (activation_root); ++ } ++ ++ if (volume != NULL) ++ { ++ monitor->disc_volumes = g_list_prepend (monitor->disc_volumes, volume); ++ *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume)); ++ ++ if (mount != NULL) ++ { ++ monitor->disc_mounts = g_list_prepend (monitor->disc_mounts, mount); ++ *added_mounts = g_list_prepend (*added_mounts, g_object_ref (mount)); ++ } ++ } ++ } ++ ++ g_object_unref (d); ++ } ++ ++ g_list_free (added); ++ g_list_free (removed); ++ ++ g_list_foreach (new_discs, (GFunc) g_object_unref, NULL); ++ g_list_free (new_discs); ++ ++ g_list_free (cur_discs); ++} +diff --git a/monitor/gdu/ggduvolumemonitor.h b/monitor/gdu/ggduvolumemonitor.h +new file mode 100644 +index 0000000..ec559c4 +--- /dev/null ++++ b/monitor/gdu/ggduvolumemonitor.h +@@ -0,0 +1,60 @@ ++/* -*- 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., 59 Temple Place, Suite 330, ++ * Boston, MA 02111-1307, USA. ++ * ++ * Author: David Zeuthen ++ */ ++ ++#ifndef __G_GDU_VOLUME_MONITOR_H__ ++#define __G_GDU_VOLUME_MONITOR_H__ ++ ++#include ++#include ++#include ++ ++#include ++ ++G_BEGIN_DECLS ++ ++#define G_TYPE_GDU_VOLUME_MONITOR (g_gdu_volume_monitor_get_type ()) ++#define G_GDU_VOLUME_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_GDU_VOLUME_MONITOR, GGduVolumeMonitor)) ++#define G_GDU_VOLUME_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_GDU_VOLUME_MONITOR, GGduVolumeMonitorClass)) ++#define G_IS_GDU_VOLUME_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_GDU_VOLUME_MONITOR)) ++#define G_IS_GDU_VOLUME_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_GDU_VOLUME_MONITOR)) ++ ++typedef struct _GGduVolumeMonitor GGduVolumeMonitor; ++typedef struct _GGduVolumeMonitorClass GGduVolumeMonitorClass; ++ ++/* Forward definitions */ ++typedef struct _GGduDrive GGduDrive; ++typedef struct _GGduVolume GGduVolume; ++typedef struct _GGduMount GGduMount; ++ ++struct _GGduVolumeMonitorClass { ++ GNativeVolumeMonitorClass parent_class; ++ ++}; ++ ++GType g_gdu_volume_monitor_get_type (void) G_GNUC_CONST; ++ ++GVolumeMonitor *g_gdu_volume_monitor_new (void); ++ ++G_END_DECLS ++ ++#endif /* __G_GDU_VOLUME_MONITOR_H__ */ +diff --git a/monitor/gdu/org.gtk.Private.GduVolumeMonitor.service.in b/monitor/gdu/org.gtk.Private.GduVolumeMonitor.service.in +new file mode 100644 +index 0000000..3fe4277 +--- /dev/null ++++ b/monitor/gdu/org.gtk.Private.GduVolumeMonitor.service.in +@@ -0,0 +1,3 @@ ++[D-BUS Service] ++Name=org.gtk.Private.GduVolumeMonitor ++Exec=@libexecdir@/gvfs-gdu-volume-monitor +diff --git a/monitor/gdu/polkit.c b/monitor/gdu/polkit.c +new file mode 100644 +index 0000000..5c37ba6 +--- /dev/null ++++ b/monitor/gdu/polkit.c +@@ -0,0 +1,137 @@ ++/* -*- 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., 59 Temple Place, Suite 330, ++ * Boston, MA 02111-1307, USA. ++ * ++ * Author: David Zeuthen ++ */ ++ ++#include ++#include ++ ++#include ++ ++#include "polkit.h" ++ ++static void ++_obtain_authz_cb (DBusMessage *reply, ++ GError *error, ++ gpointer user_data) ++{ ++ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data); ++ gboolean gained_authz; ++ DBusError derror; ++ ++ if (error != NULL) { ++ g_simple_async_result_set_from_error (simple, error); ++ goto out; ++ } ++ ++ dbus_error_init (&derror); ++ if (!dbus_message_get_args (reply, ++ &derror, ++ DBUS_TYPE_BOOLEAN, &gained_authz, ++ DBUS_TYPE_INVALID)) ++ { ++ /* no need to translate; this only happens if the auth agent is buggy */ ++ g_simple_async_result_set_error (simple, ++ G_IO_ERROR, ++ G_IO_ERROR_FAILED, ++ "Error parsing reply for ObtainAuthorization(): %s: %s", ++ derror.name, derror.message); ++ dbus_error_free (&derror); ++ goto out; ++ } ++ ++ if (!gained_authz && error == NULL) ++ { ++ /* no need to translate, is never shown */ ++ g_simple_async_result_set_error (simple, ++ G_IO_ERROR, ++ G_IO_ERROR_FAILED_HANDLED, ++ "Didn't obtain authorization (bug in libgio user, it shouldn't display this error)"); ++ } ++ ++ out: ++ g_simple_async_result_complete (simple); ++ g_object_unref (simple); ++} ++ ++ ++gboolean ++_obtain_authz_finish (GAsyncResult *res, ++ GError **error) ++{ ++ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res); ++ ++ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == _obtain_authz); ++ ++ if (g_simple_async_result_propagate_error (simple, error)) ++ return FALSE; ++ else ++ return TRUE; ++} ++ ++void ++_obtain_authz (const gchar *action_id, ++ GCancellable *cancellable, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ DBusConnection *connection; ++ DBusMessage *message; ++ GSimpleAsyncResult *simple; ++ guint xid; ++ guint pid; ++ DBusError derror; ++ ++ dbus_error_init (&derror); ++ ++ /* this connection is already integrated and guaranteed to exist, see gvfsproxyvolumemonitordaemon.c */ ++ connection = dbus_bus_get (DBUS_BUS_SESSION, &derror); ++ ++ simple = g_simple_async_result_new (NULL, ++ callback, ++ user_data, ++ _obtain_authz); ++ ++ message = dbus_message_new_method_call ("org.freedesktop.PolicyKit.AuthenticationAgent", /* bus name */ ++ "/", /* object */ ++ "org.freedesktop.PolicyKit.AuthenticationAgent", /* interface */ ++ "ObtainAuthorization"); ++ ++ xid = 0; ++ pid = getpid (); ++ ++ dbus_message_append_args (message, ++ DBUS_TYPE_STRING, ++ &(action_id), ++ DBUS_TYPE_UINT32, ++ &(xid), ++ DBUS_TYPE_UINT32, ++ &(pid), ++ DBUS_TYPE_INVALID); ++ ++ _g_dbus_connection_call_async (connection, ++ message, ++ -1, ++ (GAsyncDBusCallback) _obtain_authz_cb, ++ simple); ++ dbus_message_unref (message); ++ dbus_connection_unref (connection); ++} +diff --git a/monitor/gdu/polkit.h b/monitor/gdu/polkit.h +new file mode 100644 +index 0000000..4b26189 +--- /dev/null ++++ b/monitor/gdu/polkit.h +@@ -0,0 +1,44 @@ ++/* -*- 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., 59 Temple Place, Suite 330, ++ * Boston, MA 02111-1307, USA. ++ * ++ * Author: David Zeuthen ++ */ ++ ++ ++#ifndef __POLKIT_H__ ++#define __POLKIT_H__ ++ ++#include ++#include ++#include ++ ++G_BEGIN_DECLS ++ ++void _obtain_authz (const gchar *action_id, ++ GCancellable *cancellable, ++ GAsyncReadyCallback callback, ++ gpointer user_data); ++ ++gboolean _obtain_authz_finish (GAsyncResult *res, ++ GError **error); ++ ++G_END_DECLS ++ ++#endif /* __POLKIT_H__ */ +-- +1.6.2.2 + diff --git a/gdu-0002-Fix-how-we-determine-if-a-volume-is-ignored.patch b/gdu-0002-Fix-how-we-determine-if-a-volume-is-ignored.patch new file mode 100644 index 0000000..3cc470c --- /dev/null +++ b/gdu-0002-Fix-how-we-determine-if-a-volume-is-ignored.patch @@ -0,0 +1,69 @@ +From 94707c12442ed9ce099f110ec7089309133727ae Mon Sep 17 00:00:00 2001 +From: Tomas Bzatek +Date: Thu, 9 Apr 2009 19:03:16 -0400 +Subject: [PATCH 2/7] Fix how we determine if a volume is ignored + +This fixes a typo - wrong assignment of device file when testing whether the +volume should be ignored or not. It led to empty GVolume list associated to a +GDrive and thus inability to mount anything via computer:// + +Signed-off-by: David Zeuthen +--- + monitor/gdu/ggduvolumemonitor.c | 18 +++++++++--------- + 1 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c +index 32604d0..b52ee11 100644 +--- a/monitor/gdu/ggduvolumemonitor.c ++++ b/monitor/gdu/ggduvolumemonitor.c +@@ -617,7 +617,7 @@ get_mount_point_for_device (GduDevice *d, GList *fstab_mount_points) + for (l = fstab_mount_points; l != NULL; l = l->next) + { + GUnixMountPoint *mount_point = l->data; +- const gchar *device_file; ++ const gchar *fstab_device_file; + const gchar *fstab_mount_path; + + fstab_mount_path = g_unix_mount_point_get_mount_path (mount_point); +@@ -627,18 +627,18 @@ get_mount_point_for_device (GduDevice *d, GList *fstab_mount_points) + goto out; + } + +- device_file = g_unix_mount_point_get_device_path (mount_point); +- if (g_str_has_prefix (device_file, "LABEL=")) ++ fstab_device_file = g_unix_mount_point_get_device_path (mount_point); ++ if (g_str_has_prefix (fstab_device_file, "LABEL=")) + { +- if (g_strcmp0 (device_file + 6, gdu_device_id_get_label (d)) == 0) ++ if (g_strcmp0 (fstab_device_file + 6, gdu_device_id_get_label (d)) == 0) + { + ret = mount_point; + goto out; + } + } +- else if (g_str_has_prefix (device_file, "UUID=")) ++ else if (g_str_has_prefix (fstab_device_file, "UUID=")) + { +- if (g_ascii_strcasecmp (device_file + 5, gdu_device_id_get_uuid (d)) == 0) ++ if (g_ascii_strcasecmp (fstab_device_file + 5, gdu_device_id_get_uuid (d)) == 0) + { + ret = mount_point; + goto out; +@@ -646,11 +646,11 @@ get_mount_point_for_device (GduDevice *d, GList *fstab_mount_points) + } + else + { +- char resolved_device_file[PATH_MAX]; ++ char resolved_fstab_device_file[PATH_MAX]; + + /* handle symlinks such as /dev/disk/by-uuid/47C2-1994 */ +- if (realpath (device_file, resolved_device_file) != NULL && +- g_strcmp0 (resolved_device_file, device_file) == 0) ++ if (realpath (fstab_device_file, resolved_fstab_device_file) != NULL && ++ g_strcmp0 (resolved_fstab_device_file, device_file) == 0) + { + ret = mount_point; + goto out; +-- +1.6.2.2 + diff --git a/gdu-0003-Avoid-automounting-volumes-on-virtual-and-unknown-bu.patch b/gdu-0003-Avoid-automounting-volumes-on-virtual-and-unknown-bu.patch new file mode 100644 index 0000000..741c2ce --- /dev/null +++ b/gdu-0003-Avoid-automounting-volumes-on-virtual-and-unknown-bu.patch @@ -0,0 +1,87 @@ +From 47a663c7ad7b9de9942b9b740abff6610968a402 Mon Sep 17 00:00:00 2001 +From: David Zeuthen +Date: Thu, 9 Apr 2009 19:05:37 -0400 +Subject: [PATCH 3/7] Avoid automounting volumes on virtual and unknown buses + +Basically we want to avoid automounting volumes from + + 1. drives on a 'virtual' or unset bus + 2. volumes without a drive + +This is to avoid interference with things like Fedora's livecd-tools +that use device-mapper to set up images. See + + https://bugzilla.redhat.com/show_bug.cgi?id=494144 for more + +background. + +In the future we might want to relax 1. so automounting things like +Linux MD and LVM2 devices work. +--- + monitor/gdu/ggduvolume.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 files changed, 50 insertions(+), 0 deletions(-) + +diff --git a/monitor/gdu/ggduvolume.c b/monitor/gdu/ggduvolume.c +index b540325..a5a3321 100644 +--- a/monitor/gdu/ggduvolume.c ++++ b/monitor/gdu/ggduvolume.c +@@ -293,6 +293,56 @@ update_volume (GGduVolume *volume) + volume->should_automount = FALSE; + } + ++ /* Avoid automounting volumes from ++ * ++ * 1. drives on a 'virtual' or unset bus ++ * 2. volumes without a drive ++ * ++ * This is to avoid interference with things like Fedora's ++ * livecd-tools that use device-mapper to set up images. See ++ * https://bugzilla.redhat.com/show_bug.cgi?id=494144 for more ++ * background. ++ * ++ * In the future we might want to relax 1. so automounting ++ * things like Linux MD and LVM2 devices work. ++ */ ++ if (volume->drive != NULL) ++ { ++ GduPresentable *drive_presentable; ++ drive_presentable = g_gdu_drive_get_presentable (volume->drive); ++ if (drive_presentable != NULL) ++ { ++ GduDevice *drive_device; ++ drive_device = gdu_presentable_get_device (drive_presentable); ++ if (drive_device != NULL) ++ { ++ const gchar *bus; ++ bus = gdu_device_drive_get_connection_interface (drive_device); ++ if (bus == NULL || strlen (bus) == 0 || g_strcmp0 (bus, "virtual") == 0) ++ { ++ volume->should_automount = FALSE; ++ } ++ g_object_unref (drive_device); ++ } ++ else ++ { ++ volume->should_automount = FALSE; ++ } ++ } ++ else ++ { ++ volume->should_automount = FALSE; ++ } ++ } ++ else ++ { ++ volume->should_automount = FALSE; ++ } ++ ++ g_debug ("should_automount = %d for %s", ++ volume->should_automount, ++ device != NULL ? gdu_device_get_device_file (device) : "(none)"); ++ + g_free (activation_uri); + } + +-- +1.6.2.2 + diff --git a/gdu-0004-Remove-debug-spew.patch b/gdu-0004-Remove-debug-spew.patch new file mode 100644 index 0000000..b9da41e --- /dev/null +++ b/gdu-0004-Remove-debug-spew.patch @@ -0,0 +1,27 @@ +From 82202f50bb76248f5a6368fe08de947758674acd Mon Sep 17 00:00:00 2001 +From: David Zeuthen +Date: Thu, 9 Apr 2009 19:14:25 -0400 +Subject: [PATCH 4/7] Remove debug spew + +--- + monitor/gdu/ggduvolume.c | 4 ---- + 1 files changed, 0 insertions(+), 4 deletions(-) + +diff --git a/monitor/gdu/ggduvolume.c b/monitor/gdu/ggduvolume.c +index a5a3321..6779f0f 100644 +--- a/monitor/gdu/ggduvolume.c ++++ b/monitor/gdu/ggduvolume.c +@@ -339,10 +339,6 @@ update_volume (GGduVolume *volume) + volume->should_automount = FALSE; + } + +- g_debug ("should_automount = %d for %s", +- volume->should_automount, +- device != NULL ? gdu_device_get_device_file (device) : "(none)"); +- + g_free (activation_uri); + } + +-- +1.6.2.2 + diff --git a/gdu-0005-Don-t-add-a-volume-if-the-device-is-mounted-and-igno.patch b/gdu-0005-Don-t-add-a-volume-if-the-device-is-mounted-and-igno.patch new file mode 100644 index 0000000..eea0e04 --- /dev/null +++ b/gdu-0005-Don-t-add-a-volume-if-the-device-is-mounted-and-igno.patch @@ -0,0 +1,31 @@ +From d9a00cc6172e2bf82f6825023c7a619be7f56747 Mon Sep 17 00:00:00 2001 +From: David Zeuthen +Date: Thu, 9 Apr 2009 19:33:35 -0400 +Subject: [PATCH 5/7] Don't add a volume if the device is mounted and ignored + +This fixes a problem where e.g. /dev/sdb1 a) is not referenced in +/etc/fstab; and b) is mounted in an ignored location e.g. /mnt/live. + +Specifically this bug affects the Fedora Live CD, see +https://bugzilla.redhat.com/show_bug.cgi?id=495033 for details. +--- + monitor/gdu/ggduvolumemonitor.c | 3 --- + 1 files changed, 0 insertions(+), 3 deletions(-) + +diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c +index b52ee11..93aaf03 100644 +--- a/monitor/gdu/ggduvolumemonitor.c ++++ b/monitor/gdu/ggduvolumemonitor.c +@@ -671,9 +671,6 @@ should_mount_be_ignored (GduPool *pool, GduDevice *d) + + ret = FALSE; + +- if (gdu_device_is_mounted (d)) +- goto out; +- + mount_path = gdu_device_get_mount_path (d); + if (mount_path == NULL || strlen (mount_path) == 0) + goto out; +-- +1.6.2.2 + diff --git a/gdu-0006-Ignore-drives-if-all-volumes-of-the-drive-are-ignore.patch b/gdu-0006-Ignore-drives-if-all-volumes-of-the-drive-are-ignore.patch new file mode 100644 index 0000000..2fa3232 --- /dev/null +++ b/gdu-0006-Ignore-drives-if-all-volumes-of-the-drive-are-ignore.patch @@ -0,0 +1,41 @@ +From 346fdc3ddf383228ed58a48252e70919f6636b6e Mon Sep 17 00:00:00 2001 +From: David Zeuthen +Date: Thu, 9 Apr 2009 19:39:55 -0400 +Subject: [PATCH 6/7] Ignore drives if all volumes of the drive are ignored + +--- + monitor/gdu/ggduvolumemonitor.c | 16 +++++++++------- + 1 files changed, 9 insertions(+), 7 deletions(-) + +diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c +index 93aaf03..9ecee8b 100644 +--- a/monitor/gdu/ggduvolumemonitor.c ++++ b/monitor/gdu/ggduvolumemonitor.c +@@ -763,15 +763,17 @@ should_drive_be_ignored (GduPool *pool, GduDrive *d, GList *fstab_mount_points) + + device = gdu_presentable_get_device (GDU_PRESENTABLE (d)); + +- /* the GduDevice for an activatable drive (such as RAID) is NULL if the drive is not +- * activated; never ignore these ++ /* If there is no GduDevice for a drive, then ignore it. ++ * ++ * Note that right now the only drives without a GduDevice are Linux ++ * MD arrays not yet activated. In the future we might want to ++ * display these so the user can start the array. + */ + if (device == NULL) +- goto out; +- +- /* never ignore drives with removable media */ +- if (gdu_device_is_removable (device)) +- goto out; ++ { ++ ret = TRUE; ++ goto out; ++ } + + has_volumes = FALSE; + all_volumes_are_ignored = TRUE; +-- +1.6.2.2 + diff --git a/gdu-0007-Bug-576587-allow-eject-even-on-non-ejectable-vol.patch b/gdu-0007-Bug-576587-allow-eject-even-on-non-ejectable-vol.patch new file mode 100644 index 0000000..88999b5 --- /dev/null +++ b/gdu-0007-Bug-576587-allow-eject-even-on-non-ejectable-vol.patch @@ -0,0 +1,49 @@ +From 303cfd43578f0a4198c063f1a5fbcd16fec2b0bf Mon Sep 17 00:00:00 2001 +From: David Zeuthen +Date: Thu, 9 Apr 2009 21:04:24 -0400 +Subject: [PATCH 7/7] =?utf-8?q?Bug=20576587=20=E2=80=93=20allow=20eject=20even=20on=20non-ejectable=20volumes?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit + +This fixes a host of problems with e.g. Kindle or iPod devices +requiring to be "ejected" to display messages such as + + "If you want to use your Kindle and continue charging, please eject + your Kindle from your computer." + +to the user. + +Previously we relied on HAL fdi files or similar to tag that such +devices needed to be ejectable. Now we just set everything as +ejectable. + +For this to really work well the Nautilus patch in + + http://bugzilla.gnome.org/show_bug.cgi?id=574067 + +needs to be reverted. +--- + monitor/gdu/ggdudrive.c | 6 +++++- + 1 files changed, 5 insertions(+), 1 deletions(-) + +diff --git a/monitor/gdu/ggdudrive.c b/monitor/gdu/ggdudrive.c +index 257a113..29e108d 100644 +--- a/monitor/gdu/ggdudrive.c ++++ b/monitor/gdu/ggdudrive.c +@@ -166,7 +166,11 @@ update_drive (GGduDrive *drive) + 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); +- drive->can_eject = gdu_device_drive_get_is_media_ejectable (device) || gdu_device_drive_get_requires_eject (device); ++ /* All drives with removable media are ejectable ++ * ++ * See http://bugzilla.gnome.org/show_bug.cgi?id=576587 for why we want this. ++ */ ++ drive->can_eject = gdu_device_drive_get_is_media_ejectable (device) || gdu_device_drive_get_requires_eject (device) || gdu_device_is_removable (device); + drive->is_media_check_automatic = gdu_device_is_media_change_detected (device); + drive->can_poll_for_media = TRUE; + } +-- +1.6.2.2 + diff --git a/gvfs-1.1.7-gdu-monitor-empty-drives.patch b/gvfs-1.1.7-gdu-monitor-empty-drives.patch deleted file mode 100644 index 07a6ec5..0000000 --- a/gvfs-1.1.7-gdu-monitor-empty-drives.patch +++ /dev/null @@ -1,51 +0,0 @@ -diff -up gvfs-1.1.7/monitor/gdu/ggduvolumemonitor.c.orig gvfs-1.1.7/monitor/gdu/ggduvolumemonitor.c ---- gvfs-1.1.7/monitor/gdu/ggduvolumemonitor.c.orig 2009-03-06 13:24:00.000000000 +0100 -+++ gvfs-1.1.7/monitor/gdu/ggduvolumemonitor.c 2009-03-06 14:45:49.000000000 +0100 -@@ -617,7 +617,7 @@ get_mount_point_for_device (GduDevice *d - for (l = fstab_mount_points; l != NULL; l = l->next) - { - GUnixMountPoint *mount_point = l->data; -- const gchar *device_file; -+ const gchar *fstab_device_file; - const gchar *fstab_mount_path; - - fstab_mount_path = g_unix_mount_point_get_mount_path (mount_point); -@@ -627,18 +627,18 @@ get_mount_point_for_device (GduDevice *d - goto out; - } - -- device_file = g_unix_mount_point_get_device_path (mount_point); -- if (g_str_has_prefix (device_file, "LABEL=")) -+ fstab_device_file = g_unix_mount_point_get_device_path (mount_point); -+ if (g_str_has_prefix (fstab_device_file, "LABEL=")) - { -- if (g_strcmp0 (device_file + 6, gdu_device_id_get_label (d)) == 0) -+ if (g_strcmp0 (fstab_device_file + 6, gdu_device_id_get_label (d)) == 0) - { - ret = mount_point; - goto out; - } - } -- else if (g_str_has_prefix (device_file, "UUID=")) -+ else if (g_str_has_prefix (fstab_device_file, "UUID=")) - { -- if (g_ascii_strcasecmp (device_file + 5, gdu_device_id_get_uuid (d)) == 0) -+ if (g_ascii_strcasecmp (fstab_device_file + 5, gdu_device_id_get_uuid (d)) == 0) - { - ret = mount_point; - goto out; -@@ -646,11 +646,11 @@ get_mount_point_for_device (GduDevice *d - } - else - { -- char resolved_device_file[PATH_MAX]; -+ char resolved_fstab_device_file[PATH_MAX]; - - /* handle symlinks such as /dev/disk/by-uuid/47C2-1994 */ -- if (realpath (device_file, resolved_device_file) != NULL && -- g_strcmp0 (resolved_device_file, device_file) == 0) -+ if (realpath (fstab_device_file, resolved_fstab_device_file) != NULL && -+ g_strcmp0 (resolved_fstab_device_file, device_file) == 0) - { - ret = mount_point; - goto out; diff --git a/gvfs-1.2.0-fix-daemon-mount-op-bgo575728.patch b/gvfs-1.2.0-fix-daemon-mount-op-bgo575728.patch deleted file mode 100644 index 427d5c1..0000000 --- a/gvfs-1.2.0-fix-daemon-mount-op-bgo575728.patch +++ /dev/null @@ -1,113 +0,0 @@ ---- trunk/common/gvfsdaemonprotocol.h 2009/02/27 12:59:47 2257 -+++ trunk/common/gvfsdaemonprotocol.h 2009/03/18 21:03:15 2342 -@@ -73,6 +73,7 @@ - #define G_VFS_DBUS_MOUNT_OPERATION_INTERFACE "org.gtk.vfs.MountOperation" - #define G_VFS_DBUS_MOUNT_OPERATION_OP_ASK_PASSWORD "askPassword" - #define G_VFS_DBUS_MOUNT_OPERATION_OP_ASK_QUESTION "askQuestion" -+#define G_VFS_DBUS_MOUNT_OPERATION_OP_ABORTED "aborted" - - /* Implemented by the spawner of a process, the spawned process sends the - spawned message (with noreply) when it has spawned and gotten a dbus id */ ---- trunk/common/gmountoperationdbus.c 2008/08/25 13:27:36 1907 -+++ trunk/common/gmountoperationdbus.c 2009/03/18 21:03:15 2342 -@@ -51,6 +51,8 @@ - DBusMessage *message); - static void mount_op_ask_question (GMountOperationDBus *op_dbus, - DBusMessage *message); -+static void mount_op_aborted (GMountOperationDBus *op_dbus, -+ DBusMessage *message); - - static void - g_mount_operation_dbus_free (GMountOperationDBus *op_dbus) -@@ -131,6 +133,10 @@ - G_VFS_DBUS_MOUNT_OPERATION_INTERFACE, - G_VFS_DBUS_MOUNT_OPERATION_OP_ASK_QUESTION)) - mount_op_ask_question (op_dbus, message); -+ else if (dbus_message_is_method_call (message, -+ G_VFS_DBUS_MOUNT_OPERATION_INTERFACE, -+ G_VFS_DBUS_MOUNT_OPERATION_OP_ABORTED)) -+ mount_op_aborted (op_dbus, message); - else - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - -@@ -322,3 +328,10 @@ - - dbus_free_string_array (choices); - } -+ -+static void -+mount_op_aborted (GMountOperationDBus *op_dbus, -+ DBusMessage *message) -+{ -+ g_signal_emit_by_name (op_dbus->op, "aborted"); -+} ---- trunk/common/gmountsource.c 2008/09/23 19:16:06 2021 -+++ trunk/common/gmountsource.c 2009/03/18 21:03:15 2342 -@@ -433,8 +433,8 @@ - handled = g_mount_source_ask_password_finish (source, - res, - &aborted, -- &username, - &password, -+ &username, - &domain, - NULL, - &password_save); -@@ -475,6 +475,7 @@ - flags, - op_ask_password_reply, - g_object_ref (op)); -+ g_signal_stop_emission_by_name (op, "ask_password"); - return TRUE; - } - -@@ -695,9 +696,41 @@ - n_choices, - op_ask_question_reply, - g_object_ref (op)); -+ g_signal_stop_emission_by_name (op, "ask_question"); - return TRUE; - } - -+static gboolean -+op_aborted (GMountOperation *op, -+ GMountSource *source) -+{ -+ DBusMessage *message; -+ DBusConnection *connection; -+ -+ /* If no dbus id specified, reply that we weren't handled */ -+ if (source->dbus_id[0] == 0) -+ goto out; -+ -+ connection = dbus_bus_get (DBUS_BUS_SESSION, NULL); -+ if (connection == NULL) -+ goto out; -+ -+ message = dbus_message_new_method_call (source->dbus_id, -+ source->obj_path, -+ G_VFS_DBUS_MOUNT_OPERATION_INTERFACE, -+ G_VFS_DBUS_MOUNT_OPERATION_OP_ABORTED); -+ -+ if (message) -+ { -+ dbus_connection_send (connection, message, NULL); -+ dbus_message_unref (message); -+ } -+ -+ out: -+ return TRUE; -+} -+ -+ - GMountOperation * - g_mount_source_get_operation (GMountSource *mount_source) - { -@@ -711,6 +744,7 @@ - - g_signal_connect (op, "ask_password", (GCallback)op_ask_password, mount_source); - g_signal_connect (op, "ask_question", (GCallback)op_ask_question, mount_source); -+ g_signal_connect (op, "aborted", (GCallback)op_aborted, mount_source); - - return op; - } diff --git a/gvfs-1.2.1-only-mount-the-metal.patch b/gvfs-1.2.1-only-mount-the-metal.patch deleted file mode 100644 index 54c9d13..0000000 --- a/gvfs-1.2.1-only-mount-the-metal.patch +++ /dev/null @@ -1,59 +0,0 @@ ---- gvfs-1.2.1/monitor/gdu/ggduvolume.c.orig 2009-04-09 14:13:39.000000000 -0400 -+++ gvfs-1.2.1/monitor/gdu/ggduvolume.c 2009-04-09 14:28:51.000000000 -0400 -@@ -293,6 +293,56 @@ update_volume (GGduVolume *volume) - volume->should_automount = FALSE; - } - -+ /* Avoid automounting volumes from -+ * -+ * 1. drives on a 'virtual' or unset bus -+ * 2. volumes without a drive -+ * -+ * This is to avoid interference with things like Fedora's -+ * livecd-tools that use device-mapper to set up images. See -+ * https://bugzilla.redhat.com/show_bug.cgi?id=494144 for more -+ * background. -+ * -+ * In the future we might want to relax 1. so automounting -+ * things like Linux MD and LVM2 devices work. -+ */ -+ if (volume->drive != NULL) -+ { -+ GduPresentable *drive_presentable; -+ drive_presentable = g_gdu_drive_get_presentable (volume->drive); -+ if (drive_presentable != NULL) -+ { -+ GduDevice *drive_device; -+ drive_device = gdu_presentable_get_device (drive_presentable); -+ if (drive_device != NULL) -+ { -+ const gchar *bus; -+ bus = gdu_device_drive_get_connection_interface (drive_device); -+ if (bus == NULL || strlen (bus) == 0 || g_strcmp0 (bus, "virtual") == 0) -+ { -+ volume->should_automount = FALSE; -+ } -+ g_object_unref (drive_device); -+ } -+ else -+ { -+ volume->should_automount = FALSE; -+ } -+ } -+ else -+ { -+ volume->should_automount = FALSE; -+ } -+ } -+ else -+ { -+ volume->should_automount = FALSE; -+ } -+ -+ g_debug ("should_automount = %d for %s", -+ volume->should_automount, -+ device != NULL ? gdu_device_get_device_file (device) : "(none)"); -+ - g_free (activation_uri); - } - diff --git a/gvfs-gdu-volume-monitor-3.patch b/gvfs-gdu-volume-monitor-3.patch deleted file mode 100644 index 99f9275..0000000 --- a/gvfs-gdu-volume-monitor-3.patch +++ /dev/null @@ -1,5159 +0,0 @@ -Index: configure.ac -=================================================================== ---- configure.ac (revision 2286) -+++ configure.ac (working copy) -@@ -198,6 +198,31 @@ - - AM_CONDITIONAL(USE_GCONF, [test "$msg_gconf" = "yes"]) - -+dnl ************************************ -+dnl *** Check for gnome-disk-utility *** -+dnl ************************************ -+ -+dnl TODO: when there is a more stable version of gdu available, turn this on by default -+AC_ARG_ENABLE(gdu, [ --enable-gdu build with gdu support]) -+msg_gdu=no -+GDU_LIBS= -+GDU_CFLAGS= -+GDU_REQUIRED=0.2 -+ -+if test "x$enable_gdu" = "xyes"; then -+ PKG_CHECK_EXISTS([gdu >= $GDU_REQUIRED], msg_gdu=yes) -+ -+ if test "x$msg_gdu" == "xyes"; then -+ PKG_CHECK_MODULES([GDU],[gdu >= $GDU_REQUIRED]) -+ AC_DEFINE(HAVE_GDU, 1, [Define to 1 if gnome-disk-utility is available]) -+ fi -+fi -+ -+AC_SUBST(GDU_LIBS) -+AC_SUBST(GDU_CFLAGS) -+ -+AM_CONDITIONAL(USE_GDU, [test "$msg_gdu" = "yes"]) -+ - dnl ********************** - dnl *** Check for HAL *** - dnl ********************** -@@ -558,6 +583,7 @@ - monitor/Makefile - monitor/proxy/Makefile - monitor/hal/Makefile -+monitor/gdu/Makefile - monitor/gphoto2/Makefile - gconf/Makefile - programs/Makefile -@@ -579,7 +605,8 @@ - archive support: $msg_archive - GConf support: $msg_gconf - DNS-SD support: $msg_avahi -- Use HAL for volume monitor: $msg_hal (with fast init path: $have_hal_fast_init) -+ Build HAL volume monitor: $msg_hal (with fast init path: $have_hal_fast_init) -+ Build GDU volume monitor: $msg_gdu - GNOME Keyring support: $msg_keyring - Bash-completion support: $msg_bash_completion - " -Index: monitor/Makefile.am -=================================================================== ---- monitor/Makefile.am (revision 2286) -+++ monitor/Makefile.am (working copy) -@@ -5,6 +5,10 @@ - SUBDIRS += hal - endif - -+if USE_GDU -+SUBDIRS += gdu -+endif -+ - if USE_GPHOTO2 - SUBDIRS += gphoto2 - endif ---- /dev/null 2009-03-04 16:07:30.099029290 -0500 -+++ monitor/gdu/gdu-volume-monitor-daemon.c 2009-03-01 23:47:15.000000000 -0500 -@@ -0,0 +1,46 @@ -+/* -*- 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+ -+#include "ggduvolumemonitor.h" -+ -+int -+main (int argc, char *argv[]) -+{ -+ g_vfs_proxy_volume_monitor_daemon_init (); -+ -+ g_set_application_name (_("GVfs GDU Volume Monitor")); -+ -+ return g_vfs_proxy_volume_monitor_daemon_main (argc, -+ argv, -+ "org.gtk.Private.GduVolumeMonitor", -+ G_TYPE_GDU_VOLUME_MONITOR); -+} ---- /dev/null 2009-03-04 16:07:30.099029290 -0500 -+++ monitor/gdu/ggdudrive.c 2009-03-01 23:48:33.000000000 -0500 -@@ -0,0 +1,691 @@ -+/* -*- 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+ -+#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; -+ gboolean is_media_removable; -+ gboolean has_media; -+ gboolean can_eject; -+ gboolean can_poll_for_media; -+ gboolean is_media_check_automatic; -+ time_t time_of_last_media_insertion; -+}; -+ -+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; -+ gboolean old_is_media_removable; -+ gboolean old_has_media; -+ gboolean old_can_eject; -+ 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_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_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); -+ drive->name = gdu_presentable_get_name (drive->presentable); -+ -+ /* the GduDevice for an activatable drive (such as RAID) is NULL if the drive is not activated */ -+ if (device == NULL) -+ { -+ g_free (drive->device_file); -+ drive->device_file = NULL; -+ drive->is_media_removable = TRUE; -+ drive->has_media = TRUE; -+ drive->can_eject = FALSE; -+ } -+ else -+ { -+ g_free (drive->device_file); -+ 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); -+ drive->can_eject = gdu_device_drive_get_is_media_ejectable (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 = TRUE; -+ } -+ -+ if (device != NULL) -+ g_object_unref (device); -+ -+ if (drive->has_media != old_has_media) -+ drive->time_of_last_media_insertion = time (NULL); -+ -+ /* 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_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) && -+ 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); -+ -+ drive->time_of_last_media_insertion = time (NULL); -+ -+ 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 void -+eject_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_eject_do (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, -+ "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); -+ g_object_unref (device); -+ } -+} -+ -+typedef struct { -+ GDrive *drive; -+ GAsyncReadyCallback callback; -+ gpointer user_data; -+ GCancellable *cancellable; -+ GMountUnmountFlags flags; -+ -+ GList *pending_mounts; -+} 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 _eject_unmount_mounts (UnmountMountsOp *data); -+ -+static void -+_eject_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_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 media; one or more volumes on the media 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.. */ -+ _eject_unmount_mounts (data); -+ } -+ -+ g_object_unref (mount); -+} -+ -+static void -+_eject_unmount_mounts (UnmountMountsOp *data) -+{ -+ GMount *mount; -+ -+ if (data->pending_mounts == NULL) -+ { -+ -+ /*g_warning ("all pending mounts done; ejecting drive");*/ -+ -+ g_gdu_drive_eject_do (data->drive, -+ data->cancellable, -+ data->callback, -+ data->user_data); -+ -+ g_object_unref (data->drive); -+ g_free (data); -+ } -+ else -+ { -+ mount = data->pending_mounts->data; -+ data->pending_mounts = g_list_remove (data->pending_mounts, mount); -+ -+ /*g_warning ("unmounting %p", mount);*/ -+ -+ g_mount_unmount (mount, -+ data->flags, -+ data->cancellable, -+ _eject_unmount_mounts_cb, -+ data); -+ } -+} -+ -+static void -+g_gdu_drive_eject (GDrive *drive, -+ GMountUnmountFlags flags, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GGduDrive *gdu_drive = G_GDU_DRIVE (drive); -+ UnmountMountsOp *data; -+ GList *l; -+ -+ /* first we need to go through all the volumes and unmount their assoicated mounts (if any) */ -+ -+ data = g_new0 (UnmountMountsOp, 1); -+ data->drive = g_object_ref (drive); -+ data->cancellable = cancellable; -+ data->callback = callback; -+ data->user_data = user_data; -+ data->flags = flags; -+ -+ for (l = gdu_drive->volumes; l != NULL; l = l->next) -+ { -+ GGduVolume *volume = l->data; -+ GMount *mount; -+ -+ 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)); -+ } -+ -+ _eject_unmount_mounts (data); -+} -+ -+static gboolean -+g_gdu_drive_eject_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->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; -+} -+ -+gboolean -+g_gdu_drive_has_device_file (GGduDrive *drive, -+ const gchar *device_file) -+{ -+ return g_strcmp0 (drive->device_file, device_file) == 0; -+} -+ -+gboolean -+g_gdu_drive_has_presentable (GGduDrive *drive, -+ GduPresentable *presentable) -+{ -+ return gdu_presentable_get_id (drive->presentable) == gdu_presentable_get_id (presentable); -+} -+ -+time_t -+g_gdu_drive_get_time_of_last_media_insertion (GGduDrive *drive) -+{ -+ return drive->time_of_last_media_insertion; -+} -+ -+GduPresentable * -+g_gdu_drive_get_presentable (GGduDrive *drive) -+{ -+ return drive->presentable; -+} ---- /dev/null 2009-03-04 16:07:30.099029290 -0500 -+++ monitor/gdu/ggdudrive.h 2009-03-01 23:48:26.000000000 -0500 -@@ -0,0 +1,69 @@ -+/* -*- 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#ifndef __G_GDU_DRIVE_H__ -+#define __G_GDU_DRIVE_H__ -+ -+#include -+#include -+ -+#include "ggduvolumemonitor.h" -+ -+G_BEGIN_DECLS -+ -+#define G_TYPE_GDU_DRIVE (g_gdu_drive_get_type ()) -+#define G_GDU_DRIVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_GDU_DRIVE, GGduDrive)) -+#define G_GDU_DRIVE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_GDU_DRIVE, GGduDriveClass)) -+#define G_IS_GDU_DRIVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_GDU_DRIVE)) -+#define G_IS_GDU_DRIVE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_GDU_DRIVE)) -+ -+typedef struct _GGduDriveClass GGduDriveClass; -+ -+struct _GGduDriveClass { -+ GObjectClass parent_class; -+}; -+ -+GType g_gdu_drive_get_type (void) G_GNUC_CONST; -+ -+GGduDrive *g_gdu_drive_new (GVolumeMonitor *volume_monitor, -+ GduPresentable *presentable); -+void g_gdu_drive_set_volume (GGduDrive *drive, -+ GGduVolume *volume); -+void g_gdu_drive_unset_volume (GGduDrive *drive, -+ GGduVolume *volume); -+void g_gdu_drive_disconnected (GGduDrive *drive); -+gboolean g_gdu_drive_has_device_file (GGduDrive *drive, -+ const gchar *device_file); -+time_t g_gdu_drive_get_time_of_last_media_insertion (GGduDrive *drive); -+ -+gboolean g_gdu_drive_has_presentable (GGduDrive *drive, -+ GduPresentable *presentable); -+ -+GduPresentable *g_gdu_drive_get_presentable (GGduDrive *drive); -+ -+ -+char * _drive_get_icon (GduDevice *d); -+ -+G_END_DECLS -+ -+#endif /* __G_GDU_DRIVE_H__ */ ---- /dev/null 2009-03-04 16:07:30.099029290 -0500 -+++ monitor/gdu/ggdumount.c 2009-03-02 14:18:23.000000000 -0500 -@@ -0,0 +1,958 @@ -+/* -*- 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+ -+#include "ggduvolumemonitor.h" -+#include "ggdumount.h" -+#include "ggduvolume.h" -+ -+struct _GGduMount -+{ -+ GObject parent; -+ -+ GVolumeMonitor *volume_monitor; /* owned by volume monitor */ -+ GGduVolume *volume; /* owned by volume monitor */ -+ -+ /* the following members need to be set upon construction */ -+ GFile *root; -+ GIcon *icon; -+ gchar *name; -+ gchar *uuid; -+ gchar *device_file; -+ gchar *mount_path; -+ gboolean can_unmount; -+ -+ gchar *mount_entry_name; -+ GIcon *mount_entry_icon; -+ -+ gboolean is_burn_mount; -+ -+ GIcon *autorun_icon; -+ gboolean searched_for_autorun; -+ -+ gchar *xdg_volume_info_name; -+ GIcon *xdg_volume_info_icon; -+ gboolean searched_for_xdg_volume_info; -+}; -+ -+static gboolean update_mount (GGduMount *mount); -+ -+static void g_gdu_mount_mount_iface_init (GMountIface *iface); -+ -+G_DEFINE_TYPE_EXTENDED (GGduMount, g_gdu_mount, G_TYPE_OBJECT, 0, -+ G_IMPLEMENT_INTERFACE (G_TYPE_MOUNT, -+ g_gdu_mount_mount_iface_init)) -+ -+static void -+volume_changed (GVolume *volume, -+ gpointer user_data); -+ -+static void -+g_gdu_mount_finalize (GObject *object) -+{ -+ GGduMount *mount; -+ -+ mount = G_GDU_MOUNT (object); -+ -+ if (mount->volume != NULL) -+ { -+ g_signal_handlers_disconnect_by_func (mount->volume, volume_changed, mount); -+ g_gdu_volume_unset_mount (mount->volume, mount); -+ } -+ -+ if (mount->root != NULL) -+ g_object_unref (mount->root); -+ if (mount->icon != NULL) -+ g_object_unref (mount->icon); -+ g_free (mount->name); -+ g_free (mount->uuid); -+ g_free (mount->device_file); -+ g_free (mount->mount_path); -+ -+ g_free (mount->mount_entry_name); -+ if (mount->mount_entry_icon != NULL) -+ g_object_unref (mount->mount_entry_icon); -+ -+ 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 (G_OBJECT_CLASS (g_gdu_mount_parent_class)->finalize) -+ (*G_OBJECT_CLASS (g_gdu_mount_parent_class)->finalize) (object); -+} -+ -+static void -+g_gdu_mount_class_init (GGduMountClass *klass) -+{ -+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass); -+ -+ gobject_class->finalize = g_gdu_mount_finalize; -+} -+ -+static void -+g_gdu_mount_init (GGduMount *mount) -+{ -+} -+ -+static void -+emit_changed (GGduMount *mount) -+{ -+ g_signal_emit_by_name (mount, "changed"); -+ g_signal_emit_by_name (mount->volume_monitor, "mount_changed", mount); -+} -+ -+static void -+got_autorun_info_cb (GObject *source_object, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ GGduMount *mount = G_GDU_MOUNT (user_data); -+ -+ mount->autorun_icon = g_vfs_mount_info_query_autorun_info_finish (G_FILE (source_object), -+ res, -+ NULL); -+ -+ if (update_mount (mount)) -+ emit_changed (mount); -+ -+ g_object_unref (mount); -+} -+ -+static void -+got_xdg_volume_info_cb (GObject *source_object, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ GGduMount *mount = G_GDU_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); -+ if (update_mount (mount)) -+ emit_changed (mount); -+ -+ g_object_unref (mount); -+} -+ -+static gboolean -+update_mount (GGduMount *mount) -+{ -+ gboolean changed; -+ gboolean old_can_unmount; -+ gchar *old_name; -+ GIcon *old_icon; -+ -+ /* save old values */ -+ old_can_unmount = mount->can_unmount; -+ old_name = g_strdup (mount->name); -+ old_icon = mount->icon != NULL ? g_object_ref (mount->icon) : NULL; -+ -+ /* in with the new */ -+ if (mount->volume != NULL) -+ { -+ mount->can_unmount = TRUE; -+ -+ if (mount->icon != NULL) -+ g_object_unref (mount->icon); -+ -+ /* order of preference: xdg, autorun, probed */ -+ if (mount->xdg_volume_info_icon != NULL) -+ mount->icon = g_object_ref (mount->xdg_volume_info_icon); -+ else if (mount->autorun_icon != NULL) -+ mount->icon = g_object_ref (mount->autorun_icon); -+ else -+ mount->icon = g_volume_get_icon (G_VOLUME (mount->volume)); -+ -+ g_free (mount->name); -+ -+ /* order of preference : xdg, probed */ -+ if (mount->xdg_volume_info_name != NULL) -+ mount->name = g_strdup (mount->xdg_volume_info_name); -+ else -+ mount->name = g_volume_get_name (G_VOLUME (mount->volume)); -+ } -+ else -+ { -+ mount->can_unmount = TRUE; -+ -+ if (mount->icon != NULL) -+ g_object_unref (mount->icon); -+ -+ /* order of preference: xdg, autorun, probed */ -+ if (mount->xdg_volume_info_icon != NULL) -+ mount->icon = g_object_ref (mount->xdg_volume_info_icon); -+ else if (mount->autorun_icon != NULL) -+ mount->icon = g_object_ref (mount->autorun_icon); -+ else -+ mount->icon = mount->mount_entry_icon != NULL ? g_object_ref (mount->mount_entry_icon) : NULL; -+ -+ g_free (mount->name); -+ -+ /* order of preference : xdg, probed */ -+ if (mount->xdg_volume_info_name != NULL) -+ mount->name = g_strdup (mount->xdg_volume_info_name); -+ else -+ mount->name = g_strdup (mount->mount_entry_name); -+ } -+ -+ /* compute whether something changed */ -+ changed = !((old_can_unmount == mount->can_unmount) && -+ (g_strcmp0 (old_name, mount->name) == 0) && -+ g_icon_equal (old_icon, mount->icon) -+ ); -+ -+ /* free old values */ -+ g_free (old_name); -+ if (old_icon != NULL) -+ g_object_unref (old_icon); -+ -+ /*g_debug ("in update_mount(), changed=%d", changed);*/ -+ -+ /* search for .xdg-volume-info */ -+ if (!mount->searched_for_xdg_volume_info) -+ { -+ mount->searched_for_xdg_volume_info = TRUE; -+ g_vfs_mount_info_query_xdg_volume_info (mount->root, -+ NULL, -+ got_xdg_volume_info_cb, -+ g_object_ref (mount)); -+ } -+ -+ /* search for autorun.inf */ -+ if (!mount->searched_for_autorun) -+ { -+ mount->searched_for_autorun = TRUE; -+ g_vfs_mount_info_query_autorun_info (mount->root, -+ NULL, -+ got_autorun_info_cb, -+ g_object_ref (mount)); -+ } -+ -+ return changed; -+} -+ -+static void -+volume_changed (GVolume *volume, -+ gpointer user_data) -+{ -+ GGduMount *mount = G_GDU_MOUNT (user_data); -+ -+ if (update_mount (mount)) -+ emit_changed (mount); -+} -+ -+GGduMount * -+g_gdu_mount_new (GVolumeMonitor *volume_monitor, -+ GUnixMountEntry *mount_entry, -+ GGduVolume *volume) -+{ -+ GGduMount *mount; -+ -+ mount = NULL; -+ -+ /* Ignore internal mounts unless there's a volume */ -+ if (volume == NULL && (mount_entry != NULL && !g_unix_mount_guess_should_display (mount_entry))) -+ goto out; -+ -+ mount = g_object_new (G_TYPE_GDU_MOUNT, NULL); -+ mount->volume_monitor = volume_monitor; -+ g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(mount->volume_monitor)); -+ -+ if (mount_entry != NULL) -+ { -+ /* No ref on GUnixMountEntry so save values for later use */ -+ mount->mount_entry_name = g_unix_mount_guess_name (mount_entry); -+ mount->mount_entry_icon = g_unix_mount_guess_icon (mount_entry); -+ mount->device_file = g_strdup (g_unix_mount_get_device_path (mount_entry)); -+ mount->mount_path = g_strdup (g_unix_mount_get_mount_path (mount_entry)); -+ mount->root = g_file_new_for_path (mount->mount_path); -+ } -+ else -+ { -+ /* burn:/// mount (the only mounts we support with mount_entry == NULL) */ -+ mount->device_file = NULL; -+ mount->mount_path = NULL; -+ mount->root = g_file_new_for_uri ("burn:///"); -+ mount->is_burn_mount = TRUE; -+ } -+ -+ /* need to set the volume only when the mount is fully constructed */ -+ mount->volume = volume; -+ if (mount->volume != NULL) -+ { -+ g_gdu_volume_set_mount (volume, mount); -+ /* this is for piggy backing on the name and icon of the associated volume */ -+ g_signal_connect (mount->volume, "changed", G_CALLBACK (volume_changed), mount); -+ } -+ -+ update_mount (mount); -+ -+ out: -+ -+ return mount; -+} -+ -+void -+g_gdu_mount_unmounted (GGduMount *mount) -+{ -+ if (mount->volume != NULL) -+ { -+ g_gdu_volume_unset_mount (mount->volume, mount); -+ g_signal_handlers_disconnect_by_func (mount->volume, volume_changed, mount); -+ mount->volume = NULL; -+ emit_changed (mount); -+ } -+} -+ -+void -+g_gdu_mount_unset_volume (GGduMount *mount, -+ GGduVolume *volume) -+{ -+ if (mount->volume == volume) -+ { -+ g_signal_handlers_disconnect_by_func (mount->volume, volume_changed, mount); -+ mount->volume = NULL; -+ emit_changed (mount); -+ } -+} -+ -+static GFile * -+g_gdu_mount_get_root (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ return mount->root != NULL ? g_object_ref (mount->root) : NULL; -+} -+ -+static GIcon * -+g_gdu_mount_get_icon (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ return mount->icon != NULL ? g_object_ref (mount->icon) : NULL; -+} -+ -+static gchar * -+g_gdu_mount_get_uuid (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ return g_strdup (mount->uuid); -+} -+ -+static gchar * -+g_gdu_mount_get_name (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ return g_strdup (mount->name); -+} -+ -+gboolean -+g_gdu_mount_has_uuid (GGduMount *_mount, -+ const gchar *uuid) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ return g_strcmp0 (mount->uuid, uuid) == 0; -+} -+ -+gboolean -+g_gdu_mount_has_mount_path (GGduMount *_mount, -+ const gchar *mount_path) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ return g_strcmp0 (mount->mount_path, mount_path) == 0; -+} -+ -+static GDrive * -+g_gdu_mount_get_drive (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ GDrive *drive; -+ -+ drive = NULL; -+ if (mount->volume != NULL) -+ drive = g_volume_get_drive (G_VOLUME (mount->volume)); -+ -+ return drive; -+} -+ -+static GVolume * -+g_gdu_mount_get_volume (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ GVolume *volume; -+ -+ volume = NULL; -+ if (mount->volume) -+ volume = G_VOLUME (g_object_ref (mount->volume)); -+ -+ return volume; -+} -+ -+static gboolean -+g_gdu_mount_can_unmount (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ return mount->can_unmount; -+} -+ -+static gboolean -+g_gdu_mount_can_eject (GMount *_mount) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ GDrive *drive; -+ gboolean can_eject; -+ -+ can_eject = FALSE; -+ if (mount->volume != NULL) -+ { -+ drive = g_volume_get_drive (G_VOLUME (mount->volume)); -+ if (drive != NULL) -+ can_eject = g_drive_can_eject (drive); -+ } -+ -+ return can_eject; -+} -+ -+/* ---------------------------------------------------------------------------------------------------- */ -+ -+typedef struct { -+ GMount *mount; -+ GAsyncReadyCallback callback; -+ gpointer user_data; -+ GCancellable *cancellable; -+ int error_fd; -+ GIOChannel *error_channel; -+ guint error_channel_source_id; -+ GString *error_string; -+} UnmountEjectOp; -+ -+static void -+eject_unmount_cb (GPid pid, gint status, gpointer user_data) -+{ -+ UnmountEjectOp *data = user_data; -+ GSimpleAsyncResult *simple; -+ -+ if (WEXITSTATUS (status) != 0) -+ { -+ 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 (G_OBJECT (data->mount), -+ data->callback, -+ data->user_data, -+ error); -+ g_error_free (error); -+ } -+ else -+ { -+ simple = g_simple_async_result_new (G_OBJECT (data->mount), -+ 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_free (data); -+} -+ -+static gboolean -+eject_unmount_read_error (GIOChannel *channel, -+ GIOCondition condition, -+ gpointer user_data) -+{ -+ UnmountEjectOp *data = user_data; -+ gchar buf[BUFSIZ]; -+ gsize bytes_read; -+ GError *error; -+ GIOStatus status; -+ -+ error = NULL; -+read: -+ status = g_io_channel_read_chars (channel, buf, sizeof (buf), &bytes_read, &error); -+ if (status == G_IO_STATUS_NORMAL) -+ { -+ g_string_append_len (data->error_string, buf, bytes_read); -+ if (bytes_read == sizeof (buf)) -+ goto read; -+ } -+ else if (status == G_IO_STATUS_EOF) -+ g_string_append_len (data->error_string, buf, bytes_read); -+ else if (status == G_IO_STATUS_ERROR) -+ { -+ if (data->error_string->len > 0) -+ g_string_append (data->error_string, "\n"); -+ -+ g_string_append (data->error_string, error->message); -+ g_error_free (error); -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+static void -+eject_unmount_do (GMount *mount, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data, -+ char **argv) -+{ -+ UnmountEjectOp *data; -+ GPid child_pid; -+ GError *error; -+ -+ data = g_new0 (UnmountEjectOp, 1); -+ data->mount = mount; -+ data->callback = callback; -+ data->user_data = user_data; -+ data->cancellable = cancellable; -+ -+ 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)) { -+ g_assert (error != NULL); -+ goto handle_error; -+ } -+ -+ data->error_string = g_string_new (""); -+ -+ data->error_channel = g_io_channel_unix_new (data->error_fd); -+ g_io_channel_set_flags (data->error_channel, G_IO_FLAG_NONBLOCK, &error); -+ if (error != NULL) -+ goto handle_error; -+ -+ data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, eject_unmount_read_error, data); -+ g_child_watch_add (child_pid, eject_unmount_cb, data); -+ -+handle_error: -+ -+ if (error != NULL) -+ { -+ GSimpleAsyncResult *simple; -+ simple = g_simple_async_result_new_from_error (G_OBJECT (data->mount), -+ data->callback, -+ data->user_data, -+ error); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ -+ if (data->error_string != NULL) -+ g_string_free (data->error_string, TRUE); -+ -+ if (data->error_channel != NULL) -+ g_io_channel_unref (data->error_channel); -+ -+ g_error_free (error); -+ g_free (data); -+ } -+} -+ -+/* ---------------------------------------------------------------------------------------------------- */ -+static void -+luks_lock_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 -+unmount_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); -+ goto out; -+ } -+ -+ /* if volume is a cleartext LUKS block device, then also lock this one */ -+ if (gdu_device_is_luks_cleartext (device)) -+ { -+ const gchar *luks_cleartext_slave_object_path; -+ GduDevice *luks_cleartext_slave; -+ GduPool *pool; -+ -+ luks_cleartext_slave_object_path = gdu_device_luks_cleartext_get_slave (device); -+ if (luks_cleartext_slave_object_path == NULL) -+ { -+ g_simple_async_result_set_error (simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ "Cannot get LUKS cleartext slave"); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ goto out; -+ } -+ -+ pool = gdu_device_get_pool (device); -+ luks_cleartext_slave = gdu_pool_get_by_object_path (pool, luks_cleartext_slave_object_path); -+ g_object_unref (pool); -+ -+ if (luks_cleartext_slave == NULL) -+ { -+ g_simple_async_result_set_error (simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ "Cannot get LUKS cleartext slave"); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ goto out; -+ } -+ -+ gdu_device_op_luks_lock (luks_cleartext_slave, -+ luks_lock_cb, -+ simple); -+ -+ g_object_unref (luks_cleartext_slave); -+ goto out; -+ } -+ -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ -+ out: -+ ; -+} -+ -+static void -+g_gdu_mount_unmount (GMount *_mount, -+ GMountUnmountFlags flags, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ GSimpleAsyncResult *simple; -+ -+ if (mount->volume == NULL) -+ { -+ gchar *argv[] = {"umount", NULL, NULL}; -+ -+ /* TODO: honor flags */ -+ -+ if (mount->mount_path != NULL) -+ argv[1] = mount->mount_path; -+ else -+ argv[1] = mount->device_file; -+ -+ eject_unmount_do (_mount, cancellable, callback, user_data, argv); -+ } -+ else -+ { -+ simple = g_simple_async_result_new (G_OBJECT (mount), -+ callback, -+ user_data, -+ NULL); -+ -+ if (mount->is_burn_mount) -+ { -+ /* burn mounts are really never mounted... */ -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ } -+ else -+ { -+ GduDevice *device; -+ GduPresentable *volume; -+ -+ /* TODO: honor flags */ -+ -+ volume = g_gdu_volume_get_presentable_with_cleartext (mount->volume); -+ device = gdu_presentable_get_device (volume); -+ -+ gdu_device_op_filesystem_unmount (device, unmount_cb, simple); -+ -+ g_object_unref (device); -+ } -+ } -+} -+ -+static gboolean -+g_gdu_mount_unmount_finish (GMount *mount, -+ GAsyncResult *result, -+ GError **error) -+{ -+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); -+} -+ -+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_gdu_mount_eject (GMount *mount, -+ GMountUnmountFlags flags, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GGduMount *gdu_mount = G_GDU_MOUNT (mount); -+ GDrive *drive; -+ -+ drive = NULL; -+ if (gdu_mount->volume != NULL) -+ drive = g_volume_get_drive (G_VOLUME (gdu_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); -+ } -+ else -+ { -+ GSimpleAsyncResult *simple; -+ simple = g_simple_async_result_new_error (G_OBJECT (mount), -+ callback, -+ user_data, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ _("Operation not supported by backend")); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ } -+ -+} -+ -+static gboolean -+g_gdu_mount_eject_finish (GMount *_mount, -+ GAsyncResult *result, -+ GError **error) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ GDrive *drive; -+ gboolean res; -+ -+ res = TRUE; -+ -+ drive = NULL; -+ if (mount->volume != NULL) -+ drive = g_volume_get_drive (G_VOLUME (mount->volume)); -+ -+ if (drive != NULL) -+ { -+ res = g_drive_eject_finish (drive, result, error); -+ g_object_unref (drive); -+ } -+ else -+ { -+ g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); -+ res = FALSE; -+ } -+ -+ return res; -+} -+ -+/* TODO: handle force_rescan */ -+static gchar ** -+g_gdu_mount_guess_content_type_sync (GMount *_mount, -+ gboolean force_rescan, -+ GCancellable *cancellable, -+ GError **error) -+{ -+ GGduMount *mount = G_GDU_MOUNT (_mount); -+ const gchar *disc_type; -+ char **x_content_types; -+ GPtrArray *p; -+ gchar **result; -+ GduDevice *device; -+ guint n; -+ -+ p = g_ptr_array_new (); -+ -+ device = NULL; -+ if (mount->volume != NULL) -+ { -+ GduPresentable *presentable; -+ presentable = g_gdu_volume_get_presentable_with_cleartext (mount->volume); -+ device = gdu_presentable_get_device (presentable); -+ } -+ -+ /* doesn't make sense to probe blank discs - look at the disc type instead */ -+ if (device != NULL && gdu_device_optical_disc_get_is_blank (device)) -+ { -+ disc_type = gdu_device_drive_get_media (device); -+ if (disc_type != NULL) -+ { -+ if (g_str_has_prefix (disc_type, "optical_dvd")) -+ g_ptr_array_add (p, g_strdup ("x-content/blank-dvd")); -+ else if (g_str_has_prefix (disc_type, "optical_hddvd")) -+ g_ptr_array_add (p, g_strdup ("x-content/blank-hddvd")); -+ else if (g_str_has_prefix (disc_type, "optical_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 (mount->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); -+ } -+ } -+ -+ 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); -+ } -+ -+ if (device != NULL) -+ g_object_unref (device); -+ -+ return result; -+} -+ -+/* since we're an out-of-process volume monitor we'll just do this sync */ -+static void -+g_gdu_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 gchar ** -+g_gdu_mount_guess_content_type_finish (GMount *mount, -+ GAsyncResult *result, -+ GError **error) -+{ -+ return g_gdu_mount_guess_content_type_sync (mount, FALSE, NULL, error); -+} -+ -+static void -+g_gdu_mount_mount_iface_init (GMountIface *iface) -+{ -+ iface->get_root = g_gdu_mount_get_root; -+ iface->get_name = g_gdu_mount_get_name; -+ iface->get_icon = g_gdu_mount_get_icon; -+ iface->get_uuid = g_gdu_mount_get_uuid; -+ iface->get_drive = g_gdu_mount_get_drive; -+ iface->get_volume = g_gdu_mount_get_volume; -+ iface->can_unmount = g_gdu_mount_can_unmount; -+ iface->can_eject = g_gdu_mount_can_eject; -+ iface->unmount = g_gdu_mount_unmount; -+ iface->unmount_finish = g_gdu_mount_unmount_finish; -+ iface->eject = g_gdu_mount_eject; -+ iface->eject_finish = g_gdu_mount_eject_finish; -+ iface->guess_content_type = g_gdu_mount_guess_content_type; -+ iface->guess_content_type_finish = g_gdu_mount_guess_content_type_finish; -+ iface->guess_content_type_sync = g_gdu_mount_guess_content_type_sync; -+} -+ -+gboolean -+g_gdu_mount_has_volume (GGduMount *mount, -+ GGduVolume *volume) -+{ -+ return mount->volume == volume; -+} ---- /dev/null 2009-03-04 16:07:30.099029290 -0500 -+++ monitor/gdu/ggdumount.h 2009-03-01 23:48:16.000000000 -0500 -@@ -0,0 +1,64 @@ -+/* -*- 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#ifndef __G_GDU_MOUNT_H__ -+#define __G_GDU_MOUNT_H__ -+ -+#include -+#include -+ -+#include "ggduvolumemonitor.h" -+ -+G_BEGIN_DECLS -+ -+#define G_TYPE_GDU_MOUNT (g_gdu_mount_get_type ()) -+#define G_GDU_MOUNT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_GDU_MOUNT, GGduMount)) -+#define G_GDU_MOUNT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_GDU_MOUNT, GGduMountClass)) -+#define G_IS_GDU_MOUNT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_GDU_MOUNT)) -+#define G_IS_GDU_MOUNT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_GDU_MOUNT)) -+ -+typedef struct _GGduMountClass GGduMountClass; -+ -+struct _GGduMountClass { -+ GObjectClass parent_class; -+}; -+ -+GType g_gdu_mount_get_type (void) G_GNUC_CONST; -+ -+GGduMount * g_gdu_mount_new (GVolumeMonitor *volume_monitor, -+ GUnixMountEntry *mount_entry, -+ GGduVolume *volume); -+gboolean g_gdu_mount_has_mount_path (GGduMount *mount, -+ const gchar *mount_path); -+gboolean g_gdu_mount_has_uuid (GGduMount *mount, -+ const gchar *uuid); -+void g_gdu_mount_unset_volume (GGduMount *mount, -+ GGduVolume *volume); -+void g_gdu_mount_unmounted (GGduMount *mount); -+ -+gboolean g_gdu_mount_has_volume (GGduMount *mount, -+ GGduVolume *volume); -+ -+G_END_DECLS -+ -+#endif /* __G_GDU_MOUNT_H__ */ ---- /dev/null 2009-03-04 16:07:30.099029290 -0500 -+++ monitor/gdu/ggduvolume.c 2009-03-04 16:19:41.000000000 -0500 -@@ -0,0 +1,1408 @@ -+/* -*- 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "ggdudrive.h" -+#include "ggduvolume.h" -+#include "ggdumount.h" -+ -+#include "polkit.h" -+ -+typedef struct MountOpData MountOpData; -+ -+static void cancel_pending_mount_op (MountOpData *data); -+ -+struct _GGduVolume -+{ -+ GObject parent; -+ -+ GVolumeMonitor *volume_monitor; /* owned by volume monitor */ -+ GGduMount *mount; /* owned by volume monitor */ -+ GGduDrive *drive; /* owned by volume monitor */ -+ -+ GduVolume *gdu_volume; -+ -+ /* if the volume is encrypted, this is != NULL when unlocked */ -+ GduVolume *cleartext_gdu_volume; -+ -+ /* If a mount operation is in progress, then pending_mount_op is != NULL. This -+ * is used to cancel the operation to make possible authentication dialogs go -+ * away. -+ */ -+ MountOpData *pending_mount_op; -+ -+ /* the following members need to be set upon construction */ -+ GIcon *icon; -+ GFile *activation_root; -+ gchar *name; -+ gchar *device_file; -+ gchar *uuid; -+ gboolean can_mount; -+ gboolean should_automount; -+}; -+ -+static void g_gdu_volume_volume_iface_init (GVolumeIface *iface); -+ -+G_DEFINE_TYPE_EXTENDED (GGduVolume, g_gdu_volume, G_TYPE_OBJECT, 0, -+ G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME, -+ g_gdu_volume_volume_iface_init)) -+ -+static void gdu_volume_changed (GduPresentable *presentable, -+ GGduVolume *volume); -+static void gdu_volume_job_changed (GduPresentable *presentable, -+ GGduVolume *volume); -+ -+static void gdu_cleartext_volume_removed (GduPresentable *presentable, -+ GGduVolume *volume); -+static void gdu_cleartext_volume_changed (GduPresentable *presentable, -+ GGduVolume *volume); -+static void gdu_cleartext_volume_job_changed (GduPresentable *presentable, -+ GGduVolume *volume); -+ -+static void mount_with_mount_operation (MountOpData *data); -+ -+static void -+g_gdu_volume_finalize (GObject *object) -+{ -+ GGduVolume *volume; -+ -+ volume = G_GDU_VOLUME (object); -+ -+ if (volume->mount != NULL) -+ g_gdu_mount_unset_volume (volume->mount, volume); -+ -+ if (volume->drive != NULL) -+ g_gdu_drive_unset_volume (volume->drive, volume); -+ -+ if (volume->gdu_volume != NULL) -+ { -+ g_signal_handlers_disconnect_by_func (volume->gdu_volume, gdu_volume_changed, volume); -+ g_signal_handlers_disconnect_by_func (volume->gdu_volume, gdu_volume_job_changed, volume); -+ g_object_unref (volume->gdu_volume); -+ } -+ -+ if (volume->cleartext_gdu_volume != NULL) -+ { -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_removed, volume); -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_changed, volume); -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_job_changed, volume); -+ g_object_unref (volume->cleartext_gdu_volume); -+ } -+ -+ if (volume->icon != NULL) -+ g_object_unref (volume->icon); -+ if (volume->activation_root != NULL) -+ g_object_unref (volume->activation_root); -+ -+ g_free (volume->name); -+ g_free (volume->device_file); -+ g_free (volume->uuid); -+ -+ if (G_OBJECT_CLASS (g_gdu_volume_parent_class)->finalize) -+ (*G_OBJECT_CLASS (g_gdu_volume_parent_class)->finalize) (object); -+} -+ -+static void -+g_gdu_volume_class_init (GGduVolumeClass *klass) -+{ -+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass); -+ -+ gobject_class->finalize = g_gdu_volume_finalize; -+} -+ -+static void -+g_gdu_volume_init (GGduVolume *gdu_volume) -+{ -+} -+ -+static void -+emit_changed (GGduVolume *volume) -+{ -+ g_signal_emit_by_name (volume, "changed"); -+ g_signal_emit_by_name (volume->volume_monitor, "volume_changed", volume); -+} -+ -+static gboolean -+update_volume (GGduVolume *volume) -+{ -+ GduDevice *device; -+ GduPool *pool; -+ time_t now; -+ gboolean changed; -+ gboolean old_can_mount; -+ gboolean old_should_automount; -+ gchar *old_name; -+ gchar *old_device_file; -+ GIcon *old_icon; -+ gboolean keep_cleartext_volume; -+ -+ /* save old values */ -+ old_can_mount = volume->can_mount; -+ old_should_automount = volume->should_automount; -+ old_name = g_strdup (volume->name); -+ old_device_file = g_strdup (volume->device_file); -+ old_icon = volume->icon != NULL ? g_object_ref (volume->icon) : NULL; -+ -+ /* ---------------------------------------------------------------------------------------------------- */ -+ -+ /* in with the new */ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); -+ pool = gdu_device_get_pool (device); -+ -+ keep_cleartext_volume = FALSE; -+ if (gdu_device_is_luks (device)) -+ { -+ const gchar *holder_objpath; -+ -+ holder_objpath = gdu_device_luks_get_holder (device); -+ if (holder_objpath != NULL && g_strcmp0 (holder_objpath, "/") != 0) -+ { -+ GduDevice *cleartext_device; -+ -+ cleartext_device = gdu_pool_get_by_object_path (pool, holder_objpath); -+ if (cleartext_device != NULL) -+ { -+ GduVolume *cleartext_gdu_volume; -+ -+ cleartext_gdu_volume = GDU_VOLUME (gdu_pool_get_volume_by_device (pool, cleartext_device)); -+ if (cleartext_gdu_volume != volume->cleartext_gdu_volume) -+ { -+ if (volume->cleartext_gdu_volume != NULL) -+ { -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_removed, volume); -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_changed, volume); -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_job_changed, volume); -+ g_object_unref (volume->cleartext_gdu_volume); -+ } -+ -+ volume->cleartext_gdu_volume = g_object_ref (cleartext_gdu_volume); -+ g_signal_connect (volume->cleartext_gdu_volume, "removed", G_CALLBACK (gdu_cleartext_volume_removed), volume); -+ g_signal_connect (volume->cleartext_gdu_volume, "changed", G_CALLBACK (gdu_cleartext_volume_changed), volume); -+ g_signal_connect (volume->cleartext_gdu_volume, "job-changed", G_CALLBACK (gdu_cleartext_volume_job_changed), volume); -+ } -+ g_object_unref (cleartext_gdu_volume); -+ -+ g_object_unref (cleartext_device); -+ -+ keep_cleartext_volume = TRUE; -+ } -+ } -+ } -+ -+ if (!keep_cleartext_volume) -+ { -+ if (volume->cleartext_gdu_volume != NULL) -+ { -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_removed, volume); -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_changed, volume); -+ g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_job_changed, volume); -+ g_object_unref (volume->cleartext_gdu_volume); -+ volume->cleartext_gdu_volume = NULL; -+ } -+ } -+ -+ -+ /* Use data from cleartext LUKS volume if it is unlocked */ -+ if (volume->cleartext_gdu_volume != NULL) -+ { -+ GduDevice *luks_cleartext_volume_device; -+ -+ luks_cleartext_volume_device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); -+ -+ if (volume->icon != NULL) -+ g_object_unref (volume->icon); -+ volume->icon = gdu_presentable_get_icon (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); -+ -+ g_free (volume->name); -+ volume->name = gdu_presentable_get_name (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); -+ -+ g_free (volume->device_file); -+ volume->device_file = g_strdup (gdu_device_get_device_file (luks_cleartext_volume_device)); -+ -+ volume->can_mount = TRUE; -+ -+ volume->should_automount = FALSE; -+ -+ g_object_unref (luks_cleartext_volume_device); -+ } -+ else -+ { -+ gchar *activation_uri; -+ -+ if (volume->icon != NULL) -+ g_object_unref (volume->icon); -+ volume->icon = gdu_presentable_get_icon (GDU_PRESENTABLE (volume->gdu_volume)); -+ -+ g_free (volume->name); -+ volume->name = gdu_presentable_get_name (GDU_PRESENTABLE (volume->gdu_volume)); -+ -+ /* special case the name and icon for audio discs */ -+ activation_uri = volume->activation_root != NULL ? g_file_get_uri (volume->activation_root) : NULL; -+ if (activation_uri != NULL && g_str_has_prefix (activation_uri, "cdda://")) -+ { -+ if (volume->icon != NULL) -+ g_object_unref (volume->icon); -+ volume->icon = g_themed_icon_new_with_default_fallbacks ("media-optical-audio"); -+ g_free (volume->name); -+ volume->name = g_strdup (_("Audio Disc")); -+ } -+ -+ g_free (volume->device_file); -+ volume->device_file = g_strdup (gdu_device_get_device_file (device)); -+ -+ volume->can_mount = TRUE; -+ -+ /* If a volume (partition) appear _much later_ than when media was insertion it -+ * can only be because the media was repartitioned. We don't want to automount -+ * such volumes. -+ */ -+ volume->should_automount = TRUE; -+ if (volume->drive != NULL) -+ { -+ now = time (NULL); -+ if (now - g_gdu_drive_get_time_of_last_media_insertion (volume->drive) > 5) -+ volume->should_automount = FALSE; -+ } -+ -+ g_free (activation_uri); -+ } -+ -+ g_object_unref (pool); -+ g_object_unref (device); -+ -+ /* ---------------------------------------------------------------------------------------------------- */ -+ -+ /* compute whether something changed */ -+ changed = !((old_can_mount == volume->can_mount) && -+ (old_should_automount == volume->should_automount) && -+ (g_strcmp0 (old_name, volume->name) == 0) && -+ (g_strcmp0 (old_device_file, volume->device_file) == 0) && -+ g_icon_equal (old_icon, volume->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_volume(), changed=%d", changed);*/ -+ -+ return changed; -+} -+ -+static void -+gdu_volume_changed (GduPresentable *presentable, -+ GGduVolume *volume) -+{ -+ /*g_debug ("volume: presentable_changed: %p: %s", volume, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ -+ if (update_volume (volume)) -+ emit_changed (volume); -+} -+ -+static void -+gdu_volume_job_changed (GduPresentable *presentable, -+ GGduVolume *volume) -+{ -+ /*g_debug ("volume: presentable_job_changed %p: %s", volume, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ -+ if (update_volume (volume)) -+ emit_changed (volume); -+} -+ -+static void -+gdu_cleartext_volume_removed (GduPresentable *presentable, -+ GGduVolume *volume) -+{ -+ /*g_debug ("cleartext volume: presentable_removed: %p: %s", volume, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ -+ if (update_volume (volume)) -+ emit_changed (volume); -+} -+ -+static void -+gdu_cleartext_volume_changed (GduPresentable *presentable, -+ GGduVolume *volume) -+{ -+ /*g_debug ("cleartext volume: presentable_changed: %p: %s", volume, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ -+ if (update_volume (volume)) -+ emit_changed (volume); -+} -+ -+static void -+gdu_cleartext_volume_job_changed (GduPresentable *presentable, -+ GGduVolume *volume) -+{ -+ /*g_debug ("cleartext volume: presentable_job_changed %p: %s", volume, gdu_presentable_get_id (GDU_PRESENTABLE (presentable)));*/ -+ if (update_volume (volume)) -+ emit_changed (volume); -+} -+ -+GGduVolume * -+g_gdu_volume_new (GVolumeMonitor *volume_monitor, -+ GduVolume *gdu_volume, -+ GGduDrive *drive, -+ GFile *activation_root) -+{ -+ GGduVolume *volume; -+ -+ volume = g_object_new (G_TYPE_GDU_VOLUME, NULL); -+ volume->volume_monitor = volume_monitor; -+ g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(volume->volume_monitor)); -+ -+ volume->gdu_volume = g_object_ref (gdu_volume); -+ volume->activation_root = activation_root != NULL ? g_object_ref (activation_root) : NULL; -+ -+ g_signal_connect (volume->gdu_volume, "changed", G_CALLBACK (gdu_volume_changed), volume); -+ g_signal_connect (volume->gdu_volume, "job-changed", G_CALLBACK (gdu_volume_job_changed), volume); -+ -+ volume->drive = drive; -+ if (drive != NULL) -+ g_gdu_drive_set_volume (drive, volume); -+ -+ update_volume (volume); -+ -+ return volume; -+} -+ -+void -+g_gdu_volume_removed (GGduVolume *volume) -+{ -+ if (volume->pending_mount_op != NULL) -+ cancel_pending_mount_op (volume->pending_mount_op); -+ -+ if (volume->mount != NULL) -+ { -+ g_gdu_mount_unset_volume (volume->mount, volume); -+ volume->mount = NULL; -+ } -+ -+ if (volume->drive != NULL) -+ { -+ g_gdu_drive_unset_volume (volume->drive, volume); -+ volume->drive = NULL; -+ } -+} -+ -+void -+g_gdu_volume_set_mount (GGduVolume *volume, -+ GGduMount *mount) -+{ -+ if (volume->mount != mount) -+ { -+ -+ if (volume->mount != NULL) -+ g_gdu_mount_unset_volume (volume->mount, volume); -+ -+ volume->mount = mount; -+ -+ emit_changed (volume); -+ } -+} -+ -+void -+g_gdu_volume_unset_mount (GGduVolume *volume, -+ GGduMount *mount) -+{ -+ if (volume->mount == mount) -+ { -+ volume->mount = NULL; -+ emit_changed (volume); -+ } -+} -+ -+void -+g_gdu_volume_set_drive (GGduVolume *volume, -+ GGduDrive *drive) -+{ -+ if (volume->drive != drive) -+ { -+ if (volume->drive != NULL) -+ g_gdu_drive_unset_volume (volume->drive, volume); -+ -+ volume->drive = drive; -+ -+ emit_changed (volume); -+ } -+} -+ -+void -+g_gdu_volume_unset_drive (GGduVolume *volume, -+ GGduDrive *drive) -+{ -+ if (volume->drive == drive) -+ { -+ volume->drive = NULL; -+ emit_changed (volume); -+ } -+} -+ -+static GIcon * -+g_gdu_volume_get_icon (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ return volume->icon != NULL ? g_object_ref (volume->icon) : NULL; -+} -+ -+static char * -+g_gdu_volume_get_name (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ return g_strdup (volume->name); -+} -+ -+static char * -+g_gdu_volume_get_uuid (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ return g_strdup (volume->uuid); -+} -+ -+static gboolean -+g_gdu_volume_can_mount (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ return volume->can_mount; -+} -+ -+static gboolean -+g_gdu_volume_can_eject (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ gboolean can_eject; -+ -+ can_eject = FALSE; -+ if (volume->drive != NULL) -+ can_eject = g_drive_can_eject (G_DRIVE (volume->drive)); -+ -+ return can_eject; -+} -+ -+static gboolean -+g_gdu_volume_should_automount (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ return volume->should_automount; -+} -+ -+static GDrive * -+g_gdu_volume_get_drive (GVolume *volume) -+{ -+ GGduVolume *gdu_volume = G_GDU_VOLUME (volume); -+ GDrive *drive; -+ -+ drive = NULL; -+ if (gdu_volume->drive != NULL) -+ drive = g_object_ref (gdu_volume->drive); -+ -+ return drive; -+} -+ -+static GMount * -+g_gdu_volume_get_mount (GVolume *volume) -+{ -+ GGduVolume *gdu_volume = G_GDU_VOLUME (volume); -+ GMount *mount; -+ -+ mount = NULL; -+ if (gdu_volume->mount != NULL) -+ mount = g_object_ref (gdu_volume->mount); -+ -+ return mount; -+} -+ -+/* ---------------------------------------------------------------------------------------------------- */ -+ -+struct MountOpData -+{ -+ GGduVolume *volume; -+ GduDevice *device_to_mount; -+ GSimpleAsyncResult *simple; -+ GCancellable *cancellable; -+ gulong cancelled_handler_id; -+ -+ GMountOperation *mount_operation; -+ gulong mount_operation_reply_handler_id; -+ -+ gboolean is_cancelled; -+}; -+ -+static void -+mount_op_data_unref (MountOpData *data) -+{ -+ g_object_unref (data->volume); -+ if (data->device_to_mount != NULL) -+ g_object_unref (data->device_to_mount); -+ g_object_unref (data->simple); -+ if (data->cancelled_handler_id != 0) -+ g_signal_handler_disconnect (data->cancellable, data->cancelled_handler_id); -+ if (data->cancellable != NULL) -+ g_object_unref (data->cancellable); -+ if (data->mount_operation_reply_handler_id != 0) -+ g_signal_handler_disconnect (data->mount_operation, data->mount_operation_reply_handler_id); -+ if (data->mount_operation != NULL) -+ g_object_unref (data->mount_operation); -+ g_free (data); -+} -+ -+static void -+cancel_pending_mount_op (MountOpData *data) -+{ -+ /* we are no longer pending */ -+ data->volume->pending_mount_op = NULL; -+ -+ data->is_cancelled = TRUE; -+ -+ /* send an ::aborted signal to make the dialog go away */ -+ if (data->mount_operation != NULL) -+ g_signal_emit_by_name (data->mount_operation, "aborted"); -+ -+ /* complete the operation (sends reply to caller) */ -+ g_simple_async_result_set_error (data->simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED_HANDLED, -+ "Operation was cancelled"); -+ g_simple_async_result_complete (data->simple); -+} -+ -+static void -+mount_cb (GduDevice *device, -+ gchar *mount_point, -+ GError *error, -+ gpointer user_data); -+ -+static void -+mount_obtain_authz_cb (GObject *source_object, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ MountOpData *data = user_data; -+ gboolean obtained_authz; -+ GError *error; -+ -+ /* if we've already aborted due to device removal / cancellation, just bail out */ -+ if (data->is_cancelled) -+ goto bailout; -+ -+ error = NULL; -+ obtained_authz = _obtain_authz_finish (res, &error); -+ -+ if (!obtained_authz) -+ { -+ /* be quiet if the daemon is inhibited */ -+ if (error->code == GDU_ERROR_INHIBITED) -+ { -+ error->domain = G_IO_ERROR; -+ error->code = G_IO_ERROR_FAILED_HANDLED; -+ } -+ g_simple_async_result_set_from_error (data->simple, error); -+ g_simple_async_result_complete (data->simple); -+ } -+ else -+ { -+ /* got the authz, now try again */ -+ gdu_device_op_filesystem_mount (data->device_to_mount, mount_cb, data); -+ goto out; -+ } -+ -+ bailout: -+ data->volume->pending_mount_op = NULL; -+ mount_op_data_unref (data); -+ -+ out: -+ ; -+} -+ -+static void -+mount_cb (GduDevice *device, -+ gchar *mount_point, -+ GError *error, -+ gpointer user_data) -+{ -+ MountOpData *data = user_data; -+ -+ /* if we've already aborted due to device removal / cancellation, just bail out */ -+ if (data->is_cancelled) -+ goto bailout; -+ -+ if (error != NULL) -+ { -+ PolKitAction *pk_action; -+ PolKitResult pk_result; -+ -+ /* only attempt to show authentication dialog if we have a mount operation */ -+ if (data->mount_operation != NULL && gdu_error_check_polkit_not_authorized (error, -+ &pk_action, -+ &pk_result)) -+ { -+ if (pk_result != POLKIT_RESULT_NO && pk_result != POLKIT_RESULT_UNKNOWN) -+ { -+ const gchar *action_id; -+ /* try to obtain the authorization */ -+ polkit_action_get_action_id (pk_action, (char **) &action_id); -+ _obtain_authz (action_id, -+ data->cancellable, -+ mount_obtain_authz_cb, -+ data); -+ goto out; -+ } -+ else -+ { -+ g_simple_async_result_set_from_error (data->simple, error); -+ } -+ polkit_action_unref (pk_action); -+ } -+ else -+ { -+ /* be quiet if the daemon is inhibited */ -+ if (error->code == GDU_ERROR_INHIBITED) -+ { -+ error->domain = G_IO_ERROR; -+ error->code = G_IO_ERROR_FAILED_HANDLED; -+ } -+ g_simple_async_result_set_from_error (data->simple, error); -+ } -+ g_error_free (error); -+ } -+ else -+ { -+ g_free (mount_point); -+ } -+ -+ g_simple_async_result_complete (data->simple); -+ -+ bailout: -+ data->volume->pending_mount_op = NULL; -+ mount_op_data_unref (data); -+ -+ out: -+ ; -+} -+ -+static void -+mount_cleartext_device (MountOpData *data, -+ const gchar *object_path_of_cleartext_device) -+{ -+ GduPool *pool; -+ -+ /* if we've already aborted due to device removal / cancellation, just bail out */ -+ if (data->is_cancelled) -+ { -+ mount_op_data_unref (data); -+ goto bailout; -+ } -+ -+ pool = gdu_presentable_get_pool (GDU_PRESENTABLE (data->volume->gdu_volume)); -+ -+ data->device_to_mount = gdu_pool_get_by_object_path (pool, object_path_of_cleartext_device); -+ if (data->device_to_mount == NULL) -+ { -+ g_simple_async_result_set_error (data->simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ "Successfully unlocked encrypted volume but cleartext device does not exist"); -+ g_simple_async_result_complete (data->simple); -+ data->volume->pending_mount_op = NULL; -+ mount_op_data_unref (data); -+ } -+ else -+ { -+ gdu_device_op_filesystem_mount (data->device_to_mount, mount_cb, data); -+ } -+ -+ g_object_unref (pool); -+ -+ bailout: -+ ; -+} -+ -+static void -+unlock_from_keyring_cb (GduDevice *device, -+ char *object_path_of_cleartext_device, -+ GError *error, -+ gpointer user_data) -+{ -+ MountOpData *data = user_data; -+ -+ /* if we've already aborted due to device removal / cancellation, just bail out */ -+ if (data->is_cancelled) -+ { -+ mount_op_data_unref (data); -+ goto bailout; -+ } -+ -+ if (error != NULL) -+ { -+ /*g_debug ("keyring password didn't work: %s", error->message);*/ -+ -+ /* The password we retrieved from the keyring didn't work. So go ahead and prompt -+ * the user. -+ */ -+ mount_with_mount_operation (data); -+ -+ g_error_free (error); -+ } -+ else -+ { -+ mount_cleartext_device (data, object_path_of_cleartext_device); -+ g_free (object_path_of_cleartext_device); -+ } -+ -+ bailout: -+ ; -+} -+ -+static void -+unlock_cb (GduDevice *device, -+ gchar *object_path_of_cleartext_device, -+ GError *error, -+ gpointer user_data) -+{ -+ MountOpData *data = user_data; -+ -+ /* if we've already aborted due to device removal / cancellation, just bail out */ -+ if (data->is_cancelled) -+ { -+ mount_op_data_unref (data); -+ goto bailout; -+ } -+ -+ if (error != NULL) -+ { -+ /* be quiet if the daemon is inhibited */ -+ if (error->code == GDU_ERROR_INHIBITED) -+ { -+ error->domain = G_IO_ERROR; -+ error->code = G_IO_ERROR_FAILED_HANDLED; -+ } -+ g_simple_async_result_set_from_error (data->simple, error); -+ g_error_free (error); -+ g_simple_async_result_complete (data->simple); -+ data->volume->pending_mount_op = NULL; -+ mount_op_data_unref (data); -+ } -+ else -+ { -+ GPasswordSave password_save; -+ const gchar *password; -+ -+ password_save = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (device), "password-save")); -+ password = g_object_get_data (G_OBJECT (device), "password"); -+ -+ if (password != NULL) -+ { -+ switch (password_save) -+ { -+ case G_PASSWORD_SAVE_FOR_SESSION: -+ gdu_util_save_secret (device, password, TRUE); -+ break; -+ -+ case G_PASSWORD_SAVE_PERMANENTLY: -+ gdu_util_save_secret (device, password, FALSE); -+ break; -+ -+ default: -+ /* do nothing */ -+ break; -+ } -+ } -+ -+ /* now we have a cleartext device; update the GVolume details to show that */ -+ if (update_volume (data->volume)) -+ emit_changed (data->volume); -+ -+ mount_cleartext_device (data, object_path_of_cleartext_device); -+ g_free (object_path_of_cleartext_device); -+ } -+ -+ bailout: -+ -+ /* scrub the password */ -+ g_object_set_data (G_OBJECT (device), "password-save", NULL); -+ g_object_set_data (G_OBJECT (device), "password", NULL); -+} -+ -+static void -+scrub_n_free_string (char *password) -+{ -+ memset (password, '\0', strlen (password)); -+ g_free (password); -+} -+ -+static void -+mount_operation_reply (GMountOperation *mount_operation, -+ GMountOperationResult result, -+ gpointer user_data) -+{ -+ MountOpData *data = user_data; -+ GduDevice *device; -+ const gchar *password; -+ -+ /* if we've already aborted due to device removal, just bail out */ -+ if (data->is_cancelled) -+ { -+ mount_op_data_unref (data); -+ goto out; -+ } -+ -+ /* we got what we wanted; don't listen to any other signals from the mount operation */ -+ if (data->mount_operation_reply_handler_id != 0) -+ { -+ g_signal_handler_disconnect (data->mount_operation, data->mount_operation_reply_handler_id); -+ data->mount_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, -+ "Password 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_PERMISSION_DENIED, -+ "Expected G_MOUNT_OPERATION_HANDLED but got %d", result); -+ } -+ g_simple_async_result_complete (data->simple); -+ data->volume->pending_mount_op = NULL; -+ mount_op_data_unref (data); -+ goto out; -+ } -+ -+ password = g_mount_operation_get_password (mount_operation); -+ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (data->volume->gdu_volume)); -+ -+ g_object_set_data (G_OBJECT (device), -+ "password-save", -+ GINT_TO_POINTER (g_mount_operation_get_password_save (mount_operation))); -+ g_object_set_data_full (G_OBJECT (device), -+ "password", -+ g_strdup (password), -+ (GDestroyNotify) scrub_n_free_string); -+ -+ gdu_device_op_luks_unlock (device, password, unlock_cb, data); -+ -+ g_object_unref (device); -+ -+ out: -+ ; -+} -+ -+static void -+mount_with_mount_operation (MountOpData *data) -+{ -+ gchar *message; -+ gchar *drive_name; -+ GduPresentable *toplevel; -+ GduDevice *device; -+ -+ device = NULL; -+ drive_name = NULL; -+ message = NULL; -+ toplevel = NULL; -+ -+ /* if we've already aborted due to device removal, just bail out */ -+ if (data->is_cancelled) -+ { -+ mount_op_data_unref (data); -+ goto out; -+ } -+ -+ if (data->mount_operation == NULL) -+ { -+ g_simple_async_result_set_error (data->simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ "Password required to access the encrypted data"); -+ g_simple_async_result_complete (data->simple); -+ data->volume->pending_mount_op = NULL; -+ mount_op_data_unref (data); -+ goto out; -+ } -+ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (data->volume->gdu_volume)); -+ -+ toplevel = gdu_presentable_get_toplevel (GDU_PRESENTABLE (data->volume->gdu_volume)); -+ if (toplevel != NULL) -+ drive_name = gdu_presentable_get_name (toplevel); -+ -+ /* This is going to look ass until bug 573416 is fixed. Unfortunately -+ * the gtk+ maintain has stated "oh, I stopped using luks" but that's -+ * more of a gtk+ problem ;-) -+ */ -+ if (drive_name != NULL) -+ { -+ if (gdu_device_is_partition (device)) -+ { -+ message = g_strdup_printf (_("Enter a password to unlock the volume\n" -+ "The device \"%s\" contains encrypted data on partition %d."), -+ drive_name, -+ gdu_device_partition_get_number (device)); -+ } -+ else -+ { -+ message = g_strdup_printf (_("Enter a password to unlock the volume\n" -+ "The device \"%s\" contains encrypted data."), -+ drive_name); -+ } -+ } -+ else -+ { -+ message = g_strdup_printf (_("Enter a password to unlock the volume\n" -+ "The device %s contains encrypted data."), -+ gdu_device_get_device_file (device)); -+ } -+ -+ data->mount_operation_reply_handler_id = g_signal_connect (data->mount_operation, -+ "reply", -+ G_CALLBACK (mount_operation_reply), -+ data); -+ -+ g_signal_emit_by_name (data->mount_operation, -+ "ask-password", -+ message, -+ NULL, -+ NULL, -+ G_ASK_PASSWORD_NEED_PASSWORD | -+ G_ASK_PASSWORD_SAVING_SUPPORTED); -+ -+ out: -+ g_free (drive_name); -+ g_free (message); -+ if (device != NULL) -+ g_object_unref (device); -+ if (toplevel != NULL) -+ g_object_unref (toplevel); -+} -+ -+static void -+cancelled_cb (GCancellable *cancellable, -+ GGduVolume *volume) -+{ -+ if (volume->pending_mount_op != NULL) -+ { -+ cancel_pending_mount_op (volume->pending_mount_op); -+ } -+} -+ -+static void -+g_gdu_volume_mount (GVolume *_volume, -+ GMountMountFlags flags, -+ GMountOperation *mount_operation, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ GSimpleAsyncResult *simple; -+ GduDevice *device; -+ GduPool *pool; -+ const gchar *usage; -+ const gchar *type; -+ MountOpData *data; -+ -+ pool = NULL; -+ device = NULL; -+ -+ if (volume->pending_mount_op != NULL) -+ { -+ simple = g_simple_async_result_new_error (G_OBJECT (volume), -+ callback, -+ user_data, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ "A mount operation is already pending"); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ goto out; -+ } -+ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); -+ pool = gdu_device_get_pool (device); -+ -+ /* Makes no sense to mount -+ * -+ * - blank discs since these already have a burn:/// mount -+ * - other things that are already mounted -+ * -+ * Unfortunately Nautilus will try to do this anyway. For now, just return success for -+ * such requests. -+ */ -+ if (gdu_device_optical_disc_get_is_blank (device) || gdu_device_is_mounted (device)) -+ { -+ simple = g_simple_async_result_new (G_OBJECT (volume), -+ callback, -+ user_data, -+ g_gdu_volume_mount); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ goto out; -+ } -+ -+ data = g_new0 (MountOpData, 1); -+ -+ data->volume = g_object_ref (volume); -+ -+ data->simple = g_simple_async_result_new (G_OBJECT (volume), -+ callback, -+ user_data, -+ g_gdu_volume_mount); -+ -+ data->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL; -+ -+ data->mount_operation = mount_operation != NULL ? g_object_ref (mount_operation) : NULL; -+ -+ if (data->cancellable != NULL) -+ data->cancelled_handler_id = g_signal_connect (data->cancellable, "cancelled", G_CALLBACK (cancelled_cb), volume); -+ -+ volume->pending_mount_op = data; -+ -+ /* if the device is already unlocked, just attempt to mount it */ -+ if (volume->cleartext_gdu_volume != NULL) -+ { -+ GduDevice *luks_cleartext_volume_device; -+ const gchar *object_path_of_cleartext_device; -+ -+ luks_cleartext_volume_device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); -+ -+ object_path_of_cleartext_device = gdu_device_get_object_path (luks_cleartext_volume_device); -+ -+ mount_cleartext_device (data, object_path_of_cleartext_device); -+ -+ g_object_unref (luks_cleartext_volume_device); -+ goto out; -+ } -+ -+ usage = gdu_device_id_get_usage (device); -+ type = gdu_device_id_get_type (device); -+ if (g_strcmp0 (usage, "crypto") == 0 && g_strcmp0 (type, "crypto_LUKS") == 0) -+ { -+ gchar *password; -+ -+ /* if we have the secret in the keyring, try with that first */ -+ password = gdu_util_get_secret (device); -+ if (password != NULL) -+ { -+ gdu_device_op_luks_unlock (device, password, unlock_from_keyring_cb, data); -+ -+ scrub_n_free_string (password); -+ goto out; -+ } -+ -+ /* don't put up a password dialog if the daemon is inhibited */ -+ if (gdu_pool_is_daemon_inhibited (pool)) -+ { -+ g_simple_async_result_set_error (data->simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED_HANDLED, -+ "Daemon is currently inhibited"); -+ g_simple_async_result_complete (data->simple); -+ volume->pending_mount_op = NULL; -+ mount_op_data_unref (data); -+ goto out; -+ } -+ -+ mount_with_mount_operation (data); -+ } -+ else -+ { -+ data->device_to_mount = g_object_ref (device); -+ gdu_device_op_filesystem_mount (data->device_to_mount, mount_cb, data); -+ } -+ -+ out: -+ if (pool != NULL) -+ g_object_unref (pool); -+ if (device != NULL) -+ g_object_unref (device); -+} -+ -+static gboolean -+g_gdu_volume_mount_finish (GVolume *volume, -+ GAsyncResult *result, -+ GError **error) -+{ -+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); -+ -+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_gdu_volume_mount); -+ -+ return !g_simple_async_result_propagate_error (simple, error); -+} -+ -+/* ---------------------------------------------------------------------------------------------------- */ -+ -+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_gdu_volume_eject (GVolume *volume, -+ GMountUnmountFlags flags, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GGduVolume *gdu_volume = G_GDU_VOLUME (volume); -+ GGduDrive *drive; -+ -+ drive = NULL; -+ if (gdu_volume->drive != NULL) -+ drive = g_object_ref (gdu_volume->drive); -+ -+ 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); -+ } -+ else -+ { -+ GSimpleAsyncResult *simple; -+ simple = g_simple_async_result_new_error (G_OBJECT (volume), -+ callback, -+ user_data, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ _("Operation not supported by backend")); -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+ } -+} -+ -+static gboolean -+g_gdu_volume_eject_finish (GVolume *volume, -+ GAsyncResult *result, -+ GError **error) -+{ -+ GGduVolume *gdu_volume = G_GDU_VOLUME (volume); -+ gboolean res; -+ -+ res = TRUE; -+ if (gdu_volume->drive != NULL) -+ { -+ res = g_drive_eject_finish (G_DRIVE (gdu_volume->drive), result, error); -+ } -+ else -+ { -+ g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error); -+ res = FALSE; -+ } -+ -+ return res; -+} -+ -+static char * -+g_gdu_volume_get_identifier (GVolume *_volume, -+ const char *kind) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ GduDevice *device; -+ const gchar *label; -+ const gchar *uuid; -+ gchar *id; -+ -+ id = NULL; -+ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); -+ -+ label = gdu_device_id_get_label (device); -+ uuid = gdu_device_id_get_uuid (device); -+ -+ g_object_unref (device); -+ -+ if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0) -+ id = g_strdup (volume->device_file); -+ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_LABEL) == 0) -+ id = strlen (label) > 0 ? g_strdup (label) : NULL; -+ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UUID) == 0) -+ id = strlen (uuid) > 0 ? g_strdup (uuid) : NULL; -+ -+ return id; -+} -+ -+static char ** -+g_gdu_volume_enumerate_identifiers (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ GduDevice *device; -+ GPtrArray *p; -+ const gchar *label; -+ const gchar *uuid; -+ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume)); -+ -+ label = gdu_device_id_get_label (device); -+ uuid = gdu_device_id_get_uuid (device); -+ -+ g_object_unref (device); -+ -+ p = g_ptr_array_new (); -+ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE)); -+ if (strlen (label) > 0) -+ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_LABEL)); -+ if (strlen (uuid) > 0) -+ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UUID)); -+ -+ g_ptr_array_add (p, NULL); -+ -+ return (gchar **) g_ptr_array_free (p, FALSE); -+} -+ -+static GFile * -+g_gdu_volume_get_activation_root (GVolume *_volume) -+{ -+ GGduVolume *volume = G_GDU_VOLUME (_volume); -+ return volume->activation_root != NULL ? g_object_ref (volume->activation_root) : NULL; -+} -+ -+static void -+g_gdu_volume_volume_iface_init (GVolumeIface *iface) -+{ -+ iface->get_name = g_gdu_volume_get_name; -+ iface->get_icon = g_gdu_volume_get_icon; -+ iface->get_uuid = g_gdu_volume_get_uuid; -+ iface->get_drive = g_gdu_volume_get_drive; -+ iface->get_mount = g_gdu_volume_get_mount; -+ iface->can_mount = g_gdu_volume_can_mount; -+ iface->can_eject = g_gdu_volume_can_eject; -+ iface->should_automount = g_gdu_volume_should_automount; -+ iface->mount_fn = g_gdu_volume_mount; -+ iface->mount_finish = g_gdu_volume_mount_finish; -+ iface->eject = g_gdu_volume_eject; -+ iface->eject_finish = g_gdu_volume_eject_finish; -+ iface->get_identifier = g_gdu_volume_get_identifier; -+ iface->enumerate_identifiers = g_gdu_volume_enumerate_identifiers; -+ iface->get_activation_root = g_gdu_volume_get_activation_root; -+} -+ -+gboolean -+g_gdu_volume_has_device_file (GGduVolume *volume, -+ const gchar *device_file) -+{ -+ const gchar *_device_file; -+ -+ _device_file = volume->device_file; -+ -+ if (volume->cleartext_gdu_volume != NULL) -+ { -+ GduDevice *luks_cleartext_volume_device; -+ luks_cleartext_volume_device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); -+ _device_file = gdu_device_get_device_file (luks_cleartext_volume_device); -+ g_object_unref (luks_cleartext_volume_device); -+ } -+ -+ return g_strcmp0 (_device_file, device_file) == 0; -+} -+ -+ -+gboolean -+g_gdu_volume_has_mount_path (GGduVolume *volume, -+ const char *mount_path) -+{ -+ GduDevice *device; -+ GduPresentable *presentable; -+ gboolean ret; -+ -+ ret = FALSE; -+ -+ presentable = g_gdu_volume_get_presentable_with_cleartext (volume); -+ if (presentable != NULL) -+ { -+ device = gdu_presentable_get_device (presentable); -+ if (device != NULL) -+ { -+ ret = g_strcmp0 (gdu_device_get_mount_path (device), mount_path) == 0; -+ g_object_unref (device); -+ } -+ } -+ -+ return ret; -+} -+ -+gboolean -+g_gdu_volume_has_uuid (GGduVolume *volume, -+ const char *uuid) -+{ -+ const gchar *_uuid; -+ -+ _uuid = volume->uuid; -+ -+ if (volume->cleartext_gdu_volume != NULL) -+ { -+ GduDevice *luks_cleartext_volume_device; -+ luks_cleartext_volume_device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->cleartext_gdu_volume)); -+ _uuid = gdu_device_id_get_uuid (luks_cleartext_volume_device); -+ g_object_unref (luks_cleartext_volume_device); -+ } -+ -+ return g_strcmp0 (_uuid, uuid) == 0; -+} -+ -+GduPresentable * -+g_gdu_volume_get_presentable (GGduVolume *volume) -+{ -+ return GDU_PRESENTABLE (volume->gdu_volume); -+} -+ -+GduPresentable * -+g_gdu_volume_get_presentable_with_cleartext (GGduVolume *volume) -+{ -+ GduVolume *ret; -+ -+ ret = volume->cleartext_gdu_volume; -+ if (ret == NULL) -+ ret = volume->gdu_volume; -+ -+ return GDU_PRESENTABLE (ret); -+} ---- /dev/null 2009-03-04 16:07:30.099029290 -0500 -+++ monitor/gdu/ggduvolume.h 2009-03-01 23:48:05.000000000 -0500 -@@ -0,0 +1,78 @@ -+/* -*- 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#ifndef __G_GDU_VOLUME_H__ -+#define __G_GDU_VOLUME_H__ -+ -+#include -+#include -+ -+#include "ggduvolumemonitor.h" -+ -+G_BEGIN_DECLS -+ -+#define G_TYPE_GDU_VOLUME (g_gdu_volume_get_type ()) -+#define G_GDU_VOLUME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_GDU_VOLUME, GGduVolume)) -+#define G_GDU_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_GDU_VOLUME, GGduVolumeClass)) -+#define G_IS_GDU_VOLUME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_GDU_VOLUME)) -+#define G_IS_GDU_VOLUME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_GDU_VOLUME)) -+ -+typedef struct _GGduVolumeClass GGduVolumeClass; -+ -+struct _GGduVolumeClass { -+ GObjectClass parent_class; -+}; -+ -+GType g_gdu_volume_get_type (void) G_GNUC_CONST; -+ -+GGduVolume *g_gdu_volume_new (GVolumeMonitor *volume_monitor, -+ GduVolume *gdu_volume, -+ GGduDrive *drive, -+ GFile *activation_root); -+ -+void g_gdu_volume_set_mount (GGduVolume *volume, -+ GGduMount *mount); -+void g_gdu_volume_unset_mount (GGduVolume *volume, -+ GGduMount *mount); -+ -+void g_gdu_volume_set_drive (GGduVolume *volume, -+ GGduDrive *drive); -+void g_gdu_volume_unset_drive (GGduVolume *volume, -+ GGduDrive *drive); -+ -+void g_gdu_volume_removed (GGduVolume *volume); -+ -+gboolean g_gdu_volume_has_mount_path (GGduVolume *volume, -+ const char *mount_path); -+gboolean g_gdu_volume_has_uuid (GGduVolume *volume, -+ const char *uuid); -+gboolean g_gdu_volume_has_device_file (GGduVolume *volume, -+ const gchar *device_file); -+ -+GduPresentable *g_gdu_volume_get_presentable (GGduVolume *volume); -+ -+GduPresentable *g_gdu_volume_get_presentable_with_cleartext (GGduVolume *volume); -+ -+G_END_DECLS -+ -+#endif /* __G_GDU_VOLUME_H__ */ ---- /dev/null 2009-03-04 16:07:30.099029290 -0500 -+++ monitor/gdu/ggduvolumemonitor.c 2009-03-04 16:29:02.000000000 -0500 -@@ -0,0 +1,1432 @@ -+/* -*- 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include "ggduvolumemonitor.h" -+#include "ggdumount.h" -+#include "ggduvolume.h" -+#include "ggdudrive.h" -+ -+static GGduVolumeMonitor *the_volume_monitor = NULL; -+ -+struct _GGduVolumeMonitor { -+ GNativeVolumeMonitor parent; -+ -+ GUnixMountMonitor *mount_monitor; -+ -+ GduPool *pool; -+ -+ GList *last_optical_disc_devices; -+ GList *last_mountpoints; -+ GList *last_mounts; -+ -+ GList *drives; -+ GList *volumes; -+ GList *mounts; -+ -+ /* we keep volumes/mounts for blank and audio discs separate to handle e.g. mixed discs properly */ -+ GList *disc_volumes; -+ GList *disc_mounts; -+ -+}; -+ -+static void mountpoints_changed (GUnixMountMonitor *mount_monitor, -+ gpointer user_data); -+static void mounts_changed (GUnixMountMonitor *mount_monitor, -+ gpointer user_data); -+ -+static void presentable_added (GduPool *pool, -+ GduPresentable *presentable, -+ gpointer user_data); -+static void presentable_removed (GduPool *pool, -+ GduPresentable *presentable, -+ gpointer user_data); -+ -+static void update_all (GGduVolumeMonitor *monitor, -+ gboolean emit_changes); -+ -+static void update_drives (GGduVolumeMonitor *monitor, -+ GList **added_drives, -+ GList **removed_drives); -+static void update_volumes (GGduVolumeMonitor *monitor, -+ GList **added_volumes, -+ GList **removed_volumes); -+static void update_mounts (GGduVolumeMonitor *monitor, -+ GList **added_mounts, -+ GList **removed_mounts); -+static void update_discs (GGduVolumeMonitor *monitor, -+ GList **added_volumes, -+ GList **removed_volumes, -+ GList **added_mounts, -+ GList **removed_mounts); -+ -+ -+G_DEFINE_TYPE (GGduVolumeMonitor, g_gdu_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR) -+ -+static void -+list_free (GList *objects) -+{ -+ g_list_foreach (objects, (GFunc)g_object_unref, NULL); -+ g_list_free (objects); -+} -+ -+static void -+g_gdu_volume_monitor_dispose (GObject *object) -+{ -+ GGduVolumeMonitor *monitor; -+ -+ monitor = G_GDU_VOLUME_MONITOR (object); -+ -+ the_volume_monitor = NULL; -+ -+ if (G_OBJECT_CLASS (g_gdu_volume_monitor_parent_class)->dispose) -+ (*G_OBJECT_CLASS (g_gdu_volume_monitor_parent_class)->dispose) (object); -+} -+ -+static void -+g_gdu_volume_monitor_finalize (GObject *object) -+{ -+ GGduVolumeMonitor *monitor; -+ -+ monitor = G_GDU_VOLUME_MONITOR (object); -+ -+ g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mountpoints_changed, monitor); -+ g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mounts_changed, monitor); -+ g_signal_handlers_disconnect_by_func (monitor->mount_monitor, presentable_added, monitor); -+ g_signal_handlers_disconnect_by_func (monitor->mount_monitor, presentable_removed, monitor); -+ -+ g_object_unref (monitor->mount_monitor); -+ -+ g_object_unref (monitor->pool); -+ -+ list_free (monitor->last_optical_disc_devices); -+ list_free (monitor->last_mountpoints); -+ g_list_foreach (monitor->last_mounts, -+ (GFunc)g_unix_mount_free, NULL); -+ g_list_free (monitor->last_mounts); -+ -+ list_free (monitor->drives); -+ list_free (monitor->volumes); -+ list_free (monitor->mounts); -+ -+ list_free (monitor->disc_volumes); -+ list_free (monitor->disc_mounts); -+ -+ if (G_OBJECT_CLASS (g_gdu_volume_monitor_parent_class)->finalize) -+ (*G_OBJECT_CLASS (g_gdu_volume_monitor_parent_class)->finalize) (object); -+} -+ -+static GList * -+get_mounts (GVolumeMonitor *volume_monitor) -+{ -+ GGduVolumeMonitor *monitor; -+ GList *l, *ll; -+ -+ monitor = G_GDU_VOLUME_MONITOR (volume_monitor); -+ -+ l = g_list_copy (monitor->mounts); -+ ll = g_list_copy (monitor->disc_mounts); -+ l = g_list_concat (l, ll); -+ -+ g_list_foreach (l, (GFunc)g_object_ref, NULL); -+ -+ return l; -+} -+ -+static GList * -+get_volumes (GVolumeMonitor *volume_monitor) -+{ -+ GGduVolumeMonitor *monitor; -+ GList *l, *ll; -+ -+ monitor = G_GDU_VOLUME_MONITOR (volume_monitor); -+ -+ l = g_list_copy (monitor->volumes); -+ ll = g_list_copy (monitor->disc_volumes); -+ l = g_list_concat (l, ll); -+ -+ g_list_foreach (l, (GFunc)g_object_ref, NULL); -+ -+ return l; -+} -+ -+static GList * -+get_connected_drives (GVolumeMonitor *volume_monitor) -+{ -+ GGduVolumeMonitor *monitor; -+ GList *l; -+ -+ monitor = G_GDU_VOLUME_MONITOR (volume_monitor); -+ -+ l = g_list_copy (monitor->drives); -+ g_list_foreach (l, (GFunc)g_object_ref, NULL); -+ -+ return l; -+} -+ -+static GVolume * -+get_volume_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid) -+{ -+ GGduVolumeMonitor *monitor; -+ GGduVolume *volume; -+ GList *l; -+ -+ monitor = G_GDU_VOLUME_MONITOR (volume_monitor); -+ -+ volume = NULL; -+ -+ for (l = monitor->volumes; l != NULL; l = l->next) -+ { -+ volume = l->data; -+ if (g_gdu_volume_has_uuid (volume, uuid)) -+ goto found; -+ } -+ -+ for (l = monitor->disc_volumes; l != NULL; l = l->next) -+ { -+ volume = l->data; -+ if (g_gdu_volume_has_uuid (volume, uuid)) -+ goto found; -+ } -+ -+ return NULL; -+ -+ found: -+ -+ g_object_ref (volume); -+ -+ return (GVolume *)volume; -+} -+ -+static GMount * -+get_mount_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid) -+{ -+ GGduVolumeMonitor *monitor; -+ GGduMount *mount; -+ GList *l; -+ -+ monitor = G_GDU_VOLUME_MONITOR (volume_monitor); -+ -+ mount = NULL; -+ -+ for (l = monitor->mounts; l != NULL; l = l->next) -+ { -+ mount = l->data; -+ if (g_gdu_mount_has_uuid (mount, uuid)) -+ goto found; -+ } -+ -+ for (l = monitor->disc_mounts; l != NULL; l = l->next) -+ { -+ mount = l->data; -+ if (g_gdu_mount_has_uuid (mount, uuid)) -+ goto found; -+ } -+ -+ return NULL; -+ -+ found: -+ -+ g_object_ref (mount); -+ -+ return (GMount *)mount; -+} -+ -+static GMount * -+get_mount_for_mount_path (const char *mount_path, -+ GCancellable *cancellable) -+{ -+ GMount *mount; -+ GGduMount *gdu_mount; -+ GGduVolumeMonitor *volume_monitor; -+ -+ if (the_volume_monitor == NULL) -+ { -+ /* Dammit, no monitor is set up.. so we have to create one, find -+ * what the user asks for and throw it away again. -+ * -+ * What a waste - especially considering that there's IO -+ * involved in doing this: connect to the system message bus; -+ * IPC to DeviceKit-disks etc etc -+ */ -+ volume_monitor = G_GDU_VOLUME_MONITOR (g_gdu_volume_monitor_new ()); -+ } -+ else -+ { -+ volume_monitor = g_object_ref (the_volume_monitor); -+ } -+ -+ mount = NULL; -+ -+ /* creation of the volume monitor might actually fail */ -+ if (volume_monitor != NULL) -+ { -+ GList *l; -+ -+ for (l = volume_monitor->mounts; l != NULL; l = l->next) -+ { -+ gdu_mount = l->data; -+ -+ if (g_gdu_mount_has_mount_path (gdu_mount, mount_path)) -+ { -+ mount = g_object_ref (gdu_mount); -+ break; -+ } -+ } -+ } -+ -+ g_object_unref (volume_monitor); -+ -+ return (GMount *) mount; -+} -+ -+static void -+mountpoints_changed (GUnixMountMonitor *mount_monitor, -+ gpointer user_data) -+{ -+ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); -+ -+ update_all (monitor, TRUE); -+} -+ -+static void -+mounts_changed (GUnixMountMonitor *mount_monitor, -+ gpointer user_data) -+{ -+ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); -+ -+ update_all (monitor, TRUE); -+} -+ -+static void -+presentable_added (GduPool *pool, -+ GduPresentable *presentable, -+ gpointer user_data) -+{ -+ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); -+ -+ /*g_debug ("presentable_added %p: %s", presentable, gdu_presentable_get_id (presentable));*/ -+ -+ update_all (monitor, TRUE); -+} -+ -+static void -+presentable_removed (GduPool *pool, -+ GduPresentable *presentable, -+ gpointer user_data) -+{ -+ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); -+ -+ /*g_debug ("presentable_removed %p: %s", presentable, gdu_presentable_get_id (presentable));*/ -+ -+ update_all (monitor, TRUE); -+} -+ -+static void -+presentable_changed (GduPool *pool, -+ GduPresentable *presentable, -+ gpointer user_data) -+{ -+ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); -+ -+ /*g_debug ("presentable_changed %p: %s", presentable, gdu_presentable_get_id (presentable));*/ -+ -+ update_all (monitor, TRUE); -+} -+ -+static void -+presentable_job_changed (GduPool *pool, -+ GduPresentable *presentable, -+ gpointer user_data) -+{ -+ GGduVolumeMonitor *monitor = G_GDU_VOLUME_MONITOR (user_data); -+ -+ /*g_debug ("presentable_job_changed %p: %s", presentable, gdu_presentable_get_id (presentable));*/ -+ -+ update_all (monitor, TRUE); -+} -+ -+static GObject * -+g_gdu_volume_monitor_constructor (GType type, -+ guint n_construct_properties, -+ GObjectConstructParam *construct_properties) -+{ -+ GObject *object; -+ GGduVolumeMonitor *monitor; -+ GGduVolumeMonitorClass *klass; -+ GObjectClass *parent_class; -+ -+ if (the_volume_monitor != NULL) -+ { -+ object = g_object_ref (the_volume_monitor); -+ return object; -+ } -+ -+ /*g_warning ("creating gdu vm");*/ -+ -+ object = NULL; -+ -+ /* Invoke parent constructor. */ -+ klass = G_GDU_VOLUME_MONITOR_CLASS (g_type_class_peek (G_TYPE_GDU_VOLUME_MONITOR)); -+ parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); -+ object = parent_class->constructor (type, -+ n_construct_properties, -+ construct_properties); -+ -+ monitor = G_GDU_VOLUME_MONITOR (object); -+ -+ monitor->mount_monitor = g_unix_mount_monitor_new (); -+ -+ g_signal_connect (monitor->mount_monitor, -+ "mounts_changed", -+ G_CALLBACK (mounts_changed), -+ monitor); -+ -+ g_signal_connect (monitor->mount_monitor, -+ "mountpoints_changed", -+ G_CALLBACK (mountpoints_changed), -+ monitor); -+ -+ monitor->pool = gdu_pool_new (); -+ -+ g_signal_connect (monitor->pool, -+ "presentable_added", -+ G_CALLBACK (presentable_added), -+ monitor); -+ -+ g_signal_connect (monitor->pool, -+ "presentable_removed", -+ G_CALLBACK (presentable_removed), -+ monitor); -+ -+ g_signal_connect (monitor->pool, -+ "presentable_changed", -+ G_CALLBACK (presentable_changed), -+ monitor); -+ -+ g_signal_connect (monitor->pool, -+ "presentable_job_changed", -+ G_CALLBACK (presentable_job_changed), -+ monitor); -+ -+ update_all (monitor, FALSE); -+ -+ the_volume_monitor = monitor; -+ -+ return object; -+} -+ -+static void -+g_gdu_volume_monitor_init (GGduVolumeMonitor *monitor) -+{ -+} -+ -+static gboolean -+is_supported (void) -+{ -+ /* TODO: return FALSE if DeviceKit-disks is not available */ -+ return TRUE; -+} -+ -+static void -+g_gdu_volume_monitor_class_init (GGduVolumeMonitorClass *klass) -+{ -+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass); -+ GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS (klass); -+ GNativeVolumeMonitorClass *native_class = G_NATIVE_VOLUME_MONITOR_CLASS (klass); -+ -+ gobject_class->constructor = g_gdu_volume_monitor_constructor; -+ gobject_class->finalize = g_gdu_volume_monitor_finalize; -+ gobject_class->dispose = g_gdu_volume_monitor_dispose; -+ -+ monitor_class->get_mounts = get_mounts; -+ monitor_class->get_volumes = get_volumes; -+ monitor_class->get_connected_drives = get_connected_drives; -+ monitor_class->get_volume_for_uuid = get_volume_for_uuid; -+ monitor_class->get_mount_for_uuid = get_mount_for_uuid; -+ monitor_class->is_supported = is_supported; -+ -+ native_class->get_mount_for_mount_path = get_mount_for_mount_path; -+} -+ -+/** -+ * g_gdu_volume_monitor_new: -+ * -+ * Returns: a new #GVolumeMonitor. -+ **/ -+GVolumeMonitor * -+g_gdu_volume_monitor_new (void) -+{ -+ GGduVolumeMonitor *monitor; -+ -+ monitor = g_object_new (G_TYPE_GDU_VOLUME_MONITOR, NULL); -+ -+ return G_VOLUME_MONITOR (monitor); -+} -+ -+static void -+diff_sorted_lists (GList *list1, -+ GList *list2, -+ GCompareFunc compare, -+ GList **added, -+ GList **removed) -+{ -+ int order; -+ -+ *added = *removed = NULL; -+ -+ while (list1 != NULL && -+ list2 != NULL) -+ { -+ order = (*compare) (list1->data, list2->data); -+ if (order < 0) -+ { -+ *removed = g_list_prepend (*removed, list1->data); -+ list1 = list1->next; -+ } -+ else if (order > 0) -+ { -+ *added = g_list_prepend (*added, list2->data); -+ list2 = list2->next; -+ } -+ else -+ { /* same item */ -+ list1 = list1->next; -+ list2 = list2->next; -+ } -+ } -+ -+ while (list1 != NULL) -+ { -+ *removed = g_list_prepend (*removed, list1->data); -+ list1 = list1->next; -+ } -+ while (list2 != NULL) -+ { -+ *added = g_list_prepend (*added, list2->data); -+ list2 = list2->next; -+ } -+} -+ -+static GGduVolume * -+find_volume_for_mount_path (GGduVolumeMonitor *monitor, -+ const char *mount_path) -+{ -+ GList *l; -+ GGduVolume *found; -+ -+ found = NULL; -+ -+ for (l = monitor->volumes; l != NULL; l = l->next) -+ { -+ GGduVolume *volume = l->data; -+ -+ if (g_gdu_volume_has_mount_path (volume, mount_path)) -+ { -+ found = volume; -+ break; -+ } -+ } -+ -+ return found; -+} -+ -+static GGduMount * -+find_mount_by_mount_path (GGduVolumeMonitor *monitor, -+ const char *mount_path) -+{ -+ GList *l; -+ -+ for (l = monitor->mounts; l != NULL; l = l->next) -+ { -+ GGduMount *mount = l->data; -+ -+ if (g_gdu_mount_has_mount_path (mount, mount_path)) -+ return mount; -+ } -+ -+ return NULL; -+} -+ -+/* TODO: move to gio */ -+static gboolean -+_g_unix_mount_point_guess_should_display (GUnixMountPoint *mount_point) -+{ -+ const char *mount_path; -+ -+ mount_path = g_unix_mount_point_get_mount_path (mount_point); -+ -+ /* Never display internal mountpoints */ -+ if (g_unix_is_mount_path_system_internal (mount_path)) -+ return FALSE; -+ -+ /* Only display things in /media (which are generally user mountable) -+ and home dir (fuse stuff) */ -+ if (g_str_has_prefix (mount_path, "/media/")) -+ return TRUE; -+ -+ if (g_str_has_prefix (mount_path, g_get_home_dir ())) -+ return TRUE; -+ -+ return FALSE; -+} -+ -+static GUnixMountPoint * -+get_mount_point_for_device (GduDevice *d, GList *fstab_mount_points) -+{ -+ GList *l; -+ const gchar *device_file; -+ const gchar *mount_path; -+ GUnixMountPoint *ret; -+ -+ ret = NULL; -+ -+ mount_path = gdu_device_get_mount_path (d); -+ -+ device_file = gdu_device_get_device_file (d); -+ -+ for (l = fstab_mount_points; l != NULL; l = l->next) -+ { -+ GUnixMountPoint *mount_point = l->data; -+ const gchar *device_file; -+ const gchar *fstab_mount_path; -+ -+ fstab_mount_path = g_unix_mount_point_get_mount_path (mount_point); -+ if (g_strcmp0 (mount_path, fstab_mount_path) == 0) -+ { -+ ret = mount_point; -+ goto out; -+ } -+ -+ device_file = g_unix_mount_point_get_device_path (mount_point); -+ if (g_str_has_prefix (device_file, "LABEL=")) -+ { -+ if (g_strcmp0 (device_file + 6, gdu_device_id_get_label (d)) == 0) -+ { -+ ret = mount_point; -+ goto out; -+ } -+ } -+ else if (g_str_has_prefix (device_file, "UUID=")) -+ { -+ if (g_ascii_strcasecmp (device_file + 5, gdu_device_id_get_uuid (d)) == 0) -+ { -+ ret = mount_point; -+ goto out; -+ } -+ } -+ else -+ { -+ char resolved_device_file[PATH_MAX]; -+ -+ /* handle symlinks such as /dev/disk/by-uuid/47C2-1994 */ -+ if (realpath (device_file, resolved_device_file) != NULL && -+ g_strcmp0 (resolved_device_file, device_file) == 0) -+ { -+ ret = mount_point; -+ goto out; -+ } -+ } -+ } -+ -+ out: -+ return ret; -+} -+ -+static gboolean -+should_mount_be_ignored (GduPool *pool, GduDevice *d) -+{ -+ gboolean ret; -+ const gchar *mount_path; -+ GUnixMountEntry *mount_entry; -+ -+ ret = FALSE; -+ -+ if (gdu_device_is_mounted (d)) -+ goto out; -+ -+ mount_path = gdu_device_get_mount_path (d); -+ if (mount_path == NULL || strlen (mount_path) == 0) -+ goto out; -+ -+ mount_entry = g_unix_mount_at (mount_path, NULL); -+ if (mount_entry != NULL) -+ { -+ if (!g_unix_mount_guess_should_display (mount_entry)) -+ { -+ ret = TRUE; -+ } -+ g_unix_mount_free (mount_entry); -+ } -+ -+ out: -+ return ret; -+} -+ -+static gboolean -+should_volume_be_ignored (GduPool *pool, GduVolume *volume, GList *fstab_mount_points) -+{ -+ GduDevice *device; -+ gboolean ret; -+ const gchar *usage; -+ const gchar *type; -+ -+ ret = TRUE; -+ device = NULL; -+ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume)); -+ -+ usage = gdu_device_id_get_usage (device); -+ type = gdu_device_id_get_type (device); -+ -+ if (g_strcmp0 (usage, "filesystem") == 0) -+ { -+ GUnixMountPoint *mount_point; -+ -+ /* don't ignore volumes with a mountable filesystem unless -+ * -+ * - volume is referenced in /etc/fstab and deemed to be ignored -+ * -+ * - volume is mounted and should_mount_be_ignored() deems it should be ignored -+ * -+ * - volume is a cleartext LUKS device as the cryptotext LUKS volume will morph -+ * into the cleartext volume when unlocked (see ggduvolume.c) -+ */ -+ -+ if (gdu_device_is_luks_cleartext (device)) -+ goto out; -+ -+ mount_point = get_mount_point_for_device (device, fstab_mount_points); -+ if (mount_point != NULL && !_g_unix_mount_point_guess_should_display (mount_point)) -+ goto out; -+ -+ if (gdu_device_is_mounted (device)) -+ { -+ ret = should_mount_be_ignored (pool, device); -+ goto out; -+ } -+ -+ ret = FALSE; -+ -+ } -+ else if (g_strcmp0 (usage, "crypto") == 0 && g_strcmp0 (type, "crypto_LUKS") == 0) -+ { -+ /* don't ignore LUKS volumes */ -+ ret = FALSE; -+ } -+ -+ out: -+ -+ g_object_unref (device); -+ return ret; -+} -+ -+static gboolean -+should_drive_be_ignored (GduPool *pool, GduDrive *d, GList *fstab_mount_points) -+{ -+ GduDevice *device; -+ gboolean ret; -+ gboolean has_volumes; -+ gboolean all_volumes_are_ignored; -+ GList *enclosed; -+ GList *l; -+ -+ ret = FALSE; -+ device = NULL; -+ enclosed = NULL; -+ -+ device = gdu_presentable_get_device (GDU_PRESENTABLE (d)); -+ -+ /* the GduDevice for an activatable drive (such as RAID) is NULL if the drive is not -+ * activated; never ignore these -+ */ -+ if (device == NULL) -+ goto out; -+ -+ /* never ignore drives with removable media */ -+ if (gdu_device_is_removable (device)) -+ goto out; -+ -+ has_volumes = FALSE; -+ all_volumes_are_ignored = TRUE; -+ -+ /* never ignore a drive if it has volumes that we don't want to ignore */ -+ enclosed = gdu_pool_get_enclosed_presentables (pool, GDU_PRESENTABLE (d)); -+ for (l = enclosed; l != NULL; l = l->next) -+ { -+ GduPresentable *enclosed_presentable = GDU_PRESENTABLE (l->data); -+ -+ /* There might be other presentables that GduVolume objects; for example GduVolumeHole */ -+ if (GDU_IS_VOLUME (enclosed_presentable)) -+ { -+ GduVolume *volume = GDU_VOLUME (enclosed_presentable); -+ -+ has_volumes = TRUE; -+ -+ if (!should_volume_be_ignored (pool, volume, fstab_mount_points)) -+ { -+ all_volumes_are_ignored = FALSE; -+ break; -+ } -+ } -+ } -+ -+ ret = has_volumes && all_volumes_are_ignored; -+ -+ out: -+ g_list_foreach (enclosed, (GFunc) g_object_unref, NULL); -+ g_list_free (enclosed); -+ -+ if (device != NULL) -+ g_object_unref (device); -+ -+ return ret; -+} -+ -+static void -+list_emit (GGduVolumeMonitor *monitor, -+ const char *monitor_signal, -+ const char *object_signal, -+ GList *objects) -+{ -+ GList *l; -+ -+ for (l = objects; l != NULL; l = l->next) -+ { -+ g_signal_emit_by_name (monitor, monitor_signal, l->data); -+ if (object_signal) -+ g_signal_emit_by_name (l->data, object_signal); -+ } -+} -+ -+static void -+update_all (GGduVolumeMonitor *monitor, -+ gboolean emit_changes) -+{ -+ GList *added_drives, *removed_drives; -+ GList *added_volumes, *removed_volumes; -+ GList *added_mounts, *removed_mounts; -+ -+ added_drives = NULL; -+ removed_drives = NULL; -+ added_volumes = NULL; -+ removed_volumes = NULL; -+ added_mounts = NULL; -+ removed_mounts = NULL; -+ -+ update_drives (monitor, &added_drives, &removed_drives); -+ update_volumes (monitor, &added_volumes, &removed_volumes); -+ update_mounts (monitor, &added_mounts, &removed_mounts); -+ update_discs (monitor, -+ &added_volumes, &removed_volumes, -+ &added_mounts, &removed_mounts); -+ -+ if (emit_changes) -+ { -+ list_emit (monitor, -+ "drive_disconnected", NULL, -+ removed_drives); -+ list_emit (monitor, -+ "drive_connected", NULL, -+ added_drives); -+ -+ list_emit (monitor, -+ "volume_removed", "removed", -+ removed_volumes); -+ list_emit (monitor, -+ "volume_added", NULL, -+ added_volumes); -+ -+ list_emit (monitor, -+ "mount_removed", "unmounted", -+ removed_mounts); -+ list_emit (monitor, -+ "mount_added", NULL, -+ added_mounts); -+ } -+ -+ list_free (removed_drives); -+ list_free (added_drives); -+ list_free (removed_volumes); -+ list_free (added_volumes); -+ list_free (removed_mounts); -+ list_free (added_mounts); -+} -+ -+static GGduMount * -+find_disc_mount_for_volume (GGduVolumeMonitor *monitor, -+ GGduVolume *volume) -+{ -+ GList *l; -+ -+ for (l = monitor->disc_mounts; l != NULL; l = l->next) -+ { -+ GGduMount *mount = G_GDU_MOUNT (l->data); -+ -+ if (g_gdu_mount_has_volume (mount, volume)) -+ return mount; -+ } -+ -+ return NULL; -+} -+ -+static GGduVolume * -+find_disc_volume_for_device_file (GGduVolumeMonitor *monitor, -+ const gchar *device_file) -+{ -+ GList *l; -+ -+ for (l = monitor->disc_volumes; l != NULL; l = l->next) -+ { -+ GGduVolume *volume = G_GDU_VOLUME (l->data); -+ -+ if (g_gdu_volume_has_device_file (volume, device_file)) -+ return volume; -+ } -+ -+ return NULL; -+} -+ -+static GGduVolume * -+find_volume_for_device_file (GGduVolumeMonitor *monitor, -+ const gchar *device_file) -+{ -+ GList *l; -+ -+ for (l = monitor->volumes; l != NULL; l = l->next) -+ { -+ GGduVolume *volume = G_GDU_VOLUME (l->data); -+ -+ if (g_gdu_volume_has_device_file (volume, device_file)) -+ return volume; -+ } -+ -+ return NULL; -+} -+ -+static GGduDrive * -+find_drive_by_device_file (GGduVolumeMonitor *monitor, -+ const gchar *device_file) -+{ -+ GList *l; -+ -+ for (l = monitor->drives; l != NULL; l = l->next) -+ { -+ GGduDrive *drive = G_GDU_DRIVE (l->data); -+ -+ if (g_gdu_drive_has_device_file (drive, device_file)) -+ return drive; -+ } -+ -+ return NULL; -+} -+ -+static GGduDrive * -+find_drive_by_presentable (GGduVolumeMonitor *monitor, -+ GduPresentable *presentable) -+{ -+ GList *l; -+ -+ for (l = monitor->drives; l != NULL; l = l->next) -+ { -+ GGduDrive *drive = G_GDU_DRIVE (l->data); -+ -+ if (g_gdu_drive_has_presentable (drive, presentable)) -+ return drive; -+ } -+ -+ return NULL; -+} -+ -+static void -+update_drives (GGduVolumeMonitor *monitor, -+ GList **added_drives, -+ GList **removed_drives) -+{ -+ GList *cur_drives; -+ GList *new_drives; -+ GList *removed, *added; -+ GList *l, *ll; -+ GGduDrive *drive; -+ GList *fstab_mount_points; -+ -+ fstab_mount_points = g_unix_mount_points_get (NULL); -+ -+ cur_drives = NULL; -+ for (l = monitor->drives; l != NULL; l = l->next) -+ cur_drives = g_list_prepend (cur_drives, g_gdu_drive_get_presentable (G_GDU_DRIVE (l->data))); -+ -+ /* remove devices we want to ignore - we do it here so we get to reevaluate -+ * on the next update whether they should still be ignored -+ */ -+ new_drives = gdu_pool_get_presentables (monitor->pool); -+ for (l = new_drives; l != NULL; l = ll) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ ll = l->next; -+ if (!GDU_IS_DRIVE (p) || should_drive_be_ignored (monitor->pool, GDU_DRIVE (p), fstab_mount_points)) -+ { -+ g_object_unref (p); -+ new_drives = g_list_delete_link (new_drives, l); -+ } -+ } -+ -+ cur_drives = g_list_sort (cur_drives, (GCompareFunc) gdu_presentable_compare); -+ new_drives = g_list_sort (new_drives, (GCompareFunc) gdu_presentable_compare); -+ diff_sorted_lists (cur_drives, -+ new_drives, (GCompareFunc) gdu_presentable_compare, -+ &added, &removed); -+ -+ for (l = removed; l != NULL; l = l->next) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ GduDevice *d; -+ -+ d = gdu_presentable_get_device (p); -+ -+ drive = find_drive_by_presentable (monitor, p); -+ if (drive != NULL) -+ { -+ /*g_debug ("removing drive %s", gdu_presentable_get_id (p));*/ -+ g_gdu_drive_disconnected (drive); -+ monitor->drives = g_list_remove (monitor->drives, drive); -+ *removed_drives = g_list_prepend (*removed_drives, drive); -+ } -+ if (d != NULL) -+ g_object_unref (d); -+ } -+ -+ for (l = added; l != NULL; l = l->next) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ GduDevice *d; -+ -+ d = gdu_presentable_get_device (p); -+ -+ drive = find_drive_by_presentable (monitor, p); -+ if (drive == NULL) -+ { -+ /*g_debug ("adding drive %s", gdu_presentable_get_id (p));*/ -+ drive = g_gdu_drive_new (G_VOLUME_MONITOR (monitor), p); -+ if (drive != NULL) -+ { -+ monitor->drives = g_list_prepend (monitor->drives, drive); -+ *added_drives = g_list_prepend (*added_drives, g_object_ref (drive)); -+ } -+ } -+ if (d != NULL) -+ g_object_unref (d); -+ } -+ -+ g_list_free (added); -+ g_list_free (removed); -+ -+ g_list_free (cur_drives); -+ -+ g_list_foreach (new_drives, (GFunc) g_object_unref, NULL); -+ g_list_free (new_drives); -+ -+ g_list_foreach (fstab_mount_points, (GFunc) g_unix_mount_point_free, NULL); -+ g_list_free (fstab_mount_points); -+} -+ -+static void -+update_volumes (GGduVolumeMonitor *monitor, -+ GList **added_volumes, -+ GList **removed_volumes) -+{ -+ GList *cur_volumes; -+ GList *new_volumes; -+ GList *removed, *added; -+ GList *l, *ll; -+ GGduVolume *volume; -+ GGduDrive *drive; -+ GList *fstab_mount_points; -+ -+ fstab_mount_points = g_unix_mount_points_get (NULL); -+ -+ cur_volumes = NULL; -+ for (l = monitor->volumes; l != NULL; l = l->next) -+ cur_volumes = g_list_prepend (cur_volumes, g_gdu_volume_get_presentable (G_GDU_VOLUME (l->data))); -+ -+ /* remove devices we want to ignore - we do it here so we get to reevaluate -+ * on the next update whether they should still be ignored -+ */ -+ new_volumes = gdu_pool_get_presentables (monitor->pool); -+ for (l = new_volumes; l != NULL; l = ll) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ ll = l->next; -+ if (!GDU_IS_VOLUME (p) || should_volume_be_ignored (monitor->pool, GDU_VOLUME (p), fstab_mount_points)) -+ { -+ g_object_unref (p); -+ new_volumes = g_list_delete_link (new_volumes, l); -+ } -+ } -+ -+ cur_volumes = g_list_sort (cur_volumes, (GCompareFunc) gdu_presentable_compare); -+ new_volumes = g_list_sort (new_volumes, (GCompareFunc) gdu_presentable_compare); -+ diff_sorted_lists (cur_volumes, -+ new_volumes, (GCompareFunc) gdu_presentable_compare, -+ &added, &removed); -+ -+ for (l = removed; l != NULL; l = l->next) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ GduDevice *d; -+ -+ d = gdu_presentable_get_device (p); -+ -+ volume = find_volume_for_device_file (monitor, gdu_device_get_device_file (d)); -+ if (volume != NULL) -+ { -+ /*g_debug ("removing volume %s", gdu_device_get_device_file (d));*/ -+ g_gdu_volume_removed (volume); -+ monitor->volumes = g_list_remove (monitor->volumes, volume); -+ *removed_volumes = g_list_prepend (*removed_volumes, volume); -+ } -+ g_object_unref (d); -+ } -+ -+ for (l = added; l != NULL; l = l->next) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ GduDevice *d; -+ -+ d = gdu_presentable_get_device (p); -+ -+ volume = find_volume_for_device_file (monitor, gdu_device_get_device_file (d)); -+ if (volume == NULL) -+ { -+ GduPresentable *toplevel_presentable; -+ -+ toplevel_presentable = gdu_presentable_get_toplevel (p); -+ if (toplevel_presentable != NULL) -+ { -+ GduDevice *toplevel_device; -+ -+ toplevel_device = gdu_presentable_get_device (toplevel_presentable); -+ drive = find_drive_by_device_file (monitor, gdu_device_get_device_file (toplevel_device)); -+ /*g_debug ("adding volume %s (drive %s)", -+ gdu_device_get_device_file (d), -+ gdu_device_get_device_file (toplevel_device));*/ -+ g_object_unref (toplevel_device); -+ g_object_unref (toplevel_presentable); -+ } -+ else -+ { -+ drive = NULL; -+ /*g_debug ("adding volume %s (no drive)", gdu_device_get_device_file (d));*/ -+ } -+ -+ volume = g_gdu_volume_new (G_VOLUME_MONITOR (monitor), -+ GDU_VOLUME (p), -+ drive, -+ NULL); -+ if (volume != NULL) -+ { -+ monitor->volumes = g_list_prepend (monitor->volumes, volume); -+ *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume)); -+ } -+ } -+ -+ g_object_unref (d); -+ } -+ -+ g_list_free (added); -+ g_list_free (removed); -+ -+ g_list_foreach (new_volumes, (GFunc) g_object_unref, NULL); -+ g_list_free (new_volumes); -+ -+ g_list_free (cur_volumes); -+ -+ g_list_foreach (fstab_mount_points, (GFunc) g_unix_mount_point_free, NULL); -+ g_list_free (fstab_mount_points); -+} -+ -+static void -+update_mounts (GGduVolumeMonitor *monitor, -+ GList **added_mounts, -+ GList **removed_mounts) -+{ -+ GList *new_mounts; -+ GList *removed, *added; -+ GList *l, *ll; -+ GGduMount *mount; -+ GGduVolume *volume; -+ const char *device_file; -+ const char *mount_path; -+ -+ new_mounts = g_unix_mounts_get (NULL); -+ -+ /* remove mounts we want to ignore - we do it here so we get to reevaluate -+ * on the next update whether they should still be ignored -+ */ -+ for (l = new_mounts; l != NULL; l = ll) -+ { -+ GUnixMountEntry *mount_entry = l->data; -+ ll = l->next; -+ -+ /* keep in sync with should_mount_be_ignored() */ -+ if (!g_unix_mount_guess_should_display (mount_entry)) -+ { -+ g_unix_mount_free (mount_entry); -+ new_mounts = g_list_delete_link (new_mounts, l); -+ } -+ } -+ -+ new_mounts = g_list_sort (new_mounts, (GCompareFunc) g_unix_mount_compare); -+ -+ diff_sorted_lists (monitor->last_mounts, -+ new_mounts, (GCompareFunc) g_unix_mount_compare, -+ &added, &removed); -+ -+ for (l = removed; l != NULL; l = l->next) -+ { -+ GUnixMountEntry *mount_entry = l->data; -+ -+ mount = find_mount_by_mount_path (monitor, g_unix_mount_get_mount_path (mount_entry)); -+ if (mount) -+ { -+ /*g_debug ("removing mount %s", g_unix_mount_get_device_path (mount_entry));*/ -+ g_gdu_mount_unmounted (mount); -+ monitor->mounts = g_list_remove (monitor->mounts, mount); -+ -+ *removed_mounts = g_list_prepend (*removed_mounts, mount); -+ } -+ } -+ -+ for (l = added; l != NULL; l = l->next) -+ { -+ GUnixMountEntry *mount_entry = l->data; -+ -+ device_file = g_unix_mount_get_device_path (mount_entry); -+ mount_path = g_unix_mount_get_mount_path (mount_entry); -+ volume = find_volume_for_device_file (monitor, device_file); -+ if (volume == NULL) -+ volume = find_volume_for_mount_path (monitor, mount_path); -+ -+ /*g_debug ("adding mount %s (vol %p)", g_unix_mount_get_device_path (mount_entry), volume);*/ -+ mount = g_gdu_mount_new (G_VOLUME_MONITOR (monitor), mount_entry, volume); -+ if (mount) -+ { -+ monitor->mounts = g_list_prepend (monitor->mounts, mount); -+ *added_mounts = g_list_prepend (*added_mounts, g_object_ref (mount)); -+ } -+ } -+ -+ g_list_free (added); -+ g_list_free (removed); -+ g_list_foreach (monitor->last_mounts, -+ (GFunc)g_unix_mount_free, NULL); -+ g_list_free (monitor->last_mounts); -+ monitor->last_mounts = new_mounts; -+} -+ -+static void -+update_discs (GGduVolumeMonitor *monitor, -+ GList **added_volumes, -+ GList **removed_volumes, -+ GList **added_mounts, -+ GList **removed_mounts) -+{ -+ GList *cur_discs; -+ GList *new_discs; -+ GList *removed, *added; -+ GList *l, *ll; -+ GGduDrive *drive; -+ GGduVolume *volume; -+ GGduMount *mount; -+ -+ /* we also need to generate GVolume + GMount objects for -+ * -+ * - optical discs that have audio -+ * - optical discs that are blank -+ * -+ */ -+ -+ cur_discs = NULL; -+ for (l = monitor->disc_volumes; l != NULL; l = l->next) -+ cur_discs = g_list_prepend (cur_discs, g_gdu_volume_get_presentable (G_GDU_VOLUME (l->data))); -+ -+ new_discs = gdu_pool_get_presentables (monitor->pool); -+ for (l = new_discs; l != NULL; l = ll) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ GduDevice *d; -+ gboolean ignore; -+ -+ ll = l->next; -+ ignore = TRUE; -+ -+ /* filter out everything but discs that are blank or has audio */ -+ d = gdu_presentable_get_device (p); -+ if (GDU_IS_VOLUME (p) && d != NULL && gdu_device_is_optical_disc (d)) -+ { -+ if (gdu_device_optical_disc_get_num_audio_tracks (d) > 0 || gdu_device_optical_disc_get_is_blank (d)) -+ ignore = FALSE; -+ } -+ -+ if (ignore) -+ { -+ g_object_unref (p); -+ new_discs = g_list_delete_link (new_discs, l); -+ } -+ -+ if (d != NULL) -+ g_object_unref (d); -+ } -+ -+ cur_discs = g_list_sort (cur_discs, (GCompareFunc) gdu_presentable_compare); -+ new_discs = g_list_sort (new_discs, (GCompareFunc) gdu_presentable_compare); -+ diff_sorted_lists (cur_discs, new_discs, (GCompareFunc) gdu_presentable_compare, &added, &removed); -+ -+ for (l = removed; l != NULL; l = l->next) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ GduDevice *d; -+ -+ d = gdu_presentable_get_device (p); -+ -+ volume = find_disc_volume_for_device_file (monitor, gdu_device_get_device_file (d)); -+ mount = find_disc_mount_for_volume (monitor, volume); -+ -+ if (mount != NULL) -+ { -+ /*g_debug ("removing disc mount %s", gdu_device_get_device_file (d));*/ -+ g_gdu_mount_unmounted (mount); -+ monitor->disc_mounts = g_list_remove (monitor->disc_mounts, mount); -+ *removed_mounts = g_list_prepend (*removed_mounts, mount); -+ } -+ -+ if (volume != NULL) -+ { -+ /*g_debug ("removing disc volume %s", gdu_device_get_device_file (d));*/ -+ g_gdu_volume_removed (volume); -+ monitor->disc_volumes = g_list_remove (monitor->disc_volumes, volume); -+ *removed_volumes = g_list_prepend (*removed_volumes, volume); -+ } -+ -+ g_object_unref (d); -+ } -+ -+ for (l = added; l != NULL; l = l->next) -+ { -+ GduPresentable *p = GDU_PRESENTABLE (l->data); -+ GduDevice *d; -+ gboolean is_blank; -+ -+ d = gdu_presentable_get_device (p); -+ -+ is_blank = gdu_device_optical_disc_get_is_blank (d); -+ -+ volume = find_disc_volume_for_device_file (monitor, gdu_device_get_device_file (d)); -+ if (volume == NULL) -+ { -+ GduPresentable *toplevel_presentable; -+ -+ toplevel_presentable = gdu_presentable_get_toplevel (p); -+ if (toplevel_presentable != NULL) -+ { -+ GduDevice *toplevel_device; -+ -+ toplevel_device = gdu_presentable_get_device (toplevel_presentable); -+ drive = find_drive_by_device_file (monitor, gdu_device_get_device_file (toplevel_device)); -+ /*g_debug ("adding volume %s (drive %s)", -+ gdu_device_get_device_file (d), -+ gdu_device_get_device_file (toplevel_device));*/ -+ g_object_unref (toplevel_device); -+ g_object_unref (toplevel_presentable); -+ } -+ else -+ { -+ drive = NULL; -+ /*g_debug ("adding volume %s (no drive)", gdu_device_get_device_file (d));*/ -+ } -+ -+ mount = NULL; -+ if (is_blank) -+ { -+ volume = g_gdu_volume_new (G_VOLUME_MONITOR (monitor), -+ GDU_VOLUME (p), -+ drive, -+ NULL); -+ mount = g_gdu_mount_new (G_VOLUME_MONITOR (monitor), -+ NULL, -+ volume); -+ } -+ else -+ { -+ gchar *uri; -+ gchar *device_basename; -+ GFile *activation_root; -+ -+ /* the gvfsd-cdda backend uses URI's like these */ -+ device_basename = g_path_get_basename (gdu_device_get_device_file (d)); -+ uri = g_strdup_printf ("cdda://%s", device_basename); -+ activation_root = g_file_new_for_uri (uri); -+ g_free (device_basename); -+ g_free (uri); -+ -+ volume = g_gdu_volume_new (G_VOLUME_MONITOR (monitor), -+ GDU_VOLUME (p), -+ drive, -+ activation_root); -+ -+ g_object_unref (activation_root); -+ } -+ -+ if (volume != NULL) -+ { -+ monitor->disc_volumes = g_list_prepend (monitor->disc_volumes, volume); -+ *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume)); -+ -+ if (mount != NULL) -+ { -+ monitor->disc_mounts = g_list_prepend (monitor->disc_mounts, mount); -+ *added_mounts = g_list_prepend (*added_mounts, g_object_ref (mount)); -+ } -+ } -+ } -+ -+ g_object_unref (d); -+ } -+ -+ g_list_free (added); -+ g_list_free (removed); -+ -+ g_list_foreach (new_discs, (GFunc) g_object_unref, NULL); -+ g_list_free (new_discs); -+ -+ g_list_free (cur_discs); -+} ---- /dev/null 2009-03-04 16:07:30.099029290 -0500 -+++ monitor/gdu/ggduvolumemonitor.h 2009-03-01 23:49:48.000000000 -0500 -@@ -0,0 +1,60 @@ -+/* -*- 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#ifndef __G_GDU_VOLUME_MONITOR_H__ -+#define __G_GDU_VOLUME_MONITOR_H__ -+ -+#include -+#include -+#include -+ -+#include -+ -+G_BEGIN_DECLS -+ -+#define G_TYPE_GDU_VOLUME_MONITOR (g_gdu_volume_monitor_get_type ()) -+#define G_GDU_VOLUME_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_GDU_VOLUME_MONITOR, GGduVolumeMonitor)) -+#define G_GDU_VOLUME_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_GDU_VOLUME_MONITOR, GGduVolumeMonitorClass)) -+#define G_IS_GDU_VOLUME_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_GDU_VOLUME_MONITOR)) -+#define G_IS_GDU_VOLUME_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_GDU_VOLUME_MONITOR)) -+ -+typedef struct _GGduVolumeMonitor GGduVolumeMonitor; -+typedef struct _GGduVolumeMonitorClass GGduVolumeMonitorClass; -+ -+/* Forward definitions */ -+typedef struct _GGduDrive GGduDrive; -+typedef struct _GGduVolume GGduVolume; -+typedef struct _GGduMount GGduMount; -+ -+struct _GGduVolumeMonitorClass { -+ GNativeVolumeMonitorClass parent_class; -+ -+}; -+ -+GType g_gdu_volume_monitor_get_type (void) G_GNUC_CONST; -+ -+GVolumeMonitor *g_gdu_volume_monitor_new (void); -+ -+G_END_DECLS -+ -+#endif /* __G_GDU_VOLUME_MONITOR_H__ */ ---- /dev/null 2009-03-04 16:07:30.099029290 -0500 -+++ monitor/gdu/polkit.c 2009-03-01 23:47:50.000000000 -0500 -@@ -0,0 +1,137 @@ -+/* -*- 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+#include -+#include -+ -+#include -+ -+#include "polkit.h" -+ -+static void -+_obtain_authz_cb (DBusMessage *reply, -+ GError *error, -+ gpointer user_data) -+{ -+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data); -+ gboolean gained_authz; -+ DBusError derror; -+ -+ if (error != NULL) { -+ g_simple_async_result_set_from_error (simple, error); -+ goto out; -+ } -+ -+ dbus_error_init (&derror); -+ if (!dbus_message_get_args (reply, -+ &derror, -+ DBUS_TYPE_BOOLEAN, &gained_authz, -+ DBUS_TYPE_INVALID)) -+ { -+ /* no need to translate; this only happens if the auth agent is buggy */ -+ g_simple_async_result_set_error (simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED, -+ "Error parsing reply for ObtainAuthorization(): %s: %s", -+ derror.name, derror.message); -+ dbus_error_free (&derror); -+ goto out; -+ } -+ -+ if (!gained_authz && error == NULL) -+ { -+ /* no need to translate, is never shown */ -+ g_simple_async_result_set_error (simple, -+ G_IO_ERROR, -+ G_IO_ERROR_FAILED_HANDLED, -+ "Didn't obtain authorization (bug in libgio user, it shouldn't display this error)"); -+ } -+ -+ out: -+ g_simple_async_result_complete (simple); -+ g_object_unref (simple); -+} -+ -+ -+gboolean -+_obtain_authz_finish (GAsyncResult *res, -+ GError **error) -+{ -+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res); -+ -+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == _obtain_authz); -+ -+ if (g_simple_async_result_propagate_error (simple, error)) -+ return FALSE; -+ else -+ return TRUE; -+} -+ -+void -+_obtain_authz (const gchar *action_id, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ DBusConnection *connection; -+ DBusMessage *message; -+ GSimpleAsyncResult *simple; -+ guint xid; -+ guint pid; -+ DBusError derror; -+ -+ dbus_error_init (&derror); -+ -+ /* this connection is already integrated and guaranteed to exist, see gvfsproxyvolumemonitordaemon.c */ -+ connection = dbus_bus_get (DBUS_BUS_SESSION, &derror); -+ -+ simple = g_simple_async_result_new (NULL, -+ callback, -+ user_data, -+ _obtain_authz); -+ -+ message = dbus_message_new_method_call ("org.freedesktop.PolicyKit.AuthenticationAgent", /* bus name */ -+ "/", /* object */ -+ "org.freedesktop.PolicyKit.AuthenticationAgent", /* interface */ -+ "ObtainAuthorization"); -+ -+ xid = 0; -+ pid = getpid (); -+ -+ dbus_message_append_args (message, -+ DBUS_TYPE_STRING, -+ &(action_id), -+ DBUS_TYPE_UINT32, -+ &(xid), -+ DBUS_TYPE_UINT32, -+ &(pid), -+ DBUS_TYPE_INVALID); -+ -+ _g_dbus_connection_call_async (connection, -+ message, -+ -1, -+ (GAsyncDBusCallback) _obtain_authz_cb, -+ simple); -+ dbus_message_unref (message); -+ dbus_connection_unref (connection); -+} ---- /dev/null 2009-03-04 16:07:30.099029290 -0500 -+++ monitor/gdu/polkit.h 2009-03-01 23:47:41.000000000 -0500 -@@ -0,0 +1,44 @@ -+/* -*- 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., 59 Temple Place, Suite 330, -+ * Boston, MA 02111-1307, USA. -+ * -+ * Author: David Zeuthen -+ */ -+ -+ -+#ifndef __POLKIT_H__ -+#define __POLKIT_H__ -+ -+#include -+#include -+#include -+ -+G_BEGIN_DECLS -+ -+void _obtain_authz (const gchar *action_id, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data); -+ -+gboolean _obtain_authz_finish (GAsyncResult *res, -+ GError **error); -+ -+G_END_DECLS -+ -+#endif /* __POLKIT_H__ */ ---- /dev/null 2009-03-04 16:07:30.099029290 -0500 -+++ monitor/gdu/Makefile.am 2009-03-01 21:13:46.000000000 -0500 -@@ -0,0 +1,53 @@ -+ -+NULL = -+ -+libexec_PROGRAMS = gvfs-gdu-volume-monitor -+ -+ -+gvfs_gdu_volume_monitor_SOURCES = \ -+ gdu-volume-monitor-daemon.c \ -+ ggdudrive.c ggdudrive.h \ -+ ggduvolume.c ggduvolume.h \ -+ ggdumount.c ggdumount.h \ -+ ggduvolumemonitor.c ggduvolumemonitor.h \ -+ polkit.c polkit.h \ -+ $(NULL) -+ -+gvfs_gdu_volume_monitor_CFLAGS = \ -+ -DG_LOG_DOMAIN=\"GVFS-Gdu\" \ -+ -I$(top_srcdir)/common \ -+ -I$(top_srcdir)/monitor/proxy \ -+ $(GLIB_CFLAGS) \ -+ $(GDU_CFLAGS) \ -+ $(DBUS_CFLAGS) \ -+ -DGIO_MODULE_DIR=\"$(GIO_MODULE_DIR)\" \ -+ -DGVFS_LOCALEDIR=\""$(localedir)"\" \ -+ -DG_DISABLE_DEPRECATED \ -+ -DGDU_API_IS_SUBJECT_TO_CHANGE \ -+ $(NULL) -+ -+gvfs_gdu_volume_monitor_LDFLAGS = \ -+ $(NULL) -+ -+gvfs_gdu_volume_monitor_LDADD = \ -+ $(GLIB_LIBS) \ -+ $(GDU_LIBS) \ -+ $(DBUS_LIBS) \ -+ $(top_builddir)/common/libgvfscommon.la \ -+ $(top_builddir)/monitor/proxy/libgvfsproxyvolumemonitordaemon-noin.la \ -+ $(NULL) -+ -+remote_volume_monitorsdir = $(datadir)/gvfs/remote-volume-monitors -+remote_volume_monitors_DATA = gdu.monitor -+ -+servicedir = $(datadir)/dbus-1/services -+service_in_files = org.gtk.Private.GduVolumeMonitor.service.in -+service_DATA = $(service_in_files:.service.in=.service) -+ -+$(service_DATA): $(service_in_files) Makefile -+ @sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ -+ -+clean-local: -+ rm -f *~ *.loT $(BUILT_SOURCES) $(service_DATA) -+ -+EXTRA_DIST = $(service_in_files) gdu.monitor ---- /dev/null 2009-03-04 16:07:30.099029290 -0500 -+++ monitor/gdu/gdu.monitor 2009-02-11 06:42:26.000000000 -0500 -@@ -0,0 +1,5 @@ -+[RemoteVolumeMonitor] -+Name=GProxyVolumeMonitorGdu -+DBusName=org.gtk.Private.GduVolumeMonitor -+IsNative=true -+NativePriority=3 ---- /dev/null 2009-03-04 16:07:30.099029290 -0500 -+++ monitor/gdu/org.gtk.Private.GduVolumeMonitor.service.in 2009-02-19 22:34:26.000000000 -0500 -@@ -0,0 +1,3 @@ -+[D-BUS Service] -+Name=org.gtk.Private.GduVolumeMonitor -+Exec=@libexecdir@/gvfs-gdu-volume-monitor diff --git a/gvfs.spec b/gvfs.spec index 0915f9d..194ca5e 100644 --- a/gvfs.spec +++ b/gvfs.spec @@ -1,7 +1,7 @@ Summary: Backends for the gio framework in GLib Name: gvfs Version: 1.2.1 -Release: 2%{?dist} +Release: 3%{?dist} License: LGPLv2+ Group: System Environment/Libraries URL: http://www.gtk.org @@ -19,7 +19,7 @@ BuildRequires: gnome-keyring-devel BuildRequires: intltool BuildRequires: gettext-devel BuildRequires: GConf2-devel -BuildRequires: gnome-disk-utility-devel >= 0.2 +BuildRequires: gnome-disk-utility-devel >= 0.3 Requires(post): desktop-file-utils @@ -30,18 +30,25 @@ BuildRequires: automake autoconf BuildRequires: libtool # http://bugzilla.gnome.org/show_bug.cgi?id=567235 Patch1: gvfs-0.99.2-archive-integration.patch - # http://bugzilla.gnome.org/show_bug.cgi?id=573826 -Patch2: gvfs-gdu-volume-monitor-3.patch +Patch2: gvfs-1.1.7-gdu-computer-expose-devices.patch +# Gdu volume monitor patches, from http://cgit.freedesktop.org/~david/gvfs/log/?h=gdu-volume-monitor +# # http://bugzilla.gnome.org/show_bug.cgi?id=573826 -Patch3: gvfs-1.1.7-gdu-monitor-empty-drives.patch - +Patch101: gdu-0001-Bug-573826-gdu-volume-monitor.patch # http://bugzilla.gnome.org/show_bug.cgi?id=573826 -Patch4: gvfs-1.1.7-gdu-computer-expose-devices.patch - +Patch102: gdu-0002-Fix-how-we-determine-if-a-volume-is-ignored.patch # https://bugzilla.redhat.com/show_bug.cgi?id=494144 -Patch5: gvfs-1.2.1-only-mount-the-metal.patch +Patch103: gdu-0003-Avoid-automounting-volumes-on-virtual-and-unknown-bu.patch +Patch104: gdu-0004-Remove-debug-spew.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=495033 +Patch105: gdu-0005-Don-t-add-a-volume-if-the-device-is-mounted-and-igno.patch +Patch106: gdu-0006-Ignore-drives-if-all-volumes-of-the-drive-are-ignore.patch + +# http://bugzilla.gnome.org/show_bug.cgi?id=576587 +# - Pending discussion + requires Nautilus patch +#Patch107: gdu-0007-Bug-576587-allow-eject-even-on-non-ejectable-vol.patch %description The gvfs package provides backend implementations for the gio @@ -124,10 +131,15 @@ media players (Media Transfer Protocol) to applications using gvfs. %prep %setup -q %patch1 -p0 -b .archive-integration -%patch2 -p0 -b .gdu -%patch3 -p1 -b .gdu-volumes-typo -%patch4 -p1 -b .computer-gdu -%patch5 -p1 -b .metal +%patch2 -p1 -b .computer-expose-devices + +%patch101 -p1 -b .gdu-volume-monitor +%patch102 -p1 -b .gdu-volumes-typo +%patch103 -p1 -b .gdu-avoid-automount +%patch104 -p1 -b .gdu-debug-spew +%patch105 -p1 -b .gdu-ignore-1 +%patch106 -p1 -b .gdu-ignore-2 +#%patch107 -p1 -b .gdu-always-eject %build @@ -271,6 +283,10 @@ update-desktop-database &> /dev/null ||: %changelog +* Thu Apr 9 2009 David Zeuthen - 1.2.1-3 +- Clean up gdu patches and bump BR for gdu to 0.3 +- Avoiding showing volume for ignored mounts (#495033) + * Thu Apr 9 2009 David Zeuthen - 1.2.1-2 - Avoid automounting device-mapper devices and similar (#494144)