summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVolker Lendecke <vlendec@samba.org>2007-02-13 20:55:17 +0000
committerVolker Lendecke <vlendec@samba.org>2007-02-13 20:55:17 +0000
commit61bbf21f075441982f18160da83c6c1c5218b791 (patch)
tree181d16edf98960a557863d4660f28527c7c7622f
parent9c362d093e8f7239acbde40f5ab580824bd2bf76 (diff)
downloadsamba-61bbf21f075441982f18160da83c6c1c5218b791.tar.gz
samba-61bbf21f075441982f18160da83c6c1c5218b791.tar.xz
samba-61bbf21f075441982f18160da83c6c1c5218b791.zip
r21322: No feedback means consent :-)
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
-rw-r--r--source/Makefile.in9
-rw-r--r--source/configure.in56
-rw-r--r--source/include/event.h12
-rw-r--r--source/include/includes.h1
-rw-r--r--source/include/messages.h4
-rw-r--r--source/include/nt_status.h5
-rw-r--r--source/include/smb.h108
-rw-r--r--source/include/vfs.h12
-rw-r--r--source/include/vfs_macros.h3
-rw-r--r--source/lib/debug.c8
-rw-r--r--source/lib/dmallocmsg.c14
-rw-r--r--source/lib/events.c223
-rw-r--r--source/lib/messages.c245
-rw-r--r--source/lib/tallocmsg.c5
-rw-r--r--source/lib/util.c13
-rw-r--r--source/lib/util_tdb.c98
-rw-r--r--source/librpc/gen_ndr/ndr_notify.c242
-rw-r--r--source/librpc/gen_ndr/ndr_notify.h20
-rw-r--r--source/librpc/gen_ndr/notify.h33
-rw-r--r--source/libsmb/clidgram.c5
-rw-r--r--source/nmbd/nmbd.c18
-rw-r--r--source/nmbd/nmbd_elections.c2
-rw-r--r--source/nmbd/nmbd_winsserver.c2
-rw-r--r--source/nsswitch/winbindd.c33
-rw-r--r--source/nsswitch/winbindd_cm.c35
-rw-r--r--source/nsswitch/winbindd_cred_cache.c16
-rw-r--r--source/nsswitch/winbindd_dual.c41
-rw-r--r--source/param/loadparm.c20
-rw-r--r--source/printing/nt_printing.c5
-rw-r--r--source/printing/printing.c6
-rw-r--r--source/rpc_server/srv_spoolss_nt.c11
-rw-r--r--source/rpc_server/srv_srvsvc_nt.c2
-rw-r--r--source/smbd/blocking.c18
-rw-r--r--source/smbd/close.c5
-rw-r--r--source/smbd/conn.c3
-rw-r--r--source/smbd/dosmode.c10
-rw-r--r--source/smbd/files.c5
-rw-r--r--source/smbd/notify.c522
-rw-r--r--source/smbd/notify_fam.c464
-rw-r--r--source/smbd/notify_hash.c261
-rw-r--r--source/smbd/notify_inotify.c425
-rw-r--r--source/smbd/notify_internal.c686
-rw-r--r--source/smbd/notify_kernel.c247
-rw-r--r--source/smbd/nttrans.c78
-rw-r--r--source/smbd/open.c50
-rw-r--r--source/smbd/oplock.c35
-rw-r--r--source/smbd/process.c90
-rw-r--r--source/smbd/reply.c75
-rw-r--r--source/smbd/server.c55
-rw-r--r--source/smbd/service.c35
-rw-r--r--source/smbd/trans2.c14
-rw-r--r--source/smbd/vfs.c32
-rw-r--r--source/torture/msgtest.c17
-rw-r--r--source/torture/vfstest.c21
-rw-r--r--source/utils/net_ads.c2
-rw-r--r--source/utils/smbcontrol.c28
56 files changed, 2941 insertions, 1544 deletions
diff --git a/source/Makefile.in b/source/Makefile.in
index 13719571409..833af9647f7 100644
--- a/source/Makefile.in
+++ b/source/Makefile.in
@@ -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
diff --git a/source/configure.in b/source/configure.in
index db64eaa105e..30f4bbfb535 100644
--- a/source/configure.in
+++ b/source/configure.in
@@ -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 )
diff --git a/source/include/event.h b/source/include/event.h
index fdb990678db..ce687eca6d6 100644
--- a/source/include/event.h
+++ b/source/include/event.h
@@ -19,13 +19,7 @@
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
diff --git a/source/include/includes.h b/source/include/includes.h
index 7a6064d8264..34b9c36c8ac 100644
--- a/source/include/includes.h
+++ b/source/include/includes.h
@@ -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"
diff --git a/source/include/messages.h b/source/include/messages.h
index ead5fb08c29..7cd0e023487 100644
--- a/source/include/messages.h
+++ b/source/include/messages.h
@@ -73,6 +73,10 @@
#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
diff --git a/source/include/nt_status.h b/source/include/nt_status.h
index 968657ca44f..471ac47927a 100644
--- a/source/include/nt_status.h
+++ b/source/include/nt_status.h
@@ -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
diff --git a/source/include/smb.h b/source/include/smb.h
index 9b914f6c7f9..8fa7dee5494 100644
--- a/source/include/smb.h
+++ b/source/include/smb.h
@@ -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
diff --git a/source/include/vfs.h b/source/include/vfs.h
index fe4886567ff..de92c739d59 100644
--- a/source/include/vfs.h
+++ b/source/include/vfs.h
@@ -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. */
diff --git a/source/include/vfs_macros.h b/source/include/vfs_macros.h
index 119b616e72e..5a189ff07ff 100644
--- a/source/include/vfs_macros.h
+++ b/source/include/vfs_macros.h
@@ -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)))
@@ -190,6 +191,7 @@
#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)))
@@ -304,6 +306,7 @@
#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)))
diff --git a/source/lib/debug.c b/source/lib/debug.c
index 00f6b0e72ff..5f141661106 100644
--- a/source/lib/debug.c
+++ b/source/lib/debug.c
@@ -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);
diff --git a/source/lib/dmallocmsg.c b/source/lib/dmallocmsg.c
index 1b2308ecba6..fed7bf59c52 100644
--- a/source/lib/dmallocmsg.c
+++ b/source/lib/dmallocmsg.c
@@ -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"));
}
diff --git a/source/lib/events.c b/source/lib/events.c
index 0e00dcbb034..a00db77b6be 100644
--- a/source/lib/events.c
+++ b/source/lib/events.c
@@ -21,27 +21,65 @@
#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;
diff --git a/source/lib/messages.c b/source/lib/messages.c
index de17a03afc1..e0bf86a46ce 100644
--- a/source/lib/messages.c
+++ b/source/lib/messages.c
@@ -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);
+}
+
/** @} **/
diff --git a/source/lib/tallocmsg.c b/source/lib/tallocmsg.c
index e4e9bac94d6..0f493538f3c 100644
--- a/source/lib/tallocmsg.c
+++ b/source/lib/tallocmsg.c
@@ -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"));
}
diff --git a/source/lib/util.c b/source/lib/util.c
index 0f54ba74414..7d41a14292c 100644
--- a/source/lib/util.c
+++ b/source/lib/util.c
@@ -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());
diff --git a/source/lib/util_tdb.c b/source/lib/util_tdb.c
index e847c79369e..9136e2d6c1e 100644
--- a/source/lib/util_tdb.c
+++ b/source/lib/util_tdb.c
@@ -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
index 00000000000..c3873550bb0
--- /dev/null
+++ b/source/librpc/gen_ndr/ndr_notify.c
@@ -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
index 00000000000..793ffa51ca7
--- /dev/null
+++ b/source/librpc/gen_ndr/ndr_notify.h
@@ -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
index 00000000000..f85b9b1bac8
--- /dev/null
+++ b/source/librpc/gen_ndr/notify.h
@@ -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 */
diff --git a/source/libsmb/clidgram.c b/source/libsmb/clidgram.c
index dfb613238f6..a983f485ab4 100644
--- a/source/libsmb/clidgram.c
+++ b/source/libsmb/clidgram.c
@@ -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));
}
/*
diff --git a/source/nmbd/nmbd.c b/source/nmbd/nmbd.c
index 4a05fde28c9..46f209872b0 100644
--- a/source/nmbd/nmbd.c
+++ b/source/nmbd/nmbd.c
@@ -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();
diff --git a/source/nmbd/nmbd_elections.c b/source/nmbd/nmbd_elections.c
index 50e13729361..3aadd70b83c 100644
--- a/source/nmbd/nmbd_elections.c
+++ b/source/nmbd/nmbd_elections.c
@@ -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;
diff --git a/source/nmbd/nmbd_winsserver.c b/source/nmbd/nmbd_winsserver.c
index 320415503b3..6ea102c3913 100644
--- a/source/nmbd/nmbd_winsserver.c
+++ b/source/nmbd/nmbd_winsserver.c
@@ -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;
diff --git a/source/nsswitch/winbindd.c b/source/nsswitch/winbindd.c
index 1df1a1d27b8..341fa00c923 100644
--- a/source/nsswitch/winbindd.c
+++ b/source/nsswitch/winbindd.c
@@ -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);
diff --git a/source/nsswitch/winbindd_cm.c b/source/nsswitch/winbindd_cm.c
index f39d3ff06ae..e1434ef32bb 100644
--- a/source/nsswitch/winbindd_cm.c
+++ b/source/nsswitch/winbindd_cm.c
@@ -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);
}
/****************************************************************
diff --git a/source/nsswitch/winbindd_cred_cache.c b/source/nsswitch/winbindd_cred_cache.c
index 6f629ad15c2..50d39dd670b 100644
--- a/source/nsswitch/winbindd_cred_cache.c
+++ b/source/nsswitch/winbindd_cred_cache.c
@@ -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,
diff --git a/source/nsswitch/winbindd_dual.c b/source/nsswitch/winbindd_dual.c
index 4a652e47dac..edb4fa504b1 100644
--- a/source/nsswitch/winbindd_dual.c
+++ b/source/nsswitch/winbindd_dual.c
@@ -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 ));
diff --git a/source/param/loadparm.c b/source/param/loadparm.c
index 469976325c0..976810ee153 100644
--- a/source/param/loadparm.c
+++ b/source/param/loadparm.c
@@ -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)
diff --git a/source/printing/nt_printing.c b/source/printing/nt_printing.c
index 4a6b2e0a6de..5b5f82d1f48 100644
--- a/source/printing/nt_printing.c
+++ b/source/printing/nt_printing.c
@@ -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
diff --git a/source/printing/printing.c b/source/printing/printing.c
index 2f1d123a200..588641358f3 100644
--- a/source/printing/printing.c
+++ b/source/printing/printing.c
@@ -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) {
diff --git a/source/rpc_server/srv_spoolss_nt.c b/source/rpc_server/srv_spoolss_nt.c
index 2a997722a0e..f5a2298fe97 100644
--- a/source/rpc_server/srv_spoolss_nt.c
+++ b/source/rpc_server/srv_spoolss_nt.c
@@ -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 );
diff --git a/source/rpc_server/srv_srvsvc_nt.c b/source/rpc_server/srv_srvsvc_nt.c
index b7e63fcce13..17247b65938 100644
--- a/source/rpc_server/srv_srvsvc_nt.c
+++ b/source/rpc_server/srv_srvsvc_nt.c
@@ -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)
diff --git a/source/smbd/blocking.c b/source/smbd/blocking.c
index e0478fa762f..70b2d30aaba 100644
--- a/source/smbd/blocking.c
+++ b/source/smbd/blocking.c
@@ -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;
}
diff --git a/source/smbd/close.c b/source/smbd/close.c
index ea0d807041c..b826cd622af 100644
--- a/source/smbd/close.c
+++ b/source/smbd/close.c
@@ -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(
diff --git a/source/smbd/conn.c b/source/smbd/conn.c
index 083e8339c80..44888b777f2 100644
--- a/source/smbd/conn.c
+++ b/source/smbd/conn.c
@@ -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;
diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c
index ff4291c08c8..ad79bbacddf 100644
--- a/source/smbd/dosmode.c
+++ b/source/smbd/dosmode.c
@@ -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);
}
diff --git a/source/smbd/files.c b/source/smbd/files.c
index 7069818dee4..66ef37bb0fa 100644
--- a/source/smbd/files.c
+++ b/source/smbd/files.c
@@ -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--;
diff --git a/source/smbd/notify.c b/source/smbd/notify.c
index 4ec53567dd4..cf60720bc74 100644
--- a/source/smbd/notify.c
+++ b/source/smbd/notify.c
@@ -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
@@ -21,36 +22,95 @@
#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
index bfef4ac871e..00000000000
--- a/source/smbd/notify_fam.c
+++ /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
index 0787a3eec5e..00000000000
--- a/source/smbd/notify_hash.c
+++ /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
index 00000000000..5fb414de4cc
--- /dev/null
+++ b/source/smbd/notify_inotify.c
@@ -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
index 00000000000..72b96049350
--- /dev/null
+++ b/source/smbd/notify_internal.c
@@ -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
index 0c20effc3d1..00000000000
--- a/source/smbd/notify_kernel.c
+++ /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 */
diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c
index 2eddffb7f16..08f19e7bdb6 100644
--- a/source/smbd/nttrans.c
+++ b/source/smbd/nttrans.c
@@ -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;
}
diff --git a/source/smbd/open.c b/source/smbd/open.c
index 05023729474..89474874cc5 100644
--- a/source/smbd/open.c
+++ b/source/smbd/open.c
@@ -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;
diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c
index 526b7ced9ec..423d6b3a999 100644
--- a/source/smbd/oplock.c
+++ b/source/smbd/oplock.c
@@ -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
diff --git a/source/smbd/process.c b/source/smbd/process.c
index ffc731e42b3..5830af8f435 100644
--- a/source/smbd/process.c
+++ b/source/smbd/process.c
@@ -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);
}
@@ -1448,12 +1434,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);
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index 315b338b0ba..c48bebb0c6c 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -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);
diff --git a/source/smbd/server.c b/source/smbd/server.c
index 38767ab402e..ab32d656d38 100644
--- a/source/smbd/server.c
+++ b/source/smbd/server.c
@@ -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();
diff --git a/source/smbd/service.c b/source/smbd/service.c
index 025fd38ff79..18db2f8aba2 100644
--- a/source/smbd/service.c
+++ b/source/smbd/service.c
@@ -22,6 +22,31 @@
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);
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index 8bdd10b643d..b91cdeef702 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -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;
}
diff --git a/source/smbd/vfs.c b/source/smbd/vfs.c
index 643c48cd27c..82ea602187c 100644
--- a/source/smbd/vfs.c
+++ b/source/smbd/vfs.c
@@ -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.
diff --git a/source/torture/msgtest.c b/source/torture/msgtest.c
index d913c4903f3..5a066bc599e 100644
--- a/source/torture/msgtest.c
+++ b/source/torture/msgtest.c
@@ -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();
diff --git a/source/torture/vfstest.c b/source/torture/vfstest.c
index fa0545988e9..872c7a74c32 100644
--- a/source/torture/vfstest.c
+++ b/source/torture/vfstest.c
@@ -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[])
diff --git a/source/utils/net_ads.c b/source/utils/net_ads.c
index eb3f9da1ca7..02a0b68932c 100644
--- a/source/utils/net_ads.c
+++ b/source/utils/net_ads.c
@@ -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;
}
diff --git a/source/utils/smbcontrol.c b/source/utils/smbcontrol.c
index 9ca304c62bd..ec1e101e061 100644
--- a/source/utils/smbcontrol.c
+++ b/source/utils/smbcontrol.c
@@ -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;