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_update3a(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";
1603 struct timeval start;
1605 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1606 int normal_delay = 2000000;
1607 double sec = ((double)used_delay) / ((double)normal_delay);
1608 int msec = 1000 * sec;
1610 if (!torture_setup_dir(cli, BASEDIR)) {
1614 torture_comment(tctx, "Open the file handle\n");
1615 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1618 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1622 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1623 finfo0.basic_info.in.file.fnum = fnum1;
1628 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1629 pinfo0.basic_info.in.file.path = fname;
1636 /* get the initial times */
1637 GET_INFO_BOTH(finfo0,pinfo0);
1640 * sleep some time, to demonstrate the handling of write times
1641 * doesn't depend on the time since the open
1645 /* get the initial times */
1646 GET_INFO_BOTH(finfo1,pinfo1);
1647 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1650 * make sure the write time is updated 2 seconds later
1651 * calcuated from the first write
1652 * (but expect upto 5 seconds extra time for a busy server)
1654 start = timeval_current();
1655 end = timeval_add(&start, 7 * sec, 0);
1656 while (!timeval_expired(&end)) {
1658 torture_comment(tctx, "Do a write on the file handle\n");
1659 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1661 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1665 /* get the times after the write */
1666 GET_INFO_FILE(finfo1);
1668 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1669 double diff = timeval_elapsed(&start);
1670 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1671 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1672 "(1sec == %.2f) (wrong!)\n",
1678 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1679 "(1sec == %.2f) (correct)\n",
1686 GET_INFO_BOTH(finfo1,pinfo1);
1687 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1690 * demonstrate that a truncate write always
1691 * updates the write time immediately
1693 for (i=0; i < 3; i++) {
1696 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1697 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1699 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1703 /* get the times after the write */
1704 GET_INFO_BOTH(finfo2,pinfo2);
1705 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1709 /* sure any further write doesn't update the write time */
1710 start = timeval_current();
1711 end = timeval_add(&start, 15 * sec, 0);
1712 while (!timeval_expired(&end)) {
1714 torture_comment(tctx, "Do a write on the file handle\n");
1715 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1717 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1721 /* get the times after the write */
1722 GET_INFO_BOTH(finfo2,pinfo2);
1724 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1725 double diff = timeval_elapsed(&start);
1726 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1727 "(1sec == %.2f) (wrong!)\n",
1735 GET_INFO_BOTH(finfo2,pinfo2);
1736 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1737 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1738 torture_comment(tctx, "Server did not update write_time (correct)\n");
1744 /* get the initial times */
1745 GET_INFO_BOTH(finfo1,pinfo1);
1746 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1749 * demonstrate that a truncate write always
1750 * updates the write time immediately
1752 for (i=0; i < 3; i++) {
1755 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1756 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1758 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1762 /* get the times after the write */
1763 GET_INFO_BOTH(finfo2,pinfo2);
1764 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1771 GET_INFO_BOTH(finfo3,pinfo3);
1772 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1775 * the close doesn't update the write time
1777 torture_comment(tctx, "Close the file handle\n");
1778 smbcli_close(cli->tree, fnum1);
1781 GET_INFO_PATH(pinfo4);
1782 COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1784 if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1785 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1790 smbcli_close(cli->tree, fnum1);
1791 smbcli_unlink(cli->tree, fname);
1792 smbcli_deltree(cli->tree, BASEDIR);
1797 static bool test_delayed_write_update3b(struct torture_context *tctx,
1798 struct smbcli_state *cli,
1799 struct smbcli_state *cli2)
1801 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1802 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1803 const char *fname = BASEDIR "\\torture_file.txt";
1807 struct timeval start;
1809 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1810 int normal_delay = 2000000;
1811 double sec = ((double)used_delay) / ((double)normal_delay);
1812 int msec = 1000 * sec;
1814 if (!torture_setup_dir(cli, BASEDIR)) {
1818 torture_comment(tctx, "Open the file handle\n");
1819 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1822 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1826 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1827 finfo0.basic_info.in.file.fnum = fnum1;
1832 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1833 pinfo0.basic_info.in.file.path = fname;
1840 /* get the initial times */
1841 GET_INFO_BOTH(finfo0,pinfo0);
1844 * sleep some time, to demonstrate the handling of write times
1845 * doesn't depend on the time since the open
1849 /* get the initial times */
1850 GET_INFO_BOTH(finfo1,pinfo1);
1851 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1854 * make sure the write time is updated 2 seconds later
1855 * calcuated from the first write
1856 * (but expect upto 5 seconds extra time for a busy server)
1858 start = timeval_current();
1859 end = timeval_add(&start, 7 * sec, 0);
1860 while (!timeval_expired(&end)) {
1862 torture_comment(tctx, "Do a write on the file handle\n");
1863 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1865 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1869 /* get the times after the write */
1870 GET_INFO_FILE(finfo1);
1872 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1873 double diff = timeval_elapsed(&start);
1874 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1875 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1876 "(1sec == %.2f) (wrong!)\n",
1882 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1883 "(1sec == %.2f) (correct)\n",
1890 GET_INFO_BOTH(finfo1,pinfo1);
1891 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1893 /* sure any further write doesn't update the write time */
1894 start = timeval_current();
1895 end = timeval_add(&start, 15 * sec, 0);
1896 while (!timeval_expired(&end)) {
1898 torture_comment(tctx, "Do a write on the file handle\n");
1899 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1901 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1905 /* get the times after the write */
1906 GET_INFO_BOTH(finfo2,pinfo2);
1908 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1909 double diff = timeval_elapsed(&start);
1910 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1911 "(1sec == %.2f) (wrong!)\n",
1919 GET_INFO_BOTH(finfo2,pinfo2);
1920 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1921 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1922 torture_comment(tctx, "Server did not update write_time (correct)\n");
1928 GET_INFO_BOTH(finfo3,pinfo3);
1929 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1932 * the close updates the write time to the time of the close
1933 * and not to the time of the last write!
1935 torture_comment(tctx, "Close the file handle\n");
1936 smbcli_close(cli->tree, fnum1);
1939 GET_INFO_PATH(pinfo4);
1940 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1942 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1943 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1948 smbcli_close(cli->tree, fnum1);
1949 smbcli_unlink(cli->tree, fname);
1950 smbcli_deltree(cli->tree, BASEDIR);
1955 static bool test_delayed_write_update4(struct torture_context *tctx,
1956 struct smbcli_state *cli,
1957 struct smbcli_state *cli2)
1959 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1960 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1961 const char *fname = BASEDIR "\\torture_file.txt";
1965 struct timeval start;
1967 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1968 int normal_delay = 2000000;
1969 double sec = ((double)used_delay) / ((double)normal_delay);
1970 int msec = 1000 * sec;
1972 if (!torture_setup_dir(cli, BASEDIR)) {
1976 torture_comment(tctx, "Open the file handle\n");
1977 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1980 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1984 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1985 finfo0.basic_info.in.file.fnum = fnum1;
1990 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1991 pinfo0.basic_info.in.file.path = fname;
1998 /* get the initial times */
1999 GET_INFO_BOTH(finfo0,pinfo0);
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);
2013 GET_INFO_BOTH(finfo1,pinfo1);
2014 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2017 * make sure the write time is updated 2 seconds later
2018 * calcuated from the first write
2019 * (but expect upto 3 seconds extra time for a busy server)
2021 start = timeval_current();
2022 end = timeval_add(&start, 5 * sec, 0);
2023 while (!timeval_expired(&end)) {
2024 /* get the times after the first write */
2025 GET_INFO_FILE(finfo1);
2027 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2028 double diff = timeval_elapsed(&start);
2029 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
2030 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2031 "(1sec == %.2f) (wrong!)\n",
2037 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2038 "(1sec == %.2f) (correct)\n",
2045 GET_INFO_BOTH(finfo1,pinfo1);
2046 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2048 /* sure any further write doesn't update the write time */
2049 start = timeval_current();
2050 end = timeval_add(&start, 15 * sec, 0);
2051 while (!timeval_expired(&end)) {
2053 torture_comment(tctx, "Do a write on the file handle\n");
2054 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2056 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2060 /* get the times after the write */
2061 GET_INFO_BOTH(finfo2,pinfo2);
2063 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2064 double diff = timeval_elapsed(&start);
2065 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2066 "(1sec == %.2f) (wrong!)\n",
2074 GET_INFO_BOTH(finfo2,pinfo2);
2075 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2076 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2077 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2083 GET_INFO_BOTH(finfo3,pinfo3);
2084 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2087 * the close updates the write time to the time of the close
2088 * and not to the time of the last write!
2090 torture_comment(tctx, "Close the file handle\n");
2091 smbcli_close(cli->tree, fnum1);
2094 GET_INFO_PATH(pinfo4);
2095 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2097 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2098 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2103 smbcli_close(cli->tree, fnum1);
2104 smbcli_unlink(cli->tree, fname);
2105 smbcli_deltree(cli->tree, BASEDIR);
2110 static bool test_delayed_write_update5(struct torture_context *tctx,
2111 struct smbcli_state *cli,
2112 struct smbcli_state *cli2)
2114 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2115 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2116 const char *fname = BASEDIR "\\torture_file.txt";
2120 struct timeval start;
2122 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2123 int normal_delay = 2000000;
2124 double sec = ((double)used_delay) / ((double)normal_delay);
2125 int msec = 1000 * sec;
2127 if (!torture_setup_dir(cli, BASEDIR)) {
2131 torture_comment(tctx, "Open the file handle\n");
2132 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2135 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2139 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2140 finfo0.basic_info.in.file.fnum = fnum1;
2146 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2147 pinfo0.basic_info.in.file.path = fname;
2155 /* get the initial times */
2156 GET_INFO_BOTH(finfo0,pinfo0);
2159 torture_comment(tctx, "Do a write on the file handle\n");
2160 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2162 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2167 GET_INFO_BOTH(finfo1,pinfo1);
2168 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2170 torture_comment(tctx, "Set write time in the future on the file handle\n");
2171 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2172 GET_INFO_BOTH(finfo2,pinfo2);
2173 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2175 torture_comment(tctx, "Set write time in the past on the file handle\n");
2176 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2177 GET_INFO_BOTH(finfo2,pinfo2);
2178 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2180 /* make sure the 2 second delay from the first write are canceled */
2181 start = timeval_current();
2182 end = timeval_add(&start, 15 * sec, 0);
2183 while (!timeval_expired(&end)) {
2185 /* get the times after the first write */
2186 GET_INFO_BOTH(finfo3,pinfo3);
2188 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2189 double diff = timeval_elapsed(&start);
2190 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2191 "(1sec == %.2f) (wrong!)\n",
2199 GET_INFO_BOTH(finfo3,pinfo3);
2200 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2201 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2202 torture_comment(tctx, "Server did not update write_time (correct)\n");
2205 /* sure any further write doesn't update the write time */
2206 start = timeval_current();
2207 end = timeval_add(&start, 15 * sec, 0);
2208 while (!timeval_expired(&end)) {
2210 torture_comment(tctx, "Do a write on the file handle\n");
2211 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2213 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2217 /* get the times after the write */
2218 GET_INFO_BOTH(finfo4,pinfo4);
2220 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2221 double diff = timeval_elapsed(&start);
2222 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2223 "(1sec == %.2f) (wrong!)\n",
2231 GET_INFO_BOTH(finfo4,pinfo4);
2232 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2233 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2234 torture_comment(tctx, "Server did not update write_time (correct)\n");
2240 GET_INFO_BOTH(finfo5,pinfo5);
2241 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2244 * the close doesn't update the write time
2246 torture_comment(tctx, "Close the file handle\n");
2247 smbcli_close(cli->tree, fnum1);
2250 GET_INFO_PATH(pinfo6);
2251 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2253 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2254 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2259 smbcli_close(cli->tree, fnum1);
2260 smbcli_unlink(cli->tree, fname);
2261 smbcli_deltree(cli->tree, BASEDIR);
2266 static bool test_delayed_write_update5b(struct torture_context *tctx,
2267 struct smbcli_state *cli,
2268 struct smbcli_state *cli2)
2270 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2271 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2272 const char *fname = BASEDIR "\\torture_file.txt";
2276 struct timeval start;
2278 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2279 int normal_delay = 2000000;
2280 double sec = ((double)used_delay) / ((double)normal_delay);
2281 int msec = 1000 * sec;
2283 if (!torture_setup_dir(cli, BASEDIR)) {
2287 torture_comment(tctx, "Open the file handle\n");
2288 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2291 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2295 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2296 finfo0.basic_info.in.file.fnum = fnum1;
2302 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2303 pinfo0.basic_info.in.file.path = fname;
2311 /* get the initial times */
2312 GET_INFO_BOTH(finfo0,pinfo0);
2315 torture_comment(tctx, "Do a write on the file handle\n");
2316 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2318 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2323 GET_INFO_BOTH(finfo1,pinfo1);
2324 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2326 torture_comment(tctx, "Set write time in the future on the file handle\n");
2327 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2328 GET_INFO_BOTH(finfo2,pinfo2);
2329 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2331 torture_comment(tctx, "Set write time in the past on the file handle\n");
2332 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2333 GET_INFO_BOTH(finfo2,pinfo2);
2334 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2336 /* make sure the 2 second delay from the first write are canceled */
2337 start = timeval_current();
2338 end = timeval_add(&start, 15 * sec, 0);
2339 while (!timeval_expired(&end)) {
2341 /* get the times after the first write */
2342 GET_INFO_BOTH(finfo3,pinfo3);
2344 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2345 double diff = timeval_elapsed(&start);
2346 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2347 "(1sec == %.2f) (wrong!)\n",
2355 GET_INFO_BOTH(finfo3,pinfo3);
2356 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2357 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2358 torture_comment(tctx, "Server did not update write_time (correct)\n");
2361 /* sure any further write (truncates) update the write time */
2362 start = timeval_current();
2363 end = timeval_add(&start, 15 * sec, 0);
2364 while (!timeval_expired(&end)) {
2366 torture_comment(tctx, "Do a truncate write on the file handle\n");
2367 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 0);
2369 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2373 /* get the times after the write */
2374 GET_INFO_BOTH(finfo4,pinfo4);
2376 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2377 double diff = timeval_elapsed(&start);
2378 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2379 "(1sec == %.2f) (wrong!)\n",
2387 GET_INFO_BOTH(finfo4,pinfo4);
2388 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2389 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2390 torture_comment(tctx, "Server did not update write_time (correct)\n");
2396 GET_INFO_BOTH(finfo5,pinfo5);
2397 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2400 * the close doesn't update the write time
2402 torture_comment(tctx, "Close the file handle\n");
2403 smbcli_close(cli->tree, fnum1);
2406 GET_INFO_PATH(pinfo6);
2407 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2409 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2410 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2415 smbcli_close(cli->tree, fnum1);
2416 smbcli_unlink(cli->tree, fname);
2417 smbcli_deltree(cli->tree, BASEDIR);
2422 static bool test_delayed_write_update6(struct torture_context *tctx,
2423 struct smbcli_state *cli,
2424 struct smbcli_state *cli2)
2426 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2427 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2428 const char *fname = BASEDIR "\\torture_file.txt";
2433 struct timeval start;
2435 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2436 int normal_delay = 2000000;
2437 double sec = ((double)used_delay) / ((double)normal_delay);
2438 int msec = 1000 * sec;
2441 if (!torture_setup_dir(cli, BASEDIR)) {
2445 torture_comment(tctx, "Open the file handle\n");
2446 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2449 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2454 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2455 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2458 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2463 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2464 finfo0.basic_info.in.file.fnum = fnum1;
2470 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2471 pinfo0.basic_info.in.file.path = fname;
2480 /* get the initial times */
2481 GET_INFO_BOTH(finfo0,pinfo0);
2484 torture_comment(tctx, "Do a write on the file handle\n");
2485 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2487 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2492 GET_INFO_BOTH(finfo1,pinfo1);
2493 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2495 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2496 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2497 GET_INFO_BOTH(finfo2,pinfo2);
2498 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2500 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2501 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2502 GET_INFO_BOTH(finfo2,pinfo2);
2503 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2505 /* make sure the 2 second delay from the first write are canceled */
2506 start = timeval_current();
2507 end = timeval_add(&start, 15 * sec, 0);
2508 while (!timeval_expired(&end)) {
2510 /* get the times after the first write */
2511 GET_INFO_BOTH(finfo3,pinfo3);
2513 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2514 double diff = timeval_elapsed(&start);
2515 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2516 "(1sec == %.2f) (wrong!)\n",
2524 GET_INFO_BOTH(finfo3,pinfo3);
2525 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2526 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2527 torture_comment(tctx, "Server did not update write_time (correct)\n");
2530 /* sure any further write doesn't update the write time */
2531 start = timeval_current();
2532 end = timeval_add(&start, 15 * sec, 0);
2533 while (!timeval_expired(&end)) {
2535 torture_comment(tctx, "Do a write on the file handle\n");
2536 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2538 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2542 /* get the times after the write */
2543 GET_INFO_BOTH(finfo4,pinfo4);
2545 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2546 double diff = timeval_elapsed(&start);
2547 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2548 "(1sec == %.2f) (wrong!)\n",
2556 GET_INFO_BOTH(finfo4,pinfo4);
2557 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2558 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2559 torture_comment(tctx, "Server did not update write_time (correct)\n");
2565 GET_INFO_BOTH(finfo5,pinfo5);
2566 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2569 * the close updates the write time to the time of the close
2570 * as the write time was set on the 2nd handle
2572 torture_comment(tctx, "Close the file handle\n");
2573 smbcli_close(cli->tree, fnum1);
2576 GET_INFO_PATH(pinfo6);
2577 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2579 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2580 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2583 /* keep the 2nd handle open and rerun tests */
2590 * closing the 2nd handle will cause no write time update
2591 * as the write time was explicit set on this handle
2593 torture_comment(tctx, "Close the 2nd file handle\n");
2594 smbcli_close(cli2->tree, fnum2);
2597 GET_INFO_PATH(pinfo7);
2598 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2600 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2601 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2606 smbcli_close(cli->tree, fnum1);
2608 smbcli_close(cli2->tree, fnum2);
2609 smbcli_unlink(cli->tree, fname);
2610 smbcli_deltree(cli->tree, BASEDIR);
2617 testing of delayed update of write_time
2619 struct torture_suite *torture_delay_write(void)
2621 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "DELAYWRITE");
2623 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
2624 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
2625 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate ", test_delayed_write_update1);
2626 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
2627 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
2628 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
2629 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
2630 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
2631 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
2632 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
2633 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
2634 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
2635 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
2636 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);