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;
299 torture_comment(tctx, "\nRunning test_delayed_write_update1a\n");
301 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
303 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
305 torture_result(tctx, TORTURE_FAIL, "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_comment(tctx, "Initial write time %s\n",
328 nt_time_string(tctx, finfo1.all_info.out.write_time));
330 /* Do a zero length SMBwrite call to truncate. */
331 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
334 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)",
335 (int)written, __location__);
339 start = timeval_current();
340 end = timeval_add(&start, (120*sec), 0);
341 while (!timeval_expired(&end)) {
342 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
344 if (!NT_STATUS_IS_OK(status)) {
345 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
351 if (finfo2.all_info.out.size != 10240) {
352 torture_result(tctx, TORTURE_FAIL,
353 "file not truncated, size = %u (should be 10240)",
354 (unsigned int)finfo2.all_info.out.size);
359 torture_comment(tctx, "write time %s\n",
360 nt_time_string(tctx, finfo2.all_info.out.write_time));
361 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
362 double diff = timeval_elapsed(&start);
363 if (diff > (0.25 * (used_delay / (double)1000000))) {
364 torture_result(tctx, TORTURE_FAIL, "After SMBwrite truncate "
365 "server updated write_time after %.2f seconds"
366 "(write time update delay == %.2f)(wrong!)\n",
367 diff, used_delay / (double)1000000);
372 torture_comment(tctx, "After SMBwrite truncate "
373 "server updated write_time after %.2f seconds"
374 "(write time update delay == %.2f)(correct)\n",
375 diff, used_delay / (double)1000000);
379 smb_msleep(1 * msec);
382 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
383 torture_result(tctx, TORTURE_FAIL,
384 "Server did not update write time (wrong!)");
389 smb_msleep(2 * msec);
391 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
392 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
394 torture_assert_int_equal(tctx, written, 1,
395 "unexpected number of bytes written");
397 start = timeval_current();
398 end = timeval_add(&start, (10*sec), 0);
399 while (!timeval_expired(&end)) {
400 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
402 if (!NT_STATUS_IS_OK(status)) {
403 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s\n",
409 if (finfo3.all_info.out.size != 10240) {
410 torture_result(tctx, TORTURE_FAIL,
411 "file not truncated, size = %u (should be 10240)",
412 (unsigned int)finfo3.all_info.out.size);
417 torture_comment(tctx, "write time %s\n",
418 nt_time_string(tctx, finfo3.all_info.out.write_time));
419 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
420 double diff = timeval_elapsed(&start);
422 torture_result(tctx, TORTURE_FAIL, "server updated write_time after %.2f seconds"
423 "(write time update delay == %.2f)(correct)\n",
424 diff, used_delay / (double)1000000);
428 smb_msleep(1 * msec);
431 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
432 torture_result(tctx, TORTURE_FAIL,
433 "Server updated write time (wrong!)");
437 /* the close should trigger an write time update */
438 smbcli_close(cli->tree, fnum1);
441 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
442 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
444 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
445 torture_result(tctx, TORTURE_FAIL,
446 "Server did not update write time on close (wrong!)");
448 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
449 torture_comment(tctx, "Server updated write time on close (correct)\n");
453 smbcli_close(cli->tree, fnum1);
454 smbcli_unlink(cli->tree, fname);
455 smbcli_deltree(cli->tree, BASEDIR);
460 /* Updating with a SET_FILE_END_OF_FILE_INFO
461 * changes the write time immediately - even on expand. */
463 static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
465 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
466 const char *fname = BASEDIR "\\torture_file1b.txt";
471 struct timeval start;
473 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
474 int normal_delay = 2000000;
475 double sec = ((double)used_delay) / ((double)normal_delay);
476 int msec = 1000 * sec;
479 torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
481 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
483 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
485 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
489 memset(buf, 'x', 2048);
490 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
492 /* 3 second delay to ensure we get past any 2 second time
493 granularity (older systems may have that) */
494 smb_msleep(3 * msec);
496 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
497 finfo1.all_info.in.file.fnum = fnum1;
500 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
501 pinfo4.all_info.in.file.path = fname;
503 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
505 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
507 torture_comment(tctx, "Initial write time %s\n",
508 nt_time_string(tctx, finfo1.all_info.out.write_time));
510 /* Do a SET_END_OF_FILE_INFO call to truncate. */
511 status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
513 torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
515 start = timeval_current();
516 end = timeval_add(&start, (120*sec), 0);
517 while (!timeval_expired(&end)) {
518 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
520 if (!NT_STATUS_IS_OK(status)) {
521 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
526 if (finfo2.all_info.out.size != 10240) {
527 torture_result(tctx, TORTURE_FAIL,
528 "file not truncated (size = %u, should be 10240)",
529 (unsigned int)finfo2.all_info.out.size );
534 torture_comment(tctx, "write time %s\n",
535 nt_time_string(tctx, finfo2.all_info.out.write_time));
536 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
537 double diff = timeval_elapsed(&start);
538 if (diff > (0.25 * (used_delay / (double)1000000))) {
539 torture_result(tctx, TORTURE_FAIL,
540 "After SET_END_OF_FILE truncate "
541 "server updated write_time after %.2f seconds"
542 "(write time update delay == %.2f)(wrong!)",
543 diff, used_delay / (double)1000000);
548 torture_comment(tctx, "After SET_END_OF_FILE truncate "
549 "server updated write_time after %.2f seconds"
550 "(write time update delay == %.2f)(correct)\n",
551 diff, used_delay / (double)1000000);
555 smb_msleep(1 * msec);
558 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
559 torture_result(tctx, TORTURE_FAIL,
560 "Server did not update write time (wrong!)");
565 smb_msleep(2 * msec);
567 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
568 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
570 torture_assert_int_equal(tctx, written, 1,
571 "unexpected number of bytes written");
573 start = timeval_current();
574 end = timeval_add(&start, (10*sec), 0);
575 while (!timeval_expired(&end)) {
576 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
578 if (!NT_STATUS_IS_OK(status)) {
579 torture_result(tctx, TORTURE_FAIL,
580 "fileinfo failed: %s", nt_errstr(status));
585 if (finfo3.all_info.out.size != 10240) {
586 DEBUG(0, ("file not truncated (size = %u, should be 10240)\n",
587 (unsigned int)finfo3.all_info.out.size ));
592 torture_comment(tctx, "write time %s\n",
593 nt_time_string(tctx, finfo3.all_info.out.write_time));
594 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
595 double diff = timeval_elapsed(&start);
597 torture_comment(tctx, "server updated write_time after %.2f seconds"
598 "(write time update delay == %.2f)(correct)\n",
599 diff, used_delay / (double)1000000);
603 smb_msleep(1 * msec);
606 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
607 torture_result(tctx, TORTURE_FAIL, "Server updated write time (wrong!)\n");
611 /* the close should trigger an write time update */
612 smbcli_close(cli->tree, fnum1);
615 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
616 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
618 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
619 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
621 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
622 torture_comment(tctx, "Server updated write time on close (correct)\n");
626 smbcli_close(cli->tree, fnum1);
627 smbcli_unlink(cli->tree, fname);
628 smbcli_deltree(cli->tree, BASEDIR);
633 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
635 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
637 union smb_setfileinfo parms;
638 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
639 const char *fname = BASEDIR "\\torture_file1c.txt";
644 struct timeval start;
646 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
647 int normal_delay = 2000000;
648 double sec = ((double)used_delay) / ((double)normal_delay);
649 int msec = 1000 * sec;
652 torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
654 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
656 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
658 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
662 memset(buf, 'x', 2048);
663 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
665 /* 3 second delay to ensure we get past any 2 second time
666 granularity (older systems may have that) */
667 smb_msleep(3 * msec);
669 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
670 finfo1.all_info.in.file.fnum = fnum1;
673 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
674 pinfo4.all_info.in.file.path = fname;
676 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
678 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
680 torture_comment(tctx, "Initial write time %s\n",
681 nt_time_string(tctx, finfo1.all_info.out.write_time));
683 /* Do a SET_ALLOCATION_SIZE call to truncate. */
684 parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
685 parms.allocation_info.in.file.fnum = fnum1;
686 parms.allocation_info.in.alloc_size = 0;
688 status = smb_raw_setfileinfo(cli->tree, &parms);
690 torture_assert_ntstatus_ok(tctx, status,
691 "RAW_SFILEINFO_ALLOCATION_INFO failed");
693 start = timeval_current();
694 end = timeval_add(&start, (120*sec), 0);
695 while (!timeval_expired(&end)) {
696 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
698 if (!NT_STATUS_IS_OK(status)) {
699 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
705 if (finfo2.all_info.out.size != 0) {
706 torture_result(tctx, TORTURE_FAIL,
707 "file not truncated (size = %u, should be 10240)",
708 (unsigned int)finfo2.all_info.out.size);
713 torture_comment(tctx, "write time %s\n",
714 nt_time_string(tctx, finfo2.all_info.out.write_time));
715 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
716 double diff = timeval_elapsed(&start);
717 if (diff > (0.25 * (used_delay / (double)1000000))) {
718 torture_result(tctx, TORTURE_FAIL, "After SET_ALLOCATION_INFO truncate "
719 "server updated write_time after %.2f seconds"
720 "(write time update delay == %.2f)(wrong!)\n",
721 diff, used_delay / (double)1000000);
726 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
727 "server updated write_time after %.2f seconds"
728 "(write time update delay == %.2f)(correct)\n",
729 diff, used_delay / (double)1000000);
733 smb_msleep(1 * msec);
736 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
737 torture_result(tctx, TORTURE_FAIL,
738 "Server did not update write time (wrong!)");
743 smb_msleep(2 * msec);
745 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
746 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
747 torture_assert_int_equal(tctx, written, 1,
748 "Unexpected number of bytes written");
750 start = timeval_current();
751 end = timeval_add(&start, (10*sec), 0);
752 while (!timeval_expired(&end)) {
753 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
755 if (!NT_STATUS_IS_OK(status)) {
756 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
762 if (finfo3.all_info.out.size != 1) {
763 torture_result(tctx, TORTURE_FAIL, "file not expanded");
768 torture_comment(tctx, "write time %s\n",
769 nt_time_string(tctx, finfo3.all_info.out.write_time));
770 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
771 double diff = timeval_elapsed(&start);
773 torture_comment(tctx, "server updated write_time after %.2f seconds"
774 "(write time update delay == %.2f)(wrong)\n",
775 diff, used_delay / (double)1000000);
779 smb_msleep(1 * msec);
782 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
783 torture_result(tctx, TORTURE_FAIL,
784 "Server updated write time (wrong!)");
788 /* the close should trigger an write time update */
789 smbcli_close(cli->tree, fnum1);
792 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
793 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
795 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
796 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
798 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
799 torture_comment(tctx, "Server updated write time on close (correct)\n");
803 smbcli_close(cli->tree, fnum1);
804 smbcli_unlink(cli->tree, fname);
805 smbcli_deltree(cli->tree, BASEDIR);
811 * Do as above, but using 2 connections.
814 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
815 struct smbcli_state *cli2)
817 union smb_fileinfo finfo1, finfo2;
818 const char *fname = BASEDIR "\\torture_file.txt";
824 struct timeval start;
826 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
827 int normal_delay = 2000000;
828 double sec = ((double)used_delay) / ((double)normal_delay);
829 int msec = 1000 * sec;
830 union smb_flush flsh;
832 torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
834 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
836 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
838 torture_comment(tctx, "Failed to open %s\n", fname);
842 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
843 finfo1.basic_info.in.file.fnum = fnum1;
846 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
848 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
850 torture_comment(tctx, "Initial write time %s\n",
851 nt_time_string(tctx, finfo1.basic_info.out.write_time));
853 /* 3 second delay to ensure we get past any 2 second time
854 granularity (older systems may have that) */
855 smb_msleep(3 * msec);
858 /* Try using setfileinfo instead of write to update write time. */
859 union smb_setfileinfo sfinfo;
860 time_t t_set = time(NULL);
861 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
862 sfinfo.basic_info.in.file.fnum = fnum1;
863 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
864 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
866 /* I tried this with both + and - ve to see if it makes a different.
867 It doesn't - once the filetime is set via setfileinfo it stays that way. */
869 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
871 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
873 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
874 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
876 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
878 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
881 finfo2.basic_info.in.file.path = fname;
883 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
885 if (!NT_STATUS_IS_OK(status)) {
886 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
889 torture_comment(tctx, "write time %s\n",
890 nt_time_string(tctx, finfo2.basic_info.out.write_time));
892 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
893 torture_comment(tctx, "Server updated write_time (correct)\n");
895 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
899 /* Now try a write to see if the write time gets reset. */
901 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
902 finfo1.basic_info.in.file.fnum = fnum1;
905 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
907 if (!NT_STATUS_IS_OK(status)) {
908 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
912 torture_comment(tctx, "Modified write time %s\n",
913 nt_time_string(tctx, finfo1.basic_info.out.write_time));
916 torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
918 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
921 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
922 (int)written, __location__);
926 /* Just to prove to tridge that the an smbflush has no effect on
927 the write time :-). The setfileinfo IS STICKY. JRA. */
929 torture_comment(tctx, "Doing flush after write\n");
931 flsh.flush.level = RAW_FLUSH_FLUSH;
932 flsh.flush.in.file.fnum = fnum1;
933 status = smb_raw_flush(cli->tree, &flsh);
934 if (!NT_STATUS_IS_OK(status)) {
935 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
939 /* Once the time was set using setfileinfo then it stays set - writes
940 don't have any effect. But make sure. */
941 start = timeval_current();
942 end = timeval_add(&start, (15*sec), 0);
943 while (!timeval_expired(&end)) {
944 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
946 if (!NT_STATUS_IS_OK(status)) {
947 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
951 torture_comment(tctx, "write time %s\n",
952 nt_time_string(tctx, finfo2.basic_info.out.write_time));
953 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
954 double diff = timeval_elapsed(&start);
955 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
962 smb_msleep(1 * msec);
965 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
966 torture_comment(tctx, "Server did not update write time (correct)\n");
970 smb_msleep(2 * msec);
972 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
974 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
978 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");
980 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
983 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
984 (int)written, __location__);
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 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
1002 smbcli_close(cli->tree, fnum1);
1005 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");
1007 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
1009 if (written != 10) {
1010 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1011 (int)written, __location__);
1015 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1016 finfo1.basic_info.in.file.fnum = fnum2;
1018 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1020 if (!NT_STATUS_IS_OK(status)) {
1021 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1024 torture_comment(tctx, "write time %s\n",
1025 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1026 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1027 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1031 /* Once the time was set using setfileinfo then it stays set - writes
1032 don't have any effect. But make sure. */
1033 start = timeval_current();
1034 end = timeval_add(&start, (15*sec), 0);
1035 while (!timeval_expired(&end)) {
1036 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1038 if (!NT_STATUS_IS_OK(status)) {
1039 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1043 torture_comment(tctx, "write time %s\n",
1044 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1045 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1046 double diff = timeval_elapsed(&start);
1047 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1054 smb_msleep(1 * msec);
1057 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1058 torture_comment(tctx, "Server did not update write time (correct)\n");
1061 torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1063 smbcli_close(cli->tree, fnum2);
1066 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1068 torture_comment(tctx, "Failed to open %s\n", fname);
1072 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1073 finfo1.basic_info.in.file.fnum = fnum1;
1076 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1078 if (!NT_STATUS_IS_OK(status)) {
1079 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1083 torture_comment(tctx, "Second open initial write time %s\n",
1084 nt_time_string(tctx, finfo1.basic_info.out.write_time));
1086 smb_msleep(10 * msec);
1087 torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1089 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1091 if (written != 10) {
1092 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1093 (int)written, __location__);
1097 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1098 finfo1.basic_info.in.file.fnum = fnum1;
1100 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1102 if (!NT_STATUS_IS_OK(status)) {
1103 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1106 torture_comment(tctx, "write time %s\n",
1107 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1108 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1109 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1113 /* Now the write time should be updated again */
1114 start = timeval_current();
1115 end = timeval_add(&start, (15*sec), 0);
1116 while (!timeval_expired(&end)) {
1117 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1119 if (!NT_STATUS_IS_OK(status)) {
1120 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1124 torture_comment(tctx, "write time %s\n",
1125 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1126 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1127 double diff = timeval_elapsed(&start);
1128 if (diff < (used_delay / (double)1000000)) {
1129 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1130 "(expected > %.2f) (wrong!)\n",
1131 diff, used_delay / (double)1000000);
1136 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1145 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1146 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
1151 /* One more test to do. We should read the filetime via findfirst on the
1152 second connection to ensure it's the same. This is very easy for a Windows
1153 server but a bastard to get right on a POSIX server. JRA. */
1156 smbcli_close(cli->tree, fnum1);
1157 smbcli_unlink(cli->tree, fname);
1158 smbcli_deltree(cli->tree, BASEDIR);
1164 /* Windows does obviously not update the stat info during a write call. I
1165 * *think* this is the problem causing a spurious Excel 2003 on XP error
1166 * message when saving a file. Excel does a setfileinfo, writes, and then does
1167 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1168 * that the file might have been changed in between. What i've been able to
1169 * trace down is that this happens if the getpathinfo after the write shows a
1170 * different last write time than the setfileinfo showed. This is really
1174 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
1175 struct smbcli_state *cli2)
1177 union smb_fileinfo finfo1, finfo2;
1178 const char *fname = BASEDIR "\\torture_file.txt";
1184 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1185 int normal_delay = 2000000;
1186 double sec = ((double)used_delay) / ((double)normal_delay);
1187 int msec = 1000 * sec;
1189 torture_comment(tctx, "\nRunning test_finfo_after_write\n");
1191 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1193 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1196 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1200 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1201 finfo1.basic_info.in.file.fnum = fnum1;
1203 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1205 if (!NT_STATUS_IS_OK(status)) {
1207 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1211 smb_msleep(1 * msec);
1213 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1216 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1221 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1223 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1224 smbcli_errstr(cli2->tree));
1229 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1232 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1238 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1239 finfo2.basic_info.in.file.path = fname;
1241 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1243 if (!NT_STATUS_IS_OK(status)) {
1244 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
1250 if (finfo1.basic_info.out.create_time !=
1251 finfo2.basic_info.out.create_time) {
1252 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1257 if (finfo1.basic_info.out.access_time !=
1258 finfo2.basic_info.out.access_time) {
1259 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1264 if (finfo1.basic_info.out.write_time !=
1265 finfo2.basic_info.out.write_time) {
1266 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1267 "write time conn 1 = %s, conn 2 = %s",
1268 nt_time_string(tctx, finfo1.basic_info.out.write_time),
1269 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1274 if (finfo1.basic_info.out.change_time !=
1275 finfo2.basic_info.out.change_time) {
1276 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1281 /* One of the two following calls updates the qpathinfo. */
1283 /* If you had skipped the smbcli_write on fnum2, it would
1284 * *not* have updated the stat on disk */
1286 smbcli_close(cli2->tree, fnum2);
1289 /* This call is only for the people looking at ethereal :-) */
1290 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1291 finfo2.basic_info.in.file.path = fname;
1293 status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1295 if (!NT_STATUS_IS_OK(status)) {
1296 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1303 smbcli_close(cli->tree, fnum1);
1304 smbcli_unlink(cli->tree, fname);
1305 smbcli_deltree(cli->tree, BASEDIR);
1310 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1311 uint64_t r = 10*1000*1000; \
1312 NTTIME g = (given).basic_info.out.write_time; \
1313 NTTIME gr = (g / r) * r; \
1314 NTTIME c = (correct).basic_info.out.write_time; \
1315 NTTIME cr = (c / r) * r; \
1316 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1318 if (strict && (g cmp c)) { \
1320 } else if ((g cmp c) && (gr cmp cr)) { \
1321 /* handle filesystem without high resolution timestamps */ \
1325 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1326 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1327 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1332 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1333 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1334 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1335 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1336 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1337 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1339 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1340 NTTIME g = (given).basic_info.out.access_time; \
1341 NTTIME c = (correct).basic_info.out.access_time; \
1343 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1344 #given, nt_time_string(tctx, g), \
1345 #cmp, #correct, nt_time_string(tctx, c)); \
1350 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1351 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1353 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1354 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1355 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1358 #define GET_INFO_FILE(finfo) do { \
1360 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1361 if (!NT_STATUS_IS_OK(_status)) { \
1363 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1364 nt_errstr(_status)); \
1367 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1368 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1369 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1371 #define GET_INFO_FILE2(finfo) do { \
1373 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1374 if (!NT_STATUS_IS_OK(_status)) { \
1376 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1377 nt_errstr(_status)); \
1380 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1381 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1382 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1384 #define GET_INFO_PATH(pinfo) do { \
1386 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1387 if (!NT_STATUS_IS_OK(_status)) { \
1388 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1389 nt_errstr(_status)); \
1393 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1394 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1395 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1397 #define GET_INFO_BOTH(finfo,pinfo) do { \
1398 GET_INFO_FILE(finfo); \
1399 GET_INFO_PATH(pinfo); \
1400 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1403 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1405 union smb_setfileinfo sfinfo; \
1406 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1407 sfinfo.basic_info.in.file.fnum = tfnum; \
1408 sfinfo.basic_info.in.create_time = 0; \
1409 sfinfo.basic_info.in.access_time = 0; \
1410 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1411 sfinfo.basic_info.in.change_time = 0; \
1412 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1413 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1414 if (!NT_STATUS_IS_OK(_status)) { \
1415 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1416 nt_errstr(_status)); \
1421 #define SET_INFO_FILE(finfo, wrtime) \
1422 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1424 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1426 union smb_setfileinfo sfinfo; \
1427 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1428 sfinfo.basic_info.in.file.fnum = tfnum; \
1429 sfinfo.basic_info.in.create_time = 0; \
1430 sfinfo.basic_info.in.access_time = 0; \
1431 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1432 sfinfo.basic_info.in.write_time += (ns); \
1433 sfinfo.basic_info.in.change_time = 0; \
1434 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1435 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1436 if (!NT_STATUS_IS_OK(_status)) { \
1437 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1438 nt_errstr(_status)); \
1444 static bool test_delayed_write_update3(struct torture_context *tctx,
1445 struct smbcli_state *cli,
1446 struct smbcli_state *cli2)
1448 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1449 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1450 const char *fname = BASEDIR "\\torture_file3.txt";
1454 struct timeval start;
1456 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1457 int normal_delay = 2000000;
1458 double sec = ((double)used_delay) / ((double)normal_delay);
1459 int msec = 1000 * sec;
1461 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
1463 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1465 torture_comment(tctx, "Open the file handle\n");
1466 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1469 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1473 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1474 finfo0.basic_info.in.file.fnum = fnum1;
1478 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1479 pinfo0.basic_info.in.file.path = fname;
1485 /* get the initial times */
1486 GET_INFO_BOTH(finfo0,pinfo0);
1489 * make sure the write time is updated 2 seconds later
1490 * calcuated from the first write
1491 * (but expect upto 5 seconds extra time for a busy server)
1493 start = timeval_current();
1494 end = timeval_add(&start, 7 * sec, 0);
1495 while (!timeval_expired(&end)) {
1497 torture_comment(tctx, "Do a write on the file handle\n");
1498 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1500 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1504 /* get the times after the write */
1505 GET_INFO_FILE(finfo1);
1507 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1508 double diff = timeval_elapsed(&start);
1509 if (diff < (used_delay / (double)1000000)) {
1510 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1511 "(write time update delay == %.2f) (wrong!)\n",
1512 diff, used_delay / (double)1000000);
1517 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1522 smb_msleep(0.5 * msec);
1525 GET_INFO_BOTH(finfo1,pinfo1);
1526 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1528 /* sure any further write doesn't update the write time */
1529 start = timeval_current();
1530 end = timeval_add(&start, 15 * sec, 0);
1531 while (!timeval_expired(&end)) {
1533 torture_comment(tctx, "Do a write on the file handle\n");
1534 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1536 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1540 /* get the times after the write */
1541 GET_INFO_BOTH(finfo2,pinfo2);
1543 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1544 double diff = timeval_elapsed(&start);
1545 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1551 smb_msleep(1 * msec);
1554 GET_INFO_BOTH(finfo2,pinfo2);
1555 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1556 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1557 torture_comment(tctx, "Server did not update write_time (correct)\n");
1561 smb_msleep(5 * msec);
1563 GET_INFO_BOTH(finfo3,pinfo3);
1564 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1567 * the close updates the write time to the time of the close
1568 * and not to the time of the last write!
1570 torture_comment(tctx, "Close the file handle\n");
1571 smbcli_close(cli->tree, fnum1);
1574 GET_INFO_PATH(pinfo4);
1575 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1577 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1578 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1583 smbcli_close(cli->tree, fnum1);
1584 smbcli_unlink(cli->tree, fname);
1585 smbcli_deltree(cli->tree, BASEDIR);
1591 * Show that a truncate write always updates the write time even
1592 * if an initial write has already updated the write time.
1595 static bool test_delayed_write_update3a(struct torture_context *tctx,
1596 struct smbcli_state *cli,
1597 struct smbcli_state *cli2)
1599 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1600 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1601 const char *fname = BASEDIR "\\torture_file3a.txt";
1606 struct timeval start;
1608 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1609 int normal_delay = 2000000;
1610 double sec = ((double)used_delay) / ((double)normal_delay);
1611 int msec = 1000 * sec;
1613 torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
1615 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1617 torture_comment(tctx, "Open the file handle\n");
1618 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1621 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1625 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1626 finfo0.basic_info.in.file.fnum = fnum1;
1630 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1631 pinfo0.basic_info.in.file.path = fname;
1637 /* get the initial times */
1638 GET_INFO_BOTH(finfo0,pinfo0);
1641 * sleep some time, to demonstrate the handling of write times
1642 * doesn't depend on the time since the open
1644 smb_msleep(5 * msec);
1646 /* get the initial times */
1647 GET_INFO_BOTH(finfo1,pinfo1);
1648 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1651 * make sure the write time is updated 2 seconds later
1652 * calcuated from the first write
1653 * (but expect upto 5 seconds extra time for a busy server)
1655 start = timeval_current();
1656 end = timeval_add(&start, 7 * sec, 0);
1657 while (!timeval_expired(&end)) {
1659 torture_comment(tctx, "Do a write on the file handle\n");
1660 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1662 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1666 /* get the times after the write */
1667 GET_INFO_FILE(finfo1);
1669 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1670 double diff = timeval_elapsed(&start);
1671 if (diff < (used_delay / (double)1000000)) {
1672 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1673 "(1sec == %.2f) (wrong!)\n",
1679 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1684 smb_msleep(0.5 * msec);
1687 GET_INFO_BOTH(finfo1,pinfo1);
1688 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1690 smb_msleep(3 * msec);
1693 * demonstrate that a truncate write always
1694 * updates the write time immediately
1696 for (i=0; i < 3; i++) {
1697 smb_msleep(2 * msec);
1699 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1700 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1702 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1706 /* get the times after the write */
1707 GET_INFO_BOTH(finfo2,pinfo2);
1708 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1712 smb_msleep(3 * msec);
1714 /* sure any further write doesn't update the write time */
1715 start = timeval_current();
1716 end = timeval_add(&start, 15 * sec, 0);
1717 while (!timeval_expired(&end)) {
1719 torture_comment(tctx, "Do a write on the file handle\n");
1720 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1722 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1726 /* get the times after the write */
1727 GET_INFO_BOTH(finfo2,pinfo2);
1729 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1730 double diff = timeval_elapsed(&start);
1731 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1737 smb_msleep(1 * msec);
1740 GET_INFO_BOTH(finfo2,pinfo2);
1741 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1742 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1743 torture_comment(tctx, "Server did not update write_time (correct)\n");
1747 smb_msleep(3 * msec);
1749 /* get the initial times */
1750 GET_INFO_BOTH(finfo1,pinfo1);
1751 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1754 * demonstrate that a truncate write always
1755 * updates the write time immediately
1757 for (i=0; i < 3; i++) {
1758 smb_msleep(2 * msec);
1760 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1761 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1763 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1767 /* get the times after the write */
1768 GET_INFO_BOTH(finfo2,pinfo2);
1769 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1774 smb_msleep(3 * msec);
1776 GET_INFO_BOTH(finfo3,pinfo3);
1777 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1780 * the close doesn't update the write time
1782 torture_comment(tctx, "Close the file handle\n");
1783 smbcli_close(cli->tree, fnum1);
1786 GET_INFO_PATH(pinfo4);
1787 COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1789 if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1790 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1795 smbcli_close(cli->tree, fnum1);
1796 smbcli_unlink(cli->tree, fname);
1797 smbcli_deltree(cli->tree, BASEDIR);
1803 * Show a close after write updates the write timestamp to
1804 * the close time, not the last write time.
1807 static bool test_delayed_write_update3b(struct torture_context *tctx,
1808 struct smbcli_state *cli,
1809 struct smbcli_state *cli2)
1811 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1812 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1813 const char *fname = BASEDIR "\\torture_file3b.txt";
1817 struct timeval start;
1819 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1820 int normal_delay = 2000000;
1821 double sec = ((double)used_delay) / ((double)normal_delay);
1822 int msec = 1000 * sec;
1824 torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
1826 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1828 torture_comment(tctx, "Open the file handle\n");
1829 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1832 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1836 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1837 finfo0.basic_info.in.file.fnum = fnum1;
1841 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1842 pinfo0.basic_info.in.file.path = fname;
1848 /* get the initial times */
1849 GET_INFO_BOTH(finfo0,pinfo0);
1852 * sleep some time, to demonstrate the handling of write times
1853 * doesn't depend on the time since the open
1855 smb_msleep(5 * msec);
1857 /* get the initial times */
1858 GET_INFO_BOTH(finfo1,pinfo1);
1859 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1862 * make sure the write time is updated 2 seconds later
1863 * calcuated from the first write
1864 * (but expect upto 5 seconds extra time for a busy server)
1866 start = timeval_current();
1867 end = timeval_add(&start, 7 * sec, 0);
1868 while (!timeval_expired(&end)) {
1870 torture_comment(tctx, "Do a write on the file handle\n");
1871 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1873 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1877 /* get the times after the write */
1878 GET_INFO_FILE(finfo1);
1880 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1881 double diff = timeval_elapsed(&start);
1882 if (diff < (used_delay / (double)1000000)) {
1883 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1884 "(expected > %.2f) (wrong!)\n",
1885 diff, used_delay / (double)1000000);
1890 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1891 "(write time update delay == %.2f) (correct)\n",
1892 diff, used_delay / (double)1000000);
1895 smb_msleep(0.5 * msec);
1898 GET_INFO_BOTH(finfo1,pinfo1);
1899 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1901 /* sure any further write doesn't update the write time */
1902 start = timeval_current();
1903 end = timeval_add(&start, 15 * sec, 0);
1904 while (!timeval_expired(&end)) {
1906 torture_comment(tctx, "Do a write on the file handle\n");
1907 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1909 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1913 /* get the times after the write */
1914 GET_INFO_BOTH(finfo2,pinfo2);
1916 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1917 double diff = timeval_elapsed(&start);
1918 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1924 smb_msleep(1 * msec);
1927 GET_INFO_BOTH(finfo2,pinfo2);
1928 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1929 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1930 torture_comment(tctx, "Server did not update write_time (correct)\n");
1934 smb_msleep(5 * msec);
1936 GET_INFO_BOTH(finfo3,pinfo3);
1937 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1940 * the close updates the write time to the time of the close
1941 * and not to the time of the last write!
1943 torture_comment(tctx, "Close the file handle\n");
1944 smbcli_close(cli->tree, fnum1);
1947 GET_INFO_PATH(pinfo4);
1948 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1950 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1951 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1956 smbcli_close(cli->tree, fnum1);
1957 smbcli_unlink(cli->tree, fname);
1958 smbcli_deltree(cli->tree, BASEDIR);
1964 * Check that a write after a truncate write doesn't update
1965 * the timestamp, but a truncate write after a write does.
1966 * Also prove that a close after a truncate write updates the
1967 * timestamp to current, not the time of last write.
1970 static bool test_delayed_write_update3c(struct torture_context *tctx,
1971 struct smbcli_state *cli,
1972 struct smbcli_state *cli2)
1974 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1975 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1976 const char *fname = BASEDIR "\\torture_file3c.txt";
1981 struct timeval start;
1983 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1984 int normal_delay = 2000000;
1985 double sec = ((double)used_delay) / ((double)normal_delay);
1986 int msec = 1000 * sec;
1988 torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
1990 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1992 torture_comment(tctx, "Open the file handle\n");
1993 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1996 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2000 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2001 finfo0.basic_info.in.file.fnum = fnum1;
2005 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2006 pinfo0.basic_info.in.file.path = fname;
2012 /* get the initial times */
2013 GET_INFO_BOTH(finfo0,pinfo0);
2016 * sleep some time, to demonstrate the handling of write times
2017 * doesn't depend on the time since the open
2019 smb_msleep(5 * msec);
2021 /* get the initial times */
2022 GET_INFO_BOTH(finfo1,pinfo1);
2023 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2026 * demonstrate that a truncate write always
2027 * updates the write time immediately
2029 for (i=0; i < 3; i++) {
2030 smb_msleep(2 * msec);
2032 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
2033 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2035 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2039 /* get the times after the write */
2040 GET_INFO_BOTH(finfo2,pinfo2);
2041 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2045 start = timeval_current();
2046 end = timeval_add(&start, 7 * sec, 0);
2047 while (!timeval_expired(&end)) {
2049 torture_comment(tctx, "Do a write on the file handle\n");
2050 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2052 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2056 /* get the times after the write */
2057 GET_INFO_FILE(finfo2);
2059 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2060 double diff = timeval_elapsed(&start);
2061 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2067 smb_msleep(1 * msec);
2070 GET_INFO_BOTH(finfo2,pinfo2);
2071 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2072 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2073 torture_comment(tctx, "Server did not update write_time (correct)\n");
2077 smb_msleep(5 * msec);
2079 /* get the initial times */
2080 GET_INFO_BOTH(finfo1,pinfo1);
2081 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2084 * demonstrate that a truncate write always
2085 * updates the write time immediately
2087 for (i=0; i < 3; i++) {
2088 smb_msleep(2 * msec);
2090 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2091 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2093 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2097 /* get the times after the write */
2098 GET_INFO_BOTH(finfo2,pinfo2);
2099 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2104 smb_msleep(5 * msec);
2106 GET_INFO_BOTH(finfo2,pinfo2);
2107 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2109 /* sure any further write doesn't update the write time */
2110 start = timeval_current();
2111 end = timeval_add(&start, 15 * sec, 0);
2112 while (!timeval_expired(&end)) {
2114 torture_comment(tctx, "Do a write on the file handle\n");
2115 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2117 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2121 /* get the times after the write */
2122 GET_INFO_BOTH(finfo2,pinfo2);
2124 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2125 double diff = timeval_elapsed(&start);
2126 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2132 smb_msleep(1 * msec);
2135 GET_INFO_BOTH(finfo2,pinfo2);
2136 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2137 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2138 torture_comment(tctx, "Server did not update write_time (correct)\n");
2142 smb_msleep(5 * msec);
2144 GET_INFO_BOTH(finfo3,pinfo3);
2145 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2148 * the close updates the write time to the time of the close
2149 * and not to the time of the last write!
2151 torture_comment(tctx, "Close the file handle\n");
2152 smbcli_close(cli->tree, fnum1);
2155 GET_INFO_PATH(pinfo4);
2156 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2158 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2159 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2164 smbcli_close(cli->tree, fnum1);
2165 smbcli_unlink(cli->tree, fname);
2166 smbcli_deltree(cli->tree, BASEDIR);
2172 * Show only the first write updates the timestamp, and a close
2173 * after writes updates to current (I think this is the same
2177 static bool test_delayed_write_update4(struct torture_context *tctx,
2178 struct smbcli_state *cli,
2179 struct smbcli_state *cli2)
2181 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
2182 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
2183 const char *fname = BASEDIR "\\torture_file4.txt";
2187 struct timeval start;
2189 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2190 int normal_delay = 2000000;
2191 double sec = ((double)used_delay) / ((double)normal_delay);
2192 int msec = 1000 * sec;
2194 torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2196 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2198 torture_comment(tctx, "Open the file handle\n");
2199 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2202 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2206 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2207 finfo0.basic_info.in.file.fnum = fnum1;
2211 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2212 pinfo0.basic_info.in.file.path = fname;
2218 /* get the initial times */
2219 GET_INFO_BOTH(finfo0,pinfo0);
2222 smb_msleep(5 * msec);
2225 torture_comment(tctx, "Do a write on the file handle\n");
2226 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2228 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2233 GET_INFO_BOTH(finfo1,pinfo1);
2234 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2237 * make sure the write time is updated 2 seconds later
2238 * calcuated from the first write
2239 * (but expect upto 3 seconds extra time for a busy server)
2241 start = timeval_current();
2242 end = timeval_add(&start, 5 * sec, 0);
2243 while (!timeval_expired(&end)) {
2244 /* get the times after the first write */
2245 GET_INFO_FILE(finfo1);
2247 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2248 double diff = timeval_elapsed(&start);
2249 if (diff < (used_delay / (double)1000000)) {
2250 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
2251 "(expected > %.2f) (wrong!)\n",
2252 diff, used_delay / (double)1000000);
2257 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2258 "(write time update delay == %.2f) (correct)\n",
2259 diff, used_delay / (double)1000000);
2262 smb_msleep(0.5 * msec);
2265 GET_INFO_BOTH(finfo1,pinfo1);
2266 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2268 /* sure any further write doesn't update the write time */
2269 start = timeval_current();
2270 end = timeval_add(&start, 15 * sec, 0);
2271 while (!timeval_expired(&end)) {
2273 torture_comment(tctx, "Do a write on the file handle\n");
2274 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2276 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2280 /* get the times after the write */
2281 GET_INFO_BOTH(finfo2,pinfo2);
2283 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2284 double diff = timeval_elapsed(&start);
2285 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2291 smb_msleep(1 * msec);
2294 GET_INFO_BOTH(finfo2,pinfo2);
2295 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2296 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2297 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2301 smb_msleep(5 * msec);
2303 GET_INFO_BOTH(finfo3,pinfo3);
2304 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2307 * the close updates the write time to the time of the close
2308 * and not to the time of the last write!
2310 torture_comment(tctx, "Close the file handle\n");
2311 smbcli_close(cli->tree, fnum1);
2314 GET_INFO_PATH(pinfo4);
2315 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2317 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2318 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2323 smbcli_close(cli->tree, fnum1);
2324 smbcli_unlink(cli->tree, fname);
2325 smbcli_deltree(cli->tree, BASEDIR);
2331 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2334 static bool test_delayed_write_update5(struct torture_context *tctx,
2335 struct smbcli_state *cli,
2336 struct smbcli_state *cli2)
2338 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2339 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2340 const char *fname = BASEDIR "\\torture_file5.txt";
2344 struct timeval start;
2346 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2347 int normal_delay = 2000000;
2348 double sec = ((double)used_delay) / ((double)normal_delay);
2349 int msec = 1000 * sec;
2351 torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2353 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2355 torture_comment(tctx, "Open the file handle\n");
2356 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2359 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2363 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2364 finfo0.basic_info.in.file.fnum = fnum1;
2370 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2371 pinfo0.basic_info.in.file.path = fname;
2379 /* get the initial times */
2380 GET_INFO_BOTH(finfo0,pinfo0);
2383 torture_comment(tctx, "Do a write on the file handle\n");
2384 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2386 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2391 GET_INFO_BOTH(finfo1,pinfo1);
2392 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2394 torture_comment(tctx, "Set write time in the future on the file handle\n");
2395 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2396 GET_INFO_BOTH(finfo2,pinfo2);
2397 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2399 torture_comment(tctx, "Set write time in the past on the file handle\n");
2400 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2401 GET_INFO_BOTH(finfo2,pinfo2);
2402 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2404 /* make sure the 2 second delay from the first write are canceled */
2405 start = timeval_current();
2406 end = timeval_add(&start, 15 * sec, 0);
2407 while (!timeval_expired(&end)) {
2409 /* get the times after the first write */
2410 GET_INFO_BOTH(finfo3,pinfo3);
2412 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2413 double diff = timeval_elapsed(&start);
2414 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2420 smb_msleep(1 * msec);
2423 GET_INFO_BOTH(finfo3,pinfo3);
2424 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2425 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2426 torture_comment(tctx, "Server did not update write_time (correct)\n");
2429 /* sure any further write doesn't update the write time */
2430 start = timeval_current();
2431 end = timeval_add(&start, 15 * sec, 0);
2432 while (!timeval_expired(&end)) {
2434 torture_comment(tctx, "Do a write on the file handle\n");
2435 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2437 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2441 /* get the times after the write */
2442 GET_INFO_BOTH(finfo4,pinfo4);
2444 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2445 double diff = timeval_elapsed(&start);
2446 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2452 smb_msleep(1 * msec);
2455 GET_INFO_BOTH(finfo4,pinfo4);
2456 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2457 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2458 torture_comment(tctx, "Server did not update write_time (correct)\n");
2462 smb_msleep(5 * msec);
2464 GET_INFO_BOTH(finfo5,pinfo5);
2465 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2468 * the close doesn't update the write time
2470 torture_comment(tctx, "Close the file handle\n");
2471 smbcli_close(cli->tree, fnum1);
2474 GET_INFO_PATH(pinfo6);
2475 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2477 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2478 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2483 smbcli_close(cli->tree, fnum1);
2484 smbcli_unlink(cli->tree, fname);
2485 smbcli_deltree(cli->tree, BASEDIR);
2491 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2494 static bool test_delayed_write_update5b(struct torture_context *tctx,
2495 struct smbcli_state *cli,
2496 struct smbcli_state *cli2)
2498 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2499 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2500 const char *fname = BASEDIR "\\torture_fileb.txt";
2504 struct timeval start;
2506 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2507 int normal_delay = 2000000;
2508 double sec = ((double)used_delay) / ((double)normal_delay);
2509 int msec = 1000 * sec;
2511 torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2513 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2515 torture_comment(tctx, "Open the file handle\n");
2516 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2519 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2523 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2524 finfo0.basic_info.in.file.fnum = fnum1;
2530 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2531 pinfo0.basic_info.in.file.path = fname;
2539 /* get the initial times */
2540 GET_INFO_BOTH(finfo0,pinfo0);
2543 torture_comment(tctx, "Do a write on the file handle\n");
2544 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2546 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2551 GET_INFO_BOTH(finfo1,pinfo1);
2552 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2554 torture_comment(tctx, "Set write time in the future on the file handle\n");
2555 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2556 GET_INFO_BOTH(finfo2,pinfo2);
2557 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2559 torture_comment(tctx, "Set write time in the past on the file handle\n");
2560 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2561 GET_INFO_BOTH(finfo2,pinfo2);
2562 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2564 /* make sure the 2 second delay from the first write are canceled */
2565 start = timeval_current();
2566 end = timeval_add(&start, 15 * sec, 0);
2567 while (!timeval_expired(&end)) {
2569 /* get the times after the first write */
2570 GET_INFO_BOTH(finfo3,pinfo3);
2572 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2573 double diff = timeval_elapsed(&start);
2574 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2580 smb_msleep(1 * msec);
2583 GET_INFO_BOTH(finfo3,pinfo3);
2584 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2585 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2586 torture_comment(tctx, "Server did not update write_time (correct)\n");
2589 /* Do any further write (truncates) update the write time ? */
2590 start = timeval_current();
2591 end = timeval_add(&start, 15 * sec, 0);
2592 while (!timeval_expired(&end)) {
2594 torture_comment(tctx, "Do a truncate write on the file handle\n");
2595 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2597 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2601 /* get the times after the write */
2602 GET_INFO_BOTH(finfo4,pinfo4);
2604 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2605 double diff = timeval_elapsed(&start);
2606 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2612 smb_msleep(1 * msec);
2615 GET_INFO_BOTH(finfo4,pinfo4);
2616 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2617 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2618 torture_comment(tctx, "Server did not update write_time (correct)\n");
2622 smb_msleep(5 * msec);
2624 GET_INFO_BOTH(finfo5,pinfo5);
2625 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2628 * the close doesn't update the write time
2630 torture_comment(tctx, "Close the file handle\n");
2631 smbcli_close(cli->tree, fnum1);
2634 GET_INFO_PATH(pinfo6);
2635 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2637 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2638 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2643 smbcli_close(cli->tree, fnum1);
2644 smbcli_unlink(cli->tree, fname);
2645 smbcli_deltree(cli->tree, BASEDIR);
2651 * Open 2 handles on a file. Write one one and then set the
2652 * WRITE TIME explicitly on the other. Ensure the write time
2653 * update is cancelled. Ensure the write time is updated to
2654 * the close time when the non-explicit set handle is closed.
2658 static bool test_delayed_write_update6(struct torture_context *tctx,
2659 struct smbcli_state *cli,
2660 struct smbcli_state *cli2)
2662 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2663 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2664 const char *fname = BASEDIR "\\torture_file6.txt";
2669 struct timeval start;
2671 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2672 int normal_delay = 2000000;
2673 double sec = ((double)used_delay) / ((double)normal_delay);
2674 int msec = 1000 * sec;
2677 torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2679 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2681 torture_comment(tctx, "Open the file handle\n");
2682 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2685 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2690 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2691 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2694 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2699 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2700 finfo0.basic_info.in.file.fnum = fnum1;
2706 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2707 pinfo0.basic_info.in.file.path = fname;
2716 /* get the initial times */
2717 GET_INFO_BOTH(finfo0,pinfo0);
2720 torture_comment(tctx, "Do a write on the file handle\n");
2721 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2723 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2728 GET_INFO_BOTH(finfo1,pinfo1);
2729 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2731 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2732 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2733 GET_INFO_BOTH(finfo2,pinfo2);
2734 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2736 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2737 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2738 GET_INFO_BOTH(finfo2,pinfo2);
2739 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2741 /* make sure the 2 second delay from the first write are canceled */
2742 start = timeval_current();
2743 end = timeval_add(&start, 10 * sec, 0);
2744 while (!timeval_expired(&end)) {
2746 /* get the times after the first write */
2747 GET_INFO_BOTH(finfo3,pinfo3);
2749 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2750 double diff = timeval_elapsed(&start);
2751 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2757 smb_msleep(1 * msec);
2760 GET_INFO_BOTH(finfo3,pinfo3);
2761 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2762 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2763 torture_comment(tctx, "Server did not update write_time (correct)\n");
2766 /* sure any further write doesn't update the write time */
2767 start = timeval_current();
2768 end = timeval_add(&start, 10 * sec, 0);
2769 while (!timeval_expired(&end)) {
2771 torture_comment(tctx, "Do a write on the file handle\n");
2772 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2774 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2778 /* get the times after the write */
2779 GET_INFO_BOTH(finfo4,pinfo4);
2781 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2782 double diff = timeval_elapsed(&start);
2783 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2789 smb_msleep(1 * msec);
2792 GET_INFO_BOTH(finfo4,pinfo4);
2793 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2794 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2795 torture_comment(tctx, "Server did not update write_time (correct)\n");
2799 smb_msleep(5 * msec);
2801 GET_INFO_BOTH(finfo5,pinfo5);
2802 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2805 * the close updates the write time to the time of the close
2806 * as the write time was set on the 2nd handle
2808 torture_comment(tctx, "Close the file handle\n");
2809 smbcli_close(cli->tree, fnum1);
2812 GET_INFO_PATH(pinfo6);
2813 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2815 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2816 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2819 /* See what the second write handle thinks the time is ? */
2820 finfo5.basic_info.in.file.fnum = fnum2;
2821 GET_INFO_FILE2(finfo5);
2822 COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
2824 /* See if we have lost the sticky write time on handle2 */
2825 smb_msleep(3 * msec);
2826 torture_comment(tctx, "Have we lost the sticky write time ?\n");
2828 /* Make sure any further normal write doesn't update the write time */
2829 start = timeval_current();
2830 end = timeval_add(&start, 10 * sec, 0);
2831 while (!timeval_expired(&end)) {
2833 torture_comment(tctx, "Do a write on the second file handle\n");
2834 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
2836 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2840 /* get the times after the write */
2841 GET_INFO_FILE2(finfo5);
2842 GET_INFO_PATH(pinfo6);
2844 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2845 double diff = timeval_elapsed(&start);
2846 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2852 smb_msleep(1 * msec);
2855 /* What about a truncate write ? */
2856 start = timeval_current();
2857 end = timeval_add(&start, 10 * sec, 0);
2858 while (!timeval_expired(&end)) {
2860 torture_comment(tctx, "Do a truncate write on the second file handle\n");
2861 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
2863 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2867 /* get the times after the write */
2868 GET_INFO_FILE2(finfo5);
2869 GET_INFO_PATH(pinfo6);
2871 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2872 double diff = timeval_elapsed(&start);
2873 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2879 smb_msleep(1 * msec);
2883 /* keep the 2nd handle open and rerun tests */
2890 * closing the 2nd handle will cause no write time update
2891 * as the write time was explicit set on this handle
2893 torture_comment(tctx, "Close the 2nd file handle\n");
2894 smbcli_close(cli2->tree, fnum2);
2897 GET_INFO_PATH(pinfo7);
2898 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2900 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2901 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2906 smbcli_close(cli->tree, fnum1);
2908 smbcli_close(cli2->tree, fnum2);
2909 smbcli_unlink(cli->tree, fname);
2910 smbcli_deltree(cli->tree, BASEDIR);
2915 static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
2917 union smb_open open_parms;
2918 union smb_fileinfo finfo1, finfo2, finfo3;
2919 const char *fname = BASEDIR "\\torture_file7.txt";
2923 TALLOC_CTX *mem_ctx;
2925 torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2927 mem_ctx = talloc_init("test_delayed_write_update7");
2928 if (!mem_ctx) return false;
2930 ZERO_STRUCT(finfo1);
2931 ZERO_STRUCT(finfo2);
2932 ZERO_STRUCT(finfo3);
2933 ZERO_STRUCT(open_parms);
2935 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2937 /* Create the file. */
2938 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2940 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
2944 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2945 finfo1.basic_info.in.file.fnum = fnum1;
2949 /* Get the initial timestamps. */
2950 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
2952 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2954 /* Set the pending write time to a value with ns. */
2955 SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
2957 /* Get the current pending write time by fnum. */
2958 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
2960 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2962 /* Ensure the time is actually different. */
2963 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2964 torture_result(tctx, TORTURE_FAIL,
2965 "setfileinfo time matches original fileinfo time");
2969 /* Get the current pending write time by path. */
2970 finfo3.basic_info.in.file.path = fname;
2971 status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
2973 if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
2974 torture_result(tctx, TORTURE_FAIL,
2975 "qpathinfo time doens't match fileinfo time");
2979 /* Now close the file. Re-open and check that the write
2980 time is identical to the one we wrote. */
2982 smbcli_close(cli->tree, fnum1);
2984 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
2985 open_parms.ntcreatex.in.flags = 0;
2986 open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
2987 open_parms.ntcreatex.in.file_attr = 0;
2988 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
2989 NTCREATEX_SHARE_ACCESS_READ|
2990 NTCREATEX_SHARE_ACCESS_WRITE;
2991 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
2992 open_parms.ntcreatex.in.create_options = 0;
2993 open_parms.ntcreatex.in.fname = fname;
2995 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
2996 talloc_free(mem_ctx);
2998 if (!NT_STATUS_IS_OK(status)) {
2999 torture_result(tctx, TORTURE_FAIL,
3000 "setfileinfo time matches original fileinfo time");
3004 fnum1 = open_parms.ntcreatex.out.file.fnum;
3006 /* Check the returned time matches. */
3007 if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
3008 torture_result(tctx, TORTURE_FAIL,
3009 "final open time does not match set time");
3015 smbcli_close(cli->tree, fnum1);
3017 smbcli_unlink(cli->tree, fname);
3018 smbcli_deltree(cli->tree, BASEDIR);
3023 Test if creating a file in a directory with an open handle updates the
3024 write timestamp (it should).
3026 static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
3028 union smb_fileinfo dir_info1, dir_info2;
3029 union smb_open open_parms;
3030 const char *fname = BASEDIR "\\torture_file.txt";
3035 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3036 int normal_delay = 2000000;
3037 double sec = ((double)used_delay) / ((double)normal_delay);
3038 int msec = 1000 * sec;
3039 TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
3041 if (!mem_ctx) return false;
3043 torture_comment(tctx, "\nRunning test directory write update\n");
3045 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
3047 /* Open a handle on the directory - and leave it open. */
3048 ZERO_STRUCT(open_parms);
3049 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3050 open_parms.ntcreatex.in.flags = 0;
3051 open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
3052 open_parms.ntcreatex.in.file_attr = 0;
3053 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3054 NTCREATEX_SHARE_ACCESS_READ|
3055 NTCREATEX_SHARE_ACCESS_WRITE;
3056 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3057 open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
3058 open_parms.ntcreatex.in.fname = BASEDIR;
3060 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3061 talloc_free(mem_ctx);
3063 if (!NT_STATUS_IS_OK(status)) {
3064 torture_result(tctx, TORTURE_FAIL,
3065 "failed to open directory handle");
3070 fnum1 = open_parms.ntcreatex.out.file.fnum;
3072 /* Store the returned write time. */
3073 ZERO_STRUCT(dir_info1);
3074 dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
3076 torture_comment(tctx, "Initial write time %s\n",
3077 nt_time_string(tctx, dir_info1.basic_info.out.write_time));
3080 smb_msleep(3 * msec);
3082 /* Now create a file within the directory. */
3083 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3085 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
3089 smbcli_close(cli->tree, fnum2);
3091 /* Read the directory write time again. */
3092 ZERO_STRUCT(dir_info2);
3093 dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3094 dir_info2.basic_info.in.file.fnum = fnum1;
3096 status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
3098 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
3100 /* Ensure it's been incremented. */
3101 COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
3103 torture_comment(tctx, "Updated write time %s\n",
3104 nt_time_string(tctx, dir_info2.basic_info.out.write_time));
3109 smbcli_close(cli->tree, fnum1);
3110 smbcli_unlink(cli->tree, fname);
3111 smbcli_deltree(cli->tree, BASEDIR);
3117 testing of delayed update of write_time
3119 struct torture_suite *torture_delay_write(void)
3121 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "delaywrite");
3123 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
3124 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
3125 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
3126 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
3127 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
3128 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
3129 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
3130 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
3131 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
3132 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
3133 torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
3134 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
3135 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
3136 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
3137 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
3138 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3139 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3140 torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);