[gamin] [PATCH] Add legacy INotify backend



Hi,

Not really tested that well, but more for comment if upstream will be
interested ...

Basically add a inotify legacy support backend, disabled by default.  I
think however the HAVE_INOTIFY_IOCTL_MAGIC stuff might be considered if
the rest is not, as it should not try to compile the new backend against
system linux/inotify.h if old version.


Regards,

-- 
Martin Schlemmer

Add support for INotify Legacy backend (pre 0.24)

diff -urpN gamin-0.1.2/configure.in gamin-0.1.2.az/configure.in
--- gamin-0.1.2/configure.in	2005-07-13 13:10:43.000000000 +0200
+++ gamin-0.1.2.az/configure.in	2005-07-16 09:23:22.000000000 +0200
@@ -225,16 +225,41 @@ dnl check if inotify backend is enabled
 AM_CONDITIONAL(ENABLE_INOTIFY, test x$inotify = xtrue)
 
 if test x$inotify = xtrue; then
-	AC_CHECK_HEADERS(linux/inotify.h)
+	AC_CHECK_HEADERS(linux/inotify.h,
+	[AC_CHECK_DECL(INOTIFY_IOCTL_MAGIC,
+	 [AC_DEFINE(HAVE_INOTIFY_IOCTL_MAGIC,1,[Have legacy linux/inotify.h])],
+	 [],[#include <linux/inotify.h>])])
 	AC_DEFINE(ENABLE_INOTIFY,1,[Use inotify as backend])
 	backends="${backends}, inotify"
 fi
 
+if test x$os = xlinux-gnu; then
+	AC_ARG_ENABLE(inotify-legacy,
+	[  --enable-inotify-legacy Enable the INotify Legacy backend],
+	[case "${enableval}" in
+	  yes) inotify_legacy=true ;;
+	  no) inotify_legacy=false;;
+	  *) AC_MSG_ERROR(bad value ${enableval} for --enable-inotify-legacy) ;;
+	esac],[inotify_legacy=false])
+fi
+
+dnl check if inotify legacy backend is enabled
+AM_CONDITIONAL(ENABLE_INOTIFY_LEGACY, test x$inotify_legacy = xtrue)
+
+if test x$inotify_legacy = xtrue; then
+	AC_CHECK_HEADERS(linux/inotify.h,
+	[AC_CHECK_DECL(INOTIFY_IOCTL_MAGIC,
+	 [AC_DEFINE(HAVE_INOTIFY_IOCTL_MAGIC,1,[Have legacy linux/inotify.h])],
+	 [],[#include <linux/inotify.h>])])
+	AC_DEFINE(ENABLE_INOTIFY_LEGACY,1,[Use inotify legacy as backend])
+	backends="${backends}, inotify_legacy"
+fi
+
 if test x$os != xBogusOS; then
     	AC_CHECK_FUNC(kevent,[have_kevent=1],)
 	if test x$have_kevent = x1 ; then
 	    AC_ARG_ENABLE(kqueue,
-            [ --disable-kqueue Disable the KQueue backend],
+            [  --disable-kqueue Disable the KQueue backend],
 	    [case "${enableval}" in
 	      yes) kqueue=true ;;
 	      no) kqueue=false ;;
diff -urpN gamin-0.1.2/server/Makefile.am gamin-0.1.2.az/server/Makefile.am
--- gamin-0.1.2/server/Makefile.am	2005-06-08 23:48:00.000000000 +0200
+++ gamin-0.1.2.az/server/Makefile.am	2005-07-16 09:26:06.000000000 +0200
@@ -38,6 +38,7 @@ gam_server_SOURCES =					\
 	gam_excludes.c					\
 	gam_excludes.h					\
 	local_inotify.h					\
+	local_inotify_legacy.h				\
 	gam_debug_lists.c				\
 	server_config.h
 
@@ -45,6 +46,10 @@ if ENABLE_INOTIFY
 gam_server_SOURCES += gam_inotify.c gam_inotify.h
 endif
 
+if ENABLE_INOTIFY_LEGACY
+gam_server_SOURCES += gam_inotify_legacy.c gam_inotify_legacy.h
+endif
+
 if ENABLE_DNOTIFY
 gam_server_SOURCES += gam_dnotify.c gam_dnotify.h
 endif
diff -urpN gamin-0.1.2/server/gam_inotify.c gamin-0.1.2.az/server/gam_inotify.c
--- gamin-0.1.2/server/gam_inotify.c	2005-07-12 23:15:19.000000000 +0200
+++ gamin-0.1.2.az/server/gam_inotify.c	2005-07-16 09:24:31.000000000 +0200
@@ -31,7 +31,7 @@
 #include <glib.h>
 #include "gam_error.h"
 #include "gam_poll.h"
-#ifdef HAVE_LINUX_INOTIFY_H
+#if defined(HAVE_LINUX_INOTIFY_H) && !defined(HAVE_INOTIFY_IOCTL_MAGIC)
 #include <linux/inotify.h>
 #else
 #include "local_inotify.h"
diff -urpN gamin-0.1.2/server/gam_inotify_legacy.c gamin-0.1.2.az/server/gam_inotify_legacy.c
--- gamin-0.1.2/server/gam_inotify_legacy.c	1970-01-01 02:00:00.000000000 +0200
+++ gamin-0.1.2.az/server/gam_inotify_legacy.c	2005-07-16 09:36:47.000000000 +0200
@@ -0,0 +1,611 @@
+/* gamin inotify_legacy backend
+ * Copyright (C) 2005 John McCutchan
+ *
+ * Based off of code,
+ * Copyright (C) 2003 James Willcox, Corey Bowers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include "server_config.h"
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <glib.h>
+#include "gam_error.h"
+#include "gam_poll.h"
+#if defined(HAVE_LINUX_INOTIFY_H) && defined(HAVE_INOTIFY_IOCTL_MAGIC)
+#include <linux/inotify.h>
+#else
+#include "local_inotify_legacy.h"
+#endif
+#include "gam_inotify_legacy.h"
+#include "gam_tree.h"
+#include "gam_event.h"
+#include "gam_server.h"
+#include "gam_event.h"
+#ifdef GAMIN_DEBUG_API
+#include "gam_debugging.h"
+#endif
+
+typedef struct {
+    char *path;
+    int wd;
+    int refcount;
+    GList *subs;
+    int busy;
+    gboolean deactivated;
+    int events;
+    int deactivated_events;
+} inotify_legacy_data_t;
+
+static GHashTable *path_hash = NULL;
+static GHashTable *wd_hash = NULL;
+
+G_LOCK_DEFINE_STATIC(inotify_legacy);
+
+static GIOChannel *inotify_legacy_read_ioc = NULL;
+
+static gboolean have_consume_idler = FALSE;
+
+static int inotify_legacy_device_fd = -1;
+
+static guint should_poll_mask = IN_MODIFY|IN_ATTRIB|IN_CLOSE_WRITE|IN_MOVED_FROM|IN_MOVED_TO|IN_DELETE|IN_CREATE|IN_DELETE_SELF|IN_UNMOUNT;
+
+static void 
+gam_inotify_legacy_data_debug (gpointer key, gpointer value, gpointer user_data)
+{
+    inotify_legacy_data_t *data = (inotify_legacy_data_t *)value;
+
+    if (!data)
+        return;
+
+    int deactivated = data->deactivated;
+
+    GAM_DEBUG(DEBUG_INFO, "isub wd %d refs %d busy %d deactivated %d events (%d:%d): %s\n", data->wd, data->refcount, data->busy, deactivated, data->events, data->deactivated_events, data->path);
+}
+
+void
+gam_inotify_legacy_debug(void)
+{
+    if (inotify_legacy_device_fd == -1)
+    {
+        GAM_DEBUG(DEBUG_INFO, "Inotify device not opened\n");
+        return;
+    }
+
+    if (path_hash == NULL)
+        return;
+
+    GAM_DEBUG(DEBUG_INFO, "Inotify device fd = %d\n", inotify_legacy_device_fd);
+    GAM_DEBUG(DEBUG_INFO, "Dumping inotify_legacy subscriptions\n");
+    g_hash_table_foreach (path_hash, gam_inotify_legacy_data_debug, NULL);
+}
+
+static void print_mask(int mask)
+{
+    if (mask & IN_ACCESS)
+    {
+        GAM_DEBUG(DEBUG_INFO, "ACCESS\n");
+    }
+    if (mask & IN_MODIFY)
+    {
+        GAM_DEBUG(DEBUG_INFO, "MODIFY\n");
+    }
+    if (mask & IN_ATTRIB)
+    {
+        GAM_DEBUG(DEBUG_INFO, "ATTRIB\n");
+    }
+    if (mask & IN_CLOSE_WRITE)
+    {
+        GAM_DEBUG(DEBUG_INFO, "CLOSE_WRITE\n");
+    }
+    if (mask & IN_CLOSE_NOWRITE)
+    {
+        GAM_DEBUG(DEBUG_INFO, "CLOSE_WRITE\n");
+    }
+    if (mask & IN_OPEN)
+    {
+        GAM_DEBUG(DEBUG_INFO, "OPEN\n");
+    }
+    if (mask & IN_MOVED_FROM)
+    {
+        GAM_DEBUG(DEBUG_INFO, "MOVE_FROM\n");
+    }
+    if (mask & IN_MOVED_TO)
+    {
+        GAM_DEBUG(DEBUG_INFO, "MOVE_TO\n");
+    }
+    if (mask & IN_DELETE)
+    {
+        GAM_DEBUG(DEBUG_INFO, "DELETE\n");
+    }
+    if (mask & IN_CREATE)
+    {
+        GAM_DEBUG(DEBUG_INFO, "CREATE_SUBDIR\n");
+    }
+    if (mask & IN_DELETE_SELF)
+    {
+        GAM_DEBUG(DEBUG_INFO, "DELETE_SELF\n");
+    }
+    if (mask & IN_UNMOUNT)
+    {
+        GAM_DEBUG(DEBUG_INFO, "UNMOUNT\n");
+    }
+    if (mask & IN_Q_OVERFLOW)
+    {
+        GAM_DEBUG(DEBUG_INFO, "Q_OVERFLOW\n");
+    }
+    if (mask & IN_IGNORED)
+    {
+        GAM_DEBUG(DEBUG_INFO, "IGNORED\n");
+    }
+}
+
+static inotify_legacy_data_t *
+gam_inotify_legacy_data_new(const char *path, int wd)
+{
+    inotify_legacy_data_t *data;
+
+    data = g_new0(inotify_legacy_data_t, 1);
+    data->path = g_strdup(path);
+    data->wd = wd;
+    data->busy = 0;
+    data->refcount = 1;
+    data->deactivated_events = 0;
+    data->events = 0;
+
+    return data;
+}
+
+static void
+gam_inotify_legacy_data_free(inotify_legacy_data_t * data)
+{
+    if (data->refcount != 0) 
+	GAM_DEBUG(DEBUG_INFO, "gam_inotify_legacy_data_free called with reffed data.\n");
+    g_free(data->path);
+    g_free(data);
+}
+
+static void
+gam_inotify_legacy_directory_handler_internal(const char *path, pollHandlerMode mode)
+{
+    inotify_legacy_data_t *data;
+    int path_fd, path_wd;
+    struct inotify_watch_request iwr;
+    switch (mode) {
+        case GAMIN_ACTIVATE:
+	    GAM_DEBUG(DEBUG_INFO, "Adding %s to inotify_legacy\n", path);
+	    break;
+        case GAMIN_DESACTIVATE:
+	    GAM_DEBUG(DEBUG_INFO, "Removing %s from inotify_legacy\n", path);
+	    break;
+	case GAMIN_FLOWCONTROLSTART:
+	    GAM_DEBUG(DEBUG_INFO, "inotify_legacy: Start flow control for %s\n", path);
+	    break;
+	case GAMIN_FLOWCONTROLSTOP:
+	    GAM_DEBUG(DEBUG_INFO, "inotify_legacy: Stop flow control for %s\n", path);
+	    break;
+	default:
+	    gam_error(DEBUG_INFO, "Unknown inotify_legacy operation %d for %s\n",
+	              mode, path);
+	    return;
+    }
+
+    G_LOCK(inotify_legacy);
+
+    if (mode == GAMIN_ACTIVATE) {
+
+        if ((data = g_hash_table_lookup(path_hash, path)) != NULL) {
+            data->refcount++;
+	    GAM_DEBUG(DEBUG_INFO, "  found incremented refcount: %d\n",
+	              data->refcount);
+            G_UNLOCK(inotify_legacy);
+#ifdef GAMIN_DEBUG_API
+            gam_debug_report(GAMinotifyChange, path, data->refcount);
+#endif
+            GAM_DEBUG(DEBUG_INFO, "inotify_legacy updated refcount\n");
+            return;
+        }
+
+        path_fd = open(path, O_RDONLY);
+
+        if (path_fd < 0) {
+            G_UNLOCK(inotify_legacy);
+            return;
+        }
+
+	iwr.fd = path_fd;
+	iwr.mask = should_poll_mask;
+	path_wd = ioctl (inotify_legacy_device_fd, INOTIFY_WATCH, &iwr);
+	close (path_fd);
+
+        data = gam_inotify_legacy_data_new(path, path_wd);
+        g_hash_table_insert(wd_hash, GINT_TO_POINTER(data->wd), data);
+        g_hash_table_insert(path_hash, data->path, data);
+
+        GAM_DEBUG(DEBUG_INFO, "activated inotify_legacy for %s\n", path);
+#ifdef GAMIN_DEBUG_API
+        gam_debug_report(GAMinotifyCreate, path, 0);
+#endif
+    } else if (mode == GAMIN_DESACTIVATE) {
+	data = g_hash_table_lookup(path_hash, path);
+
+	if (!data) {
+	    GAM_DEBUG(DEBUG_INFO, "  not found !!!\n");
+
+            G_UNLOCK(inotify_legacy);
+            return;
+	}
+
+        data->refcount--;
+        GAM_DEBUG(DEBUG_INFO, "inotify_legacy decremeneted refcount for %s\n",
+                  path);
+
+        if (data->refcount == 0) {
+	    int wd = data->wd;
+	    GAM_DEBUG(DEBUG_INFO, "removed inotify_legacy watch for %s\n", 
+                    data->path);
+	    g_hash_table_remove(path_hash, data->path);
+	    g_hash_table_remove(wd_hash, GINT_TO_POINTER(data->wd));
+	    gam_inotify_legacy_data_free(data);
+	    if (ioctl (inotify_legacy_device_fd, INOTIFY_IGNORE, &wd) < 0) {
+		GAM_DEBUG (DEBUG_INFO, "INOTIFY_IGNORE failed for %s (wd = %d)\n", data->path, data->wd);
+	    }
+#ifdef GAMIN_DEBUG_API
+	    gam_debug_report(GAMinotifyDelete, data->path, 0);
+#endif
+        } else {
+	    GAM_DEBUG(DEBUG_INFO, "  found decremented refcount: %d\n",
+	              data->refcount);
+#ifdef GAMIN_DEBUG_API
+            gam_debug_report(GAMinotifyChange, data->path, data->refcount);
+#endif
+	}
+    } else if ((mode == GAMIN_FLOWCONTROLSTART) ||
+               (mode == GAMIN_FLOWCONTROLSTOP)) {
+        data = g_hash_table_lookup(path_hash, path);
+        if (!data) {
+            GAM_DEBUG(DEBUG_INFO, "  not found !!!\n");
+
+            G_UNLOCK(inotify_legacy);
+            return;
+        }
+        if (data != NULL) {
+	    if (mode == GAMIN_FLOWCONTROLSTART) {
+		GAM_DEBUG(DEBUG_INFO, "inotify_legacy: GAMIN_FLOWCONTROLSTART for %s\n", data->path);
+		if (data->wd >= 0) {
+		    if (ioctl (inotify_legacy_device_fd, INOTIFY_IGNORE, &data->wd) < 0) {
+			GAM_DEBUG (DEBUG_INFO, "INOTIFY_IGNORE failed for %s (wd = %d)\n", data->path, data->wd);
+		    }
+		    data->deactivated = TRUE;
+		    GAM_DEBUG(DEBUG_INFO, "deactivated inotify_legacy for %s\n",
+			      data->path);
+#ifdef GAMIN_DEBUG_API
+		    gam_debug_report(GAMinotifyFlowOn, data->path, 0);
+#endif
+		}
+		data->busy++;
+	    } else {
+		GAM_DEBUG(DEBUG_INFO, "inotify_legacy: GAMIN_FLOWCONTROLSTOP for %s\n", data->path);
+	        if (data->busy > 0) {
+		    GAM_DEBUG(DEBUG_INFO, "inotify_legacy: data->busy > 0 for %s\n", data->path);
+		    data->busy--;
+		    if (data->busy == 0) {
+			GAM_DEBUG(DEBUG_INFO, "inotify_legacy: data->busy == 0 for %s\n", data->path);
+			path_fd = open(data->path, O_RDONLY);
+			if (path_fd < 0) {
+			    G_UNLOCK(inotify_legacy);
+			    GAM_DEBUG(DEBUG_INFO,
+			              "failed to reactivate inotify_legacy for %s\n",
+				      data->path);
+
+                            return;
+			}
+
+			iwr.fd = path_fd;
+			iwr.mask = should_poll_mask;
+			path_wd = ioctl (inotify_legacy_device_fd, INOTIFY_WATCH, &iwr);
+			close (path_fd);
+
+			/* Remove the old wd from the hash table */
+			g_hash_table_remove(wd_hash, GINT_TO_POINTER(data->wd));
+
+			data->wd = path_wd;
+			data->deactivated = FALSE;
+
+			/* Insert the new wd into the hash table */
+			g_hash_table_insert(wd_hash, GINT_TO_POINTER(data->wd),
+			                    data);
+			GAM_DEBUG(DEBUG_INFO, "reactivated inotify_legacy for %s\n",
+			          data->path);
+#ifdef GAMIN_DEBUG_API
+			gam_debug_report(GAMinotifyFlowOff, path, 0);
+#endif
+		    }
+		}
+	    }
+	}
+    } else {
+	GAM_DEBUG(DEBUG_INFO, "Unimplemented operation\n");
+    }
+
+    G_UNLOCK(inotify_legacy);
+}
+
+static void
+gam_inotify_legacy_directory_handler(const char *path, pollHandlerMode mode)
+{
+    GAM_DEBUG(DEBUG_INFO, "gam_inotify_legacy_directory_handler %s : %d\n",
+              path, mode);
+
+    gam_inotify_legacy_directory_handler_internal(path, mode);
+}
+
+static void
+gam_inotify_legacy_file_handler(const char *path, pollHandlerMode mode)
+{
+    GAM_DEBUG(DEBUG_INFO, "gam_inotify_legacy_file_handler %s : %d\n", path, mode);
+    
+    if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
+	gam_inotify_legacy_directory_handler_internal(path, mode);
+    } else {
+	GAM_DEBUG(DEBUG_INFO, " not a dir %s, FAILED!!!\n", path);
+    }
+}
+
+static void 
+gam_inotify_legacy_q_overflow (gpointer key, gpointer value, gpointer user_data)
+{
+    inotify_legacy_data_t *data = (inotify_legacy_data_t *)value;
+
+    gam_poll_scan_directory (data->path);
+}
+
+static gboolean
+gam_inotify_legacy_read_handler(gpointer user_data)
+{
+    char *buffer;
+    int buffer_size;
+    int events;
+    gsize buffer_i, read_size;
+
+    G_LOCK(inotify_legacy);
+
+    if (ioctl(inotify_legacy_device_fd, FIONREAD, &buffer_size) < 0) {
+	G_UNLOCK(inotify_legacy);
+	GAM_DEBUG(DEBUG_INFO, "inotify_legacy FIONREAD < 0. kaboom!\n");
+	return FALSE;
+    }
+
+    buffer = g_malloc(buffer_size);
+
+    if (g_io_channel_read_chars(inotify_legacy_read_ioc, (char *)buffer, buffer_size, &read_size, NULL) != G_IO_STATUS_NORMAL) {
+	G_UNLOCK(inotify_legacy);
+	GAM_DEBUG(DEBUG_INFO, "inotify_legacy failed to read events from inotify_legacy fd.\n");
+	g_free (buffer);
+	return FALSE;
+    }
+
+    buffer_i = 0;
+    events = 0;
+    while (buffer_i < read_size) {
+	struct inotify_event *event;
+	gsize event_size;
+	inotify_legacy_data_t *data;
+
+	event = (struct inotify_event *)&buffer[buffer_i];
+	event_size = sizeof(struct inotify_event) + event->len;
+
+	data = g_hash_table_lookup (wd_hash, GINT_TO_POINTER(event->wd));
+	if (!data) {
+	    GAM_DEBUG(DEBUG_INFO, "processing event: inotify_legacy can't find wd %d\n", event->wd);
+	} else if (data->deactivated) {
+	    GAM_DEBUG(DEBUG_INFO, "inotify_legacy: ignoring event on temporarily deactivated watch %s\n", data->path);
+            data->deactivated_events++;
+	} else {
+	    if (event->mask == IN_IGNORED) {
+		GList *l;
+
+		GAM_DEBUG(DEBUG_INFO, "inotify_legacy: IN_IGNORE on wd=%d\n", event->wd);
+		GAM_DEBUG(DEBUG_INFO, "inotify_legacy: removing all subscriptions for %s\n", data->path);
+
+                data->events++;
+
+		l = data->subs;
+		data->subs = NULL;
+		for (l = l; l; l = l->next) {
+		    GamSubscription *sub = l->data;
+		    gam_inotify_legacy_remove_subscription (sub);
+		}
+	    } else if (event->mask != IN_Q_OVERFLOW) {
+		if (event->mask & should_poll_mask) {
+		    GAM_DEBUG(DEBUG_INFO, "inotify_legacy requesting poll for %s\n", data->path);
+		    GAM_DEBUG(DEBUG_INFO, "poll was requested for event = ");
+		    print_mask (event->mask);
+                    data->events++;
+		    gam_poll_scan_directory (data->path);
+		}
+	    } else if (event->mask == IN_Q_OVERFLOW) {
+		    GAM_DEBUG(DEBUG_INFO, "inotify_legacy queue over flowed, requesting poll on all watched paths\n");
+                    g_hash_table_foreach (path_hash, gam_inotify_legacy_q_overflow, NULL);
+	    }
+	}
+
+        buffer_i += event_size;
+	events++;
+    }
+    GAM_DEBUG(DEBUG_INFO, "inotify_legacy recieved %d events\n", events);
+
+    g_free(buffer);
+    G_UNLOCK(inotify_legacy);
+
+    return TRUE;
+}
+
+
+static gboolean
+gam_inotify_legacy_consume_subscriptions_real(gpointer data)
+{
+    GAM_DEBUG(DEBUG_INFO, "gam_inotify_legacy_consume_subscriptions_real()\n");
+    gam_poll_consume_subscriptions();
+    have_consume_idler = FALSE;
+    return FALSE;
+}
+
+static void
+gam_inotify_legacy_consume_subscriptions(void)
+{
+    GSource *source;
+
+    if (have_consume_idler)
+        return;
+
+    GAM_DEBUG(DEBUG_INFO, "gam_inotify_legacy_consume_subscriptions()\n");
+    have_consume_idler = TRUE;
+    source = g_idle_source_new();
+    g_source_set_callback(source, gam_inotify_legacy_consume_subscriptions_real,
+                          NULL, NULL);
+    g_source_attach(source, NULL);
+}
+
+/**
+ * @defgroup inotify_legacy inotify_legacy Backend
+ * @ingroup Backends
+ * @brief inotify_legacy backend API
+ *
+ * Since version 2.6.X, Linux kernels have included the Linux Inode
+ * Notification system (inotify_legacy).  This backend uses inotify_legacy to know when
+ * files are changed/created/deleted.  Since inotify_legacy can't watch files/dirs that
+ * don't exist we still have to cache stat() information. For this,
+ * we can just use the code in the polling backend.
+ *
+ * @{
+ */
+
+
+/**
+ * Initializes the inotify_legacy backend.  This must be called before
+ * any other functions in this module.
+ *
+ * @returns TRUE if initialization succeeded, FALSE otherwise
+ */
+gboolean
+gam_inotify_legacy_init(void)
+{
+    GSource *source;
+
+    g_return_val_if_fail(gam_poll_init_full(FALSE), FALSE);
+
+    inotify_legacy_device_fd = open("/dev/inotify", O_RDONLY);
+
+    if (inotify_legacy_device_fd < 0) {
+        GAM_DEBUG(DEBUG_INFO, "Could not open /dev/inotify\n");
+        return FALSE;
+    }
+
+    inotify_legacy_read_ioc = g_io_channel_unix_new(inotify_legacy_device_fd);
+
+    /* For binary data */
+    g_io_channel_set_encoding(inotify_legacy_read_ioc, NULL, NULL);
+    /* Non blocking */
+    g_io_channel_set_flags(inotify_legacy_read_ioc, G_IO_FLAG_NONBLOCK, NULL);
+
+    source = g_io_create_watch(inotify_legacy_read_ioc,
+			       G_IO_IN | G_IO_HUP | G_IO_ERR);
+    g_source_set_callback(source, gam_inotify_legacy_read_handler, NULL, NULL);
+
+    g_source_attach(source, NULL);
+
+    path_hash = g_hash_table_new(g_str_hash, g_str_equal);
+    wd_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
+    gam_poll_set_kernel_handler(gam_inotify_legacy_directory_handler,
+                                gam_inotify_legacy_file_handler,
+				GAMIN_K_INOTIFY);
+
+    GAM_DEBUG(DEBUG_INFO, "inotify_legacy initialized\n");
+
+    gam_backend_add_subscription = gam_inotify_legacy_add_subscription;
+    gam_backend_remove_subscription = gam_inotify_legacy_remove_subscription;
+    gam_backend_remove_all_for = gam_inotify_legacy_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_inotify_legacy_add_subscription(GamSubscription * sub)
+{
+    GAM_DEBUG(DEBUG_INFO, "gam_inotify_legacy_add_subscription\n");
+
+    if (!gam_poll_add_subscription(sub)) {
+        return FALSE;
+    }
+
+    gam_inotify_legacy_consume_subscriptions();
+
+    GAM_DEBUG(DEBUG_INFO, "gam_inotify_legacy_add_subscription: done\n");
+    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_inotify_legacy_remove_subscription(GamSubscription * sub)
+{
+    GAM_DEBUG(DEBUG_INFO, "gam_inotify_legacy_remove_subscription\n");
+
+    if (!gam_poll_remove_subscription(sub)) {
+        return FALSE;
+    }
+
+    gam_inotify_legacy_consume_subscriptions();
+
+    GAM_DEBUG(DEBUG_INFO, "gam_inotify_legacy_remove_subscription: done\n");
+    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_inotify_legacy_remove_all_for(GamListener * listener)
+{
+    if (!gam_poll_remove_all_for(listener)) {
+        return FALSE;
+    }
+
+    gam_inotify_legacy_consume_subscriptions();
+
+    return TRUE;
+}
+
+/** @} */
diff -urpN gamin-0.1.2/server/gam_inotify_legacy.h gamin-0.1.2.az/server/gam_inotify_legacy.h
--- gamin-0.1.2/server/gam_inotify_legacy.h	1970-01-01 02:00:00.000000000 +0200
+++ gamin-0.1.2.az/server/gam_inotify_legacy.h	2005-07-16 08:41:34.000000000 +0200
@@ -0,0 +1,18 @@
+#ifndef __GAM_INOTIFY_LEGACY_H__
+#define __GAM_INOTIFY_LEGACY_H__
+
+#include <glib.h>
+#include "gam_poll.h"
+#include "gam_subscription.h"
+
+G_BEGIN_DECLS
+
+gboolean   gam_inotify_legacy_init                  (void);
+gboolean   gam_inotify_legacy_add_subscription      (GamSubscription *sub);
+gboolean   gam_inotify_legacy_remove_subscription   (GamSubscription *sub);
+gboolean   gam_inotify_legacy_remove_all_for        (GamListener *listener);
+void       gam_inotify_legacy_debug                 (void); 
+
+G_END_DECLS
+
+#endif /* __GAM_INOTIFY_LEGACY_H__ */
diff -urpN gamin-0.1.2/server/gam_server.c gamin-0.1.2.az/server/gam_server.c
--- gamin-0.1.2/server/gam_server.c	2005-06-15 13:02:34.000000000 +0200
+++ gamin-0.1.2.az/server/gam_server.c	2005-07-16 08:44:19.000000000 +0200
@@ -36,6 +36,9 @@
 #ifdef ENABLE_INOTIFY
 #include "gam_inotify.h"
 #endif
+#ifdef ENABLE_INOTIFY_LEGACY
+#include "gam_inotify_legacy.h"
+#endif
 #ifdef ENABLE_DNOTIFY
 #include "gam_dnotify.h"
 #endif
@@ -85,6 +88,9 @@ gam_show_debug(void) {
 #ifdef ENABLE_INOTIFY
     gam_inotify_debug ();
 #endif
+#ifdef ENABLE_INOTIFY_LEGACY
+    gam_inotify_legacy_debug ();
+#endif
 #ifdef ENABLE_DNOTIFY
     gam_dnotify_debug ();
 #endif
@@ -110,6 +116,12 @@ gam_init_subscriptions(void)
 	    return(TRUE);
 	}
 #endif
+#ifdef ENABLE_INOTIFY_LEGACY
+	if (gam_inotify_legacy_init()) {
+	    GAM_DEBUG(DEBUG_INFO, "Using INotify Legacy as backend\n");
+	    return(TRUE);
+	}
+#endif
 #ifdef ENABLE_DNOTIFY
 	if (gam_dnotify_init()) {
 	    GAM_DEBUG(DEBUG_INFO, "Using DNotify as backend\n");
diff -urpN gamin-0.1.2/server/local_inotify_legacy.h gamin-0.1.2.az/server/local_inotify_legacy.h
--- gamin-0.1.2/server/local_inotify_legacy.h	1970-01-01 02:00:00.000000000 +0200
+++ gamin-0.1.2.az/server/local_inotify_legacy.h	2005-07-16 08:42:16.000000000 +0200
@@ -0,0 +1,124 @@
+/*
+ * Inode based directory notification for Linux
+ *
+ * Copyright (C) 2005 John McCutchan
+ */
+
+#ifndef _LINUX_INOTIFY_LEGACY_H
+#define _LINUX_INOTIFY_LEGACY_H
+
+#include <linux/types.h>
+
+/*
+ * struct inotify_event - structure read from the inotify device for each event
+ *
+ * When you are watching a directory, you will receive the filename for events
+ * such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd.
+ */
+struct inotify_event {
+	__s32		wd;		/* watch descriptor */
+	__u32		mask;		/* watch mask */
+	__u32		cookie;		/* cookie to synchronize two events */
+	__u32		len;		/* length (including nulls) of name */
+	char		name[0];	/* stub for possible name */
+};
+
+/*
+ * struct inotify_watch_request - represents a watch request
+ *
+ * Pass to the inotify device via the INOTIFY_WATCH ioctl
+ */
+struct inotify_watch_request {
+	int		fd;		/* fd of filename to watch */
+	__u32		mask;		/* event mask */
+};
+
+/* the following are legal, implemented events that user-space can watch for */
+#define IN_ACCESS		0x00000001	/* File was accessed */
+#define IN_MODIFY		0x00000002	/* File was modified */
+#define IN_ATTRIB		0x00000004	/* Metadata changed */
+#define IN_CLOSE_WRITE		0x00000008	/* Writtable file was closed */
+#define IN_CLOSE_NOWRITE	0x00000010	/* Unwrittable file closed */
+#define IN_OPEN			0x00000020	/* File was opened */
+#define IN_MOVED_FROM		0x00000040	/* File was moved from X */
+#define IN_MOVED_TO		0x00000080	/* File was moved to Y */
+#define IN_CREATE		0x00000100	/* Subfile was created */
+#define IN_DELETE		0x00000200	/* Subfile was deleted */
+#define IN_DELETE_SELF		0x00000400	/* Self was deleted */
+
+/* the following are legal events.  they are sent as needed to any watch */
+#define IN_UNMOUNT		0x00002000	/* Backing fs was unmounted */
+#define IN_Q_OVERFLOW		0x00004000	/* Event queued overflowed */
+#define IN_IGNORED		0x00008000	/* File was ignored */
+
+/* helper events */
+#define IN_CLOSE		(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) /* close */
+#define IN_MOVE			(IN_MOVED_FROM | IN_MOVED_TO) /* moves */
+
+/* special flags */
+#define IN_ISDIR		0x40000000	/* event occurred against dir */
+#define IN_ONESHOT		0x80000000	/* only send event once */
+
+/*
+ * All of the events - we build the list by hand so that we can add flags in
+ * the future and not break backward compatibility.  Apps will get only the
+ * events that they originally wanted.  Be sure to add new events here!
+ */
+#define IN_ALL_EVENTS	(IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \
+			 IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \
+			 IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF)
+
+#define INOTIFY_IOCTL_MAGIC	'Q'
+#define INOTIFY_IOCTL_MAXNR	2
+
+#define INOTIFY_WATCH  		_IOR(INOTIFY_IOCTL_MAGIC, 1, struct inotify_watch_request)
+#define INOTIFY_IGNORE 		_IOR(INOTIFY_IOCTL_MAGIC, 2, int)
+
+#ifdef __KERNEL__
+
+#include <linux/dcache.h>
+#include <linux/fs.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_INOTIFY
+
+extern void inotify_inode_queue_event(struct inode *, __u32, __u32,
+				      const char *);
+extern void inotify_dentry_parent_queue_event(struct dentry *, __u32, __u32,
+					      const char *);
+extern void inotify_unmount_inodes(struct list_head *);
+extern void inotify_inode_is_dead(struct inode *);
+extern u32 inotify_get_cookie(void);
+
+#else
+
+static inline void inotify_inode_queue_event(struct inode *inode,
+					     __u32 mask, __u32 cookie,
+					     const char *filename)
+{
+}
+
+static inline void inotify_dentry_parent_queue_event(struct dentry *dentry,
+						     __u32 mask, __u32 cookie,
+						     const char *filename)
+{
+}
+
+static inline void inotify_unmount_inodes(struct list_head *list)
+{
+}
+
+static inline void inotify_inode_is_dead(struct inode *inode)
+{
+}
+
+static inline u32 inotify_get_cookie(void)
+{
+	return 0;
+}
+
+#endif	/* CONFIG_INOTIFY */
+
+#endif	/* __KERNEL __ */
+
+#endif	/* _LINUX_INOTIFY_LEGACY_H */

Attachment: signature.asc
Description: This is a digitally signed message part



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