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);
465 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
466 "Failed to open %s", fname));
468 memset(buf, 'x', 2048);
469 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
471 /* 3 second delay to ensure we get past any 2 second time
472 granularity (older systems may have that) */
473 smb_msleep(3 * msec);
475 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
476 finfo1.all_info.in.file.fnum = fnum1;
479 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
480 pinfo4.all_info.in.file.path = fname;
482 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
484 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
486 torture_comment(tctx, "Initial write time %s\n",
487 nt_time_string(tctx, finfo1.all_info.out.write_time));
489 /* Do a SET_END_OF_FILE_INFO call to truncate. */
490 status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
492 torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
494 start = timeval_current();
495 end = timeval_add(&start, (120*sec), 0);
496 while (!timeval_expired(&end)) {
497 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
499 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
501 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
502 "file not truncated to expected size "
505 torture_comment(tctx, "write time %s\n",
506 nt_time_string(tctx, finfo2.all_info.out.write_time));
507 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
508 double diff = timeval_elapsed(&start);
509 if (diff > (0.25 * (used_delay / (double)1000000))) {
510 torture_result(tctx, TORTURE_FAIL,
511 "After SET_END_OF_FILE truncate "
512 "server updated write_time after %.2f seconds"
513 "(write time update delay == %.2f)(wrong!)",
514 diff, used_delay / (double)1000000);
519 torture_comment(tctx, "After SET_END_OF_FILE truncate "
520 "server updated write_time after %.2f seconds"
521 "(write time update delay == %.2f)(correct)\n",
522 diff, used_delay / (double)1000000);
526 smb_msleep(1 * msec);
529 torture_assert_u64_not_equal(tctx,
530 finfo2.all_info.out.write_time,
531 finfo1.all_info.out.write_time,
532 "Server did not update write time");
535 smb_msleep(2 * msec);
537 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
538 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
540 torture_assert_int_equal(tctx, written, 1,
541 "unexpected number of bytes written");
543 start = timeval_current();
544 end = timeval_add(&start, (10*sec), 0);
545 while (!timeval_expired(&end)) {
546 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
548 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
550 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
551 "file not truncated to expected size "
554 torture_comment(tctx, "write time %s\n",
555 nt_time_string(tctx, finfo3.all_info.out.write_time));
556 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
557 double diff = timeval_elapsed(&start);
559 torture_comment(tctx, "server updated write_time after %.2f seconds"
560 "(write time update delay == %.2f)(correct)\n",
561 diff, used_delay / (double)1000000);
565 smb_msleep(1 * msec);
568 torture_assert_u64_equal(tctx,
569 finfo3.all_info.out.write_time,
570 finfo2.all_info.out.write_time,
571 "Server updated write time");
573 /* the close should trigger an write time update */
574 smbcli_close(cli->tree, fnum1);
577 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
578 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
580 torture_assert_u64_not_equal(tctx,
581 pinfo4.all_info.out.write_time,
582 finfo3.all_info.out.write_time,
583 "Server did not update write time on "
585 if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
586 torture_comment(tctx, "Server updated write time on close (correct)\n");
590 smbcli_close(cli->tree, fnum1);
591 smbcli_unlink(cli->tree, fname);
592 smbcli_deltree(cli->tree, BASEDIR);
597 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
599 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
601 union smb_setfileinfo parms;
602 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
603 const char *fname = BASEDIR "\\torture_file1c.txt";
608 struct timeval start;
610 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
611 int normal_delay = 2000000;
612 double sec = ((double)used_delay) / ((double)normal_delay);
613 int msec = 1000 * sec;
616 torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
618 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
620 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
622 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
626 memset(buf, 'x', 2048);
627 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
629 /* 3 second delay to ensure we get past any 2 second time
630 granularity (older systems may have that) */
631 smb_msleep(3 * msec);
633 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
634 finfo1.all_info.in.file.fnum = fnum1;
637 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
638 pinfo4.all_info.in.file.path = fname;
640 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
642 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
644 torture_comment(tctx, "Initial write time %s\n",
645 nt_time_string(tctx, finfo1.all_info.out.write_time));
647 /* Do a SET_ALLOCATION_SIZE call to truncate. */
648 parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
649 parms.allocation_info.in.file.fnum = fnum1;
650 parms.allocation_info.in.alloc_size = 0;
652 status = smb_raw_setfileinfo(cli->tree, &parms);
654 torture_assert_ntstatus_ok(tctx, status,
655 "RAW_SFILEINFO_ALLOCATION_INFO failed");
657 start = timeval_current();
658 end = timeval_add(&start, (120*sec), 0);
659 while (!timeval_expired(&end)) {
660 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
662 if (!NT_STATUS_IS_OK(status)) {
663 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
669 if (finfo2.all_info.out.size != 0) {
670 torture_result(tctx, TORTURE_FAIL,
671 "file not truncated (size = %u, should be 10240)",
672 (unsigned int)finfo2.all_info.out.size);
677 torture_comment(tctx, "write time %s\n",
678 nt_time_string(tctx, finfo2.all_info.out.write_time));
679 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
680 double diff = timeval_elapsed(&start);
681 if (diff > (0.25 * (used_delay / (double)1000000))) {
682 torture_result(tctx, TORTURE_FAIL, "After SET_ALLOCATION_INFO truncate "
683 "server updated write_time after %.2f seconds"
684 "(write time update delay == %.2f)(wrong!)\n",
685 diff, used_delay / (double)1000000);
690 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
691 "server updated write_time after %.2f seconds"
692 "(write time update delay == %.2f)(correct)\n",
693 diff, used_delay / (double)1000000);
697 smb_msleep(1 * msec);
700 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
701 torture_result(tctx, TORTURE_FAIL,
702 "Server did not update write time (wrong!)");
707 smb_msleep(2 * msec);
709 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
710 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
711 torture_assert_int_equal(tctx, written, 1,
712 "Unexpected number of bytes written");
714 start = timeval_current();
715 end = timeval_add(&start, (10*sec), 0);
716 while (!timeval_expired(&end)) {
717 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
719 if (!NT_STATUS_IS_OK(status)) {
720 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
726 if (finfo3.all_info.out.size != 1) {
727 torture_result(tctx, TORTURE_FAIL, "file not expanded");
732 torture_comment(tctx, "write time %s\n",
733 nt_time_string(tctx, finfo3.all_info.out.write_time));
734 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
735 double diff = timeval_elapsed(&start);
737 torture_comment(tctx, "server updated write_time after %.2f seconds"
738 "(write time update delay == %.2f)(wrong)\n",
739 diff, used_delay / (double)1000000);
743 smb_msleep(1 * msec);
746 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
747 torture_result(tctx, TORTURE_FAIL,
748 "Server updated write time (wrong!)");
752 /* the close should trigger an write time update */
753 smbcli_close(cli->tree, fnum1);
756 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
757 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
759 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
760 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
762 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
763 torture_comment(tctx, "Server updated write time on close (correct)\n");
767 smbcli_close(cli->tree, fnum1);
768 smbcli_unlink(cli->tree, fname);
769 smbcli_deltree(cli->tree, BASEDIR);
775 * Do as above, but using 2 connections.
778 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
779 struct smbcli_state *cli2)
781 union smb_fileinfo finfo1, finfo2;
782 const char *fname = BASEDIR "\\torture_file.txt";
788 struct timeval start;
790 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
791 int normal_delay = 2000000;
792 double sec = ((double)used_delay) / ((double)normal_delay);
793 int msec = 1000 * sec;
794 union smb_flush flsh;
796 torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
798 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
800 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
802 torture_comment(tctx, "Failed to open %s\n", fname);
806 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
807 finfo1.basic_info.in.file.fnum = fnum1;
810 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
812 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
814 torture_comment(tctx, "Initial write time %s\n",
815 nt_time_string(tctx, finfo1.basic_info.out.write_time));
817 /* 3 second delay to ensure we get past any 2 second time
818 granularity (older systems may have that) */
819 smb_msleep(3 * msec);
822 /* Try using setfileinfo instead of write to update write time. */
823 union smb_setfileinfo sfinfo;
824 time_t t_set = time(NULL);
825 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
826 sfinfo.basic_info.in.file.fnum = fnum1;
827 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
828 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
830 /* I tried this with both + and - ve to see if it makes a different.
831 It doesn't - once the filetime is set via setfileinfo it stays that way. */
833 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
835 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
837 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
838 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
840 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
842 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
845 finfo2.basic_info.in.file.path = fname;
847 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
849 if (!NT_STATUS_IS_OK(status)) {
850 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
853 torture_comment(tctx, "write time %s\n",
854 nt_time_string(tctx, finfo2.basic_info.out.write_time));
856 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
857 torture_comment(tctx, "Server updated write_time (correct)\n");
859 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
863 /* Now try a write to see if the write time gets reset. */
865 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
866 finfo1.basic_info.in.file.fnum = fnum1;
869 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
871 if (!NT_STATUS_IS_OK(status)) {
872 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
876 torture_comment(tctx, "Modified write time %s\n",
877 nt_time_string(tctx, finfo1.basic_info.out.write_time));
880 torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
882 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
885 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
886 (int)written, __location__);
890 /* Just to prove to tridge that the an smbflush has no effect on
891 the write time :-). The setfileinfo IS STICKY. JRA. */
893 torture_comment(tctx, "Doing flush after write\n");
895 flsh.flush.level = RAW_FLUSH_FLUSH;
896 flsh.flush.in.file.fnum = fnum1;
897 status = smb_raw_flush(cli->tree, &flsh);
898 if (!NT_STATUS_IS_OK(status)) {
899 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
903 /* Once the time was set using setfileinfo then it stays set - writes
904 don't have any effect. But make sure. */
905 start = timeval_current();
906 end = timeval_add(&start, (15*sec), 0);
907 while (!timeval_expired(&end)) {
908 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
910 if (!NT_STATUS_IS_OK(status)) {
911 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
915 torture_comment(tctx, "write time %s\n",
916 nt_time_string(tctx, finfo2.basic_info.out.write_time));
917 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
918 double diff = timeval_elapsed(&start);
919 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
926 smb_msleep(1 * msec);
929 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
930 torture_comment(tctx, "Server did not update write time (correct)\n");
934 smb_msleep(2 * msec);
936 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
938 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
942 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");
944 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
947 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
948 (int)written, __location__);
952 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
954 if (!NT_STATUS_IS_OK(status)) {
955 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
958 torture_comment(tctx, "write time %s\n",
959 nt_time_string(tctx, finfo2.basic_info.out.write_time));
960 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
961 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
965 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
966 smbcli_close(cli->tree, fnum1);
969 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");
971 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
974 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
975 (int)written, __location__);
979 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
980 finfo1.basic_info.in.file.fnum = fnum2;
982 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
984 if (!NT_STATUS_IS_OK(status)) {
985 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
988 torture_comment(tctx, "write time %s\n",
989 nt_time_string(tctx, finfo2.basic_info.out.write_time));
990 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
991 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
995 /* Once the time was set using setfileinfo then it stays set - writes
996 don't have any effect. But make sure. */
997 start = timeval_current();
998 end = timeval_add(&start, (15*sec), 0);
999 while (!timeval_expired(&end)) {
1000 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1002 if (!NT_STATUS_IS_OK(status)) {
1003 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1007 torture_comment(tctx, "write time %s\n",
1008 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1009 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1010 double diff = timeval_elapsed(&start);
1011 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1018 smb_msleep(1 * msec);
1021 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1022 torture_comment(tctx, "Server did not update write time (correct)\n");
1025 torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1027 smbcli_close(cli->tree, fnum2);
1030 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1032 torture_comment(tctx, "Failed to open %s\n", fname);
1036 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1037 finfo1.basic_info.in.file.fnum = fnum1;
1040 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1042 if (!NT_STATUS_IS_OK(status)) {
1043 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1047 torture_comment(tctx, "Second open initial write time %s\n",
1048 nt_time_string(tctx, finfo1.basic_info.out.write_time));
1050 smb_msleep(10 * msec);
1051 torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1053 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1055 if (written != 10) {
1056 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1057 (int)written, __location__);
1061 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1062 finfo1.basic_info.in.file.fnum = fnum1;
1064 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1066 if (!NT_STATUS_IS_OK(status)) {
1067 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1070 torture_comment(tctx, "write time %s\n",
1071 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1072 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1073 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1077 /* Now the write time should be updated again */
1078 start = timeval_current();
1079 end = timeval_add(&start, (15*sec), 0);
1080 while (!timeval_expired(&end)) {
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)));
1088 torture_comment(tctx, "write time %s\n",
1089 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1090 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1091 double diff = timeval_elapsed(&start);
1092 if (diff < (used_delay / (double)1000000)) {
1093 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1094 "(expected > %.2f) (wrong!)\n",
1095 diff, used_delay / (double)1000000);
1100 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1109 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1110 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
1115 /* One more test to do. We should read the filetime via findfirst on the
1116 second connection to ensure it's the same. This is very easy for a Windows
1117 server but a bastard to get right on a POSIX server. JRA. */
1120 smbcli_close(cli->tree, fnum1);
1121 smbcli_unlink(cli->tree, fname);
1122 smbcli_deltree(cli->tree, BASEDIR);
1128 /* Windows does obviously not update the stat info during a write call. I
1129 * *think* this is the problem causing a spurious Excel 2003 on XP error
1130 * message when saving a file. Excel does a setfileinfo, writes, and then does
1131 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1132 * that the file might have been changed in between. What i've been able to
1133 * trace down is that this happens if the getpathinfo after the write shows a
1134 * different last write time than the setfileinfo showed. This is really
1138 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
1139 struct smbcli_state *cli2)
1141 union smb_fileinfo finfo1, finfo2;
1142 const char *fname = BASEDIR "\\torture_file.txt";
1148 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1149 int normal_delay = 2000000;
1150 double sec = ((double)used_delay) / ((double)normal_delay);
1151 int msec = 1000 * sec;
1153 torture_comment(tctx, "\nRunning test_finfo_after_write\n");
1155 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1157 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1160 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1164 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1165 finfo1.basic_info.in.file.fnum = fnum1;
1167 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1169 if (!NT_STATUS_IS_OK(status)) {
1171 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1175 smb_msleep(1 * msec);
1177 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1180 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1185 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1187 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1188 smbcli_errstr(cli2->tree));
1193 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1196 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1202 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1203 finfo2.basic_info.in.file.path = fname;
1205 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1207 if (!NT_STATUS_IS_OK(status)) {
1208 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
1214 if (finfo1.basic_info.out.create_time !=
1215 finfo2.basic_info.out.create_time) {
1216 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1221 if (finfo1.basic_info.out.access_time !=
1222 finfo2.basic_info.out.access_time) {
1223 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1228 if (finfo1.basic_info.out.write_time !=
1229 finfo2.basic_info.out.write_time) {
1230 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1231 "write time conn 1 = %s, conn 2 = %s",
1232 nt_time_string(tctx, finfo1.basic_info.out.write_time),
1233 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1238 if (finfo1.basic_info.out.change_time !=
1239 finfo2.basic_info.out.change_time) {
1240 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1245 /* One of the two following calls updates the qpathinfo. */
1247 /* If you had skipped the smbcli_write on fnum2, it would
1248 * *not* have updated the stat on disk */
1250 smbcli_close(cli2->tree, fnum2);
1253 /* This call is only for the people looking at ethereal :-) */
1254 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1255 finfo2.basic_info.in.file.path = fname;
1257 status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1259 if (!NT_STATUS_IS_OK(status)) {
1260 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1267 smbcli_close(cli->tree, fnum1);
1268 smbcli_unlink(cli->tree, fname);
1269 smbcli_deltree(cli->tree, BASEDIR);
1274 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1275 uint64_t r = 10*1000*1000; \
1276 NTTIME g = (given).basic_info.out.write_time; \
1277 NTTIME gr = (g / r) * r; \
1278 NTTIME c = (correct).basic_info.out.write_time; \
1279 NTTIME cr = (c / r) * r; \
1280 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1282 if (strict && (g cmp c)) { \
1284 } else if ((g cmp c) && (gr cmp cr)) { \
1285 /* handle filesystem without high resolution timestamps */ \
1289 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1290 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1291 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1296 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1297 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1298 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1299 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1300 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1301 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1303 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1304 NTTIME g = (given).basic_info.out.access_time; \
1305 NTTIME c = (correct).basic_info.out.access_time; \
1307 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1308 #given, nt_time_string(tctx, g), \
1309 #cmp, #correct, nt_time_string(tctx, c)); \
1314 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1315 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1317 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1318 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1319 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1322 #define GET_INFO_FILE(finfo) do { \
1324 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1325 if (!NT_STATUS_IS_OK(_status)) { \
1327 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1328 nt_errstr(_status)); \
1331 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1332 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1333 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1335 #define GET_INFO_FILE2(finfo) do { \
1337 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1338 if (!NT_STATUS_IS_OK(_status)) { \
1340 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1341 nt_errstr(_status)); \
1344 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1345 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1346 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1348 #define GET_INFO_PATH(pinfo) do { \
1350 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1351 if (!NT_STATUS_IS_OK(_status)) { \
1352 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1353 nt_errstr(_status)); \
1357 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1358 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1359 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1361 #define GET_INFO_BOTH(finfo,pinfo) do { \
1362 GET_INFO_FILE(finfo); \
1363 GET_INFO_PATH(pinfo); \
1364 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1367 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1369 union smb_setfileinfo sfinfo; \
1370 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1371 sfinfo.basic_info.in.file.fnum = tfnum; \
1372 sfinfo.basic_info.in.create_time = 0; \
1373 sfinfo.basic_info.in.access_time = 0; \
1374 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1375 sfinfo.basic_info.in.change_time = 0; \
1376 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1377 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1378 if (!NT_STATUS_IS_OK(_status)) { \
1379 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1380 nt_errstr(_status)); \
1385 #define SET_INFO_FILE(finfo, wrtime) \
1386 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1388 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1390 union smb_setfileinfo sfinfo; \
1391 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1392 sfinfo.basic_info.in.file.fnum = tfnum; \
1393 sfinfo.basic_info.in.create_time = 0; \
1394 sfinfo.basic_info.in.access_time = 0; \
1395 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1396 sfinfo.basic_info.in.write_time += (ns); \
1397 sfinfo.basic_info.in.change_time = 0; \
1398 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1399 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1400 if (!NT_STATUS_IS_OK(_status)) { \
1401 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1402 nt_errstr(_status)); \
1408 static bool test_delayed_write_update3(struct torture_context *tctx,
1409 struct smbcli_state *cli,
1410 struct smbcli_state *cli2)
1412 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1413 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1414 const char *fname = BASEDIR "\\torture_file3.txt";
1418 struct timeval start;
1420 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1421 int normal_delay = 2000000;
1422 double sec = ((double)used_delay) / ((double)normal_delay);
1423 int msec = 1000 * sec;
1425 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
1427 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1429 torture_comment(tctx, "Open the file handle\n");
1430 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1433 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1437 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1438 finfo0.basic_info.in.file.fnum = fnum1;
1442 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1443 pinfo0.basic_info.in.file.path = fname;
1449 /* get the initial times */
1450 GET_INFO_BOTH(finfo0,pinfo0);
1453 * make sure the write time is updated 2 seconds later
1454 * calcuated from the first write
1455 * (but expect upto 5 seconds extra time for a busy server)
1457 start = timeval_current();
1458 end = timeval_add(&start, 7 * sec, 0);
1459 while (!timeval_expired(&end)) {
1461 torture_comment(tctx, "Do a write on the file handle\n");
1462 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1464 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1468 /* get the times after the write */
1469 GET_INFO_FILE(finfo1);
1471 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1472 double diff = timeval_elapsed(&start);
1473 if (diff < (used_delay / (double)1000000)) {
1474 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1475 "(write time update delay == %.2f) (wrong!)\n",
1476 diff, used_delay / (double)1000000);
1481 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1486 smb_msleep(0.5 * msec);
1489 GET_INFO_BOTH(finfo1,pinfo1);
1490 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1492 /* sure any further write doesn't update the write time */
1493 start = timeval_current();
1494 end = timeval_add(&start, 15 * sec, 0);
1495 while (!timeval_expired(&end)) {
1497 torture_comment(tctx, "Do a write on the file handle\n");
1498 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1500 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1504 /* get the times after the write */
1505 GET_INFO_BOTH(finfo2,pinfo2);
1507 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1508 double diff = timeval_elapsed(&start);
1509 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1515 smb_msleep(1 * msec);
1518 GET_INFO_BOTH(finfo2,pinfo2);
1519 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1520 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1521 torture_comment(tctx, "Server did not update write_time (correct)\n");
1525 smb_msleep(5 * msec);
1527 GET_INFO_BOTH(finfo3,pinfo3);
1528 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1531 * the close updates the write time to the time of the close
1532 * and not to the time of the last write!
1534 torture_comment(tctx, "Close the file handle\n");
1535 smbcli_close(cli->tree, fnum1);
1538 GET_INFO_PATH(pinfo4);
1539 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1541 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1542 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1547 smbcli_close(cli->tree, fnum1);
1548 smbcli_unlink(cli->tree, fname);
1549 smbcli_deltree(cli->tree, BASEDIR);
1555 * Show that a truncate write always updates the write time even
1556 * if an initial write has already updated the write time.
1559 static bool test_delayed_write_update3a(struct torture_context *tctx,
1560 struct smbcli_state *cli,
1561 struct smbcli_state *cli2)
1563 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1564 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1565 const char *fname = BASEDIR "\\torture_file3a.txt";
1570 struct timeval start;
1572 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1573 int normal_delay = 2000000;
1574 double sec = ((double)used_delay) / ((double)normal_delay);
1575 int msec = 1000 * sec;
1577 torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
1579 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1581 torture_comment(tctx, "Open the file handle\n");
1582 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1585 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1589 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1590 finfo0.basic_info.in.file.fnum = fnum1;
1594 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1595 pinfo0.basic_info.in.file.path = fname;
1601 /* get the initial times */
1602 GET_INFO_BOTH(finfo0,pinfo0);
1605 * sleep some time, to demonstrate the handling of write times
1606 * doesn't depend on the time since the open
1608 smb_msleep(5 * msec);
1610 /* get the initial times */
1611 GET_INFO_BOTH(finfo1,pinfo1);
1612 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1615 * make sure the write time is updated 2 seconds later
1616 * calcuated from the first write
1617 * (but expect upto 5 seconds extra time for a busy server)
1619 start = timeval_current();
1620 end = timeval_add(&start, 7 * sec, 0);
1621 while (!timeval_expired(&end)) {
1623 torture_comment(tctx, "Do a write on the file handle\n");
1624 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1626 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1630 /* get the times after the write */
1631 GET_INFO_FILE(finfo1);
1633 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1634 double diff = timeval_elapsed(&start);
1635 if (diff < (used_delay / (double)1000000)) {
1636 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1637 "(1sec == %.2f) (wrong!)\n",
1643 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1648 smb_msleep(0.5 * msec);
1651 GET_INFO_BOTH(finfo1,pinfo1);
1652 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1654 smb_msleep(3 * msec);
1657 * demonstrate that a truncate write always
1658 * updates the write time immediately
1660 for (i=0; i < 3; i++) {
1661 smb_msleep(2 * msec);
1663 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1664 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1666 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1670 /* get the times after the write */
1671 GET_INFO_BOTH(finfo2,pinfo2);
1672 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1676 smb_msleep(3 * msec);
1678 /* sure any further write doesn't update the write time */
1679 start = timeval_current();
1680 end = timeval_add(&start, 15 * sec, 0);
1681 while (!timeval_expired(&end)) {
1683 torture_comment(tctx, "Do a write on the file handle\n");
1684 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1686 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1690 /* get the times after the write */
1691 GET_INFO_BOTH(finfo2,pinfo2);
1693 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1694 double diff = timeval_elapsed(&start);
1695 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1701 smb_msleep(1 * msec);
1704 GET_INFO_BOTH(finfo2,pinfo2);
1705 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1706 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1707 torture_comment(tctx, "Server did not update write_time (correct)\n");
1711 smb_msleep(3 * msec);
1713 /* get the initial times */
1714 GET_INFO_BOTH(finfo1,pinfo1);
1715 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1718 * demonstrate that a truncate write always
1719 * updates the write time immediately
1721 for (i=0; i < 3; i++) {
1722 smb_msleep(2 * msec);
1724 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1725 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1727 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1731 /* get the times after the write */
1732 GET_INFO_BOTH(finfo2,pinfo2);
1733 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1738 smb_msleep(3 * msec);
1740 GET_INFO_BOTH(finfo3,pinfo3);
1741 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1744 * the close doesn't update the write time
1746 torture_comment(tctx, "Close the file handle\n");
1747 smbcli_close(cli->tree, fnum1);
1750 GET_INFO_PATH(pinfo4);
1751 COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1753 if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1754 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1759 smbcli_close(cli->tree, fnum1);
1760 smbcli_unlink(cli->tree, fname);
1761 smbcli_deltree(cli->tree, BASEDIR);
1767 * Show a close after write updates the write timestamp to
1768 * the close time, not the last write time.
1771 static bool test_delayed_write_update3b(struct torture_context *tctx,
1772 struct smbcli_state *cli,
1773 struct smbcli_state *cli2)
1775 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1776 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1777 const char *fname = BASEDIR "\\torture_file3b.txt";
1781 struct timeval start;
1783 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1784 int normal_delay = 2000000;
1785 double sec = ((double)used_delay) / ((double)normal_delay);
1786 int msec = 1000 * sec;
1788 torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
1790 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1792 torture_comment(tctx, "Open the file handle\n");
1793 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1796 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1800 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1801 finfo0.basic_info.in.file.fnum = fnum1;
1805 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1806 pinfo0.basic_info.in.file.path = fname;
1812 /* get the initial times */
1813 GET_INFO_BOTH(finfo0,pinfo0);
1816 * sleep some time, to demonstrate the handling of write times
1817 * doesn't depend on the time since the open
1819 smb_msleep(5 * msec);
1821 /* get the initial times */
1822 GET_INFO_BOTH(finfo1,pinfo1);
1823 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1826 * make sure the write time is updated 2 seconds later
1827 * calcuated from the first write
1828 * (but expect upto 5 seconds extra time for a busy server)
1830 start = timeval_current();
1831 end = timeval_add(&start, 7 * sec, 0);
1832 while (!timeval_expired(&end)) {
1834 torture_comment(tctx, "Do a write on the file handle\n");
1835 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1837 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1841 /* get the times after the write */
1842 GET_INFO_FILE(finfo1);
1844 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1845 double diff = timeval_elapsed(&start);
1846 if (diff < (used_delay / (double)1000000)) {
1847 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1848 "(expected > %.2f) (wrong!)\n",
1849 diff, used_delay / (double)1000000);
1854 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1855 "(write time update delay == %.2f) (correct)\n",
1856 diff, used_delay / (double)1000000);
1859 smb_msleep(0.5 * msec);
1862 GET_INFO_BOTH(finfo1,pinfo1);
1863 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1865 /* sure any further write doesn't update the write time */
1866 start = timeval_current();
1867 end = timeval_add(&start, 15 * sec, 0);
1868 while (!timeval_expired(&end)) {
1870 torture_comment(tctx, "Do a write on the file handle\n");
1871 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1873 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1877 /* get the times after the write */
1878 GET_INFO_BOTH(finfo2,pinfo2);
1880 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1881 double diff = timeval_elapsed(&start);
1882 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1888 smb_msleep(1 * msec);
1891 GET_INFO_BOTH(finfo2,pinfo2);
1892 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1893 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1894 torture_comment(tctx, "Server did not update write_time (correct)\n");
1898 smb_msleep(5 * msec);
1900 GET_INFO_BOTH(finfo3,pinfo3);
1901 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1904 * the close updates the write time to the time of the close
1905 * and not to the time of the last write!
1907 torture_comment(tctx, "Close the file handle\n");
1908 smbcli_close(cli->tree, fnum1);
1911 GET_INFO_PATH(pinfo4);
1912 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1914 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1915 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1920 smbcli_close(cli->tree, fnum1);
1921 smbcli_unlink(cli->tree, fname);
1922 smbcli_deltree(cli->tree, BASEDIR);
1928 * Check that a write after a truncate write doesn't update
1929 * the timestamp, but a truncate write after a write does.
1930 * Also prove that a close after a truncate write updates the
1931 * timestamp to current, not the time of last write.
1934 static bool test_delayed_write_update3c(struct torture_context *tctx,
1935 struct smbcli_state *cli,
1936 struct smbcli_state *cli2)
1938 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1939 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1940 const char *fname = BASEDIR "\\torture_file3c.txt";
1945 struct timeval start;
1947 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1948 int normal_delay = 2000000;
1949 double sec = ((double)used_delay) / ((double)normal_delay);
1950 int msec = 1000 * sec;
1952 torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
1954 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1956 torture_comment(tctx, "Open the file handle\n");
1957 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1960 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1964 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1965 finfo0.basic_info.in.file.fnum = fnum1;
1969 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1970 pinfo0.basic_info.in.file.path = fname;
1976 /* get the initial times */
1977 GET_INFO_BOTH(finfo0,pinfo0);
1980 * sleep some time, to demonstrate the handling of write times
1981 * doesn't depend on the time since the open
1983 smb_msleep(5 * msec);
1985 /* get the initial times */
1986 GET_INFO_BOTH(finfo1,pinfo1);
1987 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1990 * demonstrate that a truncate write always
1991 * updates the write time immediately
1993 for (i=0; i < 3; i++) {
1994 smb_msleep(2 * msec);
1996 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1997 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1999 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2003 /* get the times after the write */
2004 GET_INFO_BOTH(finfo2,pinfo2);
2005 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2009 start = timeval_current();
2010 end = timeval_add(&start, 7 * sec, 0);
2011 while (!timeval_expired(&end)) {
2013 torture_comment(tctx, "Do a write on the file handle\n");
2014 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2016 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2020 /* get the times after the write */
2021 GET_INFO_FILE(finfo2);
2023 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2024 double diff = timeval_elapsed(&start);
2025 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2031 smb_msleep(1 * msec);
2034 GET_INFO_BOTH(finfo2,pinfo2);
2035 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2036 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2037 torture_comment(tctx, "Server did not update write_time (correct)\n");
2041 smb_msleep(5 * msec);
2043 /* get the initial times */
2044 GET_INFO_BOTH(finfo1,pinfo1);
2045 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2048 * demonstrate that a truncate write always
2049 * updates the write time immediately
2051 for (i=0; i < 3; i++) {
2052 smb_msleep(2 * msec);
2054 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2055 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2057 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2061 /* get the times after the write */
2062 GET_INFO_BOTH(finfo2,pinfo2);
2063 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2068 smb_msleep(5 * msec);
2070 GET_INFO_BOTH(finfo2,pinfo2);
2071 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2073 /* sure any further write doesn't update the write time */
2074 start = timeval_current();
2075 end = timeval_add(&start, 15 * sec, 0);
2076 while (!timeval_expired(&end)) {
2078 torture_comment(tctx, "Do a write on the file handle\n");
2079 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2081 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2085 /* get the times after the write */
2086 GET_INFO_BOTH(finfo2,pinfo2);
2088 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2089 double diff = timeval_elapsed(&start);
2090 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2096 smb_msleep(1 * msec);
2099 GET_INFO_BOTH(finfo2,pinfo2);
2100 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2101 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2102 torture_comment(tctx, "Server did not update write_time (correct)\n");
2106 smb_msleep(5 * msec);
2108 GET_INFO_BOTH(finfo3,pinfo3);
2109 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2112 * the close updates the write time to the time of the close
2113 * and not to the time of the last write!
2115 torture_comment(tctx, "Close the file handle\n");
2116 smbcli_close(cli->tree, fnum1);
2119 GET_INFO_PATH(pinfo4);
2120 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2122 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2123 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2128 smbcli_close(cli->tree, fnum1);
2129 smbcli_unlink(cli->tree, fname);
2130 smbcli_deltree(cli->tree, BASEDIR);
2136 * Show only the first write updates the timestamp, and a close
2137 * after writes updates to current (I think this is the same
2141 static bool test_delayed_write_update4(struct torture_context *tctx,
2142 struct smbcli_state *cli,
2143 struct smbcli_state *cli2)
2145 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
2146 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
2147 const char *fname = BASEDIR "\\torture_file4.txt";
2151 struct timeval start;
2153 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2154 int normal_delay = 2000000;
2155 double sec = ((double)used_delay) / ((double)normal_delay);
2156 int msec = 1000 * sec;
2158 torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2160 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2162 torture_comment(tctx, "Open the file handle\n");
2163 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2166 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2170 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2171 finfo0.basic_info.in.file.fnum = fnum1;
2175 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2176 pinfo0.basic_info.in.file.path = fname;
2182 /* get the initial times */
2183 GET_INFO_BOTH(finfo0,pinfo0);
2186 smb_msleep(5 * msec);
2189 torture_comment(tctx, "Do a write on the file handle\n");
2190 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2192 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2197 GET_INFO_BOTH(finfo1,pinfo1);
2198 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2201 * make sure the write time is updated 2 seconds later
2202 * calcuated from the first write
2203 * (but expect upto 3 seconds extra time for a busy server)
2205 start = timeval_current();
2206 end = timeval_add(&start, 5 * sec, 0);
2207 while (!timeval_expired(&end)) {
2208 /* get the times after the first write */
2209 GET_INFO_FILE(finfo1);
2211 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2212 double diff = timeval_elapsed(&start);
2213 if (diff < (used_delay / (double)1000000)) {
2214 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
2215 "(expected > %.2f) (wrong!)\n",
2216 diff, used_delay / (double)1000000);
2221 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2222 "(write time update delay == %.2f) (correct)\n",
2223 diff, used_delay / (double)1000000);
2226 smb_msleep(0.5 * msec);
2229 GET_INFO_BOTH(finfo1,pinfo1);
2230 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2232 /* sure any further write doesn't update the write time */
2233 start = timeval_current();
2234 end = timeval_add(&start, 15 * sec, 0);
2235 while (!timeval_expired(&end)) {
2237 torture_comment(tctx, "Do a write on the file handle\n");
2238 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2240 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2244 /* get the times after the write */
2245 GET_INFO_BOTH(finfo2,pinfo2);
2247 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2248 double diff = timeval_elapsed(&start);
2249 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2255 smb_msleep(1 * msec);
2258 GET_INFO_BOTH(finfo2,pinfo2);
2259 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2260 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2261 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2265 smb_msleep(5 * msec);
2267 GET_INFO_BOTH(finfo3,pinfo3);
2268 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2271 * the close updates the write time to the time of the close
2272 * and not to the time of the last write!
2274 torture_comment(tctx, "Close the file handle\n");
2275 smbcli_close(cli->tree, fnum1);
2278 GET_INFO_PATH(pinfo4);
2279 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2281 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2282 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2287 smbcli_close(cli->tree, fnum1);
2288 smbcli_unlink(cli->tree, fname);
2289 smbcli_deltree(cli->tree, BASEDIR);
2295 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2298 static bool test_delayed_write_update5(struct torture_context *tctx,
2299 struct smbcli_state *cli,
2300 struct smbcli_state *cli2)
2302 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2303 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2304 const char *fname = BASEDIR "\\torture_file5.txt";
2308 struct timeval start;
2310 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2311 int normal_delay = 2000000;
2312 double sec = ((double)used_delay) / ((double)normal_delay);
2313 int msec = 1000 * sec;
2315 torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2317 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2319 torture_comment(tctx, "Open the file handle\n");
2320 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2323 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2327 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2328 finfo0.basic_info.in.file.fnum = fnum1;
2334 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2335 pinfo0.basic_info.in.file.path = fname;
2343 /* get the initial times */
2344 GET_INFO_BOTH(finfo0,pinfo0);
2347 torture_comment(tctx, "Do a write on the file handle\n");
2348 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2350 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2355 GET_INFO_BOTH(finfo1,pinfo1);
2356 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2358 torture_comment(tctx, "Set write time in the future on the file handle\n");
2359 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2360 GET_INFO_BOTH(finfo2,pinfo2);
2361 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2363 torture_comment(tctx, "Set write time in the past on the file handle\n");
2364 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2365 GET_INFO_BOTH(finfo2,pinfo2);
2366 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2368 /* make sure the 2 second delay from the first write are canceled */
2369 start = timeval_current();
2370 end = timeval_add(&start, 15 * sec, 0);
2371 while (!timeval_expired(&end)) {
2373 /* get the times after the first write */
2374 GET_INFO_BOTH(finfo3,pinfo3);
2376 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2377 double diff = timeval_elapsed(&start);
2378 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2384 smb_msleep(1 * msec);
2387 GET_INFO_BOTH(finfo3,pinfo3);
2388 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2389 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2390 torture_comment(tctx, "Server did not update write_time (correct)\n");
2393 /* sure any further write doesn't update the write time */
2394 start = timeval_current();
2395 end = timeval_add(&start, 15 * sec, 0);
2396 while (!timeval_expired(&end)) {
2398 torture_comment(tctx, "Do a write on the file handle\n");
2399 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2401 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2405 /* get the times after the write */
2406 GET_INFO_BOTH(finfo4,pinfo4);
2408 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2409 double diff = timeval_elapsed(&start);
2410 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2416 smb_msleep(1 * msec);
2419 GET_INFO_BOTH(finfo4,pinfo4);
2420 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2421 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2422 torture_comment(tctx, "Server did not update write_time (correct)\n");
2426 smb_msleep(5 * msec);
2428 GET_INFO_BOTH(finfo5,pinfo5);
2429 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2432 * the close doesn't update the write time
2434 torture_comment(tctx, "Close the file handle\n");
2435 smbcli_close(cli->tree, fnum1);
2438 GET_INFO_PATH(pinfo6);
2439 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2441 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2442 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2447 smbcli_close(cli->tree, fnum1);
2448 smbcli_unlink(cli->tree, fname);
2449 smbcli_deltree(cli->tree, BASEDIR);
2455 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2458 static bool test_delayed_write_update5b(struct torture_context *tctx,
2459 struct smbcli_state *cli,
2460 struct smbcli_state *cli2)
2462 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2463 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2464 const char *fname = BASEDIR "\\torture_fileb.txt";
2468 struct timeval start;
2470 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2471 int normal_delay = 2000000;
2472 double sec = ((double)used_delay) / ((double)normal_delay);
2473 int msec = 1000 * sec;
2475 torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2477 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2479 torture_comment(tctx, "Open the file handle\n");
2480 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2483 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2487 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2488 finfo0.basic_info.in.file.fnum = fnum1;
2494 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2495 pinfo0.basic_info.in.file.path = fname;
2503 /* get the initial times */
2504 GET_INFO_BOTH(finfo0,pinfo0);
2507 torture_comment(tctx, "Do a write on the file handle\n");
2508 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2510 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2515 GET_INFO_BOTH(finfo1,pinfo1);
2516 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2518 torture_comment(tctx, "Set write time in the future on the file handle\n");
2519 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2520 GET_INFO_BOTH(finfo2,pinfo2);
2521 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2523 torture_comment(tctx, "Set write time in the past on the file handle\n");
2524 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2525 GET_INFO_BOTH(finfo2,pinfo2);
2526 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2528 /* make sure the 2 second delay from the first write are canceled */
2529 start = timeval_current();
2530 end = timeval_add(&start, 15 * sec, 0);
2531 while (!timeval_expired(&end)) {
2533 /* get the times after the first write */
2534 GET_INFO_BOTH(finfo3,pinfo3);
2536 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2537 double diff = timeval_elapsed(&start);
2538 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2544 smb_msleep(1 * msec);
2547 GET_INFO_BOTH(finfo3,pinfo3);
2548 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2549 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2550 torture_comment(tctx, "Server did not update write_time (correct)\n");
2553 /* Do any further write (truncates) update the write time ? */
2554 start = timeval_current();
2555 end = timeval_add(&start, 15 * sec, 0);
2556 while (!timeval_expired(&end)) {
2558 torture_comment(tctx, "Do a truncate write on the file handle\n");
2559 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2561 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2565 /* get the times after the write */
2566 GET_INFO_BOTH(finfo4,pinfo4);
2568 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2569 double diff = timeval_elapsed(&start);
2570 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2576 smb_msleep(1 * msec);
2579 GET_INFO_BOTH(finfo4,pinfo4);
2580 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2581 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2582 torture_comment(tctx, "Server did not update write_time (correct)\n");
2586 smb_msleep(5 * msec);
2588 GET_INFO_BOTH(finfo5,pinfo5);
2589 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2592 * the close doesn't update the write time
2594 torture_comment(tctx, "Close the file handle\n");
2595 smbcli_close(cli->tree, fnum1);
2598 GET_INFO_PATH(pinfo6);
2599 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2601 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2602 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2607 smbcli_close(cli->tree, fnum1);
2608 smbcli_unlink(cli->tree, fname);
2609 smbcli_deltree(cli->tree, BASEDIR);
2615 * Open 2 handles on a file. Write one one and then set the
2616 * WRITE TIME explicitly on the other. Ensure the write time
2617 * update is cancelled. Ensure the write time is updated to
2618 * the close time when the non-explicit set handle is closed.
2622 static bool test_delayed_write_update6(struct torture_context *tctx,
2623 struct smbcli_state *cli,
2624 struct smbcli_state *cli2)
2626 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2627 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2628 const char *fname = BASEDIR "\\torture_file6.txt";
2633 struct timeval start;
2635 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2636 int normal_delay = 2000000;
2637 double sec = ((double)used_delay) / ((double)normal_delay);
2638 int msec = 1000 * sec;
2641 torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2643 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2645 torture_comment(tctx, "Open the file handle\n");
2646 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2649 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2654 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2655 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2658 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2663 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2664 finfo0.basic_info.in.file.fnum = fnum1;
2670 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2671 pinfo0.basic_info.in.file.path = fname;
2680 /* get the initial times */
2681 GET_INFO_BOTH(finfo0,pinfo0);
2684 torture_comment(tctx, "Do a write on the file handle\n");
2685 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2687 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2692 GET_INFO_BOTH(finfo1,pinfo1);
2693 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2695 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2696 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2697 GET_INFO_BOTH(finfo2,pinfo2);
2698 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2700 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2701 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2702 GET_INFO_BOTH(finfo2,pinfo2);
2703 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2705 /* make sure the 2 second delay from the first write are canceled */
2706 start = timeval_current();
2707 end = timeval_add(&start, 10 * sec, 0);
2708 while (!timeval_expired(&end)) {
2710 /* get the times after the first write */
2711 GET_INFO_BOTH(finfo3,pinfo3);
2713 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2714 double diff = timeval_elapsed(&start);
2715 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2721 smb_msleep(1 * msec);
2724 GET_INFO_BOTH(finfo3,pinfo3);
2725 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2726 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2727 torture_comment(tctx, "Server did not update write_time (correct)\n");
2730 /* sure any further write doesn't update the write time */
2731 start = timeval_current();
2732 end = timeval_add(&start, 10 * sec, 0);
2733 while (!timeval_expired(&end)) {
2735 torture_comment(tctx, "Do a write on the file handle\n");
2736 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2738 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2742 /* get the times after the write */
2743 GET_INFO_BOTH(finfo4,pinfo4);
2745 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2746 double diff = timeval_elapsed(&start);
2747 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2753 smb_msleep(1 * msec);
2756 GET_INFO_BOTH(finfo4,pinfo4);
2757 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2758 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2759 torture_comment(tctx, "Server did not update write_time (correct)\n");
2763 smb_msleep(5 * msec);
2765 GET_INFO_BOTH(finfo5,pinfo5);
2766 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2769 * the close updates the write time to the time of the close
2770 * as the write time was set on the 2nd handle
2772 torture_comment(tctx, "Close the file handle\n");
2773 smbcli_close(cli->tree, fnum1);
2776 GET_INFO_PATH(pinfo6);
2777 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2779 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2780 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2783 /* See what the second write handle thinks the time is ? */
2784 finfo5.basic_info.in.file.fnum = fnum2;
2785 GET_INFO_FILE2(finfo5);
2786 COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
2788 /* See if we have lost the sticky write time on handle2 */
2789 smb_msleep(3 * msec);
2790 torture_comment(tctx, "Have we lost the sticky write time ?\n");
2792 /* Make sure any further normal write doesn't update the write time */
2793 start = timeval_current();
2794 end = timeval_add(&start, 10 * sec, 0);
2795 while (!timeval_expired(&end)) {
2797 torture_comment(tctx, "Do a write on the second file handle\n");
2798 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
2800 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2804 /* get the times after the write */
2805 GET_INFO_FILE2(finfo5);
2806 GET_INFO_PATH(pinfo6);
2808 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2809 double diff = timeval_elapsed(&start);
2810 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2816 smb_msleep(1 * msec);
2819 /* What about a truncate write ? */
2820 start = timeval_current();
2821 end = timeval_add(&start, 10 * sec, 0);
2822 while (!timeval_expired(&end)) {
2824 torture_comment(tctx, "Do a truncate write on the second file handle\n");
2825 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
2827 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2831 /* get the times after the write */
2832 GET_INFO_FILE2(finfo5);
2833 GET_INFO_PATH(pinfo6);
2835 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2836 double diff = timeval_elapsed(&start);
2837 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2843 smb_msleep(1 * msec);
2847 /* keep the 2nd handle open and rerun tests */
2854 * closing the 2nd handle will cause no write time update
2855 * as the write time was explicit set on this handle
2857 torture_comment(tctx, "Close the 2nd file handle\n");
2858 smbcli_close(cli2->tree, fnum2);
2861 GET_INFO_PATH(pinfo7);
2862 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2864 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2865 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2870 smbcli_close(cli->tree, fnum1);
2872 smbcli_close(cli2->tree, fnum2);
2873 smbcli_unlink(cli->tree, fname);
2874 smbcli_deltree(cli->tree, BASEDIR);
2879 static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
2881 union smb_open open_parms;
2882 union smb_fileinfo finfo1, finfo2, finfo3;
2883 const char *fname = BASEDIR "\\torture_file7.txt";
2887 TALLOC_CTX *mem_ctx;
2889 torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2891 mem_ctx = talloc_init("test_delayed_write_update7");
2892 if (!mem_ctx) return false;
2894 ZERO_STRUCT(finfo1);
2895 ZERO_STRUCT(finfo2);
2896 ZERO_STRUCT(finfo3);
2897 ZERO_STRUCT(open_parms);
2899 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2901 /* Create the file. */
2902 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2904 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
2908 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2909 finfo1.basic_info.in.file.fnum = fnum1;
2913 /* Get the initial timestamps. */
2914 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
2916 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2918 /* Set the pending write time to a value with ns. */
2919 SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
2921 /* Get the current pending write time by fnum. */
2922 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
2924 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2926 /* Ensure the time is actually different. */
2927 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2928 torture_result(tctx, TORTURE_FAIL,
2929 "setfileinfo time matches original fileinfo time");
2933 /* Get the current pending write time by path. */
2934 finfo3.basic_info.in.file.path = fname;
2935 status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
2937 if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
2938 torture_result(tctx, TORTURE_FAIL,
2939 "qpathinfo time doens't match fileinfo time");
2943 /* Now close the file. Re-open and check that the write
2944 time is identical to the one we wrote. */
2946 smbcli_close(cli->tree, fnum1);
2948 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
2949 open_parms.ntcreatex.in.flags = 0;
2950 open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
2951 open_parms.ntcreatex.in.file_attr = 0;
2952 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
2953 NTCREATEX_SHARE_ACCESS_READ|
2954 NTCREATEX_SHARE_ACCESS_WRITE;
2955 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
2956 open_parms.ntcreatex.in.create_options = 0;
2957 open_parms.ntcreatex.in.fname = fname;
2959 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
2960 talloc_free(mem_ctx);
2962 if (!NT_STATUS_IS_OK(status)) {
2963 torture_result(tctx, TORTURE_FAIL,
2964 "setfileinfo time matches original fileinfo time");
2968 fnum1 = open_parms.ntcreatex.out.file.fnum;
2970 /* Check the returned time matches. */
2971 if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
2972 torture_result(tctx, TORTURE_FAIL,
2973 "final open time does not match set time");
2979 smbcli_close(cli->tree, fnum1);
2981 smbcli_unlink(cli->tree, fname);
2982 smbcli_deltree(cli->tree, BASEDIR);
2987 Test if creating a file in a directory with an open handle updates the
2988 write timestamp (it should).
2990 static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
2992 union smb_fileinfo dir_info1, dir_info2;
2993 union smb_open open_parms;
2994 const char *fname = BASEDIR "\\torture_file.txt";
2999 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3000 int normal_delay = 2000000;
3001 double sec = ((double)used_delay) / ((double)normal_delay);
3002 int msec = 1000 * sec;
3003 TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
3005 if (!mem_ctx) return false;
3007 torture_comment(tctx, "\nRunning test directory write update\n");
3009 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
3011 /* Open a handle on the directory - and leave it open. */
3012 ZERO_STRUCT(open_parms);
3013 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3014 open_parms.ntcreatex.in.flags = 0;
3015 open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
3016 open_parms.ntcreatex.in.file_attr = 0;
3017 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3018 NTCREATEX_SHARE_ACCESS_READ|
3019 NTCREATEX_SHARE_ACCESS_WRITE;
3020 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3021 open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
3022 open_parms.ntcreatex.in.fname = BASEDIR;
3024 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3025 talloc_free(mem_ctx);
3027 if (!NT_STATUS_IS_OK(status)) {
3028 torture_result(tctx, TORTURE_FAIL,
3029 "failed to open directory handle");
3034 fnum1 = open_parms.ntcreatex.out.file.fnum;
3036 /* Store the returned write time. */
3037 ZERO_STRUCT(dir_info1);
3038 dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
3040 torture_comment(tctx, "Initial write time %s\n",
3041 nt_time_string(tctx, dir_info1.basic_info.out.write_time));
3044 smb_msleep(3 * msec);
3046 /* Now create a file within the directory. */
3047 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3049 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
3053 smbcli_close(cli->tree, fnum2);
3055 /* Read the directory write time again. */
3056 ZERO_STRUCT(dir_info2);
3057 dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3058 dir_info2.basic_info.in.file.fnum = fnum1;
3060 status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
3062 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
3064 /* Ensure it's been incremented. */
3065 COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
3067 torture_comment(tctx, "Updated write time %s\n",
3068 nt_time_string(tctx, dir_info2.basic_info.out.write_time));
3073 smbcli_close(cli->tree, fnum1);
3074 smbcli_unlink(cli->tree, fname);
3075 smbcli_deltree(cli->tree, BASEDIR);
3081 testing of delayed update of write_time
3083 struct torture_suite *torture_delay_write(void)
3085 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "delaywrite");
3087 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
3088 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
3089 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
3090 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
3091 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
3092 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
3093 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
3094 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
3095 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
3096 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
3097 torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
3098 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
3099 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
3100 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
3101 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
3102 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3103 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3104 torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);