summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog76
-rw-r--r--client/gdaemonfile.c2
-rw-r--r--client/gdaemonmount.c115
-rw-r--r--client/gdaemonmount.h5
-rw-r--r--client/gdaemonvolumemonitor.c14
-rw-r--r--client/gvfsfusedaemon.c11
-rw-r--r--common/gmounttracker.c8
-rw-r--r--common/gmounttracker.h1
-rw-r--r--configure.ac23
-rw-r--r--daemon/Makefile.am20
-rw-r--r--daemon/gvfsbackend.c38
-rw-r--r--daemon/gvfsbackend.h3
-rw-r--r--daemon/gvfsjobunmount.c15
-rw-r--r--daemon/mount.c18
-rw-r--r--hal/ghaldrive.c180
-rw-r--r--hal/ghalmount.c97
-rw-r--r--hal/ghalvolume.c236
-rw-r--r--hal/ghalvolume.h7
-rw-r--r--hal/ghalvolumemonitor.c109
-rw-r--r--hal/hal-device.c22
-rw-r--r--hal/hal-device.h1
-rw-r--r--hal/hal-marshal.list2
-rw-r--r--hal/hal-pool.c36
-rw-r--r--hal/hal-pool.h1
-rw-r--r--programs/Makefile.am4
-rw-r--r--programs/gvfs-mount.c51
26 files changed, 929 insertions, 166 deletions
diff --git a/ChangeLog b/ChangeLog
index f415ac1d..800a1cd7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,79 @@
+2007-12-19 David Zeuthen <davidz@redhat.com>
+
+ Add the cdda:// backend for Compact Disc Digital Audio discs.
+
+ Allow a backend to specify the fuse name directly instead of
+ using the display name
+
+ Make GDaemonVolumeMonitor and GDaemonMount use the new
+ adopt_orphan_mount() function on GVolumeMonitor in gio. Also,
+ since a GMount now can be associated with a GVolume, implement
+ eject().
+
+ Add a new gvfs-less program.
+
+ Make gvfs-mount capable of unmounting as well.
+
+ HAL backend changes: attempt to unmount all mounts from
+ enclosing volumes and fail the ejection if one of the unmount
+ operations fails. Use new adopt_orphan_mount() from gio to
+ adopt cdda:// volumes for audio discs. Emit the 'eject-button'
+ signal on GDrive. Various other fixes.
+
+ * client/gdaemonfile.c: (g_daemon_file_find_enclosing_mount):
+ * client/gdaemonmount.c: (g_daemon_mount_finalize),
+ (g_daemon_mount_new), (g_daemon_mount_get_volume),
+ (g_daemon_mount_get_drive), (g_daemon_mount_can_eject),
+ (foreign_volume_removed), (g_daemon_mount_set_foreign_volume),
+ (eject_wrapper_callback), (g_daemon_mount_eject),
+ (g_daemon_mount_eject_finish), (g_daemon_mount_mount_iface_init):
+ * client/gdaemonmount.h:
+ * client/gdaemonvolumemonitor.c: (mount_added), (mount_removed),
+ (g_daemon_volume_monitor_init):
+ * client/gvfsfusedaemon.c: (file_handle_close_stream),
+ (free_file_handle_for_path), (mount_record_new):
+ * common/gmounttracker.c: (g_mount_info_dup), (g_mount_info_unref),
+ (g_mount_info_from_dbus):
+ * common/gmounttracker.h:
+ * configure.ac:
+ * daemon/Makefile.am:
+ * daemon/gvfsbackend.c: (g_vfs_backend_finalize),
+ (g_vfs_backend_init), (g_vfs_backend_set_fuse_name),
+ (g_vfs_backend_get_fuse_name), (g_vfs_backend_register_mount):
+ * daemon/gvfsbackend.h:
+ * daemon/gvfsjobunmount.c: (unregister_mount_callback),
+ (send_reply):
+ * daemon/mount.c: (vfs_mount_free), (vfs_mount_to_dbus),
+ (register_mount), (list_mounts):
+ * hal/ghaldrive.c: (g_hal_drive_finalize), (hal_condition),
+ (g_hal_drive_new), (spawn_cb), (g_hal_drive_eject_do),
+ (free_unmount_mounts_op), (_eject_unmount_mounts_cb),
+ (_eject_unmount_mounts), (g_hal_drive_eject):
+ * hal/ghalmount.c: (g_hal_mount_finalize), (unmount_cb),
+ (unmount_read_error), (unmount_do), (g_hal_mount_unmount),
+ (eject_wrapper_callback), (g_hal_mount_eject),
+ (g_hal_mount_eject_finish):
+ * hal/ghalvolume.c: (g_hal_volume_finalize), (do_update_from_hal),
+ (g_hal_volume_new), (g_hal_volume_get_mount),
+ (foreign_mount_unmounted), (g_hal_volume_adopt_foreign_mount),
+ (g_hal_volume_has_foreign_mount_root), (spawn_cb),
+ (mount_foreign_callback), (g_hal_volume_mount),
+ (g_hal_volume_mount_finish), (eject_wrapper_callback),
+ (g_hal_volume_eject), (g_hal_volume_eject_finish):
+ * hal/ghalvolume.h:
+ * hal/ghalvolumemonitor.c: (adopt_orphan_mount),
+ (g_hal_volume_monitor_class_init), (update_volumes),
+ (update_mounts), (update_discs):
+ * hal/hal-device.c: (hal_device_class_init),
+ (_hal_device_hal_condition):
+ * hal/hal-device.h:
+ * hal/hal-marshal.list:
+ * hal/hal-pool.c: (hal_pool_class_init), (_hal_condition),
+ (hal_pool_new):
+ * hal/hal-pool.h:
+ * programs/Makefile.am:
+ * programs/gvfs-mount.c: (unmount_done_cb), (unmount), (main):
+
2007-12-18 Luca Ferretti <elle.uca@libero.it>
* configure.ac: Add ALL_LINGUAS and definition for GVFS_LOCALEDIR;
diff --git a/client/gdaemonfile.c b/client/gdaemonfile.c
index 251ce419..18a58c14 100644
--- a/client/gdaemonfile.c
+++ b/client/gdaemonfile.c
@@ -1439,7 +1439,7 @@ g_daemon_file_find_enclosing_mount (GFile *file,
if (mount_info->user_visible)
{
- mount = g_daemon_mount_new (mount_info);
+ mount = g_daemon_mount_new (mount_info, NULL);
g_mount_info_unref (mount_info);
if (mount)
diff --git a/client/gdaemonmount.c b/client/gdaemonmount.c
index be5d5136..9e803384 100644
--- a/client/gdaemonmount.c
+++ b/client/gdaemonmount.c
@@ -37,6 +37,9 @@ struct _GDaemonMount {
GObject parent;
GMountInfo *mount_info;
+
+ GVolume *foreign_volume;
+ GVolumeMonitor *volume_monitor;
};
static void g_daemon_mount_mount_iface_init (GMountIface *iface);
@@ -45,7 +48,6 @@ G_DEFINE_TYPE_WITH_CODE (GDaemonMount, g_daemon_mount, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_MOUNT,
g_daemon_mount_mount_iface_init))
-
static void
g_daemon_mount_finalize (GObject *object)
{
@@ -53,6 +55,12 @@ g_daemon_mount_finalize (GObject *object)
mount = G_DAEMON_MOUNT (object);
+ if (mount->foreign_volume != NULL)
+ g_object_unref (mount->foreign_volume);
+
+ if (mount->volume_monitor != NULL)
+ g_object_remove_weak_pointer (G_OBJECT (mount->volume_monitor), (gpointer) &(mount->volume_monitor));
+
g_mount_info_unref (mount->mount_info);
if (G_OBJECT_CLASS (g_daemon_mount_parent_class)->finalize)
@@ -73,12 +81,17 @@ g_daemon_mount_init (GDaemonMount *daemon_mount)
}
GDaemonMount *
-g_daemon_mount_new (GMountInfo *mount_info)
+g_daemon_mount_new (GMountInfo *mount_info,
+ GVolumeMonitor *volume_monitor)
{
GDaemonMount *mount;
mount = g_object_new (G_TYPE_DAEMON_MOUNT, NULL);
mount->mount_info = g_mount_info_ref (mount_info);
+ mount->volume_monitor = volume_monitor;
+ g_object_set_data (G_OBJECT (mount), "g-stable-name", (gpointer) mount_info->stable_name);
+ if (mount->volume_monitor != NULL)
+ g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(mount->volume_monitor));
return mount;
}
@@ -122,12 +135,18 @@ g_daemon_mount_get_uuid (GMount *mount)
static GVolume *
g_daemon_mount_get_volume (GMount *mount)
{
+ GDaemonMount *daemon_mount = G_DAEMON_MOUNT (mount);
+ if (daemon_mount->foreign_volume != NULL)
+ return g_object_ref (daemon_mount->foreign_volume);
return NULL;
}
static GDrive *
g_daemon_mount_get_drive (GMount *mount)
{
+ GDaemonMount *daemon_mount = G_DAEMON_MOUNT (mount);
+ if (daemon_mount->foreign_volume != NULL)
+ return g_volume_get_drive (daemon_mount->foreign_volume);
return NULL;
}
@@ -140,10 +159,41 @@ g_daemon_mount_can_unmount (GMount *mount)
static gboolean
g_daemon_mount_can_eject (GMount *mount)
{
+ GDaemonMount *daemon_mount = G_DAEMON_MOUNT (mount);
+ if (daemon_mount->foreign_volume != NULL)
+ return g_volume_can_eject (daemon_mount->foreign_volume);
return FALSE;
}
static void
+foreign_volume_removed (GVolume *volume, gpointer user_data)
+{
+ GDaemonMount *daemon_mount = G_DAEMON_MOUNT (user_data);
+ if (daemon_mount->foreign_volume == volume)
+ g_daemon_mount_set_foreign_volume (daemon_mount, NULL);
+}
+
+void
+g_daemon_mount_set_foreign_volume (GDaemonMount *mount,
+ GVolume *foreign_volume)
+{
+ if (mount->foreign_volume != NULL)
+ g_object_unref (mount->foreign_volume);
+
+ if (foreign_volume != NULL)
+ {
+ mount->foreign_volume = foreign_volume;
+ g_signal_connect_object (foreign_volume, "removed", (GCallback) foreign_volume_removed, mount, 0);
+ }
+ else
+ mount->foreign_volume = NULL;
+
+ g_signal_emit_by_name (mount, "changed");
+ if (mount->volume_monitor != NULL)
+ g_signal_emit_by_name (mount->volume_monitor, "mount_changed", mount);
+}
+
+static void
unmount_reply (DBusMessage *reply,
DBusConnection *connection,
GError *io_error,
@@ -196,6 +246,63 @@ g_daemon_mount_unmount_finish (GMount *mount,
return TRUE;
}
+typedef struct {
+ GObject *object;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} EjectWrapperOp;
+
+static void
+eject_wrapper_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ EjectWrapperOp *data = user_data;
+ data->callback (data->object, res, data->user_data);
+ g_free (data);
+}
+
+static void
+g_daemon_mount_eject (GMount *mount,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GDaemonMount *daemon_mount = G_DAEMON_MOUNT (mount);
+ GDrive *drive;
+
+ if (daemon_mount->foreign_volume != NULL)
+ {
+ drive = g_volume_get_drive (G_VOLUME (daemon_mount->foreign_volume));
+ if (drive != NULL)
+ {
+ EjectWrapperOp *data;
+ data = g_new0 (EjectWrapperOp, 1);
+ data->object = G_OBJECT (mount);
+ data->callback = callback;
+ data->user_data = user_data;
+ g_drive_eject (drive, cancellable, eject_wrapper_callback, data);
+ }
+ }
+}
+
+static gboolean
+g_daemon_mount_eject_finish (GMount *mount,
+ GAsyncResult *result,
+ GError **error)
+{
+ GDaemonMount *daemon_mount = G_DAEMON_MOUNT (mount);
+ GDrive *drive;
+
+ if (daemon_mount->foreign_volume != NULL)
+ {
+ drive = g_volume_get_drive (G_VOLUME (daemon_mount->foreign_volume));
+ if (drive != NULL)
+ return g_drive_eject_finish (drive, result, error);
+ }
+ return TRUE;
+}
+
static void
g_daemon_mount_mount_iface_init (GMountIface *iface)
{
@@ -209,6 +316,6 @@ g_daemon_mount_mount_iface_init (GMountIface *iface)
iface->can_eject = g_daemon_mount_can_eject;
iface->unmount = g_daemon_mount_unmount;
iface->unmount_finish = g_daemon_mount_unmount_finish;
- iface->eject = NULL; /* Not supported */
- iface->eject_finish = NULL; /* Not supported */
+ iface->eject = g_daemon_mount_eject;
+ iface->eject_finish = g_daemon_mount_eject_finish;
}
diff --git a/client/gdaemonmount.h b/client/gdaemonmount.h
index e44421cc..bf4ba099 100644
--- a/client/gdaemonmount.h
+++ b/client/gdaemonmount.h
@@ -45,10 +45,13 @@ struct _GDaemonMountClass {
GType g_daemon_mount_get_type (void) G_GNUC_CONST;
-GDaemonMount *g_daemon_mount_new (GMountInfo *mount_info);
+GDaemonMount *g_daemon_mount_new (GMountInfo *mount_info,
+ GVolumeMonitor *volume_monitor);
GMountInfo *g_daemon_mount_get_mount_info (GDaemonMount *mount);
+void g_daemon_mount_set_foreign_volume (GDaemonMount *mount, GVolume *foreign_volume);
+
G_END_DECLS
#endif /* __G_DAEMON_MOUNT_H__ */
diff --git a/client/gdaemonvolumemonitor.c b/client/gdaemonvolumemonitor.c
index 0d3bc8a6..77effae2 100644
--- a/client/gdaemonvolumemonitor.c
+++ b/client/gdaemonvolumemonitor.c
@@ -106,6 +106,7 @@ static void
mount_added (GDaemonVolumeMonitor *daemon_monitor, GMountInfo *mount_info)
{
GDaemonMount *mount;
+ GVolume *volume;
mount = find_mount_by_mount_info (daemon_monitor, mount_info);
if (mount)
@@ -114,10 +115,12 @@ mount_added (GDaemonVolumeMonitor *daemon_monitor, GMountInfo *mount_info)
return;
}
-
if (mount_info->user_visible)
{
- mount = g_daemon_mount_new (mount_info);
+ mount = g_daemon_mount_new (mount_info, G_VOLUME_MONITOR (daemon_monitor));
+ volume = g_volume_monitor_adopt_orphan_mount (G_MOUNT (mount));
+ if (volume != NULL)
+ g_daemon_mount_set_foreign_volume (mount, volume);
daemon_monitor->mounts = g_list_prepend (daemon_monitor->mounts, mount);
g_signal_emit_by_name (daemon_monitor, "mount_added", mount);
}
@@ -137,6 +140,7 @@ mount_removed (GDaemonVolumeMonitor *daemon_monitor, GMountInfo *mount_info)
daemon_monitor->mounts = g_list_remove (daemon_monitor->mounts, mount);
g_signal_emit_by_name (daemon_monitor, "mount_removed", mount);
+ g_signal_emit_by_name (mount, "unmounted");
g_object_unref (mount);
}
@@ -146,6 +150,7 @@ g_daemon_volume_monitor_init (GDaemonVolumeMonitor *daemon_monitor)
GList *mounts, *l;
GDaemonMount *mount;
GMountInfo *info;
+ GVolume *volume;
daemon_monitor->mount_tracker = g_mount_tracker_new (_g_daemon_vfs_get_async_bus ());
@@ -161,7 +166,10 @@ g_daemon_volume_monitor_init (GDaemonVolumeMonitor *daemon_monitor)
info = l->data;
if (info->user_visible)
{
- mount = g_daemon_mount_new (info);
+ mount = g_daemon_mount_new (info, G_VOLUME_MONITOR (daemon_monitor));
+ volume = g_volume_monitor_adopt_orphan_mount (G_MOUNT (mount));
+ if (volume != NULL)
+ g_daemon_mount_set_foreign_volume (mount, volume);
daemon_monitor->mounts = g_list_prepend (daemon_monitor->mounts, mount);
}
diff --git a/client/gvfsfusedaemon.c b/client/gvfsfusedaemon.c
index 6b2feec2..92ecea35 100644
--- a/client/gvfsfusedaemon.c
+++ b/client/gvfsfusedaemon.c
@@ -46,6 +46,7 @@
#include <glib/gurifuncs.h>
/* stuff from common/ */
+#include <gdaemonmount.h>
#include <gvfsdaemonprotocol.h>
#include <gdbusutils.h>
@@ -196,6 +197,7 @@ file_handle_new (void)
static void
file_handle_close_stream (FileHandle *file_handle)
{
+ debug_print ("file_handle_close_stream\n");
if (file_handle->stream)
{
switch (file_handle->op)
@@ -285,7 +287,7 @@ free_file_handle_for_path (const gchar *path)
if (fh)
{
g_static_mutex_lock (&global_mutex);
- g_hash_table_remove (global_fh_table, fh);
+ g_hash_table_remove (global_fh_table, path);
g_static_mutex_unlock (&global_mutex);
return TRUE;
}
@@ -302,7 +304,12 @@ mount_record_new (GMount *mount)
mount_record = g_new (MountRecord, 1);
mount_record->root = g_mount_get_root (mount);
- name = g_mount_get_name (mount);
+ name = g_object_get_data (mount, "g-stable-name");
+ if (name != NULL)
+ name = g_strdup (name);
+ else
+ name = g_mount_get_name (mount);
+
/* Keep in sync with gvfs daemon mount tracker */
mount_record->name = g_uri_escape_string (name, "+@#$., ", TRUE);
g_free (name);
diff --git a/common/gmounttracker.c b/common/gmounttracker.c
index c0f1537b..4b3b7717 100644
--- a/common/gmounttracker.c
+++ b/common/gmounttracker.c
@@ -88,6 +88,7 @@ g_mount_info_dup (GMountInfo *info)
copy = g_new (GMountInfo, 1);
copy->ref_count = 1;
copy->display_name = g_strdup (info->display_name);
+ copy->stable_name = g_strdup (info->stable_name);
copy->icon = g_strdup (info->icon);
copy->dbus_id = g_strdup (info->dbus_id);
copy->object_path = g_strdup (info->object_path);
@@ -112,6 +113,7 @@ g_mount_info_unref (GMountInfo *info)
if (g_atomic_int_dec_and_test (&info->ref_count))
{
g_free (info->display_name);
+ g_free (info->stable_name);
g_free (info->icon);
g_free (info->dbus_id);
g_free (info->object_path);
@@ -155,6 +157,7 @@ g_mount_info_from_dbus (DBusMessageIter *iter)
GMountSpec *mount_spec;
dbus_bool_t user_visible;
char *display_name;
+ char *stable_name;
char *icon;
char *prefered_filename_encoding;
char *dbus_id;
@@ -170,6 +173,7 @@ g_mount_info_from_dbus (DBusMessageIter *iter)
DBUS_TYPE_STRING, &dbus_id,
DBUS_TYPE_OBJECT_PATH, &obj_path,
DBUS_TYPE_STRING, &display_name,
+ DBUS_TYPE_STRING, &stable_name,
DBUS_TYPE_STRING, &icon,
DBUS_TYPE_STRING, &prefered_filename_encoding,
DBUS_TYPE_BOOLEAN, &user_visible,
@@ -177,9 +181,6 @@ g_mount_info_from_dbus (DBusMessageIter *iter)
0))
return NULL;
- g_free (fuse_mountpoint);
-
-
mount_spec = g_mount_spec_from_dbus (&struct_iter);
if (mount_spec == NULL) {
g_free (fuse_mountpoint);
@@ -189,6 +190,7 @@ g_mount_info_from_dbus (DBusMessageIter *iter)
info = g_new0 (GMountInfo, 1);
info->ref_count = 1;
info->display_name = g_strdup (display_name);
+ info->stable_name = g_strdup (stable_name);
info->icon = g_strdup (icon);
info->dbus_id = g_strdup (dbus_id);
info->object_path = g_strdup (obj_path);
diff --git a/common/gmounttracker.h b/common/gmounttracker.h
index 13536f04..8ff166ee 100644
--- a/common/gmounttracker.h
+++ b/common/gmounttracker.h
@@ -41,6 +41,7 @@ typedef struct _GMountTrackerClass GMountTrackerClass;
typedef struct {
volatile int ref_count;
char *display_name;
+ char *stable_name;
char *icon;
char *dbus_id;
char *object_path;
diff --git a/configure.ac b/configure.ac
index ab879555..38782961 100644
--- a/configure.ac
+++ b/configure.ac
@@ -92,6 +92,28 @@ fi
AC_SEARCH_LIBS(login_tty, util, [AC_DEFINE([HAVE_LOGIN_TTY],[],[Whether login_tty is available])])
+dnl **************************************************
+dnl *** Check if we should build with CDDA backend ***
+dnl **************************************************
+AC_ARG_ENABLE(cdda, [ --disable-cdda build without CDDA backend])
+msg_cdda=no
+CDDA_LIBS=
+CDDA_CFLAGS=
+
+if test "x$enable_cdda" != "xno"; then
+ PKG_CHECK_EXISTS(libcdio_paranoia >= 0.78.2, msg_cdda=yes)
+
+ if test "x$msg_cdda" == "xyes"; then
+ PKG_CHECK_MODULES(CDDA, libcdio_paranoia)
+ AC_DEFINE(HAVE_CDDA, 1, [Define to 1 if CDDA is going to be built])
+ fi
+fi
+
+AC_SUBST(CDDA_LIBS)
+AC_SUBST(CDDA_CFLAGS)
+
+AM_CONDITIONAL(USE_CDDA, [test "$msg_cdda" = "yes"])
+
dnl **********************
dnl *** Check for FUSE ***
dnl **********************
@@ -280,5 +302,6 @@ echo "gvfs configuration summary:"
echo "
Samba support: $msg_samba
FUSE support: $msg_fuse
+ CDDA support: $msg_cdda
Use HAL for volume monitor: $msg_hal (with fast init path: $have_hal_fast_init)
"
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 3e5ceab6..7e503188 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -30,10 +30,10 @@ service_DATA = gvfs-daemon.service
mountdir = $(sysconfdir)/gvfs/mounts
-libexec_PROGRAMS=gvfsd gvfsd-ftp gvfsd-sftp gvfsd-trash
+libexec_PROGRAMS=gvfsd gvfsd-ftp gvfsd-sftp gvfsd-trash gvfsd-cdda
-mount_in_files = ftp.mount.in sftp.mount.in trash.mount.in
-mount_DATA = ftp.mount sftp.mount trash.mount
+mount_in_files = ftp.mount.in sftp.mount.in trash.mount.in cdda.mount.in
+mount_DATA = ftp.mount sftp.mount trash.mount cdda.mount
if HAVE_SAMBA
mount_in_files += smb.mount.in smb-browse.mount.in
@@ -173,3 +173,17 @@ gvfsd_trash_CPPFLAGS = \
-DBACKEND_TYPES='"trash", G_VFS_TYPE_BACKEND_TRASH,'
gvfsd_trash_LDADD = $(libraries)
+
+gvfsd_cdda_SOURCES = \
+ gvfsbackendcdda.c gvfsbackendcdda.h \
+ daemon-main.c daemon-main.h \
+ daemon-main-generic.c
+
+gvfsd_cdda_CPPFLAGS = \
+ -DBACKEND_HEADER=gvfsbackendcdda.h \
+ -DDEFAULT_BACKEND_TYPE=cdda \
+ -DMAX_JOB_THREADS=1 \
+ $(CDDA_CFLAGS) \
+ -DBACKEND_TYPES='"cdda", G_VFS_TYPE_BACKEND_CDDA,'
+
+gvfsd_cdda_LDADD = $(libraries) $(CDDA_LIBS)
diff --git a/daemon/gvfsbackend.c b/daemon/gvfsbackend.c
index 8093efab..c116698d 100644
--- a/daemon/gvfsbackend.c
+++ b/daemon/gvfsbackend.c
@@ -65,6 +65,7 @@ struct _GVfsBackendPrivate
char *object_path;
char *display_name;
+ char *stable_name;
char *icon;
char *prefered_filename_encoding;
gboolean user_visible;
@@ -138,6 +139,7 @@ g_vfs_backend_finalize (GObject *object)
g_free (backend->priv->object_path);
g_free (backend->priv->display_name);
+ g_free (backend->priv->stable_name);
g_free (backend->priv->icon);
g_free (backend->priv->prefered_filename_encoding);
if (backend->priv->mount_spec)
@@ -189,6 +191,7 @@ g_vfs_backend_init (GVfsBackend *backend)
backend->priv->icon = g_strdup ("");
backend->priv->prefered_filename_encoding = g_strdup ("");
backend->priv->display_name = g_strdup ("");
+ backend->priv->stable_name = g_strdup ("");
backend->priv->user_visible = TRUE;
}
@@ -272,6 +275,28 @@ g_vfs_backend_set_display_name (GVfsBackend *backend,
backend->priv->display_name = g_strdup (display_name);
}
+/**
+ * g_vfs_backend_set_stable_name:
+ * @backend: backend
+ * @stable_name: the stable name
+ *
+ * For filesystems that can change the name during the lifetime
+ * of the filesystem this can be uses to set a separate stable
+ * name. This is used for instance as the directory representing
+ * the mounted file system in the standard UNIX file system
+ * namespace.
+ *
+ * If this function isn't called, the value passed to
+ * g_vfs_backend_set_display_name() will be used instead.
+ **/
+void
+g_vfs_backend_set_stable_name (GVfsBackend *backend,
+ const char *stable_name)
+{
+ g_free (backend->priv->stable_name);
+ backend->priv->stable_name = g_strdup (stable_name);
+}
+
void
g_vfs_backend_set_icon_name (GVfsBackend *backend,
const char *icon)
@@ -319,6 +344,12 @@ g_vfs_backend_get_display_name (GVfsBackend *backend)
}
const char *
+g_vfs_backend_get_stable_name (GVfsBackend *backend)
+{
+ return backend->priv->stable_name;
+}
+
+const char *
g_vfs_backend_get_icon_name (GVfsBackend *backend)
{
return backend->priv->icon;
@@ -438,6 +469,7 @@ g_vfs_backend_register_mount (GVfsBackend *backend,
GAsyncDBusCallback callback,
gpointer user_data)
{
+ const char *stable_name;
DBusMessage *message;
DBusMessageIter iter;
dbus_bool_t user_visible;
@@ -449,10 +481,16 @@ g_vfs_backend_register_mount (GVfsBackend *backend,
if (message == NULL)
_g_dbus_oom ();
+ if (backend->priv->stable_name != NULL)
+ stable_name = backend->priv->stable_name;
+ else
+ stable_name = backend->priv->display_name;
+
user_visible = backend->priv->user_visible;
if (!dbus_message_append_args (message,
DBUS_TYPE_OBJECT_PATH, &backend->priv->object_path,
DBUS_TYPE_STRING, &backend->priv->display_name,
+ DBUS_TYPE_STRING, &stable_name,
DBUS_TYPE_STRING, &backend->priv->icon,
DBUS_TYPE_STRING, &backend->priv->prefered_filename_encoding,
DBUS_TYPE_BOOLEAN, &user_visible,
diff --git a/daemon/gvfsbackend.h b/daemon/gvfsbackend.h
index aaff61ff..744e3a1b 100644
--- a/daemon/gvfsbackend.h
+++ b/daemon/gvfsbackend.h
@@ -345,6 +345,8 @@ GType g_vfs_lookup_backend (const char *type);
void g_vfs_backend_set_display_name (GVfsBackend *backend,
const char *display_name);
+void g_vfs_backend_set_stable_name (GVfsBackend *backend,
+ const char *stable_name);
void g_vfs_backend_set_icon_name (GVfsBackend *backend,
const char *icon);
void g_vfs_backend_set_prefered_filename_encoding (GVfsBackend *backend,
@@ -361,6 +363,7 @@ void g_vfs_backend_unregister_mount (GVfsBackend *ba
gpointer user_data);
const char *g_vfs_backend_get_backend_type (GVfsBackend *backend);
const char *g_vfs_backend_get_display_name (GVfsBackend *backend);
+const char *g_vfs_backend_get_stable_name (GVfsBackend *backend);
const char *g_vfs_backend_get_icon_name (GVfsBackend *backend);
GMountSpec *g_vfs_backend_get_mount_spec (GVfsBackend *backend);
GVfsDaemon *g_vfs_backend_get_daemon (GVfsBackend *backend);
diff --git a/daemon/gvfsjobunmount.c b/daemon/gvfsjobunmount.c
index 5731e3d3..a23b9be8 100644
--- a/daemon/gvfsjobunmount.c
+++ b/daemon/gvfsjobunmount.c
@@ -129,14 +129,16 @@ unregister_mount_callback (DBusMessage *unmount_reply,
GError *error,
gpointer user_data)
{
+ GVfsBackend *backend;
GVfsJobUnmount *op_job = G_VFS_JOB_UNMOUNT (user_data);
g_print ("unregister_mount_callback, unmount_reply: %p, error: %p\n", unmount_reply, error);
+ backend = op_job->backend;
(*G_VFS_JOB_CLASS (g_vfs_job_unmount_parent_class)->send_reply) (G_VFS_JOB (op_job));
/* Unlink job source from daemon */
- g_vfs_job_source_closed (G_VFS_JOB_SOURCE (op_job->backend));
+ g_vfs_job_source_closed (G_VFS_JOB_SOURCE (backend));
}
/* Might be called on an i/o thread */
@@ -146,10 +148,13 @@ send_reply (GVfsJob *job)
GVfsJobUnmount *op_job = G_VFS_JOB_UNMOUNT (job);
g_print ("send_reply, failed: %d\n", job->failed);
-
- g_vfs_backend_unregister_mount (op_job->backend,
- unregister_mount_callback,
- job);
+
+ if (job->failed)
+ (*G_VFS_JOB_CLASS (g_vfs_job_unmount_parent_class)->send_reply) (G_VFS_JOB (op_job));
+ else
+ g_vfs_backend_unregister_mount (op_job->backend,
+ unregister_mount_callback,
+ job);
}
/* Might be called on an i/o thread */
diff --git a/daemon/mount.c b/daemon/mount.c
index 12d3ff81..cfda6779 100644
--- a/daemon/mount.c
+++ b/daemon/mount.c
@@ -36,6 +36,7 @@
typedef struct {
char *display_name;
+ char *stable_name;
char *icon;
char *prefered_filename_encoding;
gboolean user_visible;
@@ -138,6 +139,7 @@ static void
vfs_mount_free (VfsMount *mount)
{
g_free (mount->display_name);
+ g_free (mount->stable_name);
g_free (mount->icon);
g_free (mount->prefered_filename_encoding);
g_free (mount->dbus_id);
@@ -175,6 +177,11 @@ vfs_mount_to_dbus (VfsMount *mount,
DBUS_TYPE_STRING,
&mount->display_name))
_g_dbus_oom ();
+
+ if (!dbus_message_iter_append_basic (&struct_iter,
+ DBUS_TYPE_STRING,
+ &mount->stable_name))
+ _g_dbus_oom ();
if (!dbus_message_iter_append_basic (&struct_iter,
DBUS_TYPE_STRING,
@@ -199,14 +206,14 @@ vfs_mount_to_dbus (VfsMount *mount,
char *fs_name;
/* Keep in sync with fuse daemon */
- fs_name = g_uri_escape_string (mount->display_name, "+@#$., ", TRUE);
+ fs_name = g_uri_escape_string (mount->stable_name, "+@#$., ", TRUE);
fuse_mountpoint = g_build_filename (g_get_home_dir(), ".gvfs", fs_name, NULL);
}
if (fuse_mountpoint == NULL)
fuse_mountpoint = g_strdup ("");
-
+
_g_dbus_message_iter_append_cstring (&struct_iter, fuse_mountpoint);
g_mount_spec_to_dbus (&struct_iter, mount->mount_spec);
@@ -551,7 +558,7 @@ register_mount (DBusConnection *connection,
VfsMount *mount;
DBusMessage *reply;
DBusError error;
- const char *display_name, *icon, *obj_path, *id, *prefered_filename_encoding;
+ const char *display_name, *stable_name, *icon, *obj_path, *id, *prefered_filename_encoding;
dbus_bool_t user_visible;
DBusMessageIter iter;
GMountSpec *mount_spec;
@@ -565,6 +572,7 @@ register_mount (DBusConnection *connection,
&error,
DBUS_TYPE_OBJECT_PATH, &obj_path,
DBUS_TYPE_STRING, &display_name,
+ DBUS_TYPE_STRING, &stable_name,
DBUS_TYPE_STRING, &icon,
DBUS_TYPE_STRING, &prefered_filename_encoding,
DBUS_TYPE_BOOLEAN, &user_visible,
@@ -577,7 +585,7 @@ register_mount (DBusConnection *connection,
else if ((mount_spec = g_mount_spec_from_dbus (&iter)) == NULL)
reply = dbus_message_new_error (message,
DBUS_ERROR_INVALID_ARGS,
- "Error in mount spec");
+ "Error in mount spec");
else if (match_vfs_mount (mount_spec) != NULL)
reply = dbus_message_new_error (message,
DBUS_ERROR_INVALID_ARGS,
@@ -586,6 +594,7 @@ register_mount (DBusConnection *connection,
{
mount = g_new0 (VfsMount, 1);
mount->display_name = g_strdup (display_name);
+ mount->stable_name = g_strdup (stable_name);
mount->icon = g_strdup (icon);
mount->prefered_filename_encoding = g_strdup (prefered_filename_encoding);
mount->user_visible = user_visible;
@@ -751,6 +760,7 @@ list_mounts (DBusConnection *connection,
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_BOOLEAN_AS_STRING
DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING
G_MOUNT_SPEC_TYPE_AS_STRING
diff --git a/hal/ghaldrive.c b/hal/ghaldrive.c
index df3a8fbd..5071e1bd 100644
--- a/hal/ghaldrive.c
+++ b/hal/ghaldrive.c
@@ -91,6 +91,9 @@ g_hal_drive_finalize (GObject *object)
g_free (drive->name);
g_free (drive->icon);
+
+ if (drive->volume_monitor != NULL)
+ g_object_remove_weak_pointer (G_OBJECT (drive->volume_monitor), (gpointer) &(drive->volume_monitor));
if (G_OBJECT_CLASS (g_hal_drive_parent_class)->finalize)
(*G_OBJECT_CLASS (g_hal_drive_parent_class)->finalize) (object);
@@ -331,6 +334,15 @@ _update_from_hal (GHalDrive *d, gboolean emit_changed)
}
static void
+hal_condition (HalDevice *device, const char *name, const char *detail, gpointer user_data)
+{
+ GHalDrive *hal_drive = G_HAL_DRIVE (user_data);
+
+ if (strcmp (name, "EjectPressed") == 0)
+ g_signal_emit_by_name (hal_drive, "eject-button");
+}
+
+static void
hal_changed (HalDevice *device, const char *key, gpointer user_data)
{
GHalDrive *hal_drive = G_HAL_DRIVE (user_data);
@@ -357,6 +369,7 @@ g_hal_drive_new (GVolumeMonitor *volume_monitor,
drive->icon = g_strdup_printf ("drive-removable-media");
g_signal_connect_object (device, "hal_property_changed", (GCallback) hal_changed, drive, 0);
+ g_signal_connect_object (device, "hal_condition", (GCallback) hal_condition, drive, 0);
_update_from_hal (drive, FALSE);
@@ -498,27 +511,37 @@ spawn_cb (GPid pid, gint status, gpointer user_data)
{
SpawnOp *data = user_data;
GSimpleAsyncResult *simple;
-
- /* TODO: how do we report an error back to the caller while telling
- * him that we already have shown an error dialog to the user?
- *
- * G_IO_ERROR_FAILED_NO_UI or something?
- */
- simple = g_simple_async_result_new (data->object,
- data->callback,
- data->user_data,
- NULL);
+
+ if (WEXITSTATUS (status) != 0)
+ {
+ GError *error;
+ error = g_error_new_literal (G_IO_ERROR,
+ G_IO_ERROR_FAILED_HANDLED,
+ "You are not supposed to show G_IO_ERROR_FAILED_HANDLED in the UI");
+ simple = g_simple_async_result_new_from_error (data->object,
+ data->callback,
+ data->user_data,
+ error);
+ g_error_free (error);
+ }
+ else
+ {
+ simple = g_simple_async_result_new (data->object,
+ data->callback,
+ data->user_data,
+ NULL);
+ }
g_simple_async_result_complete (simple);
g_object_unref (simple);
g_free (data);
}
static void
-g_hal_drive_eject (GDrive *drive,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+g_hal_drive_eject_do (GDrive *drive,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
GHalDrive *hal_drive = G_HAL_DRIVE (drive);
SpawnOp *data;
@@ -558,6 +581,135 @@ g_hal_drive_eject (GDrive *drive,
g_child_watch_add (child_pid, spawn_cb, data);
}
+
+typedef struct {
+ GDrive *drive;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+ GCancellable *cancellable;
+
+ 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 unmount %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_hal_drive_eject_do (data->drive,
+ data->cancellable,
+ data->callback,
+ data->user_data);
+ 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->cancellable,
+ _eject_unmount_mounts_cb,
+ data);
+ }
+}
+
+static void
+g_hal_drive_eject (GDrive *drive,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GHalDrive *hal_drive = G_HAL_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 = drive;
+ data->cancellable = cancellable;
+ data->callback = callback;
+ data->user_data = user_data;
+
+ for (l = hal_drive->volumes; l != NULL; l = l->next)
+ {
+ GHalVolume *volume = l->data;
+ GMount *mount; /* the mount may be foreign; cannot assume GHalMount */
+
+ mount = g_volume_get_mount (G_VOLUME (volume));
+ if (mount != NULL)
+ data->pending_mounts = g_list_prepend (data->pending_mounts, g_object_ref (mount));
+ }
+
+ _eject_unmount_mounts (data);
+}
+
static gboolean
g_hal_drive_eject_finish (GDrive *drive,
GAsyncResult *result,
diff --git a/hal/ghalmount.c b/hal/ghalmount.c
index 0224cda7..d6729e4a 100644
--- a/hal/ghalmount.c
+++ b/hal/ghalmount.c
@@ -99,6 +99,9 @@ g_hal_mount_finalize (GObject *object)
if (mount->override_root != NULL)
g_object_unref (mount->override_root);
+
+ if (mount->volume_monitor != NULL)
+ g_object_remove_weak_pointer (G_OBJECT (mount->volume_monitor), (gpointer) &(mount->volume_monitor));
if (G_OBJECT_CLASS (g_hal_mount_parent_class)->finalize)
(*G_OBJECT_CLASS (g_hal_mount_parent_class)->finalize) (object);
@@ -689,12 +692,12 @@ typedef struct {
guint error_channel_source_id;
GString *error_string;
gboolean using_legacy;
-} EjectUnmountOp;
+} UnmountOp;
static void
-eject_unmount_cb (GPid pid, gint status, gpointer user_data)
+unmount_cb (GPid pid, gint status, gpointer user_data)
{
- EjectUnmountOp *data = user_data;
+ UnmountOp *data = user_data;
GSimpleAsyncResult *simple;
if (WEXITSTATUS (status) != 0)
@@ -713,15 +716,15 @@ eject_unmount_cb (GPid pid, gint status, gpointer user_data)
}
else
{
- /* TODO: how do we report an error back to the caller while telling
- * him that we already have shown an error dialog to the user?
- *
- * G_IO_ERROR_FAILED_NO_UI or something?
- */
- simple = g_simple_async_result_new (data->object,
- data->callback,
- data->user_data,
- NULL);
+ GError *error;
+ error = g_error_new_literal (G_IO_ERROR,
+ G_IO_ERROR_FAILED_HANDLED,
+ "You are not supposed to show G_IO_ERROR_FAILED_HANDLED in the UI");
+ simple = g_simple_async_result_new_from_error (data->object,
+ data->callback,
+ data->user_data,
+ error);
+ g_error_free (error);
}
}
else
@@ -744,13 +747,13 @@ eject_unmount_cb (GPid pid, gint status, gpointer user_data)
}
static gboolean
-eject_unmount_read_error (GIOChannel *channel,
+unmount_read_error (GIOChannel *channel,
GIOCondition condition,
gpointer user_data)
{
char *str;
gsize str_len;
- EjectUnmountOp *data = user_data;
+ UnmountOp *data = user_data;
g_io_channel_read_to_end (channel, &str, &str_len, NULL);
g_string_append (data->error_string, str);
@@ -759,18 +762,18 @@ eject_unmount_read_error (GIOChannel *channel,
}
static void
-eject_unmount_do (GMount *mount,
+unmount_do (GMount *mount,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data,
char **argv,
gboolean using_legacy)
{
- EjectUnmountOp *data;
+ UnmountOp *data;
GPid child_pid;
GError *error;
- data = g_new0 (EjectUnmountOp, 1);
+ data = g_new0 (UnmountOp, 1);
data->object = G_OBJECT (mount);
data->callback = callback;
data->user_data = user_data;
@@ -802,8 +805,8 @@ eject_unmount_do (GMount *mount,
}
data->error_string = g_string_new ("");
data->error_channel = g_io_channel_unix_new (data->error_fd);
- data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, eject_unmount_read_error, data);
- g_child_watch_add (child_pid, eject_unmount_cb, data);
+ data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, unmount_read_error, data);
+ g_child_watch_add (child_pid, unmount_cb, data);
}
@@ -829,17 +832,33 @@ g_hal_mount_unmount (GMount *mount,
argv[2] = NULL;
}
- eject_unmount_do (mount, cancellable, callback, user_data, argv, using_legacy);
+ unmount_do (mount, cancellable, callback, user_data, argv, using_legacy);
}
static gboolean
g_hal_mount_unmount_finish (GMount *mount,
- GAsyncResult *result,
- GError **error)
+ GAsyncResult *result,
+ GError **error)
{
return TRUE;
}
+typedef struct {
+ GObject *object;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} EjectWrapperOp;
+
+static void
+eject_wrapper_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ EjectWrapperOp *data = user_data;
+ data->callback (data->object, res, data->user_data);
+ g_free (data);
+}
+
static void
g_hal_mount_eject (GMount *mount,
GCancellable *cancellable,
@@ -847,22 +866,21 @@ g_hal_mount_eject (GMount *mount,
gpointer user_data)
{
GHalMount *hal_mount = G_HAL_MOUNT (mount);
- char *argv[] = {"gnome-mount", "-e", "-b", "-d", NULL, NULL};
- gboolean using_legacy = FALSE;
+ GDrive *drive;
- if (hal_mount->device != NULL)
- {
- argv[4] = hal_mount->device_path;
- }
- else
+ if (hal_mount->volume != NULL)
{
- using_legacy = TRUE;
- argv[0] = "eject";
- argv[1] = hal_mount->mount_path;
- argv[2] = NULL;
+ drive = g_volume_get_drive (G_VOLUME (hal_mount->volume));
+ if (drive != NULL)
+ {
+ EjectWrapperOp *data;
+ data = g_new0 (EjectWrapperOp, 1);
+ data->object = G_OBJECT (mount);
+ data->callback = callback;
+ data->user_data = user_data;
+ g_drive_eject (drive, cancellable, eject_wrapper_callback, data);
+ }
}
-
- eject_unmount_do (mount, cancellable, callback, user_data, argv, using_legacy);
}
static gboolean
@@ -870,6 +888,15 @@ g_hal_mount_eject_finish (GMount *mount,
GAsyncResult *result,
GError **error)
{
+ GHalMount *hal_mount = G_HAL_MOUNT (mount);
+ GDrive *drive;
+
+ if (hal_mount->volume != NULL)
+ {
+ drive = g_volume_get_drive (G_VOLUME (hal_mount->volume));
+ if (drive != NULL)
+ return g_drive_eject_finish (drive, result, error);
+ }
return TRUE;
}
diff --git a/hal/ghalvolume.c b/hal/ghalvolume.c
index f839e1f8..b1863958 100644
--- a/hal/ghalvolume.c
+++ b/hal/ghalvolume.c
@@ -49,6 +49,13 @@ struct _GHalVolume {
HalDevice *device;
HalDevice *drive_device;
+ /* set on creation if we won't create a GHalMount object ourselves
+ * and instead except to adopt one, with the given mount root,
+ * via adopt_orphan_mount()
+ */
+ GFile *foreign_mount_root;
+ GMount *foreign_mount;
+
char *name;
char *icon;
};
@@ -87,6 +94,15 @@ g_hal_volume_finalize (GObject *object)
if (volume->drive_device != NULL)
g_object_unref (volume->drive_device);
+ if (volume->foreign_mount_root != NULL)
+ g_object_unref (volume->foreign_mount_root);
+
+ if (volume->foreign_mount != NULL)
+ g_object_unref (volume->foreign_mount);
+
+ if (volume->volume_monitor != NULL)
+ g_object_remove_weak_pointer (G_OBJECT (volume->volume_monitor), (gpointer) &(volume->volume_monitor));
+
g_free (volume->name);
g_free (volume->icon);
@@ -216,20 +232,27 @@ do_update_from_hal (GHalVolume *mv)
volume_disc_is_blank = hal_device_get_property_bool (volume, "volume.disc.is_blank");
volume_disc_type = hal_device_get_property_string (volume, "volume.disc.type");
- if (volume_fs_label != NULL && strlen (volume_fs_label) > 0) {
- name = g_strdup (volume_fs_label);
- } else if (volume_is_disc) {
- if (volume_disc_has_audio) {
- if (volume_disc_has_data)
- name = g_strdup (_("Mixed Audio/Data Disc"));
- else
- name = g_strdup (_("Audio Disc"));
- } else {
- name = g_strdup (get_disc_name (volume_disc_type, volume_disc_is_blank));
+ if (volume_is_disc && volume_disc_has_audio && mv->foreign_mount_root != NULL)
+ {
+ name = g_strdup (_("Audio Disc"));
+ }
+ else
+ {
+ if (volume_fs_label != NULL && strlen (volume_fs_label) > 0) {
+ name = g_strdup (volume_fs_label);
+ } else if (volume_is_disc) {
+ if (volume_disc_has_audio) {
+ if (volume_disc_has_data)
+ name = g_strdup (_("Mixed Audio/Data Disc"));
+ else
+ name = g_strdup (_("Audio Disc"));
+ } else {
+ name = g_strdup (get_disc_name (volume_disc_type, volume_disc_is_blank));
+ }
+ } else {
+ name = format_size_for_display (volume_size);
+ }
}
- } else {
- name = format_size_for_display (volume_size);
- }
mv->name = name;
mv->icon = _drive_get_icon (drive); /* use the drive icon since we're unmounted */
@@ -321,10 +344,11 @@ compute_uuid (GHalVolume *volume)
}
GHalVolume *
-g_hal_volume_new (GVolumeMonitor *volume_monitor,
- HalDevice *device,
- HalPool *pool,
- GHalDrive *drive)
+g_hal_volume_new (GVolumeMonitor *volume_monitor,
+ HalDevice *device,
+ HalPool *pool,
+ GFile *foreign_mount_root,
+ GHalDrive *drive)
{
GHalVolume *volume;
HalDevice *drive_device;
@@ -345,6 +369,7 @@ g_hal_volume_new (GVolumeMonitor *volume_monitor,
volume->device_path = g_strdup (hal_device_get_property_string (device, "block.device"));
volume->device = g_object_ref (device);
volume->drive_device = g_object_ref (drive_device);
+ volume->foreign_mount_root = foreign_mount_root != NULL ? g_object_ref (foreign_mount_root) : NULL;
g_signal_connect_object (device, "hal_property_changed", (GCallback) hal_changed, volume, 0);
g_signal_connect_object (drive_device, "hal_property_changed", (GCallback) hal_changed, volume, 0);
@@ -495,6 +520,9 @@ g_hal_volume_get_mount (GVolume *volume)
{
GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ if (hal_volume->foreign_mount != NULL)
+ return g_object_ref (hal_volume->foreign_mount);
+
if (hal_volume->mount != NULL)
return g_object_ref (hal_volume->mount);
@@ -530,6 +558,44 @@ g_hal_volume_has_uuid (GHalVolume *volume,
return FALSE;
}
+static void
+foreign_mount_unmounted (GMount *mount, gpointer user_data)
+{
+ GHalVolume *volume = G_HAL_VOLUME (user_data);
+ if (volume->foreign_mount == mount)
+ g_hal_volume_adopt_foreign_mount (volume, NULL);
+}
+
+void
+g_hal_volume_adopt_foreign_mount (GHalVolume *volume, GMount *foreign_mount)
+{
+ if (volume->foreign_mount != NULL)
+ g_object_unref (volume->foreign_mount);
+
+ if (foreign_mount != NULL)
+ {
+ volume->foreign_mount = g_object_ref (foreign_mount);
+ g_signal_connect_object (foreign_mount, "unmounted", (GCallback) foreign_mount_unmounted, volume, 0);
+ }
+ else
+ volume->foreign_mount = NULL;
+
+ g_signal_emit_by_name (volume, "changed");
+ if (volume->volume_monitor != NULL)
+ g_signal_emit_by_name (volume->volume_monitor, "volume_changed", volume);
+}
+
+gboolean
+g_hal_volume_has_foreign_mount_root (GHalVolume *volume,
+ GFile *mount_root)
+{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+ if (hal_volume->foreign_mount_root != NULL)
+ return g_file_equal (hal_volume->foreign_mount_root, mount_root);
+ return FALSE;
+}
+
+
typedef struct {
GObject *object;
GAsyncReadyCallback callback;
@@ -547,17 +613,27 @@ spawn_cb (GPid pid, gint status, gpointer user_data)
* mounted is made available before returning to the user
*/
g_hal_volume_monitor_force_update (G_HAL_VOLUME_MONITOR (G_HAL_VOLUME (data->object)->volume_monitor));
-
- /* TODO: how do we report an error back to the caller while telling
- * him that we already have shown an error dialog to the user?
- *
- * G_IO_ERROR_FAILED_NO_UI or something?
- */
- simple = g_simple_async_result_new (data->object,
- data->callback,
- data->user_data,
- NULL);
+ if (WEXITSTATUS (status) != 0)
+ {
+ GError *error;
+ error = g_error_new_literal (G_IO_ERROR,
+ G_IO_ERROR_FAILED_HANDLED,
+ "You are not supposed to show G_IO_ERROR_FAILED_HANDLED in the UI");
+ simple = g_simple_async_result_new_from_error (data->object,
+ data->callback,
+ data->user_data,
+ error);
+ g_error_free (error);
+ }
+ else
+ {
+ simple = g_simple_async_result_new (data->object,
+ data->callback,
+ data->user_data,
+ NULL);
+ }
+
g_simple_async_result_complete (simple);
g_object_unref (simple);
g_free (data);
@@ -604,48 +680,120 @@ spawn_do (GVolume *volume,
g_child_watch_add (child_pid, spawn_cb, data);
}
+typedef struct
+{
+ GHalVolume *enclosing_volume;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} ForeignMountOp;
+
+static void
+mount_foreign_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ ForeignMountOp *data = user_data;
+ data->callback (G_OBJECT (data->enclosing_volume), res, data->user_data);
+ g_free (data);
+}
+
static void
-g_hal_volume_mount (GVolume *volume,
+g_hal_volume_mount (GVolume *volume,
GMountOperation *mount_operation,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GHalVolume *hal_volume = G_HAL_VOLUME (volume);
- char *argv[] = {"gnome-mount", "-b", "-d", NULL, NULL};
-
- argv[3] = hal_volume->device_path;
- spawn_do (volume, cancellable, callback, user_data, argv);
+ if (hal_volume->foreign_mount_root != NULL)
+ {
+ ForeignMountOp *data;
+
+ data = g_new0 (ForeignMountOp, 1);
+ data->enclosing_volume = hal_volume;
+ data->callback = callback;
+ data->user_data = user_data;
+
+ g_file_mount_enclosing_volume (hal_volume->foreign_mount_root,
+ mount_operation,
+ cancellable,
+ mount_foreign_callback,
+ data);
+ }
+ else
+ {
+ char *argv[] = {"gnome-mount", "-b", "-d", NULL, NULL};
+ argv[3] = hal_volume->device_path;
+ spawn_do (volume, cancellable, callback, user_data, argv);
+ }
}
static gboolean
-g_hal_volume_mount_finish (GVolume *volume,
+g_hal_volume_mount_finish (GVolume *volume,
GAsyncResult *result,
GError **error)
{
- return TRUE;
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+
+ if (hal_volume->foreign_mount_root != NULL)
+ {
+ return g_file_mount_enclosing_volume_finish (hal_volume->foreign_mount_root, result, error);
+ }
+ else
+ {
+ return TRUE;
+ }
}
+typedef struct {
+ GObject *object;
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+} EjectWrapperOp;
+
static void
-g_hal_volume_eject (GVolume *volume,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+eject_wrapper_callback (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ EjectWrapperOp *data = user_data;
+ data->callback (data->object, res, data->user_data);
+ g_free (data);
+}
+
+static void
+g_hal_volume_eject (GVolume *volume,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
GHalVolume *hal_volume = G_HAL_VOLUME (volume);
- char *argv[] = {"gnome-mount", "-e", "-b", "-d", NULL, NULL};
- argv[4] = hal_volume->device_path;
+ g_warning ("hal_volume_eject");
- spawn_do (volume, cancellable, callback, user_data, argv);
+ if (hal_volume->drive != NULL)
+ {
+ EjectWrapperOp *data;
+ data = g_new0 (EjectWrapperOp, 1);
+ data->object = G_OBJECT (volume);
+ data->callback = callback;
+ data->user_data = user_data;
+ g_drive_eject (G_DRIVE (hal_volume->drive), cancellable, eject_wrapper_callback, data);
+ }
}
static gboolean
-g_hal_volume_eject_finish (GVolume *volume,
- GAsyncResult *result,
- GError **error)
+g_hal_volume_eject_finish (GVolume *volume,
+ GAsyncResult *result,
+ GError **error)
{
+ GHalVolume *hal_volume = G_HAL_VOLUME (volume);
+
+ if (hal_volume->drive != NULL)
+ {
+ return g_drive_eject_finish (G_DRIVE (hal_volume->drive), result, error);
+ }
return TRUE;
}
diff --git a/hal/ghalvolume.h b/hal/ghalvolume.h
index c8376b1a..7bff3421 100644
--- a/hal/ghalvolume.h
+++ b/hal/ghalvolume.h
@@ -49,6 +49,7 @@ void g_hal_volume_register (GIOModule *module);
GHalVolume *g_hal_volume_new (GVolumeMonitor *volume_monitor,
HalDevice *device,
HalPool *pool,
+ GFile *foreign_mount_root,
GHalDrive *drive);
gboolean g_hal_volume_has_mount_path (GHalVolume *volume,
@@ -58,6 +59,12 @@ gboolean g_hal_volume_has_udi (GHalVolume *volume,
gboolean g_hal_volume_has_uuid (GHalVolume *volume,
const char *uuid);
+gboolean g_hal_volume_has_foreign_mount_root (GHalVolume *volume,
+ GFile *mount_root);
+
+void g_hal_volume_adopt_foreign_mount (GHalVolume *volume,
+ GMount *foreign_mount);
+
void g_hal_volume_set_mount (GHalVolume *volume,
GHalMount *mount);
void g_hal_volume_unset_mount (GHalVolume *volume,
diff --git a/hal/ghalvolumemonitor.c b/hal/ghalvolumemonitor.c
index 4336ef13..9bc8fdee 100644
--- a/hal/ghalvolumemonitor.c
+++ b/hal/ghalvolumemonitor.c
@@ -420,6 +420,35 @@ is_supported (void)
return pool != NULL;
}
+static GVolume *
+adopt_orphan_mount (GMount *mount)
+{
+ GList *l;
+ GFile *mount_root;
+ GVolume *ret;
+
+ if (the_volume_monitor == NULL)
+ return NULL;
+
+ ret = NULL;
+ mount_root = g_mount_get_root (mount);
+
+ /* right now we only support discs as foreign mounts */
+ for (l = the_volume_monitor->disc_volumes; l != NULL; l = l->next)
+ {
+ GHalVolume *volume = l->data;
+ if (g_hal_volume_has_foreign_mount_root (volume, mount_root))
+ {
+ g_hal_volume_adopt_foreign_mount (volume, mount);
+ ret = g_object_ref (volume);
+ break;
+ }
+ }
+
+ g_object_unref (mount_root);
+ return ret;
+}
+
static void
g_hal_volume_monitor_class_init (GHalVolumeMonitorClass *klass)
{
@@ -435,6 +464,7 @@ g_hal_volume_monitor_class_init (GHalVolumeMonitorClass *klass)
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->adopt_orphan_mount = adopt_orphan_mount;
native_class->priority = 1;
native_class->name = "hal";
@@ -735,6 +765,7 @@ update_volumes (GHalVolumeMonitor *monitor)
g_hal_volume_removed (volume);
monitor->volumes = g_list_remove (monitor->volumes, volume);
g_signal_emit_by_name (monitor, "volume_removed", volume);
+ g_signal_emit_by_name (volume, "removed");
g_object_unref (volume);
}
}
@@ -749,7 +780,7 @@ update_volumes (GHalVolumeMonitor *monitor)
drive = find_drive_by_udi (monitor, hal_device_get_property_string (d, "block.storage_device"));
//g_warning ("hal adding vol %s (drive %p)", hal_device_get_property_string (d, "block.device"), drive);
- volume = g_hal_volume_new (G_VOLUME_MONITOR (monitor), d, monitor->pool, drive);
+ volume = g_hal_volume_new (G_VOLUME_MONITOR (monitor), d, monitor->pool, NULL, drive);
if (volume != NULL)
{
monitor->volumes = g_list_prepend (monitor->volumes, volume);
@@ -794,6 +825,7 @@ update_mounts (GHalVolumeMonitor *monitor)
g_hal_mount_unmounted (mount);
monitor->mounts = g_list_remove (monitor->mounts, mount);
g_signal_emit_by_name (monitor, "mount_removed", mount);
+ g_signal_emit_by_name (mount, "unmounted");
g_object_unref (mount);
}
}
@@ -874,6 +906,7 @@ update_discs (GHalVolumeMonitor *monitor)
g_hal_mount_unmounted (mount);
monitor->disc_mounts = g_list_remove (monitor->disc_mounts, mount);
g_signal_emit_by_name (monitor, "mount_removed", mount);
+ g_signal_emit_by_name (mount, "unmounted");
g_object_unref (mount);
}
@@ -883,6 +916,7 @@ update_discs (GHalVolumeMonitor *monitor)
g_hal_volume_removed (volume);
monitor->disc_volumes = g_list_remove (monitor->disc_volumes, volume);
g_signal_emit_by_name (monitor, "volume_removed", volume);
+ g_signal_emit_by_name (volume, "removed");
g_object_unref (volume);
}
}
@@ -898,74 +932,59 @@ update_discs (GHalVolumeMonitor *monitor)
drive = find_drive_by_udi (monitor, drive_udi);
if (drive != NULL)
{
- volume = g_hal_volume_new (G_VOLUME_MONITOR (monitor), d, monitor->pool, drive);
- if (volume != NULL)
+ if (hal_device_get_property_bool (d, "volume.disc.is_blank"))
{
- if (hal_device_get_property_bool (d, "volume.disc.is_blank"))
+ volume = g_hal_volume_new (G_VOLUME_MONITOR (monitor), d, monitor->pool, NULL, drive);
+ if (volume != NULL)
{
GFile *file;
-
file = g_file_new_for_uri ("burn:///");
-
- mount = g_hal_mount_new_for_hal_device (G_VOLUME_MONITOR (monitor),
- d,
- file,
- NULL,
- NULL,
- TRUE,
- monitor->pool,
- volume);
-
- g_object_unref (file);
- }
- else
- {
- char *uri;
- char *encoded_device_file;
- GFile *file;
- GIcon *icon;
-
- encoded_device_file = g_uri_escape_string (hal_device_get_property_string (d, "block.device"),
- NULL, FALSE);
- uri = g_strdup_printf ("cdda://%s/", encoded_device_file);
- file = g_file_new_for_uri (uri);
-
- icon = g_themed_icon_new ("media-optical-audio");
-
mount = g_hal_mount_new_for_hal_device (G_VOLUME_MONITOR (monitor),
d,
file,
- /* TODO: Connect to web service to get disc name */
- _("Audio Disc"),
- icon,
+ NULL,
+ NULL,
TRUE,
monitor->pool,
volume);
- g_object_unref (icon);
g_object_unref (file);
- g_free (encoded_device_file);
- g_free (uri);
}
+ }
+ else
+ {
+ char *uri;
+ char *device_basename;
+ GFile *foreign_mount_root;
+
+ /* the gvfsd-cdda backend uses URI's like these */
+ device_basename = g_path_get_basename (hal_device_get_property_string (d, "block.device"));
+ uri = g_strdup_printf ("cdda://%s", device_basename);
+ foreign_mount_root = g_file_new_for_uri (uri);
+ g_free (device_basename);
+ g_free (uri);
+
+ volume = g_hal_volume_new (G_VOLUME_MONITOR (monitor), d, monitor->pool, foreign_mount_root, drive);
+ g_object_unref (foreign_mount_root);
+ mount = NULL;
+ }
+ if (volume != NULL)
+ {
+ monitor->disc_volumes = g_list_prepend (monitor->disc_volumes, volume);
+ g_signal_emit_by_name (monitor, "volume_added", volume);
+
if (mount != NULL)
{
- monitor->disc_volumes = g_list_prepend (monitor->disc_volumes, volume);
- g_signal_emit_by_name (monitor, "volume_added", volume);
monitor->disc_mounts = g_list_prepend (monitor->disc_mounts, mount);
g_signal_emit_by_name (monitor, "mount_added", mount);
}
- else
- {
- g_object_unref (volume);
- }
}
}
}
g_list_free (added);
g_list_free (removed);
- g_list_foreach (monitor->last_optical_disc_devices,
- (GFunc)g_object_unref, NULL);
+ g_list_foreach (monitor->last_optical_disc_devices, (GFunc)g_object_unref, NULL);
g_list_free (monitor->last_optical_disc_devices);
monitor->last_optical_disc_devices = new_optical_disc_devices;
}
diff --git a/hal/hal-device.c b/hal/hal-device.c
index 42ad99a9..dcb375f6 100644
--- a/hal/hal-device.c
+++ b/hal/hal-device.c
@@ -23,6 +23,7 @@
#include <config.h>
#include <glib/gi18n.h>
#include "hal-device.h"
+#include "hal-marshal.h"
struct _HalDevicePrivate
{
@@ -33,6 +34,7 @@ struct _HalDevicePrivate
enum {
HAL_PROPERTY_CHANGED,
+ HAL_CONDITION,
LAST_SIGNAL
};
@@ -67,6 +69,17 @@ hal_device_class_init (HalDeviceClass *klass)
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1,
G_TYPE_STRING);
+
+ signals[HAL_CONDITION] =
+ g_signal_new ("hal_condition",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (HalDeviceClass, hal_condition),
+ NULL, NULL,
+ hal_marshal_VOID__STRING_STRING,
+ G_TYPE_NONE, 2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
}
static void
@@ -233,6 +246,9 @@ void
_hal_device_hal_property_changed (HalDevice *device, const char *key);
void
+_hal_device_hal_condition (HalDevice *device, const char *name, const char *detail);
+
+void
_hal_device_hal_property_changed (HalDevice *device, const char *key)
{
LibHalPropertySet *new_props;
@@ -246,6 +262,12 @@ _hal_device_hal_property_changed (HalDevice *device, const char *key)
}
}
+void
+_hal_device_hal_condition (HalDevice *device, const char *name, const char *detail)
+{
+ g_signal_emit (device, signals[HAL_CONDITION], 0, name, detail);
+}
+
const char *
hal_device_get_udi (HalDevice *device)
{
diff --git a/hal/hal-device.h b/hal/hal-device.h
index 70f063fc..6a5dd705 100644
--- a/hal/hal-device.h
+++ b/hal/hal-device.h
@@ -55,6 +55,7 @@ struct _HalDeviceClass
/* signals */
void (*hal_property_changed) (HalDevice *device, const char *key);
+ void (*hal_condition) (HalDevice *device, const char *name, const char *detail);
};
diff --git a/hal/hal-marshal.list b/hal/hal-marshal.list
index 2093925d..52c82338 100644
--- a/hal/hal-marshal.list
+++ b/hal/hal-marshal.list
@@ -1 +1,3 @@
VOID:OBJECT,STRING
+VOID:OBJECT,STRING,STRING
+VOID:STRING,STRING
diff --git a/hal/hal-pool.c b/hal/hal-pool.c
index eab17cb9..2377e09b 100644
--- a/hal/hal-pool.c
+++ b/hal/hal-pool.c
@@ -34,6 +34,7 @@ enum {
DEVICE_ADDED,
DEVICE_REMOVED,
DEVICE_PROPERTY_CHANGED,
+ DEVICE_CONDITION,
LAST_SIGNAL
};
@@ -105,6 +106,18 @@ hal_pool_class_init (HalPoolClass *klass)
G_TYPE_NONE, 2,
HAL_TYPE_DEVICE,
G_TYPE_STRING);
+
+ signals[DEVICE_CONDITION] =
+ g_signal_new ("device_condition",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (HalPoolClass, device_condition),
+ NULL, NULL,
+ hal_marshal_VOID__OBJECT_STRING_STRING,
+ G_TYPE_NONE, 3,
+ HAL_TYPE_DEVICE,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
}
static void
@@ -197,6 +210,9 @@ _hal_device_removed (LibHalContext *hal_ctx, const char *udi)
void
_hal_device_hal_property_changed (HalDevice *device, const char *key);
+void
+_hal_device_hal_condition (HalDevice *device, const char *name, const char *detail);
+
static void
_hal_property_modified (LibHalContext *ctx,
const char *udi,
@@ -217,6 +233,25 @@ _hal_property_modified (LibHalContext *ctx,
}
}
+static void
+_hal_condition (LibHalContext *ctx,
+ const char *udi,
+ const char *condition_name,
+ const char *condition_detail)
+{
+ HalPool *pool;
+ HalDevice *device;
+
+ pool = HAL_POOL (libhal_ctx_get_user_data (ctx));
+
+ device = hal_pool_get_device_by_udi (pool, udi);
+ if (device != NULL)
+ {
+ _hal_device_hal_condition (device, condition_name, condition_detail);
+ g_signal_emit (pool, signals[DEVICE_CONDITION], 0, device, condition_name, condition_detail);
+ }
+}
+
LibHalContext *
hal_pool_get_hal_ctx (HalPool *pool)
{
@@ -287,6 +322,7 @@ hal_pool_new (const char *cap_only)
libhal_ctx_set_device_added (hal_ctx, _hal_device_added);
libhal_ctx_set_device_removed (hal_ctx, _hal_device_removed);
libhal_ctx_set_device_property_modified (hal_ctx, _hal_property_modified);
+ libhal_ctx_set_device_condition (hal_ctx, _hal_condition);
libhal_ctx_set_user_data (hal_ctx, pool);
#ifdef HAVE_HAL_FAST_INIT
diff --git a/hal/hal-pool.h b/hal/hal-pool.h
index ddfa21c2..0b441f36 100644
--- a/hal/hal-pool.h
+++ b/hal/hal-pool.h
@@ -57,6 +57,7 @@ struct _HalPoolClass
void (*device_added) (HalPool *pool, HalDevice *device);
void (*device_removed) (HalPool *pool, HalDevice *device);
void (*device_property_changed) (HalPool *pool, HalDevice *device, const char *key);
+ void (*device_condition) (HalPool *pool, HalDevice *device, const char *name, const char *detail);
};
GType hal_pool_get_type (void);
diff --git a/programs/Makefile.am b/programs/Makefile.am
index 5f8bf118..ee12c56a 100644
--- a/programs/Makefile.am
+++ b/programs/Makefile.am
@@ -23,6 +23,10 @@ bin_PROGRAMS = \
gvfs-monitor-dir \
$(NULL)
+bin_SCRIPTS = \
+ gvfs-less \
+ $(NULL)
+
gvfs_cat_SOURCES = gvfs-cat.c
gvfs_cat_LDADD = $(libraries)
diff --git a/programs/gvfs-mount.c b/programs/gvfs-mount.c
index 86bd0ed5..7b9c29ef 100644
--- a/programs/gvfs-mount.c
+++ b/programs/gvfs-mount.c
@@ -34,10 +34,12 @@ static GMainLoop *main_loop;
static gboolean mount_mountable = FALSE;
+static gboolean mount_unmount = FALSE;
static GOptionEntry entries[] =
{
{ "mountable", 'm', 0, G_OPTION_ARG_NONE, &mount_mountable, "Mount as mountable", NULL },
+ { "unmount", 'u', 0, G_OPTION_ARG_NONE, &mount_unmount, "Unmount", NULL},
{ NULL }
};
@@ -170,6 +172,48 @@ mount (GFile *file)
outstanding_mounts++;
}
+static void
+unmount_done_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ gboolean succeeded;
+ GError *error = NULL;
+
+ succeeded = g_mount_unmount_finish (G_MOUNT (object), res, &error);
+
+ g_object_unref (G_MOUNT (object));
+
+ if (!succeeded)
+ g_print ("Error unmounting mount: %s\n", error->message);
+
+ outstanding_mounts--;
+
+ if (outstanding_mounts == 0)
+ g_main_loop_quit (main_loop);
+}
+
+static void
+unmount (GFile *file)
+{
+ GMount *mount;
+ GError *error = NULL;
+
+ if (file == NULL)
+ return;
+
+ mount = g_file_find_enclosing_mount (file, NULL, &error);
+ if (mount == NULL)
+ {
+ g_print ("Error finding enclosing mount: %s\n", error->message);
+ return;
+ }
+
+ g_mount_unmount (mount, NULL, unmount_done_cb, NULL);
+
+ outstanding_mounts++;
+}
+
int
main (int argc, char *argv[])
{
@@ -193,8 +237,11 @@ main (int argc, char *argv[])
for (i = 1; i < argc; i++) {
file = g_file_new_for_commandline_arg (argv[i]);
- mount (file);
- g_object_unref (file);
+ if (mount_unmount)
+ unmount (file);
+ else
+ mount (file);
+ g_object_unref (file);
}
}