From 3434cd778c975eb1bb29d257770bd6dbb2335ce9 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 21 Mar 2006 11:47:24 +0000 Subject: r14616: added notify change support to the posix backend It doesn't fully work yet, and doesn't yet have all the efficiency that is planned, but it doesn't break anything and I wanted to get the code in the tree to minimise the chance of collisions with the work metze is doing. (This used to be commit 1624ea88e6eef89caacc36e7513aa79df0d579b9) --- source4/ntvfs/posix/config.mk | 1 + source4/ntvfs/posix/pvfs_notify.c | 141 ++++++++++++++++++++++++++++++++++++++ source4/ntvfs/posix/pvfs_open.c | 3 + source4/ntvfs/posix/pvfs_unlink.c | 5 ++ source4/ntvfs/posix/vfs_posix.c | 8 +++ source4/ntvfs/posix/vfs_posix.h | 4 ++ 6 files changed, 162 insertions(+) create mode 100644 source4/ntvfs/posix/pvfs_notify.c (limited to 'source4/ntvfs/posix') diff --git a/source4/ntvfs/posix/config.mk b/source4/ntvfs/posix/config.mk index ccf2c2d1a9..c49fbc88b7 100644 --- a/source4/ntvfs/posix/config.mk +++ b/source4/ntvfs/posix/config.mk @@ -29,6 +29,7 @@ OBJ_FILES = \ pvfs_xattr.o \ pvfs_streams.o \ pvfs_acl.o \ + pvfs_notify.o \ xattr_system.o \ xattr_tdb.o REQUIRED_SUBSYSTEMS = NDR_XATTR EXT_LIB_XATTR EXT_LIB_BLKID 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; +} diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index 2724339323..3c3e13bc91 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -271,6 +271,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs, f->share_access = io->generic.in.share_access; f->impersonation = io->generic.in.impersonation; f->access_mask = access_mask; + f->notify_buffer = NULL; f->handle->pvfs = pvfs; f->handle->name = talloc_steal(f->handle, name); @@ -688,6 +689,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, f->share_access = io->generic.in.share_access; f->access_mask = access_mask; f->impersonation = io->generic.in.impersonation; + f->notify_buffer = NULL; f->handle->pvfs = pvfs; f->handle->name = talloc_steal(f->handle, name); @@ -1113,6 +1115,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, f->share_access = io->generic.in.share_access; f->access_mask = access_mask; f->impersonation = io->generic.in.impersonation; + f->notify_buffer = NULL; f->handle->pvfs = pvfs; f->handle->fd = -1; diff --git a/source4/ntvfs/posix/pvfs_unlink.c b/source4/ntvfs/posix/pvfs_unlink.c index 76c9bc10a4..3a6e4bba2f 100644 --- a/source4/ntvfs/posix/pvfs_unlink.c +++ b/source4/ntvfs/posix/pvfs_unlink.c @@ -103,6 +103,11 @@ static NTSTATUS pvfs_unlink_one(struct pvfs_state *pvfs, status = pvfs_map_errno(pvfs, errno); } + if (NT_STATUS_IS_OK(status)) { + notify_trigger(pvfs->notify_context, NOTIFY_ACTION_REMOVED, + name->full_name); + } + talloc_free(name); return status; diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c index cb441cb4c9..0469e54d35 100644 --- a/source4/ntvfs/posix/vfs_posix.c +++ b/source4/ntvfs/posix/vfs_posix.c @@ -185,6 +185,13 @@ static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs, return NT_STATUS_INTERNAL_DB_CORRUPTION; } + pvfs->notify_context = notify_init(pvfs, + pvfs->ntvfs->ctx->server_id, + pvfs->ntvfs->ctx->msg_ctx); + if (pvfs->notify_context == NULL) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + pvfs->sidmap = sidmap_open(pvfs); if (pvfs->sidmap == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; @@ -317,6 +324,7 @@ NTSTATUS ntvfs_posix_init(void) ops.logoff = pvfs_logoff; ops.async_setup = pvfs_async_setup; ops.cancel = pvfs_cancel; + ops.notify = pvfs_notify; /* register ourselves with the NTVFS subsystem. We register under the name 'default' as we wish to be the default diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h index 59e4ec1abf..aa452c6a13 100644 --- a/source4/ntvfs/posix/vfs_posix.h +++ b/source4/ntvfs/posix/vfs_posix.h @@ -42,6 +42,7 @@ struct pvfs_state { struct brl_context *brl_context; struct odb_context *odb_context; + struct notify_context *notify_context; struct sidmap_context *sidmap; /* a list of pending async requests. Needed to support @@ -179,6 +180,9 @@ struct pvfs_file { /* a count of active locks - used to avoid calling brl_close on file close */ uint64_t lock_count; + + /* for directories, a buffer of pending notify events */ + struct pvfs_notify_buffer *notify_buffer; }; /* the state of a search started with pvfs_search_first() */ -- cgit