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 const char *fname = BASEDIR "\\torture_file.txt";
47 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
48 int normal_delay = 2000000;
49 double sec = ((double)used_delay) / ((double)normal_delay);
50 int msec = 1000 * sec;
52 torture_comment(tctx, "\nRunning test_delayed_write_update\n");
54 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
56 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
57 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
58 "Failed to open %s", fname));
60 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
61 finfo1.basic_info.in.file.fnum = fnum1;
64 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
65 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
67 torture_comment(tctx, "Initial write time %s\n",
68 nt_time_string(tctx, finfo1.basic_info.out.write_time));
70 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
71 torture_assert_int_equal(tctx, written, 1,
72 "unexpected number of bytes written");
74 start = timeval_current();
75 end = timeval_add(&start, (120 * sec), 0);
76 while (!timeval_expired(&end)) {
77 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
79 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
81 torture_comment(tctx, "write time %s\n",
82 nt_time_string(tctx, finfo2.basic_info.out.write_time));
84 if (finfo1.basic_info.out.write_time !=
85 finfo2.basic_info.out.write_time)
87 double diff = timeval_elapsed(&start);
90 diff >= (used_delay / (double)1000000),
92 "Server updated write_time after %.2f "
93 "seconds (expected >= %.2f)\n",
94 diff, used_delay/(double)1000000));
96 torture_comment(tctx, "Server updated write_time after %.2f seconds (correct)\n",
101 smb_msleep(1 * msec);
104 torture_assert_u64_not_equal(tctx,
105 finfo2.basic_info.out.write_time,
106 finfo1.basic_info.out.write_time,
107 "Server did not update write time within "
111 smbcli_close(cli->tree, fnum1);
112 smbcli_unlink(cli->tree, fname);
113 smbcli_deltree(cli->tree, BASEDIR);
118 static bool test_delayed_write_update1(struct torture_context *tctx, struct smbcli_state *cli)
120 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
121 const char *fname = BASEDIR "\\torture_file1.txt";
126 struct timeval start;
128 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
129 int normal_delay = 2000000;
130 double sec = ((double)used_delay) / ((double)normal_delay);
131 int msec = 1000 * sec;
136 torture_comment(tctx, "\nRunning test_delayed_write_update1\n");
138 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
140 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
141 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
142 "Failed to open %s", fname));
144 memset(buf, 'x', 2048);
145 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
147 /* 3 second delay to ensure we get past any 2 second time
148 granularity (older systems may have that) */
149 smb_msleep(3 * msec);
151 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
152 finfo1.all_info.in.file.fnum = fnum1;
155 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
156 pinfo4.all_info.in.file.path = fname;
158 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
160 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
162 torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
163 "file size not as expected after write(2048)");
165 torture_comment(tctx, "Initial write time %s\n",
166 nt_time_string(tctx, finfo1.all_info.out.write_time));
168 /* 3 second delay to ensure we get past any 2 second time
169 granularity (older systems may have that) */
170 smb_msleep(3 * msec);
172 /* Do a zero length SMBwrite call to truncate. */
173 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
174 torture_assert_int_equal(tctx, written, 0,
175 "unexpected number of bytes written");
177 start = timeval_current();
178 end = timeval_add(&start, (120 * sec), 0);
181 while (!timeval_expired(&end)) {
182 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
184 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
186 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 1024,
187 "file not truncated to expected size "
190 torture_comment(tctx, "write time %s\n",
191 nt_time_string(tctx, finfo2.all_info.out.write_time));
193 if (finfo1.all_info.out.write_time !=
194 finfo2.all_info.out.write_time)
201 smb_msleep(1 * msec);
205 torture_assert(tctx, updated,
206 "Server did not update write time within 120 seconds");
208 torture_assert(tctx, first, talloc_asprintf(tctx,
209 "Server did not update write time immediately but only "
210 "after %.2f seconds!", timeval_elapsed(&start)));
212 torture_comment(tctx, "Server updated write time immediately. Good!\n");
215 smb_msleep(2 * msec);
217 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
218 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
219 torture_assert_int_equal(tctx, written, 1,
220 "unexpected number of bytes written");
222 start = timeval_current();
223 end = timeval_add(&start, (10*sec), 0);
224 while (!timeval_expired(&end)) {
225 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
227 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
229 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 1024,
230 "file not truncated to expected size "
233 torture_comment(tctx, "write time %s\n",
234 nt_time_string(tctx, finfo3.all_info.out.write_time));
236 torture_assert_u64_equal(tctx,
237 finfo3.all_info.out.write_time,
238 finfo2.all_info.out.write_time,
239 talloc_asprintf(tctx,
240 "Server updated write time "
241 "after %.2f seconds (wrong!)",
242 timeval_elapsed(&start)));
245 smb_msleep(1 * msec);
248 torture_comment(tctx, "Server did not update write time within 10 "
252 smb_msleep(2 * msec);
254 /* the close should trigger an write time update */
255 smbcli_close(cli->tree, fnum1);
258 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
259 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
261 torture_assert_u64_not_equal(tctx,
262 pinfo4.all_info.out.write_time,
263 finfo3.all_info.out.write_time,
264 "Server did not update write time on "
267 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
268 "Server updated write time on close, but to an earlier point "
271 torture_comment(tctx, "Server updated write time on close (correct)\n");
274 smbcli_close(cli->tree, fnum1);
275 smbcli_unlink(cli->tree, fname);
276 smbcli_deltree(cli->tree, BASEDIR);
281 /* Updating with a SMBwrite of zero length
282 * changes the write time immediately - even on expand. */
284 static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
286 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
287 const char *fname = BASEDIR "\\torture_file1a.txt";
292 struct timeval start;
294 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
295 int normal_delay = 2000000;
296 double sec = ((double)used_delay) / ((double)normal_delay);
297 int msec = 1000 * sec;
302 torture_comment(tctx, "\nRunning test_delayed_write_update1a\n");
304 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
306 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
307 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
308 "Failed to open %s", fname));
310 memset(buf, 'x', 2048);
311 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
313 /* 3 second delay to ensure we get past any 2 second time
314 granularity (older systems may have that) */
315 smb_msleep(3 * msec);
317 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
318 finfo1.all_info.in.file.fnum = fnum1;
321 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
322 pinfo4.all_info.in.file.path = fname;
324 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
326 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
328 torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
329 "file size not as expected after write(2048)");
331 torture_comment(tctx, "Initial write time %s\n",
332 nt_time_string(tctx, finfo1.all_info.out.write_time));
334 /* Do a zero length SMBwrite call to truncate. */
335 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
337 torture_assert_int_equal(tctx, written, 0,
338 "unexpected number of bytes written");
340 start = timeval_current();
341 end = timeval_add(&start, (120*sec), 0);
344 while (!timeval_expired(&end)) {
345 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
347 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
349 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
350 "file not truncated to expected size "
353 torture_comment(tctx, "write time %s\n",
354 nt_time_string(tctx, finfo2.all_info.out.write_time));
356 if (finfo1.all_info.out.write_time !=
357 finfo2.all_info.out.write_time)
364 smb_msleep(1 * msec);
368 torture_assert(tctx, updated,
369 "Server did not update write time within 120 seconds");
371 torture_assert(tctx, first, talloc_asprintf(tctx,
372 "Server did not update write time immediately but only "
373 "after %.2f seconds!", timeval_elapsed(&start)));
375 torture_comment(tctx, "Server updated write time immediately. Good!\n");
378 smb_msleep(2 * msec);
380 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
381 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
383 torture_assert_int_equal(tctx, written, 1,
384 "unexpected number of bytes written");
386 start = timeval_current();
387 end = timeval_add(&start, (10*sec), 0);
388 while (!timeval_expired(&end)) {
389 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
391 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
393 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
394 "file not truncated to expected size "
397 torture_comment(tctx, "write time %s\n",
398 nt_time_string(tctx, finfo3.all_info.out.write_time));
400 torture_assert_u64_equal(tctx,
401 finfo3.all_info.out.write_time,
402 finfo2.all_info.out.write_time,
403 talloc_asprintf(tctx,
404 "Server updated write time "
405 "after %.2f seconds (wrong!)",
406 timeval_elapsed(&start)));
409 smb_msleep(1 * msec);
412 torture_comment(tctx, "Server did not update write time within 10 "
415 /* the close should trigger an write time update */
416 smbcli_close(cli->tree, fnum1);
419 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
420 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
422 torture_assert_u64_not_equal(tctx,
423 pinfo4.all_info.out.write_time,
424 finfo3.all_info.out.write_time,
425 "Server did not update write time on "
428 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
429 "Server updated write time on close, but to an earlier point "
432 torture_comment(tctx, "Server updated write time on close (correct)\n");
435 smbcli_close(cli->tree, fnum1);
436 smbcli_unlink(cli->tree, fname);
437 smbcli_deltree(cli->tree, BASEDIR);
442 /* Updating with a SET_FILE_END_OF_FILE_INFO
443 * changes the write time immediately - even on expand. */
445 static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
447 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
448 const char *fname = BASEDIR "\\torture_file1b.txt";
453 struct timeval start;
455 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
456 int normal_delay = 2000000;
457 double sec = ((double)used_delay) / ((double)normal_delay);
458 int msec = 1000 * sec;
463 torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
465 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
467 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
468 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
469 "Failed to open %s", fname));
471 memset(buf, 'x', 2048);
472 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
474 /* 3 second delay to ensure we get past any 2 second time
475 granularity (older systems may have that) */
476 smb_msleep(3 * msec);
478 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
479 finfo1.all_info.in.file.fnum = fnum1;
482 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
483 pinfo4.all_info.in.file.path = fname;
485 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
487 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
489 torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
490 "file size not as expected after write(2048)");
492 torture_comment(tctx, "Initial write time %s\n",
493 nt_time_string(tctx, finfo1.all_info.out.write_time));
495 /* Do a SET_END_OF_FILE_INFO call to truncate. */
496 status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
498 torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
500 start = timeval_current();
501 end = timeval_add(&start, (120*sec), 0);
504 while (!timeval_expired(&end)) {
505 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
507 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
509 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
510 "file not truncated to expected size "
513 torture_comment(tctx, "write time %s\n",
514 nt_time_string(tctx, finfo2.all_info.out.write_time));
516 if (finfo1.all_info.out.write_time !=
517 finfo2.all_info.out.write_time)
524 smb_msleep(1 * msec);
528 torture_assert(tctx, updated,
529 "Server did not update write time within 120 seconds");
531 torture_assert(tctx, first, talloc_asprintf(tctx,
532 "Server did not update write time immediately but only "
533 "after %.2f seconds!", timeval_elapsed(&start)));
535 torture_comment(tctx, "Server updated write time immediately. Good!\n");
538 smb_msleep(2 * msec);
540 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
541 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
543 torture_assert_int_equal(tctx, written, 1,
544 "unexpected number of bytes written");
546 start = timeval_current();
547 end = timeval_add(&start, (10*sec), 0);
548 while (!timeval_expired(&end)) {
549 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
551 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
553 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
554 "file not truncated to expected size "
557 torture_comment(tctx, "write time %s\n",
558 nt_time_string(tctx, finfo3.all_info.out.write_time));
560 torture_assert_u64_equal(tctx,
561 finfo3.all_info.out.write_time,
562 finfo2.all_info.out.write_time,
563 talloc_asprintf(tctx,
564 "Server updated write time "
565 "after %.2f seconds (wrong!)",
566 timeval_elapsed(&start)));
569 smb_msleep(1 * msec);
572 torture_comment(tctx, "Server did not update write time within 10 "
575 /* the close should trigger an write time update */
576 smbcli_close(cli->tree, fnum1);
579 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
580 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
582 torture_assert_u64_not_equal(tctx,
583 pinfo4.all_info.out.write_time,
584 finfo3.all_info.out.write_time,
585 "Server did not update write time on "
588 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
589 "Server updated write time on close, but to an earlier point "
592 torture_comment(tctx, "Server updated write time on close (correct)\n");
595 smbcli_close(cli->tree, fnum1);
596 smbcli_unlink(cli->tree, fname);
597 smbcli_deltree(cli->tree, BASEDIR);
602 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
604 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
606 union smb_setfileinfo parms;
607 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
608 const char *fname = BASEDIR "\\torture_file1c.txt";
613 struct timeval start;
615 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
616 int normal_delay = 2000000;
617 double sec = ((double)used_delay) / ((double)normal_delay);
618 int msec = 1000 * sec;
623 torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
625 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
627 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
628 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
629 "Failed to open %s", fname));
631 memset(buf, 'x', 2048);
632 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
634 /* 3 second delay to ensure we get past any 2 second time
635 granularity (older systems may have that) */
636 smb_msleep(3 * msec);
638 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
639 finfo1.all_info.in.file.fnum = fnum1;
642 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
643 pinfo4.all_info.in.file.path = fname;
645 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
647 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
649 torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
650 "file size not as expected after write(2048)");
652 torture_comment(tctx, "Initial write time %s\n",
653 nt_time_string(tctx, finfo1.all_info.out.write_time));
655 /* Do a SET_ALLOCATION_SIZE call to truncate. */
656 parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
657 parms.allocation_info.in.file.fnum = fnum1;
658 parms.allocation_info.in.alloc_size = 0;
660 status = smb_raw_setfileinfo(cli->tree, &parms);
662 torture_assert_ntstatus_ok(tctx, status,
663 "RAW_SFILEINFO_ALLOCATION_INFO failed");
665 start = timeval_current();
666 end = timeval_add(&start, (120*sec), 0);
669 while (!timeval_expired(&end)) {
670 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
672 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
674 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 0,
675 "file not truncated to expected size "
678 torture_comment(tctx, "write time %s\n",
679 nt_time_string(tctx, finfo2.all_info.out.write_time));
681 if (finfo1.all_info.out.write_time !=
682 finfo2.all_info.out.write_time)
689 smb_msleep(1 * msec);
693 torture_assert(tctx, updated,
694 "Server did not update write time within 120 seconds");
696 torture_assert(tctx, first, talloc_asprintf(tctx,
697 "Server did not update write time immediately but only "
698 "after %.2f seconds!", timeval_elapsed(&start)));
700 torture_comment(tctx, "Server updated write time immediately. Good!\n");
703 smb_msleep(2 * msec);
705 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
706 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
707 torture_assert_int_equal(tctx, written, 1,
708 "Unexpected number of bytes written");
710 start = timeval_current();
711 end = timeval_add(&start, (10*sec), 0);
712 while (!timeval_expired(&end)) {
713 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
715 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
717 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 1,
718 "file not expaneded");
720 torture_comment(tctx, "write time %s\n",
721 nt_time_string(tctx, finfo3.all_info.out.write_time));
723 torture_assert_u64_equal(tctx,
724 finfo3.all_info.out.write_time,
725 finfo2.all_info.out.write_time,
726 talloc_asprintf(tctx,
727 "Server updated write time "
728 "after %.2f seconds (wrong!)",
729 timeval_elapsed(&start)));
732 smb_msleep(1 * msec);
735 torture_comment(tctx, "Server did not update write time within 10 "
738 /* the close should trigger an write time update */
739 smbcli_close(cli->tree, fnum1);
742 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
743 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
745 torture_assert_u64_not_equal(tctx,
746 pinfo4.all_info.out.write_time,
747 finfo3.all_info.out.write_time,
748 "Server did not update write time on "
751 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
752 "Server updated write time on close, but to an earlier point "
756 smbcli_close(cli->tree, fnum1);
757 smbcli_unlink(cli->tree, fname);
758 smbcli_deltree(cli->tree, BASEDIR);
764 * Do as above, but using 2 connections.
767 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
768 struct smbcli_state *cli2)
770 union smb_fileinfo finfo1, finfo2;
771 const char *fname = BASEDIR "\\torture_file.txt";
777 struct timeval start;
779 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
780 int normal_delay = 2000000;
781 double sec = ((double)used_delay) / ((double)normal_delay);
782 int msec = 1000 * sec;
783 union smb_flush flsh;
785 torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
787 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
789 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
791 torture_comment(tctx, "Failed to open %s\n", fname);
795 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
796 finfo1.basic_info.in.file.fnum = fnum1;
799 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
801 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
803 torture_comment(tctx, "Initial write time %s\n",
804 nt_time_string(tctx, finfo1.basic_info.out.write_time));
806 /* 3 second delay to ensure we get past any 2 second time
807 granularity (older systems may have that) */
808 smb_msleep(3 * msec);
811 /* Try using setfileinfo instead of write to update write time. */
812 union smb_setfileinfo sfinfo;
813 time_t t_set = time(NULL);
814 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
815 sfinfo.basic_info.in.file.fnum = fnum1;
816 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
817 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
819 /* I tried this with both + and - ve to see if it makes a different.
820 It doesn't - once the filetime is set via setfileinfo it stays that way. */
822 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
824 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
826 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
827 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
829 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
831 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
834 finfo2.basic_info.in.file.path = fname;
836 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
838 if (!NT_STATUS_IS_OK(status)) {
839 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
842 torture_comment(tctx, "write time %s\n",
843 nt_time_string(tctx, finfo2.basic_info.out.write_time));
845 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
846 torture_comment(tctx, "Server updated write_time (correct)\n");
848 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
852 /* Now try a write to see if the write time gets reset. */
854 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
855 finfo1.basic_info.in.file.fnum = fnum1;
858 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
860 if (!NT_STATUS_IS_OK(status)) {
861 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
865 torture_comment(tctx, "Modified write time %s\n",
866 nt_time_string(tctx, finfo1.basic_info.out.write_time));
869 torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
871 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
874 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
875 (int)written, __location__);
879 /* Just to prove to tridge that the an smbflush has no effect on
880 the write time :-). The setfileinfo IS STICKY. JRA. */
882 torture_comment(tctx, "Doing flush after write\n");
884 flsh.flush.level = RAW_FLUSH_FLUSH;
885 flsh.flush.in.file.fnum = fnum1;
886 status = smb_raw_flush(cli->tree, &flsh);
887 if (!NT_STATUS_IS_OK(status)) {
888 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
892 /* Once the time was set using setfileinfo then it stays set - writes
893 don't have any effect. But make sure. */
894 start = timeval_current();
895 end = timeval_add(&start, (15*sec), 0);
896 while (!timeval_expired(&end)) {
897 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
899 if (!NT_STATUS_IS_OK(status)) {
900 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
904 torture_comment(tctx, "write time %s\n",
905 nt_time_string(tctx, finfo2.basic_info.out.write_time));
906 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
907 double diff = timeval_elapsed(&start);
908 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
915 smb_msleep(1 * msec);
918 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
919 torture_comment(tctx, "Server did not update write time (correct)\n");
923 smb_msleep(2 * msec);
925 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
927 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
931 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");
933 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
936 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
937 (int)written, __location__);
941 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
943 if (!NT_STATUS_IS_OK(status)) {
944 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
947 torture_comment(tctx, "write time %s\n",
948 nt_time_string(tctx, finfo2.basic_info.out.write_time));
949 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
950 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
954 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
955 smbcli_close(cli->tree, fnum1);
958 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");
960 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
963 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
964 (int)written, __location__);
968 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
969 finfo1.basic_info.in.file.fnum = fnum2;
971 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
973 if (!NT_STATUS_IS_OK(status)) {
974 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
977 torture_comment(tctx, "write time %s\n",
978 nt_time_string(tctx, finfo2.basic_info.out.write_time));
979 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
980 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
984 /* Once the time was set using setfileinfo then it stays set - writes
985 don't have any effect. But make sure. */
986 start = timeval_current();
987 end = timeval_add(&start, (15*sec), 0);
988 while (!timeval_expired(&end)) {
989 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
991 if (!NT_STATUS_IS_OK(status)) {
992 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
996 torture_comment(tctx, "write time %s\n",
997 nt_time_string(tctx, finfo2.basic_info.out.write_time));
998 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
999 double diff = timeval_elapsed(&start);
1000 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1007 smb_msleep(1 * msec);
1010 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1011 torture_comment(tctx, "Server did not update write time (correct)\n");
1014 torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1016 smbcli_close(cli->tree, fnum2);
1019 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1021 torture_comment(tctx, "Failed to open %s\n", fname);
1025 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1026 finfo1.basic_info.in.file.fnum = fnum1;
1029 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1031 if (!NT_STATUS_IS_OK(status)) {
1032 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1036 torture_comment(tctx, "Second open initial write time %s\n",
1037 nt_time_string(tctx, finfo1.basic_info.out.write_time));
1039 smb_msleep(10 * msec);
1040 torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1042 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1044 if (written != 10) {
1045 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1046 (int)written, __location__);
1050 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1051 finfo1.basic_info.in.file.fnum = fnum1;
1053 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1055 if (!NT_STATUS_IS_OK(status)) {
1056 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1059 torture_comment(tctx, "write time %s\n",
1060 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1061 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1062 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1066 /* Now the write time should be updated again */
1067 start = timeval_current();
1068 end = timeval_add(&start, (15*sec), 0);
1069 while (!timeval_expired(&end)) {
1070 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1072 if (!NT_STATUS_IS_OK(status)) {
1073 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1077 torture_comment(tctx, "write time %s\n",
1078 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1079 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1080 double diff = timeval_elapsed(&start);
1081 if (diff < (used_delay / (double)1000000)) {
1082 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1083 "(expected > %.2f) (wrong!)\n",
1084 diff, used_delay / (double)1000000);
1089 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1098 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1099 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
1104 /* One more test to do. We should read the filetime via findfirst on the
1105 second connection to ensure it's the same. This is very easy for a Windows
1106 server but a bastard to get right on a POSIX server. JRA. */
1109 smbcli_close(cli->tree, fnum1);
1110 smbcli_unlink(cli->tree, fname);
1111 smbcli_deltree(cli->tree, BASEDIR);
1117 /* Windows does obviously not update the stat info during a write call. I
1118 * *think* this is the problem causing a spurious Excel 2003 on XP error
1119 * message when saving a file. Excel does a setfileinfo, writes, and then does
1120 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1121 * that the file might have been changed in between. What i've been able to
1122 * trace down is that this happens if the getpathinfo after the write shows a
1123 * different last write time than the setfileinfo showed. This is really
1127 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
1128 struct smbcli_state *cli2)
1130 union smb_fileinfo finfo1, finfo2;
1131 const char *fname = BASEDIR "\\torture_file.txt";
1137 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1138 int normal_delay = 2000000;
1139 double sec = ((double)used_delay) / ((double)normal_delay);
1140 int msec = 1000 * sec;
1142 torture_comment(tctx, "\nRunning test_finfo_after_write\n");
1144 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1146 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1149 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1153 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1154 finfo1.basic_info.in.file.fnum = fnum1;
1156 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1158 if (!NT_STATUS_IS_OK(status)) {
1160 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1164 smb_msleep(1 * msec);
1166 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1169 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1174 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1176 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1177 smbcli_errstr(cli2->tree));
1182 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1185 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1191 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1192 finfo2.basic_info.in.file.path = fname;
1194 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1196 if (!NT_STATUS_IS_OK(status)) {
1197 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
1203 if (finfo1.basic_info.out.create_time !=
1204 finfo2.basic_info.out.create_time) {
1205 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1210 if (finfo1.basic_info.out.access_time !=
1211 finfo2.basic_info.out.access_time) {
1212 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1217 if (finfo1.basic_info.out.write_time !=
1218 finfo2.basic_info.out.write_time) {
1219 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1220 "write time conn 1 = %s, conn 2 = %s",
1221 nt_time_string(tctx, finfo1.basic_info.out.write_time),
1222 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1227 if (finfo1.basic_info.out.change_time !=
1228 finfo2.basic_info.out.change_time) {
1229 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1234 /* One of the two following calls updates the qpathinfo. */
1236 /* If you had skipped the smbcli_write on fnum2, it would
1237 * *not* have updated the stat on disk */
1239 smbcli_close(cli2->tree, fnum2);
1242 /* This call is only for the people looking at ethereal :-) */
1243 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1244 finfo2.basic_info.in.file.path = fname;
1246 status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1248 if (!NT_STATUS_IS_OK(status)) {
1249 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1256 smbcli_close(cli->tree, fnum1);
1257 smbcli_unlink(cli->tree, fname);
1258 smbcli_deltree(cli->tree, BASEDIR);
1263 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1264 uint64_t r = 10*1000*1000; \
1265 NTTIME g = (given).basic_info.out.write_time; \
1266 NTTIME gr = (g / r) * r; \
1267 NTTIME c = (correct).basic_info.out.write_time; \
1268 NTTIME cr = (c / r) * r; \
1269 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1271 if (strict && (g cmp c)) { \
1273 } else if ((g cmp c) && (gr cmp cr)) { \
1274 /* handle filesystem without high resolution timestamps */ \
1278 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1279 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1280 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1285 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1286 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1287 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1288 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1289 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1290 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1292 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1293 NTTIME g = (given).basic_info.out.access_time; \
1294 NTTIME c = (correct).basic_info.out.access_time; \
1296 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1297 #given, nt_time_string(tctx, g), \
1298 #cmp, #correct, nt_time_string(tctx, c)); \
1303 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1304 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1306 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1307 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1308 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1311 #define GET_INFO_FILE(finfo) do { \
1312 struct timeval atv; \
1313 struct timeval wtv; \
1314 struct timeval_buf atvb; \
1315 struct timeval_buf wtvb; \
1317 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1318 if (!NT_STATUS_IS_OK(_status)) { \
1320 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1321 nt_errstr(_status)); \
1324 nttime_to_timeval(&atv, finfo.basic_info.out.access_time); \
1325 nttime_to_timeval(&wtv, finfo.basic_info.out.write_time); \
1326 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1327 timeval_str_buf(&atv, false, true, &atvb), \
1328 timeval_str_buf(&wtv, false, true, &wtvb)); \
1330 #define GET_INFO_FILE2(finfo) do { \
1332 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1333 if (!NT_STATUS_IS_OK(_status)) { \
1335 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1336 nt_errstr(_status)); \
1339 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1340 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1341 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1343 #define GET_INFO_PATH(pinfo) do { \
1345 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1346 if (!NT_STATUS_IS_OK(_status)) { \
1347 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1348 nt_errstr(_status)); \
1352 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1353 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1354 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1356 #define GET_INFO_BOTH(finfo,pinfo) do { \
1357 GET_INFO_FILE(finfo); \
1358 GET_INFO_PATH(pinfo); \
1359 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1362 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1364 union smb_setfileinfo sfinfo; \
1365 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1366 sfinfo.basic_info.in.file.fnum = tfnum; \
1367 sfinfo.basic_info.in.create_time = 0; \
1368 sfinfo.basic_info.in.access_time = 0; \
1369 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1370 sfinfo.basic_info.in.change_time = 0; \
1371 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1372 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1373 if (!NT_STATUS_IS_OK(_status)) { \
1374 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1375 nt_errstr(_status)); \
1380 #define SET_INFO_FILE(finfo, wrtime) \
1381 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1383 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1385 union smb_setfileinfo sfinfo; \
1386 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1387 sfinfo.basic_info.in.file.fnum = tfnum; \
1388 sfinfo.basic_info.in.create_time = 0; \
1389 sfinfo.basic_info.in.access_time = 0; \
1390 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1391 sfinfo.basic_info.in.write_time += (ns); \
1392 sfinfo.basic_info.in.change_time = 0; \
1393 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1394 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1395 if (!NT_STATUS_IS_OK(_status)) { \
1396 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1397 nt_errstr(_status)); \
1403 static bool test_delayed_write_update3(struct torture_context *tctx,
1404 struct smbcli_state *cli,
1405 struct smbcli_state *cli2)
1407 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1408 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1409 const char *fname = BASEDIR "\\torture_file3.txt";
1413 struct timeval start;
1415 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1416 //double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 1000000);
1417 //int normal_delay = 1000000;
1418 int normal_delay = 2000000;
1419 double sec = ((double)used_delay) / ((double)normal_delay);
1420 int msec = 1000 * sec;
1422 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
1424 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1426 torture_comment(tctx, "Open the file handle\n");
1427 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1430 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1434 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1435 finfo0.basic_info.in.file.fnum = fnum1;
1439 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1440 pinfo0.basic_info.in.file.path = fname;
1446 /* get the initial times */
1447 GET_INFO_BOTH(finfo0,pinfo0);
1450 * make sure the write time is updated 2 seconds later
1451 * calcuated from the first write
1452 * (but expect upto 5 seconds extra time for a busy server)
1454 start = timeval_current();
1455 end = timeval_add(&start, 7 * sec, 0);
1456 while (!timeval_expired(&end)) {
1458 torture_comment(tctx, "Do a write on the file handle\n");
1459 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1461 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1465 /* get the times after the write */
1466 GET_INFO_FILE(finfo1);
1468 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1469 double diff = timeval_elapsed(&start);
1470 if (diff < (used_delay / (double)1000000)) {
1471 torture_result(tctx, TORTURE_FAIL, "111Server updated write_time after %.2f seconds "
1472 "(write time update delay == %.2f) (wrong!)\n",
1473 diff, used_delay / (double)1000000);
1478 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1483 smb_msleep(0.5 * msec);
1486 GET_INFO_BOTH(finfo1,pinfo1);
1487 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1489 /* sure any further write doesn't update the write time */
1490 start = timeval_current();
1491 end = timeval_add(&start, 15 * sec, 0);
1492 while (!timeval_expired(&end)) {
1494 torture_comment(tctx, "Do a write on the file handle\n");
1495 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1497 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1501 /* get the times after the write */
1502 GET_INFO_BOTH(finfo2,pinfo2);
1504 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1505 double diff = timeval_elapsed(&start);
1506 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1512 smb_msleep(1 * msec);
1515 GET_INFO_BOTH(finfo2,pinfo2);
1516 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1517 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1518 torture_comment(tctx, "Server did not update write_time (correct)\n");
1522 smb_msleep(5 * msec);
1524 GET_INFO_BOTH(finfo3,pinfo3);
1525 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1528 * the close updates the write time to the time of the close
1529 * and not to the time of the last write!
1531 torture_comment(tctx, "Close the file handle\n");
1532 smbcli_close(cli->tree, fnum1);
1535 GET_INFO_PATH(pinfo4);
1536 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1538 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1539 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1544 smbcli_close(cli->tree, fnum1);
1545 smbcli_unlink(cli->tree, fname);
1546 smbcli_deltree(cli->tree, BASEDIR);
1552 * Show that a truncate write always updates the write time even
1553 * if an initial write has already updated the write time.
1556 static bool test_delayed_write_update3a(struct torture_context *tctx,
1557 struct smbcli_state *cli,
1558 struct smbcli_state *cli2)
1560 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1561 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1562 const char *fname = BASEDIR "\\torture_file3a.txt";
1567 struct timeval start;
1569 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1570 int normal_delay = 2000000;
1571 double sec = ((double)used_delay) / ((double)normal_delay);
1572 int msec = 1000 * sec;
1574 torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
1576 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1578 torture_comment(tctx, "Open the file handle\n");
1579 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1582 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1586 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1587 finfo0.basic_info.in.file.fnum = fnum1;
1591 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1592 pinfo0.basic_info.in.file.path = fname;
1598 /* get the initial times */
1599 GET_INFO_BOTH(finfo0,pinfo0);
1602 * sleep some time, to demonstrate the handling of write times
1603 * doesn't depend on the time since the open
1605 smb_msleep(5 * msec);
1607 /* get the initial times */
1608 GET_INFO_BOTH(finfo1,pinfo1);
1609 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1612 * make sure the write time is updated 2 seconds later
1613 * calcuated from the first write
1614 * (but expect upto 5 seconds extra time for a busy server)
1616 start = timeval_current();
1617 end = timeval_add(&start, 7 * sec, 0);
1618 while (!timeval_expired(&end)) {
1620 torture_comment(tctx, "Do a write on the file handle\n");
1621 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1623 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1627 /* get the times after the write */
1628 GET_INFO_FILE(finfo1);
1630 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1631 double diff = timeval_elapsed(&start);
1632 if (diff < (used_delay / (double)1000000)) {
1633 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1634 "(1sec == %.2f) (wrong!)\n",
1640 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1645 smb_msleep(0.5 * msec);
1648 GET_INFO_BOTH(finfo1,pinfo1);
1649 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1651 smb_msleep(3 * msec);
1654 * demonstrate that a truncate write always
1655 * updates the write time immediately
1657 for (i=0; i < 3; i++) {
1658 smb_msleep(2 * msec);
1660 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1661 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1663 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1667 /* get the times after the write */
1668 GET_INFO_BOTH(finfo2,pinfo2);
1669 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1673 smb_msleep(3 * msec);
1675 /* sure any further write doesn't update the write time */
1676 start = timeval_current();
1677 end = timeval_add(&start, 15 * sec, 0);
1678 while (!timeval_expired(&end)) {
1680 torture_comment(tctx, "Do a write on the file handle\n");
1681 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1683 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1687 /* get the times after the write */
1688 GET_INFO_BOTH(finfo2,pinfo2);
1690 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1691 double diff = timeval_elapsed(&start);
1692 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1698 smb_msleep(1 * msec);
1701 GET_INFO_BOTH(finfo2,pinfo2);
1702 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1703 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1704 torture_comment(tctx, "Server did not update write_time (correct)\n");
1708 smb_msleep(3 * msec);
1710 /* get the initial times */
1711 GET_INFO_BOTH(finfo1,pinfo1);
1712 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1715 * demonstrate that a truncate write always
1716 * updates the write time immediately
1718 for (i=0; i < 3; i++) {
1719 smb_msleep(2 * msec);
1721 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1722 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1724 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1728 /* get the times after the write */
1729 GET_INFO_BOTH(finfo2,pinfo2);
1730 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1735 smb_msleep(3 * msec);
1737 GET_INFO_BOTH(finfo3,pinfo3);
1738 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1741 * the close doesn't update the write time
1743 torture_comment(tctx, "Close the file handle\n");
1744 smbcli_close(cli->tree, fnum1);
1747 GET_INFO_PATH(pinfo4);
1748 COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1750 if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1751 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1756 smbcli_close(cli->tree, fnum1);
1757 smbcli_unlink(cli->tree, fname);
1758 smbcli_deltree(cli->tree, BASEDIR);
1764 * Show a close after write updates the write timestamp to
1765 * the close time, not the last write time.
1768 static bool test_delayed_write_update3b(struct torture_context *tctx,
1769 struct smbcli_state *cli,
1770 struct smbcli_state *cli2)
1772 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1773 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1774 const char *fname = BASEDIR "\\torture_file3b.txt";
1778 struct timeval start;
1780 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1781 int normal_delay = 2000000;
1782 double sec = ((double)used_delay) / ((double)normal_delay);
1783 int msec = 1000 * sec;
1785 torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
1787 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1789 torture_comment(tctx, "Open the file handle\n");
1790 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1793 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1797 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1798 finfo0.basic_info.in.file.fnum = fnum1;
1802 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1803 pinfo0.basic_info.in.file.path = fname;
1809 /* get the initial times */
1810 GET_INFO_BOTH(finfo0,pinfo0);
1813 * sleep some time, to demonstrate the handling of write times
1814 * doesn't depend on the time since the open
1816 smb_msleep(5 * msec);
1818 /* get the initial times */
1819 GET_INFO_BOTH(finfo1,pinfo1);
1820 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1823 * make sure the write time is updated 2 seconds later
1824 * calcuated from the first write
1825 * (but expect upto 5 seconds extra time for a busy server)
1827 start = timeval_current();
1828 end = timeval_add(&start, 7 * sec, 0);
1829 while (!timeval_expired(&end)) {
1831 torture_comment(tctx, "Do a write on the file handle\n");
1832 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1834 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1838 /* get the times after the write */
1839 GET_INFO_FILE(finfo1);
1841 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1842 double diff = timeval_elapsed(&start);
1843 if (diff < (used_delay / (double)1000000)) {
1844 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1845 "(expected > %.2f) (wrong!)\n",
1846 diff, used_delay / (double)1000000);
1851 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1852 "(write time update delay == %.2f) (correct)\n",
1853 diff, used_delay / (double)1000000);
1856 smb_msleep(0.5 * msec);
1859 GET_INFO_BOTH(finfo1,pinfo1);
1860 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1862 /* sure any further write doesn't update the write time */
1863 start = timeval_current();
1864 end = timeval_add(&start, 15 * sec, 0);
1865 while (!timeval_expired(&end)) {
1867 torture_comment(tctx, "Do a write on the file handle\n");
1868 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1870 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1874 /* get the times after the write */
1875 GET_INFO_BOTH(finfo2,pinfo2);
1877 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1878 double diff = timeval_elapsed(&start);
1879 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1885 smb_msleep(1 * msec);
1888 GET_INFO_BOTH(finfo2,pinfo2);
1889 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1890 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1891 torture_comment(tctx, "Server did not update write_time (correct)\n");
1895 smb_msleep(5 * msec);
1897 GET_INFO_BOTH(finfo3,pinfo3);
1898 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1901 * the close updates the write time to the time of the close
1902 * and not to the time of the last write!
1904 torture_comment(tctx, "Close the file handle\n");
1905 smbcli_close(cli->tree, fnum1);
1908 GET_INFO_PATH(pinfo4);
1909 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1911 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1912 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1917 smbcli_close(cli->tree, fnum1);
1918 smbcli_unlink(cli->tree, fname);
1919 smbcli_deltree(cli->tree, BASEDIR);
1925 * Check that a write after a truncate write doesn't update
1926 * the timestamp, but a truncate write after a write does.
1927 * Also prove that a close after a truncate write updates the
1928 * timestamp to current, not the time of last write.
1931 static bool test_delayed_write_update3c(struct torture_context *tctx,
1932 struct smbcli_state *cli,
1933 struct smbcli_state *cli2)
1935 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1936 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1937 const char *fname = BASEDIR "\\torture_file3c.txt";
1942 struct timeval start;
1944 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1945 int normal_delay = 2000000;
1946 double sec = ((double)used_delay) / ((double)normal_delay);
1947 int msec = 1000 * sec;
1949 torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
1951 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1953 torture_comment(tctx, "Open the file handle\n");
1954 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1957 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1961 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1962 finfo0.basic_info.in.file.fnum = fnum1;
1966 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1967 pinfo0.basic_info.in.file.path = fname;
1973 /* get the initial times */
1974 GET_INFO_BOTH(finfo0,pinfo0);
1977 * sleep some time, to demonstrate the handling of write times
1978 * doesn't depend on the time since the open
1980 smb_msleep(5 * msec);
1982 /* get the initial times */
1983 GET_INFO_BOTH(finfo1,pinfo1);
1984 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1987 * demonstrate that a truncate write always
1988 * updates the write time immediately
1990 for (i=0; i < 3; i++) {
1991 smb_msleep(2 * msec);
1993 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1994 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1996 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2000 /* get the times after the write */
2001 GET_INFO_BOTH(finfo2,pinfo2);
2002 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2006 start = timeval_current();
2007 end = timeval_add(&start, 7 * sec, 0);
2008 while (!timeval_expired(&end)) {
2010 torture_comment(tctx, "Do a write on the file handle\n");
2011 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2013 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2017 /* get the times after the write */
2018 GET_INFO_FILE(finfo2);
2020 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2021 double diff = timeval_elapsed(&start);
2022 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2028 smb_msleep(1 * msec);
2031 GET_INFO_BOTH(finfo2,pinfo2);
2032 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2033 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2034 torture_comment(tctx, "Server did not update write_time (correct)\n");
2038 smb_msleep(5 * msec);
2040 /* get the initial times */
2041 GET_INFO_BOTH(finfo1,pinfo1);
2042 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2045 * demonstrate that a truncate write always
2046 * updates the write time immediately
2048 for (i=0; i < 3; i++) {
2049 smb_msleep(2 * msec);
2051 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2052 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2054 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2058 /* get the times after the write */
2059 GET_INFO_BOTH(finfo2,pinfo2);
2060 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2065 smb_msleep(5 * msec);
2067 GET_INFO_BOTH(finfo2,pinfo2);
2068 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2070 /* sure any further write doesn't update the write time */
2071 start = timeval_current();
2072 end = timeval_add(&start, 15 * sec, 0);
2073 while (!timeval_expired(&end)) {
2075 torture_comment(tctx, "Do a write on the file handle\n");
2076 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2078 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2082 /* get the times after the write */
2083 GET_INFO_BOTH(finfo2,pinfo2);
2085 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2086 double diff = timeval_elapsed(&start);
2087 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2093 smb_msleep(1 * msec);
2096 GET_INFO_BOTH(finfo2,pinfo2);
2097 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2098 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2099 torture_comment(tctx, "Server did not update write_time (correct)\n");
2103 smb_msleep(5 * msec);
2105 GET_INFO_BOTH(finfo3,pinfo3);
2106 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2109 * the close updates the write time to the time of the close
2110 * and not to the time of the last write!
2112 torture_comment(tctx, "Close the file handle\n");
2113 smbcli_close(cli->tree, fnum1);
2116 GET_INFO_PATH(pinfo4);
2117 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2119 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2120 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2125 smbcli_close(cli->tree, fnum1);
2126 smbcli_unlink(cli->tree, fname);
2127 smbcli_deltree(cli->tree, BASEDIR);
2133 * Show only the first write updates the timestamp, and a close
2134 * after writes updates to current (I think this is the same
2138 static bool test_delayed_write_update4(struct torture_context *tctx,
2139 struct smbcli_state *cli,
2140 struct smbcli_state *cli2)
2142 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
2143 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
2144 const char *fname = BASEDIR "\\torture_file4.txt";
2148 struct timeval start;
2150 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2151 int normal_delay = 2000000;
2152 double sec = ((double)used_delay) / ((double)normal_delay);
2153 int msec = 1000 * sec;
2155 torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2157 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2159 torture_comment(tctx, "Open the file handle\n");
2160 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2163 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2167 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2168 finfo0.basic_info.in.file.fnum = fnum1;
2172 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2173 pinfo0.basic_info.in.file.path = fname;
2179 /* get the initial times */
2180 GET_INFO_BOTH(finfo0,pinfo0);
2183 smb_msleep(5 * msec);
2186 torture_comment(tctx, "Do a write on the file handle\n");
2187 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2189 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2194 GET_INFO_BOTH(finfo1,pinfo1);
2195 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2198 * make sure the write time is updated 2 seconds later
2199 * calcuated from the first write
2200 * (but expect upto 3 seconds extra time for a busy server)
2202 start = timeval_current();
2203 end = timeval_add(&start, 5 * sec, 0);
2204 while (!timeval_expired(&end)) {
2205 /* get the times after the first write */
2206 GET_INFO_FILE(finfo1);
2208 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2209 double diff = timeval_elapsed(&start);
2210 if (diff < (used_delay / (double)1000000)) {
2211 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
2212 "(expected > %.2f) (wrong!)\n",
2213 diff, used_delay / (double)1000000);
2218 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2219 "(write time update delay == %.2f) (correct)\n",
2220 diff, used_delay / (double)1000000);
2223 smb_msleep(0.5 * msec);
2226 GET_INFO_BOTH(finfo1,pinfo1);
2227 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2229 /* sure any further write doesn't update the write time */
2230 start = timeval_current();
2231 end = timeval_add(&start, 15 * sec, 0);
2232 while (!timeval_expired(&end)) {
2234 torture_comment(tctx, "Do a write on the file handle\n");
2235 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2237 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2241 /* get the times after the write */
2242 GET_INFO_BOTH(finfo2,pinfo2);
2244 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2245 double diff = timeval_elapsed(&start);
2246 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2252 smb_msleep(1 * msec);
2255 GET_INFO_BOTH(finfo2,pinfo2);
2256 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2257 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2258 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2262 smb_msleep(5 * msec);
2264 GET_INFO_BOTH(finfo3,pinfo3);
2265 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2268 * the close updates the write time to the time of the close
2269 * and not to the time of the last write!
2271 torture_comment(tctx, "Close the file handle\n");
2272 smbcli_close(cli->tree, fnum1);
2275 GET_INFO_PATH(pinfo4);
2276 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2278 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2279 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2284 smbcli_close(cli->tree, fnum1);
2285 smbcli_unlink(cli->tree, fname);
2286 smbcli_deltree(cli->tree, BASEDIR);
2292 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2295 static bool test_delayed_write_update5(struct torture_context *tctx,
2296 struct smbcli_state *cli,
2297 struct smbcli_state *cli2)
2299 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2300 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2301 const char *fname = BASEDIR "\\torture_file5.txt";
2305 struct timeval start;
2307 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2308 int normal_delay = 2000000;
2309 double sec = ((double)used_delay) / ((double)normal_delay);
2310 int msec = 1000 * sec;
2312 torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2314 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2316 torture_comment(tctx, "Open the file handle\n");
2317 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2320 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2324 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2325 finfo0.basic_info.in.file.fnum = fnum1;
2331 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2332 pinfo0.basic_info.in.file.path = fname;
2340 /* get the initial times */
2341 GET_INFO_BOTH(finfo0,pinfo0);
2344 torture_comment(tctx, "Do a write on the file handle\n");
2345 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2347 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2352 GET_INFO_BOTH(finfo1,pinfo1);
2353 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2355 torture_comment(tctx, "Set write time in the future on the file handle\n");
2356 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2357 GET_INFO_BOTH(finfo2,pinfo2);
2358 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2360 torture_comment(tctx, "Set write time in the past on the file handle\n");
2361 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2362 GET_INFO_BOTH(finfo2,pinfo2);
2363 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2365 /* make sure the 2 second delay from the first write are canceled */
2366 start = timeval_current();
2367 end = timeval_add(&start, 15 * sec, 0);
2368 while (!timeval_expired(&end)) {
2370 /* get the times after the first write */
2371 GET_INFO_BOTH(finfo3,pinfo3);
2373 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2374 double diff = timeval_elapsed(&start);
2375 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2381 smb_msleep(1 * msec);
2384 GET_INFO_BOTH(finfo3,pinfo3);
2385 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2386 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2387 torture_comment(tctx, "Server did not update write_time (correct)\n");
2390 /* sure any further write doesn't update the write time */
2391 start = timeval_current();
2392 end = timeval_add(&start, 15 * sec, 0);
2393 while (!timeval_expired(&end)) {
2395 torture_comment(tctx, "Do a write on the file handle\n");
2396 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2398 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2402 /* get the times after the write */
2403 GET_INFO_BOTH(finfo4,pinfo4);
2405 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2406 double diff = timeval_elapsed(&start);
2407 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2413 smb_msleep(1 * msec);
2416 GET_INFO_BOTH(finfo4,pinfo4);
2417 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2418 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2419 torture_comment(tctx, "Server did not update write_time (correct)\n");
2423 smb_msleep(5 * msec);
2425 GET_INFO_BOTH(finfo5,pinfo5);
2426 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2429 * the close doesn't update the write time
2431 torture_comment(tctx, "Close the file handle\n");
2432 smbcli_close(cli->tree, fnum1);
2435 GET_INFO_PATH(pinfo6);
2436 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2438 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2439 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2444 smbcli_close(cli->tree, fnum1);
2445 smbcli_unlink(cli->tree, fname);
2446 smbcli_deltree(cli->tree, BASEDIR);
2452 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2455 static bool test_delayed_write_update5b(struct torture_context *tctx,
2456 struct smbcli_state *cli,
2457 struct smbcli_state *cli2)
2459 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2460 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2461 const char *fname = BASEDIR "\\torture_fileb.txt";
2465 struct timeval start;
2467 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2468 int normal_delay = 2000000;
2469 double sec = ((double)used_delay) / ((double)normal_delay);
2470 int msec = 1000 * sec;
2472 torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2474 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2476 torture_comment(tctx, "Open the file handle\n");
2477 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2480 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2484 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2485 finfo0.basic_info.in.file.fnum = fnum1;
2491 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2492 pinfo0.basic_info.in.file.path = fname;
2500 /* get the initial times */
2501 GET_INFO_BOTH(finfo0,pinfo0);
2504 torture_comment(tctx, "Do a write on the file handle\n");
2505 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2507 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2512 GET_INFO_BOTH(finfo1,pinfo1);
2513 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2515 torture_comment(tctx, "Set write time in the future on the file handle\n");
2516 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2517 GET_INFO_BOTH(finfo2,pinfo2);
2518 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2520 torture_comment(tctx, "Set write time in the past on the file handle\n");
2521 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2522 GET_INFO_BOTH(finfo2,pinfo2);
2523 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2525 /* make sure the 2 second delay from the first write are canceled */
2526 start = timeval_current();
2527 end = timeval_add(&start, 15 * sec, 0);
2528 while (!timeval_expired(&end)) {
2530 /* get the times after the first write */
2531 GET_INFO_BOTH(finfo3,pinfo3);
2533 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2534 double diff = timeval_elapsed(&start);
2535 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2541 smb_msleep(1 * msec);
2544 GET_INFO_BOTH(finfo3,pinfo3);
2545 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2546 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2547 torture_comment(tctx, "Server did not update write_time (correct)\n");
2550 /* Do any further write (truncates) update the write time ? */
2551 start = timeval_current();
2552 end = timeval_add(&start, 15 * sec, 0);
2553 while (!timeval_expired(&end)) {
2555 torture_comment(tctx, "Do a truncate write on the file handle\n");
2556 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2558 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2562 /* get the times after the write */
2563 GET_INFO_BOTH(finfo4,pinfo4);
2565 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2566 double diff = timeval_elapsed(&start);
2567 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2573 smb_msleep(1 * msec);
2576 GET_INFO_BOTH(finfo4,pinfo4);
2577 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2578 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2579 torture_comment(tctx, "Server did not update write_time (correct)\n");
2583 smb_msleep(5 * msec);
2585 GET_INFO_BOTH(finfo5,pinfo5);
2586 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2589 * the close doesn't update the write time
2591 torture_comment(tctx, "Close the file handle\n");
2592 smbcli_close(cli->tree, fnum1);
2595 GET_INFO_PATH(pinfo6);
2596 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2598 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2599 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2604 smbcli_close(cli->tree, fnum1);
2605 smbcli_unlink(cli->tree, fname);
2606 smbcli_deltree(cli->tree, BASEDIR);
2612 * Open 2 handles on a file. Write one one and then set the
2613 * WRITE TIME explicitly on the other. Ensure the write time
2614 * update is cancelled. Ensure the write time is updated to
2615 * the close time when the non-explicit set handle is closed.
2619 static bool test_delayed_write_update6(struct torture_context *tctx,
2620 struct smbcli_state *cli,
2621 struct smbcli_state *cli2)
2623 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2624 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2625 const char *fname = BASEDIR "\\torture_file6.txt";
2630 struct timeval start;
2632 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2633 int normal_delay = 2000000;
2634 double sec = ((double)used_delay) / ((double)normal_delay);
2635 int msec = 1000 * sec;
2638 torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2640 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2642 torture_comment(tctx, "Open the file handle\n");
2643 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2646 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2651 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2652 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2655 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2660 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2661 finfo0.basic_info.in.file.fnum = fnum1;
2667 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2668 pinfo0.basic_info.in.file.path = fname;
2677 /* get the initial times */
2678 GET_INFO_BOTH(finfo0,pinfo0);
2681 torture_comment(tctx, "Do a write on the file handle\n");
2682 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2684 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2689 GET_INFO_BOTH(finfo1,pinfo1);
2690 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2692 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2693 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2694 GET_INFO_BOTH(finfo2,pinfo2);
2695 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2697 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2698 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2699 GET_INFO_BOTH(finfo2,pinfo2);
2700 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2702 /* make sure the 2 second delay from the first write are canceled */
2703 start = timeval_current();
2704 end = timeval_add(&start, 10 * sec, 0);
2705 while (!timeval_expired(&end)) {
2707 /* get the times after the first write */
2708 GET_INFO_BOTH(finfo3,pinfo3);
2710 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2711 double diff = timeval_elapsed(&start);
2712 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2718 smb_msleep(1 * msec);
2721 GET_INFO_BOTH(finfo3,pinfo3);
2722 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2723 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2724 torture_comment(tctx, "Server did not update write_time (correct)\n");
2727 /* sure any further write doesn't update the write time */
2728 start = timeval_current();
2729 end = timeval_add(&start, 10 * sec, 0);
2730 while (!timeval_expired(&end)) {
2732 torture_comment(tctx, "Do a write on the file handle\n");
2733 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2735 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2739 /* get the times after the write */
2740 GET_INFO_BOTH(finfo4,pinfo4);
2742 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2743 double diff = timeval_elapsed(&start);
2744 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2750 smb_msleep(1 * msec);
2753 GET_INFO_BOTH(finfo4,pinfo4);
2754 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2755 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2756 torture_comment(tctx, "Server did not update write_time (correct)\n");
2760 smb_msleep(5 * msec);
2762 GET_INFO_BOTH(finfo5,pinfo5);
2763 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2766 * the close updates the write time to the time of the close
2767 * as the write time was set on the 2nd handle
2769 torture_comment(tctx, "Close the file handle\n");
2770 smbcli_close(cli->tree, fnum1);
2773 GET_INFO_PATH(pinfo6);
2774 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2776 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2777 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2780 /* See what the second write handle thinks the time is ? */
2781 finfo5.basic_info.in.file.fnum = fnum2;
2782 GET_INFO_FILE2(finfo5);
2783 COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
2785 /* See if we have lost the sticky write time on handle2 */
2786 smb_msleep(3 * msec);
2787 torture_comment(tctx, "Have we lost the sticky write time ?\n");
2789 /* Make sure any further normal write doesn't update the write time */
2790 start = timeval_current();
2791 end = timeval_add(&start, 10 * sec, 0);
2792 while (!timeval_expired(&end)) {
2794 torture_comment(tctx, "Do a write on the second file handle\n");
2795 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
2797 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2801 /* get the times after the write */
2802 GET_INFO_FILE2(finfo5);
2803 GET_INFO_PATH(pinfo6);
2805 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2806 double diff = timeval_elapsed(&start);
2807 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2813 smb_msleep(1 * msec);
2816 /* What about a truncate write ? */
2817 start = timeval_current();
2818 end = timeval_add(&start, 10 * sec, 0);
2819 while (!timeval_expired(&end)) {
2821 torture_comment(tctx, "Do a truncate write on the second file handle\n");
2822 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
2824 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2828 /* get the times after the write */
2829 GET_INFO_FILE2(finfo5);
2830 GET_INFO_PATH(pinfo6);
2832 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2833 double diff = timeval_elapsed(&start);
2834 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2840 smb_msleep(1 * msec);
2844 /* keep the 2nd handle open and rerun tests */
2851 * closing the 2nd handle will cause no write time update
2852 * as the write time was explicit set on this handle
2854 torture_comment(tctx, "Close the 2nd file handle\n");
2855 smbcli_close(cli2->tree, fnum2);
2858 GET_INFO_PATH(pinfo7);
2859 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2861 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2862 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2867 smbcli_close(cli->tree, fnum1);
2869 smbcli_close(cli2->tree, fnum2);
2870 smbcli_unlink(cli->tree, fname);
2871 smbcli_deltree(cli->tree, BASEDIR);
2876 static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
2878 union smb_open open_parms;
2879 union smb_fileinfo finfo1, finfo2, finfo3;
2880 const char *fname = BASEDIR "\\torture_file7.txt";
2884 TALLOC_CTX *mem_ctx;
2886 torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2888 mem_ctx = talloc_init("test_delayed_write_update7");
2889 if (!mem_ctx) return false;
2891 ZERO_STRUCT(finfo1);
2892 ZERO_STRUCT(finfo2);
2893 ZERO_STRUCT(finfo3);
2894 ZERO_STRUCT(open_parms);
2896 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2898 /* Create the file. */
2899 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2901 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
2905 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2906 finfo1.basic_info.in.file.fnum = fnum1;
2910 /* Get the initial timestamps. */
2911 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
2913 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2915 /* Set the pending write time to a value with ns. */
2916 SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
2918 /* Get the current pending write time by fnum. */
2919 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
2921 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2923 /* Ensure the time is actually different. */
2924 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2925 torture_result(tctx, TORTURE_FAIL,
2926 "setfileinfo time matches original fileinfo time");
2930 /* Get the current pending write time by path. */
2931 finfo3.basic_info.in.file.path = fname;
2932 status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
2934 if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
2935 torture_result(tctx, TORTURE_FAIL,
2936 "qpathinfo time doesn't match fileinfo time");
2940 /* Now close the file. Re-open and check that the write
2941 time is identical to the one we wrote. */
2943 smbcli_close(cli->tree, fnum1);
2945 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
2946 open_parms.ntcreatex.in.flags = 0;
2947 open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
2948 open_parms.ntcreatex.in.file_attr = 0;
2949 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
2950 NTCREATEX_SHARE_ACCESS_READ|
2951 NTCREATEX_SHARE_ACCESS_WRITE;
2952 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
2953 open_parms.ntcreatex.in.create_options = 0;
2954 open_parms.ntcreatex.in.fname = fname;
2956 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
2957 talloc_free(mem_ctx);
2959 if (!NT_STATUS_IS_OK(status)) {
2960 torture_result(tctx, TORTURE_FAIL,
2961 "setfileinfo time matches original fileinfo time");
2965 fnum1 = open_parms.ntcreatex.out.file.fnum;
2967 /* Check the returned time matches. */
2968 if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
2969 torture_result(tctx, TORTURE_FAIL,
2970 "final open time does not match set time");
2976 smbcli_close(cli->tree, fnum1);
2978 smbcli_unlink(cli->tree, fname);
2979 smbcli_deltree(cli->tree, BASEDIR);
2984 Test if creating a file in a directory with an open handle updates the
2985 write timestamp (it should).
2987 static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
2989 union smb_fileinfo dir_info1, dir_info2;
2990 union smb_open open_parms;
2991 const char *fname = BASEDIR "\\torture_file.txt";
2996 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2997 int normal_delay = 2000000;
2998 double sec = ((double)used_delay) / ((double)normal_delay);
2999 int msec = 1000 * sec;
3000 TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
3002 if (!mem_ctx) return false;
3004 torture_comment(tctx, "\nRunning test directory write update\n");
3006 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
3008 /* Open a handle on the directory - and leave it open. */
3009 ZERO_STRUCT(open_parms);
3010 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3011 open_parms.ntcreatex.in.flags = 0;
3012 open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
3013 open_parms.ntcreatex.in.file_attr = 0;
3014 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3015 NTCREATEX_SHARE_ACCESS_READ|
3016 NTCREATEX_SHARE_ACCESS_WRITE;
3017 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3018 open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
3019 open_parms.ntcreatex.in.fname = BASEDIR;
3021 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3022 talloc_free(mem_ctx);
3024 if (!NT_STATUS_IS_OK(status)) {
3025 torture_result(tctx, TORTURE_FAIL,
3026 "failed to open directory handle");
3031 fnum1 = open_parms.ntcreatex.out.file.fnum;
3033 /* Store the returned write time. */
3034 ZERO_STRUCT(dir_info1);
3035 dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
3037 torture_comment(tctx, "Initial write time %s\n",
3038 nt_time_string(tctx, dir_info1.basic_info.out.write_time));
3041 smb_msleep(3 * msec);
3043 /* Now create a file within the directory. */
3044 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3046 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
3050 smbcli_close(cli->tree, fnum2);
3052 /* Read the directory write time again. */
3053 ZERO_STRUCT(dir_info2);
3054 dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3055 dir_info2.basic_info.in.file.fnum = fnum1;
3057 status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
3059 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
3061 /* Ensure it's been incremented. */
3062 COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
3064 torture_comment(tctx, "Updated write time %s\n",
3065 nt_time_string(tctx, dir_info2.basic_info.out.write_time));
3070 smbcli_close(cli->tree, fnum1);
3071 smbcli_unlink(cli->tree, fname);
3072 smbcli_deltree(cli->tree, BASEDIR);
3077 #undef COMPARE_WRITE_TIME_CMP
3078 #undef COMPARE_ACCESS_TIME_CMP
3080 #define COMPARE_TIME_CMP(given, gelem, correct, celem, cmp) do { \
3081 const uint64_t _r = 10*1000*1000; \
3082 NTTIME _g = (given).basic_info.out.gelem; \
3083 NTTIME _gr = (_g / _r) * _r; \
3084 NTTIME _c = (correct).basic_info.out.celem; \
3085 NTTIME _cr = (_c / _r) * _r; \
3086 bool _strict = torture_setting_bool(tctx, "strict mode", false); \
3087 const char *_err = NULL; \
3088 if (_strict && (_g cmp _c)) { \
3090 } else if ((_g cmp _c) && (_gr cmp _cr)) { \
3091 /* handle filesystem without high resolution timestamps */ \
3094 if (_err != NULL) { \
3095 struct timeval _gtv; \
3096 struct timeval _ctv; \
3097 struct timeval_buf _gtvb; \
3098 struct timeval_buf _ctvb; \
3099 nttime_to_timeval(&_gtv, _g); \
3100 nttime_to_timeval(&_ctv, _c); \
3101 torture_result(tctx, TORTURE_FAIL, \
3102 __location__": %s wrong (%s.%s)%s %s (%s.%s)%s", \
3105 timeval_str_buf(&_gtv, false, true, &_gtvb), \
3108 timeval_str_buf(&_ctv, false, true, &_ctvb)); \
3113 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
3114 COMPARE_TIME_CMP(given, write_time, correct, write_time, cmp); \
3116 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
3117 COMPARE_WRITE_TIME_CMP(given,correct,!=)
3118 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
3119 COMPARE_WRITE_TIME_CMP(given,correct,<=)
3121 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
3122 COMPARE_TIME_CMP(given, access_time, correct, access_time, cmp); \
3124 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
3125 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
3126 #define COMPARE_ACCESS_TIME_GREATER(given,correct) \
3127 COMPARE_ACCESS_TIME_CMP(given,correct,<=)
3129 #define COMPARE_CHANGE_TIME_CMP(given, correct, cmp) do { \
3130 COMPARE_TIME_CMP(given, change_time, correct, change_time, cmp); \
3132 #define COMPARE_CHANGE_TIME_EQUAL(given,correct) \
3133 COMPARE_CHANGE_TIME_CMP(given,correct,!=)
3134 #define COMPARE_CHANGE_TIME_GREATER(given,correct) \
3135 COMPARE_CHANGE_TIME_CMP(given,correct,<=)
3137 #define COMPARE_CREATE_TIME_CMP(given, correct, cmp) do { \
3138 COMPARE_TIME_CMP(given, create_time, correct, create_time, cmp); \
3140 #define COMPARE_CREATE_TIME_EQUAL(given,correct) \
3141 COMPARE_CREATE_TIME_CMP(given,correct,!=)
3143 #define COMPARE_ALL_TIMES_EQUAL(given,correct) do { \
3144 COMPARE_WRITE_TIME_EQUAL(given,correct); \
3145 COMPARE_CHANGE_TIME_EQUAL(given,correct); \
3146 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
3147 COMPARE_CREATE_TIME_EQUAL(given,correct); \
3150 #define COMPARE_TIMES_AFTER_WRITE(given,correct) do { \
3151 COMPARE_WRITE_TIME_GREATER(given,correct); \
3152 COMPARE_CHANGE_TIME_GREATER(given,correct); \
3153 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
3154 COMPARE_CREATE_TIME_EQUAL(given,correct); \
3155 COMPARE_TIME_CMP(given, change_time, given, write_time, !=); \
3158 struct test_delaywrite_delaywrite1_state {
3159 struct torture_context *tctx;
3160 struct smbcli_state *cli1;
3161 struct smbcli_state *cli2;
3167 static bool test_delaywrite_delaywrite1_get_info(void *private_data,
3168 union smb_fileinfo *finfo)
3170 struct test_delaywrite_delaywrite1_state *state =
3171 (struct test_delaywrite_delaywrite1_state *)private_data;
3172 struct torture_context *tctx = state->tctx;
3173 struct smbcli_state *cli = state->cli1;
3174 struct smbcli_state *cli2 = state->cli2;
3175 struct smbcli_state *tmpcli = NULL;
3176 union smb_fileinfo t1finfo;
3177 union smb_fileinfo t2finfo;
3178 union smb_fileinfo t2pinfo;
3181 ZERO_STRUCTP(finfo);
3183 ZERO_STRUCT(t1finfo);
3184 t1finfo.basic_info.level = RAW_FILEINFO_BASIC_INFORMATION;
3185 t1finfo.basic_info.in.file.fnum = state->fnum1;
3187 ZERO_STRUCT(t2finfo);
3188 t2finfo.basic_info.level = RAW_FILEINFO_BASIC_INFORMATION;
3189 t2finfo.basic_info.in.file.fnum = state->fnum2;
3190 ZERO_STRUCT(t2pinfo);
3191 t2pinfo.basic_info.level = RAW_FILEINFO_BASIC_INFORMATION;
3192 t2pinfo.basic_info.in.file.path = state->fname;
3194 if (state->fnum2 != -1) {
3195 GET_INFO_FILE2(t2finfo);
3199 if (0) GET_INFO_PATH(t2pinfo);
3201 GET_INFO_FILE(t1finfo);
3203 if (t1finfo.basic_info.out.write_time != t2finfo.basic_info.out.write_time) {
3205 * There was a race, get it again on handle 2,
3206 * but then they have to match.
3208 if (state->fnum2 != -1) {
3209 GET_INFO_FILE2(t2finfo);
3211 if (0) GET_INFO_PATH(t2pinfo);
3213 if (state->fnum2 != -1) {
3214 COMPARE_ALL_TIMES_EQUAL(t1finfo, t2finfo);
3216 COMPARE_ALL_TIMES_EQUAL(t1finfo, t2pinfo);
3218 finfo->basic_info.out = t1finfo.basic_info.out;
3223 static bool test_delaywrite_delaywrite1_write_data(void *private_data)
3225 struct test_delaywrite_delaywrite1_state *state =
3226 (struct test_delaywrite_delaywrite1_state *)private_data;
3227 struct torture_context *tctx = state->tctx;
3231 nwritten = smbcli_write(state->cli1->tree, state->fnum1, 0, "x", 0, 1);
3232 torture_assert_int_equal_goto(tctx, nwritten, 1,
3233 ret, done, "smbcli_write");
3239 static bool test_delaywrite_delaywrite1_close(void *private_data,
3240 union smb_fileinfo *finfo)
3242 struct test_delaywrite_delaywrite1_state *state =
3243 (struct test_delaywrite_delaywrite1_state *)private_data;
3244 struct torture_context *tctx = state->tctx;
3245 struct smbcli_state *cli2 = state->cli2;
3246 union smb_fileinfo t2finfo;
3247 union smb_fileinfo t2pinfo;
3250 ZERO_STRUCTP(finfo);
3253 * the close updates the write time to the time of the close
3254 * and not to the time of the last write!
3256 torture_comment(tctx, "Close the file handle\n");
3257 smbcli_close(state->cli1->tree, state->fnum1);
3260 ZERO_STRUCT(t2finfo);
3261 t2finfo.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3262 t2finfo.basic_info.in.file.fnum = state->fnum2;
3263 ZERO_STRUCT(t2pinfo);
3264 t2pinfo.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3265 t2pinfo.basic_info.in.file.path = state->fname;
3267 if (state->fnum2 != -1) {
3268 GET_INFO_FILE2(t2finfo);
3271 if (state->fnum2 != -1) {
3272 smbcli_close(state->cli2->tree, state->fnum2);
3276 GET_INFO_PATH(t2pinfo);
3277 if (state->fnum2 != -1) {
3278 COMPARE_ALL_TIMES_EQUAL(t2pinfo, t2finfo);
3281 finfo->basic_info.out = t2finfo.basic_info.out;
3282 finfo->basic_info.out = t2pinfo.basic_info.out;
3288 static bool test_delaywrite_delaywrite1(struct torture_context *tctx,
3289 struct smbcli_state *cli,
3290 struct smbcli_state *cli2)
3292 struct test_delaywrite_delaywrite1_state state = {
3299 const char *fname = BASEDIR "\\torture_file3.txt";
3301 //double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3302 //double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 1000000);
3303 double normal_delay = 1000000;
3304 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", normal_delay);
3305 //double normal_delay = 1000000;
3306 //int normal_delay = 2000000;
3309 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
3311 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
3313 torture_comment(tctx, "Open the file handle\n");
3314 state.fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3315 if (state.fnum1 == -1) {
3317 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
3320 //state.fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3321 //if (state.fnum2 == -1) {
3323 // torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
3327 state.fname = fname;
3329 ok = test_delay_writetime1(tctx, used_delay, normal_delay,
3330 "run", true, /* smb1 */
3331 test_delaywrite_delaywrite1_get_info,
3332 test_delaywrite_delaywrite1_write_data,
3333 test_delaywrite_delaywrite1_close,
3335 torture_assert_goto(tctx, ok, ret, done, "test_delay_writetime1()");
3338 if (state.fnum1 != -1) {
3339 smbcli_close(cli->tree, state.fnum1);
3341 if (state.fnum2 != -1) {
3342 smbcli_close(cli2->tree, state.fnum2);
3344 smbcli_unlink(cli->tree, fname);
3345 smbcli_deltree(cli->tree, BASEDIR);
3351 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3353 struct smb2_handle _h1;
3354 struct smb2_handle *h1 = NULL;
3355 struct smb2_handle _h2;
3356 struct smb2_handle *h2 = NULL;
3357 struct smb2_create cr1;
3358 struct smb2_create cr2;
3359 union smb_fileinfo c1finfoCR, c1finfo0, c1finfo1, c1finfo2, c1finfoCL;
3360 union smb_fileinfo c2finfoCR, c2finfo0, c2finfo1, c2finfo2, c2finfo3, c2finfoCL;
3361 struct smb2_close cl1;
3362 struct smb2_close cl2;
3363 //double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3364 //double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 1000000);
3365 double normal_delay = 1000000;
3366 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", normal_delay);
3367 //double normal_delay = 1000000;
3368 //int normal_delay = 2000000;
3369 double sec = ((double)used_delay) / ((double)normal_delay);
3370 int msec = 1000 * sec;
3374 /* Choose a random name in case the state is left a little funky. */
3375 snprintf(fname, 256, "durable_open_delaywrite1_%s.dat",
3376 generate_random_str(tctx, 8));
3378 smb2_util_unlink(tree1, fname);
3380 smb2_oplock_create_share(&cr1, fname,
3381 smb2_util_share_access(""),
3382 smb2_util_oplock_level("b"));
3383 cr1.in.durable_open = true;
3385 status = smb2_create(tree1, mem_ctx, &cr1);
3386 CHECK_STATUS(status, NT_STATUS_OK);
3387 _h1 = cr1.out.file.handle;
3389 CHECK_CREATED(&cr1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
3390 CHECK_VAL(cr1.out.oplock_level, smb2_util_oplock_level("b"));
3391 CHECK_VAL(cr1.out.durable_open, true);
3392 CHECK_VAL(cr1.out.durable_open_v2, false);
3393 CHECK_VAL(cr1.out.persistent_open, false);
3396 cr2.in.desired_access = SEC_FILE_READ_ATTRIBUTE;
3397 cr2.in.durable_open = false;
3398 cr2.in.oplock_level = 0;
3399 cr2.in.create_disposition = NTCREATEX_DISP_OPEN;
3400 status = smb2_create(tree2, mem_ctx, &cr2);
3401 CHECK_STATUS(status, NT_STATUS_OK);
3402 _h2 = cr2.out.file.handle;
3404 CHECK_CREATED(&cr2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
3405 CHECK_VAL(cr2.out.oplock_level, 0);
3406 CHECK_VAL(cr2.out.durable_open, false);
3407 CHECK_VAL(cr2.out.durable_open_v2, false);
3408 CHECK_VAL(cr2.out.persistent_open, false);
3410 ZERO_STRUCT(c1finfoCR);
3411 c1finfoCR.basic_info.out.create_time = cr1.out.create_time;
3412 c1finfoCR.basic_info.out.access_time = cr1.out.access_time;
3413 c1finfoCR.basic_info.out.write_time = cr1.out.write_time;
3414 c1finfoCR.basic_info.out.change_time = cr1.out.change_time;
3415 c1finfoCR.basic_info.out.attrib = cr1.out.file_attr;
3417 ZERO_STRUCT(c2finfoCR);
3418 c2finfoCR.basic_info.out.create_time = cr2.out.create_time;
3419 c2finfoCR.basic_info.out.access_time = cr2.out.access_time;
3420 c2finfoCR.basic_info.out.write_time = cr2.out.write_time;
3421 c2finfoCR.basic_info.out.change_time = cr2.out.change_time;
3422 c2finfoCR.basic_info.out.attrib = cr2.out.file_attr;
3424 COMPARE_ALL_TIMES_EQUAL(c1finfoCR, c2finfoCR);
3426 ZERO_STRUCT(c1finfo0);
3427 c1finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFORMATION;
3428 c1finfo0.basic_info.in.file.handle = *h1;
3429 c1finfo1 = c1finfo0;
3430 c1finfo2 = c1finfo0;
3432 ZERO_STRUCT(c2finfo0);
3433 c2finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFORMATION;
3434 c2finfo0.basic_info.in.file.handle = *h2;
3435 c2finfo1 = c2finfo0;
3436 c2finfo2 = c2finfo0;
3437 c2finfo3 = c2finfo0;
3439 GET_INFO_BOTH(c1finfo0, c2finfo0);
3440 COMPARE_ALL_TIMES_EQUAL(c1finfo0, c1finfoCR);
3445 ok = test_delay_writetime1(tctx, used_delay, normal_delay,
3447 test_delaywrite_delaywrite1_get_info,
3448 test_delaywrite_delaywrite1_write_data,
3450 torture_assert(tctx, ok, "test_delay_writetime1(1)");
3451 ok = test_delay_writetime1(tctx, used_delay, normal_delay,
3453 test_delaywrite_delaywrite1_get_info,
3454 test_delaywrite_delaywrite1_write_data,
3456 torture_assert(tctx, ok, "test_delay_writetime2(2)");
3458 GET_INFO_BOTH(c1finfo1, c2finfo1);
3459 COMPARE_TIMES_AFTER_WRITE(c1finfo1, c1finfo0);
3462 torture_comment(tctx, "Sleep ...\n");
3463 smb_msleep(5 * msec);
3464 torture_comment(tctx, "... continue\n");
3466 GET_INFO_BOTH(c1finfo2, c2finfo2);
3467 COMPARE_ALL_TIMES_EQUAL(c1finfo2, c1finfo1);
3470 * the close updates the write time to the time of the close
3471 * and not to the time of the last write!
3473 torture_comment(tctx, "Close the file handle\n");
3476 cl1.in.file.handle = *h1;
3477 cl1.in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
3478 status = smb2_close(tree1, &cl1);
3479 CHECK_STATUS(status, NT_STATUS_OK);
3481 ZERO_STRUCT(c1finfoCL);
3482 c1finfoCL.basic_info.out.create_time = cl1.out.create_time;
3483 c1finfoCL.basic_info.out.access_time = cl1.out.access_time;
3484 c1finfoCL.basic_info.out.write_time = cl1.out.write_time;
3485 c1finfoCL.basic_info.out.change_time = cl1.out.change_time;
3486 c1finfoCL.basic_info.out.attrib = cl1.out.file_attr;
3487 COMPARE_ALL_TIMES_EQUAL(c1finfoCL, c1finfo2);
3489 GET_INFO_FILE(tree2, c2finfo3);
3490 COMPARE_ALL_TIMES_EQUAL(c2finfo3, c1finfoCL);
3493 cl2.in.file.handle = *h2;
3494 cl2.in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION;
3495 status = smb2_close(tree2, &cl2);
3496 CHECK_STATUS(status, NT_STATUS_OK);
3498 ZERO_STRUCT(c2finfoCL);
3499 c2finfoCL.basic_info.out.create_time = cl2.out.create_time;
3500 c2finfoCL.basic_info.out.access_time = cl2.out.access_time;
3501 c2finfoCL.basic_info.out.write_time = cl2.out.write_time;
3502 c2finfoCL.basic_info.out.change_time = cl2.out.change_time;
3503 c2finfoCL.basic_info.out.attrib = cl2.out.file_attr;
3504 COMPARE_ALL_TIMES_EQUAL(c2finfoCL, c1finfoCL);
3508 smb2_util_close(tree1, *h1);
3511 smb2_util_close(tree2, *h2);
3514 smb2_util_unlink(tree1, fname);
3519 talloc_free(mem_ctx);
3525 testing of delayed update of write_time
3527 struct torture_suite *torture_delay_write(TALLOC_CTX *ctx)
3529 struct torture_suite *suite = torture_suite_create(ctx, "delaywrite");
3531 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
3532 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
3533 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
3534 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
3535 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
3536 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
3537 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
3538 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
3539 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
3540 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
3541 torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
3542 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
3543 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
3544 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
3545 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
3546 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3547 torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);
3548 torture_suite_add_2smb_test(suite, "delaywrite1", test_delaywrite_delaywrite1);