2 Unix SMB/CIFS implementation.
4 test suite for delayed write update
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Andrew Tridgell 2004
8 Copyright (C) Jeremy Allison 2004
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "torture/torture.h"
26 #include "libcli/raw/libcliraw.h"
27 #include "libcli/raw/raw_proto.h"
28 #include "system/time.h"
29 #include "system/filesys.h"
30 #include "libcli/libcli.h"
31 #include "torture/util.h"
32 #include "torture/basic/proto.h"
34 #define W2K8R2_TIMEDELAY_SECS 1
35 #define W2K3_TIMEDELAY_SECS 2
36 #define TIMEDELAY_SECS W2K3_TIMEDELAY_SECS
38 #define BASEDIR "\\delaywrite"
40 static bool test_delayed_write_update(struct torture_context
*tctx
, struct smbcli_state
*cli
)
42 union smb_fileinfo finfo1
, finfo2
;
43 const char *fname
= BASEDIR
"\\torture_file.txt";
50 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
51 int normal_delay
= 2000000;
52 double sec
= ((double)used_delay
) / ((double)normal_delay
);
53 int msec
= 1000 * sec
;
55 torture_comment(tctx
, "\nRunning test_delayed_write_update\n");
57 if (!torture_setup_dir(cli
, BASEDIR
)) {
61 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
63 torture_result(tctx
, TORTURE_FAIL
, "Failed to open %s", fname
);
67 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
68 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
71 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
73 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
75 torture_comment(tctx
, "Initial write time %s\n",
76 nt_time_string(tctx
, finfo1
.basic_info
.out
.write_time
));
78 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
81 torture_result(tctx
, TORTURE_FAIL
,
82 "write failed - wrote %d bytes (%s)\n",
83 (int)written
, __location__
);
87 start
= timeval_current();
88 end
= timeval_add(&start
, (120*sec
), 0);
89 while (!timeval_expired(&end
)) {
90 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
92 if (!NT_STATUS_IS_OK(status
)) {
93 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
97 torture_comment(tctx
, "write time %s\n",
98 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
99 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
100 double diff
= timeval_elapsed(&start
);
101 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
102 torture_comment(tctx
, "Server updated write_time after %.2f seconds"
103 "(1 sec == %.2f)(wrong!)\n",
109 torture_comment(tctx
, "Server updated write_time after %.2f seconds"
110 "(1 sec == %.2f)(correct)\n",
115 smb_msleep(1 * msec
);
118 if (finfo1
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
119 torture_result(tctx
, TORTURE_FAIL
,
120 "Server did not update write time (wrong!)");
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_result(tctx
, TORTURE_FAIL
, "Failed to open %s", 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) */
166 smb_msleep(3 * msec
);
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 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
179 torture_comment(tctx
, "Initial write time %s\n",
180 nt_time_string(tctx
, finfo1
.all_info
.out
.write_time
));
182 /* 3 second delay to ensure we get past any 2 second time
183 granularity (older systems may have that) */
184 smb_msleep(3 * msec
);
186 /* Do a zero length SMBwrite call to truncate. */
187 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 1024, 0);
190 torture_result(tctx
, TORTURE_FAIL
,
191 "write failed - wrote %d bytes (%s)\n",
192 (int)written
, __location__
);
196 start
= timeval_current();
197 end
= timeval_add(&start
, (120*sec
), 0);
198 while (!timeval_expired(&end
)) {
199 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
201 if (!NT_STATUS_IS_OK(status
)) {
202 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
207 if (finfo2
.all_info
.out
.size
!= 1024) {
208 torture_result(tctx
, TORTURE_FAIL
,
209 "file not truncated, size = %u (should be 1024)",
210 (unsigned int)finfo2
.all_info
.out
.size
);
215 torture_comment(tctx
, "write time %s\n",
216 nt_time_string(tctx
, finfo2
.all_info
.out
.write_time
));
217 if (finfo1
.all_info
.out
.write_time
!= finfo2
.all_info
.out
.write_time
) {
218 double diff
= timeval_elapsed(&start
);
219 if (diff
> (0.25 * sec
* 0.75)) { /* 0.75 to cope with vmware timing */
220 torture_comment(tctx
, "After SMBwrite truncate "
221 "server updated write_time after %.2f seconds"
222 "(1 sec == %.2f)(wrong!)\n",
228 torture_comment(tctx
, "After SMBwrite truncate "
229 "server updated write_time after %.2f seconds"
230 "(1 sec == %.2f)(correct)\n",
235 smb_msleep(1 * msec
);
238 if (finfo1
.all_info
.out
.write_time
== finfo2
.all_info
.out
.write_time
) {
239 torture_result(tctx
, TORTURE_FAIL
,
240 "Server did not update write time (wrong!)");
245 smb_msleep(2 * msec
);
247 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
248 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 0, 1);
251 torture_result(tctx
, TORTURE_FAIL
,
252 "write failed - wrote %d bytes (%s)",
253 (int)written
, __location__
);
257 start
= timeval_current();
258 end
= timeval_add(&start
, (10*sec
), 0);
259 while (!timeval_expired(&end
)) {
260 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo3
);
262 if (!NT_STATUS_IS_OK(status
)) {
263 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
268 if (finfo3
.all_info
.out
.size
!= 1024) {
269 DEBUG(0, ("file not truncated, size = %u (should be 1024)\n",
270 (unsigned int)finfo3
.all_info
.out
.size
));
275 torture_comment(tctx
, "write time %s\n",
276 nt_time_string(tctx
, finfo3
.all_info
.out
.write_time
));
277 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
278 double diff
= timeval_elapsed(&start
);
280 torture_comment(tctx
, "server updated write_time after %.2f seconds"
281 "(1 sec == %.2f)(wrong)\n",
286 smb_msleep(1 * msec
);
289 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
290 torture_result(tctx
, TORTURE_FAIL
,
291 "Server updated write time (wrong!)");
296 smb_msleep(2 * msec
);
298 /* the close should trigger an write time update */
299 smbcli_close(cli
->tree
, fnum1
);
302 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &pinfo4
);
303 torture_assert_ntstatus_ok(tctx
, status
, "pathinfo failed");
305 if (finfo3
.all_info
.out
.write_time
== pinfo4
.all_info
.out
.write_time
) {
306 torture_result(tctx
, TORTURE_FAIL
,
307 "Server did not update write time on close (wrong!)");
309 } else if (finfo3
.all_info
.out
.write_time
< pinfo4
.all_info
.out
.write_time
) {
310 torture_comment(tctx
, "Server updated write time on close (correct)\n");
314 smbcli_close(cli
->tree
, fnum1
);
315 smbcli_unlink(cli
->tree
, fname
);
316 smbcli_deltree(cli
->tree
, BASEDIR
);
321 /* Updating with a SMBwrite of zero length
322 * changes the write time immediately - even on expand. */
324 static bool test_delayed_write_update1a(struct torture_context
*tctx
, struct smbcli_state
*cli
)
326 union smb_fileinfo finfo1
, finfo2
, finfo3
, pinfo4
;
327 const char *fname
= BASEDIR
"\\torture_file1a.txt";
332 struct timeval start
;
334 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
335 int normal_delay
= 2000000;
336 double sec
= ((double)used_delay
) / ((double)normal_delay
);
337 int msec
= 1000 * sec
;
340 torture_comment(tctx
, "\nRunning test_delayed_write_update1a\n");
342 if (!torture_setup_dir(cli
, BASEDIR
)) {
346 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
348 torture_result(tctx
, TORTURE_FAIL
, "Failed to open %s", fname
);
352 memset(buf
, 'x', 2048);
353 written
= smbcli_write(cli
->tree
, fnum1
, 0, buf
, 0, 2048);
355 /* 3 second delay to ensure we get past any 2 second time
356 granularity (older systems may have that) */
357 smb_msleep(3 * msec
);
359 finfo1
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
360 finfo1
.all_info
.in
.file
.fnum
= fnum1
;
363 pinfo4
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
364 pinfo4
.all_info
.in
.file
.path
= fname
;
366 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
368 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
370 torture_comment(tctx
, "Initial write time %s\n",
371 nt_time_string(tctx
, finfo1
.all_info
.out
.write_time
));
373 /* Do a zero length SMBwrite call to truncate. */
374 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 10240, 0);
377 torture_result(tctx
, TORTURE_FAIL
, "write failed - wrote %d bytes (%s)",
378 (int)written
, __location__
);
382 start
= timeval_current();
383 end
= timeval_add(&start
, (120*sec
), 0);
384 while (!timeval_expired(&end
)) {
385 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
387 if (!NT_STATUS_IS_OK(status
)) {
388 torture_result(tctx
, TORTURE_FAIL
, "fileinfo failed: %s",
394 if (finfo2
.all_info
.out
.size
!= 10240) {
395 torture_result(tctx
, TORTURE_FAIL
,
396 "file not truncated, size = %u (should be 10240)",
397 (unsigned int)finfo2
.all_info
.out
.size
);
402 torture_comment(tctx
, "write time %s\n",
403 nt_time_string(tctx
, finfo2
.all_info
.out
.write_time
));
404 if (finfo1
.all_info
.out
.write_time
!= finfo2
.all_info
.out
.write_time
) {
405 double diff
= timeval_elapsed(&start
);
406 if (diff
> (0.25 * sec
* 0.75)) { /* 0.75 to cope with vmware timing */
407 torture_comment(tctx
, "After SMBwrite truncate "
408 "server updated write_time after %.2f seconds"
409 "(1 sec == %.2f)(wrong!)\n",
415 torture_comment(tctx
, "After SMBwrite truncate "
416 "server updated write_time after %.2f seconds"
417 "(1 sec == %.2f)(correct)\n",
422 smb_msleep(1 * msec
);
425 if (finfo1
.all_info
.out
.write_time
== finfo2
.all_info
.out
.write_time
) {
426 torture_result(tctx
, TORTURE_FAIL
,
427 "Server did not update write time (wrong!)");
432 smb_msleep(2 * msec
);
434 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
435 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 0, 1);
437 torture_assert_int_equal(tctx
, written
, 1,
438 "unexpected number of bytes written");
440 start
= timeval_current();
441 end
= timeval_add(&start
, (10*sec
), 0);
442 while (!timeval_expired(&end
)) {
443 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo3
);
445 if (!NT_STATUS_IS_OK(status
)) {
446 torture_result(tctx
, TORTURE_FAIL
, "fileinfo failed: %s\n",
452 if (finfo3
.all_info
.out
.size
!= 10240) {
453 torture_result(tctx
, TORTURE_FAIL
,
454 "file not truncated, size = %u (should be 10240)",
455 (unsigned int)finfo3
.all_info
.out
.size
);
460 torture_comment(tctx
, "write time %s\n",
461 nt_time_string(tctx
, finfo3
.all_info
.out
.write_time
));
462 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
463 double diff
= timeval_elapsed(&start
);
465 torture_comment(tctx
, "server updated write_time after %.2f seconds"
466 "(1 sec == %.2f)(correct)\n",
471 smb_msleep(1 * msec
);
474 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
475 torture_result(tctx
, TORTURE_FAIL
,
476 "Server updated write time (wrong!)");
480 /* the close should trigger an write time update */
481 smbcli_close(cli
->tree
, fnum1
);
484 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &pinfo4
);
485 torture_assert_ntstatus_ok(tctx
, status
, "pathinfo failed");
487 if (finfo3
.all_info
.out
.write_time
== pinfo4
.all_info
.out
.write_time
) {
488 torture_result(tctx
, TORTURE_FAIL
,
489 "Server did not update write time on close (wrong!)");
491 } else if (finfo3
.all_info
.out
.write_time
< pinfo4
.all_info
.out
.write_time
) {
492 torture_comment(tctx
, "Server updated write time on close (correct)\n");
496 smbcli_close(cli
->tree
, fnum1
);
497 smbcli_unlink(cli
->tree
, fname
);
498 smbcli_deltree(cli
->tree
, BASEDIR
);
503 /* Updating with a SET_FILE_END_OF_FILE_INFO
504 * changes the write time immediately - even on expand. */
506 static bool test_delayed_write_update1b(struct torture_context
*tctx
, struct smbcli_state
*cli
)
508 union smb_fileinfo finfo1
, finfo2
, finfo3
, pinfo4
;
509 const char *fname
= BASEDIR
"\\torture_file1b.txt";
514 struct timeval start
;
516 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
517 int normal_delay
= 2000000;
518 double sec
= ((double)used_delay
) / ((double)normal_delay
);
519 int msec
= 1000 * sec
;
522 torture_comment(tctx
, "\nRunning test_delayed_write_update1b\n");
524 if (!torture_setup_dir(cli
, BASEDIR
)) {
528 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
530 torture_result(tctx
, TORTURE_FAIL
, "Failed to open %s", fname
);
534 memset(buf
, 'x', 2048);
535 written
= smbcli_write(cli
->tree
, fnum1
, 0, buf
, 0, 2048);
537 /* 3 second delay to ensure we get past any 2 second time
538 granularity (older systems may have that) */
539 smb_msleep(3 * msec
);
541 finfo1
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
542 finfo1
.all_info
.in
.file
.fnum
= fnum1
;
545 pinfo4
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
546 pinfo4
.all_info
.in
.file
.path
= fname
;
548 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
550 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
552 torture_comment(tctx
, "Initial write time %s\n",
553 nt_time_string(tctx
, finfo1
.all_info
.out
.write_time
));
555 /* Do a SET_END_OF_FILE_INFO call to truncate. */
556 status
= smbcli_ftruncate(cli
->tree
, fnum1
, (uint64_t)10240);
558 torture_assert_ntstatus_ok(tctx
, status
, "SET_END_OF_FILE failed");
560 start
= timeval_current();
561 end
= timeval_add(&start
, (120*sec
), 0);
562 while (!timeval_expired(&end
)) {
563 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
565 if (!NT_STATUS_IS_OK(status
)) {
566 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
571 if (finfo2
.all_info
.out
.size
!= 10240) {
572 torture_result(tctx
, TORTURE_FAIL
,
573 "file not truncated (size = %u, should be 10240)",
574 (unsigned int)finfo2
.all_info
.out
.size
);
579 torture_comment(tctx
, "write time %s\n",
580 nt_time_string(tctx
, finfo2
.all_info
.out
.write_time
));
581 if (finfo1
.all_info
.out
.write_time
!= finfo2
.all_info
.out
.write_time
) {
582 double diff
= timeval_elapsed(&start
);
583 if (diff
> (0.25 * sec
* 0.75)) { /* 0.75 to cope with vmware timing */
584 torture_result(tctx
, TORTURE_FAIL
,
585 "After SET_END_OF_FILE truncate "
586 "server updated write_time after %.2f seconds"
587 "(1 sec == %.2f)(wrong!)",
593 torture_comment(tctx
, "After SET_END_OF_FILE truncate "
594 "server updated write_time after %.2f seconds"
595 "(1 sec == %.2f)(correct)\n",
600 smb_msleep(1 * msec
);
603 if (finfo1
.all_info
.out
.write_time
== finfo2
.all_info
.out
.write_time
) {
604 torture_result(tctx
, TORTURE_FAIL
,
605 "Server did not update write time (wrong!)");
610 smb_msleep(2 * msec
);
612 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
613 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 0, 1);
615 torture_assert_int_equal(tctx
, written
, 1,
616 "unexpected number of bytes written");
618 start
= timeval_current();
619 end
= timeval_add(&start
, (10*sec
), 0);
620 while (!timeval_expired(&end
)) {
621 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo3
);
623 if (!NT_STATUS_IS_OK(status
)) {
624 torture_result(tctx
, TORTURE_FAIL
,
625 "fileinfo failed: %s", nt_errstr(status
));
630 if (finfo3
.all_info
.out
.size
!= 10240) {
631 DEBUG(0, ("file not truncated (size = %u, should be 10240)\n",
632 (unsigned int)finfo3
.all_info
.out
.size
));
637 torture_comment(tctx
, "write time %s\n",
638 nt_time_string(tctx
, finfo3
.all_info
.out
.write_time
));
639 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
640 double diff
= timeval_elapsed(&start
);
642 torture_comment(tctx
, "server updated write_time after %.2f seconds"
643 "(1 sec == %.2f)(correct)\n",
648 smb_msleep(1 * msec
);
651 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
652 torture_result(tctx
, TORTURE_FAIL
, "Server updated write time (wrong!)\n");
656 /* the close should trigger an write time update */
657 smbcli_close(cli
->tree
, fnum1
);
660 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &pinfo4
);
661 torture_assert_ntstatus_ok(tctx
, status
, "pathinfo failed");
663 if (finfo3
.all_info
.out
.write_time
== pinfo4
.all_info
.out
.write_time
) {
664 torture_result(tctx
, TORTURE_FAIL
, "Server did not update write time on close (wrong!)\n");
666 } else if (finfo3
.all_info
.out
.write_time
< pinfo4
.all_info
.out
.write_time
) {
667 torture_comment(tctx
, "Server updated write time on close (correct)\n");
671 smbcli_close(cli
->tree
, fnum1
);
672 smbcli_unlink(cli
->tree
, fname
);
673 smbcli_deltree(cli
->tree
, BASEDIR
);
678 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
680 static bool test_delayed_write_update1c(struct torture_context
*tctx
, struct smbcli_state
*cli
)
682 union smb_setfileinfo parms
;
683 union smb_fileinfo finfo1
, finfo2
, finfo3
, pinfo4
;
684 const char *fname
= BASEDIR
"\\torture_file1c.txt";
689 struct timeval start
;
691 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
692 int normal_delay
= 2000000;
693 double sec
= ((double)used_delay
) / ((double)normal_delay
);
694 int msec
= 1000 * sec
;
697 torture_comment(tctx
, "\nRunning test_delayed_write_update1c\n");
699 if (!torture_setup_dir(cli
, BASEDIR
)) {
703 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
705 torture_result(tctx
, TORTURE_FAIL
, "Failed to open %s", fname
);
709 memset(buf
, 'x', 2048);
710 written
= smbcli_write(cli
->tree
, fnum1
, 0, buf
, 0, 2048);
712 /* 3 second delay to ensure we get past any 2 second time
713 granularity (older systems may have that) */
714 smb_msleep(3 * msec
);
716 finfo1
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
717 finfo1
.all_info
.in
.file
.fnum
= fnum1
;
720 pinfo4
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
721 pinfo4
.all_info
.in
.file
.path
= fname
;
723 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
725 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
727 torture_comment(tctx
, "Initial write time %s\n",
728 nt_time_string(tctx
, finfo1
.all_info
.out
.write_time
));
730 /* Do a SET_ALLOCATION_SIZE call to truncate. */
731 parms
.allocation_info
.level
= RAW_SFILEINFO_ALLOCATION_INFO
;
732 parms
.allocation_info
.in
.file
.fnum
= fnum1
;
733 parms
.allocation_info
.in
.alloc_size
= 0;
735 status
= smb_raw_setfileinfo(cli
->tree
, &parms
);
737 torture_assert_ntstatus_ok(tctx
, status
,
738 "RAW_SFILEINFO_ALLOCATION_INFO failed");
740 start
= timeval_current();
741 end
= timeval_add(&start
, (120*sec
), 0);
742 while (!timeval_expired(&end
)) {
743 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
745 if (!NT_STATUS_IS_OK(status
)) {
746 torture_result(tctx
, TORTURE_FAIL
, "fileinfo failed: %s",
752 if (finfo2
.all_info
.out
.size
!= 0) {
753 torture_result(tctx
, TORTURE_FAIL
,
754 "file not truncated (size = %u, should be 10240)",
755 (unsigned int)finfo2
.all_info
.out
.size
);
760 torture_comment(tctx
, "write time %s\n",
761 nt_time_string(tctx
, finfo2
.all_info
.out
.write_time
));
762 if (finfo1
.all_info
.out
.write_time
!= finfo2
.all_info
.out
.write_time
) {
763 double diff
= timeval_elapsed(&start
);
764 if (diff
> (0.25 * sec
* 0.75)) { /* 0.75 to cope with vmware timing */
765 torture_comment(tctx
, "After SET_ALLOCATION_INFO truncate "
766 "server updated write_time after %.2f seconds"
767 "(1 sec == %.2f)(wrong!)\n",
773 torture_comment(tctx
, "After SET_ALLOCATION_INFO truncate "
774 "server updated write_time after %.2f seconds"
775 "(1 sec == %.2f)(correct)\n",
780 smb_msleep(1 * msec
);
783 if (finfo1
.all_info
.out
.write_time
== finfo2
.all_info
.out
.write_time
) {
784 torture_result(tctx
, TORTURE_FAIL
,
785 "Server did not update write time (wrong!)");
790 smb_msleep(2 * msec
);
792 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
793 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 0, 1);
794 torture_assert_int_equal(tctx
, written
, 1,
795 "Unexpected number of bytes written");
797 start
= timeval_current();
798 end
= timeval_add(&start
, (10*sec
), 0);
799 while (!timeval_expired(&end
)) {
800 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo3
);
802 if (!NT_STATUS_IS_OK(status
)) {
803 torture_result(tctx
, TORTURE_FAIL
, "fileinfo failed: %s",
809 if (finfo3
.all_info
.out
.size
!= 1) {
810 torture_result(tctx
, TORTURE_FAIL
, "file not expanded");
815 torture_comment(tctx
, "write time %s\n",
816 nt_time_string(tctx
, finfo3
.all_info
.out
.write_time
));
817 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
818 double diff
= timeval_elapsed(&start
);
820 torture_comment(tctx
, "server updated write_time after %.2f seconds"
821 "(1 sec == %.2f)(correct)\n",
826 smb_msleep(1 * msec
);
829 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
830 torture_result(tctx
, TORTURE_FAIL
,
831 "Server updated write time (wrong!)");
835 /* the close should trigger an write time update */
836 smbcli_close(cli
->tree
, fnum1
);
839 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &pinfo4
);
840 torture_assert_ntstatus_ok(tctx
, status
, "pathinfo failed");
842 if (finfo3
.all_info
.out
.write_time
== pinfo4
.all_info
.out
.write_time
) {
843 torture_result(tctx
, TORTURE_FAIL
, "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 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
899 torture_comment(tctx
, "Initial write time %s\n",
900 nt_time_string(tctx
, finfo1
.basic_info
.out
.write_time
));
902 /* 3 second delay to ensure we get past any 2 second time
903 granularity (older systems may have that) */
904 smb_msleep(3 * msec
);
907 /* Try using setfileinfo instead of write to update write time. */
908 union smb_setfileinfo sfinfo
;
909 time_t t_set
= time(NULL
);
910 sfinfo
.basic_info
.level
= RAW_SFILEINFO_BASIC_INFO
;
911 sfinfo
.basic_info
.in
.file
.fnum
= fnum1
;
912 sfinfo
.basic_info
.in
.create_time
= finfo1
.basic_info
.out
.create_time
;
913 sfinfo
.basic_info
.in
.access_time
= finfo1
.basic_info
.out
.access_time
;
915 /* I tried this with both + and - ve to see if it makes a different.
916 It doesn't - once the filetime is set via setfileinfo it stays that way. */
918 unix_to_nt_time(&sfinfo
.basic_info
.in
.write_time
, t_set
- 30000);
920 unix_to_nt_time(&sfinfo
.basic_info
.in
.write_time
, t_set
+ 30000);
922 sfinfo
.basic_info
.in
.change_time
= finfo1
.basic_info
.out
.change_time
;
923 sfinfo
.basic_info
.in
.attrib
= finfo1
.basic_info
.out
.attrib
;
925 status
= smb_raw_setfileinfo(cli
->tree
, &sfinfo
);
927 torture_assert_ntstatus_ok(tctx
, status
, "sfileinfo failed");
930 finfo2
.basic_info
.in
.file
.path
= fname
;
932 status
= smb_raw_pathinfo(cli2
->tree
, tctx
, &finfo2
);
934 if (!NT_STATUS_IS_OK(status
)) {
935 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
938 torture_comment(tctx
, "write time %s\n",
939 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
941 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
942 torture_comment(tctx
, "Server updated write_time (correct)\n");
944 torture_result(tctx
, TORTURE_FAIL
, "Server did not update write time (wrong!)\n");
948 /* Now try a write to see if the write time gets reset. */
950 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
951 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
954 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
956 if (!NT_STATUS_IS_OK(status
)) {
957 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
961 torture_comment(tctx
, "Modified write time %s\n",
962 nt_time_string(tctx
, finfo1
.basic_info
.out
.write_time
));
965 torture_comment(tctx
, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
967 written
= smbcli_write(cli
->tree
, fnum1
, 0, "0123456789", 1, 10);
970 torture_comment(tctx
, "write failed - wrote %d bytes (%s)\n",
971 (int)written
, __location__
);
975 /* Just to prove to tridge that the an smbflush has no effect on
976 the write time :-). The setfileinfo IS STICKY. JRA. */
978 torture_comment(tctx
, "Doing flush after write\n");
980 flsh
.flush
.level
= RAW_FLUSH_FLUSH
;
981 flsh
.flush
.in
.file
.fnum
= fnum1
;
982 status
= smb_raw_flush(cli
->tree
, &flsh
);
983 if (!NT_STATUS_IS_OK(status
)) {
984 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status
)));
988 /* Once the time was set using setfileinfo then it stays set - writes
989 don't have any effect. But make sure. */
990 start
= timeval_current();
991 end
= timeval_add(&start
, (15*sec
), 0);
992 while (!timeval_expired(&end
)) {
993 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
995 if (!NT_STATUS_IS_OK(status
)) {
996 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1000 torture_comment(tctx
, "write time %s\n",
1001 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1002 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
1003 double diff
= timeval_elapsed(&start
);
1004 torture_comment(tctx
, "Server updated write_time after %.2f seconds"
1005 "(1sec == %.2f) (wrong!)\n",
1011 smb_msleep(1 * msec
);
1014 if (finfo1
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
1015 torture_comment(tctx
, "Server did not update write time (correct)\n");
1019 smb_msleep(2 * msec
);
1021 fnum2
= smbcli_open(cli
->tree
, fname
, O_RDWR
, DENY_NONE
);
1023 torture_comment(tctx
, "Failed to open %s\n", fname
);
1027 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");
1029 written
= smbcli_write(cli
->tree
, fnum2
, 0, "0123456789", 11, 10);
1031 if (written
!= 10) {
1032 torture_comment(tctx
, "write failed - wrote %d bytes (%s)\n",
1033 (int)written
, __location__
);
1037 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
1039 if (!NT_STATUS_IS_OK(status
)) {
1040 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1043 torture_comment(tctx
, "write time %s\n",
1044 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1045 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
1046 torture_comment(tctx
, "Server updated write_time (wrong!)\n");
1050 torture_comment(tctx
, "Closing the first fd to see if write time updated.\n");
1051 smbcli_close(cli
->tree
, fnum1
);
1054 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");
1056 written
= smbcli_write(cli
->tree
, fnum2
, 0, "0123456789", 21, 10);
1058 if (written
!= 10) {
1059 torture_comment(tctx
, "write failed - wrote %d bytes (%s)\n",
1060 (int)written
, __location__
);
1064 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1065 finfo1
.basic_info
.in
.file
.fnum
= fnum2
;
1067 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
1069 if (!NT_STATUS_IS_OK(status
)) {
1070 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1073 torture_comment(tctx
, "write time %s\n",
1074 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1075 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
1076 torture_comment(tctx
, "Server updated write_time (wrong!)\n");
1080 /* Once the time was set using setfileinfo then it stays set - writes
1081 don't have any effect. But make sure. */
1082 start
= timeval_current();
1083 end
= timeval_add(&start
, (15*sec
), 0);
1084 while (!timeval_expired(&end
)) {
1085 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
1087 if (!NT_STATUS_IS_OK(status
)) {
1088 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1092 torture_comment(tctx
, "write time %s\n",
1093 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1094 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
1095 double diff
= timeval_elapsed(&start
);
1096 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1097 "(1sec == %.2f) (wrong!)\n",
1103 smb_msleep(1 * msec
);
1106 if (finfo1
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
1107 torture_comment(tctx
, "Server did not update write time (correct)\n");
1110 torture_comment(tctx
, "Closing second fd to see if write time updated.\n");
1112 smbcli_close(cli
->tree
, fnum2
);
1115 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
, DENY_NONE
);
1117 torture_comment(tctx
, "Failed to open %s\n", fname
);
1121 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1122 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
1125 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
1127 if (!NT_STATUS_IS_OK(status
)) {
1128 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1132 torture_comment(tctx
, "Second open initial write time %s\n",
1133 nt_time_string(tctx
, finfo1
.basic_info
.out
.write_time
));
1135 smb_msleep(10 * msec
);
1136 torture_comment(tctx
, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1138 written
= smbcli_write(cli
->tree
, fnum1
, 0, "0123456789", 31, 10);
1140 if (written
!= 10) {
1141 torture_comment(tctx
, "write failed - wrote %d bytes (%s)\n",
1142 (int)written
, __location__
);
1146 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1147 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
1149 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
1151 if (!NT_STATUS_IS_OK(status
)) {
1152 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1155 torture_comment(tctx
, "write time %s\n",
1156 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1157 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
1158 torture_comment(tctx
, "Server updated write_time (wrong!)\n");
1162 /* Now the write time should be updated again */
1163 start
= timeval_current();
1164 end
= timeval_add(&start
, (15*sec
), 0);
1165 while (!timeval_expired(&end
)) {
1166 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
1168 if (!NT_STATUS_IS_OK(status
)) {
1169 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1173 torture_comment(tctx
, "write time %s\n",
1174 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1175 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
1176 double diff
= timeval_elapsed(&start
);
1177 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
1178 torture_comment(tctx
, "Server updated write_time after %.2f seconds"
1179 "(1sec == %.2f) (wrong!)\n",
1185 torture_comment(tctx
, "Server updated write_time after %.2f seconds"
1186 "(1sec == %.2f) (correct)\n",
1194 if (finfo1
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
1195 torture_result(tctx
, TORTURE_FAIL
, "Server did not update write time (wrong!)\n");
1200 /* One more test to do. We should read the filetime via findfirst on the
1201 second connection to ensure it's the same. This is very easy for a Windows
1202 server but a bastard to get right on a POSIX server. JRA. */
1205 smbcli_close(cli
->tree
, fnum1
);
1206 smbcli_unlink(cli
->tree
, fname
);
1207 smbcli_deltree(cli
->tree
, BASEDIR
);
1213 /* Windows does obviously not update the stat info during a write call. I
1214 * *think* this is the problem causing a spurious Excel 2003 on XP error
1215 * message when saving a file. Excel does a setfileinfo, writes, and then does
1216 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1217 * that the file might have been changed in between. What i've been able to
1218 * trace down is that this happens if the getpathinfo after the write shows a
1219 * different last write time than the setfileinfo showed. This is really
1223 static bool test_finfo_after_write(struct torture_context
*tctx
, struct smbcli_state
*cli
,
1224 struct smbcli_state
*cli2
)
1226 union smb_fileinfo finfo1
, finfo2
;
1227 const char *fname
= BASEDIR
"\\torture_file.txt";
1233 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
1234 int normal_delay
= 2000000;
1235 double sec
= ((double)used_delay
) / ((double)normal_delay
);
1236 int msec
= 1000 * sec
;
1238 torture_comment(tctx
, "\nRunning test_finfo_after_write\n");
1240 if (!torture_setup_dir(cli
, BASEDIR
)) {
1244 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
1247 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
1251 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1252 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
1254 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
1256 if (!NT_STATUS_IS_OK(status
)) {
1258 torture_result(tctx
, TORTURE_FAIL
, __location__
": fileinfo failed: %s", nt_errstr(status
));
1262 smb_msleep(1 * msec
);
1264 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1267 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1272 fnum2
= smbcli_open(cli2
->tree
, fname
, O_RDWR
, DENY_NONE
);
1274 torture_result(tctx
, TORTURE_FAIL
, __location__
": failed to open 2nd time - %s",
1275 smbcli_errstr(cli2
->tree
));
1280 written
= smbcli_write(cli2
->tree
, fnum2
, 0, "x", 0, 1);
1283 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1",
1289 finfo2
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1290 finfo2
.basic_info
.in
.file
.path
= fname
;
1292 status
= smb_raw_pathinfo(cli2
->tree
, tctx
, &finfo2
);
1294 if (!NT_STATUS_IS_OK(status
)) {
1295 torture_result(tctx
, TORTURE_FAIL
, __location__
": fileinfo failed: %s",
1301 if (finfo1
.basic_info
.out
.create_time
!=
1302 finfo2
.basic_info
.out
.create_time
) {
1303 torture_result(tctx
, TORTURE_FAIL
, __location__
": create_time changed");
1308 if (finfo1
.basic_info
.out
.access_time
!=
1309 finfo2
.basic_info
.out
.access_time
) {
1310 torture_result(tctx
, TORTURE_FAIL
, __location__
": access_time changed");
1315 if (finfo1
.basic_info
.out
.write_time
!=
1316 finfo2
.basic_info
.out
.write_time
) {
1317 torture_result(tctx
, TORTURE_FAIL
, __location__
": write_time changed:\n"
1318 "write time conn 1 = %s, conn 2 = %s",
1319 nt_time_string(tctx
, finfo1
.basic_info
.out
.write_time
),
1320 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1325 if (finfo1
.basic_info
.out
.change_time
!=
1326 finfo2
.basic_info
.out
.change_time
) {
1327 torture_result(tctx
, TORTURE_FAIL
, __location__
": change_time changed");
1332 /* One of the two following calls updates the qpathinfo. */
1334 /* If you had skipped the smbcli_write on fnum2, it would
1335 * *not* have updated the stat on disk */
1337 smbcli_close(cli2
->tree
, fnum2
);
1340 /* This call is only for the people looking at ethereal :-) */
1341 finfo2
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1342 finfo2
.basic_info
.in
.file
.path
= fname
;
1344 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo2
);
1346 if (!NT_STATUS_IS_OK(status
)) {
1347 torture_result(tctx
, TORTURE_FAIL
, __location__
": fileinfo failed: %s", nt_errstr(status
));
1354 smbcli_close(cli
->tree
, fnum1
);
1355 smbcli_unlink(cli
->tree
, fname
);
1356 smbcli_deltree(cli
->tree
, BASEDIR
);
1361 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1362 uint64_t r = 10*1000*1000; \
1363 NTTIME g = (given).basic_info.out.write_time; \
1364 NTTIME gr = (g / r) * r; \
1365 NTTIME c = (correct).basic_info.out.write_time; \
1366 NTTIME cr = (c / r) * r; \
1367 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1369 if (strict && (g cmp c)) { \
1371 } else if ((g cmp c) && (gr cmp cr)) { \
1372 /* handle filesystem without high resolution timestamps */ \
1376 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1377 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1378 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1383 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1384 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1385 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1386 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1387 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1388 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1390 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1391 NTTIME g = (given).basic_info.out.access_time; \
1392 NTTIME c = (correct).basic_info.out.access_time; \
1394 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1395 #given, nt_time_string(tctx, g), \
1396 #cmp, #correct, nt_time_string(tctx, c)); \
1401 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1402 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1404 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1405 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1406 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1409 #define GET_INFO_FILE(finfo) do { \
1411 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1412 if (!NT_STATUS_IS_OK(_status)) { \
1414 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1415 nt_errstr(_status)); \
1418 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1419 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1420 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1422 #define GET_INFO_FILE2(finfo) do { \
1424 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1425 if (!NT_STATUS_IS_OK(_status)) { \
1427 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1428 nt_errstr(_status)); \
1431 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1432 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1433 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1435 #define GET_INFO_PATH(pinfo) do { \
1437 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1438 if (!NT_STATUS_IS_OK(_status)) { \
1439 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1440 nt_errstr(_status)); \
1444 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1445 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1446 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1448 #define GET_INFO_BOTH(finfo,pinfo) do { \
1449 GET_INFO_FILE(finfo); \
1450 GET_INFO_PATH(pinfo); \
1451 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1454 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1456 union smb_setfileinfo sfinfo; \
1457 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1458 sfinfo.basic_info.in.file.fnum = tfnum; \
1459 sfinfo.basic_info.in.create_time = 0; \
1460 sfinfo.basic_info.in.access_time = 0; \
1461 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1462 sfinfo.basic_info.in.change_time = 0; \
1463 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1464 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1465 if (!NT_STATUS_IS_OK(_status)) { \
1466 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1467 nt_errstr(_status)); \
1472 #define SET_INFO_FILE(finfo, wrtime) \
1473 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1475 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1477 union smb_setfileinfo sfinfo; \
1478 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1479 sfinfo.basic_info.in.file.fnum = tfnum; \
1480 sfinfo.basic_info.in.create_time = 0; \
1481 sfinfo.basic_info.in.access_time = 0; \
1482 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1483 sfinfo.basic_info.in.write_time += (ns); \
1484 sfinfo.basic_info.in.change_time = 0; \
1485 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1486 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1487 if (!NT_STATUS_IS_OK(_status)) { \
1488 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1489 nt_errstr(_status)); \
1495 static bool test_delayed_write_update3(struct torture_context
*tctx
,
1496 struct smbcli_state
*cli
,
1497 struct smbcli_state
*cli2
)
1499 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
;
1500 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
;
1501 const char *fname
= BASEDIR
"\\torture_file3.txt";
1505 struct timeval start
;
1507 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
1508 int normal_delay
= 2000000;
1509 double sec
= ((double)used_delay
) / ((double)normal_delay
);
1510 int msec
= 1000 * sec
;
1512 torture_comment(tctx
, "\nRunning test_delayed_write_update3\n");
1514 if (!torture_setup_dir(cli
, BASEDIR
)) {
1518 torture_comment(tctx
, "Open the file handle\n");
1519 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
1522 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
1526 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1527 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
1531 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1532 pinfo0
.basic_info
.in
.file
.path
= fname
;
1538 /* get the initial times */
1539 GET_INFO_BOTH(finfo0
,pinfo0
);
1542 * make sure the write time is updated 2 seconds later
1543 * calcuated from the first write
1544 * (but expect upto 5 seconds extra time for a busy server)
1546 start
= timeval_current();
1547 end
= timeval_add(&start
, 7 * sec
, 0);
1548 while (!timeval_expired(&end
)) {
1550 torture_comment(tctx
, "Do a write on the file handle\n");
1551 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1553 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1557 /* get the times after the write */
1558 GET_INFO_FILE(finfo1
);
1560 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
1561 double diff
= timeval_elapsed(&start
);
1562 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
1563 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1564 "(1sec == %.2f) (wrong!)\n",
1570 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1571 "(1sec == %.2f) (correct)\n",
1575 smb_msleep(0.5 * msec
);
1578 GET_INFO_BOTH(finfo1
,pinfo1
);
1579 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
1581 /* sure any further write doesn't update the write time */
1582 start
= timeval_current();
1583 end
= timeval_add(&start
, 15 * sec
, 0);
1584 while (!timeval_expired(&end
)) {
1586 torture_comment(tctx
, "Do a write on the file handle\n");
1587 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1589 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1593 /* get the times after the write */
1594 GET_INFO_BOTH(finfo2
,pinfo2
);
1596 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
1597 double diff
= timeval_elapsed(&start
);
1598 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1599 "(1sec == %.2f) (wrong!)\n",
1604 smb_msleep(1 * msec
);
1607 GET_INFO_BOTH(finfo2
,pinfo2
);
1608 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
1609 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
1610 torture_comment(tctx
, "Server did not update write_time (correct)\n");
1614 smb_msleep(5 * msec
);
1616 GET_INFO_BOTH(finfo3
,pinfo3
);
1617 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
1620 * the close updates the write time to the time of the close
1621 * and not to the time of the last write!
1623 torture_comment(tctx
, "Close the file handle\n");
1624 smbcli_close(cli
->tree
, fnum1
);
1627 GET_INFO_PATH(pinfo4
);
1628 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
1630 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
1631 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
1636 smbcli_close(cli
->tree
, fnum1
);
1637 smbcli_unlink(cli
->tree
, fname
);
1638 smbcli_deltree(cli
->tree
, BASEDIR
);
1644 * Show that a truncate write always updates the write time even
1645 * if an initial write has already updated the write time.
1648 static bool test_delayed_write_update3a(struct torture_context
*tctx
,
1649 struct smbcli_state
*cli
,
1650 struct smbcli_state
*cli2
)
1652 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
;
1653 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
;
1654 const char *fname
= BASEDIR
"\\torture_file3a.txt";
1659 struct timeval start
;
1661 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
1662 int normal_delay
= 2000000;
1663 double sec
= ((double)used_delay
) / ((double)normal_delay
);
1664 int msec
= 1000 * sec
;
1666 torture_comment(tctx
, "\nRunning test_delayed_write_update3a\n");
1668 if (!torture_setup_dir(cli
, BASEDIR
)) {
1672 torture_comment(tctx
, "Open the file handle\n");
1673 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
1676 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
1680 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1681 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
1685 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1686 pinfo0
.basic_info
.in
.file
.path
= fname
;
1692 /* get the initial times */
1693 GET_INFO_BOTH(finfo0
,pinfo0
);
1696 * sleep some time, to demonstrate the handling of write times
1697 * doesn't depend on the time since the open
1699 smb_msleep(5 * msec
);
1701 /* get the initial times */
1702 GET_INFO_BOTH(finfo1
,pinfo1
);
1703 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
1706 * make sure the write time is updated 2 seconds later
1707 * calcuated from the first write
1708 * (but expect upto 5 seconds extra time for a busy server)
1710 start
= timeval_current();
1711 end
= timeval_add(&start
, 7 * sec
, 0);
1712 while (!timeval_expired(&end
)) {
1714 torture_comment(tctx
, "Do a write on the file handle\n");
1715 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1717 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1721 /* get the times after the write */
1722 GET_INFO_FILE(finfo1
);
1724 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
1725 double diff
= timeval_elapsed(&start
);
1726 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
1727 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1728 "(1sec == %.2f) (wrong!)\n",
1734 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1735 "(1sec == %.2f) (correct)\n",
1739 smb_msleep(0.5 * msec
);
1742 GET_INFO_BOTH(finfo1
,pinfo1
);
1743 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
1745 smb_msleep(3 * msec
);
1748 * demonstrate that a truncate write always
1749 * updates the write time immediately
1751 for (i
=0; i
< 3; i
++) {
1752 smb_msleep(2 * msec
);
1754 torture_comment(tctx
, "Do a truncate SMBwrite [%d] on the file handle\n", i
);
1755 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 10240, 0);
1757 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
1761 /* get the times after the write */
1762 GET_INFO_BOTH(finfo2
,pinfo2
);
1763 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
1767 smb_msleep(3 * msec
);
1769 /* sure any further write doesn't update the write time */
1770 start
= timeval_current();
1771 end
= timeval_add(&start
, 15 * sec
, 0);
1772 while (!timeval_expired(&end
)) {
1774 torture_comment(tctx
, "Do a write on the file handle\n");
1775 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1777 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1781 /* get the times after the write */
1782 GET_INFO_BOTH(finfo2
,pinfo2
);
1784 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
1785 double diff
= timeval_elapsed(&start
);
1786 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1787 "(1sec == %.2f) (wrong!)\n",
1792 smb_msleep(1 * msec
);
1795 GET_INFO_BOTH(finfo2
,pinfo2
);
1796 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
1797 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
1798 torture_comment(tctx
, "Server did not update write_time (correct)\n");
1802 smb_msleep(3 * msec
);
1804 /* get the initial times */
1805 GET_INFO_BOTH(finfo1
,pinfo1
);
1806 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo2
);
1809 * demonstrate that a truncate write always
1810 * updates the write time immediately
1812 for (i
=0; i
< 3; i
++) {
1813 smb_msleep(2 * msec
);
1815 torture_comment(tctx
, "Do a truncate SMBwrite [%d] on the file handle\n", i
);
1816 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 512, 0);
1818 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
1822 /* get the times after the write */
1823 GET_INFO_BOTH(finfo2
,pinfo2
);
1824 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
1829 smb_msleep(3 * msec
);
1831 GET_INFO_BOTH(finfo3
,pinfo3
);
1832 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
1835 * the close doesn't update the write time
1837 torture_comment(tctx
, "Close the file handle\n");
1838 smbcli_close(cli
->tree
, fnum1
);
1841 GET_INFO_PATH(pinfo4
);
1842 COMPARE_WRITE_TIME_EQUAL(pinfo4
, pinfo3
);
1844 if (pinfo4
.basic_info
.out
.write_time
== pinfo3
.basic_info
.out
.write_time
) {
1845 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
1850 smbcli_close(cli
->tree
, fnum1
);
1851 smbcli_unlink(cli
->tree
, fname
);
1852 smbcli_deltree(cli
->tree
, BASEDIR
);
1858 * Show a close after write updates the write timestamp to
1859 * the close time, not the last write time.
1862 static bool test_delayed_write_update3b(struct torture_context
*tctx
,
1863 struct smbcli_state
*cli
,
1864 struct smbcli_state
*cli2
)
1866 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
;
1867 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
;
1868 const char *fname
= BASEDIR
"\\torture_file3b.txt";
1872 struct timeval start
;
1874 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
1875 int normal_delay
= 2000000;
1876 double sec
= ((double)used_delay
) / ((double)normal_delay
);
1877 int msec
= 1000 * sec
;
1879 torture_comment(tctx
, "\nRunning test_delayed_write_update3b\n");
1881 if (!torture_setup_dir(cli
, BASEDIR
)) {
1885 torture_comment(tctx
, "Open the file handle\n");
1886 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
1889 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
1893 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1894 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
1898 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1899 pinfo0
.basic_info
.in
.file
.path
= fname
;
1905 /* get the initial times */
1906 GET_INFO_BOTH(finfo0
,pinfo0
);
1909 * sleep some time, to demonstrate the handling of write times
1910 * doesn't depend on the time since the open
1912 smb_msleep(5 * msec
);
1914 /* get the initial times */
1915 GET_INFO_BOTH(finfo1
,pinfo1
);
1916 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
1919 * make sure the write time is updated 2 seconds later
1920 * calcuated from the first write
1921 * (but expect upto 5 seconds extra time for a busy server)
1923 start
= timeval_current();
1924 end
= timeval_add(&start
, 7 * sec
, 0);
1925 while (!timeval_expired(&end
)) {
1927 torture_comment(tctx
, "Do a write on the file handle\n");
1928 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1930 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1934 /* get the times after the write */
1935 GET_INFO_FILE(finfo1
);
1937 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
1938 double diff
= timeval_elapsed(&start
);
1939 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
1940 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1941 "(1sec == %.2f) (wrong!)\n",
1947 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1948 "(1sec == %.2f) (correct)\n",
1952 smb_msleep(0.5 * msec
);
1955 GET_INFO_BOTH(finfo1
,pinfo1
);
1956 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
1958 /* sure any further write doesn't update the write time */
1959 start
= timeval_current();
1960 end
= timeval_add(&start
, 15 * sec
, 0);
1961 while (!timeval_expired(&end
)) {
1963 torture_comment(tctx
, "Do a write on the file handle\n");
1964 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1966 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1970 /* get the times after the write */
1971 GET_INFO_BOTH(finfo2
,pinfo2
);
1973 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
1974 double diff
= timeval_elapsed(&start
);
1975 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1976 "(1sec == %.2f) (wrong!)\n",
1981 smb_msleep(1 * msec
);
1984 GET_INFO_BOTH(finfo2
,pinfo2
);
1985 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
1986 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
1987 torture_comment(tctx
, "Server did not update write_time (correct)\n");
1991 smb_msleep(5 * msec
);
1993 GET_INFO_BOTH(finfo3
,pinfo3
);
1994 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
1997 * the close updates the write time to the time of the close
1998 * and not to the time of the last write!
2000 torture_comment(tctx
, "Close the file handle\n");
2001 smbcli_close(cli
->tree
, fnum1
);
2004 GET_INFO_PATH(pinfo4
);
2005 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
2007 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
2008 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
2013 smbcli_close(cli
->tree
, fnum1
);
2014 smbcli_unlink(cli
->tree
, fname
);
2015 smbcli_deltree(cli
->tree
, BASEDIR
);
2021 * Check that a write after a truncate write doesn't update
2022 * the timestamp, but a truncate write after a write does.
2023 * Also prove that a close after a truncate write updates the
2024 * timestamp to current, not the time of last write.
2027 static bool test_delayed_write_update3c(struct torture_context
*tctx
,
2028 struct smbcli_state
*cli
,
2029 struct smbcli_state
*cli2
)
2031 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
;
2032 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
;
2033 const char *fname
= BASEDIR
"\\torture_file3c.txt";
2038 struct timeval start
;
2040 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2041 int normal_delay
= 2000000;
2042 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2043 int msec
= 1000 * sec
;
2045 torture_comment(tctx
, "\nRunning test_delayed_write_update3c\n");
2047 if (!torture_setup_dir(cli
, BASEDIR
)) {
2051 torture_comment(tctx
, "Open the file handle\n");
2052 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2055 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2059 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2060 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2065 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2066 pinfo0
.basic_info
.in
.file
.path
= fname
;
2073 /* get the initial times */
2074 GET_INFO_BOTH(finfo0
,pinfo0
);
2077 * sleep some time, to demonstrate the handling of write times
2078 * doesn't depend on the time since the open
2080 smb_msleep(5 * msec
);
2082 /* get the initial times */
2083 GET_INFO_BOTH(finfo1
,pinfo1
);
2084 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
2087 * demonstrate that a truncate write always
2088 * updates the write time immediately
2090 for (i
=0; i
< 3; i
++) {
2091 smb_msleep(2 * msec
);
2093 torture_comment(tctx
, "Do a truncate SMBwrite [%d] on the file handle\n", i
);
2094 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 512, 0);
2096 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
2100 /* get the times after the write */
2101 GET_INFO_BOTH(finfo2
,pinfo2
);
2102 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2106 start
= timeval_current();
2107 end
= timeval_add(&start
, 7 * sec
, 0);
2108 while (!timeval_expired(&end
)) {
2110 torture_comment(tctx
, "Do a write on the file handle\n");
2111 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2113 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2117 /* get the times after the write */
2118 GET_INFO_FILE(finfo2
);
2120 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
2121 double diff
= timeval_elapsed(&start
);
2122 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2123 "(1sec == %.2f) (wrong!)\n",
2128 smb_msleep(1 * msec
);
2131 GET_INFO_BOTH(finfo2
,pinfo2
);
2132 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2133 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
2134 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2138 smb_msleep(5 * msec
);
2140 /* get the initial times */
2141 GET_INFO_BOTH(finfo1
,pinfo1
);
2142 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo2
);
2145 * demonstrate that a truncate write always
2146 * updates the write time immediately
2148 for (i
=0; i
< 3; i
++) {
2149 smb_msleep(2 * msec
);
2151 torture_comment(tctx
, "Do a truncate write [%d] on the file handle\n", i
);
2152 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 512, 0);
2154 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
2158 /* get the times after the write */
2159 GET_INFO_BOTH(finfo2
,pinfo2
);
2160 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2165 smb_msleep(5 * msec
);
2167 GET_INFO_BOTH(finfo2
,pinfo2
);
2168 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2170 /* sure any further write doesn't update the write time */
2171 start
= timeval_current();
2172 end
= timeval_add(&start
, 15 * sec
, 0);
2173 while (!timeval_expired(&end
)) {
2175 torture_comment(tctx
, "Do a write on the file handle\n");
2176 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2178 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2182 /* get the times after the write */
2183 GET_INFO_BOTH(finfo2
,pinfo2
);
2185 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
2186 double diff
= timeval_elapsed(&start
);
2187 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2188 "(1sec == %.2f) (wrong!)\n",
2193 smb_msleep(1 * msec
);
2196 GET_INFO_BOTH(finfo2
,pinfo2
);
2197 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2198 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
2199 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2203 smb_msleep(5 * msec
);
2205 GET_INFO_BOTH(finfo3
,pinfo3
);
2206 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2209 * the close updates the write time to the time of the close
2210 * and not to the time of the last write!
2212 torture_comment(tctx
, "Close the file handle\n");
2213 smbcli_close(cli
->tree
, fnum1
);
2216 GET_INFO_PATH(pinfo4
);
2217 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
2219 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
2220 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
2225 smbcli_close(cli
->tree
, fnum1
);
2226 smbcli_unlink(cli
->tree
, fname
);
2227 smbcli_deltree(cli
->tree
, BASEDIR
);
2233 * Show only the first write updates the timestamp, and a close
2234 * after writes updates to current (I think this is the same
2238 static bool test_delayed_write_update4(struct torture_context
*tctx
,
2239 struct smbcli_state
*cli
,
2240 struct smbcli_state
*cli2
)
2242 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
;
2243 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
;
2244 const char *fname
= BASEDIR
"\\torture_file4.txt";
2248 struct timeval start
;
2250 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2251 int normal_delay
= 2000000;
2252 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2253 int msec
= 1000 * sec
;
2255 torture_comment(tctx
, "\nRunning test_delayed_write_update4\n");
2257 if (!torture_setup_dir(cli
, BASEDIR
)) {
2261 torture_comment(tctx
, "Open the file handle\n");
2262 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2265 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2269 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2270 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2274 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2275 pinfo0
.basic_info
.in
.file
.path
= fname
;
2281 /* get the initial times */
2282 GET_INFO_BOTH(finfo0
,pinfo0
);
2285 smb_msleep(5 * msec
);
2288 torture_comment(tctx
, "Do a write on the file handle\n");
2289 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2291 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2296 GET_INFO_BOTH(finfo1
,pinfo1
);
2297 COMPARE_WRITE_TIME_EQUAL(finfo1
,finfo0
);
2300 * make sure the write time is updated 2 seconds later
2301 * calcuated from the first write
2302 * (but expect upto 3 seconds extra time for a busy server)
2304 start
= timeval_current();
2305 end
= timeval_add(&start
, 5 * sec
, 0);
2306 while (!timeval_expired(&end
)) {
2307 /* get the times after the first write */
2308 GET_INFO_FILE(finfo1
);
2310 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
2311 double diff
= timeval_elapsed(&start
);
2312 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
2313 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2314 "(1sec == %.2f) (wrong!)\n",
2320 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2321 "(1sec == %.2f) (correct)\n",
2325 smb_msleep(0.5 * msec
);
2328 GET_INFO_BOTH(finfo1
,pinfo1
);
2329 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
2331 /* sure any further write doesn't update the write time */
2332 start
= timeval_current();
2333 end
= timeval_add(&start
, 15 * sec
, 0);
2334 while (!timeval_expired(&end
)) {
2336 torture_comment(tctx
, "Do a write on the file handle\n");
2337 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2339 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2343 /* get the times after the write */
2344 GET_INFO_BOTH(finfo2
,pinfo2
);
2346 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
2347 double diff
= timeval_elapsed(&start
);
2348 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2349 "(1sec == %.2f) (wrong!)\n",
2354 smb_msleep(1 * msec
);
2357 GET_INFO_BOTH(finfo2
,pinfo2
);
2358 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2359 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
2360 torture_comment(tctx
, "Server did not updatewrite_time (correct)\n");
2364 smb_msleep(5 * msec
);
2366 GET_INFO_BOTH(finfo3
,pinfo3
);
2367 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2370 * the close updates the write time to the time of the close
2371 * and not to the time of the last write!
2373 torture_comment(tctx
, "Close the file handle\n");
2374 smbcli_close(cli
->tree
, fnum1
);
2377 GET_INFO_PATH(pinfo4
);
2378 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
2380 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
2381 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
2386 smbcli_close(cli
->tree
, fnum1
);
2387 smbcli_unlink(cli
->tree
, fname
);
2388 smbcli_deltree(cli
->tree
, BASEDIR
);
2394 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2397 static bool test_delayed_write_update5(struct torture_context
*tctx
,
2398 struct smbcli_state
*cli
,
2399 struct smbcli_state
*cli2
)
2401 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
, finfo5
;
2402 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
, pinfo6
;
2403 const char *fname
= BASEDIR
"\\torture_file5.txt";
2407 struct timeval start
;
2409 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2410 int normal_delay
= 2000000;
2411 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2412 int msec
= 1000 * sec
;
2414 torture_comment(tctx
, "\nRunning test_delayed_write_update5\n");
2416 if (!torture_setup_dir(cli
, BASEDIR
)) {
2420 torture_comment(tctx
, "Open the file handle\n");
2421 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2424 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2428 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2429 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2435 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2436 pinfo0
.basic_info
.in
.file
.path
= fname
;
2444 /* get the initial times */
2445 GET_INFO_BOTH(finfo0
,pinfo0
);
2448 torture_comment(tctx
, "Do a write on the file handle\n");
2449 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2451 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2456 GET_INFO_BOTH(finfo1
,pinfo1
);
2457 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
2459 torture_comment(tctx
, "Set write time in the future on the file handle\n");
2460 SET_INFO_FILE(finfo0
, time(NULL
) + 86400);
2461 GET_INFO_BOTH(finfo2
,pinfo2
);
2462 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2464 torture_comment(tctx
, "Set write time in the past on the file handle\n");
2465 SET_INFO_FILE(finfo0
, time(NULL
) - 86400);
2466 GET_INFO_BOTH(finfo2
,pinfo2
);
2467 COMPARE_WRITE_TIME_LESS(finfo2
, finfo1
);
2469 /* make sure the 2 second delay from the first write are canceled */
2470 start
= timeval_current();
2471 end
= timeval_add(&start
, 15 * sec
, 0);
2472 while (!timeval_expired(&end
)) {
2474 /* get the times after the first write */
2475 GET_INFO_BOTH(finfo3
,pinfo3
);
2477 if (finfo3
.basic_info
.out
.write_time
> finfo2
.basic_info
.out
.write_time
) {
2478 double diff
= timeval_elapsed(&start
);
2479 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2480 "(1sec == %.2f) (wrong!)\n",
2485 smb_msleep(1 * msec
);
2488 GET_INFO_BOTH(finfo3
,pinfo3
);
2489 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2490 if (finfo3
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
2491 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2494 /* sure any further write doesn't update the write time */
2495 start
= timeval_current();
2496 end
= timeval_add(&start
, 15 * sec
, 0);
2497 while (!timeval_expired(&end
)) {
2499 torture_comment(tctx
, "Do a write on the file handle\n");
2500 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2502 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2506 /* get the times after the write */
2507 GET_INFO_BOTH(finfo4
,pinfo4
);
2509 if (finfo4
.basic_info
.out
.write_time
> finfo3
.basic_info
.out
.write_time
) {
2510 double diff
= timeval_elapsed(&start
);
2511 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2512 "(1sec == %.2f) (wrong!)\n",
2517 smb_msleep(1 * msec
);
2520 GET_INFO_BOTH(finfo4
,pinfo4
);
2521 COMPARE_WRITE_TIME_EQUAL(finfo4
, finfo3
);
2522 if (finfo4
.basic_info
.out
.write_time
== finfo3
.basic_info
.out
.write_time
) {
2523 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2527 smb_msleep(5 * msec
);
2529 GET_INFO_BOTH(finfo5
,pinfo5
);
2530 COMPARE_WRITE_TIME_EQUAL(finfo5
, finfo4
);
2533 * the close doesn't update the write time
2535 torture_comment(tctx
, "Close the file handle\n");
2536 smbcli_close(cli
->tree
, fnum1
);
2539 GET_INFO_PATH(pinfo6
);
2540 COMPARE_WRITE_TIME_EQUAL(pinfo6
, pinfo5
);
2542 if (pinfo6
.basic_info
.out
.write_time
== pinfo5
.basic_info
.out
.write_time
) {
2543 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
2548 smbcli_close(cli
->tree
, fnum1
);
2549 smbcli_unlink(cli
->tree
, fname
);
2550 smbcli_deltree(cli
->tree
, BASEDIR
);
2556 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2559 static bool test_delayed_write_update5b(struct torture_context
*tctx
,
2560 struct smbcli_state
*cli
,
2561 struct smbcli_state
*cli2
)
2563 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
, finfo5
;
2564 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
, pinfo6
;
2565 const char *fname
= BASEDIR
"\\torture_fileb.txt";
2569 struct timeval start
;
2571 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2572 int normal_delay
= 2000000;
2573 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2574 int msec
= 1000 * sec
;
2576 torture_comment(tctx
, "\nRunning test_delayed_write_update5b\n");
2578 if (!torture_setup_dir(cli
, BASEDIR
)) {
2582 torture_comment(tctx
, "Open the file handle\n");
2583 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2586 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2590 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2591 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2597 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2598 pinfo0
.basic_info
.in
.file
.path
= fname
;
2606 /* get the initial times */
2607 GET_INFO_BOTH(finfo0
,pinfo0
);
2610 torture_comment(tctx
, "Do a write on the file handle\n");
2611 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2613 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2618 GET_INFO_BOTH(finfo1
,pinfo1
);
2619 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
2621 torture_comment(tctx
, "Set write time in the future on the file handle\n");
2622 SET_INFO_FILE(finfo0
, time(NULL
) + 86400);
2623 GET_INFO_BOTH(finfo2
,pinfo2
);
2624 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2626 torture_comment(tctx
, "Set write time in the past on the file handle\n");
2627 SET_INFO_FILE(finfo0
, time(NULL
) - 86400);
2628 GET_INFO_BOTH(finfo2
,pinfo2
);
2629 COMPARE_WRITE_TIME_LESS(finfo2
, finfo1
);
2631 /* make sure the 2 second delay from the first write are canceled */
2632 start
= timeval_current();
2633 end
= timeval_add(&start
, 15 * sec
, 0);
2634 while (!timeval_expired(&end
)) {
2636 /* get the times after the first write */
2637 GET_INFO_BOTH(finfo3
,pinfo3
);
2639 if (finfo3
.basic_info
.out
.write_time
> finfo2
.basic_info
.out
.write_time
) {
2640 double diff
= timeval_elapsed(&start
);
2641 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2642 "(1sec == %.2f) (wrong!)\n",
2647 smb_msleep(1 * msec
);
2650 GET_INFO_BOTH(finfo3
,pinfo3
);
2651 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2652 if (finfo3
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
2653 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2656 /* Do any further write (truncates) update the write time ? */
2657 start
= timeval_current();
2658 end
= timeval_add(&start
, 15 * sec
, 0);
2659 while (!timeval_expired(&end
)) {
2661 torture_comment(tctx
, "Do a truncate write on the file handle\n");
2662 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 1024, 0);
2664 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2668 /* get the times after the write */
2669 GET_INFO_BOTH(finfo4
,pinfo4
);
2671 if (finfo4
.basic_info
.out
.write_time
> finfo3
.basic_info
.out
.write_time
) {
2672 double diff
= timeval_elapsed(&start
);
2673 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2674 "(1sec == %.2f) (wrong!)\n",
2679 smb_msleep(1 * msec
);
2682 GET_INFO_BOTH(finfo4
,pinfo4
);
2683 COMPARE_WRITE_TIME_EQUAL(finfo4
, finfo3
);
2684 if (finfo4
.basic_info
.out
.write_time
== finfo3
.basic_info
.out
.write_time
) {
2685 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2689 smb_msleep(5 * msec
);
2691 GET_INFO_BOTH(finfo5
,pinfo5
);
2692 COMPARE_WRITE_TIME_EQUAL(finfo5
, finfo4
);
2695 * the close doesn't update the write time
2697 torture_comment(tctx
, "Close the file handle\n");
2698 smbcli_close(cli
->tree
, fnum1
);
2701 GET_INFO_PATH(pinfo6
);
2702 COMPARE_WRITE_TIME_EQUAL(pinfo6
, pinfo5
);
2704 if (pinfo6
.basic_info
.out
.write_time
== pinfo5
.basic_info
.out
.write_time
) {
2705 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
2710 smbcli_close(cli
->tree
, fnum1
);
2711 smbcli_unlink(cli
->tree
, fname
);
2712 smbcli_deltree(cli
->tree
, BASEDIR
);
2718 * Open 2 handles on a file. Write one one and then set the
2719 * WRITE TIME explicitly on the other. Ensure the write time
2720 * update is cancelled. Ensure the write time is updated to
2721 * the close time when the non-explicit set handle is closed.
2725 static bool test_delayed_write_update6(struct torture_context
*tctx
,
2726 struct smbcli_state
*cli
,
2727 struct smbcli_state
*cli2
)
2729 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
, finfo5
;
2730 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
, pinfo6
, pinfo7
;
2731 const char *fname
= BASEDIR
"\\torture_file6.txt";
2736 struct timeval start
;
2738 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2739 int normal_delay
= 2000000;
2740 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2741 int msec
= 1000 * sec
;
2744 torture_comment(tctx
, "\nRunning test_delayed_write_update6\n");
2746 if (!torture_setup_dir(cli
, BASEDIR
)) {
2750 torture_comment(tctx
, "Open the file handle\n");
2751 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2754 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2759 torture_comment(tctx
, "Open the 2nd file handle on 2nd connection\n");
2760 fnum2
= smbcli_open(cli2
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2763 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2768 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2769 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2775 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2776 pinfo0
.basic_info
.in
.file
.path
= fname
;
2785 /* get the initial times */
2786 GET_INFO_BOTH(finfo0
,pinfo0
);
2789 torture_comment(tctx
, "Do a write on the file handle\n");
2790 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2792 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2797 GET_INFO_BOTH(finfo1
,pinfo1
);
2798 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
2800 torture_comment(tctx
, "Set write time in the future on the 2nd file handle\n");
2801 SET_INFO_FILE_EX(finfo0
, time(NULL
) + 86400, cli2
->tree
, fnum2
);
2802 GET_INFO_BOTH(finfo2
,pinfo2
);
2803 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2805 torture_comment(tctx
, "Set write time in the past on the 2nd file handle\n");
2806 SET_INFO_FILE_EX(finfo0
, time(NULL
) - 86400, cli2
->tree
, fnum2
);
2807 GET_INFO_BOTH(finfo2
,pinfo2
);
2808 COMPARE_WRITE_TIME_LESS(finfo2
, finfo1
);
2810 /* make sure the 2 second delay from the first write are canceled */
2811 start
= timeval_current();
2812 end
= timeval_add(&start
, 10 * sec
, 0);
2813 while (!timeval_expired(&end
)) {
2815 /* get the times after the first write */
2816 GET_INFO_BOTH(finfo3
,pinfo3
);
2818 if (finfo3
.basic_info
.out
.write_time
> finfo2
.basic_info
.out
.write_time
) {
2819 double diff
= timeval_elapsed(&start
);
2820 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2821 "(1sec == %.2f) (wrong!)\n",
2826 smb_msleep(1 * msec
);
2829 GET_INFO_BOTH(finfo3
,pinfo3
);
2830 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2831 if (finfo3
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
2832 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2835 /* sure any further write doesn't update the write time */
2836 start
= timeval_current();
2837 end
= timeval_add(&start
, 10 * sec
, 0);
2838 while (!timeval_expired(&end
)) {
2840 torture_comment(tctx
, "Do a write on the file handle\n");
2841 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2843 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2847 /* get the times after the write */
2848 GET_INFO_BOTH(finfo4
,pinfo4
);
2850 if (finfo4
.basic_info
.out
.write_time
> finfo3
.basic_info
.out
.write_time
) {
2851 double diff
= timeval_elapsed(&start
);
2852 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2853 "(1sec == %.2f) (wrong!)\n",
2858 smb_msleep(1 * msec
);
2861 GET_INFO_BOTH(finfo4
,pinfo4
);
2862 COMPARE_WRITE_TIME_EQUAL(finfo4
, finfo3
);
2863 if (finfo4
.basic_info
.out
.write_time
== finfo3
.basic_info
.out
.write_time
) {
2864 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2868 smb_msleep(5 * msec
);
2870 GET_INFO_BOTH(finfo5
,pinfo5
);
2871 COMPARE_WRITE_TIME_EQUAL(finfo5
, finfo4
);
2874 * the close updates the write time to the time of the close
2875 * as the write time was set on the 2nd handle
2877 torture_comment(tctx
, "Close the file handle\n");
2878 smbcli_close(cli
->tree
, fnum1
);
2881 GET_INFO_PATH(pinfo6
);
2882 COMPARE_WRITE_TIME_GREATER(pinfo6
, pinfo5
);
2884 if (pinfo6
.basic_info
.out
.write_time
> pinfo5
.basic_info
.out
.write_time
) {
2885 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
2888 /* See what the second write handle thinks the time is ? */
2889 finfo5
.basic_info
.in
.file
.fnum
= fnum2
;
2890 GET_INFO_FILE2(finfo5
);
2891 COMPARE_WRITE_TIME_EQUAL(finfo5
, pinfo6
);
2893 /* See if we have lost the sticky write time on handle2 */
2894 smb_msleep(3 * msec
);
2895 torture_comment(tctx
, "Have we lost the sticky write time ?\n");
2897 /* Make sure any further normal write doesn't update the write time */
2898 start
= timeval_current();
2899 end
= timeval_add(&start
, 10 * sec
, 0);
2900 while (!timeval_expired(&end
)) {
2902 torture_comment(tctx
, "Do a write on the second file handle\n");
2903 written
= smbcli_write(cli2
->tree
, fnum2
, 0, "x", 0, 1);
2905 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2909 /* get the times after the write */
2910 GET_INFO_FILE2(finfo5
);
2911 GET_INFO_PATH(pinfo6
);
2913 if (finfo5
.basic_info
.out
.write_time
> pinfo6
.basic_info
.out
.write_time
) {
2914 double diff
= timeval_elapsed(&start
);
2915 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2916 "(1sec == %.2f) (wrong!)\n",
2921 smb_msleep(1 * msec
);
2924 /* What about a truncate write ? */
2925 start
= timeval_current();
2926 end
= timeval_add(&start
, 10 * sec
, 0);
2927 while (!timeval_expired(&end
)) {
2929 torture_comment(tctx
, "Do a truncate write on the second file handle\n");
2930 written
= smbcli_write(cli2
->tree
, fnum2
, 0, "x", 0, 0);
2932 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2936 /* get the times after the write */
2937 GET_INFO_FILE2(finfo5
);
2938 GET_INFO_PATH(pinfo6
);
2940 if (finfo5
.basic_info
.out
.write_time
> pinfo6
.basic_info
.out
.write_time
) {
2941 double diff
= timeval_elapsed(&start
);
2942 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2943 "(1sec == %.2f) (wrong!)\n",
2948 smb_msleep(1 * msec
);
2952 /* keep the 2nd handle open and rerun tests */
2959 * closing the 2nd handle will cause no write time update
2960 * as the write time was explicit set on this handle
2962 torture_comment(tctx
, "Close the 2nd file handle\n");
2963 smbcli_close(cli2
->tree
, fnum2
);
2966 GET_INFO_PATH(pinfo7
);
2967 COMPARE_WRITE_TIME_EQUAL(pinfo7
, pinfo6
);
2969 if (pinfo7
.basic_info
.out
.write_time
== pinfo6
.basic_info
.out
.write_time
) {
2970 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
2975 smbcli_close(cli
->tree
, fnum1
);
2977 smbcli_close(cli2
->tree
, fnum2
);
2978 smbcli_unlink(cli
->tree
, fname
);
2979 smbcli_deltree(cli
->tree
, BASEDIR
);
2984 static bool test_delayed_write_update7(struct torture_context
*tctx
, struct smbcli_state
*cli
)
2986 union smb_open open_parms
;
2987 union smb_fileinfo finfo1
, finfo2
, finfo3
;
2988 const char *fname
= BASEDIR
"\\torture_file7.txt";
2992 TALLOC_CTX
*mem_ctx
;
2994 torture_comment(tctx
, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2996 mem_ctx
= talloc_init("test_delayed_write_update7");
2997 if (!mem_ctx
) return false;
2999 ZERO_STRUCT(finfo1
);
3000 ZERO_STRUCT(finfo2
);
3001 ZERO_STRUCT(finfo3
);
3002 ZERO_STRUCT(open_parms
);
3004 if (!torture_setup_dir(cli
, BASEDIR
)) {
3008 /* Create the file. */
3009 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
3011 torture_result(tctx
, TORTURE_FAIL
, "Failed to open %s", fname
);
3015 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
3016 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
3020 /* Get the initial timestamps. */
3021 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
3023 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
3025 /* Set the pending write time to a value with ns. */
3026 SET_INFO_FILE_NS(finfo
, time(NULL
) + 86400, 103, cli
->tree
, fnum1
);
3028 /* Get the current pending write time by fnum. */
3029 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
3031 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
3033 /* Ensure the time is actually different. */
3034 if (finfo1
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
3035 torture_result(tctx
, TORTURE_FAIL
,
3036 "setfileinfo time matches original fileinfo time");
3040 /* Get the current pending write time by path. */
3041 finfo3
.basic_info
.in
.file
.path
= fname
;
3042 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo3
);
3044 if (finfo2
.basic_info
.out
.write_time
!= finfo3
.basic_info
.out
.write_time
) {
3045 torture_result(tctx
, TORTURE_FAIL
,
3046 "qpathinfo time doens't match fileinfo time");
3050 /* Now close the file. Re-open and check that the write
3051 time is identical to the one we wrote. */
3053 smbcli_close(cli
->tree
, fnum1
);
3055 open_parms
.ntcreatex
.level
= RAW_OPEN_NTCREATEX
;
3056 open_parms
.ntcreatex
.in
.flags
= 0;
3057 open_parms
.ntcreatex
.in
.access_mask
= SEC_GENERIC_READ
;
3058 open_parms
.ntcreatex
.in
.file_attr
= 0;
3059 open_parms
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
3060 NTCREATEX_SHARE_ACCESS_READ
|
3061 NTCREATEX_SHARE_ACCESS_WRITE
;
3062 open_parms
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
3063 open_parms
.ntcreatex
.in
.create_options
= 0;
3064 open_parms
.ntcreatex
.in
.fname
= fname
;
3066 status
= smb_raw_open(cli
->tree
, mem_ctx
, &open_parms
);
3067 talloc_free(mem_ctx
);
3069 if (!NT_STATUS_IS_OK(status
)) {
3070 torture_result(tctx
, TORTURE_FAIL
,
3071 "setfileinfo time matches original fileinfo time");
3075 fnum1
= open_parms
.ntcreatex
.out
.file
.fnum
;
3077 /* Check the returned time matches. */
3078 if (open_parms
.ntcreatex
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
3079 torture_result(tctx
, TORTURE_FAIL
,
3080 "final open time does not match set time");
3086 smbcli_close(cli
->tree
, fnum1
);
3088 smbcli_unlink(cli
->tree
, fname
);
3089 smbcli_deltree(cli
->tree
, BASEDIR
);
3094 testing of delayed update of write_time
3096 struct torture_suite
*torture_delay_write(void)
3098 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "delaywrite");
3100 torture_suite_add_2smb_test(suite
, "finfo update on close", test_finfo_after_write
);
3101 torture_suite_add_1smb_test(suite
, "delayed update of write time", test_delayed_write_update
);
3102 torture_suite_add_1smb_test(suite
, "update of write time and SMBwrite truncate", test_delayed_write_update1
);
3103 torture_suite_add_1smb_test(suite
, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a
);
3104 torture_suite_add_1smb_test(suite
, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b
);
3105 torture_suite_add_1smb_test(suite
, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c
);
3106 torture_suite_add_2smb_test(suite
, "delayed update of write time using 2 connections", test_delayed_write_update2
);
3107 torture_suite_add_2smb_test(suite
, "delayed update of write time 3", test_delayed_write_update3
);
3108 torture_suite_add_2smb_test(suite
, "delayed update of write time 3a", test_delayed_write_update3a
);
3109 torture_suite_add_2smb_test(suite
, "delayed update of write time 3b", test_delayed_write_update3b
);
3110 torture_suite_add_2smb_test(suite
, "delayed update of write time 3c", test_delayed_write_update3c
);
3111 torture_suite_add_2smb_test(suite
, "delayed update of write time 4", test_delayed_write_update4
);
3112 torture_suite_add_2smb_test(suite
, "delayed update of write time 5", test_delayed_write_update5
);
3113 torture_suite_add_2smb_test(suite
, "delayed update of write time 5b", test_delayed_write_update5b
);
3114 torture_suite_add_2smb_test(suite
, "delayed update of write time 6", test_delayed_write_update6
);
3115 torture_suite_add_1smb_test(suite
, "timestamp resolution test", test_delayed_write_update7
);
3116 torture_suite_add_1smb_test(suite
, "timestamp resolution test", test_delayed_write_update7
);