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;
1998 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
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;
2028 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2029 pinfo0.basic_info.in.file.path = fname;
2035 /* get the initial times */
2036 GET_INFO_BOTH(finfo0,pinfo0);
2039 * sleep some time, to demonstrate the handling of write times
2040 * doesn't depend on the time since the open
2042 smb_msleep(5 * msec);
2044 /* get the initial times */
2045 GET_INFO_BOTH(finfo1,pinfo1);
2046 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2049 * demonstrate that a truncate write always
2050 * updates the write time immediately
2052 for (i=0; i < 3; i++) {
2053 smb_msleep(2 * msec);
2055 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
2056 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2058 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2062 /* get the times after the write */
2063 GET_INFO_BOTH(finfo2,pinfo2);
2064 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2068 start = timeval_current();
2069 end = timeval_add(&start, 7 * sec, 0);
2070 while (!timeval_expired(&end)) {
2072 torture_comment(tctx, "Do a write on the file handle\n");
2073 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2075 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2079 /* get the times after the write */
2080 GET_INFO_FILE(finfo2);
2082 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2083 double diff = timeval_elapsed(&start);
2084 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2090 smb_msleep(1 * msec);
2093 GET_INFO_BOTH(finfo2,pinfo2);
2094 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2095 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2096 torture_comment(tctx, "Server did not update write_time (correct)\n");
2100 smb_msleep(5 * msec);
2102 /* get the initial times */
2103 GET_INFO_BOTH(finfo1,pinfo1);
2104 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2107 * demonstrate that a truncate write always
2108 * updates the write time immediately
2110 for (i=0; i < 3; i++) {
2111 smb_msleep(2 * msec);
2113 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2114 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2116 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2120 /* get the times after the write */
2121 GET_INFO_BOTH(finfo2,pinfo2);
2122 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2127 smb_msleep(5 * msec);
2129 GET_INFO_BOTH(finfo2,pinfo2);
2130 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2132 /* sure any further write doesn't update the write time */
2133 start = timeval_current();
2134 end = timeval_add(&start, 15 * sec, 0);
2135 while (!timeval_expired(&end)) {
2137 torture_comment(tctx, "Do a write on the file handle\n");
2138 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2140 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2144 /* get the times after the write */
2145 GET_INFO_BOTH(finfo2,pinfo2);
2147 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2148 double diff = timeval_elapsed(&start);
2149 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2155 smb_msleep(1 * msec);
2158 GET_INFO_BOTH(finfo2,pinfo2);
2159 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2160 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2161 torture_comment(tctx, "Server did not update write_time (correct)\n");
2165 smb_msleep(5 * msec);
2167 GET_INFO_BOTH(finfo3,pinfo3);
2168 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2171 * the close updates the write time to the time of the close
2172 * and not to the time of the last write!
2174 torture_comment(tctx, "Close the file handle\n");
2175 smbcli_close(cli->tree, fnum1);
2178 GET_INFO_PATH(pinfo4);
2179 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2181 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2182 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2187 smbcli_close(cli->tree, fnum1);
2188 smbcli_unlink(cli->tree, fname);
2189 smbcli_deltree(cli->tree, BASEDIR);
2195 * Show only the first write updates the timestamp, and a close
2196 * after writes updates to current (I think this is the same
2200 static bool test_delayed_write_update4(struct torture_context *tctx,
2201 struct smbcli_state *cli,
2202 struct smbcli_state *cli2)
2204 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
2205 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
2206 const char *fname = BASEDIR "\\torture_file4.txt";
2210 struct timeval start;
2212 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2213 int normal_delay = 2000000;
2214 double sec = ((double)used_delay) / ((double)normal_delay);
2215 int msec = 1000 * sec;
2217 torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2219 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2221 torture_comment(tctx, "Open the file handle\n");
2222 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2225 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2229 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2230 finfo0.basic_info.in.file.fnum = fnum1;
2234 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2235 pinfo0.basic_info.in.file.path = fname;
2241 /* get the initial times */
2242 GET_INFO_BOTH(finfo0,pinfo0);
2245 smb_msleep(5 * msec);
2248 torture_comment(tctx, "Do a write on the file handle\n");
2249 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2251 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2256 GET_INFO_BOTH(finfo1,pinfo1);
2257 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2260 * make sure the write time is updated 2 seconds later
2261 * calcuated from the first write
2262 * (but expect upto 3 seconds extra time for a busy server)
2264 start = timeval_current();
2265 end = timeval_add(&start, 5 * sec, 0);
2266 while (!timeval_expired(&end)) {
2267 /* get the times after the first write */
2268 GET_INFO_FILE(finfo1);
2270 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2271 double diff = timeval_elapsed(&start);
2272 if (diff < (used_delay / (double)1000000)) {
2273 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
2274 "(expected > %.2f) (wrong!)\n",
2275 diff, used_delay / (double)1000000);
2280 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2281 "(write time update delay == %.2f) (correct)\n",
2282 diff, used_delay / (double)1000000);
2285 smb_msleep(0.5 * msec);
2288 GET_INFO_BOTH(finfo1,pinfo1);
2289 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2291 /* sure any further write doesn't update the write time */
2292 start = timeval_current();
2293 end = timeval_add(&start, 15 * sec, 0);
2294 while (!timeval_expired(&end)) {
2296 torture_comment(tctx, "Do a write on the file handle\n");
2297 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2299 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2303 /* get the times after the write */
2304 GET_INFO_BOTH(finfo2,pinfo2);
2306 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2307 double diff = timeval_elapsed(&start);
2308 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2314 smb_msleep(1 * msec);
2317 GET_INFO_BOTH(finfo2,pinfo2);
2318 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2319 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2320 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2324 smb_msleep(5 * msec);
2326 GET_INFO_BOTH(finfo3,pinfo3);
2327 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2330 * the close updates the write time to the time of the close
2331 * and not to the time of the last write!
2333 torture_comment(tctx, "Close the file handle\n");
2334 smbcli_close(cli->tree, fnum1);
2337 GET_INFO_PATH(pinfo4);
2338 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2340 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2341 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2346 smbcli_close(cli->tree, fnum1);
2347 smbcli_unlink(cli->tree, fname);
2348 smbcli_deltree(cli->tree, BASEDIR);
2354 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2357 static bool test_delayed_write_update5(struct torture_context *tctx,
2358 struct smbcli_state *cli,
2359 struct smbcli_state *cli2)
2361 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2362 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2363 const char *fname = BASEDIR "\\torture_file5.txt";
2367 struct timeval start;
2369 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2370 int normal_delay = 2000000;
2371 double sec = ((double)used_delay) / ((double)normal_delay);
2372 int msec = 1000 * sec;
2374 torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2376 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2378 torture_comment(tctx, "Open the file handle\n");
2379 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2382 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2386 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2387 finfo0.basic_info.in.file.fnum = fnum1;
2393 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2394 pinfo0.basic_info.in.file.path = fname;
2402 /* get the initial times */
2403 GET_INFO_BOTH(finfo0,pinfo0);
2406 torture_comment(tctx, "Do a write on the file handle\n");
2407 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2409 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2414 GET_INFO_BOTH(finfo1,pinfo1);
2415 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2417 torture_comment(tctx, "Set write time in the future on the file handle\n");
2418 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2419 GET_INFO_BOTH(finfo2,pinfo2);
2420 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2422 torture_comment(tctx, "Set write time in the past on the file handle\n");
2423 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2424 GET_INFO_BOTH(finfo2,pinfo2);
2425 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2427 /* make sure the 2 second delay from the first write are canceled */
2428 start = timeval_current();
2429 end = timeval_add(&start, 15 * sec, 0);
2430 while (!timeval_expired(&end)) {
2432 /* get the times after the first write */
2433 GET_INFO_BOTH(finfo3,pinfo3);
2435 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2436 double diff = timeval_elapsed(&start);
2437 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2443 smb_msleep(1 * msec);
2446 GET_INFO_BOTH(finfo3,pinfo3);
2447 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2448 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2449 torture_comment(tctx, "Server did not update write_time (correct)\n");
2452 /* sure any further write doesn't update the write time */
2453 start = timeval_current();
2454 end = timeval_add(&start, 15 * sec, 0);
2455 while (!timeval_expired(&end)) {
2457 torture_comment(tctx, "Do a write on the file handle\n");
2458 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2460 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2464 /* get the times after the write */
2465 GET_INFO_BOTH(finfo4,pinfo4);
2467 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2468 double diff = timeval_elapsed(&start);
2469 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2475 smb_msleep(1 * msec);
2478 GET_INFO_BOTH(finfo4,pinfo4);
2479 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2480 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2481 torture_comment(tctx, "Server did not update write_time (correct)\n");
2485 smb_msleep(5 * msec);
2487 GET_INFO_BOTH(finfo5,pinfo5);
2488 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2491 * the close doesn't update the write time
2493 torture_comment(tctx, "Close the file handle\n");
2494 smbcli_close(cli->tree, fnum1);
2497 GET_INFO_PATH(pinfo6);
2498 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2500 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2501 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2506 smbcli_close(cli->tree, fnum1);
2507 smbcli_unlink(cli->tree, fname);
2508 smbcli_deltree(cli->tree, BASEDIR);
2514 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2517 static bool test_delayed_write_update5b(struct torture_context *tctx,
2518 struct smbcli_state *cli,
2519 struct smbcli_state *cli2)
2521 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2522 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2523 const char *fname = BASEDIR "\\torture_fileb.txt";
2527 struct timeval start;
2529 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2530 int normal_delay = 2000000;
2531 double sec = ((double)used_delay) / ((double)normal_delay);
2532 int msec = 1000 * sec;
2534 torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2536 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2538 torture_comment(tctx, "Open the file handle\n");
2539 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2542 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2546 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2547 finfo0.basic_info.in.file.fnum = fnum1;
2553 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2554 pinfo0.basic_info.in.file.path = fname;
2562 /* get the initial times */
2563 GET_INFO_BOTH(finfo0,pinfo0);
2566 torture_comment(tctx, "Do a write on the file handle\n");
2567 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2569 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2574 GET_INFO_BOTH(finfo1,pinfo1);
2575 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2577 torture_comment(tctx, "Set write time in the future on the file handle\n");
2578 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2579 GET_INFO_BOTH(finfo2,pinfo2);
2580 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2582 torture_comment(tctx, "Set write time in the past on the file handle\n");
2583 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2584 GET_INFO_BOTH(finfo2,pinfo2);
2585 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2587 /* make sure the 2 second delay from the first write are canceled */
2588 start = timeval_current();
2589 end = timeval_add(&start, 15 * sec, 0);
2590 while (!timeval_expired(&end)) {
2592 /* get the times after the first write */
2593 GET_INFO_BOTH(finfo3,pinfo3);
2595 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2596 double diff = timeval_elapsed(&start);
2597 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2603 smb_msleep(1 * msec);
2606 GET_INFO_BOTH(finfo3,pinfo3);
2607 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2608 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2609 torture_comment(tctx, "Server did not update write_time (correct)\n");
2612 /* Do any further write (truncates) update the write time ? */
2613 start = timeval_current();
2614 end = timeval_add(&start, 15 * sec, 0);
2615 while (!timeval_expired(&end)) {
2617 torture_comment(tctx, "Do a truncate write on the file handle\n");
2618 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2620 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2624 /* get the times after the write */
2625 GET_INFO_BOTH(finfo4,pinfo4);
2627 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2628 double diff = timeval_elapsed(&start);
2629 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2635 smb_msleep(1 * msec);
2638 GET_INFO_BOTH(finfo4,pinfo4);
2639 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2640 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2641 torture_comment(tctx, "Server did not update write_time (correct)\n");
2645 smb_msleep(5 * msec);
2647 GET_INFO_BOTH(finfo5,pinfo5);
2648 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2651 * the close doesn't update the write time
2653 torture_comment(tctx, "Close the file handle\n");
2654 smbcli_close(cli->tree, fnum1);
2657 GET_INFO_PATH(pinfo6);
2658 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2660 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2661 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2666 smbcli_close(cli->tree, fnum1);
2667 smbcli_unlink(cli->tree, fname);
2668 smbcli_deltree(cli->tree, BASEDIR);
2674 * Open 2 handles on a file. Write one one and then set the
2675 * WRITE TIME explicitly on the other. Ensure the write time
2676 * update is cancelled. Ensure the write time is updated to
2677 * the close time when the non-explicit set handle is closed.
2681 static bool test_delayed_write_update6(struct torture_context *tctx,
2682 struct smbcli_state *cli,
2683 struct smbcli_state *cli2)
2685 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2686 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2687 const char *fname = BASEDIR "\\torture_file6.txt";
2692 struct timeval start;
2694 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2695 int normal_delay = 2000000;
2696 double sec = ((double)used_delay) / ((double)normal_delay);
2697 int msec = 1000 * sec;
2700 torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2702 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2704 torture_comment(tctx, "Open the file handle\n");
2705 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2708 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2713 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2714 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2717 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2722 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2723 finfo0.basic_info.in.file.fnum = fnum1;
2729 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2730 pinfo0.basic_info.in.file.path = fname;
2739 /* get the initial times */
2740 GET_INFO_BOTH(finfo0,pinfo0);
2743 torture_comment(tctx, "Do a write on the file handle\n");
2744 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2746 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2751 GET_INFO_BOTH(finfo1,pinfo1);
2752 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2754 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2755 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2756 GET_INFO_BOTH(finfo2,pinfo2);
2757 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2759 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2760 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2761 GET_INFO_BOTH(finfo2,pinfo2);
2762 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2764 /* make sure the 2 second delay from the first write are canceled */
2765 start = timeval_current();
2766 end = timeval_add(&start, 10 * sec, 0);
2767 while (!timeval_expired(&end)) {
2769 /* get the times after the first write */
2770 GET_INFO_BOTH(finfo3,pinfo3);
2772 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2773 double diff = timeval_elapsed(&start);
2774 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2780 smb_msleep(1 * msec);
2783 GET_INFO_BOTH(finfo3,pinfo3);
2784 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2785 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2786 torture_comment(tctx, "Server did not update write_time (correct)\n");
2789 /* sure any further write doesn't update the write time */
2790 start = timeval_current();
2791 end = timeval_add(&start, 10 * sec, 0);
2792 while (!timeval_expired(&end)) {
2794 torture_comment(tctx, "Do a write on the file handle\n");
2795 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2797 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2801 /* get the times after the write */
2802 GET_INFO_BOTH(finfo4,pinfo4);
2804 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2805 double diff = timeval_elapsed(&start);
2806 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2812 smb_msleep(1 * msec);
2815 GET_INFO_BOTH(finfo4,pinfo4);
2816 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2817 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2818 torture_comment(tctx, "Server did not update write_time (correct)\n");
2822 smb_msleep(5 * msec);
2824 GET_INFO_BOTH(finfo5,pinfo5);
2825 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2828 * the close updates the write time to the time of the close
2829 * as the write time was set on the 2nd handle
2831 torture_comment(tctx, "Close the file handle\n");
2832 smbcli_close(cli->tree, fnum1);
2835 GET_INFO_PATH(pinfo6);
2836 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2838 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2839 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2842 /* See what the second write handle thinks the time is ? */
2843 finfo5.basic_info.in.file.fnum = fnum2;
2844 GET_INFO_FILE2(finfo5);
2845 COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
2847 /* See if we have lost the sticky write time on handle2 */
2848 smb_msleep(3 * msec);
2849 torture_comment(tctx, "Have we lost the sticky write time ?\n");
2851 /* Make sure any further normal write doesn't update the write time */
2852 start = timeval_current();
2853 end = timeval_add(&start, 10 * sec, 0);
2854 while (!timeval_expired(&end)) {
2856 torture_comment(tctx, "Do a write on the second file handle\n");
2857 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
2859 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2863 /* get the times after the write */
2864 GET_INFO_FILE2(finfo5);
2865 GET_INFO_PATH(pinfo6);
2867 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2868 double diff = timeval_elapsed(&start);
2869 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2875 smb_msleep(1 * msec);
2878 /* What about a truncate write ? */
2879 start = timeval_current();
2880 end = timeval_add(&start, 10 * sec, 0);
2881 while (!timeval_expired(&end)) {
2883 torture_comment(tctx, "Do a truncate write on the second file handle\n");
2884 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
2886 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2890 /* get the times after the write */
2891 GET_INFO_FILE2(finfo5);
2892 GET_INFO_PATH(pinfo6);
2894 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2895 double diff = timeval_elapsed(&start);
2896 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2902 smb_msleep(1 * msec);
2906 /* keep the 2nd handle open and rerun tests */
2913 * closing the 2nd handle will cause no write time update
2914 * as the write time was explicit set on this handle
2916 torture_comment(tctx, "Close the 2nd file handle\n");
2917 smbcli_close(cli2->tree, fnum2);
2920 GET_INFO_PATH(pinfo7);
2921 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2923 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2924 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2929 smbcli_close(cli->tree, fnum1);
2931 smbcli_close(cli2->tree, fnum2);
2932 smbcli_unlink(cli->tree, fname);
2933 smbcli_deltree(cli->tree, BASEDIR);
2938 static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
2940 union smb_open open_parms;
2941 union smb_fileinfo finfo1, finfo2, finfo3;
2942 const char *fname = BASEDIR "\\torture_file7.txt";
2946 TALLOC_CTX *mem_ctx;
2948 torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2950 mem_ctx = talloc_init("test_delayed_write_update7");
2951 if (!mem_ctx) return false;
2953 ZERO_STRUCT(finfo1);
2954 ZERO_STRUCT(finfo2);
2955 ZERO_STRUCT(finfo3);
2956 ZERO_STRUCT(open_parms);
2958 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2960 /* Create the file. */
2961 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2963 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
2967 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2968 finfo1.basic_info.in.file.fnum = fnum1;
2972 /* Get the initial timestamps. */
2973 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
2975 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2977 /* Set the pending write time to a value with ns. */
2978 SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
2980 /* Get the current pending write time by fnum. */
2981 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
2983 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2985 /* Ensure the time is actually different. */
2986 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2987 torture_result(tctx, TORTURE_FAIL,
2988 "setfileinfo time matches original fileinfo time");
2992 /* Get the current pending write time by path. */
2993 finfo3.basic_info.in.file.path = fname;
2994 status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
2996 if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
2997 torture_result(tctx, TORTURE_FAIL,
2998 "qpathinfo time doens't match fileinfo time");
3002 /* Now close the file. Re-open and check that the write
3003 time is identical to the one we wrote. */
3005 smbcli_close(cli->tree, fnum1);
3007 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3008 open_parms.ntcreatex.in.flags = 0;
3009 open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
3010 open_parms.ntcreatex.in.file_attr = 0;
3011 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3012 NTCREATEX_SHARE_ACCESS_READ|
3013 NTCREATEX_SHARE_ACCESS_WRITE;
3014 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3015 open_parms.ntcreatex.in.create_options = 0;
3016 open_parms.ntcreatex.in.fname = fname;
3018 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3019 talloc_free(mem_ctx);
3021 if (!NT_STATUS_IS_OK(status)) {
3022 torture_result(tctx, TORTURE_FAIL,
3023 "setfileinfo time matches original fileinfo time");
3027 fnum1 = open_parms.ntcreatex.out.file.fnum;
3029 /* Check the returned time matches. */
3030 if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
3031 torture_result(tctx, TORTURE_FAIL,
3032 "final open time does not match set time");
3038 smbcli_close(cli->tree, fnum1);
3040 smbcli_unlink(cli->tree, fname);
3041 smbcli_deltree(cli->tree, BASEDIR);
3046 Test if creating a file in a directory with an open handle updates the
3047 write timestamp (it should).
3049 static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
3051 union smb_fileinfo dir_info1, dir_info2;
3052 union smb_open open_parms;
3053 const char *fname = BASEDIR "\\torture_file.txt";
3058 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3059 int normal_delay = 2000000;
3060 double sec = ((double)used_delay) / ((double)normal_delay);
3061 int msec = 1000 * sec;
3062 TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
3064 if (!mem_ctx) return false;
3066 torture_comment(tctx, "\nRunning test directory write update\n");
3068 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
3070 /* Open a handle on the directory - and leave it open. */
3071 ZERO_STRUCT(open_parms);
3072 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3073 open_parms.ntcreatex.in.flags = 0;
3074 open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
3075 open_parms.ntcreatex.in.file_attr = 0;
3076 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3077 NTCREATEX_SHARE_ACCESS_READ|
3078 NTCREATEX_SHARE_ACCESS_WRITE;
3079 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3080 open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
3081 open_parms.ntcreatex.in.fname = BASEDIR;
3083 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3084 talloc_free(mem_ctx);
3086 if (!NT_STATUS_IS_OK(status)) {
3087 torture_result(tctx, TORTURE_FAIL,
3088 "failed to open directory handle");
3093 fnum1 = open_parms.ntcreatex.out.file.fnum;
3095 /* Store the returned write time. */
3096 ZERO_STRUCT(dir_info1);
3097 dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
3099 torture_comment(tctx, "Initial write time %s\n",
3100 nt_time_string(tctx, dir_info1.basic_info.out.write_time));
3103 smb_msleep(3 * msec);
3105 /* Now create a file within the directory. */
3106 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3108 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
3112 smbcli_close(cli->tree, fnum2);
3114 /* Read the directory write time again. */
3115 ZERO_STRUCT(dir_info2);
3116 dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3117 dir_info2.basic_info.in.file.fnum = fnum1;
3119 status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
3121 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
3123 /* Ensure it's been incremented. */
3124 COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
3126 torture_comment(tctx, "Updated write time %s\n",
3127 nt_time_string(tctx, dir_info2.basic_info.out.write_time));
3132 smbcli_close(cli->tree, fnum1);
3133 smbcli_unlink(cli->tree, fname);
3134 smbcli_deltree(cli->tree, BASEDIR);
3140 testing of delayed update of write_time
3142 struct torture_suite *torture_delay_write(void)
3144 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "delaywrite");
3146 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
3147 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
3148 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
3149 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
3150 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
3151 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
3152 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
3153 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
3154 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
3155 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
3156 torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
3157 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
3158 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
3159 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
3160 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
3161 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3162 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3163 torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);