r21322: No feedback means consent :-)
authorVolker Lendecke <vlendec@samba.org>
Tue, 13 Feb 2007 20:55:17 +0000 (20:55 +0000)
committerVolker Lendecke <vlendec@samba.org>
Tue, 13 Feb 2007 20:55:17 +0000 (20:55 +0000)
It does not matter if I screw up 3.0.25 or 3.0.26 with this, so do it rather
sooner than later.

Add the notify support that already exists in 3_0 to 3_0_25. If you want to
see this patch dissected into digestable parts, look at 3_0, revisions at
about 20800 and following.

Volker

56 files changed:
source/Makefile.in
source/configure.in
source/include/event.h
source/include/includes.h
source/include/messages.h
source/include/nt_status.h
source/include/smb.h
source/include/vfs.h
source/include/vfs_macros.h
source/lib/debug.c
source/lib/dmallocmsg.c
source/lib/events.c
source/lib/messages.c
source/lib/tallocmsg.c
source/lib/util.c
source/lib/util_tdb.c
source/librpc/gen_ndr/ndr_notify.c [new file with mode: 0644]
source/librpc/gen_ndr/ndr_notify.h [new file with mode: 0644]
source/librpc/gen_ndr/notify.h [new file with mode: 0644]
source/libsmb/clidgram.c
source/nmbd/nmbd.c
source/nmbd/nmbd_elections.c
source/nmbd/nmbd_winsserver.c
source/nsswitch/winbindd.c
source/nsswitch/winbindd_cm.c
source/nsswitch/winbindd_cred_cache.c
source/nsswitch/winbindd_dual.c
source/param/loadparm.c
source/printing/nt_printing.c
source/printing/printing.c
source/rpc_server/srv_spoolss_nt.c
source/rpc_server/srv_srvsvc_nt.c
source/smbd/blocking.c
source/smbd/close.c
source/smbd/conn.c
source/smbd/dosmode.c
source/smbd/files.c
source/smbd/notify.c
source/smbd/notify_fam.c [deleted file]
source/smbd/notify_hash.c [deleted file]
source/smbd/notify_inotify.c [new file with mode: 0644]
source/smbd/notify_internal.c [new file with mode: 0644]
source/smbd/notify_kernel.c [deleted file]
source/smbd/nttrans.c
source/smbd/open.c
source/smbd/oplock.c
source/smbd/process.c
source/smbd/reply.c
source/smbd/server.c
source/smbd/service.c
source/smbd/trans2.c
source/smbd/vfs.c
source/torture/msgtest.c
source/torture/vfstest.c
source/utils/net_ads.c
source/utils/smbcontrol.c

index 1371957140905826103ec188e3fec35bba4691e7..833af9647f7a5533dbb825f7610d6bfc99e78f1d 100644 (file)
@@ -215,7 +215,7 @@ LIBNDR_OBJ = librpc/ndr/ndr_basic.o librpc/ndr/ndr.o librpc/ndr/ndr_misc.o \
             librpc/ndr/ndr_sec_helper.o librpc/ndr/ndr_string.o librpc/ndr/sid.o \
             rpc_client/ndr.o
 
-LIBNDR_GEN_OBJ = librpc/gen_ndr/ndr_wkssvc.o
+LIBNDR_GEN_OBJ = librpc/gen_ndr/ndr_wkssvc.o librpc/gen_ndr/ndr_notify.o
 
 RPC_PARSE_OBJ0 = rpc_parse/parse_prs.o rpc_parse/parse_misc.o
 
@@ -398,7 +398,7 @@ PROFILES_OBJ = utils/profiles.o \
 
 OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.o
 
-NOTIFY_OBJ = smbd/notify.o smbd/notify_hash.o smbd/notify_kernel.o smbd/notify_fam.o
+NOTIFY_OBJ = smbd/notify.o smbd/notify_inotify.o smbd/notify_internal.o
 
 VFS_DEFAULT_OBJ = modules/vfs_default.o
 VFS_AUDIT_OBJ = modules/vfs_audit.o
@@ -425,6 +425,7 @@ VFS_CACHEPRIME_OBJ = modules/vfs_cacheprime.o
 VFS_PREALLOC_OBJ = modules/vfs_prealloc.o
 VFS_COMMIT_OBJ = modules/vfs_commit.o
 VFS_GPFS_OBJ = modules/vfs_gpfs.o modules/gpfs.o modules/nfs4_acls.o
+VFS_NOTIFY_FAM_OBJ = modules/vfs_notify_fam.o
 
 PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o
 
@@ -1533,6 +1534,10 @@ bin/gpfs.@SHLIBEXT@: $(VFS_GPFS_OBJ)
        @$(SHLD) $(LDSHFLAGS) -o $@ $(VFS_GPFS_OBJ) \
                @SONAMEFLAG@`basename $@`
 
+bin/notify_fam.@SHLIBEXT@: $(VFS_NOTIFY_FAM_OBJ)
+       @echo "Building plugin $@"
+       @$(SHLD) $(LDSHFLAGS) -o $@ $(VFS_NOTIFY_FAM_OBJ) \
+               @SONAMEFLAG@`basename $@`
 
 #########################################################
 ## IdMap NSS plugins
index db64eaa105e174b583d067de1a6e1f4880adab79..30f4bbfb535c6242c6ac81a085d178e029acd463 100644 (file)
@@ -2509,6 +2509,19 @@ if test x"$samba_cv_HAVE_KERNEL_CHANGE_NOTIFY" = x"yes"; then
     AC_DEFINE(HAVE_KERNEL_CHANGE_NOTIFY,1,[Whether kernel notifies changes])
 fi
 
+AC_CACHE_CHECK([for inotify support],samba_cv_HAVE_INOTIFY,[
+AC_CHECK_HEADERS(linux/inotify.h asm/unistd.h)
+AC_CHECK_FUNC(inotify_init)
+AC_HAVE_DECL(__NR_inotify_init, [#include <asm/unistd.h>])
+],
+samba_cv_HAVE_INOTIFY=yes,
+samba_cv_HAVE_INOTIFY=no,
+samba_cv_HAVE_INOTIFY=cross)
+
+if test x"$ac_cv_func_inotify_init" = x"yes" -a x"$ac_cv_header_linux_inotify_h" = x"yes"; then
+    AC_DEFINE(HAVE_INOTIFY,1,[Whether kernel has inotify support])
+fi
+
 #################################################
 # Check if FAM notifications are available. For FAM info, see
 #      http://oss.sgi.com/projects/fam/
@@ -2517,32 +2530,31 @@ AC_ARG_ENABLE(fam,
 [  --enable-fam            Turn on FAM support (default=auto)])
 
 if test x$enable_fam != xno; then
-AC_CHECK_HEADERS(fam.h, [samba_cv_HAVE_FAM_H=yes], [samba_cv_HAVE_FAM_H=no])
-if test x"$samba_cv_HAVE_FAM_H" = x"yes"; then
+    AC_CHECK_HEADERS(fam.h, [samba_cv_HAVE_FAM_H=yes], [samba_cv_HAVE_FAM_H=no])
+    if test x"$samba_cv_HAVE_FAM_H" = x"yes"; then
         # On IRIX, libfam requires libC, but other FAM implementations
        # might not need it.
-    AC_CHECK_LIB(fam, FAMOpen2,
-           [samba_cv_HAVE_LIBFAM=yes; samba_fam_libs="-lfam"],
-           [samba_cv_HAVE_LIBFAM=no])
-
-    if test x"$samba_cv_HAVE_LIBFAM" = x"no" ; then
-       samba_fam_xtra=-lC
-       AC_CHECK_LIB_EXT(fam, samba_fam_xtra, FAMOpen2,
-               [samba_cv_HAVE_LIBFAM=yes; samba_fam_libs="-lfam -lC"],
-               [samba_cv_HAVE_LIBFAM=no])
-       unset samba_fam_xtra
+        AC_CHECK_LIB(fam, FAMOpen2,
+            [samba_cv_HAVE_LIBFAM=yes; samba_fam_libs="-lfam"],
+            [samba_cv_HAVE_LIBFAM=no])
+
+        if test x"$samba_cv_HAVE_LIBFAM" = x"no" ; then
+            samba_fam_xtra=-lC
+            AC_CHECK_LIB_EXT(fam, samba_fam_xtra, FAMOpen2,
+                [samba_cv_HAVE_LIBFAM=yes; samba_fam_libs="-lfam -lC"],
+                [samba_cv_HAVE_LIBFAM=no])
+            unset samba_fam_xtra
+        fi
     fi
-fi
 
-if test x"$samba_cv_HAVE_LIBFAM" = x"yes" ; then
-    AC_DEFINE(HAVE_FAM_CHANGE_NOTIFY, 1,
-                [Whether FAM file notifications are available])
-    AC_TRY_COMPILE([#include <fam.h>],
-               [FAMCodes code = FAMChanged;],
-               AC_DEFINE(HAVE_FAM_H_FAMCODES_TYPEDEF, 1,
-                   [Whether fam.h contains a typedef for enum FAMCodes]),
-               [])
-fi
+    if test x"$samba_cv_HAVE_LIBFAM" = x"yes" ; then
+        default_shared_modules="$default_shared_modules vfs_notify_fam"
+        AC_TRY_COMPILE([#include <fam.h>],
+                    [FAMCodes code = FAMChanged;],
+                    AC_DEFINE(HAVE_FAM_H_FAMCODES_TYPEDEF, 1,
+                        [Whether fam.h contains a typedef for enum FAMCodes]),
+                    [])
+    fi
 
     if test x$enable_fam = xyes && test x"$samba_cv_HAVE_LIBFAM" != xyes ; then
         AC_MSG_ERROR(FAM support requested but FAM library not available )
index fdb990678db4489a3e7529b0bfea99156ba007f9..ce687eca6d6e13bb92560dcfc25ff2de5096ce12 100644 (file)
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-struct timed_event {
-       struct timed_event *next, *prev;
-       struct timeval when;
-       const char *event_name;
-       void (*handler)(struct timed_event *te,
-                       const struct timeval *now,
-                       void *private_data);
-       void *private_data;
-};
+/* bits for file descriptor event flags */
+#define EVENT_FD_READ 1
+#define EVENT_FD_WRITE 2
 
index 7a6064d82643c748a5f5134fe887c48e7d476aef..34b9c36c8ac1855a96d2ddd7016cfb367b54f329 100644 (file)
@@ -684,6 +684,7 @@ typedef int BOOL;
 #include "rpc_shutdown.h"
 #include "rpc_perfcount.h"
 #include "rpc_perfcount_defs.h"
+#include "librpc/gen_ndr/notify.h"
 #include "nt_printing.h"
 #include "idmap.h"
 #include "client.h"
index ead5fb08c29ee93214b28de6af0e509979aa5b78..7cd0e0234873274a1e52ddc4680a2d609fe750e4 100644 (file)
 #define MSG_SMB_BLOCKING_LOCK_CANCEL 3013
 #define MSG_SMB_NOTIFY       3014
 #define MSG_SMB_STAT_CACHE_DELETE 3015
+/*
+ * Samba4 compatibility
+ */
+#define MSG_PVFS_NOTIFY       3016
 
 /* winbind messages */
 #define MSG_WINBIND_FINISHED     4001
index 968657ca44f7044e61d2cba3ec473dd4d7b3ef42..471ac47927a7d8f1ed9415763a252ceca35a560e 100644 (file)
@@ -66,6 +66,11 @@ typedef uint32 WERROR;
         }\
 } while (0)
 
+#define NT_STATUS_NOT_OK_RETURN(x) do { \
+       if (!NT_STATUS_IS_OK(x)) {\
+               return x;\
+       }\
+} while (0)
 
 /* The top byte in an NTSTATUS code is used as a type field.
  * Windows only uses value 0xC0 as an indicator for an NT error
index 9b914f6c7f99bb7810b4662c3d7718ad033a2f3f..8fa7dee5494a71ef30a61ccddaf92022ef28760c 100644 (file)
@@ -426,6 +426,9 @@ struct fd_handle {
        unsigned long file_id;
 };
 
+struct messaging_context;
+struct event_context;
+struct fd_event;
 struct timed_event;
 struct idle_event;
 struct share_mode_entry;
@@ -439,6 +442,45 @@ struct vfs_fsp_data {
      */
 };
 
+/* the basic packet size, assuming no words or bytes */
+#define smb_size 39
+
+struct notify_change {
+       uint32_t action;
+       const char *name;
+};
+
+struct notify_mid_map;
+struct notify_entry;
+struct notify_event;
+struct notify_change_request;
+struct sys_notify_backend;
+struct sys_notify_context {
+       struct event_context *ev;
+       struct connection_struct *conn;
+       void *private_data;     /* For use by the system backend */
+};
+
+struct notify_change_buf {
+       /*
+        * If no requests are pending, changes are queued here. Simple array,
+        * we only append.
+        */
+
+       /*
+        * num_changes == -1 means that we have got a catch-all change, when
+        * asked we just return NT_STATUS_OK without specific changes.
+        */
+       int num_changes;
+       struct notify_change *changes;
+
+       /*
+        * If no changes are around requests are queued here. Using a linked
+        * list, because we have to append at the end and delete from the top.
+        */
+       struct notify_change_request *requests;
+};
+
 typedef struct files_struct {
        struct files_struct *next, *prev;
        int fnum;
@@ -483,6 +525,8 @@ typedef struct files_struct {
 
        struct vfs_fsp_data *vfs_extension;
        FAKE_FILE_HANDLE *fake_file_handle;
+
+       struct notify_change_buf *notify;
 } files_struct;
 
 #include "ntquotas.h"
@@ -627,6 +671,7 @@ typedef struct connection_struct {
        name_compare_entry *aio_write_behind_list; /* Per-share list of files to use aio write behind on. */       
        struct dfree_cached_info *dfree_info;
        struct trans_state *pending_trans;
+       struct notify_context *notify_ctx;
 } connection_struct;
 
 struct current_user {
@@ -896,9 +941,6 @@ struct bitmap {
        unsigned int n;
 };
 
-/* the basic packet size, assuming no words or bytes */
-#define smb_size 39
-
 /* offsets into message for common items */
 #define smb_com 8
 #define smb_rcls 9
@@ -1259,22 +1301,19 @@ struct bitmap {
 #define FILE_SHARE_DELETE 4
 
 /* FileAttributesField */
-#define FILE_ATTRIBUTE_READONLY         0x0001
-#define FILE_ATTRIBUTE_HIDDEN           0x0002
-#define FILE_ATTRIBUTE_SYSTEM           0x0004
-#define FILE_ATTRIBUTE_VOLUME           0x0008
-#define FILE_ATTRIBUTE_DIRECTORY        0x0010
-#define FILE_ATTRIBUTE_ARCHIVE          0x0020
-#define FILE_ATTRIBUTE_DEVICE           0x0040
-#define FILE_ATTRIBUTE_NORMAL           0x0080
-#define FILE_ATTRIBUTE_TEMPORARY        0x0100
-#define FILE_ATTRIBUTE_SPARSE           0x0200
-#define FILE_ATTRIBUTE_REPARSE_POINT    0x0400
-#define FILE_ATTRIBUTE_COMPRESSED       0x0800
-#define FILE_ATTRIBUTE_OFFLINE          0x1000
-#define FILE_ATTRIBUTE_NONINDEXED       0x2000
-#define FILE_ATTRIBUTE_ENCRYPTED        0x4000
-
+#define FILE_ATTRIBUTE_READONLY                0x001L
+#define FILE_ATTRIBUTE_HIDDEN          0x002L
+#define FILE_ATTRIBUTE_SYSTEM          0x004L
+#define FILE_ATTRIBUTE_DIRECTORY       0x010L
+#define FILE_ATTRIBUTE_ARCHIVE         0x020L
+#define FILE_ATTRIBUTE_NORMAL          0x080L
+#define FILE_ATTRIBUTE_TEMPORARY       0x100L
+#define FILE_ATTRIBUTE_SPARSE          0x200L
+#define FILE_ATTRIBUTE_REPARSE_POINT    0x400L
+#define FILE_ATTRIBUTE_COMPRESSED      0x800L
+#define FILE_ATTRIBUTE_OFFLINE          0x1000L
+#define FILE_ATTRIBUTE_NONINDEXED      0x2000L
+#define FILE_ATTRIBUTE_ENCRYPTED        0x4000L
 #define SAMBA_ATTRIBUTES_MASK          0x7F
 
 /* Flags - combined with attributes. */
@@ -1352,7 +1391,7 @@ struct bitmap {
 #define FILE_READ_ONLY_VOLUME           0x00080000
 
 /* ChangeNotify flags. */
-#define FILE_NOTIFY_CHANGE_FILE        0x001
+#define FILE_NOTIFY_CHANGE_FILE_NAME   0x001
 #define FILE_NOTIFY_CHANGE_DIR_NAME    0x002
 #define FILE_NOTIFY_CHANGE_ATTRIBUTES  0x004
 #define FILE_NOTIFY_CHANGE_SIZE        0x008
@@ -1361,7 +1400,23 @@ struct bitmap {
 #define FILE_NOTIFY_CHANGE_CREATION    0x040
 #define FILE_NOTIFY_CHANGE_EA          0x080
 #define FILE_NOTIFY_CHANGE_SECURITY    0x100
-#define FILE_NOTIFY_CHANGE_FILE_NAME   0x200
+#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200
+#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
+#define FILE_NOTIFY_CHANGE_STREAM_WRITE        0x00000800
+
+#define FILE_NOTIFY_CHANGE_NAME \
+       (FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME)
+
+/* change notify action results */
+#define NOTIFY_ACTION_ADDED 1
+#define NOTIFY_ACTION_REMOVED 2
+#define NOTIFY_ACTION_MODIFIED 3
+#define NOTIFY_ACTION_OLD_NAME 4
+#define NOTIFY_ACTION_NEW_NAME 5
+#define NOTIFY_ACTION_ADDED_STREAM 6
+#define NOTIFY_ACTION_REMOVED_STREAM 7
+#define NOTIFY_ACTION_MODIFIED_STREAM 8
+
 
 /* where to find the base of the SMB packet proper */
 #define smb_base(buf) (((char *)(buf))+4)
@@ -1638,17 +1693,6 @@ struct kernel_oplocks {
        int notification_fd;
 };
 
-
-/* this structure defines the functions for doing change notify in
-   various implementations */
-struct cnotify_fns {
-       void * (*register_notify)(connection_struct *conn, char *path, uint32 flags);
-       BOOL (*check_notify)(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *data, time_t t);
-       void (*remove_notify)(void *data);
-       int select_time;
-       int notification_fd;
-};
-
 #include "smb_macros.h"
 
 #define MAX_NETBIOSNAME_LEN 16
index fe4886567fff03bc280c96afe86ca497ff2f977c..de92c739d59e6cc1fd6e5ae9ddb449917bcc7407 100644 (file)
@@ -65,7 +65,8 @@
 /* Changed to version 17 as we removed redundant connection_struct parameters. --jpeach */
 /* Changed to version 18 to add fsp parameter to the open call -- jpeach 
    Also include kernel_flock call - jmcd */
-#define SMB_VFS_INTERFACE_VERSION 18
+/* Changed to version 19, kernel change notify has been merged */
+#define SMB_VFS_INTERFACE_VERSION 19
 
 
 /* to bug old modules which are trying to compile with the old functions */
@@ -152,6 +153,7 @@ typedef enum _vfs_op_type {
        SMB_VFS_OP_LINK,
        SMB_VFS_OP_MKNOD,
        SMB_VFS_OP_REALPATH,
+       SMB_VFS_OP_NOTIFY_WATCH,
 
        /* NT ACL operations. */
 
@@ -275,6 +277,13 @@ struct vfs_ops {
                int (*link)(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath);
                int (*mknod)(struct vfs_handle_struct *handle, const char *path, mode_t mode, SMB_DEV_T dev);
                char *(*realpath)(struct vfs_handle_struct *handle, const char *path, char *resolved_path);
+               NTSTATUS (*notify_watch)(struct vfs_handle_struct *handle,
+                                        struct sys_notify_context *ctx,
+                                        struct notify_entry *e,
+                                        void (*callback)(struct sys_notify_context *ctx, 
+                                                         void *private_data,
+                                                         struct notify_event *ev),
+                                        void *private_data, void *handle_p);
                
                /* NT ACL operations. */
                
@@ -390,6 +399,7 @@ struct vfs_ops {
                struct vfs_handle_struct *link;
                struct vfs_handle_struct *mknod;
                struct vfs_handle_struct *realpath;
+               struct vfs_handle_struct *notify_watch;
 
                /* NT ACL operations. */
 
index 119b616e72e69efc9abba3e5769be476b7bb44fa..5a189ff07ff734bf24eed89daf6a3f2ea583ff4b 100644 (file)
@@ -77,6 +77,7 @@
 #define SMB_VFS_LINK(conn, oldpath, newpath) ((conn)->vfs.ops.link((conn)->vfs.handles.link, (oldpath), (newpath)))
 #define SMB_VFS_MKNOD(conn, path, mode, dev) ((conn)->vfs.ops.mknod((conn)->vfs.handles.mknod, (path), (mode), (dev)))
 #define SMB_VFS_REALPATH(conn, path, resolved_path) ((conn)->vfs.ops.realpath((conn)->vfs.handles.realpath, (path), (resolved_path)))
+#define SMB_VFS_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs.ops.notify_watch((conn)->vfs.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p)))
 
 /* NT ACL operations. */
 #define SMB_VFS_FGET_NT_ACL(fsp, fd, security_info, ppdesc) ((fsp)->conn->vfs.ops.fget_nt_acl((fsp)->conn->vfs.handles.fget_nt_acl, (fsp), (fd), (security_info), (ppdesc)))
 #define SMB_VFS_OPAQUE_LINK(conn, oldpath, newpath) ((conn)->vfs_opaque.ops.link((conn)->vfs_opaque.handles.link, (oldpath), (newpath)))
 #define SMB_VFS_OPAQUE_MKNOD(conn, path, mode, dev) ((conn)->vfs_opaque.ops.mknod((conn)->vfs_opaque.handles.mknod, (path), (mode), (dev)))
 #define SMB_VFS_OPAQUE_REALPATH(conn, path, resolved_path) ((conn)->vfs_opaque.ops.realpath((conn)->vfs_opaque.handles.realpath, (path), (resolved_path)))
+#define SMB_VFS_OPAQUE_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs_opaque.ops.notify_watch((conn)->vfs_opaque.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p)))
 
 /* NT ACL operations. */
 #define SMB_VFS_OPAQUE_FGET_NT_ACL(fsp, fd, security_info, ppdesc) ((fsp)->conn->vfs_opaque.ops.fget_nt_acl((fsp)->conn->vfs_opaque.handles.fget_nt_acl, (fsp), (fd), (security_info), (ppdesc)))
 #define SMB_VFS_NEXT_LINK(handle, oldpath, newpath) ((handle)->vfs_next.ops.link((handle)->vfs_next.handles.link, (oldpath), (newpath)))
 #define SMB_VFS_NEXT_MKNOD(handle, path, mode, dev) ((handle)->vfs_next.ops.mknod((handle)->vfs_next.handles.mknod, (path), (mode), (dev)))
 #define SMB_VFS_NEXT_REALPATH(handle, path, resolved_path) ((handle)->vfs_next.ops.realpath((handle)->vfs_next.handles.realpath, (path), (resolved_path)))
+#define SMB_VFS_NEXT_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs_next.ops.notify_watch((conn)->vfs_next.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p)))
 
 /* NT ACL operations. */
 #define SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, fd, security_info, ppdesc) ((handle)->vfs_next.ops.fget_nt_acl((handle)->vfs_next.handles.fget_nt_acl, (fsp), (fd), (security_info), (ppdesc)))
index 00f6b0e72ff8a0af87995933b4979fd9f28f99e9..5f1416611067c96f1f50187895a63e74b8c9e533 100644 (file)
@@ -472,7 +472,7 @@ BOOL debug_parse_levels(const char *params_str)
 ****************************************************************************/
 
 static void debug_message(int msg_type, struct process_id src,
-                         void *buf, size_t len)
+                         void *buf, size_t len, void *private_data)
 {
        const char *params_str = (const char *)buf;
 
@@ -509,7 +509,7 @@ void debug_message_send(pid_t pid, const char *params_str)
 ****************************************************************************/
 
 static void debuglevel_message(int msg_type, struct process_id src,
-                              void *buf, size_t len)
+                              void *buf, size_t len, void *private_data)
 {
        char *message = debug_list_class_names_and_levels();
 
@@ -539,8 +539,8 @@ void debug_init(void)
 
        initialised = True;
 
-       message_register(MSG_DEBUG, debug_message);
-       message_register(MSG_REQ_DEBUGLEVEL, debuglevel_message);
+       message_register(MSG_DEBUG, debug_message, NULL);
+       message_register(MSG_REQ_DEBUGLEVEL, debuglevel_message, NULL);
 
        for(p = default_classname_table; *p; p++) {
                debug_add_class(*p);
index 1b2308ecba65307ea22f4f75aeb723c7b604b56d..fed7bf59c52165d4205bec0440f04b724557f929 100644 (file)
@@ -35,8 +35,10 @@ static unsigned long our_dm_mark = 0;
  * Respond to a POOL_USAGE message by sending back string form of memory
  * usage stats.
  **/
-static void msg_req_dmalloc_mark(int UNUSED(msg_type), struct process_id UNUSED(src_pid),
-                         void *UNUSED(buf), size_t UNUSED(len))
+static void msg_req_dmalloc_mark(int UNUSED(msg_type),
+                                struct process_id UNUSED(src_pid),
+                                void *UNUSED(buf), size_t UNUSED(len),
+                                void *private_data)
 {
 #ifdef ENABLE_DMALLOC
        our_dm_mark = dmalloc_mark();
@@ -50,7 +52,8 @@ static void msg_req_dmalloc_mark(int UNUSED(msg_type), struct process_id UNUSED(
 
 static void msg_req_dmalloc_log_changed(int UNUSED(msg_type),
                                        struct process_id UNUSED(src_pid),
-                                       void *UNUSED(buf), size_t UNUSED(len))
+                                       void *UNUSED(buf), size_t UNUSED(len),
+                                       void *private_data)
 {
 #ifdef ENABLE_DMALLOC
        dmalloc_log_changed(our_dm_mark, True, True, True);
@@ -66,7 +69,8 @@ static void msg_req_dmalloc_log_changed(int UNUSED(msg_type),
  **/
 void register_dmalloc_msgs(void)
 {
-       message_register(MSG_REQ_DMALLOC_MARK, msg_req_dmalloc_mark);
-       message_register(MSG_REQ_DMALLOC_LOG_CHANGED, msg_req_dmalloc_log_changed);
+       message_register(MSG_REQ_DMALLOC_MARK, msg_req_dmalloc_mark, NULL);
+       message_register(MSG_REQ_DMALLOC_LOG_CHANGED,
+                        msg_req_dmalloc_log_changed, NULL);
        DEBUG(2, ("Registered MSG_REQ_DMALLOC_MARK and LOG_CHANGED\n"));
 }      
index 0e00dcbb034f8da2c397d0e1e2f60ef34d0ec75e..a00db77b6bea3cd1fbaece208e5f9b3a3cd871d0 100644 (file)
 
 #include "includes.h"
 
-static struct timed_event *timed_events;
+struct timed_event {
+       struct timed_event *next, *prev;
+       struct event_context *event_ctx;
+       struct timeval when;
+       const char *event_name;
+       void (*handler)(struct event_context *event_ctx,
+                       struct timed_event *te,
+                       const struct timeval *now,
+                       void *private_data);
+       void *private_data;
+};
+
+struct fd_event {
+       struct fd_event *prev, *next;
+       struct event_context *event_ctx;
+       int fd;
+       uint16_t flags; /* see EVENT_FD_* flags */
+       void (*handler)(struct event_context *event_ctx,
+                       struct fd_event *event,
+                       uint16 flags,
+                       void *private_data);
+       void *private_data;
+};
+
+#define EVENT_FD_WRITEABLE(fde) \
+       event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_WRITE)
+#define EVENT_FD_READABLE(fde) \
+       event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_READ)
+
+#define EVENT_FD_NOT_WRITEABLE(fde) \
+       event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_WRITE)
+#define EVENT_FD_NOT_READABLE(fde) \
+       event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_READ)
+
+struct event_context {
+       struct timed_event *timed_events;
+       struct fd_event *fd_events;
+};
 
 static int timed_event_destructor(struct timed_event *te)
 {
        DEBUG(10, ("Destroying timed event %lx \"%s\"\n", (unsigned long)te,
                te->event_name));
-       DLIST_REMOVE(timed_events, te);
+       DLIST_REMOVE(te->event_ctx->timed_events, te);
        return 0;
 }
 
 /****************************************************************************
 Add te by time.
+ Add te by time.
 ****************************************************************************/
 
 static void add_event_by_time(struct timed_event *te)
 {
+       struct event_context *ctx = te->event_ctx;
        struct timed_event *last_te, *cur_te;
 
        /* Keep the list ordered by time. We must preserve this. */
        last_te = NULL;
-       for (cur_te = timed_events; cur_te; cur_te = cur_te->next) {
+       for (cur_te = ctx->timed_events; cur_te; cur_te = cur_te->next) {
                /* if the new event comes before the current one break */
                if (!timeval_is_zero(&cur_te->when) &&
                                timeval_compare(&te->when, &cur_te->when) < 0) {
@@ -50,7 +88,7 @@ static void add_event_by_time(struct timed_event *te)
                last_te = cur_te;
        }
 
-       DLIST_ADD_AFTER(timed_events, te, last_te);
+       DLIST_ADD_AFTER(ctx->timed_events, te, last_te);
 }
 
 /****************************************************************************
@@ -59,10 +97,12 @@ static void add_event_by_time(struct timed_event *te)
  handed to it.
 ****************************************************************************/
 
-struct timed_event *add_timed_event(TALLOC_CTX *mem_ctx,
+struct timed_event *event_add_timed(struct event_context *event_ctx,
+                               TALLOC_CTX *mem_ctx,
                                struct timeval when,
                                const char *event_name,
-                               void (*handler)(struct timed_event *te,
+                               void (*handler)(struct event_context *event_ctx,
+                                               struct timed_event *te,
                                                const struct timeval *now,
                                                void *private_data),
                                void *private_data)
@@ -75,6 +115,7 @@ struct timed_event *add_timed_event(TALLOC_CTX *mem_ctx,
                return NULL;
        }
 
+       te->event_ctx = event_ctx;
        te->when = when;
        te->event_name = event_name;
        te->handler = handler;
@@ -89,38 +130,166 @@ struct timed_event *add_timed_event(TALLOC_CTX *mem_ctx,
        return te;
 }
 
-void run_events(void)
+static int fd_event_destructor(struct fd_event *fde)
 {
+       struct event_context *event_ctx = fde->event_ctx;
+
+       DLIST_REMOVE(event_ctx->fd_events, fde);
+       return 0;
+}
+
+struct fd_event *event_add_fd(struct event_context *event_ctx,
+                             TALLOC_CTX *mem_ctx,
+                             int fd, uint16_t flags,
+                             void (*handler)(struct event_context *event_ctx,
+                                             struct fd_event *event,
+                                             uint16 flags,
+                                             void *private_data),
+                             void *private_data)
+{
+       struct fd_event *fde;
+
+       if (!(fde = TALLOC_P(mem_ctx, struct fd_event))) {
+               return NULL;
+       }
+
+       fde->event_ctx = event_ctx;
+       fde->fd = fd;
+       fde->flags = flags;
+       fde->handler = handler;
+       fde->private_data = private_data;
+
+       DLIST_ADD(event_ctx->fd_events, fde);
+
+       talloc_set_destructor(fde, fd_event_destructor);
+       return fde;
+}
+
+void event_fd_set_writeable(struct fd_event *fde)
+{
+       fde->flags |= EVENT_FD_WRITE;
+}
+
+void event_fd_set_not_writeable(struct fd_event *fde)
+{
+       fde->flags &= ~EVENT_FD_WRITE;
+}
+
+void event_fd_set_readable(struct fd_event *fde)
+{
+       fde->flags |= EVENT_FD_READ;
+}
+
+void event_fd_set_not_readable(struct fd_event *fde)
+{
+       fde->flags &= ~EVENT_FD_READ;
+}
+
+void event_add_to_select_args(struct event_context *event_ctx,
+                             const struct timeval *now,
+                             fd_set *read_fds, fd_set *write_fds,
+                             struct timeval *timeout, int *maxfd)
+{
+       struct fd_event *fde;
+       struct timeval diff;
+
+       for (fde = event_ctx->fd_events; fde; fde = fde->next) {
+               if (fde->flags & EVENT_FD_READ) {
+                       FD_SET(fde->fd, read_fds);
+               }
+               if (fde->flags & EVENT_FD_WRITE) {
+                       FD_SET(fde->fd, write_fds);
+               }
+
+               if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE))
+                   && (fde->fd > *maxfd)) {
+                       *maxfd = fde->fd;
+               }
+       }
+
+       if (event_ctx->timed_events == NULL) {
+               return;
+       }
+
+       diff = timeval_until(now, &event_ctx->timed_events->when);
+       *timeout = timeval_min(timeout, &diff);
+}
+
+BOOL run_events(struct event_context *event_ctx,
+               int selrtn, fd_set *read_fds, fd_set *write_fds)
+{
+       BOOL fired = False;
+       struct fd_event *fde, *next;
+
        /* Run all events that are pending, not just one (as we
           did previously. */
 
-       while (timed_events) {
+       while (event_ctx->timed_events) {
                struct timeval now;
                GetTimeOfDay(&now);
 
-               if (timeval_compare(&now, &timed_events->when) < 0) {
+               if (timeval_compare(
+                           &now, &event_ctx->timed_events->when) < 0) {
                        /* Nothing to do yet */
                        DEBUG(11, ("run_events: Nothing to do\n"));
-                       return;
+                       break;
                }
 
-               DEBUG(10, ("Running event \"%s\" %lx\n", timed_events->event_name,
-                       (unsigned long)timed_events));
+               DEBUG(10, ("Running event \"%s\" %lx\n",
+                          event_ctx->timed_events->event_name,
+                          (unsigned long)event_ctx->timed_events));
+
+               event_ctx->timed_events->handler(
+                       event_ctx,
+                       event_ctx->timed_events, &now,
+                       event_ctx->timed_events->private_data);
+
+               fired = True;
+       }
+
+       if (fired) {
+               /*
+                * We might have changed the socket status during the timed
+                * events, return to run select again.
+                */
+               return True;
+       }
+
+       if (selrtn == 0) {
+               /*
+                * No fd ready
+                */
+               return fired;
+       }
 
-               timed_events->handler(timed_events, &now, timed_events->private_data);
+       for (fde = event_ctx->fd_events; fde; fde = next) {
+               uint16 flags = 0;
+
+               next = fde->next;
+               if (FD_ISSET(fde->fd, read_fds)) flags |= EVENT_FD_READ;
+               if (FD_ISSET(fde->fd, write_fds)) flags |= EVENT_FD_WRITE;
+
+               if (flags) {
+                       fde->handler(event_ctx, fde, flags, fde->private_data);
+                       fired = True;
+               }
        }
+
+       return fired;
 }
 
-struct timeval *get_timed_events_timeout(struct timeval *to_ret)
+
+struct timeval *get_timed_events_timeout(struct event_context *event_ctx,
+                                        struct timeval *to_ret)
 {
        struct timeval now;
 
-       if (timed_events == NULL) {
+       if (event_ctx->timed_events == NULL) {
                return NULL;
        }
 
        now = timeval_current();
-       *to_ret = timeval_until(&now, &timed_events->when);
+       *to_ret = timeval_until(&now, &event_ctx->timed_events->when);
 
        DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec,
                (int)to_ret->tv_usec));
@@ -128,33 +297,35 @@ struct timeval *get_timed_events_timeout(struct timeval *to_ret)
        return to_ret;
 }
 
-/****************************************************************************
- Move a function within the list. Keep the list sorted by time.
-****************************************************************************/
+struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
+{
+       return TALLOC_ZERO_P(NULL, struct event_context);
+}
 
-int set_event_dispatch_time(const char *event_name, struct timeval when)
+int set_event_dispatch_time(struct event_context *event_ctx,
+                           const char *event_name, struct timeval when)
 {
        struct timed_event *te;
 
-       for (te = timed_events; te; te = te->next) {
+       for (te = event_ctx->timed_events; te; te = te->next) {
                if (strcmp(event_name, te->event_name) == 0) {
-                       DLIST_REMOVE(timed_events, te);
+                       DLIST_REMOVE(event_ctx->timed_events, te);
                        te->when = when;
                        add_event_by_time(te);
                        return 1;
                }
        }
-
        return 0;
 }
 
 /* Returns 1 if event was found and cancelled, 0 otherwise. */
 
-int cancel_named_event(const char *event_name)
+int cancel_named_event(struct event_context *event_ctx,
+                      const char *event_name)
 {
        struct timed_event *te;
 
-       for (te = timed_events; te; te = te->next) {
+       for (te = event_ctx->timed_events; te; te = te->next) {
                if (strcmp(event_name, te->event_name) == 0) {
                        TALLOC_FREE(te);
                        return 1;
index de17a03afc19d9a59a6ea7389c905da42d1e0587..e0bf86a46cee38fd564638bd5d519ce910e8a8c2 100644 (file)
@@ -66,7 +66,9 @@ struct message_rec {
 static struct dispatch_fns {
        struct dispatch_fns *next, *prev;
        int msg_type;
-       void (*fn)(int msg_type, struct process_id pid, void *buf, size_t len);
+       void (*fn)(int msg_type, struct process_id pid, void *buf, size_t len,
+                  void *private_data);
+       void *private_data;
 } *dispatch_fns;
 
 /****************************************************************************
@@ -102,7 +104,7 @@ static void sig_usr1(void)
 ****************************************************************************/
 
 static void ping_message(int msg_type, struct process_id src,
-                        void *buf, size_t len)
+                        void *buf, size_t len, void *private_data)
 {
        const char *msg = buf ? (const char *)buf : "none";
 
@@ -133,7 +135,7 @@ BOOL message_init(void)
 
        CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1);
 
-       message_register(MSG_PING, ping_message);
+       message_register(MSG_PING, ping_message, NULL);
 
        /* Register some debugging related messages */
 
@@ -164,7 +166,7 @@ static TDB_DATA message_key_pid(struct process_id pid)
  then delete its record in the database.
 ****************************************************************************/
 
-static BOOL message_notify(struct process_id procid)
+static NTSTATUS message_notify(struct process_id procid)
 {
        pid_t pid = procid.pid;
        int ret;
@@ -189,25 +191,40 @@ static BOOL message_notify(struct process_id procid)
 
        if (ret == -1) {
                if (errno == ESRCH) {
-                       DEBUG(2,("pid %d doesn't exist - deleting messages record\n", (int)pid));
+                       DEBUG(2,("pid %d doesn't exist - deleting messages record\n",
+                                (int)pid));
                        tdb_delete(tdb, message_key_pid(procid));
-               } else {
-                       DEBUG(2,("message to process %d failed - %s\n", (int)pid, strerror(errno)));
+
+                       /*
+                        * INVALID_HANDLE is the closest I can think of -- vl
+                        */
+                       return NT_STATUS_INVALID_HANDLE;
                }
-               return False;
+
+               DEBUG(2,("message to process %d failed - %s\n", (int)pid,
+                        strerror(errno)));
+
+               /*
+                * No call to map_nt_error_from_unix -- don't want to link in
+                * errormap.o into lots of utils.
+                */
+
+               if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER;
+               if (errno == EPERM)  return NT_STATUS_ACCESS_DENIED;
+               return NT_STATUS_UNSUCCESSFUL;
        }
 
-       return True;
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
  Send a message to a particular pid.
 ****************************************************************************/
 
-static BOOL message_send_pid_internal(struct process_id pid, int msg_type,
-                                     const void *buf, size_t len,
-                                     BOOL duplicates_allowed,
-                                     unsigned int timeout)
+static NTSTATUS message_send_pid_internal(struct process_id pid, int msg_type,
+                                         const void *buf, size_t len,
+                                         BOOL duplicates_allowed,
+                                         unsigned int timeout)
 {
        TDB_DATA kbuf;
        TDB_DATA dbuf;
@@ -237,8 +254,9 @@ static BOOL message_send_pid_internal(struct process_id pid, int msg_type,
        kbuf = message_key_pid(pid);
 
        dbuf.dptr = (char *)SMB_MALLOC(len + sizeof(rec));
-       if (!dbuf.dptr)
-               return False;
+       if (!dbuf.dptr) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
        memcpy(dbuf.dptr, &rec, sizeof(rec));
        if (len > 0 && buf)
@@ -253,13 +271,15 @@ static BOOL message_send_pid_internal(struct process_id pid, int msg_type,
                /* lock the record for the destination */
                if (timeout) {
                        if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) {
-                               DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout));
-                               return False;
+                               DEBUG(0,("message_send_pid_internal: failed to get "
+                                        "chainlock with timeout %ul.\n", timeout));
+                               return NT_STATUS_IO_TIMEOUT;
                        }
                } else {
                        if (tdb_chainlock(tdb, kbuf) == -1) {
-                               DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n"));
-                               return False;
+                               DEBUG(0,("message_send_pid_internal: failed to get "
+                                        "chainlock.\n"));
+                               return NT_STATUS_LOCK_NOT_GRANTED;
                        }
                }       
                tdb_append(tdb, kbuf, dbuf);
@@ -273,13 +293,15 @@ static BOOL message_send_pid_internal(struct process_id pid, int msg_type,
        /* lock the record for the destination */
        if (timeout) {
                if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) {
-                       DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout));
-                       return False;
+                       DEBUG(0,("message_send_pid_internal: failed to get chainlock "
+                                "with timeout %ul.\n", timeout));
+                       return NT_STATUS_IO_TIMEOUT;
                }
        } else {
                if (tdb_chainlock(tdb, kbuf) == -1) {
-                       DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n"));
-                       return False;
+                       DEBUG(0,("message_send_pid_internal: failed to get "
+                                "chainlock.\n"));
+                       return NT_STATUS_LOCK_NOT_GRANTED;
                }
        }       
 
@@ -308,10 +330,11 @@ static BOOL message_send_pid_internal(struct process_id pid, int msg_type,
                if (!memcmp(ptr, &rec, sizeof(rec))) {
                        if (!len || (len && !memcmp( ptr + sizeof(rec), buf, len))) {
                                tdb_chainunlock(tdb, kbuf);
-                               DEBUG(10,("message_send_pid_internal: discarding duplicate message.\n"));
+                               DEBUG(10,("message_send_pid_internal: discarding "
+                                         "duplicate message.\n"));
                                SAFE_FREE(dbuf.dptr);
                                SAFE_FREE(old_dbuf.dptr);
-                               return True;
+                               return NT_STATUS_OK;
                        }
                }
                memcpy(&prec, ptr, sizeof(prec));
@@ -334,19 +357,23 @@ static BOOL message_send_pid_internal(struct process_id pid, int msg_type,
  Send a message to a particular pid - no timeout.
 ****************************************************************************/
 
-BOOL message_send_pid(struct process_id pid, int msg_type, const void *buf, size_t len, BOOL duplicates_allowed)
+NTSTATUS message_send_pid(struct process_id pid, int msg_type, const void *buf,
+                         size_t len, BOOL duplicates_allowed)
 {
-       return message_send_pid_internal(pid, msg_type, buf, len, duplicates_allowed, 0);
+       return message_send_pid_internal(pid, msg_type, buf, len,
+                                        duplicates_allowed, 0);
 }
 
 /****************************************************************************
  Send a message to a particular pid, with timeout in seconds.
 ****************************************************************************/
 
-BOOL message_send_pid_with_timeout(struct process_id pid, int msg_type, const void *buf, size_t len,
-               BOOL duplicates_allowed, unsigned int timeout)
+NTSTATUS message_send_pid_with_timeout(struct process_id pid, int msg_type,
+                                      const void *buf, size_t len,
+                                      BOOL duplicates_allowed, unsigned int timeout)
 {
-       return message_send_pid_internal(pid, msg_type, buf, len, duplicates_allowed, timeout);
+       return message_send_pid_internal(pid, msg_type, buf, len, duplicates_allowed,
+                                        timeout);
 }
 
 /****************************************************************************
@@ -493,7 +520,9 @@ void message_dispatch(void)
                for (dfn = dispatch_fns; dfn; dfn = dfn->next) {
                        if (dfn->msg_type == msg_type) {
                                DEBUG(10,("message_dispatch: processing message of type %d.\n", msg_type));
-                               dfn->fn(msg_type, src, len ? (void *)buf : NULL, len);
+                               dfn->fn(msg_type, src,
+                                       len ? (void *)buf : NULL, len,
+                                       dfn->private_data);
                                n_handled++;
                                break;
                        }
@@ -516,7 +545,9 @@ void message_dispatch(void)
 
 void message_register(int msg_type, 
                      void (*fn)(int msg_type, struct process_id pid,
-                                void *buf, size_t len))
+                                void *buf, size_t len,
+                                void *private_data),
+                     void *private_data)
 {
        struct dispatch_fns *dfn;
 
@@ -535,6 +566,7 @@ void message_register(int msg_type,
 
                dfn->msg_type = msg_type;
                dfn->fn = fn;
+               dfn->private_data = private_data;
 
                DLIST_ADD(dispatch_fns, dfn);
        }
@@ -579,6 +611,7 @@ static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void
 {
        struct connections_data crec;
        struct msg_all *msg_all = (struct msg_all *)state;
+       NTSTATUS status;
 
        if (dbuf.dsize != sizeof(crec))
                return 0;
@@ -596,18 +629,17 @@ static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void
        /* If the msg send fails because the pid was not found (i.e. smbd died), 
         * the msg has already been deleted from the messages.tdb.*/
 
-       if (!message_send_pid(crec.pid, msg_all->msg_type,
-                             msg_all->buf, msg_all->len,
-                             msg_all->duplicates)) {
+       status = message_send_pid(crec.pid, msg_all->msg_type,
+                                 msg_all->buf, msg_all->len,
+                                 msg_all->duplicates);
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
                
                /* If the pid was not found delete the entry from connections.tdb */
 
-               if (errno == ESRCH) {
-                       DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n",
-                                procid_str_static(&crec.pid),
-                                crec.cnum, crec.name));
-                       tdb_delete(the_tdb, kbuf);
-               }
+               DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n",
+                        procid_str_static(&crec.pid), crec.cnum, crec.name));
+               tdb_delete(the_tdb, kbuf);
        }
        msg_all->n_sent++;
        return 0;
@@ -671,4 +703,135 @@ void message_unblock(void)
 {
        BlockSignals(False, SIGUSR1);
 }
+
+/*
+ * Samba4 API wrapper around the Samba3 implementation. Yes, I know, we could
+ * import the whole Samba4 thing, but I want notify.c from Samba4 in first.
+ */
+
+struct messaging_callback {
+       struct messaging_callback *prev, *next;
+       uint32 msg_type;
+       void (*fn)(struct messaging_context *msg, void *private_data, 
+                  uint32_t msg_type, 
+                  struct server_id server_id, DATA_BLOB *data);
+       void *private_data;
+};
+
+struct messaging_context {
+       struct server_id id;
+       struct messaging_callback *callbacks;
+};
+
+static int messaging_context_destructor(struct messaging_context *ctx)
+{
+       struct messaging_callback *cb;
+
+       for (cb = ctx->callbacks; cb; cb = cb->next) {
+               /*
+                * We unconditionally remove all instances of our callback
+                * from the tdb basis.
+                */
+               message_deregister(cb->msg_type);
+       }
+       return 0;
+}
+
+struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, 
+                                        struct server_id server_id, 
+                                        struct event_context *ev)
+{
+       struct messaging_context *ctx;
+
+       if (!(ctx = TALLOC_ZERO_P(mem_ctx, struct messaging_context))) {
+               return NULL;
+       }
+
+       ctx->id = server_id;
+       talloc_set_destructor(ctx, messaging_context_destructor);
+       return ctx;
+}
+
+static void messaging_callback(int msg_type, struct process_id pid,
+                              void *buf, size_t len, void *private_data)
+{
+       struct messaging_context *ctx = talloc_get_type_abort(
+               private_data, struct messaging_context);
+       struct messaging_callback *cb, *next;
+
+       for (cb = ctx->callbacks; cb; cb = next) {
+               /*
+                * Allow a callback to remove itself
+                */
+               next = cb->next;
+
+               if (msg_type == cb->msg_type) {
+                       DATA_BLOB blob;
+                       struct server_id id;
+
+                       blob.data = (uint8 *)buf;
+                       blob.length = len;
+                       id.id = pid;
+
+                       cb->fn(ctx, cb->private_data, msg_type, id, &blob);
+               }
+       }
+}
+
+/*
+ * Register a dispatch function for a particular message type. Allow multiple
+ * registrants
+*/
+NTSTATUS messaging_register(struct messaging_context *ctx, void *private_data,
+                           uint32_t msg_type,
+                           void (*fn)(struct messaging_context *msg,
+                                      void *private_data, 
+                                      uint32_t msg_type, 
+                                      struct server_id server_id,
+                                      DATA_BLOB *data))
+{
+       struct messaging_callback *cb;
+
+       if (!(cb = talloc(ctx, struct messaging_callback))) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       cb->msg_type = msg_type;
+       cb->fn = fn;
+       cb->private_data = private_data;
+
+       DLIST_ADD(ctx->callbacks, cb);
+       message_register(msg_type, messaging_callback, ctx);
+       return NT_STATUS_OK;
+}
+
+/*
+  De-register the function for a particular message type.
+*/
+void messaging_deregister(struct messaging_context *ctx, uint32_t msg_type,
+                         void *private_data)
+{
+       struct messaging_callback *cb, *next;
+
+       for (cb = ctx->callbacks; cb; cb = next) {
+               next = cb->next;
+               if ((cb->msg_type == msg_type)
+                   && (cb->private_data == private_data)) {
+                       DLIST_REMOVE(ctx->callbacks, cb);
+                       TALLOC_FREE(cb);
+               }
+       }
+}
+
+/*
+  Send a message to a particular server
+*/
+NTSTATUS messaging_send(struct messaging_context *msg,
+                       struct server_id server, 
+                       uint32_t msg_type, DATA_BLOB *data)
+{
+       return message_send_pid_internal(server.id, msg_type, data->data,
+                                        data->length, True, 0);
+}
+
 /** @} **/
index e4e9bac94d672727b3dc960daef41159260a6f49..0f493538f3c104a21f27c7cc58fed2270ff3cd91 100644 (file)
@@ -66,7 +66,8 @@ static void msg_pool_usage_helper(const void *ptr, int depth, int max_depth, int
  * usage stats.
  **/
 void msg_pool_usage(int msg_type, struct process_id src_pid,
-                   void *UNUSED(buf), size_t UNUSED(len))
+                   void *UNUSED(buf), size_t UNUSED(len),
+                   void *private_data)
 {
        struct msg_pool_usage_state state;
 
@@ -100,6 +101,6 @@ void msg_pool_usage(int msg_type, struct process_id src_pid,
  **/
 void register_msg_pool_usage(void)
 {
-       message_register(MSG_REQ_POOL_USAGE, msg_pool_usage);
+       message_register(MSG_REQ_POOL_USAGE, msg_pool_usage, NULL);
        DEBUG(2, ("Registered MSG_REQ_POOL_USAGE\n"));
 }      
index 0f54ba744147313352881aeb16750b103b1e32eb..7d41a14292c69e9c7e7e6580a661bf7bb98dd5eb 100644 (file)
@@ -3013,11 +3013,24 @@ struct process_id procid_self(void)
        return pid_to_procid(sys_getpid());
 }
 
+struct server_id server_id_self(void)
+{
+       struct server_id id;
+       id.id = procid_self();
+       return id;
+}
+
 BOOL procid_equal(const struct process_id *p1, const struct process_id *p2)
 {
        return (p1->pid == p2->pid);
 }
 
+BOOL cluster_id_equal(const struct server_id *id1,
+                     const struct server_id *id2)
+{
+       return procid_equal(&id1->id, &id2->id);
+}
+
 BOOL procid_is_me(const struct process_id *pid)
 {
        return (pid->pid == sys_getpid());
index e847c79369ea618c0194b0601de79950b6c07332..9136e2d6c1ec3901f4ddda660cad78f25eb27195 100644 (file)
@@ -838,3 +838,101 @@ int tdb_trans_delete(struct tdb_context *tdb, TDB_DATA key)
 
        return res;
 }
+
+/*
+ Log tdb messages via DEBUG().
+*/
+static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, 
+                        const char *format, ...) PRINTF_ATTRIBUTE(3,4);
+
+static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, 
+                        const char *format, ...)
+{
+       va_list ap;
+       char *ptr = NULL;
+       int debuglevel = 0;
+
+       va_start(ap, format);
+       vasprintf(&ptr, format, ap);
+       va_end(ap);
+       
+       switch (level) {
+       case TDB_DEBUG_FATAL:
+               debug_level = 0;
+               break;
+       case TDB_DEBUG_ERROR:
+               debuglevel = 1;
+               break;
+       case TDB_DEBUG_WARNING:
+               debuglevel = 2;
+               break;
+       case TDB_DEBUG_TRACE:
+               debuglevel = 5;
+               break;
+       default:
+               debuglevel = 0;
+       }               
+
+       if (ptr != NULL) {
+               const char *name = tdb_name(tdb);
+               DEBUG(debuglevel, ("tdb(%s): %s", name ? name : "unnamed", ptr));
+               free(ptr);
+       }
+}
+
+static struct tdb_wrap *tdb_list;
+
+/* destroy the last connection to a tdb */
+static int tdb_wrap_destructor(struct tdb_wrap *w)
+{
+       tdb_close(w->tdb);
+       DLIST_REMOVE(tdb_list, w);
+       return 0;
+}                               
+
+/*
+  wrapped connection to a tdb database
+  to close just talloc_free() the tdb_wrap pointer
+ */
+struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
+                              const char *name, int hash_size, int tdb_flags,
+                              int open_flags, mode_t mode)
+{
+       struct tdb_wrap *w;
+       struct tdb_logging_context log_ctx;
+       log_ctx.log_fn = tdb_wrap_log;
+
+       for (w=tdb_list;w;w=w->next) {
+               if (strcmp(name, w->name) == 0) {
+                       /*
+                        * Yes, talloc_reference is exactly what we want
+                        * here. Otherwise we would have to implement our own
+                        * reference counting.
+                        */
+                       return talloc_reference(mem_ctx, w);
+               }
+       }
+
+       w = talloc(mem_ctx, struct tdb_wrap);
+       if (w == NULL) {
+               return NULL;
+       }
+
+       if (!(w->name = talloc_strdup(w, name))) {
+               talloc_free(w);
+               return NULL;
+       }
+
+       w->tdb = tdb_open_ex(name, hash_size, tdb_flags, 
+                            open_flags, mode, &log_ctx, NULL);
+       if (w->tdb == NULL) {
+               talloc_free(w);
+               return NULL;
+       }
+
+       talloc_set_destructor(w, tdb_wrap_destructor);
+
+       DLIST_ADD(tdb_list, w);
+
+       return w;
+}
diff --git a/source/librpc/gen_ndr/ndr_notify.c b/source/librpc/gen_ndr/ndr_notify.c
new file mode 100644 (file)
index 0000000..c387355
--- /dev/null
@@ -0,0 +1,242 @@
+/* parser auto-generated by pidl */
+
+#include "includes.h"
+#include "librpc/gen_ndr/ndr_notify.h"
+
+_PUBLIC_ NTSTATUS ndr_push_notify_entry(struct ndr_push *ndr, int ndr_flags, const struct notify_entry *r)
+{
+       if (ndr_flags & NDR_SCALARS) {
+               NDR_CHECK(ndr_push_align(ndr, 8));
+               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));
+               {
+                       uint32_t _flags_save_string = ndr->flags;
+                       ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM);
+                       NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->path));
+                       ndr->flags = _flags_save_string;
+               }
+               NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->path_len));
+               NDR_CHECK(ndr_push_pointer(ndr, NDR_SCALARS, r->private_data));
+       }
+       if (ndr_flags & NDR_BUFFERS) {
+               NDR_CHECK(ndr_push_server_id(ndr, NDR_BUFFERS, &r->server));
+       }
+       return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS ndr_pull_notify_entry(struct ndr_pull *ndr, int ndr_flags, struct notify_entry *r)
+{
+       if (ndr_flags & NDR_SCALARS) {
+               NDR_CHECK(ndr_pull_align(ndr, 8));
+               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));
+               {
+                       uint32_t _flags_save_string = ndr->flags;
+                       ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM);
+                       NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->path));
+                       ndr->flags = _flags_save_string;
+               }
+               NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->path_len));
+               NDR_CHECK(ndr_pull_pointer(ndr, NDR_SCALARS, &r->private_data));
+       }
+       if (ndr_flags & NDR_BUFFERS) {
+               NDR_CHECK(ndr_pull_server_id(ndr, NDR_BUFFERS, &r->server));
+       }
+       return NT_STATUS_OK;
+}
+
+_PUBLIC_ void ndr_print_notify_entry(struct ndr_print *ndr, const char *name, const struct notify_entry *r)
+{
+       ndr_print_struct(ndr, name, "notify_entry");
+       ndr->depth++;
+       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_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--;
+}
+
+NTSTATUS ndr_push_notify_depth(struct ndr_push *ndr, int ndr_flags, const struct notify_depth *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->max_mask));
+               NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_mask_subdir));
+               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 NT_STATUS_OK;
+}
+
+NTSTATUS ndr_pull_notify_depth(struct ndr_pull *ndr, int ndr_flags, struct notify_depth *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->max_mask));
+               NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_mask_subdir));
+               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 NT_STATUS_OK;
+}
+
+_PUBLIC_ void ndr_print_notify_depth(struct ndr_print *ndr, const char *name, const struct notify_depth *r)
+{
+       uint32_t cntr_entries_0;
+       ndr_print_struct(ndr, name, "notify_depth");
+       ndr->depth++;
+       ndr_print_uint32(ndr, "max_mask", r->max_mask);
+       ndr_print_uint32(ndr, "max_mask_subdir", r->max_mask_subdir);
+       ndr_print_uint32(ndr, "num_entries", r->num_entries);
+       ndr->print(ndr, "%s: ARRAY(%d)", "entries", r->num_entries);
+       ndr->depth++;
+       for (cntr_entries_0=0;cntr_entries_0<r->num_entries;cntr_entries_0++) {
+               char *idx_0=NULL;
+               asprintf(&idx_0, "[%d]", cntr_entries_0);
+               if (idx_0) {
+                       ndr_print_notify_entry(ndr, "entries", &r->entries[cntr_entries_0]);
+                       free(idx_0);
+               }
+       }
+       ndr->depth--;
+       ndr->depth--;
+}
+
+_PUBLIC_ NTSTATUS ndr_push_notify_array(struct ndr_push *ndr, int ndr_flags, const struct notify_array *r)
+{
+       uint32_t cntr_depth_0;
+       if (ndr_flags & NDR_SCALARS) {
+               NDR_CHECK(ndr_push_align(ndr, 8));
+               NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_depths));
+               for (cntr_depth_0 = 0; cntr_depth_0 < r->num_depths; cntr_depth_0++) {
+                       NDR_CHECK(ndr_push_notify_depth(ndr, NDR_SCALARS, &r->depth[cntr_depth_0]));
+               }
+       }
+       if (ndr_flags & NDR_BUFFERS) {
+               for (cntr_depth_0 = 0; cntr_depth_0 < r->num_depths; cntr_depth_0++) {
+                       NDR_CHECK(ndr_push_notify_depth(ndr, NDR_BUFFERS, &r->depth[cntr_depth_0]));
+               }
+       }
+       return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS ndr_pull_notify_array(struct ndr_pull *ndr, int ndr_flags, struct notify_array *r)
+{
+       uint32_t cntr_depth_0;
+       TALLOC_CTX *_mem_save_depth_0;
+       if (ndr_flags & NDR_SCALARS) {
+               NDR_CHECK(ndr_pull_align(ndr, 8));
+               NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_depths));
+               NDR_PULL_ALLOC_N(ndr, r->depth, r->num_depths);
+               _mem_save_depth_0 = NDR_PULL_GET_MEM_CTX(ndr);
+               NDR_PULL_SET_MEM_CTX(ndr, r->depth, 0);
+               for (cntr_depth_0 = 0; cntr_depth_0 < r->num_depths; cntr_depth_0++) {
+                       NDR_CHECK(ndr_pull_notify_depth(ndr, NDR_SCALARS, &r->depth[cntr_depth_0]));
+               }
+               NDR_PULL_SET_MEM_CTX(ndr, _mem_save_depth_0, 0);
+       }
+       if (ndr_flags & NDR_BUFFERS) {
+               _mem_save_depth_0 = NDR_PULL_GET_MEM_CTX(ndr);
+               NDR_PULL_SET_MEM_CTX(ndr, r->depth, 0);
+               for (cntr_depth_0 = 0; cntr_depth_0 < r->num_depths; cntr_depth_0++) {
+                       NDR_CHECK(ndr_pull_notify_depth(ndr, NDR_BUFFERS, &r->depth[cntr_depth_0]));
+               }
+               NDR_PULL_SET_MEM_CTX(ndr, _mem_save_depth_0, 0);
+       }
+       return NT_STATUS_OK;
+}
+
+_PUBLIC_ void ndr_print_notify_array(struct ndr_print *ndr, const char *name, const struct notify_array *r)
+{
+       uint32_t cntr_depth_0;
+       ndr_print_struct(ndr, name, "notify_array");
+       ndr->depth++;
+       ndr_print_uint32(ndr, "num_depths", r->num_depths);
+       ndr->print(ndr, "%s: ARRAY(%d)", "depth", r->num_depths);
+       ndr->depth++;
+       for (cntr_depth_0=0;cntr_depth_0<r->num_depths;cntr_depth_0++) {
+               char *idx_0=NULL;
+               asprintf(&idx_0, "[%d]", cntr_depth_0);
+               if (idx_0) {
+                       ndr_print_notify_depth(ndr, "depth", &r->depth[cntr_depth_0]);
+                       free(idx_0);
+               }
+       }
+       ndr->depth--;
+       ndr->depth--;
+}
+
+_PUBLIC_ NTSTATUS ndr_push_notify_event(struct ndr_push *ndr, int ndr_flags, const struct notify_event *r)
+{
+       if (ndr_flags & NDR_SCALARS) {
+               NDR_CHECK(ndr_push_align(ndr, 8));
+               NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->action));
+               {
+                       uint32_t _flags_save_string = ndr->flags;
+                       ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM);
+                       NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->path));
+                       ndr->flags = _flags_save_string;
+               }
+               NDR_CHECK(ndr_push_pointer(ndr, NDR_SCALARS, r->private_data));
+       }
+       if (ndr_flags & NDR_BUFFERS) {
+       }
+       return NT_STATUS_OK;
+}
+
+_PUBLIC_ NTSTATUS ndr_pull_notify_event(struct ndr_pull *ndr, int ndr_flags, struct notify_event *r)
+{
+       if (ndr_flags & NDR_SCALARS) {
+               NDR_CHECK(ndr_pull_align(ndr, 8));
+               NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->action));
+               {
+                       uint32_t _flags_save_string = ndr->flags;
+                       ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM);
+                       NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->path));
+                       ndr->flags = _flags_save_string;
+               }
+               NDR_CHECK(ndr_pull_pointer(ndr, NDR_SCALARS, &r->private_data));
+       }
+       if (ndr_flags & NDR_BUFFERS) {
+       }
+       return NT_STATUS_OK;
+}
+
+_PUBLIC_ void ndr_print_notify_event(struct ndr_print *ndr, const char *name, const struct notify_event *r)
+{
+       ndr_print_struct(ndr, name, "notify_event");
+       ndr->depth++;
+       ndr_print_uint32(ndr, "action", r->action);
+       ndr_print_string(ndr, "path", r->path);
+       ndr_print_pointer(ndr, "private_data", r->private_data);
+       ndr->depth--;
+}
+
diff --git a/source/librpc/gen_ndr/ndr_notify.h b/source/librpc/gen_ndr/ndr_notify.h
new file mode 100644 (file)
index 0000000..793ffa5
--- /dev/null
@@ -0,0 +1,20 @@
+/* header auto-generated by pidl */
+
+#include "librpc/gen_ndr/notify.h"
+
+#ifndef _HEADER_NDR_notify
+#define _HEADER_NDR_notify
+
+#include "librpc/ndr/libndr.h"
+#define DCERPC_NOTIFY_CALL_COUNT (0)
+NTSTATUS ndr_push_notify_entry(struct ndr_push *ndr, int ndr_flags, const struct notify_entry *r);
+NTSTATUS 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);
+void ndr_print_notify_depth(struct ndr_print *ndr, const char *name, const struct notify_depth *r);
+NTSTATUS ndr_push_notify_array(struct ndr_push *ndr, int ndr_flags, const struct notify_array *r);
+NTSTATUS ndr_pull_notify_array(struct ndr_pull *ndr, int ndr_flags, struct notify_array *r);
+void ndr_print_notify_array(struct ndr_print *ndr, const char *name, const struct notify_array *r);
+NTSTATUS ndr_push_notify_event(struct ndr_push *ndr, int ndr_flags, const struct notify_event *r);
+NTSTATUS ndr_pull_notify_event(struct ndr_pull *ndr, int ndr_flags, struct notify_event *r);
+void ndr_print_notify_event(struct ndr_print *ndr, const char *name, const struct notify_event *r);
+#endif /* _HEADER_NDR_notify */
diff --git a/source/librpc/gen_ndr/notify.h b/source/librpc/gen_ndr/notify.h
new file mode 100644 (file)
index 0000000..f85b9b1
--- /dev/null
@@ -0,0 +1,33 @@
+/* header auto-generated by pidl */
+
+#ifndef _HEADER_notify
+#define _HEADER_notify
+
+struct notify_entry {
+       struct server_id server;
+       uint32_t filter;
+       uint32_t subdir_filter;
+       const char * path;/* [flag(LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM)] */
+       uint32_t path_len;
+       void* private_data;
+}/* [public] */;
+
+struct notify_depth {
+       uint32_t max_mask;
+       uint32_t max_mask_subdir;
+       uint32_t num_entries;
+       struct notify_entry *entries;
+};
+
+struct notify_array {
+       uint32_t num_depths;
+       struct notify_depth *depth;
+}/* [public] */;
+
+struct notify_event {
+       uint32_t action;
+       const char * path;/* [flag(LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM)] */
+       void* private_data;
+}/* [public] */;
+
+#endif /* _HEADER_notify */
index dfb613238f60facfd6799e9b1732aae89536008a..a983f485ab4ccc3d25e02322e8f4fa8404a9555e 100644 (file)
@@ -101,8 +101,9 @@ BOOL cli_send_mailslot(BOOL unique, const char *mailslot,
        DEBUGADD(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name),
                    inet_ntoa(dest_ip)));
 
-       return message_send_pid(pid_to_procid(nmbd_pid), MSG_SEND_PACKET, &p, sizeof(p),
-                               False);
+       return NT_STATUS_IS_OK(message_send_pid(pid_to_procid(nmbd_pid),
+                                               MSG_SEND_PACKET, &p, sizeof(p),
+                                               False));
 }
 
 /*
index 4a05fde28c9b40400fb64b413292c63ba7405e42..46f209872b03555d4bad081affa96b9e85f12dad 100644 (file)
@@ -77,7 +77,7 @@ static void terminate(void)
  **************************************************************************** */
 
 static void nmbd_terminate(int msg_type, struct process_id src,
-                          void *buf, size_t len)
+                          void *buf, size_t len, void *private_data)
 {
        terminate();
 }
@@ -272,7 +272,7 @@ static BOOL reload_nmbd_services(BOOL test)
  **************************************************************************** */
 
 static void msg_reload_nmbd_services(int msg_type, struct process_id src,
-                                    void *buf, size_t len)
+                                    void *buf, size_t len, void *private_data)
 {
        write_browse_list( 0, True );
        dump_all_namelists();
@@ -289,7 +289,7 @@ static void msg_reload_nmbd_services(int msg_type, struct process_id src,
 }
 
 static void msg_nmbd_send_packet(int msg_type, struct process_id src,
-                                void *buf, size_t len)
+                                void *buf, size_t len, void *private_data)
 {
        struct packet_struct *p = (struct packet_struct *)buf;
        struct subnet_record *subrec;
@@ -558,7 +558,7 @@ static void process(void)
                if(reload_after_sighup) {
                        DEBUG( 0, ( "Got SIGHUP dumping debug info.\n" ) );
                        msg_reload_nmbd_services(MSG_SMB_CONF_UPDATED,
-                                                pid_to_procid(0), (void*) &no_subnets, 0);
+                                                pid_to_procid(0), (void*) &no_subnets, 0, NULL);
                        if(no_subnets)
                                return;
                        reload_after_sighup = 0;
@@ -745,14 +745,14 @@ static BOOL open_sockets(BOOL isdaemon, int port)
 
        pidfile_create("nmbd");
        message_init();
-       message_register(MSG_FORCE_ELECTION, nmbd_message_election);
+       message_register(MSG_FORCE_ELECTION, nmbd_message_election, NULL);
 #if 0
        /* Until winsrepl is done. */
-       message_register(MSG_WINS_NEW_ENTRY, nmbd_wins_new_entry);
+       message_register(MSG_WINS_NEW_ENTRY, nmbd_wins_new_entry, NULL);
 #endif
-       message_register(MSG_SHUTDOWN, nmbd_terminate);
-       message_register(MSG_SMB_CONF_UPDATED, msg_reload_nmbd_services);
-       message_register(MSG_SEND_PACKET, msg_nmbd_send_packet);
+       message_register(MSG_SHUTDOWN, nmbd_terminate, NULL);
+       message_register(MSG_SMB_CONF_UPDATED, msg_reload_nmbd_services, NULL);
+       message_register(MSG_SEND_PACKET, msg_nmbd_send_packet, NULL);
 
        TimeInit();
 
index 50e13729361e2ca39660c3b934eb315bba03004b..3aadd70b83ccdee828b5aa2d1520ff4471c00c21 100644 (file)
@@ -379,7 +379,7 @@ yet registered on subnet %s\n", nmb_namestr(&nmbname), subrec->subnet_name ));
 ***************************************************************************/
 
 void nmbd_message_election(int msg_type, struct process_id src,
-                          void *buf, size_t len)
+                          void *buf, size_t len, void *private_data)
 {
        struct subnet_record *subrec;
 
index 320415503b3ad83723fdd745c876f42a3c9bf19c..6ea102c391397b867d6d098eb65c3ac924113e00 100644 (file)
@@ -2371,7 +2371,7 @@ void wins_write_database(time_t t, BOOL background)
 ***************************************************************************/
 
 void nmbd_wins_new_entry(int msg_type, struct process_id src,
-                        void *buf, size_t len)
+                        void *buf, size_t len, void *private_data)
 {
        WINS_RECORD *record;
        struct name_record *namerec = NULL;
index 1df1a1d27b8e5cf551a05484fd1a7427792394e5..341fa00c923550b49d31d65a960d17903816d873 100644 (file)
@@ -34,6 +34,16 @@ static BOOL interactive = False;
 
 extern BOOL override_logfile;
 
+struct event_context *winbind_event_context(void)
+{
+       static struct event_context *ctx;
+
+       if (!ctx && !(ctx = event_context_init(NULL))) {
+               smb_panic("Could not init winbind event context\n");
+       }
+       return ctx;
+}
+
 /* Reload configuration */
 
 static BOOL reload_services_file(void)
@@ -164,7 +174,8 @@ static void sigchld_handler(int signum)
 }
 
 /* React on 'smbcontrol winbindd reload-config' in the same way as on SIGHUP*/
-static void msg_reload_services(int msg_type, struct process_id src, void *buf, size_t len)
+static void msg_reload_services(int msg_type, struct process_id src,
+                               void *buf, size_t len, void *private_data)
 {
         /* Flush various caches */
        flush_caches();
@@ -172,7 +183,8 @@ static void msg_reload_services(int msg_type, struct process_id src, void *buf,
 }
 
 /* React on 'smbcontrol winbindd shutdown' in the same way as on SIGTERM*/
-static void msg_shutdown(int msg_type, struct process_id src, void *buf, size_t len)
+static void msg_shutdown(int msg_type, struct process_id src,
+                        void *buf, size_t len, void *private_data)
 {
        do_sigterm = True;
 }
@@ -718,7 +730,7 @@ static void process_loop(void)
 
        message_dispatch();
 
-       run_events();
+       run_events(winbind_event_context(), 0, NULL, NULL);
 
        /* refresh the trusted domain cache */
 
@@ -750,7 +762,7 @@ static void process_loop(void)
        timeout.tv_usec = 0;
 
        /* Check for any event timeouts. */
-       if (get_timed_events_timeout(&ev_timeout)) {
+       if (get_timed_events_timeout(winbind_event_context(), &ev_timeout)) {
                timeout = timeval_min(&timeout, &ev_timeout);
        }
 
@@ -869,7 +881,7 @@ static void process_loop(void)
 
                DEBUG(3, ("got SIGHUP\n"));
 
-               msg_reload_services(MSG_SMB_CONF_UPDATED, pid_to_procid(0), NULL, 0);
+               msg_reload_services(MSG_SMB_CONF_UPDATED, pid_to_procid(0), NULL, 0, NULL);
                do_sighup = False;
        }
 
@@ -1053,13 +1065,14 @@ int main(int argc, char **argv, char **envp)
        
        /* React on 'smbcontrol winbindd reload-config' in the same way
           as to SIGHUP signal */
-       message_register(MSG_SMB_CONF_UPDATED, msg_reload_services);
-       message_register(MSG_SHUTDOWN, msg_shutdown);
+       message_register(MSG_SMB_CONF_UPDATED, msg_reload_services, NULL);
+       message_register(MSG_SHUTDOWN, msg_shutdown, NULL);
 
        /* Handle online/offline messages. */
-       message_register(MSG_WINBIND_OFFLINE,winbind_msg_offline);
-       message_register(MSG_WINBIND_ONLINE,winbind_msg_online);
-       message_register(MSG_WINBIND_ONLINESTATUS,winbind_msg_onlinestatus);
+       message_register(MSG_WINBIND_OFFLINE, winbind_msg_offline, NULL);
+       message_register(MSG_WINBIND_ONLINE, winbind_msg_online, NULL);
+       message_register(MSG_WINBIND_ONLINESTATUS, winbind_msg_onlinestatus,
+                        NULL);
 
        poptFreeContext(pc);
 
index f39d3ff06aefedd4129527f79b170cba1c00ebd1..e1434ef32bbbe9612feda6b54622517249ca79dc 100644 (file)
@@ -82,7 +82,8 @@ static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain,
  Child failed to find DC's. Reschedule check.
 ****************************************************************/
 
-static void msg_failed_to_go_online(int msg_type, struct process_id src, void *buf, size_t len)
+static void msg_failed_to_go_online(int msg_type, struct process_id src,
+                                   void *buf, size_t len, void *private_data)
 {
        struct winbindd_domain *domain;
        const char *domainname = (const char *)buf;
@@ -117,7 +118,8 @@ static void msg_failed_to_go_online(int msg_type, struct process_id src, void *b
  Actually cause a reconnect from a message.
 ****************************************************************/
 
-static void msg_try_to_go_online(int msg_type, struct process_id src, void *buf, size_t len)
+static void msg_try_to_go_online(int msg_type, struct process_id src,
+                                void *buf, size_t len, void *private_data)
 {
        struct winbindd_domain *domain;
        const char *domainname = (const char *)buf;
@@ -182,8 +184,10 @@ static BOOL fork_child_dc_connect(struct winbindd_domain *domain)
 
        if (child_pid != 0) {
                /* Parent */
-               message_register(MSG_WINBIND_TRY_TO_GO_ONLINE,msg_try_to_go_online);
-               message_register(MSG_WINBIND_FAILED_TO_GO_ONLINE,msg_failed_to_go_online);
+               message_register(MSG_WINBIND_TRY_TO_GO_ONLINE,
+                                msg_try_to_go_online, NULL);
+               message_register(MSG_WINBIND_FAILED_TO_GO_ONLINE,
+                                msg_failed_to_go_online, NULL);
                message_unblock();
                return True;
        }
@@ -234,7 +238,8 @@ static BOOL fork_child_dc_connect(struct winbindd_domain *domain)
  Handler triggered if we're offline to try and detect a DC.
 ****************************************************************/
 
-static void check_domain_online_handler(struct timed_event *te,
+static void check_domain_online_handler(struct event_context *ctx,
+                                       struct timed_event *te,
                                        const struct timeval *now,
                                        void *private_data)
 {
@@ -330,7 +335,8 @@ void set_domain_offline(struct winbindd_domain *domain)
 
        calc_new_online_timeout_check(domain);
 
-       domain->check_online_event = add_timed_event( NULL,
+       domain->check_online_event = event_add_timed(winbind_event_context(),
+                                               NULL,
                                                timeval_current_ofs(domain->check_online_timeout,0),
                                                "check_domain_online_handler",
                                                check_domain_online_handler,
@@ -370,7 +376,8 @@ static void set_domain_online(struct winbindd_domain *domain)
 
        /* If we are waiting to get a krb5 ticket, trigger immediately. */
        GetTimeOfDay(&now);
-       set_event_dispatch_time("krb5_ticket_gain_handler", now);
+       set_event_dispatch_time(winbind_event_context(),
+                               "krb5_ticket_gain_handler", now);
 
        /* Ok, we're out of any startup mode now... */
        domain->startup = False;
@@ -435,11 +442,12 @@ void set_domain_online_request(struct winbindd_domain *domain)
                DEBUG(10,("set_domain_online_request: domain %s was globally offline.\n",
                        domain->name ));
 
-               domain->check_online_event = add_timed_event( NULL,
-                                               timeval_current_ofs(5, 0),
-                                               "check_domain_online_handler",
-                                               check_domain_online_handler,
-                                               domain);
+               domain->check_online_event = event_add_timed(winbind_event_context(),
+                                                               NULL,
+                                                               timeval_current_ofs(5, 0),
+                                                               "check_domain_online_handler",
+                                                               check_domain_online_handler,
+                                                               domain);
 
                /* The above *has* to succeed for winbindd to work. */
                if (!domain->check_online_event) {
@@ -454,7 +462,8 @@ void set_domain_online_request(struct winbindd_domain *domain)
        domain->startup = True;
 
        tev.tv_sec += 5;
-       set_event_dispatch_time("check_domain_online_handler", tev);
+
+       set_event_dispatch_time(winbind_event_context(), "check_domain_online_handler", tev);
 }
 
 /****************************************************************
index 6f629ad15c212603322dead5148a4797b18a5ae4..50d39dd670b6ebe22b557707c57922f552723dfe 100644 (file)
@@ -66,7 +66,8 @@ static int ccache_entry_count(void)
  Do the work of refreshing the ticket.
 ****************************************************************/
 
-static void krb5_ticket_refresh_handler(struct timed_event *te,
+static void krb5_ticket_refresh_handler(struct event_context *event_ctx,
+                                       struct timed_event *te,
                                        const struct timeval *now,
                                        void *private_data)
 {
@@ -145,7 +146,7 @@ static void krb5_ticket_refresh_handler(struct timed_event *te,
 
 done:
 
-       entry->event = add_timed_event(entry, 
+       entry->event = event_add_timed(winbind_event_context(), entry, 
                                       timeval_set(new_start, 0),
                                       "krb5_ticket_refresh_handler",
                                       krb5_ticket_refresh_handler,
@@ -158,7 +159,8 @@ done:
  Do the work of regaining a ticket when coming from offline auth.
 ****************************************************************/
 
-static void krb5_ticket_gain_handler(struct timed_event *te,
+static void krb5_ticket_gain_handler(struct event_context *event_ctx,
+                                    struct timed_event *te,
                                        const struct timeval *now,
                                        void *private_data)
 {
@@ -220,7 +222,7 @@ static void krb5_ticket_gain_handler(struct timed_event *te,
 
   retry_later:
 
-       entry->event = add_timed_event(entry,
+       entry->event = event_add_timed(winbind_event_context(), entry,
                                        timeval_current_ofs(MAX(30, lp_winbind_cache_time()), 0),
                                        "krb5_ticket_gain_handler",
                                        krb5_ticket_gain_handler,
@@ -236,7 +238,7 @@ static void krb5_ticket_gain_handler(struct timed_event *te,
        t = timeval_set(new_start, 0);
 #endif /* TESTING */
 
-       entry->event = add_timed_event(entry,
+       entry->event = event_add_timed(winbind_event_context(), entry,
                                        t,
                                        "krb5_ticket_refresh_handler",
                                        krb5_ticket_refresh_handler,
@@ -349,13 +351,13 @@ NTSTATUS add_ccache_to_list(const char *princ_name,
 
        if (lp_winbind_refresh_tickets() && renew_until > 0) {
                if (postponed_request) {
-                       entry->event = add_timed_event(entry,
+                       entry->event = event_add_timed(winbind_event_context(), entry,
                                                timeval_current_ofs(MAX(30, lp_winbind_cache_time()), 0),
                                                "krb5_ticket_gain_handler",
                                                krb5_ticket_gain_handler,
                                                entry);
                } else {
-                       entry->event = add_timed_event(entry,
+                       entry->event = event_add_timed(winbind_event_context(), entry,
                                                timeval_set((ticket_end - 1), 0),
                                                "krb5_ticket_refresh_handler",
                                                krb5_ticket_refresh_handler,
index 4a652e47dac70b55e4701d5907548c7498fb4e4f..edb4fa504b11420ba3c4095cca3bc53faa306b6c 100644 (file)
@@ -476,7 +476,8 @@ void winbindd_flush_negative_conn_cache(struct winbindd_domain *domain)
 
 /* Set our domains as offline and forward the offline message to our children. */
 
-void winbind_msg_offline(int msg_type, struct process_id src, void *buf, size_t len)
+void winbind_msg_offline(int msg_type, struct process_id src,
+                        void *buf, size_t len, void *private_data)
 {
        struct winbindd_child *child;
        struct winbindd_domain *domain;
@@ -527,7 +528,8 @@ void winbind_msg_offline(int msg_type, struct process_id src, void *buf, size_t
 
 /* Set our domains as online and forward the online message to our children. */
 
-void winbind_msg_online(int msg_type, struct process_id src, void *buf, size_t len)
+void winbind_msg_online(int msg_type, struct process_id src,
+                       void *buf, size_t len, void *private_data)
 {
        struct winbindd_child *child;
        struct winbindd_domain *domain;
@@ -579,7 +581,8 @@ void winbind_msg_online(int msg_type, struct process_id src, void *buf, size_t l
 }
 
 /* Forward the online/offline messages to our children. */
-void winbind_msg_onlinestatus(int msg_type, struct process_id src, void *buf, size_t len)
+void winbind_msg_onlinestatus(int msg_type, struct process_id src,
+                             void *buf, size_t len, void *private_data)
 {
        struct winbindd_child *child;
 
@@ -598,7 +601,8 @@ void winbind_msg_onlinestatus(int msg_type, struct process_id src, void *buf, si
 }
 
 
-static void account_lockout_policy_handler(struct timed_event *te,
+static void account_lockout_policy_handler(struct event_context *ctx,
+                                          struct timed_event *te,
                                           const struct timeval *now,
                                           void *private_data)
 {
@@ -631,7 +635,7 @@ static void account_lockout_policy_handler(struct timed_event *te,
                         nt_errstr(result)));
        }
 
-       child->lockout_policy_event = add_timed_event(NULL,
+       child->lockout_policy_event = event_add_timed(winbind_event_context(), NULL,
                                                      timeval_current_ofs(3600, 0),
                                                      "account_lockout_policy_handler",
                                                      account_lockout_policy_handler,
@@ -640,7 +644,8 @@ static void account_lockout_policy_handler(struct timed_event *te,
 
 /* Deal with a request to go offline. */
 
-static void child_msg_offline(int msg_type, struct process_id src, void *buf, size_t len)
+static void child_msg_offline(int msg_type, struct process_id src,
+                             void *buf, size_t len, void *private_data)
 {
        struct winbindd_domain *domain;
        const char *domainname = (const char *)buf;
@@ -677,7 +682,8 @@ static void child_msg_offline(int msg_type, struct process_id src, void *buf, si
 
 /* Deal with a request to go online. */
 
-static void child_msg_online(int msg_type, struct process_id src, void *buf, size_t len)
+static void child_msg_online(int msg_type, struct process_id src,
+                            void *buf, size_t len, void *private_data)
 {
        struct winbindd_domain *domain;
        const char *domainname = (const char *)buf;
@@ -738,7 +744,8 @@ static const char *collect_onlinestatus(TALLOC_CTX *mem_ctx)
        return buf;
 }
 
-static void child_msg_onlinestatus(int msg_type, struct process_id src, void *buf, size_t len)
+static void child_msg_onlinestatus(int msg_type, struct process_id src,
+                                  void *buf, size_t len, void *private_data)
 {
        TALLOC_CTX *mem_ctx;
        const char *message;
@@ -842,9 +849,10 @@ static BOOL fork_domain_child(struct winbindd_child *child)
        message_unblock();
 
        /* Handle online/offline messages. */
-       message_register(MSG_WINBIND_OFFLINE,child_msg_offline);
-       message_register(MSG_WINBIND_ONLINE,child_msg_online);
-       message_register(MSG_WINBIND_ONLINESTATUS,child_msg_onlinestatus);
+       message_register(MSG_WINBIND_OFFLINE, child_msg_offline, NULL);
+       message_register(MSG_WINBIND_ONLINE, child_msg_online, NULL);
+       message_register(MSG_WINBIND_ONLINESTATUS, child_msg_onlinestatus,
+                        NULL);
 
        if ( child->domain ) {
                child->domain->startup = True;
@@ -865,7 +873,8 @@ static BOOL fork_domain_child(struct winbindd_child *child)
        /* Ensure we're not handling an event inherited from
           our parent. */
 
-       cancel_named_event("krb5_ticket_refresh_handler");
+       cancel_named_event(winbind_event_context(),
+                          "krb5_ticket_refresh_handler");
 
        /* We might be in the idmap child...*/
        if (child->domain && !(child->domain->internal) &&
@@ -873,8 +882,8 @@ static BOOL fork_domain_child(struct winbindd_child *child)
 
                set_domain_online_request(child->domain);
 
-               child->lockout_policy_event = add_timed_event(
-                       NULL, timeval_zero(),
+               child->lockout_policy_event = event_add_timed(
+                       winbind_event_context(), NULL, timeval_zero(),
                        "account_lockout_policy_handler",
                        account_lockout_policy_handler,
                        child);
@@ -892,7 +901,7 @@ static BOOL fork_domain_child(struct winbindd_child *child)
                lp_TALLOC_FREE();
                main_loop_TALLOC_FREE();
 
-               run_events();
+               run_events(winbind_event_context(), 0, NULL, NULL);
 
                GetTimeOfDay(&now);
 
@@ -904,7 +913,7 @@ static BOOL fork_domain_child(struct winbindd_child *child)
                        child->domain->startup = False;
                }
 
-               tp = get_timed_events_timeout(&t);
+               tp = get_timed_events_timeout(winbind_event_context(), &t);
                if (tp) {
                        DEBUG(11,("select will use timeout of %u.%u seconds\n",
                                (unsigned int)tp->tv_sec, (unsigned int)tp->tv_usec ));
index 469976325c009d394aab0cb684a05668c8ece2f5..976810ee153c60d1195d0bd22c222564d3d7db1a 100644 (file)
@@ -299,8 +299,6 @@ typedef struct {
        BOOL bHostnameLookups;
        BOOL bUnixExtensions;
        BOOL bDisableNetbios;
-       BOOL bKernelChangeNotify;
-       BOOL bFamChangeNotify;
        BOOL bUseKerberosKeytab;
        BOOL bDeferSharingViolations;
        BOOL bEnablePrivileges;
@@ -451,11 +449,12 @@ typedef struct {
        BOOL bAclCheckPermissions;
        BOOL bAclMapFullControl;
        BOOL bAclGroupControl;
+       BOOL bChangeNotify;
+       BOOL bKernelChangeNotify;
        int iallocation_roundup_size;
        int iAioReadSize;
        int iAioWriteSize;
        int iMap_readonly;
-       int ichange_notify_timeout;
        param_opt_struct *param_opt;
 
        char dummy[3];          /* for alignment */
@@ -590,11 +589,12 @@ static service sDefault = {
        True,                   /* bAclCheckPermissions */
        True,                   /* bAclMapFullControl */
        False,                  /* bAclGroupControl */
+       True,                   /* bChangeNotify */
+       True,                   /* bKernelChangeNotify */
        SMB_ROUNDUP_ALLOCATION_SIZE,            /* iallocation_roundup_size */
        0,                      /* iAioReadSize */
        0,                      /* iAioWriteSize */
        MAP_READONLY_YES,       /* iMap_readonly */
-       60,                     /* ichange_notify_timeout = 1 minute default. */
        
        NULL,                   /* Parametric options */
 
@@ -1005,12 +1005,11 @@ static struct parm_struct parm_table[] = {
        {N_("Tuning Options"), P_SEP, P_SEPARATOR}, 
 
        {"block size", P_INTEGER, P_LOCAL, &sDefault.iBlock_size, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, 
-       {"change notify timeout", P_INTEGER, P_LOCAL, &sDefault.ichange_notify_timeout, NULL, NULL, FLAG_ADVANCED}, 
        {"deadtime", P_INTEGER, P_GLOBAL, &Globals.deadtime, NULL, NULL, FLAG_ADVANCED}, 
        {"getwd cache", P_BOOL, P_GLOBAL, &use_getwd_cache, NULL, NULL, FLAG_ADVANCED}, 
        {"keepalive", P_INTEGER, P_GLOBAL, &keepalive, NULL, NULL, FLAG_ADVANCED}, 
-       {"kernel change notify", P_BOOL, P_GLOBAL, &Globals.bKernelChangeNotify, NULL, NULL, FLAG_ADVANCED}, 
-       {"fam change notify", P_BOOL, P_GLOBAL, &Globals.bFamChangeNotify, NULL, NULL, FLAG_ADVANCED},
+       {"change notify", P_BOOL, P_LOCAL, &sDefault.bChangeNotify, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE },
+       {"kernel change notify", P_BOOL, P_LOCAL, &sDefault.bKernelChangeNotify, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE },
 
        {"lpq cache time", P_INTEGER, P_GLOBAL, &Globals.lpqcachetime, NULL, NULL, FLAG_ADVANCED}, 
        {"max smbd processes", P_INTEGER, P_GLOBAL, &Globals.iMaxSmbdProcesses, NULL, NULL, FLAG_ADVANCED}, 
@@ -1522,8 +1521,6 @@ static void init_globals(BOOL first_time_only)
        Globals.max_wins_ttl = 60 * 60 * 24 * 6;        /* 6 days default. */
        Globals.min_wins_ttl = 60 * 60 * 6;     /* 6 hours default. */
        Globals.machine_password_timeout = 60 * 60 * 24 * 7;    /* 7 days default. */
-       Globals.bKernelChangeNotify = True;     /* On if we have it. */
-       Globals.bFamChangeNotify = True;        /* On if we have it. */
        Globals.lm_announce = 2;        /* = Auto: send only if LM clients found */
        Globals.lm_interval = 60;
        Globals.announce_as = ANNOUNCE_AS_NT_SERVER;
@@ -1934,8 +1931,8 @@ FN_GLOBAL_BOOL(lp_unix_extensions, &Globals.bUnixExtensions)
 FN_GLOBAL_BOOL(lp_use_spnego, &Globals.bUseSpnego)
 FN_GLOBAL_BOOL(lp_client_use_spnego, &Globals.bClientUseSpnego)
 FN_GLOBAL_BOOL(lp_hostname_lookups, &Globals.bHostnameLookups)
-FN_GLOBAL_BOOL(lp_kernel_change_notify, &Globals.bKernelChangeNotify)
-FN_GLOBAL_BOOL(lp_fam_change_notify, &Globals.bFamChangeNotify)
+FN_LOCAL_PARM_BOOL(lp_change_notify, bChangeNotify)
+FN_LOCAL_PARM_BOOL(lp_kernel_change_notify, bKernelChangeNotify)
 FN_GLOBAL_BOOL(lp_use_kerberos_keytab, &Globals.bUseKerberosKeytab)
 FN_GLOBAL_BOOL(lp_defer_sharing_violations, &Globals.bDeferSharingViolations)
 FN_GLOBAL_BOOL(lp_enable_privileges, &Globals.bEnablePrivileges)
@@ -2097,7 +2094,6 @@ FN_LOCAL_INTEGER(lp_allocation_roundup_size, iallocation_roundup_size)
 FN_LOCAL_INTEGER(lp_aio_read_size, iAioReadSize)
 FN_LOCAL_INTEGER(lp_aio_write_size, iAioWriteSize)
 FN_LOCAL_INTEGER(lp_map_readonly, iMap_readonly)
-FN_LOCAL_INTEGER(lp_change_notify_timeout, ichange_notify_timeout)
 FN_LOCAL_CHAR(lp_magicchar, magic_char)
 FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time)
 FN_GLOBAL_LIST(lp_winbind_nss_info, &Globals.szWinbindNssInfo)
index 4a6b2e0a6def3f6035413b412d19739164e34eaa..5b5f82d1f48788aa0718e991e1ce1a5243a1f2fe 100644 (file)
@@ -629,14 +629,15 @@ BOOL nt_printing_init(void)
         * drivers are installed
         */
 
-       message_register( MSG_PRINTER_DRVUPGRADE, do_drv_upgrade_printer );
+       message_register(MSG_PRINTER_DRVUPGRADE, do_drv_upgrade_printer, NULL);
 
        /*
         * register callback to handle updating printer data
         * when a driver is initialized
         */
 
-       message_register( MSG_PRINTERDATA_INIT_RESET, reset_all_printerdata );
+       message_register(MSG_PRINTERDATA_INIT_RESET, reset_all_printerdata,
+                        NULL);
 
        /* of course, none of the message callbacks matter if you don't
           tell messages.c that you interested in receiving PRINT_GENERAL 
index 2f1d123a2001ea94bcfcef4982e8a5070b9cdc6f..588641358f38fea04e16d1a5c4a909d5494533b1 100644 (file)
@@ -1352,7 +1352,8 @@ static void print_queue_update_with_lock( const char *sharename,
 this is the receive function of the background lpq updater
 ****************************************************************************/
 static void print_queue_receive(int msg_type, struct process_id src,
-                               void *buf, size_t msglen)
+                               void *buf, size_t msglen,
+                               void *private_data)
 {
        fstring sharename;
        pstring lpqcommand, lprmcommand;
@@ -1403,7 +1404,8 @@ void start_background_queue(void)
                        exit(1);
                }
 
-               message_register(MSG_PRINTER_UPDATE, print_queue_receive);
+               message_register(MSG_PRINTER_UPDATE, print_queue_receive,
+                                NULL);
                
                DEBUG(5,("start_background_queue: background LPQ thread waiting for messages\n"));
                while (1) {
index 2a997722a0ee17ecc273b91ff29903f9a941a5fd..f5a2298fe973343b47358c7271871d69b1d50e2d 100644 (file)
@@ -1099,7 +1099,8 @@ static BOOL notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, struct timeval *tv, voi
  ********************************************************************/
 
 static void receive_notify2_message_list(int msg_type, struct process_id src,
-                                        void *msg, size_t len)
+                                        void *msg, size_t len,
+                                        void *private_data)
 {
        size_t                  msg_count, i;
        char                    *buf = (char *)msg;
@@ -1211,7 +1212,8 @@ static BOOL srv_spoolss_drv_upgrade_printer(char* drivername)
  over all printers, upgrading ones as necessary 
  **********************************************************************/
  
-void do_drv_upgrade_printer(int msg_type, struct process_id src, void *buf, size_t len)
+void do_drv_upgrade_printer(int msg_type, struct process_id src,
+                           void *buf, size_t len, void *private_data)
 {
        fstring drivername;
        int snum;
@@ -1309,7 +1311,7 @@ static BOOL srv_spoolss_reset_printerdata(char* drivername)
  **********************************************************************/
  
 void reset_all_printerdata(int msg_type, struct process_id src,
-                          void *buf, size_t len)
+                          void *buf, size_t len, void *private_data)
 {
        fstring drivername;
        int snum;
@@ -2598,7 +2600,8 @@ static BOOL srv_spoolss_replyopenprinter(int snum, const char *printer,
                if ( !spoolss_connect_to_client( &notify_cli_pipe, client_ip, unix_printer ))
                        return False;
                        
-               message_register(MSG_PRINTER_NOTIFY2, receive_notify2_message_list);
+               message_register(MSG_PRINTER_NOTIFY2,
+                                receive_notify2_message_list, NULL);
                /* Tell the connections db we're now interested in printer
                 * notify messages. */
                register_message_flags( True, FLAG_MSG_PRINT_NOTIFY );
index b7e63fcce134a8a82c757be05f2dae79ba31e34b..17247b659389c288d212d5e409585a89649de6bf 100644 (file)
@@ -1190,7 +1190,7 @@ WERROR _srv_net_sess_del(pipes_struct *p, SRV_Q_NET_SESS_DEL *q_u, SRV_R_NET_SES
                                become_root();
                        }
 
-                       if (message_send_pid(pid_to_procid(session_list[snum].pid), MSG_SHUTDOWN, NULL, 0, False))
+                       if (NT_STATUS_IS_OK(message_send_pid(pid_to_procid(session_list[snum].pid), MSG_SHUTDOWN, NULL, 0, False)))
                                r_u->status = WERR_OK;
 
                        if (not_root) 
index e0478fa762fedbef9e99ef03f6fa1a1da64d04b4..70b2d30aaba5b6185044089d6c1e0c2d0c12e619 100644 (file)
@@ -71,7 +71,8 @@ static BOOL in_chained_smb(void)
 }
 
 static void received_unlock_msg(int msg_type, struct process_id src,
-                               void *buf, size_t len);
+                               void *buf, size_t len,
+                               void *private_data);
 
 /****************************************************************************
  Function to push a blocking lock request onto the lock queue.
@@ -154,7 +155,8 @@ BOOL push_blocking_lock_request( struct byte_range_lock *br_lck,
 
        /* Ensure we'll receive messages when this is unlocked. */
        if (!set_lock_msg) {
-               message_register(MSG_SMB_UNLOCK, received_unlock_msg);
+               message_register(MSG_SMB_UNLOCK, received_unlock_msg,
+                                NULL);
                set_lock_msg = True;
        }
 
@@ -581,7 +583,8 @@ BOOL blocking_lock_was_deferred(int mid)
 *****************************************************************************/
 
 static void received_unlock_msg(int msg_type, struct process_id src,
-                               void *buf, size_t len)
+                               void *buf, size_t len,
+                               void *private_data)
 {
        DEBUG(10,("received_unlock_msg\n"));
        process_blocking_lock_queue();
@@ -775,8 +778,10 @@ void process_blocking_lock_queue(void)
 
 #define MSG_BLOCKING_LOCK_CANCEL_SIZE (sizeof(blocking_lock_record *) + sizeof(NTSTATUS))
 
-static void process_blocking_lock_cancel_message(int msg_type, struct process_id src,
-                                         void *buf, size_t len)
+static void process_blocking_lock_cancel_message(int msg_type,
+                                                struct process_id src,
+                                                void *buf, size_t len,
+                                                void *private_data)
 {
        NTSTATUS err;
        const char *msg = (const char *)buf;
@@ -822,7 +827,8 @@ BOOL blocking_lock_cancel(files_struct *fsp,
        if (!initialized) {
                /* Register our message. */
                message_register(MSG_SMB_BLOCKING_LOCK_CANCEL,
-                               process_blocking_lock_cancel_message);
+                                process_blocking_lock_cancel_message,
+                                NULL);
 
                initialized = True;
        }
index ea0d807041c4b411dd674fb6476505b598959ca3..b826cd622afe2ed414f736979082ff5a4516e1ed 100644 (file)
@@ -301,8 +301,6 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
        /* unbecome user. */
        pop_sec_ctx();
        
-       process_pending_change_notify_queue((time_t)0);
-
        TALLOC_FREE(lck);
        return status;
 }
@@ -496,10 +494,7 @@ static NTSTATUS close_directory(files_struct *fsp, enum file_close_type close_ty
 
                if(NT_STATUS_IS_OK(status)) {
                        remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_DELETE_PENDING);
-                       remove_pending_change_notify_requests_by_filename(fsp, NT_STATUS_DELETE_PENDING);
-
                }
-               process_pending_change_notify_queue((time_t)0);
        } else {
                TALLOC_FREE(lck);
                remove_pending_change_notify_requests_by_fid(
index 083e8339c80bfac4073e7057f84c2c9abed71fe5..44888b777f2e536b6d3014f7434a261f76d7d4df 100644 (file)
@@ -311,7 +311,8 @@ the message contains just a share name and all instances of that
 share are unmounted
 the special sharename '*' forces unmount of all shares
 ****************************************************************************/
-void msg_force_tdis(int msg_type, struct process_id pid, void *buf, size_t len)
+void msg_force_tdis(int msg_type, struct process_id pid, void *buf, size_t len,
+                   void *private_data)
 {
        connection_struct *conn, *next;
        fstring sharename;
index ff4291c08c8183e860d73066f62a5b159cb2c769..ad79bbacddf31382fa70e4331f6929ff1fbace8d 100644 (file)
@@ -491,8 +491,11 @@ int file_set_dosmode(connection_struct *conn, const char *fname,
                unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
        }
 
-       if ((ret = SMB_VFS_CHMOD(conn,fname,unixmode)) == 0)
+       if ((ret = SMB_VFS_CHMOD(conn,fname,unixmode)) == 0) {
+               notify_fname(conn, NOTIFY_ACTION_MODIFIED,
+                            FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
                return 0;
+       }
 
        if((errno != EPERM) && (errno != EACCES))
                return -1;
@@ -521,6 +524,8 @@ int file_set_dosmode(connection_struct *conn, const char *fname,
                ret = SMB_VFS_FCHMOD(fsp, fsp->fh->fd, unixmode);
                unbecome_root();
                close_file_fchmod(fsp);
+               notify_fname(conn, NOTIFY_ACTION_MODIFIED,
+                            FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
        }
 
        return( ret );
@@ -593,6 +598,9 @@ BOOL set_filetime(connection_struct *conn, const char *fname, time_t mtime)
                DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno)));
                return False;
        }
+
+       notify_fname(conn, NOTIFY_ACTION_MODIFIED,
+                    FILE_NOTIFY_CHANGE_LAST_WRITE, fname);
   
        return(True);
 } 
index 7069818dee4f1f117f10317608028ded587679e6..66ef37bb0fa24ba07961bdc99adfc4ebe916b185 100644 (file)
@@ -439,6 +439,11 @@ void file_free(files_struct *fsp)
                fsp->fh->ref_count--;
        }
 
+       if (fsp->notify) {
+               notify_remove(fsp->conn->notify_ctx, fsp);
+               TALLOC_FREE(fsp->notify);
+       }
+
        bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET);
        files_used--;
 
index 4ec53567dd4aa59133a6c49b38d6f2f121e06d49..cf60720bc744059385a0a120098fe9ee71a47e80 100644 (file)
@@ -3,6 +3,7 @@
    change notify handling
    Copyright (C) Andrew Tridgell 2000
    Copyright (C) Jeremy Allison 1994-1998
+   Copyright (C) Volker Lendecke 2007
 
    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
 
 #include "includes.h"
 
-static struct cnotify_fns *cnotify;
+struct notify_change_request {
+       struct notify_change_request *prev, *next;
+       struct files_struct *fsp;       /* backpointer for cancel by mid */
+       char request_buf[smb_size];
+       uint32 filter;
+       uint32 max_param_count;
+       uint32 current_bufsize;
+       struct notify_mid_map *mid_map;
+       void *backend_data;
+};
 
-/****************************************************************************
- This is the structure to queue to implement NT change
- notify. It consists of smb_size bytes stored from the
- transact command (to keep the mid, tid etc around).
- Plus the fid to examine and notify private data.
-*****************************************************************************/
+static void notify_fsp(files_struct *fsp, uint32 action, const char *name);
 
-struct change_notify {
-       struct change_notify *next, *prev;
-       files_struct *fsp;
-       connection_struct *conn;
-       uint32 flags;
-       char request_buf[smb_size];
-       void *change_data;
+static struct notify_mid_map *notify_changes_by_mid;
+
+/*
+ * For NTCancel, we need to find the notify_change_request indexed by
+ * mid. Separate list here.
+ */
+
+struct notify_mid_map {
+       struct notify_mid_map *prev, *next;
+       struct notify_change_request *req;
+       uint16 mid;
 };
 
-static struct change_notify *change_notify_list;
+static BOOL notify_marshall_changes(int num_changes,
+                                   struct notify_change *changes,
+                                   prs_struct *ps)
+{
+       int i;
+       UNISTR uni_name;
+
+       for (i=0; i<num_changes; i++) {
+               struct notify_change *c = &changes[i];
+               size_t namelen;
+               uint32 u32_tmp; /* Temp arg to prs_uint32 to avoid
+                                * signed/unsigned issues */
+
+               namelen = convert_string_allocate(
+                       NULL, CH_UNIX, CH_UTF16LE, c->name, strlen(c->name)+1,
+                       &uni_name.buffer, True);
+               if ((namelen == -1) || (uni_name.buffer == NULL)) {
+                       goto fail;
+               }
+
+               namelen -= 2;   /* Dump NULL termination */
+
+               /*
+                * Offset to next entry, only if there is one
+                */
+
+               u32_tmp = (i == num_changes-1) ? 0 : namelen + 12;
+               if (!prs_uint32("offset", ps, 1, &u32_tmp)) goto fail;
+
+               u32_tmp = c->action;
+               if (!prs_uint32("action", ps, 1, &u32_tmp)) goto fail;
+
+               u32_tmp = namelen;
+               if (!prs_uint32("namelen", ps, 1, &u32_tmp)) goto fail;
+
+               if (!prs_unistr("name", ps, 1, &uni_name)) goto fail;
+
+               /*
+                * Not NULL terminated, decrease by the 2 UCS2 \0 chars
+                */
+               prs_set_offset(ps, prs_offset(ps)-2);
+
+               SAFE_FREE(uni_name.buffer);
+       }
+
+       return True;
+
+ fail:
+       SAFE_FREE(uni_name.buffer);
+       return False;
+}
 
 /****************************************************************************
  Setup the common parts of the return packet and send it.
 *****************************************************************************/
 
-static void change_notify_reply_packet(char *inbuf, NTSTATUS error_code)
+static void change_notify_reply_packet(const char *request_buf,
+                                      NTSTATUS error_code)
 {
        char outbuf[smb_size+38];
 
        memset(outbuf, '\0', sizeof(outbuf));
-       construct_reply_common(inbuf, outbuf);
+       construct_reply_common(request_buf, outbuf);
 
        ERROR_NT(error_code);
 
@@ -62,193 +122,363 @@ static void change_notify_reply_packet(char *inbuf, NTSTATUS error_code)
 
        show_msg(outbuf);
        if (!send_smb(smbd_server_fd(),outbuf))
-               exit_server_cleanly("change_notify_reply_packet: send_smb failed.");
+               exit_server_cleanly("change_notify_reply_packet: send_smb "
+                                   "failed.");
 }
 
-/****************************************************************************
- Remove an entry from the list and free it, also closing any
- directory handle if necessary.
-*****************************************************************************/
+void change_notify_reply(const char *request_buf, uint32 max_param_count,
+                        struct notify_change_buf *notify_buf)
+{
+       char *outbuf = NULL;
+       prs_struct ps;
+       size_t buflen = smb_size+38+max_param_count;
+
+       if (notify_buf->num_changes == -1) {
+               change_notify_reply_packet(request_buf, NT_STATUS_OK);
+               return;
+       }
+
+       if (!prs_init(&ps, 0, NULL, False)
+           || !notify_marshall_changes(notify_buf->num_changes,
+                                       notify_buf->changes, &ps)) {
+               change_notify_reply_packet(request_buf, NT_STATUS_NO_MEMORY);
+               goto done;
+       }
 
-static void change_notify_remove(struct change_notify *cnbp)
+       if (prs_offset(&ps) > max_param_count) {
+               /*
+                * We exceed what the client is willing to accept. Send
+                * nothing.
+                */
+               change_notify_reply_packet(request_buf, NT_STATUS_OK);
+               goto done;
+       }
+
+       if (!(outbuf = SMB_MALLOC_ARRAY(char, buflen))) {
+               change_notify_reply_packet(request_buf, NT_STATUS_NO_MEMORY);
+               goto done;
+       }
+
+       construct_reply_common(request_buf, outbuf);
+
+       if (send_nt_replies(outbuf, buflen, NT_STATUS_OK, prs_data_p(&ps),
+                           prs_offset(&ps), NULL, 0) == -1) {
+               exit_server("change_notify_reply_packet: send_smb failed.");
+       }
+
+ done:
+       SAFE_FREE(outbuf);
+       prs_mem_free(&ps);
+
+       TALLOC_FREE(notify_buf->changes);
+       notify_buf->num_changes = 0;
+}
+
+static void notify_callback(void *private_data, const struct notify_event *e)
 {
-       cnotify->remove_notify(cnbp->change_data);
-       DLIST_REMOVE(change_notify_list, cnbp);
-       ZERO_STRUCTP(cnbp);
-       SAFE_FREE(cnbp);
+       files_struct *fsp = (files_struct *)private_data;
+       DEBUG(10, ("notify_callback called for %s\n", fsp->fsp_name));
+       notify_fsp(fsp, e->action, e->path);
 }
 
-/****************************************************************************
- Delete entries by fnum from the change notify pending queue.
-*****************************************************************************/
+NTSTATUS change_notify_create(struct files_struct *fsp, uint32 filter,
+                             BOOL recursive)
+{
+       char *fullpath;
+       struct notify_entry e;
+       NTSTATUS status;
+
+       SMB_ASSERT(fsp->notify == NULL);
+
+       if (!(fsp->notify = TALLOC_ZERO_P(NULL, struct notify_change_buf))) {
+               DEBUG(0, ("talloc failed\n"));
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (asprintf(&fullpath, "%s/%s", fsp->conn->connectpath,
+                    fsp->fsp_name) == -1) {
+               DEBUG(0, ("asprintf failed\n"));
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       e.path = fullpath;
+       e.filter = filter;
+       e.subdir_filter = 0;
+       if (recursive) {
+               e.subdir_filter = filter;
+       }
 
-void remove_pending_change_notify_requests_by_fid(files_struct *fsp, NTSTATUS status)
+       status = notify_add(fsp->conn->notify_ctx, &e, notify_callback, fsp);
+       SAFE_FREE(fullpath);
+
+       return status;
+}
+
+NTSTATUS change_notify_add_request(const char *inbuf, uint32 max_param_count,
+                                  uint32 filter, BOOL recursive,
+                                  struct files_struct *fsp)
 {
-       struct change_notify *cnbp, *next;
+       struct notify_change_request *request = NULL;
+       struct notify_mid_map *map = NULL;
+
+       if (!(request = SMB_MALLOC_P(struct notify_change_request))
+           || !(map = SMB_MALLOC_P(struct notify_mid_map))) {
+               SAFE_FREE(request);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       request->mid_map = map;
+       map->req = request;
+
+       memcpy(request->request_buf, inbuf, sizeof(request->request_buf));
+       request->max_param_count = max_param_count;
+       request->current_bufsize = 0;
+       request->filter = filter;
+       request->fsp = fsp;
+       request->backend_data = NULL;
+       
+       DLIST_ADD_END(fsp->notify->requests, request,
+                     struct notify_change_request *);
+
+       map->mid = SVAL(inbuf, smb_mid);
+       DLIST_ADD(notify_changes_by_mid, map);
+
+       /* Push the MID of this packet on the signing queue. */
+       srv_defer_sign_response(SVAL(inbuf,smb_mid));
 
-       for (cnbp=change_notify_list; cnbp; cnbp=next) {
-               next=cnbp->next;
-               if (cnbp->fsp->fnum == fsp->fnum) {
-                       change_notify_reply_packet(cnbp->request_buf,status);
-                       change_notify_remove(cnbp);
+       return NT_STATUS_OK;
+}
+
+static void change_notify_remove_request(struct notify_change_request *remove_req)
+{
+       files_struct *fsp;
+       struct notify_change_request *req;
+
+       /*
+        * Paranoia checks, the fsp referenced must must have the request in
+        * its list of pending requests
+        */
+
+       fsp = remove_req->fsp;
+       SMB_ASSERT(fsp->notify != NULL);
+
+       for (req = fsp->notify->requests; req; req = req->next) {
+               if (req == remove_req) {
+                       break;
                }
        }
+
+       if (req == NULL) {
+               smb_panic("notify_req not found in fsp's requests\n");
+       }
+
+       DLIST_REMOVE(fsp->notify->requests, req);
+       DLIST_REMOVE(notify_changes_by_mid, req->mid_map);
+       SAFE_FREE(req->mid_map);
+       TALLOC_FREE(req->backend_data);
+       SAFE_FREE(req);
 }
 
 /****************************************************************************
  Delete entries by mid from the change notify pending queue. Always send reply.
 *****************************************************************************/
 
-void remove_pending_change_notify_requests_by_mid(int mid)
+void remove_pending_change_notify_requests_by_mid(uint16 mid)
 {
-       struct change_notify *cnbp, *next;
+       struct notify_mid_map *map;
 
-       for (cnbp=change_notify_list; cnbp; cnbp=next) {
-               next=cnbp->next;
-               if(SVAL(cnbp->request_buf,smb_mid) == mid) {
-                       change_notify_reply_packet(cnbp->request_buf,NT_STATUS_CANCELLED);
-                       change_notify_remove(cnbp);
+       for (map = notify_changes_by_mid; map; map = map->next) {
+               if (map->mid == mid) {
+                       break;
                }
        }
+
+       if (map == NULL) {
+               return;
+       }
+
+       change_notify_reply_packet(map->req->request_buf, NT_STATUS_CANCELLED);
+       change_notify_remove_request(map->req);
 }
 
 /****************************************************************************
- Delete entries by filename and cnum from the change notify pending queue.
- Always send reply.
+ Delete entries by fnum from the change notify pending queue.
 *****************************************************************************/
 
-void remove_pending_change_notify_requests_by_filename(files_struct *fsp, NTSTATUS status)
+void remove_pending_change_notify_requests_by_fid(files_struct *fsp,
+                                                 NTSTATUS status)
 {
-       struct change_notify *cnbp, *next;
+       if (fsp->notify == NULL) {
+               return;
+       }
 
-       for (cnbp=change_notify_list; cnbp; cnbp=next) {
-               next=cnbp->next;
-               /*
-                * We know it refers to the same directory if the connection number and
-                * the filename are identical.
-                */
-               if((cnbp->fsp->conn == fsp->conn) && strequal(cnbp->fsp->fsp_name,fsp->fsp_name)) {
-                       change_notify_reply_packet(cnbp->request_buf,status);
-                       change_notify_remove(cnbp);
-               }
+       while (fsp->notify->requests != NULL) {
+               change_notify_reply_packet(
+                       fsp->notify->requests->request_buf, status);
+               change_notify_remove_request(fsp->notify->requests);
        }
 }
 
-/****************************************************************************
- Set the current change notify timeout to the lowest value across all service
- values.
-****************************************************************************/
-
-void set_change_notify_timeout(int val)
+void notify_fname(connection_struct *conn, uint32 action, uint32 filter,
+                 const char *path)
 {
-       if (val > 0) {
-               cnotify->select_time = MIN(cnotify->select_time, val);
+       char *fullpath;
+
+       if (asprintf(&fullpath, "%s/%s", conn->connectpath, path) == -1) {
+               DEBUG(0, ("asprintf failed\n"));
+               return;
        }
-}
 
-/****************************************************************************
- Longest time to sleep for before doing a change notify scan.
-****************************************************************************/
+       notify_trigger(conn->notify_ctx, action, filter, fullpath);
+       SAFE_FREE(fullpath);
+}
 
-int change_notify_timeout(void)
+static void notify_fsp(files_struct *fsp, uint32 action, const char *name)
 {
-       return cnotify->select_time;
-}
+       struct notify_change *change, *changes;
+       char *name2;
 
-/****************************************************************************
- Process the change notify queue. Note that this is only called as root.
- Returns True if there are still outstanding change notify requests on the
- queue.
-*****************************************************************************/
+       if (fsp->notify == NULL) {
+               /*
+                * Nobody is waiting, don't queue
+                */
+               return;
+       }
 
-BOOL process_pending_change_notify_queue(time_t t)
-{
-       struct change_notify *cnbp, *next;
-       uint16 vuid;
+       if (!(name2 = talloc_strdup(fsp->notify, name))) {
+               DEBUG(0, ("talloc_strdup failed\n"));
+                       return;
+       }
 
-       for (cnbp=change_notify_list; cnbp; cnbp=next) {
-               next=cnbp->next;
+       string_replace(name2, '/', '\\');
 
-               vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(cnbp->request_buf,smb_uid);
+       /*
+        * Someone has triggered a notify previously, queue the change for
+        * later.
+        */
 
-               if (cnotify->check_notify(cnbp->conn, vuid, cnbp->fsp->fsp_name, cnbp->flags, cnbp->change_data, t)) {
-                       DEBUG(10,("process_pending_change_notify_queue: dir %s changed !\n", cnbp->fsp->fsp_name ));
-                       change_notify_reply_packet(cnbp->request_buf,STATUS_NOTIFY_ENUM_DIR);
-                       change_notify_remove(cnbp);
-               }
+       if ((fsp->notify->num_changes > 1000) || (name == NULL)) {
+               /*
+                * The real number depends on the client buf, just provide a
+                * guard against a DoS here.
+                */
+               TALLOC_FREE(fsp->notify->changes);
+               TALLOC_FREE(name2);
+               fsp->notify->num_changes = -1;
+               return;
        }
 
-       return (change_notify_list != NULL);
-}
+       if (fsp->notify->num_changes == -1) {
+               return;
+       }
 
-/****************************************************************************
- Now queue an entry on the notify change list.
- We only need to save smb_size bytes from this incoming packet
- as we will always by returning a 'read the directory yourself'
- error.
-****************************************************************************/
+       if (!(changes = TALLOC_REALLOC_ARRAY(
+                     fsp->notify, fsp->notify->changes,
+                     struct notify_change, fsp->notify->num_changes+1))) {
+               DEBUG(0, ("talloc_realloc failed\n"));
+               TALLOC_FREE(name2);
+               return;
+       }
 
-BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn, uint32 flags)
-{
-       struct change_notify *cnbp;
+       fsp->notify->changes = changes;
 
-       if((cnbp = SMB_MALLOC_P(struct change_notify)) == NULL) {
-               DEBUG(0,("change_notify_set: malloc fail !\n" ));
-               return -1;
-       }
+       change = &(fsp->notify->changes[fsp->notify->num_changes]);
 
-       ZERO_STRUCTP(cnbp);
+       change->name = talloc_move(changes, &name2);
+       change->action = action;
+       fsp->notify->num_changes += 1;
 
-       memcpy(cnbp->request_buf, inbuf, smb_size);
-       cnbp->fsp = fsp;
-       cnbp->conn = conn;
-       cnbp->flags = flags;
-       cnbp->change_data = cnotify->register_notify(conn, fsp->fsp_name, flags);
-       
-       if (!cnbp->change_data) {
-               SAFE_FREE(cnbp);
-               return False;
+       if (fsp->notify->requests == NULL) {
+               /*
+                * Nobody is waiting, so don't send anything. The ot
+                */
+               return;
+       }
+
+       if (action == NOTIFY_ACTION_OLD_NAME) {
+               /*
+                * We have to send the two rename events in one reply. So hold
+                * the first part back.
+                */
+       return;
        }
 
-       DLIST_ADD(change_notify_list, cnbp);
+       /*
+        * Someone is waiting for the change, trigger the reply immediately.
+        *
+        * TODO: do we have to walk the lists of requests pending?
+        */
 
-       /* Push the MID of this packet on the signing queue. */
-       srv_defer_sign_response(SVAL(inbuf,smb_mid));
+       change_notify_reply(fsp->notify->requests->request_buf,
+                           fsp->notify->requests->max_param_count,
+                           fsp->notify);
 
-       return True;
+       change_notify_remove_request(fsp->notify->requests);
 }
 
-int change_notify_fd(void)
+char *notify_filter_string(TALLOC_CTX *mem_ctx, uint32 filter)
 {
-       if (cnotify) {
-               return cnotify->notification_fd;
-       }
-
-       return -1;
+       char *result = NULL;
+
+       result = talloc_strdup(mem_ctx, "");
+
+       if (filter & FILE_NOTIFY_CHANGE_FILE_NAME)
+               result = talloc_asprintf_append(result, "FILE_NAME|");
+       if (filter & FILE_NOTIFY_CHANGE_DIR_NAME)
+               result = talloc_asprintf_append(result, "DIR_NAME|");
+       if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)
+               result = talloc_asprintf_append(result, "ATTRIBUTES|");
+       if (filter & FILE_NOTIFY_CHANGE_SIZE)
+               result = talloc_asprintf_append(result, "SIZE|");
+       if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE)
+               result = talloc_asprintf_append(result, "LAST_WRITE|");
+       if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS)
+               result = talloc_asprintf_append(result, "LAST_ACCESS|");
+       if (filter & FILE_NOTIFY_CHANGE_CREATION)
+               result = talloc_asprintf_append(result, "CREATION|");
+       if (filter & FILE_NOTIFY_CHANGE_EA)
+               result = talloc_asprintf_append(result, "EA|");
+       if (filter & FILE_NOTIFY_CHANGE_SECURITY)
+               result = talloc_asprintf_append(result, "SECURITY|");
+       if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME)
+               result = talloc_asprintf_append(result, "STREAM_NAME|");
+       if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE)
+               result = talloc_asprintf_append(result, "STREAM_SIZE|");
+       if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE)
+               result = talloc_asprintf_append(result, "STREAM_WRITE|");
+
+       if (result == NULL) return NULL;
+       if (*result == '\0') return result;
+
+       result[strlen(result)-1] = '\0';
+       return result;
 }
 
-/****************************************************************************
- Initialise the change notify subsystem.
-****************************************************************************/
-
-BOOL init_change_notify(void)
+struct sys_notify_context *sys_notify_context_create(connection_struct *conn,
+                                                    TALLOC_CTX *mem_ctx, 
+                                                    struct event_context *ev)
 {
-       cnotify = NULL;
-
-#if HAVE_KERNEL_CHANGE_NOTIFY
-       if (cnotify == NULL && lp_kernel_change_notify())
-               cnotify = kernel_notify_init();
-#endif
-#if HAVE_FAM_CHANGE_NOTIFY
-       if (cnotify == NULL && lp_fam_change_notify())
-               cnotify = fam_notify_init();
-#endif
-       if (!cnotify) cnotify = hash_notify_init();
-       
-       if (!cnotify) {
-               DEBUG(0,("Failed to init change notify system\n"));
-               return False;
+       struct sys_notify_context *ctx;
+
+       if (!(ctx = TALLOC_P(mem_ctx, struct sys_notify_context))) {
+               DEBUG(0, ("talloc failed\n"));
+               return NULL;
        }
 
-       return True;
+       ctx->ev = ev;
+       ctx->conn = conn;
+       ctx->private_data = NULL;
+       return ctx;
 }
+
+NTSTATUS sys_notify_watch(struct sys_notify_context *ctx,
+                         struct notify_entry *e,
+                         void (*callback)(struct sys_notify_context *ctx, 
+                                          void *private_data,
+                                          struct notify_event *ev),
+                         void *private_data, void *handle)
+{
+       return SMB_VFS_NOTIFY_WATCH(ctx->conn, ctx, e, callback, private_data,
+                                   handle);
+}
+
diff --git a/source/smbd/notify_fam.c b/source/smbd/notify_fam.c
deleted file mode 100644 (file)
index bfef4ac..0000000
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * FAM file notification support.
- *
- * Copyright (c) James Peach 2005
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#include "includes.h"
-
-#ifdef HAVE_FAM_CHANGE_NOTIFY
-
-#include <fam.h>
-
-#if !defined(HAVE_FAM_H_FAMCODES_TYPEDEF)
-/* Gamin provides this typedef which means we can't use 'enum FAMCodes' as per
- * every other FAM implementation. Phooey.
- */
-typedef enum FAMCodes FAMCodes;
-#endif
-
-/* NOTE: There are multiple versions of FAM floating around the net, each with
- * slight differences from the original SGI FAM implementation. In this file,
- * we rely only on the SGI features and do not assume any extensions. For
- * example, we do not look at FAMErrno, because it is not set by the original
- * implementation.
- *
- * Random FAM links:
- *     http://oss.sgi.com/projects/fam/
- *     http://savannah.nongnu.org/projects/fam/
- *     http://sourceforge.net/projects/bsdfam/
- */
-
-struct fam_req_info
-{
-    FAMRequest     req;
-    int                    generation;
-    FAMCodes       code;
-    enum
-    {
-       /* We are waiting for an event. */
-       FAM_REQ_MONITORING,
-       /* An event has been receive, but we haven't been able to send it back
-        * to the client yet. It is stashed in the code member.
-        */
-       FAM_REQ_FIRED
-    } state;
-};
-
-/* Don't initialise this until the first register request. We want a single
- * FAM connection for each worker smbd. If we allow the master (parent) smbd to
- * open a FAM connection, multiple processes talking on the same socket will
- * undoubtedly create havoc.
- */
-static FAMConnection   global_fc;
-static int             global_fc_generation;
-
-#define FAM_TRACE      8
-#define FAM_TRACE_LOW  10
-
-#define FAM_EVENT_DRAIN                    ((uint32_t)(-1))
-
-static void * fam_register_notify(connection_struct * conn,
-                   char *              path,
-                   uint32              flags);
-
-static BOOL fam_check_notify(connection_struct * conn,
-                uint16_t               vuid,
-                char *                 path,
-                uint32_t               flags,
-                void *                 data,
-                time_t                 when);
-
-static void fam_remove_notify(void * data);
-
-static struct cnotify_fns global_fam_notify =
-{
-    fam_register_notify,
-    fam_check_notify,
-    fam_remove_notify,
-    -1,
-    -1
-};
-
-/* Turn a FAM event code into a string. Don't rely on specific code values,
- * because that might not work across all flavours of FAM.
- */
-static const char *
-fam_event_str(FAMCodes code)
-{
-    static const struct { FAMCodes code; const char * name; } evstr[] =
-    {
-       { FAMChanged,           "FAMChanged"},
-       { FAMDeleted,           "FAMDeleted"},
-       { FAMStartExecuting,    "FAMStartExecuting"},
-       { FAMStopExecuting,     "FAMStopExecuting"},
-       { FAMCreated,           "FAMCreated"},
-       { FAMMoved,             "FAMMoved"},
-       { FAMAcknowledge,       "FAMAcknowledge"},
-       { FAMExists,            "FAMExists"},
-       { FAMEndExist,          "FAMEndExist"}
-    };
-
-    int i;
-
-    for (i = 0; i < ARRAY_SIZE(evstr); ++i) {
-       if (code == evstr[i].code)
-           return(evstr[i].name);
-    }
-
-    return("<unknown>");
-}
-
-static BOOL
-fam_check_reconnect(void)
-{
-    if (FAMCONNECTION_GETFD(&global_fc) < 0) {
-       fstring name;
-
-       global_fc_generation++;
-       snprintf(name, sizeof(name), "smbd (%lu)", (unsigned long)sys_getpid());
-
-       if (FAMOpen2(&global_fc, name) < 0) {
-           DEBUG(0, ("failed to connect to FAM service\n"));
-           return(False);
-       }
-    }
-
-    global_fam_notify.notification_fd = FAMCONNECTION_GETFD(&global_fc);
-    return(True);
-}
-
-static BOOL
-fam_monitor_path(connection_struct *   conn,
-                struct fam_req_info *  info,
-                const char *           path,
-                uint32                 flags)
-{
-    SMB_STRUCT_STAT st;
-    pstring        fullpath;
-
-    DEBUG(FAM_TRACE, ("requesting FAM notifications for '%s'\n", path));
-
-    /* FAM needs an absolute pathname. */
-
-    /* It would be better to use reduce_name() here, but reduce_name does not
-     * actually return the reduced result. How utterly un-useful.
-     */
-    pstrcpy(fullpath, path);
-    if (!canonicalize_path(conn, fullpath)) {
-       DEBUG(0, ("failed to canonicalize path '%s'\n", path));
-       return(False);
-    }
-
-    if (*fullpath != '/') {
-       DEBUG(0, ("canonicalized path '%s' into `%s`\n", path, fullpath));
-       DEBUGADD(0, ("but expected an absolute path\n"));
-       return(False);
-    }
-
-    if (SMB_VFS_STAT(conn, path, &st) < 0) {
-       DEBUG(0, ("stat of '%s' failed: %s\n", path, strerror(errno)));
-       return(False);
-    }
-    /* Start monitoring this file or directory. We hand the state structure to
-     * both the caller and the FAM library so we can match up the caller's
-     * status requests with FAM notifications.
-     */
-    if (S_ISDIR(st.st_mode)) {
-       FAMMonitorDirectory(&global_fc, fullpath, &(info->req), info);
-    } else {
-       FAMMonitorFile(&global_fc, fullpath, &(info->req), info);
-    }
-
-    /* Grr. On IRIX, neither of the monitor functions return a status. */
-
-    /* We will stay in initialising state until we see the FAMendExist message
-     * for this file.
-     */
-    info->state = FAM_REQ_MONITORING;
-    info->generation = global_fc_generation;
-    return(True);
-}
-
-static BOOL
-fam_handle_event(const FAMCodes code, uint32 flags)
-{
-#define F_CHANGE_MASK (FILE_NOTIFY_CHANGE_FILE | \
-                       FILE_NOTIFY_CHANGE_ATTRIBUTES | \
-                       FILE_NOTIFY_CHANGE_SIZE | \
-                       FILE_NOTIFY_CHANGE_LAST_WRITE | \
-                       FILE_NOTIFY_CHANGE_LAST_ACCESS | \
-                       FILE_NOTIFY_CHANGE_CREATION | \
-                       FILE_NOTIFY_CHANGE_EA | \
-                       FILE_NOTIFY_CHANGE_SECURITY)
-
-#define F_DELETE_MASK (FILE_NOTIFY_CHANGE_FILE_NAME | \
-                       FILE_NOTIFY_CHANGE_DIR_NAME)
-
-#define F_CREATE_MASK (FILE_NOTIFY_CHANGE_FILE_NAME | \
-                       FILE_NOTIFY_CHANGE_DIR_NAME)
-
-    switch (code) {
-       case FAMChanged:
-           if (flags & F_CHANGE_MASK)
-               return(True);
-           break;
-       case FAMDeleted:
-           if (flags & F_DELETE_MASK)
-               return(True);
-           break;
-       case FAMCreated:
-           if (flags & F_CREATE_MASK)
-               return(True);
-           break;
-       default:
-           /* Ignore anything else. */
-           break;
-    }
-
-    return(False);
-
-#undef F_CHANGE_MASK
-#undef F_DELETE_MASK
-#undef F_CREATE_MASK
-}
-
-static BOOL
-fam_pump_events(struct fam_req_info * info, uint32_t flags)
-{
-    FAMEvent ev;
-
-    for (;;) {
-
-       /* If we are draining the event queue we must keep going until we find
-        * the correct FAMAcknowledge event or the connection drops. Otherwise
-        * we should stop when there are no more events pending.
-        */
-       if (flags != FAM_EVENT_DRAIN && !FAMPending(&global_fc)) {
-           break;
-       }
-
-       if (FAMNextEvent(&global_fc, &ev) < 0) {
-           DEBUG(0, ("failed to fetch pending FAM event\n"));
-           DEBUGADD(0, ("resetting FAM connection\n"));
-           FAMClose(&global_fc);
-           FAMCONNECTION_GETFD(&global_fc) = -1;
-           return(False);
-       }
-
-       DEBUG(FAM_TRACE_LOW, ("FAM event %s on '%s' for request %d\n",
-                   fam_event_str(ev.code), ev.filename, ev.fr.reqnum));
-
-       switch (ev.code) {
-           case FAMAcknowledge:
-               /* FAM generates an ACK event when we cancel a monitor. We need
-                * this to know when it is safe to free out request state
-                * structure.
-                */
-               if (info->generation == global_fc_generation &&
-                   info->req.reqnum == ev.fr.reqnum &&
-                   flags == FAM_EVENT_DRAIN) {
-                   return(True);
-               }
-
-           case FAMEndExist:
-           case FAMExists:
-               /* Ignore these. FAM sends these enumeration events when we
-                * start monitoring. If we are monitoring a directory, we will
-                * get a FAMExists event for each directory entry.
-                */
-
-               /* TODO: we might be able to use these to implement recursive
-                * monitoring of entire subtrees.
-                */
-           case FAMMoved:
-               /* These events never happen. A move or rename shows up as a
-                * create/delete pair.
-                */
-           case FAMStartExecuting:
-           case FAMStopExecuting:
-               /* We might get these, but we just don't care. */
-               break;
-
-           case FAMChanged:
-           case FAMDeleted:
-           case FAMCreated:
-               if (info->generation != global_fc_generation) {
-                   /* Ignore this; the req number can't be matched. */
-                   break;
-               }
-
-               if (info->req.reqnum == ev.fr.reqnum) {
-                   /* This is the event the caller was interested in. */
-                   DEBUG(FAM_TRACE, ("handling FAM %s event on '%s'\n",
-                               fam_event_str(ev.code), ev.filename));
-                   /* Ignore events if we are draining this request. */
-                   if (flags != FAM_EVENT_DRAIN) {
-                       return(fam_handle_event(ev.code, flags));
-                   }
-                   break;
-               } else {
-                   /* Caller doesn't want this event. Stash the result so we
-                    * can come back to it. Unfortunately, FAM doesn't
-                    * guarantee to give us back evinfo.
-                    */
-                   struct fam_req_info * evinfo =
-                       (struct fam_req_info *)ev.userdata;
-
-                   if (evinfo) {
-                       DEBUG(FAM_TRACE, ("storing FAM %s event for winter\n",
-                                   fam_event_str(ev.code)));
-                       evinfo->state = FAM_REQ_FIRED;
-                       evinfo->code = ev.code;
-                   } else {
-                       DEBUG(2, ("received FAM %s notification for %s, "
-                                 "but userdata was unexpectedly NULL\n",
-                                 fam_event_str(ev.code), ev.filename));
-                   }
-                   break;
-               }
-
-           default:
-               DEBUG(0, ("ignoring unknown FAM event code %d for `%s`\n",
-                           ev.code, ev.filename));
-       }
-    }
-
-    /* No more notifications pending. */
-    return(False);
-}
-
-static BOOL
-fam_test_connection(void)
-{
-    FAMConnection fc;
-
-    /* On IRIX FAMOpen2 leaks 960 bytes in 48 blocks. It's a deliberate leak
-     * in the library and there's nothing we can do about it here.
-     */
-    if (FAMOpen2(&fc, "smbd probe") < 0)
-       return(False);
-
-    FAMClose(&fc);
-    return(True);
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void *
-fam_register_notify(connection_struct * conn,
-                   char *              path,
-                   uint32              flags)
-{
-    struct fam_req_info * info;
-
-    if (!fam_check_reconnect()) {
-       return(False);
-    }
-
-    if ((info = SMB_MALLOC_P(struct fam_req_info)) == NULL) {
-       DEBUG(0, ("malloc of %u bytes failed\n", (unsigned int)sizeof(struct fam_req_info)));
-       return(NULL);
-    }
-
-    if (fam_monitor_path(conn, info, path, flags)) {
-       return(info);
-    } else {
-       SAFE_FREE(info);
-       return(NULL);
-    }
-}
-
-static BOOL
-fam_check_notify(connection_struct *   conn,
-                uint16_t               vuid,
-                char *                 path,
-                uint32_t               flags,
-                void *                 data,
-                time_t                 when)
-{
-    struct fam_req_info * info;
-
-    info = (struct fam_req_info *)data;
-    SMB_ASSERT(info != NULL);
-
-    DEBUG(10, ("checking FAM events for `%s`\n", path));
-
-    if (info->state == FAM_REQ_FIRED) {
-       DEBUG(FAM_TRACE, ("handling previously fired FAM %s event\n",
-                   fam_event_str(info->code)));
-       info->state = FAM_REQ_MONITORING;
-       return(fam_handle_event(info->code, flags));
-    }
-
-    if (!fam_check_reconnect()) {
-       return(False);
-    }
-
-    if (info->generation != global_fc_generation) {
-       DEBUG(FAM_TRACE, ("reapplying stale FAM monitor to %s\n", path));
-       fam_monitor_path(conn, info, path, flags);
-       return(False);
-    }
-
-    return(fam_pump_events(info, flags));
-}
-
-static void
-fam_remove_notify(void * data)
-{
-    struct fam_req_info * info;
-
-    if ((info = (struct fam_req_info *)data) == NULL)
-       return;
-
-    /* No need to reconnect. If the FAM connection is gone, there's no need to
-     * cancel and we can safely let FAMCancelMonitor fail. If it we
-     * reconnected, then the generation check will stop us cancelling the wrong
-     * request.
-     */
-
-    if ((FAMCONNECTION_GETFD(&global_fc) != -1)
-       && (info->generation == global_fc_generation)) {
-       DEBUG(FAM_TRACE, ("removing FAM notification for request %d\n",
-                   info->req.reqnum));
-       FAMCancelMonitor(&global_fc, &(info->req));
-
-       /* Soak up all events until the FAMAcknowledge. We can't free
-        * our request state until we are sure there are no more events in
-        * flight.
-        */
-       fam_pump_events(info, FAM_EVENT_DRAIN);
-    }
-
-    SAFE_FREE(info);
-}
-
-struct cnotify_fns * fam_notify_init(void)
-{
-    FAMCONNECTION_GETFD(&global_fc) = -1;
-
-    if (!fam_test_connection()) {
-       DEBUG(0, ("FAM file change notifications not available\n"));
-       return(NULL);
-    }
-
-    DEBUG(FAM_TRACE, ("enabling FAM change notifications\n"));
-    return &global_fam_notify;
-}
-
-#endif /* HAVE_FAM_CHANGE_NOTIFY */
diff --git a/source/smbd/notify_hash.c b/source/smbd/notify_hash.c
deleted file mode 100644 (file)
index 0787a3e..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
-   Unix SMB/CIFS implementation.
-   change notify handling - hash based implementation
-   Copyright (C) Jeremy Allison 1994-1998
-   Copyright (C) Andrew Tridgell 2000
-
-   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"
-
-struct change_data {
-       time_t last_check_time; /* time we last checked this entry */
-       struct timespec modify_time; /* Info from the directory we're monitoring. */
-       struct timespec status_time; /* Info from the directory we're monitoring. */
-       time_t total_time; /* Total time of all directory entries - don't care if it wraps. */
-       unsigned int num_entries; /* Zero or the number of files in the directory. */
-       unsigned int mode_sum;
-       unsigned char name_hash[16];
-};
-
-
-/* Compare struct timespec. */
-#define TIMESTAMP_NEQ(x, y) (((x).tv_sec != (y).tv_sec) || ((x).tv_nsec != (y).tv_nsec))
-
-/****************************************************************************
- Create the hash we will use to determine if the contents changed.
-*****************************************************************************/
-
-static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags, 
-                       struct change_data *data, struct change_data *old_data)
-{
-       SMB_STRUCT_STAT st;
-       pstring full_name;
-       char *p;
-       const char *fname;
-       size_t remaining_len;
-       size_t fullname_len;
-       struct smb_Dir *dp;
-       long offset;
-
-       ZERO_STRUCTP(data);
-
-       if(SMB_VFS_STAT(conn,path, &st) == -1)
-               return False;
-
-       data->modify_time = get_mtimespec(&st);
-       data->status_time = get_ctimespec(&st);
-
-       if (old_data) {
-               /*
-                * Shortcut to avoid directory scan if the time
-                * has changed - we always must return true then.
-                */
-               if (TIMESTAMP_NEQ(old_data->modify_time, data->modify_time) ||
-                   TIMESTAMP_NEQ(old_data->status_time, data->status_time) ) {
-                               return True;
-               }
-       }
-        if (S_ISDIR(st.st_mode) && 
-            (flags & ~(FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) == 0)
-        {
-               /* This is the case of a client wanting to know only when
-                * the contents of a directory changes. Since any file
-                * creation, rename or deletion will update the directory
-                * timestamps, we don't need to create a hash.
-                */
-                return True;
-        }
-
-       if (lp_change_notify_timeout(SNUM(conn)) <= 0) {
-               /* It change notify timeout has been disabled, never scan the directory. */
-               return True;
-       }
-
-       /*
-        * If we are to watch for changes that are only stored
-        * in inodes of files, not in the directory inode, we must
-        * scan the directory and produce a unique identifier with
-        * which we can determine if anything changed. We use the
-        * modify and change times from all the files in the
-        * directory, added together (ignoring wrapping if it's
-        * larger than the max time_t value).
-        */
-
-       dp = OpenDir(conn, path, NULL, 0);
-       if (dp == NULL)
-               return False;
-
-       data->num_entries = 0;
-       
-       pstrcpy(full_name, path);
-       pstrcat(full_name, "/");
-       
-       fullname_len = strlen(full_name);
-       remaining_len = sizeof(full_name) - fullname_len - 1;
-       p = &full_name[fullname_len];
-       
-       offset = 0;
-       while ((fname = ReadDirName(dp, &offset))) {
-               SET_STAT_INVALID(st);
-               if(strequal(fname, ".") || strequal(fname, ".."))
-                       continue;               
-
-               if (!is_visible_file(conn, path, fname, &st, True))
-                       continue;
-
-               data->num_entries++;
-               safe_strcpy(p, fname, remaining_len);
-
-               /*
-                * Do the stat - but ignore errors.
-                */             
-               if (!VALID_STAT(st)) {
-                       SMB_VFS_STAT(conn,full_name, &st);
-               }
-
-               /*
-                * Always sum the times.
-                */
-
-               data->total_time += (st.st_mtime + st.st_ctime);
-
-               /*
-                * If requested hash the names.
-                */
-
-               if (flags & (FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_FILE)) {
-                       int i;
-                       unsigned char tmp_hash[16];
-                       mdfour(tmp_hash, (const unsigned char *)fname, strlen(fname));
-                       for (i=0;i<16;i++)
-                               data->name_hash[i] ^= tmp_hash[i];
-               }
-
-               /*
-                * If requested sum the mode_t's.
-                */
-
-               if (flags & (FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_SECURITY))
-                       data->mode_sum += st.st_mode;
-       }
-       
-       CloseDir(dp);
-       
-       return True;
-}
-
-/****************************************************************************
- Register a change notify request.
-*****************************************************************************/
-
-static void *hash_register_notify(connection_struct *conn, char *path, uint32 flags)
-{
-       struct change_data data;
-
-       if (!notify_hash(conn, path, flags, &data, NULL))
-               return NULL;
-
-       data.last_check_time = time(NULL);
-
-       return (void *)memdup(&data, sizeof(data));
-}
-
-/****************************************************************************
- Check if a change notify should be issued.
- A time of zero means instantaneous check - don't modify the last check time.
-*****************************************************************************/
-
-static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t)
-{
-       struct change_data *data = (struct change_data *)datap;
-       struct change_data data2;
-       int cnto = lp_change_notify_timeout(SNUM(conn));
-
-       if (t && cnto <= 0) {
-               /* Change notify turned off on this share.
-                * Only scan when (t==0) - we think something changed. */
-               return False;
-       }
-
-       if (t && t < data->last_check_time + cnto) {
-               return False;
-       }
-
-       if (!change_to_user(conn,vuid))
-               return True;
-       if (!set_current_service(conn,FLAG_CASELESS_PATHNAMES,True)) {
-               change_to_root_user();
-               return True;
-       }
-
-       if (!notify_hash(conn, path, flags, &data2, data) ||
-           TIMESTAMP_NEQ(data2.modify_time, data->modify_time) ||
-           TIMESTAMP_NEQ(data2.status_time, data->status_time) ||
-           data2.total_time != data->total_time ||
-           data2.num_entries != data->num_entries ||
-               data2.mode_sum != data->mode_sum ||
-               memcmp(data2.name_hash, data->name_hash, sizeof(data2.name_hash))) {
-               change_to_root_user();
-               return True;
-       }
-
-       if (t) {
-               data->last_check_time = t;
-       }
-
-       change_to_root_user();
-
-       return False;
-}
-
-/****************************************************************************
- Remove a change notify data structure.
-*****************************************************************************/
-
-static void hash_remove_notify(void *datap)
-{
-       free(datap);
-}
-
-/****************************************************************************
- Setup hash based change notify.
-****************************************************************************/
-
-struct cnotify_fns *hash_notify_init(void) 
-{
-       static struct cnotify_fns cnotify;
-
-       cnotify.register_notify = hash_register_notify;
-       cnotify.check_notify = hash_check_notify;
-       cnotify.remove_notify = hash_remove_notify;
-       cnotify.select_time = 60; /* Start with 1 minute default. */
-       cnotify.notification_fd = -1;
-
-       return &cnotify;
-}
-
-/*
-  change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess);
-  change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_NOTIFY_ENUM_DIR);
-
-  chain_size = 0;
-  file_chain_reset();
-
-  uint16 vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : 
-  SVAL(cnbp->request_buf,smb_uid);
-*/
diff --git a/source/smbd/notify_inotify.c b/source/smbd/notify_inotify.c
new file mode 100644 (file)
index 0000000..5fb414d
--- /dev/null
@@ -0,0 +1,425 @@
+/* 
+   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.
+*/
+
+/*
+  notify implementation using inotify
+*/
+
+#include "includes.h"
+
+#ifdef HAVE_INOTIFY
+
+#include <linux/inotify.h>
+#include <asm/unistd.h>
+
+#ifndef HAVE_INOTIFY_INIT
+/*
+  glibc doesn't define these functions yet (as of March 2006)
+*/
+static int inotify_init(void)
+{
+       return syscall(__NR_inotify_init);
+}
+
+static int inotify_add_watch(int fd, const char *path, __u32 mask)
+{
+       return syscall(__NR_inotify_add_watch, fd, path, mask);
+}
+
+static int inotify_rm_watch(int fd, int wd)
+{
+       return syscall(__NR_inotify_rm_watch, fd, wd);
+}
+#endif
+
+
+/* older glibc headers don't have these defines either */
+#ifndef IN_ONLYDIR
+#define IN_ONLYDIR 0x01000000
+#endif
+#ifndef IN_MASK_ADD
+#define IN_MASK_ADD 0x20000000
+#endif
+
+struct inotify_private {
+       struct sys_notify_context *ctx;
+       int fd;
+       struct inotify_watch_context *watches;
+};
+
+struct inotify_watch_context {
+       struct inotify_watch_context *next, *prev;
+       struct inotify_private *in;
+       int wd;
+       void (*callback)(struct sys_notify_context *ctx, 
+                        void *private_data,
+                        struct notify_event *ev);
+       void *private_data;
+       uint32_t mask; /* the inotify mask */
+       uint32_t filter; /* the windows completion filter */
+       const char *path;
+};
+
+
+/*
+  destroy the inotify private context
+*/
+static int inotify_destructor(struct inotify_private *in)
+{
+       close(in->fd);
+       return 0;
+}
+
+
+/*
+  see if a particular event from inotify really does match a requested
+  notify event in SMB
+*/
+static BOOL filter_match(struct inotify_watch_context *w,
+                        struct inotify_event *e)
+{
+       DEBUG(10, ("filter_match: e->mask=%x, w->mask=%x, w->filter=%x\n",
+                  e->mask, w->mask, w->filter));
+
+       if ((e->mask & w->mask) == 0) {
+               /* this happens because inotify_add_watch() coalesces watches on the same
+                  path, oring their masks together */
+               return False;
+       }
+
+       /* SMB separates the filters for files and directories */
+       if (e->mask & IN_ISDIR) {
+               if ((w->filter & FILE_NOTIFY_CHANGE_DIR_NAME) == 0) {
+                       return False;
+               }
+       } else {
+               if ((e->mask & IN_ATTRIB) &&
+                   (w->filter & (FILE_NOTIFY_CHANGE_ATTRIBUTES|
+                                 FILE_NOTIFY_CHANGE_LAST_WRITE|
+                                 FILE_NOTIFY_CHANGE_LAST_ACCESS|
+                                 FILE_NOTIFY_CHANGE_EA|
+                                 FILE_NOTIFY_CHANGE_SECURITY))) {
+                       return True;
+               }
+               if ((e->mask & IN_MODIFY) && 
+                   (w->filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)) {
+                       return True;
+               }
+               if ((w->filter & FILE_NOTIFY_CHANGE_FILE_NAME) == 0) {
+                       return False;
+               }
+       }
+
+       return True;
+}
+       
+
+
+/*
+  dispatch one inotify event
+  
+  the cookies are used to correctly handle renames
+*/
+static void inotify_dispatch(struct inotify_private *in, 
+                            struct inotify_event *e, 
+                            uint32_t prev_cookie,
+                            struct inotify_event *e2)
+{
+       struct inotify_watch_context *w, *next;
+       struct notify_event ne;
+
+       DEBUG(10, ("inotify_dispatch called with mask=%x, name=[%s]\n",
+                  e->mask, e->len ? e->name : ""));
+
+       /* ignore extraneous events, such as unmount and IN_IGNORED events */
+       if ((e->mask & (IN_ATTRIB|IN_MODIFY|IN_CREATE|IN_DELETE|
+                       IN_MOVED_FROM|IN_MOVED_TO)) == 0) {
+               return;
+       }
+
+       /* map the inotify mask to a action. This gets complicated for
+          renames */
+       if (e->mask & IN_CREATE) {
+               ne.action = NOTIFY_ACTION_ADDED;
+       } else if (e->mask & IN_DELETE) {
+               ne.action = NOTIFY_ACTION_REMOVED;
+       } else if (e->mask & IN_MOVED_FROM) {
+               if (e2 != NULL && e2->cookie == e->cookie) {
+                       ne.action = NOTIFY_ACTION_OLD_NAME;
+               } else {
+                       ne.action = NOTIFY_ACTION_REMOVED;
+               }
+       } else if (e->mask & IN_MOVED_TO) {
+               if (e->cookie == prev_cookie) {
+                       ne.action = NOTIFY_ACTION_NEW_NAME;
+               } else {
+                       ne.action = NOTIFY_ACTION_ADDED;
+               }
+       } else {
+               ne.action = NOTIFY_ACTION_MODIFIED;
+       }
+       ne.path = e->name;
+
+       DEBUG(10, ("inotify_dispatch: ne.action = %d, ne.path = %s\n",
+                  ne.action, ne.path));
+
+       /* find any watches that have this watch descriptor */
+       for (w=in->watches;w;w=next) {
+               next = w->next;
+               if (w->wd == e->wd && filter_match(w, e)) {
+                       w->callback(in->ctx, w->private_data, &ne);
+               }
+       }
+
+       /* SMB expects a file rename to generate three events, two for
+          the rename and the other for a modify of the
+          destination. Strange! */
+       if (ne.action != NOTIFY_ACTION_NEW_NAME ||
+           (e->mask & IN_ISDIR) != 0) {
+               return;
+       }
+
+       ne.action = NOTIFY_ACTION_MODIFIED;
+       e->mask = IN_ATTRIB;
+       
+       for (w=in->watches;w;w=next) {
+               next = w->next;
+               if (w->wd == e->wd && filter_match(w, e) &&
+                   !(w->filter & FILE_NOTIFY_CHANGE_CREATION)) {
+                       w->callback(in->ctx, w->private_data, &ne);
+               }
+       }
+}
+
+/*
+  called when the kernel has some events for us
+*/
+static void inotify_handler(struct event_context *ev, struct fd_event *fde,
+                           uint16_t flags, void *private_data)
+{
+       struct inotify_private *in = talloc_get_type(private_data,
+                                                    struct inotify_private);
+       int bufsize = 0;
+       struct inotify_event *e0, *e;
+       uint32_t prev_cookie=0;
+
+       /*
+         we must use FIONREAD as we cannot predict the length of the
+         filenames, and thus can't know how much to allocate
+         otherwise
+       */
+       if (ioctl(in->fd, FIONREAD, &bufsize) != 0 || 
+           bufsize == 0) {
+               DEBUG(0,("No data on inotify fd?!\n"));
+               return;
+       }
+
+       e0 = e = (struct inotify_event *)talloc_size(in, bufsize);
+       if (e == NULL) return;
+
+       if (read(in->fd, e0, bufsize) != bufsize) {
+               DEBUG(0,("Failed to read all inotify data\n"));
+               talloc_free(e0);
+               return;
+       }
+
+       /* we can get more than one event in the buffer */
+       while (bufsize >= sizeof(*e)) {
+               struct inotify_event *e2 = NULL;
+               bufsize -= e->len + sizeof(*e);
+               if (bufsize >= sizeof(*e)) {
+                       e2 = (struct inotify_event *)(e->len + sizeof(*e) + (char *)e);
+               }
+               inotify_dispatch(in, e, prev_cookie, e2);
+               prev_cookie = e->cookie;
+               e = e2;
+       }
+
+       talloc_free(e0);
+}
+
+/*
+  setup the inotify handle - called the first time a watch is added on
+  this context
+*/
+static NTSTATUS inotify_setup(struct sys_notify_context *ctx)
+{
+       struct inotify_private *in;
+
+       if (!lp_parm_bool(-1, "notify", "inotify", True)) {
+               return NT_STATUS_INVALID_SYSTEM_SERVICE;
+       }
+
+       in = talloc(ctx, struct inotify_private);
+       NT_STATUS_HAVE_NO_MEMORY(in);
+       in->fd = inotify_init();
+       if (in->fd == -1) {
+               DEBUG(0,("Failed to init inotify - %s\n", strerror(errno)));
+               talloc_free(in);
+               return map_nt_error_from_unix(errno);
+       }
+       in->ctx = ctx;
+       in->watches = NULL;
+
+       ctx->private_data = in;
+       talloc_set_destructor(in, inotify_destructor);
+
+       /* add a event waiting for the inotify fd to be readable */
+       event_add_fd(ctx->ev, in, in->fd, EVENT_FD_READ, inotify_handler, in);
+       
+       return NT_STATUS_OK;
+}
+
+
+/*
+  map from a change notify mask to a inotify mask. Remove any bits
+  which we can handle
+*/
+static const struct {
+       uint32_t notify_mask;
+       uint32_t inotify_mask;
+} inotify_mapping[] = {
+       {FILE_NOTIFY_CHANGE_FILE_NAME,   IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO},
+       {FILE_NOTIFY_CHANGE_DIR_NAME,    IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO},
+       {FILE_NOTIFY_CHANGE_ATTRIBUTES,  IN_ATTRIB|IN_MOVED_TO|IN_MOVED_FROM|IN_MODIFY},
+       {FILE_NOTIFY_CHANGE_LAST_WRITE,  IN_ATTRIB},
+       {FILE_NOTIFY_CHANGE_LAST_ACCESS, IN_ATTRIB},
+       {FILE_NOTIFY_CHANGE_EA,          IN_ATTRIB},
+       {FILE_NOTIFY_CHANGE_SECURITY,    IN_ATTRIB}
+};
+
+static uint32_t inotify_map(struct notify_entry *e)
+{
+       int i;
+       uint32_t out=0;
+       for (i=0;i<ARRAY_SIZE(inotify_mapping);i++) {
+               if (inotify_mapping[i].notify_mask & e->filter) {
+                       out |= inotify_mapping[i].inotify_mask;
+                       e->filter &= ~inotify_mapping[i].notify_mask;
+               }
+       }
+       return out;
+}
+
+/*
+  destroy a watch
+*/
+static int watch_destructor(struct inotify_watch_context *w)
+{
+       struct inotify_private *in = w->in;
+       int wd = w->wd;
+       DLIST_REMOVE(w->in->watches, w);
+
+       /* only rm the watch if its the last one with this wd */
+       for (w=in->watches;w;w=w->next) {
+               if (w->wd == wd) break;
+       }
+       if (w == NULL) {
+               DEBUG(10, ("Deleting inotify watch %d\n", wd));
+               if (inotify_rm_watch(in->fd, wd) == -1) {
+                       DEBUG(1, ("inotify_rm_watch returned %s\n",
+                                 strerror(errno)));
+               }
+               
+       }
+       return 0;
+}
+
+
+/*
+  add a watch. The watch is removed when the caller calls
+  talloc_free() on *handle
+*/
+NTSTATUS inotify_watch(struct sys_notify_context *ctx,
+                      struct notify_entry *e,
+                      void (*callback)(struct sys_notify_context *ctx, 
+                                       void *private_data,
+                                       struct notify_event *ev),
+                      void *private_data, 
+                      void *handle_p)
+{
+       struct inotify_private *in;
+       int wd;
+       uint32_t mask;
+       struct inotify_watch_context *w;
+       uint32_t filter = e->filter;
+       void **handle = (void **)handle_p;
+
+       /* maybe setup the inotify fd */
+       if (ctx->private_data == NULL) {
+               NTSTATUS status;
+               status = inotify_setup(ctx);
+               NT_STATUS_NOT_OK_RETURN(status);
+       }
+
+       in = talloc_get_type(ctx->private_data, struct inotify_private);
+
+       mask = inotify_map(e);
+       if (mask == 0) {
+               /* this filter can't be handled by inotify */
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       /* using IN_MASK_ADD allows us to cope with inotify() returning the same
+          watch descriptor for muliple watches on the same path */
+       mask |= (IN_MASK_ADD | IN_ONLYDIR);
+
+       /* get a new watch descriptor for this path */
+       wd = inotify_add_watch(in->fd, e->path, mask);
+       if (wd == -1) {
+               e->filter = filter;
+               DEBUG(1, ("inotify_add_watch returned %s\n", strerror(errno)));
+               return map_nt_error_from_unix(errno);
+       }
+
+       DEBUG(10, ("inotify_add_watch for %s mask %x returned wd %d\n",
+                  e->path, mask, wd));
+
+       w = talloc(in, struct inotify_watch_context);
+       if (w == NULL) {
+               inotify_rm_watch(in->fd, wd);
+               e->filter = filter;
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       w->in = in;
+       w->wd = wd;
+       w->callback = callback;
+       w->private_data = private_data;
+       w->mask = mask;
+       w->filter = filter;
+       w->path = talloc_strdup(w, e->path);
+       if (w->path == NULL) {
+               inotify_rm_watch(in->fd, wd);
+               e->filter = filter;
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       (*handle) = w;
+
+       DLIST_ADD(in->watches, w);
+
+       /* the caller frees the handle to stop watching */
+       talloc_set_destructor(w, watch_destructor);
+       
+       return NT_STATUS_OK;
+}
+
+#endif
diff --git a/source/smbd/notify_internal.c b/source/smbd/notify_internal.c
new file mode 100644 (file)
index 0000000..72b9604
--- /dev/null
@@ -0,0 +1,686 @@
+/* 
+   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 "librpc/gen_ndr/ndr_notify.h"
+
+struct notify_context {
+       struct tdb_wrap *w;
+       struct server_id server;
+       struct messaging_context *messaging_ctx;
+       struct notify_list *list;
+       struct notify_array *array;
+       int seqnum;
+       struct sys_notify_context *sys_notify_ctx;
+};
+
+
+struct notify_list {
+       struct notify_list *next, *prev;
+       void *private_data;
+       void (*callback)(void *, const struct notify_event *);
+       void *sys_notify_handle;
+       int depth;
+};
+
+#define NOTIFY_KEY "notify array"
+
+#define NOTIFY_ENABLE          "notify:enable"
+#define NOTIFY_ENABLE_DEFAULT  True
+
+static NTSTATUS notify_remove_all(struct notify_context *notify,
+                                 const struct server_id *server);
+static void notify_handler(struct messaging_context *msg_ctx, void *private_data, 
+                          uint32_t msg_type, struct server_id server_id, DATA_BLOB *data);
+
+/*
+  destroy the notify context
+*/
+static int notify_destructor(struct notify_context *notify)
+{
+       messaging_deregister(notify->messaging_ctx, MSG_PVFS_NOTIFY, notify);
+
+       if (notify->list != NULL) {
+               notify_remove_all(notify, &notify->server);
+       }
+
+       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, struct server_id server, 
+                                  struct messaging_context *messaging_ctx,
+                                  struct event_context *ev,
+                                  connection_struct *conn)
+{
+       struct notify_context *notify;
+
+       if (!lp_change_notify(conn->params)) {
+               return NULL;
+       }
+
+       notify = talloc(mem_ctx, struct notify_context);
+       if (notify == NULL) {
+               return NULL;
+       }
+
+       notify->w = tdb_wrap_open(notify, lock_path("notify.tdb"),
+                                 0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST,
+                                 O_RDWR|O_CREAT, 0644);
+       if (notify->w == NULL) {
+               talloc_free(notify);
+               return NULL;
+       }
+
+       notify->server = server;
+       notify->messaging_ctx = messaging_ctx;
+       notify->list = NULL;
+       notify->array = NULL;
+       notify->seqnum = tdb_get_seqnum(notify->w->tdb);
+
+       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);
+
+       notify->sys_notify_ctx = sys_notify_context_create(conn, notify, ev);
+
+       return notify;
+}
+
+
+/*
+  lock the notify db
+*/
+static NTSTATUS notify_lock(struct notify_context *notify)
+{
+       if (tdb_lock_bystring(notify->w->tdb, NOTIFY_KEY) != 0) {
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+       return NT_STATUS_OK;
+}
+
+/*
+  unlock the notify db
+*/
+static void notify_unlock(struct notify_context *notify)
+{
+       tdb_unlock_bystring(notify->w->tdb, NOTIFY_KEY);
+}
+
+/*
+  load the notify array
+*/
+static NTSTATUS notify_load(struct notify_context *notify)
+{
+       TDB_DATA dbuf;
+       DATA_BLOB blob;
+       NTSTATUS status;
+       int seqnum;
+
+       seqnum = tdb_get_seqnum(notify->w->tdb);
+
+       if (seqnum == notify->seqnum && notify->array != NULL) {
+               return NT_STATUS_OK;
+       }
+
+       notify->seqnum = seqnum;
+
+       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 = (uint8 *)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);
+
+       if (DEBUGLEVEL >= 10) {
+               DEBUG(10, ("notify_load:\n"));
+               NDR_PRINT_DEBUG(notify_array, notify->array);
+       }
+
+       free(dbuf.dptr);
+
+       return status;
+}
+
+/*
+  compare notify entries for sorting
+*/
+static int notify_compare(const void *p1, const void *p2)
+{
+       const struct notify_entry *e1 = (const struct notify_entry *)p1;
+       const struct notify_entry *e2 = (const struct notify_entry *)p2;
+       return strcmp(e1->path, e2->path);
+}
+
+/*
+  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 possible, remove some depth arrays */
+       while (notify->array->num_depths > 0 &&
+              notify->array->depth[notify->array->num_depths-1].num_entries == 0) {
+               notify->array->num_depths--;
+       }
+
+       /* we might just be able to delete the record */
+       if (notify->array->num_depths == 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);
+       NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
+
+       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;
+       }
+
+       if (DEBUGLEVEL >= 10) {
+               DEBUG(10, ("notify_save:\n"));
+               NDR_PRINT_DEBUG(notify_array, notify->array);
+       }
+
+       dbuf.dptr = (char *)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_data, 
+                          uint32_t msg_type, struct server_id server_id, DATA_BLOB *data)
+{
+       struct notify_context *notify = talloc_get_type(private_data, struct notify_context);
+       NTSTATUS status;
+       struct notify_event ev;
+       TALLOC_CTX *tmp_ctx = talloc_new(notify);
+       struct notify_list *listel;
+
+       if (tmp_ctx == NULL) {
+               return;
+       }
+
+       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_data == ev.private_data) {
+                       listel->callback(listel->private_data, &ev);
+                       break;
+               }
+       }
+
+       talloc_free(tmp_ctx);   
+}
+
+/*
+  callback from sys_notify telling us about changes from the OS
+*/
+static void sys_notify_callback(struct sys_notify_context *ctx, 
+                               void *ptr, struct notify_event *ev)
+{
+       struct notify_list *listel = talloc_get_type(ptr, struct notify_list);
+       ev->private_data = listel;
+       DEBUG(10, ("sys_notify_callback called with action=%d, for %s\n",
+                  ev->action, ev->path));
+       listel->callback(listel->private_data, ev);
+}
+
+/*
+  add an entry to the notify array
+*/
+static NTSTATUS notify_add_array(struct notify_context *notify, struct notify_entry *e,
+                                void *private_data, int depth)
+{
+       int i;
+       struct notify_depth *d;
+       struct notify_entry *ee;
+
+       /* possibly expand the depths array */
+       if (depth >= notify->array->num_depths) {
+               d = talloc_realloc(notify->array, notify->array->depth, 
+                                  struct notify_depth, depth+1);
+               NT_STATUS_HAVE_NO_MEMORY(d);
+               for (i=notify->array->num_depths;i<=depth;i++) {
+                       ZERO_STRUCT(d[i]);
+               }
+               notify->array->depth = d;
+               notify->array->num_depths = depth+1;
+       }
+       d = &notify->array->depth[depth];
+
+       /* expand the entries array */
+       ee = talloc_realloc(notify->array->depth, d->entries, struct notify_entry,
+                           d->num_entries+1);
+       NT_STATUS_HAVE_NO_MEMORY(ee);
+       d->entries = ee;
+
+       d->entries[d->num_entries] = *e;
+       d->entries[d->num_entries].private_data = private_data;
+       d->entries[d->num_entries].server = notify->server;
+       d->entries[d->num_entries].path_len = strlen(e->path);
+       d->num_entries++;
+
+       d->max_mask |= e->filter;
+       d->max_mask_subdir |= e->subdir_filter;
+
+       if (d->num_entries > 1) {
+               qsort(d->entries, d->num_entries, sizeof(d->entries[0]), notify_compare);
+       }
+
+       /* recalculate the maximum masks */
+       d->max_mask = 0;
+       d->max_mask_subdir = 0;
+
+       for (i=0;i<d->num_entries;i++) {
+               d->max_mask |= d->entries[i].filter;
+               d->max_mask_subdir |= d->entries[i].subdir_filter;
+       }
+
+       return notify_save(notify);
+}
+
+/*
+  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 *e0,
+                   void (*callback)(void *, const struct notify_event *), 
+                   void *private_data)
+{
+       struct notify_entry e = *e0;
+       NTSTATUS status;
+       char *tmp_path = NULL;
+       struct notify_list *listel;
+       size_t len;
+       int depth;
+
+       /* see if change notify is enabled at all */
+       if (notify == NULL) {
+               return NT_STATUS_NOT_IMPLEMENTED;
+       }
+
+       status = notify_lock(notify);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       status = notify_load(notify);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto done;
+       }
+
+       /* cope with /. on the end of the path */
+       len = strlen(e.path);
+       if (len > 1 && e.path[len-1] == '.' && e.path[len-2] == '/') {
+               tmp_path = talloc_strndup(notify, e.path, len-2);
+               if (tmp_path == NULL) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto done;
+               }
+               e.path = tmp_path;
+       }
+
+       depth = count_chars(e.path, '/');
+
+       listel = talloc_zero(notify, struct notify_list);
+       if (listel == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
+       listel->private_data = private_data;
+       listel->callback = callback;
+       listel->depth = depth;
+       DLIST_ADD(notify->list, listel);
+
+       /* ignore failures from sys_notify */
+       if (notify->sys_notify_ctx != NULL) {
+               /*
+                 this call will modify e.filter and e.subdir_filter
+                 to remove bits handled by the backend
+               */
+               status = sys_notify_watch(notify->sys_notify_ctx, &e,
+                                         sys_notify_callback, listel, 
+                                         &listel->sys_notify_handle);
+               if (NT_STATUS_IS_OK(status)) {
+                       talloc_steal(listel, listel->sys_notify_handle);
+               }
+       }
+
+       /* 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
+          intra-samba notify handling */
+       if (e.filter != 0 || e.subdir_filter != 0) {
+               status = notify_add_array(notify, &e, private_data, depth);
+       }
+
+done:
+       notify_unlock(notify);
+       talloc_free(tmp_path);
+
+       return status;
+}
+
+/*
+  remove a notify watch. Called when the directory handle is closed
+*/
+NTSTATUS notify_remove(struct notify_context *notify, void *private_data)
+{
+       NTSTATUS status;
+       struct notify_list *listel;
+       int i, depth;
+       struct notify_depth *d;
+
+       /* see if change notify is enabled at all */
+       if (notify == NULL) {
+               return NT_STATUS_NOT_IMPLEMENTED;
+       }
+
+       for (listel=notify->list;listel;listel=listel->next) {
+               if (listel->private_data == private_data) {
+                       DLIST_REMOVE(notify->list, listel);
+                       break;
+               }
+       }
+       if (listel == NULL) {
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       depth = listel->depth;
+
+       talloc_free(listel);
+
+       status = notify_lock(notify);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       status = notify_load(notify);
+       if (!NT_STATUS_IS_OK(status)) {
+               notify_unlock(notify);
+               return status;
+       }
+
+       if (depth >= notify->array->num_depths) {
+               notify_unlock(notify);
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       /* we only have to search at the depth of this element */
+       d = &notify->array->depth[depth];
+
+       for (i=0;i<d->num_entries;i++) {
+               if (private_data == d->entries[i].private_data &&
+                   cluster_id_equal(&notify->server, &d->entries[i].server)) {
+                       break;
+               }
+       }
+       if (i == d->num_entries) {
+               notify_unlock(notify);
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       if (i < d->num_entries-1) {
+               memmove(&d->entries[i], &d->entries[i+1], 
+                       sizeof(d->entries[i])*(d->num_entries-(i+1)));
+       }
+       d->num_entries--;
+
+       status = notify_save(notify);
+
+       notify_unlock(notify);
+
+       return status;
+}
+
+/*
+  remove all notify watches for a messaging server
+*/
+static NTSTATUS notify_remove_all(struct notify_context *notify,
+                                 const struct server_id *server)
+{
+       NTSTATUS status;
+       int i, depth, del_count=0;
+
+       status = notify_lock(notify);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       status = notify_load(notify);
+       if (!NT_STATUS_IS_OK(status)) {
+               notify_unlock(notify);
+               return status;
+       }
+
+       /* we have to search for all entries across all depths, looking for matches
+          for the server id */
+       for (depth=0;depth<notify->array->num_depths;depth++) {
+               struct notify_depth *d = &notify->array->depth[depth];
+               for (i=0;i<d->num_entries;i++) {
+                       if (cluster_id_equal(server, &d->entries[i].server)) {
+                               if (i < d->num_entries-1) {
+                                       memmove(&d->entries[i], &d->entries[i+1], 
+                                               sizeof(d->entries[i])*(d->num_entries-(i+1)));
+                               }
+                               i--;
+                               d->num_entries--;
+                               del_count++;
+                       }
+               }
+       }
+
+       if (del_count > 0) {
+               status = notify_save(notify);
+       }
+
+       notify_unlock(notify);
+
+       return status;
+}
+
+
+/*
+  send a notify message to another messaging server
+*/
+static NTSTATUS 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_data = e->private_data;
+
+       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;
+       }
+
+       status = messaging_send(notify->messaging_ctx, e->server, 
+                               MSG_PVFS_NOTIFY, &data);
+       talloc_free(tmp_ctx);
+       return status;
+}
+
+
+/*
+  trigger a notify message for anyone waiting on a matching event
+
+  This function is called a lot, and needs to be very fast. The unusual data structure
+  and traversal is designed to be fast in the average case, even for large numbers of
+  notifies
+*/
+void notify_trigger(struct notify_context *notify,
+                   uint32_t action, uint32_t filter, const char *path)
+{
+       NTSTATUS status;
+       int depth;
+       const char *p, *next_p;
+
+       DEBUG(10, ("notify_trigger called action=0x%x, filter=0x%x, "
+                  "path=%s\n", (unsigned)action, (unsigned)filter, path));
+
+       /* see if change notify is enabled at all */
+       if (notify == NULL) {
+               return;
+       }
+
+ again:
+       status = notify_load(notify);
+       if (!NT_STATUS_IS_OK(status)) {
+               return;
+       }
+
+       /* loop along the given path, working with each directory depth separately */
+       for (depth=0,p=path;
+            p && depth < notify->array->num_depths;
+            p=next_p,depth++) {
+               int p_len = p - path;
+               int min_i, max_i, i;
+               struct notify_depth *d = &notify->array->depth[depth];
+               next_p = strchr(p+1, '/');
+
+               /* see if there are any entries at this depth */
+               if (d->num_entries == 0) continue;
+               
+               /* try to skip based on the maximum mask. If next_p is
+                NULL then we know it will be a 'this directory'
+                match, otherwise it must be a subdir match */
+               if (next_p != NULL) {
+                       if (0 == (filter & d->max_mask_subdir)) {
+                               continue;
+                       }
+               } else {
+                       if (0 == (filter & d->max_mask)) {
+                               continue;
+                       }
+               }
+
+               /* we know there is an entry here worth looking
+                for. Use a bisection search to find the first entry
+                with a matching path */
+               min_i = 0;
+               max_i = d->num_entries-1;
+
+               while (min_i < max_i) {
+                       struct notify_entry *e;
+                       int cmp;
+                       i = (min_i+max_i)/2;
+                       e = &d->entries[i];
+                       cmp = strncmp(path, e->path, p_len);
+                       if (cmp == 0) {
+                               if (p_len == e->path_len) {
+                                       max_i = i;
+                               } else {
+                                       max_i = i-1;
+                               }
+                       } else if (cmp < 0) {
+                               max_i = i-1;
+                       } else {
+                               min_i = i+1;
+                       }
+               }
+
+               if (min_i != max_i) {
+                       /* none match */
+                       continue;
+               }
+
+               /* we now know that the entries start at min_i */
+               for (i=min_i;i<d->num_entries;i++) {
+                       struct notify_entry *e = &d->entries[i];
+                       if (p_len != e->path_len ||
+                           strncmp(path, e->path, p_len) != 0) break;
+                       if (next_p != NULL) {
+                               if (0 == (filter & e->subdir_filter)) {
+                                       continue;
+                               }
+                       } else {
+                               if (0 == (filter & e->filter)) {
+                                       continue;
+                               }
+                       }
+                       status = notify_send(notify, e, path + e->path_len + 1,
+                                            action);
+
+                       if (NT_STATUS_EQUAL(
+                                   status, NT_STATUS_INVALID_HANDLE)) {
+                               struct server_id server = e->server;
+
+                               DEBUG(10, ("Deleting notify entries for "
+                                          "process %s because it's gone\n",
+                                          procid_str_static(&e->server.id)));
+                               notify_remove_all(notify, &server);
+                               goto again;
+                       }
+               }
+       }
+}
diff --git a/source/smbd/notify_kernel.c b/source/smbd/notify_kernel.c
deleted file mode 100644 (file)
index 0c20eff..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
-   Unix SMB/Netbios implementation.
-   Version 3.0
-   change notify handling - linux kernel based implementation
-   Copyright (C) Andrew Tridgell 2000
-
-   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"
-
-#if HAVE_KERNEL_CHANGE_NOTIFY
-
-#define FD_PENDING_SIZE 20
-static SIG_ATOMIC_T fd_pending_array[FD_PENDING_SIZE];
-static SIG_ATOMIC_T signals_received;
-
-#ifndef DN_ACCESS
-#define DN_ACCESS       0x00000001      /* File accessed in directory */
-#define DN_MODIFY       0x00000002      /* File modified in directory */
-#define DN_CREATE       0x00000004      /* File created in directory */
-#define DN_DELETE       0x00000008      /* File removed from directory */
-#define DN_RENAME       0x00000010      /* File renamed in directory */
-#define DN_ATTRIB       0x00000020      /* File changed attribute */
-#define DN_MULTISHOT    0x80000000      /* Don't remove notifier */
-#endif
-
-
-#ifndef RT_SIGNAL_NOTIFY
-#define RT_SIGNAL_NOTIFY (SIGRTMIN+2)
-#endif
-
-#ifndef F_SETSIG
-#define F_SETSIG 10
-#endif
-
-#ifndef F_NOTIFY
-#define F_NOTIFY 1026
-#endif
-
-/****************************************************************************
- This is the structure to keep the information needed to
- determine if a directory has changed.
-*****************************************************************************/
-
-struct change_data {
-       int directory_handle;
-};
-
-/****************************************************************************
- The signal handler for change notify.
- The Linux kernel has a bug in that we should be able to block any
- further delivery of RT signals until the kernel_check_notify() function
- unblocks them, but it seems that any signal mask we're setting here is
- being overwritten on exit from this handler. I should create a standalone
- test case for the kernel hackers. JRA.
-*****************************************************************************/
-
-static void signal_handler(int sig, siginfo_t *info, void *unused)
-{
-       if (signals_received < FD_PENDING_SIZE - 1) {
-               fd_pending_array[signals_received] = (SIG_ATOMIC_T)info->si_fd;
-               signals_received++;
-       } /* Else signal is lost. */
-       sys_select_signal(RT_SIGNAL_NOTIFY);
-}
-
-/****************************************************************************
- Check if a change notify should be issued.
- time non-zero means timeout check (used for hash). Ignore this (async method
- where time is zero will be used instead).
-*****************************************************************************/
-
-static BOOL kernel_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t)
-{
-       struct change_data *data = (struct change_data *)datap;
-       int i;
-       BOOL ret = False;
-
-       if (t)
-               return False;
-
-       BlockSignals(True, RT_SIGNAL_NOTIFY);
-       for (i = 0; i < signals_received; i++) {
-               if (data->directory_handle == (int)fd_pending_array[i]) {
-                       DEBUG(3,("kernel_check_notify: kernel change notify on %s fd[%d]=%d (signals_received=%d)\n",
-                                               path, i, (int)fd_pending_array[i], (int)signals_received ));
-
-                       close((int)fd_pending_array[i]);
-                       fd_pending_array[i] = (SIG_ATOMIC_T)-1;
-                       if (signals_received - i - 1) {
-                               memmove((void *)&fd_pending_array[i], (void *)&fd_pending_array[i+1],
-                                               sizeof(SIG_ATOMIC_T)*(signals_received-i-1));
-                       }
-                       data->directory_handle = -1;
-                       signals_received--;
-                       ret = True;
-                       break;
-               }
-       }
-       BlockSignals(False, RT_SIGNAL_NOTIFY);
-       return ret;
-}
-
-/****************************************************************************
- Remove a change notify data structure.
-*****************************************************************************/
-
-static void kernel_remove_notify(void *datap)
-{
-       struct change_data *data = (struct change_data *)datap;
-       int fd = data->directory_handle;
-       if (fd != -1) {
-               int i;
-               BlockSignals(True, RT_SIGNAL_NOTIFY);
-               for (i = 0; i < signals_received; i++) {
-                       if (fd == (int)fd_pending_array[i]) {
-                               fd_pending_array[i] = (SIG_ATOMIC_T)-1;
-                               if (signals_received - i - 1) {
-                                       memmove((void *)&fd_pending_array[i], (void *)&fd_pending_array[i+1],
-                                                       sizeof(SIG_ATOMIC_T)*(signals_received-i-1));
-                               }
-                               data->directory_handle = -1;
-                               signals_received--;
-                               break;
-                       }
-               }
-               close(fd);
-               BlockSignals(False, RT_SIGNAL_NOTIFY);
-       }
-       SAFE_FREE(data);
-       DEBUG(3,("kernel_remove_notify: fd=%d\n", fd));
-}
-
-/****************************************************************************
- Register a change notify request.
-*****************************************************************************/
-
-static void *kernel_register_notify(connection_struct *conn, char *path, uint32 flags)
-{
-       struct change_data data;
-       int fd;
-       unsigned long kernel_flags;
-       
-       fd = sys_open(path,O_RDONLY, 0);
-
-       if (fd == -1) {
-               DEBUG(3,("Failed to open directory %s for change notify\n", path));
-               return NULL;
-       }
-
-       if (sys_fcntl_long(fd, F_SETSIG, RT_SIGNAL_NOTIFY) == -1) {
-               DEBUG(3,("Failed to set signal handler for change notify\n"));
-               return NULL;
-       }
-
-       kernel_flags = DN_CREATE|DN_DELETE|DN_RENAME; /* creation/deletion changes everything! */
-       if (flags & FILE_NOTIFY_CHANGE_FILE)        kernel_flags |= DN_MODIFY;
-       if (flags & FILE_NOTIFY_CHANGE_DIR_NAME)    kernel_flags |= DN_RENAME|DN_DELETE;
-       if (flags & FILE_NOTIFY_CHANGE_ATTRIBUTES)  kernel_flags |= DN_ATTRIB;
-       if (flags & FILE_NOTIFY_CHANGE_SIZE)        kernel_flags |= DN_MODIFY;
-       if (flags & FILE_NOTIFY_CHANGE_LAST_WRITE)  kernel_flags |= DN_MODIFY;
-       if (flags & FILE_NOTIFY_CHANGE_LAST_ACCESS) kernel_flags |= DN_ACCESS;
-       if (flags & FILE_NOTIFY_CHANGE_CREATION)    kernel_flags |= DN_CREATE;
-       if (flags & FILE_NOTIFY_CHANGE_SECURITY)    kernel_flags |= DN_ATTRIB;
-       if (flags & FILE_NOTIFY_CHANGE_EA)          kernel_flags |= DN_ATTRIB;
-       if (flags & FILE_NOTIFY_CHANGE_FILE_NAME)   kernel_flags |= DN_RENAME|DN_DELETE;
-
-       if (sys_fcntl_long(fd, F_NOTIFY, kernel_flags) == -1) {
-               DEBUG(3,("Failed to set async flag for change notify\n"));
-               return NULL;
-       }
-
-       data.directory_handle = fd;
-
-       DEBUG(3,("kernel change notify on %s (ntflags=0x%x flags=0x%x) fd=%d\n", 
-                path, (int)flags, (int)kernel_flags, fd));
-
-       return (void *)memdup(&data, sizeof(data));
-}
-
-/****************************************************************************
- See if the kernel supports change notify.
-****************************************************************************/
-
-static BOOL kernel_notify_available(void) 
-{
-       int fd, ret;
-       fd = open("/tmp", O_RDONLY);
-       if (fd == -1)
-               return False; /* uggh! */
-       ret = sys_fcntl_long(fd, F_NOTIFY, 0);
-       close(fd);
-       return ret == 0;
-}
-
-/****************************************************************************
- Setup kernel based change notify.
-****************************************************************************/
-
-struct cnotify_fns *kernel_notify_init(void) 
-{
-       static struct cnotify_fns cnotify;
-        struct sigaction act;
-
-       ZERO_STRUCT(act);
-
-       act.sa_sigaction = signal_handler;
-       act.sa_flags = SA_SIGINFO;
-       sigemptyset( &act.sa_mask );
-       if (sigaction(RT_SIGNAL_NOTIFY, &act, NULL) != 0) {
-               DEBUG(0,("Failed to setup RT_SIGNAL_NOTIFY handler\n"));
-               return NULL;
-       }
-
-       if (!kernel_notify_available())
-               return NULL;
-
-       cnotify.register_notify = kernel_register_notify;
-       cnotify.check_notify = kernel_check_notify;
-       cnotify.remove_notify = kernel_remove_notify;
-       cnotify.select_time = -1;
-       cnotify.notification_fd = -1;
-
-       /* the signal can start off blocked due to a bug in bash */
-       BlockSignals(False, RT_SIGNAL_NOTIFY);
-
-       return &cnotify;
-}
-
-#else
- void notify_kernel_dummy(void);
-
- void notify_kernel_dummy(void) {}
-#endif /* HAVE_KERNEL_CHANGE_NOTIFY */
index 2eddffb7f1662fa2b97bc2b2c5838db947fef1df..08f19e7bdb6d51cdfa366d2f71552c3dc8ea46ac 100644 (file)
@@ -1782,11 +1782,6 @@ int reply_ntrename(connection_struct *conn,
                return ERROR_NT(status);
        }
 
-       /*
-        * Win2k needs a changenotify request response before it will
-        * update after a rename..
-        */     
-       process_pending_change_notify_queue((time_t)0);
        outsize = set_message(outbuf,0,0,False);
   
        END_PROFILE(SMBntrename);
@@ -1810,14 +1805,17 @@ static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf,
 {
        uint16 *setup = *ppsetup;
        files_struct *fsp;
-       uint32 flags;
+       uint32 filter;
+       NTSTATUS status;
+       BOOL recursive;
 
        if(setup_count < 6) {
                return ERROR_DOS(ERRDOS,ERRbadfunc);
        }
 
        fsp = file_fsp((char *)setup,4);
-       flags = IVAL(setup, 0);
+       filter = IVAL(setup, 0);
+       recursive = (SVAL(setup, 6) != 0) ? True : False;
 
        DEBUG(3,("call_nt_transact_notify_change\n"));
 
@@ -1825,16 +1823,65 @@ static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf,
                return ERROR_DOS(ERRDOS,ERRbadfid);
        }
 
+       {
+               char *filter_string;
+
+               if (!(filter_string = notify_filter_string(NULL, filter))) {
+                       return ERROR_NT(NT_STATUS_NO_MEMORY);
+               }
+
+               DEBUG(3,("call_nt_transact_notify_change: notify change "
+                        "called on %s, filter = %s, recursive = %d\n",
+                        fsp->fsp_name, filter_string, recursive));
+
+               TALLOC_FREE(filter_string);
+       }
+
        if((!fsp->is_directory) || (conn != fsp->conn)) {
-               return ERROR_DOS(ERRDOS,ERRbadfid);
+               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
        }
 
-       if (!change_notify_set(inbuf, fsp, conn, flags)) {
-               return(UNIXERROR(ERRDOS,ERRbadfid));
+       if (fsp->notify == NULL) {
+
+               status = change_notify_create(fsp, filter, recursive);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(10, ("change_notify_create returned %s\n",
+                                  nt_errstr(status)));
+                       return ERROR_NT(status);
+               }
        }
 
-       DEBUG(3,("call_nt_transact_notify_change: notify change called on directory \
-name = %s\n", fsp->fsp_name ));
+       if (fsp->notify->num_changes != 0) {
+
+               /*
+                * We've got changes pending, respond immediately
+                */
+
+               /*
+                * TODO: write a torture test to check the filtering behaviour
+                * here.
+                */
+
+               change_notify_reply(inbuf, max_param_count,
+                                   fsp->notify);
+
+               /*
+                * change_notify_reply() above has independently sent its
+                * results
+                */
+               return -1;
+       }
+
+       /*
+        * No changes pending, queue the request
+        */
+
+       status = change_notify_add_request(inbuf, max_param_count, filter,
+                                          recursive, fsp);
+       if (!NT_STATUS_IS_OK(status)) {
+               return ERROR_NT(status);
+       }
 
        return -1;
 }
@@ -1886,13 +1933,6 @@ static int call_nt_transact_rename(connection_struct *conn, char *inbuf, char *o
        DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n", 
                 fsp->fsp_name, new_name));
        
-       /*
-        * Win2k needs a changenotify request response before it will
-        * update after a rename..
-        */
-       
-       process_pending_change_notify_queue((time_t)0);
-
        return -1;
 }
 
index 050237294742b1f095ee450dcfa6b76ad3dc9c08..89474874cc5dd7381fe8ae211c2bc711fd6816d6 100644 (file)
@@ -197,7 +197,8 @@ static void change_dir_owner_to_parent(connection_struct *conn,
 static NTSTATUS open_file(files_struct *fsp,
                          connection_struct *conn,
                          const char *parent_dir,
-                         const char *fname,
+                         const char *name,
+                         const char *path,
                          SMB_STRUCT_STAT *psbuf,
                          int flags,
                          mode_t unx_mode,
@@ -226,7 +227,7 @@ static NTSTATUS open_file(files_struct *fsp,
        if (!CAN_WRITE(conn)) {
                /* It's a read-only share - fail if we wanted to write. */
                if(accmode != O_RDONLY) {
-                       DEBUG(3,("Permission denied opening %s\n",fname));
+                       DEBUG(3,("Permission denied opening %s\n", path));
                        return NT_STATUS_ACCESS_DENIED;
                } else if(flags & O_CREAT) {
                        /* We don't want to write - but we must make sure that
@@ -252,7 +253,7 @@ static NTSTATUS open_file(files_struct *fsp,
 
        if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) {
                DEBUG(10,("open_file: truncate requested on read-only open "
-                         "for file %s\n",fname ));
+                         "for file %s\n", path));
                local_flags = (flags & ~O_ACCMODE)|O_RDWR;
        }
 
@@ -281,15 +282,15 @@ static NTSTATUS open_file(files_struct *fsp,
 
                /* Don't create files with Microsoft wildcard characters. */
                if ((local_flags & O_CREAT) && !file_existed &&
-                   ms_has_wild(fname))  {
+                   ms_has_wild(path))  {
                        return NT_STATUS_OBJECT_NAME_INVALID;
                }
 
                /* Actually do the open */
-               if (!fd_open(conn, fname, fsp, local_flags, unx_mode)) {
+               if (!fd_open(conn, path, fsp, local_flags, unx_mode)) {
                        DEBUG(3,("Error opening file %s (%s) (local_flags=%d) "
                                 "(flags=%d)\n",
-                                fname,strerror(errno),local_flags,flags));
+                                path,strerror(errno),local_flags,flags));
                        return map_nt_error_from_unix(errno);
                }
 
@@ -297,7 +298,7 @@ static NTSTATUS open_file(files_struct *fsp,
 
                        /* Inherit the ACL if required */
                        if (lp_inherit_perms(SNUM(conn))) {
-                               inherit_access_acl(conn, parent_dir, fname,
+                               inherit_access_acl(conn, parent_dir, path,
                                                   unx_mode);
                        }
 
@@ -306,6 +307,9 @@ static NTSTATUS open_file(files_struct *fsp,
                                change_file_owner_to_parent(conn, parent_dir,
                                                            fsp);
                        }
+
+                       notify_fname(conn, NOTIFY_ACTION_ADDED,
+                                    FILE_NOTIFY_CHANGE_FILE_NAME, path);
                }
 
        } else {
@@ -316,13 +320,13 @@ static NTSTATUS open_file(files_struct *fsp,
                int ret;
 
                if (fsp->fh->fd == -1) {
-                       ret = SMB_VFS_STAT(conn, fname, psbuf);
+                       ret = SMB_VFS_STAT(conn, path, psbuf);
                } else {
                        ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,psbuf);
                        /* If we have an fd, this stat should succeed. */
                        if (ret == -1) {
                                DEBUG(0,("Error doing fstat on open file %s "
-                                        "(%s)\n", fname,strerror(errno) ));
+                                        "(%s)\n", path,strerror(errno) ));
                        }
                }
 
@@ -365,11 +369,11 @@ static NTSTATUS open_file(files_struct *fsp,
        fsp->is_directory = False;
        fsp->is_stat = False;
        if (conn->aio_write_behind_list &&
-           is_in_path(fname, conn->aio_write_behind_list, conn->case_sensitive)) {
+           is_in_path(path, conn->aio_write_behind_list, conn->case_sensitive)) {
                fsp->aio_write_behind = True;
        }
 
-       string_set(&fsp->fsp_name,fname);
+       string_set(&fsp->fsp_name, path);
        fsp->wcp = NULL; /* Write cache pointer. */
 
        DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
@@ -646,7 +650,7 @@ static BOOL delay_for_oplocks(struct share_mode_lock *lck,
        BOOL valid_entry = False;
        BOOL delay_it = False;
        BOOL have_level2 = False;
-       BOOL ret;
+       NTSTATUS status;
        char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
 
        if (oplock_request & INTERNAL_OPEN_ONLY) {
@@ -734,10 +738,11 @@ static BOOL delay_for_oplocks(struct share_mode_lock *lck,
                SSVAL(msg,6,exclusive->op_type | FORCE_OPLOCK_BREAK_TO_NONE);
        }
 
-       ret = message_send_pid(exclusive->pid, MSG_SMB_BREAK_REQUEST,
-                              msg, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True);
-       if (!ret) {
-               DEBUG(3, ("Could not send oplock break message\n"));
+       status = message_send_pid(exclusive->pid, MSG_SMB_BREAK_REQUEST,
+                                 msg, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(3, ("Could not send oplock break message: %s\n",
+                         nt_errstr(status)));
        }
 
        return True;
@@ -1594,8 +1599,9 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
         * open_file strips any O_TRUNC flags itself.
         */
 
-       fsp_open = open_file(fsp, conn, parent_dir, fname, psbuf, flags|flags2,
-                            unx_mode, access_mask, open_access_mask);
+       fsp_open = open_file(fsp, conn, parent_dir, newname, fname, psbuf,
+                            flags|flags2, unx_mode, access_mask,
+                            open_access_mask);
 
        if (!NT_STATUS_IS_OK(fsp_open)) {
                if (lck != NULL) {
@@ -1860,7 +1866,7 @@ NTSTATUS open_file_fchmod(connection_struct *conn, const char *fname,
 
        /* note! we must use a non-zero desired access or we don't get
            a real file descriptor. Oh what a twisted web we weave. */
-       status = open_file(fsp, conn, NULL, fname, psbuf, O_WRONLY, 0,
+       status = open_file(fsp, conn, NULL, NULL, fname, psbuf, O_WRONLY, 0,
                           FILE_WRITE_DATA, FILE_WRITE_DATA);
 
        /* 
@@ -1963,6 +1969,9 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
                change_dir_owner_to_parent(conn, parent_dir, name, psbuf);
        }
 
+       notify_fname(conn, NOTIFY_ACTION_ADDED, FILE_NOTIFY_CHANGE_DIR_NAME,
+                    name);
+
        return NT_STATUS_OK;
 }
 
@@ -2240,7 +2249,8 @@ NTSTATUS open_file_stat(connection_struct *conn, const char *fname,
  smbd process.
 ****************************************************************************/
 
-void msg_file_was_renamed(int msg_type, struct process_id src, void *buf, size_t len)
+void msg_file_was_renamed(int msg_type, struct process_id src,
+                         void *buf, size_t len, void *private_data)
 {
        files_struct *fsp;
        char *frm = (char *)buf;
index 526b7ced9ecf8e6d47a6a3a074c9dc5c564287aa..423d6b3a9991a5a9b0210b72d2830645cf394e8e 100644 (file)
@@ -342,7 +342,8 @@ static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, un
        return fsp;
 }
 
-static void oplock_timeout_handler(struct timed_event *te,
+static void oplock_timeout_handler(struct event_context *ctx,
+                                  struct timed_event *te,
                                   const struct timeval *now,
                                   void *private_data)
 {
@@ -372,7 +373,7 @@ static void add_oplock_timeout_handler(files_struct *fsp)
        }
 
        fsp->oplock_timeout =
-               add_timed_event(NULL,
+               event_add_timed(smbd_event_context(), NULL,
                                timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0),
                                "oplock_timeout_handler",
                                oplock_timeout_handler, fsp);
@@ -391,7 +392,8 @@ static void add_oplock_timeout_handler(files_struct *fsp)
 *******************************************************************/
 
 static void process_oplock_async_level2_break_message(int msg_type, struct process_id src,
-                                        void *buf, size_t len)
+                                                     void *buf, size_t len,
+                                                     void *private_data)
 {
        struct share_mode_entry msg;
        files_struct *fsp;
@@ -477,7 +479,8 @@ static void process_oplock_async_level2_break_message(int msg_type, struct proce
 *******************************************************************/
 
 static void process_oplock_break_message(int msg_type, struct process_id src,
-                                        void *buf, size_t len)
+                                        void *buf, size_t len,
+                                        void *private_data)
 {
        struct share_mode_entry msg;
        files_struct *fsp;
@@ -585,7 +588,8 @@ static void process_oplock_break_message(int msg_type, struct process_id src,
 *******************************************************************/
 
 static void process_kernel_oplock_break(int msg_type, struct process_id src,
-                                       void *buf, size_t len)
+                                       void *buf, size_t len,
+                                       void *private_data)
 {
        SMB_DEV_T dev;
        SMB_INO_T inode;
@@ -676,7 +680,8 @@ void reply_to_oplock_break_requests(files_struct *fsp)
 }
 
 static void process_oplock_break_response(int msg_type, struct process_id src,
-                                         void *buf, size_t len)
+                                         void *buf, size_t len,
+                                         void *private_data)
 {
        struct share_mode_entry msg;
 
@@ -703,7 +708,8 @@ static void process_oplock_break_response(int msg_type, struct process_id src,
 }
 
 static void process_open_retry_message(int msg_type, struct process_id src,
-                                      void *buf, size_t len)
+                                      void *buf, size_t len,
+                                      void *private_data)
 {
        struct share_mode_entry msg;
        
@@ -859,15 +865,20 @@ BOOL init_oplocks(void)
        DEBUG(3,("init_oplocks: initializing messages.\n"));
 
        message_register(MSG_SMB_BREAK_REQUEST,
-                        process_oplock_break_message);
+                        process_oplock_break_message,
+                        NULL);
        message_register(MSG_SMB_ASYNC_LEVEL2_BREAK,
-                        process_oplock_async_level2_break_message);
+                        process_oplock_async_level2_break_message,
+                        NULL);
        message_register(MSG_SMB_BREAK_RESPONSE,
-                        process_oplock_break_response);
+                        process_oplock_break_response,
+                        NULL);
        message_register(MSG_SMB_KERNEL_BREAK,
-                        process_kernel_oplock_break);
+                        process_kernel_oplock_break,
+                        NULL);
        message_register(MSG_SMB_OPEN_RETRY,
-                        process_open_retry_message);
+                        process_open_retry_message,
+                        NULL);
 
        if (lp_kernel_oplocks()) {
 #if HAVE_KERNEL_OPLOCKS_IRIX
index ffc731e42b32de6ce2724d80fd65dc3d066ff6d8..5830af8f4350b1cd2239c7c75909099a36ad3ed5 100644 (file)
@@ -225,7 +225,8 @@ struct idle_event {
        void *private_data;
 };
 
-static void idle_event_handler(struct timed_event *te,
+static void idle_event_handler(struct event_context *ctx,
+                              struct timed_event *te,
                               const struct timeval *now,
                               void *private_data)
 {
@@ -240,7 +241,8 @@ static void idle_event_handler(struct timed_event *te,
                return;
        }
 
-       event->te = add_timed_event(event, timeval_sum(now, &event->interval),
+       event->te = event_add_timed(smbd_event_context(), event,
+                                   timeval_sum(now, &event->interval),
                                    "idle_event_handler",
                                    idle_event_handler, event);
 
@@ -267,11 +269,12 @@ struct idle_event *add_idle_event(TALLOC_CTX *mem_ctx,
        result->handler = handler;
        result->private_data = private_data;
 
-       result->te = add_timed_event(result, timeval_sum(&now, &interval),
+       result->te = event_add_timed(smbd_event_context(), result,
+                                    timeval_sum(&now, &interval),
                                     "idle_event_handler",
                                     idle_event_handler, result);
        if (result->te == NULL) {
-               DEBUG(0, ("add_timed_event failed\n"));
+               DEBUG(0, ("event_add_timed failed\n"));
                TALLOC_FREE(result);
                return NULL;
        }
@@ -301,9 +304,6 @@ static void async_processing(fd_set *pfds)
                exit_server_cleanly("termination signal");
        }
 
-       /* check for async change notify events */
-       process_pending_change_notify_queue(0);
-
        /* check for sighup processing */
        if (reload_after_sighup) {
                change_to_root_user();
@@ -350,7 +350,7 @@ The timeout is in milliseconds
 
 static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
 {
-       fd_set fds;
+       fd_set r_fds, w_fds;
        int selrtn;
        struct timeval to;
        int maxfd = 0;
@@ -414,10 +414,11 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
        }
 
        /*
-        * Setup the select read fd set.
+        * Setup the select fd sets.
         */
 
-       FD_ZERO(&fds);
+       FD_ZERO(&r_fds);
+       FD_ZERO(&w_fds);
 
        /*
         * Ensure we process oplock break messages by preference.
@@ -428,9 +429,9 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
         * This is hideously complex - *MUST* be simplified for 3.0 ! JRA.
         */
 
-       if (oplock_message_waiting(&fds)) {
+       if (oplock_message_waiting(&r_fds)) {
                DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n"));
-               async_processing(&fds);
+               async_processing(&r_fds);
                /*
                 * After async processing we must go and do the select again, as
                 * the state of the flag in fds for the server file descriptor is
@@ -445,15 +446,17 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
         */
 
        {
-               struct timeval tmp;
-               struct timeval *tp = get_timed_events_timeout(&tmp);
-
-               if (tp) {
-                       to = timeval_min(&to, tp);
-                       if (timeval_is_zero(&to)) {
-                               /* Process a timed event now... */
-                               run_events();
-                       }
+               struct timeval now;
+               GetTimeOfDay(&now);
+
+               event_add_to_select_args(smbd_event_context(), &now,
+                                        &r_fds, &w_fds, &to, &maxfd);
+       }
+
+       if (timeval_is_zero(&to)) {
+               /* Process a timed event now... */
+               if (run_events(smbd_event_context(), 0, NULL, NULL)) {
+                       goto again;
                }
        }
        
@@ -461,23 +464,26 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
                int sav;
                START_PROFILE(smbd_idle);
 
-               maxfd = select_on_fd(smbd_server_fd(), maxfd, &fds);
-               maxfd = select_on_fd(change_notify_fd(), maxfd, &fds);
-               maxfd = select_on_fd(oplock_notify_fd(), maxfd, &fds);
+               maxfd = select_on_fd(smbd_server_fd(), maxfd, &r_fds);
+               maxfd = select_on_fd(oplock_notify_fd(), maxfd, &r_fds);
 
-               selrtn = sys_select(maxfd+1,&fds,NULL,NULL,&to);
+               selrtn = sys_select(maxfd+1,&r_fds,&w_fds,NULL,&to);
                sav = errno;
 
                END_PROFILE(smbd_idle);
                errno = sav;
        }
 
+       if (run_events(smbd_event_context(), selrtn, &r_fds, &w_fds)) {
+               goto again;
+       }
+
        /* if we get EINTR then maybe we have received an oplock
           signal - treat this as select returning 1. This is ugly, but
           is the best we can do until the oplock code knows more about
           signals */
        if (selrtn == -1 && errno == EINTR) {
-               async_processing(&fds);
+               async_processing(&r_fds);
                /*
                 * After async processing we must go and do the select again, as
                 * the state of the flag in fds for the server file descriptor is
@@ -505,8 +511,8 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
         * sending us an oplock break message. JRA.
         */
 
-       if (oplock_message_waiting(&fds)) {
-               async_processing(&fds);
+       if (oplock_message_waiting(&r_fds)) {
+               async_processing(&r_fds);
                /*
                 * After async processing we must go and do the select again, as
                 * the state of the flag in fds for the server file descriptor is
@@ -515,19 +521,6 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout)
                goto again;
        }
 
-       if ((change_notify_fd() >= 0) && FD_ISSET(change_notify_fd(), &fds)) {
-
-               process_pending_change_notify_queue((time_t)0);
-
-               /*
-                * Same comment as for oplock processing applies here. We
-                * might have done I/O on the client socket.
-                */
-
-               goto again;
-       }
-
-       
        return receive_smb(smbd_server_fd(), buffer, 0);
 }
 
@@ -1240,16 +1233,9 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize)
 static int setup_select_timeout(void)
 {
        int select_timeout;
-       int t;
 
        select_timeout = blocking_locks_timeout_ms(SMBD_SELECT_TIMEOUT*1000);
 
-       t = change_notify_timeout();
-       DEBUG(10, ("change_notify_timeout: %d\n", t));
-       if (t != -1) {
-               select_timeout = MIN(select_timeout, t*1000);
-       }
-
        if (print_notify_messages_pending()) {
                select_timeout = MIN(select_timeout, 1000);
        }
@@ -1447,12 +1433,6 @@ machine %s in domain %s.\n", global_myname(), lp_workgroup()));
   
        update_monitored_printq_cache();
   
-       /*
-        * Check to see if we have any change notifies 
-        * outstanding on the queue.
-        */
-       process_pending_change_notify_queue(t);
-
        /*
         * Now we are root, check if the log files need pruning.
         * Force a log file check.
@@ -1603,7 +1583,7 @@ void smbd_process(void)
                        num_smbs = 0; /* Reset smb counter. */
                }
 
-               run_events();
+               run_events(smbd_event_context(), 0, NULL, NULL);
 
 #if defined(DEVELOPER)
                clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, InBuffer, total_buffer_size);
index 315b338b0ba1deb3e0b9558678e70d53d5e7dd3d..c48bebb0c6c74899f49f291682f70a737cf4fda8 100644 (file)
@@ -1865,6 +1865,9 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype,
 
                if (SMB_VFS_UNLINK(conn,directory) == 0) {
                        count++;
+                       notify_fname(conn, NOTIFY_ACTION_REMOVED,
+                                    FILE_NOTIFY_CHANGE_FILE_NAME,
+                                    directory);
                }
        } else {
                struct smb_Dir *dir_hnd = NULL;
@@ -1921,9 +1924,15 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype,
                        if (!NT_STATUS_IS_OK(status)) {
                                continue;
                        }
-                       if (SMB_VFS_UNLINK(conn,fname) == 0)
+                       if (SMB_VFS_UNLINK(conn,fname) == 0) {
                                count++;
-                       DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
+                               DEBUG(3,("unlink_internals: succesful unlink "
+                                        "[%s]\n",fname));
+                               notify_fname(conn, NOTIFY_ACTION_REMOVED,
+                                            FILE_NOTIFY_CHANGE_FILE_NAME,
+                                            fname);
+                       }
+                               
                }
                CloseDir(dir_hnd);
        }
@@ -1972,12 +1981,6 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
                return ERROR_NT(status);
        }
 
-       /*
-        * Win2k needs a changenotify request response before it will
-        * update after a rename..
-        */
-       process_pending_change_notify_queue((time_t)0);
-       
        outsize = set_message(outbuf,0,0,False);
   
        END_PROFILE(SMBunlink);
@@ -3702,6 +3705,9 @@ NTSTATUS rmdir_internals(connection_struct *conn, const char *directory)
 
        ret = SMB_VFS_RMDIR(conn,directory);
        if (ret == 0) {
+               notify_fname(conn, NOTIFY_ACTION_REMOVED,
+                            FILE_NOTIFY_CHANGE_DIR_NAME,
+                            directory);
                return NT_STATUS_OK;
        }
 
@@ -3779,6 +3785,10 @@ NTSTATUS rmdir_internals(connection_struct *conn, const char *directory)
                return map_nt_error_from_unix(errno);
        }
 
+       notify_fname(conn, NOTIFY_ACTION_REMOVED,
+                    FILE_NOTIFY_CHANGE_DIR_NAME,
+                    directory);
+
        return NT_STATUS_OK;
 }
 
@@ -4095,6 +4105,48 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, pstrin
        return status;
 }
 
+/*
+ * Do the notify calls from a rename
+ */
+
+static void notify_rename(connection_struct *conn, BOOL is_dir,
+                         const char *oldpath, const char *newpath)
+{
+       char *olddir, *newdir;
+       const char *oldname, *newname;
+       uint32 mask;
+
+       mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
+               : FILE_NOTIFY_CHANGE_FILE_NAME;
+
+       if (!parent_dirname_talloc(NULL, oldpath, &olddir, &oldname)
+           || !parent_dirname_talloc(NULL, newpath, &newdir, &newname)) {
+               TALLOC_FREE(olddir);
+               return;
+       }
+
+       if (strcmp(olddir, newdir) == 0) {
+               notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, oldpath);
+               notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, newpath);
+       }
+       else {
+               notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, oldpath);
+               notify_fname(conn, NOTIFY_ACTION_ADDED, mask, newpath);
+       }
+       TALLOC_FREE(olddir);
+       TALLOC_FREE(newdir);
+
+       /* this is a strange one. w2k3 gives an additional event for
+          CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
+          files, but not directories */
+       if (!is_dir) {
+               notify_fname(conn, NOTIFY_ACTION_MODIFIED,
+                            FILE_NOTIFY_CHANGE_ATTRIBUTES
+                            |FILE_NOTIFY_CHANGE_CREATION,
+                            newpath);
+       }
+}
+
 /****************************************************************************
  The guts of the rename command, split out so it may be called by the NT SMB
  code. 
@@ -4301,6 +4353,8 @@ NTSTATUS rename_internals(connection_struct *conn, pstring name,
                        rename_open_files(conn, lck, sbuf1.st_dev,
                                          sbuf1.st_ino, newname);
                        TALLOC_FREE(lck);
+                       notify_rename(conn, S_ISDIR(sbuf1.st_mode),
+                                     directory, newname);
                        return NT_STATUS_OK;    
                }
 
@@ -4499,11 +4553,6 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
                return ERROR_NT(status);
        }
 
-       /*
-        * Win2k needs a changenotify request response before it will
-        * update after a rename..
-        */     
-       process_pending_change_notify_queue((time_t)0);
        outsize = set_message(outbuf,0,0,False);
   
        END_PROFILE(SMBmv);
index 38767ab402e357fce33e130ff2f4e3c3a4618db7..ab32d656d38ebba32ec6463f7c7353142745a251 100644 (file)
@@ -61,12 +61,33 @@ static void smbd_set_server_fd(int fd)
        client_setfd(fd);
 }
 
+struct event_context *smbd_event_context(void)
+{
+       static struct event_context *ctx;
+
+       if (!ctx && !(ctx = event_context_init(NULL))) {
+               smb_panic("Could not init smbd event context\n");
+       }
+       return ctx;
+}
+
+struct messaging_context *smbd_messaging_context(void)
+{
+       static struct messaging_context *ctx;
+
+       if (!ctx && !(ctx = messaging_init(NULL, server_id_self(),
+                                          smbd_event_context()))) {
+               smb_panic("Could not init smbd messaging context\n");
+       }
+       return ctx;
+}
+
 /*******************************************************************
  What to do when smb.conf is updated.
  ********************************************************************/
 
 static void smb_conf_updated(int msg_type, struct process_id src,
-                            void *buf, size_t len)
+                            void *buf, size_t len, void *private_data)
 {
        DEBUG(10,("smb_conf_updated: Got message saying smb.conf was updated. Reloading.\n"));
        reload_services(False);
@@ -78,7 +99,7 @@ static void smb_conf_updated(int msg_type, struct process_id src,
  ********************************************************************/
 
 static void smb_stat_cache_delete(int msg_type, struct process_id src,
-                            void *buf, size_t len)
+                                 void *buf, size_t len, void *private_data)
 {
        const char *name = (const char *)buf;
        DEBUG(10,("smb_stat_cache_delete: delete name %s\n", name));
@@ -129,7 +150,8 @@ static void  killkids(void)
 ****************************************************************************/
 
 static void msg_sam_sync(int UNUSED(msg_type), struct process_id UNUSED(pid),
-                        void *UNUSED(buf), size_t UNUSED(len))
+                        void *UNUSED(buf), size_t UNUSED(len),
+                        void *private_data)
 {
         DEBUG(10, ("** sam sync message received, ignoring\n"));
 }
@@ -140,7 +162,7 @@ static void msg_sam_sync(int UNUSED(msg_type), struct process_id UNUSED(pid),
 ****************************************************************************/
 
 static void msg_sam_repl(int msg_type, struct process_id pid,
-                        void *buf, size_t len)
+                        void *buf, size_t len, void *private_data)
 {
         uint32 low_serial;
 
@@ -174,7 +196,7 @@ static BOOL open_sockets_inetd(void)
 }
 
 static void msg_exit_server(int msg_type, struct process_id src,
-                           void *buf, size_t len)
+                           void *buf, size_t len, void *private_data)
 {
        DEBUG(3, ("got a SHUTDOWN message\n"));
        exit_server_cleanly(NULL);
@@ -182,7 +204,7 @@ static void msg_exit_server(int msg_type, struct process_id src,
 
 #ifdef DEVELOPER
 static void msg_inject_fault(int msg_type, struct process_id src,
-                           void *buf, size_t len)
+                           void *buf, size_t len, void *private_data)
 {
        int sig;
 
@@ -419,15 +441,16 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_
 
         /* Listen to messages */
 
-        message_register(MSG_SMB_SAM_SYNC, msg_sam_sync);
-        message_register(MSG_SMB_SAM_REPL, msg_sam_repl);
-        message_register(MSG_SHUTDOWN, msg_exit_server);
-        message_register(MSG_SMB_FILE_RENAME, msg_file_was_renamed);
-       message_register(MSG_SMB_CONF_UPDATED, smb_conf_updated); 
-       message_register(MSG_SMB_STAT_CACHE_DELETE, smb_stat_cache_delete);
+        message_register(MSG_SMB_SAM_SYNC, msg_sam_sync, NULL);
+        message_register(MSG_SMB_SAM_REPL, msg_sam_repl, NULL);
+        message_register(MSG_SHUTDOWN, msg_exit_server, NULL);
+        message_register(MSG_SMB_FILE_RENAME, msg_file_was_renamed, NULL);
+       message_register(MSG_SMB_CONF_UPDATED, smb_conf_updated, NULL); 
+       message_register(MSG_SMB_STAT_CACHE_DELETE, smb_stat_cache_delete,
+                        NULL);
 
 #ifdef DEVELOPER
-       message_register(MSG_SMB_INJECT_FAULT, msg_inject_fault); 
+       message_register(MSG_SMB_INJECT_FAULT, msg_inject_fault, NULL); 
 #endif
 
        /* now accept incoming connections - forking a new process
@@ -1078,15 +1101,11 @@ extern void build_options(BOOL screen);
        if (!init_oplocks())
                exit(1);
        
-       /* Setup change notify */
-       if (!init_change_notify())
-               exit(1);
-
        /* Setup aio signal handler. */
        initialize_async_io_handler();
 
        /* register our message handlers */
-       message_register(MSG_SMB_FORCE_TDIS, msg_force_tdis);
+       message_register(MSG_SMB_FORCE_TDIS, msg_force_tdis, NULL);
 
        smbd_process();
 
index 025fd38ff79002ab6aefa8ff1693f20f58e4dfed..18db2f8aba2f3a3c0fc30b99c2b67635c15df3dc 100644 (file)
 
 extern userdom_struct current_user_info;
 
+static BOOL canonicalize_path(connection_struct *conn, pstring path)
+{
+#ifdef REALPATH_TAKES_NULL
+       char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
+       if (!resolved_name) {
+               return False;
+       }
+       pstrcpy(path, resolved_name);
+       SAFE_FREE(resolved_name);
+       return True;
+#else
+#ifdef PATH_MAX
+        char resolved_name_buf[PATH_MAX+1];
+#else
+        pstring resolved_name_buf;
+#endif
+       char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
+       if (!resolved_name) {
+               return False;
+       }
+       pstrcpy(path, resolved_name);
+       return True;
+#endif /* REALPATH_TAKES_NULL */
+}
+
 /****************************************************************************
  Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
  absolute path stating in / and not ending in /.
@@ -827,6 +852,13 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
                set_conn_connectpath(conn,s);
        }
 
+       if ((!conn->printer) && (!conn->ipc)) {
+               conn->notify_ctx = notify_init(conn->mem_ctx, server_id_self(),
+                                              smbd_messaging_context(),
+                                              smbd_event_context(),
+                                              conn);
+       }
+
 /* ROOT Activities: */ 
        /* check number of connections */
        if (!claim_connection(conn,
@@ -980,9 +1012,6 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
                dbgtext( "(pid %d)\n", (int)sys_getpid() );
        }
        
-       /* Setup the minimum value for a change notify wait time (seconds). */
-       set_change_notify_timeout(lp_change_notify_timeout(snum));
-
        /* we've finished with the user stuff - go back to root */
        change_to_root_user();
        return(conn);
index 8bdd10b643d5680dbba4b694814f0d7416f0dab3..b91cdeef702c0338a22bb8f20a102e4eaf5d9383 100644 (file)
@@ -3800,6 +3800,11 @@ static NTSTATUS smb_set_file_time(connection_struct *conn,
                                const SMB_STRUCT_STAT *psbuf,
                                struct utimbuf tvs)
 {
+       uint32 action =
+               FILE_NOTIFY_CHANGE_LAST_ACCESS
+               |FILE_NOTIFY_CHANGE_LAST_WRITE;
+
+       
        if (!VALID_STAT(*psbuf)) {
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
@@ -3807,10 +3812,12 @@ static NTSTATUS smb_set_file_time(connection_struct *conn,
        /* get some defaults (no modifications) if any info is zero or -1. */
        if (null_mtime(tvs.actime)) {
                tvs.actime = psbuf->st_atime;
+               action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;
        }
 
        if (null_mtime(tvs.modtime)) {
                tvs.modtime = psbuf->st_mtime;
+               action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
        }
 
        DEBUG(6,("smb_set_file_time: actime: %s " , ctime(&tvs.actime)));
@@ -3847,6 +3854,9 @@ static NTSTATUS smb_set_file_time(connection_struct *conn,
        if(file_utime(conn, fname, &tvs)!=0) {
                return map_nt_error_from_unix(errno);
        }
+       if (action != 0) {
+               notify_fname(conn, NOTIFY_ACTION_MODIFIED, action, fname);
+       }
        return NT_STATUS_OK;
 }
 
@@ -4248,10 +4258,6 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn,
                status = rename_internals(conn, fname, base_name, 0, overwrite, False);
        }
 
-       if (NT_STATUS_IS_OK(status)) {
-               process_pending_change_notify_queue((time_t)0);
-       }
-
        return status;
 }
 
index 643c48cd27c1f963d7e2e2675e9ebe8f1a326e51..82ea602187c0eb95241db46d944863f526a2424b 100644 (file)
@@ -514,8 +514,13 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
        release_level_2_oplocks_on_change(fsp);
        DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
        flush_write_cache(fsp, SIZECHANGE_FLUSH);
-       if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1)
+       if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1) {
                set_filelen_write_cache(fsp, len);
+               notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
+                            FILE_NOTIFY_CHANGE_SIZE
+                            | FILE_NOTIFY_CHANGE_ATTRIBUTES,
+                            fsp->fsp_name);
+       }
 
        return ret;
 }
@@ -792,31 +797,6 @@ char *vfs_GetWd(connection_struct *conn, char *path)
        return (path);
 }
 
-BOOL canonicalize_path(connection_struct *conn, pstring path)
-{
-#ifdef REALPATH_TAKES_NULL
-       char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
-       if (!resolved_name) {
-               return False;
-       }
-       pstrcpy(path, resolved_name);
-       SAFE_FREE(resolved_name);
-       return True;
-#else
-#ifdef PATH_MAX
-        char resolved_name_buf[PATH_MAX+1];
-#else
-        pstring resolved_name_buf;
-#endif
-       char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
-       if (!resolved_name) {
-               return False;
-       }
-       pstrcpy(path, resolved_name);
-       return True;
-#endif /* REALPATH_TAKES_NULL */
-}
-
 /*******************************************************************
  Reduce a file name, removing .. elements and checking that
  it is below dir in the heirachy. This uses realpath.
index d913c4903f39ea2e6fd53e2464547f48407e5fc8..5a066bc599e0efe70ddc955b9e815ab797c81ffe 100644 (file)
@@ -29,7 +29,8 @@ static int pong_count;
 /****************************************************************************
 a useful function for testing the message system
 ****************************************************************************/
-static void pong_message(int msg_type, struct process_id src, void *buf, size_t len)
+static void pong_message(int msg_type, struct process_id src,
+                        void *buf, size_t len, void *private_data)
 {
        pong_count++;
 }
@@ -57,7 +58,7 @@ static void pong_message(int msg_type, struct process_id src, void *buf, size_t
        pid = atoi(argv[1]);
        n = atoi(argv[2]);
 
-       message_register(MSG_PONG, pong_message);
+       message_register(MSG_PONG, pong_message, NULL);
 
        for (i=0;i<n;i++) {
                message_send_pid(pid_to_procid(pid), MSG_PING, NULL, 0, True);
@@ -100,10 +101,14 @@ static void pong_message(int msg_type, struct process_id src, void *buf, size_t
 
                printf("Sending pings for %d seconds\n", (int)timelimit);
                while (timeval_elapsed(&tv) < timelimit) {              
-                       if(message_send_pid(pid_to_procid(pid), MSG_PING,
-                                           buf, 11, False)) ping_count++;
-                       if(message_send_pid(pid_to_procid(pid), MSG_PING,
-                                           NULL, 0, False)) ping_count++;
+                       if(NT_STATUS_IS_OK(message_send_pid(pid_to_procid(pid),
+                                                           MSG_PING,
+                                                           buf, 11, False)))
+                          ping_count++;
+                       if(NT_STATUS_IS_OK(message_send_pid(pid_to_procid(pid),
+                                                           MSG_PING,
+                                                           NULL, 0, False)))
+                          ping_count++;
 
                        while (ping_count > pong_count + 20) {
                                message_dispatch();
index fa0545988e9eb3064844db8e16e5ec333f0eac3c..872c7a74c32e920e147df93d8702a1bba6f1890a 100644 (file)
@@ -479,6 +479,27 @@ BOOL reload_services(BOOL test)
        return (ret);
 }
 
+struct event_context *smbd_event_context(void)
+{
+       static struct event_context *ctx;
+
+       if (!ctx && !(ctx = event_context_init(NULL))) {
+               smb_panic("Could not init smbd event context\n");
+       }
+       return ctx;
+}
+
+struct messaging_context *smbd_messaging_context(void)
+{
+       static struct messaging_context *ctx;
+
+       if (!ctx && !(ctx = messaging_init(NULL, server_id_self(),
+                                          smbd_event_context()))) {
+               smb_panic("Could not init smbd messaging context\n");
+       }
+       return ctx;
+}
+
 /* Main function */
 
 int main(int argc, char *argv[])
index eb3f9da1ca75886418a481bebdadb13a8eba245c..02a0b68932c31637508630804386c7d31aad04b8 100644 (file)
@@ -1802,7 +1802,7 @@ static int net_ads_printer_info(int argc, const char **argv)
 }
 
 void do_drv_upgrade_printer(int msg_type, struct process_id src,
-                           void *buf, size_t len)
+                           void *buf, size_t len, void *private_data)
 {
        return;
 }
index 9ca304c62bd15ffb9f5731cbf67173207768452b..ec1e101e061764272a0ae79630c15ef963d97b8e 100644 (file)
@@ -59,7 +59,8 @@ static BOOL send_message(struct process_id pid, int msg_type,
                return False;
 
        if (procid_to_pid(&pid) != 0)
-               return message_send_pid(pid, msg_type, buf, len, duplicates);
+               return NT_STATUS_IS_OK(message_send_pid(pid, msg_type, buf, len,
+                                                       duplicates));
 
        tdb = tdb_open_log(lock_path("connections.tdb"), 0, 
                           TDB_DEFAULT, O_RDWR, 0);
@@ -98,7 +99,8 @@ static void wait_replies(BOOL multiple_replies)
 
 /* Message handler callback that displays the PID and a string on stdout */
 
-static void print_pid_string_cb(int msg_type, struct process_id pid, void *buf, size_t len)
+static void print_pid_string_cb(int msg_type, struct process_id pid, void *buf,
+                               size_t len, void *private_data)
 {
        printf("PID %u: %.*s", (unsigned int)procid_to_pid(&pid),
               (int)len, (const char *)buf);
@@ -108,7 +110,7 @@ static void print_pid_string_cb(int msg_type, struct process_id pid, void *buf,
 /* Message handler callback that displays a string on stdout */
 
 static void print_string_cb(int msg_type, struct process_id pid,
-                           void *buf, size_t len)
+                           void *buf, size_t len, void *private_data)
 {
        printf("%.*s", (int)len, (const char *)buf);
        num_replies++;
@@ -371,7 +373,8 @@ static BOOL do_election(const struct process_id pid,
 
 /* Ping a samba daemon process */
 
-static void pong_cb(int msg_type, struct process_id pid, void *buf, size_t len)
+static void pong_cb(int msg_type, struct process_id pid, void *buf,
+                   size_t len, void *private_data)
 {
        char *src_string = procid_str(NULL, &pid);
        printf("PONG from pid %s\n", src_string);
@@ -391,7 +394,7 @@ static BOOL do_ping(const struct process_id pid, const int argc, const char **ar
        if (!send_message(pid, MSG_PING, NULL, 0, False))
                return False;
 
-       message_register(MSG_PONG, pong_cb);
+       message_register(MSG_PONG, pong_cb, NULL);
 
        wait_replies(procid_to_pid(&pid) == 0);
 
@@ -436,7 +439,8 @@ static BOOL do_profile(const struct process_id pid,
 
 /* Return the profiling level */
 
-static void profilelevel_cb(int msg_type, struct process_id pid, void *buf, size_t len)
+static void profilelevel_cb(int msg_type, struct process_id pid, void *buf,
+                           size_t len, void *private_data)
 {
        int level;
        const char *s;
@@ -473,7 +477,7 @@ static void profilelevel_cb(int msg_type, struct process_id pid, void *buf, size
 }
 
 static void profilelevel_rqst(int msg_type, struct process_id pid,
-                             void *buf, size_t len)
+                             void *buf, size_t len, void *private_data)
 {
        int v = 0;
 
@@ -495,8 +499,8 @@ static BOOL do_profilelevel(const struct process_id pid,
        if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False))
                return False;
 
-       message_register(MSG_PROFILELEVEL, profilelevel_cb);
-       message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst);
+       message_register(MSG_PROFILELEVEL, profilelevel_cb, NULL);
+       message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst, NULL);
 
        wait_replies(procid_to_pid(&pid) == 0);
 
@@ -525,7 +529,7 @@ static BOOL do_debuglevel(const struct process_id pid,
        if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False))
                return False;
 
-       message_register(MSG_DEBUGLEVEL, print_pid_string_cb);
+       message_register(MSG_DEBUGLEVEL, print_pid_string_cb, NULL);
 
        wait_replies(procid_to_pid(&pid) == 0);
 
@@ -732,7 +736,7 @@ static BOOL do_poolusage(const struct process_id pid,
                return False;
        }
 
-       message_register(MSG_POOL_USAGE, print_string_cb);
+       message_register(MSG_POOL_USAGE, print_string_cb, NULL);
 
        /* Send a message and register our interest in a reply */
 
@@ -923,7 +927,7 @@ static BOOL do_winbind_onlinestatus(const struct process_id pid,
                return False;
        }
 
-       message_register(MSG_WINBIND_ONLINESTATUS, print_pid_string_cb);
+       message_register(MSG_WINBIND_ONLINESTATUS, print_pid_string_cb, NULL);
 
        if (!send_message(pid, MSG_WINBIND_ONLINESTATUS, &myid, sizeof(myid), False))
                return False;