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));
560 torture_assert_u64_equal(tctx,
561 finfo3.all_info.out.write_time,
562 finfo2.all_info.out.write_time,
563 talloc_asprintf(tctx,
564 "Server updated write time "
565 "after %.2f seconds (wrong!)",
566 timeval_elapsed(&start)));
569 smb_msleep(1 * msec);
572 torture_comment(tctx, "Server did not update write time within 10 "
575 /* the close should trigger an write time update */
576 smbcli_close(cli->tree, fnum1);
579 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
580 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
582 torture_assert_u64_not_equal(tctx,
583 pinfo4.all_info.out.write_time,
584 finfo3.all_info.out.write_time,
585 "Server did not update write time on "
588 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
589 "Server updated write time on close, but to an earlier point "
592 torture_comment(tctx, "Server updated write time on close (correct)\n");
595 smbcli_close(cli->tree, fnum1);
596 smbcli_unlink(cli->tree, fname);
597 smbcli_deltree(cli->tree, BASEDIR);
602 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
604 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
606 union smb_setfileinfo parms;
607 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
608 const char *fname = BASEDIR "\\torture_file1c.txt";
613 struct timeval start;
615 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
616 int normal_delay = 2000000;
617 double sec = ((double)used_delay) / ((double)normal_delay);
618 int msec = 1000 * sec;
621 torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
623 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
625 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
627 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
631 memset(buf, 'x', 2048);
632 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
634 /* 3 second delay to ensure we get past any 2 second time
635 granularity (older systems may have that) */
636 smb_msleep(3 * msec);
638 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
639 finfo1.all_info.in.file.fnum = fnum1;
642 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
643 pinfo4.all_info.in.file.path = fname;
645 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
647 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
649 torture_comment(tctx, "Initial write time %s\n",
650 nt_time_string(tctx, finfo1.all_info.out.write_time));
652 /* Do a SET_ALLOCATION_SIZE call to truncate. */
653 parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
654 parms.allocation_info.in.file.fnum = fnum1;
655 parms.allocation_info.in.alloc_size = 0;
657 status = smb_raw_setfileinfo(cli->tree, &parms);
659 torture_assert_ntstatus_ok(tctx, status,
660 "RAW_SFILEINFO_ALLOCATION_INFO failed");
662 start = timeval_current();
663 end = timeval_add(&start, (120*sec), 0);
664 while (!timeval_expired(&end)) {
665 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
667 if (!NT_STATUS_IS_OK(status)) {
668 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
674 if (finfo2.all_info.out.size != 0) {
675 torture_result(tctx, TORTURE_FAIL,
676 "file not truncated (size = %u, should be 10240)",
677 (unsigned int)finfo2.all_info.out.size);
682 torture_comment(tctx, "write time %s\n",
683 nt_time_string(tctx, finfo2.all_info.out.write_time));
684 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
685 double diff = timeval_elapsed(&start);
686 if (diff > (0.25 * (used_delay / (double)1000000))) {
687 torture_result(tctx, TORTURE_FAIL, "After SET_ALLOCATION_INFO truncate "
688 "server updated write_time after %.2f seconds"
689 "(write time update delay == %.2f)(wrong!)\n",
690 diff, used_delay / (double)1000000);
695 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
696 "server updated write_time after %.2f seconds"
697 "(write time update delay == %.2f)(correct)\n",
698 diff, used_delay / (double)1000000);
702 smb_msleep(1 * msec);
705 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
706 torture_result(tctx, TORTURE_FAIL,
707 "Server did not update write time (wrong!)");
712 smb_msleep(2 * msec);
714 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
715 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
716 torture_assert_int_equal(tctx, written, 1,
717 "Unexpected number of bytes written");
719 start = timeval_current();
720 end = timeval_add(&start, (10*sec), 0);
721 while (!timeval_expired(&end)) {
722 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
724 if (!NT_STATUS_IS_OK(status)) {
725 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
731 if (finfo3.all_info.out.size != 1) {
732 torture_result(tctx, TORTURE_FAIL, "file not expanded");
737 torture_comment(tctx, "write time %s\n",
738 nt_time_string(tctx, finfo3.all_info.out.write_time));
739 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
740 double diff = timeval_elapsed(&start);
742 torture_comment(tctx, "server updated write_time after %.2f seconds"
743 "(write time update delay == %.2f)(wrong)\n",
744 diff, used_delay / (double)1000000);
748 smb_msleep(1 * msec);
751 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
752 torture_result(tctx, TORTURE_FAIL,
753 "Server updated write time (wrong!)");
757 /* the close should trigger an write time update */
758 smbcli_close(cli->tree, fnum1);
761 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
762 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
764 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
765 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
767 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
768 torture_comment(tctx, "Server updated write time on close (correct)\n");
772 smbcli_close(cli->tree, fnum1);
773 smbcli_unlink(cli->tree, fname);
774 smbcli_deltree(cli->tree, BASEDIR);
780 * Do as above, but using 2 connections.
783 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
784 struct smbcli_state *cli2)
786 union smb_fileinfo finfo1, finfo2;
787 const char *fname = BASEDIR "\\torture_file.txt";
793 struct timeval start;
795 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
796 int normal_delay = 2000000;
797 double sec = ((double)used_delay) / ((double)normal_delay);
798 int msec = 1000 * sec;
799 union smb_flush flsh;
801 torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
803 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
805 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
807 torture_comment(tctx, "Failed to open %s\n", fname);
811 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
812 finfo1.basic_info.in.file.fnum = fnum1;
815 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
817 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
819 torture_comment(tctx, "Initial write time %s\n",
820 nt_time_string(tctx, finfo1.basic_info.out.write_time));
822 /* 3 second delay to ensure we get past any 2 second time
823 granularity (older systems may have that) */
824 smb_msleep(3 * msec);
827 /* Try using setfileinfo instead of write to update write time. */
828 union smb_setfileinfo sfinfo;
829 time_t t_set = time(NULL);
830 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
831 sfinfo.basic_info.in.file.fnum = fnum1;
832 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
833 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
835 /* I tried this with both + and - ve to see if it makes a different.
836 It doesn't - once the filetime is set via setfileinfo it stays that way. */
838 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
840 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
842 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
843 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
845 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
847 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
850 finfo2.basic_info.in.file.path = fname;
852 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
854 if (!NT_STATUS_IS_OK(status)) {
855 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
858 torture_comment(tctx, "write time %s\n",
859 nt_time_string(tctx, finfo2.basic_info.out.write_time));
861 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
862 torture_comment(tctx, "Server updated write_time (correct)\n");
864 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
868 /* Now try a write to see if the write time gets reset. */
870 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
871 finfo1.basic_info.in.file.fnum = fnum1;
874 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
876 if (!NT_STATUS_IS_OK(status)) {
877 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
881 torture_comment(tctx, "Modified write time %s\n",
882 nt_time_string(tctx, finfo1.basic_info.out.write_time));
885 torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
887 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
890 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
891 (int)written, __location__);
895 /* Just to prove to tridge that the an smbflush has no effect on
896 the write time :-). The setfileinfo IS STICKY. JRA. */
898 torture_comment(tctx, "Doing flush after write\n");
900 flsh.flush.level = RAW_FLUSH_FLUSH;
901 flsh.flush.in.file.fnum = fnum1;
902 status = smb_raw_flush(cli->tree, &flsh);
903 if (!NT_STATUS_IS_OK(status)) {
904 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
908 /* Once the time was set using setfileinfo then it stays set - writes
909 don't have any effect. But make sure. */
910 start = timeval_current();
911 end = timeval_add(&start, (15*sec), 0);
912 while (!timeval_expired(&end)) {
913 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
915 if (!NT_STATUS_IS_OK(status)) {
916 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
920 torture_comment(tctx, "write time %s\n",
921 nt_time_string(tctx, finfo2.basic_info.out.write_time));
922 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
923 double diff = timeval_elapsed(&start);
924 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
931 smb_msleep(1 * msec);
934 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
935 torture_comment(tctx, "Server did not update write time (correct)\n");
939 smb_msleep(2 * msec);
941 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
943 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
947 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");
949 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
952 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
953 (int)written, __location__);
957 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
959 if (!NT_STATUS_IS_OK(status)) {
960 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
963 torture_comment(tctx, "write time %s\n",
964 nt_time_string(tctx, finfo2.basic_info.out.write_time));
965 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
966 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
970 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
971 smbcli_close(cli->tree, fnum1);
974 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");
976 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
979 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
980 (int)written, __location__);
984 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
985 finfo1.basic_info.in.file.fnum = fnum2;
987 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
989 if (!NT_STATUS_IS_OK(status)) {
990 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
993 torture_comment(tctx, "write time %s\n",
994 nt_time_string(tctx, finfo2.basic_info.out.write_time));
995 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
996 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1000 /* Once the time was set using setfileinfo then it stays set - writes
1001 don't have any effect. But make sure. */
1002 start = timeval_current();
1003 end = timeval_add(&start, (15*sec), 0);
1004 while (!timeval_expired(&end)) {
1005 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1007 if (!NT_STATUS_IS_OK(status)) {
1008 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1012 torture_comment(tctx, "write time %s\n",
1013 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1014 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1015 double diff = timeval_elapsed(&start);
1016 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1023 smb_msleep(1 * msec);
1026 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1027 torture_comment(tctx, "Server did not update write time (correct)\n");
1030 torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1032 smbcli_close(cli->tree, fnum2);
1035 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1037 torture_comment(tctx, "Failed to open %s\n", fname);
1041 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1042 finfo1.basic_info.in.file.fnum = fnum1;
1045 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1047 if (!NT_STATUS_IS_OK(status)) {
1048 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1052 torture_comment(tctx, "Second open initial write time %s\n",
1053 nt_time_string(tctx, finfo1.basic_info.out.write_time));
1055 smb_msleep(10 * msec);
1056 torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1058 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1060 if (written != 10) {
1061 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1062 (int)written, __location__);
1066 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1067 finfo1.basic_info.in.file.fnum = fnum1;
1069 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1071 if (!NT_STATUS_IS_OK(status)) {
1072 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1075 torture_comment(tctx, "write time %s\n",
1076 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1077 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1078 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1082 /* Now the write time should be updated again */
1083 start = timeval_current();
1084 end = timeval_add(&start, (15*sec), 0);
1085 while (!timeval_expired(&end)) {
1086 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1088 if (!NT_STATUS_IS_OK(status)) {
1089 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1093 torture_comment(tctx, "write time %s\n",
1094 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1095 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1096 double diff = timeval_elapsed(&start);
1097 if (diff < (used_delay / (double)1000000)) {
1098 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1099 "(expected > %.2f) (wrong!)\n",
1100 diff, used_delay / (double)1000000);
1105 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1114 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1115 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
1120 /* One more test to do. We should read the filetime via findfirst on the
1121 second connection to ensure it's the same. This is very easy for a Windows
1122 server but a bastard to get right on a POSIX server. JRA. */
1125 smbcli_close(cli->tree, fnum1);
1126 smbcli_unlink(cli->tree, fname);
1127 smbcli_deltree(cli->tree, BASEDIR);
1133 /* Windows does obviously not update the stat info during a write call. I
1134 * *think* this is the problem causing a spurious Excel 2003 on XP error
1135 * message when saving a file. Excel does a setfileinfo, writes, and then does
1136 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1137 * that the file might have been changed in between. What i've been able to
1138 * trace down is that this happens if the getpathinfo after the write shows a
1139 * different last write time than the setfileinfo showed. This is really
1143 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
1144 struct smbcli_state *cli2)
1146 union smb_fileinfo finfo1, finfo2;
1147 const char *fname = BASEDIR "\\torture_file.txt";
1153 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1154 int normal_delay = 2000000;
1155 double sec = ((double)used_delay) / ((double)normal_delay);
1156 int msec = 1000 * sec;
1158 torture_comment(tctx, "\nRunning test_finfo_after_write\n");
1160 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1162 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1165 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1169 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1170 finfo1.basic_info.in.file.fnum = fnum1;
1172 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1174 if (!NT_STATUS_IS_OK(status)) {
1176 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1180 smb_msleep(1 * msec);
1182 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1185 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1190 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1192 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1193 smbcli_errstr(cli2->tree));
1198 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1201 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1207 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1208 finfo2.basic_info.in.file.path = fname;
1210 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1212 if (!NT_STATUS_IS_OK(status)) {
1213 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
1219 if (finfo1.basic_info.out.create_time !=
1220 finfo2.basic_info.out.create_time) {
1221 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1226 if (finfo1.basic_info.out.access_time !=
1227 finfo2.basic_info.out.access_time) {
1228 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1233 if (finfo1.basic_info.out.write_time !=
1234 finfo2.basic_info.out.write_time) {
1235 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1236 "write time conn 1 = %s, conn 2 = %s",
1237 nt_time_string(tctx, finfo1.basic_info.out.write_time),
1238 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1243 if (finfo1.basic_info.out.change_time !=
1244 finfo2.basic_info.out.change_time) {
1245 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1250 /* One of the two following calls updates the qpathinfo. */
1252 /* If you had skipped the smbcli_write on fnum2, it would
1253 * *not* have updated the stat on disk */
1255 smbcli_close(cli2->tree, fnum2);
1258 /* This call is only for the people looking at ethereal :-) */
1259 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1260 finfo2.basic_info.in.file.path = fname;
1262 status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1264 if (!NT_STATUS_IS_OK(status)) {
1265 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1272 smbcli_close(cli->tree, fnum1);
1273 smbcli_unlink(cli->tree, fname);
1274 smbcli_deltree(cli->tree, BASEDIR);
1279 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1280 uint64_t r = 10*1000*1000; \
1281 NTTIME g = (given).basic_info.out.write_time; \
1282 NTTIME gr = (g / r) * r; \
1283 NTTIME c = (correct).basic_info.out.write_time; \
1284 NTTIME cr = (c / r) * r; \
1285 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1287 if (strict && (g cmp c)) { \
1289 } else if ((g cmp c) && (gr cmp cr)) { \
1290 /* handle filesystem without high resolution timestamps */ \
1294 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1295 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1296 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1301 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1302 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1303 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1304 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1305 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1306 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1308 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1309 NTTIME g = (given).basic_info.out.access_time; \
1310 NTTIME c = (correct).basic_info.out.access_time; \
1312 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1313 #given, nt_time_string(tctx, g), \
1314 #cmp, #correct, nt_time_string(tctx, c)); \
1319 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1320 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1322 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1323 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1324 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1327 #define GET_INFO_FILE(finfo) do { \
1329 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1330 if (!NT_STATUS_IS_OK(_status)) { \
1332 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1333 nt_errstr(_status)); \
1336 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1337 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1338 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1340 #define GET_INFO_FILE2(finfo) do { \
1342 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1343 if (!NT_STATUS_IS_OK(_status)) { \
1345 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1346 nt_errstr(_status)); \
1349 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1350 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1351 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1353 #define GET_INFO_PATH(pinfo) do { \
1355 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1356 if (!NT_STATUS_IS_OK(_status)) { \
1357 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1358 nt_errstr(_status)); \
1362 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1363 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1364 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1366 #define GET_INFO_BOTH(finfo,pinfo) do { \
1367 GET_INFO_FILE(finfo); \
1368 GET_INFO_PATH(pinfo); \
1369 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1372 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1374 union smb_setfileinfo sfinfo; \
1375 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1376 sfinfo.basic_info.in.file.fnum = tfnum; \
1377 sfinfo.basic_info.in.create_time = 0; \
1378 sfinfo.basic_info.in.access_time = 0; \
1379 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1380 sfinfo.basic_info.in.change_time = 0; \
1381 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1382 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1383 if (!NT_STATUS_IS_OK(_status)) { \
1384 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1385 nt_errstr(_status)); \
1390 #define SET_INFO_FILE(finfo, wrtime) \
1391 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1393 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1395 union smb_setfileinfo sfinfo; \
1396 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1397 sfinfo.basic_info.in.file.fnum = tfnum; \
1398 sfinfo.basic_info.in.create_time = 0; \
1399 sfinfo.basic_info.in.access_time = 0; \
1400 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1401 sfinfo.basic_info.in.write_time += (ns); \
1402 sfinfo.basic_info.in.change_time = 0; \
1403 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1404 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1405 if (!NT_STATUS_IS_OK(_status)) { \
1406 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1407 nt_errstr(_status)); \
1413 static bool test_delayed_write_update3(struct torture_context *tctx,
1414 struct smbcli_state *cli,
1415 struct smbcli_state *cli2)
1417 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1418 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1419 const char *fname = BASEDIR "\\torture_file3.txt";
1423 struct timeval start;
1425 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1426 int normal_delay = 2000000;
1427 double sec = ((double)used_delay) / ((double)normal_delay);
1428 int msec = 1000 * sec;
1430 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
1432 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1434 torture_comment(tctx, "Open the file handle\n");
1435 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1438 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1442 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1443 finfo0.basic_info.in.file.fnum = fnum1;
1447 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1448 pinfo0.basic_info.in.file.path = fname;
1454 /* get the initial times */
1455 GET_INFO_BOTH(finfo0,pinfo0);
1458 * make sure the write time is updated 2 seconds later
1459 * calcuated from the first write
1460 * (but expect upto 5 seconds extra time for a busy server)
1462 start = timeval_current();
1463 end = timeval_add(&start, 7 * sec, 0);
1464 while (!timeval_expired(&end)) {
1466 torture_comment(tctx, "Do a write on the file handle\n");
1467 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1469 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1473 /* get the times after the write */
1474 GET_INFO_FILE(finfo1);
1476 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1477 double diff = timeval_elapsed(&start);
1478 if (diff < (used_delay / (double)1000000)) {
1479 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1480 "(write time update delay == %.2f) (wrong!)\n",
1481 diff, used_delay / (double)1000000);
1486 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1491 smb_msleep(0.5 * msec);
1494 GET_INFO_BOTH(finfo1,pinfo1);
1495 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1497 /* sure any further write doesn't update the write time */
1498 start = timeval_current();
1499 end = timeval_add(&start, 15 * sec, 0);
1500 while (!timeval_expired(&end)) {
1502 torture_comment(tctx, "Do a write on the file handle\n");
1503 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1505 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1509 /* get the times after the write */
1510 GET_INFO_BOTH(finfo2,pinfo2);
1512 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1513 double diff = timeval_elapsed(&start);
1514 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1520 smb_msleep(1 * msec);
1523 GET_INFO_BOTH(finfo2,pinfo2);
1524 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1525 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1526 torture_comment(tctx, "Server did not update write_time (correct)\n");
1530 smb_msleep(5 * msec);
1532 GET_INFO_BOTH(finfo3,pinfo3);
1533 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1536 * the close updates the write time to the time of the close
1537 * and not to the time of the last write!
1539 torture_comment(tctx, "Close the file handle\n");
1540 smbcli_close(cli->tree, fnum1);
1543 GET_INFO_PATH(pinfo4);
1544 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1546 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1547 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1552 smbcli_close(cli->tree, fnum1);
1553 smbcli_unlink(cli->tree, fname);
1554 smbcli_deltree(cli->tree, BASEDIR);
1560 * Show that a truncate write always updates the write time even
1561 * if an initial write has already updated the write time.
1564 static bool test_delayed_write_update3a(struct torture_context *tctx,
1565 struct smbcli_state *cli,
1566 struct smbcli_state *cli2)
1568 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1569 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1570 const char *fname = BASEDIR "\\torture_file3a.txt";
1575 struct timeval start;
1577 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1578 int normal_delay = 2000000;
1579 double sec = ((double)used_delay) / ((double)normal_delay);
1580 int msec = 1000 * sec;
1582 torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
1584 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1586 torture_comment(tctx, "Open the file handle\n");
1587 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1590 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1594 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1595 finfo0.basic_info.in.file.fnum = fnum1;
1599 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1600 pinfo0.basic_info.in.file.path = fname;
1606 /* get the initial times */
1607 GET_INFO_BOTH(finfo0,pinfo0);
1610 * sleep some time, to demonstrate the handling of write times
1611 * doesn't depend on the time since the open
1613 smb_msleep(5 * msec);
1615 /* get the initial times */
1616 GET_INFO_BOTH(finfo1,pinfo1);
1617 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1620 * make sure the write time is updated 2 seconds later
1621 * calcuated from the first write
1622 * (but expect upto 5 seconds extra time for a busy server)
1624 start = timeval_current();
1625 end = timeval_add(&start, 7 * sec, 0);
1626 while (!timeval_expired(&end)) {
1628 torture_comment(tctx, "Do a write on the file handle\n");
1629 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1631 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1635 /* get the times after the write */
1636 GET_INFO_FILE(finfo1);
1638 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1639 double diff = timeval_elapsed(&start);
1640 if (diff < (used_delay / (double)1000000)) {
1641 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1642 "(1sec == %.2f) (wrong!)\n",
1648 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1653 smb_msleep(0.5 * msec);
1656 GET_INFO_BOTH(finfo1,pinfo1);
1657 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1659 smb_msleep(3 * msec);
1662 * demonstrate that a truncate write always
1663 * updates the write time immediately
1665 for (i=0; i < 3; i++) {
1666 smb_msleep(2 * msec);
1668 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1669 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1671 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1675 /* get the times after the write */
1676 GET_INFO_BOTH(finfo2,pinfo2);
1677 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1681 smb_msleep(3 * msec);
1683 /* sure any further write doesn't update the write time */
1684 start = timeval_current();
1685 end = timeval_add(&start, 15 * sec, 0);
1686 while (!timeval_expired(&end)) {
1688 torture_comment(tctx, "Do a write on the file handle\n");
1689 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1691 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1695 /* get the times after the write */
1696 GET_INFO_BOTH(finfo2,pinfo2);
1698 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1699 double diff = timeval_elapsed(&start);
1700 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1706 smb_msleep(1 * msec);
1709 GET_INFO_BOTH(finfo2,pinfo2);
1710 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1711 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1712 torture_comment(tctx, "Server did not update write_time (correct)\n");
1716 smb_msleep(3 * msec);
1718 /* get the initial times */
1719 GET_INFO_BOTH(finfo1,pinfo1);
1720 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1723 * demonstrate that a truncate write always
1724 * updates the write time immediately
1726 for (i=0; i < 3; i++) {
1727 smb_msleep(2 * msec);
1729 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1730 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1732 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1736 /* get the times after the write */
1737 GET_INFO_BOTH(finfo2,pinfo2);
1738 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1743 smb_msleep(3 * msec);
1745 GET_INFO_BOTH(finfo3,pinfo3);
1746 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1749 * the close doesn't update the write time
1751 torture_comment(tctx, "Close the file handle\n");
1752 smbcli_close(cli->tree, fnum1);
1755 GET_INFO_PATH(pinfo4);
1756 COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1758 if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1759 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1764 smbcli_close(cli->tree, fnum1);
1765 smbcli_unlink(cli->tree, fname);
1766 smbcli_deltree(cli->tree, BASEDIR);
1772 * Show a close after write updates the write timestamp to
1773 * the close time, not the last write time.
1776 static bool test_delayed_write_update3b(struct torture_context *tctx,
1777 struct smbcli_state *cli,
1778 struct smbcli_state *cli2)
1780 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1781 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1782 const char *fname = BASEDIR "\\torture_file3b.txt";
1786 struct timeval start;
1788 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1789 int normal_delay = 2000000;
1790 double sec = ((double)used_delay) / ((double)normal_delay);
1791 int msec = 1000 * sec;
1793 torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
1795 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1797 torture_comment(tctx, "Open the file handle\n");
1798 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1801 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1805 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1806 finfo0.basic_info.in.file.fnum = fnum1;
1810 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1811 pinfo0.basic_info.in.file.path = fname;
1817 /* get the initial times */
1818 GET_INFO_BOTH(finfo0,pinfo0);
1821 * sleep some time, to demonstrate the handling of write times
1822 * doesn't depend on the time since the open
1824 smb_msleep(5 * msec);
1826 /* get the initial times */
1827 GET_INFO_BOTH(finfo1,pinfo1);
1828 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1831 * make sure the write time is updated 2 seconds later
1832 * calcuated from the first write
1833 * (but expect upto 5 seconds extra time for a busy server)
1835 start = timeval_current();
1836 end = timeval_add(&start, 7 * sec, 0);
1837 while (!timeval_expired(&end)) {
1839 torture_comment(tctx, "Do a write on the file handle\n");
1840 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1842 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1846 /* get the times after the write */
1847 GET_INFO_FILE(finfo1);
1849 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1850 double diff = timeval_elapsed(&start);
1851 if (diff < (used_delay / (double)1000000)) {
1852 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1853 "(expected > %.2f) (wrong!)\n",
1854 diff, used_delay / (double)1000000);
1859 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1860 "(write time update delay == %.2f) (correct)\n",
1861 diff, used_delay / (double)1000000);
1864 smb_msleep(0.5 * msec);
1867 GET_INFO_BOTH(finfo1,pinfo1);
1868 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1870 /* sure any further write doesn't update the write time */
1871 start = timeval_current();
1872 end = timeval_add(&start, 15 * sec, 0);
1873 while (!timeval_expired(&end)) {
1875 torture_comment(tctx, "Do a write on the file handle\n");
1876 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1878 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1882 /* get the times after the write */
1883 GET_INFO_BOTH(finfo2,pinfo2);
1885 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1886 double diff = timeval_elapsed(&start);
1887 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1893 smb_msleep(1 * msec);
1896 GET_INFO_BOTH(finfo2,pinfo2);
1897 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1898 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1899 torture_comment(tctx, "Server did not update write_time (correct)\n");
1903 smb_msleep(5 * msec);
1905 GET_INFO_BOTH(finfo3,pinfo3);
1906 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1909 * the close updates the write time to the time of the close
1910 * and not to the time of the last write!
1912 torture_comment(tctx, "Close the file handle\n");
1913 smbcli_close(cli->tree, fnum1);
1916 GET_INFO_PATH(pinfo4);
1917 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1919 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1920 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1925 smbcli_close(cli->tree, fnum1);
1926 smbcli_unlink(cli->tree, fname);
1927 smbcli_deltree(cli->tree, BASEDIR);
1933 * Check that a write after a truncate write doesn't update
1934 * the timestamp, but a truncate write after a write does.
1935 * Also prove that a close after a truncate write updates the
1936 * timestamp to current, not the time of last write.
1939 static bool test_delayed_write_update3c(struct torture_context *tctx,
1940 struct smbcli_state *cli,
1941 struct smbcli_state *cli2)
1943 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1944 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1945 const char *fname = BASEDIR "\\torture_file3c.txt";
1950 struct timeval start;
1952 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1953 int normal_delay = 2000000;
1954 double sec = ((double)used_delay) / ((double)normal_delay);
1955 int msec = 1000 * sec;
1957 torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
1959 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1961 torture_comment(tctx, "Open the file handle\n");
1962 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1965 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1969 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1970 finfo0.basic_info.in.file.fnum = fnum1;
1974 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1975 pinfo0.basic_info.in.file.path = fname;
1981 /* get the initial times */
1982 GET_INFO_BOTH(finfo0,pinfo0);
1985 * sleep some time, to demonstrate the handling of write times
1986 * doesn't depend on the time since the open
1988 smb_msleep(5 * msec);
1990 /* get the initial times */
1991 GET_INFO_BOTH(finfo1,pinfo1);
1992 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1995 * demonstrate that a truncate write always
1996 * updates the write time immediately
1998 for (i=0; i < 3; i++) {
1999 smb_msleep(2 * msec);
2001 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
2002 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2004 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2008 /* get the times after the write */
2009 GET_INFO_BOTH(finfo2,pinfo2);
2010 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2014 start = timeval_current();
2015 end = timeval_add(&start, 7 * sec, 0);
2016 while (!timeval_expired(&end)) {
2018 torture_comment(tctx, "Do a write on the file handle\n");
2019 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2021 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2025 /* get the times after the write */
2026 GET_INFO_FILE(finfo2);
2028 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2029 double diff = timeval_elapsed(&start);
2030 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2036 smb_msleep(1 * msec);
2039 GET_INFO_BOTH(finfo2,pinfo2);
2040 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2041 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2042 torture_comment(tctx, "Server did not update write_time (correct)\n");
2046 smb_msleep(5 * msec);
2048 /* get the initial times */
2049 GET_INFO_BOTH(finfo1,pinfo1);
2050 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2053 * demonstrate that a truncate write always
2054 * updates the write time immediately
2056 for (i=0; i < 3; i++) {
2057 smb_msleep(2 * msec);
2059 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2060 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2062 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2066 /* get the times after the write */
2067 GET_INFO_BOTH(finfo2,pinfo2);
2068 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2073 smb_msleep(5 * msec);
2075 GET_INFO_BOTH(finfo2,pinfo2);
2076 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2078 /* sure any further write doesn't update the write time */
2079 start = timeval_current();
2080 end = timeval_add(&start, 15 * sec, 0);
2081 while (!timeval_expired(&end)) {
2083 torture_comment(tctx, "Do a write on the file handle\n");
2084 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2086 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2090 /* get the times after the write */
2091 GET_INFO_BOTH(finfo2,pinfo2);
2093 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2094 double diff = timeval_elapsed(&start);
2095 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2101 smb_msleep(1 * msec);
2104 GET_INFO_BOTH(finfo2,pinfo2);
2105 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2106 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2107 torture_comment(tctx, "Server did not update write_time (correct)\n");
2111 smb_msleep(5 * msec);
2113 GET_INFO_BOTH(finfo3,pinfo3);
2114 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2117 * the close updates the write time to the time of the close
2118 * and not to the time of the last write!
2120 torture_comment(tctx, "Close the file handle\n");
2121 smbcli_close(cli->tree, fnum1);
2124 GET_INFO_PATH(pinfo4);
2125 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2127 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2128 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2133 smbcli_close(cli->tree, fnum1);
2134 smbcli_unlink(cli->tree, fname);
2135 smbcli_deltree(cli->tree, BASEDIR);
2141 * Show only the first write updates the timestamp, and a close
2142 * after writes updates to current (I think this is the same
2146 static bool test_delayed_write_update4(struct torture_context *tctx,
2147 struct smbcli_state *cli,
2148 struct smbcli_state *cli2)
2150 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
2151 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
2152 const char *fname = BASEDIR "\\torture_file4.txt";
2156 struct timeval start;
2158 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2159 int normal_delay = 2000000;
2160 double sec = ((double)used_delay) / ((double)normal_delay);
2161 int msec = 1000 * sec;
2163 torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2165 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2167 torture_comment(tctx, "Open the file handle\n");
2168 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2171 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2175 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2176 finfo0.basic_info.in.file.fnum = fnum1;
2180 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2181 pinfo0.basic_info.in.file.path = fname;
2187 /* get the initial times */
2188 GET_INFO_BOTH(finfo0,pinfo0);
2191 smb_msleep(5 * msec);
2194 torture_comment(tctx, "Do a write on the file handle\n");
2195 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2197 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2202 GET_INFO_BOTH(finfo1,pinfo1);
2203 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2206 * make sure the write time is updated 2 seconds later
2207 * calcuated from the first write
2208 * (but expect upto 3 seconds extra time for a busy server)
2210 start = timeval_current();
2211 end = timeval_add(&start, 5 * sec, 0);
2212 while (!timeval_expired(&end)) {
2213 /* get the times after the first write */
2214 GET_INFO_FILE(finfo1);
2216 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2217 double diff = timeval_elapsed(&start);
2218 if (diff < (used_delay / (double)1000000)) {
2219 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
2220 "(expected > %.2f) (wrong!)\n",
2221 diff, used_delay / (double)1000000);
2226 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2227 "(write time update delay == %.2f) (correct)\n",
2228 diff, used_delay / (double)1000000);
2231 smb_msleep(0.5 * msec);
2234 GET_INFO_BOTH(finfo1,pinfo1);
2235 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2237 /* sure any further write doesn't update the write time */
2238 start = timeval_current();
2239 end = timeval_add(&start, 15 * sec, 0);
2240 while (!timeval_expired(&end)) {
2242 torture_comment(tctx, "Do a write on the file handle\n");
2243 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2245 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2249 /* get the times after the write */
2250 GET_INFO_BOTH(finfo2,pinfo2);
2252 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2253 double diff = timeval_elapsed(&start);
2254 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2260 smb_msleep(1 * msec);
2263 GET_INFO_BOTH(finfo2,pinfo2);
2264 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2265 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2266 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2270 smb_msleep(5 * msec);
2272 GET_INFO_BOTH(finfo3,pinfo3);
2273 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2276 * the close updates the write time to the time of the close
2277 * and not to the time of the last write!
2279 torture_comment(tctx, "Close the file handle\n");
2280 smbcli_close(cli->tree, fnum1);
2283 GET_INFO_PATH(pinfo4);
2284 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2286 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2287 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2292 smbcli_close(cli->tree, fnum1);
2293 smbcli_unlink(cli->tree, fname);
2294 smbcli_deltree(cli->tree, BASEDIR);
2300 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2303 static bool test_delayed_write_update5(struct torture_context *tctx,
2304 struct smbcli_state *cli,
2305 struct smbcli_state *cli2)
2307 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2308 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2309 const char *fname = BASEDIR "\\torture_file5.txt";
2313 struct timeval start;
2315 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2316 int normal_delay = 2000000;
2317 double sec = ((double)used_delay) / ((double)normal_delay);
2318 int msec = 1000 * sec;
2320 torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2322 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2324 torture_comment(tctx, "Open the file handle\n");
2325 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2328 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2332 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2333 finfo0.basic_info.in.file.fnum = fnum1;
2339 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2340 pinfo0.basic_info.in.file.path = fname;
2348 /* get the initial times */
2349 GET_INFO_BOTH(finfo0,pinfo0);
2352 torture_comment(tctx, "Do a write on the file handle\n");
2353 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2355 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2360 GET_INFO_BOTH(finfo1,pinfo1);
2361 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2363 torture_comment(tctx, "Set write time in the future on the file handle\n");
2364 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2365 GET_INFO_BOTH(finfo2,pinfo2);
2366 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2368 torture_comment(tctx, "Set write time in the past on the file handle\n");
2369 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2370 GET_INFO_BOTH(finfo2,pinfo2);
2371 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2373 /* make sure the 2 second delay from the first write are canceled */
2374 start = timeval_current();
2375 end = timeval_add(&start, 15 * sec, 0);
2376 while (!timeval_expired(&end)) {
2378 /* get the times after the first write */
2379 GET_INFO_BOTH(finfo3,pinfo3);
2381 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2382 double diff = timeval_elapsed(&start);
2383 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2389 smb_msleep(1 * msec);
2392 GET_INFO_BOTH(finfo3,pinfo3);
2393 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2394 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2395 torture_comment(tctx, "Server did not update write_time (correct)\n");
2398 /* sure any further write doesn't update the write time */
2399 start = timeval_current();
2400 end = timeval_add(&start, 15 * sec, 0);
2401 while (!timeval_expired(&end)) {
2403 torture_comment(tctx, "Do a write on the file handle\n");
2404 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2406 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2410 /* get the times after the write */
2411 GET_INFO_BOTH(finfo4,pinfo4);
2413 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2414 double diff = timeval_elapsed(&start);
2415 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2421 smb_msleep(1 * msec);
2424 GET_INFO_BOTH(finfo4,pinfo4);
2425 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2426 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2427 torture_comment(tctx, "Server did not update write_time (correct)\n");
2431 smb_msleep(5 * msec);
2433 GET_INFO_BOTH(finfo5,pinfo5);
2434 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2437 * the close doesn't update the write time
2439 torture_comment(tctx, "Close the file handle\n");
2440 smbcli_close(cli->tree, fnum1);
2443 GET_INFO_PATH(pinfo6);
2444 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2446 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2447 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2452 smbcli_close(cli->tree, fnum1);
2453 smbcli_unlink(cli->tree, fname);
2454 smbcli_deltree(cli->tree, BASEDIR);
2460 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2463 static bool test_delayed_write_update5b(struct torture_context *tctx,
2464 struct smbcli_state *cli,
2465 struct smbcli_state *cli2)
2467 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2468 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2469 const char *fname = BASEDIR "\\torture_fileb.txt";
2473 struct timeval start;
2475 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2476 int normal_delay = 2000000;
2477 double sec = ((double)used_delay) / ((double)normal_delay);
2478 int msec = 1000 * sec;
2480 torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2482 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2484 torture_comment(tctx, "Open the file handle\n");
2485 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2488 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2492 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2493 finfo0.basic_info.in.file.fnum = fnum1;
2499 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2500 pinfo0.basic_info.in.file.path = fname;
2508 /* get the initial times */
2509 GET_INFO_BOTH(finfo0,pinfo0);
2512 torture_comment(tctx, "Do a write on the file handle\n");
2513 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2515 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2520 GET_INFO_BOTH(finfo1,pinfo1);
2521 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2523 torture_comment(tctx, "Set write time in the future on the file handle\n");
2524 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2525 GET_INFO_BOTH(finfo2,pinfo2);
2526 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2528 torture_comment(tctx, "Set write time in the past on the file handle\n");
2529 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2530 GET_INFO_BOTH(finfo2,pinfo2);
2531 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2533 /* make sure the 2 second delay from the first write are canceled */
2534 start = timeval_current();
2535 end = timeval_add(&start, 15 * sec, 0);
2536 while (!timeval_expired(&end)) {
2538 /* get the times after the first write */
2539 GET_INFO_BOTH(finfo3,pinfo3);
2541 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2542 double diff = timeval_elapsed(&start);
2543 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2549 smb_msleep(1 * msec);
2552 GET_INFO_BOTH(finfo3,pinfo3);
2553 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2554 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2555 torture_comment(tctx, "Server did not update write_time (correct)\n");
2558 /* Do any further write (truncates) update the write time ? */
2559 start = timeval_current();
2560 end = timeval_add(&start, 15 * sec, 0);
2561 while (!timeval_expired(&end)) {
2563 torture_comment(tctx, "Do a truncate write on the file handle\n");
2564 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2566 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2570 /* get the times after the write */
2571 GET_INFO_BOTH(finfo4,pinfo4);
2573 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2574 double diff = timeval_elapsed(&start);
2575 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2581 smb_msleep(1 * msec);
2584 GET_INFO_BOTH(finfo4,pinfo4);
2585 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2586 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2587 torture_comment(tctx, "Server did not update write_time (correct)\n");
2591 smb_msleep(5 * msec);
2593 GET_INFO_BOTH(finfo5,pinfo5);
2594 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2597 * the close doesn't update the write time
2599 torture_comment(tctx, "Close the file handle\n");
2600 smbcli_close(cli->tree, fnum1);
2603 GET_INFO_PATH(pinfo6);
2604 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2606 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2607 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2612 smbcli_close(cli->tree, fnum1);
2613 smbcli_unlink(cli->tree, fname);
2614 smbcli_deltree(cli->tree, BASEDIR);
2620 * Open 2 handles on a file. Write one one and then set the
2621 * WRITE TIME explicitly on the other. Ensure the write time
2622 * update is cancelled. Ensure the write time is updated to
2623 * the close time when the non-explicit set handle is closed.
2627 static bool test_delayed_write_update6(struct torture_context *tctx,
2628 struct smbcli_state *cli,
2629 struct smbcli_state *cli2)
2631 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2632 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2633 const char *fname = BASEDIR "\\torture_file6.txt";
2638 struct timeval start;
2640 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2641 int normal_delay = 2000000;
2642 double sec = ((double)used_delay) / ((double)normal_delay);
2643 int msec = 1000 * sec;
2646 torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2648 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2650 torture_comment(tctx, "Open the file handle\n");
2651 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2654 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2659 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2660 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2663 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2668 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2669 finfo0.basic_info.in.file.fnum = fnum1;
2675 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2676 pinfo0.basic_info.in.file.path = fname;
2685 /* get the initial times */
2686 GET_INFO_BOTH(finfo0,pinfo0);
2689 torture_comment(tctx, "Do a write on the file handle\n");
2690 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2692 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2697 GET_INFO_BOTH(finfo1,pinfo1);
2698 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2700 torture_comment(tctx, "Set write time in the future 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_GREATER(finfo2, finfo1);
2705 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2706 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2707 GET_INFO_BOTH(finfo2,pinfo2);
2708 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2710 /* make sure the 2 second delay from the first write are canceled */
2711 start = timeval_current();
2712 end = timeval_add(&start, 10 * sec, 0);
2713 while (!timeval_expired(&end)) {
2715 /* get the times after the first write */
2716 GET_INFO_BOTH(finfo3,pinfo3);
2718 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2719 double diff = timeval_elapsed(&start);
2720 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2726 smb_msleep(1 * msec);
2729 GET_INFO_BOTH(finfo3,pinfo3);
2730 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2731 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2732 torture_comment(tctx, "Server did not update write_time (correct)\n");
2735 /* sure any further write doesn't update the write time */
2736 start = timeval_current();
2737 end = timeval_add(&start, 10 * sec, 0);
2738 while (!timeval_expired(&end)) {
2740 torture_comment(tctx, "Do a write on the file handle\n");
2741 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2743 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2747 /* get the times after the write */
2748 GET_INFO_BOTH(finfo4,pinfo4);
2750 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2751 double diff = timeval_elapsed(&start);
2752 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2758 smb_msleep(1 * msec);
2761 GET_INFO_BOTH(finfo4,pinfo4);
2762 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2763 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2764 torture_comment(tctx, "Server did not update write_time (correct)\n");
2768 smb_msleep(5 * msec);
2770 GET_INFO_BOTH(finfo5,pinfo5);
2771 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2774 * the close updates the write time to the time of the close
2775 * as the write time was set on the 2nd handle
2777 torture_comment(tctx, "Close the file handle\n");
2778 smbcli_close(cli->tree, fnum1);
2781 GET_INFO_PATH(pinfo6);
2782 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2784 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2785 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2788 /* See what the second write handle thinks the time is ? */
2789 finfo5.basic_info.in.file.fnum = fnum2;
2790 GET_INFO_FILE2(finfo5);
2791 COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
2793 /* See if we have lost the sticky write time on handle2 */
2794 smb_msleep(3 * msec);
2795 torture_comment(tctx, "Have we lost the sticky write time ?\n");
2797 /* Make sure any further normal write doesn't update the write time */
2798 start = timeval_current();
2799 end = timeval_add(&start, 10 * sec, 0);
2800 while (!timeval_expired(&end)) {
2802 torture_comment(tctx, "Do a write on the second file handle\n");
2803 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
2805 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2809 /* get the times after the write */
2810 GET_INFO_FILE2(finfo5);
2811 GET_INFO_PATH(pinfo6);
2813 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2814 double diff = timeval_elapsed(&start);
2815 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2821 smb_msleep(1 * msec);
2824 /* What about a truncate write ? */
2825 start = timeval_current();
2826 end = timeval_add(&start, 10 * sec, 0);
2827 while (!timeval_expired(&end)) {
2829 torture_comment(tctx, "Do a truncate write on the second file handle\n");
2830 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
2832 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2836 /* get the times after the write */
2837 GET_INFO_FILE2(finfo5);
2838 GET_INFO_PATH(pinfo6);
2840 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2841 double diff = timeval_elapsed(&start);
2842 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2848 smb_msleep(1 * msec);
2852 /* keep the 2nd handle open and rerun tests */
2859 * closing the 2nd handle will cause no write time update
2860 * as the write time was explicit set on this handle
2862 torture_comment(tctx, "Close the 2nd file handle\n");
2863 smbcli_close(cli2->tree, fnum2);
2866 GET_INFO_PATH(pinfo7);
2867 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2869 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2870 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2875 smbcli_close(cli->tree, fnum1);
2877 smbcli_close(cli2->tree, fnum2);
2878 smbcli_unlink(cli->tree, fname);
2879 smbcli_deltree(cli->tree, BASEDIR);
2884 static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
2886 union smb_open open_parms;
2887 union smb_fileinfo finfo1, finfo2, finfo3;
2888 const char *fname = BASEDIR "\\torture_file7.txt";
2892 TALLOC_CTX *mem_ctx;
2894 torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2896 mem_ctx = talloc_init("test_delayed_write_update7");
2897 if (!mem_ctx) return false;
2899 ZERO_STRUCT(finfo1);
2900 ZERO_STRUCT(finfo2);
2901 ZERO_STRUCT(finfo3);
2902 ZERO_STRUCT(open_parms);
2904 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2906 /* Create the file. */
2907 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2909 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
2913 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2914 finfo1.basic_info.in.file.fnum = fnum1;
2918 /* Get the initial timestamps. */
2919 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
2921 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2923 /* Set the pending write time to a value with ns. */
2924 SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
2926 /* Get the current pending write time by fnum. */
2927 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
2929 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2931 /* Ensure the time is actually different. */
2932 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2933 torture_result(tctx, TORTURE_FAIL,
2934 "setfileinfo time matches original fileinfo time");
2938 /* Get the current pending write time by path. */
2939 finfo3.basic_info.in.file.path = fname;
2940 status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
2942 if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
2943 torture_result(tctx, TORTURE_FAIL,
2944 "qpathinfo time doens't match fileinfo time");
2948 /* Now close the file. Re-open and check that the write
2949 time is identical to the one we wrote. */
2951 smbcli_close(cli->tree, fnum1);
2953 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
2954 open_parms.ntcreatex.in.flags = 0;
2955 open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
2956 open_parms.ntcreatex.in.file_attr = 0;
2957 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
2958 NTCREATEX_SHARE_ACCESS_READ|
2959 NTCREATEX_SHARE_ACCESS_WRITE;
2960 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
2961 open_parms.ntcreatex.in.create_options = 0;
2962 open_parms.ntcreatex.in.fname = fname;
2964 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
2965 talloc_free(mem_ctx);
2967 if (!NT_STATUS_IS_OK(status)) {
2968 torture_result(tctx, TORTURE_FAIL,
2969 "setfileinfo time matches original fileinfo time");
2973 fnum1 = open_parms.ntcreatex.out.file.fnum;
2975 /* Check the returned time matches. */
2976 if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
2977 torture_result(tctx, TORTURE_FAIL,
2978 "final open time does not match set time");
2984 smbcli_close(cli->tree, fnum1);
2986 smbcli_unlink(cli->tree, fname);
2987 smbcli_deltree(cli->tree, BASEDIR);
2992 Test if creating a file in a directory with an open handle updates the
2993 write timestamp (it should).
2995 static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
2997 union smb_fileinfo dir_info1, dir_info2;
2998 union smb_open open_parms;
2999 const char *fname = BASEDIR "\\torture_file.txt";
3004 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3005 int normal_delay = 2000000;
3006 double sec = ((double)used_delay) / ((double)normal_delay);
3007 int msec = 1000 * sec;
3008 TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
3010 if (!mem_ctx) return false;
3012 torture_comment(tctx, "\nRunning test directory write update\n");
3014 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
3016 /* Open a handle on the directory - and leave it open. */
3017 ZERO_STRUCT(open_parms);
3018 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3019 open_parms.ntcreatex.in.flags = 0;
3020 open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
3021 open_parms.ntcreatex.in.file_attr = 0;
3022 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3023 NTCREATEX_SHARE_ACCESS_READ|
3024 NTCREATEX_SHARE_ACCESS_WRITE;
3025 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3026 open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
3027 open_parms.ntcreatex.in.fname = BASEDIR;
3029 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3030 talloc_free(mem_ctx);
3032 if (!NT_STATUS_IS_OK(status)) {
3033 torture_result(tctx, TORTURE_FAIL,
3034 "failed to open directory handle");
3039 fnum1 = open_parms.ntcreatex.out.file.fnum;
3041 /* Store the returned write time. */
3042 ZERO_STRUCT(dir_info1);
3043 dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
3045 torture_comment(tctx, "Initial write time %s\n",
3046 nt_time_string(tctx, dir_info1.basic_info.out.write_time));
3049 smb_msleep(3 * msec);
3051 /* Now create a file within the directory. */
3052 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3054 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
3058 smbcli_close(cli->tree, fnum2);
3060 /* Read the directory write time again. */
3061 ZERO_STRUCT(dir_info2);
3062 dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3063 dir_info2.basic_info.in.file.fnum = fnum1;
3065 status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
3067 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
3069 /* Ensure it's been incremented. */
3070 COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
3072 torture_comment(tctx, "Updated write time %s\n",
3073 nt_time_string(tctx, dir_info2.basic_info.out.write_time));
3078 smbcli_close(cli->tree, fnum1);
3079 smbcli_unlink(cli->tree, fname);
3080 smbcli_deltree(cli->tree, BASEDIR);
3086 testing of delayed update of write_time
3088 struct torture_suite *torture_delay_write(void)
3090 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "delaywrite");
3092 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
3093 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
3094 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
3095 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
3096 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
3097 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
3098 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
3099 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
3100 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
3101 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
3102 torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
3103 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
3104 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
3105 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
3106 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
3107 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3108 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3109 torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);