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;
462 torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
464 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
466 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
467 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
468 "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_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
489 "file size not as expected after write(2048)");
491 torture_comment(tctx, "Initial write time %s\n",
492 nt_time_string(tctx, finfo1.all_info.out.write_time));
494 /* Do a SET_END_OF_FILE_INFO call to truncate. */
495 status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
497 torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
499 start = timeval_current();
500 end = timeval_add(&start, (120*sec), 0);
503 while (!timeval_expired(&end)) {
504 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
506 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
508 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
509 "file not truncated to expected size "
512 torture_comment(tctx, "write time %s\n",
513 nt_time_string(tctx, finfo2.all_info.out.write_time));
515 if (finfo1.all_info.out.write_time !=
516 finfo2.all_info.out.write_time)
523 smb_msleep(1 * msec);
527 torture_assert(tctx, updated,
528 "Server did not update write time within 120 seconds");
530 torture_assert(tctx, first, talloc_asprintf(tctx,
531 "Server did not update write time immediately but only "
532 "after %.2f seconds!", timeval_elapsed(&start)));
534 torture_comment(tctx, "Server updated write time immediately. Good!\n");
537 smb_msleep(2 * msec);
539 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
540 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
542 torture_assert_int_equal(tctx, written, 1,
543 "unexpected number of bytes written");
545 start = timeval_current();
546 end = timeval_add(&start, (10*sec), 0);
547 while (!timeval_expired(&end)) {
548 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
550 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
552 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
553 "file not truncated to expected size "
556 torture_comment(tctx, "write time %s\n",
557 nt_time_string(tctx, finfo3.all_info.out.write_time));
559 torture_assert_u64_equal(tctx,
560 finfo3.all_info.out.write_time,
561 finfo2.all_info.out.write_time,
562 talloc_asprintf(tctx,
563 "Server updated write time "
564 "after %.2f seconds (wrong!)",
565 timeval_elapsed(&start)));
568 smb_msleep(1 * msec);
571 torture_comment(tctx, "Server did not update write time within 10 "
574 /* the close should trigger an write time update */
575 smbcli_close(cli->tree, fnum1);
578 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
579 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
581 torture_assert_u64_not_equal(tctx,
582 pinfo4.all_info.out.write_time,
583 finfo3.all_info.out.write_time,
584 "Server did not update write time on "
587 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
588 "Server updated write time on close, but to an earlier point "
591 torture_comment(tctx, "Server updated write time on close (correct)\n");
594 smbcli_close(cli->tree, fnum1);
595 smbcli_unlink(cli->tree, fname);
596 smbcli_deltree(cli->tree, BASEDIR);
601 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
603 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
605 union smb_setfileinfo parms;
606 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
607 const char *fname = BASEDIR "\\torture_file1c.txt";
612 struct timeval start;
614 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
615 int normal_delay = 2000000;
616 double sec = ((double)used_delay) / ((double)normal_delay);
617 int msec = 1000 * sec;
620 torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
622 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
624 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
625 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
626 "Failed to open %s", fname));
628 memset(buf, 'x', 2048);
629 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
631 /* 3 second delay to ensure we get past any 2 second time
632 granularity (older systems may have that) */
633 smb_msleep(3 * msec);
635 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
636 finfo1.all_info.in.file.fnum = fnum1;
639 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
640 pinfo4.all_info.in.file.path = fname;
642 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
644 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
646 torture_comment(tctx, "Initial write time %s\n",
647 nt_time_string(tctx, finfo1.all_info.out.write_time));
649 /* Do a SET_ALLOCATION_SIZE call to truncate. */
650 parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
651 parms.allocation_info.in.file.fnum = fnum1;
652 parms.allocation_info.in.alloc_size = 0;
654 status = smb_raw_setfileinfo(cli->tree, &parms);
656 torture_assert_ntstatus_ok(tctx, status,
657 "RAW_SFILEINFO_ALLOCATION_INFO failed");
659 start = timeval_current();
660 end = timeval_add(&start, (120*sec), 0);
661 while (!timeval_expired(&end)) {
662 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
664 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
666 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 0,
667 "file not truncated to expected size "
670 torture_comment(tctx, "write time %s\n",
671 nt_time_string(tctx, finfo2.all_info.out.write_time));
672 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
673 double diff = timeval_elapsed(&start);
674 if (diff > (0.25 * (used_delay / (double)1000000))) {
675 torture_result(tctx, TORTURE_FAIL, "After SET_ALLOCATION_INFO truncate "
676 "server updated write_time after %.2f seconds"
677 "(write time update delay == %.2f)(wrong!)\n",
678 diff, used_delay / (double)1000000);
683 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
684 "server updated write_time after %.2f seconds"
685 "(write time update delay == %.2f)(correct)\n",
686 diff, used_delay / (double)1000000);
690 smb_msleep(1 * msec);
693 torture_assert_u64_not_equal(tctx,
694 finfo2.all_info.out.write_time,
695 finfo1.all_info.out.write_time,
696 "Server did not update write time");
699 smb_msleep(2 * msec);
701 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
702 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
703 torture_assert_int_equal(tctx, written, 1,
704 "Unexpected number of bytes written");
706 start = timeval_current();
707 end = timeval_add(&start, (10*sec), 0);
708 while (!timeval_expired(&end)) {
709 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
711 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
713 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 1,
714 "file not expaneded");
716 torture_comment(tctx, "write time %s\n",
717 nt_time_string(tctx, finfo3.all_info.out.write_time));
718 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
719 double diff = timeval_elapsed(&start);
721 torture_comment(tctx, "server updated write_time after %.2f seconds"
722 "(write time update delay == %.2f)(wrong)\n",
723 diff, used_delay / (double)1000000);
727 smb_msleep(1 * msec);
730 torture_assert_u64_equal(tctx,
731 finfo3.all_info.out.write_time,
732 finfo2.all_info.out.write_time,
733 "Server updated write time (wrong!)");
735 /* the close should trigger an write time update */
736 smbcli_close(cli->tree, fnum1);
739 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
740 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
742 torture_assert_u64_not_equal(tctx,
743 pinfo4.all_info.out.write_time,
744 finfo3.all_info.out.write_time,
745 "Server did not update write time on "
748 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
749 "Server updated write time on close, but to an earlier point "
753 smbcli_close(cli->tree, fnum1);
754 smbcli_unlink(cli->tree, fname);
755 smbcli_deltree(cli->tree, BASEDIR);
761 * Do as above, but using 2 connections.
764 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
765 struct smbcli_state *cli2)
767 union smb_fileinfo finfo1, finfo2;
768 const char *fname = BASEDIR "\\torture_file.txt";
774 struct timeval start;
776 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
777 int normal_delay = 2000000;
778 double sec = ((double)used_delay) / ((double)normal_delay);
779 int msec = 1000 * sec;
780 union smb_flush flsh;
782 torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
784 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
786 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
788 torture_comment(tctx, "Failed to open %s\n", fname);
792 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
793 finfo1.basic_info.in.file.fnum = fnum1;
796 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
798 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
800 torture_comment(tctx, "Initial write time %s\n",
801 nt_time_string(tctx, finfo1.basic_info.out.write_time));
803 /* 3 second delay to ensure we get past any 2 second time
804 granularity (older systems may have that) */
805 smb_msleep(3 * msec);
808 /* Try using setfileinfo instead of write to update write time. */
809 union smb_setfileinfo sfinfo;
810 time_t t_set = time(NULL);
811 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
812 sfinfo.basic_info.in.file.fnum = fnum1;
813 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
814 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
816 /* I tried this with both + and - ve to see if it makes a different.
817 It doesn't - once the filetime is set via setfileinfo it stays that way. */
819 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
821 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
823 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
824 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
826 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
828 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
831 finfo2.basic_info.in.file.path = fname;
833 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
835 if (!NT_STATUS_IS_OK(status)) {
836 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
839 torture_comment(tctx, "write time %s\n",
840 nt_time_string(tctx, finfo2.basic_info.out.write_time));
842 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
843 torture_comment(tctx, "Server updated write_time (correct)\n");
845 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
849 /* Now try a write to see if the write time gets reset. */
851 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
852 finfo1.basic_info.in.file.fnum = fnum1;
855 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
857 if (!NT_STATUS_IS_OK(status)) {
858 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
862 torture_comment(tctx, "Modified write time %s\n",
863 nt_time_string(tctx, finfo1.basic_info.out.write_time));
866 torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
868 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
871 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
872 (int)written, __location__);
876 /* Just to prove to tridge that the an smbflush has no effect on
877 the write time :-). The setfileinfo IS STICKY. JRA. */
879 torture_comment(tctx, "Doing flush after write\n");
881 flsh.flush.level = RAW_FLUSH_FLUSH;
882 flsh.flush.in.file.fnum = fnum1;
883 status = smb_raw_flush(cli->tree, &flsh);
884 if (!NT_STATUS_IS_OK(status)) {
885 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
889 /* Once the time was set using setfileinfo then it stays set - writes
890 don't have any effect. But make sure. */
891 start = timeval_current();
892 end = timeval_add(&start, (15*sec), 0);
893 while (!timeval_expired(&end)) {
894 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
896 if (!NT_STATUS_IS_OK(status)) {
897 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
901 torture_comment(tctx, "write time %s\n",
902 nt_time_string(tctx, finfo2.basic_info.out.write_time));
903 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
904 double diff = timeval_elapsed(&start);
905 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
912 smb_msleep(1 * msec);
915 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
916 torture_comment(tctx, "Server did not update write time (correct)\n");
920 smb_msleep(2 * msec);
922 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
924 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
928 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");
930 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
933 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
934 (int)written, __location__);
938 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
940 if (!NT_STATUS_IS_OK(status)) {
941 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
944 torture_comment(tctx, "write time %s\n",
945 nt_time_string(tctx, finfo2.basic_info.out.write_time));
946 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
947 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
951 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
952 smbcli_close(cli->tree, fnum1);
955 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");
957 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
960 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
961 (int)written, __location__);
965 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
966 finfo1.basic_info.in.file.fnum = fnum2;
968 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
970 if (!NT_STATUS_IS_OK(status)) {
971 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
974 torture_comment(tctx, "write time %s\n",
975 nt_time_string(tctx, finfo2.basic_info.out.write_time));
976 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
977 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
981 /* Once the time was set using setfileinfo then it stays set - writes
982 don't have any effect. But make sure. */
983 start = timeval_current();
984 end = timeval_add(&start, (15*sec), 0);
985 while (!timeval_expired(&end)) {
986 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
988 if (!NT_STATUS_IS_OK(status)) {
989 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
993 torture_comment(tctx, "write time %s\n",
994 nt_time_string(tctx, finfo2.basic_info.out.write_time));
995 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
996 double diff = timeval_elapsed(&start);
997 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1004 smb_msleep(1 * msec);
1007 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1008 torture_comment(tctx, "Server did not update write time (correct)\n");
1011 torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1013 smbcli_close(cli->tree, fnum2);
1016 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1018 torture_comment(tctx, "Failed to open %s\n", fname);
1022 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1023 finfo1.basic_info.in.file.fnum = fnum1;
1026 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1028 if (!NT_STATUS_IS_OK(status)) {
1029 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1033 torture_comment(tctx, "Second open initial write time %s\n",
1034 nt_time_string(tctx, finfo1.basic_info.out.write_time));
1036 smb_msleep(10 * msec);
1037 torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1039 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1041 if (written != 10) {
1042 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1043 (int)written, __location__);
1047 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1048 finfo1.basic_info.in.file.fnum = fnum1;
1050 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1052 if (!NT_STATUS_IS_OK(status)) {
1053 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1056 torture_comment(tctx, "write time %s\n",
1057 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1058 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1059 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1063 /* Now the write time should be updated again */
1064 start = timeval_current();
1065 end = timeval_add(&start, (15*sec), 0);
1066 while (!timeval_expired(&end)) {
1067 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1069 if (!NT_STATUS_IS_OK(status)) {
1070 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1074 torture_comment(tctx, "write time %s\n",
1075 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1076 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1077 double diff = timeval_elapsed(&start);
1078 if (diff < (used_delay / (double)1000000)) {
1079 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1080 "(expected > %.2f) (wrong!)\n",
1081 diff, used_delay / (double)1000000);
1086 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1095 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1096 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
1101 /* One more test to do. We should read the filetime via findfirst on the
1102 second connection to ensure it's the same. This is very easy for a Windows
1103 server but a bastard to get right on a POSIX server. JRA. */
1106 smbcli_close(cli->tree, fnum1);
1107 smbcli_unlink(cli->tree, fname);
1108 smbcli_deltree(cli->tree, BASEDIR);
1114 /* Windows does obviously not update the stat info during a write call. I
1115 * *think* this is the problem causing a spurious Excel 2003 on XP error
1116 * message when saving a file. Excel does a setfileinfo, writes, and then does
1117 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1118 * that the file might have been changed in between. What i've been able to
1119 * trace down is that this happens if the getpathinfo after the write shows a
1120 * different last write time than the setfileinfo showed. This is really
1124 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
1125 struct smbcli_state *cli2)
1127 union smb_fileinfo finfo1, finfo2;
1128 const char *fname = BASEDIR "\\torture_file.txt";
1134 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1135 int normal_delay = 2000000;
1136 double sec = ((double)used_delay) / ((double)normal_delay);
1137 int msec = 1000 * sec;
1139 torture_comment(tctx, "\nRunning test_finfo_after_write\n");
1141 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1143 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1146 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1150 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1151 finfo1.basic_info.in.file.fnum = fnum1;
1153 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1155 if (!NT_STATUS_IS_OK(status)) {
1157 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1161 smb_msleep(1 * msec);
1163 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1166 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1171 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1173 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1174 smbcli_errstr(cli2->tree));
1179 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1182 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1188 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1189 finfo2.basic_info.in.file.path = fname;
1191 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1193 if (!NT_STATUS_IS_OK(status)) {
1194 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
1200 if (finfo1.basic_info.out.create_time !=
1201 finfo2.basic_info.out.create_time) {
1202 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1207 if (finfo1.basic_info.out.access_time !=
1208 finfo2.basic_info.out.access_time) {
1209 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1214 if (finfo1.basic_info.out.write_time !=
1215 finfo2.basic_info.out.write_time) {
1216 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1217 "write time conn 1 = %s, conn 2 = %s",
1218 nt_time_string(tctx, finfo1.basic_info.out.write_time),
1219 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1224 if (finfo1.basic_info.out.change_time !=
1225 finfo2.basic_info.out.change_time) {
1226 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1231 /* One of the two following calls updates the qpathinfo. */
1233 /* If you had skipped the smbcli_write on fnum2, it would
1234 * *not* have updated the stat on disk */
1236 smbcli_close(cli2->tree, fnum2);
1239 /* This call is only for the people looking at ethereal :-) */
1240 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1241 finfo2.basic_info.in.file.path = fname;
1243 status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1245 if (!NT_STATUS_IS_OK(status)) {
1246 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1253 smbcli_close(cli->tree, fnum1);
1254 smbcli_unlink(cli->tree, fname);
1255 smbcli_deltree(cli->tree, BASEDIR);
1260 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1261 uint64_t r = 10*1000*1000; \
1262 NTTIME g = (given).basic_info.out.write_time; \
1263 NTTIME gr = (g / r) * r; \
1264 NTTIME c = (correct).basic_info.out.write_time; \
1265 NTTIME cr = (c / r) * r; \
1266 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1268 if (strict && (g cmp c)) { \
1270 } else if ((g cmp c) && (gr cmp cr)) { \
1271 /* handle filesystem without high resolution timestamps */ \
1275 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1276 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1277 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1282 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1283 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1284 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1285 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1286 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1287 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1289 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1290 NTTIME g = (given).basic_info.out.access_time; \
1291 NTTIME c = (correct).basic_info.out.access_time; \
1293 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1294 #given, nt_time_string(tctx, g), \
1295 #cmp, #correct, nt_time_string(tctx, c)); \
1300 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1301 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1303 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1304 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1305 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1308 #define GET_INFO_FILE(finfo) do { \
1310 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1311 if (!NT_STATUS_IS_OK(_status)) { \
1313 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1314 nt_errstr(_status)); \
1317 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1318 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1319 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1321 #define GET_INFO_FILE2(finfo) do { \
1323 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1324 if (!NT_STATUS_IS_OK(_status)) { \
1326 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1327 nt_errstr(_status)); \
1330 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1331 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1332 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1334 #define GET_INFO_PATH(pinfo) do { \
1336 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1337 if (!NT_STATUS_IS_OK(_status)) { \
1338 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1339 nt_errstr(_status)); \
1343 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1344 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1345 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1347 #define GET_INFO_BOTH(finfo,pinfo) do { \
1348 GET_INFO_FILE(finfo); \
1349 GET_INFO_PATH(pinfo); \
1350 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1353 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1355 union smb_setfileinfo sfinfo; \
1356 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1357 sfinfo.basic_info.in.file.fnum = tfnum; \
1358 sfinfo.basic_info.in.create_time = 0; \
1359 sfinfo.basic_info.in.access_time = 0; \
1360 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1361 sfinfo.basic_info.in.change_time = 0; \
1362 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1363 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1364 if (!NT_STATUS_IS_OK(_status)) { \
1365 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1366 nt_errstr(_status)); \
1371 #define SET_INFO_FILE(finfo, wrtime) \
1372 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1374 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1376 union smb_setfileinfo sfinfo; \
1377 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1378 sfinfo.basic_info.in.file.fnum = tfnum; \
1379 sfinfo.basic_info.in.create_time = 0; \
1380 sfinfo.basic_info.in.access_time = 0; \
1381 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1382 sfinfo.basic_info.in.write_time += (ns); \
1383 sfinfo.basic_info.in.change_time = 0; \
1384 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1385 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1386 if (!NT_STATUS_IS_OK(_status)) { \
1387 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1388 nt_errstr(_status)); \
1394 static bool test_delayed_write_update3(struct torture_context *tctx,
1395 struct smbcli_state *cli,
1396 struct smbcli_state *cli2)
1398 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1399 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1400 const char *fname = BASEDIR "\\torture_file3.txt";
1404 struct timeval start;
1406 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1407 int normal_delay = 2000000;
1408 double sec = ((double)used_delay) / ((double)normal_delay);
1409 int msec = 1000 * sec;
1411 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
1413 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1415 torture_comment(tctx, "Open the file handle\n");
1416 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1419 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1423 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1424 finfo0.basic_info.in.file.fnum = fnum1;
1428 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1429 pinfo0.basic_info.in.file.path = fname;
1435 /* get the initial times */
1436 GET_INFO_BOTH(finfo0,pinfo0);
1439 * make sure the write time is updated 2 seconds later
1440 * calcuated from the first write
1441 * (but expect upto 5 seconds extra time for a busy server)
1443 start = timeval_current();
1444 end = timeval_add(&start, 7 * sec, 0);
1445 while (!timeval_expired(&end)) {
1447 torture_comment(tctx, "Do a write on the file handle\n");
1448 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1450 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1454 /* get the times after the write */
1455 GET_INFO_FILE(finfo1);
1457 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1458 double diff = timeval_elapsed(&start);
1459 if (diff < (used_delay / (double)1000000)) {
1460 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1461 "(write time update delay == %.2f) (wrong!)\n",
1462 diff, used_delay / (double)1000000);
1467 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1472 smb_msleep(0.5 * msec);
1475 GET_INFO_BOTH(finfo1,pinfo1);
1476 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1478 /* sure any further write doesn't update the write time */
1479 start = timeval_current();
1480 end = timeval_add(&start, 15 * sec, 0);
1481 while (!timeval_expired(&end)) {
1483 torture_comment(tctx, "Do a write on the file handle\n");
1484 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1486 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1490 /* get the times after the write */
1491 GET_INFO_BOTH(finfo2,pinfo2);
1493 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1494 double diff = timeval_elapsed(&start);
1495 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1501 smb_msleep(1 * msec);
1504 GET_INFO_BOTH(finfo2,pinfo2);
1505 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1506 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1507 torture_comment(tctx, "Server did not update write_time (correct)\n");
1511 smb_msleep(5 * msec);
1513 GET_INFO_BOTH(finfo3,pinfo3);
1514 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1517 * the close updates the write time to the time of the close
1518 * and not to the time of the last write!
1520 torture_comment(tctx, "Close the file handle\n");
1521 smbcli_close(cli->tree, fnum1);
1524 GET_INFO_PATH(pinfo4);
1525 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1527 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1528 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1533 smbcli_close(cli->tree, fnum1);
1534 smbcli_unlink(cli->tree, fname);
1535 smbcli_deltree(cli->tree, BASEDIR);
1541 * Show that a truncate write always updates the write time even
1542 * if an initial write has already updated the write time.
1545 static bool test_delayed_write_update3a(struct torture_context *tctx,
1546 struct smbcli_state *cli,
1547 struct smbcli_state *cli2)
1549 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1550 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1551 const char *fname = BASEDIR "\\torture_file3a.txt";
1556 struct timeval start;
1558 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1559 int normal_delay = 2000000;
1560 double sec = ((double)used_delay) / ((double)normal_delay);
1561 int msec = 1000 * sec;
1563 torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
1565 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1567 torture_comment(tctx, "Open the file handle\n");
1568 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1571 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1575 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1576 finfo0.basic_info.in.file.fnum = fnum1;
1580 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1581 pinfo0.basic_info.in.file.path = fname;
1587 /* get the initial times */
1588 GET_INFO_BOTH(finfo0,pinfo0);
1591 * sleep some time, to demonstrate the handling of write times
1592 * doesn't depend on the time since the open
1594 smb_msleep(5 * msec);
1596 /* get the initial times */
1597 GET_INFO_BOTH(finfo1,pinfo1);
1598 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1601 * make sure the write time is updated 2 seconds later
1602 * calcuated from the first write
1603 * (but expect upto 5 seconds extra time for a busy server)
1605 start = timeval_current();
1606 end = timeval_add(&start, 7 * sec, 0);
1607 while (!timeval_expired(&end)) {
1609 torture_comment(tctx, "Do a write on the file handle\n");
1610 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1612 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1616 /* get the times after the write */
1617 GET_INFO_FILE(finfo1);
1619 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1620 double diff = timeval_elapsed(&start);
1621 if (diff < (used_delay / (double)1000000)) {
1622 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1623 "(1sec == %.2f) (wrong!)\n",
1629 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1634 smb_msleep(0.5 * msec);
1637 GET_INFO_BOTH(finfo1,pinfo1);
1638 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1640 smb_msleep(3 * msec);
1643 * demonstrate that a truncate write always
1644 * updates the write time immediately
1646 for (i=0; i < 3; i++) {
1647 smb_msleep(2 * msec);
1649 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1650 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1652 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1656 /* get the times after the write */
1657 GET_INFO_BOTH(finfo2,pinfo2);
1658 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1662 smb_msleep(3 * msec);
1664 /* sure any further write doesn't update the write time */
1665 start = timeval_current();
1666 end = timeval_add(&start, 15 * sec, 0);
1667 while (!timeval_expired(&end)) {
1669 torture_comment(tctx, "Do a write on the file handle\n");
1670 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1672 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1676 /* get the times after the write */
1677 GET_INFO_BOTH(finfo2,pinfo2);
1679 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1680 double diff = timeval_elapsed(&start);
1681 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1687 smb_msleep(1 * msec);
1690 GET_INFO_BOTH(finfo2,pinfo2);
1691 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1692 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1693 torture_comment(tctx, "Server did not update write_time (correct)\n");
1697 smb_msleep(3 * msec);
1699 /* get the initial times */
1700 GET_INFO_BOTH(finfo1,pinfo1);
1701 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1704 * demonstrate that a truncate write always
1705 * updates the write time immediately
1707 for (i=0; i < 3; i++) {
1708 smb_msleep(2 * msec);
1710 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1711 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1713 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1717 /* get the times after the write */
1718 GET_INFO_BOTH(finfo2,pinfo2);
1719 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1724 smb_msleep(3 * msec);
1726 GET_INFO_BOTH(finfo3,pinfo3);
1727 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1730 * the close doesn't update the write time
1732 torture_comment(tctx, "Close the file handle\n");
1733 smbcli_close(cli->tree, fnum1);
1736 GET_INFO_PATH(pinfo4);
1737 COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1739 if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1740 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1745 smbcli_close(cli->tree, fnum1);
1746 smbcli_unlink(cli->tree, fname);
1747 smbcli_deltree(cli->tree, BASEDIR);
1753 * Show a close after write updates the write timestamp to
1754 * the close time, not the last write time.
1757 static bool test_delayed_write_update3b(struct torture_context *tctx,
1758 struct smbcli_state *cli,
1759 struct smbcli_state *cli2)
1761 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1762 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1763 const char *fname = BASEDIR "\\torture_file3b.txt";
1767 struct timeval start;
1769 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1770 int normal_delay = 2000000;
1771 double sec = ((double)used_delay) / ((double)normal_delay);
1772 int msec = 1000 * sec;
1774 torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
1776 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1778 torture_comment(tctx, "Open the file handle\n");
1779 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1782 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1786 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1787 finfo0.basic_info.in.file.fnum = fnum1;
1791 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1792 pinfo0.basic_info.in.file.path = fname;
1798 /* get the initial times */
1799 GET_INFO_BOTH(finfo0,pinfo0);
1802 * sleep some time, to demonstrate the handling of write times
1803 * doesn't depend on the time since the open
1805 smb_msleep(5 * msec);
1807 /* get the initial times */
1808 GET_INFO_BOTH(finfo1,pinfo1);
1809 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1812 * make sure the write time is updated 2 seconds later
1813 * calcuated from the first write
1814 * (but expect upto 5 seconds extra time for a busy server)
1816 start = timeval_current();
1817 end = timeval_add(&start, 7 * sec, 0);
1818 while (!timeval_expired(&end)) {
1820 torture_comment(tctx, "Do a write on the file handle\n");
1821 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1823 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1827 /* get the times after the write */
1828 GET_INFO_FILE(finfo1);
1830 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1831 double diff = timeval_elapsed(&start);
1832 if (diff < (used_delay / (double)1000000)) {
1833 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1834 "(expected > %.2f) (wrong!)\n",
1835 diff, used_delay / (double)1000000);
1840 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1841 "(write time update delay == %.2f) (correct)\n",
1842 diff, used_delay / (double)1000000);
1845 smb_msleep(0.5 * msec);
1848 GET_INFO_BOTH(finfo1,pinfo1);
1849 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1851 /* sure any further write doesn't update the write time */
1852 start = timeval_current();
1853 end = timeval_add(&start, 15 * sec, 0);
1854 while (!timeval_expired(&end)) {
1856 torture_comment(tctx, "Do a write on the file handle\n");
1857 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1859 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1863 /* get the times after the write */
1864 GET_INFO_BOTH(finfo2,pinfo2);
1866 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1867 double diff = timeval_elapsed(&start);
1868 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1874 smb_msleep(1 * msec);
1877 GET_INFO_BOTH(finfo2,pinfo2);
1878 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1879 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1880 torture_comment(tctx, "Server did not update write_time (correct)\n");
1884 smb_msleep(5 * msec);
1886 GET_INFO_BOTH(finfo3,pinfo3);
1887 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1890 * the close updates the write time to the time of the close
1891 * and not to the time of the last write!
1893 torture_comment(tctx, "Close the file handle\n");
1894 smbcli_close(cli->tree, fnum1);
1897 GET_INFO_PATH(pinfo4);
1898 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1900 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1901 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1906 smbcli_close(cli->tree, fnum1);
1907 smbcli_unlink(cli->tree, fname);
1908 smbcli_deltree(cli->tree, BASEDIR);
1914 * Check that a write after a truncate write doesn't update
1915 * the timestamp, but a truncate write after a write does.
1916 * Also prove that a close after a truncate write updates the
1917 * timestamp to current, not the time of last write.
1920 static bool test_delayed_write_update3c(struct torture_context *tctx,
1921 struct smbcli_state *cli,
1922 struct smbcli_state *cli2)
1924 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1925 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1926 const char *fname = BASEDIR "\\torture_file3c.txt";
1931 struct timeval start;
1933 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1934 int normal_delay = 2000000;
1935 double sec = ((double)used_delay) / ((double)normal_delay);
1936 int msec = 1000 * sec;
1938 torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
1940 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1942 torture_comment(tctx, "Open the file handle\n");
1943 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1946 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1950 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1951 finfo0.basic_info.in.file.fnum = fnum1;
1955 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1956 pinfo0.basic_info.in.file.path = fname;
1962 /* get the initial times */
1963 GET_INFO_BOTH(finfo0,pinfo0);
1966 * sleep some time, to demonstrate the handling of write times
1967 * doesn't depend on the time since the open
1969 smb_msleep(5 * msec);
1971 /* get the initial times */
1972 GET_INFO_BOTH(finfo1,pinfo1);
1973 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1976 * demonstrate that a truncate write always
1977 * updates the write time immediately
1979 for (i=0; i < 3; i++) {
1980 smb_msleep(2 * msec);
1982 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1983 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1985 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1989 /* get the times after the write */
1990 GET_INFO_BOTH(finfo2,pinfo2);
1991 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1995 start = timeval_current();
1996 end = timeval_add(&start, 7 * sec, 0);
1997 while (!timeval_expired(&end)) {
1999 torture_comment(tctx, "Do a write on the file handle\n");
2000 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2002 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2006 /* get the times after the write */
2007 GET_INFO_FILE(finfo2);
2009 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2010 double diff = timeval_elapsed(&start);
2011 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2017 smb_msleep(1 * msec);
2020 GET_INFO_BOTH(finfo2,pinfo2);
2021 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2022 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2023 torture_comment(tctx, "Server did not update write_time (correct)\n");
2027 smb_msleep(5 * msec);
2029 /* get the initial times */
2030 GET_INFO_BOTH(finfo1,pinfo1);
2031 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2034 * demonstrate that a truncate write always
2035 * updates the write time immediately
2037 for (i=0; i < 3; i++) {
2038 smb_msleep(2 * msec);
2040 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2041 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2043 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2047 /* get the times after the write */
2048 GET_INFO_BOTH(finfo2,pinfo2);
2049 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2054 smb_msleep(5 * msec);
2056 GET_INFO_BOTH(finfo2,pinfo2);
2057 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2059 /* sure any further write doesn't update the write time */
2060 start = timeval_current();
2061 end = timeval_add(&start, 15 * sec, 0);
2062 while (!timeval_expired(&end)) {
2064 torture_comment(tctx, "Do a write on the file handle\n");
2065 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2067 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2071 /* get the times after the write */
2072 GET_INFO_BOTH(finfo2,pinfo2);
2074 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2075 double diff = timeval_elapsed(&start);
2076 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2082 smb_msleep(1 * msec);
2085 GET_INFO_BOTH(finfo2,pinfo2);
2086 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2087 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2088 torture_comment(tctx, "Server did not update write_time (correct)\n");
2092 smb_msleep(5 * msec);
2094 GET_INFO_BOTH(finfo3,pinfo3);
2095 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2098 * the close updates the write time to the time of the close
2099 * and not to the time of the last write!
2101 torture_comment(tctx, "Close the file handle\n");
2102 smbcli_close(cli->tree, fnum1);
2105 GET_INFO_PATH(pinfo4);
2106 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2108 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2109 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2114 smbcli_close(cli->tree, fnum1);
2115 smbcli_unlink(cli->tree, fname);
2116 smbcli_deltree(cli->tree, BASEDIR);
2122 * Show only the first write updates the timestamp, and a close
2123 * after writes updates to current (I think this is the same
2127 static bool test_delayed_write_update4(struct torture_context *tctx,
2128 struct smbcli_state *cli,
2129 struct smbcli_state *cli2)
2131 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
2132 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
2133 const char *fname = BASEDIR "\\torture_file4.txt";
2137 struct timeval start;
2139 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2140 int normal_delay = 2000000;
2141 double sec = ((double)used_delay) / ((double)normal_delay);
2142 int msec = 1000 * sec;
2144 torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2146 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2148 torture_comment(tctx, "Open the file handle\n");
2149 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2152 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2156 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2157 finfo0.basic_info.in.file.fnum = fnum1;
2161 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2162 pinfo0.basic_info.in.file.path = fname;
2168 /* get the initial times */
2169 GET_INFO_BOTH(finfo0,pinfo0);
2172 smb_msleep(5 * msec);
2175 torture_comment(tctx, "Do a write on the file handle\n");
2176 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2178 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2183 GET_INFO_BOTH(finfo1,pinfo1);
2184 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2187 * make sure the write time is updated 2 seconds later
2188 * calcuated from the first write
2189 * (but expect upto 3 seconds extra time for a busy server)
2191 start = timeval_current();
2192 end = timeval_add(&start, 5 * sec, 0);
2193 while (!timeval_expired(&end)) {
2194 /* get the times after the first write */
2195 GET_INFO_FILE(finfo1);
2197 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2198 double diff = timeval_elapsed(&start);
2199 if (diff < (used_delay / (double)1000000)) {
2200 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
2201 "(expected > %.2f) (wrong!)\n",
2202 diff, used_delay / (double)1000000);
2207 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2208 "(write time update delay == %.2f) (correct)\n",
2209 diff, used_delay / (double)1000000);
2212 smb_msleep(0.5 * msec);
2215 GET_INFO_BOTH(finfo1,pinfo1);
2216 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2218 /* sure any further write doesn't update the write time */
2219 start = timeval_current();
2220 end = timeval_add(&start, 15 * sec, 0);
2221 while (!timeval_expired(&end)) {
2223 torture_comment(tctx, "Do a write on the file handle\n");
2224 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2226 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2230 /* get the times after the write */
2231 GET_INFO_BOTH(finfo2,pinfo2);
2233 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2234 double diff = timeval_elapsed(&start);
2235 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2241 smb_msleep(1 * msec);
2244 GET_INFO_BOTH(finfo2,pinfo2);
2245 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2246 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2247 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2251 smb_msleep(5 * msec);
2253 GET_INFO_BOTH(finfo3,pinfo3);
2254 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2257 * the close updates the write time to the time of the close
2258 * and not to the time of the last write!
2260 torture_comment(tctx, "Close the file handle\n");
2261 smbcli_close(cli->tree, fnum1);
2264 GET_INFO_PATH(pinfo4);
2265 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2267 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2268 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2273 smbcli_close(cli->tree, fnum1);
2274 smbcli_unlink(cli->tree, fname);
2275 smbcli_deltree(cli->tree, BASEDIR);
2281 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2284 static bool test_delayed_write_update5(struct torture_context *tctx,
2285 struct smbcli_state *cli,
2286 struct smbcli_state *cli2)
2288 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2289 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2290 const char *fname = BASEDIR "\\torture_file5.txt";
2294 struct timeval start;
2296 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2297 int normal_delay = 2000000;
2298 double sec = ((double)used_delay) / ((double)normal_delay);
2299 int msec = 1000 * sec;
2301 torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2303 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2305 torture_comment(tctx, "Open the file handle\n");
2306 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2309 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2313 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2314 finfo0.basic_info.in.file.fnum = fnum1;
2320 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2321 pinfo0.basic_info.in.file.path = fname;
2329 /* get the initial times */
2330 GET_INFO_BOTH(finfo0,pinfo0);
2333 torture_comment(tctx, "Do a write on the file handle\n");
2334 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2336 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2341 GET_INFO_BOTH(finfo1,pinfo1);
2342 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2344 torture_comment(tctx, "Set write time in the future on the file handle\n");
2345 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2346 GET_INFO_BOTH(finfo2,pinfo2);
2347 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2349 torture_comment(tctx, "Set write time in the past on the file handle\n");
2350 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2351 GET_INFO_BOTH(finfo2,pinfo2);
2352 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2354 /* make sure the 2 second delay from the first write are canceled */
2355 start = timeval_current();
2356 end = timeval_add(&start, 15 * sec, 0);
2357 while (!timeval_expired(&end)) {
2359 /* get the times after the first write */
2360 GET_INFO_BOTH(finfo3,pinfo3);
2362 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2363 double diff = timeval_elapsed(&start);
2364 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2370 smb_msleep(1 * msec);
2373 GET_INFO_BOTH(finfo3,pinfo3);
2374 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2375 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2376 torture_comment(tctx, "Server did not update write_time (correct)\n");
2379 /* sure any further write doesn't update the write time */
2380 start = timeval_current();
2381 end = timeval_add(&start, 15 * sec, 0);
2382 while (!timeval_expired(&end)) {
2384 torture_comment(tctx, "Do a write on the file handle\n");
2385 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2387 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2391 /* get the times after the write */
2392 GET_INFO_BOTH(finfo4,pinfo4);
2394 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2395 double diff = timeval_elapsed(&start);
2396 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2402 smb_msleep(1 * msec);
2405 GET_INFO_BOTH(finfo4,pinfo4);
2406 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2407 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2408 torture_comment(tctx, "Server did not update write_time (correct)\n");
2412 smb_msleep(5 * msec);
2414 GET_INFO_BOTH(finfo5,pinfo5);
2415 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2418 * the close doesn't update the write time
2420 torture_comment(tctx, "Close the file handle\n");
2421 smbcli_close(cli->tree, fnum1);
2424 GET_INFO_PATH(pinfo6);
2425 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2427 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2428 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2433 smbcli_close(cli->tree, fnum1);
2434 smbcli_unlink(cli->tree, fname);
2435 smbcli_deltree(cli->tree, BASEDIR);
2441 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2444 static bool test_delayed_write_update5b(struct torture_context *tctx,
2445 struct smbcli_state *cli,
2446 struct smbcli_state *cli2)
2448 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2449 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2450 const char *fname = BASEDIR "\\torture_fileb.txt";
2454 struct timeval start;
2456 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2457 int normal_delay = 2000000;
2458 double sec = ((double)used_delay) / ((double)normal_delay);
2459 int msec = 1000 * sec;
2461 torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2463 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2465 torture_comment(tctx, "Open the file handle\n");
2466 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2469 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2473 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2474 finfo0.basic_info.in.file.fnum = fnum1;
2480 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2481 pinfo0.basic_info.in.file.path = fname;
2489 /* get the initial times */
2490 GET_INFO_BOTH(finfo0,pinfo0);
2493 torture_comment(tctx, "Do a write on the file handle\n");
2494 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2496 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2501 GET_INFO_BOTH(finfo1,pinfo1);
2502 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2504 torture_comment(tctx, "Set write time in the future on the file handle\n");
2505 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2506 GET_INFO_BOTH(finfo2,pinfo2);
2507 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2509 torture_comment(tctx, "Set write time in the past on the file handle\n");
2510 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2511 GET_INFO_BOTH(finfo2,pinfo2);
2512 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2514 /* make sure the 2 second delay from the first write are canceled */
2515 start = timeval_current();
2516 end = timeval_add(&start, 15 * sec, 0);
2517 while (!timeval_expired(&end)) {
2519 /* get the times after the first write */
2520 GET_INFO_BOTH(finfo3,pinfo3);
2522 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2523 double diff = timeval_elapsed(&start);
2524 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2530 smb_msleep(1 * msec);
2533 GET_INFO_BOTH(finfo3,pinfo3);
2534 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2535 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2536 torture_comment(tctx, "Server did not update write_time (correct)\n");
2539 /* Do any further write (truncates) update the write time ? */
2540 start = timeval_current();
2541 end = timeval_add(&start, 15 * sec, 0);
2542 while (!timeval_expired(&end)) {
2544 torture_comment(tctx, "Do a truncate write on the file handle\n");
2545 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2547 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2551 /* get the times after the write */
2552 GET_INFO_BOTH(finfo4,pinfo4);
2554 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2555 double diff = timeval_elapsed(&start);
2556 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2562 smb_msleep(1 * msec);
2565 GET_INFO_BOTH(finfo4,pinfo4);
2566 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2567 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2568 torture_comment(tctx, "Server did not update write_time (correct)\n");
2572 smb_msleep(5 * msec);
2574 GET_INFO_BOTH(finfo5,pinfo5);
2575 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2578 * the close doesn't update the write time
2580 torture_comment(tctx, "Close the file handle\n");
2581 smbcli_close(cli->tree, fnum1);
2584 GET_INFO_PATH(pinfo6);
2585 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2587 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2588 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2593 smbcli_close(cli->tree, fnum1);
2594 smbcli_unlink(cli->tree, fname);
2595 smbcli_deltree(cli->tree, BASEDIR);
2601 * Open 2 handles on a file. Write one one and then set the
2602 * WRITE TIME explicitly on the other. Ensure the write time
2603 * update is cancelled. Ensure the write time is updated to
2604 * the close time when the non-explicit set handle is closed.
2608 static bool test_delayed_write_update6(struct torture_context *tctx,
2609 struct smbcli_state *cli,
2610 struct smbcli_state *cli2)
2612 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2613 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2614 const char *fname = BASEDIR "\\torture_file6.txt";
2619 struct timeval start;
2621 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2622 int normal_delay = 2000000;
2623 double sec = ((double)used_delay) / ((double)normal_delay);
2624 int msec = 1000 * sec;
2627 torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2629 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2631 torture_comment(tctx, "Open the file handle\n");
2632 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2635 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2640 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2641 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2644 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2649 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2650 finfo0.basic_info.in.file.fnum = fnum1;
2656 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2657 pinfo0.basic_info.in.file.path = fname;
2666 /* get the initial times */
2667 GET_INFO_BOTH(finfo0,pinfo0);
2670 torture_comment(tctx, "Do a write on the file handle\n");
2671 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2673 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2678 GET_INFO_BOTH(finfo1,pinfo1);
2679 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2681 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2682 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2683 GET_INFO_BOTH(finfo2,pinfo2);
2684 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2686 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2687 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2688 GET_INFO_BOTH(finfo2,pinfo2);
2689 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2691 /* make sure the 2 second delay from the first write are canceled */
2692 start = timeval_current();
2693 end = timeval_add(&start, 10 * sec, 0);
2694 while (!timeval_expired(&end)) {
2696 /* get the times after the first write */
2697 GET_INFO_BOTH(finfo3,pinfo3);
2699 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2700 double diff = timeval_elapsed(&start);
2701 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2707 smb_msleep(1 * msec);
2710 GET_INFO_BOTH(finfo3,pinfo3);
2711 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2712 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2713 torture_comment(tctx, "Server did not update write_time (correct)\n");
2716 /* sure any further write doesn't update the write time */
2717 start = timeval_current();
2718 end = timeval_add(&start, 10 * sec, 0);
2719 while (!timeval_expired(&end)) {
2721 torture_comment(tctx, "Do a write on the file handle\n");
2722 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2724 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2728 /* get the times after the write */
2729 GET_INFO_BOTH(finfo4,pinfo4);
2731 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2732 double diff = timeval_elapsed(&start);
2733 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2739 smb_msleep(1 * msec);
2742 GET_INFO_BOTH(finfo4,pinfo4);
2743 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2744 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2745 torture_comment(tctx, "Server did not update write_time (correct)\n");
2749 smb_msleep(5 * msec);
2751 GET_INFO_BOTH(finfo5,pinfo5);
2752 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2755 * the close updates the write time to the time of the close
2756 * as the write time was set on the 2nd handle
2758 torture_comment(tctx, "Close the file handle\n");
2759 smbcli_close(cli->tree, fnum1);
2762 GET_INFO_PATH(pinfo6);
2763 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2765 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2766 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2769 /* See what the second write handle thinks the time is ? */
2770 finfo5.basic_info.in.file.fnum = fnum2;
2771 GET_INFO_FILE2(finfo5);
2772 COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
2774 /* See if we have lost the sticky write time on handle2 */
2775 smb_msleep(3 * msec);
2776 torture_comment(tctx, "Have we lost the sticky write time ?\n");
2778 /* Make sure any further normal write doesn't update the write time */
2779 start = timeval_current();
2780 end = timeval_add(&start, 10 * sec, 0);
2781 while (!timeval_expired(&end)) {
2783 torture_comment(tctx, "Do a write on the second file handle\n");
2784 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
2786 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2790 /* get the times after the write */
2791 GET_INFO_FILE2(finfo5);
2792 GET_INFO_PATH(pinfo6);
2794 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2795 double diff = timeval_elapsed(&start);
2796 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2802 smb_msleep(1 * msec);
2805 /* What about a truncate write ? */
2806 start = timeval_current();
2807 end = timeval_add(&start, 10 * sec, 0);
2808 while (!timeval_expired(&end)) {
2810 torture_comment(tctx, "Do a truncate write on the second file handle\n");
2811 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
2813 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2817 /* get the times after the write */
2818 GET_INFO_FILE2(finfo5);
2819 GET_INFO_PATH(pinfo6);
2821 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2822 double diff = timeval_elapsed(&start);
2823 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2829 smb_msleep(1 * msec);
2833 /* keep the 2nd handle open and rerun tests */
2840 * closing the 2nd handle will cause no write time update
2841 * as the write time was explicit set on this handle
2843 torture_comment(tctx, "Close the 2nd file handle\n");
2844 smbcli_close(cli2->tree, fnum2);
2847 GET_INFO_PATH(pinfo7);
2848 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2850 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2851 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2856 smbcli_close(cli->tree, fnum1);
2858 smbcli_close(cli2->tree, fnum2);
2859 smbcli_unlink(cli->tree, fname);
2860 smbcli_deltree(cli->tree, BASEDIR);
2865 static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
2867 union smb_open open_parms;
2868 union smb_fileinfo finfo1, finfo2, finfo3;
2869 const char *fname = BASEDIR "\\torture_file7.txt";
2873 TALLOC_CTX *mem_ctx;
2875 torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2877 mem_ctx = talloc_init("test_delayed_write_update7");
2878 if (!mem_ctx) return false;
2880 ZERO_STRUCT(finfo1);
2881 ZERO_STRUCT(finfo2);
2882 ZERO_STRUCT(finfo3);
2883 ZERO_STRUCT(open_parms);
2885 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2887 /* Create the file. */
2888 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2890 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
2894 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2895 finfo1.basic_info.in.file.fnum = fnum1;
2899 /* Get the initial timestamps. */
2900 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
2902 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2904 /* Set the pending write time to a value with ns. */
2905 SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
2907 /* Get the current pending write time by fnum. */
2908 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
2910 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2912 /* Ensure the time is actually different. */
2913 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2914 torture_result(tctx, TORTURE_FAIL,
2915 "setfileinfo time matches original fileinfo time");
2919 /* Get the current pending write time by path. */
2920 finfo3.basic_info.in.file.path = fname;
2921 status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
2923 if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
2924 torture_result(tctx, TORTURE_FAIL,
2925 "qpathinfo time doens't match fileinfo time");
2929 /* Now close the file. Re-open and check that the write
2930 time is identical to the one we wrote. */
2932 smbcli_close(cli->tree, fnum1);
2934 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
2935 open_parms.ntcreatex.in.flags = 0;
2936 open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
2937 open_parms.ntcreatex.in.file_attr = 0;
2938 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
2939 NTCREATEX_SHARE_ACCESS_READ|
2940 NTCREATEX_SHARE_ACCESS_WRITE;
2941 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
2942 open_parms.ntcreatex.in.create_options = 0;
2943 open_parms.ntcreatex.in.fname = fname;
2945 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
2946 talloc_free(mem_ctx);
2948 if (!NT_STATUS_IS_OK(status)) {
2949 torture_result(tctx, TORTURE_FAIL,
2950 "setfileinfo time matches original fileinfo time");
2954 fnum1 = open_parms.ntcreatex.out.file.fnum;
2956 /* Check the returned time matches. */
2957 if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
2958 torture_result(tctx, TORTURE_FAIL,
2959 "final open time does not match set time");
2965 smbcli_close(cli->tree, fnum1);
2967 smbcli_unlink(cli->tree, fname);
2968 smbcli_deltree(cli->tree, BASEDIR);
2973 Test if creating a file in a directory with an open handle updates the
2974 write timestamp (it should).
2976 static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
2978 union smb_fileinfo dir_info1, dir_info2;
2979 union smb_open open_parms;
2980 const char *fname = BASEDIR "\\torture_file.txt";
2985 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2986 int normal_delay = 2000000;
2987 double sec = ((double)used_delay) / ((double)normal_delay);
2988 int msec = 1000 * sec;
2989 TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
2991 if (!mem_ctx) return false;
2993 torture_comment(tctx, "\nRunning test directory write update\n");
2995 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2997 /* Open a handle on the directory - and leave it open. */
2998 ZERO_STRUCT(open_parms);
2999 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3000 open_parms.ntcreatex.in.flags = 0;
3001 open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
3002 open_parms.ntcreatex.in.file_attr = 0;
3003 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3004 NTCREATEX_SHARE_ACCESS_READ|
3005 NTCREATEX_SHARE_ACCESS_WRITE;
3006 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3007 open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
3008 open_parms.ntcreatex.in.fname = BASEDIR;
3010 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3011 talloc_free(mem_ctx);
3013 if (!NT_STATUS_IS_OK(status)) {
3014 torture_result(tctx, TORTURE_FAIL,
3015 "failed to open directory handle");
3020 fnum1 = open_parms.ntcreatex.out.file.fnum;
3022 /* Store the returned write time. */
3023 ZERO_STRUCT(dir_info1);
3024 dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
3026 torture_comment(tctx, "Initial write time %s\n",
3027 nt_time_string(tctx, dir_info1.basic_info.out.write_time));
3030 smb_msleep(3 * msec);
3032 /* Now create a file within the directory. */
3033 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3035 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
3039 smbcli_close(cli->tree, fnum2);
3041 /* Read the directory write time again. */
3042 ZERO_STRUCT(dir_info2);
3043 dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3044 dir_info2.basic_info.in.file.fnum = fnum1;
3046 status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
3048 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
3050 /* Ensure it's been incremented. */
3051 COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
3053 torture_comment(tctx, "Updated write time %s\n",
3054 nt_time_string(tctx, dir_info2.basic_info.out.write_time));
3059 smbcli_close(cli->tree, fnum1);
3060 smbcli_unlink(cli->tree, fname);
3061 smbcli_deltree(cli->tree, BASEDIR);
3067 testing of delayed update of write_time
3069 struct torture_suite *torture_delay_write(void)
3071 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "delaywrite");
3073 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
3074 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
3075 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
3076 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
3077 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
3078 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
3079 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
3080 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
3081 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
3082 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
3083 torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
3084 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
3085 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
3086 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
3087 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
3088 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3089 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3090 torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);