summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/ntvfs/common/notify.c61
-rw-r--r--source4/ntvfs/posix/pvfs_notify.c6
-rw-r--r--source4/ntvfs/sysdep/inotify.c22
-rw-r--r--source4/ntvfs/sysdep/sys_notify.c38
-rw-r--r--source4/ntvfs/sysdep/sys_notify.h21
5 files changed, 93 insertions, 55 deletions
diff --git a/source4/ntvfs/common/notify.c b/source4/ntvfs/common/notify.c
index 9ea024f2fc..e0d48d2b80 100644
--- a/source4/ntvfs/common/notify.c
+++ b/source4/ntvfs/common/notify.c
@@ -290,10 +290,11 @@ static NTSTATUS notify_add_array(struct notify_context *notify, struct notify_en
add a notify watch. This is called when a notify is first setup on a open
directory handle.
*/
-NTSTATUS notify_add(struct notify_context *notify, struct notify_entry *e,
+NTSTATUS notify_add(struct notify_context *notify, struct notify_entry *e0,
void (*callback)(void *, const struct notify_event *),
void *private)
{
+ struct notify_entry e = *e0;
NTSTATUS status;
struct notify_list *listel;
char *path = NULL;
@@ -304,8 +305,7 @@ NTSTATUS notify_add(struct notify_context *notify, struct notify_entry *e,
status = notify_load(notify);
if (!NT_STATUS_IS_OK(status)) {
- notify_unlock(notify);
- return status;
+ goto done;
}
notify->array->entries = talloc_realloc(notify->array, notify->array->entries,
@@ -313,18 +313,25 @@ NTSTATUS notify_add(struct notify_context *notify, struct notify_entry *e,
notify->array->num_entries+1);
if (notify->array->entries == NULL) {
- notify_unlock(notify);
- return NT_STATUS_NO_MEMORY;
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
}
/* cope with /. on the end of the path */
- len = strlen(e->path);
- if (len > 1 && e->path[len-1] == '.' && e->path[len-2] == '/') {
- path = talloc_strndup(notify, e->path, len-2);
+ len = strlen(e.path);
+ if (len > 1 && e.path[len-1] == '.' && e.path[len-2] == '/') {
+ e.path = talloc_strndup(notify, e.path, len-2);
+ if (e.path == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
}
listel = talloc_zero(notify, struct notify_list);
- NT_STATUS_HAVE_NO_MEMORY(listel);
+ if (listel == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
listel->private = private;
listel->callback = callback;
@@ -332,22 +339,31 @@ NTSTATUS notify_add(struct notify_context *notify, struct notify_entry *e,
/* ignore failures from sys_notify */
if (notify->sys_notify_ctx != NULL) {
- status = sys_notify_watch(notify->sys_notify_ctx, e->path, e->filter,
+ /*
+ this call will modify e.filter and e.subdir_filter
+ to remove bits handled by the backend
+ */
+ status = sys_notify_watch(notify->sys_notify_ctx, &e,
sys_notify_callback, listel,
&listel->sys_notify_handle);
if (NT_STATUS_IS_OK(status)) {
- /* if the kernel handler has said it can handle this notify then
- we don't need to add it to the array */
talloc_steal(listel, listel->sys_notify_handle);
- goto done;
}
}
- status = notify_add_array(notify, e, path, private);
+ /* if the system notify handler couldn't handle some of the
+ filter bits, or couldn't handle a request for recursion
+ then we need to install it in the array used for the
+ intra-samba notify handling */
+ if (e.filter != 0 || e.subdir_filter != 0) {
+ status = notify_add_array(notify, &e, path, private);
+ }
done:
notify_unlock(notify);
- talloc_free(path);
+ if (e.path != e0->path) {
+ talloc_free(e.path);
+ }
return status;
}
@@ -483,8 +499,9 @@ static BOOL notify_match(struct notify_context *notify, struct notify_entry *e,
const char *path, uint32_t filter)
{
size_t len;
+ BOOL subdir;
- if (!(filter & e->filter)) {
+ if (!(filter & e->filter) && !(filter & e->subdir_filter)) {
return False;
}
@@ -498,13 +515,15 @@ static BOOL notify_match(struct notify_context *notify, struct notify_entry *e,
return False;
}
- if (!e->recursive) {
- if (strchr(&path[len+1], '/') != NULL) {
- return False;
- }
+ /* the filter and subdir_filter are handled separately, allowing a backend
+ to flexibly choose what it can handle */
+ subdir = (strchr(&path[len+1], '/') != NULL);
+
+ if (subdir) {
+ return (filter & e->subdir_filter) != 0;
}
- return True;
+ return (filter & e->filter) != 0;
}
diff --git a/source4/ntvfs/posix/pvfs_notify.c b/source4/ntvfs/posix/pvfs_notify.c
index 121ba499b3..d2fdbfc49a 100644
--- a/source4/ntvfs/posix/pvfs_notify.c
+++ b/source4/ntvfs/posix/pvfs_notify.c
@@ -145,7 +145,11 @@ static NTSTATUS pvfs_notify_setup(struct pvfs_state *pvfs, struct pvfs_file *f,
e.filter = filter;
e.path = f->handle->name->full_name;
- e.recursive = recursive;
+ if (recursive) {
+ e.subdir_filter = filter;
+ } else {
+ e.subdir_filter = 0;
+ }
status = notify_add(pvfs->notify_context, &e,
pvfs_notify_callback, f->notify_buffer);
diff --git a/source4/ntvfs/sysdep/inotify.c b/source4/ntvfs/sysdep/inotify.c
index ec8669306e..c95c39ff01 100644
--- a/source4/ntvfs/sysdep/inotify.c
+++ b/source4/ntvfs/sysdep/inotify.c
@@ -190,13 +190,15 @@ static NTSTATUS inotify_setup(struct sys_notify_context *ctx)
/*
- map from a change notify mask to a inotify mask. Approximate only :(
+ map from a change notify mask to a inotify mask. Remove any bits
+ which we can handle
*/
static const struct {
uint32_t notify_mask;
uint32_t inotify_mask;
} inotify_mapping[] = {
{FILE_NOTIFY_CHANGE_FILE_NAME, IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO},
+ {FILE_NOTIFY_CHANGE_DIR_NAME, IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO},
{FILE_NOTIFY_CHANGE_ATTRIBUTES, IN_ATTRIB},
{FILE_NOTIFY_CHANGE_SIZE, IN_MODIFY},
{FILE_NOTIFY_CHANGE_LAST_WRITE, IN_ATTRIB},
@@ -204,13 +206,14 @@ static const struct {
{FILE_NOTIFY_CHANGE_SECURITY, IN_ATTRIB}
};
-static uint32_t inotify_map(uint32_t mask)
+static uint32_t inotify_map(struct notify_entry *e)
{
int i;
uint32_t out=0;
for (i=0;i<ARRAY_SIZE(inotify_mapping);i++) {
- if (inotify_mapping[i].notify_mask & mask) {
+ if (inotify_mapping[i].notify_mask & e->filter) {
out |= inotify_mapping[i].inotify_mask;
+ e->filter &= ~inotify_mapping[i].notify_mask;
}
}
return out;
@@ -241,14 +244,15 @@ static int watch_destructor(void *ptr)
add a watch. The watch is removed when the caller calls
talloc_free() on *handle
*/
-static NTSTATUS inotify_watch(struct sys_notify_context *ctx, const char *dirpath,
- uint32_t filter, sys_notify_callback_t callback,
- void *private, void **handle)
+static NTSTATUS inotify_watch(struct sys_notify_context *ctx, struct notify_entry *e,
+ sys_notify_callback_t callback, void *private,
+ void **handle)
{
struct inotify_private *in;
int wd;
uint32_t mask;
struct watch_context *w;
+ uint32_t filter = e->filter;
/* maybe setup the inotify fd */
if (ctx->private == NULL) {
@@ -259,7 +263,7 @@ static NTSTATUS inotify_watch(struct sys_notify_context *ctx, const char *dirpat
in = talloc_get_type(ctx->private, struct inotify_private);
- mask = inotify_map(filter);
+ mask = inotify_map(e);
if (mask == 0) {
/* this filter can't be handled by inotify */
return NT_STATUS_INVALID_PARAMETER;
@@ -270,14 +274,16 @@ static NTSTATUS inotify_watch(struct sys_notify_context *ctx, const char *dirpat
mask |= (IN_MASK_ADD | IN_ONLYDIR);
/* get a new watch descriptor for this path */
- wd = inotify_add_watch(in->fd, dirpath, mask);
+ wd = inotify_add_watch(in->fd, e->path, mask);
if (wd == -1) {
+ e->filter = filter;
return map_nt_error_from_unix(errno);
}
w = talloc(in, struct watch_context);
if (w == NULL) {
inotify_rm_watch(in->fd, wd);
+ e->filter = filter;
return NT_STATUS_NO_MEMORY;
}
diff --git a/source4/ntvfs/sysdep/sys_notify.c b/source4/ntvfs/sysdep/sys_notify.c
index 1927ac61ce..1be57dd55a 100644
--- a/source4/ntvfs/sysdep/sys_notify.c
+++ b/source4/ntvfs/sysdep/sys_notify.c
@@ -31,7 +31,7 @@
/* list of registered backends */
static struct sys_notify_backend *backends;
-
+static uint32_t num_backends;
/*
initialise a system change notify backend
@@ -43,8 +43,9 @@ struct sys_notify_context *sys_notify_init(int snum,
struct sys_notify_context *ctx;
const char *bname;
struct sys_notify_backend *b;
+ int i;
- if (backends == NULL) {
+ if (num_backends == 0) {
return NULL;
}
@@ -61,16 +62,16 @@ struct sys_notify_context *sys_notify_init(int snum,
bname = lp_parm_string(snum, "notify", "backend");
if (!bname) {
- if (backends) {
- bname = backends->name;
+ if (num_backends) {
+ bname = backends[0].name;
} else {
bname = "__unknown__";
}
}
- for (b=backends;b;b=b->next) {
- if (strcasecmp(b->name, bname) == 0) {
- bname = b->name;
+ for (i=0;i<num_backends;i++) {
+ if (strcasecmp(backends[i].name, bname) == 0) {
+ bname = backends[i].name;
break;
}
}
@@ -78,8 +79,8 @@ struct sys_notify_context *sys_notify_init(int snum,
ctx->name = bname;
ctx->notify_watch = NULL;
- if (b != NULL) {
- ctx->notify_watch = b->notify_watch;
+ if (i < num_backends) {
+ ctx->notify_watch = backends[i].notify_watch;
}
return ctx;
@@ -87,15 +88,18 @@ struct sys_notify_context *sys_notify_init(int snum,
/*
add a watch
+
+ note that this call must modify the e->filter and e->subdir_filter
+ bits to remove ones handled by this backend. Any remaining bits will
+ be handled by the generic notify layer
*/
-NTSTATUS sys_notify_watch(struct sys_notify_context *ctx, const char *dirpath,
- uint32_t filter, sys_notify_callback_t callback,
- void *private, void **handle)
+NTSTATUS sys_notify_watch(struct sys_notify_context *ctx, struct notify_entry *e,
+ sys_notify_callback_t callback, void *private, void **handle)
{
if (!ctx->notify_watch) {
return NT_STATUS_NOT_IMPLEMENTED;
}
- return ctx->notify_watch(ctx, dirpath, filter, callback, private, handle);
+ return ctx->notify_watch(ctx, e, callback, private, handle);
}
/*
@@ -103,6 +107,12 @@ NTSTATUS sys_notify_watch(struct sys_notify_context *ctx, const char *dirpath,
*/
NTSTATUS sys_notify_register(struct sys_notify_backend *backend)
{
- DLIST_ADD(backends, backend);
+ struct sys_notify_backend *b;
+ b = talloc_realloc(talloc_autofree_context(), backends,
+ struct sys_notify_backend, num_backends+1);
+ NT_STATUS_HAVE_NO_MEMORY(b);
+ backends = b;
+ backends[num_backends] = *backend;
+ num_backends++;
return NT_STATUS_OK;
}
diff --git a/source4/ntvfs/sysdep/sys_notify.h b/source4/ntvfs/sysdep/sys_notify.h
index 9ad5ed7555..9cb01a1db4 100644
--- a/source4/ntvfs/sysdep/sys_notify.h
+++ b/source4/ntvfs/sysdep/sys_notify.h
@@ -25,28 +25,27 @@ struct sys_notify_context;
typedef void (*sys_notify_callback_t)(struct sys_notify_context *,
void *, struct notify_event *ev);
+typedef NTSTATUS (*notify_watch_t)(struct sys_notify_context *ctx,
+ struct notify_event *e,
+ sys_notify_callback_t callback, void *private,
+ void **handle);
+
struct sys_notify_context {
struct event_context *ev;
void *private; /* for use of backend */
- NTSTATUS (*notify_watch)(struct sys_notify_context *ctx, const char *dirpath,
- uint32_t filter, sys_notify_callback_t callback,
- void *private, void **handle);
const char *name;
+ notify_watch_t notify_watch;
};
struct sys_notify_backend {
- struct sys_notify_backend *next, *prev;
const char *name;
- NTSTATUS (*notify_watch)(struct sys_notify_context *ctx, const char *dirpath,
- uint32_t filter, sys_notify_callback_t callback,
- void *private, void **handle);
+ notify_watch_t notify_watch;
};
NTSTATUS sys_notify_register(struct sys_notify_backend *backend);
struct sys_notify_context *sys_notify_init(int snum,
TALLOC_CTX *mem_ctx,
struct event_context *ev);
-NTSTATUS sys_notify_watch(struct sys_notify_context *ctx, const char *dirpath,
- uint32_t filter, sys_notify_callback_t callback,
- void *private, void **handle);
-
+NTSTATUS sys_notify_watch(struct sys_notify_context *ctx, struct notify_entry *e,
+ sys_notify_callback_t callback, void *private,
+ void **handle);