--- orig/ChangeLog	8 Aug 2005 09:30:22 -0000	1.2532
+++ mod/ChangeLog	10 Aug 2005 19:04:40 -0000
@@ -1,3 +1,14 @@
+2005-08-10 20:00  Johannes Berg <johannes@sipsolutions.net>
+	* src/lib/ioloop.h: remove IO_*_NOTIFY flags to io_add
+	  in favour of new function io_add_fs_notify that takes
+	  a pathname instead. Add internal IO_NOTIFY flag.
+	* src/lib/ioloop-internal.h: change prototype of
+	  io_loop_notify_add to take a pathname instead of an fd.
+	* src/lib/: ioloop-notify-dn.c  ioloop-notify-inotify.c
+	  ioloop-notify-none.c: implement the new io_loop_notify_add
+	  function, in the case of inotify with the new syscall
+	  API/ABI.
+
 2005-08-08 09:20  Timo Sirainen <tss@iki.fi>
 
 	* src/auth/: auth-stream.c, auth-stream.h: Accidentally committed
--- orig/configure.in	12 Jul 2005 15:40:33 -0000	1.209
+++ mod/configure.in	10 Aug 2005 19:04:41 -0000
@@ -366,21 +366,28 @@
     #include <sys/ioctl.h>
     #include <fcntl.h>
     #include <linux/inotify.h>
+    #include <linux/inotify-syscalls.h>
+    #include <stdio.h>
   ], [
-    struct inotify_watch_request req;
-    int wd, dev_fd;
+    int wd, fd;
     char * fn = "/tmp";
-    dev_fd = open ("/dev/inotify", O_RDONLY);
-    req.fd = open (fn, O_RDONLY);
-    if (req.fd < 0) return -1;
-    req.mask = IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO | IN_MODIFY | IN_ACCESS;
-    wd = ioctl (dev_fd, INOTIFY_WATCH, &req);
-    close(req.fd);
-    ioctl (dev_fd, INOTIFY_IGNORE, &wd);
+    
+    fd = inotify_init ();
+    if (fd < 0)
+      perror ("inotify_init");
+
+    wd = inotify_add_watch (fd, fn, IN_ALL_EVENTS);
+
+    if (wd < 0)
+      perror ("inotify_add_watch");
+
+    inotify_rm_watch (fd, wd);
+
+    close (fd);
   ], [
     AC_DEFINE(IOLOOP_NOTIFY_INOTIFY,, Use Linux inotify)
   ], [
-    AC_MSG_ERROR([inotify requested but not available, check for existence of <linux/inotify.h>])
+    AC_MSG_ERROR([inotify requested but not available, check for existence of <linux/inotify.h> and <linux/inotify-syscalls.h>])
     notify=none
   ])
 fi
--- orig/src/lib/ioloop-internal.h	12 Jul 2005 15:44:49 -0000	1.14
+++ mod/src/lib/ioloop-internal.h	10 Aug 2005 19:04:41 -0000
@@ -61,8 +61,7 @@
 void io_loop_notify_handler_init(struct ioloop *ioloop);
 void io_loop_notify_handler_deinit(struct ioloop *ioloop);
 
-struct io *io_loop_notify_add(struct ioloop *ioloop, int fd,
-			      enum io_condition condition,
+struct io *io_loop_notify_add(struct ioloop *ioloop, const char *path,
 			      io_callback_t *callback, void *context);
 void io_loop_notify_remove(struct ioloop *ioloop, struct io *io);
 
--- orig/src/lib/ioloop-notify-dn.c	12 Jul 2005 21:15:16 -0000	1.6
+++ mod/src/lib/ioloop-notify-dn.c	10 Aug 2005 19:04:41 -0000
@@ -58,16 +58,19 @@
 	}
 }
 
-struct io *io_loop_notify_add(struct ioloop *ioloop, int fd,
-			      enum io_condition condition,
+struct io *io_loop_notify_add(struct ioloop *ioloop, const char *path,
 			      io_callback_t *callback, void *context)
 {
 	struct ioloop_notify_handler_context *ctx =
 		ioloop->notify_handler_context;
 	struct io *io;
+	int fd;
 
-	if ((condition & IO_FILE_NOTIFY) != 0)
+	fd = open(path, O_RDONLY);
+	if (fd == -1) {
+		i_error("open() for dnotify failed: %m");
 		return NULL;
+	}
 
 	if (fcntl(fd, F_SETSIG, SIGRTMIN) < 0) {
 		if (errno == EINVAL) {
@@ -76,13 +79,14 @@
 			return NULL;
 		}
 		i_error("fcntl(F_SETSIG) failed: %m");
-		return FALSE;
+		return NULL;
 	}
 	if (fcntl(fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_RENAME |
 		  DN_MULTISHOT) < 0) {
 		i_error("fcntl(F_NOTIFY) failed: %m");
 		(void)fcntl(fd, F_SETSIG, 0);
-		return FALSE;
+		(void)close(fd);
+		return NULL;
 	}
 
 	if (ctx->event_io == NULL) {
@@ -92,7 +96,6 @@
 
 	io = p_new(ioloop->pool, struct io, 1);
 	io->fd = fd;
-        io->condition = condition;
 
 	io->callback = callback;
         io->context = context;
@@ -122,6 +125,8 @@
 		i_error("fcntl(F_NOTIFY, 0) failed: %m");
 	if (fcntl(io->fd, F_SETSIG, 0) < 0)
 		i_error("fcntl(F_SETSIG, 0) failed: %m");
+	if (close(io->fd))
+		i_error("close() failed: %m");
 
 	p_free(ioloop->pool, io);
 
--- orig/src/lib/ioloop-notify-inotify.c	12 Jul 2005 21:15:16 -0000	1.4
+++ mod/src/lib/ioloop-notify-inotify.c	10 Aug 2005 19:04:41 -0000
@@ -5,6 +5,7 @@
 
 #ifdef IOLOOP_NOTIFY_INOTIFY
 
+#include "fd-close-on-exec.h"
 #include "ioloop-internal.h"
 #include "buffer.h"
 #include "network.h"
@@ -14,6 +15,7 @@
 #include <fcntl.h>
 #include <sys/ioctl.h>
 #include <linux/inotify.h>
+#include <linux/inotify-syscalls.h>
 
 #define INITIAL_INOTIFY_BUFLEN (FILENAME_MAX + sizeof(struct inotify_event))
 #define MAXIMAL_INOTIFY_BUFLEN (32*1024)
@@ -87,33 +89,24 @@
 	while (event_read_next(ioloop)) ;
 }
 
-struct io *io_loop_notify_add(struct ioloop *ioloop, int fd,
-			      enum io_condition condition,
+struct io *io_loop_notify_add(struct ioloop *ioloop, const char *path,
 			      io_callback_t *callback, void *context)
 {
 	struct ioloop_notify_handler_context *ctx =
 		ioloop->notify_handler_context;
 	struct io *io;
-	struct inotify_watch_request req;
 	int watchdescriptor;
 
-	if ((condition & IO_FILE_NOTIFY) != 0)
-		return NULL;
-
 	if (ctx->disabled)
 		return NULL;
 
-	/* now set up the notification request and shoot it off */
-	req.fd = fd;
-	req.mask = IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE | IN_MODIFY;
-	watchdescriptor = ioctl(ctx->inotify_fd, INOTIFY_WATCH, &req);
+	watchdescriptor = inotify_add_watch(ctx->inotify_fd, path, IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE | IN_MODIFY);
 	
 	if (watchdescriptor < 0) {
 		ctx->disabled = TRUE;
-		i_error("ioctl(INOTIFY_WATCH) failed: %m");
+		i_error("inotify_add_watch failed: %m");
 		return NULL;
 	}
-	fd_close_on_exec(watchdescriptor, TRUE);
 
 	if (ctx->event_io == NULL) {
 		ctx->event_io = io_add(ctx->inotify_fd, IO_READ,
@@ -121,8 +114,7 @@
 	}
 
 	io = p_new(ioloop->pool, struct io, 1);
-	io->fd = fd;
-	io->condition = condition;
+	io->fd = -1;
 
 	io->callback = callback;
 	io->context = context;
@@ -149,8 +141,8 @@
 		}
 	}
 
-	if (ioctl(ctx->inotify_fd, INOTIFY_IGNORE, &io->notify_context) < 0)
-		i_error("ioctl(INOTIFY_IGNORE) failed: %m");
+	if (inotify_rm_watch(ctx->inotify_fd, io->notify_context) < 0)
+		i_error("inotify_rm_watch failed: %m");
 
 	p_free(ioloop->pool, io);
 
@@ -167,8 +159,9 @@
 	ctx = ioloop->notify_handler_context =
 		i_new(struct ioloop_notify_handler_context, 1);
 
-	ctx->inotify_fd = open("/dev/inotify", O_RDONLY);
-	if (ctx->inotify_fd < 0) {
+	ctx->inotify_fd = inotify_init();
+	if (ctx->inotify_fd == -1) {
+		i_error("inotify_init failed: %m");
 		ctx->disabled = TRUE;
 		return;
 	}
@@ -182,10 +174,12 @@
 	struct ioloop_notify_handler_context *ctx =
 		ioloop->notify_handler_context;
 
-	if (close(ctx->inotify_fd) < 0)
-		i_error("close(/dev/inotify) failed: %m");
+	if (ctx->inotify_fd != -1)
+		if (close(ctx->inotify_fd) < 0)
+			i_error("close(inotify descriptor) failed: %m");
 
-	buffer_free(ctx->buf);
+	if (ctx->buf != NULL)
+		buffer_free(ctx->buf);
 	i_free(ctx);
 }
 
--- orig/src/lib/ioloop-notify-none.c	12 Jul 2005 15:40:33 -0000	1.3
+++ mod/src/lib/ioloop-notify-none.c	10 Aug 2005 19:04:41 -0000
@@ -6,8 +6,7 @@
 #ifdef IOLOOP_NOTIFY_NONE
 
 struct io *io_loop_notify_add(struct ioloop *ioloop __attr_unused__,
-			      int fd __attr_unused__,
-			      enum io_condition condition __attr_unused__,
+			      const char *path __attr_unused__,
 			      io_callback_t *callback __attr_unused__,
 			      void *context __attr_unused__)
 {
--- orig/src/lib/ioloop.c	12 Jul 2005 15:40:33 -0000	1.26
+++ mod/src/lib/ioloop.c	10 Aug 2005 19:04:41 -0000
@@ -22,11 +22,7 @@
 
 	i_assert(fd >= 0);
 	i_assert(callback != NULL);
-
-	if ((condition & IO_NOTIFY_MASK) != 0) {
-		return io_loop_notify_add(current_ioloop, fd, condition,
-					  callback, context);
-	}
+	i_assert((condition & IO_NOTIFY) == 0);
 
 	io = p_new(current_ioloop->pool, struct io, 1);
 	io->fd = fd;
@@ -46,9 +42,23 @@
 	return io;
 }
 
+struct io *io_add_fs_notify(const char *path,
+			    io_callback_t *callback,
+			    void *context)
+{
+	struct io *io;
+	i_assert(path != NULL);
+	i_assert(callback != NULL);
+	
+	io = io_loop_notify_add(current_ioloop, path, callback, context);
+	if (io != NULL)
+		io->condition |= IO_NOTIFY;
+	return io;
+}
+
 void io_remove(struct io *io)
 {
-	if ((io->condition & IO_NOTIFY_MASK) != 0) {
+	if ((io->condition & IO_NOTIFY) != 0) {
 		io_loop_notify_remove(current_ioloop, io);
 		return;
 	}
--- orig/src/lib/ioloop.h	24 Aug 2003 12:43:53 -0000	1.11
+++ mod/src/lib/ioloop.h	10 Aug 2005 19:04:41 -0000
@@ -11,10 +11,9 @@
 enum io_condition {
 	IO_READ		= 0x01,
 	IO_WRITE	= 0x02,
-	IO_DIR_NOTIFY	= 0x04,
-	IO_FILE_NOTIFY	= 0x08,
-
-	IO_NOTIFY_MASK	= IO_DIR_NOTIFY | IO_FILE_NOTIFY
+	
+	/* internal */
+	IO_NOTIFY	= 0x04,
 };
 
 typedef void io_callback_t(void *context);
@@ -30,10 +29,12 @@
    but make sure you don't create multiple handlers of same type, it's not
    checked and removing one will stop the other from working as well.
 
-   If IO_DIR_NOTIFY or IO_FILE_NOTIFY isn't supported by operating system
-   directly, this function returns NULL. */
+ */
 struct io *io_add(int fd, enum io_condition condition,
 		  io_callback_t *callback, void *context);
+struct io *io_add_fs_notify(const char *path, 
+			    io_callback_t *callback,
+			    void *context);
 void io_remove(struct io *io);
 
 /* Timeout handlers */
--- orig/src/lib-storage/index/index-mailbox-check.c	19 Oct 2004 01:47:55 -0000	1.11
+++ mod/src/lib-storage/index/index-mailbox-check.c	10 Aug 2005 19:04:42 -0000
@@ -19,7 +19,6 @@
 struct index_notify_io {
 	struct index_notify_io *next;
 	struct io *io;
-	int fd;
 };
 
 static void check_timeout(void *context)
@@ -76,36 +75,25 @@
 	struct stat st;
 	struct io *io = NULL;
 	struct index_notify_io *aio;
-	int fd;
 
-	fd = open(path, O_RDONLY);
-	if (fd >= 0) {
-		io = io_add(fd, dir ? IO_DIR_NOTIFY : IO_FILE_NOTIFY,
-			    notify_callback, ibox);
-		if (io != NULL) {
-			aio = i_new(struct index_notify_io, 1);
-			aio->io = io;
-			aio->fd = fd;
-			aio->next = ibox->notify_ios;
-			ibox->notify_ios = aio;
-		}
+	io = io_add_fs_notify(path, notify_callback, ibox);
+	if (io != NULL) {
+		aio = i_new(struct index_notify_io, 1);
+		aio->io = io;
+		aio->next = ibox->notify_ios;
+		ibox->notify_ios = aio;
 	}
 
 	file = i_new(struct index_notify_file, 1);
 	file->path = i_strdup(path);
-	if (fd < 0)
-		file->last_stamp = stat(path, &st) < 0 ? 0 : st.st_mtime;
-	else
-		file->last_stamp = fstat(fd, &st) < 0 ? 0 : st.st_mtime;
-
-	if (io == NULL) {
-		/* we couldn't add it to notify list */
-		(void)close(fd);
-	}
+	file->last_stamp = stat(path, &st) < 0 ? 0 : st.st_mtime;
 
 	file->next = ibox->notify_files;
-        ibox->notify_files = file;
+	ibox->notify_files = file;
 
+	/* we still add a timeout if we don't have one already,
+	 * because we don't know what happens with [di]notify
+	 * when the filesystem is remote (NFS, ...) */
 	if (ibox->notify_to == NULL)
 		ibox->notify_to = timeout_add(1000, check_timeout, ibox);
 }
@@ -131,8 +119,6 @@
 		ibox->notify_ios = aio->next;
 
 		io_remove(aio->io);
-		if (close(aio->fd) < 0)
-			i_error("close(notify_io) failed: %m");
 		i_free(aio);
 	}
 
