[Utopia] gnome-vfs patch, take 2



Hey,

Here is an updated version of the HAL patch for the volume monitor of
gnome-vfs. It is attached and is against HEAD of gnome-vfs CVS. It also
applies cleanly to the gnome-vfs source RPM in Fedora development.

This version shows volumes that are not yet mounted, see a screenshot
here 

 http://freedesktop.org/~david/gnome-vfs-hal-patch2-screenshot.png

though there is a way to use the show-only-mounted volumes at compile
time - obviously this requires an automounter like g-v-m. The patch is
still a bit shaky in terms of features etc. but it seems pretty stable
so far.

Before we can do it the way that Alex wants it (see earlier mails on
this list), API changes are needed in gnome-vfs, see this bug for
details

 http://bugzilla.gnome.org/show_bug.cgi?id=143888

Cheers,
David
? gnome-vfs-hal-patch-prelim-2.patch
? gnome-vfs-hal-patch-prelim.patch
? gnome-vfs-hal-patch1.patch
? gnome-vfs-hal-patch2.patch
? daemon/gnome-vfs-daemon
? libgnomevfs/gnome-vfs-hal-mounts.c
? libgnomevfs/gnome-vfs-hal-mounts.h
? libgnomevfs/s-enum-types-c
? libgnomevfs/s-enum-types-h
Index: configure.in
===================================================================
RCS file: /cvs/gnome/gnome-vfs/configure.in,v
retrieving revision 1.305
diff -u -p -r1.305 configure.in
--- configure.in	1 Jun 2004 07:13:54 -0000	1.305
+++ configure.in	7 Jun 2004 16:22:08 -0000
@@ -618,8 +618,33 @@ if test "x$enable_gnutls" = "xyes"; then
   fi
 fi
 
-PKG_CHECK_MODULES(LIBGNOMEVFS, glib-2.0 >= $GLIB_REQUIRED gmodule-2.0 >= $GLIB_REQUIRED gthread-2.0 >= $GLIB_REQUIRED gconf-2.0 >= $GCONF_REQUIRED bonobo-activation-2.0 >= $BONOBO_ACTIVATION_REQUIRED libbonobo-2.0 >= $BONOBO_REQUIRED ORBit-2.0 >= $ORBIT_REQUIRED libxml-2.0 >= $XML_REQUIRED gnome-mime-data-2.0)
-LIBGNOMEVFS_CFLAGS="$LIBGNOMEVFS_CFLAGS $OPENSSL_CFLAGS $LIBGNUTLS_CFLAGS"
+
+
+dnl ****************************
+dnl HAL stuff
+dnl ****************************
+
+AC_ARG_ENABLE(hal,
+AC_HELP_STRING([--enable-hal],[use hal, if available]),
+[case "${enableval}" in
+yes) ENABLE_HAL=yes ;;
+no)  ENABLE_HAL=no ;;
+*) AC_MSG_ERROR(bad value ${enableval} for --enable-hal) ;;
+esac],
+[ENABLE_HAL=yes]) dnl Default value
+
+if test "x$ENABLE_HAL" = "xyes"; then
+	PKG_CHECK_MODULES(HAL, hal >= 0.2.90,
+		[ USE_HAL="hal >= 0.2.90, dbus-1 >= 0.21, dbus-glib-1 >= 0.21"; HAL_CFLAGS="-DUSE_HAL"],
+		[ USE_HAL=""; HAL_CFLAGS="-UUSE_HAL" ])
+else
+	HAL_CFLAGS="-UUSE_HAL"
+	USE_HAL=""
+fi
+AC_SUBST(HAL_CFLAGS)
+
+PKG_CHECK_MODULES(LIBGNOMEVFS, glib-2.0 >= $GLIB_REQUIRED gmodule-2.0 >= $GLIB_REQUIRED gthread-2.0 >= $GLIB_REQUIRED gconf-2.0 >= $GCONF_REQUIRED bonobo-activation-2.0 >= $BONOBO_ACTIVATION_REQUIRED libbonobo-2.0 >= $BONOBO_REQUIRED ORBit-2.0 >= $ORBIT_REQUIRED libxml-2.0 >= $XML_REQUIRED gnome-mime-data-2.0 $USE_HAL)
+LIBGNOMEVFS_CFLAGS="$LIBGNOMEVFS_CFLAGS $OPENSSL_CFLAGS $LIBGNUTLS_CFLAGS $HAL_CFLAGS"
 LIBGNOMEVFS_LIBS="$LIBGNOMEVFS_LIBS $OPENSSL_LIBS $LIBGNUTLS_LIBS"
 AC_SUBST(LIBGNOMEVFS_CFLAGS)
 AC_SUBST(LIBGNOMEVFS_LIBS)
Index: libgnomevfs/Makefile.am
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/Makefile.am,v
retrieving revision 1.122
diff -u -p -r1.122 Makefile.am
--- libgnomevfs/Makefile.am	1 Mar 2004 09:43:30 -0000	1.122
+++ libgnomevfs/Makefile.am	7 Jun 2004 16:22:08 -0000
@@ -137,6 +137,7 @@ noinst_HEADERS =				\
 	gnome-vfs-daemon-method.h		\
 	gnome-vfs-filesystem-type.h		\
 	gnome-vfs-handle-private.h		\
+	gnome-vfs-hal-mounts.h			\
 	gnome-vfs-i18n.h			\
 	gnome-vfs-iso9660.h			\
 	gnome-vfs-job-queue.h			\
@@ -238,6 +239,7 @@ libgnomevfs_2_la_SOURCES =			\
 	gnome-vfs-filesystem-type.c		\
 	gnome-vfs-find-directory.c		\
 	gnome-vfs-handle.c			\
+	gnome-vfs-hal-mounts.c			\
 	gnome-vfs-i18n.c			\
 	gnome-vfs-inet-connection.c		\
 	gnome-vfs-init.c			\
Index: libgnomevfs/gnome-vfs-drive.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-drive.c,v
retrieving revision 1.4
diff -u -p -r1.4 gnome-vfs-drive.c
--- libgnomevfs/gnome-vfs-drive.c	26 Nov 2003 12:18:38 -0000	1.4
+++ libgnomevfs/gnome-vfs-drive.c	7 Jun 2004 16:22:08 -0000
@@ -171,6 +171,9 @@ gnome_vfs_drive_finalize (GObject *objec
 	g_free (priv->activation_uri);
 	g_free (priv->display_name);
 	g_free (priv->icon);
+#ifdef USE_HAL
+	g_free (priv->hal_udi);
+#endif
 	g_free (priv);
 	drive->priv = NULL;
 	
Index: libgnomevfs/gnome-vfs-volume-monitor-daemon.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-volume-monitor-daemon.c,v
retrieving revision 1.7
diff -u -p -r1.7 gnome-vfs-volume-monitor-daemon.c
--- libgnomevfs/gnome-vfs-volume-monitor-daemon.c	18 May 2004 07:58:40 -0000	1.7
+++ libgnomevfs/gnome-vfs-volume-monitor-daemon.c	7 Jun 2004 16:22:09 -0000
@@ -34,12 +34,19 @@
 #include "gnome-vfs-cdrom.h"
 #include "gnome-vfs-filesystem-type.h"
 
+#ifdef USE_HAL
+#include "gnome-vfs-hal-mounts.h"
+#endif /* USE_HAL */
+
 static void gnome_vfs_volume_monitor_daemon_class_init (GnomeVFSVolumeMonitorDaemonClass *klass);
 static void gnome_vfs_volume_monitor_daemon_init       (GnomeVFSVolumeMonitorDaemon      *volume_monitor_daemon);
 static void gnome_vfs_volume_monitor_daemon_finalize   (GObject                          *object);
 
+#ifndef USE_HAL
 static void update_fstab_drives (GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon);
 static void update_mtab_volumes (GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon);
+#endif /* !USE_HAL */
+
 static void update_connected_servers (GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon);
 
 typedef struct {
@@ -106,6 +113,7 @@ gnome_vfs_volume_monitor_daemon_class_in
 	o_class->finalize = gnome_vfs_volume_monitor_daemon_finalize;
 }
 
+#ifndef USE_HAL
 static void
 fstab_changed (gpointer data)
 {
@@ -123,6 +131,7 @@ mtab_changed (gpointer data)
 	volume_monitor = data;
 	update_mtab_volumes (volume_monitor);
 }
+#endif  /* !USE_HAL */
 
 static void
 connected_servers_changed (GConfClient* client,
@@ -140,10 +149,14 @@ connected_servers_changed (GConfClient* 
 static void
 gnome_vfs_volume_monitor_daemon_init (GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon)
 {
+#ifdef USE_HAL
+	_gnome_vfs_monitor_hal_mounts_init (volume_monitor_daemon);
+#else
 	_gnome_vfs_monitor_unix_mounts (fstab_changed,
 					volume_monitor_daemon,
 					mtab_changed,
 					volume_monitor_daemon);
+#endif /* USE_HAL */
 
 	volume_monitor_daemon->gconf_client = gconf_client_get_default ();
 	gconf_client_add_dir (volume_monitor_daemon->gconf_client,
@@ -160,16 +173,24 @@ gnome_vfs_volume_monitor_daemon_init (Gn
 					 NULL);
 								       
 	
+#ifdef USE_HAL
+	_gnome_vfs_monitor_hal_get_volume_list (volume_monitor_daemon);
+#else
 	update_fstab_drives (volume_monitor_daemon);
 	update_mtab_volumes (volume_monitor_daemon);
+#endif /* USE_HAL */
 	update_connected_servers (volume_monitor_daemon);
 }
 
 void
 gnome_vfs_volume_monitor_daemon_force_probe (GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon)
 {
+#ifdef USE_HAL
+	_gnome_vfs_monitor_hal_get_volume_list (volume_monitor_daemon);
+#else
 	update_fstab_drives (volume_monitor_daemon);
 	update_mtab_volumes (volume_monitor_daemon);
+#endif /* USE_HAL */
 	update_connected_servers (volume_monitor_daemon);
 }
 
@@ -184,6 +205,9 @@ gnome_vfs_volume_monitor_daemon_finalize
 		
 	_gnome_vfs_stop_monitoring_unix_mounts ();
 
+#ifdef USE_HAL
+	_gnome_vfs_monitor_hal_mounts_shutdown (volume_monitor_daemon);
+#else
 	g_list_foreach (volume_monitor_daemon->last_mtab,
 			(GFunc)_gnome_vfs_unix_mount_free, NULL);
 	g_list_free (volume_monitor_daemon->last_mtab);
@@ -191,6 +215,7 @@ gnome_vfs_volume_monitor_daemon_finalize
 	g_list_foreach (volume_monitor_daemon->last_fstab,
 			(GFunc)_gnome_vfs_unix_mount_point_free, NULL);
 	g_list_free (volume_monitor_daemon->last_fstab);	
+#endif /* USE_HAL */
 
 	gconf_client_notify_remove (volume_monitor_daemon->gconf_client,
 				    volume_monitor_daemon->connected_id);
@@ -201,6 +226,7 @@ gnome_vfs_volume_monitor_daemon_finalize
 		(* G_OBJECT_CLASS (parent_class)->finalize) (object);
 }
 
+#ifndef USE_HAL
 static GnomeVFSDeviceType
 get_device_type_from_device_and_mount (const char *device_path, const char *mount_path)
 {
@@ -385,6 +411,8 @@ get_icon_from_type (GnomeVFSDeviceType t
 
 	return g_strdup (icon_name);
 }
+#endif /* !USE_HAL */
+
 
 static void
 diff_sorted_lists (GList *list1, GList *list2, GCompareFunc compare,
@@ -421,6 +449,7 @@ diff_sorted_lists (GList *list1, GList *
 
 /************************* fstab drives ***********************************/
 
+#ifndef USE_HAL
 static void
 fixup_mountpoint (GnomeVFSUnixMountPoint *mount)
 {
@@ -870,6 +899,8 @@ update_mtab_volumes (GnomeVFSVolumeMonit
 
 	
 }
+
+#endif /* !USE_HAL */
 
 /************************* connected server ***********************************/
 
Index: libgnomevfs/gnome-vfs-volume-monitor-daemon.h
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-volume-monitor-daemon.h,v
retrieving revision 1.4
diff -u -p -r1.4 gnome-vfs-volume-monitor-daemon.h
--- libgnomevfs/gnome-vfs-volume-monitor-daemon.h	27 Jan 2004 18:59:13 -0000	1.4
+++ libgnomevfs/gnome-vfs-volume-monitor-daemon.h	7 Jun 2004 16:22:09 -0000
@@ -29,6 +29,10 @@
 #include <gconf/gconf-client.h>
 #include "gnome-vfs-volume-monitor.h"
 
+#ifdef USE_HAL
+#include <hal/libhal.h>
+#endif /* USE_HAL */
+
 G_BEGIN_DECLS
 
 #define GNOME_VFS_TYPE_VOLUME_MONITOR_DAEMON        (gnome_vfs_volume_monitor_daemon_get_type ())
@@ -43,8 +47,12 @@ typedef struct _GnomeVFSVolumeMonitorDae
 struct _GnomeVFSVolumeMonitorDaemon {
 	GnomeVFSVolumeMonitor parent;
 
+#ifdef USE_HAL
+	LibHalContext *hal_ctx;
+#else
 	GList *last_fstab;
 	GList *last_mtab;
+#endif /* USE_HAL */
 	GList *last_connected_servers;
 	
 	GConfClient *gconf_client;
Index: libgnomevfs/gnome-vfs-volume-monitor-private.h
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-volume-monitor-private.h,v
retrieving revision 1.4
diff -u -p -r1.4 gnome-vfs-volume-monitor-private.h
--- libgnomevfs/gnome-vfs-volume-monitor-private.h	22 Jan 2004 15:35:01 -0000	1.4
+++ libgnomevfs/gnome-vfs-volume-monitor-private.h	7 Jun 2004 16:22:09 -0000
@@ -62,6 +62,10 @@ struct _GnomeVFSVolumePrivate {
 
 	/* Only for connected servers */
 	char *gconf_id;
+
+#ifdef USE_HAL
+	char *hal_udi;
+#endif /* USE_HAL */
 };
 
 
@@ -79,6 +83,10 @@ struct _GnomeVFSDrivePrivate {
 	
 	gboolean is_user_visible;
 	gboolean is_connected;
+
+#ifdef USE_HAL
+	char *hal_udi;
+#endif /* USE_HAL */
 };
 
 void _gnome_vfs_volume_set_drive                (GnomeVFSVolume        *volume,
@@ -123,6 +131,14 @@ GnomeVFSDrive * _gnome_vfs_volume_monito
 									      const char            *activation_uri);
 GnomeVFSVolume *_gnome_vfs_volume_monitor_find_connected_server_by_gconf_id  (GnomeVFSVolumeMonitor *volume_monitor,
 									      const char            *id);
+
+#ifdef USE_HAL
+GnomeVFSVolume *_gnome_vfs_volume_monitor_find_volume_by_hal_udi (GnomeVFSVolumeMonitor *volume_monitor,
+								  const char *hal_udi);
+GnomeVFSDrive *_gnome_vfs_volume_monitor_find_drive_by_hal_udi (GnomeVFSVolumeMonitor *volume_monitor,
+								const char           *hal_udi);
+
+#endif /* USE_HAL */
 
 
 char *_gnome_vfs_volume_monitor_uniquify_volume_name (GnomeVFSVolumeMonitor *volume_monitor,
Index: libgnomevfs/gnome-vfs-volume-monitor.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-volume-monitor.c,v
retrieving revision 1.3
diff -u -p -r1.3 gnome-vfs-volume-monitor.c
--- libgnomevfs/gnome-vfs-volume-monitor.c	26 Nov 2003 12:18:38 -0000	1.3
+++ libgnomevfs/gnome-vfs-volume-monitor.c	7 Jun 2004 16:22:10 -0000
@@ -253,6 +253,56 @@ _gnome_vfs_volume_monitor_shutdown (void
 }
 
 
+
+#ifdef USE_HAL
+GnomeVFSVolume *
+_gnome_vfs_volume_monitor_find_volume_by_hal_udi (GnomeVFSVolumeMonitor *volume_monitor,
+						  const char *hal_udi)
+{
+	GList *l;
+	GnomeVFSVolume *vol, *ret;
+
+	/* Doesn't need locks, only called internally on main thread and doesn't write */
+	
+	ret = NULL;
+	for (l = volume_monitor->priv->mtab_volumes; l != NULL; l = l->next) {
+		vol = l->data;
+		if (vol->priv != NULL && vol->priv->hal_udi != NULL && 
+		    vol->priv->activation_uri != NULL && /* Hmm */
+		    strcmp (vol->priv->hal_udi, hal_udi) == 0) {
+			ret = vol;
+			break;
+		}
+	}
+	
+	return ret;
+}
+
+GnomeVFSDrive *
+_gnome_vfs_volume_monitor_find_drive_by_hal_udi (GnomeVFSVolumeMonitor *volume_monitor,
+						 const char           *hal_udi)
+{
+	GList *l;
+	GnomeVFSDrive *drive, *ret;
+
+	/* Doesn't need locks, only called internally on main thread and doesn't write */
+	
+	ret = NULL;
+	for (l = volume_monitor->priv->fstab_drives; l != NULL; l = l->next) {
+		drive = l->data;
+		if (drive->priv != NULL && drive->priv->hal_udi != NULL &&
+		    drive->priv->activation_uri != NULL && /* Hmm */
+		    strcmp (drive->priv->hal_udi, hal_udi) == 0) {
+			ret = drive;
+			break;
+		}
+	}
+
+	return ret;
+}
+#endif /* USE_HAL */
+
+
 GnomeVFSVolume *
 _gnome_vfs_volume_monitor_find_mtab_volume_by_activation_uri (GnomeVFSVolumeMonitor *volume_monitor,
 							      const char *activation_uri)
Index: libgnomevfs/gnome-vfs-volume.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-volume.c,v
retrieving revision 1.4
diff -u -p -r1.4 gnome-vfs-volume.c
--- libgnomevfs/gnome-vfs-volume.c	26 Nov 2003 12:18:38 -0000	1.4
+++ libgnomevfs/gnome-vfs-volume.c	7 Jun 2004 16:22:10 -0000
@@ -136,6 +136,9 @@ gnome_vfs_volume_finalize (GObject *obje
 	g_free (priv->display_name);
 	g_free (priv->icon);
 	g_free (priv->gconf_id);
+#ifdef USE_HAL
+	g_free (priv->hal_udi);
+#endif
 	g_free (priv);
 	volume->priv = NULL;
 	
--- /dev/null	2004-06-07 17:03:02.000000000 +0200
+++ libgnomevfs/gnome-vfs-hal-mounts.c	2004-06-07 18:14:30.000000000 +0200
@@ -0,0 +1,1174 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gnome-vfs-hal-mounts.c - read and monitor volumes using freedesktop HAL
+
+   Copyright (C) 2004 David Zeuthen
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: David Zeuthen <david fubar dk>
+*/
+
+#ifdef USE_HAL
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fstab.h>
+#include <sys/sysmacros.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <libgnomevfs/gnome-vfs-i18n.h>
+
+#include "gnome-vfs-hal-mounts.h"
+#include "gnome-vfs-volume-monitor-daemon.h"
+#include "gnome-vfs-volume-monitor-private.h"
+
+/** Use HAL to retrieve information about drives and volumes.
+ *
+ *  TODO, in no particular order
+ *
+ *  - Fixup rest of gnome-vfs such that '/' is allowed in the name of
+ *    drives and volumes
+ *
+ *  - More fancy icons for media; e.g. Compact Flash, Smart Media, Memory
+ *    Stick, SD/MMC, optical media (CD-ROM, CD-R, CD-RW, DVDROM, DVD-R,
+ *    DVD+R, DVD+RW, DVD-RW, DVD-RAM), gnome-dev-removable and 
+ *    gnome-dev-harddisk icons with USB, IDE, SCSI, Firewire logos on;
+ *    perhaps through emblems in Nautilus?
+ *
+ *  - Find a way to expose the HAL UDI of a drive and a volume such that
+ *    e.g. Nautilus can extract more properties on the device, e.g. eject
+ *    on blank media doesn't work very well. Also nice to put a music
+ *    player emblem on a volume icon if the removable storage is from a
+ *    portable music player (e.g. capabilities merged from .fdi files
+ *    for e.g. an iPod).
+ *
+ *  - Bug XYZ
+ *
+ *  - Lots of other stuff :-)
+ *
+ */
+
+
+/** If this is defined then only mounted volumes are shown which gives
+ *  a Mac OS X like experience. Otherwise unmounted volumes are shown
+ *  as a drive icon. Obviously, this requires an automounter like
+ *  gnome-volume-manager.
+ */
+/*#define HAL_ONLY_SHOW_MOUNTED_VOLUMES*/
+
+
+typedef struct {
+	char *udi;
+
+	int device_major;
+	int device_minor;
+	char *device_file;
+
+	char *bus;                /* ide, scsi, usb, firewire, ... */
+	char *vendor;             /* may be NULL, is never "" */
+	char *model;              /* may be NULL, is never "" */
+	gboolean is_hotpluggable;
+	gboolean is_removable;
+	gboolean no_partitions;
+	char *type;               /* disk, cdrom, compact_flash, memory_stick
+				   * smart_media, sd_mmc, ... */
+} GnomeVFSHalDrive;
+
+typedef struct {
+	char *udi;
+
+	int device_major;
+	int device_minor;
+	char *device_file;
+	char *volume_label; /* may be NULL, is never "" */
+	gboolean is_mounted;
+	char *mount_point;  /* NULL iff !is_mounted */
+	char *fstype;       /* NULL iff !is_mounted or unknown */
+
+	gboolean is_disc;
+	char *disc_type;    /* NULL iff !is_disc */
+	gboolean disc_has_audio;
+	gboolean disc_has_data;
+	gboolean disc_is_appendable;
+	gboolean disc_is_blank;
+	gboolean disc_is_rewritable;
+} GnomeVFSHalVolume;
+
+static void
+_hal_free_drive (GnomeVFSHalDrive *drive)
+{
+	if (drive == NULL )
+		return;
+
+	free (drive->udi);
+	hal_free_string (drive->device_file);
+	hal_free_string (drive->bus);
+	hal_free_string (drive->vendor);
+	hal_free_string (drive->model);
+	hal_free_string (drive->type);
+}
+
+
+static void
+_hal_free_vol (GnomeVFSHalVolume *vol)
+{
+	if (vol == NULL )
+		return;
+
+	free (vol->udi);
+	hal_free_string (vol->device_file);
+	hal_free_string (vol->volume_label);
+	hal_free_string (vol->fstype);
+	hal_free_string (vol->mount_point);
+	hal_free_string (vol->disc_type);
+}
+
+
+/** Given a UDI for a HAL device of capability 'storage', this
+ *  function retrieves all the relevant properties into a convenient
+ *  structure.  Returns NULL if UDI is invalid or device is not of
+ *  capability 'storage'.
+ *
+ *  Free with _hal_free_drive().
+ */
+static GnomeVFSHalDrive *
+_hal_get_drive (const char *udi, LibHalContext *hal_ctx)
+{
+	GnomeVFSHalDrive *drive;
+
+	drive = g_new0 (GnomeVFSHalDrive, 1);
+	if (drive == NULL)
+		goto error;
+
+	drive->udi = strdup (udi);
+	if (drive->udi == NULL)
+		goto error;
+
+	drive->device_file = hal_device_get_property_string (
+		hal_ctx, udi, "block.device");
+	if (drive->device_file == NULL)
+		goto error;
+
+	drive->bus = hal_device_get_property_string (
+		hal_ctx, udi, "storage.bus");
+	if (drive->bus == NULL)
+		goto error;
+
+	drive->vendor = hal_device_get_property_string (
+		hal_ctx, udi, "storage.vendor");
+	if (drive->vendor == NULL)
+		goto error;
+
+	drive->model = hal_device_get_property_string (
+		hal_ctx, udi, "storage.model");
+	if (drive->model == NULL)
+		goto error;
+
+	drive->type = hal_device_get_property_string (
+		hal_ctx, udi, "storage.drive_type");
+	if (drive->type == NULL)
+		goto error;
+	
+	drive->is_hotpluggable = hal_device_get_property_bool (
+		hal_ctx, udi, "storage.hotpluggable");
+
+	drive->is_removable = hal_device_get_property_bool (
+		hal_ctx, udi, "storage.removable");
+
+	drive->no_partitions = hal_device_get_property_bool (
+		hal_ctx, udi, "block.no_partitions");
+
+	return drive;
+error:
+	_hal_free_drive (drive);
+	return NULL;
+}
+
+/** Given a UDI for a HAL device of capability 'volume', this function
+ *  retrieves all the relevant properties into a convenient structure.
+ *  Returns NULL if UDI is invalid or device is not of capability
+ *  'volume'.
+ *
+ *  Free with _hal_free_vol().
+ */
+static GnomeVFSHalVolume *
+_hal_get_vol (const char *udi, LibHalContext *hal_ctx)
+{
+	GnomeVFSHalVolume *vol;
+
+	vol = g_new0 (GnomeVFSHalVolume, 1);
+	if (vol == NULL)
+		goto error;
+
+	/* only care about capability volume */
+	if (!hal_device_query_capability (
+		    hal_ctx,
+		    udi, "volume"))
+		goto error;
+
+	vol->udi = strdup (udi);
+	if (vol->udi == NULL)
+		goto error;
+
+	vol->device_major = hal_device_get_property_int (
+		hal_ctx, udi, "block.major");
+
+	vol->device_minor = hal_device_get_property_int (
+		hal_ctx, udi, "block.minor");
+
+	vol->device_file = hal_device_get_property_string (
+		hal_ctx,
+		udi, "block.device");
+	if (vol->device_file == NULL)
+		goto error;
+
+	if (hal_device_property_exists (
+		    hal_ctx,
+		    udi, "volume.label")) {
+		vol->volume_label = hal_device_get_property_string (
+			hal_ctx,
+			udi, "volume.label");
+		if (strlen (vol->volume_label) == 0) {
+			hal_free_string (vol->volume_label);
+			vol->volume_label = NULL;
+		}
+	}
+
+
+	vol->is_mounted = hal_device_get_property_bool (
+		hal_ctx,
+		udi, "volume.is_mounted");
+			    
+	if (vol->is_mounted) {
+		vol->mount_point = hal_device_get_property_string (
+			hal_ctx,
+			udi, "volume.mount_point");
+		if (vol->mount_point == NULL || strlen (vol->mount_point) == 0)
+			goto error;
+		
+	}
+
+	vol->fstype = hal_device_get_property_string (
+		hal_ctx,
+		udi, "volume.fstype");
+	if (vol->fstype == NULL)
+		goto error;
+	if (strlen(vol->fstype) == 0) {
+		hal_free_string (vol->fstype);
+		vol->fstype = NULL;
+	}
+
+	/* optical disc properties */
+	if (hal_device_get_property_bool (hal_ctx,
+					  udi, "volume.is_disc")) {
+		vol->is_disc = TRUE;
+
+		vol->disc_type = hal_device_get_property_string (
+			hal_ctx,
+			udi, "volume.disc.type");
+		if (vol->disc_type == NULL || strlen (vol->disc_type) == 0)
+			goto error;
+
+		vol->disc_has_audio = hal_device_get_property_bool (
+			hal_ctx,
+			udi, "volume.disc.has_audio");
+		vol->disc_has_data = hal_device_get_property_bool (
+			hal_ctx,
+			udi, "volume.disc.has_data");
+		vol->disc_is_appendable = hal_device_get_property_bool (
+			hal_ctx,
+			udi, "volume.disc.is_appendable");
+		vol->disc_is_blank = hal_device_get_property_bool (
+			hal_ctx,
+			udi, "volume.disc.is_blank");
+		vol->disc_is_rewritable = hal_device_get_property_bool (
+			hal_ctx,
+			udi, "volume.disc.is_rewritable");
+	}
+
+
+
+	return vol;
+
+error:
+	_hal_free_vol (vol);
+	return NULL;
+}
+
+/** Get the GnomeVFSHalDrive from a GnomeVFSHalVolume. Returns NULL on error.
+ *
+ *  Free with _hal_free_drive().
+ */
+static GnomeVFSHalDrive *
+_hal_get_drive_from_vol (GnomeVFSHalVolume *vol, LibHalContext *hal_ctx)
+{
+	const char *storage_udi;
+
+	storage_udi = hal_device_get_property_string (
+		hal_ctx, vol->udi, "block.storage_device");	
+	if (storage_udi == NULL)
+		goto error;
+
+	return _hal_get_drive (storage_udi, hal_ctx);
+error:
+	return NULL;
+}
+
+
+
+/***********************************************************************/
+
+/** Fixup the name given to GnomeVFS, it may not contain '/'-characters.
+ *  Substitute these with '-'.
+ */
+static void
+fixup_name (char *name)
+{
+	int i;
+
+	for (i=0; name[i]!='\0'; i++) {
+		if (name[i] == '/')
+			name[i] = '-';
+	}
+}
+
+/***********************************************************************/
+
+static char *_hal_get_vol_name (GnomeVFSHalVolume *vol, 
+				GnomeVFSHalDrive *drive, 
+				LibHalContext *hal_ctx);
+static char *_hal_get_vol_icon (GnomeVFSHalVolume *vol, 
+				GnomeVFSHalDrive *drive, 
+				LibHalContext *hal_ctx);
+static int _hal_get_vol_type (GnomeVFSHalVolume *vol, 
+			      GnomeVFSHalDrive *drive, 
+			      LibHalContext *hal_ctx);
+
+
+
+/* vol may be NULL */
+static char *
+_hal_get_drive_name (GnomeVFSHalVolume *vol, GnomeVFSHalDrive *drive, 
+		     LibHalContext *hal_ctx)
+{
+	char *name;
+
+
+#ifdef HAL_ONLY_SHOW_MOUNTED_VOLUMES
+	/* this is safe, as drives and volumes are 1:1 */
+	if (vol != NULL)
+		return _hal_get_vol_name (vol, drive, hal_ctx);
+#else
+	/* Bork, storage.removable is a bit broken on HAL (I fear only
+	 * .fdi files will fix it), so it's not sane to rely on this..
+	 * Which is bad, because without computer:/// looks ugly, e.g.
+	 * "<drive_name> : <volume_name>" even for storage that is
+	 * not removable. Bork.
+	 */
+
+        /*
+	if (vol != NULL && !drive->is_removable)
+		return _hal_get_vol_name (vol, drive, hal_ctx);
+	*/
+#endif
+
+	if (strcmp (drive->type, "cdrom") == 0) {
+		gboolean cdr;
+		gboolean cdrw;
+		gboolean dvd;
+		gboolean dvdplusr;
+		gboolean dvdplusrw;
+		gboolean dvdr;
+		gboolean dvdram;
+		char *first;
+		char *second;
+
+		/* use the capabilities of the cdrom device */
+
+		cdr = hal_device_get_property_bool (
+			hal_ctx, drive->udi, "storage.cdrom.cdr");
+		cdrw = hal_device_get_property_bool (
+			hal_ctx, drive->udi, "storage.cdrom.cdrw");
+		dvd = hal_device_get_property_bool (
+			hal_ctx, drive->udi, "storage.cdrom.dvd");
+		dvdplusr = hal_device_get_property_bool (
+			hal_ctx, drive->udi, "storage.cdrom.dvdplusr");
+		dvdplusrw = hal_device_get_property_bool (
+			hal_ctx, drive->udi, "storage.cdrom.dvdplusrw");
+		dvdr = hal_device_get_property_bool (
+			hal_ctx, drive->udi, "storage.cdrom.dvdr");
+		dvdram = hal_device_get_property_bool (
+			hal_ctx, drive->udi, "storage.cdrom.dvdram");
+
+		first = "CD-ROM";
+		if( cdr )
+			first = "CD-R";
+		if( cdrw )
+			first = "CD-RW";
+
+		/* Hmm, '/' is not an allowed character, so use '\' instead */
+		second = "";
+		if( dvd )
+			second = "\\DVD-ROM";
+		if( dvdplusr )
+			second = "\\DVD+R";
+		if( dvdplusrw )
+			second = "\\DVD+RW";
+		if( dvdr )
+			second = "\\DVD-R";
+		if( dvdram )
+			second = "\\DVD-RAM";
+		if( dvdplusr && dvdr )
+			second = "\\DVD�R";
+		if( dvdplusr && dvdplusrw && dvdr )
+			second = "\\DVD�RW";
+
+		name = g_strdup_printf ("%s%s", first, second);
+	} else {
+		name = g_strdup (drive->model);
+	}
+
+	fixup_name (name);
+
+	return name;
+}
+
+/* vol may be NULL */
+static char *
+_hal_get_drive_icon (GnomeVFSHalVolume *vol, GnomeVFSHalDrive *drive, 
+		     LibHalContext *hal_ctx)
+{
+	return g_strdup ("gnome-dev-removable");
+}
+
+/* vol may be NULL */
+static int
+_hal_get_drive_type (GnomeVFSHalVolume *vol, GnomeVFSHalDrive *drive, 
+		     LibHalContext *hal_ctx)
+{
+	int type = GNOME_VFS_DEVICE_TYPE_HARDDRIVE;
+
+	if (strcmp (drive->type, "cdrom") == 0)
+		type = GNOME_VFS_DEVICE_TYPE_CDROM;
+	else if (strcmp (drive->type, "compact_flash") == 0 ||
+		 strcmp (drive->type, "memory_stick") == 0 ||
+		 strcmp (drive->type, "smart_media") == 0 ||
+		 strcmp (drive->type, "sd_mmc") == 0)
+		type = GNOME_VFS_DEVICE_TYPE_MEMORY_STICK;
+
+	return type;
+}
+
+
+
+/***********************************************************************/
+
+static char *
+_hal_get_vol_name (GnomeVFSHalVolume *vol, GnomeVFSHalDrive *drive, 
+		   LibHalContext *hal_ctx)
+{
+	char *name = NULL;
+
+	if (vol->volume_label != NULL ) {
+
+		/* Using the label is the best thing */
+		name = g_strdup (vol->volume_label);
+
+	} else if (strcmp (drive->type, "cdrom") == 0) {
+
+		/* If it's a optical disc, use the disc type */
+		if (strcmp (vol->disc_type, "cd_rom") == 0) {
+			name = _("CD Disc");
+		} else if (strcmp (vol->disc_type, "cd_r") == 0) {
+			if (vol->disc_is_blank)
+				name = g_strdup (_("Blank CD-R Disc"));
+			else
+				name = _("CD-R Disc");
+		} else if (strcmp (vol->disc_type, "cd_rw") == 0) {
+			if (vol->disc_is_blank)
+				name = g_strdup (_("Blank CD-RW Disc"));
+			else
+				name = g_strdup (_("CD-RW Disc"));
+		} else if (strcmp (vol->disc_type, "dvd_rom") == 0) {
+					name = g_strdup (_("DVD-ROM Disc"));
+		} else if (strcmp (vol->disc_type, "dvd_r") == 0) {
+			if (vol->disc_is_blank)
+				name = g_strdup (_("Blank DVD-R Disc"));
+			else
+				name = g_strdup (_("DVD-R Disc"));
+		} else if (strcmp (vol->disc_type, "dvd_ram") == 0) {
+			if (vol->disc_is_blank)
+				name = g_strdup (_("Blank DVD-RAM Disc"));
+			else
+				name = g_strdup (_("DVD-RAM Disc"));
+		} else if ((strcmp (vol->disc_type, "dvd_rw_restricted_overwrite") == 0) || (strcmp (vol->disc_type, "dvd_rw") == 0)) {
+			if (vol->disc_is_blank)
+				name = g_strdup (_("Blank DVD-RW Disc"));
+			else
+				name = g_strdup (_("DVD-RW Disc"));
+		} else if (strcmp (vol->disc_type, "dvd_plus_rw") == 0) {
+			if (vol->disc_is_blank)
+				name = g_strdup (_("Blank DVD+RW Disc"));
+			else
+				name = g_strdup (_("DVD+RW Disc"));
+		} else if (strcmp (vol->disc_type, "dvdplusr") == 0) {
+			if (vol->disc_is_blank)
+				name = g_strdup (_("Blank DVD+R Disc"));
+			else
+				name = g_strdup (_("DVD+R Disc"));
+		} else {
+			name = g_strdup (_("Optical Disc"));
+		}
+
+	} else if (strcmp (drive->type, "compact_flash") == 0) {
+		name = g_strdup (_("Compact Flash Media"));
+	} else if (strcmp (drive->type, "memory_stick") == 0) {
+		name = g_strdup (_("Memory Stick Media"));
+	} else if (strcmp (drive->type, "smart_media") == 0) {
+		name = g_strdup (_("Smart Media Media"));
+	} else if (strcmp (drive->type, "sd_mmc") == 0) {
+		name = g_strdup (_("SD/MMC Media"));
+	} else if (strcmp (drive->type, "disk") == 0) {
+
+		/* Look at the filesystem type, if applicable */
+		if (vol->fstype != NULL) {
+
+			    if (strcmp (vol->fstype, "hfs") == 0) {
+				    name = g_strdup (_("Mac OS disk"));
+			    } else if (strcmp (vol->fstype, "hfsplus") == 0) {
+				    name = g_strdup (_("Mac OS X disk"));
+			    } /*else if (strcmp (vol->fstype, "vfat") == 0 ||
+				strcmp (vol->fstype, "fat") == 0 ||
+				strcmp (vol->fstype, "msdos") == 0 ||
+				strcmp (vol->fstype, "msdosfs") == 0 ) {
+				name = g_strdup (_("PC Interchange Disk"));
+				}*/ 
+			    else if (strcmp (vol->fstype, "ntfs") == 0) {
+				    name = g_strdup (_("Windows Disk"));
+			    } else if (strcmp (vol->fstype, "ext2") == 0 ||
+				       strcmp (vol->fstype, "ext3") == 0 ||
+				       strcmp (vol->fstype, "jfs") == 0 ||
+				       strcmp (vol->fstype, "xfs") == 0 ||
+				       strcmp (vol->fstype, "reiser") == 0) {
+				    name = g_strdup (_("Linux Disk"));
+			    }
+		}
+	}
+
+	/* fallback; use the same name as the drive */
+	if (name == NULL)
+		name = _hal_get_drive_name (NULL, drive, hal_ctx);
+
+	fixup_name (name);
+
+	return name;
+}
+
+static char *
+_hal_get_vol_icon (GnomeVFSHalVolume *vol, GnomeVFSHalDrive *drive, 
+		   LibHalContext *hal_ctx)
+{
+	char *icon;
+
+	if (strcmp (drive->type, "cdrom") == 0) {
+		icon = g_strdup ("gnome-dev-cdrom");
+	} else if (strcmp (drive->type, "compact_flash") == 0 ||
+		   strcmp (drive->type, "memory_stick") == 0 ||
+		   strcmp (drive->type, "smart_media") == 0 ||
+		   strcmp (drive->type, "sd_mmc") == 0) {
+		icon = g_strdup ("gnome-dev-jazdisk");
+	} else {
+		icon = g_strdup ("gnome-dev-harddisk");
+	}
+	
+	return icon;
+}
+
+static int
+_hal_get_vol_type (GnomeVFSHalVolume *vol, GnomeVFSHalDrive *drive, 
+		   LibHalContext *hal_ctx)
+{
+	return _hal_get_drive_type (NULL, drive, hal_ctx);
+}
+
+/***********************************************************************/
+
+/** This function is used to skip certain volumes/drives we don't
+ *  want to expose in GnomeVFS.
+ *
+ */
+static gboolean
+_hal_check_for_skip (GnomeVFSHalDrive *hal_drive, 
+		     GnomeVFSHalVolume *hal_vol,  /* may be NULL */
+		     char *mount_point)
+{
+	/* Skip standard UNIX-like mount points */
+	if (strcmp (mount_point, "/var") == 0 ||
+	    strcmp (mount_point, "/usr") == 0 ||
+	    strcmp (mount_point, "/bin") == 0 ||
+	    strcmp (mount_point, "/sbin") == 0 ||
+	    strcmp (mount_point, "/boot") == 0 ||
+	    strcmp (mount_point, "/tmp") == 0 ||
+	    strcmp (mount_point, "/opt") == 0 ||
+	    strcmp (mount_point, "/home") == 0 ||
+	    strcmp (mount_point, "/") == 0)
+		return TRUE;
+
+	/* Skip volumes where HAL couldn't figure out the filesystem type */
+	if (hal_vol != NULL) {
+		/* but allow blank discs */
+		if (!(hal_vol->is_disc && hal_vol->disc_is_blank)) {
+			if (hal_vol->fstype == NULL)
+				return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+/***********************************************************************/
+
+
+/** Add a drive where the media is not partition based.
+ *
+ *  It's safe to call this function multiple times for the same HAL 
+ *  UDI (Unique Device Identifier).
+ */
+static void 
+_hal_add_drive_no_partitions (
+	GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon,
+	const char *udi)
+{
+	GnomeVFSHalDrive *hal_drive = NULL;
+	LibHalContext *hal_ctx = volume_monitor_daemon->hal_ctx;
+	GnomeVFSDrive *drive;
+	GnomeVFSVolumeMonitor *volume_monitor = 
+		GNOME_VFS_VOLUME_MONITOR (volume_monitor_daemon);
+	char *name = NULL;
+	char *icon = NULL;
+	GnomeVFSDeviceType device_type = GNOME_VFS_DEVICE_TYPE_HARDDRIVE;
+	gboolean computer_visible = TRUE;
+	struct fstab *fst;
+	char *mount_point = NULL;
+
+#ifdef HAL_ONLY_SHOW_MOUNTED_VOLUMES
+	return;
+#endif
+
+	/*
+	 * We create the GnomeVFSDrive for such beasts since we can
+	 * actually do it in advance due to the fact that we already
+	 * know the device file and the mount point.
+	 */
+	
+	hal_drive = _hal_get_drive (udi, hal_ctx);
+	if (hal_drive == NULL)
+		goto out;
+
+	/* get mount point from /etc/fstab */
+	if (setfsent () == 1) {
+		fst = getfsspec (hal_drive->device_file);
+		if (fst != NULL )
+			mount_point = strdup (fst->fs_file);
+		endfsent ();
+	}
+	if (mount_point == NULL || mount_point[0] != '/')
+		goto out;
+
+	/* See if we should skip this */
+	if (_hal_check_for_skip (hal_drive, NULL, mount_point))
+		goto out;
+	
+	/* see if drive was already added */
+	drive = _gnome_vfs_volume_monitor_find_drive_by_hal_udi (
+		volume_monitor, udi);
+	if (drive == NULL ) {
+
+		/* nope, make one */
+		
+		name = _hal_get_drive_name (NULL, hal_drive, hal_ctx);
+		icon = _hal_get_drive_icon (NULL, hal_drive, hal_ctx);
+		device_type = _hal_get_drive_type (NULL, hal_drive, hal_ctx);
+		
+		drive = g_object_new (GNOME_VFS_TYPE_DRIVE, NULL);
+		drive->priv->device_path = g_strdup (hal_drive->device_file);
+		
+		drive->priv->activation_uri = gnome_vfs_get_uri_from_local_path (mount_point);
+		drive->priv->is_connected = TRUE;
+		drive->priv->device_type = device_type;
+		drive->priv->icon = g_strdup (icon);
+		drive->priv->display_name = _gnome_vfs_volume_monitor_uniquify_drive_name (volume_monitor, name);
+		drive->priv->is_user_visible = computer_visible;
+		drive->priv->volume = NULL;
+		drive->priv->hal_udi = g_strdup (udi);
+		
+		_gnome_vfs_volume_monitor_connected (volume_monitor, drive);
+		gnome_vfs_drive_unref (drive);
+	}
+	
+out:
+	_hal_free_drive (hal_drive);
+	g_free (name);
+	g_free (icon);
+	free (mount_point);
+}
+
+
+/** Add a hal-volume, that is, a HalDevice of capability 'volume'. 
+ *
+ *  It's safe to call this function multiple times for the same HAL 
+ *  UDI (Unique Device Identifier).
+ */
+static void 
+_hal_add_volume (GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon,
+		 const char *udi)
+{
+	GnomeVFSHalVolume *hal_vol = NULL;
+	GnomeVFSHalDrive *hal_drive = NULL;
+	LibHalContext *hal_ctx = volume_monitor_daemon->hal_ctx;
+
+	GnomeVFSDrive *drive;
+	GnomeVFSVolume *vol;
+	GnomeVFSVolumeMonitor *volume_monitor = 
+		GNOME_VFS_VOLUME_MONITOR (volume_monitor_daemon);
+	char *name = NULL;
+	char *icon = NULL;
+	GnomeVFSDeviceType device_type = GNOME_VFS_DEVICE_TYPE_HARDDRIVE;
+	gboolean computer_visible = TRUE;
+	gboolean desktop_visible = FALSE;
+	struct fstab *fst;
+	char *mount_point = NULL;
+	gboolean is_blank_disc = FALSE;
+
+	/* Only care about capability volume */
+	if (!hal_device_query_capability (
+		    volume_monitor_daemon->hal_ctx,
+		    udi, "volume"))
+	{
+
+		/* And capability block where block.no_partition==TRUE and
+		 * block.is_volume==FALSE
+		 */
+		if (hal_device_query_capability (
+			    hal_ctx, udi, "block") &&
+		    (hal_device_get_property_bool (
+			    hal_ctx, udi, "block.no_partitions")==TRUE) &&
+		    (hal_device_get_property_bool (
+			    hal_ctx, udi, "block.is_volume")==FALSE)) {
+			/* This represent top-level block devices with
+			 * media not using partitions.. Such as floppy
+			 * drives or optical drives..
+			 */
+
+			_hal_add_drive_no_partitions (
+				volume_monitor_daemon, udi);
+			goto out;
+
+		} else {
+			/* Nothing we can use... */
+			goto out;
+		}
+	}
+
+
+	/* get HAL drive and volume objects */
+	hal_vol = _hal_get_vol (udi, hal_ctx);
+	if (hal_vol == NULL)
+		goto out;
+	hal_drive = _hal_get_drive_from_vol (hal_vol, hal_ctx);
+	if (hal_drive == NULL)
+		goto out;
+
+	/* See if we should have an icon on the desktop */
+	if (hal_drive->is_hotpluggable || hal_vol->is_disc)
+		desktop_visible = TRUE;
+
+	/* If we are mounted, use the mount point that HAL knows */
+	if (hal_vol->is_mounted) {
+		mount_point = strdup (hal_vol->mount_point);
+	} else {
+		/* Otherwise... Yuck.. 
+		 *
+		 * gnome-vfs expects a mount point for a not yet
+		 * mounted volume which is kind of gross as it may be
+		 * mounted anywhere by e.g. root in the
+		 * future. Surely, this is not needed at all,
+		 * gnome-vfs should just be able to do a 'mount
+		 * /dev/sda1' or something.
+		 *
+		 * Now, HAL *could* monitor the /etc/fstab file and
+		 * maintain volume.mount_point property while
+		 * volume.is_mounted is FALSE, but this is unclean and
+		 * we really want the volume.mount_point to be empty
+		 * if, and only if, volume.is_mounted is FALSE.
+		 *
+		 * So, we just need to read the /etc/fstab here to
+		 * find the mount point (which is probably created by
+		 * a callout anyway). Oh well, piece of cake anyway..
+		 */
+		if (setfsent () == 1) {
+			fst = getfsspec (hal_vol->device_file);
+			if (fst != NULL )
+				mount_point = strdup (fst->fs_file);
+			endfsent ();
+		}
+	}
+
+	/* And we do need a mount point, and now we tried so hard to find
+	 * one.. bail out if we haven't got any.. 
+	 *
+	 * Further, getfspec above may return 'swap', so only accept a mount
+	 * point that starts with /. Hmmm..
+	 */
+	if (mount_point == NULL || mount_point[0]!='/')
+		goto out;
+
+	/* see if we're a blank disc instead of being mounted */
+	is_blank_disc = hal_vol->is_disc && hal_vol->disc_is_blank;
+
+	/* See if we should skip this */
+	if (_hal_check_for_skip (hal_drive, hal_vol, mount_point))
+		goto out;
+
+#ifdef HAL_ONLY_SHOW_MOUNTED_VOLUMES
+	/* we should also show blank discs */
+	if (!hal_vol->is_mounted && !is_blank_disc)
+		goto out;
+#endif
+
+	/* see if it was already added */
+	drive = _gnome_vfs_volume_monitor_find_drive_by_hal_udi (
+		volume_monitor, 
+#ifdef HAL_ONLY_SHOW_MOUNTED_VOLUMES
+			udi);
+#else
+			hal_drive->no_partitions ? hal_drive->udi : udi);
+#endif
+	if (drive == NULL ) {
+
+		/* nope, make one */
+
+		name = _hal_get_drive_name (hal_vol, hal_drive, hal_ctx);
+		icon = _hal_get_drive_icon (hal_vol, hal_drive, hal_ctx);
+		device_type = _hal_get_drive_type (hal_vol, hal_drive, hal_ctx);
+
+		drive = g_object_new (GNOME_VFS_TYPE_DRIVE, NULL);
+		drive->priv->device_path = g_strdup (hal_vol->device_file);
+
+		drive->priv->activation_uri = gnome_vfs_get_uri_from_local_path (mount_point);
+		drive->priv->is_connected = TRUE;
+		drive->priv->device_type = device_type;
+		drive->priv->icon = g_strdup (icon);
+		drive->priv->display_name = _gnome_vfs_volume_monitor_uniquify_drive_name (volume_monitor, name);
+		drive->priv->is_user_visible = computer_visible;
+		drive->priv->volume = NULL;
+
+		drive->priv->hal_udi = g_strdup (
+#ifdef HAL_ONLY_SHOW_MOUNTED_VOLUMES
+			udi);
+#else
+			hal_drive->no_partitions ? hal_drive->udi : udi);
+#endif
+		
+		_gnome_vfs_volume_monitor_connected (volume_monitor, drive);
+		gnome_vfs_drive_unref (drive);
+	} 
+
+	g_free (name); name = NULL;
+	g_free (icon); icon = NULL;
+
+	/* drive is now a reference to GnomeVFSDrive */
+
+	/* Only create a GnomeVFSVolume object if the volume is mounted 
+	 * or a blank disc */
+	if (hal_vol->is_mounted || is_blank_disc) {
+		/* see if hal_vol was already added */
+		vol = _gnome_vfs_volume_monitor_find_volume_by_hal_udi (
+			volume_monitor, udi);
+		if (vol == NULL ) {
+
+			name = _hal_get_vol_name (hal_vol, hal_drive, hal_ctx);
+			icon = _hal_get_vol_icon (hal_vol, hal_drive, hal_ctx);
+			device_type = _hal_get_vol_type (hal_vol, hal_drive, hal_ctx);
+
+			vol = g_object_new (GNOME_VFS_TYPE_VOLUME, NULL);
+			vol->priv->volume_type = GNOME_VFS_VOLUME_TYPE_MOUNTPOINT;
+			
+			if (is_blank_disc) {
+				vol->priv->device_path = g_strdup (hal_vol->device_file);
+				vol->priv->activation_uri = g_strdup ("burn:///");
+				vol->priv->unix_device = makedev (hal_vol->device_major, 
+								  hal_vol->device_minor);
+				vol->priv->filesystem_type = g_strdup (hal_vol->fstype);
+
+			} else {
+				vol->priv->device_path = g_strdup (hal_vol->device_file);
+				vol->priv->activation_uri = gnome_vfs_get_uri_from_local_path (mount_point);
+				vol->priv->unix_device = makedev (hal_vol->device_major, 
+								  hal_vol->device_minor);
+				vol->priv->filesystem_type = g_strdup (hal_vol->fstype);
+			}
+
+			vol->priv->is_read_only = FALSE;
+			vol->priv->is_mounted = TRUE;
+			
+			vol->priv->device_type = device_type;
+			
+			vol->priv->display_name = _gnome_vfs_volume_monitor_uniquify_volume_name (volume_monitor, name);
+			vol->priv->icon = g_strdup(icon);
+			vol->priv->is_user_visible = desktop_visible;
+			vol->priv->hal_udi = g_strdup (udi);
+			
+			vol->priv->drive = drive;
+			_gnome_vfs_drive_set_mounted_volume (drive, vol);
+			
+			_gnome_vfs_volume_monitor_mounted (volume_monitor, vol);			gnome_vfs_volume_unref (vol);
+
+		}
+	}
+
+out:
+	_hal_free_vol (hal_vol);
+	_hal_free_drive (hal_drive);
+	g_free (name);
+	g_free (icon);
+	free (mount_point);
+}
+
+
+/** Remove a hal-volume, that is, a HalDevice of capability 'volume'. 
+ *
+ *  It's safe to call this function even though the hal-volume doesn't
+ *  correspond to any (GnomeVFSDrive, GnomeVFSVolume) pair.
+ */
+static void 
+_hal_remove_volume (GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon,
+		    const char *udi)
+{
+	GnomeVFSDrive *drive;
+	GnomeVFSVolume *vol;
+	GnomeVFSVolumeMonitor *volume_monitor;
+
+	volume_monitor = GNOME_VFS_VOLUME_MONITOR (volume_monitor_daemon);
+
+	drive = _gnome_vfs_volume_monitor_find_drive_by_hal_udi (
+		volume_monitor, udi);
+	if (drive != NULL ) {
+		_gnome_vfs_volume_monitor_disconnected (volume_monitor, drive);
+	}
+
+	vol = _gnome_vfs_volume_monitor_find_volume_by_hal_udi (
+		volume_monitor, udi);
+	if (vol != NULL ) {
+		_gnome_vfs_volume_monitor_unmounted (volume_monitor, vol);
+	}
+}
+
+
+/** Call when a HAL volume is unmounted.
+ *
+ *  It's safe to call this function even though the hal-volume doesn't
+ *  correspond to GnomeVFSVolume object.
+ */
+static void 
+_hal_volume_unmounted (GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon,
+		       const char *udi)
+{
+	GnomeVFSVolume *vol;
+	GnomeVFSVolumeMonitor *volume_monitor;
+
+	volume_monitor = GNOME_VFS_VOLUME_MONITOR (volume_monitor_daemon);
+
+	vol = _gnome_vfs_volume_monitor_find_volume_by_hal_udi (
+		volume_monitor, udi);
+
+	if (vol != NULL ) {
+		_gnome_vfs_volume_monitor_unmounted (volume_monitor, vol);
+	}
+
+#ifdef HAL_ONLY_SHOW_MOUNTED_VOLUMES
+	{
+		GnomeVFSDrive *drive;
+		drive = _gnome_vfs_volume_monitor_find_drive_by_hal_udi (
+			volume_monitor, udi);
+		if (drive != NULL ) {
+			_gnome_vfs_volume_monitor_disconnected (volume_monitor, drive);
+		}
+	}
+#endif
+
+}
+
+
+void 
+_gnome_vfs_monitor_hal_get_volume_list (GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon)
+{
+	int i;
+	int num_hal_volumes;
+	char **hal_volumes;
+	GnomeVFSVolumeMonitor *volume_monitor;
+
+
+	volume_monitor = GNOME_VFS_VOLUME_MONITOR (volume_monitor_daemon);
+
+	hal_volumes = hal_find_device_by_capability (
+		volume_monitor_daemon->hal_ctx,
+		"volume",
+		&num_hal_volumes);
+	for (i=0; i<num_hal_volumes; i++) {
+		char *udi;
+
+		udi = hal_volumes [i];
+
+		_hal_add_volume (volume_monitor_daemon, udi);
+	}
+	hal_free_string_array (hal_volumes);
+
+	hal_volumes = hal_find_device_by_capability (
+		volume_monitor_daemon->hal_ctx,
+		"block",
+		&num_hal_volumes);
+	for (i=0; i<num_hal_volumes; i++) {
+		char *udi;
+
+		udi = hal_volumes [i];
+
+		_hal_add_volume (volume_monitor_daemon, udi);
+	}
+	hal_free_string_array (hal_volumes);
+}
+
+static void
+_hal_mainloop_integration (LibHalContext *ctx, 
+			   DBusConnection * dbus_connection)
+{
+        dbus_connection_setup_with_g_main (dbus_connection, NULL);
+}
+
+static void 
+_hal_device_added (LibHalContext *ctx, 
+		   const char *udi)
+{
+	GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon;
+	volume_monitor_daemon = (GnomeVFSVolumeMonitorDaemon *)
+		hal_ctx_get_user_data (ctx);
+	_hal_add_volume (volume_monitor_daemon, udi);
+}
+
+static void 
+_hal_device_removed (LibHalContext *ctx, 
+		     const char *udi)
+{
+	GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon;
+	volume_monitor_daemon = (GnomeVFSVolumeMonitorDaemon *)
+		hal_ctx_get_user_data (ctx);
+	_hal_remove_volume (volume_monitor_daemon, udi);
+}
+
+static void 
+_hal_device_new_capability (LibHalContext *ctx, 
+			    const char *udi, 
+			    const char *capability)
+{
+	GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon;
+	volume_monitor_daemon = (GnomeVFSVolumeMonitorDaemon *)
+		hal_ctx_get_user_data (ctx);
+	_hal_add_volume (volume_monitor_daemon, udi);
+}
+
+static void 
+_hal_device_lost_capability (LibHalContext *ctx, 
+			     const char *udi,
+			     const char *capability)
+{
+}
+
+static void 
+_hal_device_property_modified (LibHalContext *ctx, 
+			       const char *udi,
+			       const char *key,
+			       dbus_bool_t is_removed,
+			       dbus_bool_t is_added)
+{
+	GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon;
+	volume_monitor_daemon = (GnomeVFSVolumeMonitorDaemon *)
+		hal_ctx_get_user_data (ctx);
+
+	if (!is_removed && strcmp (key, "volume.is_mounted") == 0) {
+		dbus_bool_t is_mounted;
+
+		is_mounted = hal_device_get_property_bool(
+			ctx, udi, "volume.is_mounted");
+
+		if( is_mounted )
+			_hal_add_volume (volume_monitor_daemon, udi);
+		else
+			_hal_volume_unmounted (volume_monitor_daemon, udi);
+	}
+}
+
+static void 
+_hal_device_condition (LibHalContext *ctx, 
+		       const char *udi,
+		       const char *condition_name,
+		       DBusMessage *message)
+{
+	GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon;
+	volume_monitor_daemon = (GnomeVFSVolumeMonitorDaemon *)
+		hal_ctx_get_user_data (ctx);
+
+	if (strcmp (condition_name, "BlockForcedUnmountPartition") == 0) {
+		_hal_remove_volume (volume_monitor_daemon, udi);
+	}
+}
+
+static LibHalFunctions
+hal_functions = { _hal_mainloop_integration,
+		  _hal_device_added,
+		  _hal_device_removed,
+		  _hal_device_new_capability,
+		  _hal_device_lost_capability,
+		  _hal_device_property_modified,
+		  _hal_device_condition };
+
+void
+_gnome_vfs_monitor_hal_mounts_init (GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon)
+{
+	/* initialise the connection to the hal daemon */
+	if ((volume_monitor_daemon->hal_ctx = 
+	     hal_initialize (&hal_functions, FALSE)) == NULL) {
+		g_warning ("hal_initialize failed\n");
+		/* XXX how should this be handled? */
+		exit (1);
+	}
+
+	hal_ctx_set_user_data (volume_monitor_daemon->hal_ctx,
+			       volume_monitor_daemon);
+
+	hal_device_property_watch_all (volume_monitor_daemon->hal_ctx);
+}
+
+void
+_gnome_vfs_monitor_hal_mounts_shutdown (GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon)
+{
+	if (hal_shutdown (volume_monitor_daemon->hal_ctx) != 0) {
+		g_warning ("hal_shutdown failed\n");
+	}
+}
+
+#endif /* USE_HAL */
--- /dev/null	2004-06-07 17:03:02.000000000 +0200
+++ libgnomevfs/gnome-vfs-hal-mounts.h	2004-05-06 22:57:38.000000000 +0200
@@ -0,0 +1,45 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gnome-vfs-hal-mounts.h - read and monitor volumes using freedesktop HAL
+
+   Copyright (C) 2004 David Zeuthen
+
+   The Gnome Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: David Zeuthen <david fubar dk>
+*/
+
+#ifndef GNOME_VFS_HAL_MOUNTS_H
+#define GNOME_VFS_HAL_MOUNTS_H
+
+#include <glib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <hal/libhal.h>
+#include <dbus/dbus-glib.h>
+
+#include "gnome-vfs-volume-monitor-daemon.h"
+
+void _gnome_vfs_monitor_hal_mounts_init (GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon);
+
+void _gnome_vfs_monitor_hal_mounts_shutdown (GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon);
+
+void _gnome_vfs_monitor_hal_get_volume_list (GnomeVFSVolumeMonitorDaemon *volume_monitor_daemon);
+
+
+
+#endif /* GNOME_VFS_HAL_MOUNTS_H */


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