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