+2007-12-14 David Zeuthen <davidz@redhat.com>
+
+ * Makefile.am:
+ * gio.symbols:
+ * gmount.c: (g_mount_get_uuid), (g_mount_can_eject),
+ (g_mount_eject), (g_mount_eject_finish):
+ * gmount.h:
+ * gunionvolumemonitor.c: (g_union_volume_monitor_finalize),
+ (get_volume_for_uuid), (get_mount_for_uuid),
+ (g_union_volume_monitor_class_init),
+ (get_default_native_type_with_exclude), (get_default_native_type),
+ (get_native_type), (update_native_type),
+ (g_union_volume_monitor_init), (_g_mount_get_for_mount_path):
+ * gunixmount.c: (_g_unix_mount_new), (g_unix_mount_get_uuid),
+ (g_unix_mount_can_eject), (eject_unmount_cb),
+ (eject_unmount_read_error), (eject_unmount_do),
+ (g_unix_mount_unmount), (g_unix_mount_eject),
+ (g_unix_mount_eject_finish), (g_unix_mount_mount_iface_init):
+ * gunixmounts.c: (g_unix_mount_guess_can_eject),
+ (g_unix_mount_point_guess_can_eject):
+ * gunixmounts.h:
+ * gunixvolume.c: (_g_unix_volume_new), (g_unix_volume_get_uuid),
+ (g_unix_volume_can_eject), (g_unix_volume_get_drive),
+ (eject_mount_cb), (eject_mount_read_error), (eject_mount_do),
+ (g_unix_volume_mount), (g_unix_volume_eject),
+ (g_unix_volume_eject_finish), (g_unix_volume_volume_iface_init):
+ * gunixvolumemonitor.c: (get_volume_for_uuid),
+ (get_mount_for_uuid), (g_unix_volume_monitor_class_init),
+ (update_mounts):
+ * gvolume.c: (g_volume_get_uuid), (g_volume_can_eject),
+ (g_volume_eject), (g_volume_eject_finish):
+ * gvolume.h:
+ * gvolumemonitor.c: (g_volume_monitor_get_volume_for_uuid),
+ (g_volume_monitor_get_mount_for_uuid):
+ * gvolumemonitor.h:
+
+ Provide eject() on both GMount and GVolume and utility functions
+ to guess whether a GUnixMountPoint or GUnixMountEntry should be
+ ejected. Introduce the concept of UUID's and wire it into GVolume
+ and GMount and provide API on GVolumeMonitor to find such
+ instances. Also handle the case where an external
+ GNativeVolumeMonitor fails to initialize. Lock around the
+ _g_get_mount_for_mount_path() function such that volume monitor
+ implementations won't have to do locking themselves.
+
2007-12-17 Matthias Clasen <mclasen@redhat.com>
* gdesktopappinfo.c:
gmemoryinputstream.h \
gmemoryoutputstream.h \
gmountoperation.h \
+ gnativevolumemonitor.h \
goutputstream.h \
gseekable.h \
gsimpleasyncresult.h \
#include <gio/gmemoryoutputstream.h>
#include <gio/gsimpleasyncresult.h>
#include <gio/gioenumtypes.h>
+#include <gio/gnativevolumemonitor.h>
#undef __GIO_GIO_H_INSIDE__
g_mount_get_root
g_mount_get_name
g_mount_get_icon
+g_mount_get_uuid
g_mount_get_volume
g_mount_get_drive
g_mount_can_unmount
+g_mount_can_eject
g_mount_unmount
g_mount_unmount_finish
+g_mount_eject
+g_mount_eject_finish
#endif
#endif
g_volume_get_type G_GNUC_CONST
g_volume_get_name
g_volume_get_icon
+g_volume_get_uuid
g_volume_get_drive
g_volume_get_mount
g_volume_can_mount
+g_volume_can_eject
g_volume_mount
g_volume_mount_finish
+g_volume_eject
+g_volume_eject_finish
#endif
#endif
g_volume_monitor_get_connected_drives
g_volume_monitor_get_volumes
g_volume_monitor_get_mounts
+g_volume_monitor_get_mount_for_uuid
#endif
#if IN_FILE(__G_UNION_VOLUME_MONITOR_C__)
g_volume_monitor_get
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
/* GIO - GLib Input, Output and Streaming Library
*
* Copyright (C) 2006-2007 Red Hat, Inc.
*/
#include <config.h>
+
+#include <string.h>
+
#include "gmount.h"
#include "gmountprivate.h"
#include "gsimpleasyncresult.h"
return (* iface->get_icon) (mount);
}
-
+
+/**
+ * g_mount_get_uuid:
+ * @mount: a #GMount.
+ *
+ * Gets the UUID for the @mount. The reference is typically based on
+ * the file system UUID for the mount in question and should be
+ * considered an opaque string. Returns %NULL if there is no UUID
+ * available.
+ *
+ * Returns: the UUID for @mount or %NULL if no UUID can be computed.
+ **/
+char *
+g_mount_get_uuid (GMount *mount)
+{
+ GMountIface *iface;
+
+ g_return_val_if_fail (G_IS_MOUNT (mount), NULL);
+
+ iface = G_MOUNT_GET_IFACE (mount);
+
+ return (* iface->get_uuid) (mount);
+}
+
/**
* g_mount_get_volume:
* @mount: a #GMount.
return (* iface->can_unmount) (mount);
}
+/**
+ * g_mount_can_eject:
+ * @mount: a #GMount.
+ *
+ * Checks if @mount can be eject.
+ *
+ * Returns: %TRUE if the @mount can be ejected.
+ **/
+gboolean
+g_mount_can_eject (GMount *mount)
+{
+ GMountIface *iface;
+
+ g_return_val_if_fail (G_IS_MOUNT (mount), FALSE);
+
+ iface = G_MOUNT_GET_IFACE (mount);
+
+ return (* iface->can_eject) (mount);
+}
+
/**
* g_mount_unmount:
* @mount: a #GMount.
return (* iface->unmount_finish) (mount, result, error);
}
+
+/**
+ * g_mount_eject:
+ * @mount: a #GMount.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: a #GAsyncReadyCallback.
+ * @user_data: user data passed to @callback.
+ *
+ * Ejects a mount. This is an asynchronous operation, and is
+ * finished by calling g_mount_eject_finish() with the @mount
+ * and #GAsyncResults data returned in the @callback.
+ **/
+void
+g_mount_eject (GMount *mount,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GMountIface *iface;
+
+ g_return_if_fail (G_IS_MOUNT (mount));
+
+ iface = G_MOUNT_GET_IFACE (mount);
+
+ if (iface->eject == NULL)
+ {
+ g_simple_async_report_error_in_idle (G_OBJECT (mount),
+ callback, user_data,
+ G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("mount doesn't implement eject"));
+
+ return;
+ }
+
+ (* iface->eject) (mount, cancellable, callback, user_data);
+}
+
+/**
+ * g_mount_eject_finish:
+ * @mount: a #GMount.
+ * @result: a #GAsyncResult.
+ * @error: a #GError location to store the error occuring, or %NULL to
+ * ignore.
+ *
+ * Finishes ejecting a mount. If any errors occured during the operation,
+ * @error will be set to contain the errors and %FALSE will be returned.
+ *
+ * Returns: %TRUE if the mount was successfully ejected. %FALSE otherwise.
+ **/
+gboolean
+g_mount_eject_finish (GMount *mount,
+ GAsyncResult *result,
+ GError **error)
+{
+ GMountIface *iface;
+
+ g_return_val_if_fail (G_IS_MOUNT (mount), FALSE);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+ if (G_IS_SIMPLE_ASYNC_RESULT (result))
+ {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+ }
+
+ iface = G_MOUNT_GET_IFACE (mount);
+ return (* iface->eject_finish) (mount, result, error);
+}
+
#define __G_MOUNT_C__
#include "gioaliasdef.c"
* @get_root: Gets a #GFile to the root directory of the #GMount.
* @get_name: Gets a string containing the name of the #GMount.
* @get_icon: Gets a #GIcon for the #GMount.
+ * @get_uuid: Gets the UUID for the #GMount. The reference is typically based on the file system UUID for the mount in question and should be considered an opaque string. Returns %NULL if there is no UUID available.
* @get_volume: Gets a #GVolume the mount is located on. Returns %NULL if the #GMount is not associated with a #GVolume.
* @get_drive: Gets a #GDrive the volume of the mount is located on. Returns %NULL if the #GMount is not associated with a #GDrive or a #GVolume. This is convenience method for getting the #GVolume and using that to get the #GDrive.
* @can_unmount: Checks if a #GMount can be unmounted.
+ * @can_eject: Checks if a #GMount can be ejected.
* @unmount: Starts unmounting a #GMount.
* @unmount_finish: Finishes an unmounting operation.
+ * @eject: Starts ejecting a #GMount.
+ * @eject_finish: Finishes an eject operation.
*
* Interface for implementing operations for mounts.
**/
GFile * (*get_root) (GMount *mount);
char * (*get_name) (GMount *mount);
GIcon * (*get_icon) (GMount *mount);
+ char * (*get_uuid) (GMount *mount);
GVolume * (*get_volume) (GMount *mount);
GDrive * (*get_drive) (GMount *mount);
gboolean (*can_unmount) (GMount *mount);
+ gboolean (*can_eject) (GMount *mount);
void (*unmount) (GMount *mount,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gboolean (*unmount_finish) (GMount *mount,
GAsyncResult *result,
GError **error);
+ void (*eject) (GMount *mount,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (*eject_finish) (GMount *mount,
+ GAsyncResult *result,
+ GError **error);
};
GType g_mount_get_type (void) G_GNUC_CONST;
GFile * g_mount_get_root (GMount *mount);
char * g_mount_get_name (GMount *mount);
GIcon * g_mount_get_icon (GMount *mount);
+char * g_mount_get_uuid (GMount *mount);
GVolume * g_mount_get_volume (GMount *mount);
GDrive * g_mount_get_drive (GMount *mount);
gboolean g_mount_can_unmount (GMount *mount);
+gboolean g_mount_can_eject (GMount *mount);
void g_mount_unmount (GMount *mount,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
gboolean g_mount_unmount_finish (GMount *mount,
- GAsyncResult *result,
- GError **error);
+ GAsyncResult *result,
+ GError **error);
+void g_mount_eject (GMount *mount,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean g_mount_eject_finish (GMount *mount,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS
g_union_volume_monitor_finalize (GObject *object)
{
GUnionVolumeMonitor *monitor;
-
+ GVolumeMonitor *child_monitor;
+
monitor = G_UNION_VOLUME_MONITOR (object);
- while (monitor->monitors != NULL)
- g_union_volume_monitor_remove_monitor (monitor,
- monitor->monitors->data);
+ while (monitor->monitors != NULL) {
+ child_monitor = monitor->monitors->data;
+ g_union_volume_monitor_remove_monitor (monitor,
+ child_monitor);
+ g_object_unref (child_monitor);
+ }
+
if (G_OBJECT_CLASS (g_union_volume_monitor_parent_class)->finalize)
(*G_OBJECT_CLASS (g_union_volume_monitor_parent_class)->finalize) (object);
return res;
}
+static GVolume *
+get_volume_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
+{
+ GUnionVolumeMonitor *monitor;
+ GVolumeMonitor *child_monitor;
+ GVolume *volume;
+ GList *l;
+
+ monitor = G_UNION_VOLUME_MONITOR (volume_monitor);
+
+ volume = NULL;
+
+ G_LOCK (the_volume_monitor);
+
+ for (l = monitor->monitors; l != NULL; l = l->next)
+ {
+ child_monitor = l->data;
+
+ volume = g_volume_monitor_get_volume_for_uuid (child_monitor, uuid);
+ if (volume != NULL)
+ break;
+
+ }
+
+ G_UNLOCK (the_volume_monitor);
+
+ return volume;
+}
+
+static GMount *
+get_mount_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
+{
+ GUnionVolumeMonitor *monitor;
+ GVolumeMonitor *child_monitor;
+ GMount *mount;
+ GList *l;
+
+ monitor = G_UNION_VOLUME_MONITOR (volume_monitor);
+
+ mount = NULL;
+
+ G_LOCK (the_volume_monitor);
+
+ for (l = monitor->monitors; l != NULL; l = l->next)
+ {
+ child_monitor = l->data;
+
+ mount = g_volume_monitor_get_mount_for_uuid (child_monitor, uuid);
+ if (mount != NULL)
+ break;
+
+ }
+
+ G_UNLOCK (the_volume_monitor);
+
+ return mount;
+}
+
static void
g_union_volume_monitor_class_init (GUnionVolumeMonitorClass *klass)
{
monitor_class->get_connected_drives = get_connected_drives;
monitor_class->get_volumes = get_volumes;
monitor_class->get_mounts = get_mounts;
+ monitor_class->get_volume_for_uuid = get_volume_for_uuid;
+ monitor_class->get_mount_for_uuid = get_mount_for_uuid;
}
static void
g_signal_handlers_disconnect_by_func (child_monitor, child_drive_changed, union_monitor);
}
-static gpointer
-get_default_native_type (gpointer data)
+static GType
+get_default_native_type_with_exclude (GType type_to_exclude)
{
GNativeVolumeMonitorClass *klass;
GType *monitors;
guint n_monitors;
GType native_type;
- GType *ret = (GType *) data;
int native_prio;
int i;
/* Ensure vfs in modules loaded */
_g_io_modules_ensure_loaded ();
-
+
monitors = g_type_children (G_TYPE_NATIVE_VOLUME_MONITOR, &n_monitors);
native_type = 0;
native_prio = -1;
for (i = 0; i < n_monitors; i++)
{
- klass = G_NATIVE_VOLUME_MONITOR_CLASS (g_type_class_ref (monitors[i]));
- if (klass->priority > native_prio)
+ if (monitors[i] != type_to_exclude)
{
- native_prio = klass->priority;
- native_type = monitors[i];
- }
+ klass = G_NATIVE_VOLUME_MONITOR_CLASS (g_type_class_ref (monitors[i]));
+
+ if (klass->priority > native_prio)
+ {
+ native_prio = klass->priority;
+ native_type = monitors[i];
+ }
- g_type_class_unref (klass);
+ g_type_class_unref (klass);
+ }
}
g_free (monitors);
- *ret = native_type;
+ return native_type;
+}
+static gpointer
+get_default_native_type (gpointer data)
+{
+ GType *ret = (GType *) data;
+
+ *ret = get_default_native_type_with_exclude (G_TYPE_INVALID);
return NULL;
}
+static GOnce _once_init = G_ONCE_INIT;
+static GType _type = G_TYPE_INVALID;
+
static GType
-get_native_type (void)
+get_native_type ()
{
- static GOnce once_init = G_ONCE_INIT;
- static GType type = G_TYPE_INVALID;
- g_once (&once_init, get_default_native_type, &type);
+ g_once (&_once_init, get_default_native_type, &_type);
- return type;
+ return _type;
+}
+
+static void
+update_native_type (GType type)
+{
+ _type = type;
}
static void
if (native_type != G_TYPE_INVALID)
{
monitor = g_object_new (native_type, NULL);
- g_union_volume_monitor_add_monitor (union_monitor, monitor);
- g_object_unref (monitor);
+ /* A native file monitor (the hal one if hald isn't running for
+ * example) may very well fail so handle falling back to the
+ * native one shipped with gio (e.g. GUnixVolumeMonitor)
+ */
+ if (monitor == NULL)
+ {
+ native_type = get_default_native_type_with_exclude (native_type);
+ monitor = g_object_new (native_type, NULL);
+ }
+
+ if (monitor != NULL)
+ {
+ g_union_volume_monitor_add_monitor (union_monitor, monitor);
+ g_object_unref (monitor);
+ update_native_type (native_type);
+ }
}
monitors = g_type_children (G_TYPE_VOLUME_MONITOR, &n_monitors);
return NULL;
mount = NULL;
-
+
klass = G_NATIVE_VOLUME_MONITOR_CLASS (g_type_class_ref (native_type));
if (klass->get_mount_for_mount_path)
- mount = klass->get_mount_for_mount_path (mount_path);
+ {
+ G_LOCK (the_volume_monitor);
+ mount = klass->get_mount_for_mount_path (mount_path);
+ G_UNLOCK (the_volume_monitor);
+ }
+
+ /* TODO: How do we know this succeeded? Keep in mind that the native
+ * volume monitor may fail (e.g. not being able to connect to
+ * hald). Is the get_mount_for_mount_path() method allowed to
+ * return NULL? Seems like it is ... probably the method needs
+ * to take a boolean and write if it succeeds or not.. Messy.
+ * Very messy.
+ */
g_type_class_unref (klass);
GIcon *icon;
char *device_path;
char *mount_path;
+
+ gboolean can_eject;
};
static void g_unix_mount_mount_iface_init (GMountIface *iface);
}
GUnixMount *
-_g_unix_mount_new (GVolumeMonitor *volume_monitor,
- GUnixMountEntry *mount_entry,
- GUnixVolume *volume)
+_g_unix_mount_new (GVolumeMonitor *volume_monitor,
+ GUnixMountEntry *mount_entry,
+ GUnixVolume *volume)
{
GUnixMount *mount;
mount->volume_monitor = volume_monitor != NULL ? g_object_ref (volume_monitor) : NULL;
mount->device_path = g_strdup (g_unix_mount_get_device_path (mount_entry));
mount->mount_path = g_strdup (g_unix_mount_get_mount_path (mount_entry));
+ mount->can_eject = g_unix_mount_guess_can_eject (mount_entry);
+
mount->name = g_unix_mount_guess_name (mount_entry);
mount->icon = g_unix_mount_guess_icon (mount_entry);
return g_object_ref (unix_mount->icon);
}
+static char *
+g_unix_mount_get_uuid (GMount *mount)
+{
+ return NULL;
+}
+
static char *
g_unix_mount_get_name (GMount *mount)
{
return TRUE;
}
+static gboolean
+g_unix_mount_can_eject (GMount *mount)
+{
+ GUnixMount *unix_mount = G_UNIX_MOUNT (mount);
+ return unix_mount->can_eject;
+}
+
typedef struct {
GUnixMount *unix_mount;
GIOChannel *error_channel;
guint error_channel_source_id;
GString *error_string;
-} UnmountOp;
+} UnmountEjectOp;
static void
-unmount_cb (GPid pid, gint status, gpointer user_data)
+eject_unmount_cb (GPid pid, gint status, gpointer user_data)
{
- UnmountOp *data = user_data;
+ UnmountEjectOp *data = user_data;
GSimpleAsyncResult *simple;
if (WEXITSTATUS (status) != 0)
}
static gboolean
-unmount_read_error (GIOChannel *channel,
+eject_unmount_read_error (GIOChannel *channel,
GIOCondition condition,
gpointer user_data)
{
char *str;
gsize str_len;
- UnmountOp *data = user_data;
+ UnmountEjectOp *data = user_data;
g_io_channel_read_to_end (channel, &str, &str_len, NULL);
g_string_append (data->error_string, str);
}
static void
-g_unix_mount_unmount (GMount *mount,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+eject_unmount_do (GMount *mount,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ char **argv)
{
GUnixMount *unix_mount = G_UNIX_MOUNT (mount);
- UnmountOp *data;
+ UnmountEjectOp *data;
GPid child_pid;
GError *error;
- char *argv[] = {"umount", NULL, NULL};
-
- if (unix_mount->mount_path != NULL)
- argv[1] = unix_mount->mount_path;
- else
- argv[1] = unix_mount->device_path;
- data = g_new0 (UnmountOp, 1);
+ data = g_new0 (UnmountEjectOp, 1);
data->unix_mount = unix_mount;
data->callback = callback;
data->user_data = user_data;
}
data->error_string = g_string_new ("");
data->error_channel = g_io_channel_unix_new (data->error_fd);
- data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, unmount_read_error, data);
- g_child_watch_add (child_pid, unmount_cb, data);
+ 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);
+}
+
+static void
+g_unix_mount_unmount (GMount *mount,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GUnixMount *unix_mount = G_UNIX_MOUNT (mount);
+ char *argv[] = {"umount", NULL, NULL};
+
+ if (unix_mount->mount_path != NULL)
+ argv[1] = unix_mount->mount_path;
+ else
+ argv[1] = unix_mount->device_path;
+
+ return eject_unmount_do (mount, cancellable, callback, user_data, argv);
}
static gboolean
return TRUE;
}
+static void
+g_unix_mount_eject (GMount *mount,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GUnixMount *unix_mount = G_UNIX_MOUNT (mount);
+ char *argv[] = {"eject", NULL, NULL};
+
+ if (unix_mount->mount_path != NULL)
+ argv[1] = unix_mount->mount_path;
+ else
+ argv[1] = unix_mount->device_path;
+
+ return eject_unmount_do (mount, cancellable, callback, user_data, argv);
+}
+
+static gboolean
+g_unix_mount_eject_finish (GMount *mount,
+ GAsyncResult *result,
+ GError **error)
+{
+ return TRUE;
+}
+
static void
g_unix_mount_mount_iface_init (GMountIface *iface)
{
iface->get_root = g_unix_mount_get_root;
iface->get_name = g_unix_mount_get_name;
iface->get_icon = g_unix_mount_get_icon;
+ iface->get_uuid = g_unix_mount_get_uuid;
iface->get_drive = g_unix_mount_get_drive;
iface->get_volume = g_unix_mount_get_volume;
iface->can_unmount = g_unix_mount_can_unmount;
+ iface->can_eject = g_unix_mount_can_eject;
iface->unmount = g_unix_mount_unmount;
iface->unmount_finish = g_unix_mount_unmount_finish;
+ iface->eject = g_unix_mount_eject;
+ iface->eject_finish = g_unix_mount_eject_finish;
}
return g_themed_icon_new (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE));
}
+gboolean
+g_unix_mount_guess_can_eject (GUnixMountEntry *mount_entry)
+{
+ GUnixMountType guessed_type;
+
+ guessed_type = g_unix_mount_guess_type (mount_entry);
+ if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
+ guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
+ return TRUE;
+
+ return FALSE;
+}
+
+gboolean
+g_unix_mount_point_guess_can_eject (GUnixMountPoint *mount_point)
+{
+ GUnixMountType guessed_type;
+
+ guessed_type = g_unix_mount_point_guess_type (mount_point);
+ if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
+ guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
+ return TRUE;
+
+ return FALSE;
+}
+
/* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */
static void
const char * g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry);
gboolean g_unix_mount_is_readonly (GUnixMountEntry *mount_entry);
gboolean g_unix_mount_is_system_internal (GUnixMountEntry *mount_entry);
+gboolean g_unix_mount_guess_can_eject (GUnixMountEntry *mount_entry);
char * g_unix_mount_guess_name (GUnixMountEntry *mount_entry);
GIcon * g_unix_mount_guess_icon (GUnixMountEntry *mount_entry);
gboolean g_unix_mount_point_is_readonly (GUnixMountPoint *mount_point);
gboolean g_unix_mount_point_is_user_mountable (GUnixMountPoint *mount_point);
gboolean g_unix_mount_point_is_loopback (GUnixMountPoint *mount_point);
+gboolean g_unix_mount_point_guess_can_eject (GUnixMountPoint *mount_point);
char * g_unix_mount_point_guess_name (GUnixMountPoint *mount_point);
GIcon * g_unix_mount_point_guess_icon (GUnixMountPoint *mount_point);
char *device_path;
char *mount_path;
+ gboolean can_eject;
+
char *name;
GIcon *icon;
};
volume->volume_monitor = volume_monitor != NULL ? g_object_ref (volume_monitor) : NULL;
volume->mount_path = g_strdup (g_unix_mount_point_get_mount_path (mountpoint));
volume->device_path = g_strdup (g_unix_mount_point_get_device_path (mountpoint));
+ volume->can_eject = g_unix_mount_point_guess_can_eject (mountpoint);
volume->name = g_unix_mount_point_guess_name (mountpoint);
volume->icon = g_unix_mount_point_guess_icon (mountpoint);
return g_strdup (unix_volume->name);
}
+static char *
+g_unix_volume_get_uuid (GVolume *volume)
+{
+ return NULL;
+}
+
static gboolean
g_unix_volume_can_mount (GVolume *volume)
{
return TRUE;
}
+static gboolean
+g_unix_volume_can_eject (GVolume *volume)
+{
+ GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
+ return unix_volume->can_eject;
+}
+
static GDrive *
g_unix_volume_get_drive (GVolume *volume)
{
- /* TODO */
return NULL;
}
GIOChannel *error_channel;
guint error_channel_source_id;
GString *error_string;
-} MountOp;
+} EjectMountOp;
static void
-mount_cb (GPid pid, gint status, gpointer user_data)
+eject_mount_cb (GPid pid, gint status, gpointer user_data)
{
- MountOp *data = user_data;
+ EjectMountOp *data = user_data;
GSimpleAsyncResult *simple;
if (WEXITSTATUS (status) != 0)
}
static gboolean
-mount_read_error (GIOChannel *channel,
+eject_mount_read_error (GIOChannel *channel,
GIOCondition condition,
gpointer user_data)
{
char *str;
gsize str_len;
- MountOp *data = user_data;
+ EjectMountOp *data = user_data;
g_io_channel_read_to_end (channel, &str, &str_len, NULL);
g_string_append (data->error_string, str);
}
static void
-g_unix_volume_mount (GVolume *volume,
- GMountOperation *mount_operation,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+eject_mount_do (GVolume *volume,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ char **argv)
{
GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
- MountOp *data;
+ EjectMountOp *data;
GPid child_pid;
GError *error;
- char *argv[] = {"mount", NULL, NULL};
-
- if (unix_volume->mount_path != NULL)
- argv[1] = unix_volume->mount_path;
- else
- argv[1] = unix_volume->device_path;
- data = g_new0 (MountOp, 1);
+ data = g_new0 (EjectMountOp, 1);
data->unix_volume = unix_volume;
data->callback = callback;
data->user_data = user_data;
}
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, mount_read_error, data);
- g_child_watch_add (child_pid, mount_cb, data);
+ data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, eject_mount_read_error, data);
+ g_child_watch_add (child_pid, eject_mount_cb, data);
}
+static void
+g_unix_volume_mount (GVolume *volume,
+ GMountOperation *mount_operation,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
+ char *argv[] = {"mount", NULL, NULL};
+
+ if (unix_volume->mount_path != NULL)
+ argv[1] = unix_volume->mount_path;
+ else
+ argv[1] = unix_volume->device_path;
+
+ eject_mount_do (volume, cancellable, callback, user_data, argv);
+}
+
static gboolean
g_unix_volume_mount_finish (GVolume *volume,
GAsyncResult *result,
return TRUE;
}
+static void
+g_unix_volume_eject (GVolume *volume,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
+ char *argv[] = {"eject", NULL, NULL};
+
+ argv[1] = unix_volume->device_path;
+
+ eject_mount_do (volume, cancellable, callback, user_data, argv);
+}
+
+static gboolean
+g_unix_volume_eject_finish (GVolume *volume,
+ GAsyncResult *result,
+ GError **error)
+{
+ return TRUE;
+}
+
static void
g_unix_volume_volume_iface_init (GVolumeIface *iface)
{
iface->get_name = g_unix_volume_get_name;
iface->get_icon = g_unix_volume_get_icon;
+ iface->get_uuid = g_unix_volume_get_uuid;
iface->get_drive = g_unix_volume_get_drive;
iface->get_mount = g_unix_volume_get_mount;
iface->can_mount = g_unix_volume_can_mount;
+ iface->can_eject = g_unix_volume_can_eject;
iface->mount_fn = g_unix_volume_mount;
iface->mount_finish = g_unix_volume_mount_finish;
+ iface->eject = g_unix_volume_eject;
+ iface->eject_finish = g_unix_volume_eject_finish;
}
return NULL;
}
+static GVolume *
+get_volume_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
+{
+ return NULL;
+}
+
+static GMount *
+get_mount_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
+{
+ return NULL;
+}
+
static GMount *
get_mount_for_mount_path (const char *mount_path)
{
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;
native_class->priority = 0;
native_class->get_mount_for_mount_path = get_mount_for_mount_path;
{
GUnixMountEntry *mount_entry = l->data;
- g_warning ("%s %s removed",
- g_unix_mount_get_mount_path (mount_entry),
- g_unix_mount_get_device_path (mount_entry));
-
mount = find_mount_by_mountpath (monitor, g_unix_mount_get_mount_path (mount_entry));
if (mount)
{
return (* iface->get_icon) (volume);
}
+
+/**
+ * g_volume_get_uuid:
+ * @volume: a #GVolume.
+ *
+ * Gets the UUID for the @volume. The reference is typically based on
+ * the file system UUID for the volume in question and should be
+ * considered an opaque string. Returns %NULL if there is no UUID
+ * available.
+ *
+ * Returns: the UUID for @volume or %NULL if no UUID can be computed.
+ **/
+char *
+g_volume_get_uuid (GVolume *volume)
+{
+ GVolumeIface *iface;
+
+ g_return_val_if_fail (G_IS_VOLUME (volume), NULL);
+
+ iface = G_VOLUME_GET_IFACE (volume);
+
+ return (* iface->get_uuid) (volume);
+}
/**
* g_volume_get_drive:
return (* iface->can_mount) (volume);
}
+/**
+ * g_volume_can_eject:
+ * @volume: a #GVolume.
+ *
+ * Checks if a volume can be ejected.
+ *
+ * Returns: %TRUE if the @volume can be ejected. %FALSE otherwise.
+ **/
+gboolean
+g_volume_can_eject (GVolume *volume)
+{
+ GVolumeIface *iface;
+
+ g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
+
+ iface = G_VOLUME_GET_IFACE (volume);
+
+ if (iface->can_eject == NULL)
+ return FALSE;
+
+ return (* iface->can_eject) (volume);
+}
+
/**
* g_volume_mount:
* @volume: a #GVolume.
return (* iface->mount_finish) (volume, result, error);
}
+/**
+ * g_volume_eject:
+ * @volume: a #GVolume.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @callback: a #GAsyncReadyCallback.
+ * @user_data: a #gpointer.
+ *
+ * Ejects a volume.
+ **/
+void
+g_volume_eject (GVolume *volume,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GVolumeIface *iface;
+
+ g_return_if_fail (G_IS_VOLUME (volume));
+
+ iface = G_VOLUME_GET_IFACE (volume);
+
+ if (iface->eject == NULL)
+ {
+ g_simple_async_report_error_in_idle (G_OBJECT (volume), callback, user_data,
+ G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("volume doesn't implement eject"));
+
+ return;
+ }
+
+ (* iface->eject) (volume, cancellable, callback, user_data);
+}
+
+/**
+ * g_volume_eject_finish:
+ * @volume: pointer to a #GVolume.
+ * @result: a #GAsyncResult.
+ * @error: a #GError.
+ *
+ * Finishes ejecting a volume.
+ *
+ * Returns: %TRUE, %FALSE if operation failed.
+ **/
+gboolean
+g_volume_eject_finish (GVolume *volume,
+ GAsyncResult *result,
+ GError **error)
+{
+ GVolumeIface *iface;
+
+ g_return_val_if_fail (G_IS_VOLUME (volume), FALSE);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+ if (G_IS_SIMPLE_ASYNC_RESULT (result))
+ {
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+ }
+
+ iface = G_VOLUME_GET_IFACE (volume);
+ return (* iface->eject_finish) (volume, result, error);
+}
+
#define __G_VOLUME_C__
#include "gioaliasdef.c"
* @changed: Changed signal that is emitted when the volume's state has changed.
* @get_name: Gets a string containing the name of the #GVolume.
* @get_icon: Gets a #GIcon for the #GVolume.
+ * @get_uuid: Gets the UUID for the #GVolume. The reference is typically based on the file system UUID for the mount in question and should be considered an opaque string. Returns %NULL if there is no UUID available.
* @get_drive: Gets a #GDrive the volume is located on. Returns %NULL if the #GVolume is not associated with a #GDrive.
* @get_mount: Gets a #GMount representing the mounted volume. Returns %NULL if the #GVolume is not mounted.
* @can_mount: Returns %TRUE if the #GVolume can be mounted.
+ * @can_eject: Checks if a #GVolume can be ejected.
* @mount_fn: Mounts a given #GVolume.
* @mount_finish: Finishes a mount operation.
+ * @eject: Ejects a given #GVolume.
+ * @eject_finish: Finishes an eject operation.
*
* Interface for implementing operations for mountable volumes.
**/
char * (*get_name) (GVolume *volume);
GIcon * (*get_icon) (GVolume *volume);
+ char * (*get_uuid) (GVolume *volume);
GDrive * (*get_drive) (GVolume *volume);
GMount * (*get_mount) (GVolume *volume);
gboolean (*can_mount) (GVolume *volume);
+ gboolean (*can_eject) (GVolume *volume);
void (*mount_fn) (GVolume *volume,
GMountOperation *mount_operation,
GCancellable *cancellable,
gboolean (*mount_finish) (GVolume *volume,
GAsyncResult *result,
GError **error);
+ void (*eject) (GVolume *volume,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (*eject_finish) (GVolume *volume,
+ GAsyncResult *result,
+ GError **error);
};
GType g_volume_get_type (void) G_GNUC_CONST;
char * g_volume_get_name (GVolume *volume);
GIcon * g_volume_get_icon (GVolume *volume);
+char * g_volume_get_uuid (GVolume *volume);
GDrive * g_volume_get_drive (GVolume *volume);
GMount * g_volume_get_mount (GVolume *volume);
gboolean g_volume_can_mount (GVolume *volume);
+gboolean g_volume_can_eject (GVolume *volume);
void g_volume_mount (GVolume *volume,
GMountOperation *mount_operation,
GCancellable *cancellable,
gboolean g_volume_mount_finish (GVolume *volume,
GAsyncResult *result,
GError **error);
+void g_volume_eject (GVolume *volume,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean g_volume_eject_finish (GVolume *volume,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS
return class->get_mounts (volume_monitor);
}
+/**
+ * g_volume_monitor_get_volume_for_uuid:
+ * @volume_monitor: a #GVolumeMonitor.
+ *
+ * Finds a #GVolume object by it's UUID (see g_volume_get_uuid())
+ *
+ * Returns: a #GVolume or %NULL if no such volume is available.
+ **/
+GVolume *
+g_volume_monitor_get_volume_for_uuid (GVolumeMonitor *volume_monitor,
+ const char *uuid)
+{
+ GVolumeMonitorClass *class;
+
+ g_return_val_if_fail (G_IS_VOLUME_MONITOR (volume_monitor), NULL);
+ g_return_val_if_fail (uuid != NULL, NULL);
+
+ class = G_VOLUME_MONITOR_GET_CLASS (volume_monitor);
+
+ return class->get_volume_for_uuid (volume_monitor, uuid);
+}
+
+/**
+ * g_volume_monitor_get_mount_for_uuid:
+ * @volume_monitor: a #GVolumeMonitor.
+ *
+ * Finds a #GMount object by it's UUID (see g_mount_get_uuid())
+ *
+ * Returns: a #GMount or %NULL if no such mount is available.
+ **/
+GMount *
+g_volume_monitor_get_mount_for_uuid (GVolumeMonitor *volume_monitor,
+ const char *uuid)
+{
+ GVolumeMonitorClass *class;
+
+ g_return_val_if_fail (G_IS_VOLUME_MONITOR (volume_monitor), NULL);
+ g_return_val_if_fail (uuid != NULL, NULL);
+
+ class = G_VOLUME_MONITOR_GET_CLASS (volume_monitor);
+
+ return class->get_mount_for_uuid (volume_monitor, uuid);
+}
+
+
#define __G_VOLUME_MONITOR_C__
#include "gioaliasdef.c"
GList * (*get_volumes) (GVolumeMonitor *volume_monitor);
GList * (*get_mounts) (GVolumeMonitor *volume_monitor);
+ GVolume * (*get_volume_for_uuid) (GVolumeMonitor *volume_monitor,
+ const char *uuid);
+
+ GMount * (*get_mount_for_uuid) (GVolumeMonitor *volume_monitor,
+ const char *uuid);
+
/*< private >*/
/* Padding for future expansion */
void (*_g_reserved1) (void);
GType g_volume_monitor_get_type (void) G_GNUC_CONST;
-GVolumeMonitor *g_volume_monitor_get (void);
-GList * g_volume_monitor_get_connected_drives (GVolumeMonitor *volume_monitor);
-GList * g_volume_monitor_get_volumes (GVolumeMonitor *volume_monitor);
-GList * g_volume_monitor_get_mounts (GVolumeMonitor *volume_monitor);
+GVolumeMonitor *g_volume_monitor_get (void);
+GList * g_volume_monitor_get_connected_drives (GVolumeMonitor *volume_monitor);
+GList * g_volume_monitor_get_volumes (GVolumeMonitor *volume_monitor);
+GList * g_volume_monitor_get_mounts (GVolumeMonitor *volume_monitor);
+GVolume * g_volume_monitor_get_volume_for_uuid (GVolumeMonitor *volume_monitor,
+ const char *uuid);
+GMount * g_volume_monitor_get_mount_for_uuid (GVolumeMonitor *volume_monitor,
+ const char *uuid);
G_END_DECLS