- Sync with the gdu-volume-monitor branch
This commit is contained in:
parent
95f1ca6f52
commit
109d2c0160
876
gdu-0010-show-user-mountable-fstab-entries.patch
Normal file
876
gdu-0010-show-user-mountable-fstab-entries.patch
Normal file
@ -0,0 +1,876 @@
|
||||
From 0f7a44dd0eac01f9783879af4ca3d3fe4a53af14 Mon Sep 17 00:00:00 2001
|
||||
From: David Zeuthen <davidz@redhat.com>
|
||||
Date: Mon, 13 Apr 2009 10:57:38 -0400
|
||||
Subject: [PATCH 10/13] show user-mountable fstab entries
|
||||
|
||||
Show all entries from /etc/fstab for which
|
||||
|
||||
- the entry is user mountable
|
||||
- the mount point is in /media or $HOME
|
||||
- if it's a /dev file make sure it exists and is not handled
|
||||
by DeviceKit-disks already
|
||||
|
||||
For example this /etc/fstab entry
|
||||
|
||||
"quad.local:/media/FusionMedia /media/FusionMedia nfs defaults,users 0 0"
|
||||
|
||||
makes Nautilus display this when unmounted
|
||||
|
||||
http://people.freedesktop.org/~david/gvfs-user-mountable-fstab-entries.png
|
||||
|
||||
and these GVolume and GMount objects to appear when mounted
|
||||
|
||||
Volume(0): FusionMedia
|
||||
Type: GProxyVolume (GProxyVolumeMonitorGdu)
|
||||
themed icons: [folder-remote] [folder]
|
||||
can_mount=1
|
||||
can_eject=0
|
||||
Mount(0): FusionMedia -> file:///media/FusionMedia
|
||||
Type: GProxyMount (GProxyVolumeMonitorGdu)
|
||||
themed icons: [folder-remote] [folder]
|
||||
can_unmount=1
|
||||
can_eject=0
|
||||
is_shadowed=0
|
||||
|
||||
This should resolve http://bugzilla.gnome.org/show_bug.cgi?id=536292
|
||||
---
|
||||
monitor/gdu/ggdumount.c | 29 +++-
|
||||
monitor/gdu/ggduvolume.c | 374 ++++++++++++++++++++++++++++++++++++---
|
||||
monitor/gdu/ggduvolume.h | 7 +-
|
||||
monitor/gdu/ggduvolumemonitor.c | 174 ++++++++++++++++++-
|
||||
4 files changed, 548 insertions(+), 36 deletions(-)
|
||||
|
||||
diff --git a/monitor/gdu/ggdumount.c b/monitor/gdu/ggdumount.c
|
||||
index 27c22d9..e074a20 100644
|
||||
--- a/monitor/gdu/ggdumount.c
|
||||
+++ b/monitor/gdu/ggdumount.c
|
||||
@@ -696,8 +696,13 @@ g_gdu_mount_unmount (GMount *_mount,
|
||||
{
|
||||
GGduMount *mount = G_GDU_MOUNT (_mount);
|
||||
GSimpleAsyncResult *simple;
|
||||
+ GduPresentable *gdu_volume;
|
||||
|
||||
- if (mount->volume == NULL)
|
||||
+ gdu_volume = NULL;
|
||||
+ if (mount->volume != NULL)
|
||||
+ gdu_volume = g_gdu_volume_get_presentable_with_cleartext (mount->volume);
|
||||
+
|
||||
+ if (mount->volume == NULL || gdu_volume == NULL)
|
||||
{
|
||||
gchar *argv[] = {"umount", NULL, NULL};
|
||||
|
||||
@@ -710,7 +715,7 @@ g_gdu_mount_unmount (GMount *_mount,
|
||||
|
||||
eject_unmount_do (_mount, cancellable, callback, user_data, argv);
|
||||
}
|
||||
- else
|
||||
+ else if (gdu_volume != NULL)
|
||||
{
|
||||
simple = g_simple_async_result_new (G_OBJECT (mount),
|
||||
callback,
|
||||
@@ -726,18 +731,25 @@ g_gdu_mount_unmount (GMount *_mount,
|
||||
else
|
||||
{
|
||||
GduDevice *device;
|
||||
- GduPresentable *volume;
|
||||
|
||||
/* TODO: honor flags */
|
||||
|
||||
- volume = g_gdu_volume_get_presentable_with_cleartext (mount->volume);
|
||||
- device = gdu_presentable_get_device (volume);
|
||||
-
|
||||
+ device = gdu_presentable_get_device (gdu_volume);
|
||||
gdu_device_op_filesystem_unmount (device, unmount_cb, simple);
|
||||
-
|
||||
g_object_unref (device);
|
||||
}
|
||||
}
|
||||
+ else
|
||||
+ {
|
||||
+ simple = g_simple_async_result_new_error (G_OBJECT (mount),
|
||||
+ callback,
|
||||
+ user_data,
|
||||
+ G_IO_ERROR,
|
||||
+ G_IO_ERROR_FAILED,
|
||||
+ _("Operation not supported by backend"));
|
||||
+ g_simple_async_result_complete (simple);
|
||||
+ g_object_unref (simple);
|
||||
+ }
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -855,7 +867,8 @@ g_gdu_mount_guess_content_type_sync (GMount *_mount,
|
||||
{
|
||||
GduPresentable *presentable;
|
||||
presentable = g_gdu_volume_get_presentable_with_cleartext (mount->volume);
|
||||
- device = gdu_presentable_get_device (presentable);
|
||||
+ if (presentable != NULL)
|
||||
+ device = gdu_presentable_get_device (presentable);
|
||||
}
|
||||
|
||||
/* doesn't make sense to probe blank discs - look at the disc type instead */
|
||||
diff --git a/monitor/gdu/ggduvolume.c b/monitor/gdu/ggduvolume.c
|
||||
index 6779f0f..49494a1 100644
|
||||
--- a/monitor/gdu/ggduvolume.c
|
||||
+++ b/monitor/gdu/ggduvolume.c
|
||||
@@ -35,12 +35,22 @@
|
||||
#include "ggduvolume.h"
|
||||
#include "ggdumount.h"
|
||||
|
||||
+/* for BUFSIZ */
|
||||
+#include <stdio.h>
|
||||
+
|
||||
#include "polkit.h"
|
||||
|
||||
typedef struct MountOpData MountOpData;
|
||||
|
||||
static void cancel_pending_mount_op (MountOpData *data);
|
||||
|
||||
+static void g_gdu_volume_mount_unix_mount_point (GGduVolume *volume,
|
||||
+ GMountMountFlags flags,
|
||||
+ GMountOperation *mount_operation,
|
||||
+ GCancellable *cancellable,
|
||||
+ GAsyncReadyCallback callback,
|
||||
+ gpointer user_data);
|
||||
+
|
||||
struct _GGduVolume
|
||||
{
|
||||
GObject parent;
|
||||
@@ -49,8 +59,12 @@ struct _GGduVolume
|
||||
GGduMount *mount; /* owned by volume monitor */
|
||||
GGduDrive *drive; /* owned by volume monitor */
|
||||
|
||||
+ /* only set if constructed via new() */
|
||||
GduVolume *gdu_volume;
|
||||
|
||||
+ /* only set if constructed via new_for_unix_mount_point() */
|
||||
+ GUnixMountPoint *unix_mount_point;
|
||||
+
|
||||
/* if the volume is encrypted, this is != NULL when unlocked */
|
||||
GduVolume *cleartext_gdu_volume;
|
||||
|
||||
@@ -60,7 +74,7 @@ struct _GGduVolume
|
||||
*/
|
||||
MountOpData *pending_mount_op;
|
||||
|
||||
- /* the following members need to be set upon construction */
|
||||
+ /* the following members need to be set upon construction, see constructors and update_volume() */
|
||||
GIcon *icon;
|
||||
GFile *activation_root;
|
||||
gchar *name;
|
||||
@@ -110,6 +124,11 @@ g_gdu_volume_finalize (GObject *object)
|
||||
g_object_unref (volume->gdu_volume);
|
||||
}
|
||||
|
||||
+ if (volume->unix_mount_point != NULL)
|
||||
+ {
|
||||
+ g_unix_mount_point_free (volume->unix_mount_point);
|
||||
+ }
|
||||
+
|
||||
if (volume->cleartext_gdu_volume != NULL)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (volume->cleartext_gdu_volume, gdu_cleartext_volume_removed, volume);
|
||||
@@ -174,6 +193,30 @@ update_volume (GGduVolume *volume)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
+ /* if the volume is a fstab mount point, get the data from there */
|
||||
+ if (volume->unix_mount_point != NULL)
|
||||
+ {
|
||||
+ volume->can_mount = TRUE;
|
||||
+ volume->should_automount = FALSE;
|
||||
+
|
||||
+ g_free (volume->device_file);
|
||||
+ volume->device_file = g_strdup (g_unix_mount_point_get_device_path (volume->unix_mount_point));
|
||||
+
|
||||
+ if (volume->icon != NULL)
|
||||
+ g_object_unref (volume->icon);
|
||||
+ if (g_strcmp0 (g_unix_mount_point_get_fs_type (volume->unix_mount_point), "nfs") == 0)
|
||||
+ volume->icon = g_themed_icon_new_with_default_fallbacks ("folder-remote");
|
||||
+ else
|
||||
+ volume->icon = g_unix_mount_point_guess_icon (volume->unix_mount_point);
|
||||
+
|
||||
+ g_free (volume->name);
|
||||
+ volume->name = g_unix_mount_point_guess_name (volume->unix_mount_point);
|
||||
+
|
||||
+ //volume->can_eject = g_unix_mount_point_guess_can_eject (volume->unix_mount_point);
|
||||
+
|
||||
+ goto update_done;
|
||||
+ }
|
||||
+
|
||||
/* in with the new */
|
||||
device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume));
|
||||
pool = gdu_device_get_pool (device);
|
||||
@@ -347,6 +390,8 @@ update_volume (GGduVolume *volume)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
+ update_done:
|
||||
+
|
||||
/* compute whether something changed */
|
||||
changed = !((old_can_mount == volume->can_mount) &&
|
||||
(old_should_automount == volume->should_automount) &&
|
||||
@@ -412,6 +457,23 @@ gdu_cleartext_volume_job_changed (GduPresentable *presentable,
|
||||
}
|
||||
|
||||
GGduVolume *
|
||||
+g_gdu_volume_new_for_unix_mount_point (GVolumeMonitor *volume_monitor,
|
||||
+ GUnixMountPoint *unix_mount_point)
|
||||
+{
|
||||
+ GGduVolume *volume;
|
||||
+
|
||||
+ volume = g_object_new (G_TYPE_GDU_VOLUME, NULL);
|
||||
+ volume->volume_monitor = volume_monitor;
|
||||
+ g_object_add_weak_pointer (G_OBJECT (volume_monitor), (gpointer) &(volume->volume_monitor));
|
||||
+
|
||||
+ volume->unix_mount_point = unix_mount_point;
|
||||
+
|
||||
+ update_volume (volume);
|
||||
+
|
||||
+ return volume;
|
||||
+}
|
||||
+
|
||||
+GGduVolume *
|
||||
g_gdu_volume_new (GVolumeMonitor *volume_monitor,
|
||||
GduVolume *gdu_volume,
|
||||
GGduDrive *drive,
|
||||
@@ -1084,6 +1146,18 @@ g_gdu_volume_mount (GVolume *_volume,
|
||||
pool = NULL;
|
||||
device = NULL;
|
||||
|
||||
+ /* for fstab mounts, call the native mount command */
|
||||
+ if (volume->unix_mount_point != NULL)
|
||||
+ {
|
||||
+ g_gdu_volume_mount_unix_mount_point (volume,
|
||||
+ flags,
|
||||
+ mount_operation,
|
||||
+ cancellable,
|
||||
+ callback,
|
||||
+ user_data);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
if (volume->pending_mount_op != NULL)
|
||||
{
|
||||
simple = g_simple_async_result_new_error (G_OBJECT (volume),
|
||||
@@ -1204,7 +1278,7 @@ g_gdu_volume_mount_finish (GVolume *volume,
|
||||
{
|
||||
GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
|
||||
|
||||
- g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_gdu_volume_mount);
|
||||
+ //g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_gdu_volume_mount);
|
||||
|
||||
return !g_simple_async_result_propagate_error (simple, error);
|
||||
}
|
||||
@@ -1212,6 +1286,247 @@ g_gdu_volume_mount_finish (GVolume *volume,
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
typedef struct {
|
||||
+ GGduVolume *volume;
|
||||
+ GAsyncReadyCallback callback;
|
||||
+ gpointer user_data;
|
||||
+ GCancellable *cancellable;
|
||||
+ int error_fd;
|
||||
+ GIOChannel *error_channel;
|
||||
+ guint error_channel_source_id;
|
||||
+ GString *error_string;
|
||||
+
|
||||
+ guint wait_for_mount_timeout_id;
|
||||
+ gulong wait_for_mount_changed_signal_handler_id;
|
||||
+} MountPointOp;
|
||||
+
|
||||
+static void
|
||||
+mount_point_op_free (MountPointOp *data)
|
||||
+{
|
||||
+ if (data->error_channel_source_id > 0)
|
||||
+ g_source_remove (data->error_channel_source_id);
|
||||
+ if (data->error_channel != NULL)
|
||||
+ g_io_channel_unref (data->error_channel);
|
||||
+ if (data->error_string != NULL)
|
||||
+ g_string_free (data->error_string, TRUE);
|
||||
+ if (data->error_fd > 0)
|
||||
+ close (data->error_fd);
|
||||
+ g_free (data);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mount_point_op_changed_cb (GVolume *volume,
|
||||
+ gpointer user_data)
|
||||
+{
|
||||
+ MountPointOp *data = user_data;
|
||||
+ GSimpleAsyncResult *simple;
|
||||
+
|
||||
+ /* keep waiting if the mount hasn't appeared */
|
||||
+ if (data->volume->mount == NULL)
|
||||
+ goto out;
|
||||
+
|
||||
+ simple = g_simple_async_result_new (G_OBJECT (data->volume),
|
||||
+ data->callback,
|
||||
+ data->user_data,
|
||||
+ NULL);
|
||||
+ /* complete in idle to make sure the mount is added before we return */
|
||||
+ g_simple_async_result_complete_in_idle (simple);
|
||||
+ g_object_unref (simple);
|
||||
+
|
||||
+ g_signal_handler_disconnect (data->volume, data->wait_for_mount_changed_signal_handler_id);
|
||||
+ g_source_remove (data->wait_for_mount_timeout_id);
|
||||
+
|
||||
+ mount_point_op_free (data);
|
||||
+
|
||||
+ out:
|
||||
+ ;
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+mount_point_op_never_appeared_cb (gpointer user_data)
|
||||
+{
|
||||
+ MountPointOp *data = user_data;
|
||||
+ GSimpleAsyncResult *simple;
|
||||
+
|
||||
+ simple = g_simple_async_result_new_error (G_OBJECT (data->volume),
|
||||
+ data->callback,
|
||||
+ data->user_data,
|
||||
+ G_IO_ERROR,
|
||||
+ G_IO_ERROR_FAILED,
|
||||
+ "Timeout waiting for mount to appear");
|
||||
+ g_simple_async_result_complete (simple);
|
||||
+ g_object_unref (simple);
|
||||
+
|
||||
+ g_signal_handler_disconnect (data->volume, data->wait_for_mount_changed_signal_handler_id);
|
||||
+ g_source_remove (data->wait_for_mount_timeout_id);
|
||||
+
|
||||
+ mount_point_op_free (data);
|
||||
+
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mount_point_op_cb (GPid pid, gint status, gpointer user_data)
|
||||
+{
|
||||
+ MountPointOp *data = user_data;
|
||||
+ GSimpleAsyncResult *simple;
|
||||
+
|
||||
+ g_spawn_close_pid (pid);
|
||||
+
|
||||
+ if (WEXITSTATUS (status) != 0)
|
||||
+ {
|
||||
+ GError *error;
|
||||
+ error = g_error_new_literal (G_IO_ERROR,
|
||||
+ G_IO_ERROR_FAILED,
|
||||
+ data->error_string->str);
|
||||
+ simple = g_simple_async_result_new_from_error (G_OBJECT (data->volume),
|
||||
+ data->callback,
|
||||
+ data->user_data,
|
||||
+ error);
|
||||
+ g_error_free (error);
|
||||
+ g_simple_async_result_complete (simple);
|
||||
+ g_object_unref (simple);
|
||||
+ mount_point_op_free (data);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* wait for the GMount to appear - this is to honor this requirement
|
||||
+ *
|
||||
+ * "If the mount operation succeeded, g_volume_get_mount() on
|
||||
+ * volume is guaranteed to return the mount right after calling
|
||||
+ * this function; there's no need to listen for the
|
||||
+ * 'mount-added' signal on GVolumeMonitor."
|
||||
+ *
|
||||
+ * So we set up a signal handler waiting for it to appear. We also set up
|
||||
+ * a timer for handling the case when it never appears.
|
||||
+ */
|
||||
+ if (data->volume->mount == NULL)
|
||||
+ {
|
||||
+ /* no need to ref, GSimpleAsyncResult has a ref on data->volume */
|
||||
+ data->wait_for_mount_timeout_id = g_timeout_add (5 * 1000,
|
||||
+ mount_point_op_never_appeared_cb,
|
||||
+ data);
|
||||
+ data->wait_for_mount_changed_signal_handler_id = g_signal_connect (data->volume,
|
||||
+ "changed",
|
||||
+ G_CALLBACK (mount_point_op_changed_cb),
|
||||
+ data);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* have the mount already, finish up */
|
||||
+ simple = g_simple_async_result_new (G_OBJECT (data->volume),
|
||||
+ data->callback,
|
||||
+ data->user_data,
|
||||
+ NULL);
|
||||
+ g_simple_async_result_complete (simple);
|
||||
+ g_object_unref (simple);
|
||||
+ mount_point_op_free (data);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+mount_point_op_read_error (GIOChannel *channel,
|
||||
+ GIOCondition condition,
|
||||
+ gpointer user_data)
|
||||
+{
|
||||
+ MountPointOp *data = user_data;
|
||||
+ gchar buf[BUFSIZ];
|
||||
+ gsize bytes_read;
|
||||
+ GError *error;
|
||||
+ GIOStatus status;
|
||||
+
|
||||
+ error = NULL;
|
||||
+read:
|
||||
+ status = g_io_channel_read_chars (channel, buf, sizeof (buf), &bytes_read, &error);
|
||||
+ if (status == G_IO_STATUS_NORMAL)
|
||||
+ {
|
||||
+ g_string_append_len (data->error_string, buf, bytes_read);
|
||||
+ if (bytes_read == sizeof (buf))
|
||||
+ goto read;
|
||||
+ }
|
||||
+ else if (status == G_IO_STATUS_EOF)
|
||||
+ {
|
||||
+ g_string_append_len (data->error_string, buf, bytes_read);
|
||||
+ }
|
||||
+ else if (status == G_IO_STATUS_ERROR)
|
||||
+ {
|
||||
+ if (data->error_string->len > 0)
|
||||
+ g_string_append (data->error_string, "\n");
|
||||
+
|
||||
+ g_string_append (data->error_string, error->message);
|
||||
+ g_error_free (error);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+g_gdu_volume_mount_unix_mount_point (GGduVolume *volume,
|
||||
+ GMountMountFlags flags,
|
||||
+ GMountOperation *mount_operation,
|
||||
+ GCancellable *cancellable,
|
||||
+ GAsyncReadyCallback callback,
|
||||
+ gpointer user_data)
|
||||
+{
|
||||
+ MountPointOp *data;
|
||||
+ GPid child_pid;
|
||||
+ GError *error;
|
||||
+ const gchar *argv[] = {"mount", NULL, NULL};
|
||||
+
|
||||
+ argv[1] = g_unix_mount_point_get_mount_path (volume->unix_mount_point);
|
||||
+
|
||||
+ data = g_new0 (MountPointOp, 1);
|
||||
+ data->volume = volume;
|
||||
+ data->callback = callback;
|
||||
+ data->user_data = user_data;
|
||||
+ data->cancellable = cancellable;
|
||||
+
|
||||
+ error = NULL;
|
||||
+ if (!g_spawn_async_with_pipes (NULL, /* working dir */
|
||||
+ (gchar **) argv,
|
||||
+ NULL, /* envp */
|
||||
+ G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH,
|
||||
+ NULL, /* child_setup */
|
||||
+ NULL, /* user_data for child_setup */
|
||||
+ &child_pid,
|
||||
+ NULL, /* standard_input */
|
||||
+ NULL, /* standard_output */
|
||||
+ &(data->error_fd),
|
||||
+ &error))
|
||||
+ {
|
||||
+ g_assert (error != NULL);
|
||||
+ goto handle_error;
|
||||
+ }
|
||||
+
|
||||
+ data->error_string = g_string_new ("");
|
||||
+
|
||||
+ data->error_channel = g_io_channel_unix_new (data->error_fd);
|
||||
+ g_io_channel_set_flags (data->error_channel, G_IO_FLAG_NONBLOCK, &error);
|
||||
+ if (error != NULL)
|
||||
+ goto handle_error;
|
||||
+
|
||||
+ data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, mount_point_op_read_error, data);
|
||||
+ g_child_watch_add (child_pid, mount_point_op_cb, data);
|
||||
+
|
||||
+handle_error:
|
||||
+ if (error != NULL)
|
||||
+ {
|
||||
+ GSimpleAsyncResult *simple;
|
||||
+ simple = g_simple_async_result_new_from_error (G_OBJECT (data->volume),
|
||||
+ data->callback,
|
||||
+ data->user_data,
|
||||
+ error);
|
||||
+ g_simple_async_result_complete (simple);
|
||||
+ g_object_unref (simple);
|
||||
+
|
||||
+ mount_point_op_free (data);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* ---------------------------------------------------------------------------------------------------- */
|
||||
+
|
||||
+typedef struct {
|
||||
GObject *object;
|
||||
GAsyncReadyCallback callback;
|
||||
gpointer user_data;
|
||||
@@ -1300,19 +1615,22 @@ g_gdu_volume_get_identifier (GVolume *_volume,
|
||||
|
||||
id = NULL;
|
||||
|
||||
- device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume));
|
||||
+ if (volume->gdu_volume != NULL)
|
||||
+ {
|
||||
+ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume));
|
||||
|
||||
- label = gdu_device_id_get_label (device);
|
||||
- uuid = gdu_device_id_get_uuid (device);
|
||||
+ label = gdu_device_id_get_label (device);
|
||||
+ uuid = gdu_device_id_get_uuid (device);
|
||||
|
||||
- g_object_unref (device);
|
||||
+ g_object_unref (device);
|
||||
|
||||
- if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0)
|
||||
- id = g_strdup (volume->device_file);
|
||||
- else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_LABEL) == 0)
|
||||
- id = strlen (label) > 0 ? g_strdup (label) : NULL;
|
||||
- else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UUID) == 0)
|
||||
- id = strlen (uuid) > 0 ? g_strdup (uuid) : NULL;
|
||||
+ if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0)
|
||||
+ id = g_strdup (volume->device_file);
|
||||
+ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_LABEL) == 0)
|
||||
+ id = strlen (label) > 0 ? g_strdup (label) : NULL;
|
||||
+ else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UUID) == 0)
|
||||
+ id = strlen (uuid) > 0 ? g_strdup (uuid) : NULL;
|
||||
+ }
|
||||
|
||||
return id;
|
||||
}
|
||||
@@ -1326,19 +1644,21 @@ g_gdu_volume_enumerate_identifiers (GVolume *_volume)
|
||||
const gchar *label;
|
||||
const gchar *uuid;
|
||||
|
||||
- device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume));
|
||||
-
|
||||
- label = gdu_device_id_get_label (device);
|
||||
- uuid = gdu_device_id_get_uuid (device);
|
||||
-
|
||||
- g_object_unref (device);
|
||||
-
|
||||
p = g_ptr_array_new ();
|
||||
- g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE));
|
||||
- if (strlen (label) > 0)
|
||||
- g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_LABEL));
|
||||
- if (strlen (uuid) > 0)
|
||||
- g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UUID));
|
||||
+
|
||||
+ if (volume->gdu_volume != NULL)
|
||||
+ {
|
||||
+ device = gdu_presentable_get_device (GDU_PRESENTABLE (volume->gdu_volume));
|
||||
+ label = gdu_device_id_get_label (device);
|
||||
+ uuid = gdu_device_id_get_uuid (device);
|
||||
+ g_object_unref (device);
|
||||
+
|
||||
+ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE));
|
||||
+ if (strlen (label) > 0)
|
||||
+ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_LABEL));
|
||||
+ if (strlen (uuid) > 0)
|
||||
+ g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UUID));
|
||||
+ }
|
||||
|
||||
g_ptr_array_add (p, NULL);
|
||||
|
||||
@@ -1452,3 +1772,9 @@ g_gdu_volume_get_presentable_with_cleartext (GGduVolume *volume)
|
||||
|
||||
return GDU_PRESENTABLE (ret);
|
||||
}
|
||||
+
|
||||
+GUnixMountPoint *
|
||||
+g_gdu_volume_get_unix_mount_point (GGduVolume *volume)
|
||||
+{
|
||||
+ return volume->unix_mount_point;
|
||||
+}
|
||||
diff --git a/monitor/gdu/ggduvolume.h b/monitor/gdu/ggduvolume.h
|
||||
index 8fd7358..a230d28 100644
|
||||
--- a/monitor/gdu/ggduvolume.h
|
||||
+++ b/monitor/gdu/ggduvolume.h
|
||||
@@ -50,6 +50,9 @@ GGduVolume *g_gdu_volume_new (GVolumeMonitor *volume_monitor,
|
||||
GGduDrive *drive,
|
||||
GFile *activation_root);
|
||||
|
||||
+GGduVolume *g_gdu_volume_new_for_unix_mount_point (GVolumeMonitor *volume_monitor,
|
||||
+ GUnixMountPoint *unix_mount_point);
|
||||
+
|
||||
void g_gdu_volume_set_mount (GGduVolume *volume,
|
||||
GGduMount *mount);
|
||||
void g_gdu_volume_unset_mount (GGduVolume *volume,
|
||||
@@ -69,10 +72,12 @@ gboolean g_gdu_volume_has_uuid (GGduVolume *volume,
|
||||
gboolean g_gdu_volume_has_device_file (GGduVolume *volume,
|
||||
const gchar *device_file);
|
||||
|
||||
-GduPresentable *g_gdu_volume_get_presentable (GGduVolume *volume);
|
||||
+GduPresentable *g_gdu_volume_get_presentable (GGduVolume *volume);
|
||||
|
||||
GduPresentable *g_gdu_volume_get_presentable_with_cleartext (GGduVolume *volume);
|
||||
|
||||
+GUnixMountPoint *g_gdu_volume_get_unix_mount_point (GGduVolume *volume);
|
||||
+
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_GDU_VOLUME_H__ */
|
||||
diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c
|
||||
index caa25a0..67e2ec0 100644
|
||||
--- a/monitor/gdu/ggduvolumemonitor.c
|
||||
+++ b/monitor/gdu/ggduvolumemonitor.c
|
||||
@@ -51,6 +51,7 @@ struct _GGduVolumeMonitor {
|
||||
|
||||
GList *drives;
|
||||
GList *volumes;
|
||||
+ GList *fstab_volumes;
|
||||
GList *mounts;
|
||||
|
||||
/* we keep volumes/mounts for blank and audio discs separate to handle e.g. mixed discs properly */
|
||||
@@ -80,6 +81,9 @@ static void update_drives (GGduVolumeMonitor *monitor,
|
||||
static void update_volumes (GGduVolumeMonitor *monitor,
|
||||
GList **added_volumes,
|
||||
GList **removed_volumes);
|
||||
+static void update_fstab_volumes (GGduVolumeMonitor *monitor,
|
||||
+ GList **added_volumes,
|
||||
+ GList **removed_volumes);
|
||||
static void update_mounts (GGduVolumeMonitor *monitor,
|
||||
GList **added_mounts,
|
||||
GList **removed_mounts);
|
||||
@@ -135,6 +139,7 @@ g_gdu_volume_monitor_finalize (GObject *object)
|
||||
g_list_free (monitor->last_mounts);
|
||||
|
||||
list_free (monitor->drives);
|
||||
+ list_free (monitor->fstab_volumes);
|
||||
list_free (monitor->volumes);
|
||||
list_free (monitor->mounts);
|
||||
|
||||
@@ -171,6 +176,8 @@ get_volumes (GVolumeMonitor *volume_monitor)
|
||||
monitor = G_GDU_VOLUME_MONITOR (volume_monitor);
|
||||
|
||||
l = g_list_copy (monitor->volumes);
|
||||
+ ll = g_list_copy (monitor->fstab_volumes);
|
||||
+ l = g_list_concat (l, ll);
|
||||
ll = g_list_copy (monitor->disc_volumes);
|
||||
l = g_list_concat (l, ll);
|
||||
|
||||
@@ -211,6 +218,13 @@ get_volume_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
|
||||
goto found;
|
||||
}
|
||||
|
||||
+ for (l = monitor->fstab_volumes; l != NULL; l = l->next)
|
||||
+ {
|
||||
+ volume = l->data;
|
||||
+ if (g_gdu_volume_has_uuid (volume, uuid))
|
||||
+ goto found;
|
||||
+ }
|
||||
+
|
||||
for (l = monitor->disc_volumes; l != NULL; l = l->next)
|
||||
{
|
||||
volume = l->data;
|
||||
@@ -549,14 +563,49 @@ find_volume_for_mount_path (GGduVolumeMonitor *monitor,
|
||||
for (l = monitor->volumes; l != NULL; l = l->next)
|
||||
{
|
||||
GGduVolume *volume = l->data;
|
||||
+ if (g_gdu_volume_has_mount_path (volume, mount_path))
|
||||
+ {
|
||||
+ found = volume;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
+ for (l = monitor->fstab_volumes; l != NULL; l = l->next)
|
||||
+ {
|
||||
+ GGduVolume *volume = l->data;
|
||||
if (g_gdu_volume_has_mount_path (volume, mount_path))
|
||||
{
|
||||
found = volume;
|
||||
- break;
|
||||
+ goto out;
|
||||
}
|
||||
}
|
||||
|
||||
+ out:
|
||||
+ return found;
|
||||
+}
|
||||
+
|
||||
+static GGduVolume *
|
||||
+find_volume_for_unix_mount_point (GGduVolumeMonitor *monitor,
|
||||
+ GUnixMountPoint *unix_mount_point)
|
||||
+{
|
||||
+ GList *l;
|
||||
+ GGduVolume *found;
|
||||
+
|
||||
+ found = NULL;
|
||||
+ for (l = monitor->fstab_volumes; l != NULL; l = l->next)
|
||||
+ {
|
||||
+ GGduVolume *volume = l->data;
|
||||
+ GUnixMountPoint *volume_mount_point;
|
||||
+
|
||||
+ volume_mount_point = g_gdu_volume_get_unix_mount_point (volume);
|
||||
+ if (g_unix_mount_point_compare (unix_mount_point, volume_mount_point) == 0)
|
||||
+ {
|
||||
+ found = volume;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ out:
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -859,6 +908,7 @@ update_all (GGduVolumeMonitor *monitor,
|
||||
|
||||
update_drives (monitor, &added_drives, &removed_drives);
|
||||
update_volumes (monitor, &added_volumes, &removed_volumes);
|
||||
+ update_fstab_volumes (monitor, &added_volumes, &removed_volumes);
|
||||
update_mounts (monitor, &added_mounts, &removed_mounts);
|
||||
update_discs (monitor,
|
||||
&added_volumes, &removed_volumes,
|
||||
@@ -935,16 +985,34 @@ find_volume_for_device_file (GGduVolumeMonitor *monitor,
|
||||
const gchar *device_file)
|
||||
{
|
||||
GList *l;
|
||||
+ GGduVolume *ret;
|
||||
|
||||
+ ret = NULL;
|
||||
for (l = monitor->volumes; l != NULL; l = l->next)
|
||||
{
|
||||
GGduVolume *volume = G_GDU_VOLUME (l->data);
|
||||
|
||||
if (g_gdu_volume_has_device_file (volume, device_file))
|
||||
- return volume;
|
||||
+ {
|
||||
+ ret = volume;
|
||||
+ goto out;
|
||||
+ }
|
||||
}
|
||||
|
||||
- return NULL;
|
||||
+ ret = NULL;
|
||||
+ for (l = monitor->fstab_volumes; l != NULL; l = l->next)
|
||||
+ {
|
||||
+ GGduVolume *volume = G_GDU_VOLUME (l->data);
|
||||
+
|
||||
+ if (g_gdu_volume_has_device_file (volume, device_file))
|
||||
+ {
|
||||
+ ret = volume;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ out:
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
static GGduDrive *
|
||||
@@ -1189,6 +1257,106 @@ update_volumes (GGduVolumeMonitor *monitor,
|
||||
}
|
||||
|
||||
static void
|
||||
+update_fstab_volumes (GGduVolumeMonitor *monitor,
|
||||
+ GList **added_volumes,
|
||||
+ GList **removed_volumes)
|
||||
+{
|
||||
+ GList *fstab_mount_points;
|
||||
+ GList *cur_fstab_mount_points;
|
||||
+ GList *new_fstab_mount_points;
|
||||
+ GList *removed, *added;
|
||||
+ GList *l;
|
||||
+ GGduVolume *volume;
|
||||
+
|
||||
+ fstab_mount_points = g_unix_mount_points_get (NULL);
|
||||
+
|
||||
+ cur_fstab_mount_points = NULL;
|
||||
+ for (l = monitor->fstab_volumes; l != NULL; l = l->next)
|
||||
+ cur_fstab_mount_points = g_list_prepend (cur_fstab_mount_points, g_gdu_volume_get_unix_mount_point (G_GDU_VOLUME (l->data)));
|
||||
+
|
||||
+ new_fstab_mount_points = NULL;
|
||||
+ for (l = fstab_mount_points; l != NULL; l = l->next)
|
||||
+ {
|
||||
+ GUnixMountPoint *mount_point = l->data;
|
||||
+ const gchar *device_file;
|
||||
+
|
||||
+ /* only show user mountable mount points */
|
||||
+ if (!g_unix_mount_point_is_user_mountable (mount_point))
|
||||
+ continue;
|
||||
+
|
||||
+ /* only show stuff that can be mounted in user-visible locations */
|
||||
+ if (!_g_unix_mount_point_guess_should_display (mount_point))
|
||||
+ continue;
|
||||
+
|
||||
+ /* ignore mount point if the device doesn't exist or is handled by DeviceKit-disks */
|
||||
+ device_file = g_unix_mount_point_get_device_path (mount_point);
|
||||
+ if (g_str_has_prefix (device_file, "/dev/"))
|
||||
+ {
|
||||
+ gchar resolved_path[PATH_MAX];
|
||||
+ GduDevice *device;
|
||||
+
|
||||
+ /* doesn't exist */
|
||||
+ if (realpath (device_file, resolved_path) != 0)
|
||||
+ continue;
|
||||
+
|
||||
+ /* is handled by DKD */
|
||||
+ device = gdu_pool_get_by_device_file (monitor->pool, resolved_path);
|
||||
+ if (device != NULL)
|
||||
+ {
|
||||
+ g_object_unref (device);
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ new_fstab_mount_points = g_list_prepend (new_fstab_mount_points, mount_point);
|
||||
+ }
|
||||
+
|
||||
+ diff_sorted_lists (cur_fstab_mount_points,
|
||||
+ new_fstab_mount_points, (GCompareFunc) g_unix_mount_point_compare,
|
||||
+ &added, &removed);
|
||||
+
|
||||
+ for (l = removed; l != NULL; l = l->next)
|
||||
+ {
|
||||
+ GUnixMountPoint *mount_point = l->data;
|
||||
+ volume = find_volume_for_unix_mount_point (monitor, mount_point);
|
||||
+ if (volume != NULL)
|
||||
+ {
|
||||
+ g_gdu_volume_removed (volume);
|
||||
+ monitor->fstab_volumes = g_list_remove (monitor->fstab_volumes, volume);
|
||||
+ *removed_volumes = g_list_prepend (*removed_volumes, volume);
|
||||
+ /*g_debug ("removed volume for /etc/fstab mount point %s", g_unix_mount_point_get_mount_path (mount_point));*/
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (l = added; l != NULL; l = l->next)
|
||||
+ {
|
||||
+ GUnixMountPoint *mount_point = l->data;
|
||||
+
|
||||
+ volume = g_gdu_volume_new_for_unix_mount_point (G_VOLUME_MONITOR (monitor), mount_point);
|
||||
+ if (volume != NULL)
|
||||
+ {
|
||||
+ /* steal mount_point since g_gdu_volume_new_for_unix_mount_point() takes ownership of it */
|
||||
+ fstab_mount_points = g_list_remove (fstab_mount_points, mount_point);
|
||||
+ monitor->fstab_volumes = g_list_prepend (monitor->fstab_volumes, volume);
|
||||
+ *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume));
|
||||
+ /*g_debug ("added volume for /etc/fstab mount point %s", g_unix_mount_point_get_mount_path (mount_point));*/
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ g_unix_mount_point_free (mount_point);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ g_list_free (added);
|
||||
+ g_list_free (removed);
|
||||
+
|
||||
+ g_list_free (cur_fstab_mount_points);
|
||||
+
|
||||
+ g_list_foreach (fstab_mount_points, (GFunc) g_unix_mount_point_free, NULL);
|
||||
+ g_list_free (fstab_mount_points);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
update_mounts (GGduVolumeMonitor *monitor,
|
||||
GList **added_mounts,
|
||||
GList **removed_mounts)
|
||||
--
|
||||
1.6.2.2
|
||||
|
326
gdu-0011-Bug-576083-pre-unmount-signals-not-being-trigger.patch
Normal file
326
gdu-0011-Bug-576083-pre-unmount-signals-not-being-trigger.patch
Normal file
@ -0,0 +1,326 @@
|
||||
From 8d9fc8a777fb1b00ae371e276a14416a0987f4af Mon Sep 17 00:00:00 2001
|
||||
From: David Zeuthen <davidz@redhat.com>
|
||||
Date: Mon, 13 Apr 2009 14:20:15 -0400
|
||||
Subject: [PATCH 11/13] =?utf-8?q?Bug=20576083=20=E2=80=93=20pre-unmount=20signals=20not=20being=20triggered?=
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Basically emit GVolumeMonitor::mount-pre-unmount on the volume monitor
|
||||
and retry unmount operation a couple of times.
|
||||
---
|
||||
monitor/gdu/ggdumount.c | 177 +++++++++++++++++++++++++++++++++++++---------
|
||||
1 files changed, 142 insertions(+), 35 deletions(-)
|
||||
|
||||
diff --git a/monitor/gdu/ggdumount.c b/monitor/gdu/ggdumount.c
|
||||
index e074a20..78088d5 100644
|
||||
--- a/monitor/gdu/ggdumount.c
|
||||
+++ b/monitor/gdu/ggdumount.c
|
||||
@@ -38,6 +38,9 @@
|
||||
#include "ggdumount.h"
|
||||
#include "ggduvolume.h"
|
||||
|
||||
+#define BUSY_UNMOUNT_NUM_ATTEMPTS 5
|
||||
+#define BUSY_UNMOUNT_MS_DELAY_BETWEEN_ATTEMPTS 500
|
||||
+
|
||||
struct _GGduMount
|
||||
{
|
||||
GObject parent;
|
||||
@@ -451,26 +454,52 @@ g_gdu_mount_can_eject (GMount *_mount)
|
||||
|
||||
typedef struct {
|
||||
GMount *mount;
|
||||
+
|
||||
+ gchar **argv;
|
||||
+ guint num_attempts_left;
|
||||
+
|
||||
GAsyncReadyCallback callback;
|
||||
gpointer user_data;
|
||||
GCancellable *cancellable;
|
||||
+
|
||||
int error_fd;
|
||||
GIOChannel *error_channel;
|
||||
guint error_channel_source_id;
|
||||
GString *error_string;
|
||||
-} UnmountEjectOp;
|
||||
+
|
||||
+} UnmountOp;
|
||||
+
|
||||
+static gboolean unmount_attempt (UnmountOp *data);
|
||||
|
||||
static void
|
||||
-eject_unmount_cb (GPid pid, gint status, gpointer user_data)
|
||||
+unmount_cb (GPid pid, gint status, gpointer user_data)
|
||||
{
|
||||
- UnmountEjectOp *data = user_data;
|
||||
+ UnmountOp *data = user_data;
|
||||
GSimpleAsyncResult *simple;
|
||||
|
||||
+ g_spawn_close_pid (pid);
|
||||
+
|
||||
if (WEXITSTATUS (status) != 0)
|
||||
{
|
||||
GError *error;
|
||||
+ gint error_code;
|
||||
+
|
||||
+ error_code = G_IO_ERROR_FAILED;
|
||||
+ /* we may want to add more strstr() checks here depending on what unmount helper is being used etc... */
|
||||
+ if (data->error_string->str != NULL && strstr (data->error_string->str, "is busy") != NULL)
|
||||
+ error_code = G_IO_ERROR_BUSY;
|
||||
+
|
||||
+ if (error_code == G_IO_ERROR_BUSY && data->num_attempts_left > 0)
|
||||
+ {
|
||||
+ g_timeout_add (BUSY_UNMOUNT_MS_DELAY_BETWEEN_ATTEMPTS,
|
||||
+ (GSourceFunc) unmount_attempt,
|
||||
+ data);
|
||||
+ data->num_attempts_left -= 1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
error = g_error_new_literal (G_IO_ERROR,
|
||||
- G_IO_ERROR_FAILED,
|
||||
+ error_code,
|
||||
data->error_string->str);
|
||||
simple = g_simple_async_result_new_from_error (G_OBJECT (data->mount),
|
||||
data->callback,
|
||||
@@ -493,16 +522,19 @@ eject_unmount_cb (GPid pid, gint status, gpointer user_data)
|
||||
g_io_channel_unref (data->error_channel);
|
||||
g_string_free (data->error_string, TRUE);
|
||||
close (data->error_fd);
|
||||
- g_spawn_close_pid (pid);
|
||||
+ g_strfreev (data->argv);
|
||||
g_free (data);
|
||||
+
|
||||
+ out:
|
||||
+ ;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
-eject_unmount_read_error (GIOChannel *channel,
|
||||
- GIOCondition condition,
|
||||
- gpointer user_data)
|
||||
+unmount_read_error (GIOChannel *channel,
|
||||
+ GIOCondition condition,
|
||||
+ gpointer user_data)
|
||||
{
|
||||
- UnmountEjectOp *data = user_data;
|
||||
+ UnmountOp *data = user_data;
|
||||
gchar buf[BUFSIZ];
|
||||
gsize bytes_read;
|
||||
GError *error;
|
||||
@@ -532,26 +564,15 @@ read:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
-static void
|
||||
-eject_unmount_do (GMount *mount,
|
||||
- GCancellable *cancellable,
|
||||
- GAsyncReadyCallback callback,
|
||||
- gpointer user_data,
|
||||
- char **argv)
|
||||
+static gboolean
|
||||
+unmount_attempt (UnmountOp *data)
|
||||
{
|
||||
- UnmountEjectOp *data;
|
||||
GPid child_pid;
|
||||
GError *error;
|
||||
|
||||
- data = g_new0 (UnmountEjectOp, 1);
|
||||
- data->mount = mount;
|
||||
- data->callback = callback;
|
||||
- data->user_data = user_data;
|
||||
- data->cancellable = cancellable;
|
||||
-
|
||||
error = NULL;
|
||||
if (!g_spawn_async_with_pipes (NULL, /* working dir */
|
||||
- argv,
|
||||
+ data->argv,
|
||||
NULL, /* envp */
|
||||
G_SPAWN_DO_NOT_REAP_CHILD|G_SPAWN_SEARCH_PATH,
|
||||
NULL, /* child_setup */
|
||||
@@ -572,8 +593,8 @@ eject_unmount_do (GMount *mount,
|
||||
if (error != NULL)
|
||||
goto handle_error;
|
||||
|
||||
- data->error_channel_source_id = g_io_add_watch (data->error_channel, G_IO_IN, eject_unmount_read_error, data);
|
||||
- g_child_watch_add (child_pid, eject_unmount_cb, data);
|
||||
+ 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);
|
||||
|
||||
handle_error:
|
||||
|
||||
@@ -596,6 +617,28 @@ handle_error:
|
||||
g_error_free (error);
|
||||
g_free (data);
|
||||
}
|
||||
+
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+unmount_do (GMount *mount,
|
||||
+ GCancellable *cancellable,
|
||||
+ GAsyncReadyCallback callback,
|
||||
+ gpointer user_data,
|
||||
+ char **argv)
|
||||
+{
|
||||
+ UnmountOp *data;
|
||||
+
|
||||
+ data = g_new0 (UnmountOp, 1);
|
||||
+ data->mount = mount;
|
||||
+ data->callback = callback;
|
||||
+ data->user_data = user_data;
|
||||
+ data->cancellable = cancellable;
|
||||
+ data->num_attempts_left = BUSY_UNMOUNT_NUM_ATTEMPTS;
|
||||
+ data->argv = g_strdupv (argv);
|
||||
+
|
||||
+ unmount_attempt (data);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
@@ -619,19 +662,54 @@ luks_lock_cb (GduDevice *device,
|
||||
g_object_unref (simple);
|
||||
}
|
||||
|
||||
+static gboolean gdu_unmount_attempt (GSimpleAsyncResult *simple);
|
||||
+
|
||||
static void
|
||||
-unmount_cb (GduDevice *device,
|
||||
- GError *error,
|
||||
- gpointer user_data)
|
||||
+gdu_unmount_cb (GduDevice *device,
|
||||
+ GError *error,
|
||||
+ gpointer user_data)
|
||||
{
|
||||
GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
+ gint error_code;
|
||||
+
|
||||
+ /*g_debug ("domain=%s error_code=%d '%s'", g_quark_to_string (error->domain), error->code, error->message);*/
|
||||
+
|
||||
+ error_code = G_IO_ERROR_FAILED;
|
||||
+ if (error->domain == GDU_ERROR && error->code == GDU_ERROR_BUSY)
|
||||
+ error_code = G_IO_ERROR_BUSY;
|
||||
+
|
||||
/* We could handle PolicyKit integration here but this action is allowed by default
|
||||
* and this won't be needed when porting to PolicyKit 1.0 anyway
|
||||
*/
|
||||
- g_simple_async_result_set_from_error (simple, error);
|
||||
+
|
||||
+ if (error_code == G_IO_ERROR_BUSY)
|
||||
+ {
|
||||
+ guint num_attempts_left;
|
||||
+
|
||||
+ num_attempts_left = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (simple), "num-attempts-left"));
|
||||
+
|
||||
+ if (num_attempts_left > 0)
|
||||
+ {
|
||||
+ num_attempts_left -= 1;
|
||||
+ g_object_set_data (G_OBJECT (simple),
|
||||
+ "num-attempts-left",
|
||||
+ GUINT_TO_POINTER (num_attempts_left));
|
||||
+
|
||||
+ g_timeout_add (BUSY_UNMOUNT_MS_DELAY_BETWEEN_ATTEMPTS,
|
||||
+ (GSourceFunc) gdu_unmount_attempt,
|
||||
+ simple);
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ g_simple_async_result_set_error (simple,
|
||||
+ G_IO_ERROR,
|
||||
+ error_code,
|
||||
+ "%s",
|
||||
+ error->message);
|
||||
g_error_free (error);
|
||||
g_simple_async_result_complete (simple);
|
||||
g_object_unref (simple);
|
||||
@@ -687,6 +765,17 @@ unmount_cb (GduDevice *device,
|
||||
;
|
||||
}
|
||||
|
||||
+static gboolean
|
||||
+gdu_unmount_attempt (GSimpleAsyncResult *simple)
|
||||
+{
|
||||
+ GduDevice *device;
|
||||
+
|
||||
+ /* TODO: honor flags */
|
||||
+ device = g_object_get_data (G_OBJECT (simple), "gdu-device");
|
||||
+ gdu_device_op_filesystem_unmount (device, gdu_unmount_cb, simple);
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
static void
|
||||
g_gdu_mount_unmount (GMount *_mount,
|
||||
GMountUnmountFlags flags,
|
||||
@@ -698,6 +787,21 @@ g_gdu_mount_unmount (GMount *_mount,
|
||||
GSimpleAsyncResult *simple;
|
||||
GduPresentable *gdu_volume;
|
||||
|
||||
+ /* emit the ::mount-pre-unmount signal */
|
||||
+ g_signal_emit_by_name (mount->volume_monitor, "mount-pre-unmount", mount);
|
||||
+
|
||||
+ /* If we end up with G_IO_ERROR_BUSY, try again BUSY_UNMOUNT_NUM_ATTEMPTS times
|
||||
+ * waiting BUSY_UNMOUNT_MS_DELAY_BETWEEN_ATTEMPTS milliseconds between each
|
||||
+ * attempt.
|
||||
+ *
|
||||
+ * This is to give other processes recieving the ::mount-pre-unmount signal some
|
||||
+ * time to close file descriptors.
|
||||
+ *
|
||||
+ * TODO: Unfortunately this code is a bit messy because we take two different
|
||||
+ * codepaths depending on whether we use GDU or the native unmount command.
|
||||
+ * It would be good to clean this up.
|
||||
+ */
|
||||
+
|
||||
gdu_volume = NULL;
|
||||
if (mount->volume != NULL)
|
||||
gdu_volume = g_gdu_volume_get_presentable_with_cleartext (mount->volume);
|
||||
@@ -713,7 +817,7 @@ g_gdu_mount_unmount (GMount *_mount,
|
||||
else
|
||||
argv[1] = mount->device_file;
|
||||
|
||||
- eject_unmount_do (_mount, cancellable, callback, user_data, argv);
|
||||
+ unmount_do (_mount, cancellable, callback, user_data, argv);
|
||||
}
|
||||
else if (gdu_volume != NULL)
|
||||
{
|
||||
@@ -722,6 +826,10 @@ g_gdu_mount_unmount (GMount *_mount,
|
||||
user_data,
|
||||
NULL);
|
||||
|
||||
+ g_object_set_data (G_OBJECT (simple),
|
||||
+ "num-attempts-left",
|
||||
+ GUINT_TO_POINTER (BUSY_UNMOUNT_NUM_ATTEMPTS));
|
||||
+
|
||||
if (mount->is_burn_mount)
|
||||
{
|
||||
/* burn mounts are really never mounted... */
|
||||
@@ -731,12 +839,9 @@ g_gdu_mount_unmount (GMount *_mount,
|
||||
else
|
||||
{
|
||||
GduDevice *device;
|
||||
-
|
||||
- /* TODO: honor flags */
|
||||
-
|
||||
device = gdu_presentable_get_device (gdu_volume);
|
||||
- gdu_device_op_filesystem_unmount (device, unmount_cb, simple);
|
||||
- g_object_unref (device);
|
||||
+ g_object_set_data_full (G_OBJECT (simple), "gdu-device", device, g_object_unref);
|
||||
+ gdu_unmount_attempt (simple);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -760,6 +865,8 @@ g_gdu_mount_unmount_finish (GMount *mount,
|
||||
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
|
||||
}
|
||||
|
||||
+/* ---------------------------------------------------------------------------------------------------- */
|
||||
+
|
||||
typedef struct {
|
||||
GObject *object;
|
||||
GAsyncReadyCallback callback;
|
||||
--
|
||||
1.6.2.2
|
||||
|
@ -0,0 +1,52 @@
|
||||
From 2bce9f36bd365be284c10af6a1f74c6120adc3e8 Mon Sep 17 00:00:00 2001
|
||||
From: David Zeuthen <davidz@redhat.com>
|
||||
Date: Wed, 15 Apr 2009 11:33:36 -0400
|
||||
Subject: [PATCH 12/13] use new gnome-disk-utility API to hide unwanted devices
|
||||
|
||||
This is to resolve bugs like
|
||||
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=495170
|
||||
---
|
||||
monitor/gdu/ggduvolumemonitor.c | 12 ++++++++++++
|
||||
1 files changed, 12 insertions(+), 0 deletions(-)
|
||||
|
||||
diff --git a/monitor/gdu/ggduvolumemonitor.c b/monitor/gdu/ggduvolumemonitor.c
|
||||
index 67e2ec0..2c1f727 100644
|
||||
--- a/monitor/gdu/ggduvolumemonitor.c
|
||||
+++ b/monitor/gdu/ggduvolumemonitor.c
|
||||
@@ -720,6 +720,12 @@ should_mount_be_ignored (GduPool *pool, GduDevice *d)
|
||||
|
||||
ret = FALSE;
|
||||
|
||||
+ if (gdu_device_get_presentation_hide (d))
|
||||
+ {
|
||||
+ ret = TRUE;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
mount_path = gdu_device_get_mount_path (d);
|
||||
if (mount_path == NULL || strlen (mount_path) == 0)
|
||||
goto out;
|
||||
@@ -751,6 +757,9 @@ should_volume_be_ignored (GduPool *pool, GduVolume *volume, GList *fstab_mount_p
|
||||
|
||||
device = gdu_presentable_get_device (GDU_PRESENTABLE (volume));
|
||||
|
||||
+ if (gdu_device_get_presentation_hide (device))
|
||||
+ goto out;
|
||||
+
|
||||
usage = gdu_device_id_get_usage (device);
|
||||
type = gdu_device_id_get_type (device);
|
||||
|
||||
@@ -824,6 +833,9 @@ should_drive_be_ignored (GduPool *pool, GduDrive *d, GList *fstab_mount_points)
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ if (gdu_device_get_presentation_hide (device))
|
||||
+ goto out;
|
||||
+
|
||||
has_volumes = FALSE;
|
||||
all_volumes_are_ignored = TRUE;
|
||||
|
||||
--
|
||||
1.6.2.2
|
||||
|
99
gdu-0013-pass-the-flush-mount-option-for-vfat.patch
Normal file
99
gdu-0013-pass-the-flush-mount-option-for-vfat.patch
Normal file
@ -0,0 +1,99 @@
|
||||
From 7fd9061afbd0ec4664adb17aed706e12fd5f3eee Mon Sep 17 00:00:00 2001
|
||||
From: David Zeuthen <davidz@redhat.com>
|
||||
Date: Wed, 15 Apr 2009 14:41:27 -0400
|
||||
Subject: [PATCH 13/13] pass the 'flush' mount option for vfat
|
||||
|
||||
This mount option makes the vfat filesystem driver flush data more
|
||||
often. As a consequence
|
||||
|
||||
1. users never get to see the gnome-disk-utility notification daemon
|
||||
dialog just added
|
||||
|
||||
http://people.freedesktop.org/~david/gdu-unmount-busy-1.png
|
||||
|
||||
but that's useful for other filesystems as well.
|
||||
|
||||
2. The Nautilus copy dialog stays up until things are on the disk
|
||||
|
||||
We do this in gvfs rather than DeviceKit-disks because in some
|
||||
scenarios 'flush' may be unwanted and there is currently no way to
|
||||
turn it off (e.g. no 'noflush' or 'flush=0' option).
|
||||
|
||||
Ideally the kernel would get this kind of thing right by itself.
|
||||
---
|
||||
monitor/gdu/ggduvolume.c | 36 +++++++++++++++++++++++++++++++++---
|
||||
1 files changed, 33 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/monitor/gdu/ggduvolume.c b/monitor/gdu/ggduvolume.c
|
||||
index 49494a1..871a1c5 100644
|
||||
--- a/monitor/gdu/ggduvolume.c
|
||||
+++ b/monitor/gdu/ggduvolume.c
|
||||
@@ -648,6 +648,27 @@ g_gdu_volume_get_mount (GVolume *volume)
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
+static gchar **
|
||||
+get_mount_options (GduDevice *device)
|
||||
+{
|
||||
+ gchar **ret;
|
||||
+
|
||||
+ /* one day we might read this from user settings */
|
||||
+ if (g_strcmp0 (gdu_device_id_get_usage (device), "filesystem") == 0 &&
|
||||
+ g_strcmp0 (gdu_device_id_get_type (device), "vfat") == 0)
|
||||
+ {
|
||||
+ ret = g_new0 (gchar *, 2);
|
||||
+ ret[0] = g_strdup ("flush");
|
||||
+ ret[1] = NULL;
|
||||
+ }
|
||||
+ else
|
||||
+ ret = NULL;
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/* ---------------------------------------------------------------------------------------------------- */
|
||||
+
|
||||
struct MountOpData
|
||||
{
|
||||
GGduVolume *volume;
|
||||
@@ -735,8 +756,11 @@ mount_obtain_authz_cb (GObject *source_object,
|
||||
}
|
||||
else
|
||||
{
|
||||
+ gchar **mount_options;
|
||||
/* got the authz, now try again */
|
||||
- gdu_device_op_filesystem_mount (data->device_to_mount, mount_cb, data);
|
||||
+ mount_options = get_mount_options (data->device_to_mount);
|
||||
+ gdu_device_op_filesystem_mount (data->device_to_mount, mount_options, mount_cb, data);
|
||||
+ g_strfreev (mount_options);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -842,7 +866,10 @@ mount_cleartext_device (MountOpData *data,
|
||||
}
|
||||
else
|
||||
{
|
||||
- gdu_device_op_filesystem_mount (data->device_to_mount, mount_cb, data);
|
||||
+ gchar **mount_options;
|
||||
+ mount_options = get_mount_options (data->device_to_mount);
|
||||
+ gdu_device_op_filesystem_mount (data->device_to_mount, mount_options, mount_cb, data);
|
||||
+ g_strfreev (mount_options);
|
||||
}
|
||||
|
||||
g_object_unref (pool);
|
||||
@@ -1260,8 +1287,11 @@ g_gdu_volume_mount (GVolume *_volume,
|
||||
}
|
||||
else
|
||||
{
|
||||
+ gchar **mount_options;
|
||||
data->device_to_mount = g_object_ref (device);
|
||||
- gdu_device_op_filesystem_mount (data->device_to_mount, mount_cb, data);
|
||||
+ mount_options = get_mount_options (data->device_to_mount);
|
||||
+ gdu_device_op_filesystem_mount (data->device_to_mount, mount_options, mount_cb, data);
|
||||
+ g_strfreev (mount_options);
|
||||
}
|
||||
|
||||
out:
|
||||
--
|
||||
1.6.2.2
|
||||
|
16
gvfs.spec
16
gvfs.spec
@ -1,7 +1,7 @@
|
||||
Summary: Backends for the gio framework in GLib
|
||||
Name: gvfs
|
||||
Version: 1.2.2
|
||||
Release: 2%{?dist}
|
||||
Release: 3%{?dist}
|
||||
License: LGPLv2+
|
||||
Group: System Environment/Libraries
|
||||
URL: http://www.gtk.org
|
||||
@ -57,6 +57,13 @@ Patch107: gdu-0007-Bug-576587-allow-eject-even-on-non-ejectable-vol.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=495152
|
||||
Patch108: gdu-0008-ignore-drives-without-volumes.patch
|
||||
Patch109: gdu-0009-never-ignore-drives-without-media.patch
|
||||
# http://bugzilla.gnome.org/show_bug.cgi?id=536292
|
||||
Patch110: gdu-0010-show-user-mountable-fstab-entries.patch
|
||||
# http://bugzilla.gnome.org/show_bug.cgi?id=576083
|
||||
Patch111: gdu-0011-Bug-576083-pre-unmount-signals-not-being-trigger.patch
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=495170
|
||||
Patch112: gdu-0012-use-new-gnome-disk-utility-API-to-hide-unwanted-devi.patch
|
||||
Patch113: gdu-0013-pass-the-flush-mount-option-for-vfat.patch
|
||||
|
||||
%description
|
||||
The gvfs package provides backend implementations for the gio
|
||||
@ -152,6 +159,10 @@ media players (Media Transfer Protocol) to applications using gvfs.
|
||||
%patch107 -p1 -b .gdu-always-eject
|
||||
%patch108 -p1 -b .gdu-ignore-drives-without-volumes
|
||||
%patch109 -p1 -b .gdu-never-ignore-drives-without-media
|
||||
%patch110 -p1 -b .gdu-user-mountable-fstab-entries
|
||||
%patch111 -p1 -b .gdu-pre-unmount-signals
|
||||
%patch112 -p1 -b .gdu-unwanted-devices
|
||||
%patch113 -p1 -b .gdu-vfat-flush
|
||||
|
||||
%build
|
||||
|
||||
@ -295,6 +306,9 @@ update-desktop-database &> /dev/null ||:
|
||||
|
||||
|
||||
%changelog
|
||||
* Wed Apr 15 2009 David Zeuthen <davidz@redhat.com> - 1.2.2-3
|
||||
- Sync with the gdu-volume-monitor branch
|
||||
|
||||
* Mon Apr 13 2009 Alexander Larsson <alexl@redhat.com> - 1.2.2-2
|
||||
- Add ssh-auth-sock patch from svn
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user