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 BASEDIR "\\delaywrite"
36 static bool test_delayed_write_update(struct torture_context
*tctx
, struct smbcli_state
*cli
)
38 union smb_fileinfo finfo1
, finfo2
;
39 const char *fname
= BASEDIR
"\\torture_file.txt";
46 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
47 int normal_delay
= 2000000;
48 double sec
= ((double)used_delay
) / ((double)normal_delay
);
49 int msec
= 1000 * sec
;
51 torture_comment(tctx
, "\nRunning test_delayed_write_update\n");
53 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
55 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
56 torture_assert_int_not_equal(tctx
, fnum1
, -1, talloc_asprintf(tctx
,
57 "Failed to open %s", fname
));
59 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
60 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
63 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
64 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
66 torture_comment(tctx
, "Initial write time %s\n",
67 nt_time_string(tctx
, finfo1
.basic_info
.out
.write_time
));
69 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
70 torture_assert_int_equal(tctx
, written
, 1,
71 "unexpected number of bytes written");
73 start
= timeval_current();
74 end
= timeval_add(&start
, (120 * sec
), 0);
75 while (!timeval_expired(&end
)) {
76 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
78 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
80 torture_comment(tctx
, "write time %s\n",
81 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
83 if (finfo1
.basic_info
.out
.write_time
!=
84 finfo2
.basic_info
.out
.write_time
)
86 double diff
= timeval_elapsed(&start
);
89 diff
>= (used_delay
/ (double)1000000),
91 "Server updated write_time after %.2f "
92 "seconds (expected >= %.2f)\n",
93 diff
, used_delay
/(double)1000000));
95 torture_comment(tctx
, "Server updated write_time after %.2f seconds (correct)\n",
100 smb_msleep(1 * msec
);
103 torture_assert_u64_not_equal(tctx
,
104 finfo2
.basic_info
.out
.write_time
,
105 finfo1
.basic_info
.out
.write_time
,
106 "Server did not update write time within "
110 smbcli_close(cli
->tree
, fnum1
);
111 smbcli_unlink(cli
->tree
, fname
);
112 smbcli_deltree(cli
->tree
, BASEDIR
);
117 static bool test_delayed_write_update1(struct torture_context
*tctx
, struct smbcli_state
*cli
)
119 union smb_fileinfo finfo1
, finfo2
, finfo3
, pinfo4
;
120 const char *fname
= BASEDIR
"\\torture_file1.txt";
125 struct timeval start
;
127 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
128 int normal_delay
= 2000000;
129 double sec
= ((double)used_delay
) / ((double)normal_delay
);
130 int msec
= 1000 * sec
;
135 torture_comment(tctx
, "\nRunning test_delayed_write_update1\n");
137 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
139 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
140 torture_assert_int_not_equal(tctx
, fnum1
, -1, talloc_asprintf(tctx
,
141 "Failed to open %s", fname
));
143 memset(buf
, 'x', 2048);
144 written
= smbcli_write(cli
->tree
, fnum1
, 0, buf
, 0, 2048);
146 /* 3 second delay to ensure we get past any 2 second time
147 granularity (older systems may have that) */
148 smb_msleep(3 * msec
);
150 finfo1
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
151 finfo1
.all_info
.in
.file
.fnum
= fnum1
;
154 pinfo4
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
155 pinfo4
.all_info
.in
.file
.path
= fname
;
157 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
159 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
161 torture_assert_u64_equal(tctx
, finfo1
.all_info
.out
.size
, 2048,
162 "file size not as expected after write(2048)");
164 torture_comment(tctx
, "Initial write time %s\n",
165 nt_time_string(tctx
, finfo1
.all_info
.out
.write_time
));
167 /* 3 second delay to ensure we get past any 2 second time
168 granularity (older systems may have that) */
169 smb_msleep(3 * msec
);
171 /* Do a zero length SMBwrite call to truncate. */
172 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 1024, 0);
173 torture_assert_int_equal(tctx
, written
, 0,
174 "unexpected number of bytes written");
176 start
= timeval_current();
177 end
= timeval_add(&start
, (120 * sec
), 0);
180 while (!timeval_expired(&end
)) {
181 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
183 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
185 torture_assert_u64_equal(tctx
, finfo2
.all_info
.out
.size
, 1024,
186 "file not truncated to expected size "
189 torture_comment(tctx
, "write time %s\n",
190 nt_time_string(tctx
, finfo2
.all_info
.out
.write_time
));
192 if (finfo1
.all_info
.out
.write_time
!=
193 finfo2
.all_info
.out
.write_time
)
200 smb_msleep(1 * msec
);
204 torture_assert(tctx
, updated
,
205 "Server did not update write time within 120 seconds");
207 torture_assert(tctx
, first
, talloc_asprintf(tctx
,
208 "Server did not update write time immediately but only "
209 "after %.2f seconds!", timeval_elapsed(&start
)));
211 torture_comment(tctx
, "Server updated write time immediately. Good!\n");
214 smb_msleep(2 * msec
);
216 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
217 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 0, 1);
218 torture_assert_int_equal(tctx
, written
, 1,
219 "unexpected number of bytes written");
221 start
= timeval_current();
222 end
= timeval_add(&start
, (10*sec
), 0);
223 while (!timeval_expired(&end
)) {
224 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo3
);
226 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
228 torture_assert_u64_equal(tctx
, finfo3
.all_info
.out
.size
, 1024,
229 "file not truncated to expected size "
232 torture_comment(tctx
, "write time %s\n",
233 nt_time_string(tctx
, finfo3
.all_info
.out
.write_time
));
235 torture_assert_u64_equal(tctx
,
236 finfo3
.all_info
.out
.write_time
,
237 finfo2
.all_info
.out
.write_time
,
238 talloc_asprintf(tctx
,
239 "Server updated write time "
240 "after %.2f seconds (wrong!)",
241 timeval_elapsed(&start
)));
244 smb_msleep(1 * msec
);
247 torture_comment(tctx
, "Server did not update write time within 10 "
251 smb_msleep(2 * msec
);
253 /* the close should trigger an write time update */
254 smbcli_close(cli
->tree
, fnum1
);
257 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &pinfo4
);
258 torture_assert_ntstatus_ok(tctx
, status
, "pathinfo failed");
260 torture_assert_u64_not_equal(tctx
,
261 pinfo4
.all_info
.out
.write_time
,
262 finfo3
.all_info
.out
.write_time
,
263 "Server did not update write time on "
266 pinfo4
.all_info
.out
.write_time
> finfo3
.all_info
.out
.write_time
,
267 "Server updated write time on close, but to an earlier point "
270 torture_comment(tctx
, "Server updated write time on close (correct)\n");
273 smbcli_close(cli
->tree
, fnum1
);
274 smbcli_unlink(cli
->tree
, fname
);
275 smbcli_deltree(cli
->tree
, BASEDIR
);
280 /* Updating with a SMBwrite of zero length
281 * changes the write time immediately - even on expand. */
283 static bool test_delayed_write_update1a(struct torture_context
*tctx
, struct smbcli_state
*cli
)
285 union smb_fileinfo finfo1
, finfo2
, finfo3
, pinfo4
;
286 const char *fname
= BASEDIR
"\\torture_file1a.txt";
291 struct timeval start
;
293 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
294 int normal_delay
= 2000000;
295 double sec
= ((double)used_delay
) / ((double)normal_delay
);
296 int msec
= 1000 * sec
;
301 torture_comment(tctx
, "\nRunning test_delayed_write_update1a\n");
303 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
305 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
306 torture_assert_int_not_equal(tctx
, fnum1
, -1, talloc_asprintf(tctx
,
307 "Failed to open %s", fname
));
309 memset(buf
, 'x', 2048);
310 written
= smbcli_write(cli
->tree
, fnum1
, 0, buf
, 0, 2048);
312 /* 3 second delay to ensure we get past any 2 second time
313 granularity (older systems may have that) */
314 smb_msleep(3 * msec
);
316 finfo1
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
317 finfo1
.all_info
.in
.file
.fnum
= fnum1
;
320 pinfo4
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
321 pinfo4
.all_info
.in
.file
.path
= fname
;
323 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
325 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
327 torture_assert_u64_equal(tctx
, finfo1
.all_info
.out
.size
, 2048,
328 "file size not as expected after write(2048)");
330 torture_comment(tctx
, "Initial write time %s\n",
331 nt_time_string(tctx
, finfo1
.all_info
.out
.write_time
));
333 /* Do a zero length SMBwrite call to truncate. */
334 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 10240, 0);
336 torture_assert_int_equal(tctx
, written
, 0,
337 "unexpected number of bytes written");
339 start
= timeval_current();
340 end
= timeval_add(&start
, (120*sec
), 0);
343 while (!timeval_expired(&end
)) {
344 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
346 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
348 torture_assert_u64_equal(tctx
, finfo2
.all_info
.out
.size
, 10240,
349 "file not truncated to expected size "
352 torture_comment(tctx
, "write time %s\n",
353 nt_time_string(tctx
, finfo2
.all_info
.out
.write_time
));
355 if (finfo1
.all_info
.out
.write_time
!=
356 finfo2
.all_info
.out
.write_time
)
363 smb_msleep(1 * msec
);
367 torture_assert(tctx
, updated
,
368 "Server did not update write time within 120 seconds");
370 torture_assert(tctx
, first
, talloc_asprintf(tctx
,
371 "Server did not update write time immediately but only "
372 "after %.2f seconds!", timeval_elapsed(&start
)));
374 torture_comment(tctx
, "Server updated write time immediately. Good!\n");
377 smb_msleep(2 * msec
);
379 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
380 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 0, 1);
382 torture_assert_int_equal(tctx
, written
, 1,
383 "unexpected number of bytes written");
385 start
= timeval_current();
386 end
= timeval_add(&start
, (10*sec
), 0);
387 while (!timeval_expired(&end
)) {
388 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo3
);
390 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
392 torture_assert_u64_equal(tctx
, finfo3
.all_info
.out
.size
, 10240,
393 "file not truncated to expected size "
396 torture_comment(tctx
, "write time %s\n",
397 nt_time_string(tctx
, finfo3
.all_info
.out
.write_time
));
399 torture_assert_u64_equal(tctx
,
400 finfo3
.all_info
.out
.write_time
,
401 finfo2
.all_info
.out
.write_time
,
402 talloc_asprintf(tctx
,
403 "Server updated write time "
404 "after %.2f seconds (wrong!)",
405 timeval_elapsed(&start
)));
408 smb_msleep(1 * msec
);
411 torture_comment(tctx
, "Server did not update write time within 10 "
414 /* the close should trigger an write time update */
415 smbcli_close(cli
->tree
, fnum1
);
418 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &pinfo4
);
419 torture_assert_ntstatus_ok(tctx
, status
, "pathinfo failed");
421 torture_assert_u64_not_equal(tctx
,
422 pinfo4
.all_info
.out
.write_time
,
423 finfo3
.all_info
.out
.write_time
,
424 "Server did not update write time on "
427 pinfo4
.all_info
.out
.write_time
> finfo3
.all_info
.out
.write_time
,
428 "Server updated write time on close, but to an earlier point "
431 torture_comment(tctx
, "Server updated write time on close (correct)\n");
434 smbcli_close(cli
->tree
, fnum1
);
435 smbcli_unlink(cli
->tree
, fname
);
436 smbcli_deltree(cli
->tree
, BASEDIR
);
441 /* Updating with a SET_FILE_END_OF_FILE_INFO
442 * changes the write time immediately - even on expand. */
444 static bool test_delayed_write_update1b(struct torture_context
*tctx
, struct smbcli_state
*cli
)
446 union smb_fileinfo finfo1
, finfo2
, finfo3
, pinfo4
;
447 const char *fname
= BASEDIR
"\\torture_file1b.txt";
452 struct timeval start
;
454 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
455 int normal_delay
= 2000000;
456 double sec
= ((double)used_delay
) / ((double)normal_delay
);
457 int msec
= 1000 * sec
;
462 torture_comment(tctx
, "\nRunning test_delayed_write_update1b\n");
464 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
466 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
467 torture_assert_int_not_equal(tctx
, fnum1
, -1, talloc_asprintf(tctx
,
468 "Failed to open %s", fname
));
470 memset(buf
, 'x', 2048);
471 written
= smbcli_write(cli
->tree
, fnum1
, 0, buf
, 0, 2048);
473 /* 3 second delay to ensure we get past any 2 second time
474 granularity (older systems may have that) */
475 smb_msleep(3 * msec
);
477 finfo1
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
478 finfo1
.all_info
.in
.file
.fnum
= fnum1
;
481 pinfo4
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
482 pinfo4
.all_info
.in
.file
.path
= fname
;
484 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
486 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
488 torture_assert_u64_equal(tctx
, finfo1
.all_info
.out
.size
, 2048,
489 "file size not as expected after write(2048)");
491 torture_comment(tctx
, "Initial write time %s\n",
492 nt_time_string(tctx
, finfo1
.all_info
.out
.write_time
));
494 /* Do a SET_END_OF_FILE_INFO call to truncate. */
495 status
= smbcli_ftruncate(cli
->tree
, fnum1
, (uint64_t)10240);
497 torture_assert_ntstatus_ok(tctx
, status
, "SET_END_OF_FILE failed");
499 start
= timeval_current();
500 end
= timeval_add(&start
, (120*sec
), 0);
503 while (!timeval_expired(&end
)) {
504 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
506 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
508 torture_assert_u64_equal(tctx
, finfo2
.all_info
.out
.size
, 10240,
509 "file not truncated to expected size "
512 torture_comment(tctx
, "write time %s\n",
513 nt_time_string(tctx
, finfo2
.all_info
.out
.write_time
));
515 if (finfo1
.all_info
.out
.write_time
!=
516 finfo2
.all_info
.out
.write_time
)
523 smb_msleep(1 * msec
);
527 torture_assert(tctx
, updated
,
528 "Server did not update write time within 120 seconds");
530 torture_assert(tctx
, first
, talloc_asprintf(tctx
,
531 "Server did not update write time immediately but only "
532 "after %.2f seconds!", timeval_elapsed(&start
)));
534 torture_comment(tctx
, "Server updated write time immediately. Good!\n");
537 smb_msleep(2 * msec
);
539 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
540 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 0, 1);
542 torture_assert_int_equal(tctx
, written
, 1,
543 "unexpected number of bytes written");
545 start
= timeval_current();
546 end
= timeval_add(&start
, (10*sec
), 0);
547 while (!timeval_expired(&end
)) {
548 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo3
);
550 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
552 torture_assert_u64_equal(tctx
, finfo3
.all_info
.out
.size
, 10240,
553 "file not truncated to expected size "
556 torture_comment(tctx
, "write time %s\n",
557 nt_time_string(tctx
, finfo3
.all_info
.out
.write_time
));
559 torture_assert_u64_equal(tctx
,
560 finfo3
.all_info
.out
.write_time
,
561 finfo2
.all_info
.out
.write_time
,
562 talloc_asprintf(tctx
,
563 "Server updated write time "
564 "after %.2f seconds (wrong!)",
565 timeval_elapsed(&start
)));
568 smb_msleep(1 * msec
);
571 torture_comment(tctx
, "Server did not update write time within 10 "
574 /* the close should trigger an write time update */
575 smbcli_close(cli
->tree
, fnum1
);
578 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &pinfo4
);
579 torture_assert_ntstatus_ok(tctx
, status
, "pathinfo failed");
581 torture_assert_u64_not_equal(tctx
,
582 pinfo4
.all_info
.out
.write_time
,
583 finfo3
.all_info
.out
.write_time
,
584 "Server did not update write time on "
587 pinfo4
.all_info
.out
.write_time
> finfo3
.all_info
.out
.write_time
,
588 "Server updated write time on close, but to an earlier point "
591 torture_comment(tctx
, "Server updated write time on close (correct)\n");
594 smbcli_close(cli
->tree
, fnum1
);
595 smbcli_unlink(cli
->tree
, fname
);
596 smbcli_deltree(cli
->tree
, BASEDIR
);
601 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
603 static bool test_delayed_write_update1c(struct torture_context
*tctx
, struct smbcli_state
*cli
)
605 union smb_setfileinfo parms
;
606 union smb_fileinfo finfo1
, finfo2
, finfo3
, pinfo4
;
607 const char *fname
= BASEDIR
"\\torture_file1c.txt";
612 struct timeval start
;
614 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
615 int normal_delay
= 2000000;
616 double sec
= ((double)used_delay
) / ((double)normal_delay
);
617 int msec
= 1000 * sec
;
622 torture_comment(tctx
, "\nRunning test_delayed_write_update1c\n");
624 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
626 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
627 torture_assert_int_not_equal(tctx
, fnum1
, -1, talloc_asprintf(tctx
,
628 "Failed to open %s", fname
));
630 memset(buf
, 'x', 2048);
631 written
= smbcli_write(cli
->tree
, fnum1
, 0, buf
, 0, 2048);
633 /* 3 second delay to ensure we get past any 2 second time
634 granularity (older systems may have that) */
635 smb_msleep(3 * msec
);
637 finfo1
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
638 finfo1
.all_info
.in
.file
.fnum
= fnum1
;
641 pinfo4
.all_info
.level
= RAW_FILEINFO_ALL_INFO
;
642 pinfo4
.all_info
.in
.file
.path
= fname
;
644 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
646 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
648 torture_assert_u64_equal(tctx
, finfo1
.all_info
.out
.size
, 2048,
649 "file size not as expected after write(2048)");
651 torture_comment(tctx
, "Initial write time %s\n",
652 nt_time_string(tctx
, finfo1
.all_info
.out
.write_time
));
654 /* Do a SET_ALLOCATION_SIZE call to truncate. */
655 parms
.allocation_info
.level
= RAW_SFILEINFO_ALLOCATION_INFO
;
656 parms
.allocation_info
.in
.file
.fnum
= fnum1
;
657 parms
.allocation_info
.in
.alloc_size
= 0;
659 status
= smb_raw_setfileinfo(cli
->tree
, &parms
);
661 torture_assert_ntstatus_ok(tctx
, status
,
662 "RAW_SFILEINFO_ALLOCATION_INFO failed");
664 start
= timeval_current();
665 end
= timeval_add(&start
, (120*sec
), 0);
668 while (!timeval_expired(&end
)) {
669 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
671 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
673 torture_assert_u64_equal(tctx
, finfo2
.all_info
.out
.size
, 0,
674 "file not truncated to expected size "
677 torture_comment(tctx
, "write time %s\n",
678 nt_time_string(tctx
, finfo2
.all_info
.out
.write_time
));
680 if (finfo1
.all_info
.out
.write_time
!=
681 finfo2
.all_info
.out
.write_time
)
688 smb_msleep(1 * msec
);
692 torture_assert(tctx
, updated
,
693 "Server did not update write time within 120 seconds");
695 torture_assert(tctx
, first
, talloc_asprintf(tctx
,
696 "Server did not update write time immediately but only "
697 "after %.2f seconds!", timeval_elapsed(&start
)));
699 torture_comment(tctx
, "Server updated write time immediately. Good!\n");
702 smb_msleep(2 * msec
);
704 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
705 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 0, 1);
706 torture_assert_int_equal(tctx
, written
, 1,
707 "Unexpected number of bytes written");
709 start
= timeval_current();
710 end
= timeval_add(&start
, (10*sec
), 0);
711 while (!timeval_expired(&end
)) {
712 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo3
);
714 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
716 torture_assert_u64_equal(tctx
, finfo3
.all_info
.out
.size
, 1,
717 "file not expaneded");
719 torture_comment(tctx
, "write time %s\n",
720 nt_time_string(tctx
, finfo3
.all_info
.out
.write_time
));
722 torture_assert_u64_equal(tctx
,
723 finfo3
.all_info
.out
.write_time
,
724 finfo2
.all_info
.out
.write_time
,
725 talloc_asprintf(tctx
,
726 "Server updated write time "
727 "after %.2f seconds (wrong!)",
728 timeval_elapsed(&start
)));
731 smb_msleep(1 * msec
);
734 torture_comment(tctx
, "Server did not update write time within 10 "
737 /* the close should trigger an write time update */
738 smbcli_close(cli
->tree
, fnum1
);
741 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &pinfo4
);
742 torture_assert_ntstatus_ok(tctx
, status
, "pathinfo failed");
744 torture_assert_u64_not_equal(tctx
,
745 pinfo4
.all_info
.out
.write_time
,
746 finfo3
.all_info
.out
.write_time
,
747 "Server did not update write time on "
750 pinfo4
.all_info
.out
.write_time
> finfo3
.all_info
.out
.write_time
,
751 "Server updated write time on close, but to an earlier point "
755 smbcli_close(cli
->tree
, fnum1
);
756 smbcli_unlink(cli
->tree
, fname
);
757 smbcli_deltree(cli
->tree
, BASEDIR
);
763 * Do as above, but using 2 connections.
766 static bool test_delayed_write_update2(struct torture_context
*tctx
, struct smbcli_state
*cli
,
767 struct smbcli_state
*cli2
)
769 union smb_fileinfo finfo1
, finfo2
;
770 const char *fname
= BASEDIR
"\\torture_file.txt";
776 struct timeval start
;
778 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
779 int normal_delay
= 2000000;
780 double sec
= ((double)used_delay
) / ((double)normal_delay
);
781 int msec
= 1000 * sec
;
782 union smb_flush flsh
;
784 torture_comment(tctx
, "\nRunning test_delayed_write_update2\n");
786 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
788 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
790 torture_comment(tctx
, "Failed to open %s\n", fname
);
794 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
795 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
798 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
800 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
802 torture_comment(tctx
, "Initial write time %s\n",
803 nt_time_string(tctx
, finfo1
.basic_info
.out
.write_time
));
805 /* 3 second delay to ensure we get past any 2 second time
806 granularity (older systems may have that) */
807 smb_msleep(3 * msec
);
810 /* Try using setfileinfo instead of write to update write time. */
811 union smb_setfileinfo sfinfo
;
812 time_t t_set
= time(NULL
);
813 sfinfo
.basic_info
.level
= RAW_SFILEINFO_BASIC_INFO
;
814 sfinfo
.basic_info
.in
.file
.fnum
= fnum1
;
815 sfinfo
.basic_info
.in
.create_time
= finfo1
.basic_info
.out
.create_time
;
816 sfinfo
.basic_info
.in
.access_time
= finfo1
.basic_info
.out
.access_time
;
818 /* I tried this with both + and - ve to see if it makes a different.
819 It doesn't - once the filetime is set via setfileinfo it stays that way. */
821 unix_to_nt_time(&sfinfo
.basic_info
.in
.write_time
, t_set
- 30000);
823 unix_to_nt_time(&sfinfo
.basic_info
.in
.write_time
, t_set
+ 30000);
825 sfinfo
.basic_info
.in
.change_time
= finfo1
.basic_info
.out
.change_time
;
826 sfinfo
.basic_info
.in
.attrib
= finfo1
.basic_info
.out
.attrib
;
828 status
= smb_raw_setfileinfo(cli
->tree
, &sfinfo
);
830 torture_assert_ntstatus_ok(tctx
, status
, "sfileinfo failed");
833 finfo2
.basic_info
.in
.file
.path
= fname
;
835 status
= smb_raw_pathinfo(cli2
->tree
, tctx
, &finfo2
);
837 if (!NT_STATUS_IS_OK(status
)) {
838 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
841 torture_comment(tctx
, "write time %s\n",
842 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
844 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
845 torture_comment(tctx
, "Server updated write_time (correct)\n");
847 torture_result(tctx
, TORTURE_FAIL
, "Server did not update write time (wrong!)\n");
851 /* Now try a write to see if the write time gets reset. */
853 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
854 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
857 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
859 if (!NT_STATUS_IS_OK(status
)) {
860 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
864 torture_comment(tctx
, "Modified write time %s\n",
865 nt_time_string(tctx
, finfo1
.basic_info
.out
.write_time
));
868 torture_comment(tctx
, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
870 written
= smbcli_write(cli
->tree
, fnum1
, 0, "0123456789", 1, 10);
873 torture_result(tctx
, TORTURE_FAIL
, "write failed - wrote %d bytes (%s)\n",
874 (int)written
, __location__
);
878 /* Just to prove to tridge that the an smbflush has no effect on
879 the write time :-). The setfileinfo IS STICKY. JRA. */
881 torture_comment(tctx
, "Doing flush after write\n");
883 flsh
.flush
.level
= RAW_FLUSH_FLUSH
;
884 flsh
.flush
.in
.file
.fnum
= fnum1
;
885 status
= smb_raw_flush(cli
->tree
, &flsh
);
886 if (!NT_STATUS_IS_OK(status
)) {
887 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status
)));
891 /* Once the time was set using setfileinfo then it stays set - writes
892 don't have any effect. But make sure. */
893 start
= timeval_current();
894 end
= timeval_add(&start
, (15*sec
), 0);
895 while (!timeval_expired(&end
)) {
896 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
898 if (!NT_STATUS_IS_OK(status
)) {
899 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
903 torture_comment(tctx
, "write time %s\n",
904 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
905 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
906 double diff
= timeval_elapsed(&start
);
907 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds"
914 smb_msleep(1 * msec
);
917 if (finfo1
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
918 torture_comment(tctx
, "Server did not update write time (correct)\n");
922 smb_msleep(2 * msec
);
924 fnum2
= smbcli_open(cli
->tree
, fname
, O_RDWR
, DENY_NONE
);
926 torture_result(tctx
, TORTURE_FAIL
, "Failed to open %s\n", fname
);
930 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");
932 written
= smbcli_write(cli
->tree
, fnum2
, 0, "0123456789", 11, 10);
935 torture_result(tctx
, TORTURE_FAIL
, "write failed - wrote %d bytes (%s)\n",
936 (int)written
, __location__
);
940 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
942 if (!NT_STATUS_IS_OK(status
)) {
943 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
946 torture_comment(tctx
, "write time %s\n",
947 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
948 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
949 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time (wrong!)\n");
953 torture_comment(tctx
, "Closing the first fd to see if write time updated.\n");
954 smbcli_close(cli
->tree
, fnum1
);
957 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");
959 written
= smbcli_write(cli
->tree
, fnum2
, 0, "0123456789", 21, 10);
962 torture_result(tctx
, TORTURE_FAIL
, "write failed - wrote %d bytes (%s)\n",
963 (int)written
, __location__
);
967 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
968 finfo1
.basic_info
.in
.file
.fnum
= fnum2
;
970 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
972 if (!NT_STATUS_IS_OK(status
)) {
973 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
976 torture_comment(tctx
, "write time %s\n",
977 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
978 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
979 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time (wrong!)\n");
983 /* Once the time was set using setfileinfo then it stays set - writes
984 don't have any effect. But make sure. */
985 start
= timeval_current();
986 end
= timeval_add(&start
, (15*sec
), 0);
987 while (!timeval_expired(&end
)) {
988 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
990 if (!NT_STATUS_IS_OK(status
)) {
991 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
995 torture_comment(tctx
, "write time %s\n",
996 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
997 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
998 double diff
= timeval_elapsed(&start
);
999 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
1006 smb_msleep(1 * msec
);
1009 if (finfo1
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
1010 torture_comment(tctx
, "Server did not update write time (correct)\n");
1013 torture_comment(tctx
, "Closing second fd to see if write time updated.\n");
1015 smbcli_close(cli
->tree
, fnum2
);
1018 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
, DENY_NONE
);
1020 torture_comment(tctx
, "Failed to open %s\n", fname
);
1024 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1025 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
1028 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
1030 if (!NT_STATUS_IS_OK(status
)) {
1031 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1035 torture_comment(tctx
, "Second open initial write time %s\n",
1036 nt_time_string(tctx
, finfo1
.basic_info
.out
.write_time
));
1038 smb_msleep(10 * msec
);
1039 torture_comment(tctx
, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1041 written
= smbcli_write(cli
->tree
, fnum1
, 0, "0123456789", 31, 10);
1043 if (written
!= 10) {
1044 torture_result(tctx
, TORTURE_FAIL
, "write failed - wrote %d bytes (%s)\n",
1045 (int)written
, __location__
);
1049 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1050 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
1052 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
1054 if (!NT_STATUS_IS_OK(status
)) {
1055 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1058 torture_comment(tctx
, "write time %s\n",
1059 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1060 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
1061 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time (wrong!)\n");
1065 /* Now the write time should be updated again */
1066 start
= timeval_current();
1067 end
= timeval_add(&start
, (15*sec
), 0);
1068 while (!timeval_expired(&end
)) {
1069 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
1071 if (!NT_STATUS_IS_OK(status
)) {
1072 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status
)));
1076 torture_comment(tctx
, "write time %s\n",
1077 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1078 if (finfo1
.basic_info
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
1079 double diff
= timeval_elapsed(&start
);
1080 if (diff
< (used_delay
/ (double)1000000)) {
1081 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds"
1082 "(expected > %.2f) (wrong!)\n",
1083 diff
, used_delay
/ (double)1000000);
1088 torture_comment(tctx
, "Server updated write_time after %.2f seconds"
1097 if (finfo1
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
1098 torture_result(tctx
, TORTURE_FAIL
, "Server did not update write time (wrong!)\n");
1103 /* One more test to do. We should read the filetime via findfirst on the
1104 second connection to ensure it's the same. This is very easy for a Windows
1105 server but a bastard to get right on a POSIX server. JRA. */
1108 smbcli_close(cli
->tree
, fnum1
);
1109 smbcli_unlink(cli
->tree
, fname
);
1110 smbcli_deltree(cli
->tree
, BASEDIR
);
1116 /* Windows does obviously not update the stat info during a write call. I
1117 * *think* this is the problem causing a spurious Excel 2003 on XP error
1118 * message when saving a file. Excel does a setfileinfo, writes, and then does
1119 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1120 * that the file might have been changed in between. What i've been able to
1121 * trace down is that this happens if the getpathinfo after the write shows a
1122 * different last write time than the setfileinfo showed. This is really
1126 static bool test_finfo_after_write(struct torture_context
*tctx
, struct smbcli_state
*cli
,
1127 struct smbcli_state
*cli2
)
1129 union smb_fileinfo finfo1
, finfo2
;
1130 const char *fname
= BASEDIR
"\\torture_file.txt";
1136 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
1137 int normal_delay
= 2000000;
1138 double sec
= ((double)used_delay
) / ((double)normal_delay
);
1139 int msec
= 1000 * sec
;
1141 torture_comment(tctx
, "\nRunning test_finfo_after_write\n");
1143 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1145 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
1148 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
1152 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1153 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
1155 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
1157 if (!NT_STATUS_IS_OK(status
)) {
1159 torture_result(tctx
, TORTURE_FAIL
, __location__
": fileinfo failed: %s", nt_errstr(status
));
1163 smb_msleep(1 * msec
);
1165 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1168 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1173 fnum2
= smbcli_open(cli2
->tree
, fname
, O_RDWR
, DENY_NONE
);
1175 torture_result(tctx
, TORTURE_FAIL
, __location__
": failed to open 2nd time - %s",
1176 smbcli_errstr(cli2
->tree
));
1181 written
= smbcli_write(cli2
->tree
, fnum2
, 0, "x", 0, 1);
1184 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1",
1190 finfo2
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1191 finfo2
.basic_info
.in
.file
.path
= fname
;
1193 status
= smb_raw_pathinfo(cli2
->tree
, tctx
, &finfo2
);
1195 if (!NT_STATUS_IS_OK(status
)) {
1196 torture_result(tctx
, TORTURE_FAIL
, __location__
": fileinfo failed: %s",
1202 if (finfo1
.basic_info
.out
.create_time
!=
1203 finfo2
.basic_info
.out
.create_time
) {
1204 torture_result(tctx
, TORTURE_FAIL
, __location__
": create_time changed");
1209 if (finfo1
.basic_info
.out
.access_time
!=
1210 finfo2
.basic_info
.out
.access_time
) {
1211 torture_result(tctx
, TORTURE_FAIL
, __location__
": access_time changed");
1216 if (finfo1
.basic_info
.out
.write_time
!=
1217 finfo2
.basic_info
.out
.write_time
) {
1218 torture_result(tctx
, TORTURE_FAIL
, __location__
": write_time changed:\n"
1219 "write time conn 1 = %s, conn 2 = %s",
1220 nt_time_string(tctx
, finfo1
.basic_info
.out
.write_time
),
1221 nt_time_string(tctx
, finfo2
.basic_info
.out
.write_time
));
1226 if (finfo1
.basic_info
.out
.change_time
!=
1227 finfo2
.basic_info
.out
.change_time
) {
1228 torture_result(tctx
, TORTURE_FAIL
, __location__
": change_time changed");
1233 /* One of the two following calls updates the qpathinfo. */
1235 /* If you had skipped the smbcli_write on fnum2, it would
1236 * *not* have updated the stat on disk */
1238 smbcli_close(cli2
->tree
, fnum2
);
1241 /* This call is only for the people looking at ethereal :-) */
1242 finfo2
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1243 finfo2
.basic_info
.in
.file
.path
= fname
;
1245 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo2
);
1247 if (!NT_STATUS_IS_OK(status
)) {
1248 torture_result(tctx
, TORTURE_FAIL
, __location__
": fileinfo failed: %s", nt_errstr(status
));
1255 smbcli_close(cli
->tree
, fnum1
);
1256 smbcli_unlink(cli
->tree
, fname
);
1257 smbcli_deltree(cli
->tree
, BASEDIR
);
1262 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1263 uint64_t r = 10*1000*1000; \
1264 NTTIME g = (given).basic_info.out.write_time; \
1265 NTTIME gr = (g / r) * r; \
1266 NTTIME c = (correct).basic_info.out.write_time; \
1267 NTTIME cr = (c / r) * r; \
1268 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1270 if (strict && (g cmp c)) { \
1272 } else if ((g cmp c) && (gr cmp cr)) { \
1273 /* handle filesystem without high resolution timestamps */ \
1277 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1278 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1279 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1284 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1285 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1286 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1287 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1288 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1289 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1291 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1292 NTTIME g = (given).basic_info.out.access_time; \
1293 NTTIME c = (correct).basic_info.out.access_time; \
1295 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1296 #given, nt_time_string(tctx, g), \
1297 #cmp, #correct, nt_time_string(tctx, c)); \
1302 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1303 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1305 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1306 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1307 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1310 #define GET_INFO_FILE(finfo) do { \
1312 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1313 if (!NT_STATUS_IS_OK(_status)) { \
1315 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1316 nt_errstr(_status)); \
1319 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1320 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1321 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1323 #define GET_INFO_FILE2(finfo) do { \
1325 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1326 if (!NT_STATUS_IS_OK(_status)) { \
1328 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1329 nt_errstr(_status)); \
1332 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1333 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1334 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1336 #define GET_INFO_PATH(pinfo) do { \
1338 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1339 if (!NT_STATUS_IS_OK(_status)) { \
1340 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1341 nt_errstr(_status)); \
1345 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1346 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1347 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1349 #define GET_INFO_BOTH(finfo,pinfo) do { \
1350 GET_INFO_FILE(finfo); \
1351 GET_INFO_PATH(pinfo); \
1352 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1355 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1357 union smb_setfileinfo sfinfo; \
1358 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1359 sfinfo.basic_info.in.file.fnum = tfnum; \
1360 sfinfo.basic_info.in.create_time = 0; \
1361 sfinfo.basic_info.in.access_time = 0; \
1362 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1363 sfinfo.basic_info.in.change_time = 0; \
1364 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1365 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1366 if (!NT_STATUS_IS_OK(_status)) { \
1367 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1368 nt_errstr(_status)); \
1373 #define SET_INFO_FILE(finfo, wrtime) \
1374 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1376 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1378 union smb_setfileinfo sfinfo; \
1379 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1380 sfinfo.basic_info.in.file.fnum = tfnum; \
1381 sfinfo.basic_info.in.create_time = 0; \
1382 sfinfo.basic_info.in.access_time = 0; \
1383 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1384 sfinfo.basic_info.in.write_time += (ns); \
1385 sfinfo.basic_info.in.change_time = 0; \
1386 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1387 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1388 if (!NT_STATUS_IS_OK(_status)) { \
1389 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1390 nt_errstr(_status)); \
1396 static bool test_delayed_write_update3(struct torture_context
*tctx
,
1397 struct smbcli_state
*cli
,
1398 struct smbcli_state
*cli2
)
1400 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
;
1401 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
;
1402 const char *fname
= BASEDIR
"\\torture_file3.txt";
1406 struct timeval start
;
1408 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
1409 int normal_delay
= 2000000;
1410 double sec
= ((double)used_delay
) / ((double)normal_delay
);
1411 int msec
= 1000 * sec
;
1413 torture_comment(tctx
, "\nRunning test_delayed_write_update3\n");
1415 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1417 torture_comment(tctx
, "Open the file handle\n");
1418 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
1421 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
1425 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1426 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
1430 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1431 pinfo0
.basic_info
.in
.file
.path
= fname
;
1437 /* get the initial times */
1438 GET_INFO_BOTH(finfo0
,pinfo0
);
1441 * make sure the write time is updated 2 seconds later
1442 * calcuated from the first write
1443 * (but expect up to 5 seconds extra time for a busy server)
1445 start
= timeval_current();
1446 end
= timeval_add(&start
, 7 * sec
, 0);
1447 while (!timeval_expired(&end
)) {
1449 torture_comment(tctx
, "Do a write on the file handle\n");
1450 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1452 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1456 /* get the times after the write */
1457 GET_INFO_FILE(finfo1
);
1459 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
1460 double diff
= timeval_elapsed(&start
);
1461 if (diff
< (used_delay
/ (double)1000000)) {
1462 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
1463 "(write time update delay == %.2f) (wrong!)\n",
1464 diff
, used_delay
/ (double)1000000);
1469 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1474 smb_msleep(0.5 * msec
);
1477 GET_INFO_BOTH(finfo1
,pinfo1
);
1478 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
1480 /* sure any further write doesn't update the write time */
1481 start
= timeval_current();
1482 end
= timeval_add(&start
, 15 * sec
, 0);
1483 while (!timeval_expired(&end
)) {
1485 torture_comment(tctx
, "Do a write on the file handle\n");
1486 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1488 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1492 /* get the times after the write */
1493 GET_INFO_BOTH(finfo2
,pinfo2
);
1495 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
1496 double diff
= timeval_elapsed(&start
);
1497 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
1503 smb_msleep(1 * msec
);
1506 GET_INFO_BOTH(finfo2
,pinfo2
);
1507 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
1508 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
1509 torture_comment(tctx
, "Server did not update write_time (correct)\n");
1513 smb_msleep(5 * msec
);
1515 GET_INFO_BOTH(finfo3
,pinfo3
);
1516 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
1519 * the close updates the write time to the time of the close
1520 * and not to the time of the last write!
1522 torture_comment(tctx
, "Close the file handle\n");
1523 smbcli_close(cli
->tree
, fnum1
);
1526 GET_INFO_PATH(pinfo4
);
1527 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
1529 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
1530 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
1535 smbcli_close(cli
->tree
, fnum1
);
1536 smbcli_unlink(cli
->tree
, fname
);
1537 smbcli_deltree(cli
->tree
, BASEDIR
);
1543 * Show that a truncate write always updates the write time even
1544 * if an initial write has already updated the write time.
1547 static bool test_delayed_write_update3a(struct torture_context
*tctx
,
1548 struct smbcli_state
*cli
,
1549 struct smbcli_state
*cli2
)
1551 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
;
1552 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
;
1553 const char *fname
= BASEDIR
"\\torture_file3a.txt";
1558 struct timeval start
;
1560 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
1561 int normal_delay
= 2000000;
1562 double sec
= ((double)used_delay
) / ((double)normal_delay
);
1563 int msec
= 1000 * sec
;
1565 torture_comment(tctx
, "\nRunning test_delayed_write_update3a\n");
1567 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1569 torture_comment(tctx
, "Open the file handle\n");
1570 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
1573 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
1577 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1578 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
1582 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1583 pinfo0
.basic_info
.in
.file
.path
= fname
;
1589 /* get the initial times */
1590 GET_INFO_BOTH(finfo0
,pinfo0
);
1593 * sleep some time, to demonstrate the handling of write times
1594 * doesn't depend on the time since the open
1596 smb_msleep(5 * msec
);
1598 /* get the initial times */
1599 GET_INFO_BOTH(finfo1
,pinfo1
);
1600 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
1603 * make sure the write time is updated 2 seconds later
1604 * calcuated from the first write
1605 * (but expect up to 5 seconds extra time for a busy server)
1607 start
= timeval_current();
1608 end
= timeval_add(&start
, 7 * sec
, 0);
1609 while (!timeval_expired(&end
)) {
1611 torture_comment(tctx
, "Do a write on the file handle\n");
1612 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1614 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1618 /* get the times after the write */
1619 GET_INFO_FILE(finfo1
);
1621 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
1622 double diff
= timeval_elapsed(&start
);
1623 if (diff
< (used_delay
/ (double)1000000)) {
1624 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
1625 "(1sec == %.2f) (wrong!)\n",
1631 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1636 smb_msleep(0.5 * msec
);
1639 GET_INFO_BOTH(finfo1
,pinfo1
);
1640 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
1642 smb_msleep(3 * msec
);
1645 * demonstrate that a truncate write always
1646 * updates the write time immediately
1648 for (i
=0; i
< 3; i
++) {
1649 smb_msleep(2 * msec
);
1651 torture_comment(tctx
, "Do a truncate SMBwrite [%d] on the file handle\n", i
);
1652 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 10240, 0);
1654 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
1658 /* get the times after the write */
1659 GET_INFO_BOTH(finfo2
,pinfo2
);
1660 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
1664 smb_msleep(3 * msec
);
1666 /* sure any further write doesn't update the write time */
1667 start
= timeval_current();
1668 end
= timeval_add(&start
, 15 * sec
, 0);
1669 while (!timeval_expired(&end
)) {
1671 torture_comment(tctx
, "Do a write on the file handle\n");
1672 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1674 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1678 /* get the times after the write */
1679 GET_INFO_BOTH(finfo2
,pinfo2
);
1681 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
1682 double diff
= timeval_elapsed(&start
);
1683 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
1689 smb_msleep(1 * msec
);
1692 GET_INFO_BOTH(finfo2
,pinfo2
);
1693 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
1694 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
1695 torture_comment(tctx
, "Server did not update write_time (correct)\n");
1699 smb_msleep(3 * msec
);
1701 /* get the initial times */
1702 GET_INFO_BOTH(finfo1
,pinfo1
);
1703 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo2
);
1706 * demonstrate that a truncate write always
1707 * updates the write time immediately
1709 for (i
=0; i
< 3; i
++) {
1710 smb_msleep(2 * msec
);
1712 torture_comment(tctx
, "Do a truncate SMBwrite [%d] on the file handle\n", i
);
1713 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 512, 0);
1715 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
1719 /* get the times after the write */
1720 GET_INFO_BOTH(finfo2
,pinfo2
);
1721 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
1726 smb_msleep(3 * msec
);
1728 GET_INFO_BOTH(finfo3
,pinfo3
);
1729 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
1732 * the close doesn't update the write time
1734 torture_comment(tctx
, "Close the file handle\n");
1735 smbcli_close(cli
->tree
, fnum1
);
1738 GET_INFO_PATH(pinfo4
);
1739 COMPARE_WRITE_TIME_EQUAL(pinfo4
, pinfo3
);
1741 if (pinfo4
.basic_info
.out
.write_time
== pinfo3
.basic_info
.out
.write_time
) {
1742 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
1747 smbcli_close(cli
->tree
, fnum1
);
1748 smbcli_unlink(cli
->tree
, fname
);
1749 smbcli_deltree(cli
->tree
, BASEDIR
);
1755 * Show a close after write updates the write timestamp to
1756 * the close time, not the last write time.
1759 static bool test_delayed_write_update3b(struct torture_context
*tctx
,
1760 struct smbcli_state
*cli
,
1761 struct smbcli_state
*cli2
)
1763 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
;
1764 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
;
1765 const char *fname
= BASEDIR
"\\torture_file3b.txt";
1769 struct timeval start
;
1771 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
1772 int normal_delay
= 2000000;
1773 double sec
= ((double)used_delay
) / ((double)normal_delay
);
1774 int msec
= 1000 * sec
;
1776 torture_comment(tctx
, "\nRunning test_delayed_write_update3b\n");
1778 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1780 torture_comment(tctx
, "Open the file handle\n");
1781 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
1784 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
1788 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1789 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
1793 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1794 pinfo0
.basic_info
.in
.file
.path
= fname
;
1800 /* get the initial times */
1801 GET_INFO_BOTH(finfo0
,pinfo0
);
1804 * sleep some time, to demonstrate the handling of write times
1805 * doesn't depend on the time since the open
1807 smb_msleep(5 * msec
);
1809 /* get the initial times */
1810 GET_INFO_BOTH(finfo1
,pinfo1
);
1811 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
1814 * make sure the write time is updated 2 seconds later
1815 * calcuated from the first write
1816 * (but expect up to 5 seconds extra time for a busy server)
1818 start
= timeval_current();
1819 end
= timeval_add(&start
, 7 * sec
, 0);
1820 while (!timeval_expired(&end
)) {
1822 torture_comment(tctx
, "Do a write on the file handle\n");
1823 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1825 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1829 /* get the times after the write */
1830 GET_INFO_FILE(finfo1
);
1832 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
1833 double diff
= timeval_elapsed(&start
);
1834 if (diff
< (used_delay
/ (double)1000000)) {
1835 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds"
1836 "(expected > %.2f) (wrong!)\n",
1837 diff
, used_delay
/ (double)1000000);
1842 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
1843 "(write time update delay == %.2f) (correct)\n",
1844 diff
, used_delay
/ (double)1000000);
1847 smb_msleep(0.5 * msec
);
1850 GET_INFO_BOTH(finfo1
,pinfo1
);
1851 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
1853 /* sure any further write doesn't update the write time */
1854 start
= timeval_current();
1855 end
= timeval_add(&start
, 15 * sec
, 0);
1856 while (!timeval_expired(&end
)) {
1858 torture_comment(tctx
, "Do a write on the file handle\n");
1859 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
1861 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
1865 /* get the times after the write */
1866 GET_INFO_BOTH(finfo2
,pinfo2
);
1868 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
1869 double diff
= timeval_elapsed(&start
);
1870 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
1876 smb_msleep(1 * msec
);
1879 GET_INFO_BOTH(finfo2
,pinfo2
);
1880 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
1881 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
1882 torture_comment(tctx
, "Server did not update write_time (correct)\n");
1886 smb_msleep(5 * msec
);
1888 GET_INFO_BOTH(finfo3
,pinfo3
);
1889 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
1892 * the close updates the write time to the time of the close
1893 * and not to the time of the last write!
1895 torture_comment(tctx
, "Close the file handle\n");
1896 smbcli_close(cli
->tree
, fnum1
);
1899 GET_INFO_PATH(pinfo4
);
1900 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
1902 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
1903 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
1908 smbcli_close(cli
->tree
, fnum1
);
1909 smbcli_unlink(cli
->tree
, fname
);
1910 smbcli_deltree(cli
->tree
, BASEDIR
);
1916 * Check that a write after a truncate write doesn't update
1917 * the timestamp, but a truncate write after a write does.
1918 * Also prove that a close after a truncate write updates the
1919 * timestamp to current, not the time of last write.
1922 static bool test_delayed_write_update3c(struct torture_context
*tctx
,
1923 struct smbcli_state
*cli
,
1924 struct smbcli_state
*cli2
)
1926 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
;
1927 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
;
1928 const char *fname
= BASEDIR
"\\torture_file3c.txt";
1933 struct timeval start
;
1935 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
1936 int normal_delay
= 2000000;
1937 double sec
= ((double)used_delay
) / ((double)normal_delay
);
1938 int msec
= 1000 * sec
;
1940 torture_comment(tctx
, "\nRunning test_delayed_write_update3c\n");
1942 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
1944 torture_comment(tctx
, "Open the file handle\n");
1945 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
1948 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
1952 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1953 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
1957 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
1958 pinfo0
.basic_info
.in
.file
.path
= fname
;
1964 /* get the initial times */
1965 GET_INFO_BOTH(finfo0
,pinfo0
);
1968 * sleep some time, to demonstrate the handling of write times
1969 * doesn't depend on the time since the open
1971 smb_msleep(5 * msec
);
1973 /* get the initial times */
1974 GET_INFO_BOTH(finfo1
,pinfo1
);
1975 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
1978 * demonstrate that a truncate write always
1979 * updates the write time immediately
1981 for (i
=0; i
< 3; i
++) {
1982 smb_msleep(2 * msec
);
1984 torture_comment(tctx
, "Do a truncate SMBwrite [%d] on the file handle\n", i
);
1985 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 512, 0);
1987 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
1991 /* get the times after the write */
1992 GET_INFO_BOTH(finfo2
,pinfo2
);
1993 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
1997 start
= timeval_current();
1998 end
= timeval_add(&start
, 7 * sec
, 0);
1999 while (!timeval_expired(&end
)) {
2001 torture_comment(tctx
, "Do a write on the file handle\n");
2002 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2004 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2008 /* get the times after the write */
2009 GET_INFO_FILE(finfo2
);
2011 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
2012 double diff
= timeval_elapsed(&start
);
2013 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
2019 smb_msleep(1 * msec
);
2022 GET_INFO_BOTH(finfo2
,pinfo2
);
2023 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2024 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
2025 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2029 smb_msleep(5 * msec
);
2031 /* get the initial times */
2032 GET_INFO_BOTH(finfo1
,pinfo1
);
2033 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo2
);
2036 * demonstrate that a truncate write always
2037 * updates the write time immediately
2039 for (i
=0; i
< 3; i
++) {
2040 smb_msleep(2 * msec
);
2042 torture_comment(tctx
, "Do a truncate write [%d] on the file handle\n", i
);
2043 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 512, 0);
2045 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 0", (int)written
);
2049 /* get the times after the write */
2050 GET_INFO_BOTH(finfo2
,pinfo2
);
2051 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2056 smb_msleep(5 * msec
);
2058 GET_INFO_BOTH(finfo2
,pinfo2
);
2059 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2061 /* sure any further write doesn't update the write time */
2062 start
= timeval_current();
2063 end
= timeval_add(&start
, 15 * sec
, 0);
2064 while (!timeval_expired(&end
)) {
2066 torture_comment(tctx
, "Do a write on the file handle\n");
2067 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2069 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2073 /* get the times after the write */
2074 GET_INFO_BOTH(finfo2
,pinfo2
);
2076 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
2077 double diff
= timeval_elapsed(&start
);
2078 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
2084 smb_msleep(1 * msec
);
2087 GET_INFO_BOTH(finfo2
,pinfo2
);
2088 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2089 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
2090 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2094 smb_msleep(5 * msec
);
2096 GET_INFO_BOTH(finfo3
,pinfo3
);
2097 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2100 * the close updates the write time to the time of the close
2101 * and not to the time of the last write!
2103 torture_comment(tctx
, "Close the file handle\n");
2104 smbcli_close(cli
->tree
, fnum1
);
2107 GET_INFO_PATH(pinfo4
);
2108 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
2110 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
2111 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
2116 smbcli_close(cli
->tree
, fnum1
);
2117 smbcli_unlink(cli
->tree
, fname
);
2118 smbcli_deltree(cli
->tree
, BASEDIR
);
2124 * Show only the first write updates the timestamp, and a close
2125 * after writes updates to current (I think this is the same
2129 static bool test_delayed_write_update4(struct torture_context
*tctx
,
2130 struct smbcli_state
*cli
,
2131 struct smbcli_state
*cli2
)
2133 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
;
2134 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
;
2135 const char *fname
= BASEDIR
"\\torture_file4.txt";
2139 struct timeval start
;
2141 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2142 int normal_delay
= 2000000;
2143 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2144 int msec
= 1000 * sec
;
2146 torture_comment(tctx
, "\nRunning test_delayed_write_update4\n");
2148 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
2150 torture_comment(tctx
, "Open the file handle\n");
2151 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2154 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2158 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2159 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2163 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2164 pinfo0
.basic_info
.in
.file
.path
= fname
;
2170 /* get the initial times */
2171 GET_INFO_BOTH(finfo0
,pinfo0
);
2174 smb_msleep(5 * msec
);
2177 torture_comment(tctx
, "Do a write on the file handle\n");
2178 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2180 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2185 GET_INFO_BOTH(finfo1
,pinfo1
);
2186 COMPARE_WRITE_TIME_EQUAL(finfo1
,finfo0
);
2189 * make sure the write time is updated 2 seconds later
2190 * calcuated from the first write
2191 * (but expect up to 3 seconds extra time for a busy server)
2193 start
= timeval_current();
2194 end
= timeval_add(&start
, 5 * sec
, 0);
2195 while (!timeval_expired(&end
)) {
2196 /* get the times after the first write */
2197 GET_INFO_FILE(finfo1
);
2199 if (finfo1
.basic_info
.out
.write_time
> finfo0
.basic_info
.out
.write_time
) {
2200 double diff
= timeval_elapsed(&start
);
2201 if (diff
< (used_delay
/ (double)1000000)) {
2202 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds"
2203 "(expected > %.2f) (wrong!)\n",
2204 diff
, used_delay
/ (double)1000000);
2209 torture_comment(tctx
, "Server updated write_time after %.2f seconds "
2210 "(write time update delay == %.2f) (correct)\n",
2211 diff
, used_delay
/ (double)1000000);
2214 smb_msleep(0.5 * msec
);
2217 GET_INFO_BOTH(finfo1
,pinfo1
);
2218 COMPARE_WRITE_TIME_GREATER(pinfo1
, pinfo0
);
2220 /* sure any further write doesn't update the write time */
2221 start
= timeval_current();
2222 end
= timeval_add(&start
, 15 * sec
, 0);
2223 while (!timeval_expired(&end
)) {
2225 torture_comment(tctx
, "Do a write on the file handle\n");
2226 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2228 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2232 /* get the times after the write */
2233 GET_INFO_BOTH(finfo2
,pinfo2
);
2235 if (finfo2
.basic_info
.out
.write_time
> finfo1
.basic_info
.out
.write_time
) {
2236 double diff
= timeval_elapsed(&start
);
2237 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
2243 smb_msleep(1 * msec
);
2246 GET_INFO_BOTH(finfo2
,pinfo2
);
2247 COMPARE_WRITE_TIME_EQUAL(finfo2
, finfo1
);
2248 if (finfo2
.basic_info
.out
.write_time
== finfo1
.basic_info
.out
.write_time
) {
2249 torture_comment(tctx
, "Server did not updatewrite_time (correct)\n");
2253 smb_msleep(5 * msec
);
2255 GET_INFO_BOTH(finfo3
,pinfo3
);
2256 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2259 * the close updates the write time to the time of the close
2260 * and not to the time of the last write!
2262 torture_comment(tctx
, "Close the file handle\n");
2263 smbcli_close(cli
->tree
, fnum1
);
2266 GET_INFO_PATH(pinfo4
);
2267 COMPARE_WRITE_TIME_GREATER(pinfo4
, pinfo3
);
2269 if (pinfo4
.basic_info
.out
.write_time
> pinfo3
.basic_info
.out
.write_time
) {
2270 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
2275 smbcli_close(cli
->tree
, fnum1
);
2276 smbcli_unlink(cli
->tree
, fname
);
2277 smbcli_deltree(cli
->tree
, BASEDIR
);
2283 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2286 static bool test_delayed_write_update5(struct torture_context
*tctx
,
2287 struct smbcli_state
*cli
,
2288 struct smbcli_state
*cli2
)
2290 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
, finfo5
;
2291 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
, pinfo6
;
2292 const char *fname
= BASEDIR
"\\torture_file5.txt";
2296 struct timeval start
;
2298 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2299 int normal_delay
= 2000000;
2300 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2301 int msec
= 1000 * sec
;
2303 torture_comment(tctx
, "\nRunning test_delayed_write_update5\n");
2305 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
2307 torture_comment(tctx
, "Open the file handle\n");
2308 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2311 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2315 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2316 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2322 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2323 pinfo0
.basic_info
.in
.file
.path
= fname
;
2331 /* get the initial times */
2332 GET_INFO_BOTH(finfo0
,pinfo0
);
2335 torture_comment(tctx
, "Do a write on the file handle\n");
2336 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2338 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2343 GET_INFO_BOTH(finfo1
,pinfo1
);
2344 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
2346 torture_comment(tctx
, "Set write time in the future on the file handle\n");
2347 SET_INFO_FILE(finfo0
, time(NULL
) + 86400);
2348 GET_INFO_BOTH(finfo2
,pinfo2
);
2349 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2351 torture_comment(tctx
, "Set write time in the past on the file handle\n");
2352 SET_INFO_FILE(finfo0
, time(NULL
) - 86400);
2353 GET_INFO_BOTH(finfo2
,pinfo2
);
2354 COMPARE_WRITE_TIME_LESS(finfo2
, finfo1
);
2356 /* make sure the 2 second delay from the first write are canceled */
2357 start
= timeval_current();
2358 end
= timeval_add(&start
, 15 * sec
, 0);
2359 while (!timeval_expired(&end
)) {
2361 /* get the times after the first write */
2362 GET_INFO_BOTH(finfo3
,pinfo3
);
2364 if (finfo3
.basic_info
.out
.write_time
> finfo2
.basic_info
.out
.write_time
) {
2365 double diff
= timeval_elapsed(&start
);
2366 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
2372 smb_msleep(1 * msec
);
2375 GET_INFO_BOTH(finfo3
,pinfo3
);
2376 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2377 if (finfo3
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
2378 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2381 /* sure any further write doesn't update the write time */
2382 start
= timeval_current();
2383 end
= timeval_add(&start
, 15 * sec
, 0);
2384 while (!timeval_expired(&end
)) {
2386 torture_comment(tctx
, "Do a write on the file handle\n");
2387 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2389 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2393 /* get the times after the write */
2394 GET_INFO_BOTH(finfo4
,pinfo4
);
2396 if (finfo4
.basic_info
.out
.write_time
> finfo3
.basic_info
.out
.write_time
) {
2397 double diff
= timeval_elapsed(&start
);
2398 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
2404 smb_msleep(1 * msec
);
2407 GET_INFO_BOTH(finfo4
,pinfo4
);
2408 COMPARE_WRITE_TIME_EQUAL(finfo4
, finfo3
);
2409 if (finfo4
.basic_info
.out
.write_time
== finfo3
.basic_info
.out
.write_time
) {
2410 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2414 smb_msleep(5 * msec
);
2416 GET_INFO_BOTH(finfo5
,pinfo5
);
2417 COMPARE_WRITE_TIME_EQUAL(finfo5
, finfo4
);
2420 * the close doesn't update the write time
2422 torture_comment(tctx
, "Close the file handle\n");
2423 smbcli_close(cli
->tree
, fnum1
);
2426 GET_INFO_PATH(pinfo6
);
2427 COMPARE_WRITE_TIME_EQUAL(pinfo6
, pinfo5
);
2429 if (pinfo6
.basic_info
.out
.write_time
== pinfo5
.basic_info
.out
.write_time
) {
2430 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
2435 smbcli_close(cli
->tree
, fnum1
);
2436 smbcli_unlink(cli
->tree
, fname
);
2437 smbcli_deltree(cli
->tree
, BASEDIR
);
2443 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2446 static bool test_delayed_write_update5b(struct torture_context
*tctx
,
2447 struct smbcli_state
*cli
,
2448 struct smbcli_state
*cli2
)
2450 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
, finfo5
;
2451 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
, pinfo6
;
2452 const char *fname
= BASEDIR
"\\torture_fileb.txt";
2456 struct timeval start
;
2458 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2459 int normal_delay
= 2000000;
2460 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2461 int msec
= 1000 * sec
;
2463 torture_comment(tctx
, "\nRunning test_delayed_write_update5b\n");
2465 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
2467 torture_comment(tctx
, "Open the file handle\n");
2468 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2471 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2475 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2476 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2482 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2483 pinfo0
.basic_info
.in
.file
.path
= fname
;
2491 /* get the initial times */
2492 GET_INFO_BOTH(finfo0
,pinfo0
);
2495 torture_comment(tctx
, "Do a write on the file handle\n");
2496 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2498 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2503 GET_INFO_BOTH(finfo1
,pinfo1
);
2504 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
2506 torture_comment(tctx
, "Set write time in the future on the file handle\n");
2507 SET_INFO_FILE(finfo0
, time(NULL
) + 86400);
2508 GET_INFO_BOTH(finfo2
,pinfo2
);
2509 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2511 torture_comment(tctx
, "Set write time in the past on the file handle\n");
2512 SET_INFO_FILE(finfo0
, time(NULL
) - 86400);
2513 GET_INFO_BOTH(finfo2
,pinfo2
);
2514 COMPARE_WRITE_TIME_LESS(finfo2
, finfo1
);
2516 /* make sure the 2 second delay from the first write are canceled */
2517 start
= timeval_current();
2518 end
= timeval_add(&start
, 15 * sec
, 0);
2519 while (!timeval_expired(&end
)) {
2521 /* get the times after the first write */
2522 GET_INFO_BOTH(finfo3
,pinfo3
);
2524 if (finfo3
.basic_info
.out
.write_time
> finfo2
.basic_info
.out
.write_time
) {
2525 double diff
= timeval_elapsed(&start
);
2526 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
2532 smb_msleep(1 * msec
);
2535 GET_INFO_BOTH(finfo3
,pinfo3
);
2536 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2537 if (finfo3
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
2538 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2541 /* Do any further write (truncates) update the write time ? */
2542 start
= timeval_current();
2543 end
= timeval_add(&start
, 15 * sec
, 0);
2544 while (!timeval_expired(&end
)) {
2546 torture_comment(tctx
, "Do a truncate write on the file handle\n");
2547 written
= smbcli_smbwrite(cli
->tree
, fnum1
, "x", 1024, 0);
2549 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2553 /* get the times after the write */
2554 GET_INFO_BOTH(finfo4
,pinfo4
);
2556 if (finfo4
.basic_info
.out
.write_time
> finfo3
.basic_info
.out
.write_time
) {
2557 double diff
= timeval_elapsed(&start
);
2558 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
2564 smb_msleep(1 * msec
);
2567 GET_INFO_BOTH(finfo4
,pinfo4
);
2568 COMPARE_WRITE_TIME_EQUAL(finfo4
, finfo3
);
2569 if (finfo4
.basic_info
.out
.write_time
== finfo3
.basic_info
.out
.write_time
) {
2570 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2574 smb_msleep(5 * msec
);
2576 GET_INFO_BOTH(finfo5
,pinfo5
);
2577 COMPARE_WRITE_TIME_EQUAL(finfo5
, finfo4
);
2580 * the close doesn't update the write time
2582 torture_comment(tctx
, "Close the file handle\n");
2583 smbcli_close(cli
->tree
, fnum1
);
2586 GET_INFO_PATH(pinfo6
);
2587 COMPARE_WRITE_TIME_EQUAL(pinfo6
, pinfo5
);
2589 if (pinfo6
.basic_info
.out
.write_time
== pinfo5
.basic_info
.out
.write_time
) {
2590 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
2595 smbcli_close(cli
->tree
, fnum1
);
2596 smbcli_unlink(cli
->tree
, fname
);
2597 smbcli_deltree(cli
->tree
, BASEDIR
);
2603 * Open 2 handles on a file. Write one one and then set the
2604 * WRITE TIME explicitly on the other. Ensure the write time
2605 * update is cancelled. Ensure the write time is updated to
2606 * the close time when the non-explicit set handle is closed.
2610 static bool test_delayed_write_update6(struct torture_context
*tctx
,
2611 struct smbcli_state
*cli
,
2612 struct smbcli_state
*cli2
)
2614 union smb_fileinfo finfo0
, finfo1
, finfo2
, finfo3
, finfo4
, finfo5
;
2615 union smb_fileinfo pinfo0
, pinfo1
, pinfo2
, pinfo3
, pinfo4
, pinfo5
, pinfo6
, pinfo7
;
2616 const char *fname
= BASEDIR
"\\torture_file6.txt";
2621 struct timeval start
;
2623 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2624 int normal_delay
= 2000000;
2625 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2626 int msec
= 1000 * sec
;
2629 torture_comment(tctx
, "\nRunning test_delayed_write_update6\n");
2631 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
2633 torture_comment(tctx
, "Open the file handle\n");
2634 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2637 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2642 torture_comment(tctx
, "Open the 2nd file handle on 2nd connection\n");
2643 fnum2
= smbcli_open(cli2
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2646 torture_result(tctx
, TORTURE_FAIL
, __location__
": unable to open %s", fname
);
2651 finfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2652 finfo0
.basic_info
.in
.file
.fnum
= fnum1
;
2658 pinfo0
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2659 pinfo0
.basic_info
.in
.file
.path
= fname
;
2668 /* get the initial times */
2669 GET_INFO_BOTH(finfo0
,pinfo0
);
2672 torture_comment(tctx
, "Do a write on the file handle\n");
2673 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2675 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2680 GET_INFO_BOTH(finfo1
,pinfo1
);
2681 COMPARE_WRITE_TIME_EQUAL(finfo1
, finfo0
);
2683 torture_comment(tctx
, "Set write time in the future on the 2nd file handle\n");
2684 SET_INFO_FILE_EX(finfo0
, time(NULL
) + 86400, cli2
->tree
, fnum2
);
2685 GET_INFO_BOTH(finfo2
,pinfo2
);
2686 COMPARE_WRITE_TIME_GREATER(finfo2
, finfo1
);
2688 torture_comment(tctx
, "Set write time in the past on the 2nd file handle\n");
2689 SET_INFO_FILE_EX(finfo0
, time(NULL
) - 86400, cli2
->tree
, fnum2
);
2690 GET_INFO_BOTH(finfo2
,pinfo2
);
2691 COMPARE_WRITE_TIME_LESS(finfo2
, finfo1
);
2693 /* make sure the 2 second delay from the first write are canceled */
2694 start
= timeval_current();
2695 end
= timeval_add(&start
, 10 * sec
, 0);
2696 while (!timeval_expired(&end
)) {
2698 /* get the times after the first write */
2699 GET_INFO_BOTH(finfo3
,pinfo3
);
2701 if (finfo3
.basic_info
.out
.write_time
> finfo2
.basic_info
.out
.write_time
) {
2702 double diff
= timeval_elapsed(&start
);
2703 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
2709 smb_msleep(1 * msec
);
2712 GET_INFO_BOTH(finfo3
,pinfo3
);
2713 COMPARE_WRITE_TIME_EQUAL(finfo3
, finfo2
);
2714 if (finfo3
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
2715 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2718 /* sure any further write doesn't update the write time */
2719 start
= timeval_current();
2720 end
= timeval_add(&start
, 10 * sec
, 0);
2721 while (!timeval_expired(&end
)) {
2723 torture_comment(tctx
, "Do a write on the file handle\n");
2724 written
= smbcli_write(cli
->tree
, fnum1
, 0, "x", 0, 1);
2726 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2730 /* get the times after the write */
2731 GET_INFO_BOTH(finfo4
,pinfo4
);
2733 if (finfo4
.basic_info
.out
.write_time
> finfo3
.basic_info
.out
.write_time
) {
2734 double diff
= timeval_elapsed(&start
);
2735 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
2741 smb_msleep(1 * msec
);
2744 GET_INFO_BOTH(finfo4
,pinfo4
);
2745 COMPARE_WRITE_TIME_EQUAL(finfo4
, finfo3
);
2746 if (finfo4
.basic_info
.out
.write_time
== finfo3
.basic_info
.out
.write_time
) {
2747 torture_comment(tctx
, "Server did not update write_time (correct)\n");
2751 smb_msleep(5 * msec
);
2753 GET_INFO_BOTH(finfo5
,pinfo5
);
2754 COMPARE_WRITE_TIME_EQUAL(finfo5
, finfo4
);
2757 * the close updates the write time to the time of the close
2758 * as the write time was set on the 2nd handle
2760 torture_comment(tctx
, "Close the file handle\n");
2761 smbcli_close(cli
->tree
, fnum1
);
2764 GET_INFO_PATH(pinfo6
);
2765 COMPARE_WRITE_TIME_GREATER(pinfo6
, pinfo5
);
2767 if (pinfo6
.basic_info
.out
.write_time
> pinfo5
.basic_info
.out
.write_time
) {
2768 torture_comment(tctx
, "Server updated the write_time on close (correct)\n");
2771 /* See what the second write handle thinks the time is ? */
2772 finfo5
.basic_info
.in
.file
.fnum
= fnum2
;
2773 GET_INFO_FILE2(finfo5
);
2774 COMPARE_WRITE_TIME_EQUAL(finfo5
, pinfo6
);
2776 /* See if we have lost the sticky write time on handle2 */
2777 smb_msleep(3 * msec
);
2778 torture_comment(tctx
, "Have we lost the sticky write time ?\n");
2780 /* Make sure any further normal write doesn't update the write time */
2781 start
= timeval_current();
2782 end
= timeval_add(&start
, 10 * sec
, 0);
2783 while (!timeval_expired(&end
)) {
2785 torture_comment(tctx
, "Do a write on the second file handle\n");
2786 written
= smbcli_write(cli2
->tree
, fnum2
, 0, "x", 0, 1);
2788 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2792 /* get the times after the write */
2793 GET_INFO_FILE2(finfo5
);
2794 GET_INFO_PATH(pinfo6
);
2796 if (finfo5
.basic_info
.out
.write_time
> pinfo6
.basic_info
.out
.write_time
) {
2797 double diff
= timeval_elapsed(&start
);
2798 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
2804 smb_msleep(1 * msec
);
2807 /* What about a truncate write ? */
2808 start
= timeval_current();
2809 end
= timeval_add(&start
, 10 * sec
, 0);
2810 while (!timeval_expired(&end
)) {
2812 torture_comment(tctx
, "Do a truncate write on the second file handle\n");
2813 written
= smbcli_write(cli2
->tree
, fnum2
, 0, "x", 0, 0);
2815 torture_result(tctx
, TORTURE_FAIL
, __location__
": written gave %d - should have been 1", (int)written
);
2819 /* get the times after the write */
2820 GET_INFO_FILE2(finfo5
);
2821 GET_INFO_PATH(pinfo6
);
2823 if (finfo5
.basic_info
.out
.write_time
> pinfo6
.basic_info
.out
.write_time
) {
2824 double diff
= timeval_elapsed(&start
);
2825 torture_result(tctx
, TORTURE_FAIL
, "Server updated write_time after %.2f seconds "
2831 smb_msleep(1 * msec
);
2835 /* keep the 2nd handle open and rerun tests */
2842 * closing the 2nd handle will cause no write time update
2843 * as the write time was explicit set on this handle
2845 torture_comment(tctx
, "Close the 2nd file handle\n");
2846 smbcli_close(cli2
->tree
, fnum2
);
2849 GET_INFO_PATH(pinfo7
);
2850 COMPARE_WRITE_TIME_EQUAL(pinfo7
, pinfo6
);
2852 if (pinfo7
.basic_info
.out
.write_time
== pinfo6
.basic_info
.out
.write_time
) {
2853 torture_comment(tctx
, "Server did not update the write_time on close (correct)\n");
2858 smbcli_close(cli
->tree
, fnum1
);
2860 smbcli_close(cli2
->tree
, fnum2
);
2861 smbcli_unlink(cli
->tree
, fname
);
2862 smbcli_deltree(cli
->tree
, BASEDIR
);
2867 static bool test_delayed_write_update7(struct torture_context
*tctx
, struct smbcli_state
*cli
)
2869 union smb_open open_parms
;
2870 union smb_fileinfo finfo1
, finfo2
, finfo3
;
2871 const char *fname
= BASEDIR
"\\torture_file7.txt";
2875 TALLOC_CTX
*mem_ctx
;
2877 torture_comment(tctx
, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2879 mem_ctx
= talloc_init("test_delayed_write_update7");
2880 if (!mem_ctx
) return false;
2882 ZERO_STRUCT(finfo1
);
2883 ZERO_STRUCT(finfo2
);
2884 ZERO_STRUCT(finfo3
);
2885 ZERO_STRUCT(open_parms
);
2887 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
2889 /* Create the file. */
2890 fnum1
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
2892 torture_result(tctx
, TORTURE_FAIL
, "Failed to open %s", fname
);
2896 finfo1
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
2897 finfo1
.basic_info
.in
.file
.fnum
= fnum1
;
2901 /* Get the initial timestamps. */
2902 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo1
);
2904 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
2906 /* Set the pending write time to a value with ns. */
2907 SET_INFO_FILE_NS(finfo
, time(NULL
) + 86400, 103, cli
->tree
, fnum1
);
2909 /* Get the current pending write time by fnum. */
2910 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &finfo2
);
2912 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
2914 /* Ensure the time is actually different. */
2915 if (finfo1
.basic_info
.out
.write_time
== finfo2
.basic_info
.out
.write_time
) {
2916 torture_result(tctx
, TORTURE_FAIL
,
2917 "setfileinfo time matches original fileinfo time");
2921 /* Get the current pending write time by path. */
2922 finfo3
.basic_info
.in
.file
.path
= fname
;
2923 status
= smb_raw_pathinfo(cli
->tree
, tctx
, &finfo3
);
2925 if (finfo2
.basic_info
.out
.write_time
!= finfo3
.basic_info
.out
.write_time
) {
2926 torture_result(tctx
, TORTURE_FAIL
,
2927 "qpathinfo time doesn't match fileinfo time");
2931 /* Now close the file. Re-open and check that the write
2932 time is identical to the one we wrote. */
2934 smbcli_close(cli
->tree
, fnum1
);
2936 open_parms
.ntcreatex
.level
= RAW_OPEN_NTCREATEX
;
2937 open_parms
.ntcreatex
.in
.flags
= 0;
2938 open_parms
.ntcreatex
.in
.access_mask
= SEC_GENERIC_READ
;
2939 open_parms
.ntcreatex
.in
.file_attr
= 0;
2940 open_parms
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
2941 NTCREATEX_SHARE_ACCESS_READ
|
2942 NTCREATEX_SHARE_ACCESS_WRITE
;
2943 open_parms
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
2944 open_parms
.ntcreatex
.in
.create_options
= 0;
2945 open_parms
.ntcreatex
.in
.fname
= fname
;
2947 status
= smb_raw_open(cli
->tree
, mem_ctx
, &open_parms
);
2948 talloc_free(mem_ctx
);
2950 if (!NT_STATUS_IS_OK(status
)) {
2951 torture_result(tctx
, TORTURE_FAIL
,
2952 "setfileinfo time matches original fileinfo time");
2956 fnum1
= open_parms
.ntcreatex
.out
.file
.fnum
;
2958 /* Check the returned time matches. */
2959 if (open_parms
.ntcreatex
.out
.write_time
!= finfo2
.basic_info
.out
.write_time
) {
2960 torture_result(tctx
, TORTURE_FAIL
,
2961 "final open time does not match set time");
2967 smbcli_close(cli
->tree
, fnum1
);
2969 smbcli_unlink(cli
->tree
, fname
);
2970 smbcli_deltree(cli
->tree
, BASEDIR
);
2975 Test if creating a file in a directory with an open handle updates the
2976 write timestamp (it should).
2978 static bool test_directory_update8(struct torture_context
*tctx
, struct smbcli_state
*cli
)
2980 union smb_fileinfo dir_info1
, dir_info2
;
2981 union smb_open open_parms
;
2982 const char *fname
= BASEDIR
"\\torture_file.txt";
2987 double used_delay
= torture_setting_int(tctx
, "writetimeupdatedelay", 2000000);
2988 int normal_delay
= 2000000;
2989 double sec
= ((double)used_delay
) / ((double)normal_delay
);
2990 int msec
= 1000 * sec
;
2991 TALLOC_CTX
*mem_ctx
= talloc_init("test_delayed_write_update8");
2993 if (!mem_ctx
) return false;
2995 torture_comment(tctx
, "\nRunning test directory write update\n");
2997 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR
), "Failed to setup up test directory: " BASEDIR
);
2999 /* Open a handle on the directory - and leave it open. */
3000 ZERO_STRUCT(open_parms
);
3001 open_parms
.ntcreatex
.level
= RAW_OPEN_NTCREATEX
;
3002 open_parms
.ntcreatex
.in
.flags
= 0;
3003 open_parms
.ntcreatex
.in
.access_mask
= SEC_RIGHTS_FILE_READ
;
3004 open_parms
.ntcreatex
.in
.file_attr
= 0;
3005 open_parms
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_DELETE
|
3006 NTCREATEX_SHARE_ACCESS_READ
|
3007 NTCREATEX_SHARE_ACCESS_WRITE
;
3008 open_parms
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
3009 open_parms
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
3010 open_parms
.ntcreatex
.in
.fname
= BASEDIR
;
3012 status
= smb_raw_open(cli
->tree
, mem_ctx
, &open_parms
);
3013 talloc_free(mem_ctx
);
3015 if (!NT_STATUS_IS_OK(status
)) {
3016 torture_result(tctx
, TORTURE_FAIL
,
3017 "failed to open directory handle");
3022 fnum1
= open_parms
.ntcreatex
.out
.file
.fnum
;
3024 /* Store the returned write time. */
3025 ZERO_STRUCT(dir_info1
);
3026 dir_info1
.basic_info
.out
.write_time
= open_parms
.ntcreatex
.out
.write_time
;
3028 torture_comment(tctx
, "Initial write time %s\n",
3029 nt_time_string(tctx
, dir_info1
.basic_info
.out
.write_time
));
3032 smb_msleep(3 * msec
);
3034 /* Now create a file within the directory. */
3035 fnum2
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
3037 torture_result(tctx
, TORTURE_FAIL
, "Failed to open %s", fname
);
3041 smbcli_close(cli
->tree
, fnum2
);
3043 /* Read the directory write time again. */
3044 ZERO_STRUCT(dir_info2
);
3045 dir_info2
.basic_info
.level
= RAW_FILEINFO_BASIC_INFO
;
3046 dir_info2
.basic_info
.in
.file
.fnum
= fnum1
;
3048 status
= smb_raw_fileinfo(cli
->tree
, tctx
, &dir_info2
);
3050 torture_assert_ntstatus_ok(tctx
, status
, "fileinfo failed");
3052 /* Ensure it's been incremented. */
3053 COMPARE_WRITE_TIME_GREATER(dir_info2
, dir_info1
);
3055 torture_comment(tctx
, "Updated write time %s\n",
3056 nt_time_string(tctx
, dir_info2
.basic_info
.out
.write_time
));
3061 smbcli_close(cli
->tree
, fnum1
);
3062 smbcli_unlink(cli
->tree
, fname
);
3063 smbcli_deltree(cli
->tree
, BASEDIR
);
3069 testing of delayed update of write_time
3071 struct torture_suite
*torture_delay_write(TALLOC_CTX
*ctx
)
3073 struct torture_suite
*suite
= torture_suite_create(ctx
, "delaywrite");
3075 torture_suite_add_2smb_test(suite
, "finfo update on close", test_finfo_after_write
);
3076 torture_suite_add_1smb_test(suite
, "delayed update of write time", test_delayed_write_update
);
3077 torture_suite_add_1smb_test(suite
, "update of write time and SMBwrite truncate", test_delayed_write_update1
);
3078 torture_suite_add_1smb_test(suite
, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a
);
3079 torture_suite_add_1smb_test(suite
, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b
);
3080 torture_suite_add_1smb_test(suite
, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c
);
3081 torture_suite_add_2smb_test(suite
, "delayed update of write time using 2 connections", test_delayed_write_update2
);
3082 torture_suite_add_2smb_test(suite
, "delayed update of write time 3", test_delayed_write_update3
);
3083 torture_suite_add_2smb_test(suite
, "delayed update of write time 3a", test_delayed_write_update3a
);
3084 torture_suite_add_2smb_test(suite
, "delayed update of write time 3b", test_delayed_write_update3b
);
3085 torture_suite_add_2smb_test(suite
, "delayed update of write time 3c", test_delayed_write_update3c
);
3086 torture_suite_add_2smb_test(suite
, "delayed update of write time 4", test_delayed_write_update4
);
3087 torture_suite_add_2smb_test(suite
, "delayed update of write time 5", test_delayed_write_update5
);
3088 torture_suite_add_2smb_test(suite
, "delayed update of write time 5b", test_delayed_write_update5b
);
3089 torture_suite_add_2smb_test(suite
, "delayed update of write time 6", test_delayed_write_update6
);
3090 torture_suite_add_1smb_test(suite
, "timestamp resolution test", test_delayed_write_update7
);
3091 torture_suite_add_1smb_test(suite
, "directory timestamp update test", test_directory_update8
);