diff --git a/gdu-0010-show-user-mountable-fstab-entries.patch b/gdu-0010-show-user-mountable-fstab-entries.patch new file mode 100644 index 0000000..ab03218 --- /dev/null +++ b/gdu-0010-show-user-mountable-fstab-entries.patch @@ -0,0 +1,876 @@ +From 0f7a44dd0eac01f9783879af4ca3d3fe4a53af14 Mon Sep 17 00:00:00 2001 +From: David Zeuthen +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 ++ + #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 + diff --git a/gdu-0011-Bug-576083-pre-unmount-signals-not-being-trigger.patch b/gdu-0011-Bug-576083-pre-unmount-signals-not-being-trigger.patch new file mode 100644 index 0000000..c199c06 --- /dev/null +++ b/gdu-0011-Bug-576083-pre-unmount-signals-not-being-trigger.patch @@ -0,0 +1,326 @@ +From 8d9fc8a777fb1b00ae371e276a14416a0987f4af Mon Sep 17 00:00:00 2001 +From: David Zeuthen +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 + diff --git a/gdu-0012-use-new-gnome-disk-utility-API-to-hide-unwanted-devi.patch b/gdu-0012-use-new-gnome-disk-utility-API-to-hide-unwanted-devi.patch new file mode 100644 index 0000000..10b287f --- /dev/null +++ b/gdu-0012-use-new-gnome-disk-utility-API-to-hide-unwanted-devi.patch @@ -0,0 +1,52 @@ +From 2bce9f36bd365be284c10af6a1f74c6120adc3e8 Mon Sep 17 00:00:00 2001 +From: David Zeuthen +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 + diff --git a/gdu-0013-pass-the-flush-mount-option-for-vfat.patch b/gdu-0013-pass-the-flush-mount-option-for-vfat.patch new file mode 100644 index 0000000..f86384d --- /dev/null +++ b/gdu-0013-pass-the-flush-mount-option-for-vfat.patch @@ -0,0 +1,99 @@ +From 7fd9061afbd0ec4664adb17aed706e12fd5f3eee Mon Sep 17 00:00:00 2001 +From: David Zeuthen +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 + diff --git a/gvfs.spec b/gvfs.spec index 66bc8ea..2e4e72b 100644 --- a/gvfs.spec +++ b/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 - 1.2.2-3 +- Sync with the gdu-volume-monitor branch + * Mon Apr 13 2009 Alexander Larsson - 1.2.2-2 - Add ssh-auth-sock patch from svn