knownfail: remove python[23] lines
[Samba.git] / source4 / torture / basic / delaywrite.c
blob620870120bdf620b6a55de71924e0e4e51352e33
1 /*
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/>.
24 #include "includes.h"
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";
40 NTSTATUS status;
41 int fnum1 = -1;
42 bool ret = true;
43 ssize_t written;
44 struct timeval start;
45 struct timeval end;
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;
61 finfo2 = finfo1;
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);
88 torture_assert(tctx,
89 diff >= (used_delay / (double)1000000),
90 talloc_asprintf(tctx,
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",
96 diff);
97 break;
99 fflush(stdout);
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 "
107 "120 seconds");
109 if (fnum1 != -1)
110 smbcli_close(cli->tree, fnum1);
111 smbcli_unlink(cli->tree, fname);
112 smbcli_deltree(cli->tree, BASEDIR);
114 return ret;
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";
121 NTSTATUS status;
122 int fnum1 = -1;
123 bool ret = true;
124 ssize_t written;
125 struct timeval start;
126 struct timeval end;
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;
131 char buf[2048];
132 bool first;
133 bool updated;
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;
152 finfo2 = finfo1;
153 finfo3 = finfo1;
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);
178 first = true;
179 updated = false;
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 "
187 "(1024)");
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)
195 updated = true;
196 break;
199 fflush(stdout);
200 smb_msleep(1 * msec);
201 first = false;
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");
213 fflush(stdout);
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 "
230 "(1024)");
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)));
243 fflush(stdout);
244 smb_msleep(1 * msec);
247 torture_comment(tctx, "Server did not update write time within 10 "
248 "seconds. Good!\n");
250 fflush(stdout);
251 smb_msleep(2 * msec);
253 /* the close should trigger an write time update */
254 smbcli_close(cli->tree, fnum1);
255 fnum1 = -1;
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 "
264 "close (wrong!)");
265 torture_assert(tctx,
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 "
268 "in time");
270 torture_comment(tctx, "Server updated write time on close (correct)\n");
272 if (fnum1 != -1)
273 smbcli_close(cli->tree, fnum1);
274 smbcli_unlink(cli->tree, fname);
275 smbcli_deltree(cli->tree, BASEDIR);
277 return ret;
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";
287 NTSTATUS status;
288 int fnum1 = -1;
289 bool ret = true;
290 ssize_t written;
291 struct timeval start;
292 struct timeval end;
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;
297 char buf[2048];
298 bool first;
299 bool updated;
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;
318 finfo2 = finfo1;
319 finfo3 = finfo1;
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);
341 first = true;
342 updated = false;
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 "
350 "(10240)");
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)
358 updated = true;
359 break;
362 fflush(stdout);
363 smb_msleep(1 * msec);
364 first = false;
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");
376 fflush(stdout);
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 "
394 "(10240)");
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)));
407 fflush(stdout);
408 smb_msleep(1 * msec);
411 torture_comment(tctx, "Server did not update write time within 10 "
412 "seconds. Good!\n");
414 /* the close should trigger an write time update */
415 smbcli_close(cli->tree, fnum1);
416 fnum1 = -1;
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 "
425 "close (wrong!)");
426 torture_assert(tctx,
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 "
429 "in time");
431 torture_comment(tctx, "Server updated write time on close (correct)\n");
433 if (fnum1 != -1)
434 smbcli_close(cli->tree, fnum1);
435 smbcli_unlink(cli->tree, fname);
436 smbcli_deltree(cli->tree, BASEDIR);
438 return ret;
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";
448 NTSTATUS status;
449 int fnum1 = -1;
450 bool ret = true;
451 ssize_t written;
452 struct timeval start;
453 struct timeval end;
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;
458 char buf[2048];
459 bool first;
460 bool updated;
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;
479 finfo2 = finfo1;
480 finfo3 = finfo1;
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);
501 first = true;
502 updated = false;
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 "
510 "(10240)");
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)
518 updated = true;
519 break;
522 fflush(stdout);
523 smb_msleep(1 * msec);
524 first = false;
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");
536 fflush(stdout);
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 "
554 "(10240)");
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)));
567 fflush(stdout);
568 smb_msleep(1 * msec);
571 torture_comment(tctx, "Server did not update write time within 10 "
572 "seconds. Good!\n");
574 /* the close should trigger an write time update */
575 smbcli_close(cli->tree, fnum1);
576 fnum1 = -1;
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 "
585 "close (wrong!)");
586 torture_assert(tctx,
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 "
589 "in time");
591 torture_comment(tctx, "Server updated write time on close (correct)\n");
593 if (fnum1 != -1)
594 smbcli_close(cli->tree, fnum1);
595 smbcli_unlink(cli->tree, fname);
596 smbcli_deltree(cli->tree, BASEDIR);
598 return ret;
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";
608 NTSTATUS status;
609 int fnum1 = -1;
610 bool ret = true;
611 ssize_t written;
612 struct timeval start;
613 struct timeval end;
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;
618 char buf[2048];
619 bool first;
620 bool updated;
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;
639 finfo2 = finfo1;
640 finfo3 = finfo1;
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);
666 first = true;
667 updated = false;
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 "
675 "(0)");
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)
683 updated = true;
684 break;
687 fflush(stdout);
688 smb_msleep(1 * msec);
689 first = false;
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");
701 fflush(stdout);
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)));
730 fflush(stdout);
731 smb_msleep(1 * msec);
734 torture_comment(tctx, "Server did not update write time within 10 "
735 "seconds. Good!\n");
737 /* the close should trigger an write time update */
738 smbcli_close(cli->tree, fnum1);
739 fnum1 = -1;
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 "
748 "close (wrong!)");
749 torture_assert(tctx,
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 "
752 "in time");
754 if (fnum1 != -1)
755 smbcli_close(cli->tree, fnum1);
756 smbcli_unlink(cli->tree, fname);
757 smbcli_deltree(cli->tree, BASEDIR);
759 return ret;
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";
771 NTSTATUS status;
772 int fnum1 = -1;
773 int fnum2 = -1;
774 bool ret = true;
775 ssize_t written;
776 struct timeval start;
777 struct timeval end;
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);
789 if (fnum1 == -1) {
790 torture_comment(tctx, "Failed to open %s\n", fname);
791 return false;
794 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
795 finfo1.basic_info.in.file.fnum = fnum1;
796 finfo2 = finfo1;
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. */
820 #if 1
821 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
822 #else
823 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
824 #endif
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)));
839 return false;
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");
846 } else {
847 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
848 ret = false;
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;
855 finfo2 = finfo1;
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)));
861 return false;
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);
872 if (written != 10) {
873 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
874 (int)written, __location__);
875 return false;
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)));
888 return false;
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)));
900 ret = false;
901 break;
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"
908 "(wrong!)\n",
909 diff);
910 ret = false;
911 break;
913 fflush(stdout);
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");
921 fflush(stdout);
922 smb_msleep(2 * msec);
924 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
925 if (fnum2 == -1) {
926 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
927 return false;
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);
934 if (written != 10) {
935 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
936 (int)written, __location__);
937 return false;
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)));
944 return false;
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");
950 ret = false;
953 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
954 smbcli_close(cli->tree, fnum1);
955 fnum1 = -1;
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);
961 if (written != 10) {
962 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
963 (int)written, __location__);
964 return false;
967 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
968 finfo1.basic_info.in.file.fnum = fnum2;
969 finfo2 = finfo1;
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)));
974 return false;
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");
980 ret = false;
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)));
992 ret = false;
993 break;
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 "
1000 "(wrong!)\n",
1001 diff);
1002 ret = false;
1003 break;
1005 fflush(stdout);
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);
1016 fnum2 = -1;
1018 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1019 if (fnum1 == -1) {
1020 torture_comment(tctx, "Failed to open %s\n", fname);
1021 return false;
1024 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1025 finfo1.basic_info.in.file.fnum = fnum1;
1026 finfo2 = finfo1;
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)));
1032 return false;
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__);
1046 return false;
1049 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1050 finfo1.basic_info.in.file.fnum = fnum1;
1051 finfo2 = finfo1;
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)));
1056 return false;
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");
1062 ret = false;
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)));
1073 ret = false;
1074 break;
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);
1084 ret = false;
1085 break;
1088 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1089 "(correct)\n",
1090 diff);
1091 break;
1093 fflush(stdout);
1094 smb_msleep(1*msec);
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");
1099 ret = false;
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. */
1107 if (fnum1 != -1)
1108 smbcli_close(cli->tree, fnum1);
1109 smbcli_unlink(cli->tree, fname);
1110 smbcli_deltree(cli->tree, BASEDIR);
1112 return ret;
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
1123 * nasty....
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";
1131 NTSTATUS status;
1132 int fnum1 = -1;
1133 int fnum2;
1134 bool ret = true;
1135 ssize_t written;
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);
1146 if (fnum1 == -1) {
1147 ret = false;
1148 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1149 goto done;
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)) {
1158 ret = false;
1159 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1160 goto done;
1163 smb_msleep(1 * msec);
1165 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1167 if (written != 1) {
1168 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1169 ret = false;
1170 goto done;
1173 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1174 if (fnum2 == -1) {
1175 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1176 smbcli_errstr(cli2->tree));
1177 ret = false;
1178 goto done;
1181 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1183 if (written != 1) {
1184 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1185 (int)written);
1186 ret = false;
1187 goto done;
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",
1197 nt_errstr(status));
1198 ret = false;
1199 goto done;
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");
1205 ret = false;
1206 goto done;
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");
1212 ret = false;
1213 goto done;
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));
1222 ret = false;
1223 goto done;
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");
1229 ret = false;
1230 goto done;
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);
1239 cli2 = NULL;
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));
1249 ret = false;
1250 goto done;
1253 done:
1254 if (fnum1 != -1)
1255 smbcli_close(cli->tree, fnum1);
1256 smbcli_unlink(cli->tree, fname);
1257 smbcli_deltree(cli->tree, BASEDIR);
1259 return ret;
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); \
1269 bool err = false; \
1270 if (strict && (g cmp c)) { \
1271 err = true; \
1272 } else if ((g cmp c) && (gr cmp cr)) { \
1273 /* handle filesystem without high resolution timestamps */ \
1274 err = true; \
1276 if (err) { \
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); \
1280 ret = false; \
1281 goto done; \
1283 } while (0)
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; \
1294 if (g cmp c) { \
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)); \
1298 ret = false; \
1299 goto done; \
1301 } while (0)
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); \
1308 } while (0)
1310 #define GET_INFO_FILE(finfo) do { \
1311 NTSTATUS _status; \
1312 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1313 if (!NT_STATUS_IS_OK(_status)) { \
1314 ret = false; \
1315 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1316 nt_errstr(_status)); \
1317 goto done; \
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)); \
1322 } while (0)
1323 #define GET_INFO_FILE2(finfo) do { \
1324 NTSTATUS _status; \
1325 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1326 if (!NT_STATUS_IS_OK(_status)) { \
1327 ret = false; \
1328 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1329 nt_errstr(_status)); \
1330 goto done; \
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)); \
1335 } while (0)
1336 #define GET_INFO_PATH(pinfo) do { \
1337 NTSTATUS _status; \
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)); \
1342 ret = false; \
1343 goto done; \
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)); \
1348 } while (0)
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); \
1353 } while (0)
1355 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1356 NTSTATUS _status; \
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)); \
1369 ret = false; \
1370 goto done; \
1372 } while (0)
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 { \
1377 NTSTATUS _status; \
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)); \
1391 ret = false; \
1392 goto done; \
1394 } while (0)
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";
1403 int fnum1 = -1;
1404 bool ret = true;
1405 ssize_t written;
1406 struct timeval start;
1407 struct timeval end;
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);
1419 if (fnum1 == -1) {
1420 ret = false;
1421 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1422 goto done;
1425 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1426 finfo0.basic_info.in.file.fnum = fnum1;
1427 finfo1 = finfo0;
1428 finfo2 = finfo0;
1429 finfo3 = finfo0;
1430 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1431 pinfo0.basic_info.in.file.path = fname;
1432 pinfo1 = pinfo0;
1433 pinfo2 = pinfo0;
1434 pinfo3 = pinfo0;
1435 pinfo4 = pinfo0;
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)) {
1448 /* do a write */
1449 torture_comment(tctx, "Do a write on the file handle\n");
1450 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1451 if (written != 1) {
1452 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1453 ret = false;
1454 goto done;
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);
1465 ret = false;
1466 break;
1469 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1470 "(correct)\n",
1471 diff);
1472 break;
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)) {
1484 /* do a write */
1485 torture_comment(tctx, "Do a write on the file handle\n");
1486 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1487 if (written != 1) {
1488 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1489 ret = false;
1490 goto done;
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 "
1498 "(wrong!)\n",
1499 diff);
1500 ret = false;
1501 break;
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");
1512 /* sleep */
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);
1524 fnum1 = -1;
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");
1533 done:
1534 if (fnum1 != -1)
1535 smbcli_close(cli->tree, fnum1);
1536 smbcli_unlink(cli->tree, fname);
1537 smbcli_deltree(cli->tree, BASEDIR);
1539 return ret;
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";
1554 int fnum1 = -1;
1555 bool ret = true;
1556 ssize_t written;
1557 int i;
1558 struct timeval start;
1559 struct timeval end;
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);
1571 if (fnum1 == -1) {
1572 ret = false;
1573 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1574 goto done;
1577 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1578 finfo0.basic_info.in.file.fnum = fnum1;
1579 finfo1 = finfo0;
1580 finfo2 = finfo0;
1581 finfo3 = finfo0;
1582 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1583 pinfo0.basic_info.in.file.path = fname;
1584 pinfo1 = pinfo0;
1585 pinfo2 = pinfo0;
1586 pinfo3 = pinfo0;
1587 pinfo4 = pinfo0;
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)) {
1610 /* do a write */
1611 torture_comment(tctx, "Do a write on the file handle\n");
1612 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1613 if (written != 1) {
1614 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1615 ret = false;
1616 goto done;
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",
1626 diff, sec);
1627 ret = false;
1628 break;
1631 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1632 "(correct)\n",
1633 diff);
1634 break;
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);
1650 /* do a write */
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);
1653 if (written != 0) {
1654 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1655 ret = false;
1656 goto done;
1658 /* get the times after the write */
1659 GET_INFO_BOTH(finfo2,pinfo2);
1660 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1661 finfo1 = finfo2;
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)) {
1670 /* do a write */
1671 torture_comment(tctx, "Do a write on the file handle\n");
1672 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1673 if (written != 1) {
1674 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1675 ret = false;
1676 goto done;
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 "
1684 "(wrong!)\n",
1685 diff);
1686 ret = false;
1687 break;
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");
1698 /* sleep */
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);
1711 /* do a write */
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);
1714 if (written != 0) {
1715 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1716 ret = false;
1717 goto done;
1719 /* get the times after the write */
1720 GET_INFO_BOTH(finfo2,pinfo2);
1721 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1722 finfo1 = finfo2;
1725 /* sleep */
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);
1736 fnum1 = -1;
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");
1745 done:
1746 if (fnum1 != -1)
1747 smbcli_close(cli->tree, fnum1);
1748 smbcli_unlink(cli->tree, fname);
1749 smbcli_deltree(cli->tree, BASEDIR);
1751 return ret;
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";
1766 int fnum1 = -1;
1767 bool ret = true;
1768 ssize_t written;
1769 struct timeval start;
1770 struct timeval end;
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);
1782 if (fnum1 == -1) {
1783 ret = false;
1784 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1785 goto done;
1788 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1789 finfo0.basic_info.in.file.fnum = fnum1;
1790 finfo1 = finfo0;
1791 finfo2 = finfo0;
1792 finfo3 = finfo0;
1793 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1794 pinfo0.basic_info.in.file.path = fname;
1795 pinfo1 = pinfo0;
1796 pinfo2 = pinfo0;
1797 pinfo3 = pinfo0;
1798 pinfo4 = pinfo0;
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)) {
1821 /* do a write */
1822 torture_comment(tctx, "Do a write on the file handle\n");
1823 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1824 if (written != 1) {
1825 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1826 ret = false;
1827 goto done;
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);
1838 ret = false;
1839 break;
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);
1845 break;
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)) {
1857 /* do a write */
1858 torture_comment(tctx, "Do a write on the file handle\n");
1859 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1860 if (written != 1) {
1861 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1862 ret = false;
1863 goto done;
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 "
1871 "(wrong!)\n",
1872 diff);
1873 ret = false;
1874 break;
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");
1885 /* sleep */
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);
1897 fnum1 = -1;
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");
1906 done:
1907 if (fnum1 != -1)
1908 smbcli_close(cli->tree, fnum1);
1909 smbcli_unlink(cli->tree, fname);
1910 smbcli_deltree(cli->tree, BASEDIR);
1912 return ret;
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";
1929 int fnum1 = -1;
1930 bool ret = true;
1931 ssize_t written;
1932 int i;
1933 struct timeval start;
1934 struct timeval end;
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);
1946 if (fnum1 == -1) {
1947 ret = false;
1948 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1949 goto done;
1952 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1953 finfo0.basic_info.in.file.fnum = fnum1;
1954 finfo1 = finfo0;
1955 finfo2 = finfo0;
1956 finfo3 = finfo0;
1957 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1958 pinfo0.basic_info.in.file.path = fname;
1959 pinfo1 = pinfo0;
1960 pinfo2 = pinfo0;
1961 pinfo3 = pinfo0;
1962 pinfo4 = pinfo0;
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);
1983 /* do a write */
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);
1986 if (written != 0) {
1987 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1988 ret = false;
1989 goto done;
1991 /* get the times after the write */
1992 GET_INFO_BOTH(finfo2,pinfo2);
1993 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1994 finfo1 = finfo2;
1997 start = timeval_current();
1998 end = timeval_add(&start, 7 * sec, 0);
1999 while (!timeval_expired(&end)) {
2000 /* do a write */
2001 torture_comment(tctx, "Do a write on the file handle\n");
2002 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2003 if (written != 1) {
2004 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2005 ret = false;
2006 goto done;
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 "
2014 "(wrong!)\n",
2015 diff);
2016 ret = false;
2017 break;
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");
2028 /* sleep */
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);
2041 /* do a write */
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);
2044 if (written != 0) {
2045 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2046 ret = false;
2047 goto done;
2049 /* get the times after the write */
2050 GET_INFO_BOTH(finfo2,pinfo2);
2051 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2052 finfo1 = finfo2;
2055 /* sleep */
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)) {
2065 /* do a write */
2066 torture_comment(tctx, "Do a write on the file handle\n");
2067 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2068 if (written != 1) {
2069 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2070 ret = false;
2071 goto done;
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 "
2079 "(wrong!)\n",
2080 diff);
2081 ret = false;
2082 break;
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");
2093 /* sleep */
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);
2105 fnum1 = -1;
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");
2114 done:
2115 if (fnum1 != -1)
2116 smbcli_close(cli->tree, fnum1);
2117 smbcli_unlink(cli->tree, fname);
2118 smbcli_deltree(cli->tree, BASEDIR);
2120 return ret;
2124 * Show only the first write updates the timestamp, and a close
2125 * after writes updates to current (I think this is the same
2126 * as test 3b. JRA).
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";
2136 int fnum1 = -1;
2137 bool ret = true;
2138 ssize_t written;
2139 struct timeval start;
2140 struct timeval end;
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);
2152 if (fnum1 == -1) {
2153 ret = false;
2154 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2155 goto done;
2158 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2159 finfo0.basic_info.in.file.fnum = fnum1;
2160 finfo1 = finfo0;
2161 finfo2 = finfo0;
2162 finfo3 = finfo0;
2163 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2164 pinfo0.basic_info.in.file.path = fname;
2165 pinfo1 = pinfo0;
2166 pinfo2 = pinfo0;
2167 pinfo3 = pinfo0;
2168 pinfo4 = pinfo0;
2170 /* get the initial times */
2171 GET_INFO_BOTH(finfo0,pinfo0);
2173 /* sleep a bit */
2174 smb_msleep(5 * msec);
2176 /* do a write */
2177 torture_comment(tctx, "Do a write on the file handle\n");
2178 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2179 if (written != 1) {
2180 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2181 ret = false;
2182 goto done;
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);
2205 ret = false;
2206 break;
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);
2212 break;
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)) {
2224 /* do a write */
2225 torture_comment(tctx, "Do a write on the file handle\n");
2226 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2227 if (written != 1) {
2228 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2229 ret = false;
2230 goto done;
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 "
2238 "(wrong!)\n",
2239 diff);
2240 ret = false;
2241 break;
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");
2252 /* sleep */
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);
2264 fnum1 = -1;
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");
2273 done:
2274 if (fnum1 != -1)
2275 smbcli_close(cli->tree, fnum1);
2276 smbcli_unlink(cli->tree, fname);
2277 smbcli_deltree(cli->tree, BASEDIR);
2279 return ret;
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";
2293 int fnum1 = -1;
2294 bool ret = true;
2295 ssize_t written;
2296 struct timeval start;
2297 struct timeval end;
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);
2309 if (fnum1 == -1) {
2310 ret = false;
2311 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2312 goto done;
2315 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2316 finfo0.basic_info.in.file.fnum = fnum1;
2317 finfo1 = finfo0;
2318 finfo2 = finfo0;
2319 finfo3 = finfo0;
2320 finfo4 = finfo0;
2321 finfo5 = finfo0;
2322 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2323 pinfo0.basic_info.in.file.path = fname;
2324 pinfo1 = pinfo0;
2325 pinfo2 = pinfo0;
2326 pinfo3 = pinfo0;
2327 pinfo4 = pinfo0;
2328 pinfo5 = pinfo0;
2329 pinfo6 = pinfo0;
2331 /* get the initial times */
2332 GET_INFO_BOTH(finfo0,pinfo0);
2334 /* do a write */
2335 torture_comment(tctx, "Do a write on the file handle\n");
2336 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2337 if (written != 1) {
2338 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2339 ret = false;
2340 goto done;
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 "
2367 "(wrong!)\n",
2368 diff);
2369 ret = false;
2370 break;
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)) {
2385 /* do a write */
2386 torture_comment(tctx, "Do a write on the file handle\n");
2387 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2388 if (written != 1) {
2389 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2390 ret = false;
2391 goto done;
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 "
2399 "(wrong!)\n",
2400 diff);
2401 ret = false;
2402 break;
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");
2413 /* sleep */
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);
2424 fnum1 = -1;
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");
2433 done:
2434 if (fnum1 != -1)
2435 smbcli_close(cli->tree, fnum1);
2436 smbcli_unlink(cli->tree, fname);
2437 smbcli_deltree(cli->tree, BASEDIR);
2439 return ret;
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";
2453 int fnum1 = -1;
2454 bool ret = true;
2455 ssize_t written;
2456 struct timeval start;
2457 struct timeval end;
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);
2469 if (fnum1 == -1) {
2470 ret = false;
2471 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2472 goto done;
2475 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2476 finfo0.basic_info.in.file.fnum = fnum1;
2477 finfo1 = finfo0;
2478 finfo2 = finfo0;
2479 finfo3 = finfo0;
2480 finfo4 = finfo0;
2481 finfo5 = finfo0;
2482 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2483 pinfo0.basic_info.in.file.path = fname;
2484 pinfo1 = pinfo0;
2485 pinfo2 = pinfo0;
2486 pinfo3 = pinfo0;
2487 pinfo4 = pinfo0;
2488 pinfo5 = pinfo0;
2489 pinfo6 = pinfo0;
2491 /* get the initial times */
2492 GET_INFO_BOTH(finfo0,pinfo0);
2494 /* do a write */
2495 torture_comment(tctx, "Do a write on the file handle\n");
2496 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2497 if (written != 1) {
2498 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2499 ret = false;
2500 goto done;
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 "
2527 "(wrong!)\n",
2528 diff);
2529 ret = false;
2530 break;
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)) {
2545 /* do a write */
2546 torture_comment(tctx, "Do a truncate write on the file handle\n");
2547 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2548 if (written != 0) {
2549 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2550 ret = false;
2551 goto done;
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 "
2559 "(wrong!)\n",
2560 diff);
2561 ret = false;
2562 break;
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");
2573 /* sleep */
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);
2584 fnum1 = -1;
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");
2593 done:
2594 if (fnum1 != -1)
2595 smbcli_close(cli->tree, fnum1);
2596 smbcli_unlink(cli->tree, fname);
2597 smbcli_deltree(cli->tree, BASEDIR);
2599 return ret;
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";
2617 int fnum1 = -1;
2618 int fnum2 = -1;
2619 bool ret = true;
2620 ssize_t written;
2621 struct timeval start;
2622 struct timeval end;
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;
2627 bool first = true;
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);
2632 again:
2633 torture_comment(tctx, "Open the file handle\n");
2634 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2635 if (fnum1 == -1) {
2636 ret = false;
2637 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2638 goto done;
2641 if (fnum2 == -1) {
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);
2644 if (fnum2 == -1) {
2645 ret = false;
2646 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2647 goto done;
2651 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2652 finfo0.basic_info.in.file.fnum = fnum1;
2653 finfo1 = finfo0;
2654 finfo2 = finfo0;
2655 finfo3 = finfo0;
2656 finfo4 = finfo0;
2657 finfo5 = finfo0;
2658 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2659 pinfo0.basic_info.in.file.path = fname;
2660 pinfo1 = pinfo0;
2661 pinfo2 = pinfo0;
2662 pinfo3 = pinfo0;
2663 pinfo4 = pinfo0;
2664 pinfo5 = pinfo0;
2665 pinfo6 = pinfo0;
2666 pinfo7 = pinfo0;
2668 /* get the initial times */
2669 GET_INFO_BOTH(finfo0,pinfo0);
2671 /* do a write */
2672 torture_comment(tctx, "Do a write on the file handle\n");
2673 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2674 if (written != 1) {
2675 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2676 ret = false;
2677 goto done;
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 "
2704 "(wrong!)\n",
2705 diff);
2706 ret = false;
2707 break;
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)) {
2722 /* do a write */
2723 torture_comment(tctx, "Do a write on the file handle\n");
2724 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2725 if (written != 1) {
2726 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2727 ret = false;
2728 goto done;
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 "
2736 "(wrong!)\n",
2737 diff);
2738 ret = false;
2739 break;
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");
2750 /* sleep */
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);
2762 fnum1 = -1;
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)) {
2784 /* do a write */
2785 torture_comment(tctx, "Do a write on the second file handle\n");
2786 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
2787 if (written != 1) {
2788 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2789 ret = false;
2790 goto done;
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 "
2799 "(wrong!)\n",
2800 diff);
2801 ret = false;
2802 break;
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)) {
2811 /* do a write */
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);
2814 if (written != 0) {
2815 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2816 ret = false;
2817 goto done;
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 "
2826 "(wrong!)\n",
2827 diff);
2828 ret = false;
2829 break;
2831 smb_msleep(1 * msec);
2835 /* keep the 2nd handle open and rerun tests */
2836 if (first) {
2837 first = false;
2838 goto again;
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);
2847 fnum2 = -1;
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");
2856 done:
2857 if (fnum1 != -1)
2858 smbcli_close(cli->tree, fnum1);
2859 if (fnum2 != -1)
2860 smbcli_close(cli2->tree, fnum2);
2861 smbcli_unlink(cli->tree, fname);
2862 smbcli_deltree(cli->tree, BASEDIR);
2864 return ret;
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";
2872 NTSTATUS status;
2873 int fnum1 = -1;
2874 bool ret = true;
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);
2891 if (fnum1 == -1) {
2892 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
2893 return false;
2896 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2897 finfo1.basic_info.in.file.fnum = fnum1;
2898 finfo2 = finfo1;
2899 finfo3 = finfo1;
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");
2918 ret = false;
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");
2928 ret = false;
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");
2953 ret = false;
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");
2962 ret = false;
2965 done:
2967 smbcli_close(cli->tree, fnum1);
2969 smbcli_unlink(cli->tree, fname);
2970 smbcli_deltree(cli->tree, BASEDIR);
2971 return ret;
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";
2983 NTSTATUS status;
2984 int fnum1 = -1;
2985 int fnum2 = -1;
2986 bool ret = true;
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");
3018 ret = false;
3019 goto done;
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));
3031 /* sleep */
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);
3036 if (fnum2 == -1) {
3037 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
3038 ret = false;
3039 goto done;
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));
3058 done:
3060 if (fnum1 != -1)
3061 smbcli_close(cli->tree, fnum1);
3062 smbcli_unlink(cli->tree, fname);
3063 smbcli_deltree(cli->tree, BASEDIR);
3065 return ret;
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);
3093 return suite;