r14616: added notify change support to the posix backend
authorAndrew Tridgell <tridge@samba.org>
Tue, 21 Mar 2006 11:47:24 +0000 (11:47 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:59:02 +0000 (13:59 -0500)
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)

13 files changed:
source4/lib/messaging/messaging.h
source4/lib/tdb/include/tdbutil.h
source4/librpc/config.mk
source4/librpc/idl/notify.idl [new file with mode: 0644]
source4/ntvfs/common/notify.c [new file with mode: 0644]
source4/ntvfs/config.mk
source4/ntvfs/ntvfs.h
source4/ntvfs/posix/config.mk
source4/ntvfs/posix/pvfs_notify.c [new file with mode: 0644]
source4/ntvfs/posix/pvfs_open.c
source4/ntvfs/posix/pvfs_unlink.c
source4/ntvfs/posix/vfs_posix.c
source4/ntvfs/posix/vfs_posix.h

index dcb20d69b1ae8ccebd7f37b02b3ac14e648cd9ab..de65eb9ffe3b1aa4645e42972a819a4bf87f1db4 100644 (file)
@@ -31,5 +31,6 @@ struct messaging_context;
 #define MSG_BRL_RETRY          4
 #define MSG_PVFS_RETRY_OPEN    5
 #define MSG_IRPC                6
+#define MSG_PVFS_NOTIFY                7
 
 #endif
index 02802c958dc2a399db0a999f11de7cac9f4109c9..26747373f4afdb3555229a0b9b2f2ea177a6a93f 100644 (file)
@@ -44,6 +44,7 @@ int tdb_traverse_delete_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA d
                      void *state);
 int tdb_store_bystring(struct tdb_context *tdb, const char *keystr, TDB_DATA data, int flags);
 TDB_DATA tdb_fetch_bystring(struct tdb_context *tdb, const char *keystr);
+int tdb_delete_bystring(struct tdb_context *tdb, const char *keystr);
 int tdb_unpack(struct tdb_context *tdb, char *buf, int bufsize, const char *fmt, ...);
 size_t tdb_pack(struct tdb_context *tdb, char *buf, int bufsize, const char *fmt, ...);
 
index 93ea86f8e3e7da2cb487a0e342d00c79814d0c45..eb8039c126e170fd76e312814c3e6ccbbc682f63 100644 (file)
@@ -326,6 +326,10 @@ REQUIRED_SUBSYSTEMS = LIBNDR NDR_SECURITY
 OBJ_FILES = gen_ndr/ndr_opendb.o
 REQUIRED_SUBSYSTEMS = LIBNDR
 
+[SUBSYSTEM::NDR_NOTIFY]
+OBJ_FILES = gen_ndr/ndr_notify.o
+REQUIRED_SUBSYSTEMS = LIBNDR
+
 [SUBSYSTEM::NDR_SCHANNEL]
 OBJ_FILES = gen_ndr/ndr_schannel.o
 REQUIRED_SUBSYSTEMS = LIBNDR
@@ -363,7 +367,7 @@ REQUIRED_SUBSYSTEMS = \
        NDR_NETLOGON NDR_TRKWKS NDR_KEYSVC NDR_KRB5PAC NDR_XATTR NDR_SCHANNEL \
        NDR_ROT NDR_DRSBLOBS NDR_SVCCTL NDR_NBT NDR_WINSREPL NDR_SECURITY \
        NDR_INITSHUTDOWN NDR_DNSSERVER NDR_WINSTATION NDR_IRPC NDR_DCOM NDR_OPENDB \
-       NDR_SASL_HELPERS
+       NDR_SASL_HELPERS NDR_NOTIFY
 
 [LIBRARY::RPC_NDR_ROT]
 VERSION = 0.0.1
diff --git a/source4/librpc/idl/notify.idl b/source4/librpc/idl/notify.idl
new file mode 100644 (file)
index 0000000..6c3414c
--- /dev/null
@@ -0,0 +1,37 @@
+#include "idl_types.h"
+
+/*
+   IDL structures for notify change code
+
+   this defines the structures used in the notify database code, and
+   the change notify buffers
+*/
+
+[
+  pointer_default(unique)
+]
+interface notify
+{
+
+       /* structure used in the notify database */
+       typedef [public] struct {
+               uint32 server;
+               uint32 filter;
+               boolean32 recursive;
+               utf8string path;
+               pointer private;
+       } notify_entry;
+
+       typedef [public] struct {
+               uint32 num_entries;
+               notify_entry entries[num_entries];
+       } notify_array;
+
+       /* structure sent between servers in notify messages */
+       typedef [public] struct {
+               uint32 action;
+               utf8string path;
+               pointer private;
+       } notify_event;
+
+}
diff --git a/source4/ntvfs/common/notify.c b/source4/ntvfs/common/notify.c
new file mode 100644 (file)
index 0000000..48b3559
--- /dev/null
@@ -0,0 +1,402 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   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.
+*/
+
+/*
+  this is the change notify database. It implements mechanisms for
+  storing current change notify waiters in a tdb, and checking if a
+  given event matches any of the stored notify waiiters.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "lib/tdb/include/tdb.h"
+#include "lib/tdb/include/tdbutil.h"
+#include "messaging/messaging.h"
+#include "db_wrap.h"
+#include "smb_server/smb_server.h"
+#include "lib/messaging/irpc.h"
+#include "librpc/gen_ndr/ndr_notify.h"
+#include "dlinklist.h"
+
+struct notify_context {
+       struct tdb_wrap *w;
+       uint32_t server;
+       struct messaging_context *messaging_ctx;
+       struct notify_list *list;
+       struct notify_array *array;
+};
+
+
+struct notify_list {
+       struct notify_list *next, *prev;
+       void *private;
+       void (*callback)(void *, const struct notify_event *);
+};
+
+#define NOTIFY_KEY "notify array"
+
+static NTSTATUS notify_remove_all(struct notify_context *notify);
+static void notify_handler(struct messaging_context *msg_ctx, void *private, 
+                          uint32_t msg_type, uint32_t server_id, DATA_BLOB *data);
+
+/*
+  destroy the notify context
+*/
+static int notify_destructor(void *p)
+{
+       struct notify_context *notify = talloc_get_type(p, struct notify_context);
+       messaging_deregister(notify->messaging_ctx, MSG_PVFS_NOTIFY, notify);
+       notify_remove_all(notify);
+       return 0;
+}
+
+/*
+  Open up the notify.tdb database. You should close it down using
+  talloc_free(). We need the messaging_ctx to allow for notifications
+  via internal messages
+*/
+struct notify_context *notify_init(TALLOC_CTX *mem_ctx, uint32_t server, 
+                                  struct messaging_context *messaging_ctx)
+{
+       char *path;
+       struct notify_context *notify;
+
+       notify = talloc(mem_ctx, struct notify_context);
+       if (notify == NULL) {
+               return NULL;
+       }
+
+       path = smbd_tmp_path(notify, "notify.tdb");
+       notify->w = tdb_wrap_open(notify, path, 0,  
+                              TDB_DEFAULT,
+                              O_RDWR|O_CREAT, 0600);
+       talloc_free(path);
+       if (notify->w == NULL) {
+               talloc_free(notify);
+               return NULL;
+       }
+
+       notify->server = server;
+       notify->messaging_ctx = messaging_ctx;
+       notify->list = NULL;
+       notify->array = NULL;
+
+       talloc_set_destructor(notify, notify_destructor);
+
+       /* register with the messaging subsystem for the notify
+          message type */
+       messaging_register(notify->messaging_ctx, notify, 
+                          MSG_PVFS_NOTIFY, notify_handler);
+
+       return notify;
+}
+
+/*
+  load the notify array
+*/
+static NTSTATUS notify_load(struct notify_context *notify)
+{
+       TDB_DATA dbuf;
+       DATA_BLOB blob;
+       NTSTATUS status;
+
+       talloc_free(notify->array);
+       notify->array = talloc_zero(notify, struct notify_array);
+       NT_STATUS_HAVE_NO_MEMORY(notify->array);
+
+       dbuf = tdb_fetch_bystring(notify->w->tdb, NOTIFY_KEY);
+       if (dbuf.dptr == NULL) {
+               return NT_STATUS_OK;
+       }
+
+       blob.data = dbuf.dptr;
+       blob.length = dbuf.dsize;
+
+       status = ndr_pull_struct_blob(&blob, notify->array, notify->array, 
+                                     (ndr_pull_flags_fn_t)ndr_pull_notify_array);
+       free(dbuf.dptr);
+
+       return status;
+}
+
+
+/*
+  save the notify array
+*/
+static NTSTATUS notify_save(struct notify_context *notify)
+{
+       TDB_DATA dbuf;
+       DATA_BLOB blob;
+       NTSTATUS status;
+       int ret;
+       TALLOC_CTX *tmp_ctx;
+
+       if (notify->array->num_entries == 0) {
+               ret = tdb_delete_bystring(notify->w->tdb, NOTIFY_KEY);
+               if (ret != 0) {
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+               return NT_STATUS_OK;
+       }
+
+       tmp_ctx = talloc_new(notify);
+
+       status = ndr_push_struct_blob(&blob, tmp_ctx, notify->array, 
+                                     (ndr_push_flags_fn_t)ndr_push_notify_array);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(tmp_ctx);
+               return status;
+       }
+
+       dbuf.dptr = blob.data;
+       dbuf.dsize = blob.length;
+               
+       ret = tdb_store_bystring(notify->w->tdb, NOTIFY_KEY, dbuf, TDB_REPLACE);
+       talloc_free(tmp_ctx);
+       if (ret != 0) {
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       return NT_STATUS_OK;
+}
+
+
+/*
+  handle incoming notify messages
+*/
+static void notify_handler(struct messaging_context *msg_ctx, void *private, 
+                          uint32_t msg_type, uint32_t server_id, DATA_BLOB *data)
+{
+       struct notify_context *notify = talloc_get_type(private, struct notify_context);
+       NTSTATUS status;
+       struct notify_event ev;
+       TALLOC_CTX *tmp_ctx = talloc_new(notify);
+       struct notify_list *listel;
+
+       status = ndr_pull_struct_blob(data, tmp_ctx, &ev, 
+                                     (ndr_pull_flags_fn_t)ndr_pull_notify_event);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(tmp_ctx);
+               return;
+       }
+
+       for (listel=notify->list;listel;listel=listel->next) {
+               if (listel->private == ev.private) {
+                       listel->callback(listel->private, &ev);
+                       break;
+               }
+       }
+
+       talloc_free(tmp_ctx);   
+}
+
+/*
+  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,
+                   void (*callback)(void *, const struct notify_event *), 
+                   void *private)
+{
+       NTSTATUS status;
+       struct notify_list *listel;
+
+       status = notify_load(notify);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       notify->array->entries = talloc_realloc(notify->array, notify->array->entries, 
+                                               struct notify_entry,
+                                               notify->array->num_entries+1);
+
+       if (notify->array->entries == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       notify->array->entries[notify->array->num_entries] = *e;
+       notify->array->entries[notify->array->num_entries].private = private;
+       notify->array->entries[notify->array->num_entries].server = notify->server;
+       notify->array->num_entries++;
+
+       status = notify_save(notify);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       listel = talloc(notify, struct notify_list);
+       NT_STATUS_HAVE_NO_MEMORY(listel);
+
+       listel->private = private;
+       listel->callback = callback;
+       DLIST_ADD(notify->list, listel);
+
+       return status;
+}
+
+/*
+  remove a notify watch. Called when the directory handle is closed
+*/
+NTSTATUS notify_remove(struct notify_context *notify, void *private)
+{
+       NTSTATUS status;
+       struct notify_list *listel;
+       int i;
+
+       for (listel=notify->list;listel;listel=listel->next) {
+               if (listel->private == private) {
+                       DLIST_REMOVE(notify->list, listel);
+                       break;
+               }
+       }
+       if (listel == NULL) {
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       status = notify_load(notify);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       for (i=0;i<notify->array->num_entries;i++) {
+               if (notify->server == notify->array->entries[i].server && 
+                   private == notify->array->entries[i].private) {
+                       break;
+               }
+       }
+       if (i == notify->array->num_entries) {
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       if (i < notify->array->num_entries-1) {
+               memmove(&notify->array->entries[i], &notify->array->entries[i+1], 
+                       sizeof(notify->array->entries[i])*(notify->array->num_entries-(i+1)));
+       }
+       notify->array->num_entries--;
+
+       return notify_save(notify);
+}
+
+/*
+  remove all notify watches for this messaging server
+*/
+static NTSTATUS notify_remove_all(struct notify_context *notify)
+{
+       NTSTATUS status;
+       int i;
+
+       if (notify->list == NULL) {
+               return NT_STATUS_OK;
+       }
+
+       status = notify_load(notify);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       for (i=0;i<notify->array->num_entries;i++) {
+               if (notify->server == notify->array->entries[i].server) {
+                       if (i < notify->array->num_entries-1) {
+                               memmove(&notify->array->entries[i], &notify->array->entries[i+1], 
+                                       sizeof(notify->array->entries[i])*(notify->array->num_entries-(i+1)));
+                       }
+                       i--;
+                       notify->array->num_entries--;
+               }
+       }
+
+
+       return notify_save(notify);
+}
+
+
+/*
+  see if a notify event matches
+*/
+static BOOL notify_match(struct notify_context *notify, struct notify_entry *e,
+                        const char *path, uint32_t action)
+{
+       size_t len = strlen(e->path);
+
+       /* TODO: check action */
+
+       if (strncmp(path, e->path, len) != 0) {
+               return False;
+       }
+
+       if (path[len] == 0) {
+               return True;
+       }
+       if (path[len] != '/') {
+               return False;
+       }
+
+       if (!e->recursive) {
+               if (strchr(&path[len+1], '/') != NULL) {
+                       return False;
+               }
+       }
+
+       return True;
+}
+
+
+/*
+  send a notify message to another messaging server
+*/
+static void notify_send(struct notify_context *notify, struct notify_entry *e,
+                       const char *path, uint32_t action)
+{
+       struct notify_event ev;
+       DATA_BLOB data;
+       NTSTATUS status;
+       TALLOC_CTX *tmp_ctx;
+
+       ev.action = action;
+       ev.path = path;
+       ev.private = e->private;
+
+       tmp_ctx = talloc_new(notify);
+
+       status = ndr_push_struct_blob(&data, tmp_ctx, &ev, 
+                                     (ndr_push_flags_fn_t)ndr_push_notify_event);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(tmp_ctx);
+               return;
+       }
+
+       status = messaging_send(notify->messaging_ctx, e->server, 
+                               MSG_PVFS_NOTIFY, &data);
+       talloc_free(tmp_ctx);
+}
+
+/*
+  trigger a notify message for anyone waiting on a matching event
+*/
+void notify_trigger(struct notify_context *notify,
+                   uint32_t action, const char *path)
+{
+       NTSTATUS status;
+       int i;
+
+       status = notify_load(notify);
+       if (!NT_STATUS_IS_OK(status)) {
+               return;
+       }
+
+       /* this needs to be changed to a log(n) search */
+       for (i=0;i<notify->array->num_entries;i++) {
+               if (notify_match(notify, &notify->array->entries[i], path, action)) {
+                       notify_send(notify, &notify->array->entries[i], path, action);
+               }
+       }
+}
index 7a37641f91540c3251ec5ec77583fb29ccb40f43..8f8e47a7e6731899c0d9f7be0ac90d2e40729875 100644 (file)
@@ -78,6 +78,7 @@ OBJ_FILES = \
                ntvfs_util.o \
                common/brlock.o \
                common/opendb.o \
+               common/notify.o \
                common/sidmap.o
 REQUIRED_SUBSYSTEMS = NDR_OPENDB
 #
index cfb5515203dc17d5343d60ad954874e027c7221a..d0d5b7fd743af70eec99d116e4f44173da9ff770 100644 (file)
@@ -266,4 +266,5 @@ struct ntvfs_critical_sizes {
 
 struct messaging_context;
 #include "librpc/gen_ndr/security.h"
+#include "librpc/gen_ndr/notify.h"
 #include "ntvfs/ntvfs_proto.h"
index ccf2c2d1a9d264a02fe09b36573fccee8a151706..c49fbc88b732f911697426930d8abe625a07542d 100644 (file)
@@ -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 (file)
index 0000000..566b6bc
--- /dev/null
@@ -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;
+}
index 27243393237b220bc66747f01b982ca0ca481ce8..3c3e13bc91d88fd31b2e0ab7c5510a912b028502 100644 (file)
@@ -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;
index 76c9bc10a408881033dc067bbecbd4d832b92694..3a6e4bba2f89f3d71cf951f47d674dbe4a60a5b6 100644 (file)
@@ -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;
index cb441cb4c980c2d7d906c27e7ea21a7b467fab50..0469e54d356287652adadd9620259d6543a84be2 100644 (file)
@@ -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
index 59e4ec1abfbf85b292b11116bcc57792fe4f33cc..aa452c6a13006dd53fd431c9cb54b21a095946d0 100644 (file)
@@ -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() */