[SCM] Samba Shared Repository - branch master updated - release-4-0-0alpha6-1035-g5bd7f9c

Steven Danneman sdanneman at samba.org
Fri Feb 20 22:11:15 GMT 2009


The branch, master has been updated
       via  5bd7f9c61bb2fea1867ac6657c9b30799ba49d8f (commit)
       via  9a90cbea83548bffb224151a24005cb916f238f5 (commit)
       via  b329ea1cf35cfe151ac026eefc8ff82b2dfd711c (commit)
       via  1a0aed36c0fc3815c832be1086a3a66256426414 (commit)
      from  e6a5f11865a55e9644292ae92e4a4b5ec0662ccd (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 5bd7f9c61bb2fea1867ac6657c9b30799ba49d8f
Author: Steven Danneman <steven.danneman at isilon.com>
Date:   Fri Feb 20 13:25:17 2009 -0800

    s3: OneFS implementation of change notify
    
    The OneFS Samba implementation of change notify is modeled after the
    usage of Linux's inotify kernel subsystem.  A single call is made
    into the onefs.so VFS module to initialize kernel tracking of certain
    file change events.  When these events occur a kernel notification is
    sent to smbd and the notification event is translated and given to the
    general Samba Change Notify layer through a callback function.
    
    The most difficult aspect is converting an SMB CompletionFilter to
    a matching ifs_event mask, and then back to an appropriate change
    notify action.  Currently, not all possible cases are handled by the
    this module, but the most prevalent ones, which are tested by
    smbtorture, are implemented.

commit 9a90cbea83548bffb224151a24005cb916f238f5
Author: Steven Danneman <steven.danneman at isilon.com>
Date:   Tue Feb 17 16:20:18 2009 -0800

    s3: Make change notify immediately return a catch-all packet on underlying error
    
    * This allows a problem in the underlying CN backend to be bubbled up
      to the general CN layer so a catch-all reply can be returned
    * We now also return a catch-all response immediately if the server-side
      event queue becomes too big

commit b329ea1cf35cfe151ac026eefc8ff82b2dfd711c
Author: Steven Danneman <steven.danneman at isilon.com>
Date:   Fri Feb 20 13:23:53 2009 -0800

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

commit 1a0aed36c0fc3815c832be1086a3a66256426414
Author: Steven Danneman <steven.danneman at isilon.com>
Date:   Thu Feb 19 17:06:27 2009 -0800

    Added torture tests to RAW-NOTIFY
    
    * This adds a test to check the change notify behavior of the SMB server
      when more events have been generated than can be returned in a single
      change notify response.
    
    * Second test makes sure the server doesn't return notification events
      for changes to the watched directory itself

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

Summary of changes:
 source3/Makefile.in                 |    5 +-
 source3/include/proto.h             |    3 +
 source3/librpc/gen_ndr/ndr_notify.c |    8 +
 source3/librpc/gen_ndr/notify.h     |    2 +
 source3/librpc/idl/notify.idl       |    2 +
 source3/librpc/ndr/util.c           |   39 ++
 source3/modules/onefs.h             |    9 +
 source3/modules/onefs_notify.c      |  680 +++++++++++++++++++++++++++++++++++
 source3/modules/vfs_onefs.c         |    2 +
 source3/smbd/notify.c               |   17 +-
 source4/torture/raw/notify.c        |  152 ++++++++-
 11 files changed, 914 insertions(+), 5 deletions(-)
 create mode 100644 source3/modules/onefs_notify.c


Changeset truncated at 500 lines:

diff --git a/source3/Makefile.in b/source3/Makefile.in
index 6ff90fc..2df995f 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -621,7 +621,8 @@ PROFILES_OBJ = utils/profiles.o \
                $(LIB_OBJ) $(LIB_DUMMY_OBJ) \
                $(POPT_LIB_OBJ)
 
-OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.o smbd/oplock_onefs.o
+OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.o \
+	     smbd/oplock_onefs.o
 
 NOTIFY_OBJ = smbd/notify.o smbd/notify_inotify.o smbd/notify_internal.o
 
@@ -666,7 +667,7 @@ VFS_ACL_TDB_OBJ = modules/vfs_acl_tdb.o
 VFS_SMB_TRAFFIC_ANALYZER_OBJ = modules/vfs_smb_traffic_analyzer.o
 VFS_ONEFS_OBJ = modules/vfs_onefs.o modules/onefs_acl.o modules/onefs_system.o \
 		modules/onefs_open.o modules/onefs_streams.o modules/onefs_dir.c \
-		modules/onefs_cbrl.o
+		modules/onefs_cbrl.o modules/onefs_notify.o
 VFS_ONEFS_SHADOW_COPY_OBJ = modules/vfs_onefs_shadow_copy.o modules/onefs_shadow_copy.o
 PERFCOUNT_ONEFS_OBJ = modules/perfcount_onefs.o
 PERFCOUNT_TEST_OBJ = modules/perfcount_test.o
diff --git a/source3/include/proto.h b/source3/include/proto.h
index ab1f2f4..1ac2ac2 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -2283,6 +2283,9 @@ ADS_STATUS gp_get_machine_token(ADS_STRUCT *ads,
 enum ndr_err_code ndr_push_server_id(struct ndr_push *ndr, int ndr_flags, const struct server_id *r);
 enum ndr_err_code ndr_pull_server_id(struct ndr_pull *ndr, int ndr_flags, struct server_id *r);
 void ndr_print_server_id(struct ndr_print *ndr, const char *name, const struct server_id *r);
+enum ndr_err_code ndr_push_file_id(struct ndr_push *ndr, int ndr_flags, const struct file_id *r);
+enum ndr_err_code ndr_pull_file_id(struct ndr_pull *ndr, int ndr_flags, struct file_id *r);
+void ndr_print_file_id(struct ndr_print *ndr, const char *name, const struct file_id *r);
 _PUBLIC_ void ndr_print_bool(struct ndr_print *ndr, const char *name, const bool b);
 _PUBLIC_ void ndr_print_sockaddr_storage(struct ndr_print *ndr, const char *name, const struct sockaddr_storage *ss);
 const char *ndr_errstr(enum ndr_err_code err);
diff --git a/source3/librpc/gen_ndr/ndr_notify.c b/source3/librpc/gen_ndr/ndr_notify.c
index 00ba8bc..d4ac42e 100644
--- a/source3/librpc/gen_ndr/ndr_notify.c
+++ b/source3/librpc/gen_ndr/ndr_notify.c
@@ -10,6 +10,8 @@ _PUBLIC_ enum ndr_err_code ndr_push_notify_entry(struct ndr_push *ndr, int ndr_f
 		NDR_CHECK(ndr_push_server_id(ndr, NDR_SCALARS, &r->server));
 		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->filter));
 		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->subdir_filter));
+		NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->dir_fd));
+		NDR_CHECK(ndr_push_file_id(ndr, NDR_SCALARS, &r->dir_id));
 		{
 			uint32_t _flags_save_string = ndr->flags;
 			ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM);
@@ -21,6 +23,7 @@ _PUBLIC_ enum ndr_err_code ndr_push_notify_entry(struct ndr_push *ndr, int ndr_f
 	}
 	if (ndr_flags & NDR_BUFFERS) {
 		NDR_CHECK(ndr_push_server_id(ndr, NDR_BUFFERS, &r->server));
+		NDR_CHECK(ndr_push_file_id(ndr, NDR_BUFFERS, &r->dir_id));
 	}
 	return NDR_ERR_SUCCESS;
 }
@@ -32,6 +35,8 @@ _PUBLIC_ enum ndr_err_code ndr_pull_notify_entry(struct ndr_pull *ndr, int ndr_f
 		NDR_CHECK(ndr_pull_server_id(ndr, NDR_SCALARS, &r->server));
 		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->filter));
 		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->subdir_filter));
+		NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->dir_fd));
+		NDR_CHECK(ndr_pull_file_id(ndr, NDR_SCALARS, &r->dir_id));
 		{
 			uint32_t _flags_save_string = ndr->flags;
 			ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM);
@@ -43,6 +48,7 @@ _PUBLIC_ enum ndr_err_code ndr_pull_notify_entry(struct ndr_pull *ndr, int ndr_f
 	}
 	if (ndr_flags & NDR_BUFFERS) {
 		NDR_CHECK(ndr_pull_server_id(ndr, NDR_BUFFERS, &r->server));
+		NDR_CHECK(ndr_pull_file_id(ndr, NDR_BUFFERS, &r->dir_id));
 	}
 	return NDR_ERR_SUCCESS;
 }
@@ -54,6 +60,8 @@ _PUBLIC_ void ndr_print_notify_entry(struct ndr_print *ndr, const char *name, co
 	ndr_print_server_id(ndr, "server", &r->server);
 	ndr_print_uint32(ndr, "filter", r->filter);
 	ndr_print_uint32(ndr, "subdir_filter", r->subdir_filter);
+	ndr_print_uint32(ndr, "dir_fd", r->dir_fd);
+	ndr_print_file_id(ndr, "dir_id", &r->dir_id);
 	ndr_print_string(ndr, "path", r->path);
 	ndr_print_uint32(ndr, "path_len", r->path_len);
 	ndr_print_pointer(ndr, "private_data", r->private_data);
diff --git a/source3/librpc/gen_ndr/notify.h b/source3/librpc/gen_ndr/notify.h
index c809702..a5ec4a4 100644
--- a/source3/librpc/gen_ndr/notify.h
+++ b/source3/librpc/gen_ndr/notify.h
@@ -9,6 +9,8 @@ struct notify_entry {
 	struct server_id server;
 	uint32_t filter;
 	uint32_t subdir_filter;
+	uint32_t dir_fd;
+	struct file_id dir_id;
 	const char * path;/* [flag(LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM)] */
 	uint32_t path_len;
 	void* private_data;
diff --git a/source3/librpc/idl/notify.idl b/source3/librpc/idl/notify.idl
index c4e633c..550783b 100644
--- a/source3/librpc/idl/notify.idl
+++ b/source3/librpc/idl/notify.idl
@@ -18,6 +18,8 @@ interface notify
 		server_id server;
 		uint32 filter; /* filter to apply in this directory */
 		uint32 subdir_filter; /* filter to apply in child directories */
+		uint32 dir_fd;   /* fd of open directory */
+		file_id dir_id;  /* file_id of open directory */
 		utf8string path;
 		uint32 path_len; /* saves some computation on search */
 		pointer private_data;
diff --git a/source3/librpc/ndr/util.c b/source3/librpc/ndr/util.c
index 5afc4f4..8fac5ea 100644
--- a/source3/librpc/ndr/util.c
+++ b/source3/librpc/ndr/util.c
@@ -155,6 +155,45 @@ void ndr_print_server_id(struct ndr_print *ndr, const char *name, const struct s
 	ndr->depth--;
 }
 
+enum ndr_err_code ndr_push_file_id(struct ndr_push *ndr, int ndr_flags, const struct file_id *r)
+{
+	if (ndr_flags & NDR_SCALARS) {
+		NDR_CHECK(ndr_push_align(ndr, 4));
+		NDR_CHECK(ndr_push_udlong(ndr, NDR_SCALARS,
+					  (uint64_t)r->devid));
+		NDR_CHECK(ndr_push_udlong(ndr, NDR_SCALARS,
+					  (uint64_t)r->inode));
+		NDR_CHECK(ndr_push_udlong(ndr, NDR_SCALARS,
+					  (uint64_t)r->extid));
+	}
+	if (ndr_flags & NDR_BUFFERS) {
+	}
+	return NDR_ERR_SUCCESS;
+}
+
+enum ndr_err_code ndr_pull_file_id(struct ndr_pull *ndr, int ndr_flags, struct file_id *r)
+{
+	if (ndr_flags & NDR_SCALARS) {
+		NDR_CHECK(ndr_pull_align(ndr, 4));
+		NDR_CHECK(ndr_pull_udlong(ndr, NDR_SCALARS, &r->devid));
+		NDR_CHECK(ndr_pull_udlong(ndr, NDR_SCALARS, &r->inode));
+		NDR_CHECK(ndr_pull_udlong(ndr, NDR_SCALARS, &r->extid));
+	}
+	if (ndr_flags & NDR_BUFFERS) {
+	}
+	return NDR_ERR_SUCCESS;
+}
+
+void ndr_print_file_id(struct ndr_print *ndr, const char *name, const struct file_id *r)
+{
+	ndr_print_struct(ndr, name, "file_id");
+	ndr->depth++;
+	ndr_print_udlong(ndr, "devid", (uint64_t)r->devid);
+	ndr_print_udlong(ndr, "inode", (uint64_t)r->inode);
+	ndr_print_udlong(ndr, "extid", (uint64_t)r->extid);
+	ndr->depth--;
+}
+
 _PUBLIC_ void ndr_print_bool(struct ndr_print *ndr, const char *name, const bool b)
 {
 	ndr->print(ndr, "%-25s: %s", name, b?"true":"false");
diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h
index c002739..ea452a4 100644
--- a/source3/modules/onefs.h
+++ b/source3/modules/onefs.h
@@ -204,6 +204,15 @@ bool onefs_brl_cancel_windows(vfs_handle_struct *handle,
 			      struct lock_struct *plock,
 			      struct blocking_lock_record *blr);
 
+NTSTATUS onefs_notify_watch(vfs_handle_struct *vfs_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);
+
 NTSTATUS onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
 			   uint32 security_info, SEC_DESC **ppdesc);
 
diff --git a/source3/modules/onefs_notify.c b/source3/modules/onefs_notify.c
new file mode 100644
index 0000000..40f6908
--- /dev/null
+++ b/source3/modules/onefs_notify.c
@@ -0,0 +1,680 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Support for change notify using OneFS's file event notification system
+ *
+ * Copyright (C) Andrew Tridgell, 2006
+ * Copyright (C) Steven Danneman, 2008
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Implement handling of change notify requests on files and directories using
+ * Isilon OneFS's "ifs event" file notification system.
+ *
+ * The structure of this file is based off the implementation of change notify
+ * using the inotify system calls in smbd/notify_inotify.c */
+
+/* TODO: We could reduce the number of file descriptors used by merging
+ * multiple watch requests on the same directory into the same
+ * onefs_notify_watch_context.  To do this we'd need mux/demux routines that
+ * when receiving an event on that watch context would check it against the
+ * CompletionFilter and WatchTree of open SMB requests, and return notify
+ * events back to the proper SMB requests */
+
+#include "onefs.h"
+
+#include <ifs/ifs_types.h>
+#include <ifs/ifs_syscalls.h>
+#include <isi_util/syscalls.h>
+
+#include <sys/event.h>
+
+#define ONEFS_IFS_EVENT_MAX_NUM 8
+#define ONEFS_IFS_EVENT_MAX_BYTES (ONEFS_IFS_EVENT_MAX_NUM * \
+				   sizeof(struct ifs_event))
+
+struct onefs_notify_watch_context {
+	struct sys_notify_context *ctx;
+	int watch_fd;
+	ino_t watch_lin;
+	const char *path;
+	int ifs_event_fd;
+	uint32_t ifs_filter; /* the ifs event mask */
+	uint32_t smb_filter; /* the windows completion filter */
+	void (*callback)(struct sys_notify_context *ctx,
+			 void *private_data,
+			 struct notify_event *ev);
+	void *private_data;
+};
+
+/**
+ * Conversion map from a SMB completion filter to an IFS event mask.
+ */
+static const struct {
+	uint32_t smb_filter;
+	uint32_t ifs_filter;
+} onefs_notify_conv[] = {
+	{FILE_NOTIFY_CHANGE_FILE_NAME,
+	    NOTE_CREATE | NOTE_DELETE | NOTE_RENAME_FROM | NOTE_RENAME_TO},
+	{FILE_NOTIFY_CHANGE_DIR_NAME,
+	    NOTE_CREATE | NOTE_DELETE | NOTE_RENAME_FROM | NOTE_RENAME_TO},
+	{FILE_NOTIFY_CHANGE_ATTRIBUTES,
+	    NOTE_CREATE | NOTE_DELETE | NOTE_RENAME_FROM | NOTE_RENAME_TO |
+	    NOTE_ATTRIB},
+	{FILE_NOTIFY_CHANGE_SIZE,
+	    NOTE_SIZE | NOTE_EXTEND},
+	{FILE_NOTIFY_CHANGE_LAST_WRITE,
+	    NOTE_WRITE | NOTE_ATTRIB},
+	/* OneFS doesn't set atime by default, but we can somewhat fake it by
+	 * notifying for other events that imply ACCESS */
+	{FILE_NOTIFY_CHANGE_LAST_ACCESS,
+	    NOTE_WRITE | NOTE_ATTRIB},
+	/* We don't have an ifs_event for the setting of create time, but we
+	 * can fake by notifying when a "new" file is created via rename */
+	{FILE_NOTIFY_CHANGE_CREATION,
+	    NOTE_RENAME_TO},
+	{FILE_NOTIFY_CHANGE_SECURITY,
+	    NOTE_SECURITY},
+	/* Unsupported bits
+	FILE_NOTIFY_CHANGE_EA		 (no EAs in OneFS)
+	FILE_NOTIFY_CHANGE_STREAM_NAME	 (no ifs_event equivalent)
+	FILE_NOTIFY_CHANGE_STREAM_SIZE	 (no ifs_event equivalent)
+	FILE_NOTIFY_CHANGE_STREAM_WRITE	 (no ifs_event equivalent) */
+};
+
+#define ONEFS_NOTIFY_UNSUPPORTED  (FILE_NOTIFY_CHANGE_LAST_ACCESS | \
+				   FILE_NOTIFY_CHANGE_CREATION    | \
+				   FILE_NOTIFY_CHANGE_EA          | \
+				   FILE_NOTIFY_CHANGE_STREAM_NAME | \
+				   FILE_NOTIFY_CHANGE_STREAM_SIZE | \
+				   FILE_NOTIFY_CHANGE_STREAM_WRITE)
+
+/**
+ * Convert Windows/SMB filter/flags to IFS event filter.
+ *
+ * @param[in] smb_filter Windows Completion Filter sent in the SMB
+ *
+ * @return ifs event filter mask
+ */
+static uint32_t
+onefs_notify_smb_filter_to_ifs_filter(uint32_t smb_filter)
+{
+	int i;
+	uint32_t ifs_filter = 0x0;
+
+	for (i=0;i<ARRAY_SIZE(onefs_notify_conv);i++) {
+		if (onefs_notify_conv[i].smb_filter & smb_filter) {
+			ifs_filter |= onefs_notify_conv[i].ifs_filter;
+		}
+	}
+
+	return ifs_filter;
+}
+
+/**
+ * Convert IFS filter/flags to a Windows notify action.
+ *
+ * Returns Win notification actions, types (1-5).
+ *
+ * @param[in] smb_filter Windows Completion Filter sent in the SMB
+ * @param[in] ifs_filter Returned from the kernel in the ifs_event
+ *
+ * @return 0 if there are no more relevant flags.
+ */
+static int
+onefs_notify_ifs_filter_to_smb_action(uint32_t smb_filter, uint32_t ifs_filter)
+{
+	/* Handle Windows special cases, before modifying events bitmask */
+
+	/* Special case 1: win32api->MoveFile needs to send a modified
+	 * notification on the new file, if smb_filter == ATTRIBUTES.
+	 * Here we handle the case where two separate ATTR & NAME notifications
+	 * have been registered.  We handle the case where both bits are set in
+	 * the same registration in onefs_notify_dispatch() */
+	if ((smb_filter & FILE_NOTIFY_CHANGE_ATTRIBUTES) &&
+		!(smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) &&
+		(ifs_filter & NOTE_FILE) && (ifs_filter & NOTE_RENAME_TO))
+	{
+		return NOTIFY_ACTION_MODIFIED;
+	}
+
+	/* Special case 2: Writes need to send a modified
+	 * notification on the file, if smb_filter = ATTRIBUTES. */
+	if ((smb_filter & FILE_NOTIFY_CHANGE_ATTRIBUTES) &&
+		(ifs_filter & NOTE_FILE) && (ifs_filter & NOTE_WRITE))
+	{
+		return NOTIFY_ACTION_MODIFIED;
+	}
+
+	/* Loop because some events may be filtered out. Eventually all
+	 * relevant events will be taken care of and returned. */
+	while (1) {
+		if (ifs_filter & NOTE_CREATE) {
+			ifs_filter &= ~NOTE_CREATE;
+			if ((smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) &&
+				(ifs_filter & NOTE_FILE))
+				return NOTIFY_ACTION_ADDED;
+			if ((smb_filter & FILE_NOTIFY_CHANGE_DIR_NAME) &&
+				(ifs_filter & NOTE_DIRECTORY))
+				return NOTIFY_ACTION_ADDED;
+		}
+		else if (ifs_filter & NOTE_DELETE) {
+			ifs_filter &= ~NOTE_DELETE;
+			if ((smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) &&
+				(ifs_filter & NOTE_FILE))
+				return NOTIFY_ACTION_REMOVED;
+			if ((smb_filter & FILE_NOTIFY_CHANGE_DIR_NAME) &&
+				(ifs_filter & NOTE_DIRECTORY))
+				return NOTIFY_ACTION_REMOVED;
+		}
+		else if (ifs_filter & NOTE_WRITE) {
+			ifs_filter &= ~NOTE_WRITE;
+			if ((smb_filter & FILE_NOTIFY_CHANGE_LAST_WRITE) ||
+				(smb_filter & FILE_NOTIFY_CHANGE_LAST_ACCESS))
+				return NOTIFY_ACTION_MODIFIED;
+		}
+		else if ((ifs_filter & NOTE_SIZE) || (ifs_filter & NOTE_EXTEND)) {
+			ifs_filter &= ~NOTE_SIZE;
+			ifs_filter &= ~NOTE_EXTEND;
+
+			/* TODO: Do something on NOTE_DIR? */
+			if ((smb_filter & FILE_NOTIFY_CHANGE_SIZE) &&
+			    (ifs_filter & NOTE_FILE))
+				return NOTIFY_ACTION_MODIFIED;
+		}
+		else if (ifs_filter & NOTE_ATTRIB) {
+			ifs_filter &= ~NOTE_ATTRIB;
+			/* NOTE_ATTRIB needs to be converted to a
+			 * LAST_WRITE as well, because we need to send
+			 * LAST_WRITE when the mtime changes. Looking into
+			 * better alternatives as this causes extra LAST_WRITE
+			 * notifications. We also return LAST_ACCESS as a
+			 * modification to attribs implies this. */
+			if ((smb_filter & FILE_NOTIFY_CHANGE_ATTRIBUTES) ||
+				(smb_filter & FILE_NOTIFY_CHANGE_LAST_WRITE) ||
+				(smb_filter & FILE_NOTIFY_CHANGE_LAST_ACCESS))
+				return NOTIFY_ACTION_MODIFIED;
+		}
+		else if (ifs_filter & NOTE_LINK) {
+			ifs_filter &= ~NOTE_LINK;
+			/* NOTE_LINK will send out NO notifications */
+		}
+		else if (ifs_filter & NOTE_REVOKE) {
+			ifs_filter &= ~NOTE_REVOKE;
+			/* NOTE_REVOKE will send out NO notifications */
+		}
+		else if (ifs_filter & NOTE_RENAME_FROM)  {
+			ifs_filter &= ~NOTE_RENAME_FROM;
+
+			if (((smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) &&
+				 (ifs_filter & NOTE_FILE)) ||
+				((smb_filter & FILE_NOTIFY_CHANGE_DIR_NAME) &&
+				 (ifs_filter & NOTE_DIRECTORY))) {
+				/* Check if this is a RENAME, not a MOVE */
+				if (ifs_filter & NOTE_RENAME_SAMEDIR) {
+					/* Remove the NOTE_RENAME_SAMEDIR, IFF
+					 * RENAME_TO is not in this event */
+					if (!(ifs_filter & NOTE_RENAME_TO))
+						ifs_filter &=
+						    ~NOTE_RENAME_SAMEDIR;
+					return NOTIFY_ACTION_OLD_NAME;
+				}
+				return NOTIFY_ACTION_REMOVED;
+			}
+		}
+		else if (ifs_filter & NOTE_RENAME_TO) {
+			ifs_filter &= ~NOTE_RENAME_TO;
+
+			if (((smb_filter & FILE_NOTIFY_CHANGE_FILE_NAME) &&
+				 (ifs_filter & NOTE_FILE)) ||
+				((smb_filter & FILE_NOTIFY_CHANGE_DIR_NAME) &&
+				 (ifs_filter & NOTE_DIRECTORY))) {
+				/* Check if this is a RENAME, not a MOVE */
+				if (ifs_filter & NOTE_RENAME_SAMEDIR) {
+					/* Remove the NOTE_RENAME_SAMEDIR, IFF
+					 * RENAME_FROM is not in this event */
+					if (!(ifs_filter & NOTE_RENAME_FROM))
+						ifs_filter &=
+						    ~NOTE_RENAME_SAMEDIR;
+					return NOTIFY_ACTION_NEW_NAME;
+				}
+				return NOTIFY_ACTION_ADDED;
+			}
+			/* RAW-NOTIFY shows us that a rename triggers a
+			 * creation time change */
+			if ((smb_filter & FILE_NOTIFY_CHANGE_CREATION) &&
+				(ifs_filter & NOTE_FILE))
+				return NOTIFY_ACTION_MODIFIED;
+		}
+		else if (ifs_filter & NOTE_SECURITY) {
+			ifs_filter &= ~NOTE_SECURITY;
+
+			if (smb_filter & FILE_NOTIFY_CHANGE_SECURITY)
+				return NOTIFY_ACTION_MODIFIED;
+		} else {
+			/* No relevant flags found */
+			return 0;
+		}
+	}
+}
+
+/**
+ * Retrieve a directory path of a changed file, relative to the watched dir
+ *
+ * @param[in] wc watch context for the returned event
+ * @param[in] e ifs_event notification returned from the kernel
+ * @param[out] path name relative to the watched dir. This is talloced
+ *		    off of wc and needs to be freed by the caller.
+ *
+ * @return true on success
+ *
+ * TODO: This function currently doesn't handle path names with multiple
+ * encodings.  enc_get_lin_path() should be used in the future to convert
+ * each path segment's encoding to UTF-8
+ */
+static bool
+get_ifs_event_path(struct onefs_notify_watch_context *wc, struct ifs_event *e,
+		   char **path)
+{
+	char *path_buf = NULL;
+	size_t pathlen = 0;
+	int error = 0;
+
+	SMB_ASSERT(path);
+
+	/* Lookup the path from watch_dir through our parent dir */
+	if (e->namelen > 0) {
+		error = lin_get_path(wc->watch_lin,
+				     e->parent_lin,
+				     HEAD_SNAPID,
+				     e->parent_parent_lin,
+				     e->parent_name_hash,
+				     &pathlen, &path_buf);
+		if (!error) {
+			/* Only add slash if a path exists in path_buf from
+			 * lin_get_path call. Windows does not expect a
+			 * leading '/' */
+			if (pathlen > 0)
+				*path = talloc_asprintf(wc, "%s/%s",
+							path_buf, e->name);
+			else
+				*path = talloc_asprintf(wc, "%s", e->name);
+			SAFE_FREE(path_buf);


-- 
Samba Shared Repository


More information about the samba-cvs mailing list