[SCM] Samba Shared Repository - branch master updated

Jeremy Allison jra at samba.org
Thu Mar 31 18:48:01 UTC 2022


The branch, master has been updated
       via  9fa67ba8eeb vfs_shadow_copy2: implement readdir()
       via  ba9c5ba8ec5 CI: add a test listing a snapshotted directory
       via  f734e960eb7 CI: avoid smb2.twrp being run by plansmbtorture4testsuite() directly
      from  06bfac2125d s3: smbd: Preserve the fsp->fsp_name->st buf across a MSG_SMB_FILE_RENAME message.

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


- Log -----------------------------------------------------------------
commit 9fa67ba8eeb6249d4b91b894e80eb1985c845314
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Mar 24 16:25:22 2022 +0100

    vfs_shadow_copy2: implement readdir()
    
    RN: shadow_copy2 fails listing snapshotted dirs with shadow:fixinodes
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15035
    
    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): Thu Mar 31 18:47:42 UTC 2022 on sn-devel-184

commit ba9c5ba8ec54e72d68e3f753a5350afe0fb50a7c
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Mar 24 17:31:00 2022 +0100

    CI: add a test listing a snapshotted directory
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15035
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit f734e960eb7ad98808ad8757de51c51d3db86a2b
Author: Ralph Boehme <slow at samba.org>
Date:   Mon Mar 28 20:05:26 2022 +0200

    CI: avoid smb2.twrp being run by plansmbtorture4testsuite() directly
    
    This should only be run by a blackbox test.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=15035
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

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

Summary of changes:
 source3/modules/vfs_shadow_copy2.c               |  91 ++++++++++++
 source3/script/tests/test_shadow_copy_torture.sh |  21 +++
 source3/selftest/tests.py                        |   3 +
 source4/selftest/tests.py                        |   1 +
 source4/torture/smb2/create.c                    | 168 +++++++++++++++++++++++
 5 files changed, 284 insertions(+)


Changeset truncated at 500 lines:

diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
index 8e92cc71e18..dfdc6735dfb 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -3331,6 +3331,96 @@ static int shadow_copy2_connect(struct vfs_handle_struct *handle,
 	return 0;
 }
 
+static struct dirent *shadow_copy2_readdir(vfs_handle_struct *handle,
+					   struct files_struct *dirfsp,
+					   DIR *dirp,
+					   SMB_STRUCT_STAT *sbuf)
+{
+	struct shadow_copy2_private *priv = NULL;
+	struct dirent *ent = NULL;
+	struct smb_filename atname;
+	struct smb_filename *full_fname = NULL;
+	time_t timestamp = 0;
+	char *stripped = NULL;
+	char *conv = NULL;
+	char *abspath = NULL;
+	bool converted = false;
+
+	SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
+				return NULL);
+
+	ent = SMB_VFS_NEXT_READDIR(handle, dirfsp, dirp, sbuf);
+	if (ent == NULL) {
+		return NULL;
+	}
+	if (sbuf == NULL) {
+		return ent;
+	}
+	if (ISDOT(dirfsp->fsp_name->base_name) && ISDOTDOT(ent->d_name)) {
+		return ent;
+	}
+
+	atname = (struct smb_filename) {
+		.base_name = ent->d_name,
+		.twrp = dirfsp->fsp_name->twrp,
+		.flags = dirfsp->fsp_name->flags,
+	};
+
+	full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+						  dirfsp,
+						  &atname);
+	if (full_fname == NULL) {
+		return NULL;
+	}
+
+	if (!shadow_copy2_strip_snapshot_converted(talloc_tos(),
+						   handle,
+						   full_fname,
+						   &timestamp,
+						   &stripped,
+						   &converted)) {
+		TALLOC_FREE(full_fname);
+		return NULL;
+	}
+
+	if (timestamp == 0 && !converted) {
+		/* Not a snapshot path, no need for convert_sbuf() */
+		TALLOC_FREE(stripped);
+		TALLOC_FREE(full_fname);
+		return ent;
+	}
+
+	if (timestamp == 0) {
+		abspath = make_path_absolute(talloc_tos(),
+					     priv,
+					     full_fname->base_name);
+		TALLOC_FREE(full_fname);
+		if (abspath == NULL) {
+			return NULL;
+		}
+	} else {
+		conv = shadow_copy2_convert(talloc_tos(),
+					    handle,
+					    stripped,
+					    timestamp);
+		TALLOC_FREE(stripped);
+		if (conv == NULL) {
+			return NULL;
+		}
+
+		abspath = make_path_absolute(talloc_tos(), priv, conv);
+		TALLOC_FREE(conv);
+		if (abspath == NULL) {
+			return NULL;
+		}
+	}
+
+	convert_sbuf(handle, abspath, sbuf);
+
+	TALLOC_FREE(abspath);
+	return ent;
+}
+
 static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
 	.connect_fn = shadow_copy2_connect,
 	.disk_free_fn = shadow_copy2_disk_free,
@@ -3362,6 +3452,7 @@ static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
 	.pwrite_recv_fn = shadow_copy2_pwrite_recv,
 	.connectpath_fn = shadow_copy2_connectpath,
 	.parent_pathname_fn = shadow_copy2_parent_pathname,
+	.readdir_fn = shadow_copy2_readdir,
 };
 
 static_decl_vfs;
diff --git a/source3/script/tests/test_shadow_copy_torture.sh b/source3/script/tests/test_shadow_copy_torture.sh
index 4ae2f9f707f..8f9d1be6927 100755
--- a/source3/script/tests/test_shadow_copy_torture.sh
+++ b/source3/script/tests/test_shadow_copy_torture.sh
@@ -191,6 +191,25 @@ test_hiddenfile()
     return 0
 }
 
+test_shadow_copy_listdir_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
+
+    testit "$msg" \
+	   $SMBTORTURE \
+	   -U$USERNAME%$PASSWORD \
+	   "//$SERVER/shadow_write" \
+	   --option="torture:twrp_snapshot=$SNAPSHOT" \
+	   smb2.twrp.listdir || \
+        failed=`expr $failed + 1`
+}
+
 build_files $WORKDIR
 
 # test open for writing and write behaviour of snapshoted files
@@ -204,4 +223,6 @@ testit "fix inodes with hardlink" test_shadow_copy_fix_inodes || failed=`expr $f
 
 testit "Test reading DOS attribute" test_hiddenfile || failed=`expr $failed + 1`
 
+test_shadow_copy_listdir_fix_inodes "fix inodes when listing directory"
+
 exit $failed
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index cae09571fe1..71a0143604e 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -1019,6 +1019,9 @@ for t in tests:
                                  "//$SERVER_IP/async_dosmode_shadow_copy2 -U$USERNAME%$PASSWORD")
     elif t == "smb2.rename":
         plansmbtorture4testsuite(t, "fileserver", '//$SERVER_IP/tmp -U$USERNAME%$PASSWORD')
+    elif t == "smb2.twrp":
+        # This is being driven by samba3.blackbox.shadow_copy_torture
+        pass
     elif t == "rpc.wkssvc":
         plansmbtorture4testsuite(t, "ad_member", '//$SERVER/tmp -U$DC_USERNAME%$DC_PASSWORD')
     elif t == "rpc.srvsvc":
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index 726b6d8fc1f..944bf110e09 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -380,6 +380,7 @@ smb2_s3only = [
     "smb2.fileid_unique",
     "smb2.timestamps",
     "smb2.async_dosmode",
+    "smb2.twrp",
 ]
 smb2 = [x for x in smbtorture4_testsuites("smb2.") if x not in smb2_s3only]
 
diff --git a/source4/torture/smb2/create.c b/source4/torture/smb2/create.c
index 4327fea9cc7..433fbe085f0 100644
--- a/source4/torture/smb2/create.c
+++ b/source4/torture/smb2/create.c
@@ -1965,6 +1965,173 @@ done:
 	return ret;
 }
 
+static bool test_twrp_listdir(struct torture_context *tctx,
+			      struct smb2_tree *tree)
+{
+	struct smb2_create create;
+	struct smb2_handle h = {{0}};
+	struct smb2_find find;
+	unsigned int count;
+	union smb_search_data *d;
+	char *p = NULL;
+	struct tm tm;
+	time_t t;
+	uint64_t nttime;
+	const char *snapshot = NULL;
+	uint64_t normal_fileid;
+	uint64_t snapshot_fileid;
+	NTSTATUS status;
+	bool ret = true;
+
+	snapshot = torture_setting_string(tctx, "twrp_snapshot", NULL);
+	if (snapshot == NULL) {
+		torture_fail(tctx, "missing 'twrp_snapshot' option\n");
+	}
+
+	torture_comment(tctx, "Testing File-Ids of directory listing "
+			"with timewarp (%s)\n",
+			snapshot);
+
+	setenv("TZ", "GMT", 1);
+
+	/* strptime does not set tm.tm_isdst but mktime assumes DST is in
+	 * effect if it is greather than 1. */
+	ZERO_STRUCT(tm);
+
+	p = strptime(snapshot, "@GMT-%Y.%m.%d-%H.%M.%S", &tm);
+	torture_assert_goto(tctx, p != NULL, ret, done, "strptime\n");
+	torture_assert_goto(tctx, *p == '\0', ret, done, "strptime\n");
+
+	t = mktime(&tm);
+	unix_to_nt_time(&nttime, t);
+
+	/*
+	 * 1: Query the file's File-Id
+	 */
+	create = (struct smb2_create) {
+		.in.desired_access = SEC_FILE_READ_DATA,
+		.in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+		.in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+		.in.create_disposition = NTCREATEX_DISP_OPEN,
+		.in.fname = "subdir/hardlink",
+		.in.query_on_disk_id = true,
+	};
+
+	status = smb2_create(tree, tctx, &create);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"test file could not be created\n");
+	smb2_util_close(tree, create.out.file.handle);
+	normal_fileid = BVAL(&create.out.on_disk_id, 0);
+
+	/*
+	 * 2: check directory listing of the file returns same File-Id
+	 */
+
+	create = (struct smb2_create) {
+		.in.desired_access = SEC_DIR_LIST,
+		.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
+		.in.create_disposition = NTCREATEX_DISP_OPEN,
+		.in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+		.in.fname = "subdir",
+		.in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
+	};
+
+	status = smb2_create(tree, tctx, &create);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_create\n");
+	h = create.out.file.handle;
+
+	find = (struct smb2_find) {
+		.in.file.handle = h,
+		.in.pattern = "*",
+		.in.max_response_size = 0x1000,
+		.in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
+	};
+
+	status = smb2_find_level(tree, tree, &find, &count, &d);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_find_level failed\n");
+
+	smb2_util_close(tree, h);
+
+	torture_assert_int_equal_goto(tctx, count, 3, ret, done, "Bad count\n");
+	torture_assert_str_equal_goto(tctx,
+				      d[2].id_both_directory_info.name.s,
+				      "hardlink",
+				      ret, done, "bad name");
+	torture_assert_u64_equal_goto(tctx,
+				      d[2].id_both_directory_info.file_id,
+				      normal_fileid,
+				      ret, done, "bad fileid\n");
+
+	/*
+	 * 3: Query File-Id of snapshot of the file and check the File-Id is
+	 * different compared to the basefile
+	 */
+
+	create = (struct smb2_create) {
+		.in.desired_access = SEC_FILE_READ_DATA,
+		.in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+		.in.file_attributes = FILE_ATTRIBUTE_NORMAL,
+		.in.create_disposition = NTCREATEX_DISP_OPEN,
+		.in.fname = "subdir/hardlink",
+		.in.query_on_disk_id = true,
+		.in.timewarp = nttime,
+	};
+
+	status = smb2_create(tree, tctx, &create);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"test file could not be created\n");
+	smb2_util_close(tree, create.out.file.handle);
+
+	snapshot_fileid = BVAL(&create.out.on_disk_id, 0);
+
+	/*
+	 * 4: List directory of the snapshot and check the File-Id returned here
+	 * is the same as in 3.
+	 */
+
+	create = (struct smb2_create) {
+		.in.desired_access = SEC_DIR_LIST,
+		.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY,
+		.in.create_disposition = NTCREATEX_DISP_OPEN,
+		.in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
+		.in.fname = "subdir",
+		.in.create_options = NTCREATEX_OPTIONS_DIRECTORY,
+		.in.timewarp = nttime,
+	};
+
+	status = smb2_create(tree, tctx, &create);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_create\n");
+	h = create.out.file.handle;
+
+	find = (struct smb2_find) {
+		.in.file.handle = h,
+		.in.pattern = "*",
+		.in.max_response_size = 0x1000,
+		.in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
+	};
+
+	status = smb2_find_level(tree, tree, &find, &count, &d);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"smb2_find_level failed\n");
+	smb2_util_close(tree, h);
+
+	torture_assert_int_equal_goto(tctx, count, 3, ret, done, "Bad count\n");
+	torture_assert_str_equal_goto(tctx,
+				      d[2].id_both_directory_info.name.s,
+				      "hardlink",
+				      ret, done, "bad name");
+	torture_assert_u64_equal_goto(tctx,
+				      snapshot_fileid,
+				      d[2].id_both_directory_info.file_id,
+				      ret, done, "bad fileid\n");
+
+done:
+	return ret;
+}
+
 static bool test_fileid(struct torture_context *tctx,
 			struct smb2_tree *tree)
 {
@@ -2988,6 +3155,7 @@ struct torture_suite *torture_smb2_twrp_init(TALLOC_CTX *ctx)
 	torture_suite_add_1smb2_test(suite, "write", test_twrp_write);
 	torture_suite_add_1smb2_test(suite, "stream", test_twrp_stream);
 	torture_suite_add_1smb2_test(suite, "openroot", test_twrp_openroot);
+	torture_suite_add_1smb2_test(suite, "listdir", test_twrp_listdir);
 
 	suite->description = talloc_strdup(suite, "SMB2-TWRP tests");
 


-- 
Samba Shared Repository



More information about the samba-cvs mailing list