From 57bde8631fc65f9b8e10eee7f948e5690412bead Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 29 Mar 2006 13:31:30 +0000 Subject: [PATCH] r14755: the change notify code now passes most of the RAW-NOTIFY test. Still more work to do though (This used to be commit 4d234b37e528137b5c00f6bbb84c2d6939fea324) --- source4/ntvfs/common/notify.c | 7 ++- source4/ntvfs/posix/pvfs_mkdir.c | 6 +++ source4/ntvfs/posix/pvfs_notify.c | 89 ++++++++++++++++++++++++++----- source4/ntvfs/posix/pvfs_wait.c | 17 ++++-- 4 files changed, 98 insertions(+), 21 deletions(-) diff --git a/source4/ntvfs/common/notify.c b/source4/ntvfs/common/notify.c index 604b6a1a2d9..bc04c830f16 100644 --- a/source4/ntvfs/common/notify.c +++ b/source4/ntvfs/common/notify.c @@ -332,9 +332,6 @@ static BOOL notify_match(struct notify_context *notify, struct notify_entry *e, return False; } - if (path[len] == 0) { - return True; - } if (path[len] != '/') { return False; } @@ -395,7 +392,9 @@ void notify_trigger(struct notify_context *notify, /* this needs to be changed to a log(n) search */ for (i=0;iarray->num_entries;i++) { if (notify_match(notify, ¬ify->array->entries[i], path, action)) { - notify_send(notify, ¬ify->array->entries[i], path, action); + notify_send(notify, ¬ify->array->entries[i], + path + strlen(notify->array->entries[i].path) + 1, + action); } } } diff --git a/source4/ntvfs/posix/pvfs_mkdir.c b/source4/ntvfs/posix/pvfs_mkdir.c index 047b6f45a7a..5ec7df3b9d3 100644 --- a/source4/ntvfs/posix/pvfs_mkdir.c +++ b/source4/ntvfs/posix/pvfs_mkdir.c @@ -83,6 +83,8 @@ static NTSTATUS pvfs_t2mkdir(struct pvfs_state *pvfs, return status; } + notify_trigger(pvfs->notify_context, NOTIFY_ACTION_ADDED, name->full_name); + return NT_STATUS_OK; } @@ -135,6 +137,8 @@ NTSTATUS pvfs_mkdir(struct ntvfs_module_context *ntvfs, return status; } + notify_trigger(pvfs->notify_context, NOTIFY_ACTION_ADDED, name->full_name); + return NT_STATUS_OK; } @@ -172,5 +176,7 @@ NTSTATUS pvfs_rmdir(struct ntvfs_module_context *ntvfs, return pvfs_map_errno(pvfs, errno); } + notify_trigger(pvfs->notify_context, NOTIFY_ACTION_REMOVED, name->full_name); + return NT_STATUS_OK; } diff --git a/source4/ntvfs/posix/pvfs_notify.c b/source4/ntvfs/posix/pvfs_notify.c index 566b6bc0e29..55a9767863e 100644 --- a/source4/ntvfs/posix/pvfs_notify.c +++ b/source4/ntvfs/posix/pvfs_notify.c @@ -33,10 +33,13 @@ struct pvfs_notify_buffer { struct notify_changes *changes; uint32_t max_buffer_size; uint32_t current_buffer_size; - void *wait_handle; + + /* these last two are only present when a notify request is + pending */ + struct ntvfs_request *req; + struct smb_notify *info; }; - /* destroy a notify buffer. Called when the handle is closed */ @@ -48,6 +51,34 @@ static int pvfs_notify_destructor(void *ptr) return 0; } +/* + send a reply to a pending notify request +*/ +static void pvfs_notify_send(struct pvfs_notify_buffer *notify_buffer) +{ + struct ntvfs_request *req = notify_buffer->req; + struct smb_notify *info = notify_buffer->info; + + info->out.num_changes = notify_buffer->num_changes; + info->out.changes = talloc_steal(req, notify_buffer->changes); + notify_buffer->num_changes = 0; + notify_buffer->changes = NULL; + notify_buffer->current_buffer_size = 0; + + notify_buffer->req = NULL; + notify_buffer->info = NULL; + + DEBUG(0,("sending %d changes\n", info->out.num_changes)); + + if (info->out.num_changes == 0) { + req->async_states->status = NT_STATUS_CANCELLED; + } else { + req->async_states->status = NT_STATUS_OK; + } + req->async_states->send_fn(req); +} + + /* called when a async notify event comes in @@ -55,7 +86,17 @@ static int pvfs_notify_destructor(void *ptr) static void pvfs_notify_callback(void *private, const struct notify_event *ev) { struct pvfs_notify_buffer *n = talloc_get_type(private, struct pvfs_notify_buffer); - DEBUG(0,("got notify for '%s'\n", ev->path)); + + n->changes = talloc_realloc(n, n->changes, struct notify_changes, n->num_changes+1); + n->changes[n->num_changes].action = ev->action; + n->changes[n->num_changes].name.s = talloc_strdup(n->changes, ev->path); + n->num_changes++; + + DEBUG(0,("got notify for '%s' action=%d\n", ev->path, ev->action)); + + if (n->req != NULL) { + pvfs_notify_send(n); + } } /* @@ -86,6 +127,22 @@ static NTSTATUS pvfs_notify_setup(struct pvfs_state *pvfs, struct pvfs_file *f, return NT_STATUS_OK; } +/* + called from the pvfs_wait code when either an event has come in, or + the notify request has been cancelled +*/ +static void pvfs_notify_end(void *private, enum pvfs_wait_notice reason) +{ + struct pvfs_notify_buffer *notify_buffer = talloc_get_type(private, struct pvfs_notify_buffer); + struct ntvfs_request *req = notify_buffer->req; + + if (req == NULL) { + /* nothing to do, nobody is waiting */ + return; + } + + pvfs_notify_send(notify_buffer); +} /* change notify request - always async. This request blocks until the event buffer is non-empty */ @@ -110,7 +167,7 @@ NTSTATUS pvfs_notify(struct ntvfs_module_context *ntvfs, /* its only valid for directories */ if (f->handle->fd != -1) { - return NT_STATUS_NOT_A_DIRECTORY; + return NT_STATUS_INVALID_PARAMETER; } /* if the handle doesn't currently have a notify buffer then @@ -123,19 +180,27 @@ NTSTATUS pvfs_notify(struct ntvfs_module_context *ntvfs, NT_STATUS_NOT_OK_RETURN(status); } + req->async_states->status = NT_STATUS_OK; + + if (f->notify_buffer->req != NULL) { + DEBUG(0,("Notify already setup\n")); + pvfs_notify_send(f->notify_buffer); + } + + f->notify_buffer->req = talloc_reference(f->notify_buffer, req); + f->notify_buffer->info = info; + /* if the buffer is empty then start waiting */ if (f->notify_buffer->num_changes == 0) { - req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; + void *wait_handle = + pvfs_wait_message(pvfs, req, -1, timeval_zero(), + pvfs_notify_end, f->notify_buffer); + NT_STATUS_HAVE_NO_MEMORY(wait_handle); + talloc_steal(req, wait_handle); return NT_STATUS_OK; } - /* otherwise if the buffer is not empty then return its - contents immediately */ - info->out.num_changes = f->notify_buffer->num_changes; - info->out.changes = talloc_steal(req, f->notify_buffer->changes); - f->notify_buffer->num_changes = 0; - f->notify_buffer->changes = NULL; - f->notify_buffer->current_buffer_size = 0; + pvfs_notify_send(f->notify_buffer); return NT_STATUS_OK; } diff --git a/source4/ntvfs/posix/pvfs_wait.c b/source4/ntvfs/posix/pvfs_wait.c index 2d7e41c2474..5750c0fe087 100644 --- a/source4/ntvfs/posix/pvfs_wait.c +++ b/source4/ntvfs/posix/pvfs_wait.c @@ -105,7 +105,9 @@ static void pvfs_wait_timeout(struct event_context *ev, static int pvfs_wait_destructor(void *ptr) { struct pvfs_wait *pwait = ptr; - messaging_deregister(pwait->msg_ctx, pwait->msg_type, pwait); + if (pwait->msg_type != -1) { + messaging_deregister(pwait->msg_ctx, pwait->msg_type, pwait); + } DLIST_REMOVE(pwait->pvfs->wait_list, pwait); return 0; } @@ -116,6 +118,9 @@ static int pvfs_wait_destructor(void *ptr) the return value is a handle. To stop waiting talloc_free this handle. + + if msg_type == -1 then no message is registered, and it is assumed + that the caller handles any messaging setup needed */ void *pvfs_wait_message(struct pvfs_state *pvfs, struct ntvfs_request *req, @@ -146,10 +151,12 @@ void *pvfs_wait_message(struct pvfs_state *pvfs, /* register with the messaging subsystem for this message type */ - messaging_register(pwait->msg_ctx, - pwait, - msg_type, - pvfs_wait_dispatch); + if (msg_type != -1) { + messaging_register(pwait->msg_ctx, + pwait, + msg_type, + pvfs_wait_dispatch); + } /* tell the main smb server layer that we will be replying asynchronously */ -- 2.34.1