[PATCH] VFS: convert to using ceph_statx structures and functions, when available

Ralph Böhme slow at samba.org
Thu Nov 17 21:39:25 UTC 2016


Hi

On Thu, Nov 17, 2016 at 01:13:57PM -0500, Jeff Layton wrote:
> Add a configure test for the ceph_statx function, and use that to
> determine whether to compile in new functions that use it and its
> variants, or whether to use a the older code that fetches birthtimes
> from an xattr.
> 
> For cephwrap_lstat, we can use ceph_statx with the AT_SYMLINK_NOFOLLOW
> flag to get the right lookup semantics.
> 
> For setting the times via cephwrap_ntimes, We can just use ceph_setattrx
> and pass them all in at the same time.

fwiw, this is something that I've been working on lately: add a full
fledged VFS_STATX call to out VFS.

The primary reason and benefit is performance, as it helps avoiding
reduntant stuff in the VFS frontend->backend interaction.

It'll also allow fetching *all* relevant file metadata attributes in a
VFS_STATX call, like btime or windows attributes, so it will be a nice
cleanup as well.

This is not ready and still work in progress, but seeing Jeff's work
on statx patches for ceph I thought I wanted to show what I have right
now.

Cheerio!
-slow
-------------- next part --------------
From 941ff3a6e222b3f36c32c55af766ae49819e8fb0 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 19 Oct 2016 08:41:11 +0200
Subject: [PATCH 01/28] s3/smbd: remove st_mask from open_files.idl and durable
 handles

st_mask is not used by any system, the only reference I found for it is
in the new statx() syscall where it's not a filesystem attribute but a
runtime flag.
---
 source3/librpc/idl/open_files.idl |  1 -
 source3/smbd/durable.c            | 14 --------------
 2 files changed, 15 deletions(-)

diff --git a/source3/librpc/idl/open_files.idl b/source3/librpc/idl/open_files.idl
index 6f74340..503385d 100644
--- a/source3/librpc/idl/open_files.idl
+++ b/source3/librpc/idl/open_files.idl
@@ -113,7 +113,6 @@ interface open_files
 		hyper		st_ex_blksize;
 		hyper		st_ex_blocks;
 		uint32		st_ex_flags;
-		uint32		st_ex_mask;
 	} vfs_default_durable_stat;
 
 	typedef [public] struct {
diff --git a/source3/smbd/durable.c b/source3/smbd/durable.c
index f39a365..8397896 100644
--- a/source3/smbd/durable.c
+++ b/source3/smbd/durable.c
@@ -120,7 +120,6 @@ NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
 	cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
 	cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
 	cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
-	cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask;
 
 	ndr_err = ndr_push_struct_blob(cookie_blob, mem_ctx, &cookie,
 			(ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
@@ -273,7 +272,6 @@ NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
 	cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
 	cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
 	cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
-	cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask;
 
 	ndr_err = ndr_push_struct_blob(&new_cookie_blob, mem_ctx, &cookie,
 			(ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
@@ -522,18 +520,6 @@ static bool vfs_default_durable_reconnect_check_stat(
 		return false;
 	}
 
-	if (cookie_st->st_ex_mask != fsp_st->st_ex_mask) {
-		DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-			  "stat_ex.%s differs: "
-			  "cookie:%llu != stat:%llu, "
-			  "denying durable reconnect\n",
-			  name,
-			  "st_ex_mask",
-			  (unsigned long long)cookie_st->st_ex_mask,
-			  (unsigned long long)fsp_st->st_ex_mask));
-		return false;
-	}
-
 	return true;
 }
 
-- 
2.7.4


From f0f8b2815a82aaf1f51870385f40dda07d4f9fa2 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 13 Oct 2016 14:00:30 +0200
Subject: [PATCH 02/28] s3/include: attribute bits for statx

These are copied verbatim from the proposed statx syscall.

Once the it landed, we can add waf checks and move this to libreplace or
similar.

It has a build check that ensures there's no conflicting system statx
header file.
---
 source3/include/includes.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/source3/include/includes.h b/source3/include/includes.h
index 234a564..82391da 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -240,6 +240,52 @@ typedef uint64_t br_off;
 #define IVAL_TO_SMB_OFF_T(buf,off) ((off_t)(( ((uint64_t)(IVAL((buf),(off)))) & ((uint64_t)0xFFFFFFFF) )))
 
 /*
+ * statx attribute flags
+ *
+ * These bits should be set in the mask argument of statx() to request
+ * particular items when calling statx(). Everything requested will be
+ * returned with stat() semantics, everything not requested might
+ * still be present.
+ */
+#ifdef STATX_MODE
+#error "Detected system statx interface"
+#endif
+
+#define STATX_MODE		0x00000001U	/* Want/got st_mode */
+#define STATX_NLINK		0x00000002U	/* Want/got st_nlink */
+#define STATX_UID		0x00000004U	/* Want/got st_uid */
+#define STATX_GID		0x00000008U	/* Want/got st_gid */
+#define STATX_RDEV		0x00000010U	/* Want/got st_rdev */
+#define STATX_ATIME		0x00000020U	/* Want/got st_atime */
+#define STATX_MTIME		0x00000040U	/* Want/got st_mtime */
+#define STATX_CTIME		0x00000080U	/* Want/got st_ctime */
+#define STATX_INO		0x00000100U	/* Want/got st_ino */
+#define STATX_SIZE		0x00000200U	/* Want/got st_size */
+#define STATX_BLOCKS		0x00000400U	/* Want/got st_blocks */
+#define STATX_BASIC_STATS	0x000007ffU	/* The stuff in the normal stat struct */
+#define STATX_BTIME		0x00000800U	/* Want/got st_btime */
+#define STATX_VERSION		0x00001000U	/* Want/got st_version */
+#define STATX_GEN		0x00002000U	/* Want/got st_gen */
+#define STATX_WIN_ATTRS		0x00004000U	/* Want/got st_win_attrs */
+#define STATX_ALL_STATS		0x00007fffU	/* All supported stats */
+
+/*
+ * Flags to be found in st_information
+ *
+ * These give information about the features or the state of a file
+ * that might be of use to ordinary userspace programs such as GUIs or
+ * ls rather than specialised tools.
+ */
+#define STATX_INFO_ENCRYPTED		0x00000001U /* File is encrypted */
+#define STATX_INFO_TEMPORARY		0x00000002U /* File is temporary */
+#define STATX_INFO_FABRICATED		0x00000004U /* File was made up by filesystem */
+#define STATX_INFO_KERNEL_API		0x00000008U /* File is kernel API (eg: procfs/sysfs) */
+#define STATX_INFO_REMOTE		0x00000010U /* File is remote */
+#define STATX_INFO_AUTOMOUNT		0x00000020U /* Dir is automount trigger */
+#define STATX_INFO_AUTODIR		0x00000040U /* Dir provides unlisted automounts */
+#define STATX_INFO_NONSYSTEM_OWNERSHIP	0x00000080U /* File has non-system ownership details */
+
+/*
  * Type for stat structure.
  */
 
-- 
2.7.4


From 8ce3bb1ef47d5c6eee15351b3669e055ba90f720 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 19 Oct 2016 14:43:34 +0200
Subject: [PATCH 03/28] s3/includes: add struct statx::st_information to struct
 stat_ex

---
 source3/include/includes.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/source3/include/includes.h b/source3/include/includes.h
index 82391da..f97a604 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -306,6 +306,7 @@ struct stat_ex {
 	bool		st_ex_calculated_birthtime;
 	blksize_t	st_ex_blksize;
 	blkcnt_t	st_ex_blocks;
+	uint32_t	st_ex_information;
 
 	uint32_t	st_ex_flags;
 	uint32_t	st_ex_mask;
-- 
2.7.4


From d5694d6cabc7822363e0fe00df07bd132e967ade Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 19 Oct 2016 14:45:37 +0200
Subject: [PATCH 04/28] s3/lib: add init_stat_ex_from_statx()

Unused for now, just adding them for completeness.
---
 source3/include/proto.h |  4 ++++
 source3/lib/system.c    | 26 ++++++++++++++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/source3/include/proto.h b/source3/include/proto.h
index 0b0a2b5..b2b5cbc 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -270,6 +270,10 @@ struct stat;
 void init_stat_ex_from_stat (struct stat_ex *dst,
 			    const struct stat *src,
 			    bool fake_dir_create_times);
+#ifdef HAVE_STRUCT_STATX
+struct statx;
+void init_stat_ex_from_statx(struct stat_ex *dst, const struct statx *src);
+#endif
 
 /* The following definitions come from lib/system_smbd.c  */
 
diff --git a/source3/lib/system.c b/source3/lib/system.c
index 3d3eeed..18db4a9 100644
--- a/source3/lib/system.c
+++ b/source3/lib/system.c
@@ -374,6 +374,32 @@ void init_stat_ex_from_stat (struct stat_ex *dst,
 #endif
 }
 
+#ifdef HAVE_STRUCT_STATX
+void init_stat_ex_from_statx(struct stat_ex *dst,
+			     const struct statx *src)
+{
+	dst->st_ex_dev = src->st_dev;
+	dst->st_ex_ino = src->st_ino;
+	dst->st_ex_mode = src->st_mode;
+	dst->st_ex_nlink = src->st_nlink;
+	dst->st_ex_uid = src->st_uid;
+	dst->st_ex_gid = src->st_gid;
+	dst->st_ex_rdev = src->st_rdev;
+	dst->st_ex_size = src->st_size;
+	dst->st_ex_atime = get_atimespec(src);
+	dst->st_ex_mtime = get_mtimespec(src);
+	dst->st_ex_ctime = get_ctimespec(src);
+	dst->st_ex_btime.tv_sec = src->st_btime;
+	dst->st_ex_btime.tv_nsec = src->st_btime_ns;
+	dst->st_ex_calculated_birthtime = false;
+	dst->st_ex_blksize = src->st_blksize;
+	dst->st_ex_blocks = src->st_blocks;
+	dst->st_ex_information = src->st_information;
+	dst->st_ex_flags = 0;
+	dst->st_ex_mask = src->st_mask;
+}
+#endif
+
 /*******************************************************************
 A stat() wrapper.
 ********************************************************************/
-- 
2.7.4


From 5d2161d977fa6d5eb0f49f37de0055ae003fe4b4 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 13 Oct 2016 18:48:18 +0200
Subject: [PATCH 05/28] s3/vfs: add statx

---
 source3/include/vfs.h        |  6 ++++++
 source3/include/vfs_macros.h |  7 +++++++
 source3/smbd/vfs.c           | 38 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+)

diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index 0810fc2..0d9aac9 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -661,6 +661,9 @@ struct vfs_fn_pointers {
 	int (*stat_fn)(struct vfs_handle_struct *handle, struct smb_filename *smb_fname);
 	int (*fstat_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_STAT *sbuf);
 	int (*lstat_fn)(struct vfs_handle_struct *handle, struct smb_filename *smb_filename);
+	int (*statx_fn)(struct vfs_handle_struct *handle,
+			files_struct *fsp, struct smb_filename *smb_fname,
+			unsigned int flags, unsigned int mask);
 	uint64_t (*get_alloc_size_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, const SMB_STRUCT_STAT *sbuf);
 	int (*unlink_fn)(struct vfs_handle_struct *handle,
 			 const struct smb_filename *smb_fname);
@@ -1122,6 +1125,9 @@ int smb_vfs_call_fstat(struct vfs_handle_struct *handle,
 		       struct files_struct *fsp, SMB_STRUCT_STAT *sbuf);
 int smb_vfs_call_lstat(struct vfs_handle_struct *handle,
 		       struct smb_filename *smb_filename);
+int smb_vfs_call_statx(struct vfs_handle_struct *handle,
+		       files_struct *fsp, struct smb_filename *smb_fname,
+		       unsigned int flags, unsigned int mask);
 uint64_t smb_vfs_call_get_alloc_size(struct vfs_handle_struct *handle,
 				     struct files_struct *fsp,
 				     const SMB_STRUCT_STAT *sbuf);
diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h
index 40c93f8..558be6a 100644
--- a/source3/include/vfs_macros.h
+++ b/source3/include/vfs_macros.h
@@ -231,6 +231,13 @@
 #define SMB_VFS_NEXT_LSTAT(handle, smb_fname) \
 	smb_vfs_call_lstat((handle)->next, (smb_fname))
 
+#define SMB_VFS_STATX(conn, fsp, smb_fname, flags, mask) \
+	smb_vfs_call_statx((conn)->vfs_handles, (fsp), (smb_fname), \
+			   (flags), (mask))
+#define SMB_VFS_NEXT_STATX(handle, fsp, smb_fname, flags, mask) \
+	smb_vfs_call_statx((handle)->next, (fsp), (smb_fname), (atflag), \
+			   (mask))
+
 #define SMB_VFS_GET_ALLOC_SIZE(conn, fsp, sbuf) \
 	smb_vfs_call_get_alloc_size((conn)->vfs_handles, (fsp), (sbuf))
 #define SMB_VFS_NEXT_GET_ALLOC_SIZE(conn, fsp, sbuf) \
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 35f560b..0036d69 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -1889,6 +1889,44 @@ int smb_vfs_call_lstat(struct vfs_handle_struct *handle,
 	return handle->fns->lstat_fn(handle, smb_filename);
 }
 
+int smb_vfs_call_statx(struct vfs_handle_struct *handle,
+		       files_struct *fsp, struct smb_filename *smb_fname,
+		       unsigned int flags, unsigned int mask)
+{
+	int ret;
+
+	VFS_FIND(statx);
+	ret = handle->fns->statx_fn(handle, fsp, smb_fname, flags, mask);
+	if (ret != 0) {
+		return ret;
+	}
+
+	/*
+	 * Ensure all requested attributes are present. We do this
+	 * here centrally to keep the VFS interface sane and so
+	 * callers can rely on the requested bit being present.
+	 */
+
+	if ((fsp != NULL) && (smb_fname == NULL)) {
+		if ((fsp->fsp_name->st.st_ex_mask & mask) != mask) {
+			DBG_ERR("[%s] expected mask [0x%u] got [0x%u]\n",
+				fsp_str_dbg(fsp), mask,
+				fsp->fsp_name->st.st_ex_mask);
+			return -1;
+		}
+		return 0;
+	}
+
+	if ((smb_fname->st.st_ex_mask & mask) != mask) {
+		DBG_ERR("[%s] expected mask [0x%x] got [0x%x]\n",
+			smb_fname_str_dbg(smb_fname), mask,
+			smb_fname->st.st_ex_mask);
+		return -1;
+	}
+
+	return 0;
+}
+
 uint64_t smb_vfs_call_get_alloc_size(struct vfs_handle_struct *handle,
 				     struct files_struct *fsp,
 				     const SMB_STRUCT_STAT *sbuf)
-- 
2.7.4


From 3bc71ad779891ca0ae514110948b247e94d87946 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 21 Oct 2016 09:19:55 +0200
Subject: [PATCH 06/28] s3/lib: set st_mask in init_stat_ex_from_stat()

---
 source3/lib/system.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/source3/lib/system.c b/source3/lib/system.c
index 18db4a9..811803e 100644
--- a/source3/lib/system.c
+++ b/source3/lib/system.c
@@ -372,6 +372,7 @@ void init_stat_ex_from_stat (struct stat_ex *dst,
 #else
 	dst->st_ex_flags = 0;
 #endif
+	dst->st_ex_mask = STATX_BASIC_STATS | STATX_BTIME;
 }
 
 #ifdef HAVE_STRUCT_STATX
-- 
2.7.4


From 587435da600f9d6e8af49ea0e319e485579433d0 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 13 Oct 2016 15:14:42 +0200
Subject: [PATCH 07/28] s3/vfs_default: statx definition in default vfs

Mapping statx to existing stat/lstat in default vfs.
---
 source3/modules/vfs_default.c | 60 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 4e8605b..0aad32c 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -1185,6 +1185,65 @@ static int vfswrap_lstat(vfs_handle_struct *handle,
 	return result;
 }
 
+static int vfswrap_statx(vfs_handle_struct *handle,
+			 files_struct *fsp,
+			 struct smb_filename *smb_fname,
+			 unsigned int flags,
+			 unsigned int mask)
+{
+	int ret = 0;
+	struct smb_filename *fname = NULL;
+
+	if (fsp != NULL) {
+		if (smb_fname != NULL) {
+			/* smb_fname could be used once we have SMB_VFS_FSTATAT() */
+			DBG_ERR("smb_fname must be NULL\n");
+			errno = EINVAL;
+			return -1;
+		}
+		fname = fsp->fsp_name;
+	} else {
+		fname = smb_fname;
+	}
+
+	fname->st.st_ex_mask = 0;
+
+	if ((mask & (STATX_BASIC_STATS | STATX_BTIME)) != 0) {
+		/*
+		 * Only stat if any of the attributes support by our
+		 * VFS stat funcs are requested.
+		 */
+		if (fsp != NULL) {
+			/* fstat semantics */
+			ret = SMB_VFS_FSTAT(fsp, &fname->st);
+			if (ret != 0) {
+				DBG_ERR("%s failed %s\n", smb_fname_str_dbg(fname),
+					strerror(errno));
+				return -1;
+			}
+		} else {
+			if (flags & AT_SYMLINK_NOFOLLOW) {
+				ret = SMB_VFS_LSTAT(handle->conn, fname);
+			} else {
+				ret = SMB_VFS_STAT(handle->conn, fname);
+			}
+			if (ret != 0) {
+				DBG_ERR("%s failed %s\n",
+					smb_fname_str_dbg(fname),
+					strerror(errno));
+				return -1;
+			}
+		}
+	}
+
+	/*
+	 * In the future we may fetch stuff like dos attributes
+	 * below ...
+	 */
+
+	return 0;
+}
+
 static NTSTATUS vfswrap_translate_name(struct vfs_handle_struct *handle,
 				       const char *name,
 				       enum vfs_translate_direction direction,
@@ -2785,6 +2844,7 @@ static struct vfs_fn_pointers vfs_default_fns = {
 	.stat_fn = vfswrap_stat,
 	.fstat_fn = vfswrap_fstat,
 	.lstat_fn = vfswrap_lstat,
+	.statx_fn = vfswrap_statx,
 	.get_alloc_size_fn = vfswrap_get_alloc_size,
 	.unlink_fn = vfswrap_unlink,
 	.chmod_fn = vfswrap_chmod,
-- 
2.7.4


From 5a923f7c072a11010037cede584e4836275681e8 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 13 Oct 2016 18:46:48 +0200
Subject: [PATCH 08/28] lib/util: gpfswrap: definition of statx and statlite

Unfortunately there's no gpfs_stat_x "l" variant (ie gpfs_lstat_x), only
for this reason we pull in the (l)statlite functions as well. Only
gpfs_lstatlite is used though in the place where we'd need gpfs_lstat_x.
---
 lib/util/gpfswrap.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/util/gpfswrap.h |  6 ++++
 2 files changed, 95 insertions(+)

diff --git a/lib/util/gpfswrap.c b/lib/util/gpfswrap.c
index 0632ee2..76e03b3 100644
--- a/lib/util/gpfswrap.c
+++ b/lib/util/gpfswrap.c
@@ -20,6 +20,9 @@
 
 #include "replace.h"
 #include "gpfswrap.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
 static int (*gpfs_set_share_fn)(int fd, unsigned int allow, unsigned int deny);
 static int (*gpfs_set_lease_fn)(int fd, unsigned int type);
@@ -45,6 +48,14 @@ static int (*gpfs_init_trace_fn)(void);
 static int (*gpfs_query_trace_fn)(void);
 static void (*gpfs_add_trace_fn)(int level, const char *msg);
 static void (*gpfs_fini_trace_fn)(void);
+static int (*gpfs_statlite_fn)(char *pathname, unsigned int *gpfsmaskp,
+			       struct stat64 *st);
+static int (*gpfs_lstatlite_fn)(char *pathname, unsigned int *gpfsmaskp,
+				struct stat64 *st);
+static int (*gpfs_stat_x_fn)(char *pathname, unsigned int *st_litemask,
+			     gpfs_iattr64_t *iattr);
+static int (*gpfs_fstat_x_fn)(int fd, unsigned int *st_litemask,
+			     gpfs_iattr64_t *iattr);
 
 int gpfswrap_init(void)
 {
@@ -78,6 +89,10 @@ int gpfswrap_init(void)
 	gpfs_query_trace_fn	      = dlsym(l, "gpfs_query_trace");
 	gpfs_add_trace_fn	      = dlsym(l, "gpfs_add_trace");
 	gpfs_fini_trace_fn	      = dlsym(l, "gpfs_fini_trace");
+	gpfs_statlite_fn	      = dlsym(l, "gpfs_statlite");
+	gpfs_lstatlite_fn	      = dlsym(l, "gpfs_lstatlite");
+	gpfs_stat_x_fn		      = dlsym(l, "gpfs_stat_x");
+	gpfs_fstat_x_fn		      = dlsym(l, "gpfs_fstat_x");
 
 	return 0;
 }
@@ -263,6 +278,80 @@ void gpfswrap_add_trace(int level, const char *msg)
 	gpfs_add_trace_fn(level, msg);
 }
 
+int gpfswrap_statlite(char *pathname, unsigned int *gpfsmaskp,
+                      struct stat64 *st)
+{
+       int rc;
+
+       if (!gpfs_statlite_fn) {
+               errno = ENOSYS;
+               return -1;
+       }
+
+       rc = gpfs_statlite_fn(pathname, gpfsmaskp, st);
+
+       if ((rc == 0) && (S_ISDIR(st->st_mode))) {
+               st->st_size = 0;
+       }
+
+       return rc;
+}
+
+int gpfswrap_lstatlite(char *pathname, unsigned int *gpfsmaskp,
+                       struct stat64 *st)
+{
+       int rc;
+
+       if (!gpfs_lstatlite_fn) {
+               errno = ENOSYS;
+               return -1;
+       }
+
+       rc = gpfs_lstatlite_fn(pathname, gpfsmaskp, st);
+
+       if ((rc == 0) && (S_ISDIR(st->st_mode))) {
+               st->st_size = 0;
+       }
+
+       return rc;
+}
+
+int gpfswrap_stat_x(char *path, unsigned int *st_litemask, gpfs_iattr64_t *iattr)
+{
+	int rc;
+
+	if (!gpfs_stat_x_fn) {
+		errno = ENOSYS;
+		return -1;
+	}
+
+	rc = gpfs_stat_x_fn(path, st_litemask, iattr);
+
+	if ((rc == 0) && (S_ISDIR(iattr->ia_mode))) {
+		iattr->ia_size = 0;
+	}
+
+	return rc;
+}
+
+int gpfswrap_fstat_x(int fd, unsigned int *st_litemask, gpfs_iattr64_t *iattr)
+{
+	int rc;
+
+	if (!gpfs_fstat_x_fn) {
+		errno = ENOSYS;
+		return -1;
+	}
+
+	rc = gpfs_fstat_x_fn(fd, st_litemask, iattr);
+
+	if ((rc == 0) && (S_ISDIR(iattr->ia_mode))) {
+		iattr->ia_size = 0;
+	}
+
+	return rc;
+}
+
 void gpfswrap_fini_trace(void)
 {
 	if (gpfs_fini_trace_fn == NULL) {
diff --git a/lib/util/gpfswrap.h b/lib/util/gpfswrap.h
index 1c9c64f..d16e58b 100644
--- a/lib/util/gpfswrap.h
+++ b/lib/util/gpfswrap.h
@@ -48,5 +48,11 @@ int gpfswrap_init_trace(void);
 int gpfswrap_query_trace(void);
 void gpfswrap_add_trace(int level, const char *msg);
 void gpfswrap_fini_trace(void);
+int gpfswrap_statlite(char *pathname, unsigned int *gpfsmaskp,
+		      struct stat64 *st);
+int gpfswrap_lstatlite(char *pathname, unsigned int *gpfsmaskp,
+		       struct stat64 *st);
+int gpfswrap_stat_x(char *path, unsigned int *st_litemask, gpfs_iattr64_t *iattr);
+int gpfswrap_fstat_x(int fd, unsigned int *st_litemask, gpfs_iattr64_t *iattr);
 
 #endif
-- 
2.7.4


From 61b8a2ca799f3b686effe85ffb9c633987d1b3bd Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 13 Oct 2016 18:46:07 +0200
Subject: [PATCH 09/28] vfs_gpfs: add statx with stat

---
 source3/modules/vfs_gpfs.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c
index 89ce3b7..a3a9f81 100644
--- a/source3/modules/vfs_gpfs.c
+++ b/source3/modules/vfs_gpfs.c
@@ -1867,6 +1867,88 @@ static int smbd_gpfs_set_times_path(char *path, struct smb_file_time *ft)
 	return rc;
 }
 
+static int vfs_gpfs_statx(struct vfs_handle_struct *handle,
+			  files_struct *fsp,
+			  struct smb_filename *smb_fname,
+			  unsigned int flags,
+			  unsigned int mask)
+{
+	struct gpfs_winattr attrs;
+	bool fake_dir_create_times = lp_fake_directory_create_times(
+		SNUM(handle->conn));
+	struct smb_filename *fname = NULL;
+	int rc;
+
+	if (fsp != NULL) {
+		if (smb_fname != NULL) {
+			/* smb_fname could be used once we have SMB_VFS_FSTATAT() */
+			DBG_ERR("smb_fname must be NULL\n");
+			errno = EINVAL;
+			return -1;
+		}
+		fname = fsp->fsp_name;
+	} else {
+		fname = smb_fname;
+	}
+
+	fname->st.st_ex_mask = 0;
+
+	if (mask & STATX_BASIC_STATS) {
+		if (fsp != NULL) {
+			/*
+			 * fstat handle based semantics
+			 */
+
+			rc = sys_fstat(fsp->fh->fd, &fname->st,
+				       fake_dir_create_times);
+			if (rc != 0) {
+				return -1;
+			}
+		} else {
+			/*
+			 * (l)stat path based semantics
+			 */
+
+			if (flags & AT_SYMLINK_NOFOLLOW) {
+				rc = sys_stat(fname->base_name,
+					      &fname->st,
+					      fake_dir_create_times);
+			} else {
+				rc = sys_lstat(fname->base_name,
+					       &fname->st,
+					       fake_dir_create_times);
+			}
+
+			if (rc != 0) {
+				if (errno != EACCES) {
+					return -1;
+				}
+#ifdef HAVE_FSTATAT
+				rc = stat_with_capability(handle, fname, flags);
+#endif
+				if (rc != 0) {
+					return -1;
+				}
+			}
+		}
+
+	}
+
+	if (mask & STATX_BTIME) {
+		rc = gpfswrap_get_winattrs_path(fname->base_name, &attrs);
+		if (rc == 0) {
+			struct timespec *btime = &fname->st.st_ex_btime;
+
+			btime->tv_sec = attrs.creationTime.tv_sec;
+			btime->tv_nsec = attrs.creationTime.tv_nsec;
+			fname->st.st_ex_calculated_birthtime = false;
+			fname->st.st_ex_mask |= STATX_BTIME;
+		}
+	}
+
+	return 0;
+}
+
 static int vfs_gpfs_ntimes(struct vfs_handle_struct *handle,
                         const struct smb_filename *smb_fname,
 			struct smb_file_time *ft)
@@ -2573,6 +2655,7 @@ static struct vfs_fn_pointers vfs_gpfs_fns = {
 	.stat_fn = vfs_gpfs_stat,
 	.fstat_fn = vfs_gpfs_fstat,
 	.lstat_fn = vfs_gpfs_lstat,
+	.statx_fn = vfs_gpfs_statx,
 	.ntimes_fn = vfs_gpfs_ntimes,
 	.aio_force_fn = vfs_gpfs_aio_force,
 	.sendfile_fn = vfs_gpfs_sendfile,
-- 
2.7.4


From 29227d80ac3d7a2b30416660c332a8066cfda27d Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 13 Oct 2016 18:47:06 +0200
Subject: [PATCH 10/28] s3/vfs: wrapper functions around vfs statx call

---
 source3/smbd/proto.h | 11 +++++++++++
 source3/smbd/vfs.c   | 29 +++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h
index 352d28c..3883fa4 100644
--- a/source3/smbd/proto.h
+++ b/source3/smbd/proto.h
@@ -1205,6 +1205,17 @@ void sys_utmp_yield(const char *username, const char *hostname,
 bool vfs_init_custom(connection_struct *conn, const char *vfs_object);
 bool smbd_vfs_init(connection_struct *conn);
 NTSTATUS vfs_file_exist(connection_struct *conn, struct smb_filename *smb_fname);
+int vfs_path_exists(connection_struct *conn,
+		    struct smb_filename *smb_fname,
+		    bool posix_pathnames);
+int vfs_posix_stat(connection_struct *conn,
+		   files_struct *fsp,
+		   struct smb_filename *smb_fname,
+		   bool posix_pathnames);
+int vfs_posix_stat_noatime(connection_struct *conn,
+			   files_struct *fsp,
+			   struct smb_filename *smb_fname,
+			   bool posix_pathnames);
 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count);
 ssize_t vfs_write_data(struct smb_request *req,
 			files_struct *fsp,
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 0036d69..466d943 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -398,6 +398,35 @@ NTSTATUS vfs_file_exist(connection_struct *conn, struct smb_filename *smb_fname)
 	return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 }
 
+int vfs_path_exists(connection_struct *conn,
+		     struct smb_filename *smb_fname,
+		     bool posix_pathnames)
+{
+	return SMB_VFS_STATX(conn, NULL, smb_fname,
+			     posix_pathnames ? AT_SYMLINK_NOFOLLOW: 0,
+			     STATX_NLINK);
+}
+
+int vfs_posix_stat(connection_struct *conn,
+		   files_struct *fsp,
+		   struct smb_filename *smb_fname,
+		   bool posix_pathnames)
+{
+	return SMB_VFS_STATX(conn, fsp, smb_fname,
+			     posix_pathnames ? AT_SYMLINK_NOFOLLOW: 0,
+			     STATX_BASIC_STATS);
+}
+
+int vfs_posix_stat_noatime(connection_struct *conn,
+			   files_struct *fsp,
+			   struct smb_filename *smb_fname,
+			   bool posix_pathnames)
+{
+	return SMB_VFS_STATX(conn, fsp, smb_fname,
+			     posix_pathnames ? AT_SYMLINK_NOFOLLOW: 0,
+			     STATX_BASIC_STATS & ~STATX_ATIME);
+}
+
 /****************************************************************************
  Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
 ****************************************************************************/
-- 
2.7.4


From 414a81be135cb45d56e3ee1bb7b04b8b220f9456 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 24 Oct 2016 11:47:02 +0200
Subject: [PATCH 11/28] s3/vfs: use vfs_posix_stat_noatime() in vfs_GetWd()

---
 source3/smbd/vfs.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 466d943..7bec1c0 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -941,7 +941,7 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
 		goto out;
 	}
 
-	if (SMB_VFS_STAT(conn, smb_fname_dot) == -1) {
+	if (vfs_posix_stat_noatime(conn, NULL, smb_fname_dot, false) == -1) {
 		/*
 		 * Known to fail for root: the directory may be NFS-mounted
 		 * and exported with root_squash (so has no root access).
@@ -969,7 +969,7 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
 		goto out;
 	}
 
-	if ((SMB_VFS_STAT(conn, smb_fname_full) == 0) &&
+	if ((vfs_posix_stat_noatime(conn, NULL, smb_fname_full, false) == 0) &&
 	    (smb_fname_dot->st.st_ex_dev == smb_fname_full->st.st_ex_dev) &&
 	    (smb_fname_dot->st.st_ex_ino == smb_fname_full->st.st_ex_ino) &&
 	    (S_ISDIR(smb_fname_dot->st.st_ex_mode))) {
-- 
2.7.4


From 0c042276989908226938b7a80b81ceb3704c15cf Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Oct 2016 18:18:14 +0200
Subject: [PATCH 12/28] s3/smbd: use vfs_posix_stat_noatime() in
 can_delete_file_in_directory()

---
 source3/smbd/file_access.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/smbd/file_access.c b/source3/smbd/file_access.c
index 66c9ed3..197ca0c 100644
--- a/source3/smbd/file_access.c
+++ b/source3/smbd/file_access.c
@@ -64,7 +64,7 @@ bool can_delete_file_in_directory(connection_struct *conn,
 		goto out;
 	}
 
-	if(SMB_VFS_STAT(conn, smb_fname_parent) != 0) {
+	if (vfs_posix_stat_noatime(conn, NULL, smb_fname_parent, false) != 0) {
 		ret = false;
 		goto out;
 	}
-- 
2.7.4


From fefba637a7ba062d3f68117a3ecc99cdfa8344a7 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Oct 2016 18:18:45 +0200
Subject: [PATCH 13/28] s3/smbd: use vfs_posix_stat_noatime() in
 change_file_owner_to_parent()

---
 source3/smbd/open.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index c6de2dc..b063d11 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -467,7 +467,7 @@ void change_file_owner_to_parent(connection_struct *conn,
 		return;
 	}
 
-	ret = SMB_VFS_STAT(conn, smb_fname_parent);
+	ret = vfs_posix_stat_noatime(conn, NULL, smb_fname_parent, false);
 	if (ret == -1) {
 		DEBUG(0,("change_file_owner_to_parent: failed to stat parent "
 			 "directory %s. Error was %s\n",
-- 
2.7.4


From 79e98d6df105a63a4380ee5e074aaed187c71caa Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Oct 2016 18:19:06 +0200
Subject: [PATCH 14/28] s3/smbd: use vfs_posix_stat_noatime() in
 change_dir_owner_to_parent()

---
 source3/smbd/open.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index b063d11..365657c 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -528,7 +528,7 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	ret = SMB_VFS_STAT(conn, smb_fname_parent);
+	ret = vfs_posix_stat_noatime(conn, NULL, smb_fname_parent, false);
 	if (ret == -1) {
 		status = map_nt_error_from_unix(errno);
 		DEBUG(0,("change_dir_owner_to_parent: failed to stat parent "
-- 
2.7.4


From f608975a8653e43b61925c6cb7c27cf6bbd36d5d Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Oct 2016 18:19:24 +0200
Subject: [PATCH 15/28] s3/smbd: use vfs_posix_stat_noatime() in
 change_dir_owner_to_parent()

---
 source3/smbd/open.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 365657c..17740be 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -569,7 +569,7 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
 		goto chdir;
 	}
 
-	ret = SMB_VFS_STAT(conn, smb_fname_cwd);
+	ret = vfs_posix_stat_noatime(conn, NULL, smb_fname_cwd, false);
 	if (ret == -1) {
 		status = map_nt_error_from_unix(errno);
 		DEBUG(0,("change_dir_owner_to_parent: failed to stat "
-- 
2.7.4


From 75bea4526406574cf44de0fd07fd9ace9808bc41 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Oct 2016 18:20:42 +0200
Subject: [PATCH 16/28] s3/smbd: use vfs_posix_stat_noatime() in
 check_reduced_name_with_privilege()

---
 source3/smbd/vfs.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 7bec1c0..2d3d7ca 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -1067,7 +1067,7 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
 		goto err;
 	}
 
-	if (SMB_VFS_STAT(conn, &priv_paths->parent_name) != 0) {
+	if (vfs_posix_stat_noatime(conn, NULL, &priv_paths->parent_name, false) != 0) {
 		status = map_nt_error_from_unix(errno);
 		goto err;
 	}
@@ -1109,7 +1109,7 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
 		goto err;
 	}
 
-	if (SMB_VFS_LSTAT(conn, smb_fname_cwd) != 0) {
+	if (vfs_posix_stat_noatime(conn, NULL, smb_fname_cwd, true) != 0) {
 		status = map_nt_error_from_unix(errno);
 		goto err;
 	}
@@ -1166,7 +1166,7 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn,
 	/* Now ensure that the last component either doesn't
 	   exist, or is *NOT* a symlink. */
 
-	ret = SMB_VFS_LSTAT(conn, &priv_paths->file_name);
+	ret = vfs_posix_stat_noatime(conn, NULL, &priv_paths->file_name, true);
 	if (ret == -1) {
 		/* Errno must be ENOENT for this be ok. */
 		if (errno != ENOENT) {
-- 
2.7.4


From 07b753a705ff6d88c188fb4c0a4a6e342d805a98 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Oct 2016 18:21:25 +0200
Subject: [PATCH 17/28] s3/smbd: use vfs_posix_stat_noatime() in
 vfs_chown_fsp()

---
 source3/smbd/vfs.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c
index 2d3d7ca..56cb941 100644
--- a/source3/smbd/vfs.c
+++ b/source3/smbd/vfs.c
@@ -2075,7 +2075,8 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid)
 		}
 
 		/* Must use lstat here. */
-		ret = SMB_VFS_LSTAT(fsp->conn, local_smb_fname);
+		ret = vfs_posix_stat_noatime(fsp->conn, NULL,
+					     local_smb_fname, true);
 		if (ret == -1) {
 			status = map_nt_error_from_unix(errno);
 			goto out;
-- 
2.7.4


From c8f9e6c861bcccb5cc395f5c8ec0b18c56661bed Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 24 Oct 2016 12:19:07 +0200
Subject: [PATCH 18/28] s3/smbd: use vfs_posix_stat_noatime() in
 mark_file_modified()

---
 source3/smbd/fileio.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c
index ec6333e..2bf4d69 100644
--- a/source3/smbd/fileio.c
+++ b/source3/smbd/fileio.c
@@ -272,6 +272,7 @@ void trigger_write_time_update_immediate(struct files_struct *fsp)
 void mark_file_modified(files_struct *fsp)
 {
 	int dosmode;
+	int ret;
 
 	if (fsp->modified) {
 		return;
@@ -279,7 +280,8 @@ void mark_file_modified(files_struct *fsp)
 
 	fsp->modified = true;
 
-	if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) {
+	ret = vfs_posix_stat_noatime(fsp->conn, fsp, NULL, false);
+	if (ret != 0) {
 		return;
 	}
 	trigger_write_time_update(fsp);
-- 
2.7.4


From 9aa1aab5d36632ad1476fa211895c1e9e2ab1af6 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 24 Oct 2016 13:04:28 +0200
Subject: [PATCH 19/28] s3/smbd: use vfs_posix_stat() in
 smbd_smb2_setinfo_send()

---
 source3/smbd/smb2_setinfo.c | 34 +++++++++++++---------------------
 1 file changed, 13 insertions(+), 21 deletions(-)

diff --git a/source3/smbd/smb2_setinfo.c b/source3/smbd/smb2_setinfo.c
index db00ba0..bb13825 100644
--- a/source3/smbd/smb2_setinfo.c
+++ b/source3/smbd/smb2_setinfo.c
@@ -404,32 +404,24 @@ static struct tevent_req *smbd_smb2_setinfo_send(TALLOC_CTX *mem_ctx,
 		}
 
 		if (fsp->fh->fd == -1) {
+			int ret;
+			bool posix_level = INFO_LEVEL_IS_UNIX(file_info_level);
+
 			/*
 			 * This is actually a SETFILEINFO on a directory
 			 * handle (returned from an NT SMB). NT5.0 seems
 			 * to do this call. JRA.
 			 */
-			if (INFO_LEVEL_IS_UNIX(file_info_level)) {
-				/* Always do lstat for UNIX calls. */
-				if (SMB_VFS_LSTAT(conn, fsp->fsp_name)) {
-					DEBUG(3,("smbd_smb2_setinfo_send: "
-						 "SMB_VFS_LSTAT of %s failed "
-						 "(%s)\n", fsp_str_dbg(fsp),
-						 strerror(errno)));
-					status = map_nt_error_from_unix(errno);
-					tevent_req_nterror(req, status);
-					return tevent_req_post(req, ev);
-				}
-			} else {
-				if (SMB_VFS_STAT(conn, fsp->fsp_name) != 0) {
-					DEBUG(3,("smbd_smb2_setinfo_send: "
-						 "fileinfo of %s failed (%s)\n",
-						 fsp_str_dbg(fsp),
-						 strerror(errno)));
-					status = map_nt_error_from_unix(errno);
-					tevent_req_nterror(req, status);
-					return tevent_req_post(req, ev);
-				}
+			ret = vfs_posix_stat(conn, NULL, fsp->fsp_name,
+					     posix_level);
+			if (ret != 0) {
+				DEBUG(3,("smbd_smb2_setinfo_send: "
+					 "fileinfo of %s failed "
+					 "(%s)\n", fsp_str_dbg(fsp),
+					 strerror(errno)));
+				status = map_nt_error_from_unix(errno);
+				tevent_req_nterror(req, status);
+				return tevent_req_post(req, ev);
 			}
 		} else if (fsp->print_file) {
 			/*
-- 
2.7.4


From 5ead9dc7a122fd6f70df0d7ff156f499cbb1c302 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 24 Oct 2016 13:41:01 +0200
Subject: [PATCH 20/28] s3/smbd: use vfs_posix_stat_noatime() in
 update_write_time_on_close()

---
 source3/smbd/close.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/source3/smbd/close.c b/source3/smbd/close.c
index bc468c7..8dc5687 100644
--- a/source3/smbd/close.c
+++ b/source3/smbd/close.c
@@ -535,6 +535,7 @@ static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
 	struct smb_file_time ft;
 	NTSTATUS status;
 	struct share_mode_lock *lck = NULL;
+	int ret;
 
 	ZERO_STRUCT(ft);
 
@@ -547,9 +548,9 @@ static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
 	}
 
 	/* Ensure we have a valid stat struct for the source. */
-	status = vfs_stat_fsp(fsp);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
+	ret = vfs_posix_stat_noatime(fsp->conn, fsp, NULL, false);
+	if (ret != 0) {
+		return map_nt_error_from_unix(errno);
 	}
 
 	if (!VALID_STAT(fsp->fsp_name->st)) {
-- 
2.7.4


From 5a02fc3bc37820a0053452e701fc36c3e251c011 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Oct 2016 18:34:49 +0200
Subject: [PATCH 21/28] s3/smbd: use vfs_path_exists() in stat_cache_lookup()

---
 source3/smbd/statcache.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c
index 89a4a3d..2383129 100644
--- a/source3/smbd/statcache.c
+++ b/source3/smbd/statcache.c
@@ -262,9 +262,7 @@ bool stat_cache_lookup(connection_struct *conn,
 		 * need it when reconstructing the string.
 		 */
 
-		if (sizechanged) {
-			num_components++;
-		}
+		num_components++;
 
 		if ((*chk_name == '\0')
 		    || ISDOT(chk_name) || ISDOTDOT(chk_name)) {
@@ -287,10 +285,15 @@ bool stat_cache_lookup(connection_struct *conn,
 	ZERO_STRUCT(smb_fname);
 	smb_fname.base_name = translated_path;
 
-	if (posix_paths) {
-		ret = SMB_VFS_LSTAT(conn, &smb_fname);
-	} else {
+	/*
+	 * If we found the full original path in the cache, we must do
+	 * a full stat, otherwise for path components we can optimize
+	 * and only check for existence.
+	 */
+	if (num_components == 0) {
 		ret = SMB_VFS_STAT(conn, &smb_fname);
+	} else {
+		ret = vfs_path_exists(conn, &smb_fname, posix_paths);
 	}
 
 	if (ret != 0) {
-- 
2.7.4


From d4d9556c011204841fde938cb4973da9d48e4132 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Oct 2016 18:30:28 +0200
Subject: [PATCH 22/28] s3/smbd: use vfs_path_exists() in check_parent_exists()

---
 source3/smbd/filename.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index a8cfb55..582b53a 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -175,11 +175,7 @@ static NTSTATUS check_parent_exists(TALLOC_CTX *ctx,
 		return NT_STATUS_OK;
 	}
 
-	if (posix_pathnames) {
-		ret = SMB_VFS_LSTAT(conn, &parent_fname);
-	} else {
-		ret = SMB_VFS_STAT(conn, &parent_fname);
-	}
+	ret = vfs_path_exists(conn, &parent_fname, posix_pathnames);
 
 	/* If the parent stat failed, just continue
 	   with the normal tree walk. */
-- 
2.7.4


From ec50c06a4871addc66dd1d26d0366231a62c27dd Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Oct 2016 18:31:10 +0200
Subject: [PATCH 23/28] s3/smbd: use vfs_path_exists() in unix_convert()

---
 source3/smbd/filename.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 582b53a..6a8db49 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -573,11 +573,9 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 					status = NT_STATUS_NO_MEMORY;
 					goto fail;
 				}
-				if (posix_pathnames) {
-					ret = SMB_VFS_LSTAT(conn, &parent_fname);
-				} else {
-					ret = SMB_VFS_STAT(conn, &parent_fname);
-				}
+
+				ret = vfs_path_exists(conn, &parent_fname,
+						      posix_pathnames);
 				if (ret == -1) {
 					if (errno == ENOTDIR ||
 							errno == ENOENT ||
-- 
2.7.4


From a543c136550f519d72a19f56bc4b0cdac216b1d5 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 7 Nov 2016 23:01:35 +0100
Subject: [PATCH 24/28] s3/smbd: use SMB_VFS_STATX() in unix_convert()

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/filename.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 6a8db49..1dfa61a 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -635,6 +635,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 	 */
 
 	for (; start ; start = (end?end+1:(char *)NULL)) {
+		unsigned int mask;
 		/*
 		 * Pinpoint the end of this section of the filename.
 		 */
@@ -696,12 +697,24 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 		 * Check if the name exists up to this point.
 		 */
 
-		if (posix_pathnames) {
-			ret = SMB_VFS_LSTAT(conn, smb_fname);
+		if (end) {
+			/*
+			 * For intermediate path components just check
+			 * for existence and type
+			 */
+			mask = STATX_NLINK | STATX_MODE;
 		} else {
-			ret = SMB_VFS_STAT(conn, smb_fname);
+			/*
+			 * For the last path compoment we need all
+			 * attributes as this is what ends up in smb_fname.st.
+			 */
+			mask = STATX_BASIC_STATS | STATX_BTIME;
 		}
 
+		ret = SMB_VFS_STATX(conn, NULL, smb_fname,
+				    posix_pathnames ? AT_SYMLINK_NOFOLLOW : 0,
+				    mask);
+
 		if (ret == 0) {
 			/*
 			 * It exists. it must either be a directory or this must
-- 
2.7.4


From b6fe5d8d4af8dfaca6348f542855de1b9392ea96 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 14 Nov 2016 12:30:00 +0100
Subject: [PATCH 25/28] s3/includes: add st_ex_win_attrs to struct stat_ex

Unused for now, will be used in subsequent commits in the new statx VFS
function to store the Windows attributes. dos_mode() will then merely be
a wrapper "return st->st_ex_win_attrs".

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/include/includes.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/source3/include/includes.h b/source3/include/includes.h
index f97a604..cf692bd 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -307,6 +307,7 @@ struct stat_ex {
 	blksize_t	st_ex_blksize;
 	blkcnt_t	st_ex_blocks;
 	uint32_t	st_ex_information;
+	uint32_t	st_ex_win_attrs;
 
 	uint32_t	st_ex_flags;
 	uint32_t	st_ex_mask;
-- 
2.7.4


From d615bf02751d7a2bb516c7a325cad1f4c2571d56 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 14 Nov 2016 12:46:48 +0100
Subject: [PATCH 26/28] s3/vfs_default: add support for STATX_WIN_ATTRS in the
 default VFS statx

---
 source3/modules/vfs_default.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 0aad32c..1f6cf9d 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -1208,6 +1208,13 @@ static int vfswrap_statx(vfs_handle_struct *handle,
 
 	fname->st.st_ex_mask = 0;
 
+	if (mask & STATX_WIN_ATTRS) {
+		/*
+		 * dos_mode() needs a valid st_mode
+		 */
+		mask |= STATX_BASIC_STATS;
+	}
+
 	if ((mask & (STATX_BASIC_STATS | STATX_BTIME)) != 0) {
 		/*
 		 * Only stat if any of the attributes support by our
@@ -1236,10 +1243,10 @@ static int vfswrap_statx(vfs_handle_struct *handle,
 		}
 	}
 
-	/*
-	 * In the future we may fetch stuff like dos attributes
-	 * below ...
-	 */
+	if (mask & STATX_WIN_ATTRS) {
+		fname->st.st_ex_win_attrs = dos_mode(handle->conn, fname);
+		fname->st.st_ex_mask |= STATX_WIN_ATTRS;
+	}
 
 	return 0;
 }
-- 
2.7.4


From 07788469fecebb37d83beaaca6e36f257d6d733f Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 14 Nov 2016 13:32:44 +0100
Subject: [PATCH 27/28] s3/smbd: modify all callers of dos_mode() to use struct
 stat_ex::st_ex_win_attrs

---
 source3/modules/vfs_tsmsm.c | 18 ++----------------
 source3/smbd/dir.c          |  2 +-
 source3/smbd/dosmode.c      | 13 +++----------
 source3/smbd/fileio.c       |  7 +++----
 source3/smbd/nttrans.c      |  6 +++---
 source3/smbd/open.c         |  4 +---
 source3/smbd/reply.c        | 22 ++++++++++++----------
 source3/smbd/smb2_close.c   |  2 +-
 source3/smbd/smb2_create.c  |  3 +--
 source3/smbd/trans2.c       | 10 +++++-----
 10 files changed, 32 insertions(+), 55 deletions(-)

diff --git a/source3/modules/vfs_tsmsm.c b/source3/modules/vfs_tsmsm.c
index eba19ff..97ef974 100644
--- a/source3/modules/vfs_tsmsm.c
+++ b/source3/modules/vfs_tsmsm.c
@@ -536,24 +536,13 @@ static NTSTATUS tsmsm_set_dos_attributes(struct vfs_handle_struct *handle,
 					 uint32_t dosmode)
 {
 	NTSTATUS status;
-	uint32_t old_dosmode;
-	struct smb_filename *fname = NULL;
-
-	/* dos_mode() doesn't like const smb_fname */
-	fname = cp_smb_filename(talloc_tos(), smb_fname);
-	if (fname == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	old_dosmode = dos_mode(handle->conn, fname);
-	TALLOC_FREE(fname);
 
 	status = SMB_VFS_NEXT_SET_DOS_ATTRIBUTES(handle, smb_fname, dosmode);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
 
-	if (!(old_dosmode & FILE_ATTRIBUTE_OFFLINE) &&
+	if (!(smb_fname->st.st_ex_win_attrs & FILE_ATTRIBUTE_OFFLINE) &&
 	    (dosmode & FILE_ATTRIBUTE_OFFLINE))
 	{
 		return NT_STATUS_OK;
@@ -567,16 +556,13 @@ static NTSTATUS tsmsm_fset_dos_attributes(struct vfs_handle_struct *handle,
 					  uint32_t dosmode)
 {
 	NTSTATUS status;
-	uint32_t old_dosmode;
-
-	old_dosmode = dos_mode(handle->conn, fsp->fsp_name);
 
 	status = SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle, fsp, dosmode);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
 
-	if (!(old_dosmode & FILE_ATTRIBUTE_OFFLINE) &&
+	if (!(fsp->fsp_name->st.st_ex_win_attrs & FILE_ATTRIBUTE_OFFLINE) &&
 	    (dosmode & FILE_ATTRIBUTE_OFFLINE))
 	{
 		return NT_STATUS_OK;
diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
index 3c6f000..1b95a03 100644
--- a/source3/smbd/dir.c
+++ b/source3/smbd/dir.c
@@ -1327,7 +1327,7 @@ static bool smbd_dirptr_8_3_mode_fn(TALLOC_CTX *ctx,
 		}
 	}
 
-	*_mode = dos_mode(conn, smb_fname);
+	*_mode = smb_fname->st.st_ex_win_attrs;
 	return true;
 }
 
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index dab47c0..dbc3721 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -878,12 +878,7 @@ NTSTATUS file_set_sparse(connection_struct *conn,
 		return NT_STATUS_INVALID_DEVICE_REQUEST;
 	}
 
-	status = vfs_stat_fsp(fsp);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
-
-	old_dosmode = dos_mode(conn, fsp->fsp_name);
+	old_dosmode = fsp->fsp_name->st.st_ex_win_attrs;
 
 	if (sparse && !(old_dosmode & FILE_ATTRIBUTE_SPARSE)) {
 		new_dosmode = old_dosmode | FILE_ATTRIBUTE_SPARSE;
@@ -1013,7 +1008,6 @@ NTSTATUS set_create_timespec_ea(connection_struct *conn,
 				struct timespec create_time)
 {
 	struct smb_filename *smb_fname;
-	uint32_t dosmode;
 	int ret;
 
 	if (!lp_store_dos_attributes(SNUM(conn))) {
@@ -1030,11 +1024,10 @@ NTSTATUS set_create_timespec_ea(connection_struct *conn,
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	dosmode = dos_mode(conn, smb_fname);
-
 	smb_fname->st.st_ex_btime = create_time;
 
-	ret = file_set_dosmode(conn, smb_fname, dosmode, NULL, false);
+	ret = file_set_dosmode(conn, smb_fname, smb_fname->st.st_ex_win_attrs,
+			       NULL, false);
 	if (ret == -1) {
 		return map_nt_error_from_unix(errno);
 	}
diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c
index 2bf4d69..dd3bfb6 100644
--- a/source3/smbd/fileio.c
+++ b/source3/smbd/fileio.c
@@ -271,7 +271,6 @@ void trigger_write_time_update_immediate(struct files_struct *fsp)
 
 void mark_file_modified(files_struct *fsp)
 {
-	int dosmode;
 	int ret;
 
 	if (fsp->modified) {
@@ -294,12 +293,12 @@ void mark_file_modified(files_struct *fsp)
 		return;
 	}
 
-	dosmode = dos_mode(fsp->conn, fsp->fsp_name);
-	if (IS_DOS_ARCHIVE(dosmode)) {
+	if (IS_DOS_ARCHIVE(fsp->fsp_name->st.st_ex_win_attrs)) {
 		return;
 	}
 	file_set_dosmode(fsp->conn, fsp->fsp_name,
-			 dosmode | FILE_ATTRIBUTE_ARCHIVE, NULL, false);
+			 fsp->fsp_name->st.st_ex_win_attrs | FILE_ATTRIBUTE_ARCHIVE,
+			 NULL, false);
 }
 
 /****************************************************************************
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 5f122a9..9433bbd 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -654,7 +654,7 @@ void reply_ntcreate_and_X(struct smb_request *req)
 	}
 	p += 4;
 
-	fattr = dos_mode(conn, smb_fname);
+	fattr = smb_fname->st.st_ex_win_attrs;
 	if (fattr == 0) {
 		fattr = FILE_ATTRIBUTE_NORMAL;
 	}
@@ -1300,7 +1300,7 @@ static void call_nt_transact_create(connection_struct *conn,
 	}
 	p += 8;
 
-	fattr = dos_mode(conn, smb_fname);
+	fattr = smb_fname->st.st_ex_win_attrs;
 	if (fattr == 0) {
 		fattr = FILE_ATTRIBUTE_NORMAL;
 	}
@@ -1434,7 +1434,7 @@ static NTSTATUS copy_internals(TALLOC_CTX *ctx,
 	}
 
 	/* Ensure attributes match. */
-	fattr = dos_mode(conn, smb_fname_src);
+	fattr = smb_fname_src->st.st_ex_win_attrs;
 	if ((fattr & ~attrs) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
 		status = NT_STATUS_NO_SUCH_FILE;
 		goto out;
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 17740be..e6a1103 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -338,12 +338,10 @@ static NTSTATUS check_base_file_access(struct connection_struct *conn,
 	}
 
 	if (access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) {
-		uint32_t dosattrs;
 		if (!CAN_WRITE(conn)) {
 			return NT_STATUS_ACCESS_DENIED;
 		}
-		dosattrs = dos_mode(conn, smb_fname);
-		if (IS_DOS_READONLY(dosattrs)) {
+		if (IS_DOS_READONLY(smb_fname->st.st_ex_win_attrs)) {
 			return NT_STATUS_ACCESS_DENIED;
 		}
 	}
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 0aec433..0d601c7 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -1418,7 +1418,7 @@ void reply_getatr(struct smb_request *req)
 			goto out;
 		}
 
-		mode = dos_mode(conn, smb_fname);
+		mode = smb_fname->st.st_ex_win_attrs;
 		size = smb_fname->st.st_ex_size;
 
 		if (ask_sharemode) {
@@ -2194,7 +2194,7 @@ void reply_open(struct smb_request *req)
 	smb_fname = fsp->fsp_name;
 
 	size = smb_fname->st.st_ex_size;
-	fattr = dos_mode(conn, smb_fname);
+	fattr = smb_fname->st.st_ex_win_attrs;
 
 	mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
 
@@ -2385,7 +2385,7 @@ void reply_open_and_X(struct smb_request *req)
 		}
 	}
 
-	fattr = dos_mode(conn, fsp->fsp_name);
+	fattr = fsp->fsp_name->st.st_ex_win_attrs;
 	mtime = convert_timespec_to_time_t(fsp->fsp_name->st.st_ex_mtime);
 	if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
 		close_file(req, fsp, ERROR_CLOSE);
@@ -2816,8 +2816,9 @@ static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
 			(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
 		/* Only bother to read the DOS attribute if we might deny the
 		   rename on the grounds of attribute mismatch. */
-		uint32_t fmode = dos_mode(conn, fsp->fsp_name);
-		if ((fmode & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) {
+		if ((fsp->fsp_name->st.st_ex_win_attrs & ~dirtype) &
+		    (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM))
+		{
 			return NT_STATUS_NO_SUCH_FILE;
 		}
 	}
@@ -2886,7 +2887,7 @@ static NTSTATUS do_unlink(connection_struct *conn,
 		return map_nt_error_from_unix(errno);
 	}
 
-	fattr = dos_mode(conn, smb_fname);
+	fattr = smb_fname->st.st_ex_win_attrs;
 
 	if (dirtype & FILE_ATTRIBUTE_NORMAL) {
 		dirtype = FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY;
@@ -6837,8 +6838,9 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
 			/* We must set the archive bit on the newly
 			   renamed file. */
 			if (SMB_VFS_STAT(conn, smb_fname_dst) == 0) {
-				uint32_t old_dosmode = dos_mode(conn,
-							smb_fname_dst);
+				uint32_t old_dosmode =
+					smb_fname_dst->st.st_ex_win_attrs;
+
 				file_set_dosmode(conn,
 					smb_fname_dst,
 					old_dosmode | FILE_ATTRIBUTE_ARCHIVE,
@@ -7486,7 +7488,7 @@ NTSTATUS copy_file(TALLOC_CTX *ctx,
 		goto out;
 	}
 
-	dosattrs = dos_mode(conn, smb_fname_src);
+	dosattrs = smb_fname_src->st.st_ex_win_attrs;
 
 	if (SMB_VFS_STAT(conn, smb_fname_dst_tmp) == -1) {
 		ZERO_STRUCTP(&smb_fname_dst_tmp->st);
@@ -8615,7 +8617,7 @@ void reply_getattrE(struct smb_request *req)
 		return;
 	}
 
-	mode = dos_mode(conn, fsp->fsp_name);
+	mode = fsp->fsp_name->st.st_ex_win_attrs;
 
 	/*
 	 * Convert the times into dos times. Set create
diff --git a/source3/smbd/smb2_close.c b/source3/smbd/smb2_close.c
index 5830228..220f130 100644
--- a/source3/smbd/smb2_close.c
+++ b/source3/smbd/smb2_close.c
@@ -172,7 +172,7 @@ static void setup_close_full_information(connection_struct *conn,
 	}
 
 	*out_flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
-	*out_file_attributes = dos_mode(conn, smb_fname);
+	*out_file_attributes = smb_fname->st.st_ex_win_attrs;
 	*out_last_write_ts = smb_fname->st.st_ex_mtime;
 	*out_last_access_ts = smb_fname->st.st_ex_atime;
 	*out_creation_ts = get_create_timespec(conn, NULL, smb_fname);
diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 8211991..1290596 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -1364,8 +1364,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		state->out_create_action = info;
 	}
 	result->op->create_action = state->out_create_action;
-	state->out_file_attributes = dos_mode(result->conn,
-					   result->fsp_name);
+	state->out_file_attributes = result->fsp_name->st.st_ex_win_attrs;
 
 	state->out_creation_ts = get_create_timespec(smb1req->conn,
 					result, result->fsp_name);
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 6999b2d..32f1a70 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -1364,7 +1364,7 @@ static void call_trans2open(connection_struct *conn,
 	}
 
 	size = get_file_size_stat(&smb_fname->st);
-	fattr = dos_mode(conn, smb_fname);
+	fattr = smb_fname->st.st_ex_win_attrs;
 	mtime = convert_timespec_to_time_t(smb_fname->st.st_ex_mtime);
 	inode = smb_fname->st.st_ex_ino;
 	if (fattr & FILE_ATTRIBUTE_DIRECTORY) {
@@ -1712,7 +1712,7 @@ static bool smbd_dirptr_lanman2_mode_fn(TALLOC_CTX *ctx,
 	if (ms_dfs_link) {
 		mode = dos_mode_msdfs(state->conn, smb_fname);
 	} else {
-		mode = dos_mode(state->conn, smb_fname);
+		mode = smb_fname->st.st_ex_win_attrs;
 	}
 
 	*_mode = mode;
@@ -4831,7 +4831,7 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn,
 		 fsp_fnum_dbg(fsp),
 		 info_level, max_data_bytes));
 
-	mode = dos_mode(conn, smb_fname);
+	mode = smb_fname->st.st_ex_win_attrs;
 	nlink = psbuf->st_ex_nlink;
 
 	if (nlink && (mode&FILE_ATTRIBUTE_DIRECTORY)) {
@@ -6249,7 +6249,7 @@ static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
 	DEBUG(6,("smb_set_file_dosmode: dosmode: 0x%x\n", (unsigned int)dosmode));
 
 	/* check the mode isn't different, before changing it */
-	if ((dosmode != 0) && (dosmode != dos_mode(conn, smb_fname_base))) {
+	if ((dosmode != 0) && (dosmode != smb_fname_base->st.st_ex_win_attrs)) {
 		DEBUG(10,("smb_set_file_dosmode: file %s : setting dos mode "
 			  "0x%x\n", smb_fname_str_dbg(smb_fname_base),
 			  (unsigned int)dosmode));
@@ -6479,7 +6479,7 @@ static NTSTATUS smb_set_file_disposition_info(connection_struct *conn,
 	}
 
 	delete_on_close = (CVAL(pdata,0) ? True : False);
-	dosmode = dos_mode(conn, smb_fname);
+	dosmode = smb_fname->st.st_ex_win_attrs;
 
 	DEBUG(10,("smb_set_file_disposition_info: file %s, dosmode = %u, "
 		"delete_on_close = %u\n",
-- 
2.7.4


From 787753720e158a90be72d61e953d96da767df9ca Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 14 Nov 2016 17:59:06 +0100
Subject: [PATCH 28/28] WIP

---
 source3/lib/system.c          |  4 ++++
 source3/modules/vfs_default.c | 10 +++++-----
 source3/smbd/filename.c       |  2 +-
 source3/smbd/statcache.c      |  5 ++++-
 4 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/source3/lib/system.c b/source3/lib/system.c
index 811803e..5100a03 100644
--- a/source3/lib/system.c
+++ b/source3/lib/system.c
@@ -286,6 +286,10 @@ static struct timespec calc_create_time_stat_ex(const struct stat_ex *st)
 static void make_create_timespec(const struct stat *pst, struct stat_ex *dst,
 				 bool fake_dir_create_times)
 {
+	if (dst->st_ex_mask & STATX_BTIME) {
+		return;
+	}
+
 	if (S_ISDIR(pst->st_mode) && fake_dir_create_times) {
 		dst->st_ex_btime.tv_sec = 315493200L;          /* 1/1/1980 */
 		dst->st_ex_btime.tv_nsec = 0;
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 1f6cf9d..5643b0d 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -1206,16 +1206,16 @@ static int vfswrap_statx(vfs_handle_struct *handle,
 		fname = smb_fname;
 	}
 
-	fname->st.st_ex_mask = 0;
+	DBG_ERR("[%s]\n", smb_fname_str_dbg(fname));
 
-	if (mask & STATX_WIN_ATTRS) {
+	if (mask & (STATX_WIN_ATTRS | STATX_BTIME)) {
 		/*
 		 * dos_mode() needs a valid st_mode
 		 */
 		mask |= STATX_BASIC_STATS;
 	}
 
-	if ((mask & (STATX_BASIC_STATS | STATX_BTIME)) != 0) {
+	if (mask & STATX_BASIC_STATS) {
 		/*
 		 * Only stat if any of the attributes support by our
 		 * VFS stat funcs are requested.
@@ -1243,9 +1243,9 @@ static int vfswrap_statx(vfs_handle_struct *handle,
 		}
 	}
 
-	if (mask & STATX_WIN_ATTRS) {
+	if (mask & (STATX_WIN_ATTRS | STATX_BTIME)) {
 		fname->st.st_ex_win_attrs = dos_mode(handle->conn, fname);
-		fname->st.st_ex_mask |= STATX_WIN_ATTRS;
+		fname->st.st_ex_mask |= STATX_WIN_ATTRS | STATX_BTIME;
 	}
 
 	return 0;
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 1dfa61a..8f9455e 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -708,7 +708,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 			 * For the last path compoment we need all
 			 * attributes as this is what ends up in smb_fname.st.
 			 */
-			mask = STATX_BASIC_STATS | STATX_BTIME;
+			mask = STATX_BASIC_STATS | STATX_BTIME | STATX_WIN_ATTRS;
 		}
 
 		ret = SMB_VFS_STATX(conn, NULL, smb_fname,
diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c
index 2383129..1da9e00 100644
--- a/source3/smbd/statcache.c
+++ b/source3/smbd/statcache.c
@@ -21,6 +21,7 @@
 */
 
 #include "includes.h"
+#include "system/filesys.h"
 #include "../lib/util/memcache.h"
 #include "smbd/smbd.h"
 #include "messages.h"
@@ -291,7 +292,9 @@ bool stat_cache_lookup(connection_struct *conn,
 	 * and only check for existence.
 	 */
 	if (num_components == 0) {
-		ret = SMB_VFS_STAT(conn, &smb_fname);
+		ret = SMB_VFS_STATX(conn, NULL, &smb_fname,
+				    posix_paths ? AT_SYMLINK_NOFOLLOW : 0,
+				    STATX_BASIC_STATS | STATX_BTIME | STATX_WIN_ATTRS);
 	} else {
 		ret = vfs_path_exists(conn, &smb_fname, posix_paths);
 	}
-- 
2.7.4



More information about the samba-technical mailing list