diff options
Diffstat (limited to 'source3/smbd/notify_kernel.c')
-rw-r--r-- | source3/smbd/notify_kernel.c | 287 |
1 files changed, 0 insertions, 287 deletions
diff --git a/source3/smbd/notify_kernel.c b/source3/smbd/notify_kernel.c deleted file mode 100644 index f90414dc79..0000000000 --- a/source3/smbd/notify_kernel.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 3.0 - change notify handling - linux kernel based implementation - Copyright (C) Andrew Tridgell 2000 - Copyright (C) Volker Lendecke 2007 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -#if HAVE_KERNEL_CHANGE_NOTIFY - -#ifndef DN_ACCESS -#define DN_ACCESS 0x00000001 /* File accessed in directory */ -#define DN_MODIFY 0x00000002 /* File modified in directory */ -#define DN_CREATE 0x00000004 /* File created in directory */ -#define DN_DELETE 0x00000008 /* File removed from directory */ -#define DN_RENAME 0x00000010 /* File renamed in directory */ -#define DN_ATTRIB 0x00000020 /* File changed attribute */ -#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */ -#endif - - -#ifndef RT_SIGNAL_NOTIFY -#define RT_SIGNAL_NOTIFY (SIGRTMIN+2) -#endif - -#ifndef F_SETSIG -#define F_SETSIG 10 -#endif - -#ifndef F_NOTIFY -#define F_NOTIFY 1026 -#endif - -/**************************************************************************** - This is the structure to keep the information needed to - determine if a directory has changed. -*****************************************************************************/ - -struct dnotify_ctx { - struct dnotify_ctx *prev, *next; - - int fd; - files_struct *fsp; -}; - -static struct dnotify_ctx *dnotify_list; -static int dnotify_signal_pipe[2]; - -/**************************************************************************** - The signal handler for change notify. - The Linux kernel has a bug in that we should be able to block any - further delivery of RT signals until the kernel_check_notify() function - unblocks them, but it seems that any signal mask we're setting here is - being overwritten on exit from this handler. I should create a standalone - test case for the kernel hackers. JRA. -*****************************************************************************/ - -static void dnotify_signal_handler(int sig, siginfo_t *info, void *unused) -{ - int saved_errno; - - /* - * According to http://www.opengroup.org/onlinepubs/009695399/ write - * to a pipe either writes all or nothing, so we can safely write a - * full sizeof(int) and not risk the pipe to become out of sync with - * the receiving end. - * - * We don't care about the result of the write() call. If the pipe is - * full, then this signal is lost, we can't do anything about it. - */ - - saved_errno = errno; - write(dnotify_signal_pipe[1], (const void *)&info->si_fd, sizeof(int)); - errno = saved_errno; - - sys_select_signal(RT_SIGNAL_NOTIFY); -} - -/**************************************************************************** - The upper level handler informed when the pipe is ready for reading -*****************************************************************************/ - -static void dnotify_pipe_handler(struct event_context *event_ctx, - struct fd_event *event, - uint16 flags, - void *private_data) -{ - int res, fd; - struct dnotify_ctx *ctx; - - res = read(dnotify_signal_pipe[0], (void *)&fd, sizeof(int)); - - if (res == -1) { - DEBUG(0, ("Read from the dnotify pipe failed: %s\n", - strerror(errno))); - TALLOC_FREE(event); /* Don't try again */ - return; - } - - if (res != sizeof(int)) { - smb_panic("read from dnotify pipe gave wrong number of " - "bytes\n"); - } - - for (ctx = dnotify_list; ctx; ctx = ctx->next) { - if (ctx->fd == fd) { - notify_fsp(ctx->fsp, 0, NULL); - } - } -} - -/**************************************************************************** - Register a change notify request. -*****************************************************************************/ - -static int kernel_register_notify(connection_struct *conn, char *path, - uint32 flags) -{ - int fd; - unsigned long kernel_flags; - - fd = sys_open(path,O_RDONLY, 0); - - if (fd == -1) { - DEBUG(3,("Failed to open directory %s for change notify\n", - path)); - return -1; - } - - if (sys_fcntl_long(fd, F_SETSIG, RT_SIGNAL_NOTIFY) == -1) { - DEBUG(3,("Failed to set signal handler for change notify\n")); - close(fd); - return -1; - } - - kernel_flags = DN_CREATE|DN_DELETE|DN_RENAME; /* creation/deletion - * changes - * everything! */ - if (flags & FILE_NOTIFY_CHANGE_FILE_NAME) kernel_flags |= DN_MODIFY; - if (flags & FILE_NOTIFY_CHANGE_DIR_NAME) kernel_flags - |= DN_RENAME - |DN_DELETE; - if (flags & FILE_NOTIFY_CHANGE_ATTRIBUTES) kernel_flags |= DN_ATTRIB; - if (flags & FILE_NOTIFY_CHANGE_SIZE) kernel_flags |= DN_MODIFY; - if (flags & FILE_NOTIFY_CHANGE_LAST_WRITE) kernel_flags |= DN_MODIFY; - if (flags & FILE_NOTIFY_CHANGE_LAST_ACCESS) kernel_flags |= DN_ACCESS; - if (flags & FILE_NOTIFY_CHANGE_CREATION) kernel_flags |= DN_CREATE; - if (flags & FILE_NOTIFY_CHANGE_SECURITY) kernel_flags |= DN_ATTRIB; - if (flags & FILE_NOTIFY_CHANGE_EA) kernel_flags |= DN_ATTRIB; - if (flags & FILE_NOTIFY_CHANGE_FILE_NAME) kernel_flags - |= DN_RENAME - |DN_DELETE; - - if (sys_fcntl_long(fd, F_NOTIFY, kernel_flags) == -1) { - DEBUG(3,("Failed to set async flag for change notify\n")); - close(fd); - return -1; - } - - DEBUG(3,("kernel change notify on %s (ntflags=0x%x flags=0x%x) " - "fd=%d\n", path, (int)flags, (int)kernel_flags, fd)); - - return fd; -} - -/**************************************************************************** - See if the kernel supports change notify. -****************************************************************************/ - -static BOOL kernel_notify_available(void) -{ - int fd, ret; - fd = open("/tmp", O_RDONLY); - if (fd == -1) - return False; /* uggh! */ - ret = sys_fcntl_long(fd, F_NOTIFY, 0); - close(fd); - return ret == 0; -} - -static int dnotify_ctx_destructor(struct dnotify_ctx *ctx) -{ - close(ctx->fd); - DLIST_REMOVE(dnotify_list, ctx); - return 0; -} - -static void *kernel_notify_add(TALLOC_CTX *mem_ctx, - struct event_context *event_ctx, - files_struct *fsp, - uint32 *filter) -{ - struct dnotify_ctx *ctx; - - if (!(ctx = TALLOC_P(mem_ctx, struct dnotify_ctx))) { - DEBUG(0, ("talloc failed\n")); - return NULL; - } - - ctx->fsp = fsp; - ctx->fd = kernel_register_notify(fsp->conn, fsp->fsp_name, *filter); - - if (ctx->fd == -1) { - TALLOC_FREE(ctx); - return NULL; - } - - DLIST_ADD(dnotify_list, ctx); - talloc_set_destructor(ctx, dnotify_ctx_destructor); - - return ctx; -} - -/**************************************************************************** - Setup kernel based change notify. -****************************************************************************/ - -struct cnotify_fns *kernel_notify_init(struct event_context *event_ctx) -{ - static struct cnotify_fns cnotify; - struct sigaction act; - - if (pipe(dnotify_signal_pipe) == -1) { - DEBUG(0, ("Failed to create signal pipe: %s\n", - strerror(errno))); - return NULL; - } - - if ((set_blocking(dnotify_signal_pipe[0], False) == -1) - || (set_blocking(dnotify_signal_pipe[1], False) == -1)) { - DEBUG(0, ("Failed to set signal pipe to non-blocking: %s\n", - strerror(errno))); - close(dnotify_signal_pipe[0]); - close(dnotify_signal_pipe[1]); - return NULL; - } - - if (event_add_fd(event_ctx, NULL, dnotify_signal_pipe[0], - EVENT_FD_READ, dnotify_pipe_handler, NULL) == NULL) { - DEBUG(0, ("Failed to set signal event handler\n")); - close(dnotify_signal_pipe[0]); - close(dnotify_signal_pipe[1]); - return NULL; - } - - ZERO_STRUCT(act); - - act.sa_sigaction = dnotify_signal_handler; - act.sa_flags = SA_SIGINFO; - sigemptyset( &act.sa_mask ); - if (sigaction(RT_SIGNAL_NOTIFY, &act, NULL) != 0) { - DEBUG(0,("Failed to setup RT_SIGNAL_NOTIFY handler\n")); - return NULL; - } - - if (!kernel_notify_available()) - return NULL; - - cnotify.notify_add = kernel_notify_add; - - /* the signal can start off blocked due to a bug in bash */ - BlockSignals(False, RT_SIGNAL_NOTIFY); - - return &cnotify; -} - -#else - void notify_kernel_dummy(void); - - void notify_kernel_dummy(void) {} -#endif /* HAVE_KERNEL_CHANGE_NOTIFY */ |