[gvfs/wip/udisks2] udisks2: generate volume objects from /etc/fstab entries



commit 8a06bc172b66857c41ec08eb91815a9b8e380bf8
Author: David Zeuthen <davidz redhat com>
Date:   Thu Sep 29 19:20:33 2011 -0400

    udisks2: generate volume objects from /etc/fstab entries
    
    Signed-off-by: David Zeuthen <davidz redhat com>

 monitor/udisks2/gvfsudisks2mount.c         |   57 ++++--
 monitor/udisks2/gvfsudisks2mount.h         |    5 +-
 monitor/udisks2/gvfsudisks2utils.c         |   17 ++
 monitor/udisks2/gvfsudisks2utils.h         |    3 +-
 monitor/udisks2/gvfsudisks2volume.c        |  263 +++++++++++++++++++--------
 monitor/udisks2/gvfsudisks2volume.h        |    6 +-
 monitor/udisks2/gvfsudisks2volumemonitor.c |  256 ++++++++++++++++++++++++++--
 7 files changed, 496 insertions(+), 111 deletions(-)
---
diff --git a/monitor/udisks2/gvfsudisks2mount.c b/monitor/udisks2/gvfsudisks2mount.c
index 0c8ab54..03cba80 100644
--- a/monitor/udisks2/gvfsudisks2mount.c
+++ b/monitor/udisks2/gvfsudisks2mount.c
@@ -61,6 +61,9 @@ struct _GVfsUDisks2Mount
   /* may be NULL */
   GVfsUDisks2Volume        *volume;  /* owned by volume monitor */
 
+  /* may be NULL */
+  GUnixMountEntry *mount_entry;
+
   /* the following members are set in update_mount() */
   GFile *root;
   GIcon *icon;
@@ -117,7 +120,6 @@ gvfs_udisks2_mount_finalize (GObject *object)
   g_free (mount->mount_path);
 
   g_free (mount->mount_entry_name);
-  g_free (mount->mount_entry_fs_type);
 
   if (mount->autorun_icon != NULL)
     g_object_unref (mount->autorun_icon);
@@ -249,18 +251,7 @@ update_mount (GVfsUDisks2Mount *mount)
         mount->icon = g_object_ref (mount->autorun_icon);
       else
         {
-          const gchar *icon_name;
-          if (g_strcmp0 (mount->mount_entry_fs_type, "nfs") == 0 ||
-              g_strcmp0 (mount->mount_entry_fs_type, "nfs4") == 0 ||
-              g_strcmp0 (mount->mount_entry_fs_type, "cifs") == 0)
-            {
-              icon_name = "folder-remote";
-            }
-          else
-            {
-              icon_name = "drive-removable-media";
-            }
-          mount->icon = g_themed_icon_new_with_default_fallbacks (icon_name);
+          mount->icon = gvfs_udisks2_utils_icon_from_fs_type (g_unix_mount_get_fs_type (mount->mount_entry));
         }
 
       g_free (mount->name);
@@ -330,7 +321,7 @@ on_volume_changed (GVolume  *volume,
 
 GVfsUDisks2Mount *
 gvfs_udisks2_mount_new (GVfsUDisks2VolumeMonitor *monitor,
-                        GUnixMountEntry          *mount_entry,
+                        GUnixMountEntry          *mount_entry, /* takes ownership */
                         GVfsUDisks2Volume        *volume)
 {
   GVfsUDisks2Mount *mount = NULL;
@@ -344,9 +335,8 @@ gvfs_udisks2_mount_new (GVfsUDisks2VolumeMonitor *monitor,
 
   if (mount_entry != NULL)
     {
-      /* No ref on GUnixMountEntry so save values for later use */
+      mount->mount_entry = mount_entry; /* takes ownership */
       mount->mount_entry_name = g_unix_mount_guess_name (mount_entry);
-      mount->mount_entry_fs_type = g_strdup (g_unix_mount_get_fs_type (mount_entry));
       mount->device_file = g_strdup (g_unix_mount_get_device_path (mount_entry));
       mount->mount_path = g_strdup (g_unix_mount_get_mount_path (mount_entry));
       mount->root = g_file_new_for_path (mount->mount_path);
@@ -400,6 +390,25 @@ gvfs_udisks2_mount_unset_volume (GVfsUDisks2Mount   *mount,
     }
 }
 
+void
+gvfs_udisks2_mount_set_volume (GVfsUDisks2Mount   *mount,
+                               GVfsUDisks2Volume  *volume)
+{
+  if (mount->volume != volume)
+    {
+      if (mount->volume != NULL)
+        gvfs_udisks2_mount_unset_volume (mount, mount->volume);
+      mount->volume = volume;
+      if (mount->volume != NULL)
+        {
+          gvfs_udisks2_volume_set_mount (volume, mount);
+          /* this is for piggy backing on the name and icon of the associated volume */
+          g_signal_connect (mount->volume, "changed", G_CALLBACK (on_volume_changed), mount);
+        }
+      emit_changed (mount);
+    }
+}
+
 static GFile *
 gvfs_udisks2_mount_get_root (GMount *_mount)
 {
@@ -437,12 +446,18 @@ gvfs_udisks2_mount_has_uuid (GVfsUDisks2Mount *_mount,
 }
 
 const gchar *
-gvfs_udisks2_mount_get_mount_path (GVfsUDisks2Mount *_mount)
+gvfs_udisks2_mount_get_mount_path (GVfsUDisks2Mount *mount)
 {
-  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
   return mount->mount_path;
 }
 
+GUnixMountEntry *
+gvfs_udisks2_mount_get_mount_entry (GVfsUDisks2Mount *_mount)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
+  return mount->mount_entry;
+}
+
 static GDrive *
 gvfs_udisks2_mount_get_drive (GMount *_mount)
 {
@@ -828,6 +843,12 @@ unmount_do (UnmountData *data,
     }
 
   block = gvfs_udisks2_volume_get_block (data->mount->volume);
+  if (block == NULL)
+    {
+      unmount_do_command (data, force);
+      goto out;
+    }
+
   filesystem = udisks_object_peek_filesystem (UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (block))));
   if (filesystem == NULL)
     {
diff --git a/monitor/udisks2/gvfsudisks2mount.h b/monitor/udisks2/gvfsudisks2mount.h
index dd16564..13c9656 100644
--- a/monitor/udisks2/gvfsudisks2mount.h
+++ b/monitor/udisks2/gvfsudisks2mount.h
@@ -45,12 +45,15 @@ void              gvfs_udisks2_mount_unmounted      (GVfsUDisks2Mount         *m
 gboolean          gvfs_udisks2_mount_has_uuid       (GVfsUDisks2Mount         *mount,
                                                      const gchar              *uuid);
 
+void              gvfs_udisks2_mount_set_volume     (GVfsUDisks2Mount         *mount,
+                                                     GVfsUDisks2Volume        *volume);
 void              gvfs_udisks2_mount_unset_volume   (GVfsUDisks2Mount         *mount,
                                                      GVfsUDisks2Volume        *volume);
 gboolean          gvfs_udisks2_mount_has_volume     (GVfsUDisks2Mount         *mount,
                                                      GVfsUDisks2Volume        *volume);
 
-const gchar      *gvfs_udisks2_mount_get_mount_path (GVfsUDisks2Mount         *mount);
+const gchar      *gvfs_udisks2_mount_get_mount_path  (GVfsUDisks2Mount        *mount);
+GUnixMountEntry  *gvfs_udisks2_mount_get_mount_entry (GVfsUDisks2Mount        *mount);
 
 G_END_DECLS
 
diff --git a/monitor/udisks2/gvfsudisks2utils.c b/monitor/udisks2/gvfsudisks2utils.c
index 4cd8ca4..ebbbc13 100644
--- a/monitor/udisks2/gvfsudisks2utils.c
+++ b/monitor/udisks2/gvfsudisks2utils.c
@@ -64,3 +64,20 @@ gvfs_udisks2_utils_udisks_error_to_gio_error (GError *error)
   g_dbus_error_strip_remote_error (error);
 }
 
+
+GIcon *
+gvfs_udisks2_utils_icon_from_fs_type (const gchar *fs_type)
+{
+  const gchar *icon_name;
+  if (g_strcmp0 (fs_type, "nfs") == 0 ||
+      g_strcmp0 (fs_type, "nfs4") == 0 ||
+      g_strcmp0 (fs_type, "cifs") == 0)
+    {
+      icon_name = "folder-remote";
+    }
+  else
+    {
+      icon_name = "drive-removable-media";
+    }
+  return g_themed_icon_new_with_default_fallbacks (icon_name);
+}
diff --git a/monitor/udisks2/gvfsudisks2utils.h b/monitor/udisks2/gvfsudisks2utils.h
index 37b3cf1..8ba4ebb 100644
--- a/monitor/udisks2/gvfsudisks2utils.h
+++ b/monitor/udisks2/gvfsudisks2utils.h
@@ -31,7 +31,8 @@
 
 G_BEGIN_DECLS
 
-void gvfs_udisks2_utils_udisks_error_to_gio_error (GError *error);
+void   gvfs_udisks2_utils_udisks_error_to_gio_error (GError *error);
+GIcon *gvfs_udisks2_utils_icon_from_fs_type (const gchar *fs_type);
 
 G_END_DECLS
 
diff --git a/monitor/udisks2/gvfsudisks2volume.c b/monitor/udisks2/gvfsudisks2volume.c
index 05cd460..23394f0 100644
--- a/monitor/udisks2/gvfsudisks2volume.c
+++ b/monitor/udisks2/gvfsudisks2volume.c
@@ -56,7 +56,9 @@ struct _GVfsUDisks2Volume
   GVfsUDisks2Mount         *mount;   /* owned by volume monitor */
   GVfsUDisks2Drive         *drive;   /* owned by volume monitor */
 
+  /* exactly one of these are set */
   UDisksBlock *block;
+  GUnixMountPoint *mount_point;
 
   /* set in update_volume() */
   GIcon *icon;
@@ -99,8 +101,14 @@ gvfs_udisks2_volume_finalize (GObject *object)
       gvfs_udisks2_drive_unset_volume (volume->drive, volume);
     }
 
-  g_signal_handlers_disconnect_by_func (volume->block, G_CALLBACK (on_block_changed), volume);
-  g_object_unref (volume->block);
+  if (volume->block != NULL)
+    {
+      g_signal_handlers_disconnect_by_func (volume->block, G_CALLBACK (on_block_changed), volume);
+      g_object_unref (volume->block);
+    }
+
+  if (volume->mount_point != NULL)
+    g_unix_mount_point_free (volume->mount_point);
 
   if (volume->icon != NULL)
     g_object_unref (volume->icon);
@@ -170,67 +178,75 @@ update_volume (GVfsUDisks2Volume *volume)
   /* ---------------------------------------------------------------------------------------------------- */
   /* in with the new */
 
-  volume->dev = makedev (udisks_block_get_major (volume->block), udisks_block_get_minor (volume->block));
-  volume->device_file = udisks_block_dup_device (volume->block);
-
-  if (strlen (udisks_block_get_id_label (volume->block)) > 0)
+  if (volume->block != NULL)
     {
-      volume->name = g_strdup (udisks_block_get_id_label (volume->block));
-    }
-  else
-    {
-      s = g_format_size (udisks_block_get_size (volume->block));
-      /* Translators: This is used for volume with no filesystem label.
-       *              The first %s is the formatted size (e.g. "42.0 MB").
-       */
-      volume->name = g_strdup_printf (_("%s Volume"), s);
-      g_free (s);
-    }
+      volume->dev = makedev (udisks_block_get_major (volume->block), udisks_block_get_minor (volume->block));
+      volume->device_file = udisks_block_dup_device (volume->block);
 
-  udisks_drive = udisks_client_get_drive_for_block (gvfs_udisks2_volume_monitor_get_udisks_client (volume->monitor),
-                                                    volume->block);
-  if (udisks_drive != NULL)
-    {
-      gchar *drive_desc;
-      GIcon *drive_icon;
-      gchar *media_desc;
-      GIcon *media_icon;
-      udisks_util_get_drive_info (udisks_drive,
-                                  NULL, /* drive_name */
-                                  &drive_desc,
-                                  &drive_icon,
-                                  &media_desc,
-                                  &media_icon);
-      if (media_desc == NULL)
+      if (strlen (udisks_block_get_id_label (volume->block)) > 0)
         {
-          media_desc = drive_desc;
-          drive_desc = NULL;
+          volume->name = g_strdup (udisks_block_get_id_label (volume->block));
         }
-      if (media_icon == NULL)
+      else
         {
-          media_icon = drive_icon;
-          drive_icon = NULL;
+          s = g_format_size (udisks_block_get_size (volume->block));
+          /* Translators: This is used for volume with no filesystem label.
+           *              The first %s is the formatted size (e.g. "42.0 MB").
+           */
+          volume->name = g_strdup_printf (_("%s Volume"), s);
+          g_free (s);
         }
 
-      /* Override name for blank and audio discs */
-      if (udisks_drive_get_optical_blank (udisks_drive))
-        {
-          g_free (volume->name);
-          volume->name = g_strdup (media_desc);
-        }
-      else if (volume->activation_root != NULL && g_file_has_uri_scheme (volume->activation_root, "cdda"))
+      udisks_drive = udisks_client_get_drive_for_block (gvfs_udisks2_volume_monitor_get_udisks_client (volume->monitor),
+                                                    volume->block);
+      if (udisks_drive != NULL)
         {
-          g_free (volume->name);
-          volume->name = g_strdup (_("Audio Disc"));
+          gchar *drive_desc;
+          GIcon *drive_icon;
+          gchar *media_desc;
+          GIcon *media_icon;
+          udisks_util_get_drive_info (udisks_drive,
+                                      NULL, /* drive_name */
+                                      &drive_desc,
+                                      &drive_icon,
+                                      &media_desc,
+                                      &media_icon);
+          if (media_desc == NULL)
+            {
+              media_desc = drive_desc;
+              drive_desc = NULL;
+            }
+          if (media_icon == NULL)
+            {
+              media_icon = drive_icon;
+              drive_icon = NULL;
+            }
+
+          /* Override name for blank and audio discs */
+          if (udisks_drive_get_optical_blank (udisks_drive))
+            {
+              g_free (volume->name);
+              volume->name = g_strdup (media_desc);
+            }
+          else if (volume->activation_root != NULL && g_file_has_uri_scheme (volume->activation_root, "cdda"))
+            {
+              g_free (volume->name);
+              volume->name = g_strdup (_("Audio Disc"));
+            }
+
+          volume->icon = media_icon != NULL ? g_object_ref (media_icon) : NULL;
+
+          g_free (media_desc);
+          if (media_icon != NULL)
+            g_object_unref (media_icon);
+
+          g_object_unref (udisks_drive);
         }
-
-      volume->icon = media_icon != NULL ? g_object_ref (media_icon) : NULL;
-
-      g_free (media_desc);
-      if (media_icon != NULL)
-        g_object_unref (media_icon);
-
-      g_object_unref (udisks_drive);
+    }
+  else
+    {
+      volume->name = g_unix_mount_point_guess_name (volume->mount_point);
+      volume->icon = gvfs_udisks2_utils_icon_from_fs_type (g_unix_mount_point_get_fs_type (volume->mount_point));
     }
 
   /* ---------------------------------------------------------------------------------------------------- */
@@ -276,9 +292,11 @@ on_block_changed (GObject    *object,
     emit_changed (volume);
 }
 
+/* takes ownership of @mount_point if not NULL */
 GVfsUDisks2Volume *
 gvfs_udisks2_volume_new (GVfsUDisks2VolumeMonitor   *monitor,
                          UDisksBlock                *block,
+                         GUnixMountPoint            *mount_point,
                          GVfsUDisks2Drive           *drive,
                          GFile                      *activation_root)
 {
@@ -287,8 +305,19 @@ gvfs_udisks2_volume_new (GVfsUDisks2VolumeMonitor   *monitor,
   volume = g_object_new (GVFS_TYPE_UDISKS2_VOLUME, NULL);
   volume->monitor = monitor;
 
-  volume->block = g_object_ref (block);
-  g_signal_connect (volume->block, "notify", G_CALLBACK (on_block_changed), volume);
+  if (block != NULL)
+    {
+      volume->block = g_object_ref (block);
+      g_signal_connect (volume->block, "notify", G_CALLBACK (on_block_changed), volume);
+    }
+  else if (mount_point != NULL)
+    {
+      volume->mount_point = mount_point;
+    }
+  else
+    {
+      g_assert_not_reached ();
+    }
 
   volume->activation_root = activation_root != NULL ? g_object_ref (activation_root) : NULL;
 
@@ -449,15 +478,18 @@ gvfs_udisks2_volume_get_identifier (GVolume      *_volume,
   const gchar *uuid;
   gchar *ret = NULL;
 
-  label = udisks_block_get_id_label (volume->block);
-  uuid = udisks_block_get_id_uuid (volume->block);
-
-  if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0)
-    ret = g_strdup (volume->device_file);
-  else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_LABEL) == 0)
-    ret = strlen (label) > 0 ? g_strdup (label) : NULL;
-  else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UUID) == 0)
-    ret = strlen (uuid) > 0 ? g_strdup (uuid) : NULL;
+  if (volume->block != NULL)
+    {
+      label = udisks_block_get_id_label (volume->block);
+      uuid = udisks_block_get_id_uuid (volume->block);
+
+      if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0)
+        ret = g_strdup (volume->device_file);
+      else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_LABEL) == 0)
+        ret = strlen (label) > 0 ? g_strdup (label) : NULL;
+      else if (strcmp (kind, G_VOLUME_IDENTIFIER_KIND_UUID) == 0)
+        ret = strlen (uuid) > 0 ? g_strdup (uuid) : NULL;
+    }
 
   return ret;
 }
@@ -466,20 +498,22 @@ static gchar **
 gvfs_udisks2_volume_enumerate_identifiers (GVolume *_volume)
 {
   GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (_volume);
-  const gchar *label;
-  const gchar *uuid;
   GPtrArray *p;
 
-  label = udisks_block_get_id_label (volume->block);
-  uuid = udisks_block_get_id_uuid (volume->block);
-
   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->block != NULL)
+    {
+      const gchar *label;
+      const gchar *uuid;
+      label = udisks_block_get_id_label (volume->block);
+      uuid = udisks_block_get_id_uuid (volume->block);
+      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);
   return (gchar **) g_ptr_array_free (p, FALSE);
 }
@@ -522,8 +556,69 @@ mount_cancel_pending_op (MountData *data)
   if (data->mount_operation != NULL)
     g_signal_emit_by_name (data->mount_operation, "aborted");
   g_cancellable_cancel (data->cancellable);
+  data->volume->mount_pending_op = NULL;
+}
+
+/* ------------------------------ */
+
+static void
+do_mount_command (MountData *data)
+{
+  GError *error;
+  gint exit_status;
+  gchar *standard_error = NULL;
+  const gchar *mount_argv[3] = {"mount", NULL, NULL};
+
+  mount_argv[1] = g_unix_mount_point_get_mount_path (data->volume->mount_point);
+
+  /* TODO: we could do this async but it's probably not worth the effort */
+  error = NULL;
+  if (!g_spawn_sync (NULL,            /* working dir */
+                     (gchar **) mount_argv,
+                     NULL,            /* envp */
+                     G_SPAWN_SEARCH_PATH,
+                     NULL,            /* child_setup */
+                     NULL,            /* user_data for child_setup */
+                     NULL,            /* standard_output */
+                     &standard_error, /* standard_error */
+                     &exit_status,
+                     &error))
+    {
+      g_prefix_error (&error, "Error running mount: ");
+      g_simple_async_result_take_error (data->simple, error);
+      g_simple_async_result_complete (data->simple);
+      mount_data_free (data);
+      goto out;
+    }
+
+  /* TODO: for e.g. NFS and CIFS mounts we could do GMountOperation stuff and pipe a
+   * password to mount(8)'s stdin channel
+   */
+
+  /* we are no longer pending */
+  data->volume->mount_pending_op = NULL;
+
+  if (WIFEXITED (exit_status) && WEXITSTATUS (exit_status) == 0)
+    {
+      gvfs_udisks2_volume_monitor_update (data->volume->monitor);
+      g_simple_async_result_complete (data->simple);
+      mount_data_free (data);
+      goto out;
+    }
+
+  g_simple_async_result_set_error (data->simple,
+                                   G_IO_ERROR,
+                                   G_IO_ERROR_FAILED,
+                                   standard_error);
+  g_simple_async_result_complete (data->simple);
+  mount_data_free (data);
+
+ out:
+  g_free (standard_error);
 }
 
+/* ------------------------------ */
+
 static void
 mount_cb (GObject       *source_object,
           GAsyncResult  *res,
@@ -574,6 +669,8 @@ gvfs_udisks2_volume_mount (GVolume             *_volume,
                                             user_data,
                                             gvfs_udisks2_volume_mount);
   data->volume = g_object_ref (volume);
+  data->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL;
+  data->mount_operation = mount_operation != NULL ? g_object_ref (mount_operation) : NULL;
 
   if (volume->mount_pending_op != NULL)
     {
@@ -585,6 +682,13 @@ gvfs_udisks2_volume_mount (GVolume             *_volume,
       mount_data_free (data);
       goto out;
     }
+  volume->mount_pending_op = data;
+
+  if (volume->block == NULL)
+    {
+      do_mount_command (data);
+      goto out;
+    }
 
   filesystem = udisks_object_peek_filesystem (UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (volume->block))));
   if (filesystem == NULL)
@@ -598,10 +702,6 @@ gvfs_udisks2_volume_mount (GVolume             *_volume,
       goto out;
     }
 
-  data->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL;
-  data->mount_operation = mount_operation != NULL ? g_object_ref (mount_operation) : NULL;
-  volume->mount_pending_op = data;
-
   g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
   if (data->mount_operation == NULL)
     {
@@ -759,6 +859,13 @@ gvfs_udisks2_volume_get_block (GVfsUDisks2Volume *volume)
   return volume->block;
 }
 
+GUnixMountPoint *
+gvfs_udisks2_volume_get_mount_point (GVfsUDisks2Volume *volume)
+{
+  g_return_val_if_fail (GVFS_IS_UDISKS2_VOLUME (volume), NULL);
+  return volume->mount_point;
+}
+
 dev_t
 gvfs_udisks2_volume_get_dev (GVfsUDisks2Volume *volume)
 {
diff --git a/monitor/udisks2/gvfsudisks2volume.h b/monitor/udisks2/gvfsudisks2volume.h
index cda2b9c..de21cbb 100644
--- a/monitor/udisks2/gvfsudisks2volume.h
+++ b/monitor/udisks2/gvfsudisks2volume.h
@@ -39,12 +39,14 @@ GType              gvfs_udisks2_volume_get_type    (void) G_GNUC_CONST;
 
 GVfsUDisks2Volume *gvfs_udisks2_volume_new         (GVfsUDisks2VolumeMonitor   *monitor,
                                                     UDisksBlock                *block,
+                                                    GUnixMountPoint            *mount_point,
                                                     GVfsUDisks2Drive           *drive,
                                                     GFile                      *activation_root);
 void               gvfs_udisks2_volume_removed     (GVfsUDisks2Volume          *volume);
 
-UDisksBlock       *gvfs_udisks2_volume_get_block   (GVfsUDisks2Volume          *volume);
-dev_t              gvfs_udisks2_volume_get_dev     (GVfsUDisks2Volume          *volume);
+UDisksBlock       *gvfs_udisks2_volume_get_block       (GVfsUDisks2Volume      *volume);
+GUnixMountPoint   *gvfs_udisks2_volume_get_mount_point (GVfsUDisks2Volume      *volume);
+dev_t              gvfs_udisks2_volume_get_dev         (GVfsUDisks2Volume      *volume);
 
 void               gvfs_udisks2_volume_set_mount   (GVfsUDisks2Volume          *volume,
                                                     GVfsUDisks2Mount           *mount);
diff --git a/monitor/udisks2/gvfsudisks2volumemonitor.c b/monitor/udisks2/gvfsudisks2volumemonitor.c
index 3b46478..5f6a7d6 100644
--- a/monitor/udisks2/gvfsudisks2volumemonitor.c
+++ b/monitor/udisks2/gvfsudisks2volumemonitor.c
@@ -57,10 +57,9 @@ struct _GVfsUDisks2VolumeMonitor
   GUdevClient *gudev_client;
   GUnixMountMonitor *mount_monitor;
 
-  GList *last_mounts;
-
   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 */
   GList *disc_volumes;
@@ -78,6 +77,9 @@ static void update_drives            (GVfsUDisks2VolumeMonitor  *monitor,
 static void update_volumes           (GVfsUDisks2VolumeMonitor  *monitor,
                                       GList                    **added_volumes,
                                       GList                    **removed_volumes);
+static void update_fstab_volumes     (GVfsUDisks2VolumeMonitor  *monitor,
+                                      GList                    **added_volumes,
+                                      GList                    **removed_volumes);
 static void update_mounts            (GVfsUDisks2VolumeMonitor  *monitor,
                                       GList                    **added_mounts,
                                       GList                    **removed_mounts);
@@ -160,11 +162,9 @@ gvfs_udisks2_volume_monitor_finalize (GObject *object)
   g_clear_object (&monitor->client);
   g_clear_object (&monitor->gudev_client);
 
-  g_list_foreach (monitor->last_mounts, (GFunc) g_unix_mount_free, NULL);
-  g_list_free (monitor->last_mounts);
-
   object_list_free (monitor->drives);
   object_list_free (monitor->volumes);
+  object_list_free (monitor->fstab_volumes);
   object_list_free (monitor->mounts);
 
   object_list_free (monitor->disc_volumes);
@@ -192,6 +192,7 @@ get_volumes (GVolumeMonitor *_monitor)
   GList *ret;
 
   ret = g_list_copy (monitor->volumes);
+  ret = g_list_concat (ret, g_list_copy (monitor->fstab_volumes));
   ret = g_list_concat (ret, g_list_copy (monitor->disc_volumes));
   g_list_foreach (ret, (GFunc) g_object_ref, NULL);
   return ret;
@@ -222,6 +223,12 @@ get_volume_for_uuid (GVolumeMonitor *_monitor,
       if (gvfs_udisks2_volume_has_uuid (l->data, uuid))
         goto found;
     }
+  for (l = monitor->fstab_volumes; l != NULL; l = l->next)
+    {
+      volume = l->data;
+      if (gvfs_udisks2_volume_has_uuid (l->data, uuid))
+        goto found;
+    }
   for (l = monitor->disc_volumes; l != NULL; l = l->next)
     {
       volume = l->data;
@@ -623,6 +630,7 @@ update_all (GVfsUDisks2VolumeMonitor *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,
@@ -878,6 +886,109 @@ find_volume_for_block (GVfsUDisks2VolumeMonitor *monitor,
 /* ---------------------------------------------------------------------------------------------------- */
 
 static GVfsUDisks2Volume *
+find_fstab_volume_for_mount_point (GVfsUDisks2VolumeMonitor *monitor,
+                                   GUnixMountPoint          *mount_point)
+{
+  GVfsUDisks2Volume *ret = NULL;
+  GList *l;
+
+  for (l = monitor->fstab_volumes; l != NULL; l = l->next)
+    {
+      GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (l->data);
+      if (g_unix_mount_point_compare (gvfs_udisks2_volume_get_mount_point (volume), mount_point) == 0)
+        {
+          ret = volume;
+          goto out;
+        }
+    }
+
+ out:
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+mount_point_matches_mount_entry (GUnixMountPoint *mount_point,
+                                 GUnixMountEntry *mount_entry)
+{
+  gboolean ret = FALSE;
+  gchar *mp_path = NULL;
+  gchar *mp_entry = NULL;
+
+  mp_path = g_strdup (g_unix_mount_point_get_mount_path (mount_point));
+  mp_entry = g_strdup (g_unix_mount_get_mount_path (mount_entry));
+
+  if (g_str_has_suffix (mp_path, "/"))
+    mp_path[strlen(mp_path) - 1] = '\0';
+  if (g_str_has_suffix (mp_entry, "/"))
+    mp_entry[strlen(mp_entry) - 1] = '\0';
+
+  if (g_strcmp0 (mp_path, mp_entry) != 0)
+    goto out;
+
+  ret = TRUE;
+
+ out:
+  g_free (mp_path);
+  g_free (mp_entry);
+  return ret;
+}
+
+static GVfsUDisks2Volume *
+find_fstab_volume_for_mount_entry (GVfsUDisks2VolumeMonitor *monitor,
+                                   GUnixMountEntry          *mount_entry)
+{
+  GVfsUDisks2Volume *ret = NULL;
+  GList *l;
+
+  for (l = monitor->fstab_volumes; l != NULL; l = l->next)
+    {
+      GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (l->data);
+      if (mount_point_matches_mount_entry (gvfs_udisks2_volume_get_mount_point (volume), mount_entry))
+        {
+          ret = volume;
+          goto out;
+        }
+    }
+
+ out:
+  return ret;
+}
+
+static GVfsUDisks2Mount *
+find_lonely_mount_for_mount_point (GVfsUDisks2VolumeMonitor *monitor,
+                                   GUnixMountPoint          *mount_point)
+{
+  GVfsUDisks2Mount *ret = NULL;
+  GList *l;
+
+  for (l = monitor->mounts; l != NULL; l = l->next)
+    {
+      GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (l->data);
+      if (mount_point != NULL &&
+          mount_point_matches_mount_entry (mount_point, gvfs_udisks2_mount_get_mount_entry (mount)))
+        {
+          GVolume *volume = g_mount_get_volume (G_MOUNT (mount));
+          if (volume != NULL)
+            {
+              g_object_unref (volume);
+            }
+          else
+            {
+              ret = mount;
+              goto out;
+            }
+        }
+    }
+
+ out:
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GVfsUDisks2Volume *
 find_volume_for_device (GVfsUDisks2VolumeMonitor *monitor,
                         const gchar              *device)
 {
@@ -1087,6 +1198,7 @@ update_volumes (GVfsUDisks2VolumeMonitor  *monitor,
             }
           volume = gvfs_udisks2_volume_new (monitor,
                                             block,
+                                            NULL, /* mount_point */
                                             drive,
                                             NULL); /* activation_root */
           if (volume != NULL)
@@ -1109,18 +1221,132 @@ update_volumes (GVfsUDisks2VolumeMonitor  *monitor,
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
+update_fstab_volumes (GVfsUDisks2VolumeMonitor  *monitor,
+                      GList                    **added_volumes,
+                      GList                    **removed_volumes)
+{
+  GList *cur_mount_points;
+  GList *new_mount_points;
+  GList *added;
+  GList *removed;
+  GList *l, *ll;
+  GVfsUDisks2Volume *volume;
+
+  cur_mount_points = NULL;
+  for (l = monitor->fstab_volumes; l != NULL; l = l->next)
+    {
+      GUnixMountPoint *mount_point = gvfs_udisks2_volume_get_mount_point (GVFS_UDISKS2_VOLUME (l->data));
+      if (mount_point != NULL)
+        cur_mount_points = g_list_prepend (cur_mount_points, mount_point);
+    }
+
+  new_mount_points = g_unix_mount_points_get (NULL);
+  /* filter the mount points that we don't want to include */
+  for (l = new_mount_points; l != NULL; l = ll)
+    {
+      GUnixMountPoint *mount_point = l->data;
+      gboolean keep = TRUE;
+
+      ll = l->next;
+
+      if (g_unix_is_mount_path_system_internal (g_unix_mount_point_get_mount_path (mount_point)))
+        {
+          keep = FALSE;
+        }
+      else
+        {
+          /* TODO: more checks - including not including the
+           * /etc/fstab entry if we've already got a udisks object for
+           * it
+           */
+        }
+
+      if (!keep)
+        new_mount_points = g_list_remove_link (new_mount_points, l);
+    }
+
+  cur_mount_points = g_list_sort (cur_mount_points, (GCompareFunc) g_unix_mount_point_compare);
+  new_mount_points = g_list_sort (new_mount_points, (GCompareFunc) g_unix_mount_point_compare);
+  diff_sorted_lists (cur_mount_points,
+                     new_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_fstab_volume_for_mount_point (monitor, mount_point);
+      if (volume != NULL)
+        {
+          gvfs_udisks2_volume_removed (volume);
+          monitor->fstab_volumes = g_list_remove (monitor->fstab_volumes, volume);
+          *removed_volumes = g_list_prepend (*removed_volumes, g_object_ref (volume));
+          g_object_unref (volume);
+        }
+    }
+
+  for (l = added; l != NULL; l = l->next)
+    {
+      GUnixMountPoint *mount_point = l->data;
+
+      volume = find_fstab_volume_for_mount_point (monitor, mount_point);
+      if (volume == NULL)
+        {
+          volume = gvfs_udisks2_volume_new (monitor,
+                                            NULL,        /* block */
+                                            mount_point,
+                                            NULL,        /* drive */
+                                            NULL);       /* activation_root */
+          if (volume != NULL)
+            {
+              GVfsUDisks2Mount *mount;
+
+              monitor->fstab_volumes = g_list_prepend (monitor->fstab_volumes, volume);
+              *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume));
+              /* since @volume takes ownership of @mount_point, don't free it below */
+              new_mount_points = g_list_remove (new_mount_points, mount_point);
+
+              /* Could be there's already a mount for this volume - for example, the
+               * user could just have added it to the /etc/fstab file
+               */
+              mount = find_lonely_mount_for_mount_point (monitor, mount_point);
+              if (mount != NULL)
+                gvfs_udisks2_mount_set_volume (mount, volume);
+            }
+        }
+    }
+
+  g_list_foreach (new_mount_points, (GFunc) g_unix_mount_point_free, NULL);
+  g_list_free (new_mount_points);
+
+  g_list_free (cur_mount_points);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
 update_mounts (GVfsUDisks2VolumeMonitor  *monitor,
                GList                    **added_mounts,
                GList                    **removed_mounts)
 {
+  GList *cur_mounts;
   GList *new_mounts;
   GList *removed, *added;
   GList *l, *ll;
   GVfsUDisks2Mount *mount;
   GVfsUDisks2Volume *volume;
 
-  new_mounts = g_unix_mounts_get (NULL);
+  cur_mounts = NULL;
+  for (l = monitor->mounts; l != NULL; l = l->next)
+    {
+      GUnixMountEntry *mount_entry;
 
+      mount = GVFS_UDISKS2_MOUNT (l->data);
+      mount_entry = gvfs_udisks2_mount_get_mount_entry (mount);
+      if (mount_entry != NULL)
+        cur_mounts = g_list_prepend (cur_mounts, mount_entry);
+    }
+
+  new_mounts = g_unix_mounts_get (NULL);
   /* remove mounts we want to ignore - we do it here so we get to reevaluate
    * on the next update whether they should still be ignored
    */
@@ -1134,9 +1360,10 @@ update_mounts (GVfsUDisks2VolumeMonitor  *monitor,
           new_mounts = g_list_delete_link (new_mounts, l);
         }
     }
-  new_mounts = g_list_sort (new_mounts, (GCompareFunc) g_unix_mount_compare);
 
-  diff_sorted_lists (monitor->last_mounts,
+  cur_mounts = g_list_sort (cur_mounts, (GCompareFunc) g_unix_mount_compare);
+  new_mounts = g_list_sort (new_mounts, (GCompareFunc) g_unix_mount_compare);
+  diff_sorted_lists (cur_mounts,
                      new_mounts, (GCompareFunc) g_unix_mount_compare,
                      &added, &removed);
 
@@ -1161,20 +1388,26 @@ update_mounts (GVfsUDisks2VolumeMonitor  *monitor,
 
       device_file = g_unix_mount_get_device_path (mount_entry);
       volume = find_volume_for_device (monitor, device_file);
+      if (volume == NULL)
+        volume = find_fstab_volume_for_mount_entry (monitor, mount_entry);
       mount = gvfs_udisks2_mount_new (monitor, mount_entry, volume); /* adopts mount_entry */
       if (mount != NULL)
         {
           monitor->mounts = g_list_prepend (monitor->mounts, mount);
           *added_mounts = g_list_prepend (*added_mounts, g_object_ref (mount));
           /*g_debug ("added mount at %s for %p", gvfs_udisks2_mount_get_mount_path (mount), volume);*/
+          /* since @mount takes ownership of @mount_entry, don't free it below */
+          new_mounts = g_list_remove (new_mounts, mount_entry);
         }
     }
 
   g_list_free (added);
   g_list_free (removed);
-  g_list_foreach (monitor->last_mounts, (GFunc) g_unix_mount_free, NULL);
-  g_list_free (monitor->last_mounts);
-  monitor->last_mounts = new_mounts;
+
+  g_list_foreach (new_mounts, (GFunc) g_unix_mount_free, NULL);
+  g_list_free (new_mounts);
+
+  g_list_free (cur_mounts);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -1282,6 +1515,7 @@ update_discs (GVfsUDisks2VolumeMonitor  *monitor,
               activation_root = g_file_new_for_uri (uri);
               volume = gvfs_udisks2_volume_new (monitor,
                                                 block,
+                                                NULL, /* mount_point */
                                                 find_drive_for_udisks_drive (monitor, udisks_drive),
                                                 activation_root);
               if (volume != NULL)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]