# HG changeset patch # User Timo Sirainen # Date 1183953597 -10800 # Node ID 772f4e8bd2a9e55be86ff33aa849b288e316f79a # Parent 2133c966701a5b1e02784ae3ac24caaac1d84cbe Changed io_add_notify() API so that it can return "file doesn't exist" error. diff -r 2133c966701a -r 772f4e8bd2a9 src/lib-storage/index/index-mailbox-check.c --- a/src/lib-storage/index/index-mailbox-check.c Mon Jul 09 06:47:17 2007 +0300 +++ b/src/lib-storage/index/index-mailbox-check.c Mon Jul 09 06:59:57 2007 +0300 @@ -73,7 +73,7 @@ struct io *io = NULL; struct index_notify_io *aio; - io = io_add_notify(path, notify_callback, ibox); + (void)io_add_notify(path, notify_callback, ibox, &io); if (io != NULL) { aio = i_new(struct index_notify_io, 1); aio->io = io; diff -r 2133c966701a -r 772f4e8bd2a9 src/lib/ioloop-notify-dn.c --- a/src/lib/ioloop-notify-dn.c Mon Jul 09 06:47:17 2007 +0300 +++ b/src/lib/ioloop-notify-dn.c Mon Jul 09 06:59:57 2007 +0300 @@ -72,48 +72,51 @@ } #undef io_add_notify -struct io *io_add_notify(const char *path, io_callback_t *callback, - void *context) +enum io_notify_result io_add_notify(const char *path, io_callback_t *callback, + void *context, struct io **io_r) { struct ioloop_notify_handler_context *ctx = current_ioloop->notify_handler_context; - int fd; + int fd, ret; + + *io_r = NULL; if (ctx == NULL) ctx = io_loop_notify_handler_init(); if (ctx->disabled) - return NULL; + return IO_NOTIFY_DISABLED; fd = open(path, O_RDONLY); if (fd == -1) { - i_error("open(%s) for dnotify failed: %m", path); - return NULL; + if (errno != ENOENT) + i_error("open(%s) for dnotify failed: %m", path); + return IO_NOTIFY_NOTFOUND; } if (fcntl(fd, F_SETSIG, SIGRTMIN) < 0) { - if (errno == EINVAL) { - /* not supported, disable dnotify */ - ctx->disabled = TRUE; - } else { + /* EINVAL means there's no realtime signals and no dnotify */ + if (errno != EINVAL) i_error("fcntl(F_SETSIG) failed: %m"); - } + ctx->disabled = TRUE; (void)close(fd); - return NULL; + return IO_NOTIFY_DISABLED; } if (fcntl(fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_RENAME | DN_MULTISHOT) < 0) { if (errno == ENOTDIR) { /* we're trying to add dnotify to a non-directory fd. fail silently. */ - } else if (errno == EINVAL) { + ret = IO_NOTIFY_NOTFOUND; + } else { /* dnotify not in kernel. disable it. */ + if (errno != EINVAL) + i_error("fcntl(F_NOTIFY) failed: %m"); ctx->disabled = TRUE; - } else { - i_error("fcntl(F_NOTIFY) failed: %m"); + ret = IO_NOTIFY_DISABLED; } (void)fcntl(fd, F_SETSIG, 0); (void)close(fd); - return NULL; + return ret; } if (ctx->event_io == NULL) { @@ -121,7 +124,8 @@ dnotify_input, current_ioloop); } - return io_notify_fd_add(&ctx->fd_ctx, fd, callback, context); + *io_r = io_notify_fd_add(&ctx->fd_ctx, fd, callback, context); + return IO_NOTIFY_ADDED; } void io_loop_notify_remove(struct ioloop *ioloop, struct io *_io) diff -r 2133c966701a -r 772f4e8bd2a9 src/lib/ioloop-notify-inotify.c --- a/src/lib/ioloop-notify-inotify.c Mon Jul 09 06:47:17 2007 +0300 +++ b/src/lib/ioloop-notify-inotify.c Mon Jul 09 06:59:57 2007 +0300 @@ -6,6 +6,7 @@ #ifdef IOLOOP_NOTIFY_INOTIFY #include "fd-close-on-exec.h" +#include "fd-set-nonblock.h" #include "ioloop-internal.h" #include "ioloop-notify-fd.h" #include "buffer.h" @@ -62,12 +63,18 @@ pos += sizeof(*event) + event->len; io = io_notify_fd_find(&ctx->fd_ctx, event->wd); - if (io != NULL) + if (io != NULL) { + if ((event->mask & IN_IGNORED) != 0) { + /* calling inotify_rm_watch() would now give + EINVAL */ + io->fd = -1; + } io->io.callback(io->io.context); + } } if (pos != ret) i_error("read(inotify) returned partial event"); - return TRUE; + return (size_t)ret >= sizeof(event_buf)-512; } static void inotify_input(struct ioloop *ioloop) @@ -76,28 +83,33 @@ } #undef io_add_notify -struct io *io_add_notify(const char *path, io_callback_t *callback, - void *context) +enum io_notify_result io_add_notify(const char *path, io_callback_t *callback, + void *context, struct io **io_r) { struct ioloop_notify_handler_context *ctx = current_ioloop->notify_handler_context; - int fd; + int wd; + + *io_r = NULL; if (ctx == NULL) ctx = io_loop_notify_handler_init(); if (ctx->disabled) - return NULL; + return IO_NOTIFY_DISABLED; - fd = inotify_add_watch(ctx->inotify_fd, path, + wd = inotify_add_watch(ctx->inotify_fd, path, IN_CREATE | IN_DELETE | IN_MOVE | IN_CLOSE | IN_MODIFY); - if (fd < 0) { + if (wd < 0) { + if (errno == ENOENT) + return IO_NOTIFY_NOTFOUND; + /* ESTALE could happen with NFS. Don't bother giving an error message then. */ if (errno != ESTALE) i_error("inotify_add_watch(%s) failed: %m", path); ctx->disabled = TRUE; - return NULL; + return IO_NOTIFY_DISABLED; } if (ctx->event_io == NULL) { @@ -105,7 +117,8 @@ inotify_input, current_ioloop); } - return io_notify_fd_add(&ctx->fd_ctx, fd, callback, context); + *io_r = io_notify_fd_add(&ctx->fd_ctx, wd, callback, context); + return IO_NOTIFY_ADDED; } void io_loop_notify_remove(struct ioloop *ioloop, struct io *_io) @@ -114,8 +127,10 @@ ioloop->notify_handler_context; struct io_notify *io = (struct io_notify *)_io; - if (inotify_rm_watch(ctx->inotify_fd, io->fd) < 0) - i_error("inotify_rm_watch() failed: %m"); + if (io->fd != -1) { + if (inotify_rm_watch(ctx->inotify_fd, io->fd) < 0) + i_error("inotify_rm_watch() failed: %m"); + } io_notify_fd_free(&ctx->fd_ctx, io); @@ -142,6 +157,7 @@ ctx->disabled = TRUE; } else { fd_close_on_exec(ctx->inotify_fd, TRUE); + fd_set_nonblock(ctx->inotify_fd, TRUE); } return ctx; } @@ -154,6 +170,7 @@ if (ctx->inotify_fd != -1) { if (close(ctx->inotify_fd) < 0) i_error("close(inotify) failed: %m"); + ctx->inotify_fd = -1; } i_free(ctx); } diff -r 2133c966701a -r 772f4e8bd2a9 src/lib/ioloop-notify-kqueue.c --- a/src/lib/ioloop-notify-kqueue.c Mon Jul 09 06:47:17 2007 +0300 +++ b/src/lib/ioloop-notify-kqueue.c Mon Jul 09 06:59:57 2007 +0300 @@ -105,8 +105,8 @@ } #undef io_add_notify -struct io *io_add_notify(const char *path, io_callback_t *callback, - void *context) +enum io_notify_result io_add_notify(const char *path, io_callback_t *callback, + void *context, struct io **io_r) { struct ioloop_notify_handler_context *ctx = current_ioloop->notify_handler_context; @@ -121,7 +121,7 @@ if (fd == -1) { if (errno != ENOENT) i_error("open(%s) for kq notify failed: %m", path); - return NULL; + return IO_NOTIFY_NOTFOUND; } fd_close_on_exec(fd, TRUE); @@ -140,14 +140,15 @@ i_error("kevent(%d, %s) for notify failed: %m", fd, path); (void)close(fd); i_free(io); - return NULL; + return IO_NOTIFY_DISABLED; } if (ctx->event_io == NULL) { ctx->event_io = io_add(ctx->kq, IO_READ, event_callback, current_ioloop->notify_handler_context); } - return &io->io; + *io_r = &io->io; + return IO_NOTIFY_ADDED; } void io_loop_notify_remove(struct ioloop *ioloop, struct io *_io) diff -r 2133c966701a -r 772f4e8bd2a9 src/lib/ioloop.h --- a/src/lib/ioloop.h Mon Jul 09 06:47:17 2007 +0300 +++ b/src/lib/ioloop.h Mon Jul 09 06:59:57 2007 +0300 @@ -19,6 +19,12 @@ IO_NOTIFY = 0x08 }; +enum io_notify_result { + IO_NOTIFY_ADDED, + IO_NOTIFY_NOTFOUND, + IO_NOTIFY_DISABLED +}; + typedef void io_callback_t(void *context); typedef void timeout_callback_t(void *context); @@ -40,10 +46,17 @@ #define io_add(fd, condition, callback, context) \ CONTEXT_CALLBACK(io_add, io_callback_t, \ callback, context, fd, condition) -struct io *io_add_notify(const char *path, io_callback_t *callback, - void *context); -#define io_add_notify(path, callback, context) \ - CONTEXT_CALLBACK(io_add_notify, io_callback_t, callback, context, path) +enum io_notify_result io_add_notify(const char *path, io_callback_t *callback, + void *context, struct io **io_r); +#ifdef CONTEXT_TYPE_SAFETY +# define io_add_notify(path, callback, context, io_r) \ + ({(void)(1 ? 0 : callback(context)); \ + io_add_notify(path, (io_callback_t *)callback, context, io_r); }) +#else +# define io_add_notify(path, callback, context, io_r) \ + io_add_notify(path, (io_callback_t *)callback, context, io_r) +#endif + /* Remove I/O handler, and set io pointer to NULL. */ void io_remove(struct io **io);