From: Ralph Boehme Date: Mon, 10 Mar 2025 18:03:42 +0000 (+0100) Subject: smbtorture: add "smb2.timestamps.modern_write_time_update-2" X-Git-Tag: tevent-0.17.0~478 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0635966c325efd751ef9dbe12186998e1e28a28d;p=thirdparty%2Fsamba.git smbtorture: add "smb2.timestamps.modern_write_time_update-2" BUG: https://bugzilla.samba.org/show_bug.cgi?id=13594 Signed-off-by: Ralph Boehme Reviewed-by: Jeremy Allison --- diff --git a/selftest/knownfail.d/samba3.base.delaywrite b/selftest/knownfail.d/samba3.base.delaywrite index 7c46956907d..97a81aa8c7b 100644 --- a/selftest/knownfail.d/samba3.base.delaywrite +++ b/selftest/knownfail.d/samba3.base.delaywrite @@ -18,3 +18,4 @@ ^samba3.smb2.timestamps.delayed-2write\(.*\) ^samba3.base.delaywrite.modern_write_time_update-1\(fileserver_smb1\) ^samba3.smb2.timestamps.modern_write_time_update-1\(.*\) +^samba3.smb2.timestamps.modern_write_time_update-2\(.*\) diff --git a/source4/torture/smb2/timestamps.c b/source4/torture/smb2/timestamps.c index aaba46ed05f..47d645eacf2 100644 --- a/source4/torture/smb2/timestamps.c +++ b/source4/torture/smb2/timestamps.c @@ -1458,6 +1458,451 @@ done: return ret; } + +/* + * Test setting filesize and allocation info vs sticky mtime + * + * | Time | Handle 1 | Handle 2 | + * |------+------------------------+------------------------| + * | 1 | Create file | Open file | + * | | Check Handle Time = 1 | Check Handle Time = 1 | + * | | Check Path Time = 1 | Check Path Time = 1 | + * | 2 | Set Filesize 0 | | + * | 3 | Check Handle Time = 2 | Check Handle Time = 2 | + * | | Check Path Time = 2 | Check Path Time = 2 | + * | 4 | Set Allocation Size = 0| | + * | 5 | Check Handle Time = 4 | Check Handle Time = 4 | + * | | Check Path Time = 4 | Check Path Time = 4 | + * | 6 | Set Filesize 1 | | + * | 7 | Check Handle Time = 6 | Check Handle Time = 6 | + * | | Check Path Time = 6 | Check Path Time = 6 | + * | 8 | Set Allocation Size = 4096| | + * | 9 | Check Handle Time = 8 | Check Handle Time = 8 | + * | | Check Path Time = 8 | Check Path Time = 8 | + * | 10 | Set Sticky Time = 99 | | + * | 11 | Check Handle Time = 99 | Check Handle Time = 99 | + * | | Check Path Time = 99 | Check Path Time = 99 | + * | 12 | Set Filesize | | + * | 13 | Check Handle Time = 99 | Check Handle Time = 99 | + * | | Check Path Time = 99 | Check Path Time = 99 | + * | 14 | Set Allocation Size | | + * | 15 | Check Handle Time = 99 | Check Handle Time = 99 | + * | | Check Path Time = 99 | Check Path Time = 99 | + * | 16 | | Set Filesize | + * | 17 | Check Handle Time = 16 | Check Handle Time = 16 | + * | | Check Path Time = 16 | Check Path Time = 16 | + * | 18 | | Set Allocation Size | + * | 19 | Check Handle Time = 18 | Check Handle Time = 18 | + * | | Check Path Time = 18 | Check Path Time = 18 | + * | 20 | | Shrink Allocation Size | + * | 21 | Check Handle Time = 20 | Check Handle Time = 20 | + * | | Check Path Time = 20 | Check Path Time = 20 | + * | 22 | Close | Close | + * | 23 | Check Path Time = 20 | Check Path Time = 20 | + */ +static bool test_modern_write_time_update2(struct torture_context *tctx, + struct smb2_tree *tree1, + struct smb2_tree *tree2) +{ + const char *fname = BASEDIR "\\test_modern_write_time_update2"; + struct smb2_create cr; + struct smb2_handle h1 = {}; + struct smb2_handle h2 = {}; + union smb_setfileinfo basicinfo; + union smb_setfileinfo eofinfo; + union smb_setfileinfo allocinfo; + NTTIME lasttime, currenttime1, currenttime2, ctime1, ctime2; + off_t size = 0; + size_t alloccount = 0; + off_t allocsize = 4096; + time_t stickytime = time(NULL) + 86400; + NTTIME stickynttime; + NTSTATUS status; + bool ret = true; + + unix_to_nt_time(&stickynttime, stickytime); + basicinfo = (union smb_setfileinfo) { + .generic.level = SMB_SFILEINFO_BASIC_INFORMATION, + }; + eofinfo = (union smb_setfileinfo) { + .generic.level = SMB_SFILEINFO_END_OF_FILE_INFORMATION, + }; + allocinfo = (union smb_setfileinfo) { + .generic.level = SMB_SFILEINFO_ALLOCATION_INFORMATION, + }; + + smb2_deltree(tree1, BASEDIR); + status = torture_smb2_testdir(tree1, BASEDIR, &h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "create failed\n"); + status = smb2_util_close(tree1, h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "close failed\n"); + + /* 1 */ + + smb2_generic_create(&cr, NULL, false, fname, + NTCREATEX_DISP_CREATE, + smb2_util_oplock_level(""), 0, 0); + status = smb2_create(tree1, tree1, &cr); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "create failed\n"); + h1 = cr.out.file.handle; + + smb2_generic_create(&cr, NULL, false, fname, + NTCREATEX_DISP_OPEN, + smb2_util_oplock_level(""), 0, 0); + status = smb2_create(tree2, tree2, &cr); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "create failed\n"); + h2 = cr.out.file.handle; + + ret = getinfo_both(tctx, tree1, &h1, fname, ¤ttime1, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + ret = getinfo_both(tctx, tree2, &h2, fname, ¤ttime2, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + torture_assert_nttime_equal_goto(tctx, currenttime1, currenttime2, + ret, done, "bad times"); + lasttime = currenttime1; + + /* 2: same size */ + + /* Bypass possible filesystem granularity */ + smb_msleep(20); + + eofinfo.end_of_file_info.in.file.handle = h1; + eofinfo.end_of_file_info.in.size = size; + + status = smb2_setinfo_file(tree1, &eofinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_setinfo_file failed\n"); + + /* 3 */ + + ret = getinfo_both(tctx, tree1, &h1, fname, ¤ttime1, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + ret = getinfo_both(tctx, tree2, &h2, fname, ¤ttime2, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + torture_assert_nttime_equal_goto(tctx, currenttime1, currenttime2, + ret, done, "bad times"); + + torture_assert_nttime_not_equal_goto(tctx, + currenttime1, + lasttime, + ret, done, + "bad time\n"); + lasttime = currenttime1; + + /* 4: same size */ + + /* Bypass possible filesystem granularity */ + smb_msleep(20); + + allocinfo.allocation_info.in.file.handle = h1; + allocinfo.allocation_info.in.alloc_size = 0; + + status = smb2_setinfo_file(tree1, &allocinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_setinfo_file failed\n"); + + /* 5 */ + + ret = getinfo_both(tctx, tree1, &h1, fname, ¤ttime1, &ctime1); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + ret = getinfo_both(tctx, tree2, &h2, fname, ¤ttime2, &ctime2); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + torture_assert_nttime_equal_goto(tctx, currenttime1, currenttime2, + ret, done, "bad times"); + torture_assert_nttime_equal_goto(tctx, ctime1, ctime2, + ret, done, "bad times"); + + torture_assert_nttime_equal_goto(tctx, + currenttime1, + lasttime, + ret, done, + "bad time\n"); + torture_assert_nttime_not_equal_goto(tctx, + ctime1, + lasttime, + ret, done, + "bad time\n"); + lasttime = currenttime1; + + /* 6: grow size */ + + /* Bypass possible filesystem granularity */ + smb_msleep(20); + + eofinfo.end_of_file_info.in.file.handle = h1; + eofinfo.end_of_file_info.in.size = ++size; + + status = smb2_setinfo_file(tree1, &eofinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_setinfo_file failed\n"); + + /* 7 */ + + ret = getinfo_both(tctx, tree1, &h1, fname, ¤ttime1, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + ret = getinfo_both(tctx, tree2, &h2, fname, ¤ttime2, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + torture_assert_nttime_equal_goto(tctx, currenttime1, currenttime2, + ret, done, "bad times"); + + torture_assert_nttime_not_equal_goto(tctx, + currenttime1, + lasttime, + ret, done, + "bad time\n"); + lasttime = currenttime1; + + /* 8: grow size */ + + /* Bypass possible filesystem granularity */ + smb_msleep(20); + + allocinfo.allocation_info.in.file.handle = h1; + allocinfo.allocation_info.in.alloc_size = ++alloccount * allocsize; + + status = smb2_setinfo_file(tree1, &allocinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_setinfo_file failed\n"); + + /* 9 */ + + ret = getinfo_both(tctx, tree1, &h1, fname, ¤ttime1, &ctime1); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + ret = getinfo_both(tctx, tree2, &h2, fname, ¤ttime2, &ctime2); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + torture_assert_nttime_equal_goto(tctx, currenttime1, currenttime2, + ret, done, "bad times"); + torture_assert_nttime_equal_goto(tctx, ctime1, ctime2, + ret, done, "bad times"); + + torture_assert_nttime_equal_goto(tctx, + currenttime1, + lasttime, + ret, done, + "bad time\n"); + torture_assert_nttime_not_equal_goto(tctx, + ctime1, + lasttime, + ret, done, + "bad time\n"); + lasttime = currenttime1; + + /* 10 */ + + basicinfo.basic_info.in.file.handle = h1; + basicinfo.basic_info.in.write_time = stickynttime; + + status = smb2_setinfo_file(tree1, &basicinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_setinfo_file failed\n"); + + /* 11 */ + + ret = getinfo_both(tctx, tree1, &h1, fname, ¤ttime1, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + ret = getinfo_both(tctx, tree2, &h2, fname, ¤ttime2, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + torture_assert_nttime_equal_goto(tctx, currenttime1, currenttime2, + ret, done, "bad times"); + + torture_assert_nttime_equal_goto(tctx, + currenttime1, + stickynttime, + ret, done, + "bad time\n"); + lasttime = currenttime1; + + /* 12 */ + + /* Bypass possible filesystem granularity */ + smb_msleep(20); + + eofinfo.end_of_file_info.in.file.handle = h1; + eofinfo.end_of_file_info.in.size = ++size; + + status = smb2_setinfo_file(tree1, &eofinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_setinfo_file failed\n"); + + /* 13 */ + + ret = getinfo_both(tctx, tree1, &h1, fname, ¤ttime1, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + ret = getinfo_both(tctx, tree2, &h2, fname, ¤ttime2, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + torture_assert_nttime_equal_goto(tctx, currenttime1, currenttime2, + ret, done, "bad times"); + + torture_assert_nttime_equal_goto(tctx, + currenttime1, + stickynttime, + ret, done, + "bad time\n"); + + /* 14 */ + + /* Bypass possible filesystem granularity */ + smb_msleep(20); + + allocinfo.allocation_info.in.file.handle = h1; + allocinfo.allocation_info.in.alloc_size = ++alloccount * allocsize; + + status = smb2_setinfo_file(tree1, &allocinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_setinfo_file failed\n"); + + /* 15 */ + + ret = getinfo_both(tctx, tree1, &h1, fname, ¤ttime1, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + ret = getinfo_both(tctx, tree2, &h2, fname, ¤ttime2, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + torture_assert_nttime_equal_goto(tctx, currenttime1, currenttime2, + ret, done, "bad times"); + + torture_assert_nttime_equal_goto(tctx, + currenttime1, + stickynttime, + ret, done, + "bad time\n"); + + /* 16 */ + + /* Bypass possible filesystem granularity */ + smb_msleep(20); + + eofinfo.end_of_file_info.in.file.handle = h2; + eofinfo.end_of_file_info.in.size = ++size; + + status = smb2_setinfo_file(tree2, &eofinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_setinfo_file failed\n"); + + /* 17 */ + + ret = getinfo_both(tctx, tree1, &h1, fname, ¤ttime1, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + ret = getinfo_both(tctx, tree2, &h2, fname, ¤ttime2, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + torture_assert_nttime_equal_goto(tctx, currenttime1, currenttime2, + ret, done, "bad times"); + + torture_assert_nttime_not_equal_goto(tctx, + currenttime1, + stickynttime, + ret, done, + "bad time\n"); + lasttime = currenttime1; + + /* 18 */ + + /* Bypass possible filesystem granularity */ + smb_msleep(20); + + allocinfo.allocation_info.in.file.handle = h2; + allocinfo.allocation_info.in.alloc_size = ++alloccount * allocsize; + + status = smb2_setinfo_file(tree2, &allocinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_setinfo_file failed\n"); + + /* 19 */ + + ret = getinfo_both(tctx, tree1, &h1, fname, ¤ttime1, &ctime1); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + ret = getinfo_both(tctx, tree2, &h2, fname, ¤ttime2, &ctime2); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + torture_assert_nttime_equal_goto(tctx, currenttime1, currenttime2, + ret, done, "bad times"); + torture_assert_nttime_equal_goto(tctx, ctime1, ctime2, + ret, done, "bad times"); + + torture_assert_nttime_equal_goto(tctx, + currenttime1, + lasttime, + ret, done, + "bad time\n"); + torture_assert_nttime_not_equal_goto(tctx, + ctime1, + lasttime, + ret, done, + "bad time\n"); + lasttime = currenttime1; + + /* 20: shrink allocation size, should update mtime+ctime */ + + /* Bypass possible filesystem granularity */ + smb_msleep(20); + + allocinfo.allocation_info.in.file.handle = h2; + allocinfo.allocation_info.in.alloc_size = 0; + + status = smb2_setinfo_file(tree2, &allocinfo); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "smb2_setinfo_file failed\n"); + + /* 21 */ + + ret = getinfo_both(tctx, tree1, &h1, fname, ¤ttime1, &ctime1); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + ret = getinfo_both(tctx, tree2, &h2, fname, ¤ttime2, &ctime2); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + torture_assert_nttime_equal_goto(tctx, currenttime1, currenttime2, + ret, done, "bad times"); + torture_assert_nttime_equal_goto(tctx, ctime1, ctime2, + ret, done, "bad times"); + + torture_assert_nttime_not_equal_goto(tctx, + currenttime1, + lasttime, + ret, done, + "bad time\n"); + torture_assert_nttime_not_equal_goto(tctx, + ctime1, + lasttime, + ret, done, + "bad time\n"); + lasttime = currenttime1; + + /* 22 */ + + status = smb2_util_close(tree1, h1); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "close failed\n"); + status = smb2_util_close(tree2, h2); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "close failed\n"); + + /* 23 */ + + ret = getinfo_both(tctx, tree1, NULL, fname, ¤ttime1, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + ret = getinfo_both(tctx, tree2, NULL, fname, ¤ttime2, NULL); + torture_assert_goto(tctx, ret, ret, done, "getinfo_both failed"); + torture_assert_nttime_equal_goto(tctx, currenttime1, currenttime2, + ret, done, "bad times"); + + torture_assert_nttime_equal_goto(tctx, + currenttime1, + lasttime, + ret, done, + "bad time\n"); + +done: + if (!smb2_util_handle_empty(h1)) { + smb2_util_close(tree1, h1); + } + if (!smb2_util_handle_empty(h2)) { + smb2_util_close(tree2, h2); + } + smb2_deltree(tree1, BASEDIR); + return ret; +} + /* basic testing of SMB2 timestamps */ @@ -1485,6 +1930,7 @@ struct torture_suite *torture_smb2_timestamps_init(TALLOC_CTX *ctx) torture_suite_add_1smb2_test(suite, "delayed-1write", test_delayed_1write); torture_suite_add_1smb2_test(suite, "delayed-2write", test_delayed_2write); torture_suite_add_2smb2_test(suite, "modern_write_time_update-1", test_modern_write_time_update1); + torture_suite_add_2smb2_test(suite, "modern_write_time_update-2", test_modern_write_time_update2); suite->description = talloc_strdup(suite, "SMB2 timestamp tests");