From b6ed1070280ffe6587310880552e267b2ba1607a Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 23 Sep 2019 15:15:01 -0700 Subject: [PATCH 01/13] torture:smb2: extend test for File-IDs This now hopefully covers most possible combinations of creating and opening files plus, checking the file's File-ID after every operation. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 432202413f4d11d761c62f46a50747fcb9b6f0cf) --- selftest/knownfail.d/samba3.smb2.fileid | 1 + source4/torture/smb2/create.c | 299 ++++++++++++++++++++---- 2 files changed, 259 insertions(+), 41 deletions(-) create mode 100644 selftest/knownfail.d/samba3.smb2.fileid diff --git a/selftest/knownfail.d/samba3.smb2.fileid b/selftest/knownfail.d/samba3.smb2.fileid new file mode 100644 index 00000000000..89455dacdf0 --- /dev/null +++ b/selftest/knownfail.d/samba3.smb2.fileid @@ -0,0 +1 @@ +^samba3.smb2.fileid.fileid\(nt4_dc\) diff --git a/source4/torture/smb2/create.c b/source4/torture/smb2/create.c index beddefc4c8d..ea83b483491 100644 --- a/source4/torture/smb2/create.c +++ b/source4/torture/smb2/create.c @@ -1919,8 +1919,8 @@ static bool test_fileid(struct torture_context *tctx, struct smb2_find f; unsigned int count; union smb_search_data *d; - uint64_t fileid; - uint64_t stream_fileid; + uint64_t expected_fileid; + uint64_t returned_fileid; NTSTATUS status; bool ret = true; @@ -1930,6 +1930,9 @@ static bool test_fileid(struct torture_context *tctx, torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir failed\n"); + /* + * Initial create with QFID + */ create = (struct smb2_create) { .in.desired_access = SEC_FILE_ALL, .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, @@ -1943,9 +1946,47 @@ static bool test_fileid(struct torture_context *tctx, torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "test file could not be created\n"); h1 = create.out.file.handle; + expected_fileid = BVAL(&create.out.on_disk_id, 0); + + /* + * Getinfo the File-ID on the just opened handle + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Open existing with QFID + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.fname = fname, + .in.query_on_disk_id = true, + }; - fileid = BVAL(&create.out.on_disk_id, 0); + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, + ret, done, "bad fileid\n"); + /* + * Getinfo the File-ID on the just opened handle + */ finfo = (union smb_fileinfo) { .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, .generic.in.file.handle = h1, @@ -1954,33 +1995,111 @@ static bool test_fileid(struct torture_context *tctx, status = smb2_getinfo_file(tree, tctx, &finfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Overwrite with QFID + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OVERWRITE, + .in.fname = fname, + .in.query_on_disk_id = true, + }; - torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, fileid, + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, ret, done, "bad fileid\n"); - f = (struct smb2_find) { - .in.file.handle = testdirh, - .in.pattern = "foo", - .in.max_response_size = 0x1000, - .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO, + /* + * Getinfo the File-ID on the open with overwrite handle + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, }; - status = smb2_find_level(tree, tree, &f, &count, &d); + status = smb2_getinfo_file(tree, tctx, &finfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, - "smb2_find_level failed\n"); + "torture_smb2_testdir\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); - torture_assert_u64_equal_goto(tctx, - d->id_both_directory_info.file_id, - fileid, + /* + * Do some modifications on the basefile (IO, setinfo), verifying + * File-ID after each step. + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.fname = fname, + .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"); + h1 = create.out.file.handle; + + status = smb2_util_write(tree, h1, "foo", 0, strlen("foo")); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_write failed\n"); + + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, ret, done, "bad fileid\n"); + sinfo = (union smb_setfileinfo) { + .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION, + .basic_info.in.file.handle = h1, + }; + unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL)); + + status = smb2_setinfo_file(tree, &sinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_setinfo_file failed\n"); + + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + /* + * Create stream, check the stream's File-ID, should be the same as the + * base file (sic!, tested against Windows). + */ create = (struct smb2_create) { .in.desired_access = SEC_FILE_ALL, .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, .in.file_attributes = FILE_ATTRIBUTE_NORMAL, - .in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF, + .in.create_disposition = NTCREATEX_DISP_CREATE, .in.fname = sname, .in.query_on_disk_id = true, }; @@ -1989,11 +2108,13 @@ static bool test_fileid(struct torture_context *tctx, torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "test file could not be created\n"); h1 = create.out.file.handle; - - stream_fileid = BVAL(&create.out.on_disk_id, 0); - torture_assert_u64_equal_goto(tctx, stream_fileid, fileid, + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, ret, done, "bad fileid\n"); + /* + * Getinfo the File-ID on the created stream + */ finfo = (union smb_fileinfo) { .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, .generic.in.file.handle = h1, @@ -2002,31 +2123,118 @@ static bool test_fileid(struct torture_context *tctx, status = smb2_getinfo_file(tree, tctx, &finfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Open stream, check the stream's File-ID, should be the same as the + * base file (sic!, tested against Windows). + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.fname = sname, + .in.query_on_disk_id = true, + }; - torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, fileid, + status = smb2_create(tree, tctx, &create); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "test file could not be created\n"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, ret, done, "bad fileid\n"); - f = (struct smb2_find) { - .in.file.handle = testdirh, - .in.pattern = "foo", - .in.max_response_size = 0x1000, - .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO, - .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART, + /* + * Getinfo the File-ID on the opened stream + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, }; - status = smb2_find_level(tree, tree, &f, &count, &d); + status = smb2_getinfo_file(tree, tctx, &finfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, - "smb2_find_level failed\n"); + "smb2_getinfo_file failed\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); - torture_assert_u64_equal_goto(tctx, - d->id_both_directory_info.file_id, - fileid, + /* + * Overwrite stream, check the stream's File-ID, should be the same as + * the base file (sic!, tested against Windows). + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OVERWRITE, + .in.fname = sname, + .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"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, ret, done, "bad fileid\n"); + /* + * Getinfo the File-ID on the overwritten stream + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Do some modifications on the stream (IO, setinfo), verifying File-ID + * after earch step. + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.fname = sname, + .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"); + h1 = create.out.file.handle; + status = smb2_util_write(tree, h1, "foo", 0, strlen("foo")); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_util_write failed\n"); + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + sinfo = (union smb_setfileinfo) { .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION, .basic_info.in.file.handle = h1, @@ -2041,16 +2249,17 @@ static bool test_fileid(struct torture_context *tctx, .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, .generic.in.file.handle = h1, }; - status = smb2_getinfo_file(tree, tctx, &finfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_getinfo_file failed\n"); - - torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, fileid, - ret, done, "bad fileid\n"); - smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + /* + * Final open of the basefile with QFID + */ create = (struct smb2_create) { .in.desired_access = SEC_FILE_ALL, .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, @@ -2064,7 +2273,13 @@ static bool test_fileid(struct torture_context *tctx, torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "test file could not be created\n"); h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, + ret, done, "bad fileid\n"); + /* + * Final Getinfo checking File-ID + */ finfo = (union smb_fileinfo) { .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, .generic.in.file.handle = h1, @@ -2073,10 +2288,15 @@ static bool test_fileid(struct torture_context *tctx, status = smb2_getinfo_file(tree, tctx, &finfo); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "torture_smb2_testdir\n"); - - torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, fileid, + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, ret, done, "bad fileid\n"); + /* + * Final list directory, verifying the operations on basefile and stream + * didn't modify the base file metadata. + */ f = (struct smb2_find) { .in.file.handle = testdirh, .in.pattern = "foo", @@ -2088,14 +2308,11 @@ static bool test_fileid(struct torture_context *tctx, status = smb2_find_level(tree, tree, &f, &count, &d); torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_find_level failed\n"); - torture_assert_u64_equal_goto(tctx, d->id_both_directory_info.file_id, - fileid, + expected_fileid, ret, done, "bad fileid\n"); - smb2_util_close(tree, h1); - done: smb2_util_close(tree, testdirh); smb2_deltree(tree, DNAME); -- 2.21.0 From 890cf736427b400638fa67a7d3c9c026d16715b5 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 24 Sep 2019 13:09:03 -0700 Subject: [PATCH 02/13] torture:smb2: add a File-ID test on directories BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 300b47442b023532bd65417fcec04d811f40ef76) --- selftest/knownfail.d/samba3.smb2.fileid | 1 + source4/torture/smb2/create.c | 328 ++++++++++++++++++++++++ 2 files changed, 329 insertions(+) diff --git a/selftest/knownfail.d/samba3.smb2.fileid b/selftest/knownfail.d/samba3.smb2.fileid index 89455dacdf0..bdf86ac61b1 100644 --- a/selftest/knownfail.d/samba3.smb2.fileid +++ b/selftest/knownfail.d/samba3.smb2.fileid @@ -1 +1,2 @@ ^samba3.smb2.fileid.fileid\(nt4_dc\) +^samba3.smb2.fileid.fileid-dir\(nt4_dc\) diff --git a/source4/torture/smb2/create.c b/source4/torture/smb2/create.c index ea83b483491..aab74f5569a 100644 --- a/source4/torture/smb2/create.c +++ b/source4/torture/smb2/create.c @@ -2320,6 +2320,333 @@ static bool test_fileid(struct torture_context *tctx, return ret; } +static bool test_fileid_dir(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + const char *dname = DNAME "\\foo"; + const char *sname = DNAME "\\foo:bar"; + struct smb2_handle testdirh; + struct smb2_handle h1; + struct smb2_create create; + union smb_fileinfo finfo; + union smb_setfileinfo sinfo; + struct smb2_find f; + unsigned int count; + union smb_search_data *d; + uint64_t expected_fileid; + uint64_t returned_fileid; + NTSTATUS status; + bool ret = true; + + smb2_deltree(tree, DNAME); + + status = torture_smb2_testdir(tree, DNAME, &testdirh); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir failed\n"); + + /* + * Initial directory create with QFID + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.create_disposition = NTCREATEX_DISP_OPEN_IF, + .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY, + .in.create_options = NTCREATEX_OPTIONS_DIRECTORY, + .in.fname = dname, + .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"); + h1 = create.out.file.handle; + expected_fileid = BVAL(&create.out.on_disk_id, 0); + + /* + * Getinfo the File-ID on the just opened handle + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Open existing directory with QFID + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY, + .in.create_options = NTCREATEX_OPTIONS_DIRECTORY, + .in.fname = dname, + .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"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Getinfo the File-ID on the just opened handle + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Create stream, check the stream's File-ID, should be the same as the + * base file (sic!, tested against Windows). + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_CREATE, + .in.fname = sname, + .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"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Getinfo the File-ID on the created stream + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Open stream, check the stream's File-ID, should be the same as the + * base file (sic!, tested against Windows). + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.fname = sname, + .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"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Getinfo the File-ID on the opened stream + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Overwrite stream, check the stream's File-ID, should be the same as + * the base file (sic!, tested against Windows). + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OVERWRITE, + .in.fname = sname, + .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"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Getinfo the File-ID on the overwritten stream + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Do some modifications on the stream (IO, setinfo), verifying File-ID + * after earch step. + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_NORMAL, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.fname = sname, + .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"); + h1 = create.out.file.handle; + + status = smb2_util_write(tree, h1, "foo", 0, strlen("foo")); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_util_write failed\n"); + + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + sinfo = (union smb_setfileinfo) { + .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION, + .basic_info.in.file.handle = h1, + }; + unix_to_nt_time(&sinfo.basic_info.in.write_time, time(NULL)); + + status = smb2_setinfo_file(tree, &sinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_setinfo_file failed\n"); + + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_getinfo_file failed\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Final open of the directory with QFID + */ + create = (struct smb2_create) { + .in.desired_access = SEC_FILE_ALL, + .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, + .in.file_attributes = FILE_ATTRIBUTE_DIRECTORY, + .in.create_options = NTCREATEX_OPTIONS_DIRECTORY, + .in.create_disposition = NTCREATEX_DISP_OPEN, + .in.fname = dname, + .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"); + h1 = create.out.file.handle; + returned_fileid = BVAL(&create.out.on_disk_id, 0); + torture_assert_u64_equal_goto(tctx, returned_fileid, expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Final Getinfo checking File-ID + */ + finfo = (union smb_fileinfo) { + .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION, + .generic.in.file.handle = h1, + }; + + status = smb2_getinfo_file(tree, tctx, &finfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "torture_smb2_testdir\n"); + smb2_util_close(tree, h1); + torture_assert_u64_equal_goto(tctx, finfo.all_info2.out.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + + /* + * Final list directory, verifying the operations on basefile and stream + * didn't modify the base file metadata. + */ + f = (struct smb2_find) { + .in.file.handle = testdirh, + .in.pattern = "foo", + .in.max_response_size = 0x1000, + .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO, + .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART, + }; + + status = smb2_find_level(tree, tree, &f, &count, &d); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_find_level failed\n"); + torture_assert_u64_equal_goto(tctx, + d->id_both_directory_info.file_id, + expected_fileid, + ret, done, "bad fileid\n"); + +done: + smb2_util_close(tree, testdirh); + smb2_deltree(tree, DNAME); + talloc_free(mem_ctx); + return ret; +} + /* basic testing of SMB2 read */ @@ -2366,6 +2693,7 @@ struct torture_suite *torture_smb2_fileid_init(TALLOC_CTX *ctx) struct torture_suite *suite = torture_suite_create(ctx, "fileid"); torture_suite_add_1smb2_test(suite, "fileid", test_fileid); + torture_suite_add_1smb2_test(suite, "fileid-dir", test_fileid_dir); suite->description = talloc_strdup(suite, "SMB2-CREATE tests"); -- 2.21.0 From 54a2c7fd7a86fb008826d7f029bf8fdd16ad7de8 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 23 Sep 2019 15:15:31 -0700 Subject: [PATCH 03/13] s3:smbd: change the place where we call dos_mode() when processing SMB2_CREATE This is needed for ordinary file or directory opens so the QFID create context response gets the correct File-ID value via dos_mode() from the DOS attributes xattr. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit e1dfaa2b038d91e43d8d34bf1526b7728dba58a5) --- source3/smbd/smb2_create.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index 61ed72169fb..66f4aad8c9e 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -1274,6 +1274,9 @@ static void smbd_smb2_create_after_exec(struct tevent_req *req) DEBUG(10, ("smbd_smb2_create_send: " "response construction phase\n")); + state->out_file_attributes = dos_mode(state->result->conn, + state->result->fsp_name); + if (state->mxac != NULL) { NTTIME last_write_time; @@ -1472,8 +1475,6 @@ static void smbd_smb2_create_finish(struct tevent_req *req) state->out_create_action = state->info; } result->op->create_action = state->out_create_action; - state->out_file_attributes = dos_mode(result->conn, - result->fsp_name); state->out_creation_ts = get_create_timespec(smb1req->conn, result, result->fsp_name); -- 2.21.0 From 388af52158096f7c9c4cdd72a1708391a39633f0 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 23 Sep 2019 15:16:58 -0700 Subject: [PATCH 04/13] s3:smbd: when storing DOS attribute call dos_mode() beforehand This is required to ensure File-ID info is populated with the correct on-disk value, before calling file_set_dosmode() which will update the on-disk value. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 49a754b82d33fb523cda4151a865584ae52a2e2f) --- selftest/knownfail.d/samba3.smb2.fileid | 1 - source3/smbd/open.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/selftest/knownfail.d/samba3.smb2.fileid b/selftest/knownfail.d/samba3.smb2.fileid index bdf86ac61b1..89455dacdf0 100644 --- a/selftest/knownfail.d/samba3.smb2.fileid +++ b/selftest/knownfail.d/samba3.smb2.fileid @@ -1,2 +1 @@ ^samba3.smb2.fileid.fileid\(nt4_dc\) -^samba3.smb2.fileid.fileid-dir\(nt4_dc\) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index a5650ac9c2d..7f1f8eae593 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -3725,6 +3725,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, /* Overwritten files should be initially set as archive */ if ((info == FILE_WAS_OVERWRITTEN && lp_map_archive(SNUM(conn))) || lp_store_dos_attributes(SNUM(conn))) { + (void)dos_mode(conn, smb_fname); if (!posix_open) { if (file_set_dosmode(conn, smb_fname, new_dos_attributes | FILE_ATTRIBUTE_ARCHIVE, -- 2.21.0 From d808e4169fa8b4b39cc3758dd0bbe2b6727dbde3 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 25 Sep 2019 08:53:29 -0700 Subject: [PATCH 05/13] s3:lib: rework a return expression into an if block Needed to add additional stuff after the if block in the next commit. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit d7dc85990a177954925644f9ff332b3481a03cc7) --- source3/lib/filename_util.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c index 8a16bacddbe..6bf29c2b0c9 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -253,7 +253,11 @@ bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) return false; } - return smb_fname->stream_name != NULL; + if (smb_fname->stream_name == NULL) { + return false; + } + + return true; } /**************************************************************************** -- 2.21.0 From 7cc039e74547334bf4f34f1986dcf8ce6ecb4010 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 25 Sep 2019 10:15:27 -0700 Subject: [PATCH 06/13] s3:lib: assert stream_name is NULL for POSIX paths BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 6c1647ca7a2f68825c34e9ccc18b86ef911e14ac) --- source3/lib/filename_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c index 6bf29c2b0c9..165adb116b5 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -250,7 +250,7 @@ bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) } if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) { - return false; + SMB_ASSERT(smb_fname->stream_name == NULL); } if (smb_fname->stream_name == NULL) { -- 2.21.0 From f97d242bc1caaa566e0fa602d2b42672cb7dbdea Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 25 Sep 2019 10:18:03 -0700 Subject: [PATCH 07/13] s3:lib: factor out stream name asserts to helper function BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit f9fdb8a2a6b9ad0fbb89a9734e81a8b1f527966f) --- source3/lib/filename_util.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c index 165adb116b5..7b3fab90c46 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -239,10 +239,7 @@ struct smb_filename *cp_smb_filename(TALLOC_CTX *mem_ctx, return out; } -/**************************************************************************** - Simple check to determine if the filename is a stream. - ***************************************************************************/ -bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) +static void assert_valid_stream_smb_fname(const struct smb_filename *smb_fname) { /* stream_name must always be NULL if there is no stream. */ if (smb_fname->stream_name) { @@ -252,6 +249,15 @@ bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) if (smb_fname->flags & SMB_FILENAME_POSIX_PATH) { SMB_ASSERT(smb_fname->stream_name == NULL); } +} + +/**************************************************************************** + Simple check to determine if the filename is a stream. + ***************************************************************************/ + +bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) +{ + assert_valid_stream_smb_fname(smb_fname); if (smb_fname->stream_name == NULL) { return false; -- 2.21.0 From 686785c97ffa53e30a9969bdd3a71c488791ec9c Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 26 Sep 2019 10:38:06 -0700 Subject: [PATCH 08/13] s3:lib: expand a comment with the function doc for is_ntfs_stream_smb_fname Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 2584b4cdeae3f83962cd11538cd4e441104c8274) --- source3/lib/filename_util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c index 7b3fab90c46..750c0bb8312 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -252,7 +252,8 @@ static void assert_valid_stream_smb_fname(const struct smb_filename *smb_fname) } /**************************************************************************** - Simple check to determine if the filename is a stream. + Simple check to determine if a smb_fname is a real named stream or the + default stream. ***************************************************************************/ bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) -- 2.21.0 From 4ee26a9053afd0e51fb25126a7637b80b586811e Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 25 Sep 2019 11:19:26 -0700 Subject: [PATCH 09/13] s3:lib: implement logic directly in is_ntfs_default_stream_smb_fname() This allows changing the semantics of is_ntfs_stream_smb_fname() in the next commit. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 3f8bc1ce3e094f943363921c46803fd5ec9f73bb) --- source3/lib/filename_util.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c index 750c0bb8312..ee49ae5ff8c 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -272,7 +272,9 @@ bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) ***************************************************************************/ bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname) { - if (!is_ntfs_stream_smb_fname(smb_fname)) { + assert_valid_stream_smb_fname(smb_fname); + + if (smb_fname->stream_name == NULL) { return false; } -- 2.21.0 From 658b9b8a4853e0954c9a66126e18bc1fde31c717 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 25 Sep 2019 11:29:04 -0700 Subject: [PATCH 10/13] s3:lib: use strequal_m() in is_ntfs_default_stream_smb_fname() BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 780a8dcba998471bb154e8bae4391786b793e332) --- source3/lib/filename_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c index ee49ae5ff8c..2917481c8bf 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -278,7 +278,7 @@ bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname) return false; } - return strcasecmp_m(smb_fname->stream_name, "::$DATA") == 0; + return strequal_m(smb_fname->stream_name, "::$DATA"); } /**************************************************************************** -- 2.21.0 From eead2afb781c6b7dd28ea14cf4830b99f43973d6 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 26 Sep 2019 10:05:40 -0700 Subject: [PATCH 11/13] s3:lib: add is_named_stream() Add a new utility functions that checks whether a struct smb_filename points to a real named stream, excluding the default stream "::$DATA". foo -> false foo::$DATA -> false foo:bar -> true foo:bar:$DATA -> true BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 091e3fdab61217251de1cf5111f070ff295d1649) --- source3/include/proto.h | 1 + source3/lib/filename_util.c | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/source3/include/proto.h b/source3/include/proto.h index ad6f3bbf9c3..cb8890d340b 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -985,6 +985,7 @@ struct smb_filename *cp_smb_filename_nostream(TALLOC_CTX *mem_ctx, const struct smb_filename *in); bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname); bool is_ntfs_default_stream_smb_fname(const struct smb_filename *smb_fname); +bool is_named_stream(const struct smb_filename *smb_fname); bool is_invalid_windows_ea_name(const char *name); bool ea_list_has_invalid_name(struct ea_list *ea_list); bool split_stream_filename(TALLOC_CTX *ctx, diff --git a/source3/lib/filename_util.c b/source3/lib/filename_util.c index 2917481c8bf..66c07001eba 100644 --- a/source3/lib/filename_util.c +++ b/source3/lib/filename_util.c @@ -267,6 +267,32 @@ bool is_ntfs_stream_smb_fname(const struct smb_filename *smb_fname) return true; } +/**************************************************************************** + Simple check to determine if a smb_fname is pointing to a normal file or + a named stream that is not the default stream "::$DATA". + + foo -> false + foo::$DATA -> false + foo:bar -> true + foo:bar:$DATA -> true + + ***************************************************************************/ + +bool is_named_stream(const struct smb_filename *smb_fname) +{ + assert_valid_stream_smb_fname(smb_fname); + + if (smb_fname->stream_name == NULL) { + return false; + } + + if (strequal_m(smb_fname->stream_name, "::$DATA")) { + return false; + } + + return true; +} + /**************************************************************************** Returns true if the filename's stream == "::$DATA" ***************************************************************************/ -- 2.21.0 From e1049400dd109d3d9080cf5bf45da78ae6f54839 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 24 Sep 2019 12:49:38 -0700 Subject: [PATCH 12/13] s3:smbd: ensure a created stream picks up the File-ID from the basefile BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit 90a14c90c4bcede1ef5414e0800aa4c84cbcf1c9) --- selftest/knownfail.d/samba3.smb2.fileid | 1 - source3/smbd/open.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 selftest/knownfail.d/samba3.smb2.fileid diff --git a/selftest/knownfail.d/samba3.smb2.fileid b/selftest/knownfail.d/samba3.smb2.fileid deleted file mode 100644 index 89455dacdf0..00000000000 --- a/selftest/knownfail.d/samba3.smb2.fileid +++ /dev/null @@ -1 +0,0 @@ -^samba3.smb2.fileid.fileid\(nt4_dc\) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 7f1f8eae593..8586b467d2e 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -3708,7 +3708,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, fsp->initial_delete_on_close = True; } - if (info == FILE_WAS_CREATED) { + if (info == FILE_WAS_CREATED && !is_named_stream(smb_fname)) { smb_fname->st.st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_ITIME; if (lp_store_dos_attributes(SNUM(conn)) && -- 2.21.0 From d47c38315bd565465edfacbe81a64aa4837a00a8 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 26 Sep 2019 10:41:37 -0700 Subject: [PATCH 13/13] s3:smbd: add a comment explaining the File-ID semantics when a file is created BUG: https://bugzilla.samba.org/show_bug.cgi?id=14137 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison (cherry picked from commit c190f3efa9eb4f633df28074b481ff884b67e65f) --- source3/smbd/open.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 8586b467d2e..5524f80af20 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -3708,6 +3708,15 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, fsp->initial_delete_on_close = True; } + /* + * If we created a file and it's not a stream, this is the point where + * we set the itime (aka invented time) that get's stored in the DOS + * attribute xattr. The value is going to be either what the filesystem + * provided or a copy of the creation date. + * + * Either way, we turn the itime into a File-ID, unless the filesystem + * provided one (unlikely). + */ if (info == FILE_WAS_CREATED && !is_named_stream(smb_fname)) { smb_fname->st.st_ex_iflags &= ~ST_EX_IFLAG_CALCULATED_ITIME; -- 2.21.0