[gvfs/wip/udisks2] Implement rudimentary parts of the udisks2 volume monitor



commit 11855863742f7c3ac9a83a8d22fc824d29e2fd17
Author: David Zeuthen <davidz redhat com>
Date:   Tue Sep 27 13:01:18 2011 -0400

    Implement rudimentary parts of the udisks2 volume monitor
    
    Still a lot of stuff missing.
    
    Signed-off-by: David Zeuthen <davidz redhat com>

 monitor/udisks2/Makefile.am                |    8 +-
 monitor/udisks2/gvfsudisks2drive.c         |  449 ++++++++++++++
 monitor/udisks2/gvfsudisks2drive.h         |   51 ++
 monitor/udisks2/gvfsudisks2mount.c         |  512 ++++++++++++++++
 monitor/udisks2/gvfsudisks2mount.h         |   57 ++
 monitor/udisks2/gvfsudisks2volume.c        |  541 +++++++++++++++++
 monitor/udisks2/gvfsudisks2volume.h        |   64 ++
 monitor/udisks2/gvfsudisks2volumemonitor.c |  892 +++++++++++++++++++++++++++-
 monitor/udisks2/gvfsudisks2volumemonitor.h |   11 +-
 9 files changed, 2560 insertions(+), 25 deletions(-)
---
diff --git a/monitor/udisks2/Makefile.am b/monitor/udisks2/Makefile.am
index 5c0ed40..890b252 100644
--- a/monitor/udisks2/Makefile.am
+++ b/monitor/udisks2/Makefile.am
@@ -3,14 +3,12 @@ NULL =
 
 libexec_PROGRAMS = gvfs-udisks2-volume-monitor
 
-#	gvfsudisks2drive.c		gvfsudisks2drive.h		\
-#	gvfsudisks2volume.c		gvfsudisks2volume.h		\
-#	gvfsudisks2mount.c		gvfsudisks2mount.h		\
-#
-
 gvfs_udisks2_volume_monitor_SOURCES =					\
 	udisks2volumemonitordaemon.c					\
 	gvfsudisks2volumemonitor.c	gvfsudisks2volumemonitor.h	\
+	gvfsudisks2drive.c		gvfsudisks2drive.h		\
+	gvfsudisks2volume.c		gvfsudisks2volume.h		\
+	gvfsudisks2mount.c		gvfsudisks2mount.h		\
 	$(NULL)
 
 gvfs_udisks2_volume_monitor_CFLAGS =		\
diff --git a/monitor/udisks2/gvfsudisks2drive.c b/monitor/udisks2/gvfsudisks2drive.c
new file mode 100644
index 0000000..d5e3a38
--- /dev/null
+++ b/monitor/udisks2/gvfsudisks2drive.c
@@ -0,0 +1,449 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* gvfs - extensions for gio
+ *
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include "gvfsudisks2volumemonitor.h"
+#include "gvfsudisks2drive.h"
+#include "gvfsudisks2volume.h"
+
+typedef struct _GVfsUDisks2DriveClass GVfsUDisks2DriveClass;
+
+struct _GVfsUDisks2DriveClass
+{
+  GObjectClass parent_class;
+};
+
+struct _GVfsUDisks2Drive
+{
+  GObject parent;
+
+  GVfsUDisks2VolumeMonitor  *monitor; /* owned by volume monitor */
+  GList                     *volumes; /* entries in list are owned by volume monitor */
+
+  UDisksDrive *udisks_drive;
+
+  GIcon *icon;
+  gchar *name;
+  gchar *device_file;
+  dev_t dev;
+  gboolean is_media_removable;
+  gboolean has_media;
+  gboolean can_eject;
+};
+
+static void gvfs_udisks2_drive_drive_iface_init (GDriveIface *iface);
+
+static void on_udisks_drive_notify (GObject     *object,
+                                    GParamSpec  *pspec,
+                                    gpointer     user_data);
+
+G_DEFINE_TYPE_EXTENDED (GVfsUDisks2Drive, gvfs_udisks2_drive, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (G_TYPE_DRIVE, gvfs_udisks2_drive_drive_iface_init))
+
+static void
+gvfs_udisks2_drive_finalize (GObject *object)
+{
+  GVfsUDisks2Drive *drive = GVFS_UDISKS2_DRIVE (object);
+  GList *l;
+
+  for (l = drive->volumes; l != NULL; l = l->next)
+    {
+      GVfsUDisks2Volume *volume = l->data;
+      gvfs_udisks2_volume_unset_drive (volume, drive);
+    }
+
+  if (drive->udisks_drive != NULL)
+    {
+      g_signal_handlers_disconnect_by_func (drive->udisks_drive, on_udisks_drive_notify, drive);
+      g_object_unref (drive->udisks_drive);
+    }
+
+  if (drive->icon != NULL)
+    g_object_unref (drive->icon);
+  g_free (drive->name);
+  g_free (drive->device_file);
+
+  G_OBJECT_CLASS (gvfs_udisks2_drive_parent_class)->finalize (object);
+}
+
+static void
+gvfs_udisks2_drive_class_init (GVfsUDisks2DriveClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = gvfs_udisks2_drive_finalize;
+}
+
+static void
+gvfs_udisks2_drive_init (GVfsUDisks2Drive *gdu_drive)
+{
+}
+
+static void
+emit_changed (GVfsUDisks2Drive *drive)
+{
+  g_signal_emit_by_name (drive, "changed");
+  g_signal_emit_by_name (drive->monitor, "drive-changed", drive);
+}
+
+static gboolean
+update_drive (GVfsUDisks2Drive *drive)
+{
+  gboolean changed;
+  GIcon *old_icon;
+  gchar *old_name;
+  gchar *old_device_file;
+  dev_t old_dev;
+  gboolean old_is_media_removable;
+  gboolean old_has_media;
+  gboolean old_can_eject;
+  UDisksBlock *block;
+
+  /* ---------------------------------------------------------------------------------------------------- */
+  /* save old values */
+
+  old_is_media_removable = drive->is_media_removable;
+  old_has_media = drive->has_media;
+  old_can_eject = drive->can_eject;
+
+  old_name = g_strdup (drive->name);
+  old_device_file = g_strdup (drive->device_file);
+  old_dev = drive->dev;
+  old_icon = drive->icon != NULL ? g_object_ref (drive->icon) : NULL;
+
+  /* ---------------------------------------------------------------------------------------------------- */
+  /* reset */
+
+  drive->is_media_removable = drive->has_media = drive->can_eject = FALSE;
+  g_free (drive->name); drive->name = NULL;
+  g_free (drive->device_file); drive->device_file = NULL;
+  drive->dev = 0;
+  g_clear_object (&drive->icon);
+
+  /* ---------------------------------------------------------------------------------------------------- */
+  /* in with the new */
+
+  block = udisks_client_get_block_for_drive (gvfs_udisks2_volume_monitor_get_udisks_client (drive->monitor),
+                                             drive->udisks_drive,
+                                             FALSE);
+  if (block != NULL)
+    {
+      drive->device_file = udisks_block_dup_device (block);
+      drive->dev = makedev (udisks_block_get_major (block), udisks_block_get_minor (block));
+      g_object_unref (block);
+    }
+
+  drive->is_media_removable = udisks_drive_get_media_removable (drive->udisks_drive);
+  if (drive->is_media_removable)
+    {
+      drive->has_media = (udisks_drive_get_size (drive->udisks_drive) > 0);
+      drive->can_eject = TRUE;
+    }
+  else
+    {
+      drive->has_media = TRUE;
+      drive->can_eject = FALSE;
+    }
+
+  udisks_util_get_drive_info (drive->udisks_drive,
+                              NULL,         /* drive_name */
+                              &drive->name,
+                              &drive->icon,
+                              NULL,         /* media_desc */
+                              NULL);        /* media_icon */
+
+  /* ---------------------------------------------------------------------------------------------------- */
+  /* fallbacks */
+
+  /* Never use empty/blank names (#582772) */
+  if (drive->name == NULL || strlen (drive->name) == 0)
+    {
+      if (drive->device_file != NULL)
+        drive->name = g_strdup_printf (_("Unnamed Drive (%s)"), drive->device_file);
+      else
+        drive->name = g_strdup (_("Unnamed Drive"));
+    }
+  if (drive->icon == NULL)
+    drive->icon = g_themed_icon_new ("drive-removable-media");
+
+  /* ---------------------------------------------------------------------------------------------------- */
+  /* compute whether something changed */
+  changed = !((old_is_media_removable == drive->is_media_removable) &&
+              (old_has_media == drive->has_media) &&
+              (old_can_eject == drive->can_eject) &&
+              (g_strcmp0 (old_name, drive->name) == 0) &&
+              (g_strcmp0 (old_device_file, drive->device_file) == 0) &&
+              (old_dev == drive->dev) &&
+              g_icon_equal (old_icon, drive->icon)
+              );
+
+  /* free old values */
+  g_free (old_name);
+  g_free (old_device_file);
+  if (old_icon != NULL)
+    g_object_unref (old_icon);
+
+  /*g_debug ("in update_drive(); has_media=%d changed=%d", drive->has_media, changed);*/
+
+  return changed;
+}
+
+static void
+on_udisks_drive_notify (GObject     *object,
+                        GParamSpec  *pspec,
+                        gpointer     user_data)
+{
+  GVfsUDisks2Drive *drive = GVFS_UDISKS2_DRIVE (user_data);
+  if (update_drive (drive))
+    emit_changed (drive);
+}
+
+GVfsUDisks2Drive *
+gvfs_udisks2_drive_new (GVfsUDisks2VolumeMonitor  *monitor,
+                        UDisksDrive               *udisks_drive)
+{
+  GVfsUDisks2Drive *drive;
+
+  drive = g_object_new (GVFS_TYPE_UDISKS2_DRIVE, NULL);
+  drive->monitor = monitor;
+
+  drive->udisks_drive = g_object_ref (udisks_drive);
+  g_signal_connect (drive->udisks_drive,
+                    "notify",
+                    G_CALLBACK (on_udisks_drive_notify),
+                    drive);
+
+  update_drive (drive);
+
+  return drive;
+}
+
+void
+gvfs_udisks2_drive_disconnected (GVfsUDisks2Drive *drive)
+{
+  GList *l, *volumes;
+
+  volumes = drive->volumes;
+  drive->volumes = NULL;
+  for (l = volumes; l != NULL; l = l->next)
+    {
+      GVfsUDisks2Volume *volume = l->data;
+      gvfs_udisks2_volume_unset_drive (volume, drive);
+    }
+  g_list_free (volumes);
+}
+
+void
+gvfs_udisks2_drive_set_volume (GVfsUDisks2Drive  *drive,
+                               GVfsUDisks2Volume *volume)
+{
+  if (g_list_find (drive->volumes, volume) == NULL)
+    {
+      drive->volumes = g_list_prepend (drive->volumes, volume);
+      emit_changed (drive);
+    }
+}
+
+void
+gvfs_udisks2_drive_unset_volume (GVfsUDisks2Drive  *drive,
+                                 GVfsUDisks2Volume *volume)
+{
+  GList *l;
+  l = g_list_find (drive->volumes, volume);
+  if (l != NULL)
+    {
+      drive->volumes = g_list_delete_link (drive->volumes, l);
+      emit_changed (drive);
+    }
+}
+
+static GIcon *
+gvfs_udisks2_drive_get_icon (GDrive *_drive)
+{
+  GVfsUDisks2Drive *drive = GVFS_UDISKS2_DRIVE (_drive);
+  return drive->icon != NULL ? g_object_ref (drive->icon) : NULL;
+}
+
+static char *
+gvfs_udisks2_drive_get_name (GDrive *_drive)
+{
+  GVfsUDisks2Drive *drive = GVFS_UDISKS2_DRIVE (_drive);
+  return g_strdup (drive->name);
+}
+
+static GList *
+gvfs_udisks2_drive_get_volumes (GDrive *_drive)
+{
+  GVfsUDisks2Drive *drive = GVFS_UDISKS2_DRIVE (_drive);
+  GList *l;
+  l = g_list_copy (drive->volumes);
+  g_list_foreach (l, (GFunc) g_object_ref, NULL);
+  return l;
+}
+
+static gboolean
+gvfs_udisks2_drive_has_volumes (GDrive *_drive)
+{
+  GVfsUDisks2Drive *drive = GVFS_UDISKS2_DRIVE (_drive);
+  gboolean res;
+  res = drive->volumes != NULL;
+  return res;
+}
+
+static gboolean
+gvfs_udisks2_drive_is_media_removable (GDrive *_drive)
+{
+  GVfsUDisks2Drive *drive = GVFS_UDISKS2_DRIVE (_drive);
+  return drive->is_media_removable;
+}
+
+static gboolean
+gvfs_udisks2_drive_has_media (GDrive *_drive)
+{
+  GVfsUDisks2Drive *drive = GVFS_UDISKS2_DRIVE (_drive);
+  return drive->has_media;
+}
+
+static gboolean
+gvfs_udisks2_drive_is_media_check_automatic (GDrive *_drive)
+{
+  return TRUE;
+}
+
+static gboolean
+gvfs_udisks2_drive_can_eject (GDrive *_drive)
+{
+  GVfsUDisks2Drive *drive = GVFS_UDISKS2_DRIVE (_drive);
+  return drive->can_eject;
+}
+
+static gboolean
+gvfs_udisks2_drive_can_poll_for_media (GDrive *_drive)
+{
+  return FALSE;
+}
+
+static gboolean
+gvfs_udisks2_drive_can_start (GDrive *_drive)
+{
+  return FALSE;
+}
+
+static gboolean
+gvfs_udisks2_drive_can_start_degraded (GDrive *_drive)
+{
+  return FALSE;
+}
+
+static gboolean
+gvfs_udisks2_drive_can_stop (GDrive *_drive)
+{
+  return FALSE;
+}
+
+static GDriveStartStopType
+gvfs_udisks2_drive_get_start_stop_type (GDrive *_drive)
+{
+  return G_DRIVE_START_STOP_TYPE_UNKNOWN;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static char *
+gvfs_udisks2_drive_get_identifier (GDrive      *_drive,
+                                   const gchar *kind)
+{
+  GVfsUDisks2Drive *drive = GVFS_UDISKS2_DRIVE (_drive);
+  gchar *ret = NULL;
+
+  if (drive->device_file != NULL)
+    {
+      if (g_strcmp0 (kind, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE) == 0)
+        ret = g_strdup (drive->device_file);
+    }
+  return ret;
+}
+
+static gchar **
+gvfs_udisks2_drive_enumerate_identifiers (GDrive *_drive)
+{
+  GVfsUDisks2Drive *drive = GVFS_UDISKS2_DRIVE (_drive);
+  GPtrArray *p;
+
+  p = g_ptr_array_new ();
+  if (drive->device_file != NULL)
+    g_ptr_array_add (p, g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE));
+  g_ptr_array_add (p, NULL);
+
+  return (gchar **) g_ptr_array_free (p, FALSE);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+gvfs_udisks2_drive_drive_iface_init (GDriveIface *iface)
+{
+  iface->get_name = gvfs_udisks2_drive_get_name;
+  iface->get_icon = gvfs_udisks2_drive_get_icon;
+  iface->has_volumes = gvfs_udisks2_drive_has_volumes;
+  iface->get_volumes = gvfs_udisks2_drive_get_volumes;
+  iface->is_media_removable = gvfs_udisks2_drive_is_media_removable;
+  iface->has_media = gvfs_udisks2_drive_has_media;
+  iface->is_media_check_automatic = gvfs_udisks2_drive_is_media_check_automatic;
+  iface->can_eject = gvfs_udisks2_drive_can_eject;
+  iface->can_poll_for_media = gvfs_udisks2_drive_can_poll_for_media;
+  iface->get_identifier = gvfs_udisks2_drive_get_identifier;
+  iface->enumerate_identifiers = gvfs_udisks2_drive_enumerate_identifiers;
+  iface->get_start_stop_type = gvfs_udisks2_drive_get_start_stop_type;
+  iface->can_start = gvfs_udisks2_drive_can_start;
+  iface->can_start_degraded = gvfs_udisks2_drive_can_start_degraded;
+  iface->can_stop = gvfs_udisks2_drive_can_stop;
+
+#if 0
+  iface->eject = gvfs_udisks2_drive_eject;
+  iface->eject_finish = gvfs_udisks2_drive_eject_finish;
+  iface->eject_with_operation = gvfs_udisks2_drive_eject_with_operation;
+  iface->eject_with_operation_finish = gvfs_udisks2_drive_eject_with_operation_finish;
+  iface->poll_for_media = gvfs_udisks2_drive_poll_for_media;
+  iface->poll_for_media_finish = gvfs_udisks2_drive_poll_for_media_finish;
+  iface->start = gvfs_udisks2_drive_start;
+  iface->start_finish = gvfs_udisks2_drive_start_finish;
+  iface->stop = gvfs_udisks2_drive_stop;
+  iface->stop_finish = gvfs_udisks2_drive_stop_finish;
+#endif
+}
+
+UDisksDrive *
+gvfs_udisks2_drive_get_udisks_drive (GVfsUDisks2Drive *drive)
+{
+  return drive->udisks_drive;
+}
diff --git a/monitor/udisks2/gvfsudisks2drive.h b/monitor/udisks2/gvfsudisks2drive.h
new file mode 100644
index 0000000..57a9255
--- /dev/null
+++ b/monitor/udisks2/gvfsudisks2drive.h
@@ -0,0 +1,51 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* gvfs - extensions for gio
+ *
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __GVFS_UDISKS2_DRIVE_H__
+#define __GVFS_UDISKS2_DRIVE_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "gvfsudisks2volumemonitor.h"
+
+G_BEGIN_DECLS
+
+#define GVFS_TYPE_UDISKS2_DRIVE  (gvfs_udisks2_drive_get_type ())
+#define GVFS_UDISKS2_DRIVE(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), GVFS_TYPE_UDISKS2_DRIVE, GVfsUDisks2Drive))
+#define GVFS_IS_UDISKS2_DRIVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVFS_TYPE_UDISKS2_DRIVE))
+
+GType             gvfs_udisks2_drive_get_type        (void) G_GNUC_CONST;
+GVfsUDisks2Drive *gvfs_udisks2_drive_new             (GVfsUDisks2VolumeMonitor *monitor,
+                                                      UDisksDrive              *udisks_drive);
+void              gvfs_udisks2_drive_disconnected    (GVfsUDisks2Drive         *drive);
+
+void              gvfs_udisks2_drive_set_volume      (GVfsUDisks2Drive         *drive,
+                                                      GVfsUDisks2Volume        *volume);
+void              gvfs_udisks2_drive_unset_volume    (GVfsUDisks2Drive         *drive,
+                                                      GVfsUDisks2Volume        *volume);
+UDisksDrive     *gvfs_udisks2_drive_get_udisks_drive (GVfsUDisks2Drive         *drive);
+
+G_END_DECLS
+
+#endif /* __GVFS_UDISKS2_DRIVE_H__ */
diff --git a/monitor/udisks2/gvfsudisks2mount.c b/monitor/udisks2/gvfsudisks2mount.c
new file mode 100644
index 0000000..6f049bb
--- /dev/null
+++ b/monitor/udisks2/gvfsudisks2mount.c
@@ -0,0 +1,512 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* gvfs - extensions for gio
+ *
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+#include <gvfsmountinfo.h>
+
+#ifdef HAVE_GUDEV
+#include <gudev/gudev.h>
+#endif
+
+#include "gvfsudisks2volumemonitor.h"
+#include "gvfsudisks2mount.h"
+#include "gvfsudisks2volume.h"
+
+#define BUSY_UNMOUNT_NUM_ATTEMPTS              5
+#define BUSY_UNMOUNT_MS_DELAY_BETWEEN_ATTEMPTS 100
+
+typedef struct _GVfsUDisks2MountClass GVfsUDisks2MountClass;
+struct _GVfsUDisks2MountClass
+{
+  GObjectClass parent_class;
+};
+
+struct _GVfsUDisks2Mount
+{
+  GObject parent;
+
+  GVfsUDisks2VolumeMonitor *monitor; /* owned by volume monitor */
+  GVfsUDisks2Volume        *volume;  /* owned by volume monitor */
+
+  /* the following members are set in update_mount() */
+  GFile *root;
+  GIcon *icon;
+  gchar *name;
+  gchar *uuid;
+  gchar *device_file;
+  gchar *mount_path;
+  gboolean can_unmount;
+  gchar *mount_entry_name;
+  GIcon *mount_entry_icon;
+
+  gboolean is_burn_mount;
+
+  GIcon *autorun_icon;
+  gboolean searched_for_autorun;
+
+  gchar *xdg_volume_info_name;
+  GIcon *xdg_volume_info_icon;
+  gboolean searched_for_xdg_volume_info;
+
+  gchar *bdmv_volume_info_name;
+  GIcon *bdmv_volume_info_icon;
+  gboolean searched_for_bdmv_volume_info;
+};
+
+static gboolean update_mount (GVfsUDisks2Mount *mount);
+
+static void gvfs_udisks2_mount_mount_iface_init (GMountIface *iface);
+
+G_DEFINE_TYPE_EXTENDED (GVfsUDisks2Mount, gvfs_udisks2_mount, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (G_TYPE_MOUNT,
+                                               gvfs_udisks2_mount_mount_iface_init))
+
+static void on_volume_changed (GVolume *volume, gpointer user_data);
+
+static void
+gvfs_udisks2_mount_finalize (GObject *object)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (object);
+
+  if (mount->volume != NULL)
+    {
+      g_signal_handlers_disconnect_by_func (mount->volume, on_volume_changed, mount);
+      gvfs_udisks2_volume_unset_mount (mount->volume, mount);
+    }
+
+  if (mount->root != NULL)
+    g_object_unref (mount->root);
+  if (mount->icon != NULL)
+    g_object_unref (mount->icon);
+  g_free (mount->name);
+  g_free (mount->uuid);
+  g_free (mount->device_file);
+  g_free (mount->mount_path);
+
+  g_free (mount->mount_entry_name);
+  if (mount->mount_entry_icon != NULL)
+    g_object_unref (mount->mount_entry_icon);
+
+  if (mount->autorun_icon != NULL)
+    g_object_unref (mount->autorun_icon);
+
+  g_free (mount->xdg_volume_info_name);
+  if (mount->xdg_volume_info_icon != NULL)
+    g_object_unref (mount->xdg_volume_info_icon);
+
+  G_OBJECT_CLASS (gvfs_udisks2_mount_parent_class)->finalize (object);
+}
+
+static void
+gvfs_udisks2_mount_class_init (GVfsUDisks2MountClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = gvfs_udisks2_mount_finalize;
+}
+
+static void
+gvfs_udisks2_mount_init (GVfsUDisks2Mount *mount)
+{
+}
+
+static void
+emit_changed (GVfsUDisks2Mount *mount)
+{
+  g_signal_emit_by_name (mount, "changed");
+  g_signal_emit_by_name (mount->monitor, "mount-changed", mount);
+}
+
+static void
+got_autorun_info_cb (GObject      *source_object,
+                     GAsyncResult *res,
+                     gpointer      user_data)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (user_data);
+  mount->autorun_icon = g_vfs_mount_info_query_autorun_info_finish (G_FILE (source_object), res, NULL);
+  if (update_mount (mount))
+    emit_changed (mount);
+  g_object_unref (mount);
+}
+
+static void
+got_xdg_volume_info_cb (GObject      *source_object,
+                        GAsyncResult *res,
+                        gpointer      user_data)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (user_data);
+  mount->xdg_volume_info_icon = g_vfs_mount_info_query_xdg_volume_info_finish (G_FILE (source_object),
+                                                                               res,
+                                                                               &(mount->xdg_volume_info_name),
+                                                                               NULL);
+  if (update_mount (mount))
+    emit_changed (mount);
+  g_object_unref (mount);
+}
+
+static void
+got_bdmv_volume_info_cb (GObject      *source_object,
+                         GAsyncResult *res,
+                         gpointer      user_data)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (user_data);
+  mount->bdmv_volume_info_icon = g_vfs_mount_info_query_bdmv_volume_info_finish (G_FILE (source_object),
+                                                                                 res,
+                                                                                 &(mount->bdmv_volume_info_name),
+                                                                                 NULL);
+  if (update_mount (mount))
+    emit_changed (mount);
+  g_object_unref (mount);
+}
+
+static gboolean
+update_mount (GVfsUDisks2Mount *mount)
+{
+  gboolean changed;
+  gboolean old_can_unmount;
+  gchar *old_name;
+  GIcon *old_icon;
+
+  /* save old values */
+  old_can_unmount = mount->can_unmount;
+  old_name = g_strdup (mount->name);
+  old_icon = mount->icon != NULL ? g_object_ref (mount->icon) : NULL;
+
+  /* in with the new */
+  if (mount->volume != NULL)
+    {
+      mount->can_unmount = TRUE;
+
+      if (mount->icon != NULL)
+        g_object_unref (mount->icon);
+
+      /* icon order of preference: bdmv, xdg, autorun, probed */
+      if (mount->bdmv_volume_info_icon != NULL)
+        mount->icon = g_object_ref (mount->bdmv_volume_info_icon);
+      else if (mount->xdg_volume_info_icon != NULL)
+        mount->icon = g_object_ref (mount->xdg_volume_info_icon);
+      else if (mount->autorun_icon != NULL)
+        mount->icon = g_object_ref (mount->autorun_icon);
+      else
+        mount->icon = g_volume_get_icon (G_VOLUME (mount->volume));
+
+      g_free (mount->name);
+
+      /* name order of preference : bdmv, xdg, probed */
+      if (mount->bdmv_volume_info_name != NULL)
+        mount->name = g_strdup (mount->bdmv_volume_info_name);
+      else if (mount->xdg_volume_info_name != NULL)
+        mount->name = g_strdup (mount->xdg_volume_info_name);
+      else
+        mount->name = g_volume_get_name (G_VOLUME (mount->volume));
+    }
+  else
+    {
+      mount->can_unmount = TRUE;
+
+      if (mount->icon != NULL)
+        g_object_unref (mount->icon);
+
+      /* icon order of preference: bdmv, xdg, autorun, probed */
+      if (mount->bdmv_volume_info_icon != NULL)
+        mount->icon = g_object_ref (mount->bdmv_volume_info_icon);
+      else if (mount->xdg_volume_info_icon != NULL)
+        mount->icon = g_object_ref (mount->xdg_volume_info_icon);
+      else if (mount->autorun_icon != NULL)
+        mount->icon = g_object_ref (mount->autorun_icon);
+      else
+        mount->icon = mount->mount_entry_icon != NULL ? g_object_ref (mount->mount_entry_icon) : NULL;
+
+      g_free (mount->name);
+
+      /* name order of preference: bdmv, xdg, probed */
+      if (mount->bdmv_volume_info_name != NULL)
+        mount->name = g_strdup (mount->bdmv_volume_info_name);
+      else if (mount->xdg_volume_info_name != NULL)
+        mount->name = g_strdup (mount->xdg_volume_info_name);
+      else
+        mount->name = g_strdup (mount->mount_entry_name);
+    }
+
+  /* compute whether something changed */
+  changed = !((old_can_unmount == mount->can_unmount) &&
+              (g_strcmp0 (old_name, mount->name) == 0) &&
+              g_icon_equal (old_icon, mount->icon));
+
+  /* free old values */
+  g_free (old_name);
+  if (old_icon != NULL)
+    g_object_unref (old_icon);
+
+  /*g_debug ("in update_mount(), changed=%d", changed);*/
+
+  /* search for BDMV */
+  if (!mount->searched_for_bdmv_volume_info)
+    {
+      mount->searched_for_bdmv_volume_info = TRUE;
+      g_vfs_mount_info_query_bdmv_volume_info (mount->root,
+      					       NULL,
+      					       got_bdmv_volume_info_cb,
+      					       g_object_ref (mount));
+    }
+
+  /* search for .xdg-volume-info */
+  if (!mount->searched_for_xdg_volume_info)
+    {
+      mount->searched_for_xdg_volume_info = TRUE;
+      g_vfs_mount_info_query_xdg_volume_info (mount->root,
+                                              NULL,
+                                              got_xdg_volume_info_cb,
+                                              g_object_ref (mount));
+    }
+
+  /* search for autorun.inf */
+  if (!mount->searched_for_autorun)
+    {
+      mount->searched_for_autorun = TRUE;
+      g_vfs_mount_info_query_autorun_info (mount->root,
+                                           NULL,
+                                           got_autorun_info_cb,
+                                           g_object_ref (mount));
+    }
+
+  return changed;
+}
+
+static void
+on_volume_changed (GVolume  *volume,
+                   gpointer  user_data)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (user_data);
+  if (update_mount (mount))
+    emit_changed (mount);
+}
+
+GVfsUDisks2Mount *
+gvfs_udisks2_mount_new (GVfsUDisks2VolumeMonitor *monitor,
+                        GUnixMountEntry          *mount_entry,
+                        GVfsUDisks2Volume        *volume)
+{
+  GVfsUDisks2Mount *mount = NULL;
+
+  /* Ignore internal mounts unless there's a volume */
+  if (volume == NULL && (mount_entry != NULL && !g_unix_mount_guess_should_display (mount_entry)))
+    goto out;
+
+  mount = g_object_new (GVFS_TYPE_UDISKS2_MOUNT, NULL);
+  mount->monitor = monitor;
+
+  if (mount_entry != NULL)
+    {
+      /* No ref on GUnixMountEntry so save values for later use */
+      mount->mount_entry_name = g_unix_mount_guess_name (mount_entry);
+      mount->mount_entry_icon = g_unix_mount_guess_icon (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);
+    }
+  else
+    {
+      /* burn:/// mount (the only mounts we support with mount_entry == NULL) */
+      mount->device_file = NULL;
+      mount->mount_path = NULL;
+      mount->root = g_file_new_for_uri ("burn:///");
+      mount->is_burn_mount = TRUE;
+    }
+
+  /* need to set the volume only when the mount is fully constructed */
+  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);
+    }
+
+  update_mount (mount);
+
+ out:
+
+  return mount;
+}
+
+void
+gvfs_udisks2_mount_unmounted (GVfsUDisks2Mount *mount)
+{
+  if (mount->volume != NULL)
+    {
+      gvfs_udisks2_volume_unset_mount (mount->volume, mount);
+      g_signal_handlers_disconnect_by_func (mount->volume, on_volume_changed, mount);
+      mount->volume = NULL;
+      emit_changed (mount);
+    }
+}
+
+void
+gvfs_udisks2_mount_unset_volume (GVfsUDisks2Mount   *mount,
+                                 GVfsUDisks2Volume  *volume)
+{
+  if (mount->volume == volume)
+    {
+      g_signal_handlers_disconnect_by_func (mount->volume, on_volume_changed, mount);
+      mount->volume = NULL;
+      emit_changed (mount);
+    }
+}
+
+static GFile *
+gvfs_udisks2_mount_get_root (GMount *_mount)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
+  return mount->root != NULL ? g_object_ref (mount->root) : NULL;
+}
+
+static GIcon *
+gvfs_udisks2_mount_get_icon (GMount *_mount)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
+  return mount->icon != NULL ? g_object_ref (mount->icon) : NULL;
+}
+
+static gchar *
+gvfs_udisks2_mount_get_uuid (GMount *_mount)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
+  return g_strdup (mount->uuid);
+}
+
+static gchar *
+gvfs_udisks2_mount_get_name (GMount *_mount)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
+  return g_strdup (mount->name);
+}
+
+gboolean
+gvfs_udisks2_mount_has_uuid (GVfsUDisks2Mount *_mount,
+                             const gchar      *uuid)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
+  return g_strcmp0 (mount->uuid, uuid) == 0;
+}
+
+gboolean
+gvfs_udisks2_mount_has_mount_path (GVfsUDisks2Mount *_mount,
+                                   const gchar      *mount_path)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
+  return g_strcmp0 (mount->mount_path, mount_path) == 0;
+}
+
+static GDrive *
+gvfs_udisks2_mount_get_drive (GMount *_mount)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
+  GDrive *drive = NULL;
+
+  if (mount->volume != NULL)
+    drive = g_volume_get_drive (G_VOLUME (mount->volume));
+  return drive;
+}
+
+static GVolume *
+gvfs_udisks2_mount_get_volume (GMount *_mount)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
+  GVolume *volume = NULL;
+
+  if (mount->volume)
+    volume = G_VOLUME (g_object_ref (mount->volume));
+  return volume;
+}
+
+static gboolean
+gvfs_udisks2_mount_can_unmount (GMount *_mount)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
+  return mount->can_unmount;
+}
+
+static gboolean
+gvfs_udisks2_mount_can_eject (GMount *_mount)
+{
+  GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (_mount);
+  GDrive *drive;
+  gboolean can_eject;
+
+  can_eject = FALSE;
+  if (mount->volume != NULL)
+    {
+      drive = g_volume_get_drive (G_VOLUME (mount->volume));
+      if (drive != NULL)
+        can_eject = g_drive_can_eject (drive);
+    }
+
+  return can_eject;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+gvfs_udisks2_mount_mount_iface_init (GMountIface *iface)
+{
+  iface->get_root = gvfs_udisks2_mount_get_root;
+  iface->get_name = gvfs_udisks2_mount_get_name;
+  iface->get_icon = gvfs_udisks2_mount_get_icon;
+  iface->get_uuid = gvfs_udisks2_mount_get_uuid;
+  iface->get_drive = gvfs_udisks2_mount_get_drive;
+  iface->get_volume = gvfs_udisks2_mount_get_volume;
+  iface->can_unmount = gvfs_udisks2_mount_can_unmount;
+  iface->can_eject = gvfs_udisks2_mount_can_eject;
+#if 0
+  iface->unmount = gvfs_udisks2_mount_unmount;
+  iface->unmount_finish = gvfs_udisks2_mount_unmount_finish;
+  iface->unmount_with_operation = gvfs_udisks2_mount_unmount_with_operation;
+  iface->unmount_with_operation_finish = gvfs_udisks2_mount_unmount_with_operation_finish;
+  iface->eject = gvfs_udisks2_mount_eject;
+  iface->eject_finish = gvfs_udisks2_mount_eject_finish;
+  iface->eject_with_operation = gvfs_udisks2_mount_eject_with_operation;
+  iface->eject_with_operation_finish = gvfs_udisks2_mount_eject_with_operation_finish;
+  iface->guess_content_type = gvfs_udisks2_mount_guess_content_type;
+  iface->guess_content_type_finish = gvfs_udisks2_mount_guess_content_type_finish;
+  iface->guess_content_type_sync = gvfs_udisks2_mount_guess_content_type_sync;
+#endif
+}
+
+gboolean
+gvfs_udisks2_mount_has_volume (GVfsUDisks2Mount   *mount,
+                               GVfsUDisks2Volume  *volume)
+{
+  return mount->volume == volume;
+}
diff --git a/monitor/udisks2/gvfsudisks2mount.h b/monitor/udisks2/gvfsudisks2mount.h
new file mode 100644
index 0000000..03b7769
--- /dev/null
+++ b/monitor/udisks2/gvfsudisks2mount.h
@@ -0,0 +1,57 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* gvfs - extensions for gio
+ *
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __GVFS_UDISKS2_MOUNT_H__
+#define __GVFS_UDISKS2_MOUNT_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "gvfsudisks2volumemonitor.h"
+
+G_BEGIN_DECLS
+
+#define GVFS_TYPE_UDISKS2_MOUNT  (gvfs_udisks2_mount_get_type ())
+#define GVFS_UDISKS2_MOUNT(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), GVFS_TYPE_UDISKS2_MOUNT, GVfsUDisks2Mount))
+#define GVFS_IS_UDISKS2_MOUNT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVFS_TYPE_UDISKS2_MOUNT))
+
+
+GType             gvfs_udisks2_mount_get_type       (void) G_GNUC_CONST;
+GVfsUDisks2Mount *gvfs_udisks2_mount_new            (GVfsUDisks2VolumeMonitor *monitor,
+                                                     GUnixMountEntry          *mount_entry,
+                                                     GVfsUDisks2Volume        *volume);
+void              gvfs_udisks2_mount_unmounted      (GVfsUDisks2Mount         *mount);
+
+gboolean          gvfs_udisks2_mount_has_mount_path (GVfsUDisks2Mount         *mount,
+                                                     const gchar              *mount_path);
+gboolean          gvfs_udisks2_mount_has_uuid       (GVfsUDisks2Mount         *mount,
+                                                     const gchar              *uuid);
+
+void              gvfs_udisks2_mount_unset_volume   (GVfsUDisks2Mount         *mount,
+                                                     GVfsUDisks2Volume        *volume);
+gboolean          gvfs_udisks2_mount_has_volume     (GVfsUDisks2Mount         *mount,
+                                                     GVfsUDisks2Volume        *volume);
+
+G_END_DECLS
+
+#endif /* __GVFS_UDISKS2_MOUNT_H__ */
diff --git a/monitor/udisks2/gvfsudisks2volume.c b/monitor/udisks2/gvfsudisks2volume.c
new file mode 100644
index 0000000..8d2e0a8
--- /dev/null
+++ b/monitor/udisks2/gvfsudisks2volume.c
@@ -0,0 +1,541 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* gvfs - extensions for gio
+ *
+ * Copyright (C) 2006-2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+#include "gvfsudisks2drive.h"
+#include "gvfsudisks2volume.h"
+#include "gvfsudisks2mount.h"
+
+typedef struct _GVfsUDisks2VolumeClass GVfsUDisks2VolumeClass;
+
+struct _GVfsUDisks2VolumeClass
+{
+  GObjectClass parent_class;
+};
+
+struct _GVfsUDisks2Volume
+{
+  GObject parent;
+
+  GVfsUDisks2VolumeMonitor *monitor; /* owned by volume monitor */
+  GVfsUDisks2Mount         *mount;   /* owned by volume monitor */
+  GVfsUDisks2Drive         *drive;   /* owned by volume monitor */
+
+  UDisksBlock *block;
+
+  /* set in update_volume() */
+  GIcon *icon;
+  GFile *activation_root;
+  gchar *name;
+  gchar *device_file;
+  dev_t dev;
+  gchar *uuid;
+  gboolean can_mount;
+  gboolean should_automount;
+};
+
+static void gvfs_udisks2_volume_volume_iface_init (GVolumeIface *iface);
+
+static void on_block_changed (GObject    *object,
+                              GParamSpec *pspec,
+                              gpointer    user_data);
+
+G_DEFINE_TYPE_EXTENDED (GVfsUDisks2Volume, gvfs_udisks2_volume, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME, gvfs_udisks2_volume_volume_iface_init))
+
+static void
+gvfs_udisks2_volume_finalize (GObject *object)
+{
+  GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (object);
+
+  if (volume->mount != NULL)
+    {
+      gvfs_udisks2_mount_unset_volume (volume->mount, volume);
+    }
+
+  if (volume->drive != NULL)
+    {
+      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->icon != NULL)
+    g_object_unref (volume->icon);
+  if (volume->activation_root != NULL)
+    g_object_unref (volume->activation_root);
+
+  g_free (volume->name);
+  g_free (volume->device_file);
+  g_free (volume->uuid);
+
+  G_OBJECT_CLASS (gvfs_udisks2_volume_parent_class)->finalize (object);
+}
+
+static void
+gvfs_udisks2_volume_class_init (GVfsUDisks2VolumeClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = gvfs_udisks2_volume_finalize;
+}
+
+static void
+gvfs_udisks2_volume_init (GVfsUDisks2Volume *volume)
+{
+}
+
+static void
+emit_changed (GVfsUDisks2Volume *volume)
+{
+  g_signal_emit_by_name (volume, "changed");
+  g_signal_emit_by_name (volume->monitor, "volume_changed", volume);
+}
+
+static UDisksDrive *
+get_udisks_drive (GVfsUDisks2Volume *volume)
+{
+  UDisksDrive *ret = NULL;
+  UDisksClient *client;
+  UDisksObject *object;
+
+  client = gvfs_udisks2_volume_monitor_get_udisks_client (volume->monitor);
+  object = (UDisksObject *) g_dbus_object_manager_get_object (udisks_client_get_object_manager (client),
+                                                              udisks_block_get_drive (volume->block));
+  if (object != NULL)
+    {
+      ret = udisks_object_peek_drive (object);
+      g_object_unref (object);
+    }
+  return ret;
+}
+
+static gboolean
+update_volume (GVfsUDisks2Volume *volume)
+{
+  gboolean changed;
+  gboolean old_can_mount;
+  gboolean old_should_automount;
+  gchar *old_name;
+  gchar *old_device_file;
+  dev_t old_dev;
+  GIcon *old_icon;
+  UDisksDrive *udisks_drive;
+  gchar *s;
+
+  /* ---------------------------------------------------------------------------------------------------- */
+  /* save old values */
+
+  old_can_mount = volume->can_mount;
+  old_should_automount = volume->should_automount;
+  old_name = g_strdup (volume->name);
+  old_device_file = g_strdup (volume->device_file);
+  old_dev = volume->dev;
+  old_icon = volume->icon != NULL ? g_object_ref (volume->icon) : NULL;
+
+  /* ---------------------------------------------------------------------------------------------------- */
+  /* reset */
+
+  volume->can_mount = volume->should_automount = FALSE;
+  g_free (volume->name); volume->name = NULL;
+  g_free (volume->device_file); volume->device_file = NULL;
+  volume->dev = 0;
+  g_clear_object (&volume->icon);
+
+  /* ---------------------------------------------------------------------------------------------------- */
+  /* 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)
+    {
+      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);
+    }
+
+  udisks_drive = get_udisks_drive (volume);
+  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)
+        {
+          media_desc = drive_desc;
+          drive_desc = NULL;
+        }
+      if (media_icon == NULL)
+        {
+          media_icon = drive_icon;
+          drive_icon = NULL;
+        }
+
+      //volume->name = g_strdup (media_desc);
+      volume->icon = media_icon != NULL ? g_object_ref (media_icon) : NULL;
+
+      g_free (media_desc);
+      if (media_icon != NULL)
+        g_object_unref (media_icon);
+    }
+  else
+    {
+    }
+
+  /* ---------------------------------------------------------------------------------------------------- */
+  /* fallbacks */
+
+  if (volume->name == NULL)
+    {
+      /* Translators: Name used for volume */
+      volume->name = g_strdup (_("Volume"));
+    }
+  if (volume->icon == NULL)
+    volume->icon = g_themed_icon_new ("drive-removable-media");
+
+  /* ---------------------------------------------------------------------------------------------------- */
+  /* compute whether something changed */
+
+  changed = !((old_can_mount == volume->can_mount) &&
+              (old_should_automount == volume->should_automount) &&
+              (g_strcmp0 (old_name, volume->name) == 0) &&
+              (g_strcmp0 (old_device_file, volume->device_file) == 0) &&
+              (old_dev == volume->dev) &&
+              g_icon_equal (old_icon, volume->icon)
+              );
+
+  /* ---------------------------------------------------------------------------------------------------- */
+  /* free old values */
+
+  g_free (old_name);
+  g_free (old_device_file);
+  if (old_icon != NULL)
+    g_object_unref (old_icon);
+
+  return changed;
+}
+
+static void
+on_block_changed (GObject    *object,
+                  GParamSpec *pspec,
+                  gpointer    user_data)
+{
+  GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (user_data);
+  if (update_volume (volume))
+    emit_changed (volume);
+}
+
+GVfsUDisks2Volume *
+gvfs_udisks2_volume_new (GVfsUDisks2VolumeMonitor   *monitor,
+                         UDisksBlock                *block,
+                         GVfsUDisks2Drive           *drive,
+                         GFile                      *activation_root)
+{
+  GVfsUDisks2Volume *volume;
+
+  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);
+
+  volume->activation_root = activation_root != NULL ? g_object_ref (activation_root) : NULL;
+
+  volume->drive = drive;
+  if (drive != NULL)
+    gvfs_udisks2_drive_set_volume (drive, volume);
+
+  update_volume (volume);
+
+  return volume;
+}
+
+void
+gvfs_udisks2_volume_removed (GVfsUDisks2Volume *volume)
+{
+#if 0
+TODO
+  if (volume->pending_mount_op != NULL)
+    cancel_pending_mount_op (volume->pending_mount_op);
+#endif
+
+  if (volume->mount != NULL)
+    {
+      gvfs_udisks2_mount_unset_volume (volume->mount, volume);
+      volume->mount = NULL;
+    }
+
+  if (volume->drive != NULL)
+    {
+      gvfs_udisks2_drive_unset_volume (volume->drive, volume);
+      volume->drive = NULL;
+    }
+}
+
+void
+gvfs_udisks2_volume_set_mount (GVfsUDisks2Volume *volume,
+                               GVfsUDisks2Mount  *mount)
+{
+  if (volume->mount != mount)
+    {
+      if (volume->mount != NULL)
+        gvfs_udisks2_mount_unset_volume (volume->mount, volume);
+
+      volume->mount = mount;
+
+      emit_changed (volume);
+    }
+}
+
+void
+gvfs_udisks2_volume_unset_mount (GVfsUDisks2Volume *volume,
+                                 GVfsUDisks2Mount  *mount)
+{
+  if (volume->mount == mount)
+    {
+      volume->mount = NULL;
+      emit_changed (volume);
+    }
+}
+
+void
+gvfs_udisks2_volume_set_drive (GVfsUDisks2Volume *volume,
+                               GVfsUDisks2Drive  *drive)
+{
+  if (volume->drive != drive)
+    {
+      if (volume->drive != NULL)
+        gvfs_udisks2_drive_unset_volume (volume->drive, volume);
+      volume->drive = drive;
+      emit_changed (volume);
+    }
+}
+
+void
+gvfs_udisks2_volume_unset_drive (GVfsUDisks2Volume *volume,
+                                 GVfsUDisks2Drive  *drive)
+{
+  if (volume->drive == drive)
+    {
+      volume->drive = NULL;
+      emit_changed (volume);
+    }
+}
+
+static GIcon *
+gvfs_udisks2_volume_get_icon (GVolume *_volume)
+{
+  GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (_volume);
+  return volume->icon != NULL ? g_object_ref (volume->icon) : NULL;
+}
+
+static char *
+gvfs_udisks2_volume_get_name (GVolume *_volume)
+{
+  GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (_volume);
+  return g_strdup (volume->name);
+}
+
+static char *
+gvfs_udisks2_volume_get_uuid (GVolume *_volume)
+{
+  GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (_volume);
+  return g_strdup (volume->uuid);
+}
+
+static gboolean
+gvfs_udisks2_volume_can_mount (GVolume *_volume)
+{
+  GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (_volume);
+  return volume->can_mount;
+}
+
+static gboolean
+gvfs_udisks2_volume_can_eject (GVolume *_volume)
+{
+  GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (_volume);
+  gboolean can_eject = FALSE;
+
+  if (volume->drive != NULL)
+    can_eject = g_drive_can_eject (G_DRIVE (volume->drive));
+  return can_eject;
+}
+
+static gboolean
+gvfs_udisks2_volume_should_automount (GVolume *_volume)
+{
+  GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (_volume);
+  return volume->should_automount;
+}
+
+static GDrive *
+gvfs_udisks2_volume_get_drive (GVolume *volume)
+{
+  GVfsUDisks2Volume *gdu_volume = GVFS_UDISKS2_VOLUME (volume);
+  GDrive *drive = NULL;
+
+  if (gdu_volume->drive != NULL)
+    drive = g_object_ref (gdu_volume->drive);
+  return drive;
+}
+
+static GMount *
+gvfs_udisks2_volume_get_mount (GVolume *volume)
+{
+  GVfsUDisks2Volume *gdu_volume = GVFS_UDISKS2_VOLUME (volume);
+  GMount *mount = NULL;
+
+  if (gdu_volume->mount != NULL)
+    mount = g_object_ref (gdu_volume->mount);
+  return mount;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gchar *
+gvfs_udisks2_volume_get_identifier (GVolume      *_volume,
+                                    const gchar  *kind)
+{
+  GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (_volume);
+  const gchar *label;
+  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;
+
+  return ret;
+}
+
+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));
+
+  g_ptr_array_add (p, NULL);
+  return (gchar **) g_ptr_array_free (p, FALSE);
+}
+
+static GFile *
+gvfs_udisks2_volume_get_activation_root (GVolume *_volume)
+{
+  GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (_volume);
+  return volume->activation_root != NULL ? g_object_ref (volume->activation_root) : NULL;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+gvfs_udisks2_volume_volume_iface_init (GVolumeIface *iface)
+{
+  iface->get_name = gvfs_udisks2_volume_get_name;
+  iface->get_icon = gvfs_udisks2_volume_get_icon;
+  iface->get_uuid = gvfs_udisks2_volume_get_uuid;
+  iface->get_drive = gvfs_udisks2_volume_get_drive;
+  iface->get_mount = gvfs_udisks2_volume_get_mount;
+  iface->can_mount = gvfs_udisks2_volume_can_mount;
+  iface->can_eject = gvfs_udisks2_volume_can_eject;
+  iface->should_automount = gvfs_udisks2_volume_should_automount;
+  iface->get_activation_root = gvfs_udisks2_volume_get_activation_root;
+  iface->enumerate_identifiers = gvfs_udisks2_volume_enumerate_identifiers;
+  iface->get_identifier = gvfs_udisks2_volume_get_identifier;
+
+#if 0
+  iface->mount_fn = gvfs_udisks2_volume_mount;
+  iface->mount_finish = gvfs_udisks2_volume_mount_finish;
+  iface->eject = gvfs_udisks2_volume_eject;
+  iface->eject_finish = gvfs_udisks2_volume_eject_finish;
+  iface->eject_with_operation = gvfs_udisks2_volume_eject_with_operation;
+  iface->eject_with_operation_finish = gvfs_udisks2_volume_eject_with_operation_finish;
+#endif
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+UDisksBlock *
+gvfs_udisks2_volume_get_block (GVfsUDisks2Volume *volume)
+{
+  g_return_val_if_fail (GVFS_IS_UDISKS2_VOLUME (volume), NULL);
+  return volume->block;
+}
+
+dev_t
+gvfs_udisks2_volume_get_dev (GVfsUDisks2Volume *volume)
+{
+  g_return_val_if_fail (GVFS_IS_UDISKS2_VOLUME (volume), 0);
+  return volume->dev;
+}
+
+gboolean
+gvfs_udisks2_volume_has_uuid (GVfsUDisks2Volume *volume,
+                              const gchar       *uuid)
+{
+  g_return_val_if_fail (GVFS_IS_UDISKS2_VOLUME (volume), FALSE);
+  return g_strcmp0 (volume->uuid, uuid) == 0;
+}
diff --git a/monitor/udisks2/gvfsudisks2volume.h b/monitor/udisks2/gvfsudisks2volume.h
new file mode 100644
index 0000000..cda2b9c
--- /dev/null
+++ b/monitor/udisks2/gvfsudisks2volume.h
@@ -0,0 +1,64 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* gvfs - extensions for gio
+ *
+ * Copyright (C) 2006-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __GVFS_UDISKS2_VOLUME_H__
+#define __GVFS_UDISKS2_VOLUME_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "gvfsudisks2volumemonitor.h"
+
+G_BEGIN_DECLS
+
+#define GVFS_TYPE_UDISKS2_VOLUME  (gvfs_udisks2_volume_get_type ())
+#define GVFS_UDISKS2_VOLUME(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), GVFS_TYPE_UDISKS2_VOLUME, GVfsUDisks2Volume))
+#define GVFS_IS_UDISKS2_VOLUME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVFS_TYPE_UDISKS2_VOLUME))
+
+GType              gvfs_udisks2_volume_get_type    (void) G_GNUC_CONST;
+
+GVfsUDisks2Volume *gvfs_udisks2_volume_new         (GVfsUDisks2VolumeMonitor   *monitor,
+                                                    UDisksBlock                *block,
+                                                    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);
+
+void               gvfs_udisks2_volume_set_mount   (GVfsUDisks2Volume          *volume,
+                                                    GVfsUDisks2Mount           *mount);
+void               gvfs_udisks2_volume_unset_mount (GVfsUDisks2Volume          *volume,
+                                                    GVfsUDisks2Mount           *mount);
+
+void               gvfs_udisks2_volume_set_drive   (GVfsUDisks2Volume          *volume,
+                                                    GVfsUDisks2Drive           *drive);
+void               gvfs_udisks2_volume_unset_drive (GVfsUDisks2Volume          *volume,
+                                                    GVfsUDisks2Drive           *drive);
+
+gboolean           gvfs_udisks2_volume_has_uuid    (GVfsUDisks2Volume          *volume,
+                                                    const gchar                *uuid);
+
+G_END_DECLS
+
+#endif /* __GVFS_UDISKS2_VOLUME_H__ */
diff --git a/monitor/udisks2/gvfsudisks2volumemonitor.c b/monitor/udisks2/gvfsudisks2volumemonitor.c
index a3fabc6..0b14f2e 100644
--- a/monitor/udisks2/gvfsudisks2volumemonitor.c
+++ b/monitor/udisks2/gvfsudisks2volumemonitor.c
@@ -27,11 +27,18 @@
 #include <string.h>
 #include <stdlib.h>
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
 #include <glib.h>
 #include <glib/gi18n-lib.h>
 #include <gio/gio.h>
 
 #include "gvfsudisks2volumemonitor.h"
+#include "gvfsudisks2drive.h"
+#include "gvfsudisks2volume.h"
+#include "gvfsudisks2mount.h"
 
 static GVfsUDisks2VolumeMonitor *the_volume_monitor = NULL;
 
@@ -47,10 +54,63 @@ struct _GVfsUDisks2VolumeMonitor
   GNativeVolumeMonitor parent;
 
   UDisksClient *client;
+
+  GList *last_mounts;
+
+  GList *drives;
+  GList *volumes;
+  GList *mounts;
+  /* we keep volumes/mounts for blank and audio discs separate to handle e.g. mixed discs properly */
+  GList *disc_volumes;
+  GList *disc_mounts;
 };
 
+static void object_list_free (GList *objects);
 static UDisksClient *get_udisks_client_sync (GError **error);
 
+static void update_all               (GVfsUDisks2VolumeMonitor  *monitor,
+                                      gboolean                   emit_changes);
+static void update_drives            (GVfsUDisks2VolumeMonitor  *monitor,
+                                      GList                    **added_drives,
+                                      GList                    **removed_drives);
+static void update_volumes           (GVfsUDisks2VolumeMonitor  *monitor,
+                                      GList                    **added_volumes,
+                                      GList                    **removed_volumes);
+static void update_mounts            (GVfsUDisks2VolumeMonitor  *monitor,
+                                      GList                    **added_mounts,
+                                      GList                    **removed_mounts);
+static void update_discs             (GVfsUDisks2VolumeMonitor  *monitor,
+                                      GList                    **added_volumes,
+                                      GList                    **removed_volumes,
+                                      GList                    **added_mounts,
+                                      GList                    **removed_mounts);
+
+
+static void on_object_added (GDBusObjectManager  *manager,
+                             GDBusObject         *object,
+                             gpointer             user_data);
+
+static void on_object_removed (GDBusObjectManager  *manager,
+                               GDBusObject         *object,
+                               gpointer             user_data);
+
+static void on_interface_added (GDBusObjectManager  *manager,
+                                GDBusObject         *object,
+                                GDBusInterface      *interface,
+                                gpointer             user_data);
+
+static void on_interface_removed (GDBusObjectManager  *manager,
+                                  GDBusObject         *object,
+                                  GDBusInterface      *interface,
+                                  gpointer             user_data);
+
+static void on_interface_proxy_properties_changed (GDBusObjectManagerClient   *manager,
+                                                   GDBusObjectProxy           *object_proxy,
+                                                   GDBusProxy                 *interface_proxy,
+                                                   GVariant                   *changed_properties,
+                                                   const gchar *const         *invalidated_properties,
+                                                   gpointer                    user_data);
+
 G_DEFINE_TYPE (GVfsUDisks2VolumeMonitor, gvfs_udisks2_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR)
 
 static void
@@ -66,55 +126,167 @@ static void
 gvfs_udisks2_volume_monitor_finalize (GObject *object)
 {
   GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (object);
+  GDBusObjectManager *object_manager;
+
+  object_manager = udisks_client_get_object_manager (monitor->client);
+  g_signal_handlers_disconnect_by_func (object_manager,
+                                        G_CALLBACK (on_object_added),
+                                        monitor);
+  g_signal_handlers_disconnect_by_func (object_manager,
+                                        G_CALLBACK (on_object_removed),
+                                        monitor);
+  g_signal_handlers_disconnect_by_func (object_manager,
+                                        G_CALLBACK (on_interface_added),
+                                        monitor);
+  g_signal_handlers_disconnect_by_func (object_manager,
+                                        G_CALLBACK (on_interface_removed),
+                                        monitor);
+  g_signal_handlers_disconnect_by_func (object_manager,
+                                        G_CALLBACK (on_interface_proxy_properties_changed),
+                                        monitor);
 
   g_clear_object (&monitor->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->mounts);
+
+  object_list_free (monitor->disc_volumes);
+  object_list_free (monitor->disc_mounts);
+
   G_OBJECT_CLASS (gvfs_udisks2_volume_monitor_parent_class)->finalize (object);
 }
 
 static GList *
-get_mounts (GVolumeMonitor *monitor)
+get_mounts (GVolumeMonitor *_monitor)
 {
-  /* TODO */
-  return NULL;
+  GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (_monitor);
+  GList *ret;
+
+  ret = g_list_copy (monitor->mounts);
+  ret = g_list_concat (ret, g_list_copy (monitor->disc_mounts));
+  g_list_foreach (ret, (GFunc) g_object_ref, NULL);
+  return ret;
 }
 
 static GList *
-get_volumes (GVolumeMonitor *monitor)
+get_volumes (GVolumeMonitor *_monitor)
 {
-  /* TODO */
-  return NULL;
+  GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (_monitor);
+  GList *ret;
+
+  ret = g_list_copy (monitor->volumes);
+  ret = g_list_concat (ret, g_list_copy (monitor->disc_volumes));
+  g_list_foreach (ret, (GFunc) g_object_ref, NULL);
+  return ret;
 }
 
 static GList *
-get_connected_drives (GVolumeMonitor *monitor)
+get_connected_drives (GVolumeMonitor *_monitor)
 {
-  /* TODO */
-  return NULL;
+  GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (_monitor);
+  GList *ret;
+
+  ret = g_list_copy (monitor->drives);
+  g_list_foreach (ret, (GFunc) g_object_ref, NULL);
+  return ret;
 }
 
 static GVolume *
-get_volume_for_uuid (GVolumeMonitor *monitor,
+get_volume_for_uuid (GVolumeMonitor *_monitor,
                      const gchar    *uuid)
 {
-  /* TODO */
+  GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (_monitor);
+  GVfsUDisks2Volume *volume;
+  GList *l;
+
+  for (l = monitor->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;
+      if (gvfs_udisks2_volume_has_uuid (volume, uuid))
+        goto found;
+    }
+
   return NULL;
+
+ found:
+  return G_VOLUME (g_object_ref (volume));
 }
 
 static GMount *
-get_mount_for_uuid (GVolumeMonitor *monitor,
+get_mount_for_uuid (GVolumeMonitor *_monitor,
                     const gchar    *uuid)
 {
-  /* TODO */
+  GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (_monitor);
+  GVfsUDisks2Mount *mount;
+  GList *l;
+
+  for (l = monitor->mounts; l != NULL; l = l->next)
+    {
+      mount = l->data;
+      if (gvfs_udisks2_mount_has_uuid (l->data, uuid))
+        goto found;
+    }
+  for (l = monitor->disc_mounts; l != NULL; l = l->next)
+    {
+      mount = l->data;
+      if (gvfs_udisks2_mount_has_uuid (mount, uuid))
+        goto found;
+    }
+
   return NULL;
+
+ found:
+  return G_MOUNT (g_object_ref (mount));
 }
 
 static GMount *
 get_mount_for_mount_path (const gchar  *mount_path,
                           GCancellable *cancellable)
 {
-  /* TODO */
-  return NULL;
+  GVfsUDisks2VolumeMonitor *monitor = NULL;
+  GMount *ret = NULL;
+
+  if (the_volume_monitor == NULL)
+    {
+      /* Bah, no monitor is set up.. so we have to create one, find
+       * what the user asks for and throw it away again.
+       */
+      monitor = GVFS_UDISKS2_VOLUME_MONITOR (gvfs_udisks2_volume_monitor_new ());
+    }
+  else
+    {
+      monitor = g_object_ref (the_volume_monitor);
+    }
+
+  /* creation of the volume monitor could fail */
+  if (monitor != NULL)
+    {
+      GList *l;
+      for (l = monitor->mounts; l != NULL; l = l->next)
+        {
+          GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (l->data);
+          if (gvfs_udisks2_mount_has_mount_path (mount, mount_path))
+            {
+              ret = g_object_ref (mount);
+              goto out;
+            }
+        }
+    }
+
+ out:
+  if (monitor != NULL)
+    g_object_unref (monitor);
+  return ret;
 }
 
 static GObject *
@@ -145,7 +317,33 @@ gvfs_udisks2_volume_monitor_constructor (GType                  type,
 static void
 gvfs_udisks2_volume_monitor_init (GVfsUDisks2VolumeMonitor *monitor)
 {
+  GDBusObjectManager *object_manager;
+
   monitor->client = get_udisks_client_sync (NULL);
+
+  object_manager = udisks_client_get_object_manager (monitor->client);
+  g_signal_connect (object_manager,
+                    "object-added",
+                    G_CALLBACK (on_object_added),
+                    monitor);
+  g_signal_connect (object_manager,
+                    "object-removed",
+                    G_CALLBACK (on_object_removed),
+                    monitor);
+  g_signal_connect (object_manager,
+                    "interface-added",
+                    G_CALLBACK (on_interface_added),
+                    monitor);
+  g_signal_connect (object_manager,
+                    "interface-removed",
+                    G_CALLBACK (on_interface_removed),
+                    monitor);
+  g_signal_connect (object_manager,
+                    "interface-proxy-properties-changed",
+                    G_CALLBACK (on_interface_proxy_properties_changed),
+                    monitor);
+
+  update_all (monitor, FALSE);
 }
 
 static gboolean
@@ -190,6 +388,15 @@ gvfs_udisks2_volume_monitor_new (void)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+UDisksClient *
+gvfs_udisks2_volume_monitor_get_udisks_client (GVfsUDisks2VolumeMonitor *monitor)
+{
+  g_return_val_if_fail (GVFS_IS_UDISKS2_VOLUME_MONITOR (monitor), NULL);
+  return monitor->client;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static UDisksClient *
 get_udisks_client_sync (GError **error)
 {
@@ -210,3 +417,658 @@ get_udisks_client_sync (GError **error)
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
+
+static void
+diff_sorted_lists (GList         *list1,
+                   GList         *list2,
+                   GCompareFunc   compare,
+                   GList        **added,
+                   GList        **removed)
+{
+  int order;
+
+  *added = *removed = NULL;
+
+  while (list1 != NULL &&
+         list2 != NULL)
+    {
+      order = (*compare) (list1->data, list2->data);
+      if (order < 0)
+        {
+          *removed = g_list_prepend (*removed, list1->data);
+          list1 = list1->next;
+        }
+      else if (order > 0)
+        {
+          *added = g_list_prepend (*added, list2->data);
+          list2 = list2->next;
+        }
+      else
+        { /* same item */
+          list1 = list1->next;
+          list2 = list2->next;
+        }
+    }
+
+  while (list1 != NULL)
+    {
+      *removed = g_list_prepend (*removed, list1->data);
+      list1 = list1->next;
+    }
+  while (list2 != NULL)
+    {
+      *added = g_list_prepend (*added, list2->data);
+      list2 = list2->next;
+    }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+object_list_free (GList *objects)
+{
+  g_list_foreach (objects, (GFunc)g_object_unref, NULL);
+  g_list_free (objects);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+object_list_emit (GVfsUDisks2VolumeMonitor *monitor,
+                  const gchar              *monitor_signal,
+                  const gchar              *object_signal,
+                  GList                    *objects)
+{
+  GList *l;
+  for (l = objects; l != NULL; l = l->next)
+    {
+      g_signal_emit_by_name (monitor, monitor_signal, l->data);
+      if (object_signal)
+        g_signal_emit_by_name (l->data, object_signal);
+    }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_object_added (GDBusObjectManager  *manager,
+                 GDBusObject         *object,
+                 gpointer             user_data)
+{
+  GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (user_data);
+  // g_debug ("on_object_added %s", g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
+  update_all (monitor, TRUE);
+}
+
+static void
+on_object_removed (GDBusObjectManager  *manager,
+                   GDBusObject         *object,
+                   gpointer             user_data)
+{
+  GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (user_data);
+  // g_debug ("on_object_removed %s", g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
+  update_all (monitor, TRUE);
+}
+
+static void
+on_interface_added (GDBusObjectManager  *manager,
+                    GDBusObject         *object,
+                    GDBusInterface      *interface,
+                    gpointer             user_data)
+{
+  GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (user_data);
+  // g_debug ("on_interface_added %s", g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
+  update_all (monitor, TRUE);
+}
+
+static void
+on_interface_removed (GDBusObjectManager  *manager,
+                      GDBusObject         *object,
+                      GDBusInterface      *interface,
+                      gpointer             user_data)
+{
+  GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (user_data);
+  // g_debug ("on_interface_removed %s", g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
+  update_all (monitor, TRUE);
+}
+
+static void
+on_interface_proxy_properties_changed (GDBusObjectManagerClient   *manager,
+                                       GDBusObjectProxy           *object_proxy,
+                                       GDBusProxy                 *interface_proxy,
+                                       GVariant                   *changed_properties,
+                                       const gchar *const         *invalidated_properties,
+                                       gpointer                    user_data)
+{
+  GVfsUDisks2VolumeMonitor *monitor = GVFS_UDISKS2_VOLUME_MONITOR (user_data);
+  // g_debug ("on_interface_proxy_properties_changed %s", g_dbus_object_get_object_path (G_DBUS_OBJECT (object_proxy)));
+  update_all (monitor, TRUE);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+update_all (GVfsUDisks2VolumeMonitor *monitor,
+            gboolean                  emit_changes)
+{
+  GList *added_drives, *removed_drives;
+  GList *added_volumes, *removed_volumes;
+  GList *added_mounts, *removed_mounts;
+
+  added_drives = NULL;
+  removed_drives = NULL;
+  added_volumes = NULL;
+  removed_volumes = NULL;
+  added_mounts = NULL;
+  removed_mounts = NULL;
+
+  update_drives (monitor, &added_drives, &removed_drives);
+  update_volumes (monitor, &added_volumes, &removed_volumes);
+  update_mounts (monitor, &added_mounts, &removed_mounts);
+  update_discs (monitor,
+                &added_volumes, &removed_volumes,
+                &added_mounts, &removed_mounts);
+
+  if (emit_changes)
+    {
+      object_list_emit (monitor,
+                        "drive-disconnected", NULL,
+                        removed_drives);
+      object_list_emit (monitor,
+                        "drive-connected", NULL,
+                        added_drives);
+
+      object_list_emit (monitor,
+                        "volume-removed", "removed",
+                        removed_volumes);
+      object_list_emit (monitor,
+                        "volume-added", NULL,
+                        added_volumes);
+
+      object_list_emit (monitor,
+                        "mount-removed", "unmounted",
+                        removed_mounts);
+      object_list_emit (monitor,
+                        "mount-added", NULL,
+                        added_mounts);
+    }
+
+  object_list_free (removed_drives);
+  object_list_free (added_drives);
+  object_list_free (removed_volumes);
+  object_list_free (added_volumes);
+  object_list_free (removed_mounts);
+  object_list_free (added_mounts);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+should_include_mount (GVfsUDisks2VolumeMonitor *monitor,
+                      GUnixMountEntry          *mount_entry)
+{
+  gboolean ret = FALSE;
+  ret = g_unix_mount_guess_should_display (mount_entry);
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+should_include_volume_check_mount_points (GVfsUDisks2VolumeMonitor *monitor,
+                                          UDisksBlock              *block)
+{
+  gboolean ret = TRUE;
+  GDBusObject *obj;
+  UDisksFilesystem *fs;
+  const gchar* const *mount_points;
+  guint n;
+
+  obj = g_dbus_interface_get_object (G_DBUS_INTERFACE (block));
+  if (obj == NULL)
+    goto out;
+
+  fs = udisks_object_peek_filesystem (UDISKS_OBJECT (obj));
+  if (fs == NULL)
+    goto out;
+
+  mount_points = udisks_filesystem_get_mount_points (fs);
+  for (n = 0; mount_points != NULL && mount_points[n] != NULL; n++)
+    {
+      const gchar *mount_point = mount_points[n];
+      GUnixMountEntry *mount_entry;
+
+      mount_entry = g_unix_mount_at (mount_point, NULL);
+      if (mount_entry != NULL)
+        {
+          if (!should_include_mount (monitor, mount_entry))
+            {
+              g_unix_mount_free (mount_entry);
+              ret = FALSE;
+              goto out;
+            }
+          g_unix_mount_free (mount_entry);
+        }
+    }
+
+ out:
+  return ret;
+}
+
+static gboolean
+should_include_volume (GVfsUDisks2VolumeMonitor *monitor,
+                       UDisksBlock              *block)
+{
+  gboolean ret = FALSE;
+
+  /* Check should_include_mount() for all mount points, if any - e.g. if a volume
+   * is mounted in a place where the mount is to be ignored, we ignore the volume
+   * as well
+   */
+  if (!should_include_volume_check_mount_points (monitor, block))
+    goto out;
+
+  /* TODO: handle crypto, fstab and a bunch of other stuff */
+  if (g_strcmp0 (udisks_block_get_id_usage (block), "filesystem") != 0)
+    goto out;
+
+  ret = TRUE;
+
+ out:
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+should_include_drive (GVfsUDisks2VolumeMonitor *monitor,
+                      UDisksDrive              *drive)
+{
+  gboolean ret = TRUE;
+  /* TODO */
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gint
+udisks_drive_compare (UDisksDrive *a, UDisksDrive *b)
+{
+  return g_strcmp0 (g_dbus_object_get_object_path (g_dbus_interface_get_object (G_DBUS_INTERFACE (a))),
+                    g_dbus_object_get_object_path (g_dbus_interface_get_object (G_DBUS_INTERFACE (b))));
+}
+
+static gint
+block_compare (UDisksBlock *a, UDisksBlock *b)
+{
+  return g_strcmp0 (udisks_block_get_device (a), udisks_block_get_device (b));
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GVfsUDisks2Drive *
+find_drive_for_udisks_drive (GVfsUDisks2VolumeMonitor *monitor,
+                             UDisksDrive              *udisks_drive)
+{
+  GVfsUDisks2Drive *ret = NULL;
+  GList *l;
+
+  for (l = monitor->drives; l != NULL; l = l->next)
+    {
+      GVfsUDisks2Drive *drive = GVFS_UDISKS2_DRIVE (l->data);
+      if (gvfs_udisks2_drive_get_udisks_drive (drive) == udisks_drive)
+        {
+          ret = drive;
+          goto out;
+        }
+    }
+
+ out:
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GVfsUDisks2Volume *
+find_volume_for_block (GVfsUDisks2VolumeMonitor *monitor,
+                       UDisksBlock              *block)
+{
+  GVfsUDisks2Volume *ret = NULL;
+  GList *l;
+
+  for (l = monitor->volumes; l != NULL; l = l->next)
+    {
+      GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (l->data);
+      if (gvfs_udisks2_volume_get_block (volume) == block)
+        {
+          ret = volume;
+          goto out;
+        }
+    }
+
+  for (l = monitor->disc_volumes; l != NULL; l = l->next)
+    {
+      GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (l->data);
+      if (gvfs_udisks2_volume_get_block (volume) == block)
+        {
+          ret = volume;
+          goto out;
+        }
+    }
+
+ out:
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GVfsUDisks2Volume *
+find_volume_for_device (GVfsUDisks2VolumeMonitor *monitor,
+                        const gchar              *device)
+{
+  GVfsUDisks2Volume *ret = NULL;
+  GList *l;
+  struct stat statbuf;
+
+  if (stat (device, &statbuf) != 0)
+    goto out;
+
+  for (l = monitor->volumes; l != NULL; l = l->next)
+    {
+      GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (l->data);
+      if (gvfs_udisks2_volume_get_dev (volume) == statbuf.st_rdev)
+        {
+          ret = volume;
+          goto out;
+        }
+    }
+
+  for (l = monitor->disc_volumes; l != NULL; l = l->next)
+    {
+      GVfsUDisks2Volume *volume = GVFS_UDISKS2_VOLUME (l->data);
+      if (gvfs_udisks2_volume_get_dev (volume) == statbuf.st_rdev)
+        {
+          ret = volume;
+          goto out;
+        }
+    }
+
+ out:
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GVfsUDisks2Mount *
+find_mount_by_mount_path (GVfsUDisks2VolumeMonitor *monitor,
+                          const gchar              *mount_path)
+{
+  GVfsUDisks2Mount *ret = NULL;
+  GList *l;
+
+  for (l = monitor->mounts; l != NULL; l = l->next)
+    {
+      GVfsUDisks2Mount *mount = GVFS_UDISKS2_MOUNT (l->data);
+      if (gvfs_udisks2_mount_has_mount_path (mount, mount_path))
+        {
+          ret = mount;
+          goto out;
+        }
+    }
+ out:
+  return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+update_drives (GVfsUDisks2VolumeMonitor  *monitor,
+               GList                    **added_drives,
+               GList                    **removed_drives)
+{
+  GList *cur_udisks_drives;
+  GList *new_udisks_drives;
+  GList *removed, *added;
+  GList *l;
+  GVfsUDisks2Drive *drive;
+  GList *objects;
+
+  objects = g_dbus_object_manager_get_objects (udisks_client_get_object_manager (monitor->client));
+
+  cur_udisks_drives = NULL;
+  for (l = monitor->drives; l != NULL; l = l->next)
+    {
+      cur_udisks_drives = g_list_prepend (cur_udisks_drives,
+                                          gvfs_udisks2_drive_get_udisks_drive (GVFS_UDISKS2_DRIVE (l->data)));
+    }
+
+  /* remove devices we want to ignore - we do it here so we get to reevaluate
+   * on the next update whether they should still be ignored
+   */
+  new_udisks_drives = NULL;
+  for (l = objects; l != NULL; l = l->next)
+    {
+      UDisksDrive *udisks_drive = udisks_object_peek_drive (UDISKS_OBJECT (l->data));
+      if (udisks_drive == NULL)
+        continue;
+      if (should_include_drive (monitor, udisks_drive))
+        new_udisks_drives = g_list_prepend (new_udisks_drives, udisks_drive);
+    }
+
+  cur_udisks_drives = g_list_sort (cur_udisks_drives, (GCompareFunc) udisks_drive_compare);
+  new_udisks_drives = g_list_sort (new_udisks_drives, (GCompareFunc) udisks_drive_compare);
+  diff_sorted_lists (cur_udisks_drives,
+                     new_udisks_drives, (GCompareFunc) udisks_drive_compare,
+                     &added, &removed);
+
+  for (l = removed; l != NULL; l = l->next)
+    {
+      UDisksDrive *udisks_drive = UDISKS_DRIVE (l->data);
+
+      drive = find_drive_for_udisks_drive (monitor, udisks_drive);
+      if (drive != NULL)
+        {
+          /*g_debug ("removing drive %s", gdu_presentable_get_id (p));*/
+          gvfs_udisks2_drive_disconnected (drive);
+          monitor->drives = g_list_remove (monitor->drives, drive);
+          *removed_drives = g_list_prepend (*removed_drives, g_object_ref (drive));
+          g_object_unref (drive);
+        }
+    }
+
+  for (l = added; l != NULL; l = l->next)
+    {
+      UDisksDrive *udisks_drive = UDISKS_DRIVE (l->data);
+
+      drive = find_drive_for_udisks_drive (monitor, udisks_drive);
+      if (drive == NULL)
+        {
+          /*g_debug ("adding drive %s", gdu_presentable_get_id (p));*/
+          drive = gvfs_udisks2_drive_new (monitor, udisks_drive);
+          if (udisks_drive != NULL)
+            {
+              monitor->drives = g_list_prepend (monitor->drives, drive);
+              *added_drives = g_list_prepend (*added_drives, g_object_ref (drive));
+            }
+        }
+    }
+
+  g_list_free (added);
+  g_list_free (removed);
+
+  g_list_free (cur_udisks_drives);
+  g_list_free (new_udisks_drives);
+
+  g_list_foreach (objects, (GFunc) g_object_unref, NULL);
+  g_list_free (objects);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+update_volumes (GVfsUDisks2VolumeMonitor  *monitor,
+                GList                    **added_volumes,
+                GList                    **removed_volumes)
+{
+  GList *cur_block_volumes;
+  GList *new_block_volumes;
+  GList *removed, *added;
+  GList *l;
+  GVfsUDisks2Volume *volume;
+  GList *objects;
+
+  objects = g_dbus_object_manager_get_objects (udisks_client_get_object_manager (monitor->client));
+
+  cur_block_volumes = NULL;
+  for (l = monitor->volumes; l != NULL; l = l->next)
+    {
+      cur_block_volumes = g_list_prepend (cur_block_volumes,
+                                          gvfs_udisks2_volume_get_block (GVFS_UDISKS2_VOLUME (l->data)));
+    }
+
+  new_block_volumes = NULL;
+  for (l = objects; l != NULL; l = l->next)
+    {
+      UDisksBlock *block = udisks_object_peek_block (UDISKS_OBJECT (l->data));
+      if (block == NULL)
+        continue;
+      if (should_include_volume (monitor, block))
+        new_block_volumes = g_list_prepend (new_block_volumes, block);
+    }
+
+  cur_block_volumes = g_list_sort (cur_block_volumes, (GCompareFunc) block_compare);
+  new_block_volumes = g_list_sort (new_block_volumes, (GCompareFunc) block_compare);
+  diff_sorted_lists (cur_block_volumes,
+                     new_block_volumes, (GCompareFunc) block_compare,
+                     &added, &removed);
+
+  for (l = removed; l != NULL; l = l->next)
+    {
+      UDisksBlock *block = UDISKS_BLOCK (l->data);
+      volume = find_volume_for_block (monitor, block);
+      if (volume != NULL)
+        {
+          gvfs_udisks2_volume_removed (volume);
+          monitor->volumes = g_list_remove (monitor->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)
+    {
+      UDisksBlock *block = UDISKS_BLOCK (l->data);
+      volume = find_volume_for_block (monitor, block);
+      if (volume == NULL)
+        {
+          GVfsUDisks2Drive *drive = NULL;
+          UDisksDrive *udisks_drive;
+
+          udisks_drive = udisks_client_get_drive_for_block (monitor->client, block);
+          if (udisks_drive != NULL)
+            {
+              drive = find_drive_for_udisks_drive (monitor, udisks_drive);
+              g_object_unref (udisks_drive);
+            }
+          volume = gvfs_udisks2_volume_new (monitor,
+                                            block,
+                                            drive,
+                                            NULL); /* activation_root */
+          if (volume != NULL)
+            {
+              monitor->volumes = g_list_prepend (monitor->volumes, volume);
+              *added_volumes = g_list_prepend (*added_volumes, g_object_ref (volume));
+            }
+         }
+    }
+
+  g_list_free (added);
+  g_list_free (removed);
+  g_list_free (new_block_volumes);
+  g_list_free (cur_block_volumes);
+
+  g_list_foreach (objects, (GFunc) g_object_unref, NULL);
+  g_list_free (objects);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+update_mounts (GVfsUDisks2VolumeMonitor  *monitor,
+               GList                    **added_mounts,
+               GList                    **removed_mounts)
+{
+  GList *new_mounts;
+  GList *removed, *added;
+  GList *l, *ll;
+  GVfsUDisks2Mount *mount;
+  GVfsUDisks2Volume *volume;
+
+  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
+   */
+  for (l = new_mounts; l != NULL; l = ll)
+    {
+      GUnixMountEntry *mount_entry = l->data;
+      ll = l->next;
+      if (!should_include_mount (monitor, mount_entry))
+        {
+          g_unix_mount_free (mount_entry);
+          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,
+                     new_mounts, (GCompareFunc) g_unix_mount_compare,
+                     &added, &removed);
+
+  for (l = removed; l != NULL; l = l->next)
+    {
+      GUnixMountEntry *mount_entry = l->data;
+      mount = find_mount_by_mount_path (monitor, g_unix_mount_get_mount_path (mount_entry));
+      if (mount != NULL)
+        {
+          gvfs_udisks2_mount_unmounted (mount);
+          monitor->mounts = g_list_remove (monitor->mounts, mount);
+          *removed_mounts = g_list_prepend (*removed_mounts, g_object_ref (mount));
+          g_object_unref (mount);
+        }
+    }
+
+  for (l = added; l != NULL; l = l->next)
+    {
+      GUnixMountEntry *mount_entry = l->data;
+      const gchar *device_file;
+
+      device_file = g_unix_mount_get_device_path (mount_entry);
+      volume = find_volume_for_device (monitor, device_file);
+      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_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;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+update_discs (GVfsUDisks2VolumeMonitor  *monitor,
+              GList                    **added_volumes,
+              GList                    **removed_volumes,
+              GList                    **added_mounts,
+              GList                    **removed_mounts)
+{
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
diff --git a/monitor/udisks2/gvfsudisks2volumemonitor.h b/monitor/udisks2/gvfsudisks2volumemonitor.h
index 57a67ac..a152743 100644
--- a/monitor/udisks2/gvfsudisks2volumemonitor.h
+++ b/monitor/udisks2/gvfsudisks2volumemonitor.h
@@ -32,9 +32,9 @@
 
 G_BEGIN_DECLS
 
-#define GVFS_TYPE_UDISKS2_VOLUME_MONITOR (gvfs_udisks2_volume_monitor_get_type ())
-#define GVFS_UDISKS2_VOLUME_MONITOR(o)   (G_TYPE_CHECK_INSTANCE_CAST ((o), GVFS_TYPE_UDISKS2_VOLUME_MONITOR, GVfsUDisks2VolumeMonitor))
-#define G_IS_GDU_VOLUME_MONITOR(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVFS_TYPE_UDISKS2_VOLUME_MONITOR))
+#define GVFS_TYPE_UDISKS2_VOLUME_MONITOR  (gvfs_udisks2_volume_monitor_get_type ())
+#define GVFS_UDISKS2_VOLUME_MONITOR(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), GVFS_TYPE_UDISKS2_VOLUME_MONITOR, GVfsUDisks2VolumeMonitor))
+#define GVFS_IS_UDISKS2_VOLUME_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVFS_TYPE_UDISKS2_VOLUME_MONITOR))
 
 typedef struct _GVfsUDisks2VolumeMonitor GVfsUDisks2VolumeMonitor;
 
@@ -43,8 +43,9 @@ typedef struct _GVfsUDisks2Drive GVfsUDisks2Drive;
 typedef struct _GVfsUDisks2Volume GVfsUDisks2Volume;
 typedef struct _GVfsUDisks2Mount GVfsUDisks2Mount;
 
-GType           gvfs_udisks2_volume_monitor_get_type (void) G_GNUC_CONST;
-GVolumeMonitor *gvfs_udisks2_volume_monitor_new      (void);
+GType           gvfs_udisks2_volume_monitor_get_type          (void) G_GNUC_CONST;
+GVolumeMonitor *gvfs_udisks2_volume_monitor_new               (void);
+UDisksClient   *gvfs_udisks2_volume_monitor_get_udisks_client (GVfsUDisks2VolumeMonitor *monitor);
 
 G_END_DECLS
 



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