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;
133 torture_comment(tctx, "\nRunning test_delayed_write_update1\n");
135 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
137 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
139 torture_result(tctx, TORTURE_FAIL, "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_comment(tctx, "Initial write time %s\n",
162 nt_time_string(tctx, finfo1.all_info.out.write_time));
164 /* 3 second delay to ensure we get past any 2 second time
165 granularity (older systems may have that) */
166 smb_msleep(3 * msec);
168 /* Do a zero length SMBwrite call to truncate. */
169 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
172 torture_result(tctx, TORTURE_FAIL,
173 "write failed - wrote %d bytes (%s)\n",
174 (int)written, __location__);
178 start = timeval_current();
179 end = timeval_add(&start, (120 * sec), 0);
180 while (!timeval_expired(&end)) {
181 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
183 if (!NT_STATUS_IS_OK(status)) {
184 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
189 if (finfo2.all_info.out.size != 1024) {
190 torture_result(tctx, TORTURE_FAIL,
191 "file not truncated, size = %u (should be 1024)",
192 (unsigned int)finfo2.all_info.out.size);
197 torture_comment(tctx, "write time %s\n",
198 nt_time_string(tctx, finfo2.all_info.out.write_time));
199 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
200 double diff = timeval_elapsed(&start);
201 if (diff > (0.25 * (used_delay / (double)1000000))) {
202 torture_result(tctx, TORTURE_FAIL, "After SMBwrite truncate "
203 "server updated write_time after %.2f seconds"
204 "(write time update dealy == %.2f)(wrong!)\n",
205 diff, used_delay / (double)1000000);
210 torture_comment(tctx, "After SMBwrite truncate "
211 "server updated write_time after %.2f seconds"
212 "(1 sec == %.2f)(correct)\n",
213 diff, used_delay / (double)1000000);
217 smb_msleep(1 * msec);
220 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
221 torture_result(tctx, TORTURE_FAIL,
222 "Server did not update write time (wrong!)");
227 smb_msleep(2 * msec);
229 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
230 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
233 torture_result(tctx, TORTURE_FAIL,
234 "write failed - wrote %d bytes (%s)",
235 (int)written, __location__);
239 start = timeval_current();
240 end = timeval_add(&start, (10*sec), 0);
241 while (!timeval_expired(&end)) {
242 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
244 if (!NT_STATUS_IS_OK(status)) {
245 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
250 if (finfo3.all_info.out.size != 1024) {
251 DEBUG(0, ("file not truncated, size = %u (should be 1024)\n",
252 (unsigned int)finfo3.all_info.out.size));
257 torture_comment(tctx, "write time %s\n",
258 nt_time_string(tctx, finfo3.all_info.out.write_time));
259 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
260 double diff = timeval_elapsed(&start);
262 torture_comment(tctx, "server updated write_time after %.2f seconds"
268 smb_msleep(1 * msec);
271 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
272 torture_result(tctx, TORTURE_FAIL,
273 "Server updated write time (wrong!)");
278 smb_msleep(2 * msec);
280 /* the close should trigger an write time update */
281 smbcli_close(cli->tree, fnum1);
284 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
285 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
287 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
288 torture_result(tctx, TORTURE_FAIL,
289 "Server did not update write time on close (wrong!)");
291 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
292 torture_comment(tctx, "Server updated write time on close (correct)\n");
296 smbcli_close(cli->tree, fnum1);
297 smbcli_unlink(cli->tree, fname);
298 smbcli_deltree(cli->tree, BASEDIR);
303 /* Updating with a SMBwrite of zero length
304 * changes the write time immediately - even on expand. */
306 static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
308 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
309 const char *fname = BASEDIR "\\torture_file1a.txt";
314 struct timeval start;
316 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
317 int normal_delay = 2000000;
318 double sec = ((double)used_delay) / ((double)normal_delay);
319 int msec = 1000 * sec;
322 torture_comment(tctx, "\nRunning test_delayed_write_update1a\n");
324 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
326 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
328 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
332 memset(buf, 'x', 2048);
333 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
335 /* 3 second delay to ensure we get past any 2 second time
336 granularity (older systems may have that) */
337 smb_msleep(3 * msec);
339 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
340 finfo1.all_info.in.file.fnum = fnum1;
343 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
344 pinfo4.all_info.in.file.path = fname;
346 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
348 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
350 torture_comment(tctx, "Initial write time %s\n",
351 nt_time_string(tctx, finfo1.all_info.out.write_time));
353 /* Do a zero length SMBwrite call to truncate. */
354 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
357 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)",
358 (int)written, __location__);
362 start = timeval_current();
363 end = timeval_add(&start, (120*sec), 0);
364 while (!timeval_expired(&end)) {
365 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
367 if (!NT_STATUS_IS_OK(status)) {
368 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
374 if (finfo2.all_info.out.size != 10240) {
375 torture_result(tctx, TORTURE_FAIL,
376 "file not truncated, size = %u (should be 10240)",
377 (unsigned int)finfo2.all_info.out.size);
382 torture_comment(tctx, "write time %s\n",
383 nt_time_string(tctx, finfo2.all_info.out.write_time));
384 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
385 double diff = timeval_elapsed(&start);
386 if (diff > (0.25 * (used_delay / (double)1000000))) {
387 torture_result(tctx, TORTURE_FAIL, "After SMBwrite truncate "
388 "server updated write_time after %.2f seconds"
389 "(write time update delay == %.2f)(wrong!)\n",
390 diff, used_delay / (double)1000000);
395 torture_comment(tctx, "After SMBwrite truncate "
396 "server updated write_time after %.2f seconds"
397 "(write time update delay == %.2f)(correct)\n",
398 diff, used_delay / (double)1000000);
402 smb_msleep(1 * msec);
405 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
406 torture_result(tctx, TORTURE_FAIL,
407 "Server did not update write time (wrong!)");
412 smb_msleep(2 * msec);
414 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
415 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
417 torture_assert_int_equal(tctx, written, 1,
418 "unexpected number of bytes written");
420 start = timeval_current();
421 end = timeval_add(&start, (10*sec), 0);
422 while (!timeval_expired(&end)) {
423 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
425 if (!NT_STATUS_IS_OK(status)) {
426 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s\n",
432 if (finfo3.all_info.out.size != 10240) {
433 torture_result(tctx, TORTURE_FAIL,
434 "file not truncated, size = %u (should be 10240)",
435 (unsigned int)finfo3.all_info.out.size);
440 torture_comment(tctx, "write time %s\n",
441 nt_time_string(tctx, finfo3.all_info.out.write_time));
442 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
443 double diff = timeval_elapsed(&start);
445 torture_result(tctx, TORTURE_FAIL, "server updated write_time after %.2f seconds"
446 "(write time update delay == %.2f)(correct)\n",
447 diff, used_delay / (double)1000000);
451 smb_msleep(1 * msec);
454 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
455 torture_result(tctx, TORTURE_FAIL,
456 "Server updated write time (wrong!)");
460 /* the close should trigger an write time update */
461 smbcli_close(cli->tree, fnum1);
464 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
465 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
467 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
468 torture_result(tctx, TORTURE_FAIL,
469 "Server did not update write time on close (wrong!)");
471 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
472 torture_comment(tctx, "Server updated write time on close (correct)\n");
476 smbcli_close(cli->tree, fnum1);
477 smbcli_unlink(cli->tree, fname);
478 smbcli_deltree(cli->tree, BASEDIR);
483 /* Updating with a SET_FILE_END_OF_FILE_INFO
484 * changes the write time immediately - even on expand. */
486 static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
488 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
489 const char *fname = BASEDIR "\\torture_file1b.txt";
494 struct timeval start;
496 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
497 int normal_delay = 2000000;
498 double sec = ((double)used_delay) / ((double)normal_delay);
499 int msec = 1000 * sec;
502 torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
504 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
506 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
508 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
512 memset(buf, 'x', 2048);
513 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
515 /* 3 second delay to ensure we get past any 2 second time
516 granularity (older systems may have that) */
517 smb_msleep(3 * msec);
519 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
520 finfo1.all_info.in.file.fnum = fnum1;
523 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
524 pinfo4.all_info.in.file.path = fname;
526 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
528 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
530 torture_comment(tctx, "Initial write time %s\n",
531 nt_time_string(tctx, finfo1.all_info.out.write_time));
533 /* Do a SET_END_OF_FILE_INFO call to truncate. */
534 status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
536 torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
538 start = timeval_current();
539 end = timeval_add(&start, (120*sec), 0);
540 while (!timeval_expired(&end)) {
541 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
543 if (!NT_STATUS_IS_OK(status)) {
544 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
549 if (finfo2.all_info.out.size != 10240) {
550 torture_result(tctx, TORTURE_FAIL,
551 "file not truncated (size = %u, should be 10240)",
552 (unsigned int)finfo2.all_info.out.size );
557 torture_comment(tctx, "write time %s\n",
558 nt_time_string(tctx, finfo2.all_info.out.write_time));
559 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
560 double diff = timeval_elapsed(&start);
561 if (diff > (0.25 * (used_delay / (double)1000000))) {
562 torture_result(tctx, TORTURE_FAIL,
563 "After SET_END_OF_FILE truncate "
564 "server updated write_time after %.2f seconds"
565 "(write time update delay == %.2f)(wrong!)",
566 diff, used_delay / (double)1000000);
571 torture_comment(tctx, "After SET_END_OF_FILE truncate "
572 "server updated write_time after %.2f seconds"
573 "(write time update delay == %.2f)(correct)\n",
574 diff, used_delay / (double)1000000);
578 smb_msleep(1 * msec);
581 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
582 torture_result(tctx, TORTURE_FAIL,
583 "Server did not update write time (wrong!)");
588 smb_msleep(2 * msec);
590 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
591 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
593 torture_assert_int_equal(tctx, written, 1,
594 "unexpected number of bytes written");
596 start = timeval_current();
597 end = timeval_add(&start, (10*sec), 0);
598 while (!timeval_expired(&end)) {
599 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
601 if (!NT_STATUS_IS_OK(status)) {
602 torture_result(tctx, TORTURE_FAIL,
603 "fileinfo failed: %s", nt_errstr(status));
608 if (finfo3.all_info.out.size != 10240) {
609 DEBUG(0, ("file not truncated (size = %u, should be 10240)\n",
610 (unsigned int)finfo3.all_info.out.size ));
615 torture_comment(tctx, "write time %s\n",
616 nt_time_string(tctx, finfo3.all_info.out.write_time));
617 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
618 double diff = timeval_elapsed(&start);
620 torture_comment(tctx, "server updated write_time after %.2f seconds"
621 "(write time update delay == %.2f)(correct)\n",
622 diff, used_delay / (double)1000000);
626 smb_msleep(1 * msec);
629 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
630 torture_result(tctx, TORTURE_FAIL, "Server updated write time (wrong!)\n");
634 /* the close should trigger an write time update */
635 smbcli_close(cli->tree, fnum1);
638 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
639 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
641 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
642 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
644 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
645 torture_comment(tctx, "Server updated write time on close (correct)\n");
649 smbcli_close(cli->tree, fnum1);
650 smbcli_unlink(cli->tree, fname);
651 smbcli_deltree(cli->tree, BASEDIR);
656 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
658 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
660 union smb_setfileinfo parms;
661 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
662 const char *fname = BASEDIR "\\torture_file1c.txt";
667 struct timeval start;
669 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
670 int normal_delay = 2000000;
671 double sec = ((double)used_delay) / ((double)normal_delay);
672 int msec = 1000 * sec;
675 torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
677 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
679 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
681 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
685 memset(buf, 'x', 2048);
686 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
688 /* 3 second delay to ensure we get past any 2 second time
689 granularity (older systems may have that) */
690 smb_msleep(3 * msec);
692 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
693 finfo1.all_info.in.file.fnum = fnum1;
696 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
697 pinfo4.all_info.in.file.path = fname;
699 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
701 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
703 torture_comment(tctx, "Initial write time %s\n",
704 nt_time_string(tctx, finfo1.all_info.out.write_time));
706 /* Do a SET_ALLOCATION_SIZE call to truncate. */
707 parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
708 parms.allocation_info.in.file.fnum = fnum1;
709 parms.allocation_info.in.alloc_size = 0;
711 status = smb_raw_setfileinfo(cli->tree, &parms);
713 torture_assert_ntstatus_ok(tctx, status,
714 "RAW_SFILEINFO_ALLOCATION_INFO failed");
716 start = timeval_current();
717 end = timeval_add(&start, (120*sec), 0);
718 while (!timeval_expired(&end)) {
719 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
721 if (!NT_STATUS_IS_OK(status)) {
722 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
728 if (finfo2.all_info.out.size != 0) {
729 torture_result(tctx, TORTURE_FAIL,
730 "file not truncated (size = %u, should be 10240)",
731 (unsigned int)finfo2.all_info.out.size);
736 torture_comment(tctx, "write time %s\n",
737 nt_time_string(tctx, finfo2.all_info.out.write_time));
738 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
739 double diff = timeval_elapsed(&start);
740 if (diff > (0.25 * (used_delay / (double)1000000))) {
741 torture_result(tctx, TORTURE_FAIL, "After SET_ALLOCATION_INFO truncate "
742 "server updated write_time after %.2f seconds"
743 "(write time update delay == %.2f)(wrong!)\n",
744 diff, used_delay / (double)1000000);
749 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
750 "server updated write_time after %.2f seconds"
751 "(write time update delay == %.2f)(correct)\n",
752 diff, used_delay / (double)1000000);
756 smb_msleep(1 * msec);
759 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
760 torture_result(tctx, TORTURE_FAIL,
761 "Server did not update write time (wrong!)");
766 smb_msleep(2 * msec);
768 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
769 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
770 torture_assert_int_equal(tctx, written, 1,
771 "Unexpected number of bytes written");
773 start = timeval_current();
774 end = timeval_add(&start, (10*sec), 0);
775 while (!timeval_expired(&end)) {
776 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
778 if (!NT_STATUS_IS_OK(status)) {
779 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
785 if (finfo3.all_info.out.size != 1) {
786 torture_result(tctx, TORTURE_FAIL, "file not expanded");
791 torture_comment(tctx, "write time %s\n",
792 nt_time_string(tctx, finfo3.all_info.out.write_time));
793 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
794 double diff = timeval_elapsed(&start);
796 torture_comment(tctx, "server updated write_time after %.2f seconds"
797 "(write time update delay == %.2f)(wrong)\n",
798 diff, used_delay / (double)1000000);
802 smb_msleep(1 * msec);
805 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
806 torture_result(tctx, TORTURE_FAIL,
807 "Server updated write time (wrong!)");
811 /* the close should trigger an write time update */
812 smbcli_close(cli->tree, fnum1);
815 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
816 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
818 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
819 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
821 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
822 torture_comment(tctx, "Server updated write time on close (correct)\n");
826 smbcli_close(cli->tree, fnum1);
827 smbcli_unlink(cli->tree, fname);
828 smbcli_deltree(cli->tree, BASEDIR);
834 * Do as above, but using 2 connections.
837 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
838 struct smbcli_state *cli2)
840 union smb_fileinfo finfo1, finfo2;
841 const char *fname = BASEDIR "\\torture_file.txt";
847 struct timeval start;
849 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
850 int normal_delay = 2000000;
851 double sec = ((double)used_delay) / ((double)normal_delay);
852 int msec = 1000 * sec;
853 union smb_flush flsh;
855 torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
857 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
859 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
861 torture_comment(tctx, "Failed to open %s\n", fname);
865 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
866 finfo1.basic_info.in.file.fnum = fnum1;
869 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
871 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
873 torture_comment(tctx, "Initial write time %s\n",
874 nt_time_string(tctx, finfo1.basic_info.out.write_time));
876 /* 3 second delay to ensure we get past any 2 second time
877 granularity (older systems may have that) */
878 smb_msleep(3 * msec);
881 /* Try using setfileinfo instead of write to update write time. */
882 union smb_setfileinfo sfinfo;
883 time_t t_set = time(NULL);
884 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
885 sfinfo.basic_info.in.file.fnum = fnum1;
886 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
887 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
889 /* I tried this with both + and - ve to see if it makes a different.
890 It doesn't - once the filetime is set via setfileinfo it stays that way. */
892 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
894 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
896 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
897 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
899 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
901 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
904 finfo2.basic_info.in.file.path = fname;
906 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
908 if (!NT_STATUS_IS_OK(status)) {
909 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
912 torture_comment(tctx, "write time %s\n",
913 nt_time_string(tctx, finfo2.basic_info.out.write_time));
915 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
916 torture_comment(tctx, "Server updated write_time (correct)\n");
918 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
922 /* Now try a write to see if the write time gets reset. */
924 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
925 finfo1.basic_info.in.file.fnum = fnum1;
928 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
930 if (!NT_STATUS_IS_OK(status)) {
931 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
935 torture_comment(tctx, "Modified write time %s\n",
936 nt_time_string(tctx, finfo1.basic_info.out.write_time));
939 torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
941 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
944 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
945 (int)written, __location__);
949 /* Just to prove to tridge that the an smbflush has no effect on
950 the write time :-). The setfileinfo IS STICKY. JRA. */
952 torture_comment(tctx, "Doing flush after write\n");
954 flsh.flush.level = RAW_FLUSH_FLUSH;
955 flsh.flush.in.file.fnum = fnum1;
956 status = smb_raw_flush(cli->tree, &flsh);
957 if (!NT_STATUS_IS_OK(status)) {
958 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
962 /* Once the time was set using setfileinfo then it stays set - writes
963 don't have any effect. But make sure. */
964 start = timeval_current();
965 end = timeval_add(&start, (15*sec), 0);
966 while (!timeval_expired(&end)) {
967 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
969 if (!NT_STATUS_IS_OK(status)) {
970 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
974 torture_comment(tctx, "write time %s\n",
975 nt_time_string(tctx, finfo2.basic_info.out.write_time));
976 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
977 double diff = timeval_elapsed(&start);
978 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
985 smb_msleep(1 * msec);
988 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
989 torture_comment(tctx, "Server did not update write time (correct)\n");
993 smb_msleep(2 * msec);
995 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
997 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
1001 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");
1003 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
1005 if (written != 10) {
1006 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1007 (int)written, __location__);
1011 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1013 if (!NT_STATUS_IS_OK(status)) {
1014 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1017 torture_comment(tctx, "write time %s\n",
1018 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1019 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1020 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1024 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
1025 smbcli_close(cli->tree, fnum1);
1028 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");
1030 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
1032 if (written != 10) {
1033 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1034 (int)written, __location__);
1038 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1039 finfo1.basic_info.in.file.fnum = fnum2;
1041 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1043 if (!NT_STATUS_IS_OK(status)) {
1044 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1047 torture_comment(tctx, "write time %s\n",
1048 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1049 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1050 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1054 /* Once the time was set using setfileinfo then it stays set - writes
1055 don't have any effect. But make sure. */
1056 start = timeval_current();
1057 end = timeval_add(&start, (15*sec), 0);
1058 while (!timeval_expired(&end)) {
1059 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1061 if (!NT_STATUS_IS_OK(status)) {
1062 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1066 torture_comment(tctx, "write time %s\n",
1067 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1068 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1069 double diff = timeval_elapsed(&start);
1070 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1077 smb_msleep(1 * msec);
1080 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1081 torture_comment(tctx, "Server did not update write time (correct)\n");
1084 torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1086 smbcli_close(cli->tree, fnum2);
1089 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1091 torture_comment(tctx, "Failed to open %s\n", fname);
1095 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1096 finfo1.basic_info.in.file.fnum = fnum1;
1099 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1101 if (!NT_STATUS_IS_OK(status)) {
1102 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1106 torture_comment(tctx, "Second open initial write time %s\n",
1107 nt_time_string(tctx, finfo1.basic_info.out.write_time));
1109 smb_msleep(10 * msec);
1110 torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1112 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1114 if (written != 10) {
1115 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1116 (int)written, __location__);
1120 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1121 finfo1.basic_info.in.file.fnum = fnum1;
1123 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1125 if (!NT_STATUS_IS_OK(status)) {
1126 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1129 torture_comment(tctx, "write time %s\n",
1130 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1131 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1132 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1136 /* Now the write time should be updated again */
1137 start = timeval_current();
1138 end = timeval_add(&start, (15*sec), 0);
1139 while (!timeval_expired(&end)) {
1140 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1142 if (!NT_STATUS_IS_OK(status)) {
1143 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1147 torture_comment(tctx, "write time %s\n",
1148 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1149 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1150 double diff = timeval_elapsed(&start);
1151 if (diff < (used_delay / (double)1000000)) {
1152 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1153 "(expected > %.2f) (wrong!)\n",
1154 diff, used_delay / (double)1000000);
1159 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1168 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1169 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
1174 /* One more test to do. We should read the filetime via findfirst on the
1175 second connection to ensure it's the same. This is very easy for a Windows
1176 server but a bastard to get right on a POSIX server. JRA. */
1179 smbcli_close(cli->tree, fnum1);
1180 smbcli_unlink(cli->tree, fname);
1181 smbcli_deltree(cli->tree, BASEDIR);
1187 /* Windows does obviously not update the stat info during a write call. I
1188 * *think* this is the problem causing a spurious Excel 2003 on XP error
1189 * message when saving a file. Excel does a setfileinfo, writes, and then does
1190 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1191 * that the file might have been changed in between. What i've been able to
1192 * trace down is that this happens if the getpathinfo after the write shows a
1193 * different last write time than the setfileinfo showed. This is really
1197 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
1198 struct smbcli_state *cli2)
1200 union smb_fileinfo finfo1, finfo2;
1201 const char *fname = BASEDIR "\\torture_file.txt";
1207 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1208 int normal_delay = 2000000;
1209 double sec = ((double)used_delay) / ((double)normal_delay);
1210 int msec = 1000 * sec;
1212 torture_comment(tctx, "\nRunning test_finfo_after_write\n");
1214 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1216 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1219 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1223 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1224 finfo1.basic_info.in.file.fnum = fnum1;
1226 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1228 if (!NT_STATUS_IS_OK(status)) {
1230 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1234 smb_msleep(1 * msec);
1236 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1239 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1244 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1246 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1247 smbcli_errstr(cli2->tree));
1252 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1255 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1261 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1262 finfo2.basic_info.in.file.path = fname;
1264 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1266 if (!NT_STATUS_IS_OK(status)) {
1267 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
1273 if (finfo1.basic_info.out.create_time !=
1274 finfo2.basic_info.out.create_time) {
1275 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1280 if (finfo1.basic_info.out.access_time !=
1281 finfo2.basic_info.out.access_time) {
1282 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1287 if (finfo1.basic_info.out.write_time !=
1288 finfo2.basic_info.out.write_time) {
1289 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1290 "write time conn 1 = %s, conn 2 = %s",
1291 nt_time_string(tctx, finfo1.basic_info.out.write_time),
1292 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1297 if (finfo1.basic_info.out.change_time !=
1298 finfo2.basic_info.out.change_time) {
1299 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1304 /* One of the two following calls updates the qpathinfo. */
1306 /* If you had skipped the smbcli_write on fnum2, it would
1307 * *not* have updated the stat on disk */
1309 smbcli_close(cli2->tree, fnum2);
1312 /* This call is only for the people looking at ethereal :-) */
1313 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1314 finfo2.basic_info.in.file.path = fname;
1316 status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1318 if (!NT_STATUS_IS_OK(status)) {
1319 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1326 smbcli_close(cli->tree, fnum1);
1327 smbcli_unlink(cli->tree, fname);
1328 smbcli_deltree(cli->tree, BASEDIR);
1333 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1334 uint64_t r = 10*1000*1000; \
1335 NTTIME g = (given).basic_info.out.write_time; \
1336 NTTIME gr = (g / r) * r; \
1337 NTTIME c = (correct).basic_info.out.write_time; \
1338 NTTIME cr = (c / r) * r; \
1339 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1341 if (strict && (g cmp c)) { \
1343 } else if ((g cmp c) && (gr cmp cr)) { \
1344 /* handle filesystem without high resolution timestamps */ \
1348 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1349 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1350 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1355 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1356 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1357 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1358 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1359 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1360 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1362 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1363 NTTIME g = (given).basic_info.out.access_time; \
1364 NTTIME c = (correct).basic_info.out.access_time; \
1366 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1367 #given, nt_time_string(tctx, g), \
1368 #cmp, #correct, nt_time_string(tctx, c)); \
1373 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1374 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1376 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1377 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1378 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1381 #define GET_INFO_FILE(finfo) do { \
1383 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1384 if (!NT_STATUS_IS_OK(_status)) { \
1386 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1387 nt_errstr(_status)); \
1390 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1391 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1392 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1394 #define GET_INFO_FILE2(finfo) do { \
1396 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1397 if (!NT_STATUS_IS_OK(_status)) { \
1399 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1400 nt_errstr(_status)); \
1403 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1404 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1405 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1407 #define GET_INFO_PATH(pinfo) do { \
1409 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1410 if (!NT_STATUS_IS_OK(_status)) { \
1411 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1412 nt_errstr(_status)); \
1416 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1417 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1418 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1420 #define GET_INFO_BOTH(finfo,pinfo) do { \
1421 GET_INFO_FILE(finfo); \
1422 GET_INFO_PATH(pinfo); \
1423 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1426 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1428 union smb_setfileinfo sfinfo; \
1429 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1430 sfinfo.basic_info.in.file.fnum = tfnum; \
1431 sfinfo.basic_info.in.create_time = 0; \
1432 sfinfo.basic_info.in.access_time = 0; \
1433 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1434 sfinfo.basic_info.in.change_time = 0; \
1435 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1436 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1437 if (!NT_STATUS_IS_OK(_status)) { \
1438 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1439 nt_errstr(_status)); \
1444 #define SET_INFO_FILE(finfo, wrtime) \
1445 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1447 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1449 union smb_setfileinfo sfinfo; \
1450 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1451 sfinfo.basic_info.in.file.fnum = tfnum; \
1452 sfinfo.basic_info.in.create_time = 0; \
1453 sfinfo.basic_info.in.access_time = 0; \
1454 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1455 sfinfo.basic_info.in.write_time += (ns); \
1456 sfinfo.basic_info.in.change_time = 0; \
1457 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1458 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1459 if (!NT_STATUS_IS_OK(_status)) { \
1460 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1461 nt_errstr(_status)); \
1467 static bool test_delayed_write_update3(struct torture_context *tctx,
1468 struct smbcli_state *cli,
1469 struct smbcli_state *cli2)
1471 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1472 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1473 const char *fname = BASEDIR "\\torture_file3.txt";
1477 struct timeval start;
1479 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1480 int normal_delay = 2000000;
1481 double sec = ((double)used_delay) / ((double)normal_delay);
1482 int msec = 1000 * sec;
1484 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
1486 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1488 torture_comment(tctx, "Open the file handle\n");
1489 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1492 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1496 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1497 finfo0.basic_info.in.file.fnum = fnum1;
1501 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1502 pinfo0.basic_info.in.file.path = fname;
1508 /* get the initial times */
1509 GET_INFO_BOTH(finfo0,pinfo0);
1512 * make sure the write time is updated 2 seconds later
1513 * calcuated from the first write
1514 * (but expect upto 5 seconds extra time for a busy server)
1516 start = timeval_current();
1517 end = timeval_add(&start, 7 * sec, 0);
1518 while (!timeval_expired(&end)) {
1520 torture_comment(tctx, "Do a write on the file handle\n");
1521 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1523 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1527 /* get the times after the write */
1528 GET_INFO_FILE(finfo1);
1530 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1531 double diff = timeval_elapsed(&start);
1532 if (diff < (used_delay / (double)1000000)) {
1533 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1534 "(write time update delay == %.2f) (wrong!)\n",
1535 diff, used_delay / (double)1000000);
1540 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1545 smb_msleep(0.5 * msec);
1548 GET_INFO_BOTH(finfo1,pinfo1);
1549 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1551 /* sure any further write doesn't update the write time */
1552 start = timeval_current();
1553 end = timeval_add(&start, 15 * sec, 0);
1554 while (!timeval_expired(&end)) {
1556 torture_comment(tctx, "Do a write on the file handle\n");
1557 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1559 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1563 /* get the times after the write */
1564 GET_INFO_BOTH(finfo2,pinfo2);
1566 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1567 double diff = timeval_elapsed(&start);
1568 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1574 smb_msleep(1 * msec);
1577 GET_INFO_BOTH(finfo2,pinfo2);
1578 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1579 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1580 torture_comment(tctx, "Server did not update write_time (correct)\n");
1584 smb_msleep(5 * msec);
1586 GET_INFO_BOTH(finfo3,pinfo3);
1587 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1590 * the close updates the write time to the time of the close
1591 * and not to the time of the last write!
1593 torture_comment(tctx, "Close the file handle\n");
1594 smbcli_close(cli->tree, fnum1);
1597 GET_INFO_PATH(pinfo4);
1598 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1600 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1601 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1606 smbcli_close(cli->tree, fnum1);
1607 smbcli_unlink(cli->tree, fname);
1608 smbcli_deltree(cli->tree, BASEDIR);
1614 * Show that a truncate write always updates the write time even
1615 * if an initial write has already updated the write time.
1618 static bool test_delayed_write_update3a(struct torture_context *tctx,
1619 struct smbcli_state *cli,
1620 struct smbcli_state *cli2)
1622 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1623 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1624 const char *fname = BASEDIR "\\torture_file3a.txt";
1629 struct timeval start;
1631 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1632 int normal_delay = 2000000;
1633 double sec = ((double)used_delay) / ((double)normal_delay);
1634 int msec = 1000 * sec;
1636 torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
1638 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1640 torture_comment(tctx, "Open the file handle\n");
1641 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1644 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1648 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1649 finfo0.basic_info.in.file.fnum = fnum1;
1653 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1654 pinfo0.basic_info.in.file.path = fname;
1660 /* get the initial times */
1661 GET_INFO_BOTH(finfo0,pinfo0);
1664 * sleep some time, to demonstrate the handling of write times
1665 * doesn't depend on the time since the open
1667 smb_msleep(5 * msec);
1669 /* get the initial times */
1670 GET_INFO_BOTH(finfo1,pinfo1);
1671 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1674 * make sure the write time is updated 2 seconds later
1675 * calcuated from the first write
1676 * (but expect upto 5 seconds extra time for a busy server)
1678 start = timeval_current();
1679 end = timeval_add(&start, 7 * sec, 0);
1680 while (!timeval_expired(&end)) {
1682 torture_comment(tctx, "Do a write on the file handle\n");
1683 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1685 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1689 /* get the times after the write */
1690 GET_INFO_FILE(finfo1);
1692 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1693 double diff = timeval_elapsed(&start);
1694 if (diff < (used_delay / (double)1000000)) {
1695 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1696 "(1sec == %.2f) (wrong!)\n",
1702 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1707 smb_msleep(0.5 * msec);
1710 GET_INFO_BOTH(finfo1,pinfo1);
1711 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1713 smb_msleep(3 * msec);
1716 * demonstrate that a truncate write always
1717 * updates the write time immediately
1719 for (i=0; i < 3; i++) {
1720 smb_msleep(2 * msec);
1722 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1723 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1725 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1729 /* get the times after the write */
1730 GET_INFO_BOTH(finfo2,pinfo2);
1731 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1735 smb_msleep(3 * msec);
1737 /* sure any further write doesn't update the write time */
1738 start = timeval_current();
1739 end = timeval_add(&start, 15 * sec, 0);
1740 while (!timeval_expired(&end)) {
1742 torture_comment(tctx, "Do a write on the file handle\n");
1743 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1745 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1749 /* get the times after the write */
1750 GET_INFO_BOTH(finfo2,pinfo2);
1752 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1753 double diff = timeval_elapsed(&start);
1754 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1760 smb_msleep(1 * msec);
1763 GET_INFO_BOTH(finfo2,pinfo2);
1764 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1765 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1766 torture_comment(tctx, "Server did not update write_time (correct)\n");
1770 smb_msleep(3 * msec);
1772 /* get the initial times */
1773 GET_INFO_BOTH(finfo1,pinfo1);
1774 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1777 * demonstrate that a truncate write always
1778 * updates the write time immediately
1780 for (i=0; i < 3; i++) {
1781 smb_msleep(2 * msec);
1783 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1784 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1786 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1790 /* get the times after the write */
1791 GET_INFO_BOTH(finfo2,pinfo2);
1792 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1797 smb_msleep(3 * msec);
1799 GET_INFO_BOTH(finfo3,pinfo3);
1800 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1803 * the close doesn't update the write time
1805 torture_comment(tctx, "Close the file handle\n");
1806 smbcli_close(cli->tree, fnum1);
1809 GET_INFO_PATH(pinfo4);
1810 COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1812 if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1813 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1818 smbcli_close(cli->tree, fnum1);
1819 smbcli_unlink(cli->tree, fname);
1820 smbcli_deltree(cli->tree, BASEDIR);
1826 * Show a close after write updates the write timestamp to
1827 * the close time, not the last write time.
1830 static bool test_delayed_write_update3b(struct torture_context *tctx,
1831 struct smbcli_state *cli,
1832 struct smbcli_state *cli2)
1834 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1835 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1836 const char *fname = BASEDIR "\\torture_file3b.txt";
1840 struct timeval start;
1842 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1843 int normal_delay = 2000000;
1844 double sec = ((double)used_delay) / ((double)normal_delay);
1845 int msec = 1000 * sec;
1847 torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
1849 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1851 torture_comment(tctx, "Open the file handle\n");
1852 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1855 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1859 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1860 finfo0.basic_info.in.file.fnum = fnum1;
1864 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1865 pinfo0.basic_info.in.file.path = fname;
1871 /* get the initial times */
1872 GET_INFO_BOTH(finfo0,pinfo0);
1875 * sleep some time, to demonstrate the handling of write times
1876 * doesn't depend on the time since the open
1878 smb_msleep(5 * msec);
1880 /* get the initial times */
1881 GET_INFO_BOTH(finfo1,pinfo1);
1882 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1885 * make sure the write time is updated 2 seconds later
1886 * calcuated from the first write
1887 * (but expect upto 5 seconds extra time for a busy server)
1889 start = timeval_current();
1890 end = timeval_add(&start, 7 * sec, 0);
1891 while (!timeval_expired(&end)) {
1893 torture_comment(tctx, "Do a write on the file handle\n");
1894 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1896 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1900 /* get the times after the write */
1901 GET_INFO_FILE(finfo1);
1903 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1904 double diff = timeval_elapsed(&start);
1905 if (diff < (used_delay / (double)1000000)) {
1906 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1907 "(expected > %.2f) (wrong!)\n",
1908 diff, used_delay / (double)1000000);
1913 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1914 "(write time update delay == %.2f) (correct)\n",
1915 diff, used_delay / (double)1000000);
1918 smb_msleep(0.5 * msec);
1921 GET_INFO_BOTH(finfo1,pinfo1);
1922 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1924 /* sure any further write doesn't update the write time */
1925 start = timeval_current();
1926 end = timeval_add(&start, 15 * sec, 0);
1927 while (!timeval_expired(&end)) {
1929 torture_comment(tctx, "Do a write on the file handle\n");
1930 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1932 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1936 /* get the times after the write */
1937 GET_INFO_BOTH(finfo2,pinfo2);
1939 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1940 double diff = timeval_elapsed(&start);
1941 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1947 smb_msleep(1 * msec);
1950 GET_INFO_BOTH(finfo2,pinfo2);
1951 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1952 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1953 torture_comment(tctx, "Server did not update write_time (correct)\n");
1957 smb_msleep(5 * msec);
1959 GET_INFO_BOTH(finfo3,pinfo3);
1960 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1963 * the close updates the write time to the time of the close
1964 * and not to the time of the last write!
1966 torture_comment(tctx, "Close the file handle\n");
1967 smbcli_close(cli->tree, fnum1);
1970 GET_INFO_PATH(pinfo4);
1971 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1973 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1974 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1979 smbcli_close(cli->tree, fnum1);
1980 smbcli_unlink(cli->tree, fname);
1981 smbcli_deltree(cli->tree, BASEDIR);
1987 * Check that a write after a truncate write doesn't update
1988 * the timestamp, but a truncate write after a write does.
1989 * Also prove that a close after a truncate write updates the
1990 * timestamp to current, not the time of last write.
1993 static bool test_delayed_write_update3c(struct torture_context *tctx,
1994 struct smbcli_state *cli,
1995 struct smbcli_state *cli2)
1997 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1998 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1999 const char *fname = BASEDIR "\\torture_file3c.txt";
2004 struct timeval start;
2006 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2007 int normal_delay = 2000000;
2008 double sec = ((double)used_delay) / ((double)normal_delay);
2009 int msec = 1000 * sec;
2011 torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
2013 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2015 torture_comment(tctx, "Open the file handle\n");
2016 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2019 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2023 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2024 finfo0.basic_info.in.file.fnum = fnum1;
2029 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2030 pinfo0.basic_info.in.file.path = fname;
2037 /* get the initial times */
2038 GET_INFO_BOTH(finfo0,pinfo0);
2041 * sleep some time, to demonstrate the handling of write times
2042 * doesn't depend on the time since the open
2044 smb_msleep(5 * msec);
2046 /* get the initial times */
2047 GET_INFO_BOTH(finfo1,pinfo1);
2048 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2051 * demonstrate that a truncate write always
2052 * updates the write time immediately
2054 for (i=0; i < 3; i++) {
2055 smb_msleep(2 * msec);
2057 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
2058 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2060 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2064 /* get the times after the write */
2065 GET_INFO_BOTH(finfo2,pinfo2);
2066 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2070 start = timeval_current();
2071 end = timeval_add(&start, 7 * sec, 0);
2072 while (!timeval_expired(&end)) {
2074 torture_comment(tctx, "Do a write on the file handle\n");
2075 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2077 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2081 /* get the times after the write */
2082 GET_INFO_FILE(finfo2);
2084 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2085 double diff = timeval_elapsed(&start);
2086 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2092 smb_msleep(1 * msec);
2095 GET_INFO_BOTH(finfo2,pinfo2);
2096 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2097 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2098 torture_comment(tctx, "Server did not update write_time (correct)\n");
2102 smb_msleep(5 * msec);
2104 /* get the initial times */
2105 GET_INFO_BOTH(finfo1,pinfo1);
2106 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2109 * demonstrate that a truncate write always
2110 * updates the write time immediately
2112 for (i=0; i < 3; i++) {
2113 smb_msleep(2 * msec);
2115 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2116 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2118 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2122 /* get the times after the write */
2123 GET_INFO_BOTH(finfo2,pinfo2);
2124 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2129 smb_msleep(5 * msec);
2131 GET_INFO_BOTH(finfo2,pinfo2);
2132 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2134 /* sure any further write doesn't update the write time */
2135 start = timeval_current();
2136 end = timeval_add(&start, 15 * sec, 0);
2137 while (!timeval_expired(&end)) {
2139 torture_comment(tctx, "Do a write on the file handle\n");
2140 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2142 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2146 /* get the times after the write */
2147 GET_INFO_BOTH(finfo2,pinfo2);
2149 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2150 double diff = timeval_elapsed(&start);
2151 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2157 smb_msleep(1 * msec);
2160 GET_INFO_BOTH(finfo2,pinfo2);
2161 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2162 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2163 torture_comment(tctx, "Server did not update write_time (correct)\n");
2167 smb_msleep(5 * msec);
2169 GET_INFO_BOTH(finfo3,pinfo3);
2170 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2173 * the close updates the write time to the time of the close
2174 * and not to the time of the last write!
2176 torture_comment(tctx, "Close the file handle\n");
2177 smbcli_close(cli->tree, fnum1);
2180 GET_INFO_PATH(pinfo4);
2181 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2183 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2184 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2189 smbcli_close(cli->tree, fnum1);
2190 smbcli_unlink(cli->tree, fname);
2191 smbcli_deltree(cli->tree, BASEDIR);
2197 * Show only the first write updates the timestamp, and a close
2198 * after writes updates to current (I think this is the same
2202 static bool test_delayed_write_update4(struct torture_context *tctx,
2203 struct smbcli_state *cli,
2204 struct smbcli_state *cli2)
2206 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
2207 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
2208 const char *fname = BASEDIR "\\torture_file4.txt";
2212 struct timeval start;
2214 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2215 int normal_delay = 2000000;
2216 double sec = ((double)used_delay) / ((double)normal_delay);
2217 int msec = 1000 * sec;
2219 torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2221 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2223 torture_comment(tctx, "Open the file handle\n");
2224 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2227 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2231 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2232 finfo0.basic_info.in.file.fnum = fnum1;
2236 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2237 pinfo0.basic_info.in.file.path = fname;
2243 /* get the initial times */
2244 GET_INFO_BOTH(finfo0,pinfo0);
2247 smb_msleep(5 * msec);
2250 torture_comment(tctx, "Do a write on the file handle\n");
2251 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2253 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2258 GET_INFO_BOTH(finfo1,pinfo1);
2259 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2262 * make sure the write time is updated 2 seconds later
2263 * calcuated from the first write
2264 * (but expect upto 3 seconds extra time for a busy server)
2266 start = timeval_current();
2267 end = timeval_add(&start, 5 * sec, 0);
2268 while (!timeval_expired(&end)) {
2269 /* get the times after the first write */
2270 GET_INFO_FILE(finfo1);
2272 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2273 double diff = timeval_elapsed(&start);
2274 if (diff < (used_delay / (double)1000000)) {
2275 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
2276 "(expected > %.2f) (wrong!)\n",
2277 diff, used_delay / (double)1000000);
2282 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2283 "(write time update delay == %.2f) (correct)\n",
2284 diff, used_delay / (double)1000000);
2287 smb_msleep(0.5 * msec);
2290 GET_INFO_BOTH(finfo1,pinfo1);
2291 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2293 /* sure any further write doesn't update the write time */
2294 start = timeval_current();
2295 end = timeval_add(&start, 15 * sec, 0);
2296 while (!timeval_expired(&end)) {
2298 torture_comment(tctx, "Do a write on the file handle\n");
2299 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2301 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2305 /* get the times after the write */
2306 GET_INFO_BOTH(finfo2,pinfo2);
2308 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2309 double diff = timeval_elapsed(&start);
2310 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2316 smb_msleep(1 * msec);
2319 GET_INFO_BOTH(finfo2,pinfo2);
2320 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2321 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2322 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2326 smb_msleep(5 * msec);
2328 GET_INFO_BOTH(finfo3,pinfo3);
2329 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2332 * the close updates the write time to the time of the close
2333 * and not to the time of the last write!
2335 torture_comment(tctx, "Close the file handle\n");
2336 smbcli_close(cli->tree, fnum1);
2339 GET_INFO_PATH(pinfo4);
2340 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2342 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2343 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2348 smbcli_close(cli->tree, fnum1);
2349 smbcli_unlink(cli->tree, fname);
2350 smbcli_deltree(cli->tree, BASEDIR);
2356 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2359 static bool test_delayed_write_update5(struct torture_context *tctx,
2360 struct smbcli_state *cli,
2361 struct smbcli_state *cli2)
2363 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2364 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2365 const char *fname = BASEDIR "\\torture_file5.txt";
2369 struct timeval start;
2371 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2372 int normal_delay = 2000000;
2373 double sec = ((double)used_delay) / ((double)normal_delay);
2374 int msec = 1000 * sec;
2376 torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2378 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2380 torture_comment(tctx, "Open the file handle\n");
2381 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2384 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2388 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2389 finfo0.basic_info.in.file.fnum = fnum1;
2395 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2396 pinfo0.basic_info.in.file.path = fname;
2404 /* get the initial times */
2405 GET_INFO_BOTH(finfo0,pinfo0);
2408 torture_comment(tctx, "Do a write on the file handle\n");
2409 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2411 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2416 GET_INFO_BOTH(finfo1,pinfo1);
2417 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2419 torture_comment(tctx, "Set write time in the future on the file handle\n");
2420 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2421 GET_INFO_BOTH(finfo2,pinfo2);
2422 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2424 torture_comment(tctx, "Set write time in the past on the file handle\n");
2425 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2426 GET_INFO_BOTH(finfo2,pinfo2);
2427 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2429 /* make sure the 2 second delay from the first write are canceled */
2430 start = timeval_current();
2431 end = timeval_add(&start, 15 * sec, 0);
2432 while (!timeval_expired(&end)) {
2434 /* get the times after the first write */
2435 GET_INFO_BOTH(finfo3,pinfo3);
2437 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2438 double diff = timeval_elapsed(&start);
2439 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2445 smb_msleep(1 * msec);
2448 GET_INFO_BOTH(finfo3,pinfo3);
2449 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2450 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2451 torture_comment(tctx, "Server did not update write_time (correct)\n");
2454 /* sure any further write doesn't update the write time */
2455 start = timeval_current();
2456 end = timeval_add(&start, 15 * sec, 0);
2457 while (!timeval_expired(&end)) {
2459 torture_comment(tctx, "Do a write on the file handle\n");
2460 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2462 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2466 /* get the times after the write */
2467 GET_INFO_BOTH(finfo4,pinfo4);
2469 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2470 double diff = timeval_elapsed(&start);
2471 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2477 smb_msleep(1 * msec);
2480 GET_INFO_BOTH(finfo4,pinfo4);
2481 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2482 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2483 torture_comment(tctx, "Server did not update write_time (correct)\n");
2487 smb_msleep(5 * msec);
2489 GET_INFO_BOTH(finfo5,pinfo5);
2490 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2493 * the close doesn't update the write time
2495 torture_comment(tctx, "Close the file handle\n");
2496 smbcli_close(cli->tree, fnum1);
2499 GET_INFO_PATH(pinfo6);
2500 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2502 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2503 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2508 smbcli_close(cli->tree, fnum1);
2509 smbcli_unlink(cli->tree, fname);
2510 smbcli_deltree(cli->tree, BASEDIR);
2516 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2519 static bool test_delayed_write_update5b(struct torture_context *tctx,
2520 struct smbcli_state *cli,
2521 struct smbcli_state *cli2)
2523 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2524 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2525 const char *fname = BASEDIR "\\torture_fileb.txt";
2529 struct timeval start;
2531 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2532 int normal_delay = 2000000;
2533 double sec = ((double)used_delay) / ((double)normal_delay);
2534 int msec = 1000 * sec;
2536 torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2538 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2540 torture_comment(tctx, "Open the file handle\n");
2541 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2544 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2548 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2549 finfo0.basic_info.in.file.fnum = fnum1;
2555 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2556 pinfo0.basic_info.in.file.path = fname;
2564 /* get the initial times */
2565 GET_INFO_BOTH(finfo0,pinfo0);
2568 torture_comment(tctx, "Do a write on the file handle\n");
2569 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2571 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2576 GET_INFO_BOTH(finfo1,pinfo1);
2577 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2579 torture_comment(tctx, "Set write time in the future on the file handle\n");
2580 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2581 GET_INFO_BOTH(finfo2,pinfo2);
2582 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2584 torture_comment(tctx, "Set write time in the past on the file handle\n");
2585 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2586 GET_INFO_BOTH(finfo2,pinfo2);
2587 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2589 /* make sure the 2 second delay from the first write are canceled */
2590 start = timeval_current();
2591 end = timeval_add(&start, 15 * sec, 0);
2592 while (!timeval_expired(&end)) {
2594 /* get the times after the first write */
2595 GET_INFO_BOTH(finfo3,pinfo3);
2597 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2598 double diff = timeval_elapsed(&start);
2599 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2605 smb_msleep(1 * msec);
2608 GET_INFO_BOTH(finfo3,pinfo3);
2609 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2610 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2611 torture_comment(tctx, "Server did not update write_time (correct)\n");
2614 /* Do any further write (truncates) update the write time ? */
2615 start = timeval_current();
2616 end = timeval_add(&start, 15 * sec, 0);
2617 while (!timeval_expired(&end)) {
2619 torture_comment(tctx, "Do a truncate write on the file handle\n");
2620 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2622 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2626 /* get the times after the write */
2627 GET_INFO_BOTH(finfo4,pinfo4);
2629 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2630 double diff = timeval_elapsed(&start);
2631 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2637 smb_msleep(1 * msec);
2640 GET_INFO_BOTH(finfo4,pinfo4);
2641 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2642 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2643 torture_comment(tctx, "Server did not update write_time (correct)\n");
2647 smb_msleep(5 * msec);
2649 GET_INFO_BOTH(finfo5,pinfo5);
2650 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2653 * the close doesn't update the write time
2655 torture_comment(tctx, "Close the file handle\n");
2656 smbcli_close(cli->tree, fnum1);
2659 GET_INFO_PATH(pinfo6);
2660 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2662 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2663 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2668 smbcli_close(cli->tree, fnum1);
2669 smbcli_unlink(cli->tree, fname);
2670 smbcli_deltree(cli->tree, BASEDIR);
2676 * Open 2 handles on a file. Write one one and then set the
2677 * WRITE TIME explicitly on the other. Ensure the write time
2678 * update is cancelled. Ensure the write time is updated to
2679 * the close time when the non-explicit set handle is closed.
2683 static bool test_delayed_write_update6(struct torture_context *tctx,
2684 struct smbcli_state *cli,
2685 struct smbcli_state *cli2)
2687 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2688 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2689 const char *fname = BASEDIR "\\torture_file6.txt";
2694 struct timeval start;
2696 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2697 int normal_delay = 2000000;
2698 double sec = ((double)used_delay) / ((double)normal_delay);
2699 int msec = 1000 * sec;
2702 torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2704 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2706 torture_comment(tctx, "Open the file handle\n");
2707 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2710 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2715 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2716 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2719 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2724 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2725 finfo0.basic_info.in.file.fnum = fnum1;
2731 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2732 pinfo0.basic_info.in.file.path = fname;
2741 /* get the initial times */
2742 GET_INFO_BOTH(finfo0,pinfo0);
2745 torture_comment(tctx, "Do a write on the file handle\n");
2746 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2748 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2753 GET_INFO_BOTH(finfo1,pinfo1);
2754 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2756 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2757 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2758 GET_INFO_BOTH(finfo2,pinfo2);
2759 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2761 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2762 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2763 GET_INFO_BOTH(finfo2,pinfo2);
2764 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2766 /* make sure the 2 second delay from the first write are canceled */
2767 start = timeval_current();
2768 end = timeval_add(&start, 10 * sec, 0);
2769 while (!timeval_expired(&end)) {
2771 /* get the times after the first write */
2772 GET_INFO_BOTH(finfo3,pinfo3);
2774 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2775 double diff = timeval_elapsed(&start);
2776 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2782 smb_msleep(1 * msec);
2785 GET_INFO_BOTH(finfo3,pinfo3);
2786 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2787 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2788 torture_comment(tctx, "Server did not update write_time (correct)\n");
2791 /* sure any further write doesn't update the write time */
2792 start = timeval_current();
2793 end = timeval_add(&start, 10 * sec, 0);
2794 while (!timeval_expired(&end)) {
2796 torture_comment(tctx, "Do a write on the file handle\n");
2797 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2799 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2803 /* get the times after the write */
2804 GET_INFO_BOTH(finfo4,pinfo4);
2806 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2807 double diff = timeval_elapsed(&start);
2808 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2814 smb_msleep(1 * msec);
2817 GET_INFO_BOTH(finfo4,pinfo4);
2818 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2819 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2820 torture_comment(tctx, "Server did not update write_time (correct)\n");
2824 smb_msleep(5 * msec);
2826 GET_INFO_BOTH(finfo5,pinfo5);
2827 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2830 * the close updates the write time to the time of the close
2831 * as the write time was set on the 2nd handle
2833 torture_comment(tctx, "Close the file handle\n");
2834 smbcli_close(cli->tree, fnum1);
2837 GET_INFO_PATH(pinfo6);
2838 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2840 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2841 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2844 /* See what the second write handle thinks the time is ? */
2845 finfo5.basic_info.in.file.fnum = fnum2;
2846 GET_INFO_FILE2(finfo5);
2847 COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
2849 /* See if we have lost the sticky write time on handle2 */
2850 smb_msleep(3 * msec);
2851 torture_comment(tctx, "Have we lost the sticky write time ?\n");
2853 /* Make sure any further normal write doesn't update the write time */
2854 start = timeval_current();
2855 end = timeval_add(&start, 10 * sec, 0);
2856 while (!timeval_expired(&end)) {
2858 torture_comment(tctx, "Do a write on the second file handle\n");
2859 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
2861 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2865 /* get the times after the write */
2866 GET_INFO_FILE2(finfo5);
2867 GET_INFO_PATH(pinfo6);
2869 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2870 double diff = timeval_elapsed(&start);
2871 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2877 smb_msleep(1 * msec);
2880 /* What about a truncate write ? */
2881 start = timeval_current();
2882 end = timeval_add(&start, 10 * sec, 0);
2883 while (!timeval_expired(&end)) {
2885 torture_comment(tctx, "Do a truncate write on the second file handle\n");
2886 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
2888 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2892 /* get the times after the write */
2893 GET_INFO_FILE2(finfo5);
2894 GET_INFO_PATH(pinfo6);
2896 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2897 double diff = timeval_elapsed(&start);
2898 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2904 smb_msleep(1 * msec);
2908 /* keep the 2nd handle open and rerun tests */
2915 * closing the 2nd handle will cause no write time update
2916 * as the write time was explicit set on this handle
2918 torture_comment(tctx, "Close the 2nd file handle\n");
2919 smbcli_close(cli2->tree, fnum2);
2922 GET_INFO_PATH(pinfo7);
2923 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2925 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2926 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2931 smbcli_close(cli->tree, fnum1);
2933 smbcli_close(cli2->tree, fnum2);
2934 smbcli_unlink(cli->tree, fname);
2935 smbcli_deltree(cli->tree, BASEDIR);
2940 static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
2942 union smb_open open_parms;
2943 union smb_fileinfo finfo1, finfo2, finfo3;
2944 const char *fname = BASEDIR "\\torture_file7.txt";
2948 TALLOC_CTX *mem_ctx;
2950 torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2952 mem_ctx = talloc_init("test_delayed_write_update7");
2953 if (!mem_ctx) return false;
2955 ZERO_STRUCT(finfo1);
2956 ZERO_STRUCT(finfo2);
2957 ZERO_STRUCT(finfo3);
2958 ZERO_STRUCT(open_parms);
2960 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2962 /* Create the file. */
2963 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2965 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
2969 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2970 finfo1.basic_info.in.file.fnum = fnum1;
2974 /* Get the initial timestamps. */
2975 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
2977 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2979 /* Set the pending write time to a value with ns. */
2980 SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
2982 /* Get the current pending write time by fnum. */
2983 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
2985 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2987 /* Ensure the time is actually different. */
2988 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2989 torture_result(tctx, TORTURE_FAIL,
2990 "setfileinfo time matches original fileinfo time");
2994 /* Get the current pending write time by path. */
2995 finfo3.basic_info.in.file.path = fname;
2996 status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
2998 if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
2999 torture_result(tctx, TORTURE_FAIL,
3000 "qpathinfo time doens't match fileinfo time");
3004 /* Now close the file. Re-open and check that the write
3005 time is identical to the one we wrote. */
3007 smbcli_close(cli->tree, fnum1);
3009 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3010 open_parms.ntcreatex.in.flags = 0;
3011 open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
3012 open_parms.ntcreatex.in.file_attr = 0;
3013 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3014 NTCREATEX_SHARE_ACCESS_READ|
3015 NTCREATEX_SHARE_ACCESS_WRITE;
3016 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3017 open_parms.ntcreatex.in.create_options = 0;
3018 open_parms.ntcreatex.in.fname = fname;
3020 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3021 talloc_free(mem_ctx);
3023 if (!NT_STATUS_IS_OK(status)) {
3024 torture_result(tctx, TORTURE_FAIL,
3025 "setfileinfo time matches original fileinfo time");
3029 fnum1 = open_parms.ntcreatex.out.file.fnum;
3031 /* Check the returned time matches. */
3032 if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
3033 torture_result(tctx, TORTURE_FAIL,
3034 "final open time does not match set time");
3040 smbcli_close(cli->tree, fnum1);
3042 smbcli_unlink(cli->tree, fname);
3043 smbcli_deltree(cli->tree, BASEDIR);
3048 Test if creating a file in a directory with an open handle updates the
3049 write timestamp (it should).
3051 static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
3053 union smb_fileinfo dir_info1, dir_info2;
3054 union smb_open open_parms;
3055 const char *fname = BASEDIR "\\torture_file.txt";
3060 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3061 int normal_delay = 2000000;
3062 double sec = ((double)used_delay) / ((double)normal_delay);
3063 int msec = 1000 * sec;
3064 TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
3066 if (!mem_ctx) return false;
3068 torture_comment(tctx, "\nRunning test directory write update\n");
3070 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
3072 /* Open a handle on the directory - and leave it open. */
3073 ZERO_STRUCT(open_parms);
3074 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3075 open_parms.ntcreatex.in.flags = 0;
3076 open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
3077 open_parms.ntcreatex.in.file_attr = 0;
3078 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3079 NTCREATEX_SHARE_ACCESS_READ|
3080 NTCREATEX_SHARE_ACCESS_WRITE;
3081 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3082 open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
3083 open_parms.ntcreatex.in.fname = BASEDIR;
3085 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3086 talloc_free(mem_ctx);
3088 if (!NT_STATUS_IS_OK(status)) {
3089 torture_result(tctx, TORTURE_FAIL,
3090 "failed to open directory handle");
3095 fnum1 = open_parms.ntcreatex.out.file.fnum;
3097 /* Store the returned write time. */
3098 ZERO_STRUCT(dir_info1);
3099 dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
3101 torture_comment(tctx, "Initial write time %s\n",
3102 nt_time_string(tctx, dir_info1.basic_info.out.write_time));
3105 smb_msleep(3 * msec);
3107 /* Now create a file within the directory. */
3108 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3110 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
3114 smbcli_close(cli->tree, fnum2);
3116 /* Read the directory write time again. */
3117 ZERO_STRUCT(dir_info2);
3118 dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3119 dir_info2.basic_info.in.file.fnum = fnum1;
3121 status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
3123 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
3125 /* Ensure it's been incremented. */
3126 COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
3128 torture_comment(tctx, "Updated write time %s\n",
3129 nt_time_string(tctx, dir_info2.basic_info.out.write_time));
3134 smbcli_close(cli->tree, fnum1);
3135 smbcli_unlink(cli->tree, fname);
3136 smbcli_deltree(cli->tree, BASEDIR);
3142 testing of delayed update of write_time
3144 struct torture_suite *torture_delay_write(void)
3146 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "delaywrite");
3148 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
3149 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
3150 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
3151 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
3152 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
3153 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
3154 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
3155 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
3156 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
3157 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
3158 torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
3159 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
3160 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
3161 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
3162 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
3163 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3164 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3165 torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);