diff options
-rw-r--r-- | source4/ntvfs/common/notify.c | 61 | ||||
-rw-r--r-- | source4/ntvfs/posix/pvfs_notify.c | 6 | ||||
-rw-r--r-- | source4/ntvfs/sysdep/inotify.c | 22 | ||||
-rw-r--r-- | source4/ntvfs/sysdep/sys_notify.c | 38 | ||||
-rw-r--r-- | source4/ntvfs/sysdep/sys_notify.h | 21 |
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); |