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_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
487 "file size not as expected after write(2048)");
489 torture_comment(tctx, "Initial write time %s\n",
490 nt_time_string(tctx, finfo1.all_info.out.write_time));
492 /* Do a SET_END_OF_FILE_INFO call to truncate. */
493 status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
495 torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
497 start = timeval_current();
498 end = timeval_add(&start, (120*sec), 0);
499 while (!timeval_expired(&end)) {
500 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
502 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
504 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
505 "file not truncated to expected size "
508 torture_comment(tctx, "write time %s\n",
509 nt_time_string(tctx, finfo2.all_info.out.write_time));
510 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
511 double diff = timeval_elapsed(&start);
512 if (diff > (0.25 * (used_delay / (double)1000000))) {
513 torture_result(tctx, TORTURE_FAIL,
514 "After SET_END_OF_FILE truncate "
515 "server updated write_time after %.2f seconds"
516 "(write time update delay == %.2f)(wrong!)",
517 diff, used_delay / (double)1000000);
522 torture_comment(tctx, "After SET_END_OF_FILE truncate "
523 "server updated write_time after %.2f seconds"
524 "(write time update delay == %.2f)(correct)\n",
525 diff, used_delay / (double)1000000);
529 smb_msleep(1 * msec);
532 torture_assert_u64_not_equal(tctx,
533 finfo2.all_info.out.write_time,
534 finfo1.all_info.out.write_time,
535 "Server did not update write time");
538 smb_msleep(2 * msec);
540 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
541 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
543 torture_assert_int_equal(tctx, written, 1,
544 "unexpected number of bytes written");
546 start = timeval_current();
547 end = timeval_add(&start, (10*sec), 0);
548 while (!timeval_expired(&end)) {
549 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
551 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
553 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
554 "file not truncated to expected size "
557 torture_comment(tctx, "write time %s\n",
558 nt_time_string(tctx, finfo3.all_info.out.write_time));
559 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
560 double diff = timeval_elapsed(&start);
562 torture_comment(tctx, "server updated write_time after %.2f seconds"
563 "(write time update delay == %.2f)(correct)\n",
564 diff, used_delay / (double)1000000);
568 smb_msleep(1 * msec);
571 torture_assert_u64_equal(tctx,
572 finfo3.all_info.out.write_time,
573 finfo2.all_info.out.write_time,
574 "Server updated write time");
576 /* the close should trigger an write time update */
577 smbcli_close(cli->tree, fnum1);
580 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
581 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
583 torture_assert_u64_not_equal(tctx,
584 pinfo4.all_info.out.write_time,
585 finfo3.all_info.out.write_time,
586 "Server did not update write time on "
589 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
590 "Server updated write time on close, but to an earlier point "
593 torture_comment(tctx, "Server updated write time on close (correct)\n");
596 smbcli_close(cli->tree, fnum1);
597 smbcli_unlink(cli->tree, fname);
598 smbcli_deltree(cli->tree, BASEDIR);
603 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
605 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
607 union smb_setfileinfo parms;
608 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
609 const char *fname = BASEDIR "\\torture_file1c.txt";
614 struct timeval start;
616 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
617 int normal_delay = 2000000;
618 double sec = ((double)used_delay) / ((double)normal_delay);
619 int msec = 1000 * sec;
622 torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
624 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
626 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
628 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
632 memset(buf, 'x', 2048);
633 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
635 /* 3 second delay to ensure we get past any 2 second time
636 granularity (older systems may have that) */
637 smb_msleep(3 * msec);
639 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
640 finfo1.all_info.in.file.fnum = fnum1;
643 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
644 pinfo4.all_info.in.file.path = fname;
646 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
648 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
650 torture_comment(tctx, "Initial write time %s\n",
651 nt_time_string(tctx, finfo1.all_info.out.write_time));
653 /* Do a SET_ALLOCATION_SIZE call to truncate. */
654 parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
655 parms.allocation_info.in.file.fnum = fnum1;
656 parms.allocation_info.in.alloc_size = 0;
658 status = smb_raw_setfileinfo(cli->tree, &parms);
660 torture_assert_ntstatus_ok(tctx, status,
661 "RAW_SFILEINFO_ALLOCATION_INFO failed");
663 start = timeval_current();
664 end = timeval_add(&start, (120*sec), 0);
665 while (!timeval_expired(&end)) {
666 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
668 if (!NT_STATUS_IS_OK(status)) {
669 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
675 if (finfo2.all_info.out.size != 0) {
676 torture_result(tctx, TORTURE_FAIL,
677 "file not truncated (size = %u, should be 10240)",
678 (unsigned int)finfo2.all_info.out.size);
683 torture_comment(tctx, "write time %s\n",
684 nt_time_string(tctx, finfo2.all_info.out.write_time));
685 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
686 double diff = timeval_elapsed(&start);
687 if (diff > (0.25 * (used_delay / (double)1000000))) {
688 torture_result(tctx, TORTURE_FAIL, "After SET_ALLOCATION_INFO truncate "
689 "server updated write_time after %.2f seconds"
690 "(write time update delay == %.2f)(wrong!)\n",
691 diff, used_delay / (double)1000000);
696 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
697 "server updated write_time after %.2f seconds"
698 "(write time update delay == %.2f)(correct)\n",
699 diff, used_delay / (double)1000000);
703 smb_msleep(1 * msec);
706 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
707 torture_result(tctx, TORTURE_FAIL,
708 "Server did not update write time (wrong!)");
713 smb_msleep(2 * msec);
715 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
716 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
717 torture_assert_int_equal(tctx, written, 1,
718 "Unexpected number of bytes written");
720 start = timeval_current();
721 end = timeval_add(&start, (10*sec), 0);
722 while (!timeval_expired(&end)) {
723 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
725 if (!NT_STATUS_IS_OK(status)) {
726 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
732 if (finfo3.all_info.out.size != 1) {
733 torture_result(tctx, TORTURE_FAIL, "file not expanded");
738 torture_comment(tctx, "write time %s\n",
739 nt_time_string(tctx, finfo3.all_info.out.write_time));
740 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
741 double diff = timeval_elapsed(&start);
743 torture_comment(tctx, "server updated write_time after %.2f seconds"
744 "(write time update delay == %.2f)(wrong)\n",
745 diff, used_delay / (double)1000000);
749 smb_msleep(1 * msec);
752 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
753 torture_result(tctx, TORTURE_FAIL,
754 "Server updated write time (wrong!)");
758 /* the close should trigger an write time update */
759 smbcli_close(cli->tree, fnum1);
762 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
763 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
765 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
766 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
768 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
769 torture_comment(tctx, "Server updated write time on close (correct)\n");
773 smbcli_close(cli->tree, fnum1);
774 smbcli_unlink(cli->tree, fname);
775 smbcli_deltree(cli->tree, BASEDIR);
781 * Do as above, but using 2 connections.
784 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
785 struct smbcli_state *cli2)
787 union smb_fileinfo finfo1, finfo2;
788 const char *fname = BASEDIR "\\torture_file.txt";
794 struct timeval start;
796 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
797 int normal_delay = 2000000;
798 double sec = ((double)used_delay) / ((double)normal_delay);
799 int msec = 1000 * sec;
800 union smb_flush flsh;
802 torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
804 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
806 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
808 torture_comment(tctx, "Failed to open %s\n", fname);
812 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
813 finfo1.basic_info.in.file.fnum = fnum1;
816 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
818 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
820 torture_comment(tctx, "Initial write time %s\n",
821 nt_time_string(tctx, finfo1.basic_info.out.write_time));
823 /* 3 second delay to ensure we get past any 2 second time
824 granularity (older systems may have that) */
825 smb_msleep(3 * msec);
828 /* Try using setfileinfo instead of write to update write time. */
829 union smb_setfileinfo sfinfo;
830 time_t t_set = time(NULL);
831 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
832 sfinfo.basic_info.in.file.fnum = fnum1;
833 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
834 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
836 /* I tried this with both + and - ve to see if it makes a different.
837 It doesn't - once the filetime is set via setfileinfo it stays that way. */
839 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
841 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
843 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
844 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
846 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
848 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
851 finfo2.basic_info.in.file.path = fname;
853 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
855 if (!NT_STATUS_IS_OK(status)) {
856 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
859 torture_comment(tctx, "write time %s\n",
860 nt_time_string(tctx, finfo2.basic_info.out.write_time));
862 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
863 torture_comment(tctx, "Server updated write_time (correct)\n");
865 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
869 /* Now try a write to see if the write time gets reset. */
871 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
872 finfo1.basic_info.in.file.fnum = fnum1;
875 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
877 if (!NT_STATUS_IS_OK(status)) {
878 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
882 torture_comment(tctx, "Modified write time %s\n",
883 nt_time_string(tctx, finfo1.basic_info.out.write_time));
886 torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
888 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
891 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
892 (int)written, __location__);
896 /* Just to prove to tridge that the an smbflush has no effect on
897 the write time :-). The setfileinfo IS STICKY. JRA. */
899 torture_comment(tctx, "Doing flush after write\n");
901 flsh.flush.level = RAW_FLUSH_FLUSH;
902 flsh.flush.in.file.fnum = fnum1;
903 status = smb_raw_flush(cli->tree, &flsh);
904 if (!NT_STATUS_IS_OK(status)) {
905 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
909 /* Once the time was set using setfileinfo then it stays set - writes
910 don't have any effect. But make sure. */
911 start = timeval_current();
912 end = timeval_add(&start, (15*sec), 0);
913 while (!timeval_expired(&end)) {
914 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
916 if (!NT_STATUS_IS_OK(status)) {
917 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
921 torture_comment(tctx, "write time %s\n",
922 nt_time_string(tctx, finfo2.basic_info.out.write_time));
923 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
924 double diff = timeval_elapsed(&start);
925 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
932 smb_msleep(1 * msec);
935 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
936 torture_comment(tctx, "Server did not update write time (correct)\n");
940 smb_msleep(2 * msec);
942 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
944 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
948 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");
950 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
953 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
954 (int)written, __location__);
958 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
960 if (!NT_STATUS_IS_OK(status)) {
961 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
964 torture_comment(tctx, "write time %s\n",
965 nt_time_string(tctx, finfo2.basic_info.out.write_time));
966 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
967 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
971 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
972 smbcli_close(cli->tree, fnum1);
975 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");
977 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
980 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
981 (int)written, __location__);
985 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
986 finfo1.basic_info.in.file.fnum = fnum2;
988 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
990 if (!NT_STATUS_IS_OK(status)) {
991 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
994 torture_comment(tctx, "write time %s\n",
995 nt_time_string(tctx, finfo2.basic_info.out.write_time));
996 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
997 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1001 /* Once the time was set using setfileinfo then it stays set - writes
1002 don't have any effect. But make sure. */
1003 start = timeval_current();
1004 end = timeval_add(&start, (15*sec), 0);
1005 while (!timeval_expired(&end)) {
1006 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1008 if (!NT_STATUS_IS_OK(status)) {
1009 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1013 torture_comment(tctx, "write time %s\n",
1014 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1015 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1016 double diff = timeval_elapsed(&start);
1017 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1024 smb_msleep(1 * msec);
1027 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1028 torture_comment(tctx, "Server did not update write time (correct)\n");
1031 torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1033 smbcli_close(cli->tree, fnum2);
1036 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1038 torture_comment(tctx, "Failed to open %s\n", fname);
1042 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1043 finfo1.basic_info.in.file.fnum = fnum1;
1046 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1048 if (!NT_STATUS_IS_OK(status)) {
1049 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1053 torture_comment(tctx, "Second open initial write time %s\n",
1054 nt_time_string(tctx, finfo1.basic_info.out.write_time));
1056 smb_msleep(10 * msec);
1057 torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1059 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1061 if (written != 10) {
1062 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1063 (int)written, __location__);
1067 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1068 finfo1.basic_info.in.file.fnum = fnum1;
1070 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1072 if (!NT_STATUS_IS_OK(status)) {
1073 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1076 torture_comment(tctx, "write time %s\n",
1077 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1078 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1079 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1083 /* Now the write time should be updated again */
1084 start = timeval_current();
1085 end = timeval_add(&start, (15*sec), 0);
1086 while (!timeval_expired(&end)) {
1087 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1089 if (!NT_STATUS_IS_OK(status)) {
1090 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1094 torture_comment(tctx, "write time %s\n",
1095 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1096 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1097 double diff = timeval_elapsed(&start);
1098 if (diff < (used_delay / (double)1000000)) {
1099 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1100 "(expected > %.2f) (wrong!)\n",
1101 diff, used_delay / (double)1000000);
1106 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1115 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1116 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
1121 /* One more test to do. We should read the filetime via findfirst on the
1122 second connection to ensure it's the same. This is very easy for a Windows
1123 server but a bastard to get right on a POSIX server. JRA. */
1126 smbcli_close(cli->tree, fnum1);
1127 smbcli_unlink(cli->tree, fname);
1128 smbcli_deltree(cli->tree, BASEDIR);
1134 /* Windows does obviously not update the stat info during a write call. I
1135 * *think* this is the problem causing a spurious Excel 2003 on XP error
1136 * message when saving a file. Excel does a setfileinfo, writes, and then does
1137 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1138 * that the file might have been changed in between. What i've been able to
1139 * trace down is that this happens if the getpathinfo after the write shows a
1140 * different last write time than the setfileinfo showed. This is really
1144 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
1145 struct smbcli_state *cli2)
1147 union smb_fileinfo finfo1, finfo2;
1148 const char *fname = BASEDIR "\\torture_file.txt";
1154 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1155 int normal_delay = 2000000;
1156 double sec = ((double)used_delay) / ((double)normal_delay);
1157 int msec = 1000 * sec;
1159 torture_comment(tctx, "\nRunning test_finfo_after_write\n");
1161 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1163 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1166 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1170 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1171 finfo1.basic_info.in.file.fnum = fnum1;
1173 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1175 if (!NT_STATUS_IS_OK(status)) {
1177 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1181 smb_msleep(1 * msec);
1183 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1186 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1191 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1193 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1194 smbcli_errstr(cli2->tree));
1199 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1202 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1208 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1209 finfo2.basic_info.in.file.path = fname;
1211 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1213 if (!NT_STATUS_IS_OK(status)) {
1214 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
1220 if (finfo1.basic_info.out.create_time !=
1221 finfo2.basic_info.out.create_time) {
1222 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1227 if (finfo1.basic_info.out.access_time !=
1228 finfo2.basic_info.out.access_time) {
1229 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1234 if (finfo1.basic_info.out.write_time !=
1235 finfo2.basic_info.out.write_time) {
1236 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1237 "write time conn 1 = %s, conn 2 = %s",
1238 nt_time_string(tctx, finfo1.basic_info.out.write_time),
1239 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1244 if (finfo1.basic_info.out.change_time !=
1245 finfo2.basic_info.out.change_time) {
1246 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1251 /* One of the two following calls updates the qpathinfo. */
1253 /* If you had skipped the smbcli_write on fnum2, it would
1254 * *not* have updated the stat on disk */
1256 smbcli_close(cli2->tree, fnum2);
1259 /* This call is only for the people looking at ethereal :-) */
1260 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1261 finfo2.basic_info.in.file.path = fname;
1263 status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1265 if (!NT_STATUS_IS_OK(status)) {
1266 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1273 smbcli_close(cli->tree, fnum1);
1274 smbcli_unlink(cli->tree, fname);
1275 smbcli_deltree(cli->tree, BASEDIR);
1280 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1281 uint64_t r = 10*1000*1000; \
1282 NTTIME g = (given).basic_info.out.write_time; \
1283 NTTIME gr = (g / r) * r; \
1284 NTTIME c = (correct).basic_info.out.write_time; \
1285 NTTIME cr = (c / r) * r; \
1286 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1288 if (strict && (g cmp c)) { \
1290 } else if ((g cmp c) && (gr cmp cr)) { \
1291 /* handle filesystem without high resolution timestamps */ \
1295 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1296 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1297 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1302 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1303 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1304 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1305 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1306 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1307 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1309 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1310 NTTIME g = (given).basic_info.out.access_time; \
1311 NTTIME c = (correct).basic_info.out.access_time; \
1313 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1314 #given, nt_time_string(tctx, g), \
1315 #cmp, #correct, nt_time_string(tctx, c)); \
1320 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1321 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1323 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1324 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1325 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1328 #define GET_INFO_FILE(finfo) do { \
1330 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1331 if (!NT_STATUS_IS_OK(_status)) { \
1333 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1334 nt_errstr(_status)); \
1337 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1338 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1339 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1341 #define GET_INFO_FILE2(finfo) do { \
1343 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1344 if (!NT_STATUS_IS_OK(_status)) { \
1346 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1347 nt_errstr(_status)); \
1350 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1351 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1352 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1354 #define GET_INFO_PATH(pinfo) do { \
1356 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1357 if (!NT_STATUS_IS_OK(_status)) { \
1358 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1359 nt_errstr(_status)); \
1363 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1364 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1365 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1367 #define GET_INFO_BOTH(finfo,pinfo) do { \
1368 GET_INFO_FILE(finfo); \
1369 GET_INFO_PATH(pinfo); \
1370 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1373 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1375 union smb_setfileinfo sfinfo; \
1376 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1377 sfinfo.basic_info.in.file.fnum = tfnum; \
1378 sfinfo.basic_info.in.create_time = 0; \
1379 sfinfo.basic_info.in.access_time = 0; \
1380 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1381 sfinfo.basic_info.in.change_time = 0; \
1382 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1383 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1384 if (!NT_STATUS_IS_OK(_status)) { \
1385 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1386 nt_errstr(_status)); \
1391 #define SET_INFO_FILE(finfo, wrtime) \
1392 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1394 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1396 union smb_setfileinfo sfinfo; \
1397 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1398 sfinfo.basic_info.in.file.fnum = tfnum; \
1399 sfinfo.basic_info.in.create_time = 0; \
1400 sfinfo.basic_info.in.access_time = 0; \
1401 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1402 sfinfo.basic_info.in.write_time += (ns); \
1403 sfinfo.basic_info.in.change_time = 0; \
1404 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1405 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1406 if (!NT_STATUS_IS_OK(_status)) { \
1407 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1408 nt_errstr(_status)); \
1414 static bool test_delayed_write_update3(struct torture_context *tctx,
1415 struct smbcli_state *cli,
1416 struct smbcli_state *cli2)
1418 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1419 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1420 const char *fname = BASEDIR "\\torture_file3.txt";
1424 struct timeval start;
1426 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1427 int normal_delay = 2000000;
1428 double sec = ((double)used_delay) / ((double)normal_delay);
1429 int msec = 1000 * sec;
1431 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
1433 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1435 torture_comment(tctx, "Open the file handle\n");
1436 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1439 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1443 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1444 finfo0.basic_info.in.file.fnum = fnum1;
1448 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1449 pinfo0.basic_info.in.file.path = fname;
1455 /* get the initial times */
1456 GET_INFO_BOTH(finfo0,pinfo0);
1459 * make sure the write time is updated 2 seconds later
1460 * calcuated from the first write
1461 * (but expect upto 5 seconds extra time for a busy server)
1463 start = timeval_current();
1464 end = timeval_add(&start, 7 * sec, 0);
1465 while (!timeval_expired(&end)) {
1467 torture_comment(tctx, "Do a write on the file handle\n");
1468 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1470 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1474 /* get the times after the write */
1475 GET_INFO_FILE(finfo1);
1477 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1478 double diff = timeval_elapsed(&start);
1479 if (diff < (used_delay / (double)1000000)) {
1480 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1481 "(write time update delay == %.2f) (wrong!)\n",
1482 diff, used_delay / (double)1000000);
1487 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1492 smb_msleep(0.5 * msec);
1495 GET_INFO_BOTH(finfo1,pinfo1);
1496 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1498 /* sure any further write doesn't update the write time */
1499 start = timeval_current();
1500 end = timeval_add(&start, 15 * sec, 0);
1501 while (!timeval_expired(&end)) {
1503 torture_comment(tctx, "Do a write on the file handle\n");
1504 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1506 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1510 /* get the times after the write */
1511 GET_INFO_BOTH(finfo2,pinfo2);
1513 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1514 double diff = timeval_elapsed(&start);
1515 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1521 smb_msleep(1 * msec);
1524 GET_INFO_BOTH(finfo2,pinfo2);
1525 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1526 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1527 torture_comment(tctx, "Server did not update write_time (correct)\n");
1531 smb_msleep(5 * msec);
1533 GET_INFO_BOTH(finfo3,pinfo3);
1534 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1537 * the close updates the write time to the time of the close
1538 * and not to the time of the last write!
1540 torture_comment(tctx, "Close the file handle\n");
1541 smbcli_close(cli->tree, fnum1);
1544 GET_INFO_PATH(pinfo4);
1545 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1547 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1548 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1553 smbcli_close(cli->tree, fnum1);
1554 smbcli_unlink(cli->tree, fname);
1555 smbcli_deltree(cli->tree, BASEDIR);
1561 * Show that a truncate write always updates the write time even
1562 * if an initial write has already updated the write time.
1565 static bool test_delayed_write_update3a(struct torture_context *tctx,
1566 struct smbcli_state *cli,
1567 struct smbcli_state *cli2)
1569 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1570 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1571 const char *fname = BASEDIR "\\torture_file3a.txt";
1576 struct timeval start;
1578 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1579 int normal_delay = 2000000;
1580 double sec = ((double)used_delay) / ((double)normal_delay);
1581 int msec = 1000 * sec;
1583 torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
1585 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1587 torture_comment(tctx, "Open the file handle\n");
1588 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1591 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1595 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1596 finfo0.basic_info.in.file.fnum = fnum1;
1600 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1601 pinfo0.basic_info.in.file.path = fname;
1607 /* get the initial times */
1608 GET_INFO_BOTH(finfo0,pinfo0);
1611 * sleep some time, to demonstrate the handling of write times
1612 * doesn't depend on the time since the open
1614 smb_msleep(5 * msec);
1616 /* get the initial times */
1617 GET_INFO_BOTH(finfo1,pinfo1);
1618 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1621 * make sure the write time is updated 2 seconds later
1622 * calcuated from the first write
1623 * (but expect upto 5 seconds extra time for a busy server)
1625 start = timeval_current();
1626 end = timeval_add(&start, 7 * sec, 0);
1627 while (!timeval_expired(&end)) {
1629 torture_comment(tctx, "Do a write on the file handle\n");
1630 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1632 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1636 /* get the times after the write */
1637 GET_INFO_FILE(finfo1);
1639 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1640 double diff = timeval_elapsed(&start);
1641 if (diff < (used_delay / (double)1000000)) {
1642 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1643 "(1sec == %.2f) (wrong!)\n",
1649 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1654 smb_msleep(0.5 * msec);
1657 GET_INFO_BOTH(finfo1,pinfo1);
1658 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1660 smb_msleep(3 * msec);
1663 * demonstrate that a truncate write always
1664 * updates the write time immediately
1666 for (i=0; i < 3; i++) {
1667 smb_msleep(2 * msec);
1669 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1670 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1672 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1676 /* get the times after the write */
1677 GET_INFO_BOTH(finfo2,pinfo2);
1678 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1682 smb_msleep(3 * msec);
1684 /* sure any further write doesn't update the write time */
1685 start = timeval_current();
1686 end = timeval_add(&start, 15 * sec, 0);
1687 while (!timeval_expired(&end)) {
1689 torture_comment(tctx, "Do a write on the file handle\n");
1690 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1692 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1696 /* get the times after the write */
1697 GET_INFO_BOTH(finfo2,pinfo2);
1699 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1700 double diff = timeval_elapsed(&start);
1701 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1707 smb_msleep(1 * msec);
1710 GET_INFO_BOTH(finfo2,pinfo2);
1711 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1712 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1713 torture_comment(tctx, "Server did not update write_time (correct)\n");
1717 smb_msleep(3 * msec);
1719 /* get the initial times */
1720 GET_INFO_BOTH(finfo1,pinfo1);
1721 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1724 * demonstrate that a truncate write always
1725 * updates the write time immediately
1727 for (i=0; i < 3; i++) {
1728 smb_msleep(2 * msec);
1730 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1731 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1733 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1737 /* get the times after the write */
1738 GET_INFO_BOTH(finfo2,pinfo2);
1739 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1744 smb_msleep(3 * msec);
1746 GET_INFO_BOTH(finfo3,pinfo3);
1747 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1750 * the close doesn't update the write time
1752 torture_comment(tctx, "Close the file handle\n");
1753 smbcli_close(cli->tree, fnum1);
1756 GET_INFO_PATH(pinfo4);
1757 COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1759 if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1760 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1765 smbcli_close(cli->tree, fnum1);
1766 smbcli_unlink(cli->tree, fname);
1767 smbcli_deltree(cli->tree, BASEDIR);
1773 * Show a close after write updates the write timestamp to
1774 * the close time, not the last write time.
1777 static bool test_delayed_write_update3b(struct torture_context *tctx,
1778 struct smbcli_state *cli,
1779 struct smbcli_state *cli2)
1781 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1782 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1783 const char *fname = BASEDIR "\\torture_file3b.txt";
1787 struct timeval start;
1789 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1790 int normal_delay = 2000000;
1791 double sec = ((double)used_delay) / ((double)normal_delay);
1792 int msec = 1000 * sec;
1794 torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
1796 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1798 torture_comment(tctx, "Open the file handle\n");
1799 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1802 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1806 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1807 finfo0.basic_info.in.file.fnum = fnum1;
1811 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1812 pinfo0.basic_info.in.file.path = fname;
1818 /* get the initial times */
1819 GET_INFO_BOTH(finfo0,pinfo0);
1822 * sleep some time, to demonstrate the handling of write times
1823 * doesn't depend on the time since the open
1825 smb_msleep(5 * msec);
1827 /* get the initial times */
1828 GET_INFO_BOTH(finfo1,pinfo1);
1829 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1832 * make sure the write time is updated 2 seconds later
1833 * calcuated from the first write
1834 * (but expect upto 5 seconds extra time for a busy server)
1836 start = timeval_current();
1837 end = timeval_add(&start, 7 * sec, 0);
1838 while (!timeval_expired(&end)) {
1840 torture_comment(tctx, "Do a write on the file handle\n");
1841 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1843 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1847 /* get the times after the write */
1848 GET_INFO_FILE(finfo1);
1850 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1851 double diff = timeval_elapsed(&start);
1852 if (diff < (used_delay / (double)1000000)) {
1853 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1854 "(expected > %.2f) (wrong!)\n",
1855 diff, used_delay / (double)1000000);
1860 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1861 "(write time update delay == %.2f) (correct)\n",
1862 diff, used_delay / (double)1000000);
1865 smb_msleep(0.5 * msec);
1868 GET_INFO_BOTH(finfo1,pinfo1);
1869 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1871 /* sure any further write doesn't update the write time */
1872 start = timeval_current();
1873 end = timeval_add(&start, 15 * sec, 0);
1874 while (!timeval_expired(&end)) {
1876 torture_comment(tctx, "Do a write on the file handle\n");
1877 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1879 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1883 /* get the times after the write */
1884 GET_INFO_BOTH(finfo2,pinfo2);
1886 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1887 double diff = timeval_elapsed(&start);
1888 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1894 smb_msleep(1 * msec);
1897 GET_INFO_BOTH(finfo2,pinfo2);
1898 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1899 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1900 torture_comment(tctx, "Server did not update write_time (correct)\n");
1904 smb_msleep(5 * msec);
1906 GET_INFO_BOTH(finfo3,pinfo3);
1907 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1910 * the close updates the write time to the time of the close
1911 * and not to the time of the last write!
1913 torture_comment(tctx, "Close the file handle\n");
1914 smbcli_close(cli->tree, fnum1);
1917 GET_INFO_PATH(pinfo4);
1918 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1920 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1921 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1926 smbcli_close(cli->tree, fnum1);
1927 smbcli_unlink(cli->tree, fname);
1928 smbcli_deltree(cli->tree, BASEDIR);
1934 * Check that a write after a truncate write doesn't update
1935 * the timestamp, but a truncate write after a write does.
1936 * Also prove that a close after a truncate write updates the
1937 * timestamp to current, not the time of last write.
1940 static bool test_delayed_write_update3c(struct torture_context *tctx,
1941 struct smbcli_state *cli,
1942 struct smbcli_state *cli2)
1944 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1945 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1946 const char *fname = BASEDIR "\\torture_file3c.txt";
1951 struct timeval start;
1953 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1954 int normal_delay = 2000000;
1955 double sec = ((double)used_delay) / ((double)normal_delay);
1956 int msec = 1000 * sec;
1958 torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
1960 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1962 torture_comment(tctx, "Open the file handle\n");
1963 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1966 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1970 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1971 finfo0.basic_info.in.file.fnum = fnum1;
1975 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1976 pinfo0.basic_info.in.file.path = fname;
1982 /* get the initial times */
1983 GET_INFO_BOTH(finfo0,pinfo0);
1986 * sleep some time, to demonstrate the handling of write times
1987 * doesn't depend on the time since the open
1989 smb_msleep(5 * msec);
1991 /* get the initial times */
1992 GET_INFO_BOTH(finfo1,pinfo1);
1993 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1996 * demonstrate that a truncate write always
1997 * updates the write time immediately
1999 for (i=0; i < 3; i++) {
2000 smb_msleep(2 * msec);
2002 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
2003 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2005 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2009 /* get the times after the write */
2010 GET_INFO_BOTH(finfo2,pinfo2);
2011 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2015 start = timeval_current();
2016 end = timeval_add(&start, 7 * sec, 0);
2017 while (!timeval_expired(&end)) {
2019 torture_comment(tctx, "Do a write on the file handle\n");
2020 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2022 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2026 /* get the times after the write */
2027 GET_INFO_FILE(finfo2);
2029 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2030 double diff = timeval_elapsed(&start);
2031 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2037 smb_msleep(1 * msec);
2040 GET_INFO_BOTH(finfo2,pinfo2);
2041 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2042 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2043 torture_comment(tctx, "Server did not update write_time (correct)\n");
2047 smb_msleep(5 * msec);
2049 /* get the initial times */
2050 GET_INFO_BOTH(finfo1,pinfo1);
2051 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2054 * demonstrate that a truncate write always
2055 * updates the write time immediately
2057 for (i=0; i < 3; i++) {
2058 smb_msleep(2 * msec);
2060 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2061 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2063 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2067 /* get the times after the write */
2068 GET_INFO_BOTH(finfo2,pinfo2);
2069 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2074 smb_msleep(5 * msec);
2076 GET_INFO_BOTH(finfo2,pinfo2);
2077 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2079 /* sure any further write doesn't update the write time */
2080 start = timeval_current();
2081 end = timeval_add(&start, 15 * sec, 0);
2082 while (!timeval_expired(&end)) {
2084 torture_comment(tctx, "Do a write on the file handle\n");
2085 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2087 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2091 /* get the times after the write */
2092 GET_INFO_BOTH(finfo2,pinfo2);
2094 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2095 double diff = timeval_elapsed(&start);
2096 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2102 smb_msleep(1 * msec);
2105 GET_INFO_BOTH(finfo2,pinfo2);
2106 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2107 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2108 torture_comment(tctx, "Server did not update write_time (correct)\n");
2112 smb_msleep(5 * msec);
2114 GET_INFO_BOTH(finfo3,pinfo3);
2115 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2118 * the close updates the write time to the time of the close
2119 * and not to the time of the last write!
2121 torture_comment(tctx, "Close the file handle\n");
2122 smbcli_close(cli->tree, fnum1);
2125 GET_INFO_PATH(pinfo4);
2126 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2128 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2129 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2134 smbcli_close(cli->tree, fnum1);
2135 smbcli_unlink(cli->tree, fname);
2136 smbcli_deltree(cli->tree, BASEDIR);
2142 * Show only the first write updates the timestamp, and a close
2143 * after writes updates to current (I think this is the same
2147 static bool test_delayed_write_update4(struct torture_context *tctx,
2148 struct smbcli_state *cli,
2149 struct smbcli_state *cli2)
2151 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
2152 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
2153 const char *fname = BASEDIR "\\torture_file4.txt";
2157 struct timeval start;
2159 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2160 int normal_delay = 2000000;
2161 double sec = ((double)used_delay) / ((double)normal_delay);
2162 int msec = 1000 * sec;
2164 torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2166 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2168 torture_comment(tctx, "Open the file handle\n");
2169 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2172 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2176 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2177 finfo0.basic_info.in.file.fnum = fnum1;
2181 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2182 pinfo0.basic_info.in.file.path = fname;
2188 /* get the initial times */
2189 GET_INFO_BOTH(finfo0,pinfo0);
2192 smb_msleep(5 * msec);
2195 torture_comment(tctx, "Do a write on the file handle\n");
2196 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2198 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2203 GET_INFO_BOTH(finfo1,pinfo1);
2204 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2207 * make sure the write time is updated 2 seconds later
2208 * calcuated from the first write
2209 * (but expect upto 3 seconds extra time for a busy server)
2211 start = timeval_current();
2212 end = timeval_add(&start, 5 * sec, 0);
2213 while (!timeval_expired(&end)) {
2214 /* get the times after the first write */
2215 GET_INFO_FILE(finfo1);
2217 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2218 double diff = timeval_elapsed(&start);
2219 if (diff < (used_delay / (double)1000000)) {
2220 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
2221 "(expected > %.2f) (wrong!)\n",
2222 diff, used_delay / (double)1000000);
2227 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2228 "(write time update delay == %.2f) (correct)\n",
2229 diff, used_delay / (double)1000000);
2232 smb_msleep(0.5 * msec);
2235 GET_INFO_BOTH(finfo1,pinfo1);
2236 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2238 /* sure any further write doesn't update the write time */
2239 start = timeval_current();
2240 end = timeval_add(&start, 15 * sec, 0);
2241 while (!timeval_expired(&end)) {
2243 torture_comment(tctx, "Do a write on the file handle\n");
2244 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2246 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2250 /* get the times after the write */
2251 GET_INFO_BOTH(finfo2,pinfo2);
2253 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2254 double diff = timeval_elapsed(&start);
2255 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2261 smb_msleep(1 * msec);
2264 GET_INFO_BOTH(finfo2,pinfo2);
2265 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2266 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2267 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2271 smb_msleep(5 * msec);
2273 GET_INFO_BOTH(finfo3,pinfo3);
2274 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2277 * the close updates the write time to the time of the close
2278 * and not to the time of the last write!
2280 torture_comment(tctx, "Close the file handle\n");
2281 smbcli_close(cli->tree, fnum1);
2284 GET_INFO_PATH(pinfo4);
2285 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2287 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2288 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2293 smbcli_close(cli->tree, fnum1);
2294 smbcli_unlink(cli->tree, fname);
2295 smbcli_deltree(cli->tree, BASEDIR);
2301 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2304 static bool test_delayed_write_update5(struct torture_context *tctx,
2305 struct smbcli_state *cli,
2306 struct smbcli_state *cli2)
2308 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2309 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2310 const char *fname = BASEDIR "\\torture_file5.txt";
2314 struct timeval start;
2316 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2317 int normal_delay = 2000000;
2318 double sec = ((double)used_delay) / ((double)normal_delay);
2319 int msec = 1000 * sec;
2321 torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2323 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2325 torture_comment(tctx, "Open the file handle\n");
2326 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2329 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2333 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2334 finfo0.basic_info.in.file.fnum = fnum1;
2340 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2341 pinfo0.basic_info.in.file.path = fname;
2349 /* get the initial times */
2350 GET_INFO_BOTH(finfo0,pinfo0);
2353 torture_comment(tctx, "Do a write on the file handle\n");
2354 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2356 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2361 GET_INFO_BOTH(finfo1,pinfo1);
2362 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2364 torture_comment(tctx, "Set write time in the future on the file handle\n");
2365 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2366 GET_INFO_BOTH(finfo2,pinfo2);
2367 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2369 torture_comment(tctx, "Set write time in the past on the file handle\n");
2370 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2371 GET_INFO_BOTH(finfo2,pinfo2);
2372 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2374 /* make sure the 2 second delay from the first write are canceled */
2375 start = timeval_current();
2376 end = timeval_add(&start, 15 * sec, 0);
2377 while (!timeval_expired(&end)) {
2379 /* get the times after the first write */
2380 GET_INFO_BOTH(finfo3,pinfo3);
2382 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2383 double diff = timeval_elapsed(&start);
2384 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2390 smb_msleep(1 * msec);
2393 GET_INFO_BOTH(finfo3,pinfo3);
2394 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2395 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2396 torture_comment(tctx, "Server did not update write_time (correct)\n");
2399 /* sure any further write doesn't update the write time */
2400 start = timeval_current();
2401 end = timeval_add(&start, 15 * sec, 0);
2402 while (!timeval_expired(&end)) {
2404 torture_comment(tctx, "Do a write on the file handle\n");
2405 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2407 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2411 /* get the times after the write */
2412 GET_INFO_BOTH(finfo4,pinfo4);
2414 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2415 double diff = timeval_elapsed(&start);
2416 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2422 smb_msleep(1 * msec);
2425 GET_INFO_BOTH(finfo4,pinfo4);
2426 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2427 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2428 torture_comment(tctx, "Server did not update write_time (correct)\n");
2432 smb_msleep(5 * msec);
2434 GET_INFO_BOTH(finfo5,pinfo5);
2435 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2438 * the close doesn't update the write time
2440 torture_comment(tctx, "Close the file handle\n");
2441 smbcli_close(cli->tree, fnum1);
2444 GET_INFO_PATH(pinfo6);
2445 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2447 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2448 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2453 smbcli_close(cli->tree, fnum1);
2454 smbcli_unlink(cli->tree, fname);
2455 smbcli_deltree(cli->tree, BASEDIR);
2461 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2464 static bool test_delayed_write_update5b(struct torture_context *tctx,
2465 struct smbcli_state *cli,
2466 struct smbcli_state *cli2)
2468 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2469 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2470 const char *fname = BASEDIR "\\torture_fileb.txt";
2474 struct timeval start;
2476 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2477 int normal_delay = 2000000;
2478 double sec = ((double)used_delay) / ((double)normal_delay);
2479 int msec = 1000 * sec;
2481 torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2483 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2485 torture_comment(tctx, "Open the file handle\n");
2486 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2489 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2493 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2494 finfo0.basic_info.in.file.fnum = fnum1;
2500 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2501 pinfo0.basic_info.in.file.path = fname;
2509 /* get the initial times */
2510 GET_INFO_BOTH(finfo0,pinfo0);
2513 torture_comment(tctx, "Do a write on the file handle\n");
2514 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2516 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2521 GET_INFO_BOTH(finfo1,pinfo1);
2522 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2524 torture_comment(tctx, "Set write time in the future on the file handle\n");
2525 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2526 GET_INFO_BOTH(finfo2,pinfo2);
2527 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2529 torture_comment(tctx, "Set write time in the past on the file handle\n");
2530 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2531 GET_INFO_BOTH(finfo2,pinfo2);
2532 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2534 /* make sure the 2 second delay from the first write are canceled */
2535 start = timeval_current();
2536 end = timeval_add(&start, 15 * sec, 0);
2537 while (!timeval_expired(&end)) {
2539 /* get the times after the first write */
2540 GET_INFO_BOTH(finfo3,pinfo3);
2542 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2543 double diff = timeval_elapsed(&start);
2544 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2550 smb_msleep(1 * msec);
2553 GET_INFO_BOTH(finfo3,pinfo3);
2554 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2555 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2556 torture_comment(tctx, "Server did not update write_time (correct)\n");
2559 /* Do any further write (truncates) update the write time ? */
2560 start = timeval_current();
2561 end = timeval_add(&start, 15 * sec, 0);
2562 while (!timeval_expired(&end)) {
2564 torture_comment(tctx, "Do a truncate write on the file handle\n");
2565 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2567 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2571 /* get the times after the write */
2572 GET_INFO_BOTH(finfo4,pinfo4);
2574 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2575 double diff = timeval_elapsed(&start);
2576 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2582 smb_msleep(1 * msec);
2585 GET_INFO_BOTH(finfo4,pinfo4);
2586 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2587 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2588 torture_comment(tctx, "Server did not update write_time (correct)\n");
2592 smb_msleep(5 * msec);
2594 GET_INFO_BOTH(finfo5,pinfo5);
2595 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2598 * the close doesn't update the write time
2600 torture_comment(tctx, "Close the file handle\n");
2601 smbcli_close(cli->tree, fnum1);
2604 GET_INFO_PATH(pinfo6);
2605 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2607 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2608 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2613 smbcli_close(cli->tree, fnum1);
2614 smbcli_unlink(cli->tree, fname);
2615 smbcli_deltree(cli->tree, BASEDIR);
2621 * Open 2 handles on a file. Write one one and then set the
2622 * WRITE TIME explicitly on the other. Ensure the write time
2623 * update is cancelled. Ensure the write time is updated to
2624 * the close time when the non-explicit set handle is closed.
2628 static bool test_delayed_write_update6(struct torture_context *tctx,
2629 struct smbcli_state *cli,
2630 struct smbcli_state *cli2)
2632 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2633 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2634 const char *fname = BASEDIR "\\torture_file6.txt";
2639 struct timeval start;
2641 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2642 int normal_delay = 2000000;
2643 double sec = ((double)used_delay) / ((double)normal_delay);
2644 int msec = 1000 * sec;
2647 torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2649 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2651 torture_comment(tctx, "Open the file handle\n");
2652 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2655 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2660 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2661 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2664 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2669 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2670 finfo0.basic_info.in.file.fnum = fnum1;
2676 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2677 pinfo0.basic_info.in.file.path = fname;
2686 /* get the initial times */
2687 GET_INFO_BOTH(finfo0,pinfo0);
2690 torture_comment(tctx, "Do a write on the file handle\n");
2691 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2693 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2698 GET_INFO_BOTH(finfo1,pinfo1);
2699 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2701 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2702 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2703 GET_INFO_BOTH(finfo2,pinfo2);
2704 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2706 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2707 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2708 GET_INFO_BOTH(finfo2,pinfo2);
2709 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2711 /* make sure the 2 second delay from the first write are canceled */
2712 start = timeval_current();
2713 end = timeval_add(&start, 10 * sec, 0);
2714 while (!timeval_expired(&end)) {
2716 /* get the times after the first write */
2717 GET_INFO_BOTH(finfo3,pinfo3);
2719 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2720 double diff = timeval_elapsed(&start);
2721 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2727 smb_msleep(1 * msec);
2730 GET_INFO_BOTH(finfo3,pinfo3);
2731 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2732 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2733 torture_comment(tctx, "Server did not update write_time (correct)\n");
2736 /* sure any further write doesn't update the write time */
2737 start = timeval_current();
2738 end = timeval_add(&start, 10 * sec, 0);
2739 while (!timeval_expired(&end)) {
2741 torture_comment(tctx, "Do a write on the file handle\n");
2742 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2744 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2748 /* get the times after the write */
2749 GET_INFO_BOTH(finfo4,pinfo4);
2751 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2752 double diff = timeval_elapsed(&start);
2753 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2759 smb_msleep(1 * msec);
2762 GET_INFO_BOTH(finfo4,pinfo4);
2763 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2764 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2765 torture_comment(tctx, "Server did not update write_time (correct)\n");
2769 smb_msleep(5 * msec);
2771 GET_INFO_BOTH(finfo5,pinfo5);
2772 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2775 * the close updates the write time to the time of the close
2776 * as the write time was set on the 2nd handle
2778 torture_comment(tctx, "Close the file handle\n");
2779 smbcli_close(cli->tree, fnum1);
2782 GET_INFO_PATH(pinfo6);
2783 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2785 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2786 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2789 /* See what the second write handle thinks the time is ? */
2790 finfo5.basic_info.in.file.fnum = fnum2;
2791 GET_INFO_FILE2(finfo5);
2792 COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
2794 /* See if we have lost the sticky write time on handle2 */
2795 smb_msleep(3 * msec);
2796 torture_comment(tctx, "Have we lost the sticky write time ?\n");
2798 /* Make sure any further normal write doesn't update the write time */
2799 start = timeval_current();
2800 end = timeval_add(&start, 10 * sec, 0);
2801 while (!timeval_expired(&end)) {
2803 torture_comment(tctx, "Do a write on the second file handle\n");
2804 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
2806 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2810 /* get the times after the write */
2811 GET_INFO_FILE2(finfo5);
2812 GET_INFO_PATH(pinfo6);
2814 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2815 double diff = timeval_elapsed(&start);
2816 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2822 smb_msleep(1 * msec);
2825 /* What about a truncate write ? */
2826 start = timeval_current();
2827 end = timeval_add(&start, 10 * sec, 0);
2828 while (!timeval_expired(&end)) {
2830 torture_comment(tctx, "Do a truncate write on the second file handle\n");
2831 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
2833 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2837 /* get the times after the write */
2838 GET_INFO_FILE2(finfo5);
2839 GET_INFO_PATH(pinfo6);
2841 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2842 double diff = timeval_elapsed(&start);
2843 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2849 smb_msleep(1 * msec);
2853 /* keep the 2nd handle open and rerun tests */
2860 * closing the 2nd handle will cause no write time update
2861 * as the write time was explicit set on this handle
2863 torture_comment(tctx, "Close the 2nd file handle\n");
2864 smbcli_close(cli2->tree, fnum2);
2867 GET_INFO_PATH(pinfo7);
2868 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2870 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2871 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2876 smbcli_close(cli->tree, fnum1);
2878 smbcli_close(cli2->tree, fnum2);
2879 smbcli_unlink(cli->tree, fname);
2880 smbcli_deltree(cli->tree, BASEDIR);
2885 static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
2887 union smb_open open_parms;
2888 union smb_fileinfo finfo1, finfo2, finfo3;
2889 const char *fname = BASEDIR "\\torture_file7.txt";
2893 TALLOC_CTX *mem_ctx;
2895 torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2897 mem_ctx = talloc_init("test_delayed_write_update7");
2898 if (!mem_ctx) return false;
2900 ZERO_STRUCT(finfo1);
2901 ZERO_STRUCT(finfo2);
2902 ZERO_STRUCT(finfo3);
2903 ZERO_STRUCT(open_parms);
2905 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2907 /* Create the file. */
2908 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2910 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
2914 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2915 finfo1.basic_info.in.file.fnum = fnum1;
2919 /* Get the initial timestamps. */
2920 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
2922 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2924 /* Set the pending write time to a value with ns. */
2925 SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
2927 /* Get the current pending write time by fnum. */
2928 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
2930 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2932 /* Ensure the time is actually different. */
2933 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2934 torture_result(tctx, TORTURE_FAIL,
2935 "setfileinfo time matches original fileinfo time");
2939 /* Get the current pending write time by path. */
2940 finfo3.basic_info.in.file.path = fname;
2941 status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
2943 if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
2944 torture_result(tctx, TORTURE_FAIL,
2945 "qpathinfo time doens't match fileinfo time");
2949 /* Now close the file. Re-open and check that the write
2950 time is identical to the one we wrote. */
2952 smbcli_close(cli->tree, fnum1);
2954 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
2955 open_parms.ntcreatex.in.flags = 0;
2956 open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
2957 open_parms.ntcreatex.in.file_attr = 0;
2958 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
2959 NTCREATEX_SHARE_ACCESS_READ|
2960 NTCREATEX_SHARE_ACCESS_WRITE;
2961 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
2962 open_parms.ntcreatex.in.create_options = 0;
2963 open_parms.ntcreatex.in.fname = fname;
2965 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
2966 talloc_free(mem_ctx);
2968 if (!NT_STATUS_IS_OK(status)) {
2969 torture_result(tctx, TORTURE_FAIL,
2970 "setfileinfo time matches original fileinfo time");
2974 fnum1 = open_parms.ntcreatex.out.file.fnum;
2976 /* Check the returned time matches. */
2977 if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
2978 torture_result(tctx, TORTURE_FAIL,
2979 "final open time does not match set time");
2985 smbcli_close(cli->tree, fnum1);
2987 smbcli_unlink(cli->tree, fname);
2988 smbcli_deltree(cli->tree, BASEDIR);
2993 Test if creating a file in a directory with an open handle updates the
2994 write timestamp (it should).
2996 static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
2998 union smb_fileinfo dir_info1, dir_info2;
2999 union smb_open open_parms;
3000 const char *fname = BASEDIR "\\torture_file.txt";
3005 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3006 int normal_delay = 2000000;
3007 double sec = ((double)used_delay) / ((double)normal_delay);
3008 int msec = 1000 * sec;
3009 TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
3011 if (!mem_ctx) return false;
3013 torture_comment(tctx, "\nRunning test directory write update\n");
3015 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
3017 /* Open a handle on the directory - and leave it open. */
3018 ZERO_STRUCT(open_parms);
3019 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3020 open_parms.ntcreatex.in.flags = 0;
3021 open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
3022 open_parms.ntcreatex.in.file_attr = 0;
3023 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3024 NTCREATEX_SHARE_ACCESS_READ|
3025 NTCREATEX_SHARE_ACCESS_WRITE;
3026 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3027 open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
3028 open_parms.ntcreatex.in.fname = BASEDIR;
3030 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3031 talloc_free(mem_ctx);
3033 if (!NT_STATUS_IS_OK(status)) {
3034 torture_result(tctx, TORTURE_FAIL,
3035 "failed to open directory handle");
3040 fnum1 = open_parms.ntcreatex.out.file.fnum;
3042 /* Store the returned write time. */
3043 ZERO_STRUCT(dir_info1);
3044 dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
3046 torture_comment(tctx, "Initial write time %s\n",
3047 nt_time_string(tctx, dir_info1.basic_info.out.write_time));
3050 smb_msleep(3 * msec);
3052 /* Now create a file within the directory. */
3053 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3055 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
3059 smbcli_close(cli->tree, fnum2);
3061 /* Read the directory write time again. */
3062 ZERO_STRUCT(dir_info2);
3063 dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3064 dir_info2.basic_info.in.file.fnum = fnum1;
3066 status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
3068 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
3070 /* Ensure it's been incremented. */
3071 COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
3073 torture_comment(tctx, "Updated write time %s\n",
3074 nt_time_string(tctx, dir_info2.basic_info.out.write_time));
3079 smbcli_close(cli->tree, fnum1);
3080 smbcli_unlink(cli->tree, fname);
3081 smbcli_deltree(cli->tree, BASEDIR);
3087 testing of delayed update of write_time
3089 struct torture_suite *torture_delay_write(void)
3091 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "delaywrite");
3093 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
3094 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
3095 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
3096 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
3097 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
3098 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
3099 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
3100 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
3101 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
3102 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
3103 torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
3104 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
3105 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
3106 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
3107 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
3108 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3109 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3110 torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);