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"
33 #define BASEDIR "\\delaywrite"
35 static bool test_delayed_write_update(struct torture_context *tctx, struct smbcli_state *cli)
37 union smb_fileinfo finfo1, finfo2;
38 const char *fname = BASEDIR "\\torture_file.txt";
45 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
46 int normal_delay = 2000000;
47 double sec = ((double)used_delay) / ((double)normal_delay);
48 int msec = 1000 * sec;
50 if (!torture_setup_dir(cli, BASEDIR)) {
54 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
56 torture_comment(tctx, "Failed to open %s\n", fname);
60 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
61 finfo1.basic_info.in.file.fnum = fnum1;
64 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
66 if (!NT_STATUS_IS_OK(status)) {
67 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
71 torture_comment(tctx, "Initial write time %s\n",
72 nt_time_string(tctx, finfo1.basic_info.out.write_time));
74 /* 3 second delay to ensure we get past any 2 second time
75 granularity (older systems may have that) */
78 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
81 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
82 (int)written, __location__);
86 start = timeval_current();
87 end = timeval_add(&start, (120*sec), 0);
88 while (!timeval_expired(&end)) {
89 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
91 if (!NT_STATUS_IS_OK(status)) {
92 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
96 torture_comment(tctx, "write time %s\n",
97 nt_time_string(tctx, finfo2.basic_info.out.write_time));
98 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
99 double diff = timeval_elapsed(&start);
100 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
101 torture_comment(tctx, "Server updated write_time after %.2f seconds"
102 "(1 sec == %.2f)(wrong!)\n",
108 torture_comment(tctx, "Server updated write_time after %.2f seconds"
109 "(1 sec == %.2f)(correct)\n",
117 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
118 torture_comment(tctx, "Server did not update write time (wrong!)\n");
124 smbcli_close(cli->tree, fnum1);
125 smbcli_unlink(cli->tree, fname);
126 smbcli_deltree(cli->tree, BASEDIR);
131 static bool test_delayed_write_update1(struct torture_context *tctx, struct smbcli_state *cli)
133 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
134 const char *fname = BASEDIR "\\torture_file1.txt";
139 struct timeval start;
141 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
142 int normal_delay = 2000000;
143 double sec = ((double)used_delay) / ((double)normal_delay);
144 int msec = 1000 * sec;
147 if (!torture_setup_dir(cli, BASEDIR)) {
151 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
153 torture_comment(tctx, "Failed to open %s\n", fname);
157 memset(buf, 'x', 2048);
158 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
160 /* 3 second delay to ensure we get past any 2 second time
161 granularity (older systems may have that) */
164 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
165 finfo1.all_info.in.file.fnum = fnum1;
168 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
169 pinfo4.all_info.in.file.path = fname;
171 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
173 if (!NT_STATUS_IS_OK(status)) {
174 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
178 torture_comment(tctx, "Initial write time %s\n",
179 nt_time_string(tctx, finfo1.all_info.out.write_time));
181 /* Do a zero length SMBwrite call to truncate. */
182 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
185 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
186 (int)written, __location__);
190 start = timeval_current();
191 end = timeval_add(&start, (120*sec), 0);
192 while (!timeval_expired(&end)) {
193 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
195 if (!NT_STATUS_IS_OK(status)) {
196 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
201 if (finfo2.all_info.out.size != 1024) {
202 DEBUG(0, ("file not truncated\n"));
207 torture_comment(tctx, "write time %s\n",
208 nt_time_string(tctx, finfo2.all_info.out.write_time));
209 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
210 double diff = timeval_elapsed(&start);
211 if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
212 torture_comment(tctx, "After SMBwrite truncate "
213 "server updated write_time after %.2f seconds"
214 "(1 sec == %.2f)(wrong!)\n",
220 torture_comment(tctx, "After SMBwrite truncate "
221 "server updated write_time after %.2f seconds"
222 "(1 sec == %.2f)(correct)\n",
230 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
231 torture_comment(tctx, "Server did not update write time (wrong!)\n");
235 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
236 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
239 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
240 (int)written, __location__);
244 start = timeval_current();
245 end = timeval_add(&start, (10*sec), 0);
246 while (!timeval_expired(&end)) {
247 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
249 if (!NT_STATUS_IS_OK(status)) {
250 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
255 if (finfo3.all_info.out.size != 1024) {
256 DEBUG(0, ("file not truncated\n"));
261 torture_comment(tctx, "write time %s\n",
262 nt_time_string(tctx, finfo3.all_info.out.write_time));
263 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
264 double diff = timeval_elapsed(&start);
266 torture_comment(tctx, "server updated write_time after %.2f seconds"
267 "(1 sec == %.2f)(correct)\n",
275 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
276 torture_comment(tctx, "Server updated write time (wrong!)\n");
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 if (!NT_STATUS_IS_OK(status)) {
286 DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
290 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
291 torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
293 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
294 torture_comment(tctx, "Server updated write time on close (correct)\n");
298 smbcli_close(cli->tree, fnum1);
299 smbcli_unlink(cli->tree, fname);
300 smbcli_deltree(cli->tree, BASEDIR);
305 /* Updating with a SMBwrite of zero length
306 * changes the write time immediately - even on expand. */
308 static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
310 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
311 const char *fname = BASEDIR "\\torture_file1a.txt";
316 struct timeval start;
318 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
319 int normal_delay = 2000000;
320 double sec = ((double)used_delay) / ((double)normal_delay);
321 int msec = 1000 * sec;
324 if (!torture_setup_dir(cli, BASEDIR)) {
328 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
330 torture_comment(tctx, "Failed to open %s\n", fname);
334 memset(buf, 'x', 2048);
335 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
337 /* 3 second delay to ensure we get past any 2 second time
338 granularity (older systems may have that) */
341 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
342 finfo1.all_info.in.file.fnum = fnum1;
345 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
346 pinfo4.all_info.in.file.path = fname;
348 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
350 if (!NT_STATUS_IS_OK(status)) {
351 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
355 torture_comment(tctx, "Initial write time %s\n",
356 nt_time_string(tctx, finfo1.all_info.out.write_time));
358 /* Do a zero length SMBwrite call to truncate. */
359 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
362 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
363 (int)written, __location__);
367 start = timeval_current();
368 end = timeval_add(&start, (120*sec), 0);
369 while (!timeval_expired(&end)) {
370 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
372 if (!NT_STATUS_IS_OK(status)) {
373 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
378 if (finfo2.all_info.out.size != 10240) {
379 DEBUG(0, ("file not truncated\n"));
384 torture_comment(tctx, "write time %s\n",
385 nt_time_string(tctx, finfo2.all_info.out.write_time));
386 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
387 double diff = timeval_elapsed(&start);
388 if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
389 torture_comment(tctx, "After SMBwrite truncate "
390 "server updated write_time after %.2f seconds"
391 "(1 sec == %.2f)(wrong!)\n",
397 torture_comment(tctx, "After SMBwrite truncate "
398 "server updated write_time after %.2f seconds"
399 "(1 sec == %.2f)(correct)\n",
407 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
408 torture_comment(tctx, "Server did not update write time (wrong!)\n");
412 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
413 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
416 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
417 (int)written, __location__);
421 start = timeval_current();
422 end = timeval_add(&start, (10*sec), 0);
423 while (!timeval_expired(&end)) {
424 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
426 if (!NT_STATUS_IS_OK(status)) {
427 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
432 if (finfo3.all_info.out.size != 10240) {
433 DEBUG(0, ("file not truncated\n"));
438 torture_comment(tctx, "write time %s\n",
439 nt_time_string(tctx, finfo3.all_info.out.write_time));
440 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
441 double diff = timeval_elapsed(&start);
443 torture_comment(tctx, "server updated write_time after %.2f seconds"
444 "(1 sec == %.2f)(correct)\n",
452 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
453 torture_comment(tctx, "Server updated write time (wrong!)\n");
457 /* the close should trigger an write time update */
458 smbcli_close(cli->tree, fnum1);
461 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
462 if (!NT_STATUS_IS_OK(status)) {
463 DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
467 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
468 torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
470 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
471 torture_comment(tctx, "Server updated write time on close (correct)\n");
475 smbcli_close(cli->tree, fnum1);
476 smbcli_unlink(cli->tree, fname);
477 smbcli_deltree(cli->tree, BASEDIR);
482 /* Updating with a SET_FILE_END_OF_FILE_INFO
483 * changes the write time immediately - even on expand. */
485 static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
487 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
488 const char *fname = BASEDIR "\\torture_file1b.txt";
493 struct timeval start;
495 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
496 int normal_delay = 2000000;
497 double sec = ((double)used_delay) / ((double)normal_delay);
498 int msec = 1000 * sec;
501 if (!torture_setup_dir(cli, BASEDIR)) {
505 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
507 torture_comment(tctx, "Failed to open %s\n", fname);
511 memset(buf, 'x', 2048);
512 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
514 /* 3 second delay to ensure we get past any 2 second time
515 granularity (older systems may have that) */
518 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
519 finfo1.all_info.in.file.fnum = fnum1;
522 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
523 pinfo4.all_info.in.file.path = fname;
525 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
527 if (!NT_STATUS_IS_OK(status)) {
528 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
532 torture_comment(tctx, "Initial write time %s\n",
533 nt_time_string(tctx, finfo1.all_info.out.write_time));
535 /* Do a SET_END_OF_FILE_INFO call to truncate. */
536 status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
538 if (!NT_STATUS_IS_OK(status)) {
539 torture_comment(tctx, "SET_END_OF_FILE failed (%s)\n",
544 start = timeval_current();
545 end = timeval_add(&start, (120*sec), 0);
546 while (!timeval_expired(&end)) {
547 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
549 if (!NT_STATUS_IS_OK(status)) {
550 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
555 if (finfo2.all_info.out.size != 10240) {
556 DEBUG(0, ("file not truncated\n"));
561 torture_comment(tctx, "write time %s\n",
562 nt_time_string(tctx, finfo2.all_info.out.write_time));
563 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
564 double diff = timeval_elapsed(&start);
565 if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
566 torture_comment(tctx, "After SET_END_OF_FILE truncate "
567 "server updated write_time after %.2f seconds"
568 "(1 sec == %.2f)(wrong!)\n",
574 torture_comment(tctx, "After SET_END_OF_FILE truncate "
575 "server updated write_time after %.2f seconds"
576 "(1 sec == %.2f)(correct)\n",
584 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
585 torture_comment(tctx, "Server did not update write time (wrong!)\n");
589 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
590 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
593 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
594 (int)written, __location__);
598 start = timeval_current();
599 end = timeval_add(&start, (10*sec), 0);
600 while (!timeval_expired(&end)) {
601 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
603 if (!NT_STATUS_IS_OK(status)) {
604 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
609 if (finfo3.all_info.out.size != 10240) {
610 DEBUG(0, ("file not truncated\n"));
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 "(1 sec == %.2f)(correct)\n",
629 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
630 torture_comment(tctx, "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 if (!NT_STATUS_IS_OK(status)) {
640 DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
644 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
645 torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
647 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
648 torture_comment(tctx, "Server updated write time on close (correct)\n");
652 smbcli_close(cli->tree, fnum1);
653 smbcli_unlink(cli->tree, fname);
654 smbcli_deltree(cli->tree, BASEDIR);
659 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
661 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
663 union smb_setfileinfo parms;
664 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
665 const char *fname = BASEDIR "\\torture_file1c.txt";
670 struct timeval start;
672 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
673 int normal_delay = 2000000;
674 double sec = ((double)used_delay) / ((double)normal_delay);
675 int msec = 1000 * sec;
678 if (!torture_setup_dir(cli, BASEDIR)) {
682 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
684 torture_comment(tctx, "Failed to open %s\n", fname);
688 memset(buf, 'x', 2048);
689 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
691 /* 3 second delay to ensure we get past any 2 second time
692 granularity (older systems may have that) */
695 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
696 finfo1.all_info.in.file.fnum = fnum1;
699 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
700 pinfo4.all_info.in.file.path = fname;
702 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
704 if (!NT_STATUS_IS_OK(status)) {
705 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
709 torture_comment(tctx, "Initial write time %s\n",
710 nt_time_string(tctx, finfo1.all_info.out.write_time));
712 /* Do a SET_ALLOCATION_SIZE call to truncate. */
713 parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
714 parms.allocation_info.in.file.fnum = fnum1;
715 parms.allocation_info.in.alloc_size = 0;
717 status = smb_raw_setfileinfo(cli->tree, &parms);
719 if (!NT_STATUS_IS_OK(status)) {
720 torture_comment(tctx, "RAW_SFILEINFO_ALLOCATION_INFO failed (%s)\n",
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 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
736 if (finfo2.all_info.out.size != 0) {
737 DEBUG(0, ("file not truncated\n"));
742 torture_comment(tctx, "write time %s\n",
743 nt_time_string(tctx, finfo2.all_info.out.write_time));
744 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
745 double diff = timeval_elapsed(&start);
746 if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
747 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
748 "server updated write_time after %.2f seconds"
749 "(1 sec == %.2f)(wrong!)\n",
755 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
756 "server updated write_time after %.2f seconds"
757 "(1 sec == %.2f)(correct)\n",
765 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
766 torture_comment(tctx, "Server did not update write time (wrong!)\n");
770 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
771 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
774 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
775 (int)written, __location__);
779 start = timeval_current();
780 end = timeval_add(&start, (10*sec), 0);
781 while (!timeval_expired(&end)) {
782 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
784 if (!NT_STATUS_IS_OK(status)) {
785 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
790 if (finfo3.all_info.out.size != 1) {
791 DEBUG(0, ("file not expanded\n"));
796 torture_comment(tctx, "write time %s\n",
797 nt_time_string(tctx, finfo3.all_info.out.write_time));
798 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
799 double diff = timeval_elapsed(&start);
801 torture_comment(tctx, "server updated write_time after %.2f seconds"
802 "(1 sec == %.2f)(correct)\n",
810 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
811 torture_comment(tctx, "Server updated write time (wrong!)\n");
815 /* the close should trigger an write time update */
816 smbcli_close(cli->tree, fnum1);
819 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
820 if (!NT_STATUS_IS_OK(status)) {
821 DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
825 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
826 torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
828 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
829 torture_comment(tctx, "Server updated write time on close (correct)\n");
833 smbcli_close(cli->tree, fnum1);
834 smbcli_unlink(cli->tree, fname);
835 smbcli_deltree(cli->tree, BASEDIR);
841 * Do as above, but using 2 connections.
844 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
845 struct smbcli_state *cli2)
847 union smb_fileinfo finfo1, finfo2;
848 const char *fname = BASEDIR "\\torture_file.txt";
854 struct timeval start;
856 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
857 int normal_delay = 2000000;
858 double sec = ((double)used_delay) / ((double)normal_delay);
859 int msec = 1000 * sec;
860 union smb_flush flsh;
862 if (!torture_setup_dir(cli, BASEDIR)) {
866 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
868 torture_comment(tctx, "Failed to open %s\n", fname);
872 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
873 finfo1.basic_info.in.file.fnum = fnum1;
876 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
878 if (!NT_STATUS_IS_OK(status)) {
879 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
883 torture_comment(tctx, "Initial write time %s\n",
884 nt_time_string(tctx, finfo1.basic_info.out.write_time));
886 /* 3 second delay to ensure we get past any 2 second time
887 granularity (older systems may have that) */
891 /* Try using setfileinfo instead of write to update write time. */
892 union smb_setfileinfo sfinfo;
893 time_t t_set = time(NULL);
894 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
895 sfinfo.basic_info.in.file.fnum = fnum1;
896 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
897 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
899 /* I tried this with both + and - ve to see if it makes a different.
900 It doesn't - once the filetime is set via setfileinfo it stays that way. */
902 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
904 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
906 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
907 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
909 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
911 if (!NT_STATUS_IS_OK(status)) {
912 DEBUG(0, ("sfileinfo failed: %s\n", nt_errstr(status)));
917 finfo2.basic_info.in.file.path = fname;
919 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
921 if (!NT_STATUS_IS_OK(status)) {
922 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
925 torture_comment(tctx, "write time %s\n",
926 nt_time_string(tctx, finfo2.basic_info.out.write_time));
928 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
929 torture_comment(tctx, "Server updated write_time (correct)\n");
931 torture_comment(tctx, "Server did not update write time (wrong!)\n");
935 /* Now try a write to see if the write time gets reset. */
937 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
938 finfo1.basic_info.in.file.fnum = fnum1;
941 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
943 if (!NT_STATUS_IS_OK(status)) {
944 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
948 torture_comment(tctx, "Modified write time %s\n",
949 nt_time_string(tctx, finfo1.basic_info.out.write_time));
952 torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
954 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
957 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
958 (int)written, __location__);
962 /* Just to prove to tridge that the an smbflush has no effect on
963 the write time :-). The setfileinfo IS STICKY. JRA. */
965 torture_comment(tctx, "Doing flush after write\n");
967 flsh.flush.level = RAW_FLUSH_FLUSH;
968 flsh.flush.in.file.fnum = fnum1;
969 status = smb_raw_flush(cli->tree, &flsh);
970 if (!NT_STATUS_IS_OK(status)) {
971 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
975 /* Once the time was set using setfileinfo then it stays set - writes
976 don't have any effect. But make sure. */
977 start = timeval_current();
978 end = timeval_add(&start, (15*sec), 0);
979 while (!timeval_expired(&end)) {
980 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
982 if (!NT_STATUS_IS_OK(status)) {
983 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
987 torture_comment(tctx, "write time %s\n",
988 nt_time_string(tctx, finfo2.basic_info.out.write_time));
989 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
990 double diff = timeval_elapsed(&start);
991 torture_comment(tctx, "Server updated write_time after %.2f seconds"
992 "(1sec == %.2f) (wrong!)\n",
1001 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1002 torture_comment(tctx, "Server did not update write time (correct)\n");
1005 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1007 torture_comment(tctx, "Failed to open %s\n", fname);
1011 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");
1013 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
1015 if (written != 10) {
1016 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
1017 (int)written, __location__);
1021 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1023 if (!NT_STATUS_IS_OK(status)) {
1024 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1027 torture_comment(tctx, "write time %s\n",
1028 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1029 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1030 torture_comment(tctx, "Server updated write_time (wrong!)\n");
1034 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
1035 smbcli_close(cli->tree, fnum1);
1038 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");
1040 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
1042 if (written != 10) {
1043 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
1044 (int)written, __location__);
1048 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1049 finfo1.basic_info.in.file.fnum = fnum2;
1051 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1053 if (!NT_STATUS_IS_OK(status)) {
1054 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1057 torture_comment(tctx, "write time %s\n",
1058 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1059 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1060 torture_comment(tctx, "Server updated write_time (wrong!)\n");
1064 /* Once the time was set using setfileinfo then it stays set - writes
1065 don't have any effect. But make sure. */
1066 start = timeval_current();
1067 end = timeval_add(&start, (15*sec), 0);
1068 while (!timeval_expired(&end)) {
1069 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1071 if (!NT_STATUS_IS_OK(status)) {
1072 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1076 torture_comment(tctx, "write time %s\n",
1077 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1078 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1079 double diff = timeval_elapsed(&start);
1080 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1081 "(1sec == %.2f) (wrong!)\n",
1090 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1091 torture_comment(tctx, "Server did not update write time (correct)\n");
1094 torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1096 smbcli_close(cli->tree, fnum2);
1099 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1101 torture_comment(tctx, "Failed to open %s\n", fname);
1105 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1106 finfo1.basic_info.in.file.fnum = fnum1;
1109 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1111 if (!NT_STATUS_IS_OK(status)) {
1112 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1116 torture_comment(tctx, "Second open initial write time %s\n",
1117 nt_time_string(tctx, finfo1.basic_info.out.write_time));
1120 torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1122 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1124 if (written != 10) {
1125 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
1126 (int)written, __location__);
1130 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1131 finfo1.basic_info.in.file.fnum = fnum1;
1133 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1135 if (!NT_STATUS_IS_OK(status)) {
1136 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1139 torture_comment(tctx, "write time %s\n",
1140 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1141 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1142 torture_comment(tctx, "Server updated write_time (wrong!)\n");
1146 /* Now the write time should be updated again */
1147 start = timeval_current();
1148 end = timeval_add(&start, (15*sec), 0);
1149 while (!timeval_expired(&end)) {
1150 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1152 if (!NT_STATUS_IS_OK(status)) {
1153 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1157 torture_comment(tctx, "write time %s\n",
1158 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1159 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1160 double diff = timeval_elapsed(&start);
1161 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1162 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1163 "(1sec == %.2f) (wrong!)\n",
1169 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1170 "(1sec == %.2f) (correct)\n",
1178 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1179 torture_comment(tctx, "Server did not update write time (wrong!)\n");
1184 /* One more test to do. We should read the filetime via findfirst on the
1185 second connection to ensure it's the same. This is very easy for a Windows
1186 server but a bastard to get right on a POSIX server. JRA. */
1189 smbcli_close(cli->tree, fnum1);
1190 smbcli_unlink(cli->tree, fname);
1191 smbcli_deltree(cli->tree, BASEDIR);
1197 /* Windows does obviously not update the stat info during a write call. I
1198 * *think* this is the problem causing a spurious Excel 2003 on XP error
1199 * message when saving a file. Excel does a setfileinfo, writes, and then does
1200 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1201 * that the file might have been changed in between. What i've been able to
1202 * trace down is that this happens if the getpathinfo after the write shows a
1203 * different last write time than the setfileinfo showed. This is really
1207 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
1208 struct smbcli_state *cli2)
1210 union smb_fileinfo finfo1, finfo2;
1211 const char *fname = BASEDIR "\\torture_file.txt";
1217 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1218 int normal_delay = 2000000;
1219 double sec = ((double)used_delay) / ((double)normal_delay);
1220 int msec = 1000 * sec;
1222 if (!torture_setup_dir(cli, BASEDIR)) {
1226 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1229 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1233 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1234 finfo1.basic_info.in.file.fnum = fnum1;
1236 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1238 if (!NT_STATUS_IS_OK(status)) {
1240 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1246 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1249 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1254 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1256 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1257 smbcli_errstr(cli2->tree));
1262 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1265 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1271 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1272 finfo2.basic_info.in.file.path = fname;
1274 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1276 if (!NT_STATUS_IS_OK(status)) {
1277 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
1283 if (finfo1.basic_info.out.create_time !=
1284 finfo2.basic_info.out.create_time) {
1285 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1290 if (finfo1.basic_info.out.access_time !=
1291 finfo2.basic_info.out.access_time) {
1292 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1297 if (finfo1.basic_info.out.write_time !=
1298 finfo2.basic_info.out.write_time) {
1299 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1300 "write time conn 1 = %s, conn 2 = %s",
1301 nt_time_string(tctx, finfo1.basic_info.out.write_time),
1302 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1307 if (finfo1.basic_info.out.change_time !=
1308 finfo2.basic_info.out.change_time) {
1309 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1314 /* One of the two following calls updates the qpathinfo. */
1316 /* If you had skipped the smbcli_write on fnum2, it would
1317 * *not* have updated the stat on disk */
1319 smbcli_close(cli2->tree, fnum2);
1322 /* This call is only for the people looking at ethereal :-) */
1323 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1324 finfo2.basic_info.in.file.path = fname;
1326 status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1328 if (!NT_STATUS_IS_OK(status)) {
1329 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1336 smbcli_close(cli->tree, fnum1);
1337 smbcli_unlink(cli->tree, fname);
1338 smbcli_deltree(cli->tree, BASEDIR);
1343 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1344 uint64_t r = 10*1000*1000; \
1345 NTTIME g = (given).basic_info.out.write_time; \
1346 NTTIME gr = (g / r) * r; \
1347 NTTIME c = (correct).basic_info.out.write_time; \
1348 NTTIME cr = (c / r) * r; \
1349 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1351 if (strict && (g cmp c)) { \
1353 } else if ((g cmp c) && (gr cmp cr)) { \
1354 /* handle filesystem without high resolution timestamps */ \
1358 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1359 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1360 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1365 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1366 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1367 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1368 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1369 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1370 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1372 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1373 NTTIME g = (given).basic_info.out.access_time; \
1374 NTTIME c = (correct).basic_info.out.access_time; \
1376 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1377 #given, nt_time_string(tctx, g), \
1378 #cmp, #correct, nt_time_string(tctx, c)); \
1383 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1384 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1386 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1387 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1388 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1391 #define GET_INFO_FILE(finfo) do { \
1393 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1394 if (!NT_STATUS_IS_OK(_status)) { \
1396 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1397 nt_errstr(_status)); \
1400 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1401 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1402 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1404 #define GET_INFO_PATH(pinfo) do { \
1406 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1407 if (!NT_STATUS_IS_OK(_status)) { \
1408 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1409 nt_errstr(_status)); \
1413 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1414 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1415 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1417 #define GET_INFO_BOTH(finfo,pinfo) do { \
1418 GET_INFO_FILE(finfo); \
1419 GET_INFO_PATH(pinfo); \
1420 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1423 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1425 union smb_setfileinfo sfinfo; \
1426 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1427 sfinfo.basic_info.in.file.fnum = tfnum; \
1428 sfinfo.basic_info.in.create_time = 0; \
1429 sfinfo.basic_info.in.access_time = 0; \
1430 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1431 sfinfo.basic_info.in.change_time = 0; \
1432 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1433 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1434 if (!NT_STATUS_IS_OK(_status)) { \
1435 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1436 nt_errstr(_status)); \
1441 #define SET_INFO_FILE(finfo, wrtime) \
1442 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1444 static bool test_delayed_write_update3(struct torture_context *tctx,
1445 struct smbcli_state *cli,
1446 struct smbcli_state *cli2)
1448 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1449 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1450 const char *fname = BASEDIR "\\torture_file.txt";
1454 struct timeval start;
1456 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1457 int normal_delay = 2000000;
1458 double sec = ((double)used_delay) / ((double)normal_delay);
1459 int msec = 1000 * sec;
1461 if (!torture_setup_dir(cli, BASEDIR)) {
1465 torture_comment(tctx, "Open the file handle\n");
1466 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1469 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1473 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1474 finfo0.basic_info.in.file.fnum = fnum1;
1479 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1480 pinfo0.basic_info.in.file.path = fname;
1487 /* get the initial times */
1488 GET_INFO_BOTH(finfo0,pinfo0);
1491 * make sure the write time is updated 2 seconds later
1492 * calcuated from the first write
1493 * (but expect upto 5 seconds extra time for a busy server)
1495 start = timeval_current();
1496 end = timeval_add(&start, 7 * sec, 0);
1497 while (!timeval_expired(&end)) {
1499 torture_comment(tctx, "Do a write on the file handle\n");
1500 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1502 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1506 /* get the times after the write */
1507 GET_INFO_FILE(finfo1);
1509 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1510 double diff = timeval_elapsed(&start);
1511 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1512 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1513 "(1sec == %.2f) (wrong!)\n",
1519 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1520 "(1sec == %.2f) (correct)\n",
1527 GET_INFO_BOTH(finfo1,pinfo1);
1528 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1530 /* sure any further write doesn't update the write time */
1531 start = timeval_current();
1532 end = timeval_add(&start, 15 * sec, 0);
1533 while (!timeval_expired(&end)) {
1535 torture_comment(tctx, "Do a write on the file handle\n");
1536 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1538 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1542 /* get the times after the write */
1543 GET_INFO_BOTH(finfo2,pinfo2);
1545 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1546 double diff = timeval_elapsed(&start);
1547 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1548 "(1sec == %.2f) (wrong!)\n",
1556 GET_INFO_BOTH(finfo2,pinfo2);
1557 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1558 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1559 torture_comment(tctx, "Server did not update write_time (correct)\n");
1565 GET_INFO_BOTH(finfo3,pinfo3);
1566 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1569 * the close updates the write time to the time of the close
1570 * and not to the time of the last write!
1572 torture_comment(tctx, "Close the file handle\n");
1573 smbcli_close(cli->tree, fnum1);
1576 GET_INFO_PATH(pinfo4);
1577 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1579 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1580 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1585 smbcli_close(cli->tree, fnum1);
1586 smbcli_unlink(cli->tree, fname);
1587 smbcli_deltree(cli->tree, BASEDIR);
1592 static bool test_delayed_write_update3b(struct torture_context *tctx,
1593 struct smbcli_state *cli,
1594 struct smbcli_state *cli2)
1596 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1597 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1598 const char *fname = BASEDIR "\\torture_file.txt";
1602 struct timeval start;
1604 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1605 int normal_delay = 2000000;
1606 double sec = ((double)used_delay) / ((double)normal_delay);
1607 int msec = 1000 * sec;
1609 if (!torture_setup_dir(cli, BASEDIR)) {
1613 torture_comment(tctx, "Open the file handle\n");
1614 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1617 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1621 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1622 finfo0.basic_info.in.file.fnum = fnum1;
1627 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1628 pinfo0.basic_info.in.file.path = fname;
1635 /* get the initial times */
1636 GET_INFO_BOTH(finfo0,pinfo0);
1639 * sleep some time, to demonstrate the handling of write times
1640 * doesn't depend on the time since the open
1644 /* get the initial times */
1645 GET_INFO_BOTH(finfo1,pinfo1);
1646 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1649 * make sure the write time is updated 2 seconds later
1650 * calcuated from the first write
1651 * (but expect upto 5 seconds extra time for a busy server)
1653 start = timeval_current();
1654 end = timeval_add(&start, 7 * sec, 0);
1655 while (!timeval_expired(&end)) {
1657 torture_comment(tctx, "Do a write on the file handle\n");
1658 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1660 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1664 /* get the times after the write */
1665 GET_INFO_FILE(finfo1);
1667 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1668 double diff = timeval_elapsed(&start);
1669 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1670 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1671 "(1sec == %.2f) (wrong!)\n",
1677 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1678 "(1sec == %.2f) (correct)\n",
1685 GET_INFO_BOTH(finfo1,pinfo1);
1686 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1688 /* sure any further write doesn't update the write time */
1689 start = timeval_current();
1690 end = timeval_add(&start, 15 * sec, 0);
1691 while (!timeval_expired(&end)) {
1693 torture_comment(tctx, "Do a write on the file handle\n");
1694 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1696 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1700 /* get the times after the write */
1701 GET_INFO_BOTH(finfo2,pinfo2);
1703 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1704 double diff = timeval_elapsed(&start);
1705 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1706 "(1sec == %.2f) (wrong!)\n",
1714 GET_INFO_BOTH(finfo2,pinfo2);
1715 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1716 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1717 torture_comment(tctx, "Server did not update write_time (correct)\n");
1723 GET_INFO_BOTH(finfo3,pinfo3);
1724 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1727 * the close updates the write time to the time of the close
1728 * and not to the time of the last write!
1730 torture_comment(tctx, "Close the file handle\n");
1731 smbcli_close(cli->tree, fnum1);
1734 GET_INFO_PATH(pinfo4);
1735 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1737 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1738 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1743 smbcli_close(cli->tree, fnum1);
1744 smbcli_unlink(cli->tree, fname);
1745 smbcli_deltree(cli->tree, BASEDIR);
1750 static bool test_delayed_write_update4(struct torture_context *tctx,
1751 struct smbcli_state *cli,
1752 struct smbcli_state *cli2)
1754 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1755 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1756 const char *fname = BASEDIR "\\torture_file.txt";
1760 struct timeval start;
1762 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1763 int normal_delay = 2000000;
1764 double sec = ((double)used_delay) / ((double)normal_delay);
1765 int msec = 1000 * sec;
1767 if (!torture_setup_dir(cli, BASEDIR)) {
1771 torture_comment(tctx, "Open the file handle\n");
1772 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1775 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1779 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1780 finfo0.basic_info.in.file.fnum = fnum1;
1785 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1786 pinfo0.basic_info.in.file.path = fname;
1793 /* get the initial times */
1794 GET_INFO_BOTH(finfo0,pinfo0);
1800 torture_comment(tctx, "Do a write on the file handle\n");
1801 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1803 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1808 GET_INFO_BOTH(finfo1,pinfo1);
1809 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
1812 * make sure the write time is updated 2 seconds later
1813 * calcuated from the first write
1814 * (but expect upto 3 seconds extra time for a busy server)
1816 start = timeval_current();
1817 end = timeval_add(&start, 5 * sec, 0);
1818 while (!timeval_expired(&end)) {
1819 /* get the times after the first write */
1820 GET_INFO_FILE(finfo1);
1822 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1823 double diff = timeval_elapsed(&start);
1824 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1825 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1826 "(1sec == %.2f) (wrong!)\n",
1832 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1833 "(1sec == %.2f) (correct)\n",
1840 GET_INFO_BOTH(finfo1,pinfo1);
1841 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1843 /* sure any further write doesn't update the write time */
1844 start = timeval_current();
1845 end = timeval_add(&start, 15 * sec, 0);
1846 while (!timeval_expired(&end)) {
1848 torture_comment(tctx, "Do a write on the file handle\n");
1849 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1851 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1855 /* get the times after the write */
1856 GET_INFO_BOTH(finfo2,pinfo2);
1858 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1859 double diff = timeval_elapsed(&start);
1860 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1861 "(1sec == %.2f) (wrong!)\n",
1869 GET_INFO_BOTH(finfo2,pinfo2);
1870 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1871 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1872 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
1878 GET_INFO_BOTH(finfo3,pinfo3);
1879 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1882 * the close updates the write time to the time of the close
1883 * and not to the time of the last write!
1885 torture_comment(tctx, "Close the file handle\n");
1886 smbcli_close(cli->tree, fnum1);
1889 GET_INFO_PATH(pinfo4);
1890 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1892 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1893 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1898 smbcli_close(cli->tree, fnum1);
1899 smbcli_unlink(cli->tree, fname);
1900 smbcli_deltree(cli->tree, BASEDIR);
1905 static bool test_delayed_write_update5(struct torture_context *tctx,
1906 struct smbcli_state *cli,
1907 struct smbcli_state *cli2)
1909 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
1910 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
1911 const char *fname = BASEDIR "\\torture_file.txt";
1915 struct timeval start;
1917 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1918 int normal_delay = 2000000;
1919 double sec = ((double)used_delay) / ((double)normal_delay);
1920 int msec = 1000 * sec;
1922 if (!torture_setup_dir(cli, BASEDIR)) {
1926 torture_comment(tctx, "Open the file handle\n");
1927 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1930 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1934 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1935 finfo0.basic_info.in.file.fnum = fnum1;
1941 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1942 pinfo0.basic_info.in.file.path = fname;
1950 /* get the initial times */
1951 GET_INFO_BOTH(finfo0,pinfo0);
1954 torture_comment(tctx, "Do a write on the file handle\n");
1955 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1957 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1962 GET_INFO_BOTH(finfo1,pinfo1);
1963 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1965 torture_comment(tctx, "Set write time in the future on the file handle\n");
1966 SET_INFO_FILE(finfo0, time(NULL) + 86400);
1967 GET_INFO_BOTH(finfo2,pinfo2);
1968 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1970 torture_comment(tctx, "Set write time in the past on the file handle\n");
1971 SET_INFO_FILE(finfo0, time(NULL) - 86400);
1972 GET_INFO_BOTH(finfo2,pinfo2);
1973 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
1975 /* make sure the 2 second delay from the first write are canceled */
1976 start = timeval_current();
1977 end = timeval_add(&start, 15 * sec, 0);
1978 while (!timeval_expired(&end)) {
1980 /* get the times after the first write */
1981 GET_INFO_BOTH(finfo3,pinfo3);
1983 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
1984 double diff = timeval_elapsed(&start);
1985 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1986 "(1sec == %.2f) (wrong!)\n",
1994 GET_INFO_BOTH(finfo3,pinfo3);
1995 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1996 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1997 torture_comment(tctx, "Server did not update write_time (correct)\n");
2000 /* sure any further write doesn't update the write time */
2001 start = timeval_current();
2002 end = timeval_add(&start, 15 * sec, 0);
2003 while (!timeval_expired(&end)) {
2005 torture_comment(tctx, "Do a write on the file handle\n");
2006 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2008 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2012 /* get the times after the write */
2013 GET_INFO_BOTH(finfo4,pinfo4);
2015 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2016 double diff = timeval_elapsed(&start);
2017 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2018 "(1sec == %.2f) (wrong!)\n",
2026 GET_INFO_BOTH(finfo4,pinfo4);
2027 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2028 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2029 torture_comment(tctx, "Server did not update write_time (correct)\n");
2035 GET_INFO_BOTH(finfo5,pinfo5);
2036 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2039 * the close doesn't update the write time
2041 torture_comment(tctx, "Close the file handle\n");
2042 smbcli_close(cli->tree, fnum1);
2045 GET_INFO_PATH(pinfo6);
2046 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2048 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2049 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2054 smbcli_close(cli->tree, fnum1);
2055 smbcli_unlink(cli->tree, fname);
2056 smbcli_deltree(cli->tree, BASEDIR);
2061 static bool test_delayed_write_update5b(struct torture_context *tctx,
2062 struct smbcli_state *cli,
2063 struct smbcli_state *cli2)
2065 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2066 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2067 const char *fname = BASEDIR "\\torture_file.txt";
2071 struct timeval start;
2073 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2074 int normal_delay = 2000000;
2075 double sec = ((double)used_delay) / ((double)normal_delay);
2076 int msec = 1000 * sec;
2078 if (!torture_setup_dir(cli, BASEDIR)) {
2082 torture_comment(tctx, "Open the file handle\n");
2083 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2086 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2090 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2091 finfo0.basic_info.in.file.fnum = fnum1;
2097 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2098 pinfo0.basic_info.in.file.path = fname;
2106 /* get the initial times */
2107 GET_INFO_BOTH(finfo0,pinfo0);
2110 torture_comment(tctx, "Do a write on the file handle\n");
2111 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2113 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2118 GET_INFO_BOTH(finfo1,pinfo1);
2119 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2121 torture_comment(tctx, "Set write time in the future on the file handle\n");
2122 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2123 GET_INFO_BOTH(finfo2,pinfo2);
2124 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2126 torture_comment(tctx, "Set write time in the past on the file handle\n");
2127 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2128 GET_INFO_BOTH(finfo2,pinfo2);
2129 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2131 /* make sure the 2 second delay from the first write are canceled */
2132 start = timeval_current();
2133 end = timeval_add(&start, 15 * sec, 0);
2134 while (!timeval_expired(&end)) {
2136 /* get the times after the first write */
2137 GET_INFO_BOTH(finfo3,pinfo3);
2139 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2140 double diff = timeval_elapsed(&start);
2141 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2142 "(1sec == %.2f) (wrong!)\n",
2150 GET_INFO_BOTH(finfo3,pinfo3);
2151 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2152 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2153 torture_comment(tctx, "Server did not update write_time (correct)\n");
2156 /* sure any further write (truncates) update the write time */
2157 start = timeval_current();
2158 end = timeval_add(&start, 15 * sec, 0);
2159 while (!timeval_expired(&end)) {
2161 torture_comment(tctx, "Do a truncate write on the file handle\n");
2162 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 0);
2164 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2168 /* get the times after the write */
2169 GET_INFO_BOTH(finfo4,pinfo4);
2171 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2172 double diff = timeval_elapsed(&start);
2173 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2174 "(1sec == %.2f) (wrong!)\n",
2182 GET_INFO_BOTH(finfo4,pinfo4);
2183 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2184 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2185 torture_comment(tctx, "Server did not update write_time (correct)\n");
2191 GET_INFO_BOTH(finfo5,pinfo5);
2192 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2195 * the close doesn't update the write time
2197 torture_comment(tctx, "Close the file handle\n");
2198 smbcli_close(cli->tree, fnum1);
2201 GET_INFO_PATH(pinfo6);
2202 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2204 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2205 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2210 smbcli_close(cli->tree, fnum1);
2211 smbcli_unlink(cli->tree, fname);
2212 smbcli_deltree(cli->tree, BASEDIR);
2217 static bool test_delayed_write_update6(struct torture_context *tctx,
2218 struct smbcli_state *cli,
2219 struct smbcli_state *cli2)
2221 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2222 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2223 const char *fname = BASEDIR "\\torture_file.txt";
2228 struct timeval start;
2230 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2231 int normal_delay = 2000000;
2232 double sec = ((double)used_delay) / ((double)normal_delay);
2233 int msec = 1000 * sec;
2236 if (!torture_setup_dir(cli, BASEDIR)) {
2240 torture_comment(tctx, "Open the file handle\n");
2241 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2244 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2249 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2250 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2253 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2258 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2259 finfo0.basic_info.in.file.fnum = fnum1;
2265 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2266 pinfo0.basic_info.in.file.path = fname;
2275 /* get the initial times */
2276 GET_INFO_BOTH(finfo0,pinfo0);
2279 torture_comment(tctx, "Do a write on the file handle\n");
2280 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2282 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2287 GET_INFO_BOTH(finfo1,pinfo1);
2288 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2290 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2291 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2292 GET_INFO_BOTH(finfo2,pinfo2);
2293 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2295 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2296 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2297 GET_INFO_BOTH(finfo2,pinfo2);
2298 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2300 /* make sure the 2 second delay from the first write are canceled */
2301 start = timeval_current();
2302 end = timeval_add(&start, 15 * sec, 0);
2303 while (!timeval_expired(&end)) {
2305 /* get the times after the first write */
2306 GET_INFO_BOTH(finfo3,pinfo3);
2308 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2309 double diff = timeval_elapsed(&start);
2310 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2311 "(1sec == %.2f) (wrong!)\n",
2319 GET_INFO_BOTH(finfo3,pinfo3);
2320 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2321 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2322 torture_comment(tctx, "Server did not update write_time (correct)\n");
2325 /* sure any further write doesn't update the write time */
2326 start = timeval_current();
2327 end = timeval_add(&start, 15 * sec, 0);
2328 while (!timeval_expired(&end)) {
2330 torture_comment(tctx, "Do a write on the file handle\n");
2331 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2333 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2337 /* get the times after the write */
2338 GET_INFO_BOTH(finfo4,pinfo4);
2340 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2341 double diff = timeval_elapsed(&start);
2342 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2343 "(1sec == %.2f) (wrong!)\n",
2351 GET_INFO_BOTH(finfo4,pinfo4);
2352 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2353 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2354 torture_comment(tctx, "Server did not update write_time (correct)\n");
2360 GET_INFO_BOTH(finfo5,pinfo5);
2361 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2364 * the close updates the write time to the time of the close
2365 * as the write time was set on the 2nd handle
2367 torture_comment(tctx, "Close the file handle\n");
2368 smbcli_close(cli->tree, fnum1);
2371 GET_INFO_PATH(pinfo6);
2372 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2374 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2375 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2378 /* keep the 2nd handle open and rerun tests */
2385 * closing the 2nd handle will cause no write time update
2386 * as the write time was explicit set on this handle
2388 torture_comment(tctx, "Close the 2nd file handle\n");
2389 smbcli_close(cli2->tree, fnum2);
2392 GET_INFO_PATH(pinfo7);
2393 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2395 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2396 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2401 smbcli_close(cli->tree, fnum1);
2403 smbcli_close(cli2->tree, fnum2);
2404 smbcli_unlink(cli->tree, fname);
2405 smbcli_deltree(cli->tree, BASEDIR);
2412 testing of delayed update of write_time
2414 struct torture_suite *torture_delay_write(void)
2416 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "DELAYWRITE");
2418 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
2419 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
2420 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate ", test_delayed_write_update1);
2421 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
2422 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
2423 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
2424 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
2425 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
2426 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
2427 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
2428 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
2429 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
2430 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);