[SCM] Samba Shared Repository - branch v4-14-test updated

Karolin Seeger kseeger at samba.org
Tue Aug 17 10:08:01 UTC 2021


The branch, v4-14-test has been updated
       via  3228383d8ae vfs_shadow_copy2: ensure we call convert_sbuf() in shadow_copy2_*stat() on already converted paths with absolute path
       via  8222ff1110c vfs_streams_xattr: ensure fstat calls NEXT fstat
       via  262d09c511a selftest: add a test for shadow:fixinodes
       via  9d6d585ca00 selftest: simplify snapshot directory creation in test_shadow_copy_torture.sh
       via  5ae4300a36b selftest: enable "shadow:fixinodes" in "shadow_write" share
       via  a2ac4ee3d71 selftest: pass smbclient arg to samba3.blackbox.shadow_copy_torture test
       via  93383852f0d smbd: update smb_fname statinfo from fsp
       via  e12c92d0175 smbd: canonicalize SMB_VFS_FSTAT() stat buffer
       via  46995a8b146 smbd: return correct timestamps for quota fake file
       via  b53968656ee smbd: handle fake file handles in fdos_mode()
       via  7e1d4a4b138 smbd: add dosmode_from_fake_filehandle()
       via  8abd1abca64 smbtorture: verify attributes on fake quota file handle
      from  618fd6c2594 s3: smbd: For FSCTL calls that go async, add the outstanding tevent_reqs to the aio list on the file handle.

https://git.samba.org/?p=samba.git;a=shortlog;h=v4-14-test


- Log -----------------------------------------------------------------
commit 3228383d8ae56d53dd8d726eec8e81353b988624
Author: Ralph Boehme <slow at samba.org>
Date:   Sat Jul 3 15:46:11 2021 +0200

    vfs_shadow_copy2: ensure we call convert_sbuf() in shadow_copy2_*stat() on already converted paths with absolute path
    
    shadow_copy2_strip_snapshot() will happily return without modifying the passed
    timestamp=0 if the path is already converted and refers to an object in a
    snapshot, eg (first debug line from extra debugging patch [1]):
    
    [10 2021/07/02 08:19:28.811424 pid=738290 ../../source3/modules/vfs_shadow_copy2.c:1303 shadow_copy2_fstat]
      shadow_copy2_fstat: fsp [test.txt {@GMT-2000.01.02-03.04.05}]
    [10 2021/07/02 08:19:28.811449 pid=738290 ../../source3/modules/vfs_shadow_copy2.c:607 _shadow_copy2_strip_snapshot_internal]
      _shadow_copy2_strip_snapshot_internal: [from shadow_copy2_fstat()] Path 'test.txt {@GMT-2000.01.02-03.04.05}'
    [10 2021/07/02 08:19:28.811474 pid=738290 ../../source3/modules/vfs_shadow_copy2.c:619 _shadow_copy2_strip_snapshot_internal]
      _shadow_copy2_strip_snapshot_internal: abs path '/gpfs0/smb_snapshots2/filesetone/.snapshots/@GMT-2000.01.02-03.04.05/test.txt'
    [10 2021/07/02 08:19:28.811496 pid=738290 ../../source3/modules/vfs_shadow_copy2.c:1924 shadow_copy2_snapshot_to_gmt]
      shadow_copy2_snapshot_to_gmt: match @GMT-%Y.%m.%d-%H.%M.%S: @GMT-2000.01.02-03.04.05
    [10 2021/07/02 08:19:28.811536 pid=738290 ../../source3/modules/vfs_shadow_copy2.c:566 check_for_converted_path]
      check_for_converted_path: path |/gpfs0/smb_snapshots2/filesetone/.snapshots/@GMT-2000.01.02-03.04.05/test.txt| is already converted. connect path = |/gpfs0/smb_snapshots2/filesetone/.snapshots/@GMT-2000.01.02-03.04.05|
    
    As check_for_converted_path() detects an "already converted path",
    _shadow_copy2_strip_snapshot_internal() just returns without modifying the value
    of the timestamp.
    
    By using shadow_copy2_strip_snapshot_converted() instead of
    shadow_copy2_strip_snapshot() we can check if the path is in fact referring to a
    VSS object by checking the "converted" bool.
    
    An alternative way would have been directly checking fsp->fsp_name->twrp != 0,
    but that would be a new semantic in the module, I'll leave this excersize for
    the future when we clean up the usage of shadow_copy2_strip_snapshot() in the
    whole module.
    
    This change also switches to using the absolute paths in both place where
    convert_sbuf() is called.
    
    [1]
    @@ -1309,8 +1348,16 @@ static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
                    saved_errno = errno;
            }
    
    +       DBG_DEBUG("fsp [%s]\n", fsp_str_dbg(fsp));
    
    RN: vfs_shadow_copy2 fixinodes not correctly updating inode numbers
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14756
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit c7d6745858f2efdd24ed6fd353ec5ece898033fa)
    
    Autobuild-User(v4-14-test): Karolin Seeger <kseeger at samba.org>
    Autobuild-Date(v4-14-test): Tue Aug 17 10:07:42 UTC 2021 on sn-devel-184

commit 8222ff1110c3ff506e3153b3294f2979206cdbfd
Author: Ralph Boehme <slow at samba.org>
Date:   Wed Jul 28 17:16:27 2021 +0200

    vfs_streams_xattr: ensure fstat calls NEXT fstat
    
    This ensures fstat behaves the same as stat by calling the NEXT VFS stat
    function. This is required for matching path and handle based inode
    numbers.
    
    This bug is currently only exposed in a special case: a VSS snapshot of a
    stream.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14756
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 262d09c511a66562f397af099cfdef588813d1ab
Author: Ralph Boehme <slow at samba.org>
Date:   Tue Jul 6 07:24:00 2021 +0200

    selftest: add a test for shadow:fixinodes
    
    This will fail with
    
      Failed to open file \@GMT-2015.10.31-19.40.30\subdir\hardlink. NT_STATUS_ACCESS_DENIED
    
    The open is failing in openat_pathref_fsp():
    
      [2021/07/06 04:58:17.677104, 10, pid=95070, effective(1000, 1000), real(1000, 0)] ../../source3/smbd/files.c:541(openat_pathref_fsp)
        openat_pathref_fsp: file [subdir/hardlink {@GMT-2015.10.31-19.40.30}] - dev/ino mismatch. Old (dev=64770, ino=3826943444). New (dev=64770, ino=1746568660).
      [2021/07/06 04:58:17.677114, 10, pid=95070, effective(1000, 1000), real(1000, 0)] ../../source3/smbd/files.c:568(openat_pathref_fsp)
        openat_pathref_fsp: Opening pathref for [subdir/hardlink {@GMT-2015.10.31-19.40.30}] failed: NT_STATUS_ACCESS_DENIED
    
    The reason is subtle:
    
    shadow_copy2 calculates inode numbers of snapshot files based on the path of the
    file. The result of that when doing a path based stat() from filename_convert()
    was
    
      [2021/07/06 04:58:17.676159, 10, pid=95070, effective(1000, 1000), real(1000, 0)] ../../source3/smbd/filename.c:1945(filename_convert_internal)
        filename_convert_internal: XXX smb_fname [subdir/hardlink {@GMT-2015.10.31-19.40.30}] (dev=64770, ino=3826943444).
    
    which is the "Old" inode shown above.
    
    Later in the open code called from openat_pathref_fsp() -> fd_openat() ->
    non_widelink_open() since 4.14 we call SMB_VFS_FSTAT() where fsp->fsp_name will
    be set to the new relative *basename* of the file:
    
      [2021/07/06 04:58:17.676917, 10, pid=95070, effective(1000, 1000), real(1000, 0), class=vfs] ../../source3/modules/vfs_default.c:1302(vfswrap_fstat)
        vfswrap_fstat: XXX fsp [hardlink {@GMT-2015.10.31-19.40.30}] (dev=64770, ino=3826943444)
    
    So for stat() the hash function in called with the full path relative to the share
    root:
    
      subdir/hardlink
    
    while for fstat() the hash function will used
    
      hardlink
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14756
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit 4a7e483c516cf2b9767919a764f05c43f4620cd7)

commit 9d6d585ca00f7d001932fab8fc16b6a72ec3ec89
Author: Ralph Boehme <slow at samba.org>
Date:   Tue Jul 6 07:22:40 2021 +0200

    selftest: simplify snapshot directory creation in test_shadow_copy_torture.sh
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14756
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit 3aabc9825ca108641c2becf322fa0bd90ea18424)

commit 5ae4300a36b63de302af174a8fc6bd29dbecac82
Author: Ralph Boehme <slow at samba.org>
Date:   Tue Jul 6 07:20:15 2021 +0200

    selftest: enable "shadow:fixinodes" in "shadow_write" share
    
    The existing tests don't care and this will be used in a subsequent commit to
    demonstrate that this option is currently broken.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14756
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit 0a0b438b8ab534eeb552a58ad72a714988e84d89)

commit a2ac4ee3d71480b3fc15b6a2e6308bb467b14e6b
Author: Ralph Boehme <slow at samba.org>
Date:   Tue Jul 6 07:19:36 2021 +0200

    selftest: pass smbclient arg to samba3.blackbox.shadow_copy_torture test
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14756
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit 745ded9afe12fda6d45638097a32b01122748649)

commit 93383852f0dec537e2f9b062f113c6f5747a80b9
Author: Ralph Boehme <slow at samba.org>
Date:   Wed Jul 7 12:40:05 2021 +0200

    smbd: update smb_fname statinfo from fsp
    
    fd_openat() has done an FSTAT on the handle so update the smb_fname stat info
    with "truth".  from the handle.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14756
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit b32e56d6eb29bfb5f368602edbc10d4b8bc9b4f0)

commit e12c92d0175ea8a0057e9bc6b01ad65ce9153d84
Author: Ralph Boehme <slow at samba.org>
Date:   Tue Jul 6 09:04:26 2021 +0200

    smbd: canonicalize SMB_VFS_FSTAT() stat buffer
    
    This helps code inside any module implementing fstat() looking at
    fsp->fsp_name->st instead of the passed in stat buf.
    
    I only ran afoul of this in a DEBUG message I added while debugging some inode
    related problem.
    
    No change in behaviour.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14756
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit 18a30d939e6f7d49300f235385953412f9e971b9)

commit 46995a8b14675f30536a65ceeaf687fa7cbedd9e
Author: Ralph Boehme <slow at samba.org>
Date:   Mon Jun 7 19:02:56 2021 +0200

    smbd: return correct timestamps for quota fake file
    
    Prior to 572d4e3a56eef00e29f93482daa21647af7310d0 it was sufficient to
    initialize struct timespec to zero to return NTTIME 0 (ie not set) over
    SMB.
    
    This fixes the same problem from bug 14714 where the timestamps in an SMB2 CLOSE
    response.
    
    Windows of course does return *some* timestamps, but as it's neither documented
    nor was I able to figure out where they would be coming from, as well as the
    Windows client apparently doesn't care, I didn't bother with implementing some
    sophisticated heuristic to return some timestamps.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14731
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    
    Autobuild-User(master): Jeremy Allison <jra at samba.org>
    Autobuild-Date(master): Wed Jun  9 20:38:02 UTC 2021 on sn-devel-184
    
    (cherry picked from commit 52a421111218d94d2e5cb131648bcdf5411d910b)

commit b53968656eee6c57e281ee32bff1d4643b4292f0
Author: Ralph Boehme <slow at samba.org>
Date:   Fri Jun 4 15:54:20 2021 +0200

    smbd: handle fake file handles in fdos_mode()
    
    This ensures SMB requests on the quote fake file "$Extend/$Quota" don't hit the
    VFS, where specifically in vfs_gpfs we log an error message if we fail to read
    the DOS attributes for a file with
    
      vfs_gpfs_get_dos_attributes: Getting winattrs failed for $Extend/$Quota
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14731
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit e093eaed1046638193d973c39fa9df74e41148d3)

commit 7e1d4a4b1385b9bc75ce61531c8df77584bb9ead
Author: Ralph Boehme <slow at samba.org>
Date:   Fri Jun 4 16:31:20 2021 +0200

    smbd: add dosmode_from_fake_filehandle()
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14731
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit 51b0fd0c566ff6bf112ab9752d9b105a6bb786a8)

commit 8abd1abca64bd9034482498484310692a411b9dd
Author: Ralph Boehme <slow at samba.org>
Date:   Mon Jun 7 19:03:05 2021 +0200

    smbtorture: verify attributes on fake quota file handle
    
    The expected DOS attributes are taken from a Windows 2016 server. The expected
    timestamps are what Samba has returned before commit 572d4e3a56eef00e29f9348:
    NTTIME(0), ie no value.
    
    The upcoming fix will restore this behaviour. Windows of course does
    return *some* timestamps, but as it's neither documented nor was I able to
    figure out where they would be coming from, as well as the Windows client apparently
    doesn't care, I didn't bother with implementing some sophisticated heuristic to
    return some timestamps.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14731
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    (cherry picked from commit 1e338d51602a7dca6108e5e8704f5cdde4740713)

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

Summary of changes:
 selftest/knownfail                               |   1 +
 selftest/target/Samba3.pm                        |   1 +
 source3/include/fake_file.h                      |   1 +
 source3/modules/vfs_shadow_copy2.c               | 180 +++++++++++++++++------
 source3/modules/vfs_streams_xattr.c              |  27 +---
 source3/script/tests/test_shadow_copy_torture.sh |  32 +++-
 source3/selftest/tests.py                        |   2 +-
 source3/smbd/dosmode.c                           |   5 +
 source3/smbd/fake_file.c                         |  15 ++
 source3/smbd/filename.c                          |   5 +
 source3/smbd/files.c                             |   7 +
 source3/smbd/open.c                              |   4 +-
 source4/torture/smb2/create.c                    |  63 ++++++++
 13 files changed, 275 insertions(+), 68 deletions(-)


Changeset truncated at 500 lines:

diff --git a/selftest/knownfail b/selftest/knownfail
index 6c005d1f4de..ea72ea27620 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -144,6 +144,7 @@
 ^samba4.raw.acls.*.create_owner_file
 ^samba4.smb2.create.*.acldir
 ^samba4.smb2.create.*.impersonation
+^samba4.smb2.create.quota-fake-file\(ad_dc_ntvfs\) # not supported by the NTVFS
 ^samba4.smb2.acls.*.generic
 ^samba4.smb2.acls.*.inheritflags
 ^samba4.smb2.acls.*.owner
diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm
index b0910433940..4afcc47b82b 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -2810,6 +2810,7 @@ sub provision($$)
 	aio write size = 0
 	error_inject:pwrite = EBADF
 	shadow:mountpoint = $shadow_tstdir
+	shadow:fixinodes = yes
 
 [dfq]
 	path = $shrdir/dfree
diff --git a/source3/include/fake_file.h b/source3/include/fake_file.h
index 00ebc88f7a7..c267df25188 100644
--- a/source3/include/fake_file.h
+++ b/source3/include/fake_file.h
@@ -47,5 +47,6 @@ NTSTATUS open_fake_file(struct smb_request *req, connection_struct *conn,
 				uint32_t access_mask,
 				files_struct **result);
 NTSTATUS close_fake_file(struct smb_request *req, files_struct *fsp);
+uint32_t dosmode_from_fake_filehandle(const struct fake_file_handle *ffh);
 
 #endif /* _FAKE_FILE_H */
diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
index 227ac148260..e340382ff3c 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -1168,19 +1168,45 @@ static int shadow_copy2_linkat(vfs_handle_struct *handle,
 static int shadow_copy2_stat(vfs_handle_struct *handle,
 			     struct smb_filename *smb_fname)
 {
+	struct shadow_copy2_private *priv = NULL;
 	time_t timestamp = 0;
 	char *stripped = NULL;
+	bool converted = false;
+	char *abspath = NULL;
 	char *tmp;
-	int saved_errno = 0;
-	int ret;
+	int ret = 0;
 
-	if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
-					 smb_fname,
-					 &timestamp, &stripped)) {
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+				return -1);
+
+	if (!shadow_copy2_strip_snapshot_converted(talloc_tos(),
+						   handle,
+						   smb_fname,
+						   &timestamp,
+						   &stripped,
+						   &converted)) {
 		return -1;
 	}
 	if (timestamp == 0) {
-		return SMB_VFS_NEXT_STAT(handle, smb_fname);
+		TALLOC_FREE(stripped);
+		ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
+		if (ret != 0) {
+			return ret;
+		}
+		if (!converted) {
+			return 0;
+		}
+
+		abspath = make_path_absolute(talloc_tos(),
+					     priv,
+					     smb_fname->base_name);
+		if (abspath == NULL) {
+			return -1;
+		}
+
+		convert_sbuf(handle, abspath, &smb_fname->st);
+		TALLOC_FREE(abspath);
+		return 0;
 	}
 
 	tmp = smb_fname->base_name;
@@ -1194,38 +1220,70 @@ static int shadow_copy2_stat(vfs_handle_struct *handle,
 	}
 
 	ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
-	if (ret == -1) {
-		saved_errno = errno;
+	if (ret != 0) {
+		goto out;
 	}
 
+	abspath = make_path_absolute(talloc_tos(),
+				     priv,
+				     smb_fname->base_name);
+	if (abspath == NULL) {
+		ret = -1;
+		goto out;
+	}
+
+	convert_sbuf(handle, abspath, &smb_fname->st);
+	TALLOC_FREE(abspath);
+
+out:
 	TALLOC_FREE(smb_fname->base_name);
 	smb_fname->base_name = tmp;
 
-	if (ret == 0) {
-		convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
-	}
-	if (saved_errno != 0) {
-		errno = saved_errno;
-	}
 	return ret;
 }
 
 static int shadow_copy2_lstat(vfs_handle_struct *handle,
 			      struct smb_filename *smb_fname)
 {
+	struct shadow_copy2_private *priv = NULL;
 	time_t timestamp = 0;
 	char *stripped = NULL;
+	bool converted = false;
+	char *abspath = NULL;
 	char *tmp;
-	int saved_errno = 0;
-	int ret;
+	int ret = 0;
 
-	if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
-					 smb_fname,
-					 &timestamp, &stripped)) {
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+				return -1);
+
+	if (!shadow_copy2_strip_snapshot_converted(talloc_tos(),
+						   handle,
+						   smb_fname,
+						   &timestamp,
+						   &stripped,
+						   &converted)) {
 		return -1;
 	}
 	if (timestamp == 0) {
-		return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
+		TALLOC_FREE(stripped);
+		ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
+		if (ret != 0) {
+			return ret;
+		}
+		if (!converted) {
+			return 0;
+		}
+
+		abspath = make_path_absolute(talloc_tos(),
+					     priv,
+					     smb_fname->base_name);
+		if (abspath == NULL) {
+			return -1;
+		}
+
+		convert_sbuf(handle, abspath, &smb_fname->st);
+		TALLOC_FREE(abspath);
+		return 0;
 	}
 
 	tmp = smb_fname->base_name;
@@ -1239,45 +1297,76 @@ static int shadow_copy2_lstat(vfs_handle_struct *handle,
 	}
 
 	ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
-	if (ret == -1) {
-		saved_errno = errno;
+	if (ret != 0) {
+		goto out;
+	}
+
+	abspath = make_path_absolute(talloc_tos(),
+				     priv,
+				     smb_fname->base_name);
+	if (abspath == NULL) {
+		ret = -1;
+		goto out;
 	}
 
+	convert_sbuf(handle, abspath, &smb_fname->st);
+	TALLOC_FREE(abspath);
+
+out:
 	TALLOC_FREE(smb_fname->base_name);
 	smb_fname->base_name = tmp;
 
-	if (ret == 0) {
-		convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
-	}
-	if (saved_errno != 0) {
-		errno = saved_errno;
-	}
 	return ret;
 }
 
 static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
 			      SMB_STRUCT_STAT *sbuf)
 {
+	struct shadow_copy2_private *priv = NULL;
 	time_t timestamp = 0;
 	struct smb_filename *orig_smb_fname = NULL;
 	struct smb_filename vss_smb_fname;
 	struct smb_filename *orig_base_smb_fname = NULL;
 	struct smb_filename vss_base_smb_fname;
 	char *stripped = NULL;
-	int saved_errno = 0;
+	char *abspath = NULL;
+	bool converted = false;
 	bool ok;
 	int ret;
 
-	ok = shadow_copy2_strip_snapshot(talloc_tos(), handle,
-					 fsp->fsp_name,
-					 &timestamp, &stripped);
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+				return -1);
+
+	ok = shadow_copy2_strip_snapshot_converted(talloc_tos(),
+						   handle,
+						   fsp->fsp_name,
+						   &timestamp,
+						   &stripped,
+						   &converted);
 	if (!ok) {
 		return -1;
 	}
 
 	if (timestamp == 0) {
 		TALLOC_FREE(stripped);
-		return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+		ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+		if (ret != 0) {
+			return ret;
+		}
+		if (!converted) {
+			return 0;
+		}
+
+		abspath = make_path_absolute(talloc_tos(),
+					     priv,
+					     fsp->fsp_name->base_name);
+		if (abspath == NULL) {
+			return -1;
+		}
+
+		convert_sbuf(handle, abspath, sbuf);
+		TALLOC_FREE(abspath);
+		return 0;
 	}
 
 	vss_smb_fname = *fsp->fsp_name;
@@ -1301,20 +1390,27 @@ static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
 	}
 
 	ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+	if (ret != 0) {
+		goto out;
+	}
+
+	abspath = make_path_absolute(talloc_tos(),
+				     priv,
+				     fsp->fsp_name->base_name);
+	if (abspath == NULL) {
+		ret = -1;
+		goto out;
+	}
+
+	convert_sbuf(handle, abspath, sbuf);
+	TALLOC_FREE(abspath);
+
+out:
 	fsp->fsp_name = orig_smb_fname;
 	if (fsp->base_fsp != NULL) {
 		fsp->base_fsp->fsp_name = orig_base_smb_fname;
 	}
-	if (ret == -1) {
-		saved_errno = errno;
-	}
 
-	if (ret == 0) {
-		convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
-	}
-	if (saved_errno != 0) {
-		errno = saved_errno;
-	}
 	return ret;
 }
 
diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c
index 72032824b93..743cbd2e8b6 100644
--- a/source3/modules/vfs_streams_xattr.c
+++ b/source3/modules/vfs_streams_xattr.c
@@ -199,7 +199,6 @@ static int streams_xattr_stat_base(vfs_handle_struct *handle,
 static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
 			       SMB_STRUCT_STAT *sbuf)
 {
-	struct smb_filename *smb_fname_base = NULL;
 	int ret = -1;
 	struct stream_io *io = (struct stream_io *)
 		VFS_FETCH_FSP_EXTENSION(handle, fsp);
@@ -214,30 +213,19 @@ static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
 		return -1;
 	}
 
-	/* Create an smb_filename with stream_name == NULL. */
-	smb_fname_base = synthetic_smb_fname(talloc_tos(),
-					io->base,
-					NULL,
-					NULL,
-					fsp->fsp_name->twrp,
-					fsp->fsp_name->flags);
-	if (smb_fname_base == NULL) {
-		errno = ENOMEM;
-		return -1;
-	}
-
-	ret = vfs_stat(handle->conn, smb_fname_base);
-	*sbuf = smb_fname_base->st;
-
+	ret = streams_xattr_stat_base(
+		handle,
+		fsp->fsp_name,
+		fsp->fsp_name->flags & SMB_FILENAME_POSIX_PATH);
 	if (ret == -1) {
-		TALLOC_FREE(smb_fname_base);
 		return -1;
 	}
 
+	*sbuf = fsp->fsp_name->st;
+
 	sbuf->st_ex_size = get_xattr_size(handle->conn,
-					smb_fname_base, io->xattr_name);
+					  fsp->fsp_name, io->xattr_name);
 	if (sbuf->st_ex_size == -1) {
-		TALLOC_FREE(smb_fname_base);
 		SET_STAT_INVALID(*sbuf);
 		return -1;
 	}
@@ -250,7 +238,6 @@ static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
         sbuf->st_ex_mode |= S_IFREG;
         sbuf->st_ex_blocks = sbuf->st_ex_size / STAT_ST_BLOCKSIZE + 1;
 
-	TALLOC_FREE(smb_fname_base);
 	return 0;
 }
 
diff --git a/source3/script/tests/test_shadow_copy_torture.sh b/source3/script/tests/test_shadow_copy_torture.sh
index 240a0083506..1185ad5da11 100755
--- a/source3/script/tests/test_shadow_copy_torture.sh
+++ b/source3/script/tests/test_shadow_copy_torture.sh
@@ -5,7 +5,7 @@
 
 if [ $# -lt 7 ]; then
 cat <<EOF
-Usage: test_shadow_copy SERVER SERVER_IP DOMAIN USERNAME PASSWORD WORKDIR SMBTORTURE
+Usage: test_shadow_copy SERVER SERVER_IP DOMAIN USERNAME PASSWORD WORKDIR SMBTORTURE SMBCLIENT
 EOF
 exit 1;
 fi
@@ -17,6 +17,7 @@ USERNAME=${4}
 PASSWORD=${5}
 WORKDIR=${6}
 SMBTORTURE="$VALGRIND ${7}"
+SMBCLIENT="$VALGRIND ${8}"
 shift 7
 
 incdir=`dirname $0`/../../../testprogs/blackbox
@@ -33,6 +34,9 @@ build_files()
     destdir=$1
 
     echo "$content" > $destdir/foo
+
+    mkdir -p $WORKDIR/subdir/
+    touch $WORKDIR/subdir/hardlink
 }
 
 # build a snapshots directory
@@ -42,10 +46,12 @@ build_snapshots()
 
     snapdir=$WORKDIR/.snapshots
 
-    mkdir -p $snapdir
-    mkdir $snapdir/$SNAPSHOT
+    mkdir -p $snapdir/$SNAPSHOT
 
     build_files $snapdir/$SNAPSHOT
+
+    mkdir -p $snapdir/$SNAPSHOT/subdir
+    ln "$WORKDIR"/subdir/hardlink "$snapdir"/$SNAPSHOT/subdir/hardlink
 }
 
 build_stream_on_snapshot()
@@ -124,6 +130,24 @@ test_shadow_copy_openroot()
         failed=`expr $failed + 1`
 }
 
+test_shadow_copy_fix_inodes()
+{
+    local msg
+
+    msg=$1
+
+    #delete snapshots from previous tests
+    find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+    build_snapshots
+
+    out=$($SMBCLIENT \
+	   -U $USERNAME%$PASSWORD \
+	   "//$SERVER/shadow_write" \
+	   -c "open $SNAPSHOT/subdir/hardlink") || failed=`expr $failed + 1`
+    echo $out
+    echo $out | grep "hardlink: for read/write fnum 1" || return 1
+}
+
 build_files $WORKDIR
 
 # test open for writing and write behaviour of snapshoted files
@@ -133,4 +157,6 @@ test_shadow_copy_stream "reading stream of snapshotted file"
 
 test_shadow_copy_openroot "opening root of shadow copy share"
 
+testit "fix inodes with hardlink" test_shadow_copy_fix_inodes || failed=`expr $failed + 1`
+
 exit $failed
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index fe2fee610e5..533b58d6d9c 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -454,7 +454,7 @@ for env in ["fileserver"]:
     plantestsuite("samba3.blackbox.offline", env, [os.path.join(samba3srcdir, "script/tests/test_offline.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/offline', smbclient3])
     plantestsuite("samba3.blackbox.shadow_copy2.NT1", env + "_smb1_done", [os.path.join(samba3srcdir, "script/tests/test_shadow_copy.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbclient3, '-m', 'NT1'])
     plantestsuite("samba3.blackbox.shadow_copy2.SMB3", env, [os.path.join(samba3srcdir, "script/tests/test_shadow_copy.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbclient3, '-m', 'SMB3'])
-    plantestsuite("samba3.blackbox.shadow_copy_torture", env, [os.path.join(samba3srcdir, "script/tests/test_shadow_copy_torture.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbtorture4])
+    plantestsuite("samba3.blackbox.shadow_copy_torture", env, [os.path.join(samba3srcdir, "script/tests/test_shadow_copy_torture.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbtorture4, smbclient3])
     plantestsuite("samba3.blackbox.smbclient.forceuser_validusers", env, [os.path.join(samba3srcdir, "script/tests/test_forceuser_validusers.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH', smbclient3])
     plantestsuite("samba3.blackbox.smbget", env, [os.path.join(samba3srcdir, "script/tests/test_smbget.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', 'smbget_user', '$PASSWORD', '$LOCAL_PATH/smbget', smbget])
     plantestsuite("samba3.blackbox.netshareenum", env, [os.path.join(samba3srcdir, "script/tests/test_shareenum.sh"), '$SERVER', '$USERNAME', '$PASSWORD', rpcclient])
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index 844f5efe389..79158007654 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -28,6 +28,7 @@
 #include "lib/param/loadparm.h"
 #include "lib/util/tevent_ntstatus.h"
 #include "lib/util/string_wrappers.h"
+#include "fake_file.h"
 
 static NTSTATUS get_file_handle_for_metadata(connection_struct *conn,
 				const struct smb_filename *smb_fname,
@@ -751,6 +752,10 @@ uint32_t fdos_mode(struct files_struct *fsp)
 
 	DBG_DEBUG("%s\n", fsp_str_dbg(fsp));
 
+	if (fsp->fake_file_handle != NULL) {
+		return dosmode_from_fake_filehandle(fsp->fake_file_handle);
+	}
+
 	if (!VALID_STAT(fsp->fsp_name->st)) {
 		return 0;
 	}
diff --git a/source3/smbd/fake_file.c b/source3/smbd/fake_file.c
index c4c81dd19f9..6f6d5b3778a 100644
--- a/source3/smbd/fake_file.c
+++ b/source3/smbd/fake_file.c
@@ -115,6 +115,21 @@ enum FAKE_FILE_TYPE is_fake_file(const struct smb_filename *smb_fname)
 	return ret;
 }
 
+uint32_t dosmode_from_fake_filehandle(const struct fake_file_handle *ffh)
+{
+	if (ffh->type != FAKE_FILE_TYPE_QUOTA) {
+		DBG_ERR("Unexpected fake_file_handle: %d\n", ffh->type);
+		log_stack_trace();
+		return FILE_ATTRIBUTE_NORMAL;
+	}
+
+	/* This is what Windows 2016 returns */
+	return FILE_ATTRIBUTE_HIDDEN
+		| FILE_ATTRIBUTE_SYSTEM
+		| FILE_ATTRIBUTE_DIRECTORY
+		| FILE_ATTRIBUTE_ARCHIVE;
+}
+
 /****************************************************************************
  Open a fake quota file with a share mode.


-- 
Samba Shared Repository



More information about the samba-cvs mailing list