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