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 torture_comment(tctx, "\nRunning test_delayed_write_update\n");
52 if (!torture_setup_dir(cli, BASEDIR)) {
56 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
58 torture_comment(tctx, "Failed to open %s\n", fname);
62 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
63 finfo1.basic_info.in.file.fnum = fnum1;
66 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
68 if (!NT_STATUS_IS_OK(status)) {
69 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
73 torture_comment(tctx, "Initial write time %s\n",
74 nt_time_string(tctx, finfo1.basic_info.out.write_time));
76 /* 3 second delay to ensure we get past any 2 second time
77 granularity (older systems may have that) */
80 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
83 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
84 (int)written, __location__);
88 start = timeval_current();
89 end = timeval_add(&start, (120*sec), 0);
90 while (!timeval_expired(&end)) {
91 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
93 if (!NT_STATUS_IS_OK(status)) {
94 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
98 torture_comment(tctx, "write time %s\n",
99 nt_time_string(tctx, finfo2.basic_info.out.write_time));
100 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
101 double diff = timeval_elapsed(&start);
102 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
103 torture_comment(tctx, "Server updated write_time after %.2f seconds"
104 "(1 sec == %.2f)(wrong!)\n",
110 torture_comment(tctx, "Server updated write_time after %.2f seconds"
111 "(1 sec == %.2f)(correct)\n",
119 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
120 torture_comment(tctx, "Server did not update write time (wrong!)\n");
126 smbcli_close(cli->tree, fnum1);
127 smbcli_unlink(cli->tree, fname);
128 smbcli_deltree(cli->tree, BASEDIR);
133 static bool test_delayed_write_update1(struct torture_context *tctx, struct smbcli_state *cli)
135 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
136 const char *fname = BASEDIR "\\torture_file1.txt";
141 struct timeval start;
143 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
144 int normal_delay = 2000000;
145 double sec = ((double)used_delay) / ((double)normal_delay);
146 int msec = 1000 * sec;
149 torture_comment(tctx, "\nRunning test_delayed_write_update1\n");
151 if (!torture_setup_dir(cli, BASEDIR)) {
155 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
157 torture_comment(tctx, "Failed to open %s\n", fname);
161 memset(buf, 'x', 2048);
162 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
164 /* 3 second delay to ensure we get past any 2 second time
165 granularity (older systems may have that) */
168 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
169 finfo1.all_info.in.file.fnum = fnum1;
172 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
173 pinfo4.all_info.in.file.path = fname;
175 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
177 if (!NT_STATUS_IS_OK(status)) {
178 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
182 torture_comment(tctx, "Initial write time %s\n",
183 nt_time_string(tctx, finfo1.all_info.out.write_time));
185 /* Do a zero length SMBwrite call to truncate. */
186 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
189 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
190 (int)written, __location__);
194 start = timeval_current();
195 end = timeval_add(&start, (120*sec), 0);
196 while (!timeval_expired(&end)) {
197 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
199 if (!NT_STATUS_IS_OK(status)) {
200 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
205 if (finfo2.all_info.out.size != 1024) {
206 DEBUG(0, ("file not truncated, size = %u (should be 1024)\n",
207 (unsigned int)finfo2.all_info.out.size));
212 torture_comment(tctx, "write time %s\n",
213 nt_time_string(tctx, finfo2.all_info.out.write_time));
214 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
215 double diff = timeval_elapsed(&start);
216 if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
217 torture_comment(tctx, "After SMBwrite truncate "
218 "server updated write_time after %.2f seconds"
219 "(1 sec == %.2f)(wrong!)\n",
225 torture_comment(tctx, "After SMBwrite truncate "
226 "server updated write_time after %.2f seconds"
227 "(1 sec == %.2f)(correct)\n",
235 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
236 torture_comment(tctx, "Server did not update write time (wrong!)\n");
240 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
241 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
244 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
245 (int)written, __location__);
249 start = timeval_current();
250 end = timeval_add(&start, (10*sec), 0);
251 while (!timeval_expired(&end)) {
252 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
254 if (!NT_STATUS_IS_OK(status)) {
255 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
260 if (finfo3.all_info.out.size != 1024) {
261 DEBUG(0, ("file not truncated, size = %u (should be 1024)\n",
262 (unsigned int)finfo3.all_info.out.size));
267 torture_comment(tctx, "write time %s\n",
268 nt_time_string(tctx, finfo3.all_info.out.write_time));
269 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
270 double diff = timeval_elapsed(&start);
272 torture_comment(tctx, "server updated write_time after %.2f seconds"
273 "(1 sec == %.2f)(correct)\n",
281 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
282 torture_comment(tctx, "Server updated write time (wrong!)\n");
286 /* the close should trigger an write time update */
287 smbcli_close(cli->tree, fnum1);
290 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
291 if (!NT_STATUS_IS_OK(status)) {
292 DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
296 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
297 torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
299 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
300 torture_comment(tctx, "Server updated write time on close (correct)\n");
304 smbcli_close(cli->tree, fnum1);
305 smbcli_unlink(cli->tree, fname);
306 smbcli_deltree(cli->tree, BASEDIR);
311 /* Updating with a SMBwrite of zero length
312 * changes the write time immediately - even on expand. */
314 static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
316 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
317 const char *fname = BASEDIR "\\torture_file1a.txt";
322 struct timeval start;
324 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
325 int normal_delay = 2000000;
326 double sec = ((double)used_delay) / ((double)normal_delay);
327 int msec = 1000 * sec;
330 torture_comment(tctx, "\nRunning test_delayed_write_update1a\n");
332 if (!torture_setup_dir(cli, BASEDIR)) {
336 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
338 torture_comment(tctx, "Failed to open %s\n", fname);
342 memset(buf, 'x', 2048);
343 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
345 /* 3 second delay to ensure we get past any 2 second time
346 granularity (older systems may have that) */
349 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
350 finfo1.all_info.in.file.fnum = fnum1;
353 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
354 pinfo4.all_info.in.file.path = fname;
356 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
358 if (!NT_STATUS_IS_OK(status)) {
359 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
363 torture_comment(tctx, "Initial write time %s\n",
364 nt_time_string(tctx, finfo1.all_info.out.write_time));
366 /* Do a zero length SMBwrite call to truncate. */
367 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
370 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
371 (int)written, __location__);
375 start = timeval_current();
376 end = timeval_add(&start, (120*sec), 0);
377 while (!timeval_expired(&end)) {
378 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
380 if (!NT_STATUS_IS_OK(status)) {
381 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
386 if (finfo2.all_info.out.size != 10240) {
387 DEBUG(0, ("file not truncated, size = %u (should be 10240)\n",
388 (unsigned int)finfo2.all_info.out.size));
393 torture_comment(tctx, "write time %s\n",
394 nt_time_string(tctx, finfo2.all_info.out.write_time));
395 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
396 double diff = timeval_elapsed(&start);
397 if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
398 torture_comment(tctx, "After SMBwrite truncate "
399 "server updated write_time after %.2f seconds"
400 "(1 sec == %.2f)(wrong!)\n",
406 torture_comment(tctx, "After SMBwrite truncate "
407 "server updated write_time after %.2f seconds"
408 "(1 sec == %.2f)(correct)\n",
416 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
417 torture_comment(tctx, "Server did not update write time (wrong!)\n");
421 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
422 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
425 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
426 (int)written, __location__);
430 start = timeval_current();
431 end = timeval_add(&start, (10*sec), 0);
432 while (!timeval_expired(&end)) {
433 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
435 if (!NT_STATUS_IS_OK(status)) {
436 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
441 if (finfo3.all_info.out.size != 10240) {
442 DEBUG(0, ("file not truncated, size = %u (should be 10240)\n",
443 (unsigned int)finfo3.all_info.out.size));
448 torture_comment(tctx, "write time %s\n",
449 nt_time_string(tctx, finfo3.all_info.out.write_time));
450 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
451 double diff = timeval_elapsed(&start);
453 torture_comment(tctx, "server updated write_time after %.2f seconds"
454 "(1 sec == %.2f)(correct)\n",
462 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
463 torture_comment(tctx, "Server updated write time (wrong!)\n");
467 /* the close should trigger an write time update */
468 smbcli_close(cli->tree, fnum1);
471 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
472 if (!NT_STATUS_IS_OK(status)) {
473 DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
477 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
478 torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
480 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
481 torture_comment(tctx, "Server updated write time on close (correct)\n");
485 smbcli_close(cli->tree, fnum1);
486 smbcli_unlink(cli->tree, fname);
487 smbcli_deltree(cli->tree, BASEDIR);
492 /* Updating with a SET_FILE_END_OF_FILE_INFO
493 * changes the write time immediately - even on expand. */
495 static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
497 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
498 const char *fname = BASEDIR "\\torture_file1b.txt";
503 struct timeval start;
505 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
506 int normal_delay = 2000000;
507 double sec = ((double)used_delay) / ((double)normal_delay);
508 int msec = 1000 * sec;
511 torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
513 if (!torture_setup_dir(cli, BASEDIR)) {
517 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
519 torture_comment(tctx, "Failed to open %s\n", fname);
523 memset(buf, 'x', 2048);
524 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
526 /* 3 second delay to ensure we get past any 2 second time
527 granularity (older systems may have that) */
530 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
531 finfo1.all_info.in.file.fnum = fnum1;
534 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
535 pinfo4.all_info.in.file.path = fname;
537 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
539 if (!NT_STATUS_IS_OK(status)) {
540 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
544 torture_comment(tctx, "Initial write time %s\n",
545 nt_time_string(tctx, finfo1.all_info.out.write_time));
547 /* Do a SET_END_OF_FILE_INFO call to truncate. */
548 status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
550 if (!NT_STATUS_IS_OK(status)) {
551 torture_comment(tctx, "SET_END_OF_FILE failed (%s)\n",
556 start = timeval_current();
557 end = timeval_add(&start, (120*sec), 0);
558 while (!timeval_expired(&end)) {
559 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
561 if (!NT_STATUS_IS_OK(status)) {
562 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
567 if (finfo2.all_info.out.size != 10240) {
568 DEBUG(0, ("file not truncated (size = %u, should be 10240)\n",
569 (unsigned int)finfo2.all_info.out.size ));
574 torture_comment(tctx, "write time %s\n",
575 nt_time_string(tctx, finfo2.all_info.out.write_time));
576 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
577 double diff = timeval_elapsed(&start);
578 if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
579 torture_comment(tctx, "After SET_END_OF_FILE truncate "
580 "server updated write_time after %.2f seconds"
581 "(1 sec == %.2f)(wrong!)\n",
587 torture_comment(tctx, "After SET_END_OF_FILE truncate "
588 "server updated write_time after %.2f seconds"
589 "(1 sec == %.2f)(correct)\n",
597 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
598 torture_comment(tctx, "Server did not update write time (wrong!)\n");
602 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
603 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
606 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
607 (int)written, __location__);
611 start = timeval_current();
612 end = timeval_add(&start, (10*sec), 0);
613 while (!timeval_expired(&end)) {
614 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
616 if (!NT_STATUS_IS_OK(status)) {
617 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
622 if (finfo3.all_info.out.size != 10240) {
623 DEBUG(0, ("file not truncated (size = %u, should be 10240)\n",
624 (unsigned int)finfo3.all_info.out.size ));
629 torture_comment(tctx, "write time %s\n",
630 nt_time_string(tctx, finfo3.all_info.out.write_time));
631 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
632 double diff = timeval_elapsed(&start);
634 torture_comment(tctx, "server updated write_time after %.2f seconds"
635 "(1 sec == %.2f)(correct)\n",
643 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
644 torture_comment(tctx, "Server updated write time (wrong!)\n");
648 /* the close should trigger an write time update */
649 smbcli_close(cli->tree, fnum1);
652 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
653 if (!NT_STATUS_IS_OK(status)) {
654 DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
658 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
659 torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
661 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
662 torture_comment(tctx, "Server updated write time on close (correct)\n");
666 smbcli_close(cli->tree, fnum1);
667 smbcli_unlink(cli->tree, fname);
668 smbcli_deltree(cli->tree, BASEDIR);
673 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
675 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
677 union smb_setfileinfo parms;
678 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
679 const char *fname = BASEDIR "\\torture_file1c.txt";
684 struct timeval start;
686 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
687 int normal_delay = 2000000;
688 double sec = ((double)used_delay) / ((double)normal_delay);
689 int msec = 1000 * sec;
692 torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
694 if (!torture_setup_dir(cli, BASEDIR)) {
698 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
700 torture_comment(tctx, "Failed to open %s\n", fname);
704 memset(buf, 'x', 2048);
705 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
707 /* 3 second delay to ensure we get past any 2 second time
708 granularity (older systems may have that) */
711 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
712 finfo1.all_info.in.file.fnum = fnum1;
715 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
716 pinfo4.all_info.in.file.path = fname;
718 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
720 if (!NT_STATUS_IS_OK(status)) {
721 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
725 torture_comment(tctx, "Initial write time %s\n",
726 nt_time_string(tctx, finfo1.all_info.out.write_time));
728 /* Do a SET_ALLOCATION_SIZE call to truncate. */
729 parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
730 parms.allocation_info.in.file.fnum = fnum1;
731 parms.allocation_info.in.alloc_size = 0;
733 status = smb_raw_setfileinfo(cli->tree, &parms);
735 if (!NT_STATUS_IS_OK(status)) {
736 torture_comment(tctx, "RAW_SFILEINFO_ALLOCATION_INFO failed (%s)\n",
741 start = timeval_current();
742 end = timeval_add(&start, (120*sec), 0);
743 while (!timeval_expired(&end)) {
744 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
746 if (!NT_STATUS_IS_OK(status)) {
747 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
752 if (finfo2.all_info.out.size != 0) {
753 DEBUG(0, ("file not truncated (size = %u, should be 10240)\n",
754 (unsigned int)finfo2.all_info.out.size ));
759 torture_comment(tctx, "write time %s\n",
760 nt_time_string(tctx, finfo2.all_info.out.write_time));
761 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
762 double diff = timeval_elapsed(&start);
763 if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
764 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
765 "server updated write_time after %.2f seconds"
766 "(1 sec == %.2f)(wrong!)\n",
772 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
773 "server updated write_time after %.2f seconds"
774 "(1 sec == %.2f)(correct)\n",
782 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
783 torture_comment(tctx, "Server did not update write time (wrong!)\n");
787 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
788 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
791 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
792 (int)written, __location__);
796 start = timeval_current();
797 end = timeval_add(&start, (10*sec), 0);
798 while (!timeval_expired(&end)) {
799 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
801 if (!NT_STATUS_IS_OK(status)) {
802 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
807 if (finfo3.all_info.out.size != 1) {
808 DEBUG(0, ("file not expanded\n"));
813 torture_comment(tctx, "write time %s\n",
814 nt_time_string(tctx, finfo3.all_info.out.write_time));
815 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
816 double diff = timeval_elapsed(&start);
818 torture_comment(tctx, "server updated write_time after %.2f seconds"
819 "(1 sec == %.2f)(correct)\n",
827 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
828 torture_comment(tctx, "Server updated write time (wrong!)\n");
832 /* the close should trigger an write time update */
833 smbcli_close(cli->tree, fnum1);
836 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
837 if (!NT_STATUS_IS_OK(status)) {
838 DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
842 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
843 torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
845 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
846 torture_comment(tctx, "Server updated write time on close (correct)\n");
850 smbcli_close(cli->tree, fnum1);
851 smbcli_unlink(cli->tree, fname);
852 smbcli_deltree(cli->tree, BASEDIR);
858 * Do as above, but using 2 connections.
861 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
862 struct smbcli_state *cli2)
864 union smb_fileinfo finfo1, finfo2;
865 const char *fname = BASEDIR "\\torture_file.txt";
871 struct timeval start;
873 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
874 int normal_delay = 2000000;
875 double sec = ((double)used_delay) / ((double)normal_delay);
876 int msec = 1000 * sec;
877 union smb_flush flsh;
879 torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
881 if (!torture_setup_dir(cli, BASEDIR)) {
885 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
887 torture_comment(tctx, "Failed to open %s\n", fname);
891 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
892 finfo1.basic_info.in.file.fnum = fnum1;
895 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
897 if (!NT_STATUS_IS_OK(status)) {
898 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
902 torture_comment(tctx, "Initial write time %s\n",
903 nt_time_string(tctx, finfo1.basic_info.out.write_time));
905 /* 3 second delay to ensure we get past any 2 second time
906 granularity (older systems may have that) */
910 /* Try using setfileinfo instead of write to update write time. */
911 union smb_setfileinfo sfinfo;
912 time_t t_set = time(NULL);
913 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
914 sfinfo.basic_info.in.file.fnum = fnum1;
915 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
916 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
918 /* I tried this with both + and - ve to see if it makes a different.
919 It doesn't - once the filetime is set via setfileinfo it stays that way. */
921 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
923 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
925 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
926 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
928 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
930 if (!NT_STATUS_IS_OK(status)) {
931 DEBUG(0, ("sfileinfo failed: %s\n", nt_errstr(status)));
936 finfo2.basic_info.in.file.path = fname;
938 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
940 if (!NT_STATUS_IS_OK(status)) {
941 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
944 torture_comment(tctx, "write time %s\n",
945 nt_time_string(tctx, finfo2.basic_info.out.write_time));
947 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
948 torture_comment(tctx, "Server updated write_time (correct)\n");
950 torture_comment(tctx, "Server did not update write time (wrong!)\n");
954 /* Now try a write to see if the write time gets reset. */
956 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
957 finfo1.basic_info.in.file.fnum = fnum1;
960 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
962 if (!NT_STATUS_IS_OK(status)) {
963 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
967 torture_comment(tctx, "Modified write time %s\n",
968 nt_time_string(tctx, finfo1.basic_info.out.write_time));
971 torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
973 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
976 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
977 (int)written, __location__);
981 /* Just to prove to tridge that the an smbflush has no effect on
982 the write time :-). The setfileinfo IS STICKY. JRA. */
984 torture_comment(tctx, "Doing flush after write\n");
986 flsh.flush.level = RAW_FLUSH_FLUSH;
987 flsh.flush.in.file.fnum = fnum1;
988 status = smb_raw_flush(cli->tree, &flsh);
989 if (!NT_STATUS_IS_OK(status)) {
990 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
994 /* Once the time was set using setfileinfo then it stays set - writes
995 don't have any effect. But make sure. */
996 start = timeval_current();
997 end = timeval_add(&start, (15*sec), 0);
998 while (!timeval_expired(&end)) {
999 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1001 if (!NT_STATUS_IS_OK(status)) {
1002 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1006 torture_comment(tctx, "write time %s\n",
1007 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1008 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1009 double diff = timeval_elapsed(&start);
1010 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1011 "(1sec == %.2f) (wrong!)\n",
1020 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1021 torture_comment(tctx, "Server did not update write time (correct)\n");
1024 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1026 torture_comment(tctx, "Failed to open %s\n", fname);
1030 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");
1032 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
1034 if (written != 10) {
1035 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
1036 (int)written, __location__);
1040 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1042 if (!NT_STATUS_IS_OK(status)) {
1043 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1046 torture_comment(tctx, "write time %s\n",
1047 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1048 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1049 torture_comment(tctx, "Server updated write_time (wrong!)\n");
1053 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
1054 smbcli_close(cli->tree, fnum1);
1057 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");
1059 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
1061 if (written != 10) {
1062 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
1063 (int)written, __location__);
1067 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1068 finfo1.basic_info.in.file.fnum = fnum2;
1070 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1072 if (!NT_STATUS_IS_OK(status)) {
1073 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 torture_comment(tctx, "Server updated write_time (wrong!)\n");
1083 /* Once the time was set using setfileinfo then it stays set - writes
1084 don't have any effect. But make sure. */
1085 start = timeval_current();
1086 end = timeval_add(&start, (15*sec), 0);
1087 while (!timeval_expired(&end)) {
1088 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1090 if (!NT_STATUS_IS_OK(status)) {
1091 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1095 torture_comment(tctx, "write time %s\n",
1096 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1097 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1098 double diff = timeval_elapsed(&start);
1099 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1100 "(1sec == %.2f) (wrong!)\n",
1109 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1110 torture_comment(tctx, "Server did not update write time (correct)\n");
1113 torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1115 smbcli_close(cli->tree, fnum2);
1118 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1120 torture_comment(tctx, "Failed to open %s\n", fname);
1124 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1125 finfo1.basic_info.in.file.fnum = fnum1;
1128 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1130 if (!NT_STATUS_IS_OK(status)) {
1131 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1135 torture_comment(tctx, "Second open initial write time %s\n",
1136 nt_time_string(tctx, finfo1.basic_info.out.write_time));
1139 torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1141 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1143 if (written != 10) {
1144 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
1145 (int)written, __location__);
1149 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1150 finfo1.basic_info.in.file.fnum = fnum1;
1152 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1154 if (!NT_STATUS_IS_OK(status)) {
1155 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1158 torture_comment(tctx, "write time %s\n",
1159 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1160 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1161 torture_comment(tctx, "Server updated write_time (wrong!)\n");
1165 /* Now the write time should be updated again */
1166 start = timeval_current();
1167 end = timeval_add(&start, (15*sec), 0);
1168 while (!timeval_expired(&end)) {
1169 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1171 if (!NT_STATUS_IS_OK(status)) {
1172 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1176 torture_comment(tctx, "write time %s\n",
1177 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1178 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1179 double diff = timeval_elapsed(&start);
1180 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1181 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1182 "(1sec == %.2f) (wrong!)\n",
1188 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1189 "(1sec == %.2f) (correct)\n",
1197 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1198 torture_comment(tctx, "Server did not update write time (wrong!)\n");
1203 /* One more test to do. We should read the filetime via findfirst on the
1204 second connection to ensure it's the same. This is very easy for a Windows
1205 server but a bastard to get right on a POSIX server. JRA. */
1208 smbcli_close(cli->tree, fnum1);
1209 smbcli_unlink(cli->tree, fname);
1210 smbcli_deltree(cli->tree, BASEDIR);
1216 /* Windows does obviously not update the stat info during a write call. I
1217 * *think* this is the problem causing a spurious Excel 2003 on XP error
1218 * message when saving a file. Excel does a setfileinfo, writes, and then does
1219 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1220 * that the file might have been changed in between. What i've been able to
1221 * trace down is that this happens if the getpathinfo after the write shows a
1222 * different last write time than the setfileinfo showed. This is really
1226 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
1227 struct smbcli_state *cli2)
1229 union smb_fileinfo finfo1, finfo2;
1230 const char *fname = BASEDIR "\\torture_file.txt";
1236 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1237 int normal_delay = 2000000;
1238 double sec = ((double)used_delay) / ((double)normal_delay);
1239 int msec = 1000 * sec;
1241 torture_comment(tctx, "\nRunning test_finfo_after_write\n");
1243 if (!torture_setup_dir(cli, BASEDIR)) {
1247 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1250 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1254 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1255 finfo1.basic_info.in.file.fnum = fnum1;
1257 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1259 if (!NT_STATUS_IS_OK(status)) {
1261 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1267 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1270 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1275 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1277 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1278 smbcli_errstr(cli2->tree));
1283 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1286 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1292 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1293 finfo2.basic_info.in.file.path = fname;
1295 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1297 if (!NT_STATUS_IS_OK(status)) {
1298 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
1304 if (finfo1.basic_info.out.create_time !=
1305 finfo2.basic_info.out.create_time) {
1306 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1311 if (finfo1.basic_info.out.access_time !=
1312 finfo2.basic_info.out.access_time) {
1313 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1318 if (finfo1.basic_info.out.write_time !=
1319 finfo2.basic_info.out.write_time) {
1320 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1321 "write time conn 1 = %s, conn 2 = %s",
1322 nt_time_string(tctx, finfo1.basic_info.out.write_time),
1323 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1328 if (finfo1.basic_info.out.change_time !=
1329 finfo2.basic_info.out.change_time) {
1330 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1335 /* One of the two following calls updates the qpathinfo. */
1337 /* If you had skipped the smbcli_write on fnum2, it would
1338 * *not* have updated the stat on disk */
1340 smbcli_close(cli2->tree, fnum2);
1343 /* This call is only for the people looking at ethereal :-) */
1344 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1345 finfo2.basic_info.in.file.path = fname;
1347 status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1349 if (!NT_STATUS_IS_OK(status)) {
1350 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1357 smbcli_close(cli->tree, fnum1);
1358 smbcli_unlink(cli->tree, fname);
1359 smbcli_deltree(cli->tree, BASEDIR);
1364 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1365 uint64_t r = 10*1000*1000; \
1366 NTTIME g = (given).basic_info.out.write_time; \
1367 NTTIME gr = (g / r) * r; \
1368 NTTIME c = (correct).basic_info.out.write_time; \
1369 NTTIME cr = (c / r) * r; \
1370 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1372 if (strict && (g cmp c)) { \
1374 } else if ((g cmp c) && (gr cmp cr)) { \
1375 /* handle filesystem without high resolution timestamps */ \
1379 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1380 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1381 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1386 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1387 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1388 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1389 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1390 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1391 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1393 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1394 NTTIME g = (given).basic_info.out.access_time; \
1395 NTTIME c = (correct).basic_info.out.access_time; \
1397 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1398 #given, nt_time_string(tctx, g), \
1399 #cmp, #correct, nt_time_string(tctx, c)); \
1404 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1405 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1407 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1408 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1409 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1412 #define GET_INFO_FILE(finfo) do { \
1414 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1415 if (!NT_STATUS_IS_OK(_status)) { \
1417 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1418 nt_errstr(_status)); \
1421 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1422 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1423 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1425 #define GET_INFO_PATH(pinfo) do { \
1427 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1428 if (!NT_STATUS_IS_OK(_status)) { \
1429 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1430 nt_errstr(_status)); \
1434 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1435 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1436 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1438 #define GET_INFO_BOTH(finfo,pinfo) do { \
1439 GET_INFO_FILE(finfo); \
1440 GET_INFO_PATH(pinfo); \
1441 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1444 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1446 union smb_setfileinfo sfinfo; \
1447 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1448 sfinfo.basic_info.in.file.fnum = tfnum; \
1449 sfinfo.basic_info.in.create_time = 0; \
1450 sfinfo.basic_info.in.access_time = 0; \
1451 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1452 sfinfo.basic_info.in.change_time = 0; \
1453 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1454 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1455 if (!NT_STATUS_IS_OK(_status)) { \
1456 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1457 nt_errstr(_status)); \
1462 #define SET_INFO_FILE(finfo, wrtime) \
1463 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1465 static bool test_delayed_write_update3(struct torture_context *tctx,
1466 struct smbcli_state *cli,
1467 struct smbcli_state *cli2)
1469 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1470 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1471 const char *fname = BASEDIR "\\torture_file3.txt";
1475 struct timeval start;
1477 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1478 int normal_delay = 2000000;
1479 double sec = ((double)used_delay) / ((double)normal_delay);
1480 int msec = 1000 * sec;
1482 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
1484 if (!torture_setup_dir(cli, BASEDIR)) {
1488 torture_comment(tctx, "Open the file handle\n");
1489 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1492 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1496 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1497 finfo0.basic_info.in.file.fnum = fnum1;
1502 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1503 pinfo0.basic_info.in.file.path = fname;
1510 /* get the initial times */
1511 GET_INFO_BOTH(finfo0,pinfo0);
1514 * make sure the write time is updated 2 seconds later
1515 * calcuated from the first write
1516 * (but expect upto 5 seconds extra time for a busy server)
1518 start = timeval_current();
1519 end = timeval_add(&start, 7 * sec, 0);
1520 while (!timeval_expired(&end)) {
1522 torture_comment(tctx, "Do a write on the file handle\n");
1523 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1525 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1529 /* get the times after the write */
1530 GET_INFO_FILE(finfo1);
1532 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1533 double diff = timeval_elapsed(&start);
1534 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1535 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1536 "(1sec == %.2f) (wrong!)\n",
1542 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1543 "(1sec == %.2f) (correct)\n",
1550 GET_INFO_BOTH(finfo1,pinfo1);
1551 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1553 /* sure any further write doesn't update the write time */
1554 start = timeval_current();
1555 end = timeval_add(&start, 15 * sec, 0);
1556 while (!timeval_expired(&end)) {
1558 torture_comment(tctx, "Do a write on the file handle\n");
1559 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1561 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1565 /* get the times after the write */
1566 GET_INFO_BOTH(finfo2,pinfo2);
1568 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1569 double diff = timeval_elapsed(&start);
1570 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1571 "(1sec == %.2f) (wrong!)\n",
1579 GET_INFO_BOTH(finfo2,pinfo2);
1580 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1581 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1582 torture_comment(tctx, "Server did not update write_time (correct)\n");
1588 GET_INFO_BOTH(finfo3,pinfo3);
1589 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1592 * the close updates the write time to the time of the close
1593 * and not to the time of the last write!
1595 torture_comment(tctx, "Close the file handle\n");
1596 smbcli_close(cli->tree, fnum1);
1599 GET_INFO_PATH(pinfo4);
1600 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1602 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1603 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1608 smbcli_close(cli->tree, fnum1);
1609 smbcli_unlink(cli->tree, fname);
1610 smbcli_deltree(cli->tree, BASEDIR);
1615 static bool test_delayed_write_update3a(struct torture_context *tctx,
1616 struct smbcli_state *cli,
1617 struct smbcli_state *cli2)
1619 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1620 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1621 const char *fname = BASEDIR "\\torture_file3a.txt";
1626 struct timeval start;
1628 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1629 int normal_delay = 2000000;
1630 double sec = ((double)used_delay) / ((double)normal_delay);
1631 int msec = 1000 * sec;
1633 torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
1635 if (!torture_setup_dir(cli, BASEDIR)) {
1639 torture_comment(tctx, "Open the file handle\n");
1640 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1643 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1647 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1648 finfo0.basic_info.in.file.fnum = fnum1;
1653 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1654 pinfo0.basic_info.in.file.path = fname;
1661 /* get the initial times */
1662 GET_INFO_BOTH(finfo0,pinfo0);
1665 * sleep some time, to demonstrate the handling of write times
1666 * doesn't depend on the time since the open
1670 /* get the initial times */
1671 GET_INFO_BOTH(finfo1,pinfo1);
1672 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1675 * make sure the write time is updated 2 seconds later
1676 * calcuated from the first write
1677 * (but expect upto 5 seconds extra time for a busy server)
1679 start = timeval_current();
1680 end = timeval_add(&start, 7 * sec, 0);
1681 while (!timeval_expired(&end)) {
1683 torture_comment(tctx, "Do a write on the file handle\n");
1684 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1686 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1690 /* get the times after the write */
1691 GET_INFO_FILE(finfo1);
1693 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1694 double diff = timeval_elapsed(&start);
1695 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1696 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1697 "(1sec == %.2f) (wrong!)\n",
1703 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1704 "(1sec == %.2f) (correct)\n",
1711 GET_INFO_BOTH(finfo1,pinfo1);
1712 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1715 * demonstrate that a truncate write always
1716 * updates the write time immediately
1718 for (i=0; i < 3; i++) {
1721 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1722 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1724 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1728 /* get the times after the write */
1729 GET_INFO_BOTH(finfo2,pinfo2);
1730 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1734 /* sure any further write doesn't update the write time */
1735 start = timeval_current();
1736 end = timeval_add(&start, 15 * sec, 0);
1737 while (!timeval_expired(&end)) {
1739 torture_comment(tctx, "Do a write on the file handle\n");
1740 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1742 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1746 /* get the times after the write */
1747 GET_INFO_BOTH(finfo2,pinfo2);
1749 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1750 double diff = timeval_elapsed(&start);
1751 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1752 "(1sec == %.2f) (wrong!)\n",
1760 GET_INFO_BOTH(finfo2,pinfo2);
1761 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1762 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1763 torture_comment(tctx, "Server did not update write_time (correct)\n");
1769 /* get the initial times */
1770 GET_INFO_BOTH(finfo1,pinfo1);
1771 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1774 * demonstrate that a truncate write always
1775 * updates the write time immediately
1777 for (i=0; i < 3; i++) {
1780 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1781 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1783 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1787 /* get the times after the write */
1788 GET_INFO_BOTH(finfo2,pinfo2);
1789 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1796 GET_INFO_BOTH(finfo3,pinfo3);
1797 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1800 * the close doesn't update the write time
1802 torture_comment(tctx, "Close the file handle\n");
1803 smbcli_close(cli->tree, fnum1);
1806 GET_INFO_PATH(pinfo4);
1807 COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1809 if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1810 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1815 smbcli_close(cli->tree, fnum1);
1816 smbcli_unlink(cli->tree, fname);
1817 smbcli_deltree(cli->tree, BASEDIR);
1822 static bool test_delayed_write_update3b(struct torture_context *tctx,
1823 struct smbcli_state *cli,
1824 struct smbcli_state *cli2)
1826 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1827 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1828 const char *fname = BASEDIR "\\torture_file3b.txt";
1832 struct timeval start;
1834 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1835 int normal_delay = 2000000;
1836 double sec = ((double)used_delay) / ((double)normal_delay);
1837 int msec = 1000 * sec;
1839 torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
1841 if (!torture_setup_dir(cli, BASEDIR)) {
1845 torture_comment(tctx, "Open the file handle\n");
1846 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1849 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1853 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1854 finfo0.basic_info.in.file.fnum = fnum1;
1859 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1860 pinfo0.basic_info.in.file.path = fname;
1867 /* get the initial times */
1868 GET_INFO_BOTH(finfo0,pinfo0);
1871 * sleep some time, to demonstrate the handling of write times
1872 * doesn't depend on the time since the open
1876 /* get the initial times */
1877 GET_INFO_BOTH(finfo1,pinfo1);
1878 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1881 * make sure the write time is updated 2 seconds later
1882 * calcuated from the first write
1883 * (but expect upto 5 seconds extra time for a busy server)
1885 start = timeval_current();
1886 end = timeval_add(&start, 7 * sec, 0);
1887 while (!timeval_expired(&end)) {
1889 torture_comment(tctx, "Do a write on the file handle\n");
1890 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1892 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1896 /* get the times after the write */
1897 GET_INFO_FILE(finfo1);
1899 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1900 double diff = timeval_elapsed(&start);
1901 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1902 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1903 "(1sec == %.2f) (wrong!)\n",
1909 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1910 "(1sec == %.2f) (correct)\n",
1917 GET_INFO_BOTH(finfo1,pinfo1);
1918 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1920 /* sure any further write doesn't update the write time */
1921 start = timeval_current();
1922 end = timeval_add(&start, 15 * sec, 0);
1923 while (!timeval_expired(&end)) {
1925 torture_comment(tctx, "Do a write on the file handle\n");
1926 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1928 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1932 /* get the times after the write */
1933 GET_INFO_BOTH(finfo2,pinfo2);
1935 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1936 double diff = timeval_elapsed(&start);
1937 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1938 "(1sec == %.2f) (wrong!)\n",
1946 GET_INFO_BOTH(finfo2,pinfo2);
1947 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1948 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1949 torture_comment(tctx, "Server did not update write_time (correct)\n");
1955 GET_INFO_BOTH(finfo3,pinfo3);
1956 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1959 * the close updates the write time to the time of the close
1960 * and not to the time of the last write!
1962 torture_comment(tctx, "Close the file handle\n");
1963 smbcli_close(cli->tree, fnum1);
1966 GET_INFO_PATH(pinfo4);
1967 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1969 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1970 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1975 smbcli_close(cli->tree, fnum1);
1976 smbcli_unlink(cli->tree, fname);
1977 smbcli_deltree(cli->tree, BASEDIR);
1982 static bool test_delayed_write_update3c(struct torture_context *tctx,
1983 struct smbcli_state *cli,
1984 struct smbcli_state *cli2)
1986 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1987 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1988 const char *fname = BASEDIR "\\torture_file3c.txt";
1993 struct timeval start;
1995 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1996 int normal_delay = 2000000;
1997 double sec = ((double)used_delay) / ((double)normal_delay);
1998 int msec = 1000 * sec;
2000 torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
2002 if (!torture_setup_dir(cli, BASEDIR)) {
2006 torture_comment(tctx, "Open the file handle\n");
2007 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2010 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2014 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2015 finfo0.basic_info.in.file.fnum = fnum1;
2020 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2021 pinfo0.basic_info.in.file.path = fname;
2028 /* get the initial times */
2029 GET_INFO_BOTH(finfo0,pinfo0);
2032 * sleep some time, to demonstrate the handling of write times
2033 * doesn't depend on the time since the open
2037 /* get the initial times */
2038 GET_INFO_BOTH(finfo1,pinfo1);
2039 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2042 * demonstrate that a truncate write always
2043 * updates the write time immediately
2045 for (i=0; i < 3; i++) {
2048 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
2049 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2051 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2055 /* get the times after the write */
2056 GET_INFO_BOTH(finfo2,pinfo2);
2057 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2061 start = timeval_current();
2062 end = timeval_add(&start, 7 * sec, 0);
2063 while (!timeval_expired(&end)) {
2065 torture_comment(tctx, "Do a write on the file handle\n");
2066 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2068 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2072 /* get the times after the write */
2073 GET_INFO_FILE(finfo2);
2075 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2076 double diff = timeval_elapsed(&start);
2077 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2078 "(1sec == %.2f) (wrong!)\n",
2086 GET_INFO_BOTH(finfo2,pinfo2);
2087 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2088 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2089 torture_comment(tctx, "Server did not update write_time (correct)\n");
2095 /* get the initial times */
2096 GET_INFO_BOTH(finfo1,pinfo1);
2097 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2100 * demonstrate that a truncate write always
2101 * updates the write time immediately
2103 for (i=0; i < 3; i++) {
2106 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2107 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2109 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2113 /* get the times after the write */
2114 GET_INFO_BOTH(finfo2,pinfo2);
2115 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2122 GET_INFO_BOTH(finfo2,pinfo2);
2123 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2125 /* sure any further write doesn't update the write time */
2126 start = timeval_current();
2127 end = timeval_add(&start, 15 * sec, 0);
2128 while (!timeval_expired(&end)) {
2130 torture_comment(tctx, "Do a write on the file handle\n");
2131 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2133 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2137 /* get the times after the write */
2138 GET_INFO_BOTH(finfo2,pinfo2);
2140 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2141 double diff = timeval_elapsed(&start);
2142 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2143 "(1sec == %.2f) (wrong!)\n",
2151 GET_INFO_BOTH(finfo2,pinfo2);
2152 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2153 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2154 torture_comment(tctx, "Server did not update write_time (correct)\n");
2160 GET_INFO_BOTH(finfo3,pinfo3);
2161 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2164 * the close updates the write time to the time of the close
2165 * and not to the time of the last write!
2167 torture_comment(tctx, "Close the file handle\n");
2168 smbcli_close(cli->tree, fnum1);
2171 GET_INFO_PATH(pinfo4);
2172 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2174 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2175 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2180 smbcli_close(cli->tree, fnum1);
2181 smbcli_unlink(cli->tree, fname);
2182 smbcli_deltree(cli->tree, BASEDIR);
2187 static bool test_delayed_write_update4(struct torture_context *tctx,
2188 struct smbcli_state *cli,
2189 struct smbcli_state *cli2)
2191 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
2192 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
2193 const char *fname = BASEDIR "\\torture_file4.txt";
2197 struct timeval start;
2199 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2200 int normal_delay = 2000000;
2201 double sec = ((double)used_delay) / ((double)normal_delay);
2202 int msec = 1000 * sec;
2204 torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2206 if (!torture_setup_dir(cli, BASEDIR)) {
2210 torture_comment(tctx, "Open the file handle\n");
2211 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2214 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2218 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2219 finfo0.basic_info.in.file.fnum = fnum1;
2224 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2225 pinfo0.basic_info.in.file.path = fname;
2232 /* get the initial times */
2233 GET_INFO_BOTH(finfo0,pinfo0);
2239 torture_comment(tctx, "Do a write on the file handle\n");
2240 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2242 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2247 GET_INFO_BOTH(finfo1,pinfo1);
2248 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2251 * make sure the write time is updated 2 seconds later
2252 * calcuated from the first write
2253 * (but expect upto 3 seconds extra time for a busy server)
2255 start = timeval_current();
2256 end = timeval_add(&start, 5 * sec, 0);
2257 while (!timeval_expired(&end)) {
2258 /* get the times after the first write */
2259 GET_INFO_FILE(finfo1);
2261 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2262 double diff = timeval_elapsed(&start);
2263 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
2264 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2265 "(1sec == %.2f) (wrong!)\n",
2271 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2272 "(1sec == %.2f) (correct)\n",
2279 GET_INFO_BOTH(finfo1,pinfo1);
2280 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2282 /* sure any further write doesn't update the write time */
2283 start = timeval_current();
2284 end = timeval_add(&start, 15 * sec, 0);
2285 while (!timeval_expired(&end)) {
2287 torture_comment(tctx, "Do a write on the file handle\n");
2288 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2290 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2294 /* get the times after the write */
2295 GET_INFO_BOTH(finfo2,pinfo2);
2297 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2298 double diff = timeval_elapsed(&start);
2299 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2300 "(1sec == %.2f) (wrong!)\n",
2308 GET_INFO_BOTH(finfo2,pinfo2);
2309 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2310 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2311 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2317 GET_INFO_BOTH(finfo3,pinfo3);
2318 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2321 * the close updates the write time to the time of the close
2322 * and not to the time of the last write!
2324 torture_comment(tctx, "Close the file handle\n");
2325 smbcli_close(cli->tree, fnum1);
2328 GET_INFO_PATH(pinfo4);
2329 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2331 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2332 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2337 smbcli_close(cli->tree, fnum1);
2338 smbcli_unlink(cli->tree, fname);
2339 smbcli_deltree(cli->tree, BASEDIR);
2344 static bool test_delayed_write_update5(struct torture_context *tctx,
2345 struct smbcli_state *cli,
2346 struct smbcli_state *cli2)
2348 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2349 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2350 const char *fname = BASEDIR "\\torture_file5.txt";
2354 struct timeval start;
2356 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2357 int normal_delay = 2000000;
2358 double sec = ((double)used_delay) / ((double)normal_delay);
2359 int msec = 1000 * sec;
2361 torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2363 if (!torture_setup_dir(cli, BASEDIR)) {
2367 torture_comment(tctx, "Open the file handle\n");
2368 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2371 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2375 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2376 finfo0.basic_info.in.file.fnum = fnum1;
2382 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2383 pinfo0.basic_info.in.file.path = fname;
2391 /* get the initial times */
2392 GET_INFO_BOTH(finfo0,pinfo0);
2395 torture_comment(tctx, "Do a write on the file handle\n");
2396 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2398 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2403 GET_INFO_BOTH(finfo1,pinfo1);
2404 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2406 torture_comment(tctx, "Set write time in the future on the file handle\n");
2407 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2408 GET_INFO_BOTH(finfo2,pinfo2);
2409 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2411 torture_comment(tctx, "Set write time in the past on the file handle\n");
2412 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2413 GET_INFO_BOTH(finfo2,pinfo2);
2414 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2416 /* make sure the 2 second delay from the first write are canceled */
2417 start = timeval_current();
2418 end = timeval_add(&start, 15 * sec, 0);
2419 while (!timeval_expired(&end)) {
2421 /* get the times after the first write */
2422 GET_INFO_BOTH(finfo3,pinfo3);
2424 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2425 double diff = timeval_elapsed(&start);
2426 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2427 "(1sec == %.2f) (wrong!)\n",
2435 GET_INFO_BOTH(finfo3,pinfo3);
2436 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2437 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2438 torture_comment(tctx, "Server did not update write_time (correct)\n");
2441 /* sure any further write doesn't update the write time */
2442 start = timeval_current();
2443 end = timeval_add(&start, 15 * sec, 0);
2444 while (!timeval_expired(&end)) {
2446 torture_comment(tctx, "Do a write on the file handle\n");
2447 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2449 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2453 /* get the times after the write */
2454 GET_INFO_BOTH(finfo4,pinfo4);
2456 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2457 double diff = timeval_elapsed(&start);
2458 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2459 "(1sec == %.2f) (wrong!)\n",
2467 GET_INFO_BOTH(finfo4,pinfo4);
2468 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2469 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2470 torture_comment(tctx, "Server did not update write_time (correct)\n");
2476 GET_INFO_BOTH(finfo5,pinfo5);
2477 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2480 * the close doesn't update the write time
2482 torture_comment(tctx, "Close the file handle\n");
2483 smbcli_close(cli->tree, fnum1);
2486 GET_INFO_PATH(pinfo6);
2487 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2489 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2490 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2495 smbcli_close(cli->tree, fnum1);
2496 smbcli_unlink(cli->tree, fname);
2497 smbcli_deltree(cli->tree, BASEDIR);
2502 static bool test_delayed_write_update5b(struct torture_context *tctx,
2503 struct smbcli_state *cli,
2504 struct smbcli_state *cli2)
2506 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2507 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2508 const char *fname = BASEDIR "\\torture_fileb.txt";
2512 struct timeval start;
2514 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2515 int normal_delay = 2000000;
2516 double sec = ((double)used_delay) / ((double)normal_delay);
2517 int msec = 1000 * sec;
2519 torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2521 if (!torture_setup_dir(cli, BASEDIR)) {
2525 torture_comment(tctx, "Open the file handle\n");
2526 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2529 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2533 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2534 finfo0.basic_info.in.file.fnum = fnum1;
2540 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2541 pinfo0.basic_info.in.file.path = fname;
2549 /* get the initial times */
2550 GET_INFO_BOTH(finfo0,pinfo0);
2553 torture_comment(tctx, "Do a write on the file handle\n");
2554 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2556 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2561 GET_INFO_BOTH(finfo1,pinfo1);
2562 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2564 torture_comment(tctx, "Set write time in the future on the file handle\n");
2565 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2566 GET_INFO_BOTH(finfo2,pinfo2);
2567 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2569 torture_comment(tctx, "Set write time in the past on the file handle\n");
2570 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2571 GET_INFO_BOTH(finfo2,pinfo2);
2572 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2574 /* make sure the 2 second delay from the first write are canceled */
2575 start = timeval_current();
2576 end = timeval_add(&start, 15 * sec, 0);
2577 while (!timeval_expired(&end)) {
2579 /* get the times after the first write */
2580 GET_INFO_BOTH(finfo3,pinfo3);
2582 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2583 double diff = timeval_elapsed(&start);
2584 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2585 "(1sec == %.2f) (wrong!)\n",
2593 GET_INFO_BOTH(finfo3,pinfo3);
2594 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2595 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2596 torture_comment(tctx, "Server did not update write_time (correct)\n");
2599 /* sure any further write (truncates) update the write time */
2600 start = timeval_current();
2601 end = timeval_add(&start, 15 * sec, 0);
2602 while (!timeval_expired(&end)) {
2604 torture_comment(tctx, "Do a truncate write on the file handle\n");
2605 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2607 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2611 /* get the times after the write */
2612 GET_INFO_BOTH(finfo4,pinfo4);
2614 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2615 double diff = timeval_elapsed(&start);
2616 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2617 "(1sec == %.2f) (wrong!)\n",
2625 GET_INFO_BOTH(finfo4,pinfo4);
2626 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2627 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2628 torture_comment(tctx, "Server did not update write_time (correct)\n");
2634 GET_INFO_BOTH(finfo5,pinfo5);
2635 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2638 * the close doesn't update the write time
2640 torture_comment(tctx, "Close the file handle\n");
2641 smbcli_close(cli->tree, fnum1);
2644 GET_INFO_PATH(pinfo6);
2645 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2647 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2648 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2653 smbcli_close(cli->tree, fnum1);
2654 smbcli_unlink(cli->tree, fname);
2655 smbcli_deltree(cli->tree, BASEDIR);
2660 static bool test_delayed_write_update6(struct torture_context *tctx,
2661 struct smbcli_state *cli,
2662 struct smbcli_state *cli2)
2664 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2665 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2666 const char *fname = BASEDIR "\\torture_file6.txt";
2671 struct timeval start;
2673 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2674 int normal_delay = 2000000;
2675 double sec = ((double)used_delay) / ((double)normal_delay);
2676 int msec = 1000 * sec;
2679 torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2681 if (!torture_setup_dir(cli, BASEDIR)) {
2685 torture_comment(tctx, "Open the file handle\n");
2686 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2689 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2694 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2695 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2698 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2703 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2704 finfo0.basic_info.in.file.fnum = fnum1;
2710 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2711 pinfo0.basic_info.in.file.path = fname;
2720 /* get the initial times */
2721 GET_INFO_BOTH(finfo0,pinfo0);
2724 torture_comment(tctx, "Do a write on the file handle\n");
2725 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2727 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2732 GET_INFO_BOTH(finfo1,pinfo1);
2733 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2735 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2736 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2737 GET_INFO_BOTH(finfo2,pinfo2);
2738 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2740 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2741 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2742 GET_INFO_BOTH(finfo2,pinfo2);
2743 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2745 /* make sure the 2 second delay from the first write are canceled */
2746 start = timeval_current();
2747 end = timeval_add(&start, 15 * sec, 0);
2748 while (!timeval_expired(&end)) {
2750 /* get the times after the first write */
2751 GET_INFO_BOTH(finfo3,pinfo3);
2753 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2754 double diff = timeval_elapsed(&start);
2755 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2756 "(1sec == %.2f) (wrong!)\n",
2764 GET_INFO_BOTH(finfo3,pinfo3);
2765 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2766 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2767 torture_comment(tctx, "Server did not update write_time (correct)\n");
2770 /* sure any further write doesn't update the write time */
2771 start = timeval_current();
2772 end = timeval_add(&start, 15 * sec, 0);
2773 while (!timeval_expired(&end)) {
2775 torture_comment(tctx, "Do a write on the file handle\n");
2776 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2778 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2782 /* get the times after the write */
2783 GET_INFO_BOTH(finfo4,pinfo4);
2785 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2786 double diff = timeval_elapsed(&start);
2787 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2788 "(1sec == %.2f) (wrong!)\n",
2796 GET_INFO_BOTH(finfo4,pinfo4);
2797 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2798 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2799 torture_comment(tctx, "Server did not update write_time (correct)\n");
2805 GET_INFO_BOTH(finfo5,pinfo5);
2806 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2809 * the close updates the write time to the time of the close
2810 * as the write time was set on the 2nd handle
2812 torture_comment(tctx, "Close the file handle\n");
2813 smbcli_close(cli->tree, fnum1);
2816 GET_INFO_PATH(pinfo6);
2817 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2819 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2820 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2823 /* keep the 2nd handle open and rerun tests */
2830 * closing the 2nd handle will cause no write time update
2831 * as the write time was explicit set on this handle
2833 torture_comment(tctx, "Close the 2nd file handle\n");
2834 smbcli_close(cli2->tree, fnum2);
2837 GET_INFO_PATH(pinfo7);
2838 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2840 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2841 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2846 smbcli_close(cli->tree, fnum1);
2848 smbcli_close(cli2->tree, fnum2);
2849 smbcli_unlink(cli->tree, fname);
2850 smbcli_deltree(cli->tree, BASEDIR);
2857 testing of delayed update of write_time
2859 struct torture_suite *torture_delay_write(void)
2861 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "DELAYWRITE");
2863 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
2864 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
2865 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate ", test_delayed_write_update1);
2866 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
2867 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
2868 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
2869 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
2870 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
2871 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
2872 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
2873 torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
2874 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
2875 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
2876 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
2877 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);