s4:torture:basic: add update into past as error condition in delayed_write_update1
[Samba.git] / source4 / torture / basic / delaywrite.c
blob759f68ec774f1a68ec5cafd7aeec9aaab2c210cb
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];
133 torture_comment(tctx, "\nRunning test_delayed_write_update1\n");
135 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
137 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
138 torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
139 "Failed to open %s", fname));
141 memset(buf, 'x', 2048);
142 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
144 /* 3 second delay to ensure we get past any 2 second time
145 granularity (older systems may have that) */
146 smb_msleep(3 * msec);
148 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
149 finfo1.all_info.in.file.fnum = fnum1;
150 finfo2 = finfo1;
151 finfo3 = finfo1;
152 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
153 pinfo4.all_info.in.file.path = fname;
155 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
157 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
159 torture_comment(tctx, "Initial write time %s\n",
160 nt_time_string(tctx, finfo1.all_info.out.write_time));
162 /* 3 second delay to ensure we get past any 2 second time
163 granularity (older systems may have that) */
164 smb_msleep(3 * msec);
166 /* Do a zero length SMBwrite call to truncate. */
167 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
168 torture_assert_int_equal(tctx, written, 0,
169 "unexpected number of bytes written");
171 start = timeval_current();
172 end = timeval_add(&start, (120 * sec), 0);
173 while (!timeval_expired(&end)) {
174 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
176 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
178 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 1024,
179 "file not truncated to expected size "
180 "(1024)");
182 torture_comment(tctx, "write time %s\n",
183 nt_time_string(tctx, finfo2.all_info.out.write_time));
184 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
185 double diff = timeval_elapsed(&start);
186 if (diff > (0.25 * (used_delay / (double)1000000))) {
187 torture_result(tctx, TORTURE_FAIL, "After SMBwrite truncate "
188 "server updated write_time after %.2f seconds"
189 "(write time update dealy == %.2f)(wrong!)\n",
190 diff, used_delay / (double)1000000);
191 ret = false;
192 break;
195 torture_comment(tctx, "After SMBwrite truncate "
196 "server updated write_time after %.2f seconds"
197 "(1 sec == %.2f)(correct)\n",
198 diff, used_delay / (double)1000000);
199 break;
201 fflush(stdout);
202 smb_msleep(1 * msec);
205 torture_assert_u64_not_equal(tctx,
206 finfo2.all_info.out.write_time,
207 finfo1.all_info.out.write_time,
208 "Server did not update write time");
210 fflush(stdout);
211 smb_msleep(2 * msec);
213 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
214 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
215 torture_assert_int_equal(tctx, written, 1,
216 "unexpected number of bytes written");
218 start = timeval_current();
219 end = timeval_add(&start, (10*sec), 0);
220 while (!timeval_expired(&end)) {
221 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
223 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
225 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 1024,
226 "file not truncated to expected size "
227 "(1024)");
229 torture_comment(tctx, "write time %s\n",
230 nt_time_string(tctx, finfo3.all_info.out.write_time));
231 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
232 double diff = timeval_elapsed(&start);
234 torture_comment(tctx, "server updated write_time after %.2f seconds"
235 "(wrong)\n",
236 diff);
237 break;
239 fflush(stdout);
240 smb_msleep(1 * msec);
243 torture_assert_u64_equal(tctx,
244 finfo3.all_info.out.write_time,
245 finfo2.all_info.out.write_time,
246 "Server updated write time (wrong!)");
248 fflush(stdout);
249 smb_msleep(2 * msec);
251 /* the close should trigger an write time update */
252 smbcli_close(cli->tree, fnum1);
253 fnum1 = -1;
255 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
256 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
258 torture_assert_u64_not_equal(tctx,
259 pinfo4.all_info.out.write_time,
260 finfo3.all_info.out.write_time,
261 "Server did not update write time on "
262 "close (wrong!)");
263 torture_assert(tctx,
264 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
265 "Server updated write time on close, but to an earlier point "
266 "in time");
268 torture_comment(tctx, "Server updated write time on close (correct)\n");
270 if (fnum1 != -1)
271 smbcli_close(cli->tree, fnum1);
272 smbcli_unlink(cli->tree, fname);
273 smbcli_deltree(cli->tree, BASEDIR);
275 return ret;
278 /* Updating with a SMBwrite of zero length
279 * changes the write time immediately - even on expand. */
281 static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
283 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
284 const char *fname = BASEDIR "\\torture_file1a.txt";
285 NTSTATUS status;
286 int fnum1 = -1;
287 bool ret = true;
288 ssize_t written;
289 struct timeval start;
290 struct timeval end;
291 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
292 int normal_delay = 2000000;
293 double sec = ((double)used_delay) / ((double)normal_delay);
294 int msec = 1000 * sec;
295 char buf[2048];
297 torture_comment(tctx, "\nRunning test_delayed_write_update1a\n");
299 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
301 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
302 if (fnum1 == -1) {
303 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
304 return false;
307 memset(buf, 'x', 2048);
308 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
310 /* 3 second delay to ensure we get past any 2 second time
311 granularity (older systems may have that) */
312 smb_msleep(3 * msec);
314 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
315 finfo1.all_info.in.file.fnum = fnum1;
316 finfo2 = finfo1;
317 finfo3 = finfo1;
318 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
319 pinfo4.all_info.in.file.path = fname;
321 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
323 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
325 torture_comment(tctx, "Initial write time %s\n",
326 nt_time_string(tctx, finfo1.all_info.out.write_time));
328 /* Do a zero length SMBwrite call to truncate. */
329 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
331 if (written != 0) {
332 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)",
333 (int)written, __location__);
334 return false;
337 start = timeval_current();
338 end = timeval_add(&start, (120*sec), 0);
339 while (!timeval_expired(&end)) {
340 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
342 if (!NT_STATUS_IS_OK(status)) {
343 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
344 nt_errstr(status));
345 ret = false;
346 break;
349 if (finfo2.all_info.out.size != 10240) {
350 torture_result(tctx, TORTURE_FAIL,
351 "file not truncated, size = %u (should be 10240)",
352 (unsigned int)finfo2.all_info.out.size);
353 ret = false;
354 break;
357 torture_comment(tctx, "write time %s\n",
358 nt_time_string(tctx, finfo2.all_info.out.write_time));
359 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
360 double diff = timeval_elapsed(&start);
361 if (diff > (0.25 * (used_delay / (double)1000000))) {
362 torture_result(tctx, TORTURE_FAIL, "After SMBwrite truncate "
363 "server updated write_time after %.2f seconds"
364 "(write time update delay == %.2f)(wrong!)\n",
365 diff, used_delay / (double)1000000);
366 ret = false;
367 break;
370 torture_comment(tctx, "After SMBwrite truncate "
371 "server updated write_time after %.2f seconds"
372 "(write time update delay == %.2f)(correct)\n",
373 diff, used_delay / (double)1000000);
374 break;
376 fflush(stdout);
377 smb_msleep(1 * msec);
380 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
381 torture_result(tctx, TORTURE_FAIL,
382 "Server did not update write time (wrong!)");
383 ret = false;
386 fflush(stdout);
387 smb_msleep(2 * msec);
389 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
390 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
392 torture_assert_int_equal(tctx, written, 1,
393 "unexpected number of bytes written");
395 start = timeval_current();
396 end = timeval_add(&start, (10*sec), 0);
397 while (!timeval_expired(&end)) {
398 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
400 if (!NT_STATUS_IS_OK(status)) {
401 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s\n",
402 nt_errstr(status));
403 ret = false;
404 break;
407 if (finfo3.all_info.out.size != 10240) {
408 torture_result(tctx, TORTURE_FAIL,
409 "file not truncated, size = %u (should be 10240)",
410 (unsigned int)finfo3.all_info.out.size);
411 ret = false;
412 break;
415 torture_comment(tctx, "write time %s\n",
416 nt_time_string(tctx, finfo3.all_info.out.write_time));
417 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
418 double diff = timeval_elapsed(&start);
420 torture_result(tctx, TORTURE_FAIL, "server updated write_time after %.2f seconds"
421 "(write time update delay == %.2f)(correct)\n",
422 diff, used_delay / (double)1000000);
423 break;
425 fflush(stdout);
426 smb_msleep(1 * msec);
429 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
430 torture_result(tctx, TORTURE_FAIL,
431 "Server updated write time (wrong!)");
432 ret = false;
435 /* the close should trigger an write time update */
436 smbcli_close(cli->tree, fnum1);
437 fnum1 = -1;
439 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
440 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
442 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
443 torture_result(tctx, TORTURE_FAIL,
444 "Server did not update write time on close (wrong!)");
445 ret = false;
446 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
447 torture_comment(tctx, "Server updated write time on close (correct)\n");
450 if (fnum1 != -1)
451 smbcli_close(cli->tree, fnum1);
452 smbcli_unlink(cli->tree, fname);
453 smbcli_deltree(cli->tree, BASEDIR);
455 return ret;
458 /* Updating with a SET_FILE_END_OF_FILE_INFO
459 * changes the write time immediately - even on expand. */
461 static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
463 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
464 const char *fname = BASEDIR "\\torture_file1b.txt";
465 NTSTATUS status;
466 int fnum1 = -1;
467 bool ret = true;
468 ssize_t written;
469 struct timeval start;
470 struct timeval end;
471 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
472 int normal_delay = 2000000;
473 double sec = ((double)used_delay) / ((double)normal_delay);
474 int msec = 1000 * sec;
475 char buf[2048];
477 torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
479 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
481 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
482 if (fnum1 == -1) {
483 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
484 return false;
487 memset(buf, 'x', 2048);
488 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
490 /* 3 second delay to ensure we get past any 2 second time
491 granularity (older systems may have that) */
492 smb_msleep(3 * msec);
494 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
495 finfo1.all_info.in.file.fnum = fnum1;
496 finfo2 = finfo1;
497 finfo3 = finfo1;
498 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
499 pinfo4.all_info.in.file.path = fname;
501 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
503 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
505 torture_comment(tctx, "Initial write time %s\n",
506 nt_time_string(tctx, finfo1.all_info.out.write_time));
508 /* Do a SET_END_OF_FILE_INFO call to truncate. */
509 status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
511 torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
513 start = timeval_current();
514 end = timeval_add(&start, (120*sec), 0);
515 while (!timeval_expired(&end)) {
516 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
518 if (!NT_STATUS_IS_OK(status)) {
519 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
520 ret = false;
521 break;
524 if (finfo2.all_info.out.size != 10240) {
525 torture_result(tctx, TORTURE_FAIL,
526 "file not truncated (size = %u, should be 10240)",
527 (unsigned int)finfo2.all_info.out.size );
528 ret = false;
529 break;
532 torture_comment(tctx, "write time %s\n",
533 nt_time_string(tctx, finfo2.all_info.out.write_time));
534 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
535 double diff = timeval_elapsed(&start);
536 if (diff > (0.25 * (used_delay / (double)1000000))) {
537 torture_result(tctx, TORTURE_FAIL,
538 "After SET_END_OF_FILE truncate "
539 "server updated write_time after %.2f seconds"
540 "(write time update delay == %.2f)(wrong!)",
541 diff, used_delay / (double)1000000);
542 ret = false;
543 break;
546 torture_comment(tctx, "After SET_END_OF_FILE truncate "
547 "server updated write_time after %.2f seconds"
548 "(write time update delay == %.2f)(correct)\n",
549 diff, used_delay / (double)1000000);
550 break;
552 fflush(stdout);
553 smb_msleep(1 * msec);
556 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
557 torture_result(tctx, TORTURE_FAIL,
558 "Server did not update write time (wrong!)");
559 ret = false;
562 fflush(stdout);
563 smb_msleep(2 * msec);
565 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
566 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
568 torture_assert_int_equal(tctx, written, 1,
569 "unexpected number of bytes written");
571 start = timeval_current();
572 end = timeval_add(&start, (10*sec), 0);
573 while (!timeval_expired(&end)) {
574 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
576 if (!NT_STATUS_IS_OK(status)) {
577 torture_result(tctx, TORTURE_FAIL,
578 "fileinfo failed: %s", nt_errstr(status));
579 ret = false;
580 break;
583 if (finfo3.all_info.out.size != 10240) {
584 DEBUG(0, ("file not truncated (size = %u, should be 10240)\n",
585 (unsigned int)finfo3.all_info.out.size ));
586 ret = false;
587 break;
590 torture_comment(tctx, "write time %s\n",
591 nt_time_string(tctx, finfo3.all_info.out.write_time));
592 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
593 double diff = timeval_elapsed(&start);
595 torture_comment(tctx, "server updated write_time after %.2f seconds"
596 "(write time update delay == %.2f)(correct)\n",
597 diff, used_delay / (double)1000000);
598 break;
600 fflush(stdout);
601 smb_msleep(1 * msec);
604 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
605 torture_result(tctx, TORTURE_FAIL, "Server updated write time (wrong!)\n");
606 ret = false;
609 /* the close should trigger an write time update */
610 smbcli_close(cli->tree, fnum1);
611 fnum1 = -1;
613 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
614 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
616 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
617 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
618 ret = false;
619 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
620 torture_comment(tctx, "Server updated write time on close (correct)\n");
623 if (fnum1 != -1)
624 smbcli_close(cli->tree, fnum1);
625 smbcli_unlink(cli->tree, fname);
626 smbcli_deltree(cli->tree, BASEDIR);
628 return ret;
631 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
633 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
635 union smb_setfileinfo parms;
636 union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
637 const char *fname = BASEDIR "\\torture_file1c.txt";
638 NTSTATUS status;
639 int fnum1 = -1;
640 bool ret = true;
641 ssize_t written;
642 struct timeval start;
643 struct timeval end;
644 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
645 int normal_delay = 2000000;
646 double sec = ((double)used_delay) / ((double)normal_delay);
647 int msec = 1000 * sec;
648 char buf[2048];
650 torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
652 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
654 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
655 if (fnum1 == -1) {
656 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
657 return false;
660 memset(buf, 'x', 2048);
661 written = smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
663 /* 3 second delay to ensure we get past any 2 second time
664 granularity (older systems may have that) */
665 smb_msleep(3 * msec);
667 finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
668 finfo1.all_info.in.file.fnum = fnum1;
669 finfo2 = finfo1;
670 finfo3 = finfo1;
671 pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
672 pinfo4.all_info.in.file.path = fname;
674 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
676 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
678 torture_comment(tctx, "Initial write time %s\n",
679 nt_time_string(tctx, finfo1.all_info.out.write_time));
681 /* Do a SET_ALLOCATION_SIZE call to truncate. */
682 parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
683 parms.allocation_info.in.file.fnum = fnum1;
684 parms.allocation_info.in.alloc_size = 0;
686 status = smb_raw_setfileinfo(cli->tree, &parms);
688 torture_assert_ntstatus_ok(tctx, status,
689 "RAW_SFILEINFO_ALLOCATION_INFO failed");
691 start = timeval_current();
692 end = timeval_add(&start, (120*sec), 0);
693 while (!timeval_expired(&end)) {
694 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
696 if (!NT_STATUS_IS_OK(status)) {
697 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
698 nt_errstr(status));
699 ret = false;
700 break;
703 if (finfo2.all_info.out.size != 0) {
704 torture_result(tctx, TORTURE_FAIL,
705 "file not truncated (size = %u, should be 10240)",
706 (unsigned int)finfo2.all_info.out.size);
707 ret = false;
708 break;
711 torture_comment(tctx, "write time %s\n",
712 nt_time_string(tctx, finfo2.all_info.out.write_time));
713 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
714 double diff = timeval_elapsed(&start);
715 if (diff > (0.25 * (used_delay / (double)1000000))) {
716 torture_result(tctx, TORTURE_FAIL, "After SET_ALLOCATION_INFO truncate "
717 "server updated write_time after %.2f seconds"
718 "(write time update delay == %.2f)(wrong!)\n",
719 diff, used_delay / (double)1000000);
720 ret = false;
721 break;
724 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
725 "server updated write_time after %.2f seconds"
726 "(write time update delay == %.2f)(correct)\n",
727 diff, used_delay / (double)1000000);
728 break;
730 fflush(stdout);
731 smb_msleep(1 * msec);
734 if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
735 torture_result(tctx, TORTURE_FAIL,
736 "Server did not update write time (wrong!)");
737 ret = false;
740 fflush(stdout);
741 smb_msleep(2 * msec);
743 /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
744 written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
745 torture_assert_int_equal(tctx, written, 1,
746 "Unexpected number of bytes written");
748 start = timeval_current();
749 end = timeval_add(&start, (10*sec), 0);
750 while (!timeval_expired(&end)) {
751 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
753 if (!NT_STATUS_IS_OK(status)) {
754 torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s",
755 nt_errstr(status));
756 ret = false;
757 break;
760 if (finfo3.all_info.out.size != 1) {
761 torture_result(tctx, TORTURE_FAIL, "file not expanded");
762 ret = false;
763 break;
766 torture_comment(tctx, "write time %s\n",
767 nt_time_string(tctx, finfo3.all_info.out.write_time));
768 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
769 double diff = timeval_elapsed(&start);
771 torture_comment(tctx, "server updated write_time after %.2f seconds"
772 "(write time update delay == %.2f)(wrong)\n",
773 diff, used_delay / (double)1000000);
774 break;
776 fflush(stdout);
777 smb_msleep(1 * msec);
780 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
781 torture_result(tctx, TORTURE_FAIL,
782 "Server updated write time (wrong!)");
783 ret = false;
786 /* the close should trigger an write time update */
787 smbcli_close(cli->tree, fnum1);
788 fnum1 = -1;
790 status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
791 torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
793 if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
794 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
795 ret = false;
796 } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
797 torture_comment(tctx, "Server updated write time on close (correct)\n");
800 if (fnum1 != -1)
801 smbcli_close(cli->tree, fnum1);
802 smbcli_unlink(cli->tree, fname);
803 smbcli_deltree(cli->tree, BASEDIR);
805 return ret;
809 * Do as above, but using 2 connections.
812 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli,
813 struct smbcli_state *cli2)
815 union smb_fileinfo finfo1, finfo2;
816 const char *fname = BASEDIR "\\torture_file.txt";
817 NTSTATUS status;
818 int fnum1 = -1;
819 int fnum2 = -1;
820 bool ret = true;
821 ssize_t written;
822 struct timeval start;
823 struct timeval end;
824 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
825 int normal_delay = 2000000;
826 double sec = ((double)used_delay) / ((double)normal_delay);
827 int msec = 1000 * sec;
828 union smb_flush flsh;
830 torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
832 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
834 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
835 if (fnum1 == -1) {
836 torture_comment(tctx, "Failed to open %s\n", fname);
837 return false;
840 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
841 finfo1.basic_info.in.file.fnum = fnum1;
842 finfo2 = finfo1;
844 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
846 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
848 torture_comment(tctx, "Initial write time %s\n",
849 nt_time_string(tctx, finfo1.basic_info.out.write_time));
851 /* 3 second delay to ensure we get past any 2 second time
852 granularity (older systems may have that) */
853 smb_msleep(3 * msec);
856 /* Try using setfileinfo instead of write to update write time. */
857 union smb_setfileinfo sfinfo;
858 time_t t_set = time(NULL);
859 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
860 sfinfo.basic_info.in.file.fnum = fnum1;
861 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
862 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
864 /* I tried this with both + and - ve to see if it makes a different.
865 It doesn't - once the filetime is set via setfileinfo it stays that way. */
866 #if 1
867 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
868 #else
869 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
870 #endif
871 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
872 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
874 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
876 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
879 finfo2.basic_info.in.file.path = fname;
881 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
883 if (!NT_STATUS_IS_OK(status)) {
884 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
885 return false;
887 torture_comment(tctx, "write time %s\n",
888 nt_time_string(tctx, finfo2.basic_info.out.write_time));
890 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
891 torture_comment(tctx, "Server updated write_time (correct)\n");
892 } else {
893 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
894 ret = false;
897 /* Now try a write to see if the write time gets reset. */
899 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
900 finfo1.basic_info.in.file.fnum = fnum1;
901 finfo2 = finfo1;
903 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
905 if (!NT_STATUS_IS_OK(status)) {
906 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
907 return false;
910 torture_comment(tctx, "Modified write time %s\n",
911 nt_time_string(tctx, finfo1.basic_info.out.write_time));
914 torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
916 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
918 if (written != 10) {
919 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
920 (int)written, __location__);
921 return false;
924 /* Just to prove to tridge that the an smbflush has no effect on
925 the write time :-). The setfileinfo IS STICKY. JRA. */
927 torture_comment(tctx, "Doing flush after write\n");
929 flsh.flush.level = RAW_FLUSH_FLUSH;
930 flsh.flush.in.file.fnum = fnum1;
931 status = smb_raw_flush(cli->tree, &flsh);
932 if (!NT_STATUS_IS_OK(status)) {
933 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
934 return false;
937 /* Once the time was set using setfileinfo then it stays set - writes
938 don't have any effect. But make sure. */
939 start = timeval_current();
940 end = timeval_add(&start, (15*sec), 0);
941 while (!timeval_expired(&end)) {
942 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
944 if (!NT_STATUS_IS_OK(status)) {
945 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
946 ret = false;
947 break;
949 torture_comment(tctx, "write time %s\n",
950 nt_time_string(tctx, finfo2.basic_info.out.write_time));
951 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
952 double diff = timeval_elapsed(&start);
953 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
954 "(wrong!)\n",
955 diff);
956 ret = false;
957 break;
959 fflush(stdout);
960 smb_msleep(1 * msec);
963 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
964 torture_comment(tctx, "Server did not update write time (correct)\n");
967 fflush(stdout);
968 smb_msleep(2 * msec);
970 fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
971 if (fnum2 == -1) {
972 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
973 return false;
976 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");
978 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
980 if (written != 10) {
981 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
982 (int)written, __location__);
983 return false;
986 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
988 if (!NT_STATUS_IS_OK(status)) {
989 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
990 return false;
992 torture_comment(tctx, "write time %s\n",
993 nt_time_string(tctx, finfo2.basic_info.out.write_time));
994 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
995 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
996 ret = false;
999 torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
1000 smbcli_close(cli->tree, fnum1);
1001 fnum1 = -1;
1003 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");
1005 written = smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
1007 if (written != 10) {
1008 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1009 (int)written, __location__);
1010 return false;
1013 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1014 finfo1.basic_info.in.file.fnum = fnum2;
1015 finfo2 = finfo1;
1016 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1018 if (!NT_STATUS_IS_OK(status)) {
1019 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1020 return false;
1022 torture_comment(tctx, "write time %s\n",
1023 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1024 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1025 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1026 ret = false;
1029 /* Once the time was set using setfileinfo then it stays set - writes
1030 don't have any effect. But make sure. */
1031 start = timeval_current();
1032 end = timeval_add(&start, (15*sec), 0);
1033 while (!timeval_expired(&end)) {
1034 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1036 if (!NT_STATUS_IS_OK(status)) {
1037 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1038 ret = false;
1039 break;
1041 torture_comment(tctx, "write time %s\n",
1042 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1043 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1044 double diff = timeval_elapsed(&start);
1045 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1046 "(wrong!)\n",
1047 diff);
1048 ret = false;
1049 break;
1051 fflush(stdout);
1052 smb_msleep(1 * msec);
1055 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1056 torture_comment(tctx, "Server did not update write time (correct)\n");
1059 torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1061 smbcli_close(cli->tree, fnum2);
1062 fnum2 = -1;
1064 fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1065 if (fnum1 == -1) {
1066 torture_comment(tctx, "Failed to open %s\n", fname);
1067 return false;
1070 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1071 finfo1.basic_info.in.file.fnum = fnum1;
1072 finfo2 = finfo1;
1074 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1076 if (!NT_STATUS_IS_OK(status)) {
1077 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1078 return false;
1081 torture_comment(tctx, "Second open initial write time %s\n",
1082 nt_time_string(tctx, finfo1.basic_info.out.write_time));
1084 smb_msleep(10 * msec);
1085 torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1087 written = smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1089 if (written != 10) {
1090 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1091 (int)written, __location__);
1092 return false;
1095 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1096 finfo1.basic_info.in.file.fnum = fnum1;
1097 finfo2 = finfo1;
1098 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1100 if (!NT_STATUS_IS_OK(status)) {
1101 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1102 return false;
1104 torture_comment(tctx, "write time %s\n",
1105 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1106 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1107 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1108 ret = false;
1111 /* Now the write time should be updated again */
1112 start = timeval_current();
1113 end = timeval_add(&start, (15*sec), 0);
1114 while (!timeval_expired(&end)) {
1115 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1117 if (!NT_STATUS_IS_OK(status)) {
1118 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1119 ret = false;
1120 break;
1122 torture_comment(tctx, "write time %s\n",
1123 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1124 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1125 double diff = timeval_elapsed(&start);
1126 if (diff < (used_delay / (double)1000000)) {
1127 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1128 "(expected > %.2f) (wrong!)\n",
1129 diff, used_delay / (double)1000000);
1130 ret = false;
1131 break;
1134 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1135 "(correct)\n",
1136 diff);
1137 break;
1139 fflush(stdout);
1140 smb_msleep(1*msec);
1143 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1144 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
1145 ret = false;
1149 /* One more test to do. We should read the filetime via findfirst on the
1150 second connection to ensure it's the same. This is very easy for a Windows
1151 server but a bastard to get right on a POSIX server. JRA. */
1153 if (fnum1 != -1)
1154 smbcli_close(cli->tree, fnum1);
1155 smbcli_unlink(cli->tree, fname);
1156 smbcli_deltree(cli->tree, BASEDIR);
1158 return ret;
1162 /* Windows does obviously not update the stat info during a write call. I
1163 * *think* this is the problem causing a spurious Excel 2003 on XP error
1164 * message when saving a file. Excel does a setfileinfo, writes, and then does
1165 * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1166 * that the file might have been changed in between. What i've been able to
1167 * trace down is that this happens if the getpathinfo after the write shows a
1168 * different last write time than the setfileinfo showed. This is really
1169 * nasty....
1172 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli,
1173 struct smbcli_state *cli2)
1175 union smb_fileinfo finfo1, finfo2;
1176 const char *fname = BASEDIR "\\torture_file.txt";
1177 NTSTATUS status;
1178 int fnum1 = -1;
1179 int fnum2;
1180 bool ret = true;
1181 ssize_t written;
1182 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1183 int normal_delay = 2000000;
1184 double sec = ((double)used_delay) / ((double)normal_delay);
1185 int msec = 1000 * sec;
1187 torture_comment(tctx, "\nRunning test_finfo_after_write\n");
1189 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1191 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1192 if (fnum1 == -1) {
1193 ret = false;
1194 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1195 goto done;
1198 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1199 finfo1.basic_info.in.file.fnum = fnum1;
1201 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1203 if (!NT_STATUS_IS_OK(status)) {
1204 ret = false;
1205 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1206 goto done;
1209 smb_msleep(1 * msec);
1211 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1213 if (written != 1) {
1214 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1215 ret = false;
1216 goto done;
1219 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1220 if (fnum2 == -1) {
1221 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s",
1222 smbcli_errstr(cli2->tree));
1223 ret = false;
1224 goto done;
1227 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1229 if (written != 1) {
1230 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1",
1231 (int)written);
1232 ret = false;
1233 goto done;
1236 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1237 finfo2.basic_info.in.file.path = fname;
1239 status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1241 if (!NT_STATUS_IS_OK(status)) {
1242 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s",
1243 nt_errstr(status));
1244 ret = false;
1245 goto done;
1248 if (finfo1.basic_info.out.create_time !=
1249 finfo2.basic_info.out.create_time) {
1250 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1251 ret = false;
1252 goto done;
1255 if (finfo1.basic_info.out.access_time !=
1256 finfo2.basic_info.out.access_time) {
1257 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1258 ret = false;
1259 goto done;
1262 if (finfo1.basic_info.out.write_time !=
1263 finfo2.basic_info.out.write_time) {
1264 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1265 "write time conn 1 = %s, conn 2 = %s",
1266 nt_time_string(tctx, finfo1.basic_info.out.write_time),
1267 nt_time_string(tctx, finfo2.basic_info.out.write_time));
1268 ret = false;
1269 goto done;
1272 if (finfo1.basic_info.out.change_time !=
1273 finfo2.basic_info.out.change_time) {
1274 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1275 ret = false;
1276 goto done;
1279 /* One of the two following calls updates the qpathinfo. */
1281 /* If you had skipped the smbcli_write on fnum2, it would
1282 * *not* have updated the stat on disk */
1284 smbcli_close(cli2->tree, fnum2);
1285 cli2 = NULL;
1287 /* This call is only for the people looking at ethereal :-) */
1288 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1289 finfo2.basic_info.in.file.path = fname;
1291 status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1293 if (!NT_STATUS_IS_OK(status)) {
1294 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1295 ret = false;
1296 goto done;
1299 done:
1300 if (fnum1 != -1)
1301 smbcli_close(cli->tree, fnum1);
1302 smbcli_unlink(cli->tree, fname);
1303 smbcli_deltree(cli->tree, BASEDIR);
1305 return ret;
1308 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1309 uint64_t r = 10*1000*1000; \
1310 NTTIME g = (given).basic_info.out.write_time; \
1311 NTTIME gr = (g / r) * r; \
1312 NTTIME c = (correct).basic_info.out.write_time; \
1313 NTTIME cr = (c / r) * r; \
1314 bool strict = torture_setting_bool(tctx, "strict mode", false); \
1315 bool err = false; \
1316 if (strict && (g cmp c)) { \
1317 err = true; \
1318 } else if ((g cmp c) && (gr cmp cr)) { \
1319 /* handle filesystem without high resolution timestamps */ \
1320 err = true; \
1322 if (err) { \
1323 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1324 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1325 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1326 ret = false; \
1327 goto done; \
1329 } while (0)
1330 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1331 COMPARE_WRITE_TIME_CMP(given,correct,!=)
1332 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1333 COMPARE_WRITE_TIME_CMP(given,correct,<=)
1334 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1335 COMPARE_WRITE_TIME_CMP(given,correct,>=)
1337 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1338 NTTIME g = (given).basic_info.out.access_time; \
1339 NTTIME c = (correct).basic_info.out.access_time; \
1340 if (g cmp c) { \
1341 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1342 #given, nt_time_string(tctx, g), \
1343 #cmp, #correct, nt_time_string(tctx, c)); \
1344 ret = false; \
1345 goto done; \
1347 } while (0)
1348 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1349 COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1351 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1352 COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1353 COMPARE_WRITE_TIME_EQUAL(given,correct); \
1354 } while (0)
1356 #define GET_INFO_FILE(finfo) do { \
1357 NTSTATUS _status; \
1358 _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1359 if (!NT_STATUS_IS_OK(_status)) { \
1360 ret = false; \
1361 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1362 nt_errstr(_status)); \
1363 goto done; \
1365 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1366 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1367 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1368 } while (0)
1369 #define GET_INFO_FILE2(finfo) do { \
1370 NTSTATUS _status; \
1371 _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1372 if (!NT_STATUS_IS_OK(_status)) { \
1373 ret = false; \
1374 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1375 nt_errstr(_status)); \
1376 goto done; \
1378 torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1379 nt_time_string(tctx, finfo.basic_info.out.access_time), \
1380 nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1381 } while (0)
1382 #define GET_INFO_PATH(pinfo) do { \
1383 NTSTATUS _status; \
1384 _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1385 if (!NT_STATUS_IS_OK(_status)) { \
1386 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1387 nt_errstr(_status)); \
1388 ret = false; \
1389 goto done; \
1391 torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1392 nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1393 nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1394 } while (0)
1395 #define GET_INFO_BOTH(finfo,pinfo) do { \
1396 GET_INFO_FILE(finfo); \
1397 GET_INFO_PATH(pinfo); \
1398 COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1399 } while (0)
1401 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1402 NTSTATUS _status; \
1403 union smb_setfileinfo sfinfo; \
1404 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1405 sfinfo.basic_info.in.file.fnum = tfnum; \
1406 sfinfo.basic_info.in.create_time = 0; \
1407 sfinfo.basic_info.in.access_time = 0; \
1408 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1409 sfinfo.basic_info.in.change_time = 0; \
1410 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1411 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1412 if (!NT_STATUS_IS_OK(_status)) { \
1413 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1414 nt_errstr(_status)); \
1415 ret = false; \
1416 goto done; \
1418 } while (0)
1419 #define SET_INFO_FILE(finfo, wrtime) \
1420 SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1422 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1423 NTSTATUS _status; \
1424 union smb_setfileinfo sfinfo; \
1425 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1426 sfinfo.basic_info.in.file.fnum = tfnum; \
1427 sfinfo.basic_info.in.create_time = 0; \
1428 sfinfo.basic_info.in.access_time = 0; \
1429 unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1430 sfinfo.basic_info.in.write_time += (ns); \
1431 sfinfo.basic_info.in.change_time = 0; \
1432 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1433 _status = smb_raw_setfileinfo(tree, &sfinfo); \
1434 if (!NT_STATUS_IS_OK(_status)) { \
1435 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1436 nt_errstr(_status)); \
1437 ret = false; \
1438 goto done; \
1440 } while (0)
1442 static bool test_delayed_write_update3(struct torture_context *tctx,
1443 struct smbcli_state *cli,
1444 struct smbcli_state *cli2)
1446 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1447 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1448 const char *fname = BASEDIR "\\torture_file3.txt";
1449 int fnum1 = -1;
1450 bool ret = true;
1451 ssize_t written;
1452 struct timeval start;
1453 struct timeval end;
1454 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1455 int normal_delay = 2000000;
1456 double sec = ((double)used_delay) / ((double)normal_delay);
1457 int msec = 1000 * sec;
1459 torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
1461 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1463 torture_comment(tctx, "Open the file handle\n");
1464 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1465 if (fnum1 == -1) {
1466 ret = false;
1467 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1468 goto done;
1471 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1472 finfo0.basic_info.in.file.fnum = fnum1;
1473 finfo1 = finfo0;
1474 finfo2 = finfo0;
1475 finfo3 = finfo0;
1476 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1477 pinfo0.basic_info.in.file.path = fname;
1478 pinfo1 = pinfo0;
1479 pinfo2 = pinfo0;
1480 pinfo3 = pinfo0;
1481 pinfo4 = pinfo0;
1483 /* get the initial times */
1484 GET_INFO_BOTH(finfo0,pinfo0);
1487 * make sure the write time is updated 2 seconds later
1488 * calcuated from the first write
1489 * (but expect upto 5 seconds extra time for a busy server)
1491 start = timeval_current();
1492 end = timeval_add(&start, 7 * sec, 0);
1493 while (!timeval_expired(&end)) {
1494 /* do a write */
1495 torture_comment(tctx, "Do a write on the file handle\n");
1496 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1497 if (written != 1) {
1498 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1499 ret = false;
1500 goto done;
1502 /* get the times after the write */
1503 GET_INFO_FILE(finfo1);
1505 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1506 double diff = timeval_elapsed(&start);
1507 if (diff < (used_delay / (double)1000000)) {
1508 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1509 "(write time update delay == %.2f) (wrong!)\n",
1510 diff, used_delay / (double)1000000);
1511 ret = false;
1512 break;
1515 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1516 "(correct)\n",
1517 diff);
1518 break;
1520 smb_msleep(0.5 * msec);
1523 GET_INFO_BOTH(finfo1,pinfo1);
1524 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1526 /* sure any further write doesn't update the write time */
1527 start = timeval_current();
1528 end = timeval_add(&start, 15 * sec, 0);
1529 while (!timeval_expired(&end)) {
1530 /* do a write */
1531 torture_comment(tctx, "Do a write on the file handle\n");
1532 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1533 if (written != 1) {
1534 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1535 ret = false;
1536 goto done;
1538 /* get the times after the write */
1539 GET_INFO_BOTH(finfo2,pinfo2);
1541 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1542 double diff = timeval_elapsed(&start);
1543 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1544 "(wrong!)\n",
1545 diff);
1546 ret = false;
1547 break;
1549 smb_msleep(1 * msec);
1552 GET_INFO_BOTH(finfo2,pinfo2);
1553 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1554 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1555 torture_comment(tctx, "Server did not update write_time (correct)\n");
1558 /* sleep */
1559 smb_msleep(5 * msec);
1561 GET_INFO_BOTH(finfo3,pinfo3);
1562 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1565 * the close updates the write time to the time of the close
1566 * and not to the time of the last write!
1568 torture_comment(tctx, "Close the file handle\n");
1569 smbcli_close(cli->tree, fnum1);
1570 fnum1 = -1;
1572 GET_INFO_PATH(pinfo4);
1573 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1575 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1576 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1579 done:
1580 if (fnum1 != -1)
1581 smbcli_close(cli->tree, fnum1);
1582 smbcli_unlink(cli->tree, fname);
1583 smbcli_deltree(cli->tree, BASEDIR);
1585 return ret;
1589 * Show that a truncate write always updates the write time even
1590 * if an initial write has already updated the write time.
1593 static bool test_delayed_write_update3a(struct torture_context *tctx,
1594 struct smbcli_state *cli,
1595 struct smbcli_state *cli2)
1597 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1598 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1599 const char *fname = BASEDIR "\\torture_file3a.txt";
1600 int fnum1 = -1;
1601 bool ret = true;
1602 ssize_t written;
1603 int i;
1604 struct timeval start;
1605 struct timeval end;
1606 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1607 int normal_delay = 2000000;
1608 double sec = ((double)used_delay) / ((double)normal_delay);
1609 int msec = 1000 * sec;
1611 torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
1613 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1615 torture_comment(tctx, "Open the file handle\n");
1616 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1617 if (fnum1 == -1) {
1618 ret = false;
1619 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1620 goto done;
1623 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1624 finfo0.basic_info.in.file.fnum = fnum1;
1625 finfo1 = finfo0;
1626 finfo2 = finfo0;
1627 finfo3 = finfo0;
1628 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1629 pinfo0.basic_info.in.file.path = fname;
1630 pinfo1 = pinfo0;
1631 pinfo2 = pinfo0;
1632 pinfo3 = pinfo0;
1633 pinfo4 = pinfo0;
1635 /* get the initial times */
1636 GET_INFO_BOTH(finfo0,pinfo0);
1639 * sleep some time, to demonstrate the handling of write times
1640 * doesn't depend on the time since the open
1642 smb_msleep(5 * msec);
1644 /* get the initial times */
1645 GET_INFO_BOTH(finfo1,pinfo1);
1646 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1649 * make sure the write time is updated 2 seconds later
1650 * calcuated from the first write
1651 * (but expect upto 5 seconds extra time for a busy server)
1653 start = timeval_current();
1654 end = timeval_add(&start, 7 * sec, 0);
1655 while (!timeval_expired(&end)) {
1656 /* do a write */
1657 torture_comment(tctx, "Do a write on the file handle\n");
1658 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1659 if (written != 1) {
1660 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1661 ret = false;
1662 goto done;
1664 /* get the times after the write */
1665 GET_INFO_FILE(finfo1);
1667 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1668 double diff = timeval_elapsed(&start);
1669 if (diff < (used_delay / (double)1000000)) {
1670 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1671 "(1sec == %.2f) (wrong!)\n",
1672 diff, sec);
1673 ret = false;
1674 break;
1677 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1678 "(correct)\n",
1679 diff);
1680 break;
1682 smb_msleep(0.5 * msec);
1685 GET_INFO_BOTH(finfo1,pinfo1);
1686 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1688 smb_msleep(3 * msec);
1691 * demonstrate that a truncate write always
1692 * updates the write time immediately
1694 for (i=0; i < 3; i++) {
1695 smb_msleep(2 * msec);
1696 /* do a write */
1697 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1698 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1699 if (written != 0) {
1700 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1701 ret = false;
1702 goto done;
1704 /* get the times after the write */
1705 GET_INFO_BOTH(finfo2,pinfo2);
1706 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1707 finfo1 = finfo2;
1710 smb_msleep(3 * msec);
1712 /* sure any further write doesn't update the write time */
1713 start = timeval_current();
1714 end = timeval_add(&start, 15 * sec, 0);
1715 while (!timeval_expired(&end)) {
1716 /* do a write */
1717 torture_comment(tctx, "Do a write on the file handle\n");
1718 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1719 if (written != 1) {
1720 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1721 ret = false;
1722 goto done;
1724 /* get the times after the write */
1725 GET_INFO_BOTH(finfo2,pinfo2);
1727 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1728 double diff = timeval_elapsed(&start);
1729 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1730 "(wrong!)\n",
1731 diff);
1732 ret = false;
1733 break;
1735 smb_msleep(1 * msec);
1738 GET_INFO_BOTH(finfo2,pinfo2);
1739 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1740 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1741 torture_comment(tctx, "Server did not update write_time (correct)\n");
1744 /* sleep */
1745 smb_msleep(3 * msec);
1747 /* get the initial times */
1748 GET_INFO_BOTH(finfo1,pinfo1);
1749 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1752 * demonstrate that a truncate write always
1753 * updates the write time immediately
1755 for (i=0; i < 3; i++) {
1756 smb_msleep(2 * msec);
1757 /* do a write */
1758 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1759 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1760 if (written != 0) {
1761 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1762 ret = false;
1763 goto done;
1765 /* get the times after the write */
1766 GET_INFO_BOTH(finfo2,pinfo2);
1767 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1768 finfo1 = finfo2;
1771 /* sleep */
1772 smb_msleep(3 * msec);
1774 GET_INFO_BOTH(finfo3,pinfo3);
1775 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1778 * the close doesn't update the write time
1780 torture_comment(tctx, "Close the file handle\n");
1781 smbcli_close(cli->tree, fnum1);
1782 fnum1 = -1;
1784 GET_INFO_PATH(pinfo4);
1785 COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1787 if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1788 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1791 done:
1792 if (fnum1 != -1)
1793 smbcli_close(cli->tree, fnum1);
1794 smbcli_unlink(cli->tree, fname);
1795 smbcli_deltree(cli->tree, BASEDIR);
1797 return ret;
1801 * Show a close after write updates the write timestamp to
1802 * the close time, not the last write time.
1805 static bool test_delayed_write_update3b(struct torture_context *tctx,
1806 struct smbcli_state *cli,
1807 struct smbcli_state *cli2)
1809 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1810 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1811 const char *fname = BASEDIR "\\torture_file3b.txt";
1812 int fnum1 = -1;
1813 bool ret = true;
1814 ssize_t written;
1815 struct timeval start;
1816 struct timeval end;
1817 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1818 int normal_delay = 2000000;
1819 double sec = ((double)used_delay) / ((double)normal_delay);
1820 int msec = 1000 * sec;
1822 torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
1824 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1826 torture_comment(tctx, "Open the file handle\n");
1827 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1828 if (fnum1 == -1) {
1829 ret = false;
1830 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1831 goto done;
1834 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1835 finfo0.basic_info.in.file.fnum = fnum1;
1836 finfo1 = finfo0;
1837 finfo2 = finfo0;
1838 finfo3 = finfo0;
1839 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1840 pinfo0.basic_info.in.file.path = fname;
1841 pinfo1 = pinfo0;
1842 pinfo2 = pinfo0;
1843 pinfo3 = pinfo0;
1844 pinfo4 = pinfo0;
1846 /* get the initial times */
1847 GET_INFO_BOTH(finfo0,pinfo0);
1850 * sleep some time, to demonstrate the handling of write times
1851 * doesn't depend on the time since the open
1853 smb_msleep(5 * msec);
1855 /* get the initial times */
1856 GET_INFO_BOTH(finfo1,pinfo1);
1857 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1860 * make sure the write time is updated 2 seconds later
1861 * calcuated from the first write
1862 * (but expect upto 5 seconds extra time for a busy server)
1864 start = timeval_current();
1865 end = timeval_add(&start, 7 * sec, 0);
1866 while (!timeval_expired(&end)) {
1867 /* do a write */
1868 torture_comment(tctx, "Do a write on the file handle\n");
1869 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1870 if (written != 1) {
1871 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1872 ret = false;
1873 goto done;
1875 /* get the times after the write */
1876 GET_INFO_FILE(finfo1);
1878 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1879 double diff = timeval_elapsed(&start);
1880 if (diff < (used_delay / (double)1000000)) {
1881 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1882 "(expected > %.2f) (wrong!)\n",
1883 diff, used_delay / (double)1000000);
1884 ret = false;
1885 break;
1888 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1889 "(write time update delay == %.2f) (correct)\n",
1890 diff, used_delay / (double)1000000);
1891 break;
1893 smb_msleep(0.5 * msec);
1896 GET_INFO_BOTH(finfo1,pinfo1);
1897 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1899 /* sure any further write doesn't update the write time */
1900 start = timeval_current();
1901 end = timeval_add(&start, 15 * sec, 0);
1902 while (!timeval_expired(&end)) {
1903 /* do a write */
1904 torture_comment(tctx, "Do a write on the file handle\n");
1905 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1906 if (written != 1) {
1907 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1908 ret = false;
1909 goto done;
1911 /* get the times after the write */
1912 GET_INFO_BOTH(finfo2,pinfo2);
1914 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1915 double diff = timeval_elapsed(&start);
1916 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1917 "(wrong!)\n",
1918 diff);
1919 ret = false;
1920 break;
1922 smb_msleep(1 * msec);
1925 GET_INFO_BOTH(finfo2,pinfo2);
1926 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1927 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1928 torture_comment(tctx, "Server did not update write_time (correct)\n");
1931 /* sleep */
1932 smb_msleep(5 * msec);
1934 GET_INFO_BOTH(finfo3,pinfo3);
1935 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1938 * the close updates the write time to the time of the close
1939 * and not to the time of the last write!
1941 torture_comment(tctx, "Close the file handle\n");
1942 smbcli_close(cli->tree, fnum1);
1943 fnum1 = -1;
1945 GET_INFO_PATH(pinfo4);
1946 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1948 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1949 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1952 done:
1953 if (fnum1 != -1)
1954 smbcli_close(cli->tree, fnum1);
1955 smbcli_unlink(cli->tree, fname);
1956 smbcli_deltree(cli->tree, BASEDIR);
1958 return ret;
1962 * Check that a write after a truncate write doesn't update
1963 * the timestamp, but a truncate write after a write does.
1964 * Also prove that a close after a truncate write updates the
1965 * timestamp to current, not the time of last write.
1968 static bool test_delayed_write_update3c(struct torture_context *tctx,
1969 struct smbcli_state *cli,
1970 struct smbcli_state *cli2)
1972 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1973 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1974 const char *fname = BASEDIR "\\torture_file3c.txt";
1975 int fnum1 = -1;
1976 bool ret = true;
1977 ssize_t written;
1978 int i;
1979 struct timeval start;
1980 struct timeval end;
1981 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1982 int normal_delay = 2000000;
1983 double sec = ((double)used_delay) / ((double)normal_delay);
1984 int msec = 1000 * sec;
1986 torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
1988 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1990 torture_comment(tctx, "Open the file handle\n");
1991 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1992 if (fnum1 == -1) {
1993 ret = false;
1994 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1995 goto done;
1998 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1999 finfo0.basic_info.in.file.fnum = fnum1;
2000 finfo1 = finfo0;
2001 finfo2 = finfo0;
2002 finfo3 = finfo0;
2003 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2004 pinfo0.basic_info.in.file.path = fname;
2005 pinfo1 = pinfo0;
2006 pinfo2 = pinfo0;
2007 pinfo3 = pinfo0;
2008 pinfo4 = pinfo0;
2010 /* get the initial times */
2011 GET_INFO_BOTH(finfo0,pinfo0);
2014 * sleep some time, to demonstrate the handling of write times
2015 * doesn't depend on the time since the open
2017 smb_msleep(5 * msec);
2019 /* get the initial times */
2020 GET_INFO_BOTH(finfo1,pinfo1);
2021 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2024 * demonstrate that a truncate write always
2025 * updates the write time immediately
2027 for (i=0; i < 3; i++) {
2028 smb_msleep(2 * msec);
2029 /* do a write */
2030 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
2031 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2032 if (written != 0) {
2033 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2034 ret = false;
2035 goto done;
2037 /* get the times after the write */
2038 GET_INFO_BOTH(finfo2,pinfo2);
2039 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2040 finfo1 = finfo2;
2043 start = timeval_current();
2044 end = timeval_add(&start, 7 * sec, 0);
2045 while (!timeval_expired(&end)) {
2046 /* do a write */
2047 torture_comment(tctx, "Do a write on the file handle\n");
2048 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2049 if (written != 1) {
2050 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2051 ret = false;
2052 goto done;
2054 /* get the times after the write */
2055 GET_INFO_FILE(finfo2);
2057 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2058 double diff = timeval_elapsed(&start);
2059 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2060 "(wrong!)\n",
2061 diff);
2062 ret = false;
2063 break;
2065 smb_msleep(1 * msec);
2068 GET_INFO_BOTH(finfo2,pinfo2);
2069 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2070 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2071 torture_comment(tctx, "Server did not update write_time (correct)\n");
2074 /* sleep */
2075 smb_msleep(5 * msec);
2077 /* get the initial times */
2078 GET_INFO_BOTH(finfo1,pinfo1);
2079 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2082 * demonstrate that a truncate write always
2083 * updates the write time immediately
2085 for (i=0; i < 3; i++) {
2086 smb_msleep(2 * msec);
2087 /* do a write */
2088 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2089 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2090 if (written != 0) {
2091 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2092 ret = false;
2093 goto done;
2095 /* get the times after the write */
2096 GET_INFO_BOTH(finfo2,pinfo2);
2097 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2098 finfo1 = finfo2;
2101 /* sleep */
2102 smb_msleep(5 * msec);
2104 GET_INFO_BOTH(finfo2,pinfo2);
2105 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2107 /* sure any further write doesn't update the write time */
2108 start = timeval_current();
2109 end = timeval_add(&start, 15 * sec, 0);
2110 while (!timeval_expired(&end)) {
2111 /* do a write */
2112 torture_comment(tctx, "Do a write on the file handle\n");
2113 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2114 if (written != 1) {
2115 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2116 ret = false;
2117 goto done;
2119 /* get the times after the write */
2120 GET_INFO_BOTH(finfo2,pinfo2);
2122 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2123 double diff = timeval_elapsed(&start);
2124 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2125 "(wrong!)\n",
2126 diff);
2127 ret = false;
2128 break;
2130 smb_msleep(1 * msec);
2133 GET_INFO_BOTH(finfo2,pinfo2);
2134 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2135 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2136 torture_comment(tctx, "Server did not update write_time (correct)\n");
2139 /* sleep */
2140 smb_msleep(5 * msec);
2142 GET_INFO_BOTH(finfo3,pinfo3);
2143 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2146 * the close updates the write time to the time of the close
2147 * and not to the time of the last write!
2149 torture_comment(tctx, "Close the file handle\n");
2150 smbcli_close(cli->tree, fnum1);
2151 fnum1 = -1;
2153 GET_INFO_PATH(pinfo4);
2154 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2156 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2157 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2160 done:
2161 if (fnum1 != -1)
2162 smbcli_close(cli->tree, fnum1);
2163 smbcli_unlink(cli->tree, fname);
2164 smbcli_deltree(cli->tree, BASEDIR);
2166 return ret;
2170 * Show only the first write updates the timestamp, and a close
2171 * after writes updates to current (I think this is the same
2172 * as test 3b. JRA).
2175 static bool test_delayed_write_update4(struct torture_context *tctx,
2176 struct smbcli_state *cli,
2177 struct smbcli_state *cli2)
2179 union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
2180 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
2181 const char *fname = BASEDIR "\\torture_file4.txt";
2182 int fnum1 = -1;
2183 bool ret = true;
2184 ssize_t written;
2185 struct timeval start;
2186 struct timeval end;
2187 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2188 int normal_delay = 2000000;
2189 double sec = ((double)used_delay) / ((double)normal_delay);
2190 int msec = 1000 * sec;
2192 torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2194 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2196 torture_comment(tctx, "Open the file handle\n");
2197 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2198 if (fnum1 == -1) {
2199 ret = false;
2200 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2201 goto done;
2204 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2205 finfo0.basic_info.in.file.fnum = fnum1;
2206 finfo1 = finfo0;
2207 finfo2 = finfo0;
2208 finfo3 = finfo0;
2209 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2210 pinfo0.basic_info.in.file.path = fname;
2211 pinfo1 = pinfo0;
2212 pinfo2 = pinfo0;
2213 pinfo3 = pinfo0;
2214 pinfo4 = pinfo0;
2216 /* get the initial times */
2217 GET_INFO_BOTH(finfo0,pinfo0);
2219 /* sleep a bit */
2220 smb_msleep(5 * msec);
2222 /* do a write */
2223 torture_comment(tctx, "Do a write on the file handle\n");
2224 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2225 if (written != 1) {
2226 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2227 ret = false;
2228 goto done;
2231 GET_INFO_BOTH(finfo1,pinfo1);
2232 COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2235 * make sure the write time is updated 2 seconds later
2236 * calcuated from the first write
2237 * (but expect upto 3 seconds extra time for a busy server)
2239 start = timeval_current();
2240 end = timeval_add(&start, 5 * sec, 0);
2241 while (!timeval_expired(&end)) {
2242 /* get the times after the first write */
2243 GET_INFO_FILE(finfo1);
2245 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2246 double diff = timeval_elapsed(&start);
2247 if (diff < (used_delay / (double)1000000)) {
2248 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
2249 "(expected > %.2f) (wrong!)\n",
2250 diff, used_delay / (double)1000000);
2251 ret = false;
2252 break;
2255 torture_comment(tctx, "Server updated write_time after %.2f seconds "
2256 "(write time update delay == %.2f) (correct)\n",
2257 diff, used_delay / (double)1000000);
2258 break;
2260 smb_msleep(0.5 * msec);
2263 GET_INFO_BOTH(finfo1,pinfo1);
2264 COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2266 /* sure any further write doesn't update the write time */
2267 start = timeval_current();
2268 end = timeval_add(&start, 15 * sec, 0);
2269 while (!timeval_expired(&end)) {
2270 /* do a write */
2271 torture_comment(tctx, "Do a write on the file handle\n");
2272 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2273 if (written != 1) {
2274 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2275 ret = false;
2276 goto done;
2278 /* get the times after the write */
2279 GET_INFO_BOTH(finfo2,pinfo2);
2281 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2282 double diff = timeval_elapsed(&start);
2283 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2284 "(wrong!)\n",
2285 diff);
2286 ret = false;
2287 break;
2289 smb_msleep(1 * msec);
2292 GET_INFO_BOTH(finfo2,pinfo2);
2293 COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2294 if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2295 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2298 /* sleep */
2299 smb_msleep(5 * msec);
2301 GET_INFO_BOTH(finfo3,pinfo3);
2302 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2305 * the close updates the write time to the time of the close
2306 * and not to the time of the last write!
2308 torture_comment(tctx, "Close the file handle\n");
2309 smbcli_close(cli->tree, fnum1);
2310 fnum1 = -1;
2312 GET_INFO_PATH(pinfo4);
2313 COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2315 if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2316 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2319 done:
2320 if (fnum1 != -1)
2321 smbcli_close(cli->tree, fnum1);
2322 smbcli_unlink(cli->tree, fname);
2323 smbcli_deltree(cli->tree, BASEDIR);
2325 return ret;
2329 * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2332 static bool test_delayed_write_update5(struct torture_context *tctx,
2333 struct smbcli_state *cli,
2334 struct smbcli_state *cli2)
2336 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2337 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2338 const char *fname = BASEDIR "\\torture_file5.txt";
2339 int fnum1 = -1;
2340 bool ret = true;
2341 ssize_t written;
2342 struct timeval start;
2343 struct timeval end;
2344 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2345 int normal_delay = 2000000;
2346 double sec = ((double)used_delay) / ((double)normal_delay);
2347 int msec = 1000 * sec;
2349 torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2351 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2353 torture_comment(tctx, "Open the file handle\n");
2354 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2355 if (fnum1 == -1) {
2356 ret = false;
2357 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2358 goto done;
2361 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2362 finfo0.basic_info.in.file.fnum = fnum1;
2363 finfo1 = finfo0;
2364 finfo2 = finfo0;
2365 finfo3 = finfo0;
2366 finfo4 = finfo0;
2367 finfo5 = finfo0;
2368 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2369 pinfo0.basic_info.in.file.path = fname;
2370 pinfo1 = pinfo0;
2371 pinfo2 = pinfo0;
2372 pinfo3 = pinfo0;
2373 pinfo4 = pinfo0;
2374 pinfo5 = pinfo0;
2375 pinfo6 = pinfo0;
2377 /* get the initial times */
2378 GET_INFO_BOTH(finfo0,pinfo0);
2380 /* do a write */
2381 torture_comment(tctx, "Do a write on the file handle\n");
2382 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2383 if (written != 1) {
2384 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2385 ret = false;
2386 goto done;
2389 GET_INFO_BOTH(finfo1,pinfo1);
2390 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2392 torture_comment(tctx, "Set write time in the future on the file handle\n");
2393 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2394 GET_INFO_BOTH(finfo2,pinfo2);
2395 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2397 torture_comment(tctx, "Set write time in the past on the file handle\n");
2398 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2399 GET_INFO_BOTH(finfo2,pinfo2);
2400 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2402 /* make sure the 2 second delay from the first write are canceled */
2403 start = timeval_current();
2404 end = timeval_add(&start, 15 * sec, 0);
2405 while (!timeval_expired(&end)) {
2407 /* get the times after the first write */
2408 GET_INFO_BOTH(finfo3,pinfo3);
2410 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2411 double diff = timeval_elapsed(&start);
2412 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2413 "(wrong!)\n",
2414 diff);
2415 ret = false;
2416 break;
2418 smb_msleep(1 * msec);
2421 GET_INFO_BOTH(finfo3,pinfo3);
2422 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2423 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2424 torture_comment(tctx, "Server did not update write_time (correct)\n");
2427 /* sure any further write doesn't update the write time */
2428 start = timeval_current();
2429 end = timeval_add(&start, 15 * sec, 0);
2430 while (!timeval_expired(&end)) {
2431 /* do a write */
2432 torture_comment(tctx, "Do a write on the file handle\n");
2433 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2434 if (written != 1) {
2435 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2436 ret = false;
2437 goto done;
2439 /* get the times after the write */
2440 GET_INFO_BOTH(finfo4,pinfo4);
2442 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2443 double diff = timeval_elapsed(&start);
2444 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2445 "(wrong!)\n",
2446 diff);
2447 ret = false;
2448 break;
2450 smb_msleep(1 * msec);
2453 GET_INFO_BOTH(finfo4,pinfo4);
2454 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2455 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2456 torture_comment(tctx, "Server did not update write_time (correct)\n");
2459 /* sleep */
2460 smb_msleep(5 * msec);
2462 GET_INFO_BOTH(finfo5,pinfo5);
2463 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2466 * the close doesn't update the write time
2468 torture_comment(tctx, "Close the file handle\n");
2469 smbcli_close(cli->tree, fnum1);
2470 fnum1 = -1;
2472 GET_INFO_PATH(pinfo6);
2473 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2475 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2476 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2479 done:
2480 if (fnum1 != -1)
2481 smbcli_close(cli->tree, fnum1);
2482 smbcli_unlink(cli->tree, fname);
2483 smbcli_deltree(cli->tree, BASEDIR);
2485 return ret;
2489 * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2492 static bool test_delayed_write_update5b(struct torture_context *tctx,
2493 struct smbcli_state *cli,
2494 struct smbcli_state *cli2)
2496 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2497 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2498 const char *fname = BASEDIR "\\torture_fileb.txt";
2499 int fnum1 = -1;
2500 bool ret = true;
2501 ssize_t written;
2502 struct timeval start;
2503 struct timeval end;
2504 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2505 int normal_delay = 2000000;
2506 double sec = ((double)used_delay) / ((double)normal_delay);
2507 int msec = 1000 * sec;
2509 torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2511 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2513 torture_comment(tctx, "Open the file handle\n");
2514 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2515 if (fnum1 == -1) {
2516 ret = false;
2517 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2518 goto done;
2521 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2522 finfo0.basic_info.in.file.fnum = fnum1;
2523 finfo1 = finfo0;
2524 finfo2 = finfo0;
2525 finfo3 = finfo0;
2526 finfo4 = finfo0;
2527 finfo5 = finfo0;
2528 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2529 pinfo0.basic_info.in.file.path = fname;
2530 pinfo1 = pinfo0;
2531 pinfo2 = pinfo0;
2532 pinfo3 = pinfo0;
2533 pinfo4 = pinfo0;
2534 pinfo5 = pinfo0;
2535 pinfo6 = pinfo0;
2537 /* get the initial times */
2538 GET_INFO_BOTH(finfo0,pinfo0);
2540 /* do a write */
2541 torture_comment(tctx, "Do a write on the file handle\n");
2542 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2543 if (written != 1) {
2544 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2545 ret = false;
2546 goto done;
2549 GET_INFO_BOTH(finfo1,pinfo1);
2550 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2552 torture_comment(tctx, "Set write time in the future on the file handle\n");
2553 SET_INFO_FILE(finfo0, time(NULL) + 86400);
2554 GET_INFO_BOTH(finfo2,pinfo2);
2555 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2557 torture_comment(tctx, "Set write time in the past on the file handle\n");
2558 SET_INFO_FILE(finfo0, time(NULL) - 86400);
2559 GET_INFO_BOTH(finfo2,pinfo2);
2560 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2562 /* make sure the 2 second delay from the first write are canceled */
2563 start = timeval_current();
2564 end = timeval_add(&start, 15 * sec, 0);
2565 while (!timeval_expired(&end)) {
2567 /* get the times after the first write */
2568 GET_INFO_BOTH(finfo3,pinfo3);
2570 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2571 double diff = timeval_elapsed(&start);
2572 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2573 "(wrong!)\n",
2574 diff);
2575 ret = false;
2576 break;
2578 smb_msleep(1 * msec);
2581 GET_INFO_BOTH(finfo3,pinfo3);
2582 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2583 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2584 torture_comment(tctx, "Server did not update write_time (correct)\n");
2587 /* Do any further write (truncates) update the write time ? */
2588 start = timeval_current();
2589 end = timeval_add(&start, 15 * sec, 0);
2590 while (!timeval_expired(&end)) {
2591 /* do a write */
2592 torture_comment(tctx, "Do a truncate write on the file handle\n");
2593 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2594 if (written != 0) {
2595 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2596 ret = false;
2597 goto done;
2599 /* get the times after the write */
2600 GET_INFO_BOTH(finfo4,pinfo4);
2602 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2603 double diff = timeval_elapsed(&start);
2604 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2605 "(wrong!)\n",
2606 diff);
2607 ret = false;
2608 break;
2610 smb_msleep(1 * msec);
2613 GET_INFO_BOTH(finfo4,pinfo4);
2614 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2615 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2616 torture_comment(tctx, "Server did not update write_time (correct)\n");
2619 /* sleep */
2620 smb_msleep(5 * msec);
2622 GET_INFO_BOTH(finfo5,pinfo5);
2623 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2626 * the close doesn't update the write time
2628 torture_comment(tctx, "Close the file handle\n");
2629 smbcli_close(cli->tree, fnum1);
2630 fnum1 = -1;
2632 GET_INFO_PATH(pinfo6);
2633 COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2635 if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2636 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2639 done:
2640 if (fnum1 != -1)
2641 smbcli_close(cli->tree, fnum1);
2642 smbcli_unlink(cli->tree, fname);
2643 smbcli_deltree(cli->tree, BASEDIR);
2645 return ret;
2649 * Open 2 handles on a file. Write one one and then set the
2650 * WRITE TIME explicitly on the other. Ensure the write time
2651 * update is cancelled. Ensure the write time is updated to
2652 * the close time when the non-explicit set handle is closed.
2656 static bool test_delayed_write_update6(struct torture_context *tctx,
2657 struct smbcli_state *cli,
2658 struct smbcli_state *cli2)
2660 union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2661 union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2662 const char *fname = BASEDIR "\\torture_file6.txt";
2663 int fnum1 = -1;
2664 int fnum2 = -1;
2665 bool ret = true;
2666 ssize_t written;
2667 struct timeval start;
2668 struct timeval end;
2669 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2670 int normal_delay = 2000000;
2671 double sec = ((double)used_delay) / ((double)normal_delay);
2672 int msec = 1000 * sec;
2673 bool first = true;
2675 torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2677 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2678 again:
2679 torture_comment(tctx, "Open the file handle\n");
2680 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2681 if (fnum1 == -1) {
2682 ret = false;
2683 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2684 goto done;
2687 if (fnum2 == -1) {
2688 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2689 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2690 if (fnum2 == -1) {
2691 ret = false;
2692 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2693 goto done;
2697 finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2698 finfo0.basic_info.in.file.fnum = fnum1;
2699 finfo1 = finfo0;
2700 finfo2 = finfo0;
2701 finfo3 = finfo0;
2702 finfo4 = finfo0;
2703 finfo5 = finfo0;
2704 pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2705 pinfo0.basic_info.in.file.path = fname;
2706 pinfo1 = pinfo0;
2707 pinfo2 = pinfo0;
2708 pinfo3 = pinfo0;
2709 pinfo4 = pinfo0;
2710 pinfo5 = pinfo0;
2711 pinfo6 = pinfo0;
2712 pinfo7 = pinfo0;
2714 /* get the initial times */
2715 GET_INFO_BOTH(finfo0,pinfo0);
2717 /* do a write */
2718 torture_comment(tctx, "Do a write on the file handle\n");
2719 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2720 if (written != 1) {
2721 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2722 ret = false;
2723 goto done;
2726 GET_INFO_BOTH(finfo1,pinfo1);
2727 COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2729 torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2730 SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2731 GET_INFO_BOTH(finfo2,pinfo2);
2732 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2734 torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2735 SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2736 GET_INFO_BOTH(finfo2,pinfo2);
2737 COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2739 /* make sure the 2 second delay from the first write are canceled */
2740 start = timeval_current();
2741 end = timeval_add(&start, 10 * sec, 0);
2742 while (!timeval_expired(&end)) {
2744 /* get the times after the first write */
2745 GET_INFO_BOTH(finfo3,pinfo3);
2747 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2748 double diff = timeval_elapsed(&start);
2749 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2750 "(wrong!)\n",
2751 diff);
2752 ret = false;
2753 break;
2755 smb_msleep(1 * msec);
2758 GET_INFO_BOTH(finfo3,pinfo3);
2759 COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2760 if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2761 torture_comment(tctx, "Server did not update write_time (correct)\n");
2764 /* sure any further write doesn't update the write time */
2765 start = timeval_current();
2766 end = timeval_add(&start, 10 * sec, 0);
2767 while (!timeval_expired(&end)) {
2768 /* do a write */
2769 torture_comment(tctx, "Do a write on the file handle\n");
2770 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2771 if (written != 1) {
2772 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2773 ret = false;
2774 goto done;
2776 /* get the times after the write */
2777 GET_INFO_BOTH(finfo4,pinfo4);
2779 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2780 double diff = timeval_elapsed(&start);
2781 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2782 "(wrong!)\n",
2783 diff);
2784 ret = false;
2785 break;
2787 smb_msleep(1 * msec);
2790 GET_INFO_BOTH(finfo4,pinfo4);
2791 COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2792 if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2793 torture_comment(tctx, "Server did not update write_time (correct)\n");
2796 /* sleep */
2797 smb_msleep(5 * msec);
2799 GET_INFO_BOTH(finfo5,pinfo5);
2800 COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2803 * the close updates the write time to the time of the close
2804 * as the write time was set on the 2nd handle
2806 torture_comment(tctx, "Close the file handle\n");
2807 smbcli_close(cli->tree, fnum1);
2808 fnum1 = -1;
2810 GET_INFO_PATH(pinfo6);
2811 COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2813 if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2814 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2817 /* See what the second write handle thinks the time is ? */
2818 finfo5.basic_info.in.file.fnum = fnum2;
2819 GET_INFO_FILE2(finfo5);
2820 COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
2822 /* See if we have lost the sticky write time on handle2 */
2823 smb_msleep(3 * msec);
2824 torture_comment(tctx, "Have we lost the sticky write time ?\n");
2826 /* Make sure any further normal write doesn't update the write time */
2827 start = timeval_current();
2828 end = timeval_add(&start, 10 * sec, 0);
2829 while (!timeval_expired(&end)) {
2830 /* do a write */
2831 torture_comment(tctx, "Do a write on the second file handle\n");
2832 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
2833 if (written != 1) {
2834 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2835 ret = false;
2836 goto done;
2838 /* get the times after the write */
2839 GET_INFO_FILE2(finfo5);
2840 GET_INFO_PATH(pinfo6);
2842 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2843 double diff = timeval_elapsed(&start);
2844 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2845 "(wrong!)\n",
2846 diff);
2847 ret = false;
2848 break;
2850 smb_msleep(1 * msec);
2853 /* What about a truncate write ? */
2854 start = timeval_current();
2855 end = timeval_add(&start, 10 * sec, 0);
2856 while (!timeval_expired(&end)) {
2857 /* do a write */
2858 torture_comment(tctx, "Do a truncate write on the second file handle\n");
2859 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
2860 if (written != 0) {
2861 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2862 ret = false;
2863 goto done;
2865 /* get the times after the write */
2866 GET_INFO_FILE2(finfo5);
2867 GET_INFO_PATH(pinfo6);
2869 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2870 double diff = timeval_elapsed(&start);
2871 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2872 "(wrong!)\n",
2873 diff);
2874 ret = false;
2875 break;
2877 smb_msleep(1 * msec);
2881 /* keep the 2nd handle open and rerun tests */
2882 if (first) {
2883 first = false;
2884 goto again;
2888 * closing the 2nd handle will cause no write time update
2889 * as the write time was explicit set on this handle
2891 torture_comment(tctx, "Close the 2nd file handle\n");
2892 smbcli_close(cli2->tree, fnum2);
2893 fnum2 = -1;
2895 GET_INFO_PATH(pinfo7);
2896 COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2898 if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2899 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2902 done:
2903 if (fnum1 != -1)
2904 smbcli_close(cli->tree, fnum1);
2905 if (fnum2 != -1)
2906 smbcli_close(cli2->tree, fnum2);
2907 smbcli_unlink(cli->tree, fname);
2908 smbcli_deltree(cli->tree, BASEDIR);
2910 return ret;
2913 static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
2915 union smb_open open_parms;
2916 union smb_fileinfo finfo1, finfo2, finfo3;
2917 const char *fname = BASEDIR "\\torture_file7.txt";
2918 NTSTATUS status;
2919 int fnum1 = -1;
2920 bool ret = true;
2921 TALLOC_CTX *mem_ctx;
2923 torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2925 mem_ctx = talloc_init("test_delayed_write_update7");
2926 if (!mem_ctx) return false;
2928 ZERO_STRUCT(finfo1);
2929 ZERO_STRUCT(finfo2);
2930 ZERO_STRUCT(finfo3);
2931 ZERO_STRUCT(open_parms);
2933 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2935 /* Create the file. */
2936 fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2937 if (fnum1 == -1) {
2938 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
2939 return false;
2942 finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2943 finfo1.basic_info.in.file.fnum = fnum1;
2944 finfo2 = finfo1;
2945 finfo3 = finfo1;
2947 /* Get the initial timestamps. */
2948 status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
2950 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2952 /* Set the pending write time to a value with ns. */
2953 SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
2955 /* Get the current pending write time by fnum. */
2956 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
2958 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2960 /* Ensure the time is actually different. */
2961 if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2962 torture_result(tctx, TORTURE_FAIL,
2963 "setfileinfo time matches original fileinfo time");
2964 ret = false;
2967 /* Get the current pending write time by path. */
2968 finfo3.basic_info.in.file.path = fname;
2969 status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
2971 if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
2972 torture_result(tctx, TORTURE_FAIL,
2973 "qpathinfo time doens't match fileinfo time");
2974 ret = false;
2977 /* Now close the file. Re-open and check that the write
2978 time is identical to the one we wrote. */
2980 smbcli_close(cli->tree, fnum1);
2982 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
2983 open_parms.ntcreatex.in.flags = 0;
2984 open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
2985 open_parms.ntcreatex.in.file_attr = 0;
2986 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
2987 NTCREATEX_SHARE_ACCESS_READ|
2988 NTCREATEX_SHARE_ACCESS_WRITE;
2989 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
2990 open_parms.ntcreatex.in.create_options = 0;
2991 open_parms.ntcreatex.in.fname = fname;
2993 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
2994 talloc_free(mem_ctx);
2996 if (!NT_STATUS_IS_OK(status)) {
2997 torture_result(tctx, TORTURE_FAIL,
2998 "setfileinfo time matches original fileinfo time");
2999 ret = false;
3002 fnum1 = open_parms.ntcreatex.out.file.fnum;
3004 /* Check the returned time matches. */
3005 if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
3006 torture_result(tctx, TORTURE_FAIL,
3007 "final open time does not match set time");
3008 ret = false;
3011 done:
3013 smbcli_close(cli->tree, fnum1);
3015 smbcli_unlink(cli->tree, fname);
3016 smbcli_deltree(cli->tree, BASEDIR);
3017 return ret;
3021 Test if creating a file in a directory with an open handle updates the
3022 write timestamp (it should).
3024 static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
3026 union smb_fileinfo dir_info1, dir_info2;
3027 union smb_open open_parms;
3028 const char *fname = BASEDIR "\\torture_file.txt";
3029 NTSTATUS status;
3030 int fnum1 = -1;
3031 int fnum2 = -1;
3032 bool ret = true;
3033 double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3034 int normal_delay = 2000000;
3035 double sec = ((double)used_delay) / ((double)normal_delay);
3036 int msec = 1000 * sec;
3037 TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
3039 if (!mem_ctx) return false;
3041 torture_comment(tctx, "\nRunning test directory write update\n");
3043 torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
3045 /* Open a handle on the directory - and leave it open. */
3046 ZERO_STRUCT(open_parms);
3047 open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3048 open_parms.ntcreatex.in.flags = 0;
3049 open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
3050 open_parms.ntcreatex.in.file_attr = 0;
3051 open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3052 NTCREATEX_SHARE_ACCESS_READ|
3053 NTCREATEX_SHARE_ACCESS_WRITE;
3054 open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3055 open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
3056 open_parms.ntcreatex.in.fname = BASEDIR;
3058 status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3059 talloc_free(mem_ctx);
3061 if (!NT_STATUS_IS_OK(status)) {
3062 torture_result(tctx, TORTURE_FAIL,
3063 "failed to open directory handle");
3064 ret = false;
3065 goto done;
3068 fnum1 = open_parms.ntcreatex.out.file.fnum;
3070 /* Store the returned write time. */
3071 ZERO_STRUCT(dir_info1);
3072 dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
3074 torture_comment(tctx, "Initial write time %s\n",
3075 nt_time_string(tctx, dir_info1.basic_info.out.write_time));
3077 /* sleep */
3078 smb_msleep(3 * msec);
3080 /* Now create a file within the directory. */
3081 fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3082 if (fnum2 == -1) {
3083 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
3084 ret = false;
3085 goto done;
3087 smbcli_close(cli->tree, fnum2);
3089 /* Read the directory write time again. */
3090 ZERO_STRUCT(dir_info2);
3091 dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3092 dir_info2.basic_info.in.file.fnum = fnum1;
3094 status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
3096 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
3098 /* Ensure it's been incremented. */
3099 COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
3101 torture_comment(tctx, "Updated write time %s\n",
3102 nt_time_string(tctx, dir_info2.basic_info.out.write_time));
3104 done:
3106 if (fnum1 != -1)
3107 smbcli_close(cli->tree, fnum1);
3108 smbcli_unlink(cli->tree, fname);
3109 smbcli_deltree(cli->tree, BASEDIR);
3111 return ret;
3115 testing of delayed update of write_time
3117 struct torture_suite *torture_delay_write(void)
3119 struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "delaywrite");
3121 torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
3122 torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
3123 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
3124 torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
3125 torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
3126 torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
3127 torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
3128 torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
3129 torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
3130 torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
3131 torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
3132 torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
3133 torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
3134 torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
3135 torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
3136 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3137 torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3138 torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);
3140 return suite;