The branch, v3-2-ctdb has been updated
       via  c500507e5e558c11d354f807a7031c675b8a977c (commit)
       via  66f0303708ab953185368b936cd0b160154cd9a4 (commit)
       via  c216d1e64298f6013e9f1f542d0289883c0cbffd (commit)
      from  d00bc38588e9138c8948843f07b7a101ce6e8b23 (commit)

http://gitweb.samba.org/?p=obnox/samba-ctdb.git;a=shortlog;h=v3-2-ctdb


- Log -----------------------------------------------------------------
commit c500507e5e558c11d354f807a7031c675b8a977c
Author: Volker Lendecke <v...@samba.org>
Date:   Tue Apr 14 20:39:14 2009 +0200

    Add notify_onelevel.tdb
    
    This optimizes non-recursive notifys. For non-recursive notifies we can use 
a
    per-directory file-id indexed notify record. This matters for the Windows
    Explorer and IIS cases which do not use recursive notifies. In these cases, 
we
    do not have to shuffle around the whole notify record on every change.
    
    For the cluster case, this improves correctness of the notifies, ctdb only
    distributes the tdb seqnum once a second, so we can lose notifies.

commit 66f0303708ab953185368b936cd0b160154cd9a4
Author: Volker Lendecke <v...@samba.org>
Date:   Tue Apr 14 14:56:35 2009 +0200

    Rename notify_context->db to db_recursive

commit c216d1e64298f6013e9f1f542d0289883c0cbffd
Author: Steven Danneman <steven.danne...@isilon.com>
Date:   Fri Feb 20 13:23:53 2009 -0800

    s3: Modifications to generic notify structures to allow implementation of 
OneFS notify.
    
    The OneFS kernel based change notify system takes an fd of the directory
    to watch in it's initialization syscall.  Since we already have this
    directory open, this commit plumbs that fd down to the VFS layer via the
    notify_entry struct.
    
    We also need to know if the watch is taken out on a snapshot directory.
    The full file_id struct is also passed down to make this determination.
    The file_id marshalling wrappers are hand written here, but should
    eventually be auto-generated by moving the struct file_id into the idl.

-----------------------------------------------------------------------

Summary of changes:
 source/librpc/gen_ndr/ndr_notify.c |   71 +++++++++
 source/librpc/gen_ndr/ndr_notify.h |    3 +
 source/librpc/gen_ndr/notify.h     |    7 +
 source/librpc/idl/notify.idl       |    7 +
 source/librpc/ndr/ndr_basic.c      |   35 ++++
 source/smbd/files.c                |    4 +
 source/smbd/notify.c               |   13 ++
 source/smbd/notify_internal.c      |  307 ++++++++++++++++++++++++++++++++++-
 8 files changed, 438 insertions(+), 9 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source/librpc/gen_ndr/ndr_notify.c 
b/source/librpc/gen_ndr/ndr_notify.c
index 00ba8bc..844c278 100644
--- a/source/librpc/gen_ndr/ndr_notify.c
+++ b/source/librpc/gen_ndr/ndr_notify.c
@@ -10,6 +10,8 @@ _PUBLIC_ enum ndr_err_code ndr_push_notify_entry(struct 
ndr_push *ndr, int ndr_f
                NDR_CHECK(ndr_push_server_id(ndr, NDR_SCALARS, &r->server));
                NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->filter));
                NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->subdir_filter));
+               NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->dir_fd));
+               NDR_CHECK(ndr_push_file_id(ndr, NDR_SCALARS, &r->dir_id));
                {
                        uint32_t _flags_save_string = ndr->flags;
                        ndr_set_flags(&ndr->flags, 
LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM);
@@ -21,6 +23,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_notify_entry(struct 
ndr_push *ndr, int ndr_f
        }
        if (ndr_flags & NDR_BUFFERS) {
                NDR_CHECK(ndr_push_server_id(ndr, NDR_BUFFERS, &r->server));
+               NDR_CHECK(ndr_push_file_id(ndr, NDR_BUFFERS, &r->dir_id));
        }
        return NDR_ERR_SUCCESS;
 }
@@ -32,6 +35,8 @@ _PUBLIC_ enum ndr_err_code ndr_pull_notify_entry(struct 
ndr_pull *ndr, int ndr_f
                NDR_CHECK(ndr_pull_server_id(ndr, NDR_SCALARS, &r->server));
                NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->filter));
                NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->subdir_filter));
+               NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->dir_fd));
+               NDR_CHECK(ndr_pull_file_id(ndr, NDR_SCALARS, &r->dir_id));
                {
                        uint32_t _flags_save_string = ndr->flags;
                        ndr_set_flags(&ndr->flags, 
LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM);
@@ -43,6 +48,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_notify_entry(struct 
ndr_pull *ndr, int ndr_f
        }
        if (ndr_flags & NDR_BUFFERS) {
                NDR_CHECK(ndr_pull_server_id(ndr, NDR_BUFFERS, &r->server));
+               NDR_CHECK(ndr_pull_file_id(ndr, NDR_BUFFERS, &r->dir_id));
        }
        return NDR_ERR_SUCCESS;
 }
@@ -54,12 +60,77 @@ _PUBLIC_ void ndr_print_notify_entry(struct ndr_print *ndr, 
const char *name, co
        ndr_print_server_id(ndr, "server", &r->server);
        ndr_print_uint32(ndr, "filter", r->filter);
        ndr_print_uint32(ndr, "subdir_filter", r->subdir_filter);
+       ndr_print_uint32(ndr, "dir_fd", r->dir_fd);
+       ndr_print_file_id(ndr, "dir_id", &r->dir_id);
        ndr_print_string(ndr, "path", r->path);
        ndr_print_uint32(ndr, "path_len", r->path_len);
        ndr_print_pointer(ndr, "private_data", r->private_data);
        ndr->depth--;
 }
 
+_PUBLIC_ enum ndr_err_code ndr_push_notify_entry_array(struct ndr_push *ndr, 
int ndr_flags, const struct notify_entry_array *r)
+{
+       uint32_t cntr_entries_0;
+       if (ndr_flags & NDR_SCALARS) {
+               NDR_CHECK(ndr_push_align(ndr, 8));
+               NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_entries));
+               for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; 
cntr_entries_0++) {
+                       NDR_CHECK(ndr_push_notify_entry(ndr, NDR_SCALARS, 
&r->entries[cntr_entries_0]));
+               }
+       }
+       if (ndr_flags & NDR_BUFFERS) {
+               for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; 
cntr_entries_0++) {
+                       NDR_CHECK(ndr_push_notify_entry(ndr, NDR_BUFFERS, 
&r->entries[cntr_entries_0]));
+               }
+       }
+       return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ enum ndr_err_code ndr_pull_notify_entry_array(struct ndr_pull *ndr, 
int ndr_flags, struct notify_entry_array *r)
+{
+       uint32_t cntr_entries_0;
+       TALLOC_CTX *_mem_save_entries_0;
+       if (ndr_flags & NDR_SCALARS) {
+               NDR_CHECK(ndr_pull_align(ndr, 8));
+               NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_entries));
+               NDR_PULL_ALLOC_N(ndr, r->entries, r->num_entries);
+               _mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+               NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+               for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; 
cntr_entries_0++) {
+                       NDR_CHECK(ndr_pull_notify_entry(ndr, NDR_SCALARS, 
&r->entries[cntr_entries_0]));
+               }
+               NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0);
+       }
+       if (ndr_flags & NDR_BUFFERS) {
+               _mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr);
+               NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0);
+               for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; 
cntr_entries_0++) {
+                       NDR_CHECK(ndr_pull_notify_entry(ndr, NDR_BUFFERS, 
&r->entries[cntr_entries_0]));
+               }
+               NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0);
+       }
+       return NDR_ERR_SUCCESS;
+}
+
+_PUBLIC_ void ndr_print_notify_entry_array(struct ndr_print *ndr, const char 
*name, const struct notify_entry_array *r)
+{
+       uint32_t cntr_entries_0;
+       ndr_print_struct(ndr, name, "notify_entry_array");
+       ndr->depth++;
+       ndr_print_uint32(ndr, "num_entries", r->num_entries);
+       ndr->print(ndr, "%s: ARRAY(%d)", "entries", (int)r->num_entries);
+       ndr->depth++;
+       for (cntr_entries_0=0;cntr_entries_0<r->num_entries;cntr_entries_0++) {
+               char *idx_0=NULL;
+               if (asprintf(&idx_0, "[%d]", cntr_entries_0) != -1) {
+                       ndr_print_notify_entry(ndr, "entries", 
&r->entries[cntr_entries_0]);
+                       free(idx_0);
+               }
+       }
+       ndr->depth--;
+       ndr->depth--;
+}
+
 static enum ndr_err_code ndr_push_notify_depth(struct ndr_push *ndr, int 
ndr_flags, const struct notify_depth *r)
 {
        uint32_t cntr_entries_0;
diff --git a/source/librpc/gen_ndr/ndr_notify.h 
b/source/librpc/gen_ndr/ndr_notify.h
index 23d3d3f..fa2972d 100644
--- a/source/librpc/gen_ndr/ndr_notify.h
+++ b/source/librpc/gen_ndr/ndr_notify.h
@@ -10,6 +10,9 @@
 enum ndr_err_code ndr_push_notify_entry(struct ndr_push *ndr, int ndr_flags, 
const struct notify_entry *r);
 enum ndr_err_code ndr_pull_notify_entry(struct ndr_pull *ndr, int ndr_flags, 
struct notify_entry *r);
 void ndr_print_notify_entry(struct ndr_print *ndr, const char *name, const 
struct notify_entry *r);
+enum ndr_err_code ndr_push_notify_entry_array(struct ndr_push *ndr, int 
ndr_flags, const struct notify_entry_array *r);
+enum ndr_err_code ndr_pull_notify_entry_array(struct ndr_pull *ndr, int 
ndr_flags, struct notify_entry_array *r);
+void ndr_print_notify_entry_array(struct ndr_print *ndr, const char *name, 
const struct notify_entry_array *r);
 void ndr_print_notify_depth(struct ndr_print *ndr, const char *name, const 
struct notify_depth *r);
 enum ndr_err_code ndr_push_notify_array(struct ndr_push *ndr, int ndr_flags, 
const struct notify_array *r);
 enum ndr_err_code ndr_pull_notify_array(struct ndr_pull *ndr, int ndr_flags, 
struct notify_array *r);
diff --git a/source/librpc/gen_ndr/notify.h b/source/librpc/gen_ndr/notify.h
index c809702..9452805 100644
--- a/source/librpc/gen_ndr/notify.h
+++ b/source/librpc/gen_ndr/notify.h
@@ -9,11 +9,18 @@ struct notify_entry {
        struct server_id server;
        uint32_t filter;
        uint32_t subdir_filter;
+       uint32_t dir_fd;
+       struct file_id dir_id;
        const char * path;/* 
[flag(LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM)] */
        uint32_t path_len;
        void* private_data;
 }/* [public] */;
 
+struct notify_entry_array {
+       uint32_t num_entries;
+       struct notify_entry *entries;
+}/* [public] */;
+
 struct notify_depth {
        uint32_t max_mask;
        uint32_t max_mask_subdir;
diff --git a/source/librpc/idl/notify.idl b/source/librpc/idl/notify.idl
index c4e633c..0e80679 100644
--- a/source/librpc/idl/notify.idl
+++ b/source/librpc/idl/notify.idl
@@ -18,11 +18,18 @@ interface notify
                server_id server;
                uint32 filter; /* filter to apply in this directory */
                uint32 subdir_filter; /* filter to apply in child directories */
+               uint32 dir_fd;   /* fd of open directory */
+               file_id dir_id;  /* file_id of open directory */
                utf8string path;
                uint32 path_len; /* saves some computation on search */
                pointer private_data;
        } notify_entry;
 
+       typedef [public] struct {
+               uint32 num_entries;
+               notify_entry entries[num_entries];
+       } notify_entry_array;
+
        /*
          to allow for efficient search for matching entries, we
          divide them by the directory depth, with a separate array
diff --git a/source/librpc/ndr/ndr_basic.c b/source/librpc/ndr/ndr_basic.c
index c8fa70b..f81ac7b 100644
--- a/source/librpc/ndr/ndr_basic.c
+++ b/source/librpc/ndr/ndr_basic.c
@@ -857,3 +857,38 @@ _PUBLIC_ void ndr_print_sockaddr_storage(struct ndr_print 
*ndr, const char *name
        char addr[INET6_ADDRSTRLEN];
        ndr->print(ndr, "%-25s: %s", name, print_sockaddr(addr, sizeof(addr), 
ss));
 }
+
+enum ndr_err_code ndr_push_file_id(struct ndr_push *ndr, int ndr_flags, const 
struct file_id *r)
+{
+       if (ndr_flags & NDR_SCALARS) {
+               NDR_CHECK(ndr_push_align(ndr, 4));
+               NDR_CHECK(ndr_push_udlong(ndr, NDR_SCALARS,
+                                         (uint64_t)r->devid));
+               NDR_CHECK(ndr_push_udlong(ndr, NDR_SCALARS,
+                                         (uint64_t)r->inode));
+       }
+       if (ndr_flags & NDR_BUFFERS) {
+       }
+       return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_file_id(struct ndr_pull *ndr, int ndr_flags, struct 
file_id *r)
+{
+       if (ndr_flags & NDR_SCALARS) {
+               NDR_CHECK(ndr_pull_align(ndr, 4));
+               NDR_CHECK(ndr_pull_udlong(ndr, NDR_SCALARS, &r->devid));
+               NDR_CHECK(ndr_pull_udlong(ndr, NDR_SCALARS, &r->inode));
+       }
+       if (ndr_flags & NDR_BUFFERS) {
+       }
+       return NDR_ERR_SUCCESS;
+}
+
+void ndr_print_file_id(struct ndr_print *ndr, const char *name, const struct 
file_id *r)
+{
+       ndr_print_struct(ndr, name, "file_id");
+       ndr->depth++;
+       ndr_print_udlong(ndr, "devid", (uint64_t)r->devid);
+       ndr_print_udlong(ndr, "inode", (uint64_t)r->inode);
+       ndr->depth--;
+}
diff --git a/source/smbd/files.c b/source/smbd/files.c
index f643892..6c4a022 100644
--- a/source/smbd/files.c
+++ b/source/smbd/files.c
@@ -435,6 +435,10 @@ void file_free(files_struct *fsp)
        }
 
        if (fsp->notify) {
+               if (fsp->is_directory) {
+                       notify_remove_onelevel(fsp->conn->notify_ctx,
+                                              &fsp->file_id, fsp);
+               }
                notify_remove(fsp->conn->notify_ctx, fsp);
                TALLOC_FREE(fsp->notify);
        }
diff --git a/source/smbd/notify.c b/source/smbd/notify.c
index d1cd8df..180e086 100644
--- a/source/smbd/notify.c
+++ b/source/smbd/notify.c
@@ -237,6 +237,8 @@ NTSTATUS change_notify_create(struct files_struct *fsp, 
uint32 filter,
 
        ZERO_STRUCT(e);
        e.path = fullpath;
+       e.dir_fd = fsp->fh->fd;
+       e.dir_id = fsp->file_id;
        e.filter = filter;
        e.subdir_filter = 0;
        if (recursive) {
@@ -359,6 +361,9 @@ void notify_fname(connection_struct *conn, uint32 action, 
uint32 filter,
                  const char *path)
 {
        char *fullpath;
+       char *parent;
+       const char *name;
+       SMB_STRUCT_STAT sbuf;
 
        if (path[0] == '.' && path[1] == '/') {
                path += 2;
@@ -368,6 +373,14 @@ void notify_fname(connection_struct *conn, uint32 action, 
uint32 filter,
                return;
        }
 
+       if (parent_dirname_talloc(talloc_tos(), path, &parent, &name)
+           && (SMB_VFS_STAT(conn, parent, &sbuf) != -1)) {
+               notify_onelevel(conn->notify_ctx, action, filter,
+                               SMB_VFS_FILE_ID_CREATE(conn, sbuf.st_dev,
+                                                      sbuf.st_ino),
+                               name);
+       }
+
        notify_trigger(conn->notify_ctx, action, filter, fullpath);
        SAFE_FREE(fullpath);
 }
diff --git a/source/smbd/notify_internal.c b/source/smbd/notify_internal.c
index 84b8e10..b28e345 100644
--- a/source/smbd/notify_internal.c
+++ b/source/smbd/notify_internal.c
@@ -27,7 +27,8 @@
 #include "librpc/gen_ndr/ndr_notify.h"
 
 struct notify_context {
-       struct db_context *db;
+       struct db_context *db_recursive;
+       struct db_context *db_onelevel;
        struct server_id server;
        struct messaging_context *messaging_ctx;
        struct notify_list *list;
@@ -91,10 +92,18 @@ struct notify_context *notify_init(TALLOC_CTX *mem_ctx, 
struct server_id server,
                return NULL;
        }
 
-       notify->db = db_open(notify, lock_path("notify.tdb"),
-                                 0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST,
-                                 O_RDWR|O_CREAT, 0644);
-       if (notify->db == NULL) {
+       notify->db_recursive = db_open(notify, lock_path("notify.tdb"),
+                                      0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST,
+                                      O_RDWR|O_CREAT, 0644);
+       if (notify->db_recursive == NULL) {
+               talloc_free(notify);
+               return NULL;
+       }
+
+       notify->db_onelevel = db_open(notify, lock_path("notify_onelevel.tdb"),
+                                     0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST,
+                                     O_RDWR|O_CREAT, 0644);
+       if (notify->db_onelevel == NULL) {
                talloc_free(notify);
                return NULL;
        }
@@ -103,7 +112,8 @@ struct notify_context *notify_init(TALLOC_CTX *mem_ctx, 
struct server_id server,
        notify->messaging_ctx = messaging_ctx;
        notify->list = NULL;
        notify->array = NULL;
-       notify->seqnum = notify->db->get_seqnum(notify->db);
+       notify->seqnum = notify->db_recursive->get_seqnum(
+               notify->db_recursive);
        notify->key = string_term_tdb_data(NOTIFY_KEY);
 
        talloc_set_destructor(notify, notify_destructor);
@@ -123,7 +133,8 @@ struct notify_context *notify_init(TALLOC_CTX *mem_ctx, 
struct server_id server,
 */
 static NTSTATUS notify_fetch_locked(struct notify_context *notify, struct 
db_record **rec)
 {
-       *rec = notify->db->fetch_locked(notify->db, notify, notify->key);
+       *rec = notify->db_recursive->fetch_locked(notify->db_recursive,
+                                                 notify, notify->key);
        if (*rec == NULL) {
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
@@ -140,7 +151,7 @@ static NTSTATUS notify_load(struct notify_context *notify, 
struct db_record *rec
        NTSTATUS status;
        int seqnum;
 
-       seqnum = notify->db->get_seqnum(notify->db);
+       seqnum = notify->db_recursive->get_seqnum(notify->db_recursive);
 
        if (seqnum == notify->seqnum && notify->array != NULL) {
                return NT_STATUS_OK;
@@ -153,7 +164,8 @@ static NTSTATUS notify_load(struct notify_context *notify, 
struct db_record *rec
        NT_STATUS_HAVE_NO_MEMORY(notify->array);
 
        if (!rec) {
-               if (notify->db->fetch(notify->db, notify, notify->key, &dbuf) 
!= 0) {
+               if (notify->db_recursive->fetch(notify->db_recursive, notify,
+                                               notify->key, &dbuf) != 0) {
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
        } else {
@@ -344,6 +356,96 @@ static NTSTATUS notify_add_array(struct notify_context 
*notify, struct db_record
 }
 
 /*
+  Add a non-recursive watch
+*/
+
+static void notify_add_onelevel(struct notify_context *notify,
+                               struct notify_entry *e, void *private_data)
+{
+       struct notify_entry_array *array;
+       struct db_record *rec;
+       DATA_BLOB blob;
+       TDB_DATA dbuf;
+       enum ndr_err_code ndr_err;
+       NTSTATUS status;
+
+       array = talloc_zero(talloc_tos(), struct notify_entry_array);
+       if (array == NULL) {
+               return;
+       }
+
+       rec = notify->db_onelevel->fetch_locked(
+               notify->db_onelevel, talloc_tos(),
+               make_tdb_data((uint8_t *)&e->dir_id, sizeof(e->dir_id)));
+       if (rec == NULL) {
+               DEBUG(10, ("notify_add_onelevel: fetch_locked for %s failed"
+                          "\n", file_id_string_tos(&e->dir_id)));
+               TALLOC_FREE(array);
+               return;
+       }
+
+       blob.data = (uint8_t *)rec->value.dptr;
+       blob.length = rec->value.dsize;
+
+       if (blob.length > 0) {
+               ndr_err = ndr_pull_struct_blob(
+                       &blob, array, array,
+                       (ndr_pull_flags_fn_t)ndr_pull_notify_entry_array);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       DEBUG(10, ("ndr_pull_notify_entry_array failed: %s\n",
+                                  ndr_errstr(ndr_err)));
+                       TALLOC_FREE(array);
+                       return;
+               }
+               if (DEBUGLEVEL >= 10) {
+                       DEBUG(10, ("notify_add_onelevel:\n"));
+                       NDR_PRINT_DEBUG(notify_entry_array, array);
+               }
+       }
+
+       array->entries = talloc_realloc(array, array->entries,
+                                       struct notify_entry,
+                                       array->num_entries+1);
+       if (array->entries == NULL) {
+               TALLOC_FREE(array);
+               return;
+       }
+       array->entries[array->num_entries] = *e;
+       array->entries[array->num_entries].private_data = private_data;
+       array->entries[array->num_entries].server = notify->server;
+       array->num_entries += 1;
+
+       ndr_err = ndr_push_struct_blob(
+               &blob, rec, array,
+               (ndr_push_flags_fn_t)ndr_push_notify_entry_array);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               DEBUG(10, ("ndr_push_notify_entry_array failed: %s\n",
+                          ndr_errstr(ndr_err)));
+               TALLOC_FREE(array);
+               return;
+       }
+
+       if (DEBUGLEVEL >= 10) {
+               DEBUG(10, ("notify_add_onelevel:\n"));
+               NDR_PRINT_DEBUG(notify_entry_array, array);
+       }
+
+       dbuf.dptr = blob.data;
+       dbuf.dsize = blob.length;
+
+       status = rec->store(rec, dbuf, TDB_REPLACE);
+       TALLOC_FREE(array);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("notify_add_onelevel: store failed: %s\n",
+                          nt_errstr(status)));
+               return;
+       }
+       e->filter = 0;
+       return;
+}
+
+
+/*
   add a notify watch. This is called when a notify is first setup on a open
   directory handle.
 */
@@ -411,6 +513,11 @@ NTSTATUS notify_add(struct notify_context *notify, struct 
notify_entry *e0,
                }
        }
 
+       if (e.filter != 0) {
+               notify_add_onelevel(notify, &e, private_data);
+               status = NT_STATUS_OK;
+       }
+
        /* 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
@@ -426,6 +533,102 @@ done:
        return status;
 }
 
+NTSTATUS notify_remove_onelevel(struct notify_context *notify,
+                               const struct file_id *fid,
+                               void *private_data)
+{
+       struct notify_entry_array *array;
+       struct db_record *rec;
+       DATA_BLOB blob;
+       TDB_DATA dbuf;
+       enum ndr_err_code ndr_err;
+       NTSTATUS status;
+       int i;
+
+       array = talloc_zero(talloc_tos(), struct notify_entry_array);
+       if (array == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       rec = notify->db_onelevel->fetch_locked(
+               notify->db_onelevel, talloc_tos(),
+               make_tdb_data((uint8_t *)fid, sizeof(*fid)));
+       if (rec == NULL) {
+               DEBUG(10, ("notify_remove_onelevel: fetch_locked for %s failed"
+                          "\n", file_id_string_tos(fid)));
+               TALLOC_FREE(array);
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       blob.data = (uint8_t *)rec->value.dptr;
+       blob.length = rec->value.dsize;
+
+       if (blob.length > 0) {
+               ndr_err = ndr_pull_struct_blob(
+                       &blob, array, array,
+                       (ndr_pull_flags_fn_t)ndr_pull_notify_entry_array);
+               if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+                       DEBUG(10, ("ndr_pull_notify_entry_array failed: %s\n",
+                                  ndr_errstr(ndr_err)));
+                       TALLOC_FREE(array);
+                       return ndr_map_error2ntstatus(ndr_err);


-- 
SAMBA-CTDB repository

Reply via email to