2 Unix SMB/CIFS implementation.
4 test suite for delayed write update
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Andrew Tridgell 2004
8 Copyright (C) Jeremy Allison 2004
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "torture/torture.h"
26 #include "libcli/raw/libcliraw.h"
27 #include "libcli/raw/raw_proto.h"
28 #include "system/time.h"
29 #include "system/filesys.h"
30 #include "libcli/libcli.h"
31 #include "torture/util.h"
32 #include "torture/basic/proto.h"
34 #define BASEDIR "\\delaywrite"
36 static bool test_delayed_write_update(struct torture_context *tctx, struct smbcli_state *cli)
38 union smb_fileinfo finfo1, finfo2;
39 const char *fname = BASEDIR "\\torture_file.txt";
46 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
47 int normal_delay = 2000000;
48 double sec = ((double)used_delay) / ((double)normal_delay);
49 int msec = 1000 * sec;
51 torture_comment(tctx, "\nRunning test_delayed_write_update\n");
53 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
55 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
56 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
57 "Failed to open %s", fname));
59 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
60 finfo1.basic_info.in.file.fnum = fnum1;
63 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
64 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
66 torture_comment(tctx, "Initial write time %s\n",
67 nt_time_string(tctx, finfo1.basic_info.out.write_time));
69 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
70 torture_assert_int_equal(tctx, written, 1,
71 "unexpected number of bytes written");
73 start = timeval_current();
74 end = timeval_add(&start, (120 * sec), 0);
75 while (!timeval_expired(&end)) {
76 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
78 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
80 torture_comment(tctx, "write time %s\n",
81 nt_time_string(tctx, finfo2.basic_info.out.write_time));
83 if (finfo1.basic_info.out.write_time !=
84 finfo2.basic_info.out.write_time)
86 double diff = timeval_elapsed(&start);
89 diff >= (used_delay / (double)1000000),
91 "Server updated write_time after %.2f "
92 "seconds (expected >= %.2f)\n",
93 diff, used_delay/(double)1000000));
95 torture_comment(tctx, "Server updated write_time after %.2f seconds (correct)\n",
100 smb_msleep(1 * msec);
103 torture_assert_u64_not_equal(tctx,
104 finfo2.basic_info.out.write_time,
105 finfo1.basic_info.out.write_time,
106 "Server did not update write time within "
110 smbcli_close(cli->tree, fnum1);
111 smbcli_unlink(cli->tree, fname);
112 smbcli_deltree(cli->tree, BASEDIR);
117 static bool test_delayed_write_update1(struct torture_context *tctx, struct smbcli_state *cli)
119 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
120 const char *fname = BASEDIR "\\torture_file1.txt";
125 struct timeval start;
127 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
128 int normal_delay = 2000000;
129 double sec = ((double)used_delay) / ((double)normal_delay);
130 int msec = 1000 * sec;
135 torture_comment(tctx, "\nRunning test_delayed_write_update1\n");
137 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
139 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
140 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
141 "Failed to open %s", fname));
143 memset(buf, 'x', 2048);
144 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
146 /* 3 second delay to ensure we get past any 2 second time
147 granularity (older systems may have that) */
148 smb_msleep(3 * msec);
150 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
151 finfo1.all_info.in.file.fnum = fnum1;
154 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
155 pinfo4.all_info.in.file.path = fname;
157 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
159 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
161 torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
162 "file size not as expected after write(2048)");
164 torture_comment(tctx, "Initial write time %s\n",
165 nt_time_string(tctx, finfo1.all_info.out.write_time));
167 /* 3 second delay to ensure we get past any 2 second time
168 granularity (older systems may have that) */
169 smb_msleep(3 * msec);
171 /* Do a zero length SMBwrite call to truncate. */
172 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
173 torture_assert_int_equal(tctx, written, 0,
174 "unexpected number of bytes written");
176 start = timeval_current();
177 end = timeval_add(&start, (120 * sec), 0);
180 while (!timeval_expired(&end)) {
181 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
183 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
185 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 1024,
186 "file not truncated to expected size "
189 torture_comment(tctx, "write time %s\n",
190 nt_time_string(tctx, finfo2.all_info.out.write_time));
192 if (finfo1.all_info.out.write_time !=
193 finfo2.all_info.out.write_time)
200 smb_msleep(1 * msec);
204 torture_assert(tctx, updated,
205 "Server did not update write time within 120 seconds");
207 torture_assert(tctx, first, talloc_asprintf(tctx,
208 "Server did not update write time immediately but only "
209 "after %.2f seconds!", timeval_elapsed(&start)));
211 torture_comment(tctx, "Server updated write time immediately. Good!\n");
214 smb_msleep(2 * msec);
216 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
217 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
218 torture_assert_int_equal(tctx, written, 1,
219 "unexpected number of bytes written");
221 start = timeval_current();
222 end = timeval_add(&start, (10*sec), 0);
223 while (!timeval_expired(&end)) {
224 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
226 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
228 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 1024,
229 "file not truncated to expected size "
232 torture_comment(tctx, "write time %s\n",
233 nt_time_string(tctx, finfo3.all_info.out.write_time));
235 torture_assert_u64_equal(tctx,
236 finfo3.all_info.out.write_time,
237 finfo2.all_info.out.write_time,
238 talloc_asprintf(tctx,
239 "Server updated write time "
240 "after %.2f seconds (wrong!)",
241 timeval_elapsed(&start)));
244 smb_msleep(1 * msec);
247 torture_comment(tctx, "Server did not update write time within 10 "
251 smb_msleep(2 * msec);
253 /* the close should trigger an write time update */
254 smbcli_close(cli->tree, fnum1);
257 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
258 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
260 torture_assert_u64_not_equal(tctx,
261 pinfo4.all_info.out.write_time,
262 finfo3.all_info.out.write_time,
263 "Server did not update write time on "
266 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
267 "Server updated write time on close, but to an earlier point "
270 torture_comment(tctx, "Server updated write time on close (correct)\n");
273 smbcli_close(cli->tree, fnum1);
274 smbcli_unlink(cli->tree, fname);
275 smbcli_deltree(cli->tree, BASEDIR);
280 /* Updating with a SMBwrite of zero length
281 * changes the write time immediately - even on expand. */
283 static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
285 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
286 const char *fname = BASEDIR "\\torture_file1a.txt";
291 struct timeval start;
293 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
294 int normal_delay = 2000000;
295 double sec = ((double)used_delay) / ((double)normal_delay);
296 int msec = 1000 * sec;
299 torture_comment(tctx, "\nRunning test_delayed_write_update1a\n");
301 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
303 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
304 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
305 "Failed to open %s", fname));
307 memset(buf, 'x', 2048);
308 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
310 /* 3 second delay to ensure we get past any 2 second time
311 granularity (older systems may have that) */
312 smb_msleep(3 * msec);
314 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
315 finfo1.all_info.in.file.fnum = fnum1;
318 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
319 pinfo4.all_info.in.file.path = fname;
321 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
323 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
325 torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
326 "file size not as expected after write(2048)");
328 torture_comment(tctx, "Initial write time %s\n",
329 nt_time_string(tctx, finfo1.all_info.out.write_time));
331 /* Do a zero length SMBwrite call to truncate. */
332 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
334 torture_assert_int_equal(tctx, written, 0,
335 "unexpected number of bytes written");
337 start = timeval_current();
338 end = timeval_add(&start, (120*sec), 0);
339 while (!timeval_expired(&end)) {
340 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
342 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
344 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
345 "file not truncated to expected size "
348 torture_comment(tctx, "write time %s\n",
349 nt_time_string(tctx, finfo2.all_info.out.write_time));
350 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
351 double diff = timeval_elapsed(&start);
352 if (diff > (0.25 * (used_delay / (double)1000000))) {
353 torture_result(tctx, TORTURE_FAIL, "After SMBwrite truncate "
354 "server updated write_time after %.2f seconds"
355 "(write time update delay == %.2f)(wrong!)\n",
356 diff, used_delay / (double)1000000);
361 torture_comment(tctx, "After SMBwrite truncate "
362 "server updated write_time after %.2f seconds"
363 "(write time update delay == %.2f)(correct)\n",
364 diff, used_delay / (double)1000000);
369 smb_msleep(1 * msec);
372 torture_assert_u64_not_equal(tctx,
373 finfo1.all_info.out.write_time,
374 finfo2.all_info.out.write_time,
375 "Server did not update write time.");
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));
399 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
400 double diff = timeval_elapsed(&start);
402 torture_result(tctx, TORTURE_FAIL, "server updated write_time after %.2f seconds"
403 "(write time update delay == %.2f)(correct)\n",
404 diff, used_delay / (double)1000000);
408 smb_msleep(1 * msec);
411 torture_assert_int_equal(tctx,
412 finfo3.all_info.out.write_time,
413 finfo2.all_info.out.write_time,
414 "Server updated write time (wrong!)");
416 /* the close should trigger an write time update */
417 smbcli_close(cli->tree, fnum1);
420 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
421 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
423 torture_assert_u64_not_equal(tctx,
424 pinfo4.all_info.out.write_time,
425 finfo3.all_info.out.write_time,
426 "Server did not update write time on "
429 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
430 "Server updated write time on close, but to an earlier point "
433 torture_comment(tctx, "Server updated write time on close (correct)\n");
436 smbcli_close(cli->tree, fnum1);
437 smbcli_unlink(cli->tree, fname);
438 smbcli_deltree(cli->tree, BASEDIR);
443 /* Updating with a SET_FILE_END_OF_FILE_INFO
444 * changes the write time immediately - even on expand. */
446 static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
448 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
449 const char *fname = BASEDIR "\\torture_file1b.txt";
454 struct timeval start;
456 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
457 int normal_delay = 2000000;
458 double sec = ((double)used_delay) / ((double)normal_delay);
459 int msec = 1000 * sec;
462 torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
464 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
466 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
468 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
472 memset(buf, 'x', 2048);
473 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
475 /* 3 second delay to ensure we get past any 2 second time
476 granularity (older systems may have that) */
477 smb_msleep(3 * msec);
479 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
480 finfo1.all_info.in.file.fnum = fnum1;
483 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
484 pinfo4.all_info.in.file.path = fname;
486 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
488 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
490 torture_comment(tctx, "Initial write time %s\n",
491 nt_time_string(tctx, finfo1.all_info.out.write_time));
493 /* Do a SET_END_OF_FILE_INFO call to truncate. */
494 status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
496 torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
498 start = timeval_current();
499 end = timeval_add(&start, (120*sec), 0);
500 while (!timeval_expired(&end)) {
501 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
503 if (!NT_STATUS_IS_OK(status)) {
504 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
509 if (finfo2.all_info.out.size != 10240) {
510 torture_result(tctx, TORTURE_FAIL,
511 "file not truncated (size = %u, should be 10240)",
512 (unsigned int)finfo2.all_info.out.size );
517 torture_comment(tctx, "write time %s\n",
518 nt_time_string(tctx, finfo2.all_info.out.write_time));
519 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
520 double diff = timeval_elapsed(&start);
521 if (diff > (0.25 * (used_delay / (double)1000000))) {
522 torture_result(tctx, TORTURE_FAIL,
523 "After SET_END_OF_FILE truncate "
524 "server updated write_time after %.2f seconds"
525 "(write time update delay == %.2f)(wrong!)",
526 diff, used_delay / (double)1000000);
531 torture_comment(tctx, "After SET_END_OF_FILE truncate "
532 "server updated write_time after %.2f seconds"
533 "(write time update delay == %.2f)(correct)\n",
534 diff, used_delay / (double)1000000);
538 smb_msleep(1 * msec);
541 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
542 torture_result(tctx, TORTURE_FAIL,
543 "Server did not update write time (wrong!)");
548 smb_msleep(2 * msec);
550 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
551 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
553 torture_assert_int_equal(tctx, written, 1,
554 "unexpected number of bytes written");
556 start = timeval_current();
557 end = timeval_add(&start, (10*sec), 0);
558 while (!timeval_expired(&end)) {
559 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
561 if (!NT_STATUS_IS_OK(status)) {
562 torture_result(tctx, TORTURE_FAIL,
563 "fileinfo failed: %s", nt_errstr(status));
568 if (finfo3.all_info.out.size != 10240) {
569 DEBUG(0, ("file not truncated (size = %u, should be 10240)\n",
570 (unsigned int)finfo3.all_info.out.size ));
575 torture_comment(tctx, "write time %s\n",
576 nt_time_string(tctx, finfo3.all_info.out.write_time));
577 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
578 double diff = timeval_elapsed(&start);
580 torture_comment(tctx, "server updated write_time after %.2f seconds"
581 "(write time update delay == %.2f)(correct)\n",
582 diff, used_delay / (double)1000000);
586 smb_msleep(1 * msec);
589 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
590 torture_result(tctx, TORTURE_FAIL, "Server updated write time (wrong!)\n");
594 /* the close should trigger an write time update */
595 smbcli_close(cli->tree, fnum1);
598 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
599 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
601 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
602 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
604 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
605 torture_comment(tctx, "Server updated write time on close (correct)\n");
609 smbcli_close(cli->tree, fnum1);
610 smbcli_unlink(cli->tree, fname);
611 smbcli_deltree(cli->tree, BASEDIR);
616 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
618 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
620 union smb_setfileinfo parms;
621 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
622 const char *fname = BASEDIR "\\torture_file1c.txt";
627 struct timeval start;
629 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
630 int normal_delay = 2000000;
631 double sec = ((double)used_delay) / ((double)normal_delay);
632 int msec = 1000 * sec;
635 torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
637 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
639 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
641 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
645 memset(buf, 'x', 2048);
646 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
648 /* 3 second delay to ensure we get past any 2 second time
649 granularity (older systems may have that) */
650 smb_msleep(3 * msec);
652 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
653 finfo1.all_info.in.file.fnum = fnum1;
656 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
657 pinfo4.all_info.in.file.path = fname;
659 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
661 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
663 torture_comment(tctx, "Initial write time %s\n",
664 nt_time_string(tctx, finfo1.all_info.out.write_time));
666 /* Do a SET_ALLOCATION_SIZE call to truncate. */
667 parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
668 parms.allocation_info.in.file.fnum = fnum1;
669 parms.allocation_info.in.alloc_size = 0;
671 status = smb_raw_setfileinfo(cli->tree, &parms);
673 torture_assert_ntstatus_ok(tctx, status,
674 "RAW_SFILEINFO_ALLOCATION_INFO failed");
676 start = timeval_current();
677 end = timeval_add(&start, (120*sec), 0);
678 while (!timeval_expired(&end)) {
679 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
681 if (!NT_STATUS_IS_OK(status)) {
682 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
688 if (finfo2.all_info.out.size != 0) {
689 torture_result(tctx, TORTURE_FAIL,
690 "file not truncated (size = %u, should be 10240)",
691 (unsigned int)finfo2.all_info.out.size);
696 torture_comment(tctx, "write time %s\n",
697 nt_time_string(tctx, finfo2.all_info.out.write_time));
698 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
699 double diff = timeval_elapsed(&start);
700 if (diff > (0.25 * (used_delay / (double)1000000))) {
701 torture_result(tctx, TORTURE_FAIL, "After SET_ALLOCATION_INFO truncate "
702 "server updated write_time after %.2f seconds"
703 "(write time update delay == %.2f)(wrong!)\n",
704 diff, used_delay / (double)1000000);
709 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
710 "server updated write_time after %.2f seconds"
711 "(write time update delay == %.2f)(correct)\n",
712 diff, used_delay / (double)1000000);
716 smb_msleep(1 * msec);
719 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
720 torture_result(tctx, TORTURE_FAIL,
721 "Server did not update write time (wrong!)");
726 smb_msleep(2 * msec);
728 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
729 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
730 torture_assert_int_equal(tctx, written, 1,
731 "Unexpected number of bytes written");
733 start = timeval_current();
734 end = timeval_add(&start, (10*sec), 0);
735 while (!timeval_expired(&end)) {
736 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
738 if (!NT_STATUS_IS_OK(status)) {
739 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
745 if (finfo3.all_info.out.size != 1) {
746 torture_result(tctx, TORTURE_FAIL, "file not expanded");
751 torture_comment(tctx, "write time %s\n",
752 nt_time_string(tctx, finfo3.all_info.out.write_time));
753 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
754 double diff = timeval_elapsed(&start);
756 torture_comment(tctx, "server updated write_time after %.2f seconds"
757 "(write time update delay == %.2f)(wrong)\n",
758 diff, used_delay / (double)1000000);
762 smb_msleep(1 * msec);
765 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
766 torture_result(tctx, TORTURE_FAIL,
767 "Server updated write time (wrong!)");
771 /* the close should trigger an write time update */
772 smbcli_close(cli->tree, fnum1);
775 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
776 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
778 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
779 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
781 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
782 torture_comment(tctx, "Server updated write time on close (correct)\n");
786 smbcli_close(cli->tree, fnum1);
787 smbcli_unlink(cli->tree, fname);
788 smbcli_deltree(cli->tree, BASEDIR);
794 * Do as above, but using 2 connections.
797 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
798 struct smbcli_state *cli2)
800 union smb_fileinfo finfo1, finfo2;
801 const char *fname = BASEDIR "\\torture_file.txt";
807 struct timeval start;
809 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
810 int normal_delay = 2000000;
811 double sec = ((double)used_delay) / ((double)normal_delay);
812 int msec = 1000 * sec;
813 union smb_flush flsh;
815 torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
817 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
819 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
821 torture_comment(tctx, "Failed to open %s\n", fname);
825 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
826 finfo1.basic_info.in.file.fnum = fnum1;
829 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
831 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
833 torture_comment(tctx, "Initial write time %s\n",
834 nt_time_string(tctx, finfo1.basic_info.out.write_time));
836 /* 3 second delay to ensure we get past any 2 second time
837 granularity (older systems may have that) */
838 smb_msleep(3 * msec);
841 /* Try using setfileinfo instead of write to update write time. */
842 union smb_setfileinfo sfinfo;
843 time_t t_set = time(NULL);
844 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
845 sfinfo.basic_info.in.file.fnum = fnum1;
846 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
847 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
849 /* I tried this with both + and - ve to see if it makes a different.
850 It doesn't - once the filetime is set via setfileinfo it stays that way. */
852 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
854 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
856 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
857 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
859 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
861 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
864 finfo2.basic_info.in.file.path = fname;
866 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
868 if (!NT_STATUS_IS_OK(status)) {
869 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
872 torture_comment(tctx, "write time %s\n",
873 nt_time_string(tctx, finfo2.basic_info.out.write_time));
875 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
876 torture_comment(tctx, "Server updated write_time (correct)\n");
878 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
882 /* Now try a write to see if the write time gets reset. */
884 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
885 finfo1.basic_info.in.file.fnum = fnum1;
888 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
890 if (!NT_STATUS_IS_OK(status)) {
891 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
895 torture_comment(tctx, "Modified write time %s\n",
896 nt_time_string(tctx, finfo1.basic_info.out.write_time));
899 torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
901 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
904 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
905 (int)written, __location__);
909 /* Just to prove to tridge that the an smbflush has no effect on
910 the write time :-). The setfileinfo IS STICKY. JRA. */
912 torture_comment(tctx, "Doing flush after write\n");
914 flsh.flush.level = RAW_FLUSH_FLUSH;
915 flsh.flush.in.file.fnum = fnum1;
916 status = smb_raw_flush(cli->tree, &flsh);
917 if (!NT_STATUS_IS_OK(status)) {
918 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
922 /* Once the time was set using setfileinfo then it stays set - writes
923 don't have any effect. But make sure. */
924 start = timeval_current();
925 end = timeval_add(&start, (15*sec), 0);
926 while (!timeval_expired(&end)) {
927 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
929 if (!NT_STATUS_IS_OK(status)) {
930 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
934 torture_comment(tctx, "write time %s\n",
935 nt_time_string(tctx, finfo2.basic_info.out.write_time));
936 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
937 double diff = timeval_elapsed(&start);
938 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
945 smb_msleep(1 * msec);
948 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
949 torture_comment(tctx, "Server did not update write time (correct)\n");
953 smb_msleep(2 * msec);
955 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
957 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
961 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");
963 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
966 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
967 (int)written, __location__);
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 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
985 smbcli_close(cli->tree, fnum1);
988 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");
990 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
993 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
994 (int)written, __location__);
998 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
999 finfo1.basic_info.in.file.fnum = fnum2;
1001 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1003 if (!NT_STATUS_IS_OK(status)) {
1004 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1007 torture_comment(tctx, "write time %s\n",
1008 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1009 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1010 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1014 /* Once the time was set using setfileinfo then it stays set - writes
1015 don't have any effect. But make sure. */
1016 start = timeval_current();
1017 end = timeval_add(&start, (15*sec), 0);
1018 while (!timeval_expired(&end)) {
1019 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1021 if (!NT_STATUS_IS_OK(status)) {
1022 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1026 torture_comment(tctx, "write time %s\n",
1027 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1028 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1029 double diff = timeval_elapsed(&start);
1030 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1037 smb_msleep(1 * msec);
1040 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1041 torture_comment(tctx, "Server did not update write time (correct)\n");
1044 torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1046 smbcli_close(cli->tree, fnum2);
1049 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1051 torture_comment(tctx, "Failed to open %s\n", fname);
1055 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1056 finfo1.basic_info.in.file.fnum = fnum1;
1059 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1061 if (!NT_STATUS_IS_OK(status)) {
1062 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1066 torture_comment(tctx, "Second open initial write time %s\n",
1067 nt_time_string(tctx, finfo1.basic_info.out.write_time));
1069 smb_msleep(10 * msec);
1070 torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1072 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1074 if (written != 10) {
1075 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1076 (int)written, __location__);
1080 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1081 finfo1.basic_info.in.file.fnum = fnum1;
1083 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1085 if (!NT_STATUS_IS_OK(status)) {
1086 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1089 torture_comment(tctx, "write time %s\n",
1090 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1091 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1092 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1096 /* Now the write time should be updated again */
1097 start = timeval_current();
1098 end = timeval_add(&start, (15*sec), 0);
1099 while (!timeval_expired(&end)) {
1100 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1102 if (!NT_STATUS_IS_OK(status)) {
1103 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1107 torture_comment(tctx, "write time %s\n",
1108 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1109 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1110 double diff = timeval_elapsed(&start);
1111 if (diff < (used_delay / (double)1000000)) {
1112 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1113 "(expected > %.2f) (wrong!)\n",
1114 diff, used_delay / (double)1000000);
1119 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1128 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1129 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
1134 /* One more test to do. We should read the filetime via findfirst on the
1135 second connection to ensure it's the same. This is very easy for a Windows
1136 server but a bastard to get right on a POSIX server. JRA. */
1139 smbcli_close(cli->tree, fnum1);
1140 smbcli_unlink(cli->tree, fname);
1141 smbcli_deltree(cli->tree, BASEDIR);
1147 /* Windows does obviously not update the stat info during a write call. I
1148 * *think* this is the problem causing a spurious Excel 2003 on XP error
1149 * message when saving a file. Excel does a setfileinfo, writes, and then does
1150 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1151 * that the file might have been changed in between. What i've been able to
1152 * trace down is that this happens if the getpathinfo after the write shows a
1153 * different last write time than the setfileinfo showed. This is really
1157 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
1158 struct smbcli_state *cli2)
1160 union smb_fileinfo finfo1, finfo2;
1161 const char *fname = BASEDIR "\\torture_file.txt";
1167 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1168 int normal_delay = 2000000;
1169 double sec = ((double)used_delay) / ((double)normal_delay);
1170 int msec = 1000 * sec;
1172 torture_comment(tctx, "\nRunning test_finfo_after_write\n");
1174 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1176 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1179 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1183 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1184 finfo1.basic_info.in.file.fnum = fnum1;
1186 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1188 if (!NT_STATUS_IS_OK(status)) {
1190 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1194 smb_msleep(1 * msec);
1196 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1199 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1204 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1206 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1207 smbcli_errstr(cli2->tree));
1212 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1215 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1221 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1222 finfo2.basic_info.in.file.path = fname;
1224 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1226 if (!NT_STATUS_IS_OK(status)) {
1227 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
1233 if (finfo1.basic_info.out.create_time !=
1234 finfo2.basic_info.out.create_time) {
1235 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1240 if (finfo1.basic_info.out.access_time !=
1241 finfo2.basic_info.out.access_time) {
1242 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1247 if (finfo1.basic_info.out.write_time !=
1248 finfo2.basic_info.out.write_time) {
1249 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1250 "write time conn 1 = %s, conn 2 = %s",
1251 nt_time_string(tctx, finfo1.basic_info.out.write_time),
1252 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1257 if (finfo1.basic_info.out.change_time !=
1258 finfo2.basic_info.out.change_time) {
1259 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1264 /* One of the two following calls updates the qpathinfo. */
1266 /* If you had skipped the smbcli_write on fnum2, it would
1267 * *not* have updated the stat on disk */
1269 smbcli_close(cli2->tree, fnum2);
1272 /* This call is only for the people looking at ethereal :-) */
1273 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1274 finfo2.basic_info.in.file.path = fname;
1276 status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1278 if (!NT_STATUS_IS_OK(status)) {
1279 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1286 smbcli_close(cli->tree, fnum1);
1287 smbcli_unlink(cli->tree, fname);
1288 smbcli_deltree(cli->tree, BASEDIR);
1293 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1294 uint64_t r = 10*1000*1000; \
1295 NTTIME g = (given).basic_info.out.write_time; \
1296 NTTIME gr = (g / r) * r; \
1297 NTTIME c = (correct).basic_info.out.write_time; \
1298 NTTIME cr = (c / r) * r; \
1299 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1301 if (strict && (g cmp c)) { \
1303 } else if ((g cmp c) && (gr cmp cr)) { \
1304 /* handle filesystem without high resolution timestamps */ \
1308 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1309 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1310 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1315 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1316 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1317 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1318 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1319 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1320 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1322 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1323 NTTIME g = (given).basic_info.out.access_time; \
1324 NTTIME c = (correct).basic_info.out.access_time; \
1326 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1327 #given, nt_time_string(tctx, g), \
1328 #cmp, #correct, nt_time_string(tctx, c)); \
1333 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1334 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1336 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1337 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1338 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1341 #define GET_INFO_FILE(finfo) do { \
1343 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1344 if (!NT_STATUS_IS_OK(_status)) { \
1346 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1347 nt_errstr(_status)); \
1350 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1351 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1352 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1354 #define GET_INFO_FILE2(finfo) do { \
1356 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1357 if (!NT_STATUS_IS_OK(_status)) { \
1359 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1360 nt_errstr(_status)); \
1363 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1364 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1365 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1367 #define GET_INFO_PATH(pinfo) do { \
1369 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1370 if (!NT_STATUS_IS_OK(_status)) { \
1371 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1372 nt_errstr(_status)); \
1376 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1377 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1378 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1380 #define GET_INFO_BOTH(finfo,pinfo) do { \
1381 GET_INFO_FILE(finfo); \
1382 GET_INFO_PATH(pinfo); \
1383 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1386 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1388 union smb_setfileinfo sfinfo; \
1389 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1390 sfinfo.basic_info.in.file.fnum = tfnum; \
1391 sfinfo.basic_info.in.create_time = 0; \
1392 sfinfo.basic_info.in.access_time = 0; \
1393 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1394 sfinfo.basic_info.in.change_time = 0; \
1395 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1396 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1397 if (!NT_STATUS_IS_OK(_status)) { \
1398 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1399 nt_errstr(_status)); \
1404 #define SET_INFO_FILE(finfo, wrtime) \
1405 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1407 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1409 union smb_setfileinfo sfinfo; \
1410 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1411 sfinfo.basic_info.in.file.fnum = tfnum; \
1412 sfinfo.basic_info.in.create_time = 0; \
1413 sfinfo.basic_info.in.access_time = 0; \
1414 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1415 sfinfo.basic_info.in.write_time += (ns); \
1416 sfinfo.basic_info.in.change_time = 0; \
1417 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1418 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1419 if (!NT_STATUS_IS_OK(_status)) { \
1420 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1421 nt_errstr(_status)); \
1427 static bool test_delayed_write_update3(struct torture_context *tctx,
1428 struct smbcli_state *cli,
1429 struct smbcli_state *cli2)
1431 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1432 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1433 const char *fname = BASEDIR "\\torture_file3.txt";
1437 struct timeval start;
1439 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1440 int normal_delay = 2000000;
1441 double sec = ((double)used_delay) / ((double)normal_delay);
1442 int msec = 1000 * sec;
1444 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
1446 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1448 torture_comment(tctx, "Open the file handle\n");
1449 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1452 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1456 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1457 finfo0.basic_info.in.file.fnum = fnum1;
1461 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1462 pinfo0.basic_info.in.file.path = fname;
1468 /* get the initial times */
1469 GET_INFO_BOTH(finfo0,pinfo0);
1472 * make sure the write time is updated 2 seconds later
1473 * calcuated from the first write
1474 * (but expect upto 5 seconds extra time for a busy server)
1476 start = timeval_current();
1477 end = timeval_add(&start, 7 * sec, 0);
1478 while (!timeval_expired(&end)) {
1480 torture_comment(tctx, "Do a write on the file handle\n");
1481 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1483 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1487 /* get the times after the write */
1488 GET_INFO_FILE(finfo1);
1490 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1491 double diff = timeval_elapsed(&start);
1492 if (diff < (used_delay / (double)1000000)) {
1493 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1494 "(write time update delay == %.2f) (wrong!)\n",
1495 diff, used_delay / (double)1000000);
1500 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1505 smb_msleep(0.5 * msec);
1508 GET_INFO_BOTH(finfo1,pinfo1);
1509 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1511 /* sure any further write doesn't update the write time */
1512 start = timeval_current();
1513 end = timeval_add(&start, 15 * sec, 0);
1514 while (!timeval_expired(&end)) {
1516 torture_comment(tctx, "Do a write on the file handle\n");
1517 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1519 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1523 /* get the times after the write */
1524 GET_INFO_BOTH(finfo2,pinfo2);
1526 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1527 double diff = timeval_elapsed(&start);
1528 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1534 smb_msleep(1 * msec);
1537 GET_INFO_BOTH(finfo2,pinfo2);
1538 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1539 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1540 torture_comment(tctx, "Server did not update write_time (correct)\n");
1544 smb_msleep(5 * msec);
1546 GET_INFO_BOTH(finfo3,pinfo3);
1547 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1550 * the close updates the write time to the time of the close
1551 * and not to the time of the last write!
1553 torture_comment(tctx, "Close the file handle\n");
1554 smbcli_close(cli->tree, fnum1);
1557 GET_INFO_PATH(pinfo4);
1558 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1560 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1561 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1566 smbcli_close(cli->tree, fnum1);
1567 smbcli_unlink(cli->tree, fname);
1568 smbcli_deltree(cli->tree, BASEDIR);
1574 * Show that a truncate write always updates the write time even
1575 * if an initial write has already updated the write time.
1578 static bool test_delayed_write_update3a(struct torture_context *tctx,
1579 struct smbcli_state *cli,
1580 struct smbcli_state *cli2)
1582 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1583 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1584 const char *fname = BASEDIR "\\torture_file3a.txt";
1589 struct timeval start;
1591 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1592 int normal_delay = 2000000;
1593 double sec = ((double)used_delay) / ((double)normal_delay);
1594 int msec = 1000 * sec;
1596 torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
1598 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1600 torture_comment(tctx, "Open the file handle\n");
1601 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1604 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1608 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1609 finfo0.basic_info.in.file.fnum = fnum1;
1613 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1614 pinfo0.basic_info.in.file.path = fname;
1620 /* get the initial times */
1621 GET_INFO_BOTH(finfo0,pinfo0);
1624 * sleep some time, to demonstrate the handling of write times
1625 * doesn't depend on the time since the open
1627 smb_msleep(5 * msec);
1629 /* get the initial times */
1630 GET_INFO_BOTH(finfo1,pinfo1);
1631 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1634 * make sure the write time is updated 2 seconds later
1635 * calcuated from the first write
1636 * (but expect upto 5 seconds extra time for a busy server)
1638 start = timeval_current();
1639 end = timeval_add(&start, 7 * sec, 0);
1640 while (!timeval_expired(&end)) {
1642 torture_comment(tctx, "Do a write on the file handle\n");
1643 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1645 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1649 /* get the times after the write */
1650 GET_INFO_FILE(finfo1);
1652 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1653 double diff = timeval_elapsed(&start);
1654 if (diff < (used_delay / (double)1000000)) {
1655 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1656 "(1sec == %.2f) (wrong!)\n",
1662 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1667 smb_msleep(0.5 * msec);
1670 GET_INFO_BOTH(finfo1,pinfo1);
1671 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1673 smb_msleep(3 * msec);
1676 * demonstrate that a truncate write always
1677 * updates the write time immediately
1679 for (i=0; i < 3; i++) {
1680 smb_msleep(2 * msec);
1682 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1683 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1685 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1689 /* get the times after the write */
1690 GET_INFO_BOTH(finfo2,pinfo2);
1691 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1695 smb_msleep(3 * msec);
1697 /* sure any further write doesn't update the write time */
1698 start = timeval_current();
1699 end = timeval_add(&start, 15 * sec, 0);
1700 while (!timeval_expired(&end)) {
1702 torture_comment(tctx, "Do a write on the file handle\n");
1703 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1705 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1709 /* get the times after the write */
1710 GET_INFO_BOTH(finfo2,pinfo2);
1712 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1713 double diff = timeval_elapsed(&start);
1714 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1720 smb_msleep(1 * msec);
1723 GET_INFO_BOTH(finfo2,pinfo2);
1724 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1725 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1726 torture_comment(tctx, "Server did not update write_time (correct)\n");
1730 smb_msleep(3 * msec);
1732 /* get the initial times */
1733 GET_INFO_BOTH(finfo1,pinfo1);
1734 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1737 * demonstrate that a truncate write always
1738 * updates the write time immediately
1740 for (i=0; i < 3; i++) {
1741 smb_msleep(2 * msec);
1743 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1744 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1746 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1750 /* get the times after the write */
1751 GET_INFO_BOTH(finfo2,pinfo2);
1752 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1757 smb_msleep(3 * msec);
1759 GET_INFO_BOTH(finfo3,pinfo3);
1760 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1763 * the close doesn't update the write time
1765 torture_comment(tctx, "Close the file handle\n");
1766 smbcli_close(cli->tree, fnum1);
1769 GET_INFO_PATH(pinfo4);
1770 COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1772 if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1773 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1778 smbcli_close(cli->tree, fnum1);
1779 smbcli_unlink(cli->tree, fname);
1780 smbcli_deltree(cli->tree, BASEDIR);
1786 * Show a close after write updates the write timestamp to
1787 * the close time, not the last write time.
1790 static bool test_delayed_write_update3b(struct torture_context *tctx,
1791 struct smbcli_state *cli,
1792 struct smbcli_state *cli2)
1794 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1795 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1796 const char *fname = BASEDIR "\\torture_file3b.txt";
1800 struct timeval start;
1802 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1803 int normal_delay = 2000000;
1804 double sec = ((double)used_delay) / ((double)normal_delay);
1805 int msec = 1000 * sec;
1807 torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
1809 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1811 torture_comment(tctx, "Open the file handle\n");
1812 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1815 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1819 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1820 finfo0.basic_info.in.file.fnum = fnum1;
1824 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1825 pinfo0.basic_info.in.file.path = fname;
1831 /* get the initial times */
1832 GET_INFO_BOTH(finfo0,pinfo0);
1835 * sleep some time, to demonstrate the handling of write times
1836 * doesn't depend on the time since the open
1838 smb_msleep(5 * msec);
1840 /* get the initial times */
1841 GET_INFO_BOTH(finfo1,pinfo1);
1842 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1845 * make sure the write time is updated 2 seconds later
1846 * calcuated from the first write
1847 * (but expect upto 5 seconds extra time for a busy server)
1849 start = timeval_current();
1850 end = timeval_add(&start, 7 * sec, 0);
1851 while (!timeval_expired(&end)) {
1853 torture_comment(tctx, "Do a write on the file handle\n");
1854 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1856 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1860 /* get the times after the write */
1861 GET_INFO_FILE(finfo1);
1863 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1864 double diff = timeval_elapsed(&start);
1865 if (diff < (used_delay / (double)1000000)) {
1866 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1867 "(expected > %.2f) (wrong!)\n",
1868 diff, used_delay / (double)1000000);
1873 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1874 "(write time update delay == %.2f) (correct)\n",
1875 diff, used_delay / (double)1000000);
1878 smb_msleep(0.5 * msec);
1881 GET_INFO_BOTH(finfo1,pinfo1);
1882 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1884 /* sure any further write doesn't update the write time */
1885 start = timeval_current();
1886 end = timeval_add(&start, 15 * sec, 0);
1887 while (!timeval_expired(&end)) {
1889 torture_comment(tctx, "Do a write on the file handle\n");
1890 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1892 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1896 /* get the times after the write */
1897 GET_INFO_BOTH(finfo2,pinfo2);
1899 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1900 double diff = timeval_elapsed(&start);
1901 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1907 smb_msleep(1 * msec);
1910 GET_INFO_BOTH(finfo2,pinfo2);
1911 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1912 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1913 torture_comment(tctx, "Server did not update write_time (correct)\n");
1917 smb_msleep(5 * msec);
1919 GET_INFO_BOTH(finfo3,pinfo3);
1920 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1923 * the close updates the write time to the time of the close
1924 * and not to the time of the last write!
1926 torture_comment(tctx, "Close the file handle\n");
1927 smbcli_close(cli->tree, fnum1);
1930 GET_INFO_PATH(pinfo4);
1931 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1933 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1934 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1939 smbcli_close(cli->tree, fnum1);
1940 smbcli_unlink(cli->tree, fname);
1941 smbcli_deltree(cli->tree, BASEDIR);
1947 * Check that a write after a truncate write doesn't update
1948 * the timestamp, but a truncate write after a write does.
1949 * Also prove that a close after a truncate write updates the
1950 * timestamp to current, not the time of last write.
1953 static bool test_delayed_write_update3c(struct torture_context *tctx,
1954 struct smbcli_state *cli,
1955 struct smbcli_state *cli2)
1957 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1958 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1959 const char *fname = BASEDIR "\\torture_file3c.txt";
1964 struct timeval start;
1966 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1967 int normal_delay = 2000000;
1968 double sec = ((double)used_delay) / ((double)normal_delay);
1969 int msec = 1000 * sec;
1971 torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
1973 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1975 torture_comment(tctx, "Open the file handle\n");
1976 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1979 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1983 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1984 finfo0.basic_info.in.file.fnum = fnum1;
1988 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1989 pinfo0.basic_info.in.file.path = fname;
1995 /* get the initial times */
1996 GET_INFO_BOTH(finfo0,pinfo0);
1999 * sleep some time, to demonstrate the handling of write times
2000 * doesn't depend on the time since the open
2002 smb_msleep(5 * msec);
2004 /* get the initial times */
2005 GET_INFO_BOTH(finfo1,pinfo1);
2006 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2009 * demonstrate that a truncate write always
2010 * updates the write time immediately
2012 for (i=0; i < 3; i++) {
2013 smb_msleep(2 * msec);
2015 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
2016 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2018 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2022 /* get the times after the write */
2023 GET_INFO_BOTH(finfo2,pinfo2);
2024 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2028 start = timeval_current();
2029 end = timeval_add(&start, 7 * sec, 0);
2030 while (!timeval_expired(&end)) {
2032 torture_comment(tctx, "Do a write on the file handle\n");
2033 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2035 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2039 /* get the times after the write */
2040 GET_INFO_FILE(finfo2);
2042 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2043 double diff = timeval_elapsed(&start);
2044 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2050 smb_msleep(1 * msec);
2053 GET_INFO_BOTH(finfo2,pinfo2);
2054 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2055 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2056 torture_comment(tctx, "Server did not update write_time (correct)\n");
2060 smb_msleep(5 * msec);
2062 /* get the initial times */
2063 GET_INFO_BOTH(finfo1,pinfo1);
2064 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2067 * demonstrate that a truncate write always
2068 * updates the write time immediately
2070 for (i=0; i < 3; i++) {
2071 smb_msleep(2 * msec);
2073 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2074 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2076 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2080 /* get the times after the write */
2081 GET_INFO_BOTH(finfo2,pinfo2);
2082 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2087 smb_msleep(5 * msec);
2089 GET_INFO_BOTH(finfo2,pinfo2);
2090 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2092 /* sure any further write doesn't update the write time */
2093 start = timeval_current();
2094 end = timeval_add(&start, 15 * sec, 0);
2095 while (!timeval_expired(&end)) {
2097 torture_comment(tctx, "Do a write on the file handle\n");
2098 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2100 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2104 /* get the times after the write */
2105 GET_INFO_BOTH(finfo2,pinfo2);
2107 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2108 double diff = timeval_elapsed(&start);
2109 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2115 smb_msleep(1 * msec);
2118 GET_INFO_BOTH(finfo2,pinfo2);
2119 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2120 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2121 torture_comment(tctx, "Server did not update write_time (correct)\n");
2125 smb_msleep(5 * msec);
2127 GET_INFO_BOTH(finfo3,pinfo3);
2128 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2131 * the close updates the write time to the time of the close
2132 * and not to the time of the last write!
2134 torture_comment(tctx, "Close the file handle\n");
2135 smbcli_close(cli->tree, fnum1);
2138 GET_INFO_PATH(pinfo4);
2139 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2141 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2142 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2147 smbcli_close(cli->tree, fnum1);
2148 smbcli_unlink(cli->tree, fname);
2149 smbcli_deltree(cli->tree, BASEDIR);
2155 * Show only the first write updates the timestamp, and a close
2156 * after writes updates to current (I think this is the same
2160 static bool test_delayed_write_update4(struct torture_context *tctx,
2161 struct smbcli_state *cli,
2162 struct smbcli_state *cli2)
2164 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
2165 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
2166 const char *fname = BASEDIR "\\torture_file4.txt";
2170 struct timeval start;
2172 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2173 int normal_delay = 2000000;
2174 double sec = ((double)used_delay) / ((double)normal_delay);
2175 int msec = 1000 * sec;
2177 torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2179 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2181 torture_comment(tctx, "Open the file handle\n");
2182 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2185 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2189 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2190 finfo0.basic_info.in.file.fnum = fnum1;
2194 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2195 pinfo0.basic_info.in.file.path = fname;
2201 /* get the initial times */
2202 GET_INFO_BOTH(finfo0,pinfo0);
2205 smb_msleep(5 * msec);
2208 torture_comment(tctx, "Do a write on the file handle\n");
2209 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2211 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2216 GET_INFO_BOTH(finfo1,pinfo1);
2217 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2220 * make sure the write time is updated 2 seconds later
2221 * calcuated from the first write
2222 * (but expect upto 3 seconds extra time for a busy server)
2224 start = timeval_current();
2225 end = timeval_add(&start, 5 * sec, 0);
2226 while (!timeval_expired(&end)) {
2227 /* get the times after the first write */
2228 GET_INFO_FILE(finfo1);
2230 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2231 double diff = timeval_elapsed(&start);
2232 if (diff < (used_delay / (double)1000000)) {
2233 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
2234 "(expected > %.2f) (wrong!)\n",
2235 diff, used_delay / (double)1000000);
2240 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2241 "(write time update delay == %.2f) (correct)\n",
2242 diff, used_delay / (double)1000000);
2245 smb_msleep(0.5 * msec);
2248 GET_INFO_BOTH(finfo1,pinfo1);
2249 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2251 /* sure any further write doesn't update the write time */
2252 start = timeval_current();
2253 end = timeval_add(&start, 15 * sec, 0);
2254 while (!timeval_expired(&end)) {
2256 torture_comment(tctx, "Do a write on the file handle\n");
2257 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2259 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2263 /* get the times after the write */
2264 GET_INFO_BOTH(finfo2,pinfo2);
2266 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2267 double diff = timeval_elapsed(&start);
2268 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2274 smb_msleep(1 * msec);
2277 GET_INFO_BOTH(finfo2,pinfo2);
2278 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2279 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2280 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2284 smb_msleep(5 * msec);
2286 GET_INFO_BOTH(finfo3,pinfo3);
2287 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2290 * the close updates the write time to the time of the close
2291 * and not to the time of the last write!
2293 torture_comment(tctx, "Close the file handle\n");
2294 smbcli_close(cli->tree, fnum1);
2297 GET_INFO_PATH(pinfo4);
2298 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2300 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2301 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2306 smbcli_close(cli->tree, fnum1);
2307 smbcli_unlink(cli->tree, fname);
2308 smbcli_deltree(cli->tree, BASEDIR);
2314 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2317 static bool test_delayed_write_update5(struct torture_context *tctx,
2318 struct smbcli_state *cli,
2319 struct smbcli_state *cli2)
2321 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2322 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2323 const char *fname = BASEDIR "\\torture_file5.txt";
2327 struct timeval start;
2329 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2330 int normal_delay = 2000000;
2331 double sec = ((double)used_delay) / ((double)normal_delay);
2332 int msec = 1000 * sec;
2334 torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2336 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2338 torture_comment(tctx, "Open the file handle\n");
2339 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2342 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2346 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2347 finfo0.basic_info.in.file.fnum = fnum1;
2353 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2354 pinfo0.basic_info.in.file.path = fname;
2362 /* get the initial times */
2363 GET_INFO_BOTH(finfo0,pinfo0);
2366 torture_comment(tctx, "Do a write on the file handle\n");
2367 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2369 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2374 GET_INFO_BOTH(finfo1,pinfo1);
2375 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2377 torture_comment(tctx, "Set write time in the future on the file handle\n");
2378 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2379 GET_INFO_BOTH(finfo2,pinfo2);
2380 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2382 torture_comment(tctx, "Set write time in the past on the file handle\n");
2383 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2384 GET_INFO_BOTH(finfo2,pinfo2);
2385 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2387 /* make sure the 2 second delay from the first write are canceled */
2388 start = timeval_current();
2389 end = timeval_add(&start, 15 * sec, 0);
2390 while (!timeval_expired(&end)) {
2392 /* get the times after the first write */
2393 GET_INFO_BOTH(finfo3,pinfo3);
2395 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2396 double diff = timeval_elapsed(&start);
2397 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2403 smb_msleep(1 * msec);
2406 GET_INFO_BOTH(finfo3,pinfo3);
2407 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2408 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2409 torture_comment(tctx, "Server did not update write_time (correct)\n");
2412 /* sure any further write doesn't update the write time */
2413 start = timeval_current();
2414 end = timeval_add(&start, 15 * sec, 0);
2415 while (!timeval_expired(&end)) {
2417 torture_comment(tctx, "Do a write on the file handle\n");
2418 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2420 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2424 /* get the times after the write */
2425 GET_INFO_BOTH(finfo4,pinfo4);
2427 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2428 double diff = timeval_elapsed(&start);
2429 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2435 smb_msleep(1 * msec);
2438 GET_INFO_BOTH(finfo4,pinfo4);
2439 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2440 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2441 torture_comment(tctx, "Server did not update write_time (correct)\n");
2445 smb_msleep(5 * msec);
2447 GET_INFO_BOTH(finfo5,pinfo5);
2448 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2451 * the close doesn't update the write time
2453 torture_comment(tctx, "Close the file handle\n");
2454 smbcli_close(cli->tree, fnum1);
2457 GET_INFO_PATH(pinfo6);
2458 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2460 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2461 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2466 smbcli_close(cli->tree, fnum1);
2467 smbcli_unlink(cli->tree, fname);
2468 smbcli_deltree(cli->tree, BASEDIR);
2474 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2477 static bool test_delayed_write_update5b(struct torture_context *tctx,
2478 struct smbcli_state *cli,
2479 struct smbcli_state *cli2)
2481 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2482 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2483 const char *fname = BASEDIR "\\torture_fileb.txt";
2487 struct timeval start;
2489 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2490 int normal_delay = 2000000;
2491 double sec = ((double)used_delay) / ((double)normal_delay);
2492 int msec = 1000 * sec;
2494 torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2496 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2498 torture_comment(tctx, "Open the file handle\n");
2499 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2502 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2506 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2507 finfo0.basic_info.in.file.fnum = fnum1;
2513 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2514 pinfo0.basic_info.in.file.path = fname;
2522 /* get the initial times */
2523 GET_INFO_BOTH(finfo0,pinfo0);
2526 torture_comment(tctx, "Do a write on the file handle\n");
2527 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2529 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2534 GET_INFO_BOTH(finfo1,pinfo1);
2535 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2537 torture_comment(tctx, "Set write time in the future on the file handle\n");
2538 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2539 GET_INFO_BOTH(finfo2,pinfo2);
2540 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2542 torture_comment(tctx, "Set write time in the past on the file handle\n");
2543 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2544 GET_INFO_BOTH(finfo2,pinfo2);
2545 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2547 /* make sure the 2 second delay from the first write are canceled */
2548 start = timeval_current();
2549 end = timeval_add(&start, 15 * sec, 0);
2550 while (!timeval_expired(&end)) {
2552 /* get the times after the first write */
2553 GET_INFO_BOTH(finfo3,pinfo3);
2555 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2556 double diff = timeval_elapsed(&start);
2557 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2563 smb_msleep(1 * msec);
2566 GET_INFO_BOTH(finfo3,pinfo3);
2567 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2568 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2569 torture_comment(tctx, "Server did not update write_time (correct)\n");
2572 /* Do any further write (truncates) update the write time ? */
2573 start = timeval_current();
2574 end = timeval_add(&start, 15 * sec, 0);
2575 while (!timeval_expired(&end)) {
2577 torture_comment(tctx, "Do a truncate write on the file handle\n");
2578 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2580 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2584 /* get the times after the write */
2585 GET_INFO_BOTH(finfo4,pinfo4);
2587 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2588 double diff = timeval_elapsed(&start);
2589 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2595 smb_msleep(1 * msec);
2598 GET_INFO_BOTH(finfo4,pinfo4);
2599 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2600 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2601 torture_comment(tctx, "Server did not update write_time (correct)\n");
2605 smb_msleep(5 * msec);
2607 GET_INFO_BOTH(finfo5,pinfo5);
2608 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2611 * the close doesn't update the write time
2613 torture_comment(tctx, "Close the file handle\n");
2614 smbcli_close(cli->tree, fnum1);
2617 GET_INFO_PATH(pinfo6);
2618 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2620 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2621 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2626 smbcli_close(cli->tree, fnum1);
2627 smbcli_unlink(cli->tree, fname);
2628 smbcli_deltree(cli->tree, BASEDIR);
2634 * Open 2 handles on a file. Write one one and then set the
2635 * WRITE TIME explicitly on the other. Ensure the write time
2636 * update is cancelled. Ensure the write time is updated to
2637 * the close time when the non-explicit set handle is closed.
2641 static bool test_delayed_write_update6(struct torture_context *tctx,
2642 struct smbcli_state *cli,
2643 struct smbcli_state *cli2)
2645 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2646 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2647 const char *fname = BASEDIR "\\torture_file6.txt";
2652 struct timeval start;
2654 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2655 int normal_delay = 2000000;
2656 double sec = ((double)used_delay) / ((double)normal_delay);
2657 int msec = 1000 * sec;
2660 torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2662 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2664 torture_comment(tctx, "Open the file handle\n");
2665 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2668 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2673 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2674 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2677 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2682 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2683 finfo0.basic_info.in.file.fnum = fnum1;
2689 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2690 pinfo0.basic_info.in.file.path = fname;
2699 /* get the initial times */
2700 GET_INFO_BOTH(finfo0,pinfo0);
2703 torture_comment(tctx, "Do a write on the file handle\n");
2704 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2706 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2711 GET_INFO_BOTH(finfo1,pinfo1);
2712 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2714 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2715 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2716 GET_INFO_BOTH(finfo2,pinfo2);
2717 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2719 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2720 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2721 GET_INFO_BOTH(finfo2,pinfo2);
2722 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2724 /* make sure the 2 second delay from the first write are canceled */
2725 start = timeval_current();
2726 end = timeval_add(&start, 10 * sec, 0);
2727 while (!timeval_expired(&end)) {
2729 /* get the times after the first write */
2730 GET_INFO_BOTH(finfo3,pinfo3);
2732 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2733 double diff = timeval_elapsed(&start);
2734 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2740 smb_msleep(1 * msec);
2743 GET_INFO_BOTH(finfo3,pinfo3);
2744 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2745 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2746 torture_comment(tctx, "Server did not update write_time (correct)\n");
2749 /* sure any further write doesn't update the write time */
2750 start = timeval_current();
2751 end = timeval_add(&start, 10 * sec, 0);
2752 while (!timeval_expired(&end)) {
2754 torture_comment(tctx, "Do a write on the file handle\n");
2755 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2757 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2761 /* get the times after the write */
2762 GET_INFO_BOTH(finfo4,pinfo4);
2764 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2765 double diff = timeval_elapsed(&start);
2766 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2772 smb_msleep(1 * msec);
2775 GET_INFO_BOTH(finfo4,pinfo4);
2776 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2777 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2778 torture_comment(tctx, "Server did not update write_time (correct)\n");
2782 smb_msleep(5 * msec);
2784 GET_INFO_BOTH(finfo5,pinfo5);
2785 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2788 * the close updates the write time to the time of the close
2789 * as the write time was set on the 2nd handle
2791 torture_comment(tctx, "Close the file handle\n");
2792 smbcli_close(cli->tree, fnum1);
2795 GET_INFO_PATH(pinfo6);
2796 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2798 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2799 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2802 /* See what the second write handle thinks the time is ? */
2803 finfo5.basic_info.in.file.fnum = fnum2;
2804 GET_INFO_FILE2(finfo5);
2805 COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
2807 /* See if we have lost the sticky write time on handle2 */
2808 smb_msleep(3 * msec);
2809 torture_comment(tctx, "Have we lost the sticky write time ?\n");
2811 /* Make sure any further normal write doesn't update the write time */
2812 start = timeval_current();
2813 end = timeval_add(&start, 10 * sec, 0);
2814 while (!timeval_expired(&end)) {
2816 torture_comment(tctx, "Do a write on the second file handle\n");
2817 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
2819 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2823 /* get the times after the write */
2824 GET_INFO_FILE2(finfo5);
2825 GET_INFO_PATH(pinfo6);
2827 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2828 double diff = timeval_elapsed(&start);
2829 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2835 smb_msleep(1 * msec);
2838 /* What about a truncate write ? */
2839 start = timeval_current();
2840 end = timeval_add(&start, 10 * sec, 0);
2841 while (!timeval_expired(&end)) {
2843 torture_comment(tctx, "Do a truncate write on the second file handle\n");
2844 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
2846 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2850 /* get the times after the write */
2851 GET_INFO_FILE2(finfo5);
2852 GET_INFO_PATH(pinfo6);
2854 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2855 double diff = timeval_elapsed(&start);
2856 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2862 smb_msleep(1 * msec);
2866 /* keep the 2nd handle open and rerun tests */
2873 * closing the 2nd handle will cause no write time update
2874 * as the write time was explicit set on this handle
2876 torture_comment(tctx, "Close the 2nd file handle\n");
2877 smbcli_close(cli2->tree, fnum2);
2880 GET_INFO_PATH(pinfo7);
2881 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2883 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2884 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2889 smbcli_close(cli->tree, fnum1);
2891 smbcli_close(cli2->tree, fnum2);
2892 smbcli_unlink(cli->tree, fname);
2893 smbcli_deltree(cli->tree, BASEDIR);
2898 static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
2900 union smb_open open_parms;
2901 union smb_fileinfo finfo1, finfo2, finfo3;
2902 const char *fname = BASEDIR "\\torture_file7.txt";
2906 TALLOC_CTX *mem_ctx;
2908 torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2910 mem_ctx = talloc_init("test_delayed_write_update7");
2911 if (!mem_ctx) return false;
2913 ZERO_STRUCT(finfo1);
2914 ZERO_STRUCT(finfo2);
2915 ZERO_STRUCT(finfo3);
2916 ZERO_STRUCT(open_parms);
2918 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2920 /* Create the file. */
2921 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2923 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
2927 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2928 finfo1.basic_info.in.file.fnum = fnum1;
2932 /* Get the initial timestamps. */
2933 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
2935 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2937 /* Set the pending write time to a value with ns. */
2938 SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
2940 /* Get the current pending write time by fnum. */
2941 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
2943 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2945 /* Ensure the time is actually different. */
2946 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2947 torture_result(tctx, TORTURE_FAIL,
2948 "setfileinfo time matches original fileinfo time");
2952 /* Get the current pending write time by path. */
2953 finfo3.basic_info.in.file.path = fname;
2954 status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
2956 if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
2957 torture_result(tctx, TORTURE_FAIL,
2958 "qpathinfo time doens't match fileinfo time");
2962 /* Now close the file. Re-open and check that the write
2963 time is identical to the one we wrote. */
2965 smbcli_close(cli->tree, fnum1);
2967 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
2968 open_parms.ntcreatex.in.flags = 0;
2969 open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
2970 open_parms.ntcreatex.in.file_attr = 0;
2971 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
2972 NTCREATEX_SHARE_ACCESS_READ|
2973 NTCREATEX_SHARE_ACCESS_WRITE;
2974 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
2975 open_parms.ntcreatex.in.create_options = 0;
2976 open_parms.ntcreatex.in.fname = fname;
2978 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
2979 talloc_free(mem_ctx);
2981 if (!NT_STATUS_IS_OK(status)) {
2982 torture_result(tctx, TORTURE_FAIL,
2983 "setfileinfo time matches original fileinfo time");
2987 fnum1 = open_parms.ntcreatex.out.file.fnum;
2989 /* Check the returned time matches. */
2990 if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
2991 torture_result(tctx, TORTURE_FAIL,
2992 "final open time does not match set time");
2998 smbcli_close(cli->tree, fnum1);
3000 smbcli_unlink(cli->tree, fname);
3001 smbcli_deltree(cli->tree, BASEDIR);
3006 Test if creating a file in a directory with an open handle updates the
3007 write timestamp (it should).
3009 static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
3011 union smb_fileinfo dir_info1, dir_info2;
3012 union smb_open open_parms;
3013 const char *fname = BASEDIR "\\torture_file.txt";
3018 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3019 int normal_delay = 2000000;
3020 double sec = ((double)used_delay) / ((double)normal_delay);
3021 int msec = 1000 * sec;
3022 TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
3024 if (!mem_ctx) return false;
3026 torture_comment(tctx, "\nRunning test directory write update\n");
3028 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
3030 /* Open a handle on the directory - and leave it open. */
3031 ZERO_STRUCT(open_parms);
3032 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3033 open_parms.ntcreatex.in.flags = 0;
3034 open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
3035 open_parms.ntcreatex.in.file_attr = 0;
3036 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3037 NTCREATEX_SHARE_ACCESS_READ|
3038 NTCREATEX_SHARE_ACCESS_WRITE;
3039 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3040 open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
3041 open_parms.ntcreatex.in.fname = BASEDIR;
3043 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3044 talloc_free(mem_ctx);
3046 if (!NT_STATUS_IS_OK(status)) {
3047 torture_result(tctx, TORTURE_FAIL,
3048 "failed to open directory handle");
3053 fnum1 = open_parms.ntcreatex.out.file.fnum;
3055 /* Store the returned write time. */
3056 ZERO_STRUCT(dir_info1);
3057 dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
3059 torture_comment(tctx, "Initial write time %s\n",
3060 nt_time_string(tctx, dir_info1.basic_info.out.write_time));
3063 smb_msleep(3 * msec);
3065 /* Now create a file within the directory. */
3066 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3068 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
3072 smbcli_close(cli->tree, fnum2);
3074 /* Read the directory write time again. */
3075 ZERO_STRUCT(dir_info2);
3076 dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3077 dir_info2.basic_info.in.file.fnum = fnum1;
3079 status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
3081 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
3083 /* Ensure it's been incremented. */
3084 COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
3086 torture_comment(tctx, "Updated write time %s\n",
3087 nt_time_string(tctx, dir_info2.basic_info.out.write_time));
3092 smbcli_close(cli->tree, fnum1);
3093 smbcli_unlink(cli->tree, fname);
3094 smbcli_deltree(cli->tree, BASEDIR);
3100 testing of delayed update of write_time
3102 struct torture_suite *torture_delay_write(void)
3104 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "delaywrite");
3106 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
3107 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
3108 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
3109 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
3110 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
3111 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
3112 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
3113 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
3114 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
3115 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
3116 torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
3117 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
3118 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
3119 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
3120 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
3121 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3122 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3123 torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);