2 Unix SMB/CIFS implementation.
4 test suite for delayed write update
6 Copyright (C) Volker Lendecke 2004
7 Copyright (C) Andrew Tridgell 2004
8 Copyright (C) Jeremy Allison 2004
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "torture/torture.h"
26 #include "libcli/raw/libcliraw.h"
27 #include "libcli/raw/raw_proto.h"
28 #include "system/time.h"
29 #include "system/filesys.h"
30 #include "libcli/libcli.h"
31 #include "torture/util.h"
33 #define W2K8R2_TIMEDELAY_SECS 1
34 #define W2K3_TIMEDELAY_SECS 2
35 #define TIMEDELAY_SECS W2K3_TIMEDELAY_SECS
37 #define BASEDIR "\\delaywrite"
39 static bool test_delayed_write_update(struct torture_context
*tctx
, struct smbcli_state
*cli
)
41 union smb_fileinfo finfo1
, finfo2
;
42 const char *fname
= BASEDIR
"\\torture_file.txt";
49 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
50 int normal_delay
= 2000000;
51 double sec
= ((double)used_delay
) / ((double)normal_delay
);
52 int msec
= 1000 * sec
;
54 torture_comment(tctx
, "\nRunning test_delayed_write_update\n");
56 if (!torture_setup_dir(cli
, BASEDIR
)) {
60 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
62 torture_result(tctx
, TORTURE_FAIL
, "Failed to open %s", fname
);
66 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
67 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
70 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
72 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
74 torture_comment(tctx
, "Initial write time %s\n",
75 nt_time_string(tctx
, finfo1
.basic_info
.out
.write_time
));
77 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
80 torture_result(tctx
, TORTURE_FAIL
,
81 "write failed - wrote %d bytes (%s)\n",
82 (int)written
, __location__
);
86 start
= timeval_current();
87 end
= timeval_add(&start
, (120*sec
), 0);
88 while (!timeval_expired(&end
)) {
89 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
91 if (!NT_STATUS_IS_OK(status
)) {
92 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
96 torture_comment(tctx
, "write time %s\n",
97 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
98 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
99 double diff
= timeval_elapsed(&start
);
100 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
101 torture_comment(tctx
, "Server updated write_time after %.2f seconds"
102 "(1 sec == %.2f)(wrong!)\n",
108 torture_comment(tctx
, "Server updated write_time after %.2f seconds"
109 "(1 sec == %.2f)(correct)\n",
117 if (finfo1
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
118 torture_result(tctx
, TORTURE_FAIL
,
119 "Server did not update write time (wrong!)");
125 smbcli_close(cli
->tree
, fnum1
);
126 smbcli_unlink(cli
->tree
, fname
);
127 smbcli_deltree(cli
->tree
, BASEDIR
);
132 static bool test_delayed_write_update1(struct torture_context
*tctx
, struct smbcli_state
*cli
)
134 union smb_fileinfo finfo1
, finfo2
, finfo3
, pinfo4
;
135 const char *fname
= BASEDIR
"\\torture_file1.txt";
140 struct timeval start
;
142 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
143 int normal_delay
= 2000000;
144 double sec
= ((double)used_delay
) / ((double)normal_delay
);
145 int msec
= 1000 * sec
;
148 torture_comment(tctx
, "\nRunning test_delayed_write_update1\n");
150 if (!torture_setup_dir(cli
, BASEDIR
)) {
154 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
156 torture_result(tctx
, TORTURE_FAIL
, "Failed to open %s", fname
);
160 memset(buf
, 'x', 2048);
161 written
= smbcli_write(cli
->tree
, fnum1
, 0, buf
, 0, 2048);
163 /* 3 second delay to ensure we get past any 2 second time
164 granularity (older systems may have that) */
167 finfo1
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
168 finfo1
.all_info
.in
.file
.fnum
= fnum1
;
171 pinfo4
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
172 pinfo4
.all_info
.in
.file
.path
= fname
;
174 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
176 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
178 torture_comment(tctx
, "Initial write time %s\n",
179 nt_time_string(tctx
, finfo1
.all_info
.out
.write_time
));
181 /* 3 second delay to ensure we get past any 2 second time
182 granularity (older systems may have that) */
185 /* Do a zero length SMBwrite call to truncate. */
186 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 1024, 0);
189 torture_result(tctx
, TORTURE_FAIL
,
190 "write failed - wrote %d bytes (%s)\n",
191 (int)written
, __location__
);
195 start
= timeval_current();
196 end
= timeval_add(&start
, (120*sec
), 0);
197 while (!timeval_expired(&end
)) {
198 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
200 if (!NT_STATUS_IS_OK(status
)) {
201 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
206 if (finfo2
.all_info
.out
.size
!= 1024) {
207 torture_result(tctx
, TORTURE_FAIL
,
208 "file not truncated, size = %u (should be 1024)",
209 (unsigned int)finfo2
.all_info
.out
.size
);
214 torture_comment(tctx
, "write time %s\n",
215 nt_time_string(tctx
, finfo2
.all_info
.out
.write_time
));
216 if (finfo1
.all_info
.out
.write_time
!= finfo2
.all_info
.out
.write_time
) {
217 double diff
= timeval_elapsed(&start
);
218 if (diff
> (0.25 * sec
* 0.75)) { /* 0.75 to cope with vmware timing */
219 torture_comment(tctx
, "After SMBwrite truncate "
220 "server updated write_time after %.2f seconds"
221 "(1 sec == %.2f)(wrong!)\n",
227 torture_comment(tctx
, "After SMBwrite truncate "
228 "server updated write_time after %.2f seconds"
229 "(1 sec == %.2f)(correct)\n",
237 if (finfo1
.all_info
.out
.write_time
== finfo2
.all_info
.out
.write_time
) {
238 torture_result(tctx
, TORTURE_FAIL
,
239 "Server did not update write time (wrong!)");
246 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
247 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 0, 1);
250 torture_result(tctx
, TORTURE_FAIL
,
251 "write failed - wrote %d bytes (%s)",
252 (int)written
, __location__
);
256 start
= timeval_current();
257 end
= timeval_add(&start
, (10*sec
), 0);
258 while (!timeval_expired(&end
)) {
259 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo3
);
261 if (!NT_STATUS_IS_OK(status
)) {
262 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
267 if (finfo3
.all_info
.out
.size
!= 1024) {
268 DEBUG(0, ("file not truncated, size = %u (should be 1024)\n",
269 (unsigned int)finfo3
.all_info
.out
.size
));
274 torture_comment(tctx
, "write time %s\n",
275 nt_time_string(tctx
, finfo3
.all_info
.out
.write_time
));
276 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
277 double diff
= timeval_elapsed(&start
);
279 torture_comment(tctx
, "server updated write_time after %.2f seconds"
280 "(1 sec == %.2f)(wrong)\n",
288 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
289 torture_result(tctx
, TORTURE_FAIL
,
290 "Server updated write time (wrong!)");
297 /* the close should trigger an write time update */
298 smbcli_close(cli
->tree
, fnum1
);
301 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &pinfo4
);
302 torture_assert_ntstatus_ok(tctx
, status
, "pathinfo failed");
304 if (finfo3
.all_info
.out
.write_time
== pinfo4
.all_info
.out
.write_time
) {
305 torture_result(tctx
, TORTURE_FAIL
,
306 "Server did not update write time on close (wrong!)");
308 } else if (finfo3
.all_info
.out
.write_time
< pinfo4
.all_info
.out
.write_time
) {
309 torture_comment(tctx
, "Server updated write time on close (correct)\n");
313 smbcli_close(cli
->tree
, fnum1
);
314 smbcli_unlink(cli
->tree
, fname
);
315 smbcli_deltree(cli
->tree
, BASEDIR
);
320 /* Updating with a SMBwrite of zero length
321 * changes the write time immediately - even on expand. */
323 static bool test_delayed_write_update1a(struct torture_context
*tctx
, struct smbcli_state
*cli
)
325 union smb_fileinfo finfo1
, finfo2
, finfo3
, pinfo4
;
326 const char *fname
= BASEDIR
"\\torture_file1a.txt";
331 struct timeval start
;
333 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
334 int normal_delay
= 2000000;
335 double sec
= ((double)used_delay
) / ((double)normal_delay
);
336 int msec
= 1000 * sec
;
339 torture_comment(tctx
, "\nRunning test_delayed_write_update1a\n");
341 if (!torture_setup_dir(cli
, BASEDIR
)) {
345 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
347 torture_result(tctx
, TORTURE_FAIL
, "Failed to open %s", fname
);
351 memset(buf
, 'x', 2048);
352 written
= smbcli_write(cli
->tree
, fnum1
, 0, buf
, 0, 2048);
354 /* 3 second delay to ensure we get past any 2 second time
355 granularity (older systems may have that) */
358 finfo1
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
359 finfo1
.all_info
.in
.file
.fnum
= fnum1
;
362 pinfo4
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
363 pinfo4
.all_info
.in
.file
.path
= fname
;
365 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
367 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
369 torture_comment(tctx
, "Initial write time %s\n",
370 nt_time_string(tctx
, finfo1
.all_info
.out
.write_time
));
372 /* Do a zero length SMBwrite call to truncate. */
373 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 10240, 0);
376 torture_result(tctx
, TORTURE_FAIL
, "write failed - wrote %d bytes (%s)",
377 (int)written
, __location__
);
381 start
= timeval_current();
382 end
= timeval_add(&start
, (120*sec
), 0);
383 while (!timeval_expired(&end
)) {
384 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
386 if (!NT_STATUS_IS_OK(status
)) {
387 torture_result(tctx
, TORTURE_FAIL
, "fileinfo failed: %s",
393 if (finfo2
.all_info
.out
.size
!= 10240) {
394 torture_result(tctx
, TORTURE_FAIL
,
395 "file not truncated, size = %u (should be 10240)",
396 (unsigned int)finfo2
.all_info
.out
.size
);
401 torture_comment(tctx
, "write time %s\n",
402 nt_time_string(tctx
, finfo2
.all_info
.out
.write_time
));
403 if (finfo1
.all_info
.out
.write_time
!= finfo2
.all_info
.out
.write_time
) {
404 double diff
= timeval_elapsed(&start
);
405 if (diff
> (0.25 * sec
* 0.75)) { /* 0.75 to cope with vmware timing */
406 torture_comment(tctx
, "After SMBwrite truncate "
407 "server updated write_time after %.2f seconds"
408 "(1 sec == %.2f)(wrong!)\n",
414 torture_comment(tctx
, "After SMBwrite truncate "
415 "server updated write_time after %.2f seconds"
416 "(1 sec == %.2f)(correct)\n",
424 if (finfo1
.all_info
.out
.write_time
== finfo2
.all_info
.out
.write_time
) {
425 torture_result(tctx
, TORTURE_FAIL
,
426 "Server did not update write time (wrong!)");
433 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
434 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 0, 1);
436 torture_assert_int_equal(tctx
, written
, 1,
437 "unexpected number of bytes written");
439 start
= timeval_current();
440 end
= timeval_add(&start
, (10*sec
), 0);
441 while (!timeval_expired(&end
)) {
442 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo3
);
444 if (!NT_STATUS_IS_OK(status
)) {
445 torture_result(tctx
, TORTURE_FAIL
, "fileinfo failed: %s\n",
451 if (finfo3
.all_info
.out
.size
!= 10240) {
452 torture_result(tctx
, TORTURE_FAIL
,
453 "file not truncated, size = %u (should be 10240)",
454 (unsigned int)finfo3
.all_info
.out
.size
);
459 torture_comment(tctx
, "write time %s\n",
460 nt_time_string(tctx
, finfo3
.all_info
.out
.write_time
));
461 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
462 double diff
= timeval_elapsed(&start
);
464 torture_comment(tctx
, "server updated write_time after %.2f seconds"
465 "(1 sec == %.2f)(correct)\n",
473 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
474 torture_result(tctx
, TORTURE_FAIL
,
475 "Server updated write time (wrong!)");
479 /* the close should trigger an write time update */
480 smbcli_close(cli
->tree
, fnum1
);
483 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &pinfo4
);
484 torture_assert_ntstatus_ok(tctx
, status
, "pathinfo failed");
486 if (finfo3
.all_info
.out
.write_time
== pinfo4
.all_info
.out
.write_time
) {
487 torture_result(tctx
, TORTURE_FAIL
,
488 "Server did not update write time on close (wrong!)");
490 } else if (finfo3
.all_info
.out
.write_time
< pinfo4
.all_info
.out
.write_time
) {
491 torture_comment(tctx
, "Server updated write time on close (correct)\n");
495 smbcli_close(cli
->tree
, fnum1
);
496 smbcli_unlink(cli
->tree
, fname
);
497 smbcli_deltree(cli
->tree
, BASEDIR
);
502 /* Updating with a SET_FILE_END_OF_FILE_INFO
503 * changes the write time immediately - even on expand. */
505 static bool test_delayed_write_update1b(struct torture_context
*tctx
, struct smbcli_state
*cli
)
507 union smb_fileinfo finfo1
, finfo2
, finfo3
, pinfo4
;
508 const char *fname
= BASEDIR
"\\torture_file1b.txt";
513 struct timeval start
;
515 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
516 int normal_delay
= 2000000;
517 double sec
= ((double)used_delay
) / ((double)normal_delay
);
518 int msec
= 1000 * sec
;
521 torture_comment(tctx
, "\nRunning test_delayed_write_update1b\n");
523 if (!torture_setup_dir(cli
, BASEDIR
)) {
527 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
529 torture_result(tctx
, TORTURE_FAIL
, "Failed to open %s", fname
);
533 memset(buf
, 'x', 2048);
534 written
= smbcli_write(cli
->tree
, fnum1
, 0, buf
, 0, 2048);
536 /* 3 second delay to ensure we get past any 2 second time
537 granularity (older systems may have that) */
540 finfo1
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
541 finfo1
.all_info
.in
.file
.fnum
= fnum1
;
544 pinfo4
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
545 pinfo4
.all_info
.in
.file
.path
= fname
;
547 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
549 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
551 torture_comment(tctx
, "Initial write time %s\n",
552 nt_time_string(tctx
, finfo1
.all_info
.out
.write_time
));
554 /* Do a SET_END_OF_FILE_INFO call to truncate. */
555 status
= smbcli_ftruncate(cli
->tree
, fnum1
, (uint64_t)10240);
557 torture_assert_ntstatus_ok(tctx
, status
, "SET_END_OF_FILE failed");
559 start
= timeval_current();
560 end
= timeval_add(&start
, (120*sec
), 0);
561 while (!timeval_expired(&end
)) {
562 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
564 if (!NT_STATUS_IS_OK(status
)) {
565 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
570 if (finfo2
.all_info
.out
.size
!= 10240) {
571 torture_result(tctx
, TORTURE_FAIL
,
572 "file not truncated (size = %u, should be 10240)",
573 (unsigned int)finfo2
.all_info
.out
.size
);
578 torture_comment(tctx
, "write time %s\n",
579 nt_time_string(tctx
, finfo2
.all_info
.out
.write_time
));
580 if (finfo1
.all_info
.out
.write_time
!= finfo2
.all_info
.out
.write_time
) {
581 double diff
= timeval_elapsed(&start
);
582 if (diff
> (0.25 * sec
* 0.75)) { /* 0.75 to cope with vmware timing */
583 torture_result(tctx
, TORTURE_FAIL
,
584 "After SET_END_OF_FILE truncate "
585 "server updated write_time after %.2f seconds"
586 "(1 sec == %.2f)(wrong!)",
592 torture_comment(tctx
, "After SET_END_OF_FILE truncate "
593 "server updated write_time after %.2f seconds"
594 "(1 sec == %.2f)(correct)\n",
602 if (finfo1
.all_info
.out
.write_time
== finfo2
.all_info
.out
.write_time
) {
603 torture_result(tctx
, TORTURE_FAIL
,
604 "Server did not update write time (wrong!)");
611 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
612 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 0, 1);
614 torture_assert_int_equal(tctx
, written
, 1,
615 "unexpected number of bytes written");
617 start
= timeval_current();
618 end
= timeval_add(&start
, (10*sec
), 0);
619 while (!timeval_expired(&end
)) {
620 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo3
);
622 if (!NT_STATUS_IS_OK(status
)) {
623 torture_result(tctx
, TORTURE_FAIL
,
624 "fileinfo failed: %s", nt_errstr(status
));
629 if (finfo3
.all_info
.out
.size
!= 10240) {
630 DEBUG(0, ("file not truncated (size = %u, should be 10240)\n",
631 (unsigned int)finfo3
.all_info
.out
.size
));
636 torture_comment(tctx
, "write time %s\n",
637 nt_time_string(tctx
, finfo3
.all_info
.out
.write_time
));
638 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
639 double diff
= timeval_elapsed(&start
);
641 torture_comment(tctx
, "server updated write_time after %.2f seconds"
642 "(1 sec == %.2f)(correct)\n",
650 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
651 torture_result(tctx
, TORTURE_FAIL
, "Server updated write time (wrong!)\n");
655 /* the close should trigger an write time update */
656 smbcli_close(cli
->tree
, fnum1
);
659 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &pinfo4
);
660 torture_assert_ntstatus_ok(tctx
, status
, "pathinfo failed");
662 if (finfo3
.all_info
.out
.write_time
== pinfo4
.all_info
.out
.write_time
) {
663 torture_result(tctx
, TORTURE_FAIL
, "Server did not update write time on close (wrong!)\n");
665 } else if (finfo3
.all_info
.out
.write_time
< pinfo4
.all_info
.out
.write_time
) {
666 torture_comment(tctx
, "Server updated write time on close (correct)\n");
670 smbcli_close(cli
->tree
, fnum1
);
671 smbcli_unlink(cli
->tree
, fname
);
672 smbcli_deltree(cli
->tree
, BASEDIR
);
677 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
679 static bool test_delayed_write_update1c(struct torture_context
*tctx
, struct smbcli_state
*cli
)
681 union smb_setfileinfo parms
;
682 union smb_fileinfo finfo1
, finfo2
, finfo3
, pinfo4
;
683 const char *fname
= BASEDIR
"\\torture_file1c.txt";
688 struct timeval start
;
690 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
691 int normal_delay
= 2000000;
692 double sec
= ((double)used_delay
) / ((double)normal_delay
);
693 int msec
= 1000 * sec
;
696 torture_comment(tctx
, "\nRunning test_delayed_write_update1c\n");
698 if (!torture_setup_dir(cli
, BASEDIR
)) {
702 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
704 torture_result(tctx
, TORTURE_FAIL
, "Failed to open %s", fname
);
708 memset(buf
, 'x', 2048);
709 written
= smbcli_write(cli
->tree
, fnum1
, 0, buf
, 0, 2048);
711 /* 3 second delay to ensure we get past any 2 second time
712 granularity (older systems may have that) */
715 finfo1
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
716 finfo1
.all_info
.in
.file
.fnum
= fnum1
;
719 pinfo4
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
720 pinfo4
.all_info
.in
.file
.path
= fname
;
722 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
724 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
726 torture_comment(tctx
, "Initial write time %s\n",
727 nt_time_string(tctx
, finfo1
.all_info
.out
.write_time
));
729 /* Do a SET_ALLOCATION_SIZE call to truncate. */
730 parms
.allocation_info
.level
= RAW_SFILEINFO_ALLOCATION_INFO
;
731 parms
.allocation_info
.in
.file
.fnum
= fnum1
;
732 parms
.allocation_info
.in
.alloc_size
= 0;
734 status
= smb_raw_setfileinfo(cli
->tree
, &parms
);
736 torture_assert_ntstatus_ok(tctx
, status
,
737 "RAW_SFILEINFO_ALLOCATION_INFO failed");
739 start
= timeval_current();
740 end
= timeval_add(&start
, (120*sec
), 0);
741 while (!timeval_expired(&end
)) {
742 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
744 if (!NT_STATUS_IS_OK(status
)) {
745 torture_result(tctx
, TORTURE_FAIL
, "fileinfo failed: %s",
751 if (finfo2
.all_info
.out
.size
!= 0) {
752 torture_result(tctx
, TORTURE_FAIL
,
753 "file not truncated (size = %u, should be 10240)",
754 (unsigned int)finfo2
.all_info
.out
.size
);
759 torture_comment(tctx
, "write time %s\n",
760 nt_time_string(tctx
, finfo2
.all_info
.out
.write_time
));
761 if (finfo1
.all_info
.out
.write_time
!= finfo2
.all_info
.out
.write_time
) {
762 double diff
= timeval_elapsed(&start
);
763 if (diff
> (0.25 * sec
* 0.75)) { /* 0.75 to cope with vmware timing */
764 torture_comment(tctx
, "After SET_ALLOCATION_INFO truncate "
765 "server updated write_time after %.2f seconds"
766 "(1 sec == %.2f)(wrong!)\n",
772 torture_comment(tctx
, "After SET_ALLOCATION_INFO truncate "
773 "server updated write_time after %.2f seconds"
774 "(1 sec == %.2f)(correct)\n",
782 if (finfo1
.all_info
.out
.write_time
== finfo2
.all_info
.out
.write_time
) {
783 torture_result(tctx
, TORTURE_FAIL
,
784 "Server did not update write time (wrong!)");
791 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
792 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 0, 1);
793 torture_assert_int_equal(tctx
, written
, 1,
794 "Unexpected number of bytes written");
796 start
= timeval_current();
797 end
= timeval_add(&start
, (10*sec
), 0);
798 while (!timeval_expired(&end
)) {
799 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo3
);
801 if (!NT_STATUS_IS_OK(status
)) {
802 torture_result(tctx
, TORTURE_FAIL
, "fileinfo failed: %s",
808 if (finfo3
.all_info
.out
.size
!= 1) {
809 torture_result(tctx
, TORTURE_FAIL
, "file not expanded");
814 torture_comment(tctx
, "write time %s\n",
815 nt_time_string(tctx
, finfo3
.all_info
.out
.write_time
));
816 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
817 double diff
= timeval_elapsed(&start
);
819 torture_comment(tctx
, "server updated write_time after %.2f seconds"
820 "(1 sec == %.2f)(correct)\n",
828 if (finfo2
.all_info
.out
.write_time
!= finfo3
.all_info
.out
.write_time
) {
829 torture_result(tctx
, TORTURE_FAIL
,
830 "Server updated write time (wrong!)");
834 /* the close should trigger an write time update */
835 smbcli_close(cli
->tree
, fnum1
);
838 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &pinfo4
);
839 torture_assert_ntstatus_ok(tctx
, status
, "pathinfo failed");
841 if (finfo3
.all_info
.out
.write_time
== pinfo4
.all_info
.out
.write_time
) {
842 torture_result(tctx
, TORTURE_FAIL
, "Server did not update write time on close (wrong!)\n");
844 } else if (finfo3
.all_info
.out
.write_time
< pinfo4
.all_info
.out
.write_time
) {
845 torture_comment(tctx
, "Server updated write time on close (correct)\n");
849 smbcli_close(cli
->tree
, fnum1
);
850 smbcli_unlink(cli
->tree
, fname
);
851 smbcli_deltree(cli
->tree
, BASEDIR
);
857 * Do as above, but using 2 connections.
860 static bool test_delayed_write_update2(struct torture_context
*tctx
, struct smbcli_state
*cli
,
861 struct smbcli_state
*cli2
)
863 union smb_fileinfo finfo1
, finfo2
;
864 const char *fname
= BASEDIR
"\\torture_file.txt";
870 struct timeval start
;
872 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
873 int normal_delay
= 2000000;
874 double sec
= ((double)used_delay
) / ((double)normal_delay
);
875 int msec
= 1000 * sec
;
876 union smb_flush flsh
;
878 torture_comment(tctx
, "\nRunning test_delayed_write_update2\n");
880 if (!torture_setup_dir(cli
, BASEDIR
)) {
884 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
886 torture_comment(tctx
, "Failed to open %s\n", fname
);
890 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
891 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
894 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
896 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
898 torture_comment(tctx
, "Initial write time %s\n",
899 nt_time_string(tctx
, finfo1
.basic_info
.out
.write_time
));
901 /* 3 second delay to ensure we get past any 2 second time
902 granularity (older systems may have that) */
906 /* Try using setfileinfo instead of write to update write time. */
907 union smb_setfileinfo sfinfo
;
908 time_t t_set
= time(NULL
);
909 sfinfo
.basic_info
.level
= RAW_SFILEINFO_BASIC_INFO
;
910 sfinfo
.basic_info
.in
.file
.fnum
= fnum1
;
911 sfinfo
.basic_info
.in
.create_time
= finfo1
.basic_info
.out
.create_time
;
912 sfinfo
.basic_info
.in
.access_time
= finfo1
.basic_info
.out
.access_time
;
914 /* I tried this with both + and - ve to see if it makes a different.
915 It doesn't - once the filetime is set via setfileinfo it stays that way. */
917 unix_to_nt_time(&sfinfo
.basic_info
.in
.write_time
, t_set
- 30000);
919 unix_to_nt_time(&sfinfo
.basic_info
.in
.write_time
, t_set
+ 30000);
921 sfinfo
.basic_info
.in
.change_time
= finfo1
.basic_info
.out
.change_time
;
922 sfinfo
.basic_info
.in
.attrib
= finfo1
.basic_info
.out
.attrib
;
924 status
= smb_raw_setfileinfo(cli
->tree
, &sfinfo
);
926 torture_assert_ntstatus_ok(tctx
, status
, "sfileinfo failed");
929 finfo2
.basic_info
.in
.file
.path
= fname
;
931 status
= smb_raw_pathinfo(cli2
->tree
, tctx
, &finfo2
);
933 if (!NT_STATUS_IS_OK(status
)) {
934 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
937 torture_comment(tctx
, "write time %s\n",
938 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
940 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
941 torture_comment(tctx
, "Server updated write_time (correct)\n");
943 torture_result(tctx
, TORTURE_FAIL
, "Server did not update write time (wrong!)\n");
947 /* Now try a write to see if the write time gets reset. */
949 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
950 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
953 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
955 if (!NT_STATUS_IS_OK(status
)) {
956 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
960 torture_comment(tctx
, "Modified write time %s\n",
961 nt_time_string(tctx
, finfo1
.basic_info
.out
.write_time
));
964 torture_comment(tctx
, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
966 written
= smbcli_write(cli
->tree
, fnum1
, 0, "0123456789", 1, 10);
969 torture_comment(tctx
, "write failed - wrote %d bytes (%s)\n",
970 (int)written
, __location__
);
974 /* Just to prove to tridge that the an smbflush has no effect on
975 the write time :-). The setfileinfo IS STICKY. JRA. */
977 torture_comment(tctx
, "Doing flush after write\n");
979 flsh
.flush
.level
= RAW_FLUSH_FLUSH
;
980 flsh
.flush
.in
.file
.fnum
= fnum1
;
981 status
= smb_raw_flush(cli
->tree
, &flsh
);
982 if (!NT_STATUS_IS_OK(status
)) {
983 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status
)));
987 /* Once the time was set using setfileinfo then it stays set - writes
988 don't have any effect. But make sure. */
989 start
= timeval_current();
990 end
= timeval_add(&start
, (15*sec
), 0);
991 while (!timeval_expired(&end
)) {
992 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
994 if (!NT_STATUS_IS_OK(status
)) {
995 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
999 torture_comment(tctx
, "write time %s\n",
1000 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1001 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
1002 double diff
= timeval_elapsed(&start
);
1003 torture_comment(tctx
, "Server updated write_time after %.2f seconds"
1004 "(1sec == %.2f) (wrong!)\n",
1013 if (finfo1
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
1014 torture_comment(tctx
, "Server did not update write time (correct)\n");
1020 fnum2
= smbcli_open(cli
->tree
, fname
, O_RDWR
, DENY_NONE
);
1022 torture_comment(tctx
, "Failed to open %s\n", fname
);
1026 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");
1028 written
= smbcli_write(cli
->tree
, fnum2
, 0, "0123456789", 11, 10);
1030 if (written
!= 10) {
1031 torture_comment(tctx
, "write failed - wrote %d bytes (%s)\n",
1032 (int)written
, __location__
);
1036 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
1038 if (!NT_STATUS_IS_OK(status
)) {
1039 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1042 torture_comment(tctx
, "write time %s\n",
1043 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1044 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
1045 torture_comment(tctx
, "Server updated write_time (wrong!)\n");
1049 torture_comment(tctx
, "Closing the first fd to see if write time updated.\n");
1050 smbcli_close(cli
->tree
, fnum1
);
1053 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");
1055 written
= smbcli_write(cli
->tree
, fnum2
, 0, "0123456789", 21, 10);
1057 if (written
!= 10) {
1058 torture_comment(tctx
, "write failed - wrote %d bytes (%s)\n",
1059 (int)written
, __location__
);
1063 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1064 finfo1
.basic_info
.in
.file
.fnum
= fnum2
;
1066 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
1068 if (!NT_STATUS_IS_OK(status
)) {
1069 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1072 torture_comment(tctx
, "write time %s\n",
1073 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1074 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
1075 torture_comment(tctx
, "Server updated write_time (wrong!)\n");
1079 /* Once the time was set using setfileinfo then it stays set - writes
1080 don't have any effect. But make sure. */
1081 start
= timeval_current();
1082 end
= timeval_add(&start
, (15*sec
), 0);
1083 while (!timeval_expired(&end
)) {
1084 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
1086 if (!NT_STATUS_IS_OK(status
)) {
1087 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1091 torture_comment(tctx
, "write time %s\n",
1092 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1093 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
1094 double diff
= timeval_elapsed(&start
);
1095 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1096 "(1sec == %.2f) (wrong!)\n",
1105 if (finfo1
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
1106 torture_comment(tctx
, "Server did not update write time (correct)\n");
1109 torture_comment(tctx
, "Closing second fd to see if write time updated.\n");
1111 smbcli_close(cli
->tree
, fnum2
);
1114 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
, DENY_NONE
);
1116 torture_comment(tctx
, "Failed to open %s\n", fname
);
1120 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1121 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
1124 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
1126 if (!NT_STATUS_IS_OK(status
)) {
1127 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1131 torture_comment(tctx
, "Second open initial write time %s\n",
1132 nt_time_string(tctx
, finfo1
.basic_info
.out
.write_time
));
1135 torture_comment(tctx
, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1137 written
= smbcli_write(cli
->tree
, fnum1
, 0, "0123456789", 31, 10);
1139 if (written
!= 10) {
1140 torture_comment(tctx
, "write failed - wrote %d bytes (%s)\n",
1141 (int)written
, __location__
);
1145 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1146 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
1148 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
1150 if (!NT_STATUS_IS_OK(status
)) {
1151 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1154 torture_comment(tctx
, "write time %s\n",
1155 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1156 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
1157 torture_comment(tctx
, "Server updated write_time (wrong!)\n");
1161 /* Now the write time should be updated again */
1162 start
= timeval_current();
1163 end
= timeval_add(&start
, (15*sec
), 0);
1164 while (!timeval_expired(&end
)) {
1165 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
1167 if (!NT_STATUS_IS_OK(status
)) {
1168 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1172 torture_comment(tctx
, "write time %s\n",
1173 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1174 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
1175 double diff
= timeval_elapsed(&start
);
1176 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
1177 torture_comment(tctx
, "Server updated write_time after %.2f seconds"
1178 "(1sec == %.2f) (wrong!)\n",
1184 torture_comment(tctx
, "Server updated write_time after %.2f seconds"
1185 "(1sec == %.2f) (correct)\n",
1193 if (finfo1
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
1194 torture_result(tctx
, TORTURE_FAIL
, "Server did not update write time (wrong!)\n");
1199 /* One more test to do. We should read the filetime via findfirst on the
1200 second connection to ensure it's the same. This is very easy for a Windows
1201 server but a bastard to get right on a POSIX server. JRA. */
1204 smbcli_close(cli
->tree
, fnum1
);
1205 smbcli_unlink(cli
->tree
, fname
);
1206 smbcli_deltree(cli
->tree
, BASEDIR
);
1212 /* Windows does obviously not update the stat info during a write call. I
1213 * *think* this is the problem causing a spurious Excel 2003 on XP error
1214 * message when saving a file. Excel does a setfileinfo, writes, and then does
1215 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1216 * that the file might have been changed in between. What i've been able to
1217 * trace down is that this happens if the getpathinfo after the write shows a
1218 * different last write time than the setfileinfo showed. This is really
1222 static bool test_finfo_after_write(struct torture_context
*tctx
, struct smbcli_state
*cli
,
1223 struct smbcli_state
*cli2
)
1225 union smb_fileinfo finfo1
, finfo2
;
1226 const char *fname
= BASEDIR
"\\torture_file.txt";
1232 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
1233 int normal_delay
= 2000000;
1234 double sec
= ((double)used_delay
) / ((double)normal_delay
);
1235 int msec
= 1000 * sec
;
1237 torture_comment(tctx
, "\nRunning test_finfo_after_write\n");
1239 if (!torture_setup_dir(cli
, BASEDIR
)) {
1243 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
1246 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
1250 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1251 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
1253 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
1255 if (!NT_STATUS_IS_OK(status
)) {
1257 torture_result(tctx
, TORTURE_FAIL
, __location__
": fileinfo failed: %s", nt_errstr(status
));
1263 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1266 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1271 fnum2
= smbcli_open(cli2
->tree
, fname
, O_RDWR
, DENY_NONE
);
1273 torture_result(tctx
, TORTURE_FAIL
, __location__
": failed to open 2nd time - %s",
1274 smbcli_errstr(cli2
->tree
));
1279 written
= smbcli_write(cli2
->tree
, fnum2
, 0, "x", 0, 1);
1282 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1",
1288 finfo2
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1289 finfo2
.basic_info
.in
.file
.path
= fname
;
1291 status
= smb_raw_pathinfo(cli2
->tree
, tctx
, &finfo2
);
1293 if (!NT_STATUS_IS_OK(status
)) {
1294 torture_result(tctx
, TORTURE_FAIL
, __location__
": fileinfo failed: %s",
1300 if (finfo1
.basic_info
.out
.create_time
!=
1301 finfo2
.basic_info
.out
.create_time
) {
1302 torture_result(tctx
, TORTURE_FAIL
, __location__
": create_time changed");
1307 if (finfo1
.basic_info
.out
.access_time
!=
1308 finfo2
.basic_info
.out
.access_time
) {
1309 torture_result(tctx
, TORTURE_FAIL
, __location__
": access_time changed");
1314 if (finfo1
.basic_info
.out
.write_time
!=
1315 finfo2
.basic_info
.out
.write_time
) {
1316 torture_result(tctx
, TORTURE_FAIL
, __location__
": write_time changed:\n"
1317 "write time conn 1 = %s, conn 2 = %s",
1318 nt_time_string(tctx
, finfo1
.basic_info
.out
.write_time
),
1319 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1324 if (finfo1
.basic_info
.out
.change_time
!=
1325 finfo2
.basic_info
.out
.change_time
) {
1326 torture_result(tctx
, TORTURE_FAIL
, __location__
": change_time changed");
1331 /* One of the two following calls updates the qpathinfo. */
1333 /* If you had skipped the smbcli_write on fnum2, it would
1334 * *not* have updated the stat on disk */
1336 smbcli_close(cli2
->tree
, fnum2
);
1339 /* This call is only for the people looking at ethereal :-) */
1340 finfo2
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1341 finfo2
.basic_info
.in
.file
.path
= fname
;
1343 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo2
);
1345 if (!NT_STATUS_IS_OK(status
)) {
1346 torture_result(tctx
, TORTURE_FAIL
, __location__
": fileinfo failed: %s", nt_errstr(status
));
1353 smbcli_close(cli
->tree
, fnum1
);
1354 smbcli_unlink(cli
->tree
, fname
);
1355 smbcli_deltree(cli
->tree
, BASEDIR
);
1360 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1361 uint64_t r = 10*1000*1000; \
1362 NTTIME g = (given).basic_info.out.write_time; \
1363 NTTIME gr = (g / r) * r; \
1364 NTTIME c = (correct).basic_info.out.write_time; \
1365 NTTIME cr = (c / r) * r; \
1366 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1368 if (strict && (g cmp c)) { \
1370 } else if ((g cmp c) && (gr cmp cr)) { \
1371 /* handle filesystem without high resolution timestamps */ \
1375 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1376 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1377 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1382 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1383 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1384 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1385 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1386 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1387 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1389 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1390 NTTIME g = (given).basic_info.out.access_time; \
1391 NTTIME c = (correct).basic_info.out.access_time; \
1393 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1394 #given, nt_time_string(tctx, g), \
1395 #cmp, #correct, nt_time_string(tctx, c)); \
1400 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1401 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1403 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1404 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1405 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1408 #define GET_INFO_FILE(finfo) do { \
1410 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1411 if (!NT_STATUS_IS_OK(_status)) { \
1413 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1414 nt_errstr(_status)); \
1417 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1418 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1419 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1421 #define GET_INFO_FILE2(finfo) do { \
1423 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1424 if (!NT_STATUS_IS_OK(_status)) { \
1426 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1427 nt_errstr(_status)); \
1430 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1431 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1432 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1434 #define GET_INFO_PATH(pinfo) do { \
1436 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1437 if (!NT_STATUS_IS_OK(_status)) { \
1438 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1439 nt_errstr(_status)); \
1443 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1444 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1445 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1447 #define GET_INFO_BOTH(finfo,pinfo) do { \
1448 GET_INFO_FILE(finfo); \
1449 GET_INFO_PATH(pinfo); \
1450 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1453 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1455 union smb_setfileinfo sfinfo; \
1456 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1457 sfinfo.basic_info.in.file.fnum = tfnum; \
1458 sfinfo.basic_info.in.create_time = 0; \
1459 sfinfo.basic_info.in.access_time = 0; \
1460 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1461 sfinfo.basic_info.in.change_time = 0; \
1462 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1463 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1464 if (!NT_STATUS_IS_OK(_status)) { \
1465 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1466 nt_errstr(_status)); \
1471 #define SET_INFO_FILE(finfo, wrtime) \
1472 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1474 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1476 union smb_setfileinfo sfinfo; \
1477 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1478 sfinfo.basic_info.in.file.fnum = tfnum; \
1479 sfinfo.basic_info.in.create_time = 0; \
1480 sfinfo.basic_info.in.access_time = 0; \
1481 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1482 sfinfo.basic_info.in.write_time += (ns); \
1483 sfinfo.basic_info.in.change_time = 0; \
1484 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1485 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1486 if (!NT_STATUS_IS_OK(_status)) { \
1487 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1488 nt_errstr(_status)); \
1494 static bool test_delayed_write_update3(struct torture_context
*tctx
,
1495 struct smbcli_state
*cli
,
1496 struct smbcli_state
*cli2
)
1498 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
;
1499 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
;
1500 const char *fname
= BASEDIR
"\\torture_file3.txt";
1504 struct timeval start
;
1506 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
1507 int normal_delay
= 2000000;
1508 double sec
= ((double)used_delay
) / ((double)normal_delay
);
1509 int msec
= 1000 * sec
;
1511 torture_comment(tctx
, "\nRunning test_delayed_write_update3\n");
1513 if (!torture_setup_dir(cli
, BASEDIR
)) {
1517 torture_comment(tctx
, "Open the file handle\n");
1518 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
1521 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
1525 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1526 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
1531 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1532 pinfo0
.basic_info
.in
.file
.path
= fname
;
1539 /* get the initial times */
1540 GET_INFO_BOTH(finfo0
,pinfo0
);
1543 * make sure the write time is updated 2 seconds later
1544 * calcuated from the first write
1545 * (but expect upto 5 seconds extra time for a busy server)
1547 start
= timeval_current();
1548 end
= timeval_add(&start
, 7 * sec
, 0);
1549 while (!timeval_expired(&end
)) {
1551 torture_comment(tctx
, "Do a write on the file handle\n");
1552 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1554 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1558 /* get the times after the write */
1559 GET_INFO_FILE(finfo1
);
1561 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
1562 double diff
= timeval_elapsed(&start
);
1563 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
1564 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1565 "(1sec == %.2f) (wrong!)\n",
1571 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1572 "(1sec == %.2f) (correct)\n",
1579 GET_INFO_BOTH(finfo1
,pinfo1
);
1580 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
1582 /* sure any further write doesn't update the write time */
1583 start
= timeval_current();
1584 end
= timeval_add(&start
, 15 * sec
, 0);
1585 while (!timeval_expired(&end
)) {
1587 torture_comment(tctx
, "Do a write on the file handle\n");
1588 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1590 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1594 /* get the times after the write */
1595 GET_INFO_BOTH(finfo2
,pinfo2
);
1597 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
1598 double diff
= timeval_elapsed(&start
);
1599 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1600 "(1sec == %.2f) (wrong!)\n",
1608 GET_INFO_BOTH(finfo2
,pinfo2
);
1609 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
1610 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
1611 torture_comment(tctx
, "Server did not update write_time (correct)\n");
1617 GET_INFO_BOTH(finfo3
,pinfo3
);
1618 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
1621 * the close updates the write time to the time of the close
1622 * and not to the time of the last write!
1624 torture_comment(tctx
, "Close the file handle\n");
1625 smbcli_close(cli
->tree
, fnum1
);
1628 GET_INFO_PATH(pinfo4
);
1629 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
1631 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
1632 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
1637 smbcli_close(cli
->tree
, fnum1
);
1638 smbcli_unlink(cli
->tree
, fname
);
1639 smbcli_deltree(cli
->tree
, BASEDIR
);
1645 * Show that a truncate write always updates the write time even
1646 * if an initial write has already updated the write time.
1649 static bool test_delayed_write_update3a(struct torture_context
*tctx
,
1650 struct smbcli_state
*cli
,
1651 struct smbcli_state
*cli2
)
1653 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
;
1654 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
;
1655 const char *fname
= BASEDIR
"\\torture_file3a.txt";
1660 struct timeval start
;
1662 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
1663 int normal_delay
= 2000000;
1664 double sec
= ((double)used_delay
) / ((double)normal_delay
);
1665 int msec
= 1000 * sec
;
1667 torture_comment(tctx
, "\nRunning test_delayed_write_update3a\n");
1669 if (!torture_setup_dir(cli
, BASEDIR
)) {
1673 torture_comment(tctx
, "Open the file handle\n");
1674 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
1677 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
1681 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1682 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
1687 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1688 pinfo0
.basic_info
.in
.file
.path
= fname
;
1695 /* get the initial times */
1696 GET_INFO_BOTH(finfo0
,pinfo0
);
1699 * sleep some time, to demonstrate the handling of write times
1700 * doesn't depend on the time since the open
1704 /* get the initial times */
1705 GET_INFO_BOTH(finfo1
,pinfo1
);
1706 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
1709 * make sure the write time is updated 2 seconds later
1710 * calcuated from the first write
1711 * (but expect upto 5 seconds extra time for a busy server)
1713 start
= timeval_current();
1714 end
= timeval_add(&start
, 7 * sec
, 0);
1715 while (!timeval_expired(&end
)) {
1717 torture_comment(tctx
, "Do a write on the file handle\n");
1718 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1720 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1724 /* get the times after the write */
1725 GET_INFO_FILE(finfo1
);
1727 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
1728 double diff
= timeval_elapsed(&start
);
1729 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
1730 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1731 "(1sec == %.2f) (wrong!)\n",
1737 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1738 "(1sec == %.2f) (correct)\n",
1745 GET_INFO_BOTH(finfo1
,pinfo1
);
1746 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
1751 * demonstrate that a truncate write always
1752 * updates the write time immediately
1754 for (i
=0; i
< 3; i
++) {
1757 torture_comment(tctx
, "Do a truncate SMBwrite [%d] on the file handle\n", i
);
1758 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 10240, 0);
1760 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
1764 /* get the times after the write */
1765 GET_INFO_BOTH(finfo2
,pinfo2
);
1766 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
1772 /* sure any further write doesn't update the write time */
1773 start
= timeval_current();
1774 end
= timeval_add(&start
, 15 * sec
, 0);
1775 while (!timeval_expired(&end
)) {
1777 torture_comment(tctx
, "Do a write on the file handle\n");
1778 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1780 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1784 /* get the times after the write */
1785 GET_INFO_BOTH(finfo2
,pinfo2
);
1787 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
1788 double diff
= timeval_elapsed(&start
);
1789 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1790 "(1sec == %.2f) (wrong!)\n",
1798 GET_INFO_BOTH(finfo2
,pinfo2
);
1799 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
1800 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
1801 torture_comment(tctx
, "Server did not update write_time (correct)\n");
1807 /* get the initial times */
1808 GET_INFO_BOTH(finfo1
,pinfo1
);
1809 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo2
);
1812 * demonstrate that a truncate write always
1813 * updates the write time immediately
1815 for (i
=0; i
< 3; i
++) {
1818 torture_comment(tctx
, "Do a truncate SMBwrite [%d] on the file handle\n", i
);
1819 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 512, 0);
1821 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
1825 /* get the times after the write */
1826 GET_INFO_BOTH(finfo2
,pinfo2
);
1827 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
1834 GET_INFO_BOTH(finfo3
,pinfo3
);
1835 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
1838 * the close doesn't update the write time
1840 torture_comment(tctx
, "Close the file handle\n");
1841 smbcli_close(cli
->tree
, fnum1
);
1844 GET_INFO_PATH(pinfo4
);
1845 COMPARE_WRITE_TIME_EQUAL(pinfo4
, pinfo3
);
1847 if (pinfo4
.basic_info
.out
.write_time
== pinfo3
.basic_info
.out
.write_time
) {
1848 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
1853 smbcli_close(cli
->tree
, fnum1
);
1854 smbcli_unlink(cli
->tree
, fname
);
1855 smbcli_deltree(cli
->tree
, BASEDIR
);
1861 * Show a close after write updates the write timestamp to
1862 * the close time, not the last write time.
1865 static bool test_delayed_write_update3b(struct torture_context
*tctx
,
1866 struct smbcli_state
*cli
,
1867 struct smbcli_state
*cli2
)
1869 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
;
1870 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
;
1871 const char *fname
= BASEDIR
"\\torture_file3b.txt";
1875 struct timeval start
;
1877 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
1878 int normal_delay
= 2000000;
1879 double sec
= ((double)used_delay
) / ((double)normal_delay
);
1880 int msec
= 1000 * sec
;
1882 torture_comment(tctx
, "\nRunning test_delayed_write_update3b\n");
1884 if (!torture_setup_dir(cli
, BASEDIR
)) {
1888 torture_comment(tctx
, "Open the file handle\n");
1889 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
1892 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
1896 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1897 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
1902 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1903 pinfo0
.basic_info
.in
.file
.path
= fname
;
1910 /* get the initial times */
1911 GET_INFO_BOTH(finfo0
,pinfo0
);
1914 * sleep some time, to demonstrate the handling of write times
1915 * doesn't depend on the time since the open
1919 /* get the initial times */
1920 GET_INFO_BOTH(finfo1
,pinfo1
);
1921 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
1924 * make sure the write time is updated 2 seconds later
1925 * calcuated from the first write
1926 * (but expect upto 5 seconds extra time for a busy server)
1928 start
= timeval_current();
1929 end
= timeval_add(&start
, 7 * sec
, 0);
1930 while (!timeval_expired(&end
)) {
1932 torture_comment(tctx
, "Do a write on the file handle\n");
1933 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1935 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1939 /* get the times after the write */
1940 GET_INFO_FILE(finfo1
);
1942 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
1943 double diff
= timeval_elapsed(&start
);
1944 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
1945 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1946 "(1sec == %.2f) (wrong!)\n",
1952 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1953 "(1sec == %.2f) (correct)\n",
1960 GET_INFO_BOTH(finfo1
,pinfo1
);
1961 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
1963 /* sure any further write doesn't update the write time */
1964 start
= timeval_current();
1965 end
= timeval_add(&start
, 15 * sec
, 0);
1966 while (!timeval_expired(&end
)) {
1968 torture_comment(tctx
, "Do a write on the file handle\n");
1969 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1971 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1975 /* get the times after the write */
1976 GET_INFO_BOTH(finfo2
,pinfo2
);
1978 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
1979 double diff
= timeval_elapsed(&start
);
1980 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1981 "(1sec == %.2f) (wrong!)\n",
1989 GET_INFO_BOTH(finfo2
,pinfo2
);
1990 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
1991 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
1992 torture_comment(tctx
, "Server did not update write_time (correct)\n");
1998 GET_INFO_BOTH(finfo3
,pinfo3
);
1999 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2002 * the close updates the write time to the time of the close
2003 * and not to the time of the last write!
2005 torture_comment(tctx
, "Close the file handle\n");
2006 smbcli_close(cli
->tree
, fnum1
);
2009 GET_INFO_PATH(pinfo4
);
2010 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
2012 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
2013 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
2018 smbcli_close(cli
->tree
, fnum1
);
2019 smbcli_unlink(cli
->tree
, fname
);
2020 smbcli_deltree(cli
->tree
, BASEDIR
);
2026 * Check that a write after a truncate write doesn't update
2027 * the timestamp, but a truncate write after a write does.
2028 * Also prove that a close after a truncate write updates the
2029 * timestamp to current, not the time of last write.
2032 static bool test_delayed_write_update3c(struct torture_context
*tctx
,
2033 struct smbcli_state
*cli
,
2034 struct smbcli_state
*cli2
)
2036 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
;
2037 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
;
2038 const char *fname
= BASEDIR
"\\torture_file3c.txt";
2043 struct timeval start
;
2045 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2046 int normal_delay
= 2000000;
2047 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2048 int msec
= 1000 * sec
;
2050 torture_comment(tctx
, "\nRunning test_delayed_write_update3c\n");
2052 if (!torture_setup_dir(cli
, BASEDIR
)) {
2056 torture_comment(tctx
, "Open the file handle\n");
2057 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2060 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2064 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2065 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2070 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2071 pinfo0
.basic_info
.in
.file
.path
= fname
;
2078 /* get the initial times */
2079 GET_INFO_BOTH(finfo0
,pinfo0
);
2082 * sleep some time, to demonstrate the handling of write times
2083 * doesn't depend on the time since the open
2087 /* get the initial times */
2088 GET_INFO_BOTH(finfo1
,pinfo1
);
2089 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
2092 * demonstrate that a truncate write always
2093 * updates the write time immediately
2095 for (i
=0; i
< 3; i
++) {
2098 torture_comment(tctx
, "Do a truncate SMBwrite [%d] on the file handle\n", i
);
2099 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 512, 0);
2101 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
2105 /* get the times after the write */
2106 GET_INFO_BOTH(finfo2
,pinfo2
);
2107 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2111 start
= timeval_current();
2112 end
= timeval_add(&start
, 7 * sec
, 0);
2113 while (!timeval_expired(&end
)) {
2115 torture_comment(tctx
, "Do a write on the file handle\n");
2116 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2118 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2122 /* get the times after the write */
2123 GET_INFO_FILE(finfo2
);
2125 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
2126 double diff
= timeval_elapsed(&start
);
2127 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2128 "(1sec == %.2f) (wrong!)\n",
2136 GET_INFO_BOTH(finfo2
,pinfo2
);
2137 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2138 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
2139 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2145 /* get the initial times */
2146 GET_INFO_BOTH(finfo1
,pinfo1
);
2147 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo2
);
2150 * demonstrate that a truncate write always
2151 * updates the write time immediately
2153 for (i
=0; i
< 3; i
++) {
2156 torture_comment(tctx
, "Do a truncate write [%d] on the file handle\n", i
);
2157 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 512, 0);
2159 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
2163 /* get the times after the write */
2164 GET_INFO_BOTH(finfo2
,pinfo2
);
2165 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2172 GET_INFO_BOTH(finfo2
,pinfo2
);
2173 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2175 /* sure any further write doesn't update the write time */
2176 start
= timeval_current();
2177 end
= timeval_add(&start
, 15 * sec
, 0);
2178 while (!timeval_expired(&end
)) {
2180 torture_comment(tctx
, "Do a write on the file handle\n");
2181 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2183 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2187 /* get the times after the write */
2188 GET_INFO_BOTH(finfo2
,pinfo2
);
2190 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
2191 double diff
= timeval_elapsed(&start
);
2192 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2193 "(1sec == %.2f) (wrong!)\n",
2201 GET_INFO_BOTH(finfo2
,pinfo2
);
2202 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2203 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
2204 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2210 GET_INFO_BOTH(finfo3
,pinfo3
);
2211 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2214 * the close updates the write time to the time of the close
2215 * and not to the time of the last write!
2217 torture_comment(tctx
, "Close the file handle\n");
2218 smbcli_close(cli
->tree
, fnum1
);
2221 GET_INFO_PATH(pinfo4
);
2222 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
2224 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
2225 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
2230 smbcli_close(cli
->tree
, fnum1
);
2231 smbcli_unlink(cli
->tree
, fname
);
2232 smbcli_deltree(cli
->tree
, BASEDIR
);
2238 * Show only the first write updates the timestamp, and a close
2239 * after writes updates to current (I think this is the same
2243 static bool test_delayed_write_update4(struct torture_context
*tctx
,
2244 struct smbcli_state
*cli
,
2245 struct smbcli_state
*cli2
)
2247 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
;
2248 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
;
2249 const char *fname
= BASEDIR
"\\torture_file4.txt";
2253 struct timeval start
;
2255 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2256 int normal_delay
= 2000000;
2257 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2258 int msec
= 1000 * sec
;
2260 torture_comment(tctx
, "\nRunning test_delayed_write_update4\n");
2262 if (!torture_setup_dir(cli
, BASEDIR
)) {
2266 torture_comment(tctx
, "Open the file handle\n");
2267 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2270 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2274 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2275 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2280 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2281 pinfo0
.basic_info
.in
.file
.path
= fname
;
2288 /* get the initial times */
2289 GET_INFO_BOTH(finfo0
,pinfo0
);
2295 torture_comment(tctx
, "Do a write on the file handle\n");
2296 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2298 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2303 GET_INFO_BOTH(finfo1
,pinfo1
);
2304 COMPARE_WRITE_TIME_EQUAL(finfo1
,finfo0
);
2307 * make sure the write time is updated 2 seconds later
2308 * calcuated from the first write
2309 * (but expect upto 3 seconds extra time for a busy server)
2311 start
= timeval_current();
2312 end
= timeval_add(&start
, 5 * sec
, 0);
2313 while (!timeval_expired(&end
)) {
2314 /* get the times after the first write */
2315 GET_INFO_FILE(finfo1
);
2317 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
2318 double diff
= timeval_elapsed(&start
);
2319 if (diff
< (TIMEDELAY_SECS
* sec
* 0.3)) { /* 0.3 to cope with vmware timing */
2320 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2321 "(1sec == %.2f) (wrong!)\n",
2327 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2328 "(1sec == %.2f) (correct)\n",
2335 GET_INFO_BOTH(finfo1
,pinfo1
);
2336 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
2338 /* sure any further write doesn't update the write time */
2339 start
= timeval_current();
2340 end
= timeval_add(&start
, 15 * sec
, 0);
2341 while (!timeval_expired(&end
)) {
2343 torture_comment(tctx
, "Do a write on the file handle\n");
2344 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2346 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2350 /* get the times after the write */
2351 GET_INFO_BOTH(finfo2
,pinfo2
);
2353 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
2354 double diff
= timeval_elapsed(&start
);
2355 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2356 "(1sec == %.2f) (wrong!)\n",
2364 GET_INFO_BOTH(finfo2
,pinfo2
);
2365 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2366 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
2367 torture_comment(tctx
, "Server did not updatewrite_time (correct)\n");
2373 GET_INFO_BOTH(finfo3
,pinfo3
);
2374 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2377 * the close updates the write time to the time of the close
2378 * and not to the time of the last write!
2380 torture_comment(tctx
, "Close the file handle\n");
2381 smbcli_close(cli
->tree
, fnum1
);
2384 GET_INFO_PATH(pinfo4
);
2385 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
2387 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
2388 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
2393 smbcli_close(cli
->tree
, fnum1
);
2394 smbcli_unlink(cli
->tree
, fname
);
2395 smbcli_deltree(cli
->tree
, BASEDIR
);
2401 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2404 static bool test_delayed_write_update5(struct torture_context
*tctx
,
2405 struct smbcli_state
*cli
,
2406 struct smbcli_state
*cli2
)
2408 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
, finfo5
;
2409 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
, pinfo6
;
2410 const char *fname
= BASEDIR
"\\torture_file5.txt";
2414 struct timeval start
;
2416 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2417 int normal_delay
= 2000000;
2418 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2419 int msec
= 1000 * sec
;
2421 torture_comment(tctx
, "\nRunning test_delayed_write_update5\n");
2423 if (!torture_setup_dir(cli
, BASEDIR
)) {
2427 torture_comment(tctx
, "Open the file handle\n");
2428 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2431 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2435 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2436 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2442 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2443 pinfo0
.basic_info
.in
.file
.path
= fname
;
2451 /* get the initial times */
2452 GET_INFO_BOTH(finfo0
,pinfo0
);
2455 torture_comment(tctx
, "Do a write on the file handle\n");
2456 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2458 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2463 GET_INFO_BOTH(finfo1
,pinfo1
);
2464 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
2466 torture_comment(tctx
, "Set write time in the future on the file handle\n");
2467 SET_INFO_FILE(finfo0
, time(NULL
) + 86400);
2468 GET_INFO_BOTH(finfo2
,pinfo2
);
2469 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2471 torture_comment(tctx
, "Set write time in the past on the file handle\n");
2472 SET_INFO_FILE(finfo0
, time(NULL
) - 86400);
2473 GET_INFO_BOTH(finfo2
,pinfo2
);
2474 COMPARE_WRITE_TIME_LESS(finfo2
, finfo1
);
2476 /* make sure the 2 second delay from the first write are canceled */
2477 start
= timeval_current();
2478 end
= timeval_add(&start
, 15 * sec
, 0);
2479 while (!timeval_expired(&end
)) {
2481 /* get the times after the first write */
2482 GET_INFO_BOTH(finfo3
,pinfo3
);
2484 if (finfo3
.basic_info
.out
.write_time
> finfo2
.basic_info
.out
.write_time
) {
2485 double diff
= timeval_elapsed(&start
);
2486 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2487 "(1sec == %.2f) (wrong!)\n",
2495 GET_INFO_BOTH(finfo3
,pinfo3
);
2496 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2497 if (finfo3
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
2498 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2501 /* sure any further write doesn't update the write time */
2502 start
= timeval_current();
2503 end
= timeval_add(&start
, 15 * sec
, 0);
2504 while (!timeval_expired(&end
)) {
2506 torture_comment(tctx
, "Do a write on the file handle\n");
2507 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2509 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2513 /* get the times after the write */
2514 GET_INFO_BOTH(finfo4
,pinfo4
);
2516 if (finfo4
.basic_info
.out
.write_time
> finfo3
.basic_info
.out
.write_time
) {
2517 double diff
= timeval_elapsed(&start
);
2518 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2519 "(1sec == %.2f) (wrong!)\n",
2527 GET_INFO_BOTH(finfo4
,pinfo4
);
2528 COMPARE_WRITE_TIME_EQUAL(finfo4
, finfo3
);
2529 if (finfo4
.basic_info
.out
.write_time
== finfo3
.basic_info
.out
.write_time
) {
2530 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2536 GET_INFO_BOTH(finfo5
,pinfo5
);
2537 COMPARE_WRITE_TIME_EQUAL(finfo5
, finfo4
);
2540 * the close doesn't update the write time
2542 torture_comment(tctx
, "Close the file handle\n");
2543 smbcli_close(cli
->tree
, fnum1
);
2546 GET_INFO_PATH(pinfo6
);
2547 COMPARE_WRITE_TIME_EQUAL(pinfo6
, pinfo5
);
2549 if (pinfo6
.basic_info
.out
.write_time
== pinfo5
.basic_info
.out
.write_time
) {
2550 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
2555 smbcli_close(cli
->tree
, fnum1
);
2556 smbcli_unlink(cli
->tree
, fname
);
2557 smbcli_deltree(cli
->tree
, BASEDIR
);
2563 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2566 static bool test_delayed_write_update5b(struct torture_context
*tctx
,
2567 struct smbcli_state
*cli
,
2568 struct smbcli_state
*cli2
)
2570 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
, finfo5
;
2571 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
, pinfo6
;
2572 const char *fname
= BASEDIR
"\\torture_fileb.txt";
2576 struct timeval start
;
2578 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2579 int normal_delay
= 2000000;
2580 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2581 int msec
= 1000 * sec
;
2583 torture_comment(tctx
, "\nRunning test_delayed_write_update5b\n");
2585 if (!torture_setup_dir(cli
, BASEDIR
)) {
2589 torture_comment(tctx
, "Open the file handle\n");
2590 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2593 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2597 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2598 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2604 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2605 pinfo0
.basic_info
.in
.file
.path
= fname
;
2613 /* get the initial times */
2614 GET_INFO_BOTH(finfo0
,pinfo0
);
2617 torture_comment(tctx
, "Do a write on the file handle\n");
2618 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2620 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2625 GET_INFO_BOTH(finfo1
,pinfo1
);
2626 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
2628 torture_comment(tctx
, "Set write time in the future on the file handle\n");
2629 SET_INFO_FILE(finfo0
, time(NULL
) + 86400);
2630 GET_INFO_BOTH(finfo2
,pinfo2
);
2631 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2633 torture_comment(tctx
, "Set write time in the past on the file handle\n");
2634 SET_INFO_FILE(finfo0
, time(NULL
) - 86400);
2635 GET_INFO_BOTH(finfo2
,pinfo2
);
2636 COMPARE_WRITE_TIME_LESS(finfo2
, finfo1
);
2638 /* make sure the 2 second delay from the first write are canceled */
2639 start
= timeval_current();
2640 end
= timeval_add(&start
, 15 * sec
, 0);
2641 while (!timeval_expired(&end
)) {
2643 /* get the times after the first write */
2644 GET_INFO_BOTH(finfo3
,pinfo3
);
2646 if (finfo3
.basic_info
.out
.write_time
> finfo2
.basic_info
.out
.write_time
) {
2647 double diff
= timeval_elapsed(&start
);
2648 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2649 "(1sec == %.2f) (wrong!)\n",
2657 GET_INFO_BOTH(finfo3
,pinfo3
);
2658 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2659 if (finfo3
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
2660 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2663 /* Do any further write (truncates) update the write time ? */
2664 start
= timeval_current();
2665 end
= timeval_add(&start
, 15 * sec
, 0);
2666 while (!timeval_expired(&end
)) {
2668 torture_comment(tctx
, "Do a truncate write on the file handle\n");
2669 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 1024, 0);
2671 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2675 /* get the times after the write */
2676 GET_INFO_BOTH(finfo4
,pinfo4
);
2678 if (finfo4
.basic_info
.out
.write_time
> finfo3
.basic_info
.out
.write_time
) {
2679 double diff
= timeval_elapsed(&start
);
2680 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2681 "(1sec == %.2f) (wrong!)\n",
2689 GET_INFO_BOTH(finfo4
,pinfo4
);
2690 COMPARE_WRITE_TIME_EQUAL(finfo4
, finfo3
);
2691 if (finfo4
.basic_info
.out
.write_time
== finfo3
.basic_info
.out
.write_time
) {
2692 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2698 GET_INFO_BOTH(finfo5
,pinfo5
);
2699 COMPARE_WRITE_TIME_EQUAL(finfo5
, finfo4
);
2702 * the close doesn't update the write time
2704 torture_comment(tctx
, "Close the file handle\n");
2705 smbcli_close(cli
->tree
, fnum1
);
2708 GET_INFO_PATH(pinfo6
);
2709 COMPARE_WRITE_TIME_EQUAL(pinfo6
, pinfo5
);
2711 if (pinfo6
.basic_info
.out
.write_time
== pinfo5
.basic_info
.out
.write_time
) {
2712 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
2717 smbcli_close(cli
->tree
, fnum1
);
2718 smbcli_unlink(cli
->tree
, fname
);
2719 smbcli_deltree(cli
->tree
, BASEDIR
);
2725 * Open 2 handles on a file. Write one one and then set the
2726 * WRITE TIME explicitly on the other. Ensure the write time
2727 * update is cancelled. Ensure the write time is updated to
2728 * the close time when the non-explicit set handle is closed.
2732 static bool test_delayed_write_update6(struct torture_context
*tctx
,
2733 struct smbcli_state
*cli
,
2734 struct smbcli_state
*cli2
)
2736 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
, finfo5
;
2737 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
, pinfo6
, pinfo7
;
2738 const char *fname
= BASEDIR
"\\torture_file6.txt";
2743 struct timeval start
;
2745 int used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2746 int normal_delay
= 2000000;
2747 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2748 int msec
= 1000 * sec
;
2751 torture_comment(tctx
, "\nRunning test_delayed_write_update6\n");
2753 if (!torture_setup_dir(cli
, BASEDIR
)) {
2757 torture_comment(tctx
, "Open the file handle\n");
2758 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2761 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2766 torture_comment(tctx
, "Open the 2nd file handle on 2nd connection\n");
2767 fnum2
= smbcli_open(cli2
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2770 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2775 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2776 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2782 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2783 pinfo0
.basic_info
.in
.file
.path
= fname
;
2792 /* get the initial times */
2793 GET_INFO_BOTH(finfo0
,pinfo0
);
2796 torture_comment(tctx
, "Do a write on the file handle\n");
2797 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2799 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2804 GET_INFO_BOTH(finfo1
,pinfo1
);
2805 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
2807 torture_comment(tctx
, "Set write time in the future on the 2nd file handle\n");
2808 SET_INFO_FILE_EX(finfo0
, time(NULL
) + 86400, cli2
->tree
, fnum2
);
2809 GET_INFO_BOTH(finfo2
,pinfo2
);
2810 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2812 torture_comment(tctx
, "Set write time in the past on the 2nd file handle\n");
2813 SET_INFO_FILE_EX(finfo0
, time(NULL
) - 86400, cli2
->tree
, fnum2
);
2814 GET_INFO_BOTH(finfo2
,pinfo2
);
2815 COMPARE_WRITE_TIME_LESS(finfo2
, finfo1
);
2817 /* make sure the 2 second delay from the first write are canceled */
2818 start
= timeval_current();
2819 end
= timeval_add(&start
, 10 * sec
, 0);
2820 while (!timeval_expired(&end
)) {
2822 /* get the times after the first write */
2823 GET_INFO_BOTH(finfo3
,pinfo3
);
2825 if (finfo3
.basic_info
.out
.write_time
> finfo2
.basic_info
.out
.write_time
) {
2826 double diff
= timeval_elapsed(&start
);
2827 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2828 "(1sec == %.2f) (wrong!)\n",
2836 GET_INFO_BOTH(finfo3
,pinfo3
);
2837 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2838 if (finfo3
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
2839 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2842 /* sure any further write doesn't update the write time */
2843 start
= timeval_current();
2844 end
= timeval_add(&start
, 10 * sec
, 0);
2845 while (!timeval_expired(&end
)) {
2847 torture_comment(tctx
, "Do a write on the file handle\n");
2848 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2850 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2854 /* get the times after the write */
2855 GET_INFO_BOTH(finfo4
,pinfo4
);
2857 if (finfo4
.basic_info
.out
.write_time
> finfo3
.basic_info
.out
.write_time
) {
2858 double diff
= timeval_elapsed(&start
);
2859 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2860 "(1sec == %.2f) (wrong!)\n",
2868 GET_INFO_BOTH(finfo4
,pinfo4
);
2869 COMPARE_WRITE_TIME_EQUAL(finfo4
, finfo3
);
2870 if (finfo4
.basic_info
.out
.write_time
== finfo3
.basic_info
.out
.write_time
) {
2871 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2877 GET_INFO_BOTH(finfo5
,pinfo5
);
2878 COMPARE_WRITE_TIME_EQUAL(finfo5
, finfo4
);
2881 * the close updates the write time to the time of the close
2882 * as the write time was set on the 2nd handle
2884 torture_comment(tctx
, "Close the file handle\n");
2885 smbcli_close(cli
->tree
, fnum1
);
2888 GET_INFO_PATH(pinfo6
);
2889 COMPARE_WRITE_TIME_GREATER(pinfo6
, pinfo5
);
2891 if (pinfo6
.basic_info
.out
.write_time
> pinfo5
.basic_info
.out
.write_time
) {
2892 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
2895 /* See what the second write handle thinks the time is ? */
2896 finfo5
.basic_info
.in
.file
.fnum
= fnum2
;
2897 GET_INFO_FILE2(finfo5
);
2898 COMPARE_WRITE_TIME_EQUAL(finfo5
, pinfo6
);
2900 /* See if we have lost the sticky write time on handle2 */
2902 torture_comment(tctx
, "Have we lost the sticky write time ?\n");
2904 /* Make sure any further normal write doesn't update the write time */
2905 start
= timeval_current();
2906 end
= timeval_add(&start
, 10 * sec
, 0);
2907 while (!timeval_expired(&end
)) {
2909 torture_comment(tctx
, "Do a write on the second file handle\n");
2910 written
= smbcli_write(cli2
->tree
, fnum2
, 0, "x", 0, 1);
2912 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2916 /* get the times after the write */
2917 GET_INFO_FILE2(finfo5
);
2918 GET_INFO_PATH(pinfo6
);
2920 if (finfo5
.basic_info
.out
.write_time
> pinfo6
.basic_info
.out
.write_time
) {
2921 double diff
= timeval_elapsed(&start
);
2922 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2923 "(1sec == %.2f) (wrong!)\n",
2931 /* What about a truncate write ? */
2932 start
= timeval_current();
2933 end
= timeval_add(&start
, 10 * sec
, 0);
2934 while (!timeval_expired(&end
)) {
2936 torture_comment(tctx
, "Do a truncate write on the second file handle\n");
2937 written
= smbcli_write(cli2
->tree
, fnum2
, 0, "x", 0, 0);
2939 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2943 /* get the times after the write */
2944 GET_INFO_FILE2(finfo5
);
2945 GET_INFO_PATH(pinfo6
);
2947 if (finfo5
.basic_info
.out
.write_time
> pinfo6
.basic_info
.out
.write_time
) {
2948 double diff
= timeval_elapsed(&start
);
2949 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2950 "(1sec == %.2f) (wrong!)\n",
2959 /* keep the 2nd handle open and rerun tests */
2966 * closing the 2nd handle will cause no write time update
2967 * as the write time was explicit set on this handle
2969 torture_comment(tctx
, "Close the 2nd file handle\n");
2970 smbcli_close(cli2
->tree
, fnum2
);
2973 GET_INFO_PATH(pinfo7
);
2974 COMPARE_WRITE_TIME_EQUAL(pinfo7
, pinfo6
);
2976 if (pinfo7
.basic_info
.out
.write_time
== pinfo6
.basic_info
.out
.write_time
) {
2977 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
2982 smbcli_close(cli
->tree
, fnum1
);
2984 smbcli_close(cli2
->tree
, fnum2
);
2985 smbcli_unlink(cli
->tree
, fname
);
2986 smbcli_deltree(cli
->tree
, BASEDIR
);
2991 static bool test_delayed_write_update7(struct torture_context
*tctx
, struct smbcli_state
*cli
)
2993 union smb_open open_parms
;
2994 union smb_fileinfo finfo1
, finfo2
, finfo3
;
2995 const char *fname
= BASEDIR
"\\torture_file7.txt";
2999 TALLOC_CTX
*mem_ctx
;
3001 torture_comment(tctx
, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
3003 mem_ctx
= talloc_init("test_delayed_write_update7");
3004 if (!mem_ctx
) return false;
3006 ZERO_STRUCT(finfo1
);
3007 ZERO_STRUCT(finfo2
);
3008 ZERO_STRUCT(finfo3
);
3009 ZERO_STRUCT(open_parms
);
3011 if (!torture_setup_dir(cli
, BASEDIR
)) {
3015 /* Create the file. */
3016 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
3018 torture_result(tctx
, TORTURE_FAIL
, "Failed to open %s", fname
);
3022 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
3023 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
3027 /* Get the initial timestamps. */
3028 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
3030 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
3032 /* Set the pending write time to a value with ns. */
3033 SET_INFO_FILE_NS(finfo
, time(NULL
) + 86400, 103, cli
->tree
, fnum1
);
3035 /* Get the current pending write time by fnum. */
3036 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
3038 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
3040 /* Ensure the time is actually different. */
3041 if (finfo1
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
3042 torture_result(tctx
, TORTURE_FAIL
,
3043 "setfileinfo time matches original fileinfo time");
3047 /* Get the current pending write time by path. */
3048 finfo3
.basic_info
.in
.file
.path
= fname
;
3049 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo3
);
3051 if (finfo2
.basic_info
.out
.write_time
!= finfo3
.basic_info
.out
.write_time
) {
3052 torture_result(tctx
, TORTURE_FAIL
,
3053 "qpathinfo time doens't match fileinfo time");
3057 /* Now close the file. Re-open and check that the write
3058 time is identical to the one we wrote. */
3060 smbcli_close(cli
->tree
, fnum1
);
3062 open_parms
.ntcreatex
.level
= RAW_OPEN_NTCREATEX
;
3063 open_parms
.ntcreatex
.in
.flags
= 0;
3064 open_parms
.ntcreatex
.in
.access_mask
= SEC_GENERIC_READ
;
3065 open_parms
.ntcreatex
.in
.file_attr
= 0;
3066 open_parms
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
3067 NTCREATEX_SHARE_ACCESS_READ
|
3068 NTCREATEX_SHARE_ACCESS_WRITE
;
3069 open_parms
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
3070 open_parms
.ntcreatex
.in
.create_options
= 0;
3071 open_parms
.ntcreatex
.in
.fname
= fname
;
3073 status
= smb_raw_open(cli
->tree
, mem_ctx
, &open_parms
);
3074 talloc_free(mem_ctx
);
3076 if (!NT_STATUS_IS_OK(status
)) {
3077 torture_result(tctx
, TORTURE_FAIL
,
3078 "setfileinfo time matches original fileinfo time");
3082 fnum1
= open_parms
.ntcreatex
.out
.file
.fnum
;
3084 /* Check the returned time matches. */
3085 if (open_parms
.ntcreatex
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
3086 torture_result(tctx
, TORTURE_FAIL
,
3087 "final open time does not match set time");
3093 smbcli_close(cli
->tree
, fnum1
);
3095 smbcli_unlink(cli
->tree
, fname
);
3096 smbcli_deltree(cli
->tree
, BASEDIR
);
3101 testing of delayed update of write_time
3103 struct torture_suite
*torture_delay_write(void)
3105 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "DELAYWRITE");
3107 torture_suite_add_2smb_test(suite
, "finfo update on close", test_finfo_after_write
);
3108 torture_suite_add_1smb_test(suite
, "delayed update of write time", test_delayed_write_update
);
3109 torture_suite_add_1smb_test(suite
, "update of write time and SMBwrite truncate", test_delayed_write_update1
);
3110 torture_suite_add_1smb_test(suite
, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a
);
3111 torture_suite_add_1smb_test(suite
, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b
);
3112 torture_suite_add_1smb_test(suite
, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c
);
3113 torture_suite_add_2smb_test(suite
, "delayed update of write time using 2 connections", test_delayed_write_update2
);
3114 torture_suite_add_2smb_test(suite
, "delayed update of write time 3", test_delayed_write_update3
);
3115 torture_suite_add_2smb_test(suite
, "delayed update of write time 3a", test_delayed_write_update3a
);
3116 torture_suite_add_2smb_test(suite
, "delayed update of write time 3b", test_delayed_write_update3b
);
3117 torture_suite_add_2smb_test(suite
, "delayed update of write time 3c", test_delayed_write_update3c
);
3118 torture_suite_add_2smb_test(suite
, "delayed update of write time 4", test_delayed_write_update4
);
3119 torture_suite_add_2smb_test(suite
, "delayed update of write time 5", test_delayed_write_update5
);
3120 torture_suite_add_2smb_test(suite
, "delayed update of write time 5b", test_delayed_write_update5b
);
3121 torture_suite_add_2smb_test(suite
, "delayed update of write time 6", test_delayed_write_update6
);
3122 torture_suite_add_1smb_test(suite
, "timestamp resolution test", test_delayed_write_update7
);
3123 torture_suite_add_1smb_test(suite
, "timestamp resolution test", test_delayed_write_update7
);