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"
33 #include "lib/util/time_basic.h"
35 #define BASEDIR "\\delaywrite"
37 static bool test_delayed_write_update(struct torture_context *tctx, struct smbcli_state *cli)
39 union smb_fileinfo finfo1, finfo2;
40 union smb_fileinfo pinfo1;
41 const char *fname = BASEDIR "\\torture_file.txt";
48 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
49 int normal_delay = 2000000;
50 double sec = ((double)used_delay) / ((double)normal_delay);
51 int msec = 1000 * sec;
53 torture_comment(tctx, "\nRunning test_delayed_write_update\n");
55 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
57 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
58 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
59 "Failed to open %s", fname));
61 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
62 finfo1.basic_info.in.file.fnum = fnum1;
65 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
66 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
68 torture_comment(tctx, "Initial write time %s\n",
69 nt_time_string(tctx, finfo1.basic_info.out.write_time));
71 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
72 torture_assert_int_equal(tctx, written, 1,
73 "unexpected number of bytes written");
75 pinfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
76 pinfo1.basic_info.in.file.path = fname;
77 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo1);
78 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
80 start = timeval_current();
81 end = timeval_add(&start, (120 * sec), 0);
82 while (!timeval_expired(&end)) {
83 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
85 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
87 torture_comment(tctx, "write time %s\n",
88 nt_time_string(tctx, finfo2.basic_info.out.write_time));
90 if (finfo1.basic_info.out.write_time !=
91 finfo2.basic_info.out.write_time)
93 double diff = timeval_elapsed(&start);
96 diff >= (used_delay / (double)1000000),
98 "Server updated write_time after %.2f "
99 "seconds (expected >= %.2f)\n",
100 diff, used_delay/(double)1000000));
102 torture_comment(tctx, "Server updated write_time after %.2f seconds (correct)\n",
107 smb_msleep(1 * msec);
110 torture_assert_u64_not_equal(tctx,
111 finfo2.basic_info.out.write_time,
112 finfo1.basic_info.out.write_time,
113 "Server did not update write time within "
117 smbcli_close(cli->tree, fnum1);
118 smbcli_unlink(cli->tree, fname);
119 smbcli_deltree(cli->tree, BASEDIR);
124 static bool test_delayed_write_update1(struct torture_context *tctx, struct smbcli_state *cli)
126 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
127 const char *fname = BASEDIR "\\torture_file1.txt";
132 struct timeval start;
134 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
135 int normal_delay = 2000000;
136 double sec = ((double)used_delay) / ((double)normal_delay);
137 int msec = 1000 * sec;
142 torture_comment(tctx, "\nRunning test_delayed_write_update1\n");
144 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
146 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
147 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
148 "Failed to open %s", fname));
150 memset(buf, 'x', 2048);
151 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
153 /* 3 second delay to ensure we get past any 2 second time
154 granularity (older systems may have that) */
155 smb_msleep(3 * msec);
157 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
158 finfo1.all_info.in.file.fnum = fnum1;
161 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
162 pinfo4.all_info.in.file.path = fname;
164 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
166 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
168 torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
169 "file size not as expected after write(2048)");
171 torture_comment(tctx, "Initial write time %s\n",
172 nt_time_string(tctx, finfo1.all_info.out.write_time));
174 /* 3 second delay to ensure we get past any 2 second time
175 granularity (older systems may have that) */
176 smb_msleep(3 * msec);
178 /* Do a zero length SMBwrite call to truncate. */
179 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
180 torture_assert_int_equal(tctx, written, 0,
181 "unexpected number of bytes written");
183 start = timeval_current();
184 end = timeval_add(&start, (120 * sec), 0);
187 while (!timeval_expired(&end)) {
188 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
190 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
192 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 1024,
193 "file not truncated to expected size "
196 torture_comment(tctx, "write time %s\n",
197 nt_time_string(tctx, finfo2.all_info.out.write_time));
199 if (finfo1.all_info.out.write_time !=
200 finfo2.all_info.out.write_time)
207 smb_msleep(1 * msec);
211 torture_assert(tctx, updated,
212 "Server did not update write time within 120 seconds");
214 torture_assert(tctx, first, talloc_asprintf(tctx,
215 "Server did not update write time immediately but only "
216 "after %.2f seconds!", timeval_elapsed(&start)));
218 torture_comment(tctx, "Server updated write time immediately. Good!\n");
221 smb_msleep(2 * msec);
223 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
224 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
225 torture_assert_int_equal(tctx, written, 1,
226 "unexpected number of bytes written");
228 start = timeval_current();
229 end = timeval_add(&start, (10*sec), 0);
230 while (!timeval_expired(&end)) {
231 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
233 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
235 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 1024,
236 "file not truncated to expected size "
239 torture_comment(tctx, "write time %s\n",
240 nt_time_string(tctx, finfo3.all_info.out.write_time));
242 torture_assert_u64_equal(tctx,
243 finfo3.all_info.out.write_time,
244 finfo2.all_info.out.write_time,
245 talloc_asprintf(tctx,
246 "Server updated write time "
247 "after %.2f seconds (wrong!)",
248 timeval_elapsed(&start)));
251 smb_msleep(1 * msec);
254 torture_comment(tctx, "Server did not update write time within 10 "
258 smb_msleep(2 * msec);
260 /* the close should trigger an write time update */
261 smbcli_close(cli->tree, fnum1);
264 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
265 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
267 torture_assert_u64_not_equal(tctx,
268 pinfo4.all_info.out.write_time,
269 finfo3.all_info.out.write_time,
270 "Server did not update write time on "
273 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
274 "Server updated write time on close, but to an earlier point "
277 torture_comment(tctx, "Server updated write time on close (correct)\n");
280 smbcli_close(cli->tree, fnum1);
281 smbcli_unlink(cli->tree, fname);
282 smbcli_deltree(cli->tree, BASEDIR);
287 /* Updating with a SMBwrite of zero length
288 * changes the write time immediately - even on expand. */
290 static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
292 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
293 const char *fname = BASEDIR "\\torture_file1a.txt";
298 struct timeval start;
300 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
301 int normal_delay = 2000000;
302 double sec = ((double)used_delay) / ((double)normal_delay);
303 int msec = 1000 * sec;
308 torture_comment(tctx, "\nRunning test_delayed_write_update1a\n");
310 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
312 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
313 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
314 "Failed to open %s", fname));
316 memset(buf, 'x', 2048);
317 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
319 /* 3 second delay to ensure we get past any 2 second time
320 granularity (older systems may have that) */
321 smb_msleep(3 * msec);
323 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
324 finfo1.all_info.in.file.fnum = fnum1;
327 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
328 pinfo4.all_info.in.file.path = fname;
330 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
332 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
334 torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
335 "file size not as expected after write(2048)");
337 torture_comment(tctx, "Initial write time %s\n",
338 nt_time_string(tctx, finfo1.all_info.out.write_time));
340 /* Do a zero length SMBwrite call to truncate. */
341 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
343 torture_assert_int_equal(tctx, written, 0,
344 "unexpected number of bytes written");
346 start = timeval_current();
347 end = timeval_add(&start, (120*sec), 0);
350 while (!timeval_expired(&end)) {
351 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
353 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
355 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
356 "file not truncated to expected size "
359 torture_comment(tctx, "write time %s\n",
360 nt_time_string(tctx, finfo2.all_info.out.write_time));
362 if (finfo1.all_info.out.write_time !=
363 finfo2.all_info.out.write_time)
370 smb_msleep(1 * msec);
374 torture_assert(tctx, updated,
375 "Server did not update write time within 120 seconds");
377 torture_assert(tctx, first, talloc_asprintf(tctx,
378 "Server did not update write time immediately but only "
379 "after %.2f seconds!", timeval_elapsed(&start)));
381 torture_comment(tctx, "Server updated write time immediately. Good!\n");
384 smb_msleep(2 * msec);
386 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
387 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
389 torture_assert_int_equal(tctx, written, 1,
390 "unexpected number of bytes written");
392 start = timeval_current();
393 end = timeval_add(&start, (10*sec), 0);
394 while (!timeval_expired(&end)) {
395 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
397 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
399 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
400 "file not truncated to expected size "
403 torture_comment(tctx, "write time %s\n",
404 nt_time_string(tctx, finfo3.all_info.out.write_time));
406 torture_assert_u64_equal(tctx,
407 finfo3.all_info.out.write_time,
408 finfo2.all_info.out.write_time,
409 talloc_asprintf(tctx,
410 "Server updated write time "
411 "after %.2f seconds (wrong!)",
412 timeval_elapsed(&start)));
415 smb_msleep(1 * msec);
418 torture_comment(tctx, "Server did not update write time within 10 "
421 /* the close should trigger an write time update */
422 smbcli_close(cli->tree, fnum1);
425 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
426 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
428 torture_assert_u64_not_equal(tctx,
429 pinfo4.all_info.out.write_time,
430 finfo3.all_info.out.write_time,
431 "Server did not update write time on "
434 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
435 "Server updated write time on close, but to an earlier point "
438 torture_comment(tctx, "Server updated write time on close (correct)\n");
441 smbcli_close(cli->tree, fnum1);
442 smbcli_unlink(cli->tree, fname);
443 smbcli_deltree(cli->tree, BASEDIR);
448 /* Updating with a SET_FILE_END_OF_FILE_INFO
449 * changes the write time immediately - even on expand. */
451 static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
453 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
454 const char *fname = BASEDIR "\\torture_file1b.txt";
459 struct timeval start;
461 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
462 int normal_delay = 2000000;
463 double sec = ((double)used_delay) / ((double)normal_delay);
464 int msec = 1000 * sec;
469 torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
471 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
473 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
474 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
475 "Failed to open %s", fname));
477 memset(buf, 'x', 2048);
478 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
480 /* 3 second delay to ensure we get past any 2 second time
481 granularity (older systems may have that) */
482 smb_msleep(3 * msec);
484 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
485 finfo1.all_info.in.file.fnum = fnum1;
488 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
489 pinfo4.all_info.in.file.path = fname;
491 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
493 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
495 torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
496 "file size not as expected after write(2048)");
498 torture_comment(tctx, "Initial write time %s\n",
499 nt_time_string(tctx, finfo1.all_info.out.write_time));
501 /* Do a SET_END_OF_FILE_INFO call to truncate. */
502 status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
504 torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
506 start = timeval_current();
507 end = timeval_add(&start, (120*sec), 0);
510 while (!timeval_expired(&end)) {
511 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
513 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
515 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
516 "file not truncated to expected size "
519 torture_comment(tctx, "write time %s\n",
520 nt_time_string(tctx, finfo2.all_info.out.write_time));
522 if (finfo1.all_info.out.write_time !=
523 finfo2.all_info.out.write_time)
530 smb_msleep(1 * msec);
534 torture_assert(tctx, updated,
535 "Server did not update write time within 120 seconds");
537 torture_assert(tctx, first, talloc_asprintf(tctx,
538 "Server did not update write time immediately but only "
539 "after %.2f seconds!", timeval_elapsed(&start)));
541 torture_comment(tctx, "Server updated write time immediately. Good!\n");
544 smb_msleep(2 * msec);
546 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
547 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
549 torture_assert_int_equal(tctx, written, 1,
550 "unexpected number of bytes written");
552 start = timeval_current();
553 end = timeval_add(&start, (10*sec), 0);
554 while (!timeval_expired(&end)) {
555 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
557 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
559 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
560 "file not truncated to expected size "
563 torture_comment(tctx, "write time %s\n",
564 nt_time_string(tctx, finfo3.all_info.out.write_time));
566 torture_assert_u64_equal(tctx,
567 finfo3.all_info.out.write_time,
568 finfo2.all_info.out.write_time,
569 talloc_asprintf(tctx,
570 "Server updated write time "
571 "after %.2f seconds (wrong!)",
572 timeval_elapsed(&start)));
575 smb_msleep(1 * msec);
578 torture_comment(tctx, "Server did not update write time within 10 "
581 /* the close should trigger an write time update */
582 smbcli_close(cli->tree, fnum1);
585 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
586 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
588 torture_assert_u64_not_equal(tctx,
589 pinfo4.all_info.out.write_time,
590 finfo3.all_info.out.write_time,
591 "Server did not update write time on "
594 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
595 "Server updated write time on close, but to an earlier point "
598 torture_comment(tctx, "Server updated write time on close (correct)\n");
601 smbcli_close(cli->tree, fnum1);
602 smbcli_unlink(cli->tree, fname);
603 smbcli_deltree(cli->tree, BASEDIR);
608 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
610 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
612 union smb_setfileinfo parms;
613 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
614 const char *fname = BASEDIR "\\torture_file1c.txt";
619 struct timeval start;
621 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
622 int normal_delay = 2000000;
623 double sec = ((double)used_delay) / ((double)normal_delay);
624 int msec = 1000 * sec;
629 torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
631 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
633 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
634 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
635 "Failed to open %s", fname));
637 memset(buf, 'x', 2048);
638 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
640 /* 3 second delay to ensure we get past any 2 second time
641 granularity (older systems may have that) */
642 smb_msleep(3 * msec);
644 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
645 finfo1.all_info.in.file.fnum = fnum1;
648 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
649 pinfo4.all_info.in.file.path = fname;
651 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
653 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
655 torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
656 "file size not as expected after write(2048)");
658 torture_comment(tctx, "Initial write time %s\n",
659 nt_time_string(tctx, finfo1.all_info.out.write_time));
661 /* Do a SET_ALLOCATION_SIZE call to truncate. */
662 parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
663 parms.allocation_info.in.file.fnum = fnum1;
664 parms.allocation_info.in.alloc_size = 0;
666 status = smb_raw_setfileinfo(cli->tree, &parms);
668 torture_assert_ntstatus_ok(tctx, status,
669 "RAW_SFILEINFO_ALLOCATION_INFO failed");
671 start = timeval_current();
672 end = timeval_add(&start, (120*sec), 0);
675 while (!timeval_expired(&end)) {
676 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
678 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
680 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 0,
681 "file not truncated to expected size "
684 torture_comment(tctx, "write time %s\n",
685 nt_time_string(tctx, finfo2.all_info.out.write_time));
687 if (finfo1.all_info.out.write_time !=
688 finfo2.all_info.out.write_time)
695 smb_msleep(1 * msec);
699 torture_assert(tctx, updated,
700 "Server did not update write time within 120 seconds");
702 torture_assert(tctx, first, talloc_asprintf(tctx,
703 "Server did not update write time immediately but only "
704 "after %.2f seconds!", timeval_elapsed(&start)));
706 torture_comment(tctx, "Server updated write time immediately. Good!\n");
709 smb_msleep(2 * msec);
711 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
712 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
713 torture_assert_int_equal(tctx, written, 1,
714 "Unexpected number of bytes written");
716 start = timeval_current();
717 end = timeval_add(&start, (10*sec), 0);
718 while (!timeval_expired(&end)) {
719 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
721 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
723 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 1,
724 "file not expaneded");
726 torture_comment(tctx, "write time %s\n",
727 nt_time_string(tctx, finfo3.all_info.out.write_time));
729 torture_assert_u64_equal(tctx,
730 finfo3.all_info.out.write_time,
731 finfo2.all_info.out.write_time,
732 talloc_asprintf(tctx,
733 "Server updated write time "
734 "after %.2f seconds (wrong!)",
735 timeval_elapsed(&start)));
738 smb_msleep(1 * msec);
741 torture_comment(tctx, "Server did not update write time within 10 "
744 /* the close should trigger an write time update */
745 smbcli_close(cli->tree, fnum1);
748 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
749 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
751 torture_assert_u64_not_equal(tctx,
752 pinfo4.all_info.out.write_time,
753 finfo3.all_info.out.write_time,
754 "Server did not update write time on "
757 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
758 "Server updated write time on close, but to an earlier point "
762 smbcli_close(cli->tree, fnum1);
763 smbcli_unlink(cli->tree, fname);
764 smbcli_deltree(cli->tree, BASEDIR);
770 * Do as above, but using 2 connections.
773 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
774 struct smbcli_state *cli2)
776 union smb_fileinfo finfo1, finfo2;
777 const char *fname = BASEDIR "\\torture_file.txt";
783 struct timeval start;
785 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
786 int normal_delay = 2000000;
787 double sec = ((double)used_delay) / ((double)normal_delay);
788 int msec = 1000 * sec;
789 union smb_flush flsh;
791 torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
793 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
795 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
797 torture_comment(tctx, "Failed to open %s\n", fname);
801 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
802 finfo1.basic_info.in.file.fnum = fnum1;
805 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
807 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
809 torture_comment(tctx, "Initial write time %s\n",
810 nt_time_string(tctx, finfo1.basic_info.out.write_time));
812 /* 3 second delay to ensure we get past any 2 second time
813 granularity (older systems may have that) */
814 smb_msleep(3 * msec);
817 /* Try using setfileinfo instead of write to update write time. */
818 union smb_setfileinfo sfinfo;
819 time_t t_set = time(NULL);
820 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
821 sfinfo.basic_info.in.file.fnum = fnum1;
822 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
823 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
825 /* I tried this with both + and - ve to see if it makes a different.
826 It doesn't - once the filetime is set via setfileinfo it stays that way. */
828 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
830 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
832 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
833 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
835 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
837 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
840 finfo2.basic_info.in.file.path = fname;
842 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
844 if (!NT_STATUS_IS_OK(status)) {
845 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
848 torture_comment(tctx, "write time %s\n",
849 nt_time_string(tctx, finfo2.basic_info.out.write_time));
851 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
852 torture_comment(tctx, "Server updated write_time (correct)\n");
854 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
858 /* Now try a write to see if the write time gets reset. */
860 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
861 finfo1.basic_info.in.file.fnum = fnum1;
864 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
866 if (!NT_STATUS_IS_OK(status)) {
867 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
871 torture_comment(tctx, "Modified write time %s\n",
872 nt_time_string(tctx, finfo1.basic_info.out.write_time));
875 torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
877 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
880 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
881 (int)written, __location__);
885 /* Just to prove to tridge that the an smbflush has no effect on
886 the write time :-). The setfileinfo IS STICKY. JRA. */
888 torture_comment(tctx, "Doing flush after write\n");
890 flsh.flush.level = RAW_FLUSH_FLUSH;
891 flsh.flush.in.file.fnum = fnum1;
892 status = smb_raw_flush(cli->tree, &flsh);
893 if (!NT_STATUS_IS_OK(status)) {
894 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
898 /* Once the time was set using setfileinfo then it stays set - writes
899 don't have any effect. But make sure. */
900 start = timeval_current();
901 end = timeval_add(&start, (15*sec), 0);
902 while (!timeval_expired(&end)) {
903 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
905 if (!NT_STATUS_IS_OK(status)) {
906 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
910 torture_comment(tctx, "write time %s\n",
911 nt_time_string(tctx, finfo2.basic_info.out.write_time));
912 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
913 double diff = timeval_elapsed(&start);
914 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
921 smb_msleep(1 * msec);
924 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
925 torture_comment(tctx, "Server did not update write time (correct)\n");
929 smb_msleep(2 * msec);
931 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
933 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
937 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");
939 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
942 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
943 (int)written, __location__);
947 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
949 if (!NT_STATUS_IS_OK(status)) {
950 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
953 torture_comment(tctx, "write time %s\n",
954 nt_time_string(tctx, finfo2.basic_info.out.write_time));
955 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
956 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
960 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
961 smbcli_close(cli->tree, fnum1);
964 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");
966 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
969 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
970 (int)written, __location__);
974 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
975 finfo1.basic_info.in.file.fnum = fnum2;
977 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
979 if (!NT_STATUS_IS_OK(status)) {
980 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
983 torture_comment(tctx, "write time %s\n",
984 nt_time_string(tctx, finfo2.basic_info.out.write_time));
985 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
986 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
990 /* Once the time was set using setfileinfo then it stays set - writes
991 don't have any effect. But make sure. */
992 start = timeval_current();
993 end = timeval_add(&start, (15*sec), 0);
994 while (!timeval_expired(&end)) {
995 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
997 if (!NT_STATUS_IS_OK(status)) {
998 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1002 torture_comment(tctx, "write time %s\n",
1003 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1004 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1005 double diff = timeval_elapsed(&start);
1006 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1013 smb_msleep(1 * msec);
1016 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1017 torture_comment(tctx, "Server did not update write time (correct)\n");
1020 torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1022 smbcli_close(cli->tree, fnum2);
1025 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1027 torture_comment(tctx, "Failed to open %s\n", fname);
1031 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1032 finfo1.basic_info.in.file.fnum = fnum1;
1035 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1037 if (!NT_STATUS_IS_OK(status)) {
1038 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1042 torture_comment(tctx, "Second open initial write time %s\n",
1043 nt_time_string(tctx, finfo1.basic_info.out.write_time));
1045 smb_msleep(10 * msec);
1046 torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1048 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1050 if (written != 10) {
1051 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1052 (int)written, __location__);
1056 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1057 finfo1.basic_info.in.file.fnum = fnum1;
1059 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1061 if (!NT_STATUS_IS_OK(status)) {
1062 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1065 torture_comment(tctx, "write time %s\n",
1066 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1067 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1068 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1072 /* Now the write time should be updated again */
1073 start = timeval_current();
1074 end = timeval_add(&start, (15*sec), 0);
1075 while (!timeval_expired(&end)) {
1076 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1078 if (!NT_STATUS_IS_OK(status)) {
1079 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1083 torture_comment(tctx, "write time %s\n",
1084 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1085 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1086 double diff = timeval_elapsed(&start);
1087 if (diff < (used_delay / (double)1000000)) {
1088 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1089 "(expected > %.2f) (wrong!)\n",
1090 diff, used_delay / (double)1000000);
1095 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1104 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1105 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
1110 /* One more test to do. We should read the filetime via findfirst on the
1111 second connection to ensure it's the same. This is very easy for a Windows
1112 server but a bastard to get right on a POSIX server. JRA. */
1115 smbcli_close(cli->tree, fnum1);
1116 smbcli_unlink(cli->tree, fname);
1117 smbcli_deltree(cli->tree, BASEDIR);
1123 /* Windows does obviously not update the stat info during a write call. I
1124 * *think* this is the problem causing a spurious Excel 2003 on XP error
1125 * message when saving a file. Excel does a setfileinfo, writes, and then does
1126 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1127 * that the file might have been changed in between. What i've been able to
1128 * trace down is that this happens if the getpathinfo after the write shows a
1129 * different last write time than the setfileinfo showed. This is really
1133 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
1134 struct smbcli_state *cli2)
1136 union smb_fileinfo finfo1, finfo2;
1137 const char *fname = BASEDIR "\\torture_file.txt";
1143 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1144 int normal_delay = 2000000;
1145 double sec = ((double)used_delay) / ((double)normal_delay);
1146 int msec = 1000 * sec;
1148 torture_comment(tctx, "\nRunning test_finfo_after_write\n");
1150 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1152 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1155 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1159 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1160 finfo1.basic_info.in.file.fnum = fnum1;
1162 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1164 if (!NT_STATUS_IS_OK(status)) {
1166 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1170 smb_msleep(1 * msec);
1172 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1175 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1180 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1182 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1183 smbcli_errstr(cli2->tree));
1188 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1191 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1197 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1198 finfo2.basic_info.in.file.path = fname;
1200 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1202 if (!NT_STATUS_IS_OK(status)) {
1203 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
1209 if (finfo1.basic_info.out.create_time !=
1210 finfo2.basic_info.out.create_time) {
1211 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1216 if (finfo1.basic_info.out.access_time !=
1217 finfo2.basic_info.out.access_time) {
1218 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1223 if (finfo1.basic_info.out.write_time !=
1224 finfo2.basic_info.out.write_time) {
1225 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1226 "write time conn 1 = %s, conn 2 = %s",
1227 nt_time_string(tctx, finfo1.basic_info.out.write_time),
1228 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1233 if (finfo1.basic_info.out.change_time !=
1234 finfo2.basic_info.out.change_time) {
1235 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1240 /* One of the two following calls updates the qpathinfo. */
1242 /* If you had skipped the smbcli_write on fnum2, it would
1243 * *not* have updated the stat on disk */
1245 smbcli_close(cli2->tree, fnum2);
1248 /* This call is only for the people looking at ethereal :-) */
1249 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1250 finfo2.basic_info.in.file.path = fname;
1252 status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1254 if (!NT_STATUS_IS_OK(status)) {
1255 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1262 smbcli_close(cli->tree, fnum1);
1263 smbcli_unlink(cli->tree, fname);
1264 smbcli_deltree(cli->tree, BASEDIR);
1269 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1270 uint64_t r = 10*1000*1000; \
1271 NTTIME g = (given).basic_info.out.write_time; \
1272 NTTIME gr = (g / r) * r; \
1273 NTTIME c = (correct).basic_info.out.write_time; \
1274 NTTIME cr = (c / r) * r; \
1275 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1277 if (strict && (g cmp c)) { \
1279 } else if ((g cmp c) && (gr cmp cr)) { \
1280 /* handle filesystem without high resolution timestamps */ \
1284 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1285 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1286 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1291 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1292 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1293 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1294 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1295 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1296 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1298 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1299 NTTIME g = (given).basic_info.out.access_time; \
1300 NTTIME c = (correct).basic_info.out.access_time; \
1302 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1303 #given, nt_time_string(tctx, g), \
1304 #cmp, #correct, nt_time_string(tctx, c)); \
1309 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1310 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1312 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1313 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1314 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1317 #define GET_INFO_FILE(finfo) do { \
1318 struct timeval atv; \
1319 struct timeval wtv; \
1320 struct timeval_buf atvb; \
1321 struct timeval_buf wtvb; \
1323 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1324 if (!NT_STATUS_IS_OK(_status)) { \
1326 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1327 nt_errstr(_status)); \
1330 nttime_to_timeval(&atv, finfo.basic_info.out.access_time); \
1331 nttime_to_timeval(&wtv, finfo.basic_info.out.write_time); \
1332 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1333 timeval_str_buf(&atv, false, true, &atvb), \
1334 timeval_str_buf(&wtv, false, true, &wtvb)); \
1336 #define GET_INFO_FILE2(finfo) do { \
1338 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1339 if (!NT_STATUS_IS_OK(_status)) { \
1341 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1342 nt_errstr(_status)); \
1345 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1346 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1347 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1349 #define GET_INFO_PATH(pinfo) do { \
1351 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1352 if (!NT_STATUS_IS_OK(_status)) { \
1353 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1354 nt_errstr(_status)); \
1358 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1359 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1360 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1362 #define GET_INFO_BOTH(finfo,pinfo) do { \
1363 GET_INFO_FILE(finfo); \
1364 GET_INFO_PATH(pinfo); \
1365 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1368 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1370 union smb_setfileinfo sfinfo; \
1371 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1372 sfinfo.basic_info.in.file.fnum = tfnum; \
1373 sfinfo.basic_info.in.create_time = 0; \
1374 sfinfo.basic_info.in.access_time = 0; \
1375 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1376 sfinfo.basic_info.in.change_time = 0; \
1377 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1378 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1379 if (!NT_STATUS_IS_OK(_status)) { \
1380 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1381 nt_errstr(_status)); \
1386 #define SET_INFO_FILE(finfo, wrtime) \
1387 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1389 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1391 union smb_setfileinfo sfinfo; \
1392 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1393 sfinfo.basic_info.in.file.fnum = tfnum; \
1394 sfinfo.basic_info.in.create_time = 0; \
1395 sfinfo.basic_info.in.access_time = 0; \
1396 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1397 sfinfo.basic_info.in.write_time += (ns); \
1398 sfinfo.basic_info.in.change_time = 0; \
1399 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1400 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1401 if (!NT_STATUS_IS_OK(_status)) { \
1402 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1403 nt_errstr(_status)); \
1409 static bool test_delayed_write_update3(struct torture_context *tctx,
1410 struct smbcli_state *cli,
1411 struct smbcli_state *cli2)
1413 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1414 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1415 const char *fname = BASEDIR "\\torture_file3.txt";
1419 struct timeval start;
1421 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1422 //double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 1000000);
1423 //int normal_delay = 1000000;
1424 int normal_delay = 2000000;
1425 double sec = ((double)used_delay) / ((double)normal_delay);
1426 int msec = 1000 * sec;
1428 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
1430 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1432 torture_comment(tctx, "Open the file handle\n");
1433 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1436 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1440 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1441 finfo0.basic_info.in.file.fnum = fnum1;
1445 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1446 pinfo0.basic_info.in.file.path = fname;
1452 /* get the initial times */
1453 GET_INFO_BOTH(finfo0,pinfo0);
1456 * make sure the write time is updated 2 seconds later
1457 * calcuated from the first write
1458 * (but expect upto 5 seconds extra time for a busy server)
1460 start = timeval_current();
1461 end = timeval_add(&start, 7 * sec, 0);
1462 while (!timeval_expired(&end)) {
1464 torture_comment(tctx, "Do a write on the file handle\n");
1465 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1467 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1471 /* get the times after the write */
1472 GET_INFO_FILE(finfo1);
1474 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1475 double diff = timeval_elapsed(&start);
1476 if (diff < (used_delay / (double)1000000)) {
1477 torture_result(tctx, TORTURE_FAIL, "111Server updated write_time after %.2f seconds "
1478 "(write time update delay == %.2f) (wrong!)\n",
1479 diff, used_delay / (double)1000000);
1484 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1489 smb_msleep(0.5 * msec);
1492 GET_INFO_BOTH(finfo1,pinfo1);
1493 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1495 /* sure any further write doesn't update the write time */
1496 start = timeval_current();
1497 end = timeval_add(&start, 15 * sec, 0);
1498 while (!timeval_expired(&end)) {
1500 torture_comment(tctx, "Do a write on the file handle\n");
1501 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1503 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1507 /* get the times after the write */
1508 GET_INFO_BOTH(finfo2,pinfo2);
1510 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1511 double diff = timeval_elapsed(&start);
1512 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1518 smb_msleep(1 * msec);
1521 GET_INFO_BOTH(finfo2,pinfo2);
1522 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1523 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1524 torture_comment(tctx, "Server did not update write_time (correct)\n");
1528 smb_msleep(5 * msec);
1530 GET_INFO_BOTH(finfo3,pinfo3);
1531 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1534 * the close updates the write time to the time of the close
1535 * and not to the time of the last write!
1537 torture_comment(tctx, "Close the file handle\n");
1538 smbcli_close(cli->tree, fnum1);
1541 GET_INFO_PATH(pinfo4);
1542 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1544 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1545 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1550 smbcli_close(cli->tree, fnum1);
1551 smbcli_unlink(cli->tree, fname);
1552 smbcli_deltree(cli->tree, BASEDIR);
1558 * Show that a truncate write always updates the write time even
1559 * if an initial write has already updated the write time.
1562 static bool test_delayed_write_update3a(struct torture_context *tctx,
1563 struct smbcli_state *cli,
1564 struct smbcli_state *cli2)
1566 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1567 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1568 const char *fname = BASEDIR "\\torture_file3a.txt";
1573 struct timeval start;
1575 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1576 int normal_delay = 2000000;
1577 double sec = ((double)used_delay) / ((double)normal_delay);
1578 int msec = 1000 * sec;
1580 torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
1582 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1584 torture_comment(tctx, "Open the file handle\n");
1585 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1588 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1592 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1593 finfo0.basic_info.in.file.fnum = fnum1;
1597 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1598 pinfo0.basic_info.in.file.path = fname;
1604 /* get the initial times */
1605 GET_INFO_BOTH(finfo0,pinfo0);
1608 * sleep some time, to demonstrate the handling of write times
1609 * doesn't depend on the time since the open
1611 smb_msleep(5 * msec);
1613 /* get the initial times */
1614 GET_INFO_BOTH(finfo1,pinfo1);
1615 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1618 * make sure the write time is updated 2 seconds later
1619 * calcuated from the first write
1620 * (but expect upto 5 seconds extra time for a busy server)
1622 start = timeval_current();
1623 end = timeval_add(&start, 7 * sec, 0);
1624 while (!timeval_expired(&end)) {
1626 torture_comment(tctx, "Do a write on the file handle\n");
1627 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1629 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1633 /* get the times after the write */
1634 GET_INFO_FILE(finfo1);
1636 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1637 double diff = timeval_elapsed(&start);
1638 if (diff < (used_delay / (double)1000000)) {
1639 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1640 "(1sec == %.2f) (wrong!)\n",
1646 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1651 smb_msleep(0.5 * msec);
1654 GET_INFO_BOTH(finfo1,pinfo1);
1655 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1657 smb_msleep(3 * msec);
1660 * demonstrate that a truncate write always
1661 * updates the write time immediately
1663 for (i=0; i < 3; i++) {
1664 smb_msleep(2 * msec);
1666 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1667 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1669 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1673 /* get the times after the write */
1674 GET_INFO_BOTH(finfo2,pinfo2);
1675 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1679 smb_msleep(3 * msec);
1681 /* sure any further write doesn't update the write time */
1682 start = timeval_current();
1683 end = timeval_add(&start, 15 * sec, 0);
1684 while (!timeval_expired(&end)) {
1686 torture_comment(tctx, "Do a write on the file handle\n");
1687 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1689 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1693 /* get the times after the write */
1694 GET_INFO_BOTH(finfo2,pinfo2);
1696 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1697 double diff = timeval_elapsed(&start);
1698 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1704 smb_msleep(1 * msec);
1707 GET_INFO_BOTH(finfo2,pinfo2);
1708 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1709 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1710 torture_comment(tctx, "Server did not update write_time (correct)\n");
1714 smb_msleep(3 * msec);
1716 /* get the initial times */
1717 GET_INFO_BOTH(finfo1,pinfo1);
1718 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1721 * demonstrate that a truncate write always
1722 * updates the write time immediately
1724 for (i=0; i < 3; i++) {
1725 smb_msleep(2 * msec);
1727 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1728 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1730 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1734 /* get the times after the write */
1735 GET_INFO_BOTH(finfo2,pinfo2);
1736 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1741 smb_msleep(3 * msec);
1743 GET_INFO_BOTH(finfo3,pinfo3);
1744 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1747 * the close doesn't update the write time
1749 torture_comment(tctx, "Close the file handle\n");
1750 smbcli_close(cli->tree, fnum1);
1753 GET_INFO_PATH(pinfo4);
1754 COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1756 if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1757 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1762 smbcli_close(cli->tree, fnum1);
1763 smbcli_unlink(cli->tree, fname);
1764 smbcli_deltree(cli->tree, BASEDIR);
1770 * Show a close after write updates the write timestamp to
1771 * the close time, not the last write time.
1774 static bool test_delayed_write_update3b(struct torture_context *tctx,
1775 struct smbcli_state *cli,
1776 struct smbcli_state *cli2)
1778 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1779 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1780 const char *fname = BASEDIR "\\torture_file3b.txt";
1784 struct timeval start;
1786 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1787 int normal_delay = 2000000;
1788 double sec = ((double)used_delay) / ((double)normal_delay);
1789 int msec = 1000 * sec;
1791 torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
1793 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1795 torture_comment(tctx, "Open the file handle\n");
1796 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1799 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1803 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1804 finfo0.basic_info.in.file.fnum = fnum1;
1808 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1809 pinfo0.basic_info.in.file.path = fname;
1815 /* get the initial times */
1816 GET_INFO_BOTH(finfo0,pinfo0);
1819 * sleep some time, to demonstrate the handling of write times
1820 * doesn't depend on the time since the open
1822 smb_msleep(5 * msec);
1824 /* get the initial times */
1825 GET_INFO_BOTH(finfo1,pinfo1);
1826 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1829 * make sure the write time is updated 2 seconds later
1830 * calcuated from the first write
1831 * (but expect upto 5 seconds extra time for a busy server)
1833 start = timeval_current();
1834 end = timeval_add(&start, 7 * sec, 0);
1835 while (!timeval_expired(&end)) {
1837 torture_comment(tctx, "Do a write on the file handle\n");
1838 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1840 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1844 /* get the times after the write */
1845 GET_INFO_FILE(finfo1);
1847 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1848 double diff = timeval_elapsed(&start);
1849 if (diff < (used_delay / (double)1000000)) {
1850 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1851 "(expected > %.2f) (wrong!)\n",
1852 diff, used_delay / (double)1000000);
1857 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1858 "(write time update delay == %.2f) (correct)\n",
1859 diff, used_delay / (double)1000000);
1862 smb_msleep(0.5 * msec);
1865 GET_INFO_BOTH(finfo1,pinfo1);
1866 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1868 /* sure any further write doesn't update the write time */
1869 start = timeval_current();
1870 end = timeval_add(&start, 15 * sec, 0);
1871 while (!timeval_expired(&end)) {
1873 torture_comment(tctx, "Do a write on the file handle\n");
1874 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1876 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1880 /* get the times after the write */
1881 GET_INFO_BOTH(finfo2,pinfo2);
1883 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1884 double diff = timeval_elapsed(&start);
1885 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1891 smb_msleep(1 * msec);
1894 GET_INFO_BOTH(finfo2,pinfo2);
1895 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1896 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1897 torture_comment(tctx, "Server did not update write_time (correct)\n");
1901 smb_msleep(5 * msec);
1903 GET_INFO_BOTH(finfo3,pinfo3);
1904 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1907 * the close updates the write time to the time of the close
1908 * and not to the time of the last write!
1910 torture_comment(tctx, "Close the file handle\n");
1911 smbcli_close(cli->tree, fnum1);
1914 GET_INFO_PATH(pinfo4);
1915 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1917 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1918 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1923 smbcli_close(cli->tree, fnum1);
1924 smbcli_unlink(cli->tree, fname);
1925 smbcli_deltree(cli->tree, BASEDIR);
1931 * Check that a write after a truncate write doesn't update
1932 * the timestamp, but a truncate write after a write does.
1933 * Also prove that a close after a truncate write updates the
1934 * timestamp to current, not the time of last write.
1937 static bool test_delayed_write_update3c(struct torture_context *tctx,
1938 struct smbcli_state *cli,
1939 struct smbcli_state *cli2)
1941 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1942 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1943 const char *fname = BASEDIR "\\torture_file3c.txt";
1948 struct timeval start;
1950 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1951 int normal_delay = 2000000;
1952 double sec = ((double)used_delay) / ((double)normal_delay);
1953 int msec = 1000 * sec;
1955 torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
1957 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1959 torture_comment(tctx, "Open the file handle\n");
1960 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1963 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1967 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1968 finfo0.basic_info.in.file.fnum = fnum1;
1972 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1973 pinfo0.basic_info.in.file.path = fname;
1979 /* get the initial times */
1980 GET_INFO_BOTH(finfo0,pinfo0);
1983 * sleep some time, to demonstrate the handling of write times
1984 * doesn't depend on the time since the open
1986 smb_msleep(5 * msec);
1988 /* get the initial times */
1989 GET_INFO_BOTH(finfo1,pinfo1);
1990 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1993 * demonstrate that a truncate write always
1994 * updates the write time immediately
1996 for (i=0; i < 3; i++) {
1997 smb_msleep(2 * msec);
1999 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
2000 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2002 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2006 /* get the times after the write */
2007 GET_INFO_BOTH(finfo2,pinfo2);
2008 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2012 start = timeval_current();
2013 end = timeval_add(&start, 7 * sec, 0);
2014 while (!timeval_expired(&end)) {
2016 torture_comment(tctx, "Do a write on the file handle\n");
2017 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2019 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2023 /* get the times after the write */
2024 GET_INFO_FILE(finfo2);
2026 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2027 double diff = timeval_elapsed(&start);
2028 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2034 smb_msleep(1 * msec);
2037 GET_INFO_BOTH(finfo2,pinfo2);
2038 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2039 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2040 torture_comment(tctx, "Server did not update write_time (correct)\n");
2044 smb_msleep(5 * msec);
2046 /* get the initial times */
2047 GET_INFO_BOTH(finfo1,pinfo1);
2048 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2051 * demonstrate that a truncate write always
2052 * updates the write time immediately
2054 for (i=0; i < 3; i++) {
2055 smb_msleep(2 * msec);
2057 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2058 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2060 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2064 /* get the times after the write */
2065 GET_INFO_BOTH(finfo2,pinfo2);
2066 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2071 smb_msleep(5 * msec);
2073 GET_INFO_BOTH(finfo2,pinfo2);
2074 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2076 /* sure any further write doesn't update the write time */
2077 start = timeval_current();
2078 end = timeval_add(&start, 15 * sec, 0);
2079 while (!timeval_expired(&end)) {
2081 torture_comment(tctx, "Do a write on the file handle\n");
2082 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2084 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2088 /* get the times after the write */
2089 GET_INFO_BOTH(finfo2,pinfo2);
2091 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2092 double diff = timeval_elapsed(&start);
2093 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2099 smb_msleep(1 * msec);
2102 GET_INFO_BOTH(finfo2,pinfo2);
2103 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2104 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2105 torture_comment(tctx, "Server did not update write_time (correct)\n");
2109 smb_msleep(5 * msec);
2111 GET_INFO_BOTH(finfo3,pinfo3);
2112 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2115 * the close updates the write time to the time of the close
2116 * and not to the time of the last write!
2118 torture_comment(tctx, "Close the file handle\n");
2119 smbcli_close(cli->tree, fnum1);
2122 GET_INFO_PATH(pinfo4);
2123 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2125 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2126 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2131 smbcli_close(cli->tree, fnum1);
2132 smbcli_unlink(cli->tree, fname);
2133 smbcli_deltree(cli->tree, BASEDIR);
2139 * Show only the first write updates the timestamp, and a close
2140 * after writes updates to current (I think this is the same
2144 static bool test_delayed_write_update4(struct torture_context *tctx,
2145 struct smbcli_state *cli,
2146 struct smbcli_state *cli2)
2148 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
2149 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
2150 const char *fname = BASEDIR "\\torture_file4.txt";
2154 struct timeval start;
2156 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2157 int normal_delay = 2000000;
2158 double sec = ((double)used_delay) / ((double)normal_delay);
2159 int msec = 1000 * sec;
2161 torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2163 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2165 torture_comment(tctx, "Open the file handle\n");
2166 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2169 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2173 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2174 finfo0.basic_info.in.file.fnum = fnum1;
2178 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2179 pinfo0.basic_info.in.file.path = fname;
2185 /* get the initial times */
2186 GET_INFO_BOTH(finfo0,pinfo0);
2189 smb_msleep(5 * msec);
2192 torture_comment(tctx, "Do a write on the file handle\n");
2193 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2195 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2200 GET_INFO_BOTH(finfo1,pinfo1);
2201 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2204 * make sure the write time is updated 2 seconds later
2205 * calcuated from the first write
2206 * (but expect upto 3 seconds extra time for a busy server)
2208 start = timeval_current();
2209 end = timeval_add(&start, 5 * sec, 0);
2210 while (!timeval_expired(&end)) {
2211 /* get the times after the first write */
2212 GET_INFO_FILE(finfo1);
2214 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2215 double diff = timeval_elapsed(&start);
2216 if (diff < (used_delay / (double)1000000)) {
2217 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
2218 "(expected > %.2f) (wrong!)\n",
2219 diff, used_delay / (double)1000000);
2224 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2225 "(write time update delay == %.2f) (correct)\n",
2226 diff, used_delay / (double)1000000);
2229 smb_msleep(0.5 * msec);
2232 GET_INFO_BOTH(finfo1,pinfo1);
2233 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2235 /* sure any further write doesn't update the write time */
2236 start = timeval_current();
2237 end = timeval_add(&start, 15 * sec, 0);
2238 while (!timeval_expired(&end)) {
2240 torture_comment(tctx, "Do a write on the file handle\n");
2241 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2243 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2247 /* get the times after the write */
2248 GET_INFO_BOTH(finfo2,pinfo2);
2250 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2251 double diff = timeval_elapsed(&start);
2252 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2258 smb_msleep(1 * msec);
2261 GET_INFO_BOTH(finfo2,pinfo2);
2262 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2263 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2264 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2268 smb_msleep(5 * msec);
2270 GET_INFO_BOTH(finfo3,pinfo3);
2271 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2274 * the close updates the write time to the time of the close
2275 * and not to the time of the last write!
2277 torture_comment(tctx, "Close the file handle\n");
2278 smbcli_close(cli->tree, fnum1);
2281 GET_INFO_PATH(pinfo4);
2282 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2284 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2285 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2290 smbcli_close(cli->tree, fnum1);
2291 smbcli_unlink(cli->tree, fname);
2292 smbcli_deltree(cli->tree, BASEDIR);
2298 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2301 static bool test_delayed_write_update5(struct torture_context *tctx,
2302 struct smbcli_state *cli,
2303 struct smbcli_state *cli2)
2305 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2306 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2307 const char *fname = BASEDIR "\\torture_file5.txt";
2311 struct timeval start;
2313 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2314 int normal_delay = 2000000;
2315 double sec = ((double)used_delay) / ((double)normal_delay);
2316 int msec = 1000 * sec;
2318 torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2320 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2322 torture_comment(tctx, "Open the file handle\n");
2323 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2326 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2330 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2331 finfo0.basic_info.in.file.fnum = fnum1;
2337 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2338 pinfo0.basic_info.in.file.path = fname;
2346 /* get the initial times */
2347 GET_INFO_BOTH(finfo0,pinfo0);
2350 torture_comment(tctx, "Do a write on the file handle\n");
2351 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2353 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2358 GET_INFO_BOTH(finfo1,pinfo1);
2359 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2361 torture_comment(tctx, "Set write time in the future on the file handle\n");
2362 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2363 GET_INFO_BOTH(finfo2,pinfo2);
2364 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2366 torture_comment(tctx, "Set write time in the past on the file handle\n");
2367 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2368 GET_INFO_BOTH(finfo2,pinfo2);
2369 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2371 /* make sure the 2 second delay from the first write are canceled */
2372 start = timeval_current();
2373 end = timeval_add(&start, 15 * sec, 0);
2374 while (!timeval_expired(&end)) {
2376 /* get the times after the first write */
2377 GET_INFO_BOTH(finfo3,pinfo3);
2379 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2380 double diff = timeval_elapsed(&start);
2381 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2387 smb_msleep(1 * msec);
2390 GET_INFO_BOTH(finfo3,pinfo3);
2391 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2392 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2393 torture_comment(tctx, "Server did not update write_time (correct)\n");
2396 /* sure any further write doesn't update the write time */
2397 start = timeval_current();
2398 end = timeval_add(&start, 15 * sec, 0);
2399 while (!timeval_expired(&end)) {
2401 torture_comment(tctx, "Do a write on the file handle\n");
2402 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2404 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2408 /* get the times after the write */
2409 GET_INFO_BOTH(finfo4,pinfo4);
2411 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2412 double diff = timeval_elapsed(&start);
2413 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2419 smb_msleep(1 * msec);
2422 GET_INFO_BOTH(finfo4,pinfo4);
2423 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2424 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2425 torture_comment(tctx, "Server did not update write_time (correct)\n");
2429 smb_msleep(5 * msec);
2431 GET_INFO_BOTH(finfo5,pinfo5);
2432 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2435 * the close doesn't update the write time
2437 torture_comment(tctx, "Close the file handle\n");
2438 smbcli_close(cli->tree, fnum1);
2441 GET_INFO_PATH(pinfo6);
2442 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2444 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2445 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2450 smbcli_close(cli->tree, fnum1);
2451 smbcli_unlink(cli->tree, fname);
2452 smbcli_deltree(cli->tree, BASEDIR);
2458 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2461 static bool test_delayed_write_update5b(struct torture_context *tctx,
2462 struct smbcli_state *cli,
2463 struct smbcli_state *cli2)
2465 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2466 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2467 const char *fname = BASEDIR "\\torture_fileb.txt";
2471 struct timeval start;
2473 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2474 int normal_delay = 2000000;
2475 double sec = ((double)used_delay) / ((double)normal_delay);
2476 int msec = 1000 * sec;
2478 torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2480 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2482 torture_comment(tctx, "Open the file handle\n");
2483 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2486 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2490 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2491 finfo0.basic_info.in.file.fnum = fnum1;
2497 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2498 pinfo0.basic_info.in.file.path = fname;
2506 /* get the initial times */
2507 GET_INFO_BOTH(finfo0,pinfo0);
2510 torture_comment(tctx, "Do a write on the file handle\n");
2511 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2513 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2518 GET_INFO_BOTH(finfo1,pinfo1);
2519 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2521 torture_comment(tctx, "Set write time in the future on the file handle\n");
2522 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2523 GET_INFO_BOTH(finfo2,pinfo2);
2524 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2526 torture_comment(tctx, "Set write time in the past on the file handle\n");
2527 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2528 GET_INFO_BOTH(finfo2,pinfo2);
2529 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2531 /* make sure the 2 second delay from the first write are canceled */
2532 start = timeval_current();
2533 end = timeval_add(&start, 15 * sec, 0);
2534 while (!timeval_expired(&end)) {
2536 /* get the times after the first write */
2537 GET_INFO_BOTH(finfo3,pinfo3);
2539 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2540 double diff = timeval_elapsed(&start);
2541 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2547 smb_msleep(1 * msec);
2550 GET_INFO_BOTH(finfo3,pinfo3);
2551 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2552 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2553 torture_comment(tctx, "Server did not update write_time (correct)\n");
2556 /* Do any further write (truncates) update the write time ? */
2557 start = timeval_current();
2558 end = timeval_add(&start, 15 * sec, 0);
2559 while (!timeval_expired(&end)) {
2561 torture_comment(tctx, "Do a truncate write on the file handle\n");
2562 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2564 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2568 /* get the times after the write */
2569 GET_INFO_BOTH(finfo4,pinfo4);
2571 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2572 double diff = timeval_elapsed(&start);
2573 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2579 smb_msleep(1 * msec);
2582 GET_INFO_BOTH(finfo4,pinfo4);
2583 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2584 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2585 torture_comment(tctx, "Server did not update write_time (correct)\n");
2589 smb_msleep(5 * msec);
2591 GET_INFO_BOTH(finfo5,pinfo5);
2592 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2595 * the close doesn't update the write time
2597 torture_comment(tctx, "Close the file handle\n");
2598 smbcli_close(cli->tree, fnum1);
2601 GET_INFO_PATH(pinfo6);
2602 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2604 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2605 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2610 smbcli_close(cli->tree, fnum1);
2611 smbcli_unlink(cli->tree, fname);
2612 smbcli_deltree(cli->tree, BASEDIR);
2618 * Open 2 handles on a file. Write one one and then set the
2619 * WRITE TIME explicitly on the other. Ensure the write time
2620 * update is cancelled. Ensure the write time is updated to
2621 * the close time when the non-explicit set handle is closed.
2625 static bool test_delayed_write_update6(struct torture_context *tctx,
2626 struct smbcli_state *cli,
2627 struct smbcli_state *cli2)
2629 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2630 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2631 const char *fname = BASEDIR "\\torture_file6.txt";
2636 struct timeval start;
2638 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2639 int normal_delay = 2000000;
2640 double sec = ((double)used_delay) / ((double)normal_delay);
2641 int msec = 1000 * sec;
2644 torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2646 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2648 torture_comment(tctx, "Open the file handle\n");
2649 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2652 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2657 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2658 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2661 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2666 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2667 finfo0.basic_info.in.file.fnum = fnum1;
2673 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2674 pinfo0.basic_info.in.file.path = fname;
2683 /* get the initial times */
2684 GET_INFO_BOTH(finfo0,pinfo0);
2687 torture_comment(tctx, "Do a write on the file handle\n");
2688 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2690 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2695 GET_INFO_BOTH(finfo1,pinfo1);
2696 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2698 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2699 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2700 GET_INFO_BOTH(finfo2,pinfo2);
2701 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2703 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2704 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2705 GET_INFO_BOTH(finfo2,pinfo2);
2706 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2708 /* make sure the 2 second delay from the first write are canceled */
2709 start = timeval_current();
2710 end = timeval_add(&start, 10 * sec, 0);
2711 while (!timeval_expired(&end)) {
2713 /* get the times after the first write */
2714 GET_INFO_BOTH(finfo3,pinfo3);
2716 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2717 double diff = timeval_elapsed(&start);
2718 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2724 smb_msleep(1 * msec);
2727 GET_INFO_BOTH(finfo3,pinfo3);
2728 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2729 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2730 torture_comment(tctx, "Server did not update write_time (correct)\n");
2733 /* sure any further write doesn't update the write time */
2734 start = timeval_current();
2735 end = timeval_add(&start, 10 * sec, 0);
2736 while (!timeval_expired(&end)) {
2738 torture_comment(tctx, "Do a write on the file handle\n");
2739 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2741 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2745 /* get the times after the write */
2746 GET_INFO_BOTH(finfo4,pinfo4);
2748 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2749 double diff = timeval_elapsed(&start);
2750 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2756 smb_msleep(1 * msec);
2759 GET_INFO_BOTH(finfo4,pinfo4);
2760 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2761 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2762 torture_comment(tctx, "Server did not update write_time (correct)\n");
2766 smb_msleep(5 * msec);
2768 GET_INFO_BOTH(finfo5,pinfo5);
2769 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2772 * the close updates the write time to the time of the close
2773 * as the write time was set on the 2nd handle
2775 torture_comment(tctx, "Close the file handle\n");
2776 smbcli_close(cli->tree, fnum1);
2779 GET_INFO_PATH(pinfo6);
2780 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2782 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2783 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2786 /* See what the second write handle thinks the time is ? */
2787 finfo5.basic_info.in.file.fnum = fnum2;
2788 GET_INFO_FILE2(finfo5);
2789 COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
2791 /* See if we have lost the sticky write time on handle2 */
2792 smb_msleep(3 * msec);
2793 torture_comment(tctx, "Have we lost the sticky write time ?\n");
2795 /* Make sure any further normal write doesn't update the write time */
2796 start = timeval_current();
2797 end = timeval_add(&start, 10 * sec, 0);
2798 while (!timeval_expired(&end)) {
2800 torture_comment(tctx, "Do a write on the second file handle\n");
2801 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
2803 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2807 /* get the times after the write */
2808 GET_INFO_FILE2(finfo5);
2809 GET_INFO_PATH(pinfo6);
2811 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2812 double diff = timeval_elapsed(&start);
2813 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2819 smb_msleep(1 * msec);
2822 /* What about a truncate write ? */
2823 start = timeval_current();
2824 end = timeval_add(&start, 10 * sec, 0);
2825 while (!timeval_expired(&end)) {
2827 torture_comment(tctx, "Do a truncate write on the second file handle\n");
2828 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
2830 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2834 /* get the times after the write */
2835 GET_INFO_FILE2(finfo5);
2836 GET_INFO_PATH(pinfo6);
2838 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2839 double diff = timeval_elapsed(&start);
2840 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2846 smb_msleep(1 * msec);
2850 /* keep the 2nd handle open and rerun tests */
2857 * closing the 2nd handle will cause no write time update
2858 * as the write time was explicit set on this handle
2860 torture_comment(tctx, "Close the 2nd file handle\n");
2861 smbcli_close(cli2->tree, fnum2);
2864 GET_INFO_PATH(pinfo7);
2865 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2867 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2868 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2873 smbcli_close(cli->tree, fnum1);
2875 smbcli_close(cli2->tree, fnum2);
2876 smbcli_unlink(cli->tree, fname);
2877 smbcli_deltree(cli->tree, BASEDIR);
2882 static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
2884 union smb_open open_parms;
2885 union smb_fileinfo finfo1, finfo2, finfo3;
2886 const char *fname = BASEDIR "\\torture_file7.txt";
2890 TALLOC_CTX *mem_ctx;
2892 torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2894 mem_ctx = talloc_init("test_delayed_write_update7");
2895 if (!mem_ctx) return false;
2897 ZERO_STRUCT(finfo1);
2898 ZERO_STRUCT(finfo2);
2899 ZERO_STRUCT(finfo3);
2900 ZERO_STRUCT(open_parms);
2902 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2904 /* Create the file. */
2905 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2907 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
2911 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2912 finfo1.basic_info.in.file.fnum = fnum1;
2916 /* Get the initial timestamps. */
2917 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
2919 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2921 /* Set the pending write time to a value with ns. */
2922 SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
2924 /* Get the current pending write time by fnum. */
2925 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
2927 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2929 /* Ensure the time is actually different. */
2930 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2931 torture_result(tctx, TORTURE_FAIL,
2932 "setfileinfo time matches original fileinfo time");
2936 /* Get the current pending write time by path. */
2937 finfo3.basic_info.in.file.path = fname;
2938 status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
2940 if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
2941 torture_result(tctx, TORTURE_FAIL,
2942 "qpathinfo time doesn't match fileinfo time");
2946 /* Now close the file. Re-open and check that the write
2947 time is identical to the one we wrote. */
2949 smbcli_close(cli->tree, fnum1);
2951 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
2952 open_parms.ntcreatex.in.flags = 0;
2953 open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
2954 open_parms.ntcreatex.in.file_attr = 0;
2955 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
2956 NTCREATEX_SHARE_ACCESS_READ|
2957 NTCREATEX_SHARE_ACCESS_WRITE;
2958 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
2959 open_parms.ntcreatex.in.create_options = 0;
2960 open_parms.ntcreatex.in.fname = fname;
2962 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
2963 talloc_free(mem_ctx);
2965 if (!NT_STATUS_IS_OK(status)) {
2966 torture_result(tctx, TORTURE_FAIL,
2967 "setfileinfo time matches original fileinfo time");
2971 fnum1 = open_parms.ntcreatex.out.file.fnum;
2973 /* Check the returned time matches. */
2974 if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
2975 torture_result(tctx, TORTURE_FAIL,
2976 "final open time does not match set time");
2982 smbcli_close(cli->tree, fnum1);
2984 smbcli_unlink(cli->tree, fname);
2985 smbcli_deltree(cli->tree, BASEDIR);
2990 Test if creating a file in a directory with an open handle updates the
2991 write timestamp (it should).
2993 static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
2995 union smb_fileinfo dir_info1, dir_info2;
2996 union smb_open open_parms;
2997 const char *fname = BASEDIR "\\torture_file.txt";
3002 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3003 int normal_delay = 2000000;
3004 double sec = ((double)used_delay) / ((double)normal_delay);
3005 int msec = 1000 * sec;
3006 TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
3008 if (!mem_ctx) return false;
3010 torture_comment(tctx, "\nRunning test directory write update\n");
3012 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
3014 /* Open a handle on the directory - and leave it open. */
3015 ZERO_STRUCT(open_parms);
3016 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3017 open_parms.ntcreatex.in.flags = 0;
3018 open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
3019 open_parms.ntcreatex.in.file_attr = 0;
3020 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3021 NTCREATEX_SHARE_ACCESS_READ|
3022 NTCREATEX_SHARE_ACCESS_WRITE;
3023 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3024 open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
3025 open_parms.ntcreatex.in.fname = BASEDIR;
3027 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3028 talloc_free(mem_ctx);
3030 if (!NT_STATUS_IS_OK(status)) {
3031 torture_result(tctx, TORTURE_FAIL,
3032 "failed to open directory handle");
3037 fnum1 = open_parms.ntcreatex.out.file.fnum;
3039 /* Store the returned write time. */
3040 ZERO_STRUCT(dir_info1);
3041 dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
3043 torture_comment(tctx, "Initial write time %s\n",
3044 nt_time_string(tctx, dir_info1.basic_info.out.write_time));
3047 smb_msleep(3 * msec);
3049 /* Now create a file within the directory. */
3050 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3052 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
3056 smbcli_close(cli->tree, fnum2);
3058 /* Read the directory write time again. */
3059 ZERO_STRUCT(dir_info2);
3060 dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3061 dir_info2.basic_info.in.file.fnum = fnum1;
3063 status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
3065 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
3067 /* Ensure it's been incremented. */
3068 COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
3070 torture_comment(tctx, "Updated write time %s\n",
3071 nt_time_string(tctx, dir_info2.basic_info.out.write_time));
3076 smbcli_close(cli->tree, fnum1);
3077 smbcli_unlink(cli->tree, fname);
3078 smbcli_deltree(cli->tree, BASEDIR);
3083 #undef COMPARE_WRITE_TIME_CMP
3084 #undef COMPARE_ACCESS_TIME_CMP
3086 #define COMPARE_TIME_CMP(given, gelem, correct, celem, cmp) do { \
3087 const uint64_t _r = 10*1000*1000; \
3088 NTTIME _g = (given).basic_info.out.gelem; \
3089 NTTIME _gr = (_g / _r) * _r; \
3090 NTTIME _c = (correct).basic_info.out.celem; \
3091 NTTIME _cr = (_c / _r) * _r; \
3092 bool _strict = torture_setting_bool(tctx, "strict mode", false); \
3093 const char *_err = NULL; \
3094 if (_strict && (_g cmp _c)) { \
3096 } else if ((_g cmp _c) && (_gr cmp _cr)) { \
3097 /* handle filesystem without high resolution timestamps */ \
3100 if (_err != NULL) { \
3101 struct timeval _gtv; \
3102 struct timeval _ctv; \
3103 struct timeval_buf _gtvb; \
3104 struct timeval_buf _ctvb; \
3105 nttime_to_timeval(&_gtv, _g); \
3106 nttime_to_timeval(&_ctv, _c); \
3107 torture_result(tctx, TORTURE_FAIL, \
3108 __location__": %s wrong (%s.%s)%s %s (%s.%s)%s", \
3111 timeval_str_buf(&_gtv, false, true, &_gtvb), \
3114 timeval_str_buf(&_ctv, false, true, &_ctvb)); \
3119 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
3120 COMPARE_TIME_CMP(given, write_time, correct, write_time, cmp); \
3122 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
3123 COMPARE_WRITE_TIME_CMP(given,correct,!=)
3124 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
3125 COMPARE_WRITE_TIME_CMP(given,correct,<=)
3127 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
3128 COMPARE_TIME_CMP(given, access_time, correct, access_time, cmp); \
3130 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
3131 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
3132 #define COMPARE_ACCESS_TIME_GREATER(given,correct) \
3133 COMPARE_ACCESS_TIME_CMP(given,correct,<=)
3135 #define COMPARE_CHANGE_TIME_CMP(given, correct, cmp) do { \
3136 COMPARE_TIME_CMP(given, change_time, correct, change_time, cmp); \
3138 #define COMPARE_CHANGE_TIME_EQUAL(given,correct) \
3139 COMPARE_CHANGE_TIME_CMP(given,correct,!=)
3140 #define COMPARE_CHANGE_TIME_GREATER(given,correct) \
3141 COMPARE_CHANGE_TIME_CMP(given,correct,<=)
3143 #define COMPARE_CREATE_TIME_CMP(given, correct, cmp) do { \
3144 COMPARE_TIME_CMP(given, create_time, correct, create_time, cmp); \
3146 #define COMPARE_CREATE_TIME_EQUAL(given,correct) \
3147 COMPARE_CREATE_TIME_CMP(given,correct,!=)
3149 #define COMPARE_ALL_TIMES_EQUAL(given,correct) do { \
3150 COMPARE_WRITE_TIME_EQUAL(given,correct); \
3151 COMPARE_CHANGE_TIME_EQUAL(given,correct); \
3152 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
3153 COMPARE_CREATE_TIME_EQUAL(given,correct); \
3156 #define COMPARE_TIMES_AFTER_WRITE(given,correct) do { \
3157 COMPARE_WRITE_TIME_GREATER(given,correct); \
3158 COMPARE_CHANGE_TIME_GREATER(given,correct); \
3159 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
3160 COMPARE_CREATE_TIME_EQUAL(given,correct); \
3161 COMPARE_TIME_CMP(given, change_time, given, write_time, !=); \
3164 struct test_delaywrite_delaywrite1_state {
3165 struct torture_context *tctx;
3166 struct smbcli_state *cli1;
3167 struct smbcli_state *cli2;
3173 static bool test_delaywrite_delaywrite1_get_info(void *private_data,
3174 union smb_fileinfo *finfo)
3176 struct test_delaywrite_delaywrite1_state *state =
3177 (struct test_delaywrite_delaywrite1_state *)private_data;
3178 struct torture_context *tctx = state->tctx;
3179 struct smbcli_state *cli = state->cli1;
3180 struct smbcli_state *cli2 = state->cli2;
3181 union smb_fileinfo t1finfo;
3182 union smb_fileinfo t2finfo;
3185 ZERO_STRUCTP(finfo);
3187 ZERO_STRUCT(t1finfo);
3188 t1finfo.basic_info.level = RAW_FILEINFO_BASIC_INFORMATION;
3189 t1finfo.basic_info.in.file.fnum = state->fnum1;
3191 ZERO_STRUCT(t2finfo);
3192 t2finfo.basic_info.level = RAW_FILEINFO_BASIC_INFORMATION;
3193 t2finfo.basic_info.in.file.fnum = state->fnum2;
3195 GET_INFO_FILE2(t2finfo);
3196 GET_INFO_FILE(t1finfo);
3197 if (t1finfo.basic_info.out.write_time != t2finfo.basic_info.out.write_time) {
3199 * There was a race, get it again on handle 2,
3200 * but then they have to match.
3202 GET_INFO_FILE2(t2finfo);
3204 COMPARE_ALL_TIMES_EQUAL(t1finfo, t2finfo);
3206 finfo->basic_info.out = t1finfo.basic_info.out;
3211 static bool test_delaywrite_delaywrite1_write_data(void *private_data)
3213 struct test_delaywrite_delaywrite1_state *state =
3214 (struct test_delaywrite_delaywrite1_state *)private_data;
3215 struct torture_context *tctx = state->tctx;
3219 nwritten = smbcli_write(state->cli1->tree, state->fnum1, 0, "x", 0, 1);
3220 torture_assert_int_equal_goto(tctx, nwritten, 1,
3221 ret, done, "smbcli_write");
3227 static bool test_delaywrite_delaywrite1_close(void *private_data,
3228 union smb_fileinfo *finfo)
3230 struct test_delaywrite_delaywrite1_state *state =
3231 (struct test_delaywrite_delaywrite1_state *)private_data;
3232 struct torture_context *tctx = state->tctx;
3233 struct smbcli_state *cli2 = state->cli2;
3234 union smb_fileinfo t2finfo;
3235 union smb_fileinfo t2pinfo;
3238 ZERO_STRUCTP(finfo);
3241 * the close updates the write time to the time of the close
3242 * and not to the time of the last write!
3244 torture_comment(tctx, "Close the file handle\n");
3245 smbcli_close(state->cli1->tree, state->fnum1);
3248 ZERO_STRUCT(t2finfo);
3249 t2finfo.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3250 t2finfo.basic_info.in.file.fnum = state->fnum2;
3251 ZERO_STRUCT(t2pinfo);
3252 t2pinfo.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3253 t2pinfo.basic_info.in.file.path = state->fname;
3255 GET_INFO_FILE2(t2finfo);
3257 smbcli_close(state->cli2->tree, state->fnum2);
3260 GET_INFO_PATH(t2pinfo);
3261 COMPARE_ALL_TIMES_EQUAL(t2pinfo, t2finfo);
3263 finfo->basic_info.out = t2pinfo.basic_info.out;
3269 static bool test_delaywrite_delaywrite1(struct torture_context *tctx,
3270 struct smbcli_state *cli,
3271 struct smbcli_state *cli2)
3273 struct test_delaywrite_delaywrite1_state state = {
3280 const char *fname = BASEDIR "\\torture_file3.txt";
3282 //double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3283 //double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 1000000);
3284 double normal_delay = 1000000;
3285 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", normal_delay);
3286 //double normal_delay = 1000000;
3287 //int normal_delay = 2000000;
3290 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
3292 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
3294 torture_comment(tctx, "Open the file handle\n");
3295 state.fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3296 if (state.fnum1 == -1) {
3298 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
3301 state.fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3302 if (state.fnum2 == -1) {
3304 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
3308 state.fname = fname;
3310 ok = test_delay_writetime1(tctx, used_delay, normal_delay,
3311 "run", true, /* smb1 */
3312 test_delaywrite_delaywrite1_get_info,
3313 test_delaywrite_delaywrite1_write_data,
3314 test_delaywrite_delaywrite1_close,
3316 torture_assert_goto(tctx, ok, ret, done, "test_delay_writetime1()");
3319 if (state.fnum1 != -1) {
3320 smbcli_close(cli->tree, state.fnum1);
3322 if (state.fnum2 != -1) {
3323 smbcli_close(cli2->tree, state.fnum2);
3325 smbcli_unlink(cli->tree, fname);
3326 smbcli_deltree(cli->tree, BASEDIR);
3332 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3334 struct smb2_handle _h1;
3335 struct smb2_handle *h1 = NULL;
3336 struct smb2_handle _h2;
3337 struct smb2_handle *h2 = NULL;
3338 struct smb2_create cr1;
3339 struct smb2_create cr2;
3340 union smb_fileinfo c1finfoCR, c1finfo0, c1finfo1, c1finfo2, c1finfoCL;
3341 union smb_fileinfo c2finfoCR, c2finfo0, c2finfo1, c2finfo2, c2finfo3, c2finfoCL;
3342 struct smb2_close cl1;
3343 struct smb2_close cl2;
3344 //double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3345 //double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 1000000);
3346 double normal_delay = 1000000;
3347 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", normal_delay);
3348 //double normal_delay = 1000000;
3349 //int normal_delay = 2000000;
3350 double sec = ((double)used_delay) / ((double)normal_delay);
3351 int msec = 1000 * sec;
3355 /* Choose a random name in case the state is left a little funky. */
3356 snprintf(fname, 256, "durable_open_delaywrite1_%s.dat",
3357 generate_random_str(tctx, 8));
3359 smb2_util_unlink(tree1, fname);
3361 smb2_oplock_create_share(&cr1, fname,
3362 smb2_util_share_access(""),
3363 smb2_util_oplock_level("b"));
3364 cr1.in.durable_open = true;
3366 status = smb2_create(tree1, mem_ctx, &cr1);
3367 CHECK_STATUS(status, NT_STATUS_OK);
3368 _h1 = cr1.out.file.handle;
3370 CHECK_CREATED(&cr1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3371 CHECK_VAL(cr1.out.oplock_level, smb2_util_oplock_level("b"));
3372 CHECK_VAL(cr1.out.durable_open, true);
3373 CHECK_VAL(cr1.out.durable_open_v2, false);
3374 CHECK_VAL(cr1.out.persistent_open, false);
3377 cr2.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
3378 cr2.in.durable_open = false;
3379 cr2.in.oplock_level = 0;
3380 cr2.in.create_disposition = NTCREATEX_DISP_OPEN;
3381 status = smb2_create(tree2, mem_ctx, &cr2);
3382 CHECK_STATUS(status, NT_STATUS_OK);
3383 _h2 = cr2.out.file.handle;
3385 CHECK_CREATED(&cr2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3386 CHECK_VAL(cr2.out.oplock_level, 0);
3387 CHECK_VAL(cr2.out.durable_open, false);
3388 CHECK_VAL(cr2.out.durable_open_v2, false);
3389 CHECK_VAL(cr2.out.persistent_open, false);
3391 ZERO_STRUCT(c1finfoCR);
3392 c1finfoCR.basic_info.out.create_time = cr1.out.create_time;
3393 c1finfoCR.basic_info.out.access_time = cr1.out.access_time;
3394 c1finfoCR.basic_info.out.write_time = cr1.out.write_time;
3395 c1finfoCR.basic_info.out.change_time = cr1.out.change_time;
3396 c1finfoCR.basic_info.out.attrib = cr1.out.file_attr;
3398 ZERO_STRUCT(c2finfoCR);
3399 c2finfoCR.basic_info.out.create_time = cr2.out.create_time;
3400 c2finfoCR.basic_info.out.access_time = cr2.out.access_time;
3401 c2finfoCR.basic_info.out.write_time = cr2.out.write_time;
3402 c2finfoCR.basic_info.out.change_time = cr2.out.change_time;
3403 c2finfoCR.basic_info.out.attrib = cr2.out.file_attr;
3405 COMPARE_ALL_TIMES_EQUAL(c1finfoCR, c2finfoCR);
3407 ZERO_STRUCT(c1finfo0);
3408 c1finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFORMATION;
3409 c1finfo0.basic_info.in.file.handle = *h1;
3410 c1finfo1 = c1finfo0;
3411 c1finfo2 = c1finfo0;
3413 ZERO_STRUCT(c2finfo0);
3414 c2finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFORMATION;
3415 c2finfo0.basic_info.in.file.handle = *h2;
3416 c2finfo1 = c2finfo0;
3417 c2finfo2 = c2finfo0;
3418 c2finfo3 = c2finfo0;
3420 GET_INFO_BOTH(c1finfo0, c2finfo0);
3421 COMPARE_ALL_TIMES_EQUAL(c1finfo0, c1finfoCR);
3426 ok = test_delay_writetime1(tctx, used_delay, normal_delay,
3428 test_delaywrite_delaywrite1_get_info,
3429 test_delaywrite_delaywrite1_write_data,
3431 torture_assert(tctx, ok, "test_delay_writetime1(1)");
3432 ok = test_delay_writetime1(tctx, used_delay, normal_delay,
3434 test_delaywrite_delaywrite1_get_info,
3435 test_delaywrite_delaywrite1_write_data,
3437 torture_assert(tctx, ok, "test_delay_writetime2(2)");
3439 GET_INFO_BOTH(c1finfo1, c2finfo1);
3440 COMPARE_TIMES_AFTER_WRITE(c1finfo1, c1finfo0);
3443 torture_comment(tctx, "Sleep ...\n");
3444 smb_msleep(5 * msec);
3445 torture_comment(tctx, "... continue\n");
3447 GET_INFO_BOTH(c1finfo2, c2finfo2);
3448 COMPARE_ALL_TIMES_EQUAL(c1finfo2, c1finfo1);
3451 * the close updates the write time to the time of the close
3452 * and not to the time of the last write!
3454 torture_comment(tctx, "Close the file handle\n");
3457 cl1.in.file.handle = *h1;
3458 cl1.in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
3459 status = smb2_close(tree1, &cl1);
3460 CHECK_STATUS(status, NT_STATUS_OK);
3462 ZERO_STRUCT(c1finfoCL);
3463 c1finfoCL.basic_info.out.create_time = cl1.out.create_time;
3464 c1finfoCL.basic_info.out.access_time = cl1.out.access_time;
3465 c1finfoCL.basic_info.out.write_time = cl1.out.write_time;
3466 c1finfoCL.basic_info.out.change_time = cl1.out.change_time;
3467 c1finfoCL.basic_info.out.attrib = cl1.out.file_attr;
3468 COMPARE_ALL_TIMES_EQUAL(c1finfoCL, c1finfo2);
3470 GET_INFO_FILE(tree2, c2finfo3);
3471 COMPARE_ALL_TIMES_EQUAL(c2finfo3, c1finfoCL);
3474 cl2.in.file.handle = *h2;
3475 cl2.in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
3476 status = smb2_close(tree2, &cl2);
3477 CHECK_STATUS(status, NT_STATUS_OK);
3479 ZERO_STRUCT(c2finfoCL);
3480 c2finfoCL.basic_info.out.create_time = cl2.out.create_time;
3481 c2finfoCL.basic_info.out.access_time = cl2.out.access_time;
3482 c2finfoCL.basic_info.out.write_time = cl2.out.write_time;
3483 c2finfoCL.basic_info.out.change_time = cl2.out.change_time;
3484 c2finfoCL.basic_info.out.attrib = cl2.out.file_attr;
3485 COMPARE_ALL_TIMES_EQUAL(c2finfoCL, c1finfoCL);
3489 smb2_util_close(tree1, *h1);
3492 smb2_util_close(tree2, *h2);
3495 smb2_util_unlink(tree1, fname);
3500 talloc_free(mem_ctx);
3506 testing of delayed update of write_time
3508 struct torture_suite *torture_delay_write(TALLOC_CTX *ctx)
3510 struct torture_suite *suite = torture_suite_create(ctx, "delaywrite");
3512 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
3513 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
3514 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
3515 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
3516 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
3517 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
3518 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
3519 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
3520 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
3521 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
3522 torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
3523 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
3524 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
3525 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
3526 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
3527 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3528 torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);
3529 torture_suite_add_2smb_test(suite, "delaywrite1", test_delaywrite_delaywrite1);