Unix SMB/CIFS implementation.
Copyright (C) Andrew Tridgell 2006
-
+
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 3 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, see <http://www.gnu.org/licenses/>.
*/
*/
#include "includes.h"
+#include "../librpc/gen_ndr/notify.h"
+#include "smbd/smbd.h"
#ifdef HAVE_INOTIFY
-#ifdef HAVE_ASM_TYPES_H
-#include <asm/types.h>
-#endif
-
-#include <linux/inotify.h>
-#include <asm/unistd.h>
-
-#ifndef HAVE_INOTIFY_INIT
-/*
- glibc doesn't define these functions yet (as of March 2006)
-*/
-static int inotify_init(void)
-{
- return syscall(__NR_inotify_init);
-}
-
-static int inotify_add_watch(int fd, const char *path, __u32 mask)
-{
- return syscall(__NR_inotify_add_watch, fd, path, mask);
-}
-
-static int inotify_rm_watch(int fd, int wd)
-{
- return syscall(__NR_inotify_rm_watch, fd, wd);
-}
-#endif
-
+#include <sys/inotify.h>
-/* older glibc headers don't have these defines either */
+/* glibc < 2.5 headers don't have these defines */
#ifndef IN_ONLYDIR
#define IN_ONLYDIR 0x01000000
#endif
see if a particular event from inotify really does match a requested
notify event in SMB
*/
-static BOOL filter_match(struct inotify_watch_context *w,
+static bool filter_match(struct inotify_watch_context *w,
struct inotify_event *e)
{
DEBUG(10, ("filter_match: e->mask=%x, w->mask=%x, w->filter=%x\n",
return True;
}
-
+
/*
dispatch one inotify event
-
+
the cookies are used to correctly handle renames
*/
static void inotify_dispatch(struct inotify_private *in,
ne.action = NOTIFY_ACTION_MODIFIED;
e->mask = IN_ATTRIB;
-
+
for (w=in->watches;w;w=next) {
next = w->next;
if (w->wd == e->wd && filter_match(w, e) &&
int bufsize = 0;
struct inotify_event *e0, *e;
uint32_t prev_cookie=0;
+ NTSTATUS status;
/*
we must use FIONREAD as we cannot predict the length of the
if (ioctl(in->fd, FIONREAD, &bufsize) != 0 ||
bufsize == 0) {
DEBUG(0,("No data on inotify fd?!\n"));
+ TALLOC_FREE(fde);
return;
}
- e0 = e = (struct inotify_event *)TALLOC_SIZE(in, bufsize);
+ e0 = e = (struct inotify_event *)TALLOC_SIZE(in, bufsize + 1);
if (e == NULL) return;
+ ((uint8_t *)e)[bufsize] = '\0';
- if (read(in->fd, e0, bufsize) != bufsize) {
- DEBUG(0,("Failed to read all inotify data\n"));
+ status = read_data(in->fd, (char *)e0, bufsize);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0,("Failed to read all inotify data - %s\n",
+ nt_errstr(status)));
talloc_free(e0);
+ /* the inotify fd will now be out of sync,
+ * can't keep reading data off it */
+ TALLOC_FREE(fde);
return;
}
/* we can get more than one event in the buffer */
- while (bufsize >= sizeof(*e)) {
+ while (e && (bufsize >= sizeof(*e))) {
struct inotify_event *e2 = NULL;
bufsize -= e->len + sizeof(*e);
if (bufsize >= sizeof(*e)) {
/* add a event waiting for the inotify fd to be readable */
event_add_fd(ctx->ev, in, in->fd, EVENT_FD_READ, inotify_handler, in);
-
+
return NT_STATUS_OK;
}
{FILE_NOTIFY_CHANGE_SECURITY, IN_ATTRIB}
};
-static uint32_t inotify_map(struct notify_entry *e)
+static uint32_t inotify_map(uint32_t *filter)
{
int i;
uint32_t out=0;
for (i=0;i<ARRAY_SIZE(inotify_mapping);i++) {
- if (inotify_mapping[i].notify_mask & e->filter) {
+ if (inotify_mapping[i].notify_mask & *filter) {
out |= inotify_mapping[i].inotify_mask;
- e->filter &= ~inotify_mapping[i].notify_mask;
+ *filter &= ~inotify_mapping[i].notify_mask;
}
}
return out;
DEBUG(1, ("inotify_rm_watch returned %s\n",
strerror(errno)));
}
-
+
}
return 0;
}
talloc_free() on *handle
*/
NTSTATUS inotify_watch(struct sys_notify_context *ctx,
- struct notify_entry *e,
+ const char *path,
+ uint32_t *filter,
+ uint32_t *subdir_filter,
void (*callback)(struct sys_notify_context *ctx,
void *private_data,
struct notify_event *ev),
int wd;
uint32_t mask;
struct inotify_watch_context *w;
- uint32_t filter = e->filter;
+ uint32_t orig_filter = *filter;
void **handle = (void **)handle_p;
/* maybe setup the inotify fd */
in = talloc_get_type(ctx->private_data, struct inotify_private);
- mask = inotify_map(e);
+ mask = inotify_map(filter);
if (mask == 0) {
/* this filter can't be handled by inotify */
return NT_STATUS_INVALID_PARAMETER;
}
/* using IN_MASK_ADD allows us to cope with inotify() returning the same
- watch descriptor for muliple watches on the same path */
+ watch descriptor for multiple watches on the same path */
mask |= (IN_MASK_ADD | IN_ONLYDIR);
/* get a new watch descriptor for this path */
- wd = inotify_add_watch(in->fd, e->path, mask);
+ wd = inotify_add_watch(in->fd, path, mask);
if (wd == -1) {
- e->filter = filter;
+ *filter = orig_filter;
DEBUG(1, ("inotify_add_watch returned %s\n", strerror(errno)));
return map_nt_error_from_unix(errno);
}
DEBUG(10, ("inotify_add_watch for %s mask %x returned wd %d\n",
- e->path, mask, wd));
+ path, mask, wd));
w = talloc(in, struct inotify_watch_context);
if (w == NULL) {
inotify_rm_watch(in->fd, wd);
- e->filter = filter;
+ *filter = orig_filter;
return NT_STATUS_NO_MEMORY;
}
w->callback = callback;
w->private_data = private_data;
w->mask = mask;
- w->filter = filter;
- w->path = talloc_strdup(w, e->path);
+ w->filter = orig_filter;
+ w->path = talloc_strdup(w, path);
if (w->path == NULL) {
inotify_rm_watch(in->fd, wd);
- e->filter = filter;
+ *filter = orig_filter;
return NT_STATUS_NO_MEMORY;
}
/* the caller frees the handle to stop watching */
talloc_set_destructor(w, watch_destructor);
-
+
return NT_STATUS_OK;
}