Bug#312369: marked as done ([patch] Native Hurd support and run-time fixes)

Debian Bug Tracking System owner@bugs.debian.org
Mon, 13 Jun 2005 13:03:16 -0700


Your message dated Mon, 13 Jun 2005 15:47:43 -0400
with message-id <E1DhuuN-0007yQ-00@newraff.debian.org>
and subject line Bug#312369: fixed in gamin 0.1.1-1
has caused the attached Bug report to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what I am
talking about this indicates a serious mail system misconfiguration
somewhere.  Please contact me immediately.)

Debian bug tracking system administrator
(administrator, Debian Bugs database)

--------------------------------------
Received: (at submit) by bugs.debian.org; 7 Jun 2005 18:45:47 +0000
>From mbanck@gmx.net Tue Jun 07 11:45:47 2005
Return-path: <mbanck@gmx.net>
Received: from pop.gmx.de (mail.gmx.net) [213.165.64.20] 
	by spohr.debian.org with smtp (Exim 3.35 1 (Debian))
	id 1Dfj58-0007Sh-00; Tue, 07 Jun 2005 11:45:46 -0700
Received: (qmail invoked by alias); 07 Jun 2005 18:45:13 -0000
Received: from ppp-82-135-11-27.mnet-online.de (EHLO localhost.localdomain) [82.135.11.27]
  by mail.gmx.net (mp013) with SMTP; 07 Jun 2005 20:45:13 +0200
X-Authenticated: #686195
Received: from mbanck by localhost.localdomain with local (Exim 4.34)
	id 1Dfj4k-0006Up-IY
	for submit@bugs.debian.org; Tue, 07 Jun 2005 20:45:22 +0200
Date: Tue, 7 Jun 2005 20:45:22 +0200
From: Michael Banck <mbanck@debian.org>
To: submit@bugs.debian.org
Subject: [patch] Native Hurd support and run-time fixes
Message-ID: <20050607184522.GG9281@chemicalconnection.dyndns.org>
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="twz1s1Hj1O0rHoT0"
Content-Disposition: inline
User-Agent: Mutt/1.5.6+20040907i
X-Y-GMX-Trusted: 0
Delivered-To: submit@bugs.debian.org
X-Spam-Checker-Version: SpamAssassin 2.60-bugs.debian.org_2005_01_02 
	(1.212-2003-09-23-exp) on spohr.debian.org
X-Spam-Status: No, hits=-4.2 required=4.0 tests=HAS_PACKAGE,
	REMOVE_REMOVAL_NEAR autolearn=no 
	version=2.60-bugs.debian.org_2005_01_02
X-Spam-Level: 


--twz1s1Hj1O0rHoT0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Package: gamin
Severity: normal
Tags: patch

Hi,

while gamin builds fine for a while now on the Hurd, it didn't actually
work.  Neal Walfield has worked on it over the last days and the test
suite now passes at an acceptable level (one failure, one alledgedly
wrong test according to Neal, a couple of bugus differences to the Linux
output) and it actually works with GNOME.

Moreover, Neal has written a native backend for the Hurd, as it supports
file alteration notifications for ages now.

He filed the patches as #306706 and #306707 upstream and I have them
attached for convenience.  Note that gamin_hurd_backend.patch needs a
automake/autoconf rerun in order to be effective.


cheers,

Michael

-- 
Michael Banck
Debian Developer
mbanck@debian.org
http://www.advogato.org/person/mbanck/diary.html

--twz1s1Hj1O0rHoT0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="gamin_hurd_fix.patch"

2005-06-03  Neal H. Walfield  <neal@gnu.org>

	* libgamin/gam_api.c (gamin_check_cred): only check for the
	credential if the operating system actually delivers credentials
	* server/gam_channel.c (gam_client_conn_check_cred): likewise

diff -urN gamin-0.0.26-upstream/libgamin/gam_api.c gamin-0.0.26/libgamin/gam_api.c
--- gamin-0.0.26-upstream/libgamin/gam_api.c	2005-02-17 11:42:57.000000000 +0000
+++ gamin-0.0.26/libgamin/gam_api.c	2005-06-05 15:43:31.000000000 +0100
@@ -656,6 +656,6 @@
         goto failed;
     }
-#ifdef HAVE_CMSGCRED
+#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
     if (cmsg->cmsg_len < sizeof(cmsgmem) || cmsg->cmsg_type != SCM_CREDS) {
         GAM_DEBUG(DEBUG_INFO,
                   "Message from recvmsg() was not SCM_CREDS\n");
@@ -686,7 +691,7 @@
                       fd, cr_len, (int) sizeof(cr));
             goto failed;
         }
-#elif defined(HAVE_CMSGCRED)
+#elif defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
         struct cmsgcred *cred;
 
         cred = (struct cmsgcred *) CMSG_DATA(cmsg);
@@ -694,10 +699,14 @@
         c_pid = cred->cmcred_pid;
         c_uid = cred->cmcred_euid;
         c_gid = cred->cmcred_groups[0];
-#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
+#else /* !SO_PEERCRED && !(LOCAL_CREDS && HAVE_CMSGCRED) */
+	/* Can't use 0 as that triggers an assertion nor -1 as that is
+	   sometimes used to indicate an error occured.  Our pid is as
+	   good as other.  */
+	c_pid = getpid ();
         GAM_DEBUG(DEBUG_INFO,
                   "Socket credentials not supported on this OS\n");
-        goto failed;
+        goto out;
 #endif
     }
 
@@ -710,6 +719,8 @@
     GAM_DEBUG(DEBUG_INFO,
               "Credentials: s_uid %d, c_uid %d, c_gid %d, c_pid %d\n",
               (int) s_uid, (int) c_uid, (int) c_gid, (int) c_pid);
+
+out:
     gamin_data_done_auth(conn);
 
     return(0);
diff -urN gamin-0.0.26-upstream/server/gam_channel.c gamin-0.0.26/server/gam_channel.c
--- gamin-0.0.26-upstream/server/gam_channel.c	2005-01-28 15:54:42.000000000 +0000
+++ gamin-0.0.26/server/gam_channel.c	2005-06-03 17:28:18.000000000 +0100
@@ -89,6 +90,6 @@
         goto failed;
     }
-#ifdef HAVE_CMSGCRED
+#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
     if (cmsg->cmsg_len < sizeof(cmsgmem) || cmsg->cmsg_type != SCM_CREDS) {
         GAM_DEBUG(DEBUG_INFO,
                   "Message from recvmsg() was not SCM_CREDS\n");
@@ -119,7 +125,7 @@
                       fd, cr_len, (int) sizeof(cr));
             goto failed;
         }
-#elif defined(HAVE_CMSGCRED)
+#elif defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
         struct cmsgcred *cred;
 
         cred = (struct cmsgcred *) CMSG_DATA(cmsg);
@@ -127,10 +133,14 @@
         c_pid = cred->cmcred_pid;
         c_uid = cred->cmcred_euid;
         c_gid = cred->cmcred_groups[0];
-#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
+#else /* !SO_PEERCRED && !(defined(LOCAL_CREDS) && HAVE_CMSGCRED) */
+	/* Can't use 0 as that triggers an assertion nor -1 as that is
+	   sometimes used to indicate an error occured.  Our pid is as
+	   good as other.  */
+	c_pid = getpid ();
         GAM_DEBUG(DEBUG_INFO,
                   "Socket credentials not supported on this OS\n");
-        goto failed;
+        goto out;
 #endif
     }
 
@@ -144,6 +154,7 @@
               "Credentials: s_uid %d, c_uid %d, c_gid %d, c_pid %d\n",
               (int) s_uid, (int) c_uid, (int) c_gid, (int) c_pid);
 
+out:
     if (gam_connection_set_pid(conn, c_pid) < 0) {
         GAM_DEBUG(DEBUG_INFO, "Failed to save PID\n");
         goto failed;

--twz1s1Hj1O0rHoT0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="gamin_hurd_backend.patch"

2005-06-06  Neal H. Walfield  <neal@gnu.org>

	* configure.in: If running on the GNU Hurd on Mach, enable the
	native GNU Hurd on Mach backend.
	* server/Makefile.am [ENABLE_HURD_MACH_NOTIFY] (gam_server_LDADD):
	Add gam_hurd_mach_notify.c, gam_hurd_mach_notify.h, fs_notify.c
	and fs_notify.h
	[ENABLE_HURD_MACH_NOTIFY] (BUILT_SOURCES): Add fs_notify.c and
	fs_notify.h
	[ENABLE_HURD_MACH_NOTIFY] (CLEANFILES): Add fs_notify.c and
	fs_notify.h
	[ENABLE_HURD_MACH_NOTIFY] Provide rules to build fs_notify.c and
	fs_notify.c
	[ENABLE_HURD_MACH_NOTIFY] (gam_server_LDADD): Add -lports and
	-lthread
	* server/gam_hurd_mach_notify.c: New file.
	* server/gam_hurd_mach_notify.h: New file.
	* server/gam_server.c [ENABLE_HURD_MACH_NOTIFY]: Include
	"gam_hurd_mach_notify.h"
	[ENABLE_HURD_MACH_NOTIFY] (gam_init_subscriptions): Try to
	initialize the GNU Hurd on Mach backend

diff -urN gamin-0.0.26-upstream/configure.in gamin-0.0.26/configure.in
--- gamin-0.0.26-upstream/configure.in	2005-03-15 12:39:29.000000000 +0000
+++ gamin-0.0.26/configure.in	2005-06-06 19:12:03.000000000 +0100
@@ -230,6 +230,40 @@
 	backends="${backends}, inotify"
 fi
 
+# It may just be gnu but it could also be gnu0.3, etc.
+#   if echo x$os | grep -E -e '^xgnu[0-9]*\.?[0-9]*$' >/dev/null;
+# won't work as m4 eats the []s.
+if case x$os in xgnu*) true;; *) false;; esac; then
+	AC_ARG_ENABLE(hurd_mach_notify,
+	[  --disable-hurd_mach_notify Disable the Hurd Mach Notify backend],
+	[case "${enableval}" in
+	  yes) hurd_mach_notify=true ;;
+	  no) hurd_mach_notify=false;;
+	  *) AC_MSG_ERROR(bad value ${enableval} for --disable-hurd_mach_notify) ;;
+	esac],[hurd_mach_notify=true])
+fi
+
+dnl check if hurd_mach_notify backend is enabled
+AM_CONDITIONAL(ENABLE_HURD_MACH_NOTIFY, test x$hurd_mach_notify = xtrue)
+
+if test x$hurd_mach_notify = xtrue; then
+        # <hurd/ports.h> requires _GNU_SOURCE.
+	old_CPPFLAGS="$CPPFLAGS"
+	CPPFLAGS="$old_CPPFLAGS -D_GNU_SOURCE"
+	AC_CHECK_HEADERS([hurd/ports.h], ,
+                         [AC_MSG_ERROR([<hurd/ports.h> not found but required to build hurd_mach_notify backend.])])
+	CPPFLAGS="$old_CPPFLAGS"
+
+	AC_CHECK_LIB([ports], [ports_create_port], [:],
+	             [AC_MSG_ERROR([libports not found but required to build hurd_mach_notify backend.])], [-lthreads])
+
+        AC_CHECK_TOOL(MIG, [mig], [AC_MSG_ERROR([mig not found but required to build hurd_mach_notify backend.])])
+	AC_SUBST(MIG)
+
+	AC_DEFINE(ENABLE_HURD_MACH_NOTIFY,1,[Use hurd_mach_notify as backend])
+	backends="${backends}, hurd_mach_notify"
+fi
+
 dnl check for flavours of varargs macros (test from GLib)
 AC_MSG_CHECKING(for ISO C99 varargs macros in C)
 AC_TRY_COMPILE([],[
diff -urN gamin-0.0.26-upstream/server/gam_hurd_mach_notify.c gamin-0.0.26/server/gam_hurd_mach_notify.c
diff -urN gamin-0.0.26-upstream/server/Makefile.am gamin-0.0.26/server/Makefile.am
--- gamin-0.0.26-upstream/server/Makefile.am	2005-02-16 21:50:16.000000000 +0000
+++ gamin-0.0.26/server/Makefile.am	2005-06-06 19:27:52.000000000 +0100
@@ -47,6 +47,21 @@
 gam_server_SOURCES += gam_dnotify.c gam_dnotify.h
 endif
 
+if ENABLE_HURD_MACH_NOTIFY
+gam_server_SOURCES += gam_hurd_mach_notify.c gam_hurd_mach_notify.h \
+	fs_notify.c fs_notify.h
+
+BUILT_SOURCES = fs_notify.c fs_notify.h
+CLEANFILES = fs_notify.c fs_notify.h
+
+fs_notify.c fs_notify.h: $(includedir)/hurd/fs_notify.defs
+	@MIG@ -s -server $(top_builddir)/server/fs_notify.c $(includedir)/hurd/fs_notify.defs
+endif
+
 gam_server_LDFLAGS =
 gam_server_DEPENDENCIES = $(DEPS)
 gam_server_LDADD= $(top_builddir)/lib/libgamin_shared.a $(LDADDS) $(LIBGAMIN_LIBS)
+
+if ENABLE_HURD_MACH_NOTIFY
+gam_server_LDADD += -lports -lthreads
+endif

--- gamin-0.0.26-upstream/server/gam_hurd_mach_notify.c	1970-01-01 01:00:00.000000000 +0100
+++ gamin-0.0.26/server/gam_hurd_mach_notify.c	2005-06-06 16:49:31.000000000 +0100
@@ -0,0 +1,784 @@
+/* 
+ * Copyright (C) 2005 Neal H. Walfield
+ * Loosely based on gam_inotify.c which is
+ * Copyright (C) 2004 John McCutchan, James Willcox, Corey Bowers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Lesser Public License
+ * as published by the Free Software Foundation; either version 2, 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 General Lesser Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+#define _GNU_SOURCE
+
+#include <string.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <assert.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include <hurd/fs.h>
+#include <hurd/fd.h>
+#include <hurd/ports.h>
+#include <cthreads.h>
+#include "fs_notify.h"
+
+#include <glib.h>
+#include "gam_error.h"
+#include "gam_hurd_mach_notify.h"
+#include "gam_server.h"
+#include "gam_event.h"
+
+/* Hash from paths to monitor structures.  */
+static GHashTable *path_hash;
+
+/* Pending subscriptions.  */
+static GList *new_subs;
+/* Pending subscriptions to remove.  */
+static GList *removed_subs;
+
+/* The main lock: must be held when mucking with monitors, etc.  */
+static struct mutex lock = MUTEX_INITIALIZER;
+
+/* The monitor engine.  */
+
+static struct port_bucket *port_bucket;
+static struct port_class *monitor_portclass;
+
+struct monitor
+{
+    /* The port info data (the notification receive right, etc.).  */
+    struct port_info port_info;
+
+    /* File or directory we are monitoring.  */
+    char *path;
+
+    /* And the file descriptor pointing to PATH.  If we close this
+       after we request notifications, the server will drop the
+       notification request when the last hard reference (i.e. the
+       last file descriptor) to the in memory node disappears.
+
+       If -1 then PATH doesn't exist and we are waiting for a creation
+       event from the parent directory monitor.  */
+    int fd;
+
+    /* List of subscriptions waiting for events on this monitor.  Each
+       subscription holds a reference to this monitor.  */
+    GList *subs;
+
+    /* A hash from file names to monitors.  PATH is a directory and
+       entries on this list are listening for events on their
+       respective paths.  */
+    GHashTable *children;
+
+    /* The parent monitor (i.e. the monitor of the directory
+       containing PATH).  */
+    struct monitor *parent;
+};
+
+/* Attempt to make a passive monitor active.  */
+static error_t
+monitor_watch (struct monitor *m)
+{
+    error_t err;
+
+    assert (m->fd == -1);
+    m->fd = open (m->path, O_RDONLY);
+    if (m->fd < 0) {
+	GAM_DEBUG (DEBUG_INFO, "%s: failed to open `%s': %s\n",
+		   __FUNCTION__, m->path, strerror (errno));
+	return errno;
+    }
+
+    err = HURD_FD_USE (m->fd,
+		       (file_notice_changes (descriptor->port.port,
+					     ports_get_right (m),
+					     MACH_MSG_TYPE_MAKE_SEND)));
+    if (err == EISDIR)
+	err = 0;
+    if (err)
+	GAM_DEBUG (DEBUG_INFO, "%s: file_notice_changes (%s): %s\n",
+		   __FUNCTION__, m->path, strerror (err));
+    
+    if (! err) {
+	err = HURD_FD_USE (m->fd,
+			   (dir_notice_changes (descriptor->port.port,
+						ports_get_right (m),
+						MACH_MSG_TYPE_MAKE_SEND)));
+	if (err == ENOTDIR)
+	    err = 0;
+	if (err)
+	    GAM_DEBUG (DEBUG_INFO, "%s: dir_notice_changes (%s): %s\n",
+		       __FUNCTION__, m->path, strerror (err));
+    }
+
+    return err;
+}
+
+/* Attempt to make an active monitor passive.  */
+static void
+monitor_unwatch (struct monitor *m)
+{
+    assert (m->fd != -1);
+
+    /* Destroy the receive right.  */
+    ports_reallocate_port (m);
+
+    /* And close the file descriptor.  */
+    close (m->fd);
+    m->fd = -1;
+}
+
+/* Start monitoring PATH.  Returns NULL on failure.  LOCK should
+   be held.  */
+static struct monitor *
+monitor_create (const char *path)
+{
+    error_t err;
+    struct monitor *m;
+    char *tail;
+    char *filename;
+    char *dir;
+
+    assert (! mutex_try_lock (&lock));
+
+    /* See if there is already a monitor watching PATH.  */
+    m = g_hash_table_lookup (path_hash, path);
+    if (m) {
+	GAM_DEBUG (DEBUG_INFO, "%s: monitor on `%s' exists; reusing that\n",
+		   __FUNCTION__, path);
+	return m;
+    }
+
+    GAM_DEBUG (DEBUG_INFO, "%s: creating monitor for `%s'\n",
+	       __FUNCTION__, path);
+
+    if (path[0] != '/') {
+	GAM_DEBUG (DEBUG_INFO, "%s: `%s' invalid: not an absolute path.\n",
+		   __FUNCTION__, path);
+	return NULL;
+    }
+
+    err = ports_create_port (monitor_portclass, port_bucket,
+			     sizeof (struct monitor), &m);
+    if (err) {
+	GAM_DEBUG (DEBUG_INFO, "%s: failed to create port: %s\n",
+		   __FUNCTION__, strerror (err));
+	return NULL;
+    }
+
+    m->fd = -1;
+    /* Compute the path without any trailing slashes.  */
+    {
+	/* strlen (path) is at least one: we've already verified that
+	   the first character is a slash.  */
+	const char *tail = path + strlen (path) - 1;
+
+	/* This won't strip the leading slash.  */
+	while (tail > path && *tail == '/')
+	    tail --;
+
+	m->path = g_malloc (tail - path + 1 + 1);
+	memcpy (m->path, path, tail - path + 1);
+	m->path[tail - path + 1] = '\0';
+    }
+    m->subs = 0;
+    m->children = g_hash_table_new (g_str_hash, g_str_equal);
+
+    err = monitor_watch (m);
+    if (err && err != ENOENT)
+	goto die;
+
+    /* Monitor the containing directory for creation and deletetion events.  */
+    if (strcmp (m->path, "/") == 0) {
+	/* Except / which has no parent... */
+	m->parent = 0;
+    } else {
+	if (m->path[0] == '/' && m->path[1] == '\0') {
+	    /* Failed to open `/'!!!  */
+	    GAM_DEBUG (DEBUG_INFO,
+		       "%s: `/' does not exist?  Nothing to monitor.\n",
+		       __FUNCTION__, m->path);
+	    goto die;
+	}
+
+	tail = strrchr (m->path, '/');
+	/* There is at least the leading /.  */
+	assert (tail);
+
+	filename = tail + 1;
+
+	/* Make TAIL point to the last character in the file name:
+	   not the following slash.  */
+	while (tail > m->path && *tail == '/')
+	    tail --;
+
+	dir = g_malloc (tail - m->path + 1 + 1);
+	memcpy (dir, m->path, tail - m->path + 1);
+	dir[tail - m->path + 1] = '\0';
+
+	m->parent = monitor_create (dir);
+	g_free (dir);
+	if (! m->parent)
+	    goto die;
+
+	/* Insert it into the parent's children hash table.  */
+	g_hash_table_insert (m->parent->children, filename, m);
+
+	GAM_DEBUG (DEBUG_INFO,
+		   "%s: Added `%s' to children list of `%s''s monitor.\n",
+		   __FUNCTION__, filename, m->parent->path);
+    }
+
+    /* Insert the monitor into the path hash table.  */
+    g_hash_table_insert (path_hash, m->path, m);
+
+    return m;
+
+ die:
+    if (m->fd != -1)
+	close (m->fd);
+    g_hash_table_destroy (m->children);
+    g_free (m->path);
+    /* We didn't manage to make a send right so we'll never get a dead
+       name notification.  Force the descruction of the receive
+       right.  */
+    ports_destroy_right (m);
+    ports_port_deref (m);
+    return NULL;
+}
+
+/* If there are no references to M left clean it up.  Must be called
+   whenever a subscription or child is removed.  */
+static void
+monitor_consider (struct monitor *m)
+{
+    assert (! mutex_try_lock (&lock));
+
+    if (m->subs || g_hash_table_size (m->children) > 0)
+	/* Still have subscribers or children.  */
+	return;
+
+    GAM_DEBUG(DEBUG_INFO, "%s: no more subscribers to `%s', killing\n",
+	      __FUNCTION__, m->path);
+
+    close (m->fd);
+    if (m->parent) {
+	const char *filename = strrchr (m->path, '/');
+	assert (filename);
+	filename ++;
+
+	assert (g_hash_table_lookup (m->parent->children, filename));
+	g_hash_table_remove (m->parent->children, filename);
+
+	monitor_consider (m->parent);
+    } else
+	assert (strcmp (m->path, "/") == 0);
+    g_hash_table_destroy (m->children);
+#ifndef NDEBUG
+    m->children = 0;
+#endif
+
+    assert (g_hash_table_lookup (path_hash, m->path));
+    g_hash_table_remove (path_hash, m->path);
+
+    ports_port_deref (m);
+
+    /* Kill the port libports will take care of the rest.  */
+    ports_destroy_right (m);
+}
+
+/* All references to monitor M have been dropped.  Clean it up.  */
+static void
+monitor_clean (void *p)
+{
+    struct monitor *m = p;
+
+    GAM_DEBUG (DEBUG_INFO, "%s (%s)\n", __FUNCTION__, m->path);
+    g_free (m->path);
+
+    assert (! m->subs);
+    assert (! m->children);
+}
+
+/* Emit an event.  */
+static void
+monitor_emit (struct monitor *m, const char *item, GaminEventType event)
+{
+    if (event == GAMIN_EVENT_UNKNOWN)
+	return;
+
+    GAM_DEBUG (DEBUG_INFO, "%s: emitting event %s for `%s' on `%s'\n",
+	       __FUNCTION__, gam_event_to_string(event), item, m->path);
+
+    gam_server_emit_event (item, 0, event, m->subs, 0);
+}
+
+/* Directory changed callback.  */
+error_t
+dir_changed (fs_notify_t notify_port,
+	     natural_t tickno,
+	     dir_changed_type_t change,
+	     string_t name)
+{
+    error_t err;
+    struct monitor *m;
+    struct monitor *child;
+
+    mutex_lock (&lock);
+
+    m = ports_lookup_port (port_bucket, notify_port, monitor_portclass);
+    if (! m) {
+	mutex_unlock (&lock);
+	return EINVAL;
+    }
+
+    switch (change) {
+    case DIR_CHANGED_NULL:
+	GAM_DEBUG (DEBUG_INFO, "%s (%s): DIR_CHANGED_NULL\n",
+		   __FUNCTION__, m->path);
+	break;
+
+    case DIR_CHANGED_NEW:
+	GAM_DEBUG (DEBUG_INFO, "%s (%s): DIR_CHANGED_NEW: `%s'\n",
+		   __FUNCTION__, m->path, name);
+
+	monitor_emit (m, name, GAMIN_EVENT_CREATED);
+
+	child = g_hash_table_lookup (m->children, name);
+	if (child) {
+	    err = monitor_watch (child);
+	    if (! err) {
+		monitor_emit (child, child->path, GAMIN_EVENT_CREATED);
+	    }
+	}
+	break;
+
+    case DIR_CHANGED_UNLINK:
+	GAM_DEBUG (DEBUG_INFO, "%s (%s): DIR_CHANGED_UNLINK: `%s'\n",
+		   __FUNCTION__, m->path, name);
+
+	if (name[0] == '.' && (name[1] == '\0'
+			       || (name[1] == '.' && name[2] == '\0')))
+	    /* Ignore `.' and `..'.  */
+	    break;
+
+	monitor_emit (m, name, GAMIN_EVENT_DELETED);
+
+	child = g_hash_table_lookup (m->children, name);
+	if (child) {
+	    monitor_unwatch (child);
+	    monitor_emit (child, child->path, GAMIN_EVENT_DELETED);
+	}
+	break;
+
+    case DIR_CHANGED_RENUMBER:
+	GAM_DEBUG (DEBUG_INFO, "%s (%s): DIR_CHANGED_RENUMBER: `%s'\n",
+		   __FUNCTION__, m->path, name);
+	monitor_emit (m, name, GAMIN_EVENT_CHANGED);
+	break;
+
+    default:
+	GAM_DEBUG (DEBUG_INFO, "%s (%s): unknown\n", __FUNCTION__, m->path);
+	break;
+    }
+
+    mutex_unlock (&lock);
+
+    ports_port_deref (m);
+    return 0;
+}
+
+/* File changed callback.  */
+error_t
+file_changed (fs_notify_t notify_port,
+	      natural_t tickno,
+	      file_changed_type_t change,
+	      loff_t start,
+	      loff_t end)
+{
+    struct monitor *m;
+
+    mutex_lock (&lock);
+
+    m = ports_lookup_port (port_bucket, notify_port, monitor_portclass);
+    if (! m) {
+	mutex_unlock (&lock);
+	return EINVAL;
+    }
+
+    switch (change) {
+    case FILE_CHANGED_NULL:
+	GAM_DEBUG (DEBUG_INFO, "%s (%s): FILE_CHANGED_NULL\n",
+		   __FUNCTION__, m->path);
+	break;
+
+    case FILE_CHANGED_WRITE:
+	GAM_DEBUG (DEBUG_INFO, "%s (%s): FILE_CHANGED_WRITE\n",
+		   __FUNCTION__, m->path);
+	monitor_emit (m, m->path, GAMIN_EVENT_CHANGED);
+	break;
+
+    case FILE_CHANGED_EXTEND:
+	GAM_DEBUG (DEBUG_INFO, "%s (%s): FILE_CHANGED_EXTEND\n",
+		   __FUNCTION__, m->path);
+	monitor_emit (m, m->path, GAMIN_EVENT_CHANGED);
+	break;
+
+    case FILE_CHANGED_TRUNCATE:
+	GAM_DEBUG (DEBUG_INFO, "%s (%s): FILE_CHANGED_TRUNCATE\n",
+		   __FUNCTION__, m->path);
+	monitor_emit (m, m->path, GAMIN_EVENT_CHANGED);
+	break;
+
+    case FILE_CHANGED_META:
+	GAM_DEBUG (DEBUG_INFO, "%s (%s): FILE_CHANGED_META\n",
+		   __FUNCTION__, m->path);
+	monitor_emit (m, m->path, GAMIN_EVENT_CHANGED);
+	break;
+
+    default:
+	GAM_DEBUG (DEBUG_INFO, "%s (%s): unknown\n", __FUNCTION__, m->path);
+	break;
+    }
+
+    mutex_unlock (&lock);
+
+    ports_port_deref (m);
+    return 0;
+}
+
+/* The server loop: waits for messages from the file systems.  */
+static void *
+server (void *bucket)
+{
+  extern boolean_t fs_notify_server (mach_msg_header_t *in,
+				     mach_msg_header_t *out);
+
+  int s (mach_msg_header_t *in, mach_msg_header_t *out)
+      {
+	  return fs_notify_server (in, out)
+	      || ports_notify_server (in, out);
+      }
+
+  while (1)
+    ports_manage_port_operations_one_thread (bucket, s, 0);
+}
+
+/* If ADD is true, add the subscription SUB, otherwise, remove
+   it.  LOCK must be held.  */
+static void
+gam_hurd_notify_add_rm_handler(const char *path,
+			       GamSubscription *sub, gboolean add)
+{
+    struct monitor *m;
+
+    assert (! mutex_try_lock (&lock));
+
+    if (add) {
+	/* Add subscription SUB to the monitor watching PATH.  */
+
+	DIR *dir;
+
+	if (gam_subscription_is_dir (sub)) {
+	    dir = opendir (path);
+	    if (dir) {
+		GAM_DEBUG(DEBUG_INFO, "%s: `%s' is a directory\n",
+			  __FUNCTION__, path);
+	    } else {
+		/* What was the problem?  */
+		if (errno != ENOTDIR && errno != ENOENT) {
+		    /* Fatal error.  */
+		    GAM_DEBUG(DEBUG_INFO, "%s: opening `%s': %s\n",
+			      __FUNCTION__, path, strerror (errno));
+		    return;
+		}
+	    }
+	} else
+	    dir = NULL;
+
+	/* Create a new monitor.  */
+	m = monitor_create (path);
+	if (m) {
+	    /* Add the subscription.  The monitor comes with a
+	       reference.  */
+	    m->subs = g_list_prepend(m->subs, sub);
+
+	    GAM_DEBUG(DEBUG_INFO, "%s: created monitor for `%s'\n",
+		      __FUNCTION__, path);
+	} else {
+	    GAM_DEBUG(DEBUG_INFO,
+		      "%s: failed to create monitor for `%s': %s\n",
+		      __FUNCTION__, path, strerror (errno));
+	    if (dir)
+		closedir (dir);
+	    return;
+	}
+
+	/* According to the FAM documentation: "[w]hen the application
+	   requests that a file be monitored, FAM generates a
+	   FAMExists event for that file (if it exists). When the
+	   application requests that a directory be monitored, FAM
+	   generates a FAMExists event for that directory (if it
+	   exists) and every file contained in that directory."  */
+	monitor_emit (m, m->path,
+		      m->fd == -1 ? GAMIN_EVENT_DELETED : GAMIN_EVENT_EXISTS);
+	if (dir) {
+	    union
+	    {
+		struct dirent d;
+		char b[offsetof (struct dirent, d_name) + NAME_MAX + 1];
+	    } u;
+	    struct dirent *res;
+
+	    while (readdir_r (dir, &u.d, &res) == 0) {
+		if (! res)
+		    break;
+
+		if (res->d_name[0] == '.'
+		    && (res->d_name[1] == '\0'
+			|| (res->d_name[1] == '.' && res->d_name[2] == '\0')))
+		    /* Skip `.' and `..'.  */
+		    continue;
+
+		monitor_emit (m, res->d_name, GAMIN_EVENT_EXISTS);
+	    }
+	    closedir (dir);
+	}
+	monitor_emit (m, m->path, GAMIN_EVENT_ENDEXISTS);
+    } else {
+	/* Remove subscription SUB from the monitor watching PATH.  */
+
+        m = g_hash_table_lookup (path_hash, path);
+        if (!m) {
+	    GAM_DEBUG(DEBUG_INFO, "%s: request to remove subscription to "
+		      "`%s' but no monitor found!\n",
+		      __FUNCTION__, path);
+            return;
+        }
+
+	if (g_list_find (m->subs, sub)) {
+	    GAM_DEBUG(DEBUG_INFO,
+		      "%s: removed subscription from `%s' monitor (%d)\n",
+		      __FUNCTION__, path, m->port_info.refcnt);
+
+	    m->subs = g_list_remove_all (m->subs, sub);
+	    monitor_consider (m);
+	}
+    }
+}
+
+static int have_consume_idler;
+
+/* Called by glib's idle handler.  Add any subscriptions on NEW_SUBS
+   and remove any subscriptions on REMOVED_SUBS.  */
+static gboolean
+gam_hurd_notify_consume_subscriptions_real(gpointer data)
+{
+    GList *subs, *l;
+	
+    mutex_lock (&lock);
+
+    /* Pending additions.  */
+    subs = new_subs;
+    new_subs = NULL;
+    for (l = subs; l; l = l->next) {
+	GamSubscription *sub = l->data;
+	GAM_DEBUG(DEBUG_INFO, "%s: adding `%s'\n",
+		  __FUNCTION__, gam_subscription_get_path (sub));
+	gam_hurd_notify_add_rm_handler (gam_subscription_get_path (sub),
+					sub, TRUE);
+    }
+
+    /* Pending removals.  */
+    subs = removed_subs;
+    removed_subs = NULL;
+    for (l = subs; l; l = l->next) {
+	GamSubscription *sub = l->data;
+	GAM_DEBUG(DEBUG_INFO, "%s: removing `%s'\n",
+		  __FUNCTION__, gam_subscription_get_path (sub));
+	gam_hurd_notify_add_rm_handler (gam_subscription_get_path (sub),
+					sub, FALSE);
+    }
+
+    GAM_DEBUG(DEBUG_INFO, "%s done\n", __FUNCTION__);
+
+    have_consume_idler = FALSE;
+
+    mutex_unlock (&lock);
+    return FALSE;
+}
+
+/* Register the real adder and remover of subscriptions callback to be
+   called by glib's idle thread.  LOCK must be held.  */
+static void
+gam_hurd_notify_consume_subscriptions(void)
+{
+    if (! have_consume_idler) {
+	GSource *source;
+
+	have_consume_idler = TRUE;
+
+	source = g_idle_source_new ();
+	g_source_set_callback (source,
+			       gam_hurd_notify_consume_subscriptions_real,
+			       NULL, NULL);
+	g_source_attach (source, NULL);
+    }
+}
+
+/**
+ * @defgroup hurd notify backend
+ * @ingroup Backends
+ * @brief hurd notify backend API
+ *
+ * Since version 1991, the Hurd has included the fs_notify interface.
+ * This backend uses fs_notify to know when files are
+ * changed/created/deleted.
+ *
+ * @{
+ */
+
+extern gboolean gam_hurd_notify_add_subscription(GamSubscription * sub);
+extern gboolean gam_hurd_notify_remove_subscription(GamSubscription * sub);
+extern gboolean gam_hurd_notify_remove_all_for(GamListener * listener);
+
+/**
+ * Initializes the hurd notify system.  This must be called before any
+ * other functions in this module.
+ *
+ * @returns TRUE if initialization succeeded, FALSE otherwise
+ */
+gboolean
+gam_hurd_notify_init(void)
+{
+    path_hash = g_hash_table_new(g_str_hash, g_str_equal);
+
+    port_bucket = ports_create_bucket ();
+    if (! port_bucket) {
+	GAM_DEBUG(DEBUG_INFO, "Could not create port bucket\n");
+        return FALSE;
+    }
+
+    monitor_portclass = ports_create_class (monitor_clean, NULL);
+    if (! monitor_portclass) {
+	GAM_DEBUG(DEBUG_INFO, "Could not create port class\n");
+        return FALSE;
+    }
+
+    /* Launch the monitor server.  */
+    cthread_detach (cthread_fork (server, port_bucket));
+
+    GAM_DEBUG (DEBUG_INFO, "hurd notify initialized\n");
+
+    gam_backend_add_subscription = gam_hurd_notify_add_subscription;
+    gam_backend_remove_subscription = gam_hurd_notify_remove_subscription;
+    gam_backend_remove_all_for = gam_hurd_notify_remove_all_for;
+
+    return TRUE;
+}
+  
+/**
+ * Adds a subscription to be monitored.
+ *
+ * @param sub a #GamSubscription to be polled
+ * @returns TRUE if adding the subscription succeeded, FALSE otherwise
+ */
+gboolean
+gam_hurd_notify_add_subscription(GamSubscription * sub)
+{
+    gam_listener_add_subscription(gam_subscription_get_listener(sub), sub);
+
+    mutex_lock (&lock);
+    new_subs = g_list_prepend(new_subs, sub);
+
+    GAM_DEBUG(DEBUG_INFO, "%s\n", __FUNCTION__);
+
+    gam_hurd_notify_consume_subscriptions();
+    mutex_unlock (&lock);
+
+    return TRUE;
+}
+
+/**
+ * Removes a subscription which was being monitored.
+ *
+ * @param sub a #GamSubscription to remove
+ * @returns TRUE if removing the subscription succeeded, FALSE otherwise
+ */
+gboolean
+gam_hurd_notify_remove_subscription(GamSubscription * sub)
+{
+    mutex_lock (&lock);
+    if (g_list_find(new_subs, sub)) {
+	GAM_DEBUG(DEBUG_INFO,
+		  "%s: subscription `%s' removed from new_subs list\n",
+		  __FUNCTION__, gam_subscription_get_path (sub));
+
+	new_subs = g_list_remove_all (new_subs, sub);
+	mutex_unlock (&lock);
+	return TRUE;
+    }
+    mutex_unlock (&lock);
+
+    GAM_DEBUG(DEBUG_INFO, "%s: adding `%s' to removed_subs for removal\n",
+	      __FUNCTION__, gam_subscription_get_path (sub));
+
+    gam_subscription_cancel (sub);
+    gam_listener_remove_subscription(gam_subscription_get_listener(sub), sub);
+
+    mutex_lock (&lock);
+    removed_subs = g_list_prepend (removed_subs, sub);
+    gam_hurd_notify_consume_subscriptions();
+    mutex_unlock (&lock);
+
+    return TRUE;
+}
+
+/**
+ * Stop monitoring all subscriptions for a given listener.
+ *
+ * @param listener a #GamListener
+ * @returns TRUE if removing the subscriptions succeeded, FALSE otherwise
+ */
+gboolean
+gam_hurd_notify_remove_all_for(GamListener * listener)
+{
+    GList *subs, *l;
+
+    subs = gam_listener_get_subscriptions (listener);
+    if (! subs)
+	return FALSE;
+
+    for (l = subs; l; l = l->next) {
+	GamSubscription *sub = l->data;
+	g_assert (sub != NULL);
+	gam_hurd_notify_remove_subscription (sub);
+    }
+
+    g_list_free (subs);
+    return TRUE;
+}
+
+/** @} */
+
+
+/*
+   Local Variables:
+   c-basic-offset: 4
+   End:
+*/
diff -urN gamin-0.0.26-upstream/server/gam_hurd_mach_notify.h gamin-0.0.26/server/gam_hurd_mach_notify.h
--- gamin-0.0.26-upstream/server/gam_hurd_mach_notify.h	1970-01-01 01:00:00.000000000 +0100
+++ gamin-0.0.26/server/gam_hurd_mach_notify.h	2005-06-05 14:24:42.000000000 +0100
@@ -0,0 +1,13 @@
+
+#ifndef __MD_HURD_MACH_NOTIFY_H__
+#define __MD_HURD_MACH_NOTIFY_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+gboolean   gam_hurd_notify_init                  (void);
+
+G_END_DECLS
+
+#endif /* __MD_HURD_MACH_NOTIFY_H__ */
diff -urN gamin-0.0.26-upstream/server/gam_server.c gamin-0.0.26/server/gam_server.c
--- gamin-0.0.26-upstream/server/gam_server.c	2004-12-02 17:42:56.000000000 +0000
+++ gamin-0.0.26/server/gam_server.c	2005-06-06 14:39:24.000000000 +0100
@@ -39,6 +39,9 @@
 #ifdef ENABLE_DNOTIFY
 #include "gam_dnotify.h"
 #endif
+#ifdef ENABLE_HURD_MACH_NOTIFY
+#include "gam_hurd_mach_notify.h"
+#endif
 #include "gam_excludes.h"
 
 static int poll_only = 0;
@@ -90,6 +93,12 @@
 	    return(TRUE);
 	}
 #endif
+#ifdef ENABLE_HURD_MACH_NOTIFY
+	if (gam_hurd_notify_init()) {
+	    GAM_DEBUG(DEBUG_INFO, "Using Hurd Notify as backend\n");
+	    return(TRUE);
+	}
+#endif	
     }
     if (gam_poll_init()) {
 	GAM_DEBUG(DEBUG_INFO, "Using Poll as backend\n");

--twz1s1Hj1O0rHoT0--

---------------------------------------
Received: (at 312369-close) by bugs.debian.org; 13 Jun 2005 19:53:42 +0000
>From katie@ftp-master.debian.org Mon Jun 13 12:53:42 2005
Return-path: <katie@ftp-master.debian.org>
Received: from newraff.debian.org [208.185.25.31] (mail)
	by spohr.debian.org with esmtp (Exim 3.35 1 (Debian))
	id 1Dhv0A-00037F-00; Mon, 13 Jun 2005 12:53:42 -0700
Received: from katie by newraff.debian.org with local (Exim 3.35 1 (Debian))
	id 1DhuuN-0007yQ-00; Mon, 13 Jun 2005 15:47:43 -0400
From: Sjoerd Simons <sjoerd@debian.org>
To: 312369-close@bugs.debian.org
X-Katie: $Revision: 1.56 $
Subject: Bug#312369: fixed in gamin 0.1.1-1
Message-Id: <E1DhuuN-0007yQ-00@newraff.debian.org>
Sender: Archive Administrator <katie@ftp-master.debian.org>
Date: Mon, 13 Jun 2005 15:47:43 -0400
Delivered-To: 312369-close@bugs.debian.org
X-Spam-Checker-Version: SpamAssassin 2.60-bugs.debian.org_2005_01_02 
	(1.212-2003-09-23-exp) on spohr.debian.org
X-Spam-Status: No, hits=-6.0 required=4.0 tests=BAYES_00,HAS_BUG_NUMBER 
	autolearn=no version=2.60-bugs.debian.org_2005_01_02
X-Spam-Level: 

Source: gamin
Source-Version: 0.1.1-1

We believe that the bug you reported is fixed in the latest version of
gamin, which is due to be installed in the Debian FTP archive:

gamin_0.1.1-1.diff.gz
  to pool/main/g/gamin/gamin_0.1.1-1.diff.gz
gamin_0.1.1-1.dsc
  to pool/main/g/gamin/gamin_0.1.1-1.dsc
gamin_0.1.1-1_powerpc.deb
  to pool/main/g/gamin/gamin_0.1.1-1_powerpc.deb
gamin_0.1.1.orig.tar.gz
  to pool/main/g/gamin/gamin_0.1.1.orig.tar.gz
libgamin-dev_0.1.1-1_powerpc.deb
  to pool/main/g/gamin/libgamin-dev_0.1.1-1_powerpc.deb
libgamin0_0.1.1-1_powerpc.deb
  to pool/main/g/gamin/libgamin0_0.1.1-1_powerpc.deb
python2.3-gamin_0.1.1-1_powerpc.deb
  to pool/main/g/gamin/python2.3-gamin_0.1.1-1_powerpc.deb



A summary of the changes between this version and the previous one is
attached.

Thank you for reporting the bug, which will now be closed.  If you
have further comments please address them to 312369@bugs.debian.org,
and the maintainer will reopen the bug report if appropriate.

Debian distribution maintenance software
pp.
Sjoerd Simons <sjoerd@debian.org> (supplier of updated gamin package)

(This message was generated automatically at their request; if you
believe that there is a problem with it please contact the archive
administrators by mailing ftpmaster@debian.org)


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Format: 1.7
Date: Mon, 13 Jun 2005 20:58:28 +0200
Source: gamin
Binary: gamin python2.3-gamin libgamin0 libgamin-dev
Architecture: source powerpc
Version: 0.1.1-1
Distribution: unstable
Urgency: low
Maintainer: Debian GNOME Maintainers <pkg-gnome-maintainers@lists.alioth.debian.org>
Changed-By: Sjoerd Simons <sjoerd@debian.org>
Description: 
 gamin      - File and directory monitoring system
 libgamin-dev - Development files for the gamin client library
 libgamin0  - Client library for the gamin file and directory monitoring system
 python2.3-gamin - Python binding for the gamin client library
Closes: 312369
Changes: 
 gamin (0.1.1-1) unstable; urgency=low
 .
   * New upstream release
     + Includes native hurd support (Closes: #312369)
Files: 
 c595ca7f6c28d8983f13bcb9cd3cf189 1537 admin optional gamin_0.1.1-1.dsc
 5c5330c3df26ece7d71b69a0b8f4a126 512316 admin optional gamin_0.1.1.orig.tar.gz
 d4312c1bea45190e783f345a53987fba 2846 admin optional gamin_0.1.1-1.diff.gz
 d11901e6b44e01dd63d7757defa6f025 41292 admin optional gamin_0.1.1-1_powerpc.deb
 89bfad677673faabf7369ad46e28a04b 28680 libs optional libgamin0_0.1.1-1_powerpc.deb
 996772f8de523e9ed091c50654d38f1e 46596 libdevel optional libgamin-dev_0.1.1-1_powerpc.deb
 7d9fa880e42747b17653795ea4a3bdcd 22298 python optional python2.3-gamin_0.1.1-1_powerpc.deb

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFCrdqVgTd+SodosdIRAvRRAKCq5+1GnSAW2FMIQB/sHYSclu9QBQCgyIBh
skqLr33Sn2pm33hbfrdAdWk=
=TFTJ
-----END PGP SIGNATURE-----