hal: Branch 'master' - 3 commits

Joe Marcus Clarke marcus at kemper.freedesktop.org
Tue Dec 25 22:57:31 PST 2007


 hald/freebsd/Makefile.am        |   71 +--
 hald/freebsd/hal-file-monitor.c |  784 ++++++++++++++++++++++++++++++++++++++++
 hald/freebsd/osspec.c           |   11 
 3 files changed, 829 insertions(+), 37 deletions(-)

New commits:
commit 105aeaba0fbe6679de536d3662a336a0d6d65557
Author: Joe Marcus Clarke <marcus at FreeBSD.org>
Date:   Tue Dec 25 16:30:09 2007 -0500

    clean up some compiler warnings
    
    Fix some problems exposed under -pedantic.

diff --git a/hald/freebsd/hal-file-monitor.c b/hald/freebsd/hal-file-monitor.c
index 9187512..997d2f9 100644
--- a/hald/freebsd/hal-file-monitor.c
+++ b/hald/freebsd/hal-file-monitor.c
@@ -78,7 +78,7 @@ struct HalFileMonitorPrivate
   GHashTable *fd_to_adata;
 };
 
-G_DEFINE_TYPE (HalFileMonitor, hal_file_monitor, G_TYPE_OBJECT);
+G_DEFINE_TYPE (HalFileMonitor, hal_file_monitor, G_TYPE_OBJECT)
 
 static gpointer monitor_object = NULL;
 
@@ -95,7 +95,7 @@ static gboolean remove_adata_foreach (gpointer fd, FileAccessData *data, HalFile
 static void setup_monitor (HalFileMonitor *monitor);
 static void close_monitor (HalFileMonitor *monitor);
 static gboolean hal_file_access_monitor (gpointer data);
-static char *fflags_to_str (int fflags);
+/*static char *fflags_to_str (int fflags);*/
 static void emit_monitor_event (HalFileMonitor *monitor, HalFileMonitorEvent event, const char *path, HalFileMonitorNotifyFunc func, gpointer udata);
 static gboolean handle_kqueue_event (GIOChannel *source, GIOCondition condition, gpointer udata);
 
@@ -144,7 +144,6 @@ hal_file_monitor_add_notify (HalFileMonitor *monitor,
   struct kevent ev;
   struct stat *sb;
   int fd;
-  int kmask;
 
   if (! monitor->priv->initialized_kqueue)
     {
@@ -216,6 +215,7 @@ hal_file_monitor_add_notify (HalFileMonitor *monitor,
           kdata->dir_contents = get_dir_contents (path);
         }
 
+      /*g_warning ("XXX: Adding event with mask %s", fflags_to_str (kmask));*/
       EV_SET (&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
               kmask, 0, monitor);
       if (kevent (monitor->priv->kqueue_fd, &ev, 1, NULL, 0, NULL) < 0)
@@ -388,6 +388,8 @@ hal_file_access_monitor (gpointer data)
           emit_monitor_event (monitor, HAL_FILE_MONITOR_EVENT_ACCESS, adata->path, adata->func, adata->udata);
         }
     }
+
+  return TRUE;
 }
 
 static void
@@ -482,6 +484,7 @@ hal_file_monitor_new (void)
   return HAL_FILE_MONITOR (monitor_object);
 }
 
+/*
 static char *
 fflags_to_str (int fflags)
 {
@@ -521,6 +524,7 @@ fflags_to_str (int fflags)
 
   return g_string_free (out, FALSE);
 }
+*/
 
 static void
 emit_monitor_event (HalFileMonitor *monitor,
@@ -546,7 +550,6 @@ handle_kqueue_event (GIOChannel *source,
       0, 0
     };
   int nevents;
-  int event;
   HalFileMonitor *monitor;
 
   g_return_val_if_fail (HAL_IS_FILE_MONITOR (udata), FALSE);
commit e64ac4d3e883277365155095258ecd6a4dffcf6e
Author: Joe Marcus Clarke <marcus at FreeBSD.org>
Date:   Tue Dec 25 16:18:14 2007 -0500

    add a kqueue file monitor
    
    Add a HalFileMonitor implementation based on kqueue.

diff --git a/hald/freebsd/Makefile.am b/hald/freebsd/Makefile.am
index cbcd98d..d8eeccc 100644
--- a/hald/freebsd/Makefile.am
+++ b/hald/freebsd/Makefile.am
@@ -13,41 +13,42 @@ if HALD_COMPILE_FREEBSD
 noinst_LTLIBRARIES = libhald_freebsd.la
 endif
 
-libhald_freebsd_la_SOURCES = \
-	hf-acpi.c	\
-	hf-acpi.h	\
-	hf-ata.c	\
-	hf-ata.h	\
-	hf-block.c	\
-	hf-block.h	\
-	hf-computer.c	\
-	hf-computer.h	\
-	hf-devd.c	\
-	hf-devd.h	\
-	hf-devtree.c	\
-	hf-devtree.h	\
-	hf-net.c	\
-	hf-net.h	\
-	hf-osspec.h	\
-	hf-pci.c	\
-	hf-pci.h	\
-	hf-pcmcia.c	\
-	hf-pcmcia.h	\
-	hf-scsi.c	\
-	hf-scsi.h	\
-	hf-serial.c	\
-	hf-serial.h	\
-	hf-sound.c	\
-	hf-sound.h	\
-	hf-storage.c	\
-	hf-storage.h	\
-	hf-usb.c	\
-	hf-usb.h	\
-	hf-util.c	\
-	hf-util.h	\
-	hf-volume.c	\
-	hf-volume.h	\
-	osspec.c
+libhald_freebsd_la_SOURCES = 	\
+	hf-acpi.c		\
+	hf-acpi.h		\
+	hf-ata.c		\
+	hf-ata.h		\
+	hf-block.c		\
+	hf-block.h		\
+	hf-computer.c		\
+	hf-computer.h		\
+	hf-devd.c		\
+	hf-devd.h		\
+	hf-devtree.c		\
+	hf-devtree.h		\
+	hf-net.c		\
+	hf-net.h		\
+	hf-osspec.h		\
+	hf-pci.c		\
+	hf-pci.h		\
+	hf-pcmcia.c		\
+	hf-pcmcia.h		\
+	hf-scsi.c		\
+	hf-scsi.h		\
+	hf-serial.c		\
+	hf-serial.h		\
+	hf-sound.c		\
+	hf-sound.h		\
+	hf-storage.c		\
+	hf-storage.h		\
+	hf-usb.c		\
+	hf-usb.h		\
+	hf-util.c		\
+	hf-util.h		\
+	hf-volume.c		\
+	hf-volume.h		\
+	osspec.c		\
+	hal-filemonitor.c	\
 
 libhald_freebsd_la_LDFLAGS = -lcam
 
commit ce4744daf44c7210c42e955c744e0f86fc1bf4b9
Author: Joe Marcus Clarke <marcus at FreeBSD.org>
Date:   Tue Dec 25 16:16:19 2007 -0500

    add a kqueue file monitor
    
    Add a HalFileMonitor implementation based on kqueue.

diff --git a/hald/freebsd/hal-file-monitor.c b/hald/freebsd/hal-file-monitor.c
new file mode 100644
index 0000000..9187512
--- /dev/null
+++ b/hald/freebsd/hal-file-monitor.c
@@ -0,0 +1,781 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * hal-file-monitor.c: Kqueue-based file monitor
+ *
+ * Copyright (C) 2007 Joe Marcus Clarke <marcus at FreeBSD.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ **************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+
+#include "../hal-file-monitor.h"
+
+#define HAL_FILE_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), HAL_TYPE_FILE_MONITOR, HalFileMonitorPrivate))
+
+#define VN_NOTE_CHANGED (NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_LINK)
+#define VN_NOTE_DELETED (NOTE_DELETE | NOTE_REVOKE)
+#define VN_NOTE_ALL     (VN_NOTE_CHANGED | VN_NOTE_DELETED | NOTE_RENAME)
+
+typedef struct
+{
+  char *path;
+  struct stat *stat;
+  int omask;
+  gboolean isdir;
+  HalFileMonitorNotifyFunc func;
+  gpointer udata;
+  GHashTable *dir_contents;
+} FileKqueueData;
+
+typedef struct
+{
+  char *path;
+  time_t atime;
+  HalFileMonitorNotifyFunc func;
+  gpointer udata;
+} FileAccessData;
+
+struct HalFileMonitorPrivate
+{
+  int kqueue_fd;
+  guint io_watch;
+  guint access_source;
+
+  gboolean initialized_kqueue;
+
+  GHashTable *fd_to_kdata;
+  GHashTable *fd_to_adata;
+};
+
+G_DEFINE_TYPE (HalFileMonitor, hal_file_monitor, G_TYPE_OBJECT);
+
+static gpointer monitor_object = NULL;
+
+static void hal_file_monitor_class_init (HalFileMonitorClass *klass);
+static void hal_file_monitor_init (HalFileMonitor *monitor);
+static void hal_file_monitor_finalize (GObject *object);
+static GHashTable *get_dir_contents (const char *path);
+static GHashTable *diff_dir_contents (FileKqueueData *data, GSList **added, GSList **removed);
+static int hal_mask_to_kmask (int mask);
+static void monitor_release_kdata (HalFileMonitor *monitor, int fd, FileKqueueData *data);
+static void monitor_release_adata (HalFileMonitor *monitor, int fd, FileAccessData *data);
+static gboolean remove_kdata_foreach (gpointer fd, FileKqueueData *data, HalFileMonitor *monitor);
+static gboolean remove_adata_foreach (gpointer fd, FileAccessData *data, HalFileMonitor *monitor);
+static void setup_monitor (HalFileMonitor *monitor);
+static void close_monitor (HalFileMonitor *monitor);
+static gboolean hal_file_access_monitor (gpointer data);
+static char *fflags_to_str (int fflags);
+static void emit_monitor_event (HalFileMonitor *monitor, HalFileMonitorEvent event, const char *path, HalFileMonitorNotifyFunc func, gpointer udata);
+static gboolean handle_kqueue_event (GIOChannel *source, GIOCondition condition, gpointer udata);
+
+GQuark
+hal_file_monitor_error_quark (void)
+{
+  static GQuark ret = 0;
+  if (ret == 0)
+    {
+      ret = g_quark_from_static_string ("hal_file_monitor_error");
+    }
+
+  return ret;
+}
+
+static int
+hal_mask_to_kmask (int mask)
+{
+  int kmask = 0;
+
+  if (mask & HAL_FILE_MONITOR_EVENT_CREATE)
+    {
+      kmask |= NOTE_WRITE | NOTE_LINK;
+    }
+
+  if (mask & HAL_FILE_MONITOR_EVENT_DELETE)
+    {
+      kmask |= NOTE_WRITE | NOTE_LINK | VN_NOTE_DELETED;
+    }
+
+  if (mask & HAL_FILE_MONITOR_EVENT_CHANGE)
+    {
+      kmask |= VN_NOTE_CHANGED;
+    }
+
+  return kmask;
+}
+
+guint
+hal_file_monitor_add_notify (HalFileMonitor *monitor,
+                             const char *path,
+                             int mask,
+                             HalFileMonitorNotifyFunc notify_func,
+                             gpointer data)
+{
+  struct kevent ev;
+  struct stat *sb;
+  int fd;
+  int kmask;
+
+  if (! monitor->priv->initialized_kqueue)
+    {
+      return 0;
+    }
+
+  fd = open (path, O_RDONLY);
+  if (fd < 0)
+    {
+      return 0;
+    }
+
+  sb = g_new (struct stat, 1);
+  if (sb == NULL)
+    {
+      close (fd);
+      return 0;
+    }
+
+  if (fstat (fd, sb) == -1)
+    {
+      close (fd);
+      g_free (sb);
+      return 0;
+    }
+
+  if (mask & HAL_FILE_MONITOR_EVENT_ACCESS)
+    {
+      FileAccessData *adata;
+
+      adata = g_new0 (FileAccessData, 1);
+      adata->path = g_strdup (path);
+      adata->atime = sb->st_atime;
+      adata->func = notify_func;
+      adata->udata = data;
+      g_hash_table_insert (monitor->priv->fd_to_adata,
+                           GINT_TO_POINTER (fd),
+                           adata);
+    }
+
+  if ((mask & HAL_FILE_MONITOR_EVENT_CREATE) ||
+      (mask & HAL_FILE_MONITOR_EVENT_DELETE) ||
+      (mask & HAL_FILE_MONITOR_EVENT_CHANGE))
+    {
+      FileKqueueData *kdata;
+      int kmask;
+      gboolean isdir;
+
+      kmask = hal_mask_to_kmask (mask);
+
+      isdir = (sb->st_mode & S_IFDIR) != 0;
+      if (! isdir && mask == HAL_FILE_MONITOR_EVENT_CREATE)
+        {
+          /* We can't monitor creation on a file. */
+          close (fd);
+          g_free (sb);
+          return 0;
+        }
+
+      kdata = g_new0 (FileKqueueData, 1);
+      kdata->path = g_strdup (path);
+      kdata->omask = mask;
+      kdata->stat = sb;
+      kdata->isdir = isdir;
+      kdata->func = notify_func;
+      kdata->udata = data;
+      if (isdir)
+        {
+          kdata->dir_contents = get_dir_contents (path);
+        }
+
+      EV_SET (&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
+              kmask, 0, monitor);
+      if (kevent (monitor->priv->kqueue_fd, &ev, 1, NULL, 0, NULL) < 0)
+        {
+          monitor_release_kdata (monitor, fd, kdata);
+          return 0;
+        }
+      g_hash_table_insert (monitor->priv->fd_to_kdata,
+                           GINT_TO_POINTER (fd),
+                           kdata);
+    }
+  else
+    {
+      g_free (sb);
+    }
+
+  return fd;
+}
+
+void
+hal_file_monitor_remove_notify (HalFileMonitor *monitor,
+                                guint id)
+{
+  FileKqueueData *kdata;
+  FileAccessData *adata;
+
+  if (! monitor->priv->initialized_kqueue)
+    return;
+
+  kdata = (FileKqueueData *) g_hash_table_lookup (monitor->priv->fd_to_kdata, GINT_TO_POINTER (id));
+  adata = (FileAccessData *) g_hash_table_lookup (monitor->priv->fd_to_adata, GINT_TO_POINTER (id));
+
+  if (kdata)
+    {
+      g_hash_table_remove (monitor->priv->fd_to_kdata, GINT_TO_POINTER (id));
+      monitor_release_kdata (monitor, id, kdata);
+    }
+
+  if (adata)
+    {
+      g_hash_table_remove (monitor->priv->fd_to_adata, GINT_TO_POINTER (id));
+      monitor_release_adata (monitor, id, adata);
+    }
+}
+
+static void
+monitor_release_kdata (HalFileMonitor *monitor,
+                       int fd,
+                       FileKqueueData *data)
+{
+  g_free (data->path);
+  data->path = NULL;
+
+  g_free (data->stat);
+  data->stat = NULL;
+
+  if (data->dir_contents)
+    {
+      g_hash_table_remove_all (data->dir_contents);
+      g_hash_table_destroy (data->dir_contents);
+    }
+  data->dir_contents = NULL;
+
+  close (fd);
+}
+
+static void
+monitor_release_adata (HalFileMonitor *monitor,
+                       int fd,
+                       FileAccessData *data)
+{
+  g_free (data->path);
+  data->path = NULL;
+
+  close (fd);
+}
+
+static gboolean
+remove_kdata_foreach (gpointer fd,
+                      FileKqueueData *data,
+                      HalFileMonitor *monitor)
+{
+  monitor_release_kdata (monitor, GPOINTER_TO_INT (fd), data);
+  return TRUE;
+}
+
+static gboolean
+remove_adata_foreach (gpointer fd,
+                      FileAccessData *data,
+                      HalFileMonitor *monitor)
+{
+  monitor_release_adata (monitor, GPOINTER_TO_INT (fd), data);
+  return TRUE;
+}
+
+static void
+close_monitor (HalFileMonitor *monitor)
+{
+  if (! monitor->priv->initialized_kqueue)
+    {
+      return;
+    }
+
+  monitor->priv->initialized_kqueue = FALSE;
+
+  g_hash_table_foreach_remove (monitor->priv->fd_to_kdata,
+                               (GHRFunc) remove_kdata_foreach,
+                               monitor);
+
+  g_hash_table_foreach_remove (monitor->priv->fd_to_adata,
+                               (GHRFunc) remove_adata_foreach,
+                               monitor);
+
+  if (monitor->priv->io_watch)
+    {
+      g_source_remove (monitor->priv->io_watch);
+    }
+  monitor->priv->io_watch = 0;
+
+  if (monitor->priv->access_source)
+    {
+      g_source_remove (monitor->priv->access_source);
+    }
+  monitor->priv->access_source = 0;
+
+  if (monitor->priv->kqueue_fd > -1)
+    {
+      close (monitor->priv->kqueue_fd);
+    }
+  monitor->priv->kqueue_fd = -1;
+}
+
+static gboolean
+hal_file_access_monitor (gpointer data)
+{
+  HalFileMonitor *monitor;
+  GList *keys, *l;
+
+  g_return_val_if_fail (HAL_IS_FILE_MONITOR (data), FALSE);
+
+  monitor = HAL_FILE_MONITOR (data);
+
+  g_return_val_if_fail (monitor->priv != NULL, FALSE);
+
+  keys = g_hash_table_get_keys (monitor->priv->fd_to_adata);
+
+  for (l = keys; l != NULL; l = l->next)
+    {
+      FileAccessData *adata;
+      struct stat sb;
+      int fd;
+
+      fd = GPOINTER_TO_INT (l->data);
+      adata = g_hash_table_lookup (monitor->priv->fd_to_adata,
+                                   l->data);
+
+      if (! adata)
+        {
+          continue;
+        }
+
+      if (fstat (fd, &sb) == -1)
+        {
+          continue;
+        }
+
+      if (sb.st_atime != adata->atime)
+        {
+          adata->atime = sb.st_atime;
+          emit_monitor_event (monitor, HAL_FILE_MONITOR_EVENT_ACCESS, adata->path, adata->func, adata->udata);
+        }
+    }
+}
+
+static void
+setup_monitor (HalFileMonitor *monitor)
+{
+  GIOChannel *io_channel;
+  int fd;
+
+  if (monitor->priv->initialized_kqueue)
+    {
+      return;
+    }
+
+  if ((fd = kqueue ()) < 0)
+    {
+      g_warning ("Failed to initialize kqueue: %s",
+                 g_strerror (errno));
+      return;
+    }
+
+  monitor->priv->kqueue_fd = fd;
+
+  io_channel = g_io_channel_unix_new (fd);
+  monitor->priv->io_watch = g_io_add_watch (io_channel,
+                            G_IO_IN|G_IO_PRI,
+                            (GIOFunc) handle_kqueue_event,
+                            monitor);
+  g_io_channel_unref (io_channel);
+
+  monitor->priv->access_source = g_idle_add ((GSourceFunc) hal_file_access_monitor, monitor);
+  monitor->priv->fd_to_kdata = g_hash_table_new (g_direct_hash,
+                               g_direct_equal);
+  monitor->priv->fd_to_adata = g_hash_table_new (g_direct_hash,
+                               g_direct_equal);
+
+  monitor->priv->initialized_kqueue = TRUE;
+}
+
+static void
+hal_file_monitor_init (HalFileMonitor *monitor)
+{
+  monitor->priv = HAL_FILE_MONITOR_GET_PRIVATE (monitor);
+
+  setup_monitor (monitor);
+}
+
+static void
+hal_file_monitor_class_init (HalFileMonitorClass *klass)
+{
+  GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = hal_file_monitor_finalize;
+
+  g_type_class_add_private (klass, sizeof (HalFileMonitorPrivate));
+}
+
+static void
+hal_file_monitor_finalize (GObject *object)
+{
+  HalFileMonitor *monitor;
+
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (HAL_IS_FILE_MONITOR (object));
+
+  monitor = HAL_FILE_MONITOR (object);
+
+  g_return_if_fail (monitor->priv != NULL);
+
+  close_monitor (monitor);
+
+  g_hash_table_destroy (monitor->priv->fd_to_kdata);
+  g_hash_table_destroy (monitor->priv->fd_to_adata);
+
+  G_OBJECT_CLASS (hal_file_monitor_parent_class)->finalize (object);
+}
+
+HalFileMonitor *
+hal_file_monitor_new (void)
+{
+  if (monitor_object != NULL)
+    {
+      g_object_ref (monitor_object);
+    }
+  else
+    {
+      monitor_object = g_object_new (HAL_TYPE_FILE_MONITOR, NULL);
+
+      g_object_add_weak_pointer (monitor_object,
+                                 (gpointer *) &monitor_object);
+    }
+
+  return HAL_FILE_MONITOR (monitor_object);
+}
+
+static char *
+fflags_to_str (int fflags)
+{
+
+  GString *out;
+
+  out = g_string_new (NULL);
+
+  if (fflags & NOTE_WRITE)
+    {
+      g_string_append (out, " WRITE ");
+    }
+  if (fflags & NOTE_EXTEND)
+    {
+      g_string_append (out, " EXTEND ");
+    }
+  if (fflags & NOTE_ATTRIB)
+    {
+      g_string_append (out, " ATTRIB ");
+    }
+  if (fflags & NOTE_LINK)
+    {
+      g_string_append (out, " LINK ");
+    }
+  if (fflags & NOTE_DELETE)
+    {
+      g_string_append (out, " DELETE ");
+    }
+  if (fflags & NOTE_REVOKE)
+    {
+      g_string_append (out, " REVOKE ");
+    }
+  if (fflags & NOTE_RENAME)
+    {
+      g_string_append (out, " RENAME ");
+    }
+
+  return g_string_free (out, FALSE);
+}
+
+static void
+emit_monitor_event (HalFileMonitor *monitor,
+                    HalFileMonitorEvent event,
+                    const char *path,
+                    HalFileMonitorNotifyFunc func,
+                    gpointer udata)
+{
+  if (func)
+    {
+      func (monitor, event, path, udata);
+    }
+}
+
+static gboolean
+handle_kqueue_event (GIOChannel *source,
+                     GIOCondition   condition,
+                     gpointer udata)
+{
+  struct kevent ev;
+  struct timespec timeout =
+    {
+      0, 0
+    };
+  int nevents;
+  int event;
+  HalFileMonitor *monitor;
+
+  g_return_val_if_fail (HAL_IS_FILE_MONITOR (udata), FALSE);
+
+  monitor = HAL_FILE_MONITOR (udata);
+
+  g_return_val_if_fail (monitor->priv != NULL, FALSE);
+
+  nevents = kevent (monitor->priv->kqueue_fd, NULL, 0, &ev, 1, &timeout);
+  if (nevents == 1)
+    {
+      int fd;
+      FileKqueueData *data;
+
+      fd = ev.ident;
+      data = g_hash_table_lookup (monitor->priv->fd_to_kdata,
+                                  GINT_TO_POINTER (fd));
+      if (! data)
+        {
+          /* The monitor may have been deleted. */
+          return TRUE;
+        }
+
+      if ((data->omask & HAL_FILE_MONITOR_EVENT_DELETE) &&
+          (ev.fflags & VN_NOTE_DELETED))
+        {
+          emit_monitor_event (monitor, HAL_FILE_MONITOR_EVENT_DELETE, data->path, data->func, data->udata);
+          return TRUE;
+        }
+
+      if ((data->omask & HAL_FILE_MONITOR_EVENT_CREATE) ||
+          (data->omask & HAL_FILE_MONITOR_EVENT_DELETE))
+        {
+          if (data->isdir)
+            {
+              GSList *added = NULL;
+              GSList *removed = NULL;
+              GSList *l;
+              GHashTable *table;
+
+              table = diff_dir_contents (data, &added, &removed);
+              if (data->omask & HAL_FILE_MONITOR_EVENT_CREATE)
+                {
+                  for (l = added; l != NULL; l = l->next)
+                    {
+                      char *path;
+
+                      path = g_build_filename (data->path, l->data, NULL);
+                      emit_monitor_event (monitor, HAL_FILE_MONITOR_EVENT_CREATE, path, data->func, data->udata);
+                      g_free (path);
+                    }
+                }
+
+              if (data->omask & HAL_FILE_MONITOR_EVENT_DELETE)
+                {
+                  for (l = removed; l != NULL; l = l->next)
+                    {
+                      char *path;
+
+                      path = g_build_filename (data->path, l->data, NULL);
+                      emit_monitor_event (monitor, HAL_FILE_MONITOR_EVENT_DELETE, path, data->func, data->udata);
+                      g_free (path);
+                    }
+                }
+
+              if (added || removed)
+                {
+                  g_hash_table_remove_all (data->dir_contents);
+                  g_hash_table_destroy (data->dir_contents);
+                  data->dir_contents = table;
+                }
+              else if (table)
+                {
+                  g_hash_table_remove_all (table);
+                  g_hash_table_destroy (table);
+                }
+
+              if (added)
+                {
+                  g_slist_foreach (added, (GFunc) g_free, NULL);
+                  g_slist_free (added);
+                }
+              if (removed)
+                {
+                  g_slist_foreach (removed, (GFunc) g_free, NULL);
+                  g_slist_free (removed);
+                }
+            }
+        }
+
+      if (data->omask & HAL_FILE_MONITOR_EVENT_CHANGE)
+        {
+          emit_monitor_event (monitor, HAL_FILE_MONITOR_EVENT_CHANGE, data->path, data->func, data->udata);
+        }
+    }
+  else
+    {
+      g_warning ("Failed to read from kqueue: %s", g_strerror (errno));
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static GHashTable *
+diff_dir_contents (FileKqueueData *data,
+                   GSList **added,
+                   GSList **removed)
+{
+  GDir *dir;
+  GHashTable *table = NULL;
+
+  dir = g_dir_open (data->path, 0, NULL);
+  if (dir)
+    {
+      const char *fname;
+
+      table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+      while ((fname = g_dir_read_name (dir)))
+        {
+          if (added)
+            {
+              if (! g_hash_table_lookup (data->dir_contents, fname))
+                {
+                  *added = g_slist_prepend (*added, g_strdup (fname));
+                }
+            }
+
+          g_hash_table_insert (table, g_strdup (fname), GINT_TO_POINTER (TRUE));
+        }
+
+      if (removed)
+        {
+          GList *keys;
+          GList *l;
+
+          keys = g_hash_table_get_keys (data->dir_contents);
+
+          for (l = keys; l != NULL; l = l->next)
+            {
+              if (! g_hash_table_lookup (table, l->data))
+                {
+                  *removed = g_slist_prepend (*removed, g_strdup (l->data));
+                }
+            }
+        }
+
+    }
+
+  return table;
+}
+
+static GHashTable *
+get_dir_contents (const char *path)
+{
+  GDir *dir;
+  GError *err = NULL;
+  GHashTable *table = NULL;
+
+  dir = g_dir_open (path, 0, &err);
+  if (dir)
+    {
+      const char *fname;
+
+      table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+      while ((fname = g_dir_read_name (dir)))
+        {
+          g_hash_table_insert (table, g_strdup (fname), GINT_TO_POINTER (TRUE));
+        }
+      g_dir_close (dir);
+    }
+  else
+    {
+      g_warning ("Failed to open directory %s: %s\n", path, err->message);
+    }
+
+  return table;
+}
+
+/*
+static void
+print_event (HalFileMonitor *monitor,
+             HalFileMonitorEvent event,
+             const char *path,
+             gpointer udata)
+{
+  GString *ename;
+
+  ename = g_string_new (NULL);
+
+  if (event & HAL_FILE_MONITOR_EVENT_ACCESS)
+    {
+      g_string_append (ename, "ACCESS ");
+    }
+  if (event & HAL_FILE_MONITOR_EVENT_CREATE)
+    {
+      g_string_append (ename, "CREATE ");
+    }
+  if (event & HAL_FILE_MONITOR_EVENT_DELETE)
+    {
+      g_string_append (ename, "DELETE ");
+    }
+  if (event & HAL_FILE_MONITOR_EVENT_CHANGE)
+    {
+      g_string_append (ename, "CHANGE ");
+    }
+
+  printf("Received event for %s: %s\n", path, g_string_free (ename, FALSE));
+}
+
+int
+main(void)
+{
+  const char *path = "/tmp/kqueue.d";
+  guint watch;
+  GMainLoop *loop;
+  HalFileMonitor *monitor;
+
+  g_type_init ();
+
+  monitor = hal_file_monitor_new ();
+  hal_file_monitor_add_notify (monitor, path, HAL_FILE_MONITOR_EVENT_CREATE|HAL_FILE_MONITOR_EVENT_DELETE|HAL_FILE_MONITOR_EVENT_CHANGE,print_event, NULL);
+
+  loop = g_main_loop_new (NULL, FALSE);
+
+  g_main_loop_run (loop);
+
+  return 0;
+}
+*/
diff --git a/hald/freebsd/osspec.c b/hald/freebsd/osspec.c
index 1b047b1..70b7ac9 100644
--- a/hald/freebsd/osspec.c
+++ b/hald/freebsd/osspec.c
@@ -62,11 +62,12 @@ static HFHandler *handlers[] = {
   &hf_devd_handler
 };
 
+static HalFileMonitor *file_monitor = NULL;
+
 HalFileMonitor *
 osspec_get_file_monitor (void)
 {
-#warning Please implement
-        return NULL;
+  return file_monitor;
 }
 
 void
@@ -86,6 +87,12 @@ osspec_init (void)
 
   pci_ids_init();
 
+  file_monitor = hal_file_monitor_new ();
+  if (file_monitor == NULL)
+    {
+      HAL_INFO(("Cannot initialize file monitor"));
+    }
+
   for (i = 0; i < (int) G_N_ELEMENTS(handlers); i++)
     if (handlers[i]->init)
       handlers[i]->init();


More information about the hal-commit mailing list