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_result(tctx, TORTURE_FAIL, "Failed to open %s", 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 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
70 torture_comment(tctx, "Initial write time %s\n",
71 nt_time_string(tctx, finfo1.basic_info.out.write_time));
73 /* 3 second delay to ensure we get past any 2 second time
74 granularity (older systems may have that) */
77 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
80 torture_result(tctx, TORTURE_FAIL,
81 "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_result(tctx, TORTURE_FAIL,
119 "Server did not update write time (wrong!)");
125 smbcli_close(cli->tree, fnum1);
126 smbcli_unlink(cli->tree, fname);
127 smbcli_deltree(cli->tree, BASEDIR);
132 static bool test_delayed_write_update1(struct torture_context *tctx, struct smbcli_state *cli)
134 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
135 const char *fname = BASEDIR "\\torture_file1.txt";
140 struct timeval start;
142 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
143 int normal_delay = 2000000;
144 double sec = ((double)used_delay) / ((double)normal_delay);
145 int msec = 1000 * sec;
148 torture_comment(tctx, "\nRunning test_delayed_write_update1\n");
150 if (!torture_setup_dir(cli, BASEDIR)) {
154 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
156 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
160 memset(buf, 'x', 2048);
161 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
163 /* 3 second delay to ensure we get past any 2 second time
164 granularity (older systems may have that) */
167 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
168 finfo1.all_info.in.file.fnum = fnum1;
171 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
172 pinfo4.all_info.in.file.path = fname;
174 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
176 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
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_result(tctx, TORTURE_FAIL,
186 "write failed - wrote %d bytes (%s)\n",
187 (int)written, __location__);
191 start = timeval_current();
192 end = timeval_add(&start, (120*sec), 0);
193 while (!timeval_expired(&end)) {
194 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
196 if (!NT_STATUS_IS_OK(status)) {
197 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
202 if (finfo2.all_info.out.size != 1024) {
203 torture_result(tctx, TORTURE_FAIL,
204 "file not truncated, size = %u (should be 1024)",
205 (unsigned int)finfo2.all_info.out.size);
210 torture_comment(tctx, "write time %s\n",
211 nt_time_string(tctx, finfo2.all_info.out.write_time));
212 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
213 double diff = timeval_elapsed(&start);
214 if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
215 torture_comment(tctx, "After SMBwrite truncate "
216 "server updated write_time after %.2f seconds"
217 "(1 sec == %.2f)(wrong!)\n",
223 torture_comment(tctx, "After SMBwrite truncate "
224 "server updated write_time after %.2f seconds"
225 "(1 sec == %.2f)(correct)\n",
233 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
234 torture_result(tctx, TORTURE_FAIL,
235 "Server did not update write time (wrong!)");
239 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
240 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
243 torture_result(tctx, TORTURE_FAIL,
244 "write failed - wrote %d bytes (%s)",
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_result(tctx, TORTURE_FAIL,
283 "Server updated write time (wrong!)");
287 /* the close should trigger an write time update */
288 smbcli_close(cli->tree, fnum1);
291 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
292 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
294 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
295 torture_result(tctx, TORTURE_FAIL,
296 "Server did not update write time on close (wrong!)");
298 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
299 torture_comment(tctx, "Server updated write time on close (correct)\n");
303 smbcli_close(cli->tree, fnum1);
304 smbcli_unlink(cli->tree, fname);
305 smbcli_deltree(cli->tree, BASEDIR);
310 /* Updating with a SMBwrite of zero length
311 * changes the write time immediately - even on expand. */
313 static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
315 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
316 const char *fname = BASEDIR "\\torture_file1a.txt";
321 struct timeval start;
323 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
324 int normal_delay = 2000000;
325 double sec = ((double)used_delay) / ((double)normal_delay);
326 int msec = 1000 * sec;
329 torture_comment(tctx, "\nRunning test_delayed_write_update1a\n");
331 if (!torture_setup_dir(cli, BASEDIR)) {
335 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
337 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
341 memset(buf, 'x', 2048);
342 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
344 /* 3 second delay to ensure we get past any 2 second time
345 granularity (older systems may have that) */
348 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
349 finfo1.all_info.in.file.fnum = fnum1;
352 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
353 pinfo4.all_info.in.file.path = fname;
355 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
357 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
359 torture_comment(tctx, "Initial write time %s\n",
360 nt_time_string(tctx, finfo1.all_info.out.write_time));
362 /* Do a zero length SMBwrite call to truncate. */
363 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
366 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)",
367 (int)written, __location__);
371 start = timeval_current();
372 end = timeval_add(&start, (120*sec), 0);
373 while (!timeval_expired(&end)) {
374 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
376 if (!NT_STATUS_IS_OK(status)) {
377 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
383 if (finfo2.all_info.out.size != 10240) {
384 torture_result(tctx, TORTURE_FAIL,
385 "file not truncated, size = %u (should be 10240)",
386 (unsigned int)finfo2.all_info.out.size);
391 torture_comment(tctx, "write time %s\n",
392 nt_time_string(tctx, finfo2.all_info.out.write_time));
393 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
394 double diff = timeval_elapsed(&start);
395 if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
396 torture_comment(tctx, "After SMBwrite truncate "
397 "server updated write_time after %.2f seconds"
398 "(1 sec == %.2f)(wrong!)\n",
404 torture_comment(tctx, "After SMBwrite truncate "
405 "server updated write_time after %.2f seconds"
406 "(1 sec == %.2f)(correct)\n",
414 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
415 torture_result(tctx, TORTURE_FAIL,
416 "Server did not update write time (wrong!)");
420 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
421 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
423 torture_assert_int_equal(tctx, written, 1,
424 "unexpected number of bytes written");
426 start = timeval_current();
427 end = timeval_add(&start, (10*sec), 0);
428 while (!timeval_expired(&end)) {
429 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
431 if (!NT_STATUS_IS_OK(status)) {
432 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s\n",
438 if (finfo3.all_info.out.size != 10240) {
439 torture_result(tctx, TORTURE_FAIL,
440 "file not truncated, size = %u (should be 10240)",
441 (unsigned int)finfo3.all_info.out.size);
446 torture_comment(tctx, "write time %s\n",
447 nt_time_string(tctx, finfo3.all_info.out.write_time));
448 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
449 double diff = timeval_elapsed(&start);
451 torture_comment(tctx, "server updated write_time after %.2f seconds"
452 "(1 sec == %.2f)(correct)\n",
460 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
461 torture_result(tctx, TORTURE_FAIL,
462 "Server updated write time (wrong!)");
466 /* the close should trigger an write time update */
467 smbcli_close(cli->tree, fnum1);
470 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
471 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
473 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
474 torture_result(tctx, TORTURE_FAIL,
475 "Server did not update write time on close (wrong!)");
477 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
478 torture_comment(tctx, "Server updated write time on close (correct)\n");
482 smbcli_close(cli->tree, fnum1);
483 smbcli_unlink(cli->tree, fname);
484 smbcli_deltree(cli->tree, BASEDIR);
489 /* Updating with a SET_FILE_END_OF_FILE_INFO
490 * changes the write time immediately - even on expand. */
492 static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
494 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
495 const char *fname = BASEDIR "\\torture_file1b.txt";
500 struct timeval start;
502 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
503 int normal_delay = 2000000;
504 double sec = ((double)used_delay) / ((double)normal_delay);
505 int msec = 1000 * sec;
508 torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
510 if (!torture_setup_dir(cli, BASEDIR)) {
514 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
516 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
520 memset(buf, 'x', 2048);
521 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
523 /* 3 second delay to ensure we get past any 2 second time
524 granularity (older systems may have that) */
527 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
528 finfo1.all_info.in.file.fnum = fnum1;
531 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
532 pinfo4.all_info.in.file.path = fname;
534 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
536 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
538 torture_comment(tctx, "Initial write time %s\n",
539 nt_time_string(tctx, finfo1.all_info.out.write_time));
541 /* Do a SET_END_OF_FILE_INFO call to truncate. */
542 status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
544 torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
546 start = timeval_current();
547 end = timeval_add(&start, (120*sec), 0);
548 while (!timeval_expired(&end)) {
549 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
551 if (!NT_STATUS_IS_OK(status)) {
552 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
557 if (finfo2.all_info.out.size != 10240) {
558 torture_result(tctx, TORTURE_FAIL,
559 "file not truncated (size = %u, should be 10240)",
560 (unsigned int)finfo2.all_info.out.size );
565 torture_comment(tctx, "write time %s\n",
566 nt_time_string(tctx, finfo2.all_info.out.write_time));
567 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
568 double diff = timeval_elapsed(&start);
569 if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
570 torture_result(tctx, TORTURE_FAIL,
571 "After SET_END_OF_FILE truncate "
572 "server updated write_time after %.2f seconds"
573 "(1 sec == %.2f)(wrong!)",
579 torture_comment(tctx, "After SET_END_OF_FILE truncate "
580 "server updated write_time after %.2f seconds"
581 "(1 sec == %.2f)(correct)\n",
589 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
590 torture_result(tctx, TORTURE_FAIL,
591 "Server did not update write time (wrong!)");
595 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
596 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
598 torture_assert_int_equal(tctx, written, 1,
599 "unexpected number of bytes written");
601 start = timeval_current();
602 end = timeval_add(&start, (10*sec), 0);
603 while (!timeval_expired(&end)) {
604 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
606 if (!NT_STATUS_IS_OK(status)) {
607 torture_result(tctx, TORTURE_FAIL,
608 "fileinfo failed: %s", nt_errstr(status));
613 if (finfo3.all_info.out.size != 10240) {
614 DEBUG(0, ("file not truncated (size = %u, should be 10240)\n",
615 (unsigned int)finfo3.all_info.out.size ));
620 torture_comment(tctx, "write time %s\n",
621 nt_time_string(tctx, finfo3.all_info.out.write_time));
622 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
623 double diff = timeval_elapsed(&start);
625 torture_comment(tctx, "server updated write_time after %.2f seconds"
626 "(1 sec == %.2f)(correct)\n",
634 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
635 torture_result(tctx, TORTURE_FAIL, "Server updated write time (wrong!)\n");
639 /* the close should trigger an write time update */
640 smbcli_close(cli->tree, fnum1);
643 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
644 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
646 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
647 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
649 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
650 torture_comment(tctx, "Server updated write time on close (correct)\n");
654 smbcli_close(cli->tree, fnum1);
655 smbcli_unlink(cli->tree, fname);
656 smbcli_deltree(cli->tree, BASEDIR);
661 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
663 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
665 union smb_setfileinfo parms;
666 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
667 const char *fname = BASEDIR "\\torture_file1c.txt";
672 struct timeval start;
674 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
675 int normal_delay = 2000000;
676 double sec = ((double)used_delay) / ((double)normal_delay);
677 int msec = 1000 * sec;
680 torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
682 if (!torture_setup_dir(cli, BASEDIR)) {
686 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
688 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
692 memset(buf, 'x', 2048);
693 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
695 /* 3 second delay to ensure we get past any 2 second time
696 granularity (older systems may have that) */
699 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
700 finfo1.all_info.in.file.fnum = fnum1;
703 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
704 pinfo4.all_info.in.file.path = fname;
706 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
708 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
710 torture_comment(tctx, "Initial write time %s\n",
711 nt_time_string(tctx, finfo1.all_info.out.write_time));
713 /* Do a SET_ALLOCATION_SIZE call to truncate. */
714 parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
715 parms.allocation_info.in.file.fnum = fnum1;
716 parms.allocation_info.in.alloc_size = 0;
718 status = smb_raw_setfileinfo(cli->tree, &parms);
720 torture_assert_ntstatus_ok(tctx, status,
721 "RAW_SFILEINFO_ALLOCATION_INFO failed");
723 start = timeval_current();
724 end = timeval_add(&start, (120*sec), 0);
725 while (!timeval_expired(&end)) {
726 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
728 if (!NT_STATUS_IS_OK(status)) {
729 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
735 if (finfo2.all_info.out.size != 0) {
736 torture_result(tctx, TORTURE_FAIL,
737 "file not truncated (size = %u, should be 10240)",
738 (unsigned int)finfo2.all_info.out.size);
743 torture_comment(tctx, "write time %s\n",
744 nt_time_string(tctx, finfo2.all_info.out.write_time));
745 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
746 double diff = timeval_elapsed(&start);
747 if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
748 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
749 "server updated write_time after %.2f seconds"
750 "(1 sec == %.2f)(wrong!)\n",
756 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
757 "server updated write_time after %.2f seconds"
758 "(1 sec == %.2f)(correct)\n",
766 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
767 torture_result(tctx, TORTURE_FAIL,
768 "Server did not update write time (wrong!)");
772 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
773 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
774 torture_assert_int_equal(tctx, written, 1,
775 "Unexpected number of bytes written");
777 start = timeval_current();
778 end = timeval_add(&start, (10*sec), 0);
779 while (!timeval_expired(&end)) {
780 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
782 if (!NT_STATUS_IS_OK(status)) {
783 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
789 if (finfo3.all_info.out.size != 1) {
790 torture_result(tctx, TORTURE_FAIL, "file not expanded");
795 torture_comment(tctx, "write time %s\n",
796 nt_time_string(tctx, finfo3.all_info.out.write_time));
797 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
798 double diff = timeval_elapsed(&start);
800 torture_comment(tctx, "server updated write_time after %.2f seconds"
801 "(1 sec == %.2f)(correct)\n",
809 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
810 torture_result(tctx, TORTURE_FAIL,
811 "Server updated write time (wrong!)");
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 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
822 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
823 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
825 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
826 torture_comment(tctx, "Server updated write time on close (correct)\n");
830 smbcli_close(cli->tree, fnum1);
831 smbcli_unlink(cli->tree, fname);
832 smbcli_deltree(cli->tree, BASEDIR);
838 * Do as above, but using 2 connections.
841 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
842 struct smbcli_state *cli2)
844 union smb_fileinfo finfo1, finfo2;
845 const char *fname = BASEDIR "\\torture_file.txt";
851 struct timeval start;
853 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
854 int normal_delay = 2000000;
855 double sec = ((double)used_delay) / ((double)normal_delay);
856 int msec = 1000 * sec;
857 union smb_flush flsh;
859 torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
861 if (!torture_setup_dir(cli, BASEDIR)) {
865 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
867 torture_comment(tctx, "Failed to open %s\n", fname);
871 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
872 finfo1.basic_info.in.file.fnum = fnum1;
875 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
877 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
879 torture_comment(tctx, "Initial write time %s\n",
880 nt_time_string(tctx, finfo1.basic_info.out.write_time));
882 /* 3 second delay to ensure we get past any 2 second time
883 granularity (older systems may have that) */
887 /* Try using setfileinfo instead of write to update write time. */
888 union smb_setfileinfo sfinfo;
889 time_t t_set = time(NULL);
890 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
891 sfinfo.basic_info.in.file.fnum = fnum1;
892 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
893 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
895 /* I tried this with both + and - ve to see if it makes a different.
896 It doesn't - once the filetime is set via setfileinfo it stays that way. */
898 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
900 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
902 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
903 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
905 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
907 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
910 finfo2.basic_info.in.file.path = fname;
912 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
914 if (!NT_STATUS_IS_OK(status)) {
915 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
918 torture_comment(tctx, "write time %s\n",
919 nt_time_string(tctx, finfo2.basic_info.out.write_time));
921 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
922 torture_comment(tctx, "Server updated write_time (correct)\n");
924 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
928 /* Now try a write to see if the write time gets reset. */
930 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
931 finfo1.basic_info.in.file.fnum = fnum1;
934 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
936 if (!NT_STATUS_IS_OK(status)) {
937 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
941 torture_comment(tctx, "Modified write time %s\n",
942 nt_time_string(tctx, finfo1.basic_info.out.write_time));
945 torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
947 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
950 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
951 (int)written, __location__);
955 /* Just to prove to tridge that the an smbflush has no effect on
956 the write time :-). The setfileinfo IS STICKY. JRA. */
958 torture_comment(tctx, "Doing flush after write\n");
960 flsh.flush.level = RAW_FLUSH_FLUSH;
961 flsh.flush.in.file.fnum = fnum1;
962 status = smb_raw_flush(cli->tree, &flsh);
963 if (!NT_STATUS_IS_OK(status)) {
964 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
968 /* Once the time was set using setfileinfo then it stays set - writes
969 don't have any effect. But make sure. */
970 start = timeval_current();
971 end = timeval_add(&start, (15*sec), 0);
972 while (!timeval_expired(&end)) {
973 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
975 if (!NT_STATUS_IS_OK(status)) {
976 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
980 torture_comment(tctx, "write time %s\n",
981 nt_time_string(tctx, finfo2.basic_info.out.write_time));
982 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
983 double diff = timeval_elapsed(&start);
984 torture_comment(tctx, "Server updated write_time after %.2f seconds"
985 "(1sec == %.2f) (wrong!)\n",
994 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
995 torture_comment(tctx, "Server did not update write time (correct)\n");
998 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1000 torture_comment(tctx, "Failed to open %s\n", fname);
1004 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");
1006 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
1008 if (written != 10) {
1009 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
1010 (int)written, __location__);
1014 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1016 if (!NT_STATUS_IS_OK(status)) {
1017 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1020 torture_comment(tctx, "write time %s\n",
1021 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1022 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1023 torture_comment(tctx, "Server updated write_time (wrong!)\n");
1027 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
1028 smbcli_close(cli->tree, fnum1);
1031 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");
1033 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
1035 if (written != 10) {
1036 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
1037 (int)written, __location__);
1041 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1042 finfo1.basic_info.in.file.fnum = fnum2;
1044 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1046 if (!NT_STATUS_IS_OK(status)) {
1047 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1050 torture_comment(tctx, "write time %s\n",
1051 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1052 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1053 torture_comment(tctx, "Server updated write_time (wrong!)\n");
1057 /* Once the time was set using setfileinfo then it stays set - writes
1058 don't have any effect. But make sure. */
1059 start = timeval_current();
1060 end = timeval_add(&start, (15*sec), 0);
1061 while (!timeval_expired(&end)) {
1062 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1064 if (!NT_STATUS_IS_OK(status)) {
1065 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1069 torture_comment(tctx, "write time %s\n",
1070 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1071 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1072 double diff = timeval_elapsed(&start);
1073 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1074 "(1sec == %.2f) (wrong!)\n",
1083 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1084 torture_comment(tctx, "Server did not update write time (correct)\n");
1087 torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1089 smbcli_close(cli->tree, fnum2);
1092 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1094 torture_comment(tctx, "Failed to open %s\n", fname);
1098 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1099 finfo1.basic_info.in.file.fnum = fnum1;
1102 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1104 if (!NT_STATUS_IS_OK(status)) {
1105 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1109 torture_comment(tctx, "Second open initial write time %s\n",
1110 nt_time_string(tctx, finfo1.basic_info.out.write_time));
1113 torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1115 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1117 if (written != 10) {
1118 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
1119 (int)written, __location__);
1123 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1124 finfo1.basic_info.in.file.fnum = fnum1;
1126 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1128 if (!NT_STATUS_IS_OK(status)) {
1129 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1132 torture_comment(tctx, "write time %s\n",
1133 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1134 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1135 torture_comment(tctx, "Server updated write_time (wrong!)\n");
1139 /* Now the write time should be updated again */
1140 start = timeval_current();
1141 end = timeval_add(&start, (15*sec), 0);
1142 while (!timeval_expired(&end)) {
1143 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1145 if (!NT_STATUS_IS_OK(status)) {
1146 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1150 torture_comment(tctx, "write time %s\n",
1151 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1152 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1153 double diff = timeval_elapsed(&start);
1154 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1155 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1156 "(1sec == %.2f) (wrong!)\n",
1162 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1163 "(1sec == %.2f) (correct)\n",
1171 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1172 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
1177 /* One more test to do. We should read the filetime via findfirst on the
1178 second connection to ensure it's the same. This is very easy for a Windows
1179 server but a bastard to get right on a POSIX server. JRA. */
1182 smbcli_close(cli->tree, fnum1);
1183 smbcli_unlink(cli->tree, fname);
1184 smbcli_deltree(cli->tree, BASEDIR);
1190 /* Windows does obviously not update the stat info during a write call. I
1191 * *think* this is the problem causing a spurious Excel 2003 on XP error
1192 * message when saving a file. Excel does a setfileinfo, writes, and then does
1193 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1194 * that the file might have been changed in between. What i've been able to
1195 * trace down is that this happens if the getpathinfo after the write shows a
1196 * different last write time than the setfileinfo showed. This is really
1200 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
1201 struct smbcli_state *cli2)
1203 union smb_fileinfo finfo1, finfo2;
1204 const char *fname = BASEDIR "\\torture_file.txt";
1210 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1211 int normal_delay = 2000000;
1212 double sec = ((double)used_delay) / ((double)normal_delay);
1213 int msec = 1000 * sec;
1215 torture_comment(tctx, "\nRunning test_finfo_after_write\n");
1217 if (!torture_setup_dir(cli, BASEDIR)) {
1221 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1224 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1228 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1229 finfo1.basic_info.in.file.fnum = fnum1;
1231 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1233 if (!NT_STATUS_IS_OK(status)) {
1235 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1241 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1244 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1249 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1251 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1252 smbcli_errstr(cli2->tree));
1257 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1260 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1266 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1267 finfo2.basic_info.in.file.path = fname;
1269 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1271 if (!NT_STATUS_IS_OK(status)) {
1272 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
1278 if (finfo1.basic_info.out.create_time !=
1279 finfo2.basic_info.out.create_time) {
1280 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1285 if (finfo1.basic_info.out.access_time !=
1286 finfo2.basic_info.out.access_time) {
1287 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1292 if (finfo1.basic_info.out.write_time !=
1293 finfo2.basic_info.out.write_time) {
1294 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1295 "write time conn 1 = %s, conn 2 = %s",
1296 nt_time_string(tctx, finfo1.basic_info.out.write_time),
1297 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1302 if (finfo1.basic_info.out.change_time !=
1303 finfo2.basic_info.out.change_time) {
1304 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1309 /* One of the two following calls updates the qpathinfo. */
1311 /* If you had skipped the smbcli_write on fnum2, it would
1312 * *not* have updated the stat on disk */
1314 smbcli_close(cli2->tree, fnum2);
1317 /* This call is only for the people looking at ethereal :-) */
1318 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1319 finfo2.basic_info.in.file.path = fname;
1321 status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1323 if (!NT_STATUS_IS_OK(status)) {
1324 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1331 smbcli_close(cli->tree, fnum1);
1332 smbcli_unlink(cli->tree, fname);
1333 smbcli_deltree(cli->tree, BASEDIR);
1338 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1339 uint64_t r = 10*1000*1000; \
1340 NTTIME g = (given).basic_info.out.write_time; \
1341 NTTIME gr = (g / r) * r; \
1342 NTTIME c = (correct).basic_info.out.write_time; \
1343 NTTIME cr = (c / r) * r; \
1344 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1346 if (strict && (g cmp c)) { \
1348 } else if ((g cmp c) && (gr cmp cr)) { \
1349 /* handle filesystem without high resolution timestamps */ \
1353 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1354 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1355 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1360 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1361 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1362 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1363 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1364 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1365 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1367 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1368 NTTIME g = (given).basic_info.out.access_time; \
1369 NTTIME c = (correct).basic_info.out.access_time; \
1371 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1372 #given, nt_time_string(tctx, g), \
1373 #cmp, #correct, nt_time_string(tctx, c)); \
1378 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1379 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1381 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1382 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1383 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1386 #define GET_INFO_FILE(finfo) do { \
1388 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1389 if (!NT_STATUS_IS_OK(_status)) { \
1391 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1392 nt_errstr(_status)); \
1395 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1396 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1397 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1399 #define GET_INFO_PATH(pinfo) do { \
1401 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1402 if (!NT_STATUS_IS_OK(_status)) { \
1403 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1404 nt_errstr(_status)); \
1408 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1409 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1410 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1412 #define GET_INFO_BOTH(finfo,pinfo) do { \
1413 GET_INFO_FILE(finfo); \
1414 GET_INFO_PATH(pinfo); \
1415 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1418 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1420 union smb_setfileinfo sfinfo; \
1421 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1422 sfinfo.basic_info.in.file.fnum = tfnum; \
1423 sfinfo.basic_info.in.create_time = 0; \
1424 sfinfo.basic_info.in.access_time = 0; \
1425 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1426 sfinfo.basic_info.in.change_time = 0; \
1427 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1428 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1429 if (!NT_STATUS_IS_OK(_status)) { \
1430 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1431 nt_errstr(_status)); \
1436 #define SET_INFO_FILE(finfo, wrtime) \
1437 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1439 static bool test_delayed_write_update3(struct torture_context *tctx,
1440 struct smbcli_state *cli,
1441 struct smbcli_state *cli2)
1443 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1444 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1445 const char *fname = BASEDIR "\\torture_file3.txt";
1449 struct timeval start;
1451 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1452 int normal_delay = 2000000;
1453 double sec = ((double)used_delay) / ((double)normal_delay);
1454 int msec = 1000 * sec;
1456 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
1458 if (!torture_setup_dir(cli, BASEDIR)) {
1462 torture_comment(tctx, "Open the file handle\n");
1463 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1466 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1470 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1471 finfo0.basic_info.in.file.fnum = fnum1;
1476 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1477 pinfo0.basic_info.in.file.path = fname;
1484 /* get the initial times */
1485 GET_INFO_BOTH(finfo0,pinfo0);
1488 * make sure the write time is updated 2 seconds later
1489 * calcuated from the first write
1490 * (but expect upto 5 seconds extra time for a busy server)
1492 start = timeval_current();
1493 end = timeval_add(&start, 7 * sec, 0);
1494 while (!timeval_expired(&end)) {
1496 torture_comment(tctx, "Do a write on the file handle\n");
1497 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1499 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1503 /* get the times after the write */
1504 GET_INFO_FILE(finfo1);
1506 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1507 double diff = timeval_elapsed(&start);
1508 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1509 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1510 "(1sec == %.2f) (wrong!)\n",
1516 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1517 "(1sec == %.2f) (correct)\n",
1524 GET_INFO_BOTH(finfo1,pinfo1);
1525 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1527 /* sure any further write doesn't update the write time */
1528 start = timeval_current();
1529 end = timeval_add(&start, 15 * sec, 0);
1530 while (!timeval_expired(&end)) {
1532 torture_comment(tctx, "Do a write on the file handle\n");
1533 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1535 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1539 /* get the times after the write */
1540 GET_INFO_BOTH(finfo2,pinfo2);
1542 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1543 double diff = timeval_elapsed(&start);
1544 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1545 "(1sec == %.2f) (wrong!)\n",
1553 GET_INFO_BOTH(finfo2,pinfo2);
1554 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1555 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1556 torture_comment(tctx, "Server did not update write_time (correct)\n");
1562 GET_INFO_BOTH(finfo3,pinfo3);
1563 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1566 * the close updates the write time to the time of the close
1567 * and not to the time of the last write!
1569 torture_comment(tctx, "Close the file handle\n");
1570 smbcli_close(cli->tree, fnum1);
1573 GET_INFO_PATH(pinfo4);
1574 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1576 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1577 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1582 smbcli_close(cli->tree, fnum1);
1583 smbcli_unlink(cli->tree, fname);
1584 smbcli_deltree(cli->tree, BASEDIR);
1590 * Show that a truncate write always updates the write time even
1591 * if an initial write has already updated the write time.
1594 static bool test_delayed_write_update3a(struct torture_context *tctx,
1595 struct smbcli_state *cli,
1596 struct smbcli_state *cli2)
1598 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1599 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1600 const char *fname = BASEDIR "\\torture_file3a.txt";
1605 struct timeval start;
1607 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1608 int normal_delay = 2000000;
1609 double sec = ((double)used_delay) / ((double)normal_delay);
1610 int msec = 1000 * sec;
1612 torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
1614 if (!torture_setup_dir(cli, BASEDIR)) {
1618 torture_comment(tctx, "Open the file handle\n");
1619 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1622 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1626 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1627 finfo0.basic_info.in.file.fnum = fnum1;
1632 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1633 pinfo0.basic_info.in.file.path = fname;
1640 /* get the initial times */
1641 GET_INFO_BOTH(finfo0,pinfo0);
1644 * sleep some time, to demonstrate the handling of write times
1645 * doesn't depend on the time since the open
1649 /* get the initial times */
1650 GET_INFO_BOTH(finfo1,pinfo1);
1651 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1654 * make sure the write time is updated 2 seconds later
1655 * calcuated from the first write
1656 * (but expect upto 5 seconds extra time for a busy server)
1658 start = timeval_current();
1659 end = timeval_add(&start, 7 * sec, 0);
1660 while (!timeval_expired(&end)) {
1662 torture_comment(tctx, "Do a write on the file handle\n");
1663 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1665 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1669 /* get the times after the write */
1670 GET_INFO_FILE(finfo1);
1672 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1673 double diff = timeval_elapsed(&start);
1674 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1675 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1676 "(1sec == %.2f) (wrong!)\n",
1682 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1683 "(1sec == %.2f) (correct)\n",
1690 GET_INFO_BOTH(finfo1,pinfo1);
1691 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1694 * demonstrate that a truncate write always
1695 * updates the write time immediately
1697 for (i=0; i < 3; i++) {
1700 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1701 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1703 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1707 /* get the times after the write */
1708 GET_INFO_BOTH(finfo2,pinfo2);
1709 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1713 /* sure any further write doesn't update the write time */
1714 start = timeval_current();
1715 end = timeval_add(&start, 15 * sec, 0);
1716 while (!timeval_expired(&end)) {
1718 torture_comment(tctx, "Do a write on the file handle\n");
1719 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1721 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1725 /* get the times after the write */
1726 GET_INFO_BOTH(finfo2,pinfo2);
1728 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1729 double diff = timeval_elapsed(&start);
1730 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1731 "(1sec == %.2f) (wrong!)\n",
1739 GET_INFO_BOTH(finfo2,pinfo2);
1740 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1741 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1742 torture_comment(tctx, "Server did not update write_time (correct)\n");
1748 /* get the initial times */
1749 GET_INFO_BOTH(finfo1,pinfo1);
1750 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1753 * demonstrate that a truncate write always
1754 * updates the write time immediately
1756 for (i=0; i < 3; i++) {
1759 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1760 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1762 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1766 /* get the times after the write */
1767 GET_INFO_BOTH(finfo2,pinfo2);
1768 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1775 GET_INFO_BOTH(finfo3,pinfo3);
1776 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1779 * the close doesn't update the write time
1781 torture_comment(tctx, "Close the file handle\n");
1782 smbcli_close(cli->tree, fnum1);
1785 GET_INFO_PATH(pinfo4);
1786 COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1788 if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1789 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1794 smbcli_close(cli->tree, fnum1);
1795 smbcli_unlink(cli->tree, fname);
1796 smbcli_deltree(cli->tree, BASEDIR);
1802 * Show a close after write updates the write timestamp to
1803 * the close time, not the last write time.
1806 static bool test_delayed_write_update3b(struct torture_context *tctx,
1807 struct smbcli_state *cli,
1808 struct smbcli_state *cli2)
1810 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1811 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1812 const char *fname = BASEDIR "\\torture_file3b.txt";
1816 struct timeval start;
1818 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1819 int normal_delay = 2000000;
1820 double sec = ((double)used_delay) / ((double)normal_delay);
1821 int msec = 1000 * sec;
1823 torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
1825 if (!torture_setup_dir(cli, BASEDIR)) {
1829 torture_comment(tctx, "Open the file handle\n");
1830 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1833 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1837 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1838 finfo0.basic_info.in.file.fnum = fnum1;
1843 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1844 pinfo0.basic_info.in.file.path = fname;
1851 /* get the initial times */
1852 GET_INFO_BOTH(finfo0,pinfo0);
1855 * sleep some time, to demonstrate the handling of write times
1856 * doesn't depend on the time since the open
1860 /* get the initial times */
1861 GET_INFO_BOTH(finfo1,pinfo1);
1862 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1865 * make sure the write time is updated 2 seconds later
1866 * calcuated from the first write
1867 * (but expect upto 5 seconds extra time for a busy server)
1869 start = timeval_current();
1870 end = timeval_add(&start, 7 * sec, 0);
1871 while (!timeval_expired(&end)) {
1873 torture_comment(tctx, "Do a write on the file handle\n");
1874 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1876 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1880 /* get the times after the write */
1881 GET_INFO_FILE(finfo1);
1883 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1884 double diff = timeval_elapsed(&start);
1885 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1886 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1887 "(1sec == %.2f) (wrong!)\n",
1893 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1894 "(1sec == %.2f) (correct)\n",
1901 GET_INFO_BOTH(finfo1,pinfo1);
1902 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1904 /* sure any further write doesn't update the write time */
1905 start = timeval_current();
1906 end = timeval_add(&start, 15 * sec, 0);
1907 while (!timeval_expired(&end)) {
1909 torture_comment(tctx, "Do a write on the file handle\n");
1910 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1912 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1916 /* get the times after the write */
1917 GET_INFO_BOTH(finfo2,pinfo2);
1919 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1920 double diff = timeval_elapsed(&start);
1921 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1922 "(1sec == %.2f) (wrong!)\n",
1930 GET_INFO_BOTH(finfo2,pinfo2);
1931 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1932 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1933 torture_comment(tctx, "Server did not update write_time (correct)\n");
1939 GET_INFO_BOTH(finfo3,pinfo3);
1940 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1943 * the close updates the write time to the time of the close
1944 * and not to the time of the last write!
1946 torture_comment(tctx, "Close the file handle\n");
1947 smbcli_close(cli->tree, fnum1);
1950 GET_INFO_PATH(pinfo4);
1951 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1953 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1954 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1959 smbcli_close(cli->tree, fnum1);
1960 smbcli_unlink(cli->tree, fname);
1961 smbcli_deltree(cli->tree, BASEDIR);
1967 * Check that a write after a truncate write doesn't update
1968 * the timestamp, but a truncate write after a write does.
1969 * Also prove that a close after a truncate write updates the
1970 * timestamp to current, not the time of last write.
1973 static bool test_delayed_write_update3c(struct torture_context *tctx,
1974 struct smbcli_state *cli,
1975 struct smbcli_state *cli2)
1977 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1978 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1979 const char *fname = BASEDIR "\\torture_file3c.txt";
1984 struct timeval start;
1986 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1987 int normal_delay = 2000000;
1988 double sec = ((double)used_delay) / ((double)normal_delay);
1989 int msec = 1000 * sec;
1991 torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
1993 if (!torture_setup_dir(cli, BASEDIR)) {
1997 torture_comment(tctx, "Open the file handle\n");
1998 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2001 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2005 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2006 finfo0.basic_info.in.file.fnum = fnum1;
2011 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2012 pinfo0.basic_info.in.file.path = fname;
2019 /* get the initial times */
2020 GET_INFO_BOTH(finfo0,pinfo0);
2023 * sleep some time, to demonstrate the handling of write times
2024 * doesn't depend on the time since the open
2028 /* get the initial times */
2029 GET_INFO_BOTH(finfo1,pinfo1);
2030 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2033 * demonstrate that a truncate write always
2034 * updates the write time immediately
2036 for (i=0; i < 3; i++) {
2039 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
2040 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2042 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2046 /* get the times after the write */
2047 GET_INFO_BOTH(finfo2,pinfo2);
2048 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2052 start = timeval_current();
2053 end = timeval_add(&start, 7 * sec, 0);
2054 while (!timeval_expired(&end)) {
2056 torture_comment(tctx, "Do a write on the file handle\n");
2057 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2059 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2063 /* get the times after the write */
2064 GET_INFO_FILE(finfo2);
2066 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2067 double diff = timeval_elapsed(&start);
2068 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2069 "(1sec == %.2f) (wrong!)\n",
2077 GET_INFO_BOTH(finfo2,pinfo2);
2078 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2079 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2080 torture_comment(tctx, "Server did not update write_time (correct)\n");
2086 /* get the initial times */
2087 GET_INFO_BOTH(finfo1,pinfo1);
2088 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2091 * demonstrate that a truncate write always
2092 * updates the write time immediately
2094 for (i=0; i < 3; i++) {
2097 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2098 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2100 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2104 /* get the times after the write */
2105 GET_INFO_BOTH(finfo2,pinfo2);
2106 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2113 GET_INFO_BOTH(finfo2,pinfo2);
2114 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2116 /* sure any further write doesn't update the write time */
2117 start = timeval_current();
2118 end = timeval_add(&start, 15 * sec, 0);
2119 while (!timeval_expired(&end)) {
2121 torture_comment(tctx, "Do a write on the file handle\n");
2122 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2124 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2128 /* get the times after the write */
2129 GET_INFO_BOTH(finfo2,pinfo2);
2131 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2132 double diff = timeval_elapsed(&start);
2133 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2134 "(1sec == %.2f) (wrong!)\n",
2142 GET_INFO_BOTH(finfo2,pinfo2);
2143 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2144 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2145 torture_comment(tctx, "Server did not update write_time (correct)\n");
2151 GET_INFO_BOTH(finfo3,pinfo3);
2152 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2155 * the close updates the write time to the time of the close
2156 * and not to the time of the last write!
2158 torture_comment(tctx, "Close the file handle\n");
2159 smbcli_close(cli->tree, fnum1);
2162 GET_INFO_PATH(pinfo4);
2163 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2165 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2166 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2171 smbcli_close(cli->tree, fnum1);
2172 smbcli_unlink(cli->tree, fname);
2173 smbcli_deltree(cli->tree, BASEDIR);
2179 * Show only the first write updates the timestamp, and a close
2180 * after writes updates to current (I think this is the same
2184 static bool test_delayed_write_update4(struct torture_context *tctx,
2185 struct smbcli_state *cli,
2186 struct smbcli_state *cli2)
2188 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
2189 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
2190 const char *fname = BASEDIR "\\torture_file4.txt";
2194 struct timeval start;
2196 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2197 int normal_delay = 2000000;
2198 double sec = ((double)used_delay) / ((double)normal_delay);
2199 int msec = 1000 * sec;
2201 torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2203 if (!torture_setup_dir(cli, BASEDIR)) {
2207 torture_comment(tctx, "Open the file handle\n");
2208 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2211 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2215 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2216 finfo0.basic_info.in.file.fnum = fnum1;
2221 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2222 pinfo0.basic_info.in.file.path = fname;
2229 /* get the initial times */
2230 GET_INFO_BOTH(finfo0,pinfo0);
2236 torture_comment(tctx, "Do a write on the file handle\n");
2237 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2239 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2244 GET_INFO_BOTH(finfo1,pinfo1);
2245 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2248 * make sure the write time is updated 2 seconds later
2249 * calcuated from the first write
2250 * (but expect upto 3 seconds extra time for a busy server)
2252 start = timeval_current();
2253 end = timeval_add(&start, 5 * sec, 0);
2254 while (!timeval_expired(&end)) {
2255 /* get the times after the first write */
2256 GET_INFO_FILE(finfo1);
2258 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2259 double diff = timeval_elapsed(&start);
2260 if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
2261 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2262 "(1sec == %.2f) (wrong!)\n",
2268 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2269 "(1sec == %.2f) (correct)\n",
2276 GET_INFO_BOTH(finfo1,pinfo1);
2277 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2279 /* sure any further write doesn't update the write time */
2280 start = timeval_current();
2281 end = timeval_add(&start, 15 * sec, 0);
2282 while (!timeval_expired(&end)) {
2284 torture_comment(tctx, "Do a write on the file handle\n");
2285 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2287 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2291 /* get the times after the write */
2292 GET_INFO_BOTH(finfo2,pinfo2);
2294 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2295 double diff = timeval_elapsed(&start);
2296 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2297 "(1sec == %.2f) (wrong!)\n",
2305 GET_INFO_BOTH(finfo2,pinfo2);
2306 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2307 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2308 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2314 GET_INFO_BOTH(finfo3,pinfo3);
2315 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2318 * the close updates the write time to the time of the close
2319 * and not to the time of the last write!
2321 torture_comment(tctx, "Close the file handle\n");
2322 smbcli_close(cli->tree, fnum1);
2325 GET_INFO_PATH(pinfo4);
2326 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2328 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2329 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2334 smbcli_close(cli->tree, fnum1);
2335 smbcli_unlink(cli->tree, fname);
2336 smbcli_deltree(cli->tree, BASEDIR);
2342 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2345 static bool test_delayed_write_update5(struct torture_context *tctx,
2346 struct smbcli_state *cli,
2347 struct smbcli_state *cli2)
2349 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2350 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2351 const char *fname = BASEDIR "\\torture_file5.txt";
2355 struct timeval start;
2357 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2358 int normal_delay = 2000000;
2359 double sec = ((double)used_delay) / ((double)normal_delay);
2360 int msec = 1000 * sec;
2362 torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2364 if (!torture_setup_dir(cli, BASEDIR)) {
2368 torture_comment(tctx, "Open the file handle\n");
2369 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2372 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2376 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2377 finfo0.basic_info.in.file.fnum = fnum1;
2383 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2384 pinfo0.basic_info.in.file.path = fname;
2392 /* get the initial times */
2393 GET_INFO_BOTH(finfo0,pinfo0);
2396 torture_comment(tctx, "Do a write on the file handle\n");
2397 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2399 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2404 GET_INFO_BOTH(finfo1,pinfo1);
2405 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2407 torture_comment(tctx, "Set write time in the future on the file handle\n");
2408 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2409 GET_INFO_BOTH(finfo2,pinfo2);
2410 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2412 torture_comment(tctx, "Set write time in the past on the file handle\n");
2413 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2414 GET_INFO_BOTH(finfo2,pinfo2);
2415 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2417 /* make sure the 2 second delay from the first write are canceled */
2418 start = timeval_current();
2419 end = timeval_add(&start, 15 * sec, 0);
2420 while (!timeval_expired(&end)) {
2422 /* get the times after the first write */
2423 GET_INFO_BOTH(finfo3,pinfo3);
2425 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2426 double diff = timeval_elapsed(&start);
2427 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2428 "(1sec == %.2f) (wrong!)\n",
2436 GET_INFO_BOTH(finfo3,pinfo3);
2437 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2438 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2439 torture_comment(tctx, "Server did not update write_time (correct)\n");
2442 /* sure any further write doesn't update the write time */
2443 start = timeval_current();
2444 end = timeval_add(&start, 15 * sec, 0);
2445 while (!timeval_expired(&end)) {
2447 torture_comment(tctx, "Do a write on the file handle\n");
2448 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2450 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2454 /* get the times after the write */
2455 GET_INFO_BOTH(finfo4,pinfo4);
2457 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2458 double diff = timeval_elapsed(&start);
2459 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2460 "(1sec == %.2f) (wrong!)\n",
2468 GET_INFO_BOTH(finfo4,pinfo4);
2469 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2470 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2471 torture_comment(tctx, "Server did not update write_time (correct)\n");
2477 GET_INFO_BOTH(finfo5,pinfo5);
2478 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2481 * the close doesn't update the write time
2483 torture_comment(tctx, "Close the file handle\n");
2484 smbcli_close(cli->tree, fnum1);
2487 GET_INFO_PATH(pinfo6);
2488 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2490 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2491 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2496 smbcli_close(cli->tree, fnum1);
2497 smbcli_unlink(cli->tree, fname);
2498 smbcli_deltree(cli->tree, BASEDIR);
2504 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2507 static bool test_delayed_write_update5b(struct torture_context *tctx,
2508 struct smbcli_state *cli,
2509 struct smbcli_state *cli2)
2511 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2512 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2513 const char *fname = BASEDIR "\\torture_fileb.txt";
2517 struct timeval start;
2519 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2520 int normal_delay = 2000000;
2521 double sec = ((double)used_delay) / ((double)normal_delay);
2522 int msec = 1000 * sec;
2524 torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2526 if (!torture_setup_dir(cli, BASEDIR)) {
2530 torture_comment(tctx, "Open the file handle\n");
2531 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2534 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2538 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2539 finfo0.basic_info.in.file.fnum = fnum1;
2545 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2546 pinfo0.basic_info.in.file.path = fname;
2554 /* get the initial times */
2555 GET_INFO_BOTH(finfo0,pinfo0);
2558 torture_comment(tctx, "Do a write on the file handle\n");
2559 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2561 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2566 GET_INFO_BOTH(finfo1,pinfo1);
2567 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2569 torture_comment(tctx, "Set write time in the future on the file handle\n");
2570 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2571 GET_INFO_BOTH(finfo2,pinfo2);
2572 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2574 torture_comment(tctx, "Set write time in the past on the file handle\n");
2575 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2576 GET_INFO_BOTH(finfo2,pinfo2);
2577 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2579 /* make sure the 2 second delay from the first write are canceled */
2580 start = timeval_current();
2581 end = timeval_add(&start, 15 * sec, 0);
2582 while (!timeval_expired(&end)) {
2584 /* get the times after the first write */
2585 GET_INFO_BOTH(finfo3,pinfo3);
2587 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2588 double diff = timeval_elapsed(&start);
2589 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2590 "(1sec == %.2f) (wrong!)\n",
2598 GET_INFO_BOTH(finfo3,pinfo3);
2599 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2600 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2601 torture_comment(tctx, "Server did not update write_time (correct)\n");
2604 /* Do any further write (truncates) update the write time ? */
2605 start = timeval_current();
2606 end = timeval_add(&start, 15 * sec, 0);
2607 while (!timeval_expired(&end)) {
2609 torture_comment(tctx, "Do a truncate write on the file handle\n");
2610 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2612 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2616 /* get the times after the write */
2617 GET_INFO_BOTH(finfo4,pinfo4);
2619 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2620 double diff = timeval_elapsed(&start);
2621 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2622 "(1sec == %.2f) (wrong!)\n",
2630 GET_INFO_BOTH(finfo4,pinfo4);
2631 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2632 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2633 torture_comment(tctx, "Server did not update write_time (correct)\n");
2639 GET_INFO_BOTH(finfo5,pinfo5);
2640 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2643 * the close doesn't update the write time
2645 torture_comment(tctx, "Close the file handle\n");
2646 smbcli_close(cli->tree, fnum1);
2649 GET_INFO_PATH(pinfo6);
2650 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2652 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2653 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2658 smbcli_close(cli->tree, fnum1);
2659 smbcli_unlink(cli->tree, fname);
2660 smbcli_deltree(cli->tree, BASEDIR);
2666 * Open 2 handles on a file. Write one one and then set the
2667 * WRITE TIME explicitly on the other. Ensure the write time
2668 * update is cancelled. Ensure the write time is updated to
2669 * the close time when the non-explicit set handle is closed.
2673 static bool test_delayed_write_update6(struct torture_context *tctx,
2674 struct smbcli_state *cli,
2675 struct smbcli_state *cli2)
2677 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2678 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2679 const char *fname = BASEDIR "\\torture_file6.txt";
2684 struct timeval start;
2686 int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2687 int normal_delay = 2000000;
2688 double sec = ((double)used_delay) / ((double)normal_delay);
2689 int msec = 1000 * sec;
2692 torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2694 if (!torture_setup_dir(cli, BASEDIR)) {
2698 torture_comment(tctx, "Open the file handle\n");
2699 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2702 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2707 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2708 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2711 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2716 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2717 finfo0.basic_info.in.file.fnum = fnum1;
2723 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2724 pinfo0.basic_info.in.file.path = fname;
2733 /* get the initial times */
2734 GET_INFO_BOTH(finfo0,pinfo0);
2737 torture_comment(tctx, "Do a write on the file handle\n");
2738 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2740 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2745 GET_INFO_BOTH(finfo1,pinfo1);
2746 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2748 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2749 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2750 GET_INFO_BOTH(finfo2,pinfo2);
2751 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2753 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2754 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2755 GET_INFO_BOTH(finfo2,pinfo2);
2756 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2758 /* make sure the 2 second delay from the first write are canceled */
2759 start = timeval_current();
2760 end = timeval_add(&start, 15 * sec, 0);
2761 while (!timeval_expired(&end)) {
2763 /* get the times after the first write */
2764 GET_INFO_BOTH(finfo3,pinfo3);
2766 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2767 double diff = timeval_elapsed(&start);
2768 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2769 "(1sec == %.2f) (wrong!)\n",
2777 GET_INFO_BOTH(finfo3,pinfo3);
2778 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2779 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2780 torture_comment(tctx, "Server did not update write_time (correct)\n");
2783 /* sure any further write doesn't update the write time */
2784 start = timeval_current();
2785 end = timeval_add(&start, 15 * sec, 0);
2786 while (!timeval_expired(&end)) {
2788 torture_comment(tctx, "Do a write on the file handle\n");
2789 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2791 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2795 /* get the times after the write */
2796 GET_INFO_BOTH(finfo4,pinfo4);
2798 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2799 double diff = timeval_elapsed(&start);
2800 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2801 "(1sec == %.2f) (wrong!)\n",
2809 GET_INFO_BOTH(finfo4,pinfo4);
2810 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2811 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2812 torture_comment(tctx, "Server did not update write_time (correct)\n");
2818 GET_INFO_BOTH(finfo5,pinfo5);
2819 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2822 * the close updates the write time to the time of the close
2823 * as the write time was set on the 2nd handle
2825 torture_comment(tctx, "Close the file handle\n");
2826 smbcli_close(cli->tree, fnum1);
2829 GET_INFO_PATH(pinfo6);
2830 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2832 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2833 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2836 /* keep the 2nd handle open and rerun tests */
2843 * closing the 2nd handle will cause no write time update
2844 * as the write time was explicit set on this handle
2846 torture_comment(tctx, "Close the 2nd file handle\n");
2847 smbcli_close(cli2->tree, fnum2);
2850 GET_INFO_PATH(pinfo7);
2851 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2853 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2854 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2859 smbcli_close(cli->tree, fnum1);
2861 smbcli_close(cli2->tree, fnum2);
2862 smbcli_unlink(cli->tree, fname);
2863 smbcli_deltree(cli->tree, BASEDIR);
2869 testing of delayed update of write_time
2871 struct torture_suite *torture_delay_write(void)
2873 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "DELAYWRITE");
2875 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
2876 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
2877 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
2878 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
2879 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
2880 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
2881 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
2882 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
2883 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
2884 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
2885 torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
2886 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
2887 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
2888 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
2889 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);