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);
57 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
61 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
62 finfo1.basic_info.in.file.fnum = fnum1;
65 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
67 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
69 torture_comment(tctx, "Initial write time %s\n",
70 nt_time_string(tctx, finfo1.basic_info.out.write_time));
72 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
75 torture_result(tctx, TORTURE_FAIL,
76 "write failed - wrote %d bytes (%s)\n",
77 (int)written, __location__);
81 start = timeval_current();
82 end = timeval_add(&start, (120 * sec), 0);
83 while (!timeval_expired(&end)) {
84 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
86 if (!NT_STATUS_IS_OK(status)) {
87 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
91 torture_comment(tctx, "write time %s\n",
92 nt_time_string(tctx, finfo2.basic_info.out.write_time));
93 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
94 double diff = timeval_elapsed(&start);
95 if (diff < (used_delay / (double)1000000)) {
96 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
97 "(expected > %.2f) (wrong!)\n",
98 diff, used_delay / (double)1000000);
103 torture_comment(tctx, "Server updated write_time after %.2f seconds (correct)\n",
108 smb_msleep(1 * msec);
111 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
112 torture_result(tctx, TORTURE_FAIL,
113 "Server did not update write time (wrong!)");
119 smbcli_close(cli->tree, fnum1);
120 smbcli_unlink(cli->tree, fname);
121 smbcli_deltree(cli->tree, BASEDIR);
126 static bool test_delayed_write_update1(struct torture_context *tctx, struct smbcli_state *cli)
128 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
129 const char *fname = BASEDIR "\\torture_file1.txt";
134 struct timeval start;
136 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
137 int normal_delay = 2000000;
138 double sec = ((double)used_delay) / ((double)normal_delay);
139 int msec = 1000 * sec;
142 torture_comment(tctx, "\nRunning test_delayed_write_update1\n");
144 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
146 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
148 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
152 memset(buf, 'x', 2048);
153 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
155 /* 3 second delay to ensure we get past any 2 second time
156 granularity (older systems may have that) */
157 smb_msleep(3 * msec);
159 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
160 finfo1.all_info.in.file.fnum = fnum1;
163 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
164 pinfo4.all_info.in.file.path = fname;
166 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
168 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
170 torture_comment(tctx, "Initial write time %s\n",
171 nt_time_string(tctx, finfo1.all_info.out.write_time));
173 /* 3 second delay to ensure we get past any 2 second time
174 granularity (older systems may have that) */
175 smb_msleep(3 * msec);
177 /* Do a zero length SMBwrite call to truncate. */
178 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
181 torture_result(tctx, TORTURE_FAIL,
182 "write failed - wrote %d bytes (%s)\n",
183 (int)written, __location__);
187 start = timeval_current();
188 end = timeval_add(&start, (120 * sec), 0);
189 while (!timeval_expired(&end)) {
190 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
192 if (!NT_STATUS_IS_OK(status)) {
193 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
198 if (finfo2.all_info.out.size != 1024) {
199 torture_result(tctx, TORTURE_FAIL,
200 "file not truncated, size = %u (should be 1024)",
201 (unsigned int)finfo2.all_info.out.size);
206 torture_comment(tctx, "write time %s\n",
207 nt_time_string(tctx, finfo2.all_info.out.write_time));
208 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
209 double diff = timeval_elapsed(&start);
210 if (diff > (0.25 * (used_delay / (double)1000000))) {
211 torture_result(tctx, TORTURE_FAIL, "After SMBwrite truncate "
212 "server updated write_time after %.2f seconds"
213 "(write time update dealy == %.2f)(wrong!)\n",
214 diff, used_delay / (double)1000000);
219 torture_comment(tctx, "After SMBwrite truncate "
220 "server updated write_time after %.2f seconds"
221 "(1 sec == %.2f)(correct)\n",
222 diff, used_delay / (double)1000000);
226 smb_msleep(1 * msec);
229 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
230 torture_result(tctx, TORTURE_FAIL,
231 "Server did not update write time (wrong!)");
236 smb_msleep(2 * msec);
238 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
239 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
242 torture_result(tctx, TORTURE_FAIL,
243 "write failed - wrote %d bytes (%s)",
244 (int)written, __location__);
248 start = timeval_current();
249 end = timeval_add(&start, (10*sec), 0);
250 while (!timeval_expired(&end)) {
251 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
253 if (!NT_STATUS_IS_OK(status)) {
254 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
259 if (finfo3.all_info.out.size != 1024) {
260 DEBUG(0, ("file not truncated, size = %u (should be 1024)\n",
261 (unsigned int)finfo3.all_info.out.size));
266 torture_comment(tctx, "write time %s\n",
267 nt_time_string(tctx, finfo3.all_info.out.write_time));
268 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
269 double diff = timeval_elapsed(&start);
271 torture_comment(tctx, "server updated write_time after %.2f seconds"
277 smb_msleep(1 * msec);
280 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
281 torture_result(tctx, TORTURE_FAIL,
282 "Server updated write time (wrong!)");
287 smb_msleep(2 * msec);
289 /* the close should trigger an write time update */
290 smbcli_close(cli->tree, fnum1);
293 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
294 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
296 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
297 torture_result(tctx, TORTURE_FAIL,
298 "Server did not update write time on close (wrong!)");
300 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
301 torture_comment(tctx, "Server updated write time on close (correct)\n");
305 smbcli_close(cli->tree, fnum1);
306 smbcli_unlink(cli->tree, fname);
307 smbcli_deltree(cli->tree, BASEDIR);
312 /* Updating with a SMBwrite of zero length
313 * changes the write time immediately - even on expand. */
315 static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
317 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
318 const char *fname = BASEDIR "\\torture_file1a.txt";
323 struct timeval start;
325 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
326 int normal_delay = 2000000;
327 double sec = ((double)used_delay) / ((double)normal_delay);
328 int msec = 1000 * sec;
331 torture_comment(tctx, "\nRunning test_delayed_write_update1a\n");
333 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
335 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
337 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
341 memset(buf, 'x', 2048);
342 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
344 /* 3 second delay to ensure we get past any 2 second time
345 granularity (older systems may have that) */
346 smb_msleep(3 * msec);
348 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
349 finfo1.all_info.in.file.fnum = fnum1;
352 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
353 pinfo4.all_info.in.file.path = fname;
355 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
357 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
359 torture_comment(tctx, "Initial write time %s\n",
360 nt_time_string(tctx, finfo1.all_info.out.write_time));
362 /* Do a zero length SMBwrite call to truncate. */
363 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
366 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)",
367 (int)written, __location__);
371 start = timeval_current();
372 end = timeval_add(&start, (120*sec), 0);
373 while (!timeval_expired(&end)) {
374 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
376 if (!NT_STATUS_IS_OK(status)) {
377 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
383 if (finfo2.all_info.out.size != 10240) {
384 torture_result(tctx, TORTURE_FAIL,
385 "file not truncated, size = %u (should be 10240)",
386 (unsigned int)finfo2.all_info.out.size);
391 torture_comment(tctx, "write time %s\n",
392 nt_time_string(tctx, finfo2.all_info.out.write_time));
393 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
394 double diff = timeval_elapsed(&start);
395 if (diff > (0.25 * (used_delay / (double)1000000))) {
396 torture_result(tctx, TORTURE_FAIL, "After SMBwrite truncate "
397 "server updated write_time after %.2f seconds"
398 "(write time update delay == %.2f)(wrong!)\n",
399 diff, used_delay / (double)1000000);
404 torture_comment(tctx, "After SMBwrite truncate "
405 "server updated write_time after %.2f seconds"
406 "(write time update delay == %.2f)(correct)\n",
407 diff, used_delay / (double)1000000);
411 smb_msleep(1 * msec);
414 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
415 torture_result(tctx, TORTURE_FAIL,
416 "Server did not update write time (wrong!)");
421 smb_msleep(2 * msec);
423 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
424 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
426 torture_assert_int_equal(tctx, written, 1,
427 "unexpected number of bytes written");
429 start = timeval_current();
430 end = timeval_add(&start, (10*sec), 0);
431 while (!timeval_expired(&end)) {
432 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
434 if (!NT_STATUS_IS_OK(status)) {
435 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s\n",
441 if (finfo3.all_info.out.size != 10240) {
442 torture_result(tctx, TORTURE_FAIL,
443 "file not truncated, size = %u (should be 10240)",
444 (unsigned int)finfo3.all_info.out.size);
449 torture_comment(tctx, "write time %s\n",
450 nt_time_string(tctx, finfo3.all_info.out.write_time));
451 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
452 double diff = timeval_elapsed(&start);
454 torture_result(tctx, TORTURE_FAIL, "server updated write_time after %.2f seconds"
455 "(write time update delay == %.2f)(correct)\n",
456 diff, used_delay / (double)1000000);
460 smb_msleep(1 * msec);
463 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
464 torture_result(tctx, TORTURE_FAIL,
465 "Server updated write time (wrong!)");
469 /* the close should trigger an write time update */
470 smbcli_close(cli->tree, fnum1);
473 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
474 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
476 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
477 torture_result(tctx, TORTURE_FAIL,
478 "Server did not update write time on close (wrong!)");
480 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
481 torture_comment(tctx, "Server updated write time on close (correct)\n");
485 smbcli_close(cli->tree, fnum1);
486 smbcli_unlink(cli->tree, fname);
487 smbcli_deltree(cli->tree, BASEDIR);
492 /* Updating with a SET_FILE_END_OF_FILE_INFO
493 * changes the write time immediately - even on expand. */
495 static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
497 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
498 const char *fname = BASEDIR "\\torture_file1b.txt";
503 struct timeval start;
505 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
506 int normal_delay = 2000000;
507 double sec = ((double)used_delay) / ((double)normal_delay);
508 int msec = 1000 * sec;
511 torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
513 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
515 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
517 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
521 memset(buf, 'x', 2048);
522 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
524 /* 3 second delay to ensure we get past any 2 second time
525 granularity (older systems may have that) */
526 smb_msleep(3 * msec);
528 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
529 finfo1.all_info.in.file.fnum = fnum1;
532 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
533 pinfo4.all_info.in.file.path = fname;
535 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
537 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
539 torture_comment(tctx, "Initial write time %s\n",
540 nt_time_string(tctx, finfo1.all_info.out.write_time));
542 /* Do a SET_END_OF_FILE_INFO call to truncate. */
543 status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
545 torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
547 start = timeval_current();
548 end = timeval_add(&start, (120*sec), 0);
549 while (!timeval_expired(&end)) {
550 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
552 if (!NT_STATUS_IS_OK(status)) {
553 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
558 if (finfo2.all_info.out.size != 10240) {
559 torture_result(tctx, TORTURE_FAIL,
560 "file not truncated (size = %u, should be 10240)",
561 (unsigned int)finfo2.all_info.out.size );
566 torture_comment(tctx, "write time %s\n",
567 nt_time_string(tctx, finfo2.all_info.out.write_time));
568 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
569 double diff = timeval_elapsed(&start);
570 if (diff > (0.25 * (used_delay / (double)1000000))) {
571 torture_result(tctx, TORTURE_FAIL,
572 "After SET_END_OF_FILE truncate "
573 "server updated write_time after %.2f seconds"
574 "(write time update delay == %.2f)(wrong!)",
575 diff, used_delay / (double)1000000);
580 torture_comment(tctx, "After SET_END_OF_FILE truncate "
581 "server updated write_time after %.2f seconds"
582 "(write time update delay == %.2f)(correct)\n",
583 diff, used_delay / (double)1000000);
587 smb_msleep(1 * msec);
590 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
591 torture_result(tctx, TORTURE_FAIL,
592 "Server did not update write time (wrong!)");
597 smb_msleep(2 * msec);
599 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
600 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
602 torture_assert_int_equal(tctx, written, 1,
603 "unexpected number of bytes written");
605 start = timeval_current();
606 end = timeval_add(&start, (10*sec), 0);
607 while (!timeval_expired(&end)) {
608 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
610 if (!NT_STATUS_IS_OK(status)) {
611 torture_result(tctx, TORTURE_FAIL,
612 "fileinfo failed: %s", nt_errstr(status));
617 if (finfo3.all_info.out.size != 10240) {
618 DEBUG(0, ("file not truncated (size = %u, should be 10240)\n",
619 (unsigned int)finfo3.all_info.out.size ));
624 torture_comment(tctx, "write time %s\n",
625 nt_time_string(tctx, finfo3.all_info.out.write_time));
626 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
627 double diff = timeval_elapsed(&start);
629 torture_comment(tctx, "server updated write_time after %.2f seconds"
630 "(write time update delay == %.2f)(correct)\n",
631 diff, used_delay / (double)1000000);
635 smb_msleep(1 * msec);
638 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
639 torture_result(tctx, TORTURE_FAIL, "Server updated write time (wrong!)\n");
643 /* the close should trigger an write time update */
644 smbcli_close(cli->tree, fnum1);
647 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
648 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
650 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
651 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
653 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
654 torture_comment(tctx, "Server updated write time on close (correct)\n");
658 smbcli_close(cli->tree, fnum1);
659 smbcli_unlink(cli->tree, fname);
660 smbcli_deltree(cli->tree, BASEDIR);
665 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
667 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
669 union smb_setfileinfo parms;
670 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
671 const char *fname = BASEDIR "\\torture_file1c.txt";
676 struct timeval start;
678 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
679 int normal_delay = 2000000;
680 double sec = ((double)used_delay) / ((double)normal_delay);
681 int msec = 1000 * sec;
684 torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
686 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
688 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
690 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
694 memset(buf, 'x', 2048);
695 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
697 /* 3 second delay to ensure we get past any 2 second time
698 granularity (older systems may have that) */
699 smb_msleep(3 * msec);
701 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
702 finfo1.all_info.in.file.fnum = fnum1;
705 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
706 pinfo4.all_info.in.file.path = fname;
708 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
710 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
712 torture_comment(tctx, "Initial write time %s\n",
713 nt_time_string(tctx, finfo1.all_info.out.write_time));
715 /* Do a SET_ALLOCATION_SIZE call to truncate. */
716 parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
717 parms.allocation_info.in.file.fnum = fnum1;
718 parms.allocation_info.in.alloc_size = 0;
720 status = smb_raw_setfileinfo(cli->tree, &parms);
722 torture_assert_ntstatus_ok(tctx, status,
723 "RAW_SFILEINFO_ALLOCATION_INFO failed");
725 start = timeval_current();
726 end = timeval_add(&start, (120*sec), 0);
727 while (!timeval_expired(&end)) {
728 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
730 if (!NT_STATUS_IS_OK(status)) {
731 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
737 if (finfo2.all_info.out.size != 0) {
738 torture_result(tctx, TORTURE_FAIL,
739 "file not truncated (size = %u, should be 10240)",
740 (unsigned int)finfo2.all_info.out.size);
745 torture_comment(tctx, "write time %s\n",
746 nt_time_string(tctx, finfo2.all_info.out.write_time));
747 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
748 double diff = timeval_elapsed(&start);
749 if (diff > (0.25 * (used_delay / (double)1000000))) {
750 torture_result(tctx, TORTURE_FAIL, "After SET_ALLOCATION_INFO truncate "
751 "server updated write_time after %.2f seconds"
752 "(write time update delay == %.2f)(wrong!)\n",
753 diff, used_delay / (double)1000000);
758 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
759 "server updated write_time after %.2f seconds"
760 "(write time update delay == %.2f)(correct)\n",
761 diff, used_delay / (double)1000000);
765 smb_msleep(1 * msec);
768 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
769 torture_result(tctx, TORTURE_FAIL,
770 "Server did not update write time (wrong!)");
775 smb_msleep(2 * msec);
777 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
778 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
779 torture_assert_int_equal(tctx, written, 1,
780 "Unexpected number of bytes written");
782 start = timeval_current();
783 end = timeval_add(&start, (10*sec), 0);
784 while (!timeval_expired(&end)) {
785 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
787 if (!NT_STATUS_IS_OK(status)) {
788 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
794 if (finfo3.all_info.out.size != 1) {
795 torture_result(tctx, TORTURE_FAIL, "file not expanded");
800 torture_comment(tctx, "write time %s\n",
801 nt_time_string(tctx, finfo3.all_info.out.write_time));
802 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
803 double diff = timeval_elapsed(&start);
805 torture_comment(tctx, "server updated write_time after %.2f seconds"
806 "(write time update delay == %.2f)(wrong)\n",
807 diff, used_delay / (double)1000000);
811 smb_msleep(1 * msec);
814 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
815 torture_result(tctx, TORTURE_FAIL,
816 "Server updated write time (wrong!)");
820 /* the close should trigger an write time update */
821 smbcli_close(cli->tree, fnum1);
824 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
825 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
827 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
828 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
830 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
831 torture_comment(tctx, "Server updated write time on close (correct)\n");
835 smbcli_close(cli->tree, fnum1);
836 smbcli_unlink(cli->tree, fname);
837 smbcli_deltree(cli->tree, BASEDIR);
843 * Do as above, but using 2 connections.
846 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
847 struct smbcli_state *cli2)
849 union smb_fileinfo finfo1, finfo2;
850 const char *fname = BASEDIR "\\torture_file.txt";
856 struct timeval start;
858 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
859 int normal_delay = 2000000;
860 double sec = ((double)used_delay) / ((double)normal_delay);
861 int msec = 1000 * sec;
862 union smb_flush flsh;
864 torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
866 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
868 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
870 torture_comment(tctx, "Failed to open %s\n", fname);
874 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
875 finfo1.basic_info.in.file.fnum = fnum1;
878 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
880 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
882 torture_comment(tctx, "Initial write time %s\n",
883 nt_time_string(tctx, finfo1.basic_info.out.write_time));
885 /* 3 second delay to ensure we get past any 2 second time
886 granularity (older systems may have that) */
887 smb_msleep(3 * msec);
890 /* Try using setfileinfo instead of write to update write time. */
891 union smb_setfileinfo sfinfo;
892 time_t t_set = time(NULL);
893 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
894 sfinfo.basic_info.in.file.fnum = fnum1;
895 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
896 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
898 /* I tried this with both + and - ve to see if it makes a different.
899 It doesn't - once the filetime is set via setfileinfo it stays that way. */
901 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
903 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
905 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
906 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
908 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
910 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
913 finfo2.basic_info.in.file.path = fname;
915 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
917 if (!NT_STATUS_IS_OK(status)) {
918 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
921 torture_comment(tctx, "write time %s\n",
922 nt_time_string(tctx, finfo2.basic_info.out.write_time));
924 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
925 torture_comment(tctx, "Server updated write_time (correct)\n");
927 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
931 /* Now try a write to see if the write time gets reset. */
933 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
934 finfo1.basic_info.in.file.fnum = fnum1;
937 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
939 if (!NT_STATUS_IS_OK(status)) {
940 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
944 torture_comment(tctx, "Modified write time %s\n",
945 nt_time_string(tctx, finfo1.basic_info.out.write_time));
948 torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
950 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
953 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
954 (int)written, __location__);
958 /* Just to prove to tridge that the an smbflush has no effect on
959 the write time :-). The setfileinfo IS STICKY. JRA. */
961 torture_comment(tctx, "Doing flush after write\n");
963 flsh.flush.level = RAW_FLUSH_FLUSH;
964 flsh.flush.in.file.fnum = fnum1;
965 status = smb_raw_flush(cli->tree, &flsh);
966 if (!NT_STATUS_IS_OK(status)) {
967 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
971 /* Once the time was set using setfileinfo then it stays set - writes
972 don't have any effect. But make sure. */
973 start = timeval_current();
974 end = timeval_add(&start, (15*sec), 0);
975 while (!timeval_expired(&end)) {
976 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
978 if (!NT_STATUS_IS_OK(status)) {
979 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
983 torture_comment(tctx, "write time %s\n",
984 nt_time_string(tctx, finfo2.basic_info.out.write_time));
985 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
986 double diff = timeval_elapsed(&start);
987 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
994 smb_msleep(1 * msec);
997 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
998 torture_comment(tctx, "Server did not update write time (correct)\n");
1002 smb_msleep(2 * msec);
1004 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1006 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
1010 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");
1012 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
1014 if (written != 10) {
1015 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1016 (int)written, __location__);
1020 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1022 if (!NT_STATUS_IS_OK(status)) {
1023 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1026 torture_comment(tctx, "write time %s\n",
1027 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1028 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1029 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1033 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
1034 smbcli_close(cli->tree, fnum1);
1037 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");
1039 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
1041 if (written != 10) {
1042 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1043 (int)written, __location__);
1047 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1048 finfo1.basic_info.in.file.fnum = fnum2;
1050 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1052 if (!NT_STATUS_IS_OK(status)) {
1053 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1056 torture_comment(tctx, "write time %s\n",
1057 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1058 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1059 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1063 /* Once the time was set using setfileinfo then it stays set - writes
1064 don't have any effect. But make sure. */
1065 start = timeval_current();
1066 end = timeval_add(&start, (15*sec), 0);
1067 while (!timeval_expired(&end)) {
1068 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1070 if (!NT_STATUS_IS_OK(status)) {
1071 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1075 torture_comment(tctx, "write time %s\n",
1076 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1077 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1078 double diff = timeval_elapsed(&start);
1079 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1086 smb_msleep(1 * msec);
1089 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1090 torture_comment(tctx, "Server did not update write time (correct)\n");
1093 torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1095 smbcli_close(cli->tree, fnum2);
1098 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1100 torture_comment(tctx, "Failed to open %s\n", fname);
1104 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1105 finfo1.basic_info.in.file.fnum = fnum1;
1108 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1110 if (!NT_STATUS_IS_OK(status)) {
1111 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1115 torture_comment(tctx, "Second open initial write time %s\n",
1116 nt_time_string(tctx, finfo1.basic_info.out.write_time));
1118 smb_msleep(10 * msec);
1119 torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1121 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1123 if (written != 10) {
1124 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1125 (int)written, __location__);
1129 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1130 finfo1.basic_info.in.file.fnum = fnum1;
1132 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1134 if (!NT_STATUS_IS_OK(status)) {
1135 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1138 torture_comment(tctx, "write time %s\n",
1139 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1140 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1141 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1145 /* Now the write time should be updated again */
1146 start = timeval_current();
1147 end = timeval_add(&start, (15*sec), 0);
1148 while (!timeval_expired(&end)) {
1149 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1151 if (!NT_STATUS_IS_OK(status)) {
1152 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1156 torture_comment(tctx, "write time %s\n",
1157 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1158 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1159 double diff = timeval_elapsed(&start);
1160 if (diff < (used_delay / (double)1000000)) {
1161 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1162 "(expected > %.2f) (wrong!)\n",
1163 diff, used_delay / (double)1000000);
1168 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1177 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1178 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
1183 /* One more test to do. We should read the filetime via findfirst on the
1184 second connection to ensure it's the same. This is very easy for a Windows
1185 server but a bastard to get right on a POSIX server. JRA. */
1188 smbcli_close(cli->tree, fnum1);
1189 smbcli_unlink(cli->tree, fname);
1190 smbcli_deltree(cli->tree, BASEDIR);
1196 /* Windows does obviously not update the stat info during a write call. I
1197 * *think* this is the problem causing a spurious Excel 2003 on XP error
1198 * message when saving a file. Excel does a setfileinfo, writes, and then does
1199 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1200 * that the file might have been changed in between. What i've been able to
1201 * trace down is that this happens if the getpathinfo after the write shows a
1202 * different last write time than the setfileinfo showed. This is really
1206 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
1207 struct smbcli_state *cli2)
1209 union smb_fileinfo finfo1, finfo2;
1210 const char *fname = BASEDIR "\\torture_file.txt";
1216 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1217 int normal_delay = 2000000;
1218 double sec = ((double)used_delay) / ((double)normal_delay);
1219 int msec = 1000 * sec;
1221 torture_comment(tctx, "\nRunning test_finfo_after_write\n");
1223 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1225 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1228 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1232 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1233 finfo1.basic_info.in.file.fnum = fnum1;
1235 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1237 if (!NT_STATUS_IS_OK(status)) {
1239 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1243 smb_msleep(1 * msec);
1245 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1248 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1253 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1255 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1256 smbcli_errstr(cli2->tree));
1261 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1264 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1270 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1271 finfo2.basic_info.in.file.path = fname;
1273 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1275 if (!NT_STATUS_IS_OK(status)) {
1276 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
1282 if (finfo1.basic_info.out.create_time !=
1283 finfo2.basic_info.out.create_time) {
1284 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1289 if (finfo1.basic_info.out.access_time !=
1290 finfo2.basic_info.out.access_time) {
1291 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1296 if (finfo1.basic_info.out.write_time !=
1297 finfo2.basic_info.out.write_time) {
1298 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1299 "write time conn 1 = %s, conn 2 = %s",
1300 nt_time_string(tctx, finfo1.basic_info.out.write_time),
1301 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1306 if (finfo1.basic_info.out.change_time !=
1307 finfo2.basic_info.out.change_time) {
1308 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1313 /* One of the two following calls updates the qpathinfo. */
1315 /* If you had skipped the smbcli_write on fnum2, it would
1316 * *not* have updated the stat on disk */
1318 smbcli_close(cli2->tree, fnum2);
1321 /* This call is only for the people looking at ethereal :-) */
1322 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1323 finfo2.basic_info.in.file.path = fname;
1325 status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1327 if (!NT_STATUS_IS_OK(status)) {
1328 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1335 smbcli_close(cli->tree, fnum1);
1336 smbcli_unlink(cli->tree, fname);
1337 smbcli_deltree(cli->tree, BASEDIR);
1342 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1343 uint64_t r = 10*1000*1000; \
1344 NTTIME g = (given).basic_info.out.write_time; \
1345 NTTIME gr = (g / r) * r; \
1346 NTTIME c = (correct).basic_info.out.write_time; \
1347 NTTIME cr = (c / r) * r; \
1348 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1350 if (strict && (g cmp c)) { \
1352 } else if ((g cmp c) && (gr cmp cr)) { \
1353 /* handle filesystem without high resolution timestamps */ \
1357 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1358 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1359 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1364 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1365 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1366 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1367 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1368 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1369 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1371 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1372 NTTIME g = (given).basic_info.out.access_time; \
1373 NTTIME c = (correct).basic_info.out.access_time; \
1375 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1376 #given, nt_time_string(tctx, g), \
1377 #cmp, #correct, nt_time_string(tctx, c)); \
1382 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1383 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1385 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1386 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1387 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1390 #define GET_INFO_FILE(finfo) do { \
1392 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1393 if (!NT_STATUS_IS_OK(_status)) { \
1395 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1396 nt_errstr(_status)); \
1399 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1400 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1401 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1403 #define GET_INFO_FILE2(finfo) do { \
1405 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1406 if (!NT_STATUS_IS_OK(_status)) { \
1408 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1409 nt_errstr(_status)); \
1412 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1413 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1414 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1416 #define GET_INFO_PATH(pinfo) do { \
1418 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1419 if (!NT_STATUS_IS_OK(_status)) { \
1420 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1421 nt_errstr(_status)); \
1425 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1426 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1427 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1429 #define GET_INFO_BOTH(finfo,pinfo) do { \
1430 GET_INFO_FILE(finfo); \
1431 GET_INFO_PATH(pinfo); \
1432 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1435 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1437 union smb_setfileinfo sfinfo; \
1438 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1439 sfinfo.basic_info.in.file.fnum = tfnum; \
1440 sfinfo.basic_info.in.create_time = 0; \
1441 sfinfo.basic_info.in.access_time = 0; \
1442 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1443 sfinfo.basic_info.in.change_time = 0; \
1444 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1445 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1446 if (!NT_STATUS_IS_OK(_status)) { \
1447 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1448 nt_errstr(_status)); \
1453 #define SET_INFO_FILE(finfo, wrtime) \
1454 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1456 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1458 union smb_setfileinfo sfinfo; \
1459 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1460 sfinfo.basic_info.in.file.fnum = tfnum; \
1461 sfinfo.basic_info.in.create_time = 0; \
1462 sfinfo.basic_info.in.access_time = 0; \
1463 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1464 sfinfo.basic_info.in.write_time += (ns); \
1465 sfinfo.basic_info.in.change_time = 0; \
1466 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1467 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1468 if (!NT_STATUS_IS_OK(_status)) { \
1469 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1470 nt_errstr(_status)); \
1476 static bool test_delayed_write_update3(struct torture_context *tctx,
1477 struct smbcli_state *cli,
1478 struct smbcli_state *cli2)
1480 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1481 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1482 const char *fname = BASEDIR "\\torture_file3.txt";
1486 struct timeval start;
1488 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1489 int normal_delay = 2000000;
1490 double sec = ((double)used_delay) / ((double)normal_delay);
1491 int msec = 1000 * sec;
1493 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
1495 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1497 torture_comment(tctx, "Open the file handle\n");
1498 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1501 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1505 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1506 finfo0.basic_info.in.file.fnum = fnum1;
1510 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1511 pinfo0.basic_info.in.file.path = fname;
1517 /* get the initial times */
1518 GET_INFO_BOTH(finfo0,pinfo0);
1521 * make sure the write time is updated 2 seconds later
1522 * calcuated from the first write
1523 * (but expect upto 5 seconds extra time for a busy server)
1525 start = timeval_current();
1526 end = timeval_add(&start, 7 * sec, 0);
1527 while (!timeval_expired(&end)) {
1529 torture_comment(tctx, "Do a write on the file handle\n");
1530 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1532 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1536 /* get the times after the write */
1537 GET_INFO_FILE(finfo1);
1539 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1540 double diff = timeval_elapsed(&start);
1541 if (diff < (used_delay / (double)1000000)) {
1542 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1543 "(write time update delay == %.2f) (wrong!)\n",
1544 diff, used_delay / (double)1000000);
1549 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1554 smb_msleep(0.5 * msec);
1557 GET_INFO_BOTH(finfo1,pinfo1);
1558 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1560 /* sure any further write doesn't update the write time */
1561 start = timeval_current();
1562 end = timeval_add(&start, 15 * sec, 0);
1563 while (!timeval_expired(&end)) {
1565 torture_comment(tctx, "Do a write on the file handle\n");
1566 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1568 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1572 /* get the times after the write */
1573 GET_INFO_BOTH(finfo2,pinfo2);
1575 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1576 double diff = timeval_elapsed(&start);
1577 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1583 smb_msleep(1 * msec);
1586 GET_INFO_BOTH(finfo2,pinfo2);
1587 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1588 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1589 torture_comment(tctx, "Server did not update write_time (correct)\n");
1593 smb_msleep(5 * msec);
1595 GET_INFO_BOTH(finfo3,pinfo3);
1596 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1599 * the close updates the write time to the time of the close
1600 * and not to the time of the last write!
1602 torture_comment(tctx, "Close the file handle\n");
1603 smbcli_close(cli->tree, fnum1);
1606 GET_INFO_PATH(pinfo4);
1607 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1609 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1610 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1615 smbcli_close(cli->tree, fnum1);
1616 smbcli_unlink(cli->tree, fname);
1617 smbcli_deltree(cli->tree, BASEDIR);
1623 * Show that a truncate write always updates the write time even
1624 * if an initial write has already updated the write time.
1627 static bool test_delayed_write_update3a(struct torture_context *tctx,
1628 struct smbcli_state *cli,
1629 struct smbcli_state *cli2)
1631 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1632 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1633 const char *fname = BASEDIR "\\torture_file3a.txt";
1638 struct timeval start;
1640 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1641 int normal_delay = 2000000;
1642 double sec = ((double)used_delay) / ((double)normal_delay);
1643 int msec = 1000 * sec;
1645 torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
1647 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1649 torture_comment(tctx, "Open the file handle\n");
1650 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1653 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1657 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1658 finfo0.basic_info.in.file.fnum = fnum1;
1662 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1663 pinfo0.basic_info.in.file.path = fname;
1669 /* get the initial times */
1670 GET_INFO_BOTH(finfo0,pinfo0);
1673 * sleep some time, to demonstrate the handling of write times
1674 * doesn't depend on the time since the open
1676 smb_msleep(5 * msec);
1678 /* get the initial times */
1679 GET_INFO_BOTH(finfo1,pinfo1);
1680 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1683 * make sure the write time is updated 2 seconds later
1684 * calcuated from the first write
1685 * (but expect upto 5 seconds extra time for a busy server)
1687 start = timeval_current();
1688 end = timeval_add(&start, 7 * sec, 0);
1689 while (!timeval_expired(&end)) {
1691 torture_comment(tctx, "Do a write on the file handle\n");
1692 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1694 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1698 /* get the times after the write */
1699 GET_INFO_FILE(finfo1);
1701 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1702 double diff = timeval_elapsed(&start);
1703 if (diff < (used_delay / (double)1000000)) {
1704 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1705 "(1sec == %.2f) (wrong!)\n",
1711 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1716 smb_msleep(0.5 * msec);
1719 GET_INFO_BOTH(finfo1,pinfo1);
1720 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1722 smb_msleep(3 * msec);
1725 * demonstrate that a truncate write always
1726 * updates the write time immediately
1728 for (i=0; i < 3; i++) {
1729 smb_msleep(2 * msec);
1731 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1732 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1734 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1738 /* get the times after the write */
1739 GET_INFO_BOTH(finfo2,pinfo2);
1740 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1744 smb_msleep(3 * msec);
1746 /* sure any further write doesn't update the write time */
1747 start = timeval_current();
1748 end = timeval_add(&start, 15 * sec, 0);
1749 while (!timeval_expired(&end)) {
1751 torture_comment(tctx, "Do a write on the file handle\n");
1752 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1754 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1758 /* get the times after the write */
1759 GET_INFO_BOTH(finfo2,pinfo2);
1761 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1762 double diff = timeval_elapsed(&start);
1763 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1769 smb_msleep(1 * msec);
1772 GET_INFO_BOTH(finfo2,pinfo2);
1773 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1774 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1775 torture_comment(tctx, "Server did not update write_time (correct)\n");
1779 smb_msleep(3 * msec);
1781 /* get the initial times */
1782 GET_INFO_BOTH(finfo1,pinfo1);
1783 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1786 * demonstrate that a truncate write always
1787 * updates the write time immediately
1789 for (i=0; i < 3; i++) {
1790 smb_msleep(2 * msec);
1792 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1793 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1795 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1799 /* get the times after the write */
1800 GET_INFO_BOTH(finfo2,pinfo2);
1801 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1806 smb_msleep(3 * msec);
1808 GET_INFO_BOTH(finfo3,pinfo3);
1809 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1812 * the close doesn't update the write time
1814 torture_comment(tctx, "Close the file handle\n");
1815 smbcli_close(cli->tree, fnum1);
1818 GET_INFO_PATH(pinfo4);
1819 COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1821 if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1822 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1827 smbcli_close(cli->tree, fnum1);
1828 smbcli_unlink(cli->tree, fname);
1829 smbcli_deltree(cli->tree, BASEDIR);
1835 * Show a close after write updates the write timestamp to
1836 * the close time, not the last write time.
1839 static bool test_delayed_write_update3b(struct torture_context *tctx,
1840 struct smbcli_state *cli,
1841 struct smbcli_state *cli2)
1843 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1844 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1845 const char *fname = BASEDIR "\\torture_file3b.txt";
1849 struct timeval start;
1851 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1852 int normal_delay = 2000000;
1853 double sec = ((double)used_delay) / ((double)normal_delay);
1854 int msec = 1000 * sec;
1856 torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
1858 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1860 torture_comment(tctx, "Open the file handle\n");
1861 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1864 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1868 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1869 finfo0.basic_info.in.file.fnum = fnum1;
1873 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1874 pinfo0.basic_info.in.file.path = fname;
1880 /* get the initial times */
1881 GET_INFO_BOTH(finfo0,pinfo0);
1884 * sleep some time, to demonstrate the handling of write times
1885 * doesn't depend on the time since the open
1887 smb_msleep(5 * msec);
1889 /* get the initial times */
1890 GET_INFO_BOTH(finfo1,pinfo1);
1891 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1894 * make sure the write time is updated 2 seconds later
1895 * calcuated from the first write
1896 * (but expect upto 5 seconds extra time for a busy server)
1898 start = timeval_current();
1899 end = timeval_add(&start, 7 * sec, 0);
1900 while (!timeval_expired(&end)) {
1902 torture_comment(tctx, "Do a write on the file handle\n");
1903 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1905 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1909 /* get the times after the write */
1910 GET_INFO_FILE(finfo1);
1912 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1913 double diff = timeval_elapsed(&start);
1914 if (diff < (used_delay / (double)1000000)) {
1915 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1916 "(expected > %.2f) (wrong!)\n",
1917 diff, used_delay / (double)1000000);
1922 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1923 "(write time update delay == %.2f) (correct)\n",
1924 diff, used_delay / (double)1000000);
1927 smb_msleep(0.5 * msec);
1930 GET_INFO_BOTH(finfo1,pinfo1);
1931 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1933 /* sure any further write doesn't update the write time */
1934 start = timeval_current();
1935 end = timeval_add(&start, 15 * sec, 0);
1936 while (!timeval_expired(&end)) {
1938 torture_comment(tctx, "Do a write on the file handle\n");
1939 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1941 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1945 /* get the times after the write */
1946 GET_INFO_BOTH(finfo2,pinfo2);
1948 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1949 double diff = timeval_elapsed(&start);
1950 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1956 smb_msleep(1 * msec);
1959 GET_INFO_BOTH(finfo2,pinfo2);
1960 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1961 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1962 torture_comment(tctx, "Server did not update write_time (correct)\n");
1966 smb_msleep(5 * msec);
1968 GET_INFO_BOTH(finfo3,pinfo3);
1969 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1972 * the close updates the write time to the time of the close
1973 * and not to the time of the last write!
1975 torture_comment(tctx, "Close the file handle\n");
1976 smbcli_close(cli->tree, fnum1);
1979 GET_INFO_PATH(pinfo4);
1980 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1982 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1983 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1988 smbcli_close(cli->tree, fnum1);
1989 smbcli_unlink(cli->tree, fname);
1990 smbcli_deltree(cli->tree, BASEDIR);
1996 * Check that a write after a truncate write doesn't update
1997 * the timestamp, but a truncate write after a write does.
1998 * Also prove that a close after a truncate write updates the
1999 * timestamp to current, not the time of last write.
2002 static bool test_delayed_write_update3c(struct torture_context *tctx,
2003 struct smbcli_state *cli,
2004 struct smbcli_state *cli2)
2006 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
2007 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
2008 const char *fname = BASEDIR "\\torture_file3c.txt";
2013 struct timeval start;
2015 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2016 int normal_delay = 2000000;
2017 double sec = ((double)used_delay) / ((double)normal_delay);
2018 int msec = 1000 * sec;
2020 torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
2022 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2024 torture_comment(tctx, "Open the file handle\n");
2025 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2028 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2032 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2033 finfo0.basic_info.in.file.fnum = fnum1;
2038 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2039 pinfo0.basic_info.in.file.path = fname;
2046 /* get the initial times */
2047 GET_INFO_BOTH(finfo0,pinfo0);
2050 * sleep some time, to demonstrate the handling of write times
2051 * doesn't depend on the time since the open
2053 smb_msleep(5 * msec);
2055 /* get the initial times */
2056 GET_INFO_BOTH(finfo1,pinfo1);
2057 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2060 * demonstrate that a truncate write always
2061 * updates the write time immediately
2063 for (i=0; i < 3; i++) {
2064 smb_msleep(2 * msec);
2066 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
2067 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2069 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2073 /* get the times after the write */
2074 GET_INFO_BOTH(finfo2,pinfo2);
2075 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2079 start = timeval_current();
2080 end = timeval_add(&start, 7 * sec, 0);
2081 while (!timeval_expired(&end)) {
2083 torture_comment(tctx, "Do a write on the file handle\n");
2084 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2086 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2090 /* get the times after the write */
2091 GET_INFO_FILE(finfo2);
2093 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2094 double diff = timeval_elapsed(&start);
2095 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2101 smb_msleep(1 * msec);
2104 GET_INFO_BOTH(finfo2,pinfo2);
2105 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2106 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2107 torture_comment(tctx, "Server did not update write_time (correct)\n");
2111 smb_msleep(5 * msec);
2113 /* get the initial times */
2114 GET_INFO_BOTH(finfo1,pinfo1);
2115 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2118 * demonstrate that a truncate write always
2119 * updates the write time immediately
2121 for (i=0; i < 3; i++) {
2122 smb_msleep(2 * msec);
2124 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2125 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2127 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2131 /* get the times after the write */
2132 GET_INFO_BOTH(finfo2,pinfo2);
2133 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2138 smb_msleep(5 * msec);
2140 GET_INFO_BOTH(finfo2,pinfo2);
2141 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2143 /* sure any further write doesn't update the write time */
2144 start = timeval_current();
2145 end = timeval_add(&start, 15 * sec, 0);
2146 while (!timeval_expired(&end)) {
2148 torture_comment(tctx, "Do a write on the file handle\n");
2149 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2151 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2155 /* get the times after the write */
2156 GET_INFO_BOTH(finfo2,pinfo2);
2158 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2159 double diff = timeval_elapsed(&start);
2160 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2166 smb_msleep(1 * msec);
2169 GET_INFO_BOTH(finfo2,pinfo2);
2170 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2171 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2172 torture_comment(tctx, "Server did not update write_time (correct)\n");
2176 smb_msleep(5 * msec);
2178 GET_INFO_BOTH(finfo3,pinfo3);
2179 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2182 * the close updates the write time to the time of the close
2183 * and not to the time of the last write!
2185 torture_comment(tctx, "Close the file handle\n");
2186 smbcli_close(cli->tree, fnum1);
2189 GET_INFO_PATH(pinfo4);
2190 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2192 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2193 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2198 smbcli_close(cli->tree, fnum1);
2199 smbcli_unlink(cli->tree, fname);
2200 smbcli_deltree(cli->tree, BASEDIR);
2206 * Show only the first write updates the timestamp, and a close
2207 * after writes updates to current (I think this is the same
2211 static bool test_delayed_write_update4(struct torture_context *tctx,
2212 struct smbcli_state *cli,
2213 struct smbcli_state *cli2)
2215 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
2216 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
2217 const char *fname = BASEDIR "\\torture_file4.txt";
2221 struct timeval start;
2223 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2224 int normal_delay = 2000000;
2225 double sec = ((double)used_delay) / ((double)normal_delay);
2226 int msec = 1000 * sec;
2228 torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2230 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2232 torture_comment(tctx, "Open the file handle\n");
2233 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2236 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2240 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2241 finfo0.basic_info.in.file.fnum = fnum1;
2245 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2246 pinfo0.basic_info.in.file.path = fname;
2252 /* get the initial times */
2253 GET_INFO_BOTH(finfo0,pinfo0);
2256 smb_msleep(5 * msec);
2259 torture_comment(tctx, "Do a write on the file handle\n");
2260 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2262 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2267 GET_INFO_BOTH(finfo1,pinfo1);
2268 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2271 * make sure the write time is updated 2 seconds later
2272 * calcuated from the first write
2273 * (but expect upto 3 seconds extra time for a busy server)
2275 start = timeval_current();
2276 end = timeval_add(&start, 5 * sec, 0);
2277 while (!timeval_expired(&end)) {
2278 /* get the times after the first write */
2279 GET_INFO_FILE(finfo1);
2281 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2282 double diff = timeval_elapsed(&start);
2283 if (diff < (used_delay / (double)1000000)) {
2284 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
2285 "(expected > %.2f) (wrong!)\n",
2286 diff, used_delay / (double)1000000);
2291 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2292 "(write time update delay == %.2f) (correct)\n",
2293 diff, used_delay / (double)1000000);
2296 smb_msleep(0.5 * msec);
2299 GET_INFO_BOTH(finfo1,pinfo1);
2300 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2302 /* sure any further write doesn't update the write time */
2303 start = timeval_current();
2304 end = timeval_add(&start, 15 * sec, 0);
2305 while (!timeval_expired(&end)) {
2307 torture_comment(tctx, "Do a write on the file handle\n");
2308 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2310 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2314 /* get the times after the write */
2315 GET_INFO_BOTH(finfo2,pinfo2);
2317 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2318 double diff = timeval_elapsed(&start);
2319 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2325 smb_msleep(1 * msec);
2328 GET_INFO_BOTH(finfo2,pinfo2);
2329 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2330 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2331 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2335 smb_msleep(5 * msec);
2337 GET_INFO_BOTH(finfo3,pinfo3);
2338 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2341 * the close updates the write time to the time of the close
2342 * and not to the time of the last write!
2344 torture_comment(tctx, "Close the file handle\n");
2345 smbcli_close(cli->tree, fnum1);
2348 GET_INFO_PATH(pinfo4);
2349 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2351 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2352 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2357 smbcli_close(cli->tree, fnum1);
2358 smbcli_unlink(cli->tree, fname);
2359 smbcli_deltree(cli->tree, BASEDIR);
2365 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2368 static bool test_delayed_write_update5(struct torture_context *tctx,
2369 struct smbcli_state *cli,
2370 struct smbcli_state *cli2)
2372 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2373 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2374 const char *fname = BASEDIR "\\torture_file5.txt";
2378 struct timeval start;
2380 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2381 int normal_delay = 2000000;
2382 double sec = ((double)used_delay) / ((double)normal_delay);
2383 int msec = 1000 * sec;
2385 torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2387 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2389 torture_comment(tctx, "Open the file handle\n");
2390 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2393 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2397 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2398 finfo0.basic_info.in.file.fnum = fnum1;
2404 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2405 pinfo0.basic_info.in.file.path = fname;
2413 /* get the initial times */
2414 GET_INFO_BOTH(finfo0,pinfo0);
2417 torture_comment(tctx, "Do a write on the file handle\n");
2418 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2420 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2425 GET_INFO_BOTH(finfo1,pinfo1);
2426 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2428 torture_comment(tctx, "Set write time in the future on the file handle\n");
2429 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2430 GET_INFO_BOTH(finfo2,pinfo2);
2431 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2433 torture_comment(tctx, "Set write time in the past on the file handle\n");
2434 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2435 GET_INFO_BOTH(finfo2,pinfo2);
2436 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2438 /* make sure the 2 second delay from the first write are canceled */
2439 start = timeval_current();
2440 end = timeval_add(&start, 15 * sec, 0);
2441 while (!timeval_expired(&end)) {
2443 /* get the times after the first write */
2444 GET_INFO_BOTH(finfo3,pinfo3);
2446 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2447 double diff = timeval_elapsed(&start);
2448 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2454 smb_msleep(1 * msec);
2457 GET_INFO_BOTH(finfo3,pinfo3);
2458 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2459 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2460 torture_comment(tctx, "Server did not update write_time (correct)\n");
2463 /* sure any further write doesn't update the write time */
2464 start = timeval_current();
2465 end = timeval_add(&start, 15 * sec, 0);
2466 while (!timeval_expired(&end)) {
2468 torture_comment(tctx, "Do a write on the file handle\n");
2469 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2471 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2475 /* get the times after the write */
2476 GET_INFO_BOTH(finfo4,pinfo4);
2478 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2479 double diff = timeval_elapsed(&start);
2480 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2486 smb_msleep(1 * msec);
2489 GET_INFO_BOTH(finfo4,pinfo4);
2490 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2491 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2492 torture_comment(tctx, "Server did not update write_time (correct)\n");
2496 smb_msleep(5 * msec);
2498 GET_INFO_BOTH(finfo5,pinfo5);
2499 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2502 * the close doesn't update the write time
2504 torture_comment(tctx, "Close the file handle\n");
2505 smbcli_close(cli->tree, fnum1);
2508 GET_INFO_PATH(pinfo6);
2509 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2511 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2512 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2517 smbcli_close(cli->tree, fnum1);
2518 smbcli_unlink(cli->tree, fname);
2519 smbcli_deltree(cli->tree, BASEDIR);
2525 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2528 static bool test_delayed_write_update5b(struct torture_context *tctx,
2529 struct smbcli_state *cli,
2530 struct smbcli_state *cli2)
2532 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2533 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2534 const char *fname = BASEDIR "\\torture_fileb.txt";
2538 struct timeval start;
2540 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2541 int normal_delay = 2000000;
2542 double sec = ((double)used_delay) / ((double)normal_delay);
2543 int msec = 1000 * sec;
2545 torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2547 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2549 torture_comment(tctx, "Open the file handle\n");
2550 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2553 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2557 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2558 finfo0.basic_info.in.file.fnum = fnum1;
2564 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2565 pinfo0.basic_info.in.file.path = fname;
2573 /* get the initial times */
2574 GET_INFO_BOTH(finfo0,pinfo0);
2577 torture_comment(tctx, "Do a write on the file handle\n");
2578 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2580 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2585 GET_INFO_BOTH(finfo1,pinfo1);
2586 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2588 torture_comment(tctx, "Set write time in the future on the file handle\n");
2589 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2590 GET_INFO_BOTH(finfo2,pinfo2);
2591 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2593 torture_comment(tctx, "Set write time in the past on the file handle\n");
2594 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2595 GET_INFO_BOTH(finfo2,pinfo2);
2596 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2598 /* make sure the 2 second delay from the first write are canceled */
2599 start = timeval_current();
2600 end = timeval_add(&start, 15 * sec, 0);
2601 while (!timeval_expired(&end)) {
2603 /* get the times after the first write */
2604 GET_INFO_BOTH(finfo3,pinfo3);
2606 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2607 double diff = timeval_elapsed(&start);
2608 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2614 smb_msleep(1 * msec);
2617 GET_INFO_BOTH(finfo3,pinfo3);
2618 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2619 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2620 torture_comment(tctx, "Server did not update write_time (correct)\n");
2623 /* Do any further write (truncates) update the write time ? */
2624 start = timeval_current();
2625 end = timeval_add(&start, 15 * sec, 0);
2626 while (!timeval_expired(&end)) {
2628 torture_comment(tctx, "Do a truncate write on the file handle\n");
2629 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2631 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2635 /* get the times after the write */
2636 GET_INFO_BOTH(finfo4,pinfo4);
2638 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2639 double diff = timeval_elapsed(&start);
2640 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2646 smb_msleep(1 * msec);
2649 GET_INFO_BOTH(finfo4,pinfo4);
2650 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2651 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2652 torture_comment(tctx, "Server did not update write_time (correct)\n");
2656 smb_msleep(5 * msec);
2658 GET_INFO_BOTH(finfo5,pinfo5);
2659 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2662 * the close doesn't update the write time
2664 torture_comment(tctx, "Close the file handle\n");
2665 smbcli_close(cli->tree, fnum1);
2668 GET_INFO_PATH(pinfo6);
2669 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2671 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2672 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2677 smbcli_close(cli->tree, fnum1);
2678 smbcli_unlink(cli->tree, fname);
2679 smbcli_deltree(cli->tree, BASEDIR);
2685 * Open 2 handles on a file. Write one one and then set the
2686 * WRITE TIME explicitly on the other. Ensure the write time
2687 * update is cancelled. Ensure the write time is updated to
2688 * the close time when the non-explicit set handle is closed.
2692 static bool test_delayed_write_update6(struct torture_context *tctx,
2693 struct smbcli_state *cli,
2694 struct smbcli_state *cli2)
2696 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2697 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2698 const char *fname = BASEDIR "\\torture_file6.txt";
2703 struct timeval start;
2705 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2706 int normal_delay = 2000000;
2707 double sec = ((double)used_delay) / ((double)normal_delay);
2708 int msec = 1000 * sec;
2711 torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2713 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2715 torture_comment(tctx, "Open the file handle\n");
2716 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2719 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2724 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2725 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2728 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2733 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2734 finfo0.basic_info.in.file.fnum = fnum1;
2740 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2741 pinfo0.basic_info.in.file.path = fname;
2750 /* get the initial times */
2751 GET_INFO_BOTH(finfo0,pinfo0);
2754 torture_comment(tctx, "Do a write on the file handle\n");
2755 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2757 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2762 GET_INFO_BOTH(finfo1,pinfo1);
2763 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2765 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2766 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2767 GET_INFO_BOTH(finfo2,pinfo2);
2768 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2770 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2771 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2772 GET_INFO_BOTH(finfo2,pinfo2);
2773 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2775 /* make sure the 2 second delay from the first write are canceled */
2776 start = timeval_current();
2777 end = timeval_add(&start, 10 * sec, 0);
2778 while (!timeval_expired(&end)) {
2780 /* get the times after the first write */
2781 GET_INFO_BOTH(finfo3,pinfo3);
2783 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2784 double diff = timeval_elapsed(&start);
2785 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2791 smb_msleep(1 * msec);
2794 GET_INFO_BOTH(finfo3,pinfo3);
2795 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2796 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2797 torture_comment(tctx, "Server did not update write_time (correct)\n");
2800 /* sure any further write doesn't update the write time */
2801 start = timeval_current();
2802 end = timeval_add(&start, 10 * sec, 0);
2803 while (!timeval_expired(&end)) {
2805 torture_comment(tctx, "Do a write on the file handle\n");
2806 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2808 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2812 /* get the times after the write */
2813 GET_INFO_BOTH(finfo4,pinfo4);
2815 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2816 double diff = timeval_elapsed(&start);
2817 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2823 smb_msleep(1 * msec);
2826 GET_INFO_BOTH(finfo4,pinfo4);
2827 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2828 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2829 torture_comment(tctx, "Server did not update write_time (correct)\n");
2833 smb_msleep(5 * msec);
2835 GET_INFO_BOTH(finfo5,pinfo5);
2836 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2839 * the close updates the write time to the time of the close
2840 * as the write time was set on the 2nd handle
2842 torture_comment(tctx, "Close the file handle\n");
2843 smbcli_close(cli->tree, fnum1);
2846 GET_INFO_PATH(pinfo6);
2847 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2849 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2850 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2853 /* See what the second write handle thinks the time is ? */
2854 finfo5.basic_info.in.file.fnum = fnum2;
2855 GET_INFO_FILE2(finfo5);
2856 COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
2858 /* See if we have lost the sticky write time on handle2 */
2859 smb_msleep(3 * msec);
2860 torture_comment(tctx, "Have we lost the sticky write time ?\n");
2862 /* Make sure any further normal write doesn't update the write time */
2863 start = timeval_current();
2864 end = timeval_add(&start, 10 * sec, 0);
2865 while (!timeval_expired(&end)) {
2867 torture_comment(tctx, "Do a write on the second file handle\n");
2868 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
2870 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2874 /* get the times after the write */
2875 GET_INFO_FILE2(finfo5);
2876 GET_INFO_PATH(pinfo6);
2878 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2879 double diff = timeval_elapsed(&start);
2880 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2886 smb_msleep(1 * msec);
2889 /* What about a truncate write ? */
2890 start = timeval_current();
2891 end = timeval_add(&start, 10 * sec, 0);
2892 while (!timeval_expired(&end)) {
2894 torture_comment(tctx, "Do a truncate write on the second file handle\n");
2895 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
2897 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2901 /* get the times after the write */
2902 GET_INFO_FILE2(finfo5);
2903 GET_INFO_PATH(pinfo6);
2905 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2906 double diff = timeval_elapsed(&start);
2907 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2913 smb_msleep(1 * msec);
2917 /* keep the 2nd handle open and rerun tests */
2924 * closing the 2nd handle will cause no write time update
2925 * as the write time was explicit set on this handle
2927 torture_comment(tctx, "Close the 2nd file handle\n");
2928 smbcli_close(cli2->tree, fnum2);
2931 GET_INFO_PATH(pinfo7);
2932 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2934 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2935 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2940 smbcli_close(cli->tree, fnum1);
2942 smbcli_close(cli2->tree, fnum2);
2943 smbcli_unlink(cli->tree, fname);
2944 smbcli_deltree(cli->tree, BASEDIR);
2949 static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
2951 union smb_open open_parms;
2952 union smb_fileinfo finfo1, finfo2, finfo3;
2953 const char *fname = BASEDIR "\\torture_file7.txt";
2957 TALLOC_CTX *mem_ctx;
2959 torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2961 mem_ctx = talloc_init("test_delayed_write_update7");
2962 if (!mem_ctx) return false;
2964 ZERO_STRUCT(finfo1);
2965 ZERO_STRUCT(finfo2);
2966 ZERO_STRUCT(finfo3);
2967 ZERO_STRUCT(open_parms);
2969 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2971 /* Create the file. */
2972 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2974 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
2978 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2979 finfo1.basic_info.in.file.fnum = fnum1;
2983 /* Get the initial timestamps. */
2984 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
2986 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2988 /* Set the pending write time to a value with ns. */
2989 SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
2991 /* Get the current pending write time by fnum. */
2992 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
2994 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2996 /* Ensure the time is actually different. */
2997 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2998 torture_result(tctx, TORTURE_FAIL,
2999 "setfileinfo time matches original fileinfo time");
3003 /* Get the current pending write time by path. */
3004 finfo3.basic_info.in.file.path = fname;
3005 status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
3007 if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
3008 torture_result(tctx, TORTURE_FAIL,
3009 "qpathinfo time doens't match fileinfo time");
3013 /* Now close the file. Re-open and check that the write
3014 time is identical to the one we wrote. */
3016 smbcli_close(cli->tree, fnum1);
3018 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3019 open_parms.ntcreatex.in.flags = 0;
3020 open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
3021 open_parms.ntcreatex.in.file_attr = 0;
3022 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3023 NTCREATEX_SHARE_ACCESS_READ|
3024 NTCREATEX_SHARE_ACCESS_WRITE;
3025 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3026 open_parms.ntcreatex.in.create_options = 0;
3027 open_parms.ntcreatex.in.fname = fname;
3029 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3030 talloc_free(mem_ctx);
3032 if (!NT_STATUS_IS_OK(status)) {
3033 torture_result(tctx, TORTURE_FAIL,
3034 "setfileinfo time matches original fileinfo time");
3038 fnum1 = open_parms.ntcreatex.out.file.fnum;
3040 /* Check the returned time matches. */
3041 if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
3042 torture_result(tctx, TORTURE_FAIL,
3043 "final open time does not match set time");
3049 smbcli_close(cli->tree, fnum1);
3051 smbcli_unlink(cli->tree, fname);
3052 smbcli_deltree(cli->tree, BASEDIR);
3057 Test if creating a file in a directory with an open handle updates the
3058 write timestamp (it should).
3060 static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
3062 union smb_fileinfo dir_info1, dir_info2;
3063 union smb_open open_parms;
3064 const char *fname = BASEDIR "\\torture_file.txt";
3069 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3070 int normal_delay = 2000000;
3071 double sec = ((double)used_delay) / ((double)normal_delay);
3072 int msec = 1000 * sec;
3073 TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
3075 if (!mem_ctx) return false;
3077 torture_comment(tctx, "\nRunning test directory write update\n");
3079 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
3081 /* Open a handle on the directory - and leave it open. */
3082 ZERO_STRUCT(open_parms);
3083 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3084 open_parms.ntcreatex.in.flags = 0;
3085 open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
3086 open_parms.ntcreatex.in.file_attr = 0;
3087 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3088 NTCREATEX_SHARE_ACCESS_READ|
3089 NTCREATEX_SHARE_ACCESS_WRITE;
3090 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3091 open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
3092 open_parms.ntcreatex.in.fname = BASEDIR;
3094 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3095 talloc_free(mem_ctx);
3097 if (!NT_STATUS_IS_OK(status)) {
3098 torture_result(tctx, TORTURE_FAIL,
3099 "failed to open directory handle");
3104 fnum1 = open_parms.ntcreatex.out.file.fnum;
3106 /* Store the returned write time. */
3107 ZERO_STRUCT(dir_info1);
3108 dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
3110 torture_comment(tctx, "Initial write time %s\n",
3111 nt_time_string(tctx, dir_info1.basic_info.out.write_time));
3114 smb_msleep(3 * msec);
3116 /* Now create a file within the directory. */
3117 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3119 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
3123 smbcli_close(cli->tree, fnum2);
3125 /* Read the directory write time again. */
3126 ZERO_STRUCT(dir_info2);
3127 dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3128 dir_info2.basic_info.in.file.fnum = fnum1;
3130 status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
3132 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
3134 /* Ensure it's been incremented. */
3135 COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
3137 torture_comment(tctx, "Updated write time %s\n",
3138 nt_time_string(tctx, dir_info2.basic_info.out.write_time));
3143 smbcli_close(cli->tree, fnum1);
3144 smbcli_unlink(cli->tree, fname);
3145 smbcli_deltree(cli->tree, BASEDIR);
3151 testing of delayed update of write_time
3153 struct torture_suite *torture_delay_write(void)
3155 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "delaywrite");
3157 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
3158 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
3159 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
3160 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
3161 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
3162 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
3163 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
3164 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
3165 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
3166 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
3167 torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
3168 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
3169 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
3170 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
3171 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
3172 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3173 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3174 torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);