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
, finfo4
;
1500 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
;
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
;
1532 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1533 pinfo0
.basic_info
.in
.file
.path
= fname
;
1540 /* get the initial times */
1541 GET_INFO_BOTH(finfo0
,pinfo0
);
1544 * make sure the write time is updated 2 seconds later
1545 * calcuated from the first write
1546 * (but expect upto 5 seconds extra time for a busy server)
1548 start
= timeval_current();
1549 end
= timeval_add(&start
, 7 * sec
, 0);
1550 while (!timeval_expired(&end
)) {
1552 torture_comment(tctx
, "Do a write on the file handle\n");
1553 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1555 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1559 /* get the times after the write */
1560 GET_INFO_FILE(finfo1
);
1562 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
1563 double diff
= timeval_elapsed(&start
);
1564 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
1565 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1566 "(1sec == %.2f) (wrong!)\n",
1572 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1573 "(1sec == %.2f) (correct)\n",
1577 smb_msleep(0.5 * msec
);
1580 GET_INFO_BOTH(finfo1
,pinfo1
);
1581 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
1583 /* sure any further write doesn't update the write time */
1584 start
= timeval_current();
1585 end
= timeval_add(&start
, 15 * sec
, 0);
1586 while (!timeval_expired(&end
)) {
1588 torture_comment(tctx
, "Do a write on the file handle\n");
1589 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1591 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1595 /* get the times after the write */
1596 GET_INFO_BOTH(finfo2
,pinfo2
);
1598 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
1599 double diff
= timeval_elapsed(&start
);
1600 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1601 "(1sec == %.2f) (wrong!)\n",
1606 smb_msleep(1 * msec
);
1609 GET_INFO_BOTH(finfo2
,pinfo2
);
1610 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
1611 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
1612 torture_comment(tctx
, "Server did not update write_time (correct)\n");
1616 smb_msleep(5 * msec
);
1618 GET_INFO_BOTH(finfo3
,pinfo3
);
1619 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
1622 * the close updates the write time to the time of the close
1623 * and not to the time of the last write!
1625 torture_comment(tctx
, "Close the file handle\n");
1626 smbcli_close(cli
->tree
, fnum1
);
1629 GET_INFO_PATH(pinfo4
);
1630 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
1632 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
1633 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
1638 smbcli_close(cli
->tree
, fnum1
);
1639 smbcli_unlink(cli
->tree
, fname
);
1640 smbcli_deltree(cli
->tree
, BASEDIR
);
1646 * Show that a truncate write always updates the write time even
1647 * if an initial write has already updated the write time.
1650 static bool test_delayed_write_update3a(struct torture_context
*tctx
,
1651 struct smbcli_state
*cli
,
1652 struct smbcli_state
*cli2
)
1654 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
;
1655 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
;
1656 const char *fname
= BASEDIR
"\\torture_file3a.txt";
1661 struct timeval start
;
1663 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
1664 int normal_delay
= 2000000;
1665 double sec
= ((double)used_delay
) / ((double)normal_delay
);
1666 int msec
= 1000 * sec
;
1668 torture_comment(tctx
, "\nRunning test_delayed_write_update3a\n");
1670 if (!torture_setup_dir(cli
, BASEDIR
)) {
1674 torture_comment(tctx
, "Open the file handle\n");
1675 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
1678 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
1682 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1683 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
1688 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1689 pinfo0
.basic_info
.in
.file
.path
= fname
;
1696 /* get the initial times */
1697 GET_INFO_BOTH(finfo0
,pinfo0
);
1700 * sleep some time, to demonstrate the handling of write times
1701 * doesn't depend on the time since the open
1703 smb_msleep(5 * msec
);
1705 /* get the initial times */
1706 GET_INFO_BOTH(finfo1
,pinfo1
);
1707 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
1710 * make sure the write time is updated 2 seconds later
1711 * calcuated from the first write
1712 * (but expect upto 5 seconds extra time for a busy server)
1714 start
= timeval_current();
1715 end
= timeval_add(&start
, 7 * 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_FILE(finfo1
);
1728 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
1729 double diff
= timeval_elapsed(&start
);
1730 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
1731 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1732 "(1sec == %.2f) (wrong!)\n",
1738 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1739 "(1sec == %.2f) (correct)\n",
1743 smb_msleep(0.5 * msec
);
1746 GET_INFO_BOTH(finfo1
,pinfo1
);
1747 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
1749 smb_msleep(3 * msec
);
1752 * demonstrate that a truncate write always
1753 * updates the write time immediately
1755 for (i
=0; i
< 3; i
++) {
1756 smb_msleep(2 * msec
);
1758 torture_comment(tctx
, "Do a truncate SMBwrite [%d] on the file handle\n", i
);
1759 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 10240, 0);
1761 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
1765 /* get the times after the write */
1766 GET_INFO_BOTH(finfo2
,pinfo2
);
1767 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
1771 smb_msleep(3 * msec
);
1773 /* sure any further write doesn't update the write time */
1774 start
= timeval_current();
1775 end
= timeval_add(&start
, 15 * sec
, 0);
1776 while (!timeval_expired(&end
)) {
1778 torture_comment(tctx
, "Do a write on the file handle\n");
1779 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1781 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1785 /* get the times after the write */
1786 GET_INFO_BOTH(finfo2
,pinfo2
);
1788 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
1789 double diff
= timeval_elapsed(&start
);
1790 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1791 "(1sec == %.2f) (wrong!)\n",
1796 smb_msleep(1 * msec
);
1799 GET_INFO_BOTH(finfo2
,pinfo2
);
1800 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
1801 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
1802 torture_comment(tctx
, "Server did not update write_time (correct)\n");
1806 smb_msleep(3 * msec
);
1808 /* get the initial times */
1809 GET_INFO_BOTH(finfo1
,pinfo1
);
1810 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo2
);
1813 * demonstrate that a truncate write always
1814 * updates the write time immediately
1816 for (i
=0; i
< 3; i
++) {
1817 smb_msleep(2 * msec
);
1819 torture_comment(tctx
, "Do a truncate SMBwrite [%d] on the file handle\n", i
);
1820 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 512, 0);
1822 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
1826 /* get the times after the write */
1827 GET_INFO_BOTH(finfo2
,pinfo2
);
1828 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
1833 smb_msleep(3 * msec
);
1835 GET_INFO_BOTH(finfo3
,pinfo3
);
1836 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
1839 * the close doesn't update the write time
1841 torture_comment(tctx
, "Close the file handle\n");
1842 smbcli_close(cli
->tree
, fnum1
);
1845 GET_INFO_PATH(pinfo4
);
1846 COMPARE_WRITE_TIME_EQUAL(pinfo4
, pinfo3
);
1848 if (pinfo4
.basic_info
.out
.write_time
== pinfo3
.basic_info
.out
.write_time
) {
1849 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
1854 smbcli_close(cli
->tree
, fnum1
);
1855 smbcli_unlink(cli
->tree
, fname
);
1856 smbcli_deltree(cli
->tree
, BASEDIR
);
1862 * Show a close after write updates the write timestamp to
1863 * the close time, not the last write time.
1866 static bool test_delayed_write_update3b(struct torture_context
*tctx
,
1867 struct smbcli_state
*cli
,
1868 struct smbcli_state
*cli2
)
1870 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
;
1871 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
;
1872 const char *fname
= BASEDIR
"\\torture_file3b.txt";
1876 struct timeval start
;
1878 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
1879 int normal_delay
= 2000000;
1880 double sec
= ((double)used_delay
) / ((double)normal_delay
);
1881 int msec
= 1000 * sec
;
1883 torture_comment(tctx
, "\nRunning test_delayed_write_update3b\n");
1885 if (!torture_setup_dir(cli
, BASEDIR
)) {
1889 torture_comment(tctx
, "Open the file handle\n");
1890 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
1893 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
1897 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1898 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
1903 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1904 pinfo0
.basic_info
.in
.file
.path
= fname
;
1911 /* get the initial times */
1912 GET_INFO_BOTH(finfo0
,pinfo0
);
1915 * sleep some time, to demonstrate the handling of write times
1916 * doesn't depend on the time since the open
1918 smb_msleep(5 * msec
);
1920 /* get the initial times */
1921 GET_INFO_BOTH(finfo1
,pinfo1
);
1922 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
1925 * make sure the write time is updated 2 seconds later
1926 * calcuated from the first write
1927 * (but expect upto 5 seconds extra time for a busy server)
1929 start
= timeval_current();
1930 end
= timeval_add(&start
, 7 * sec
, 0);
1931 while (!timeval_expired(&end
)) {
1933 torture_comment(tctx
, "Do a write on the file handle\n");
1934 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1936 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1940 /* get the times after the write */
1941 GET_INFO_FILE(finfo1
);
1943 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
1944 double diff
= timeval_elapsed(&start
);
1945 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
1946 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1947 "(1sec == %.2f) (wrong!)\n",
1953 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1954 "(1sec == %.2f) (correct)\n",
1958 smb_msleep(0.5 * msec
);
1961 GET_INFO_BOTH(finfo1
,pinfo1
);
1962 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
1964 /* sure any further write doesn't update the write time */
1965 start
= timeval_current();
1966 end
= timeval_add(&start
, 15 * sec
, 0);
1967 while (!timeval_expired(&end
)) {
1969 torture_comment(tctx
, "Do a write on the file handle\n");
1970 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1972 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1976 /* get the times after the write */
1977 GET_INFO_BOTH(finfo2
,pinfo2
);
1979 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
1980 double diff
= timeval_elapsed(&start
);
1981 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1982 "(1sec == %.2f) (wrong!)\n",
1987 smb_msleep(1 * msec
);
1990 GET_INFO_BOTH(finfo2
,pinfo2
);
1991 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
1992 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
1993 torture_comment(tctx
, "Server did not update write_time (correct)\n");
1997 smb_msleep(5 * msec
);
1999 GET_INFO_BOTH(finfo3
,pinfo3
);
2000 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2003 * the close updates the write time to the time of the close
2004 * and not to the time of the last write!
2006 torture_comment(tctx
, "Close the file handle\n");
2007 smbcli_close(cli
->tree
, fnum1
);
2010 GET_INFO_PATH(pinfo4
);
2011 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
2013 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
2014 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
2019 smbcli_close(cli
->tree
, fnum1
);
2020 smbcli_unlink(cli
->tree
, fname
);
2021 smbcli_deltree(cli
->tree
, BASEDIR
);
2027 * Check that a write after a truncate write doesn't update
2028 * the timestamp, but a truncate write after a write does.
2029 * Also prove that a close after a truncate write updates the
2030 * timestamp to current, not the time of last write.
2033 static bool test_delayed_write_update3c(struct torture_context
*tctx
,
2034 struct smbcli_state
*cli
,
2035 struct smbcli_state
*cli2
)
2037 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
;
2038 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
;
2039 const char *fname
= BASEDIR
"\\torture_file3c.txt";
2044 struct timeval start
;
2046 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2047 int normal_delay
= 2000000;
2048 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2049 int msec
= 1000 * sec
;
2051 torture_comment(tctx
, "\nRunning test_delayed_write_update3c\n");
2053 if (!torture_setup_dir(cli
, BASEDIR
)) {
2057 torture_comment(tctx
, "Open the file handle\n");
2058 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2061 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2065 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2066 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2071 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2072 pinfo0
.basic_info
.in
.file
.path
= fname
;
2079 /* get the initial times */
2080 GET_INFO_BOTH(finfo0
,pinfo0
);
2083 * sleep some time, to demonstrate the handling of write times
2084 * doesn't depend on the time since the open
2086 smb_msleep(5 * msec
);
2088 /* get the initial times */
2089 GET_INFO_BOTH(finfo1
,pinfo1
);
2090 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
2093 * demonstrate that a truncate write always
2094 * updates the write time immediately
2096 for (i
=0; i
< 3; i
++) {
2097 smb_msleep(2 * msec
);
2099 torture_comment(tctx
, "Do a truncate SMBwrite [%d] on the file handle\n", i
);
2100 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 512, 0);
2102 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
2106 /* get the times after the write */
2107 GET_INFO_BOTH(finfo2
,pinfo2
);
2108 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2112 start
= timeval_current();
2113 end
= timeval_add(&start
, 7 * sec
, 0);
2114 while (!timeval_expired(&end
)) {
2116 torture_comment(tctx
, "Do a write on the file handle\n");
2117 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2119 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2123 /* get the times after the write */
2124 GET_INFO_FILE(finfo2
);
2126 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
2127 double diff
= timeval_elapsed(&start
);
2128 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2129 "(1sec == %.2f) (wrong!)\n",
2134 smb_msleep(1 * msec
);
2137 GET_INFO_BOTH(finfo2
,pinfo2
);
2138 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2139 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
2140 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2144 smb_msleep(5 * msec
);
2146 /* get the initial times */
2147 GET_INFO_BOTH(finfo1
,pinfo1
);
2148 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo2
);
2151 * demonstrate that a truncate write always
2152 * updates the write time immediately
2154 for (i
=0; i
< 3; i
++) {
2155 smb_msleep(2 * msec
);
2157 torture_comment(tctx
, "Do a truncate write [%d] on the file handle\n", i
);
2158 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 512, 0);
2160 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
2164 /* get the times after the write */
2165 GET_INFO_BOTH(finfo2
,pinfo2
);
2166 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2171 smb_msleep(5 * msec
);
2173 GET_INFO_BOTH(finfo2
,pinfo2
);
2174 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2176 /* sure any further write doesn't update the write time */
2177 start
= timeval_current();
2178 end
= timeval_add(&start
, 15 * sec
, 0);
2179 while (!timeval_expired(&end
)) {
2181 torture_comment(tctx
, "Do a write on the file handle\n");
2182 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2184 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2188 /* get the times after the write */
2189 GET_INFO_BOTH(finfo2
,pinfo2
);
2191 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
2192 double diff
= timeval_elapsed(&start
);
2193 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2194 "(1sec == %.2f) (wrong!)\n",
2199 smb_msleep(1 * msec
);
2202 GET_INFO_BOTH(finfo2
,pinfo2
);
2203 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2204 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
2205 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2209 smb_msleep(5 * msec
);
2211 GET_INFO_BOTH(finfo3
,pinfo3
);
2212 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2215 * the close updates the write time to the time of the close
2216 * and not to the time of the last write!
2218 torture_comment(tctx
, "Close the file handle\n");
2219 smbcli_close(cli
->tree
, fnum1
);
2222 GET_INFO_PATH(pinfo4
);
2223 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
2225 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
2226 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
2231 smbcli_close(cli
->tree
, fnum1
);
2232 smbcli_unlink(cli
->tree
, fname
);
2233 smbcli_deltree(cli
->tree
, BASEDIR
);
2239 * Show only the first write updates the timestamp, and a close
2240 * after writes updates to current (I think this is the same
2244 static bool test_delayed_write_update4(struct torture_context
*tctx
,
2245 struct smbcli_state
*cli
,
2246 struct smbcli_state
*cli2
)
2248 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
;
2249 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
;
2250 const char *fname
= BASEDIR
"\\torture_file4.txt";
2254 struct timeval start
;
2256 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2257 int normal_delay
= 2000000;
2258 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2259 int msec
= 1000 * sec
;
2261 torture_comment(tctx
, "\nRunning test_delayed_write_update4\n");
2263 if (!torture_setup_dir(cli
, BASEDIR
)) {
2267 torture_comment(tctx
, "Open the file handle\n");
2268 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2271 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2275 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2276 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2281 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2282 pinfo0
.basic_info
.in
.file
.path
= fname
;
2289 /* get the initial times */
2290 GET_INFO_BOTH(finfo0
,pinfo0
);
2293 smb_msleep(5 * msec
);
2296 torture_comment(tctx
, "Do a write on the file handle\n");
2297 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2299 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2304 GET_INFO_BOTH(finfo1
,pinfo1
);
2305 COMPARE_WRITE_TIME_EQUAL(finfo1
,finfo0
);
2308 * make sure the write time is updated 2 seconds later
2309 * calcuated from the first write
2310 * (but expect upto 3 seconds extra time for a busy server)
2312 start
= timeval_current();
2313 end
= timeval_add(&start
, 5 * sec
, 0);
2314 while (!timeval_expired(&end
)) {
2315 /* get the times after the first write */
2316 GET_INFO_FILE(finfo1
);
2318 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
2319 double diff
= timeval_elapsed(&start
);
2320 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
2321 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2322 "(1sec == %.2f) (wrong!)\n",
2328 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2329 "(1sec == %.2f) (correct)\n",
2333 smb_msleep(0.5 * msec
);
2336 GET_INFO_BOTH(finfo1
,pinfo1
);
2337 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
2339 /* sure any further write doesn't update the write time */
2340 start
= timeval_current();
2341 end
= timeval_add(&start
, 15 * sec
, 0);
2342 while (!timeval_expired(&end
)) {
2344 torture_comment(tctx
, "Do a write on the file handle\n");
2345 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2347 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2351 /* get the times after the write */
2352 GET_INFO_BOTH(finfo2
,pinfo2
);
2354 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
2355 double diff
= timeval_elapsed(&start
);
2356 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2357 "(1sec == %.2f) (wrong!)\n",
2362 smb_msleep(1 * msec
);
2365 GET_INFO_BOTH(finfo2
,pinfo2
);
2366 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2367 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
2368 torture_comment(tctx
, "Server did not updatewrite_time (correct)\n");
2372 smb_msleep(5 * msec
);
2374 GET_INFO_BOTH(finfo3
,pinfo3
);
2375 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2378 * the close updates the write time to the time of the close
2379 * and not to the time of the last write!
2381 torture_comment(tctx
, "Close the file handle\n");
2382 smbcli_close(cli
->tree
, fnum1
);
2385 GET_INFO_PATH(pinfo4
);
2386 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
2388 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
2389 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
2394 smbcli_close(cli
->tree
, fnum1
);
2395 smbcli_unlink(cli
->tree
, fname
);
2396 smbcli_deltree(cli
->tree
, BASEDIR
);
2402 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2405 static bool test_delayed_write_update5(struct torture_context
*tctx
,
2406 struct smbcli_state
*cli
,
2407 struct smbcli_state
*cli2
)
2409 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
, finfo5
;
2410 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
, pinfo6
;
2411 const char *fname
= BASEDIR
"\\torture_file5.txt";
2415 struct timeval start
;
2417 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2418 int normal_delay
= 2000000;
2419 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2420 int msec
= 1000 * sec
;
2422 torture_comment(tctx
, "\nRunning test_delayed_write_update5\n");
2424 if (!torture_setup_dir(cli
, BASEDIR
)) {
2428 torture_comment(tctx
, "Open the file handle\n");
2429 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2432 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2436 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2437 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2443 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2444 pinfo0
.basic_info
.in
.file
.path
= fname
;
2452 /* get the initial times */
2453 GET_INFO_BOTH(finfo0
,pinfo0
);
2456 torture_comment(tctx
, "Do a write on the file handle\n");
2457 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2459 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2464 GET_INFO_BOTH(finfo1
,pinfo1
);
2465 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
2467 torture_comment(tctx
, "Set write time in the future on the file handle\n");
2468 SET_INFO_FILE(finfo0
, time(NULL
) + 86400);
2469 GET_INFO_BOTH(finfo2
,pinfo2
);
2470 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2472 torture_comment(tctx
, "Set write time in the past on the file handle\n");
2473 SET_INFO_FILE(finfo0
, time(NULL
) - 86400);
2474 GET_INFO_BOTH(finfo2
,pinfo2
);
2475 COMPARE_WRITE_TIME_LESS(finfo2
, finfo1
);
2477 /* make sure the 2 second delay from the first write are canceled */
2478 start
= timeval_current();
2479 end
= timeval_add(&start
, 15 * sec
, 0);
2480 while (!timeval_expired(&end
)) {
2482 /* get the times after the first write */
2483 GET_INFO_BOTH(finfo3
,pinfo3
);
2485 if (finfo3
.basic_info
.out
.write_time
> finfo2
.basic_info
.out
.write_time
) {
2486 double diff
= timeval_elapsed(&start
);
2487 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2488 "(1sec == %.2f) (wrong!)\n",
2493 smb_msleep(1 * msec
);
2496 GET_INFO_BOTH(finfo3
,pinfo3
);
2497 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2498 if (finfo3
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
2499 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2502 /* sure any further write doesn't update the write time */
2503 start
= timeval_current();
2504 end
= timeval_add(&start
, 15 * sec
, 0);
2505 while (!timeval_expired(&end
)) {
2507 torture_comment(tctx
, "Do a write on the file handle\n");
2508 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2510 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2514 /* get the times after the write */
2515 GET_INFO_BOTH(finfo4
,pinfo4
);
2517 if (finfo4
.basic_info
.out
.write_time
> finfo3
.basic_info
.out
.write_time
) {
2518 double diff
= timeval_elapsed(&start
);
2519 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2520 "(1sec == %.2f) (wrong!)\n",
2525 smb_msleep(1 * msec
);
2528 GET_INFO_BOTH(finfo4
,pinfo4
);
2529 COMPARE_WRITE_TIME_EQUAL(finfo4
, finfo3
);
2530 if (finfo4
.basic_info
.out
.write_time
== finfo3
.basic_info
.out
.write_time
) {
2531 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2535 smb_msleep(5 * msec
);
2537 GET_INFO_BOTH(finfo5
,pinfo5
);
2538 COMPARE_WRITE_TIME_EQUAL(finfo5
, finfo4
);
2541 * the close doesn't update the write time
2543 torture_comment(tctx
, "Close the file handle\n");
2544 smbcli_close(cli
->tree
, fnum1
);
2547 GET_INFO_PATH(pinfo6
);
2548 COMPARE_WRITE_TIME_EQUAL(pinfo6
, pinfo5
);
2550 if (pinfo6
.basic_info
.out
.write_time
== pinfo5
.basic_info
.out
.write_time
) {
2551 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
2556 smbcli_close(cli
->tree
, fnum1
);
2557 smbcli_unlink(cli
->tree
, fname
);
2558 smbcli_deltree(cli
->tree
, BASEDIR
);
2564 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2567 static bool test_delayed_write_update5b(struct torture_context
*tctx
,
2568 struct smbcli_state
*cli
,
2569 struct smbcli_state
*cli2
)
2571 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
, finfo5
;
2572 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
, pinfo6
;
2573 const char *fname
= BASEDIR
"\\torture_fileb.txt";
2577 struct timeval start
;
2579 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2580 int normal_delay
= 2000000;
2581 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2582 int msec
= 1000 * sec
;
2584 torture_comment(tctx
, "\nRunning test_delayed_write_update5b\n");
2586 if (!torture_setup_dir(cli
, BASEDIR
)) {
2590 torture_comment(tctx
, "Open the file handle\n");
2591 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2594 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2598 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2599 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2605 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2606 pinfo0
.basic_info
.in
.file
.path
= fname
;
2614 /* get the initial times */
2615 GET_INFO_BOTH(finfo0
,pinfo0
);
2618 torture_comment(tctx
, "Do a write on the file handle\n");
2619 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2621 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2626 GET_INFO_BOTH(finfo1
,pinfo1
);
2627 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
2629 torture_comment(tctx
, "Set write time in the future on the file handle\n");
2630 SET_INFO_FILE(finfo0
, time(NULL
) + 86400);
2631 GET_INFO_BOTH(finfo2
,pinfo2
);
2632 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2634 torture_comment(tctx
, "Set write time in the past on the file handle\n");
2635 SET_INFO_FILE(finfo0
, time(NULL
) - 86400);
2636 GET_INFO_BOTH(finfo2
,pinfo2
);
2637 COMPARE_WRITE_TIME_LESS(finfo2
, finfo1
);
2639 /* make sure the 2 second delay from the first write are canceled */
2640 start
= timeval_current();
2641 end
= timeval_add(&start
, 15 * sec
, 0);
2642 while (!timeval_expired(&end
)) {
2644 /* get the times after the first write */
2645 GET_INFO_BOTH(finfo3
,pinfo3
);
2647 if (finfo3
.basic_info
.out
.write_time
> finfo2
.basic_info
.out
.write_time
) {
2648 double diff
= timeval_elapsed(&start
);
2649 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2650 "(1sec == %.2f) (wrong!)\n",
2655 smb_msleep(1 * msec
);
2658 GET_INFO_BOTH(finfo3
,pinfo3
);
2659 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2660 if (finfo3
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
2661 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2664 /* Do any further write (truncates) update the write time ? */
2665 start
= timeval_current();
2666 end
= timeval_add(&start
, 15 * sec
, 0);
2667 while (!timeval_expired(&end
)) {
2669 torture_comment(tctx
, "Do a truncate write on the file handle\n");
2670 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 1024, 0);
2672 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2676 /* get the times after the write */
2677 GET_INFO_BOTH(finfo4
,pinfo4
);
2679 if (finfo4
.basic_info
.out
.write_time
> finfo3
.basic_info
.out
.write_time
) {
2680 double diff
= timeval_elapsed(&start
);
2681 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2682 "(1sec == %.2f) (wrong!)\n",
2687 smb_msleep(1 * msec
);
2690 GET_INFO_BOTH(finfo4
,pinfo4
);
2691 COMPARE_WRITE_TIME_EQUAL(finfo4
, finfo3
);
2692 if (finfo4
.basic_info
.out
.write_time
== finfo3
.basic_info
.out
.write_time
) {
2693 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2697 smb_msleep(5 * msec
);
2699 GET_INFO_BOTH(finfo5
,pinfo5
);
2700 COMPARE_WRITE_TIME_EQUAL(finfo5
, finfo4
);
2703 * the close doesn't update the write time
2705 torture_comment(tctx
, "Close the file handle\n");
2706 smbcli_close(cli
->tree
, fnum1
);
2709 GET_INFO_PATH(pinfo6
);
2710 COMPARE_WRITE_TIME_EQUAL(pinfo6
, pinfo5
);
2712 if (pinfo6
.basic_info
.out
.write_time
== pinfo5
.basic_info
.out
.write_time
) {
2713 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
2718 smbcli_close(cli
->tree
, fnum1
);
2719 smbcli_unlink(cli
->tree
, fname
);
2720 smbcli_deltree(cli
->tree
, BASEDIR
);
2726 * Open 2 handles on a file. Write one one and then set the
2727 * WRITE TIME explicitly on the other. Ensure the write time
2728 * update is cancelled. Ensure the write time is updated to
2729 * the close time when the non-explicit set handle is closed.
2733 static bool test_delayed_write_update6(struct torture_context
*tctx
,
2734 struct smbcli_state
*cli
,
2735 struct smbcli_state
*cli2
)
2737 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
, finfo5
;
2738 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
, pinfo6
, pinfo7
;
2739 const char *fname
= BASEDIR
"\\torture_file6.txt";
2744 struct timeval start
;
2746 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2747 int normal_delay
= 2000000;
2748 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2749 int msec
= 1000 * sec
;
2752 torture_comment(tctx
, "\nRunning test_delayed_write_update6\n");
2754 if (!torture_setup_dir(cli
, BASEDIR
)) {
2758 torture_comment(tctx
, "Open the file handle\n");
2759 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2762 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2767 torture_comment(tctx
, "Open the 2nd file handle on 2nd connection\n");
2768 fnum2
= smbcli_open(cli2
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2771 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2776 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2777 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2783 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2784 pinfo0
.basic_info
.in
.file
.path
= fname
;
2793 /* get the initial times */
2794 GET_INFO_BOTH(finfo0
,pinfo0
);
2797 torture_comment(tctx
, "Do a write on the file handle\n");
2798 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2800 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2805 GET_INFO_BOTH(finfo1
,pinfo1
);
2806 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
2808 torture_comment(tctx
, "Set write time in the future on the 2nd file handle\n");
2809 SET_INFO_FILE_EX(finfo0
, time(NULL
) + 86400, cli2
->tree
, fnum2
);
2810 GET_INFO_BOTH(finfo2
,pinfo2
);
2811 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2813 torture_comment(tctx
, "Set write time in the past on the 2nd file handle\n");
2814 SET_INFO_FILE_EX(finfo0
, time(NULL
) - 86400, cli2
->tree
, fnum2
);
2815 GET_INFO_BOTH(finfo2
,pinfo2
);
2816 COMPARE_WRITE_TIME_LESS(finfo2
, finfo1
);
2818 /* make sure the 2 second delay from the first write are canceled */
2819 start
= timeval_current();
2820 end
= timeval_add(&start
, 10 * sec
, 0);
2821 while (!timeval_expired(&end
)) {
2823 /* get the times after the first write */
2824 GET_INFO_BOTH(finfo3
,pinfo3
);
2826 if (finfo3
.basic_info
.out
.write_time
> finfo2
.basic_info
.out
.write_time
) {
2827 double diff
= timeval_elapsed(&start
);
2828 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2829 "(1sec == %.2f) (wrong!)\n",
2834 smb_msleep(1 * msec
);
2837 GET_INFO_BOTH(finfo3
,pinfo3
);
2838 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2839 if (finfo3
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
2840 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2843 /* sure any further write doesn't update the write time */
2844 start
= timeval_current();
2845 end
= timeval_add(&start
, 10 * sec
, 0);
2846 while (!timeval_expired(&end
)) {
2848 torture_comment(tctx
, "Do a write on the file handle\n");
2849 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2851 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2855 /* get the times after the write */
2856 GET_INFO_BOTH(finfo4
,pinfo4
);
2858 if (finfo4
.basic_info
.out
.write_time
> finfo3
.basic_info
.out
.write_time
) {
2859 double diff
= timeval_elapsed(&start
);
2860 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2861 "(1sec == %.2f) (wrong!)\n",
2866 smb_msleep(1 * msec
);
2869 GET_INFO_BOTH(finfo4
,pinfo4
);
2870 COMPARE_WRITE_TIME_EQUAL(finfo4
, finfo3
);
2871 if (finfo4
.basic_info
.out
.write_time
== finfo3
.basic_info
.out
.write_time
) {
2872 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2876 smb_msleep(5 * msec
);
2878 GET_INFO_BOTH(finfo5
,pinfo5
);
2879 COMPARE_WRITE_TIME_EQUAL(finfo5
, finfo4
);
2882 * the close updates the write time to the time of the close
2883 * as the write time was set on the 2nd handle
2885 torture_comment(tctx
, "Close the file handle\n");
2886 smbcli_close(cli
->tree
, fnum1
);
2889 GET_INFO_PATH(pinfo6
);
2890 COMPARE_WRITE_TIME_GREATER(pinfo6
, pinfo5
);
2892 if (pinfo6
.basic_info
.out
.write_time
> pinfo5
.basic_info
.out
.write_time
) {
2893 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
2896 /* See what the second write handle thinks the time is ? */
2897 finfo5
.basic_info
.in
.file
.fnum
= fnum2
;
2898 GET_INFO_FILE2(finfo5
);
2899 COMPARE_WRITE_TIME_EQUAL(finfo5
, pinfo6
);
2901 /* See if we have lost the sticky write time on handle2 */
2902 smb_msleep(3 * msec
);
2903 torture_comment(tctx
, "Have we lost the sticky write time ?\n");
2905 /* Make sure any further normal write doesn't update the write time */
2906 start
= timeval_current();
2907 end
= timeval_add(&start
, 10 * sec
, 0);
2908 while (!timeval_expired(&end
)) {
2910 torture_comment(tctx
, "Do a write on the second file handle\n");
2911 written
= smbcli_write(cli2
->tree
, fnum2
, 0, "x", 0, 1);
2913 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2917 /* get the times after the write */
2918 GET_INFO_FILE2(finfo5
);
2919 GET_INFO_PATH(pinfo6
);
2921 if (finfo5
.basic_info
.out
.write_time
> pinfo6
.basic_info
.out
.write_time
) {
2922 double diff
= timeval_elapsed(&start
);
2923 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2924 "(1sec == %.2f) (wrong!)\n",
2929 smb_msleep(1 * msec
);
2932 /* What about a truncate write ? */
2933 start
= timeval_current();
2934 end
= timeval_add(&start
, 10 * sec
, 0);
2935 while (!timeval_expired(&end
)) {
2937 torture_comment(tctx
, "Do a truncate write on the second file handle\n");
2938 written
= smbcli_write(cli2
->tree
, fnum2
, 0, "x", 0, 0);
2940 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2944 /* get the times after the write */
2945 GET_INFO_FILE2(finfo5
);
2946 GET_INFO_PATH(pinfo6
);
2948 if (finfo5
.basic_info
.out
.write_time
> pinfo6
.basic_info
.out
.write_time
) {
2949 double diff
= timeval_elapsed(&start
);
2950 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2951 "(1sec == %.2f) (wrong!)\n",
2956 smb_msleep(1 * msec
);
2960 /* keep the 2nd handle open and rerun tests */
2967 * closing the 2nd handle will cause no write time update
2968 * as the write time was explicit set on this handle
2970 torture_comment(tctx
, "Close the 2nd file handle\n");
2971 smbcli_close(cli2
->tree
, fnum2
);
2974 GET_INFO_PATH(pinfo7
);
2975 COMPARE_WRITE_TIME_EQUAL(pinfo7
, pinfo6
);
2977 if (pinfo7
.basic_info
.out
.write_time
== pinfo6
.basic_info
.out
.write_time
) {
2978 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
2983 smbcli_close(cli
->tree
, fnum1
);
2985 smbcli_close(cli2
->tree
, fnum2
);
2986 smbcli_unlink(cli
->tree
, fname
);
2987 smbcli_deltree(cli
->tree
, BASEDIR
);
2992 static bool test_delayed_write_update7(struct torture_context
*tctx
, struct smbcli_state
*cli
)
2994 union smb_open open_parms
;
2995 union smb_fileinfo finfo1
, finfo2
, finfo3
;
2996 const char *fname
= BASEDIR
"\\torture_file7.txt";
3000 TALLOC_CTX
*mem_ctx
;
3002 torture_comment(tctx
, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
3004 mem_ctx
= talloc_init("test_delayed_write_update7");
3005 if (!mem_ctx
) return false;
3007 ZERO_STRUCT(finfo1
);
3008 ZERO_STRUCT(finfo2
);
3009 ZERO_STRUCT(finfo3
);
3010 ZERO_STRUCT(open_parms
);
3012 if (!torture_setup_dir(cli
, BASEDIR
)) {
3016 /* Create the file. */
3017 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
3019 torture_result(tctx
, TORTURE_FAIL
, "Failed to open %s", fname
);
3023 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
3024 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
3028 /* Get the initial timestamps. */
3029 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
3031 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
3033 /* Set the pending write time to a value with ns. */
3034 SET_INFO_FILE_NS(finfo
, time(NULL
) + 86400, 103, cli
->tree
, fnum1
);
3036 /* Get the current pending write time by fnum. */
3037 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
3039 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
3041 /* Ensure the time is actually different. */
3042 if (finfo1
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
3043 torture_result(tctx
, TORTURE_FAIL
,
3044 "setfileinfo time matches original fileinfo time");
3048 /* Get the current pending write time by path. */
3049 finfo3
.basic_info
.in
.file
.path
= fname
;
3050 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo3
);
3052 if (finfo2
.basic_info
.out
.write_time
!= finfo3
.basic_info
.out
.write_time
) {
3053 torture_result(tctx
, TORTURE_FAIL
,
3054 "qpathinfo time doens't match fileinfo time");
3058 /* Now close the file. Re-open and check that the write
3059 time is identical to the one we wrote. */
3061 smbcli_close(cli
->tree
, fnum1
);
3063 open_parms
.ntcreatex
.level
= RAW_OPEN_NTCREATEX
;
3064 open_parms
.ntcreatex
.in
.flags
= 0;
3065 open_parms
.ntcreatex
.in
.access_mask
= SEC_GENERIC_READ
;
3066 open_parms
.ntcreatex
.in
.file_attr
= 0;
3067 open_parms
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
3068 NTCREATEX_SHARE_ACCESS_READ
|
3069 NTCREATEX_SHARE_ACCESS_WRITE
;
3070 open_parms
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
3071 open_parms
.ntcreatex
.in
.create_options
= 0;
3072 open_parms
.ntcreatex
.in
.fname
= fname
;
3074 status
= smb_raw_open(cli
->tree
, mem_ctx
, &open_parms
);
3075 talloc_free(mem_ctx
);
3077 if (!NT_STATUS_IS_OK(status
)) {
3078 torture_result(tctx
, TORTURE_FAIL
,
3079 "setfileinfo time matches original fileinfo time");
3083 fnum1
= open_parms
.ntcreatex
.out
.file
.fnum
;
3085 /* Check the returned time matches. */
3086 if (open_parms
.ntcreatex
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
3087 torture_result(tctx
, TORTURE_FAIL
,
3088 "final open time does not match set time");
3094 smbcli_close(cli
->tree
, fnum1
);
3096 smbcli_unlink(cli
->tree
, fname
);
3097 smbcli_deltree(cli
->tree
, BASEDIR
);
3102 testing of delayed update of write_time
3104 struct torture_suite
*torture_delay_write(void)
3106 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "delaywrite");
3108 torture_suite_add_2smb_test(suite
, "finfo update on close", test_finfo_after_write
);
3109 torture_suite_add_1smb_test(suite
, "delayed update of write time", test_delayed_write_update
);
3110 torture_suite_add_1smb_test(suite
, "update of write time and SMBwrite truncate", test_delayed_write_update1
);
3111 torture_suite_add_1smb_test(suite
, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a
);
3112 torture_suite_add_1smb_test(suite
, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b
);
3113 torture_suite_add_1smb_test(suite
, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c
);
3114 torture_suite_add_2smb_test(suite
, "delayed update of write time using 2 connections", test_delayed_write_update2
);
3115 torture_suite_add_2smb_test(suite
, "delayed update of write time 3", test_delayed_write_update3
);
3116 torture_suite_add_2smb_test(suite
, "delayed update of write time 3a", test_delayed_write_update3a
);
3117 torture_suite_add_2smb_test(suite
, "delayed update of write time 3b", test_delayed_write_update3b
);
3118 torture_suite_add_2smb_test(suite
, "delayed update of write time 3c", test_delayed_write_update3c
);
3119 torture_suite_add_2smb_test(suite
, "delayed update of write time 4", test_delayed_write_update4
);
3120 torture_suite_add_2smb_test(suite
, "delayed update of write time 5", test_delayed_write_update5
);
3121 torture_suite_add_2smb_test(suite
, "delayed update of write time 5b", test_delayed_write_update5b
);
3122 torture_suite_add_2smb_test(suite
, "delayed update of write time 6", test_delayed_write_update6
);
3123 torture_suite_add_1smb_test(suite
, "timestamp resolution test", test_delayed_write_update7
);
3124 torture_suite_add_1smb_test(suite
, "timestamp resolution test", test_delayed_write_update7
);