diff options
Diffstat (limited to 'source4/ntvfs/posix/pvfs_notify.c')
-rw-r--r-- | source4/ntvfs/posix/pvfs_notify.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/source4/ntvfs/posix/pvfs_notify.c b/source4/ntvfs/posix/pvfs_notify.c new file mode 100644 index 0000000000..566b6bc0e2 --- /dev/null +++ b/source4/ntvfs/posix/pvfs_notify.c @@ -0,0 +1,141 @@ +/* + Unix SMB/CIFS implementation. + + POSIX NTVFS backend - notify + + 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 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" +#include "vfs_posix.h" +#include "lib/messaging/irpc.h" +#include "messaging/messaging.h" + +/* pending notifies buffer, hung off struct pvfs_file for open directories + that have used change notify */ +struct pvfs_notify_buffer { + struct pvfs_file *f; + uint32_t num_changes; + struct notify_changes *changes; + uint32_t max_buffer_size; + uint32_t current_buffer_size; + void *wait_handle; +}; + + +/* + destroy a notify buffer. Called when the handle is closed + */ +static int pvfs_notify_destructor(void *ptr) +{ + struct pvfs_notify_buffer *n = talloc_get_type(ptr, struct pvfs_notify_buffer); + notify_remove(n->f->pvfs->notify_context, n); + n->f->notify_buffer = NULL; + return 0; +} + + +/* + called when a async notify event comes in +*/ +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)); +} + +/* + setup a notify buffer on a directory handle +*/ +static NTSTATUS pvfs_notify_setup(struct pvfs_state *pvfs, struct pvfs_file *f, + uint32_t buffer_size, uint32_t filter, BOOL recursive) +{ + NTSTATUS status; + struct notify_entry e; + + f->notify_buffer = talloc_zero(f, struct pvfs_notify_buffer); + NT_STATUS_HAVE_NO_MEMORY(f->notify_buffer); + + f->notify_buffer->max_buffer_size = buffer_size; + f->notify_buffer->f = f; + + e.filter = filter; + e.path = f->handle->name->full_name; + e.recursive = recursive; + + status = notify_add(pvfs->notify_context, &e, + pvfs_notify_callback, f->notify_buffer); + NT_STATUS_NOT_OK_RETURN(status); + + talloc_set_destructor(f->notify_buffer, pvfs_notify_destructor); + + return NT_STATUS_OK; +} + + +/* change notify request - always async. This request blocks until the + event buffer is non-empty */ +NTSTATUS pvfs_notify(struct ntvfs_module_context *ntvfs, + struct ntvfs_request *req, + struct smb_notify *info) +{ + struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data, + struct pvfs_state); + struct pvfs_file *f; + NTSTATUS status; + + f = pvfs_find_fd(pvfs, req, info->in.file.fnum); + if (!f) { + return NT_STATUS_INVALID_HANDLE; + } + + /* this request doesn't make sense unless its async */ + if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { + return NT_STATUS_INVALID_PARAMETER; + } + + /* its only valid for directories */ + if (f->handle->fd != -1) { + return NT_STATUS_NOT_A_DIRECTORY; + } + + /* if the handle doesn't currently have a notify buffer then + create one */ + if (f->notify_buffer == NULL) { + status = pvfs_notify_setup(pvfs, f, + info->in.buffer_size, + info->in.completion_filter, + info->in.recursive); + NT_STATUS_NOT_OK_RETURN(status); + } + + /* if the buffer is empty then start waiting */ + if (f->notify_buffer->num_changes == 0) { + req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC; + 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; + + return NT_STATUS_OK; +} |