2 Unix SMB/CIFS implementation.
4 test suite for delayed write update
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Andrew Tridgell 2004
8 Copyright (C) Jeremy Allison 2004
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "torture/torture.h"
26 #include "libcli/raw/libcliraw.h"
27 #include "libcli/raw/raw_proto.h"
28 #include "system/time.h"
29 #include "system/filesys.h"
30 #include "libcli/libcli.h"
31 #include "torture/util.h"
32 #include "torture/basic/proto.h"
34 #define BASEDIR "\\delaywrite"
36 static bool test_delayed_write_update(struct torture_context *tctx, struct smbcli_state *cli)
38 union smb_fileinfo finfo1, finfo2;
39 const char *fname = BASEDIR "\\torture_file.txt";
46 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
47 int normal_delay = 2000000;
48 double sec = ((double)used_delay) / ((double)normal_delay);
49 int msec = 1000 * sec;
51 torture_comment(tctx, "\nRunning test_delayed_write_update\n");
53 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
55 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
56 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
57 "Failed to open %s", fname));
59 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
60 finfo1.basic_info.in.file.fnum = fnum1;
63 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
64 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
66 torture_comment(tctx, "Initial write time %s\n",
67 nt_time_string(tctx, finfo1.basic_info.out.write_time));
69 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
70 torture_assert_int_equal(tctx, written, 1,
71 "unexpected number of bytes written");
73 start = timeval_current();
74 end = timeval_add(&start, (120 * sec), 0);
75 while (!timeval_expired(&end)) {
76 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
78 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
80 torture_comment(tctx, "write time %s\n",
81 nt_time_string(tctx, finfo2.basic_info.out.write_time));
83 if (finfo1.basic_info.out.write_time !=
84 finfo2.basic_info.out.write_time)
86 double diff = timeval_elapsed(&start);
89 diff >= (used_delay / (double)1000000),
91 "Server updated write_time after %.2f "
92 "seconds (expected >= %.2f)\n",
93 diff, used_delay/(double)1000000));
95 torture_comment(tctx, "Server updated write_time after %.2f seconds (correct)\n",
100 smb_msleep(1 * msec);
103 torture_assert_u64_not_equal(tctx,
104 finfo2.basic_info.out.write_time,
105 finfo1.basic_info.out.write_time,
106 "Server did not update write time within "
110 smbcli_close(cli->tree, fnum1);
111 smbcli_unlink(cli->tree, fname);
112 smbcli_deltree(cli->tree, BASEDIR);
117 static bool test_delayed_write_update1(struct torture_context *tctx, struct smbcli_state *cli)
119 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
120 const char *fname = BASEDIR "\\torture_file1.txt";
125 struct timeval start;
127 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
128 int normal_delay = 2000000;
129 double sec = ((double)used_delay) / ((double)normal_delay);
130 int msec = 1000 * sec;
135 torture_comment(tctx, "\nRunning test_delayed_write_update1\n");
137 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
139 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
140 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
141 "Failed to open %s", fname));
143 memset(buf, 'x', 2048);
144 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
146 /* 3 second delay to ensure we get past any 2 second time
147 granularity (older systems may have that) */
148 smb_msleep(3 * msec);
150 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
151 finfo1.all_info.in.file.fnum = fnum1;
154 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
155 pinfo4.all_info.in.file.path = fname;
157 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
159 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
161 torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
162 "file size not as expected after write(2048)");
164 torture_comment(tctx, "Initial write time %s\n",
165 nt_time_string(tctx, finfo1.all_info.out.write_time));
167 /* 3 second delay to ensure we get past any 2 second time
168 granularity (older systems may have that) */
169 smb_msleep(3 * msec);
171 /* Do a zero length SMBwrite call to truncate. */
172 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
173 torture_assert_int_equal(tctx, written, 0,
174 "unexpected number of bytes written");
176 start = timeval_current();
177 end = timeval_add(&start, (120 * sec), 0);
180 while (!timeval_expired(&end)) {
181 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
183 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
185 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 1024,
186 "file not truncated to expected size "
189 torture_comment(tctx, "write time %s\n",
190 nt_time_string(tctx, finfo2.all_info.out.write_time));
192 if (finfo1.all_info.out.write_time !=
193 finfo2.all_info.out.write_time)
200 smb_msleep(1 * msec);
204 torture_assert(tctx, updated,
205 "Server did not update write time within 120 seconds");
207 torture_assert(tctx, first, talloc_asprintf(tctx,
208 "Server did not update write time immediately but only "
209 "after %.2f seconds!", timeval_elapsed(&start)));
211 torture_comment(tctx, "Server updated write time immediately. Good!\n");
214 smb_msleep(2 * msec);
216 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
217 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
218 torture_assert_int_equal(tctx, written, 1,
219 "unexpected number of bytes written");
221 start = timeval_current();
222 end = timeval_add(&start, (10*sec), 0);
223 while (!timeval_expired(&end)) {
224 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
226 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
228 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 1024,
229 "file not truncated to expected size "
232 torture_comment(tctx, "write time %s\n",
233 nt_time_string(tctx, finfo3.all_info.out.write_time));
235 torture_assert_u64_equal(tctx,
236 finfo3.all_info.out.write_time,
237 finfo2.all_info.out.write_time,
238 talloc_asprintf(tctx,
239 "Server updated write time "
240 "after %.2f seconds (wrong!)",
241 timeval_elapsed(&start)));
244 smb_msleep(1 * msec);
247 torture_comment(tctx, "Server did not update write time within 10 "
251 smb_msleep(2 * msec);
253 /* the close should trigger an write time update */
254 smbcli_close(cli->tree, fnum1);
257 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
258 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
260 torture_assert_u64_not_equal(tctx,
261 pinfo4.all_info.out.write_time,
262 finfo3.all_info.out.write_time,
263 "Server did not update write time on "
266 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
267 "Server updated write time on close, but to an earlier point "
270 torture_comment(tctx, "Server updated write time on close (correct)\n");
273 smbcli_close(cli->tree, fnum1);
274 smbcli_unlink(cli->tree, fname);
275 smbcli_deltree(cli->tree, BASEDIR);
280 /* Updating with a SMBwrite of zero length
281 * changes the write time immediately - even on expand. */
283 static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
285 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
286 const char *fname = BASEDIR "\\torture_file1a.txt";
291 struct timeval start;
293 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
294 int normal_delay = 2000000;
295 double sec = ((double)used_delay) / ((double)normal_delay);
296 int msec = 1000 * sec;
301 torture_comment(tctx, "\nRunning test_delayed_write_update1a\n");
303 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
305 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
306 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
307 "Failed to open %s", fname));
309 memset(buf, 'x', 2048);
310 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
312 /* 3 second delay to ensure we get past any 2 second time
313 granularity (older systems may have that) */
314 smb_msleep(3 * msec);
316 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
317 finfo1.all_info.in.file.fnum = fnum1;
320 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
321 pinfo4.all_info.in.file.path = fname;
323 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
325 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
327 torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
328 "file size not as expected after write(2048)");
330 torture_comment(tctx, "Initial write time %s\n",
331 nt_time_string(tctx, finfo1.all_info.out.write_time));
333 /* Do a zero length SMBwrite call to truncate. */
334 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
336 torture_assert_int_equal(tctx, written, 0,
337 "unexpected number of bytes written");
339 start = timeval_current();
340 end = timeval_add(&start, (120*sec), 0);
343 while (!timeval_expired(&end)) {
344 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
346 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
348 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
349 "file not truncated to expected size "
352 torture_comment(tctx, "write time %s\n",
353 nt_time_string(tctx, finfo2.all_info.out.write_time));
355 if (finfo1.all_info.out.write_time !=
356 finfo2.all_info.out.write_time)
363 smb_msleep(1 * msec);
367 torture_assert(tctx, updated,
368 "Server did not update write time within 120 seconds");
370 torture_assert(tctx, first, talloc_asprintf(tctx,
371 "Server did not update write time immediately but only "
372 "after %.2f seconds!", timeval_elapsed(&start)));
374 torture_comment(tctx, "Server updated write time immediately. Good!\n");
377 smb_msleep(2 * msec);
379 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
380 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
382 torture_assert_int_equal(tctx, written, 1,
383 "unexpected number of bytes written");
385 start = timeval_current();
386 end = timeval_add(&start, (10*sec), 0);
387 while (!timeval_expired(&end)) {
388 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
390 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
392 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
393 "file not truncated to expected size "
396 torture_comment(tctx, "write time %s\n",
397 nt_time_string(tctx, finfo3.all_info.out.write_time));
399 torture_assert_u64_equal(tctx,
400 finfo3.all_info.out.write_time,
401 finfo2.all_info.out.write_time,
402 talloc_asprintf(tctx,
403 "Server updated write time "
404 "after %.2f seconds (wrong!)",
405 timeval_elapsed(&start)));
408 smb_msleep(1 * msec);
411 torture_comment(tctx, "Server did not update write time within 10 "
414 /* the close should trigger an write time update */
415 smbcli_close(cli->tree, fnum1);
418 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
419 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
421 torture_assert_u64_not_equal(tctx,
422 pinfo4.all_info.out.write_time,
423 finfo3.all_info.out.write_time,
424 "Server did not update write time on "
427 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
428 "Server updated write time on close, but to an earlier point "
431 torture_comment(tctx, "Server updated write time on close (correct)\n");
434 smbcli_close(cli->tree, fnum1);
435 smbcli_unlink(cli->tree, fname);
436 smbcli_deltree(cli->tree, BASEDIR);
441 /* Updating with a SET_FILE_END_OF_FILE_INFO
442 * changes the write time immediately - even on expand. */
444 static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
446 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
447 const char *fname = BASEDIR "\\torture_file1b.txt";
452 struct timeval start;
454 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
455 int normal_delay = 2000000;
456 double sec = ((double)used_delay) / ((double)normal_delay);
457 int msec = 1000 * sec;
460 torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
462 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
464 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
466 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
470 memset(buf, 'x', 2048);
471 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
473 /* 3 second delay to ensure we get past any 2 second time
474 granularity (older systems may have that) */
475 smb_msleep(3 * msec);
477 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
478 finfo1.all_info.in.file.fnum = fnum1;
481 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
482 pinfo4.all_info.in.file.path = fname;
484 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
486 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
488 torture_comment(tctx, "Initial write time %s\n",
489 nt_time_string(tctx, finfo1.all_info.out.write_time));
491 /* Do a SET_END_OF_FILE_INFO call to truncate. */
492 status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
494 torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
496 start = timeval_current();
497 end = timeval_add(&start, (120*sec), 0);
498 while (!timeval_expired(&end)) {
499 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
501 if (!NT_STATUS_IS_OK(status)) {
502 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
507 if (finfo2.all_info.out.size != 10240) {
508 torture_result(tctx, TORTURE_FAIL,
509 "file not truncated (size = %u, should be 10240)",
510 (unsigned int)finfo2.all_info.out.size );
515 torture_comment(tctx, "write time %s\n",
516 nt_time_string(tctx, finfo2.all_info.out.write_time));
517 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
518 double diff = timeval_elapsed(&start);
519 if (diff > (0.25 * (used_delay / (double)1000000))) {
520 torture_result(tctx, TORTURE_FAIL,
521 "After SET_END_OF_FILE truncate "
522 "server updated write_time after %.2f seconds"
523 "(write time update delay == %.2f)(wrong!)",
524 diff, used_delay / (double)1000000);
529 torture_comment(tctx, "After SET_END_OF_FILE truncate "
530 "server updated write_time after %.2f seconds"
531 "(write time update delay == %.2f)(correct)\n",
532 diff, used_delay / (double)1000000);
536 smb_msleep(1 * msec);
539 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
540 torture_result(tctx, TORTURE_FAIL,
541 "Server did not update write time (wrong!)");
546 smb_msleep(2 * msec);
548 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
549 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
551 torture_assert_int_equal(tctx, written, 1,
552 "unexpected number of bytes written");
554 start = timeval_current();
555 end = timeval_add(&start, (10*sec), 0);
556 while (!timeval_expired(&end)) {
557 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
559 if (!NT_STATUS_IS_OK(status)) {
560 torture_result(tctx, TORTURE_FAIL,
561 "fileinfo failed: %s", nt_errstr(status));
566 if (finfo3.all_info.out.size != 10240) {
567 DEBUG(0, ("file not truncated (size = %u, should be 10240)\n",
568 (unsigned int)finfo3.all_info.out.size ));
573 torture_comment(tctx, "write time %s\n",
574 nt_time_string(tctx, finfo3.all_info.out.write_time));
575 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
576 double diff = timeval_elapsed(&start);
578 torture_comment(tctx, "server updated write_time after %.2f seconds"
579 "(write time update delay == %.2f)(correct)\n",
580 diff, used_delay / (double)1000000);
584 smb_msleep(1 * msec);
587 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
588 torture_result(tctx, TORTURE_FAIL, "Server updated write time (wrong!)\n");
592 /* the close should trigger an write time update */
593 smbcli_close(cli->tree, fnum1);
596 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
597 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
599 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
600 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
602 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
603 torture_comment(tctx, "Server updated write time on close (correct)\n");
607 smbcli_close(cli->tree, fnum1);
608 smbcli_unlink(cli->tree, fname);
609 smbcli_deltree(cli->tree, BASEDIR);
614 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
616 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
618 union smb_setfileinfo parms;
619 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
620 const char *fname = BASEDIR "\\torture_file1c.txt";
625 struct timeval start;
627 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
628 int normal_delay = 2000000;
629 double sec = ((double)used_delay) / ((double)normal_delay);
630 int msec = 1000 * sec;
633 torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
635 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
637 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
639 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
643 memset(buf, 'x', 2048);
644 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
646 /* 3 second delay to ensure we get past any 2 second time
647 granularity (older systems may have that) */
648 smb_msleep(3 * msec);
650 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
651 finfo1.all_info.in.file.fnum = fnum1;
654 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
655 pinfo4.all_info.in.file.path = fname;
657 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
659 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
661 torture_comment(tctx, "Initial write time %s\n",
662 nt_time_string(tctx, finfo1.all_info.out.write_time));
664 /* Do a SET_ALLOCATION_SIZE call to truncate. */
665 parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
666 parms.allocation_info.in.file.fnum = fnum1;
667 parms.allocation_info.in.alloc_size = 0;
669 status = smb_raw_setfileinfo(cli->tree, &parms);
671 torture_assert_ntstatus_ok(tctx, status,
672 "RAW_SFILEINFO_ALLOCATION_INFO failed");
674 start = timeval_current();
675 end = timeval_add(&start, (120*sec), 0);
676 while (!timeval_expired(&end)) {
677 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
679 if (!NT_STATUS_IS_OK(status)) {
680 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
686 if (finfo2.all_info.out.size != 0) {
687 torture_result(tctx, TORTURE_FAIL,
688 "file not truncated (size = %u, should be 10240)",
689 (unsigned int)finfo2.all_info.out.size);
694 torture_comment(tctx, "write time %s\n",
695 nt_time_string(tctx, finfo2.all_info.out.write_time));
696 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
697 double diff = timeval_elapsed(&start);
698 if (diff > (0.25 * (used_delay / (double)1000000))) {
699 torture_result(tctx, TORTURE_FAIL, "After SET_ALLOCATION_INFO truncate "
700 "server updated write_time after %.2f seconds"
701 "(write time update delay == %.2f)(wrong!)\n",
702 diff, used_delay / (double)1000000);
707 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
708 "server updated write_time after %.2f seconds"
709 "(write time update delay == %.2f)(correct)\n",
710 diff, used_delay / (double)1000000);
714 smb_msleep(1 * msec);
717 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
718 torture_result(tctx, TORTURE_FAIL,
719 "Server did not update write time (wrong!)");
724 smb_msleep(2 * msec);
726 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
727 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
728 torture_assert_int_equal(tctx, written, 1,
729 "Unexpected number of bytes written");
731 start = timeval_current();
732 end = timeval_add(&start, (10*sec), 0);
733 while (!timeval_expired(&end)) {
734 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
736 if (!NT_STATUS_IS_OK(status)) {
737 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
743 if (finfo3.all_info.out.size != 1) {
744 torture_result(tctx, TORTURE_FAIL, "file not expanded");
749 torture_comment(tctx, "write time %s\n",
750 nt_time_string(tctx, finfo3.all_info.out.write_time));
751 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
752 double diff = timeval_elapsed(&start);
754 torture_comment(tctx, "server updated write_time after %.2f seconds"
755 "(write time update delay == %.2f)(wrong)\n",
756 diff, used_delay / (double)1000000);
760 smb_msleep(1 * msec);
763 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
764 torture_result(tctx, TORTURE_FAIL,
765 "Server updated write time (wrong!)");
769 /* the close should trigger an write time update */
770 smbcli_close(cli->tree, fnum1);
773 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
774 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
776 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
777 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
779 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
780 torture_comment(tctx, "Server updated write time on close (correct)\n");
784 smbcli_close(cli->tree, fnum1);
785 smbcli_unlink(cli->tree, fname);
786 smbcli_deltree(cli->tree, BASEDIR);
792 * Do as above, but using 2 connections.
795 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
796 struct smbcli_state *cli2)
798 union smb_fileinfo finfo1, finfo2;
799 const char *fname = BASEDIR "\\torture_file.txt";
805 struct timeval start;
807 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
808 int normal_delay = 2000000;
809 double sec = ((double)used_delay) / ((double)normal_delay);
810 int msec = 1000 * sec;
811 union smb_flush flsh;
813 torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
815 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
817 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
819 torture_comment(tctx, "Failed to open %s\n", fname);
823 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
824 finfo1.basic_info.in.file.fnum = fnum1;
827 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
829 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
831 torture_comment(tctx, "Initial write time %s\n",
832 nt_time_string(tctx, finfo1.basic_info.out.write_time));
834 /* 3 second delay to ensure we get past any 2 second time
835 granularity (older systems may have that) */
836 smb_msleep(3 * msec);
839 /* Try using setfileinfo instead of write to update write time. */
840 union smb_setfileinfo sfinfo;
841 time_t t_set = time(NULL);
842 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
843 sfinfo.basic_info.in.file.fnum = fnum1;
844 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
845 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
847 /* I tried this with both + and - ve to see if it makes a different.
848 It doesn't - once the filetime is set via setfileinfo it stays that way. */
850 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
852 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
854 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
855 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
857 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
859 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
862 finfo2.basic_info.in.file.path = fname;
864 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
866 if (!NT_STATUS_IS_OK(status)) {
867 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
870 torture_comment(tctx, "write time %s\n",
871 nt_time_string(tctx, finfo2.basic_info.out.write_time));
873 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
874 torture_comment(tctx, "Server updated write_time (correct)\n");
876 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
880 /* Now try a write to see if the write time gets reset. */
882 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
883 finfo1.basic_info.in.file.fnum = fnum1;
886 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
888 if (!NT_STATUS_IS_OK(status)) {
889 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
893 torture_comment(tctx, "Modified write time %s\n",
894 nt_time_string(tctx, finfo1.basic_info.out.write_time));
897 torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
899 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
902 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
903 (int)written, __location__);
907 /* Just to prove to tridge that the an smbflush has no effect on
908 the write time :-). The setfileinfo IS STICKY. JRA. */
910 torture_comment(tctx, "Doing flush after write\n");
912 flsh.flush.level = RAW_FLUSH_FLUSH;
913 flsh.flush.in.file.fnum = fnum1;
914 status = smb_raw_flush(cli->tree, &flsh);
915 if (!NT_STATUS_IS_OK(status)) {
916 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
920 /* Once the time was set using setfileinfo then it stays set - writes
921 don't have any effect. But make sure. */
922 start = timeval_current();
923 end = timeval_add(&start, (15*sec), 0);
924 while (!timeval_expired(&end)) {
925 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
927 if (!NT_STATUS_IS_OK(status)) {
928 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
932 torture_comment(tctx, "write time %s\n",
933 nt_time_string(tctx, finfo2.basic_info.out.write_time));
934 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
935 double diff = timeval_elapsed(&start);
936 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
943 smb_msleep(1 * msec);
946 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
947 torture_comment(tctx, "Server did not update write time (correct)\n");
951 smb_msleep(2 * msec);
953 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
955 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
959 torture_comment(tctx, "Doing a 10 byte write to extend the file via second fd and see if this changes the last write time.\n");
961 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
964 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
965 (int)written, __location__);
969 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
971 if (!NT_STATUS_IS_OK(status)) {
972 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
975 torture_comment(tctx, "write time %s\n",
976 nt_time_string(tctx, finfo2.basic_info.out.write_time));
977 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
978 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
982 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
983 smbcli_close(cli->tree, fnum1);
986 torture_comment(tctx, "Doing a 10 byte write to extend the file via second fd and see if this changes the last write time.\n");
988 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
991 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
992 (int)written, __location__);
996 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
997 finfo1.basic_info.in.file.fnum = fnum2;
999 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1001 if (!NT_STATUS_IS_OK(status)) {
1002 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1005 torture_comment(tctx, "write time %s\n",
1006 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1007 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1008 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1012 /* Once the time was set using setfileinfo then it stays set - writes
1013 don't have any effect. But make sure. */
1014 start = timeval_current();
1015 end = timeval_add(&start, (15*sec), 0);
1016 while (!timeval_expired(&end)) {
1017 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1019 if (!NT_STATUS_IS_OK(status)) {
1020 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1024 torture_comment(tctx, "write time %s\n",
1025 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1026 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1027 double diff = timeval_elapsed(&start);
1028 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1035 smb_msleep(1 * msec);
1038 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1039 torture_comment(tctx, "Server did not update write time (correct)\n");
1042 torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1044 smbcli_close(cli->tree, fnum2);
1047 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1049 torture_comment(tctx, "Failed to open %s\n", fname);
1053 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1054 finfo1.basic_info.in.file.fnum = fnum1;
1057 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1059 if (!NT_STATUS_IS_OK(status)) {
1060 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1064 torture_comment(tctx, "Second open initial write time %s\n",
1065 nt_time_string(tctx, finfo1.basic_info.out.write_time));
1067 smb_msleep(10 * msec);
1068 torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1070 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1072 if (written != 10) {
1073 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1074 (int)written, __location__);
1078 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1079 finfo1.basic_info.in.file.fnum = fnum1;
1081 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1083 if (!NT_STATUS_IS_OK(status)) {
1084 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1087 torture_comment(tctx, "write time %s\n",
1088 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1089 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1090 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1094 /* Now the write time should be updated again */
1095 start = timeval_current();
1096 end = timeval_add(&start, (15*sec), 0);
1097 while (!timeval_expired(&end)) {
1098 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1100 if (!NT_STATUS_IS_OK(status)) {
1101 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1105 torture_comment(tctx, "write time %s\n",
1106 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1107 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1108 double diff = timeval_elapsed(&start);
1109 if (diff < (used_delay / (double)1000000)) {
1110 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1111 "(expected > %.2f) (wrong!)\n",
1112 diff, used_delay / (double)1000000);
1117 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1126 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1127 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
1132 /* One more test to do. We should read the filetime via findfirst on the
1133 second connection to ensure it's the same. This is very easy for a Windows
1134 server but a bastard to get right on a POSIX server. JRA. */
1137 smbcli_close(cli->tree, fnum1);
1138 smbcli_unlink(cli->tree, fname);
1139 smbcli_deltree(cli->tree, BASEDIR);
1145 /* Windows does obviously not update the stat info during a write call. I
1146 * *think* this is the problem causing a spurious Excel 2003 on XP error
1147 * message when saving a file. Excel does a setfileinfo, writes, and then does
1148 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1149 * that the file might have been changed in between. What i've been able to
1150 * trace down is that this happens if the getpathinfo after the write shows a
1151 * different last write time than the setfileinfo showed. This is really
1155 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
1156 struct smbcli_state *cli2)
1158 union smb_fileinfo finfo1, finfo2;
1159 const char *fname = BASEDIR "\\torture_file.txt";
1165 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1166 int normal_delay = 2000000;
1167 double sec = ((double)used_delay) / ((double)normal_delay);
1168 int msec = 1000 * sec;
1170 torture_comment(tctx, "\nRunning test_finfo_after_write\n");
1172 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1174 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1177 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1181 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1182 finfo1.basic_info.in.file.fnum = fnum1;
1184 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1186 if (!NT_STATUS_IS_OK(status)) {
1188 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1192 smb_msleep(1 * msec);
1194 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1197 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1202 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1204 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1205 smbcli_errstr(cli2->tree));
1210 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1213 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1219 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1220 finfo2.basic_info.in.file.path = fname;
1222 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1224 if (!NT_STATUS_IS_OK(status)) {
1225 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
1231 if (finfo1.basic_info.out.create_time !=
1232 finfo2.basic_info.out.create_time) {
1233 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1238 if (finfo1.basic_info.out.access_time !=
1239 finfo2.basic_info.out.access_time) {
1240 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1245 if (finfo1.basic_info.out.write_time !=
1246 finfo2.basic_info.out.write_time) {
1247 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1248 "write time conn 1 = %s, conn 2 = %s",
1249 nt_time_string(tctx, finfo1.basic_info.out.write_time),
1250 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1255 if (finfo1.basic_info.out.change_time !=
1256 finfo2.basic_info.out.change_time) {
1257 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1262 /* One of the two following calls updates the qpathinfo. */
1264 /* If you had skipped the smbcli_write on fnum2, it would
1265 * *not* have updated the stat on disk */
1267 smbcli_close(cli2->tree, fnum2);
1270 /* This call is only for the people looking at ethereal :-) */
1271 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1272 finfo2.basic_info.in.file.path = fname;
1274 status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1276 if (!NT_STATUS_IS_OK(status)) {
1277 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1284 smbcli_close(cli->tree, fnum1);
1285 smbcli_unlink(cli->tree, fname);
1286 smbcli_deltree(cli->tree, BASEDIR);
1291 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1292 uint64_t r = 10*1000*1000; \
1293 NTTIME g = (given).basic_info.out.write_time; \
1294 NTTIME gr = (g / r) * r; \
1295 NTTIME c = (correct).basic_info.out.write_time; \
1296 NTTIME cr = (c / r) * r; \
1297 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1299 if (strict && (g cmp c)) { \
1301 } else if ((g cmp c) && (gr cmp cr)) { \
1302 /* handle filesystem without high resolution timestamps */ \
1306 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1307 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1308 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1313 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1314 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1315 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1316 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1317 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1318 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1320 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1321 NTTIME g = (given).basic_info.out.access_time; \
1322 NTTIME c = (correct).basic_info.out.access_time; \
1324 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1325 #given, nt_time_string(tctx, g), \
1326 #cmp, #correct, nt_time_string(tctx, c)); \
1331 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1332 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1334 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1335 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1336 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1339 #define GET_INFO_FILE(finfo) do { \
1341 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1342 if (!NT_STATUS_IS_OK(_status)) { \
1344 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1345 nt_errstr(_status)); \
1348 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1349 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1350 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1352 #define GET_INFO_FILE2(finfo) do { \
1354 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1355 if (!NT_STATUS_IS_OK(_status)) { \
1357 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1358 nt_errstr(_status)); \
1361 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1362 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1363 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1365 #define GET_INFO_PATH(pinfo) do { \
1367 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1368 if (!NT_STATUS_IS_OK(_status)) { \
1369 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1370 nt_errstr(_status)); \
1374 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1375 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1376 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1378 #define GET_INFO_BOTH(finfo,pinfo) do { \
1379 GET_INFO_FILE(finfo); \
1380 GET_INFO_PATH(pinfo); \
1381 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1384 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1386 union smb_setfileinfo sfinfo; \
1387 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1388 sfinfo.basic_info.in.file.fnum = tfnum; \
1389 sfinfo.basic_info.in.create_time = 0; \
1390 sfinfo.basic_info.in.access_time = 0; \
1391 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1392 sfinfo.basic_info.in.change_time = 0; \
1393 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1394 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1395 if (!NT_STATUS_IS_OK(_status)) { \
1396 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1397 nt_errstr(_status)); \
1402 #define SET_INFO_FILE(finfo, wrtime) \
1403 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1405 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1407 union smb_setfileinfo sfinfo; \
1408 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1409 sfinfo.basic_info.in.file.fnum = tfnum; \
1410 sfinfo.basic_info.in.create_time = 0; \
1411 sfinfo.basic_info.in.access_time = 0; \
1412 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1413 sfinfo.basic_info.in.write_time += (ns); \
1414 sfinfo.basic_info.in.change_time = 0; \
1415 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1416 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1417 if (!NT_STATUS_IS_OK(_status)) { \
1418 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1419 nt_errstr(_status)); \
1425 static bool test_delayed_write_update3(struct torture_context *tctx,
1426 struct smbcli_state *cli,
1427 struct smbcli_state *cli2)
1429 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1430 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1431 const char *fname = BASEDIR "\\torture_file3.txt";
1435 struct timeval start;
1437 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1438 int normal_delay = 2000000;
1439 double sec = ((double)used_delay) / ((double)normal_delay);
1440 int msec = 1000 * sec;
1442 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
1444 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1446 torture_comment(tctx, "Open the file handle\n");
1447 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1450 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1454 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1455 finfo0.basic_info.in.file.fnum = fnum1;
1459 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1460 pinfo0.basic_info.in.file.path = fname;
1466 /* get the initial times */
1467 GET_INFO_BOTH(finfo0,pinfo0);
1470 * make sure the write time is updated 2 seconds later
1471 * calcuated from the first write
1472 * (but expect upto 5 seconds extra time for a busy server)
1474 start = timeval_current();
1475 end = timeval_add(&start, 7 * sec, 0);
1476 while (!timeval_expired(&end)) {
1478 torture_comment(tctx, "Do a write on the file handle\n");
1479 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1481 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1485 /* get the times after the write */
1486 GET_INFO_FILE(finfo1);
1488 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1489 double diff = timeval_elapsed(&start);
1490 if (diff < (used_delay / (double)1000000)) {
1491 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1492 "(write time update delay == %.2f) (wrong!)\n",
1493 diff, used_delay / (double)1000000);
1498 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1503 smb_msleep(0.5 * msec);
1506 GET_INFO_BOTH(finfo1,pinfo1);
1507 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1509 /* sure any further write doesn't update the write time */
1510 start = timeval_current();
1511 end = timeval_add(&start, 15 * sec, 0);
1512 while (!timeval_expired(&end)) {
1514 torture_comment(tctx, "Do a write on the file handle\n");
1515 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1517 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1521 /* get the times after the write */
1522 GET_INFO_BOTH(finfo2,pinfo2);
1524 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1525 double diff = timeval_elapsed(&start);
1526 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1532 smb_msleep(1 * msec);
1535 GET_INFO_BOTH(finfo2,pinfo2);
1536 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1537 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1538 torture_comment(tctx, "Server did not update write_time (correct)\n");
1542 smb_msleep(5 * msec);
1544 GET_INFO_BOTH(finfo3,pinfo3);
1545 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1548 * the close updates the write time to the time of the close
1549 * and not to the time of the last write!
1551 torture_comment(tctx, "Close the file handle\n");
1552 smbcli_close(cli->tree, fnum1);
1555 GET_INFO_PATH(pinfo4);
1556 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1558 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1559 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1564 smbcli_close(cli->tree, fnum1);
1565 smbcli_unlink(cli->tree, fname);
1566 smbcli_deltree(cli->tree, BASEDIR);
1572 * Show that a truncate write always updates the write time even
1573 * if an initial write has already updated the write time.
1576 static bool test_delayed_write_update3a(struct torture_context *tctx,
1577 struct smbcli_state *cli,
1578 struct smbcli_state *cli2)
1580 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1581 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1582 const char *fname = BASEDIR "\\torture_file3a.txt";
1587 struct timeval start;
1589 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1590 int normal_delay = 2000000;
1591 double sec = ((double)used_delay) / ((double)normal_delay);
1592 int msec = 1000 * sec;
1594 torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
1596 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1598 torture_comment(tctx, "Open the file handle\n");
1599 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1602 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1606 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1607 finfo0.basic_info.in.file.fnum = fnum1;
1611 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1612 pinfo0.basic_info.in.file.path = fname;
1618 /* get the initial times */
1619 GET_INFO_BOTH(finfo0,pinfo0);
1622 * sleep some time, to demonstrate the handling of write times
1623 * doesn't depend on the time since the open
1625 smb_msleep(5 * msec);
1627 /* get the initial times */
1628 GET_INFO_BOTH(finfo1,pinfo1);
1629 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1632 * make sure the write time is updated 2 seconds later
1633 * calcuated from the first write
1634 * (but expect upto 5 seconds extra time for a busy server)
1636 start = timeval_current();
1637 end = timeval_add(&start, 7 * sec, 0);
1638 while (!timeval_expired(&end)) {
1640 torture_comment(tctx, "Do a write on the file handle\n");
1641 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1643 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1647 /* get the times after the write */
1648 GET_INFO_FILE(finfo1);
1650 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1651 double diff = timeval_elapsed(&start);
1652 if (diff < (used_delay / (double)1000000)) {
1653 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1654 "(1sec == %.2f) (wrong!)\n",
1660 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1665 smb_msleep(0.5 * msec);
1668 GET_INFO_BOTH(finfo1,pinfo1);
1669 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1671 smb_msleep(3 * msec);
1674 * demonstrate that a truncate write always
1675 * updates the write time immediately
1677 for (i=0; i < 3; i++) {
1678 smb_msleep(2 * msec);
1680 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1681 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1683 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1687 /* get the times after the write */
1688 GET_INFO_BOTH(finfo2,pinfo2);
1689 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1693 smb_msleep(3 * msec);
1695 /* sure any further write doesn't update the write time */
1696 start = timeval_current();
1697 end = timeval_add(&start, 15 * sec, 0);
1698 while (!timeval_expired(&end)) {
1700 torture_comment(tctx, "Do a write on the file handle\n");
1701 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1703 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1707 /* get the times after the write */
1708 GET_INFO_BOTH(finfo2,pinfo2);
1710 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1711 double diff = timeval_elapsed(&start);
1712 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1718 smb_msleep(1 * msec);
1721 GET_INFO_BOTH(finfo2,pinfo2);
1722 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1723 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1724 torture_comment(tctx, "Server did not update write_time (correct)\n");
1728 smb_msleep(3 * msec);
1730 /* get the initial times */
1731 GET_INFO_BOTH(finfo1,pinfo1);
1732 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1735 * demonstrate that a truncate write always
1736 * updates the write time immediately
1738 for (i=0; i < 3; i++) {
1739 smb_msleep(2 * msec);
1741 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1742 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1744 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1748 /* get the times after the write */
1749 GET_INFO_BOTH(finfo2,pinfo2);
1750 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1755 smb_msleep(3 * msec);
1757 GET_INFO_BOTH(finfo3,pinfo3);
1758 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1761 * the close doesn't update the write time
1763 torture_comment(tctx, "Close the file handle\n");
1764 smbcli_close(cli->tree, fnum1);
1767 GET_INFO_PATH(pinfo4);
1768 COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1770 if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1771 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1776 smbcli_close(cli->tree, fnum1);
1777 smbcli_unlink(cli->tree, fname);
1778 smbcli_deltree(cli->tree, BASEDIR);
1784 * Show a close after write updates the write timestamp to
1785 * the close time, not the last write time.
1788 static bool test_delayed_write_update3b(struct torture_context *tctx,
1789 struct smbcli_state *cli,
1790 struct smbcli_state *cli2)
1792 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1793 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1794 const char *fname = BASEDIR "\\torture_file3b.txt";
1798 struct timeval start;
1800 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1801 int normal_delay = 2000000;
1802 double sec = ((double)used_delay) / ((double)normal_delay);
1803 int msec = 1000 * sec;
1805 torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
1807 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1809 torture_comment(tctx, "Open the file handle\n");
1810 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1813 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1817 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1818 finfo0.basic_info.in.file.fnum = fnum1;
1822 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1823 pinfo0.basic_info.in.file.path = fname;
1829 /* get the initial times */
1830 GET_INFO_BOTH(finfo0,pinfo0);
1833 * sleep some time, to demonstrate the handling of write times
1834 * doesn't depend on the time since the open
1836 smb_msleep(5 * msec);
1838 /* get the initial times */
1839 GET_INFO_BOTH(finfo1,pinfo1);
1840 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1843 * make sure the write time is updated 2 seconds later
1844 * calcuated from the first write
1845 * (but expect upto 5 seconds extra time for a busy server)
1847 start = timeval_current();
1848 end = timeval_add(&start, 7 * sec, 0);
1849 while (!timeval_expired(&end)) {
1851 torture_comment(tctx, "Do a write on the file handle\n");
1852 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1854 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1858 /* get the times after the write */
1859 GET_INFO_FILE(finfo1);
1861 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1862 double diff = timeval_elapsed(&start);
1863 if (diff < (used_delay / (double)1000000)) {
1864 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1865 "(expected > %.2f) (wrong!)\n",
1866 diff, used_delay / (double)1000000);
1871 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1872 "(write time update delay == %.2f) (correct)\n",
1873 diff, used_delay / (double)1000000);
1876 smb_msleep(0.5 * msec);
1879 GET_INFO_BOTH(finfo1,pinfo1);
1880 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1882 /* sure any further write doesn't update the write time */
1883 start = timeval_current();
1884 end = timeval_add(&start, 15 * sec, 0);
1885 while (!timeval_expired(&end)) {
1887 torture_comment(tctx, "Do a write on the file handle\n");
1888 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1890 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1894 /* get the times after the write */
1895 GET_INFO_BOTH(finfo2,pinfo2);
1897 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1898 double diff = timeval_elapsed(&start);
1899 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1905 smb_msleep(1 * msec);
1908 GET_INFO_BOTH(finfo2,pinfo2);
1909 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1910 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1911 torture_comment(tctx, "Server did not update write_time (correct)\n");
1915 smb_msleep(5 * msec);
1917 GET_INFO_BOTH(finfo3,pinfo3);
1918 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1921 * the close updates the write time to the time of the close
1922 * and not to the time of the last write!
1924 torture_comment(tctx, "Close the file handle\n");
1925 smbcli_close(cli->tree, fnum1);
1928 GET_INFO_PATH(pinfo4);
1929 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1931 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1932 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1937 smbcli_close(cli->tree, fnum1);
1938 smbcli_unlink(cli->tree, fname);
1939 smbcli_deltree(cli->tree, BASEDIR);
1945 * Check that a write after a truncate write doesn't update
1946 * the timestamp, but a truncate write after a write does.
1947 * Also prove that a close after a truncate write updates the
1948 * timestamp to current, not the time of last write.
1951 static bool test_delayed_write_update3c(struct torture_context *tctx,
1952 struct smbcli_state *cli,
1953 struct smbcli_state *cli2)
1955 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1956 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1957 const char *fname = BASEDIR "\\torture_file3c.txt";
1962 struct timeval start;
1964 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1965 int normal_delay = 2000000;
1966 double sec = ((double)used_delay) / ((double)normal_delay);
1967 int msec = 1000 * sec;
1969 torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
1971 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1973 torture_comment(tctx, "Open the file handle\n");
1974 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1977 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1981 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1982 finfo0.basic_info.in.file.fnum = fnum1;
1986 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1987 pinfo0.basic_info.in.file.path = fname;
1993 /* get the initial times */
1994 GET_INFO_BOTH(finfo0,pinfo0);
1997 * sleep some time, to demonstrate the handling of write times
1998 * doesn't depend on the time since the open
2000 smb_msleep(5 * msec);
2002 /* get the initial times */
2003 GET_INFO_BOTH(finfo1,pinfo1);
2004 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2007 * demonstrate that a truncate write always
2008 * updates the write time immediately
2010 for (i=0; i < 3; i++) {
2011 smb_msleep(2 * msec);
2013 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
2014 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2016 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2020 /* get the times after the write */
2021 GET_INFO_BOTH(finfo2,pinfo2);
2022 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2026 start = timeval_current();
2027 end = timeval_add(&start, 7 * sec, 0);
2028 while (!timeval_expired(&end)) {
2030 torture_comment(tctx, "Do a write on the file handle\n");
2031 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2033 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2037 /* get the times after the write */
2038 GET_INFO_FILE(finfo2);
2040 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2041 double diff = timeval_elapsed(&start);
2042 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2048 smb_msleep(1 * msec);
2051 GET_INFO_BOTH(finfo2,pinfo2);
2052 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2053 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2054 torture_comment(tctx, "Server did not update write_time (correct)\n");
2058 smb_msleep(5 * msec);
2060 /* get the initial times */
2061 GET_INFO_BOTH(finfo1,pinfo1);
2062 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2065 * demonstrate that a truncate write always
2066 * updates the write time immediately
2068 for (i=0; i < 3; i++) {
2069 smb_msleep(2 * msec);
2071 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2072 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2074 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2078 /* get the times after the write */
2079 GET_INFO_BOTH(finfo2,pinfo2);
2080 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2085 smb_msleep(5 * msec);
2087 GET_INFO_BOTH(finfo2,pinfo2);
2088 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2090 /* sure any further write doesn't update the write time */
2091 start = timeval_current();
2092 end = timeval_add(&start, 15 * sec, 0);
2093 while (!timeval_expired(&end)) {
2095 torture_comment(tctx, "Do a write on the file handle\n");
2096 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2098 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2102 /* get the times after the write */
2103 GET_INFO_BOTH(finfo2,pinfo2);
2105 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2106 double diff = timeval_elapsed(&start);
2107 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2113 smb_msleep(1 * msec);
2116 GET_INFO_BOTH(finfo2,pinfo2);
2117 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2118 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2119 torture_comment(tctx, "Server did not update write_time (correct)\n");
2123 smb_msleep(5 * msec);
2125 GET_INFO_BOTH(finfo3,pinfo3);
2126 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2129 * the close updates the write time to the time of the close
2130 * and not to the time of the last write!
2132 torture_comment(tctx, "Close the file handle\n");
2133 smbcli_close(cli->tree, fnum1);
2136 GET_INFO_PATH(pinfo4);
2137 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2139 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2140 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2145 smbcli_close(cli->tree, fnum1);
2146 smbcli_unlink(cli->tree, fname);
2147 smbcli_deltree(cli->tree, BASEDIR);
2153 * Show only the first write updates the timestamp, and a close
2154 * after writes updates to current (I think this is the same
2158 static bool test_delayed_write_update4(struct torture_context *tctx,
2159 struct smbcli_state *cli,
2160 struct smbcli_state *cli2)
2162 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
2163 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
2164 const char *fname = BASEDIR "\\torture_file4.txt";
2168 struct timeval start;
2170 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2171 int normal_delay = 2000000;
2172 double sec = ((double)used_delay) / ((double)normal_delay);
2173 int msec = 1000 * sec;
2175 torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2177 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2179 torture_comment(tctx, "Open the file handle\n");
2180 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2183 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2187 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2188 finfo0.basic_info.in.file.fnum = fnum1;
2192 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2193 pinfo0.basic_info.in.file.path = fname;
2199 /* get the initial times */
2200 GET_INFO_BOTH(finfo0,pinfo0);
2203 smb_msleep(5 * msec);
2206 torture_comment(tctx, "Do a write on the file handle\n");
2207 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2209 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2214 GET_INFO_BOTH(finfo1,pinfo1);
2215 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2218 * make sure the write time is updated 2 seconds later
2219 * calcuated from the first write
2220 * (but expect upto 3 seconds extra time for a busy server)
2222 start = timeval_current();
2223 end = timeval_add(&start, 5 * sec, 0);
2224 while (!timeval_expired(&end)) {
2225 /* get the times after the first write */
2226 GET_INFO_FILE(finfo1);
2228 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2229 double diff = timeval_elapsed(&start);
2230 if (diff < (used_delay / (double)1000000)) {
2231 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
2232 "(expected > %.2f) (wrong!)\n",
2233 diff, used_delay / (double)1000000);
2238 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2239 "(write time update delay == %.2f) (correct)\n",
2240 diff, used_delay / (double)1000000);
2243 smb_msleep(0.5 * msec);
2246 GET_INFO_BOTH(finfo1,pinfo1);
2247 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2249 /* sure any further write doesn't update the write time */
2250 start = timeval_current();
2251 end = timeval_add(&start, 15 * sec, 0);
2252 while (!timeval_expired(&end)) {
2254 torture_comment(tctx, "Do a write on the file handle\n");
2255 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2257 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2261 /* get the times after the write */
2262 GET_INFO_BOTH(finfo2,pinfo2);
2264 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2265 double diff = timeval_elapsed(&start);
2266 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2272 smb_msleep(1 * msec);
2275 GET_INFO_BOTH(finfo2,pinfo2);
2276 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2277 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2278 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2282 smb_msleep(5 * msec);
2284 GET_INFO_BOTH(finfo3,pinfo3);
2285 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2288 * the close updates the write time to the time of the close
2289 * and not to the time of the last write!
2291 torture_comment(tctx, "Close the file handle\n");
2292 smbcli_close(cli->tree, fnum1);
2295 GET_INFO_PATH(pinfo4);
2296 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2298 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2299 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2304 smbcli_close(cli->tree, fnum1);
2305 smbcli_unlink(cli->tree, fname);
2306 smbcli_deltree(cli->tree, BASEDIR);
2312 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2315 static bool test_delayed_write_update5(struct torture_context *tctx,
2316 struct smbcli_state *cli,
2317 struct smbcli_state *cli2)
2319 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2320 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2321 const char *fname = BASEDIR "\\torture_file5.txt";
2325 struct timeval start;
2327 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2328 int normal_delay = 2000000;
2329 double sec = ((double)used_delay) / ((double)normal_delay);
2330 int msec = 1000 * sec;
2332 torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2334 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2336 torture_comment(tctx, "Open the file handle\n");
2337 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2340 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2344 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2345 finfo0.basic_info.in.file.fnum = fnum1;
2351 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2352 pinfo0.basic_info.in.file.path = fname;
2360 /* get the initial times */
2361 GET_INFO_BOTH(finfo0,pinfo0);
2364 torture_comment(tctx, "Do a write on the file handle\n");
2365 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2367 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2372 GET_INFO_BOTH(finfo1,pinfo1);
2373 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2375 torture_comment(tctx, "Set write time in the future on the file handle\n");
2376 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2377 GET_INFO_BOTH(finfo2,pinfo2);
2378 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2380 torture_comment(tctx, "Set write time in the past on the file handle\n");
2381 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2382 GET_INFO_BOTH(finfo2,pinfo2);
2383 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2385 /* make sure the 2 second delay from the first write are canceled */
2386 start = timeval_current();
2387 end = timeval_add(&start, 15 * sec, 0);
2388 while (!timeval_expired(&end)) {
2390 /* get the times after the first write */
2391 GET_INFO_BOTH(finfo3,pinfo3);
2393 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2394 double diff = timeval_elapsed(&start);
2395 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2401 smb_msleep(1 * msec);
2404 GET_INFO_BOTH(finfo3,pinfo3);
2405 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2406 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2407 torture_comment(tctx, "Server did not update write_time (correct)\n");
2410 /* sure any further write doesn't update the write time */
2411 start = timeval_current();
2412 end = timeval_add(&start, 15 * sec, 0);
2413 while (!timeval_expired(&end)) {
2415 torture_comment(tctx, "Do a write on the file handle\n");
2416 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2418 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2422 /* get the times after the write */
2423 GET_INFO_BOTH(finfo4,pinfo4);
2425 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2426 double diff = timeval_elapsed(&start);
2427 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2433 smb_msleep(1 * msec);
2436 GET_INFO_BOTH(finfo4,pinfo4);
2437 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2438 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2439 torture_comment(tctx, "Server did not update write_time (correct)\n");
2443 smb_msleep(5 * msec);
2445 GET_INFO_BOTH(finfo5,pinfo5);
2446 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2449 * the close doesn't update the write time
2451 torture_comment(tctx, "Close the file handle\n");
2452 smbcli_close(cli->tree, fnum1);
2455 GET_INFO_PATH(pinfo6);
2456 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2458 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2459 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2464 smbcli_close(cli->tree, fnum1);
2465 smbcli_unlink(cli->tree, fname);
2466 smbcli_deltree(cli->tree, BASEDIR);
2472 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2475 static bool test_delayed_write_update5b(struct torture_context *tctx,
2476 struct smbcli_state *cli,
2477 struct smbcli_state *cli2)
2479 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2480 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2481 const char *fname = BASEDIR "\\torture_fileb.txt";
2485 struct timeval start;
2487 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2488 int normal_delay = 2000000;
2489 double sec = ((double)used_delay) / ((double)normal_delay);
2490 int msec = 1000 * sec;
2492 torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2494 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2496 torture_comment(tctx, "Open the file handle\n");
2497 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2500 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2504 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2505 finfo0.basic_info.in.file.fnum = fnum1;
2511 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2512 pinfo0.basic_info.in.file.path = fname;
2520 /* get the initial times */
2521 GET_INFO_BOTH(finfo0,pinfo0);
2524 torture_comment(tctx, "Do a write on the file handle\n");
2525 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2527 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2532 GET_INFO_BOTH(finfo1,pinfo1);
2533 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2535 torture_comment(tctx, "Set write time in the future on the file handle\n");
2536 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2537 GET_INFO_BOTH(finfo2,pinfo2);
2538 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2540 torture_comment(tctx, "Set write time in the past on the file handle\n");
2541 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2542 GET_INFO_BOTH(finfo2,pinfo2);
2543 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2545 /* make sure the 2 second delay from the first write are canceled */
2546 start = timeval_current();
2547 end = timeval_add(&start, 15 * sec, 0);
2548 while (!timeval_expired(&end)) {
2550 /* get the times after the first write */
2551 GET_INFO_BOTH(finfo3,pinfo3);
2553 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2554 double diff = timeval_elapsed(&start);
2555 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2561 smb_msleep(1 * msec);
2564 GET_INFO_BOTH(finfo3,pinfo3);
2565 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2566 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2567 torture_comment(tctx, "Server did not update write_time (correct)\n");
2570 /* Do any further write (truncates) update the write time ? */
2571 start = timeval_current();
2572 end = timeval_add(&start, 15 * sec, 0);
2573 while (!timeval_expired(&end)) {
2575 torture_comment(tctx, "Do a truncate write on the file handle\n");
2576 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2578 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2582 /* get the times after the write */
2583 GET_INFO_BOTH(finfo4,pinfo4);
2585 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2586 double diff = timeval_elapsed(&start);
2587 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2593 smb_msleep(1 * msec);
2596 GET_INFO_BOTH(finfo4,pinfo4);
2597 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2598 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2599 torture_comment(tctx, "Server did not update write_time (correct)\n");
2603 smb_msleep(5 * msec);
2605 GET_INFO_BOTH(finfo5,pinfo5);
2606 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2609 * the close doesn't update the write time
2611 torture_comment(tctx, "Close the file handle\n");
2612 smbcli_close(cli->tree, fnum1);
2615 GET_INFO_PATH(pinfo6);
2616 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2618 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2619 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2624 smbcli_close(cli->tree, fnum1);
2625 smbcli_unlink(cli->tree, fname);
2626 smbcli_deltree(cli->tree, BASEDIR);
2632 * Open 2 handles on a file. Write one one and then set the
2633 * WRITE TIME explicitly on the other. Ensure the write time
2634 * update is cancelled. Ensure the write time is updated to
2635 * the close time when the non-explicit set handle is closed.
2639 static bool test_delayed_write_update6(struct torture_context *tctx,
2640 struct smbcli_state *cli,
2641 struct smbcli_state *cli2)
2643 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2644 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2645 const char *fname = BASEDIR "\\torture_file6.txt";
2650 struct timeval start;
2652 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2653 int normal_delay = 2000000;
2654 double sec = ((double)used_delay) / ((double)normal_delay);
2655 int msec = 1000 * sec;
2658 torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2660 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2662 torture_comment(tctx, "Open the file handle\n");
2663 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2666 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2671 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2672 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2675 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2680 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2681 finfo0.basic_info.in.file.fnum = fnum1;
2687 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2688 pinfo0.basic_info.in.file.path = fname;
2697 /* get the initial times */
2698 GET_INFO_BOTH(finfo0,pinfo0);
2701 torture_comment(tctx, "Do a write on the file handle\n");
2702 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2704 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2709 GET_INFO_BOTH(finfo1,pinfo1);
2710 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2712 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2713 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2714 GET_INFO_BOTH(finfo2,pinfo2);
2715 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2717 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2718 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2719 GET_INFO_BOTH(finfo2,pinfo2);
2720 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2722 /* make sure the 2 second delay from the first write are canceled */
2723 start = timeval_current();
2724 end = timeval_add(&start, 10 * sec, 0);
2725 while (!timeval_expired(&end)) {
2727 /* get the times after the first write */
2728 GET_INFO_BOTH(finfo3,pinfo3);
2730 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2731 double diff = timeval_elapsed(&start);
2732 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2738 smb_msleep(1 * msec);
2741 GET_INFO_BOTH(finfo3,pinfo3);
2742 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2743 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2744 torture_comment(tctx, "Server did not update write_time (correct)\n");
2747 /* sure any further write doesn't update the write time */
2748 start = timeval_current();
2749 end = timeval_add(&start, 10 * sec, 0);
2750 while (!timeval_expired(&end)) {
2752 torture_comment(tctx, "Do a write on the file handle\n");
2753 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2755 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2759 /* get the times after the write */
2760 GET_INFO_BOTH(finfo4,pinfo4);
2762 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2763 double diff = timeval_elapsed(&start);
2764 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2770 smb_msleep(1 * msec);
2773 GET_INFO_BOTH(finfo4,pinfo4);
2774 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2775 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2776 torture_comment(tctx, "Server did not update write_time (correct)\n");
2780 smb_msleep(5 * msec);
2782 GET_INFO_BOTH(finfo5,pinfo5);
2783 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2786 * the close updates the write time to the time of the close
2787 * as the write time was set on the 2nd handle
2789 torture_comment(tctx, "Close the file handle\n");
2790 smbcli_close(cli->tree, fnum1);
2793 GET_INFO_PATH(pinfo6);
2794 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2796 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2797 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2800 /* See what the second write handle thinks the time is ? */
2801 finfo5.basic_info.in.file.fnum = fnum2;
2802 GET_INFO_FILE2(finfo5);
2803 COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
2805 /* See if we have lost the sticky write time on handle2 */
2806 smb_msleep(3 * msec);
2807 torture_comment(tctx, "Have we lost the sticky write time ?\n");
2809 /* Make sure any further normal write doesn't update the write time */
2810 start = timeval_current();
2811 end = timeval_add(&start, 10 * sec, 0);
2812 while (!timeval_expired(&end)) {
2814 torture_comment(tctx, "Do a write on the second file handle\n");
2815 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
2817 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2821 /* get the times after the write */
2822 GET_INFO_FILE2(finfo5);
2823 GET_INFO_PATH(pinfo6);
2825 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2826 double diff = timeval_elapsed(&start);
2827 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2833 smb_msleep(1 * msec);
2836 /* What about a truncate write ? */
2837 start = timeval_current();
2838 end = timeval_add(&start, 10 * sec, 0);
2839 while (!timeval_expired(&end)) {
2841 torture_comment(tctx, "Do a truncate write on the second file handle\n");
2842 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
2844 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2848 /* get the times after the write */
2849 GET_INFO_FILE2(finfo5);
2850 GET_INFO_PATH(pinfo6);
2852 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2853 double diff = timeval_elapsed(&start);
2854 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2860 smb_msleep(1 * msec);
2864 /* keep the 2nd handle open and rerun tests */
2871 * closing the 2nd handle will cause no write time update
2872 * as the write time was explicit set on this handle
2874 torture_comment(tctx, "Close the 2nd file handle\n");
2875 smbcli_close(cli2->tree, fnum2);
2878 GET_INFO_PATH(pinfo7);
2879 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2881 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2882 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2887 smbcli_close(cli->tree, fnum1);
2889 smbcli_close(cli2->tree, fnum2);
2890 smbcli_unlink(cli->tree, fname);
2891 smbcli_deltree(cli->tree, BASEDIR);
2896 static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
2898 union smb_open open_parms;
2899 union smb_fileinfo finfo1, finfo2, finfo3;
2900 const char *fname = BASEDIR "\\torture_file7.txt";
2904 TALLOC_CTX *mem_ctx;
2906 torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2908 mem_ctx = talloc_init("test_delayed_write_update7");
2909 if (!mem_ctx) return false;
2911 ZERO_STRUCT(finfo1);
2912 ZERO_STRUCT(finfo2);
2913 ZERO_STRUCT(finfo3);
2914 ZERO_STRUCT(open_parms);
2916 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2918 /* Create the file. */
2919 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2921 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
2925 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2926 finfo1.basic_info.in.file.fnum = fnum1;
2930 /* Get the initial timestamps. */
2931 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
2933 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2935 /* Set the pending write time to a value with ns. */
2936 SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
2938 /* Get the current pending write time by fnum. */
2939 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
2941 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2943 /* Ensure the time is actually different. */
2944 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2945 torture_result(tctx, TORTURE_FAIL,
2946 "setfileinfo time matches original fileinfo time");
2950 /* Get the current pending write time by path. */
2951 finfo3.basic_info.in.file.path = fname;
2952 status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
2954 if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
2955 torture_result(tctx, TORTURE_FAIL,
2956 "qpathinfo time doens't match fileinfo time");
2960 /* Now close the file. Re-open and check that the write
2961 time is identical to the one we wrote. */
2963 smbcli_close(cli->tree, fnum1);
2965 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
2966 open_parms.ntcreatex.in.flags = 0;
2967 open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
2968 open_parms.ntcreatex.in.file_attr = 0;
2969 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
2970 NTCREATEX_SHARE_ACCESS_READ|
2971 NTCREATEX_SHARE_ACCESS_WRITE;
2972 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
2973 open_parms.ntcreatex.in.create_options = 0;
2974 open_parms.ntcreatex.in.fname = fname;
2976 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
2977 talloc_free(mem_ctx);
2979 if (!NT_STATUS_IS_OK(status)) {
2980 torture_result(tctx, TORTURE_FAIL,
2981 "setfileinfo time matches original fileinfo time");
2985 fnum1 = open_parms.ntcreatex.out.file.fnum;
2987 /* Check the returned time matches. */
2988 if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
2989 torture_result(tctx, TORTURE_FAIL,
2990 "final open time does not match set time");
2996 smbcli_close(cli->tree, fnum1);
2998 smbcli_unlink(cli->tree, fname);
2999 smbcli_deltree(cli->tree, BASEDIR);
3004 Test if creating a file in a directory with an open handle updates the
3005 write timestamp (it should).
3007 static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
3009 union smb_fileinfo dir_info1, dir_info2;
3010 union smb_open open_parms;
3011 const char *fname = BASEDIR "\\torture_file.txt";
3016 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3017 int normal_delay = 2000000;
3018 double sec = ((double)used_delay) / ((double)normal_delay);
3019 int msec = 1000 * sec;
3020 TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
3022 if (!mem_ctx) return false;
3024 torture_comment(tctx, "\nRunning test directory write update\n");
3026 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
3028 /* Open a handle on the directory - and leave it open. */
3029 ZERO_STRUCT(open_parms);
3030 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3031 open_parms.ntcreatex.in.flags = 0;
3032 open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
3033 open_parms.ntcreatex.in.file_attr = 0;
3034 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3035 NTCREATEX_SHARE_ACCESS_READ|
3036 NTCREATEX_SHARE_ACCESS_WRITE;
3037 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3038 open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
3039 open_parms.ntcreatex.in.fname = BASEDIR;
3041 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3042 talloc_free(mem_ctx);
3044 if (!NT_STATUS_IS_OK(status)) {
3045 torture_result(tctx, TORTURE_FAIL,
3046 "failed to open directory handle");
3051 fnum1 = open_parms.ntcreatex.out.file.fnum;
3053 /* Store the returned write time. */
3054 ZERO_STRUCT(dir_info1);
3055 dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
3057 torture_comment(tctx, "Initial write time %s\n",
3058 nt_time_string(tctx, dir_info1.basic_info.out.write_time));
3061 smb_msleep(3 * msec);
3063 /* Now create a file within the directory. */
3064 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3066 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
3070 smbcli_close(cli->tree, fnum2);
3072 /* Read the directory write time again. */
3073 ZERO_STRUCT(dir_info2);
3074 dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3075 dir_info2.basic_info.in.file.fnum = fnum1;
3077 status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
3079 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
3081 /* Ensure it's been incremented. */
3082 COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
3084 torture_comment(tctx, "Updated write time %s\n",
3085 nt_time_string(tctx, dir_info2.basic_info.out.write_time));
3090 smbcli_close(cli->tree, fnum1);
3091 smbcli_unlink(cli->tree, fname);
3092 smbcli_deltree(cli->tree, BASEDIR);
3098 testing of delayed update of write_time
3100 struct torture_suite *torture_delay_write(void)
3102 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "delaywrite");
3104 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
3105 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
3106 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
3107 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
3108 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
3109 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
3110 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
3111 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
3112 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
3113 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
3114 torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
3115 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
3116 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
3117 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
3118 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
3119 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3120 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3121 torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);