s4:torture:basic: use assert in the second loop in delayed_write_update1b
[metze/samba/wip.git] / source4 / torture / basic / delaywrite.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    test suite for delayed write update 
5
6    Copyright (C) Volker Lendecke 2004
7    Copyright (C) Andrew Tridgell 2004
8    Copyright (C) Jeremy Allison 2004
9    
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.
14    
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.
19    
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/>.
22 */
23
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"
33
34 #define BASEDIR "\\delaywrite"
35
36 static bool test_delayed_write_update(struct torture_context *tctx, struct smbcli_state *cli)
37 {
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;
50
51         torture_comment(tctx, "\nRunning test_delayed_write_update\n");
52
53         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
54
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));
58
59         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
60         finfo1.basic_info.in.file.fnum = fnum1;
61         finfo2 = finfo1;
62
63         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
64         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
65
66         torture_comment(tctx, "Initial write time %s\n",
67                         nt_time_string(tctx, finfo1.basic_info.out.write_time));
68
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");
72
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);
77
78                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
79
80                 torture_comment(tctx, "write time %s\n",
81                         nt_time_string(tctx, finfo2.basic_info.out.write_time));
82
83                 if (finfo1.basic_info.out.write_time !=
84                     finfo2.basic_info.out.write_time)
85                 {
86                         double diff = timeval_elapsed(&start);
87
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));
94
95                         torture_comment(tctx, "Server updated write_time after %.2f seconds (correct)\n",
96                                         diff);
97                         break;
98                 }
99                 fflush(stdout);
100                 smb_msleep(1 * msec);
101         }
102
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");
108
109         if (fnum1 != -1)
110                 smbcli_close(cli->tree, fnum1);
111         smbcli_unlink(cli->tree, fname);
112         smbcli_deltree(cli->tree, BASEDIR);
113
114         return ret;
115 }
116
117 static bool test_delayed_write_update1(struct torture_context *tctx, struct smbcli_state *cli)
118 {
119         union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
120         const char *fname = BASEDIR "\\torture_file1.txt";
121         NTSTATUS status;
122         int fnum1 = -1;
123         bool ret = true;
124         ssize_t written;
125         struct timeval start;
126         struct timeval end;
127         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
128         int normal_delay = 2000000;
129         double sec = ((double)used_delay) / ((double)normal_delay);
130         int msec = 1000 * sec;
131         char buf[2048];
132         bool first;
133         bool updated;
134
135         torture_comment(tctx, "\nRunning test_delayed_write_update1\n");
136
137         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
138
139         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
140         torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
141                                      "Failed to open %s", fname));
142
143         memset(buf, 'x', 2048);
144         written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
145
146         /* 3 second delay to ensure we get past any 2 second time
147            granularity (older systems may have that) */
148         smb_msleep(3 * msec);
149
150         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
151         finfo1.all_info.in.file.fnum = fnum1;
152         finfo2 = finfo1;
153         finfo3 = finfo1;
154         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
155         pinfo4.all_info.in.file.path = fname;
156
157         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
158
159         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
160
161         torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
162                                  "file size not as expected after write(2048)");
163
164         torture_comment(tctx, "Initial write time %s\n",
165                         nt_time_string(tctx, finfo1.all_info.out.write_time));
166
167         /* 3 second delay to ensure we get past any 2 second time
168            granularity (older systems may have that) */
169         smb_msleep(3 * msec);
170
171         /* Do a zero length SMBwrite call to truncate. */
172         written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
173         torture_assert_int_equal(tctx, written, 0,
174                                  "unexpected number of bytes written");
175
176         start = timeval_current();
177         end = timeval_add(&start, (120 * sec), 0);
178         first = true;
179         updated = false;
180         while (!timeval_expired(&end)) {
181                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
182
183                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
184
185                 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 1024,
186                                          "file not truncated to expected size "
187                                          "(1024)");
188
189                 torture_comment(tctx, "write time %s\n",
190                         nt_time_string(tctx, finfo2.all_info.out.write_time));
191
192                 if (finfo1.all_info.out.write_time !=
193                     finfo2.all_info.out.write_time)
194                 {
195                         updated = true;
196                         break;
197                 }
198
199                 fflush(stdout);
200                 smb_msleep(1 * msec);
201                 first = false;
202         }
203
204         torture_assert(tctx, updated,
205                        "Server did not update write time within 120 seconds");
206
207         torture_assert(tctx, first, talloc_asprintf(tctx,
208                        "Server did not update write time immediately but only "
209                        "after %.2f seconds!", timeval_elapsed(&start)));
210
211         torture_comment(tctx, "Server updated write time immediately. Good!\n");
212
213         fflush(stdout);
214         smb_msleep(2 * msec);
215
216         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
217         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
218         torture_assert_int_equal(tctx, written, 1,
219                                  "unexpected number of bytes written");
220
221         start = timeval_current();
222         end = timeval_add(&start, (10*sec), 0);
223         while (!timeval_expired(&end)) {
224                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
225
226                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
227
228                 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 1024,
229                                          "file not truncated to expected size "
230                                          "(1024)");
231
232                 torture_comment(tctx, "write time %s\n",
233                         nt_time_string(tctx, finfo3.all_info.out.write_time));
234
235                 torture_assert_u64_equal(tctx,
236                                          finfo3.all_info.out.write_time,
237                                          finfo2.all_info.out.write_time,
238                                          talloc_asprintf(tctx,
239                                                 "Server updated write time "
240                                                 "after %.2f seconds (wrong!)",
241                                                 timeval_elapsed(&start)));
242
243                 fflush(stdout);
244                 smb_msleep(1 * msec);
245         }
246
247         torture_comment(tctx, "Server did not update write time within 10 "
248                         "seconds. Good!\n");
249
250         fflush(stdout);
251         smb_msleep(2 * msec);
252
253         /* the close should trigger an write time update */
254         smbcli_close(cli->tree, fnum1);
255         fnum1 = -1;
256
257         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
258         torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
259
260         torture_assert_u64_not_equal(tctx,
261                                      pinfo4.all_info.out.write_time,
262                                      finfo3.all_info.out.write_time,
263                                      "Server did not update write time on "
264                                      "close (wrong!)");
265         torture_assert(tctx,
266                 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
267                 "Server updated write time on close, but to an earlier point "
268                 "in time");
269
270         torture_comment(tctx, "Server updated write time on close (correct)\n");
271
272         if (fnum1 != -1)
273                 smbcli_close(cli->tree, fnum1);
274         smbcli_unlink(cli->tree, fname);
275         smbcli_deltree(cli->tree, BASEDIR);
276
277         return ret;
278 }
279
280 /* Updating with a SMBwrite of zero length
281  * changes the write time immediately - even on expand. */
282
283 static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
284 {
285         union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
286         const char *fname = BASEDIR "\\torture_file1a.txt";
287         NTSTATUS status;
288         int fnum1 = -1;
289         bool ret = true;
290         ssize_t written;
291         struct timeval start;
292         struct timeval end;
293         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
294         int normal_delay = 2000000;
295         double sec = ((double)used_delay) / ((double)normal_delay);
296         int msec = 1000 * sec;
297         char buf[2048];
298         bool first;
299         bool updated;
300
301         torture_comment(tctx, "\nRunning test_delayed_write_update1a\n");
302
303         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
304
305         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
306         torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
307                                      "Failed to open %s", fname));
308
309         memset(buf, 'x', 2048);
310         written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
311
312         /* 3 second delay to ensure we get past any 2 second time
313            granularity (older systems may have that) */
314         smb_msleep(3 * msec);
315
316         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
317         finfo1.all_info.in.file.fnum = fnum1;
318         finfo2 = finfo1;
319         finfo3 = finfo1;
320         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
321         pinfo4.all_info.in.file.path = fname;
322
323         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
324
325         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
326
327         torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
328                                  "file size not as expected after write(2048)");
329
330         torture_comment(tctx, "Initial write time %s\n",
331                         nt_time_string(tctx, finfo1.all_info.out.write_time));
332
333         /* Do a zero length SMBwrite call to truncate. */
334         written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
335
336         torture_assert_int_equal(tctx, written, 0,
337                                  "unexpected number of bytes written");
338
339         start = timeval_current();
340         end = timeval_add(&start, (120*sec), 0);
341         first = true;
342         updated = false;
343         while (!timeval_expired(&end)) {
344                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
345
346                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
347
348                 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
349                                          "file not truncated to expected size "
350                                          "(10240)");
351
352                 torture_comment(tctx, "write time %s\n",
353                         nt_time_string(tctx, finfo2.all_info.out.write_time));
354
355                 if (finfo1.all_info.out.write_time !=
356                     finfo2.all_info.out.write_time)
357                 {
358                         updated = true;
359                         break;
360                 }
361
362                 fflush(stdout);
363                 smb_msleep(1 * msec);
364                 first = false;
365         }
366
367         torture_assert(tctx, updated,
368                        "Server did not update write time within 120 seconds");
369
370         torture_assert(tctx, first, talloc_asprintf(tctx,
371                        "Server did not update write time immediately but only "
372                        "after %.2f seconds!", timeval_elapsed(&start)));
373
374         torture_comment(tctx, "Server updated write time immediately. Good!\n");
375
376         fflush(stdout);
377         smb_msleep(2 * msec);
378
379         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
380         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
381
382         torture_assert_int_equal(tctx, written, 1,
383                                  "unexpected number of bytes written");
384
385         start = timeval_current();
386         end = timeval_add(&start, (10*sec), 0);
387         while (!timeval_expired(&end)) {
388                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
389
390                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
391
392                 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
393                                          "file not truncated to expected size "
394                                          "(10240)");
395
396                 torture_comment(tctx, "write time %s\n",
397                         nt_time_string(tctx, finfo3.all_info.out.write_time));
398
399                 torture_assert_u64_equal(tctx,
400                                          finfo3.all_info.out.write_time,
401                                          finfo2.all_info.out.write_time,
402                                          talloc_asprintf(tctx,
403                                                 "Server updated write time "
404                                                 "after %.2f seconds (wrong!)",
405                                                 timeval_elapsed(&start)));
406
407                 fflush(stdout);
408                 smb_msleep(1 * msec);
409         }
410
411         torture_comment(tctx, "Server did not update write time within 10 "
412                         "seconds. Good!\n");
413
414         /* the close should trigger an write time update */
415         smbcli_close(cli->tree, fnum1);
416         fnum1 = -1;
417
418         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
419         torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
420
421         torture_assert_u64_not_equal(tctx,
422                                      pinfo4.all_info.out.write_time,
423                                      finfo3.all_info.out.write_time,
424                                      "Server did not update write time on "
425                                      "close (wrong!)");
426         torture_assert(tctx,
427                 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
428                 "Server updated write time on close, but to an earlier point "
429                 "in time");
430
431         torture_comment(tctx, "Server updated write time on close (correct)\n");
432
433         if (fnum1 != -1)
434                 smbcli_close(cli->tree, fnum1);
435         smbcli_unlink(cli->tree, fname);
436         smbcli_deltree(cli->tree, BASEDIR);
437
438         return ret;
439 }
440
441 /* Updating with a SET_FILE_END_OF_FILE_INFO
442  * changes the write time immediately - even on expand. */
443
444 static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
445 {
446         union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
447         const char *fname = BASEDIR "\\torture_file1b.txt";
448         NTSTATUS status;
449         int fnum1 = -1;
450         bool ret = true;
451         ssize_t written;
452         struct timeval start;
453         struct timeval end;
454         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
455         int normal_delay = 2000000;
456         double sec = ((double)used_delay) / ((double)normal_delay);
457         int msec = 1000 * sec;
458         char buf[2048];
459
460         torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
461
462         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
463
464         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
465         torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
466                                      "Failed to open %s", fname));
467
468         memset(buf, 'x', 2048);
469         written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
470
471         /* 3 second delay to ensure we get past any 2 second time
472            granularity (older systems may have that) */
473         smb_msleep(3 * msec);
474
475         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
476         finfo1.all_info.in.file.fnum = fnum1;
477         finfo2 = finfo1;
478         finfo3 = finfo1;
479         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
480         pinfo4.all_info.in.file.path = fname;
481
482         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
483
484         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
485
486         torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
487                                  "file size not as expected after write(2048)");
488
489         torture_comment(tctx, "Initial write time %s\n",
490                 nt_time_string(tctx, finfo1.all_info.out.write_time));
491
492         /* Do a SET_END_OF_FILE_INFO call to truncate. */
493         status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
494
495         torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
496
497         start = timeval_current();
498         end = timeval_add(&start, (120*sec), 0);
499         while (!timeval_expired(&end)) {
500                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
501
502                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
503
504                 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
505                                          "file not truncated to expected size "
506                                          "(10240)");
507
508                 torture_comment(tctx, "write time %s\n",
509                         nt_time_string(tctx, finfo2.all_info.out.write_time));
510                 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
511                         double diff = timeval_elapsed(&start);
512                         if (diff > (0.25 * (used_delay / (double)1000000))) {
513                                 torture_result(tctx, TORTURE_FAIL, 
514                                         "After SET_END_OF_FILE truncate "
515                                         "server updated write_time after %.2f seconds"
516                                         "(write time update delay == %.2f)(wrong!)",
517                                         diff, used_delay / (double)1000000);
518                                 ret = false;
519                                 break;
520                         }
521
522                         torture_comment(tctx, "After SET_END_OF_FILE truncate "
523                                         "server updated write_time after %.2f seconds"
524                                         "(write time update delay == %.2f)(correct)\n",
525                                         diff, used_delay / (double)1000000);
526                         break;
527                 }
528                 fflush(stdout);
529                 smb_msleep(1 * msec);
530         }
531
532         torture_assert_u64_not_equal(tctx,
533                                      finfo2.all_info.out.write_time,
534                                      finfo1.all_info.out.write_time,
535                                      "Server did not update write time");
536
537         fflush(stdout);
538         smb_msleep(2 * msec);
539
540         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
541         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
542
543         torture_assert_int_equal(tctx, written, 1,
544                                  "unexpected number of bytes written");
545
546         start = timeval_current();
547         end = timeval_add(&start, (10*sec), 0);
548         while (!timeval_expired(&end)) {
549                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
550
551                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
552
553                 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
554                                          "file not truncated to expected size "
555                                          "(10240)");
556
557                 torture_comment(tctx, "write time %s\n",
558                         nt_time_string(tctx, finfo3.all_info.out.write_time));
559
560                 torture_assert_u64_equal(tctx,
561                                          finfo3.all_info.out.write_time,
562                                          finfo2.all_info.out.write_time,
563                                          talloc_asprintf(tctx,
564                                                 "Server updated write time "
565                                                 "after %.2f seconds (wrong!)",
566                                                 timeval_elapsed(&start)));
567
568                 fflush(stdout);
569                 smb_msleep(1 * msec);
570         }
571
572         torture_comment(tctx, "Server did not update write time within 10 "
573                         "seconds. Good!\n");
574
575         /* the close should trigger an write time update */
576         smbcli_close(cli->tree, fnum1);
577         fnum1 = -1;
578
579         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
580         torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
581
582         torture_assert_u64_not_equal(tctx,
583                                      pinfo4.all_info.out.write_time,
584                                      finfo3.all_info.out.write_time,
585                                      "Server did not update write time on "
586                                      "close (wrong!)");
587         torture_assert(tctx,
588                 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
589                 "Server updated write time on close, but to an earlier point "
590                 "in time");
591
592         torture_comment(tctx, "Server updated write time on close (correct)\n");
593
594         if (fnum1 != -1)
595                 smbcli_close(cli->tree, fnum1);
596         smbcli_unlink(cli->tree, fname);
597         smbcli_deltree(cli->tree, BASEDIR);
598
599         return ret;
600 }
601
602 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
603
604 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
605 {
606         union smb_setfileinfo parms;
607         union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
608         const char *fname = BASEDIR "\\torture_file1c.txt";
609         NTSTATUS status;
610         int fnum1 = -1;
611         bool ret = true;
612         ssize_t written;
613         struct timeval start;
614         struct timeval end;
615         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
616         int normal_delay = 2000000;
617         double sec = ((double)used_delay) / ((double)normal_delay);
618         int msec = 1000 * sec;
619         char buf[2048];
620
621         torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
622
623         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
624
625         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
626         if (fnum1 == -1) {
627                 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
628                 return false;
629         }
630
631         memset(buf, 'x', 2048);
632         written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
633
634         /* 3 second delay to ensure we get past any 2 second time
635            granularity (older systems may have that) */
636         smb_msleep(3 * msec);
637
638         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
639         finfo1.all_info.in.file.fnum = fnum1;
640         finfo2 = finfo1;
641         finfo3 = finfo1;
642         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
643         pinfo4.all_info.in.file.path = fname;
644
645         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
646
647         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
648
649         torture_comment(tctx, "Initial write time %s\n",
650                nt_time_string(tctx, finfo1.all_info.out.write_time));
651
652         /* Do a SET_ALLOCATION_SIZE call to truncate. */
653         parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
654         parms.allocation_info.in.file.fnum = fnum1;
655         parms.allocation_info.in.alloc_size = 0;
656
657         status = smb_raw_setfileinfo(cli->tree, &parms);
658
659         torture_assert_ntstatus_ok(tctx, status, 
660                                                            "RAW_SFILEINFO_ALLOCATION_INFO failed");
661
662         start = timeval_current();
663         end = timeval_add(&start, (120*sec), 0);
664         while (!timeval_expired(&end)) {
665                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
666
667                 if (!NT_STATUS_IS_OK(status)) {
668                         torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s", 
669                                                    nt_errstr(status));
670                         ret = false;
671                         break;
672                 }
673
674                 if (finfo2.all_info.out.size != 0) {
675                         torture_result(tctx, TORTURE_FAIL, 
676                                                    "file not truncated (size = %u, should be 10240)",
677                                 (unsigned int)finfo2.all_info.out.size);
678                         ret = false;
679                         break;
680                 }
681
682                 torture_comment(tctx, "write time %s\n",
683                        nt_time_string(tctx, finfo2.all_info.out.write_time));
684                 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
685                         double diff = timeval_elapsed(&start);
686                         if (diff > (0.25 * (used_delay / (double)1000000))) {
687                                 torture_result(tctx, TORTURE_FAIL, "After SET_ALLOCATION_INFO truncate "
688                                         "server updated write_time after %.2f seconds"
689                                         "(write time update delay == %.2f)(wrong!)\n",
690                                         diff, used_delay / (double)1000000);
691                                 ret = false;
692                                 break;
693                         }
694
695                         torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
696                                         "server updated write_time after %.2f seconds"
697                                         "(write time update delay == %.2f)(correct)\n",
698                                         diff, used_delay / (double)1000000);
699                         break;
700                 }
701                 fflush(stdout);
702                 smb_msleep(1 * msec);
703         }
704
705         if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
706                 torture_result(tctx, TORTURE_FAIL, 
707                                            "Server did not update write time (wrong!)");
708                 ret = false;
709         }
710
711         fflush(stdout);
712         smb_msleep(2 * msec);
713
714         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
715         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
716         torture_assert_int_equal(tctx, written, 1, 
717                                                          "Unexpected number of bytes written");
718
719         start = timeval_current();
720         end = timeval_add(&start, (10*sec), 0);
721         while (!timeval_expired(&end)) {
722                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
723
724                 if (!NT_STATUS_IS_OK(status)) {
725                         torture_result(tctx, TORTURE_FAIL, "fileinfo failed: %s", 
726                                                    nt_errstr(status));
727                         ret = false;
728                         break;
729                 }
730
731                 if (finfo3.all_info.out.size != 1) {
732                         torture_result(tctx, TORTURE_FAIL, "file not expanded");
733                         ret = false;
734                         break;
735                 }
736
737                 torture_comment(tctx, "write time %s\n",
738                        nt_time_string(tctx, finfo3.all_info.out.write_time));
739                 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
740                         double diff = timeval_elapsed(&start);
741
742                         torture_comment(tctx, "server updated write_time after %.2f seconds"
743                                         "(write time update delay == %.2f)(wrong)\n",
744                                         diff, used_delay / (double)1000000);
745                         break;
746                 }
747                 fflush(stdout);
748                 smb_msleep(1 * msec);
749         }
750
751         if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
752                 torture_result(tctx, TORTURE_FAIL, 
753                                            "Server updated write time (wrong!)");
754                 ret = false;
755         }
756
757         /* the close should trigger an write time update */
758         smbcli_close(cli->tree, fnum1);
759         fnum1 = -1;
760
761         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
762         torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
763
764         if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
765                 torture_result(tctx, TORTURE_FAIL, "Server did not update write time on close (wrong!)\n");
766                 ret = false;
767         } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
768                 torture_comment(tctx, "Server updated write time on close (correct)\n");
769         }
770
771         if (fnum1 != -1)
772                 smbcli_close(cli->tree, fnum1);
773         smbcli_unlink(cli->tree, fname);
774         smbcli_deltree(cli->tree, BASEDIR);
775
776         return ret;
777 }
778
779 /*
780  * Do as above, but using 2 connections.
781  */
782
783 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli, 
784                                                                            struct smbcli_state *cli2)
785 {
786         union smb_fileinfo finfo1, finfo2;
787         const char *fname = BASEDIR "\\torture_file.txt";
788         NTSTATUS status;
789         int fnum1 = -1;
790         int fnum2 = -1;
791         bool ret = true;
792         ssize_t written;
793         struct timeval start;
794         struct timeval end;
795         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
796         int normal_delay = 2000000;
797         double sec = ((double)used_delay) / ((double)normal_delay);
798         int msec = 1000 * sec;
799         union smb_flush flsh;
800
801         torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
802
803         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
804
805         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
806         if (fnum1 == -1) {
807                 torture_comment(tctx, "Failed to open %s\n", fname);
808                 return false;
809         }
810
811         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
812         finfo1.basic_info.in.file.fnum = fnum1;
813         finfo2 = finfo1;
814
815         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
816
817         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
818         
819         torture_comment(tctx, "Initial write time %s\n", 
820                nt_time_string(tctx, finfo1.basic_info.out.write_time));
821
822         /* 3 second delay to ensure we get past any 2 second time
823            granularity (older systems may have that) */
824         smb_msleep(3 * msec);
825
826         {
827                 /* Try using setfileinfo instead of write to update write time. */
828                 union smb_setfileinfo sfinfo;
829                 time_t t_set = time(NULL);
830                 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
831                 sfinfo.basic_info.in.file.fnum = fnum1;
832                 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
833                 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
834
835                 /* I tried this with both + and - ve to see if it makes a different.
836                    It doesn't - once the filetime is set via setfileinfo it stays that way. */
837 #if 1
838                 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
839 #else
840                 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
841 #endif
842                 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
843                 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
844
845                 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
846
847                 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
848         }
849
850         finfo2.basic_info.in.file.path = fname;
851         
852         status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
853
854         if (!NT_STATUS_IS_OK(status)) {
855                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
856                 return false;
857         }
858         torture_comment(tctx, "write time %s\n",
859                nt_time_string(tctx, finfo2.basic_info.out.write_time));
860
861         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
862                 torture_comment(tctx, "Server updated write_time (correct)\n");
863         } else {
864                 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
865                 ret = false;
866         }
867
868         /* Now try a write to see if the write time gets reset. */
869
870         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
871         finfo1.basic_info.in.file.fnum = fnum1;
872         finfo2 = finfo1;
873
874         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
875
876         if (!NT_STATUS_IS_OK(status)) {
877                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
878                 return false;
879         }
880         
881         torture_comment(tctx, "Modified write time %s\n", 
882                nt_time_string(tctx, finfo1.basic_info.out.write_time));
883
884
885         torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
886
887         written =  smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
888
889         if (written != 10) {
890                 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
891                        (int)written, __location__);
892                 return false;
893         }
894
895         /* Just to prove to tridge that the an smbflush has no effect on
896            the write time :-). The setfileinfo IS STICKY. JRA. */
897
898         torture_comment(tctx, "Doing flush after write\n");
899
900         flsh.flush.level        = RAW_FLUSH_FLUSH;
901         flsh.flush.in.file.fnum = fnum1;
902         status = smb_raw_flush(cli->tree, &flsh);
903         if (!NT_STATUS_IS_OK(status)) {
904                 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
905                 return false;
906         }
907
908         /* Once the time was set using setfileinfo then it stays set - writes
909            don't have any effect. But make sure. */
910         start = timeval_current();
911         end = timeval_add(&start, (15*sec), 0);
912         while (!timeval_expired(&end)) {
913                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
914
915                 if (!NT_STATUS_IS_OK(status)) {
916                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
917                         ret = false;
918                         break;
919                 }
920                 torture_comment(tctx, "write time %s\n", 
921                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
922                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
923                         double diff = timeval_elapsed(&start);
924                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
925                                         "(wrong!)\n",
926                                         diff);
927                         ret = false;
928                         break;
929                 }
930                 fflush(stdout);
931                 smb_msleep(1 * msec);
932         }
933         
934         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
935                 torture_comment(tctx, "Server did not update write time (correct)\n");
936         }
937
938         fflush(stdout);
939         smb_msleep(2 * msec);
940
941         fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
942         if (fnum2 == -1) {
943                 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
944                 return false;
945         }
946         
947         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");
948
949         written =  smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
950
951         if (written != 10) {
952                 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
953                        (int)written, __location__);
954                 return false;
955         }
956
957         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
958
959         if (!NT_STATUS_IS_OK(status)) {
960                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
961                 return false;
962         }
963         torture_comment(tctx, "write time %s\n", 
964                nt_time_string(tctx, finfo2.basic_info.out.write_time));
965         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
966                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
967                 ret = false;
968         }
969
970         torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
971         smbcli_close(cli->tree, fnum1);
972         fnum1 = -1;
973
974         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");
975
976         written =  smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
977
978         if (written != 10) {
979                 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
980                        (int)written, __location__);
981                 return false;
982         }
983
984         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
985         finfo1.basic_info.in.file.fnum = fnum2;
986         finfo2 = finfo1;
987         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
988
989         if (!NT_STATUS_IS_OK(status)) {
990                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
991                 return false;
992         }
993         torture_comment(tctx, "write time %s\n", 
994                nt_time_string(tctx, finfo2.basic_info.out.write_time));
995         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
996                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
997                 ret = false;
998         }
999
1000         /* Once the time was set using setfileinfo then it stays set - writes
1001            don't have any effect. But make sure. */
1002         start = timeval_current();
1003         end = timeval_add(&start, (15*sec), 0);
1004         while (!timeval_expired(&end)) {
1005                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1006
1007                 if (!NT_STATUS_IS_OK(status)) {
1008                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1009                         ret = false;
1010                         break;
1011                 }
1012                 torture_comment(tctx, "write time %s\n", 
1013                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
1014                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1015                         double diff = timeval_elapsed(&start);
1016                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1017                                         "(wrong!)\n",
1018                                         diff);
1019                         ret = false;
1020                         break;
1021                 }
1022                 fflush(stdout);
1023                 smb_msleep(1 * msec);
1024         }
1025         
1026         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1027                 torture_comment(tctx, "Server did not update write time (correct)\n");
1028         }
1029
1030         torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1031
1032         smbcli_close(cli->tree, fnum2);
1033         fnum2 = -1;
1034
1035         fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1036         if (fnum1 == -1) {
1037                 torture_comment(tctx, "Failed to open %s\n", fname);
1038                 return false;
1039         }
1040
1041         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1042         finfo1.basic_info.in.file.fnum = fnum1;
1043         finfo2 = finfo1;
1044
1045         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1046
1047         if (!NT_STATUS_IS_OK(status)) {
1048                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1049                 return false;
1050         }
1051         
1052         torture_comment(tctx, "Second open initial write time %s\n", 
1053                nt_time_string(tctx, finfo1.basic_info.out.write_time));
1054
1055         smb_msleep(10 * msec);
1056         torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1057
1058         written =  smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1059
1060         if (written != 10) {
1061                 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
1062                        (int)written, __location__);
1063                 return false;
1064         }
1065
1066         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1067         finfo1.basic_info.in.file.fnum = fnum1;
1068         finfo2 = finfo1;
1069         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1070
1071         if (!NT_STATUS_IS_OK(status)) {
1072                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1073                 return false;
1074         }
1075         torture_comment(tctx, "write time %s\n", 
1076                nt_time_string(tctx, finfo2.basic_info.out.write_time));
1077         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1078                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
1079                 ret = false;
1080         }
1081
1082         /* Now the write time should be updated again */
1083         start = timeval_current();
1084         end = timeval_add(&start, (15*sec), 0);
1085         while (!timeval_expired(&end)) {
1086                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1087
1088                 if (!NT_STATUS_IS_OK(status)) {
1089                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1090                         ret = false;
1091                         break;
1092                 }
1093                 torture_comment(tctx, "write time %s\n", 
1094                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
1095                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1096                         double diff = timeval_elapsed(&start);
1097                         if (diff < (used_delay / (double)1000000)) {
1098                                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1099                                                 "(expected > %.2f) (wrong!)\n",
1100                                                 diff, used_delay / (double)1000000);
1101                                 ret = false;
1102                                 break;
1103                         }
1104
1105                         torture_comment(tctx, "Server updated write_time after %.2f seconds"
1106                                         "(correct)\n",
1107                                         diff);
1108                         break;
1109                 }
1110                 fflush(stdout);
1111                 smb_msleep(1*msec);
1112         }
1113         
1114         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1115                 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
1116                 ret = false;
1117         }
1118
1119
1120         /* One more test to do. We should read the filetime via findfirst on the
1121            second connection to ensure it's the same. This is very easy for a Windows
1122            server but a bastard to get right on a POSIX server. JRA. */
1123
1124         if (fnum1 != -1)
1125                 smbcli_close(cli->tree, fnum1);
1126         smbcli_unlink(cli->tree, fname);
1127         smbcli_deltree(cli->tree, BASEDIR);
1128
1129         return ret;
1130 }
1131
1132
1133 /* Windows does obviously not update the stat info during a write call. I
1134  * *think* this is the problem causing a spurious Excel 2003 on XP error
1135  * message when saving a file. Excel does a setfileinfo, writes, and then does
1136  * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1137  * that the file might have been changed in between. What i've been able to
1138  * trace down is that this happens if the getpathinfo after the write shows a
1139  * different last write time than the setfileinfo showed. This is really
1140  * nasty....
1141  */
1142
1143 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli, 
1144                                                                    struct smbcli_state *cli2)
1145 {
1146         union smb_fileinfo finfo1, finfo2;
1147         const char *fname = BASEDIR "\\torture_file.txt";
1148         NTSTATUS status;
1149         int fnum1 = -1;
1150         int fnum2;
1151         bool ret = true;
1152         ssize_t written;
1153         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1154         int normal_delay = 2000000;
1155         double sec = ((double)used_delay) / ((double)normal_delay);
1156         int msec = 1000 * sec;
1157
1158         torture_comment(tctx, "\nRunning test_finfo_after_write\n");
1159
1160         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1161
1162         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1163         if (fnum1 == -1) {
1164                 ret = false;
1165                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1166                 goto done;
1167         }
1168
1169         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1170         finfo1.basic_info.in.file.fnum = fnum1;
1171
1172         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1173
1174         if (!NT_STATUS_IS_OK(status)) {
1175                 ret = false;
1176                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1177                 goto done;
1178         }
1179
1180         smb_msleep(1 * msec);
1181
1182         written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1183
1184         if (written != 1) {
1185                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1186                 ret = false;
1187                 goto done;
1188         }
1189
1190         fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1191         if (fnum2 == -1) {
1192                 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s", 
1193                        smbcli_errstr(cli2->tree));
1194                 ret = false;
1195                 goto done;
1196         }
1197
1198         written =  smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1199
1200         if (written != 1) {
1201                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", 
1202                        (int)written);
1203                 ret = false;
1204                 goto done;
1205         }
1206
1207         finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1208         finfo2.basic_info.in.file.path = fname;
1209
1210         status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1211
1212         if (!NT_STATUS_IS_OK(status)) {
1213                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", 
1214                           nt_errstr(status));
1215                 ret = false;
1216                 goto done;
1217         }
1218
1219         if (finfo1.basic_info.out.create_time !=
1220             finfo2.basic_info.out.create_time) {
1221                 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1222                 ret = false;
1223                 goto done;
1224         }
1225
1226         if (finfo1.basic_info.out.access_time !=
1227             finfo2.basic_info.out.access_time) {
1228                 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1229                 ret = false;
1230                 goto done;
1231         }
1232
1233         if (finfo1.basic_info.out.write_time !=
1234             finfo2.basic_info.out.write_time) {
1235                 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1236                                            "write time conn 1 = %s, conn 2 = %s", 
1237                        nt_time_string(tctx, finfo1.basic_info.out.write_time),
1238                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
1239                 ret = false;
1240                 goto done;
1241         }
1242
1243         if (finfo1.basic_info.out.change_time !=
1244             finfo2.basic_info.out.change_time) {
1245                 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1246                 ret = false;
1247                 goto done;
1248         }
1249
1250         /* One of the two following calls updates the qpathinfo. */
1251
1252         /* If you had skipped the smbcli_write on fnum2, it would
1253          * *not* have updated the stat on disk */
1254
1255         smbcli_close(cli2->tree, fnum2);
1256         cli2 = NULL;
1257
1258         /* This call is only for the people looking at ethereal :-) */
1259         finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1260         finfo2.basic_info.in.file.path = fname;
1261
1262         status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1263
1264         if (!NT_STATUS_IS_OK(status)) {
1265                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1266                 ret = false;
1267                 goto done;
1268         }
1269
1270  done:
1271         if (fnum1 != -1)
1272                 smbcli_close(cli->tree, fnum1);
1273         smbcli_unlink(cli->tree, fname);
1274         smbcli_deltree(cli->tree, BASEDIR);
1275
1276         return ret;
1277 }
1278
1279 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1280         uint64_t r = 10*1000*1000; \
1281         NTTIME g = (given).basic_info.out.write_time; \
1282         NTTIME gr = (g / r) * r; \
1283         NTTIME c = (correct).basic_info.out.write_time; \
1284         NTTIME cr = (c / r) * r; \
1285         bool strict = torture_setting_bool(tctx, "strict mode", false); \
1286         bool err = false; \
1287         if (strict && (g cmp c)) { \
1288                 err = true; \
1289         } else if ((g cmp c) && (gr cmp cr)) { \
1290                 /* handle filesystem without high resolution timestamps */ \
1291                 err = true; \
1292         } \
1293         if (err) { \
1294                 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1295                                 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1296                                 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1297                 ret = false; \
1298                 goto done; \
1299         } \
1300 } while (0)
1301 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1302         COMPARE_WRITE_TIME_CMP(given,correct,!=)
1303 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1304         COMPARE_WRITE_TIME_CMP(given,correct,<=)
1305 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1306         COMPARE_WRITE_TIME_CMP(given,correct,>=)
1307
1308 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1309         NTTIME g = (given).basic_info.out.access_time; \
1310         NTTIME c = (correct).basic_info.out.access_time; \
1311         if (g cmp c) { \
1312                 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1313                                 #given, nt_time_string(tctx, g), \
1314                                 #cmp, #correct, nt_time_string(tctx, c)); \
1315                 ret = false; \
1316                 goto done; \
1317         } \
1318 } while (0)
1319 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1320         COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1321
1322 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1323         COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1324         COMPARE_WRITE_TIME_EQUAL(given,correct); \
1325 } while (0)
1326
1327 #define GET_INFO_FILE(finfo) do { \
1328         NTSTATUS _status; \
1329         _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1330         if (!NT_STATUS_IS_OK(_status)) { \
1331                 ret = false; \
1332                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1333                                nt_errstr(_status)); \
1334                 goto done; \
1335         } \
1336         torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1337                         nt_time_string(tctx, finfo.basic_info.out.access_time), \
1338                         nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1339 } while (0)
1340 #define GET_INFO_FILE2(finfo) do { \
1341         NTSTATUS _status; \
1342         _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
1343         if (!NT_STATUS_IS_OK(_status)) { \
1344                 ret = false; \
1345                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1346                                nt_errstr(_status)); \
1347                 goto done; \
1348         } \
1349         torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1350                         nt_time_string(tctx, finfo.basic_info.out.access_time), \
1351                         nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1352 } while (0)
1353 #define GET_INFO_PATH(pinfo) do { \
1354         NTSTATUS _status; \
1355         _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1356         if (!NT_STATUS_IS_OK(_status)) { \
1357                 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1358                                nt_errstr(_status)); \
1359                 ret = false; \
1360                 goto done; \
1361         } \
1362         torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1363                         nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1364                         nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1365 } while (0)
1366 #define GET_INFO_BOTH(finfo,pinfo) do { \
1367         GET_INFO_FILE(finfo); \
1368         GET_INFO_PATH(pinfo); \
1369         COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1370 } while (0)
1371
1372 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1373         NTSTATUS _status; \
1374         union smb_setfileinfo sfinfo; \
1375         sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1376         sfinfo.basic_info.in.file.fnum = tfnum; \
1377         sfinfo.basic_info.in.create_time = 0; \
1378         sfinfo.basic_info.in.access_time = 0; \
1379         unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1380         sfinfo.basic_info.in.change_time = 0; \
1381         sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1382         _status = smb_raw_setfileinfo(tree, &sfinfo); \
1383         if (!NT_STATUS_IS_OK(_status)) { \
1384                 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1385                                nt_errstr(_status)); \
1386                 ret = false; \
1387                 goto done; \
1388         } \
1389 } while (0)
1390 #define SET_INFO_FILE(finfo, wrtime) \
1391         SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1392
1393 #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
1394         NTSTATUS _status; \
1395         union smb_setfileinfo sfinfo; \
1396         sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1397         sfinfo.basic_info.in.file.fnum = tfnum; \
1398         sfinfo.basic_info.in.create_time = 0; \
1399         sfinfo.basic_info.in.access_time = 0; \
1400         unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1401         sfinfo.basic_info.in.write_time += (ns); \
1402         sfinfo.basic_info.in.change_time = 0; \
1403         sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1404         _status = smb_raw_setfileinfo(tree, &sfinfo); \
1405         if (!NT_STATUS_IS_OK(_status)) { \
1406                 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1407                                nt_errstr(_status)); \
1408                 ret = false; \
1409                 goto done; \
1410         } \
1411 } while (0)
1412
1413 static bool test_delayed_write_update3(struct torture_context *tctx,
1414                                        struct smbcli_state *cli,
1415                                        struct smbcli_state *cli2)
1416 {
1417         union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1418         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1419         const char *fname = BASEDIR "\\torture_file3.txt";
1420         int fnum1 = -1;
1421         bool ret = true;
1422         ssize_t written;
1423         struct timeval start;
1424         struct timeval end;
1425         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1426         int normal_delay = 2000000;
1427         double sec = ((double)used_delay) / ((double)normal_delay);
1428         int msec = 1000 * sec;
1429
1430         torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
1431
1432         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1433
1434         torture_comment(tctx, "Open the file handle\n");
1435         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1436         if (fnum1 == -1) {
1437                 ret = false;
1438                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1439                 goto done;
1440         }
1441
1442         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1443         finfo0.basic_info.in.file.fnum = fnum1;
1444         finfo1 = finfo0;
1445         finfo2 = finfo0;
1446         finfo3 = finfo0;
1447         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1448         pinfo0.basic_info.in.file.path = fname;
1449         pinfo1 = pinfo0;
1450         pinfo2 = pinfo0;
1451         pinfo3 = pinfo0;
1452         pinfo4 = pinfo0;
1453
1454         /* get the initial times */
1455         GET_INFO_BOTH(finfo0,pinfo0);
1456
1457         /*
1458          * make sure the write time is updated 2 seconds later
1459          * calcuated from the first write
1460          * (but expect upto 5 seconds extra time for a busy server)
1461          */
1462         start = timeval_current();
1463         end = timeval_add(&start, 7 * sec, 0);
1464         while (!timeval_expired(&end)) {
1465                 /* do a write */
1466                 torture_comment(tctx, "Do a write on the file handle\n");
1467                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1468                 if (written != 1) {
1469                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1470                         ret = false;
1471                         goto done;
1472                 }
1473                 /* get the times after the write */
1474                 GET_INFO_FILE(finfo1);
1475
1476                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1477                         double diff = timeval_elapsed(&start);
1478                         if (diff < (used_delay / (double)1000000)) {
1479                                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1480                                                 "(write time update delay == %.2f) (wrong!)\n",
1481                                                 diff, used_delay / (double)1000000);
1482                                 ret = false;
1483                                 break;
1484                         }
1485
1486                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
1487                                         "(correct)\n",
1488                                         diff);
1489                         break;
1490                 }
1491                 smb_msleep(0.5 * msec);
1492         }
1493
1494         GET_INFO_BOTH(finfo1,pinfo1);
1495         COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1496
1497         /* sure any further write doesn't update the write time */
1498         start = timeval_current();
1499         end = timeval_add(&start, 15 * sec, 0);
1500         while (!timeval_expired(&end)) {
1501                 /* do a write */
1502                 torture_comment(tctx, "Do a write on the file handle\n");
1503                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1504                 if (written != 1) {
1505                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1506                         ret = false;
1507                         goto done;
1508                 }
1509                 /* get the times after the write */
1510                 GET_INFO_BOTH(finfo2,pinfo2);
1511
1512                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1513                         double diff = timeval_elapsed(&start);
1514                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1515                                         "(wrong!)\n",
1516                                         diff);
1517                         ret = false;
1518                         break;
1519                 }
1520                 smb_msleep(1 * msec);
1521         }
1522
1523         GET_INFO_BOTH(finfo2,pinfo2);
1524         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1525         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1526                 torture_comment(tctx, "Server did not update write_time (correct)\n");
1527         }
1528
1529         /* sleep */
1530         smb_msleep(5 * msec);
1531
1532         GET_INFO_BOTH(finfo3,pinfo3);
1533         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1534
1535         /*
1536          * the close updates the write time to the time of the close
1537          * and not to the time of the last write!
1538          */
1539         torture_comment(tctx, "Close the file handle\n");
1540         smbcli_close(cli->tree, fnum1);
1541         fnum1 = -1;
1542
1543         GET_INFO_PATH(pinfo4);
1544         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1545
1546         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1547                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1548         }
1549
1550  done:
1551         if (fnum1 != -1)
1552                 smbcli_close(cli->tree, fnum1);
1553         smbcli_unlink(cli->tree, fname);
1554         smbcli_deltree(cli->tree, BASEDIR);
1555
1556         return ret;
1557 }
1558
1559 /*
1560  * Show that a truncate write always updates the write time even
1561  * if an initial write has already updated the write time.
1562  */
1563
1564 static bool test_delayed_write_update3a(struct torture_context *tctx,
1565                                         struct smbcli_state *cli,
1566                                         struct smbcli_state *cli2)
1567 {
1568         union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1569         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1570         const char *fname = BASEDIR "\\torture_file3a.txt";
1571         int fnum1 = -1;
1572         bool ret = true;
1573         ssize_t written;
1574         int i;
1575         struct timeval start;
1576         struct timeval end;
1577         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1578         int normal_delay = 2000000;
1579         double sec = ((double)used_delay) / ((double)normal_delay);
1580         int msec = 1000 * sec;
1581
1582         torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
1583
1584         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1585
1586         torture_comment(tctx, "Open the file handle\n");
1587         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1588         if (fnum1 == -1) {
1589                 ret = false;
1590                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1591                 goto done;
1592         }
1593
1594         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1595         finfo0.basic_info.in.file.fnum = fnum1;
1596         finfo1 = finfo0;
1597         finfo2 = finfo0;
1598         finfo3 = finfo0;
1599         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1600         pinfo0.basic_info.in.file.path = fname;
1601         pinfo1 = pinfo0;
1602         pinfo2 = pinfo0;
1603         pinfo3 = pinfo0;
1604         pinfo4 = pinfo0;
1605
1606         /* get the initial times */
1607         GET_INFO_BOTH(finfo0,pinfo0);
1608
1609         /*
1610          * sleep some time, to demonstrate the handling of write times
1611          * doesn't depend on the time since the open
1612          */
1613         smb_msleep(5 * msec);
1614
1615         /* get the initial times */
1616         GET_INFO_BOTH(finfo1,pinfo1);
1617         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1618
1619         /*
1620          * make sure the write time is updated 2 seconds later
1621          * calcuated from the first write
1622          * (but expect upto 5 seconds extra time for a busy server)
1623          */
1624         start = timeval_current();
1625         end = timeval_add(&start, 7 * sec, 0);
1626         while (!timeval_expired(&end)) {
1627                 /* do a write */
1628                 torture_comment(tctx, "Do a write on the file handle\n");
1629                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1630                 if (written != 1) {
1631                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1632                         ret = false;
1633                         goto done;
1634                 }
1635                 /* get the times after the write */
1636                 GET_INFO_FILE(finfo1);
1637
1638                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1639                         double diff = timeval_elapsed(&start);
1640                         if (diff < (used_delay / (double)1000000)) {
1641                                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1642                                                 "(1sec == %.2f) (wrong!)\n",
1643                                                 diff, sec);
1644                                 ret = false;
1645                                 break;
1646                         }
1647
1648                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
1649                                         "(correct)\n",
1650                                         diff);
1651                         break;
1652                 }
1653                 smb_msleep(0.5 * msec);
1654         }
1655
1656         GET_INFO_BOTH(finfo1,pinfo1);
1657         COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1658
1659         smb_msleep(3 * msec);
1660
1661         /*
1662          * demonstrate that a truncate write always
1663          * updates the write time immediately
1664          */
1665         for (i=0; i < 3; i++) {
1666                 smb_msleep(2 * msec);
1667                 /* do a write */
1668                 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1669                 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
1670                 if (written != 0) {
1671                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1672                         ret = false;
1673                         goto done;
1674                 }
1675                 /* get the times after the write */
1676                 GET_INFO_BOTH(finfo2,pinfo2);
1677                 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1678                 finfo1 = finfo2;
1679         }
1680
1681         smb_msleep(3 * msec);
1682
1683         /* sure any further write doesn't update the write time */
1684         start = timeval_current();
1685         end = timeval_add(&start, 15 * sec, 0);
1686         while (!timeval_expired(&end)) {
1687                 /* do a write */
1688                 torture_comment(tctx, "Do a write on the file handle\n");
1689                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1690                 if (written != 1) {
1691                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1692                         ret = false;
1693                         goto done;
1694                 }
1695                 /* get the times after the write */
1696                 GET_INFO_BOTH(finfo2,pinfo2);
1697
1698                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1699                         double diff = timeval_elapsed(&start);
1700                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1701                                         "(wrong!)\n",
1702                                         diff);
1703                         ret = false;
1704                         break;
1705                 }
1706                 smb_msleep(1 * msec);
1707         }
1708
1709         GET_INFO_BOTH(finfo2,pinfo2);
1710         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1711         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1712                 torture_comment(tctx, "Server did not update write_time (correct)\n");
1713         }
1714
1715         /* sleep */
1716         smb_msleep(3 * msec);
1717
1718         /* get the initial times */
1719         GET_INFO_BOTH(finfo1,pinfo1);
1720         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
1721
1722         /*
1723          * demonstrate that a truncate write always
1724          * updates the write time immediately
1725          */
1726         for (i=0; i < 3; i++) {
1727                 smb_msleep(2 * msec);
1728                 /* do a write */
1729                 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
1730                 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
1731                 if (written != 0) {
1732                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
1733                         ret = false;
1734                         goto done;
1735                 }
1736                 /* get the times after the write */
1737                 GET_INFO_BOTH(finfo2,pinfo2);
1738                 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1739                 finfo1 = finfo2;
1740         }
1741
1742         /* sleep */
1743         smb_msleep(3 * msec);
1744
1745         GET_INFO_BOTH(finfo3,pinfo3);
1746         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1747
1748         /*
1749          * the close doesn't update the write time
1750          */
1751         torture_comment(tctx, "Close the file handle\n");
1752         smbcli_close(cli->tree, fnum1);
1753         fnum1 = -1;
1754
1755         GET_INFO_PATH(pinfo4);
1756         COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
1757
1758         if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
1759                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1760         }
1761
1762  done:
1763         if (fnum1 != -1)
1764                 smbcli_close(cli->tree, fnum1);
1765         smbcli_unlink(cli->tree, fname);
1766         smbcli_deltree(cli->tree, BASEDIR);
1767
1768         return ret;
1769 }
1770
1771 /*
1772  * Show a close after write updates the write timestamp to
1773  * the close time, not the last write time.
1774  */
1775
1776 static bool test_delayed_write_update3b(struct torture_context *tctx,
1777                                         struct smbcli_state *cli,
1778                                         struct smbcli_state *cli2)
1779 {
1780         union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1781         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1782         const char *fname = BASEDIR "\\torture_file3b.txt";
1783         int fnum1 = -1;
1784         bool ret = true;
1785         ssize_t written;
1786         struct timeval start;
1787         struct timeval end;
1788         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1789         int normal_delay = 2000000;
1790         double sec = ((double)used_delay) / ((double)normal_delay);
1791         int msec = 1000 * sec;
1792
1793         torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
1794
1795         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1796
1797         torture_comment(tctx, "Open the file handle\n");
1798         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1799         if (fnum1 == -1) {
1800                 ret = false;
1801                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1802                 goto done;
1803         }
1804
1805         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1806         finfo0.basic_info.in.file.fnum = fnum1;
1807         finfo1 = finfo0;
1808         finfo2 = finfo0;
1809         finfo3 = finfo0;
1810         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1811         pinfo0.basic_info.in.file.path = fname;
1812         pinfo1 = pinfo0;
1813         pinfo2 = pinfo0;
1814         pinfo3 = pinfo0;
1815         pinfo4 = pinfo0;
1816
1817         /* get the initial times */
1818         GET_INFO_BOTH(finfo0,pinfo0);
1819
1820         /*
1821          * sleep some time, to demonstrate the handling of write times
1822          * doesn't depend on the time since the open
1823          */
1824         smb_msleep(5 * msec);
1825
1826         /* get the initial times */
1827         GET_INFO_BOTH(finfo1,pinfo1);
1828         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1829
1830         /*
1831          * make sure the write time is updated 2 seconds later
1832          * calcuated from the first write
1833          * (but expect upto 5 seconds extra time for a busy server)
1834          */
1835         start = timeval_current();
1836         end = timeval_add(&start, 7 * sec, 0);
1837         while (!timeval_expired(&end)) {
1838                 /* do a write */
1839                 torture_comment(tctx, "Do a write on the file handle\n");
1840                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1841                 if (written != 1) {
1842                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1843                         ret = false;
1844                         goto done;
1845                 }
1846                 /* get the times after the write */
1847                 GET_INFO_FILE(finfo1);
1848
1849                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1850                         double diff = timeval_elapsed(&start);
1851                         if (diff < (used_delay / (double)1000000)) {
1852                                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
1853                                                 "(expected > %.2f) (wrong!)\n",
1854                                                 diff, used_delay / (double)1000000);
1855                                 ret = false;
1856                                 break;
1857                         }
1858
1859                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
1860                                         "(write time update delay == %.2f) (correct)\n",
1861                                         diff, used_delay / (double)1000000);
1862                         break;
1863                 }
1864                 smb_msleep(0.5 * msec);
1865         }
1866
1867         GET_INFO_BOTH(finfo1,pinfo1);
1868         COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1869
1870         /* sure any further write doesn't update the write time */
1871         start = timeval_current();
1872         end = timeval_add(&start, 15 * sec, 0);
1873         while (!timeval_expired(&end)) {
1874                 /* do a write */
1875                 torture_comment(tctx, "Do a write on the file handle\n");
1876                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1877                 if (written != 1) {
1878                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1879                         ret = false;
1880                         goto done;
1881                 }
1882                 /* get the times after the write */
1883                 GET_INFO_BOTH(finfo2,pinfo2);
1884
1885                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1886                         double diff = timeval_elapsed(&start);
1887                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
1888                                         "(wrong!)\n",
1889                                         diff);
1890                         ret = false;
1891                         break;
1892                 }
1893                 smb_msleep(1 * msec);
1894         }
1895
1896         GET_INFO_BOTH(finfo2,pinfo2);
1897         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1898         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1899                 torture_comment(tctx, "Server did not update write_time (correct)\n");
1900         }
1901
1902         /* sleep */
1903         smb_msleep(5 * msec);
1904
1905         GET_INFO_BOTH(finfo3,pinfo3);
1906         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1907
1908         /*
1909          * the close updates the write time to the time of the close
1910          * and not to the time of the last write!
1911          */
1912         torture_comment(tctx, "Close the file handle\n");
1913         smbcli_close(cli->tree, fnum1);
1914         fnum1 = -1;
1915
1916         GET_INFO_PATH(pinfo4);
1917         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1918
1919         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1920                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1921         }
1922
1923  done:
1924         if (fnum1 != -1)
1925                 smbcli_close(cli->tree, fnum1);
1926         smbcli_unlink(cli->tree, fname);
1927         smbcli_deltree(cli->tree, BASEDIR);
1928
1929         return ret;
1930 }
1931
1932 /*
1933  * Check that a write after a truncate write doesn't update
1934  * the timestamp, but a truncate write after a write does.
1935  * Also prove that a close after a truncate write updates the
1936  * timestamp to current, not the time of last write.
1937  */
1938
1939 static bool test_delayed_write_update3c(struct torture_context *tctx,
1940                                         struct smbcli_state *cli,
1941                                         struct smbcli_state *cli2)
1942 {
1943         union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
1944         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
1945         const char *fname = BASEDIR "\\torture_file3c.txt";
1946         int fnum1 = -1;
1947         bool ret = true;
1948         ssize_t written;
1949         int i;
1950         struct timeval start;
1951         struct timeval end;
1952         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1953         int normal_delay = 2000000;
1954         double sec = ((double)used_delay) / ((double)normal_delay);
1955         int msec = 1000 * sec;
1956
1957         torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
1958
1959         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
1960
1961         torture_comment(tctx, "Open the file handle\n");
1962         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1963         if (fnum1 == -1) {
1964                 ret = false;
1965                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1966                 goto done;
1967         }
1968
1969         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1970         finfo0.basic_info.in.file.fnum = fnum1;
1971         finfo1 = finfo0;
1972         finfo2 = finfo0;
1973         finfo3 = finfo0;
1974         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1975         pinfo0.basic_info.in.file.path = fname;
1976         pinfo1 = pinfo0;
1977         pinfo2 = pinfo0;
1978         pinfo3 = pinfo0;
1979         pinfo4 = pinfo0;
1980
1981         /* get the initial times */
1982         GET_INFO_BOTH(finfo0,pinfo0);
1983
1984         /*
1985          * sleep some time, to demonstrate the handling of write times
1986          * doesn't depend on the time since the open
1987          */
1988         smb_msleep(5 * msec);
1989
1990         /* get the initial times */
1991         GET_INFO_BOTH(finfo1,pinfo1);
1992         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1993
1994         /*
1995          * demonstrate that a truncate write always
1996          * updates the write time immediately
1997          */
1998         for (i=0; i < 3; i++) {
1999                 smb_msleep(2 * msec);
2000                 /* do a write */
2001                 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
2002                 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2003                 if (written != 0) {
2004                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2005                         ret = false;
2006                         goto done;
2007                 }
2008                 /* get the times after the write */
2009                 GET_INFO_BOTH(finfo2,pinfo2);
2010                 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2011                 finfo1 = finfo2;
2012         }
2013
2014         start = timeval_current();
2015         end = timeval_add(&start, 7 * sec, 0);
2016         while (!timeval_expired(&end)) {
2017                 /* do a write */
2018                 torture_comment(tctx, "Do a write on the file handle\n");
2019                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2020                 if (written != 1) {
2021                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2022                         ret = false;
2023                         goto done;
2024                 }
2025                 /* get the times after the write */
2026                 GET_INFO_FILE(finfo2);
2027
2028                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2029                         double diff = timeval_elapsed(&start);
2030                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2031                                         "(wrong!)\n",
2032                                         diff);
2033                         ret = false;
2034                         break;
2035                 }
2036                 smb_msleep(1 * msec);
2037         }
2038
2039         GET_INFO_BOTH(finfo2,pinfo2);
2040         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2041         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2042                 torture_comment(tctx, "Server did not update write_time (correct)\n");
2043         }
2044
2045         /* sleep */
2046         smb_msleep(5 * msec);
2047
2048         /* get the initial times */
2049         GET_INFO_BOTH(finfo1,pinfo1);
2050         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
2051
2052         /*
2053          * demonstrate that a truncate write always
2054          * updates the write time immediately
2055          */
2056         for (i=0; i < 3; i++) {
2057                 smb_msleep(2 * msec);
2058                 /* do a write */
2059                 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
2060                 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
2061                 if (written != 0) {
2062                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
2063                         ret = false;
2064                         goto done;
2065                 }
2066                 /* get the times after the write */
2067                 GET_INFO_BOTH(finfo2,pinfo2);
2068                 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2069                 finfo1 = finfo2;
2070         }
2071
2072         /* sleep */
2073         smb_msleep(5 * msec);
2074
2075         GET_INFO_BOTH(finfo2,pinfo2);
2076         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2077
2078         /* sure any further write doesn't update the write time */
2079         start = timeval_current();
2080         end = timeval_add(&start, 15 * sec, 0);
2081         while (!timeval_expired(&end)) {
2082                 /* do a write */
2083                 torture_comment(tctx, "Do a write on the file handle\n");
2084                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2085                 if (written != 1) {
2086                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2087                         ret = false;
2088                         goto done;
2089                 }
2090                 /* get the times after the write */
2091                 GET_INFO_BOTH(finfo2,pinfo2);
2092
2093                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2094                         double diff = timeval_elapsed(&start);
2095                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2096                                         "(wrong!)\n",
2097                                         diff);
2098                         ret = false;
2099                         break;
2100                 }
2101                 smb_msleep(1 * msec);
2102         }
2103
2104         GET_INFO_BOTH(finfo2,pinfo2);
2105         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2106         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2107                 torture_comment(tctx, "Server did not update write_time (correct)\n");
2108         }
2109
2110         /* sleep */
2111         smb_msleep(5 * msec);
2112
2113         GET_INFO_BOTH(finfo3,pinfo3);
2114         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2115
2116         /*
2117          * the close updates the write time to the time of the close
2118          * and not to the time of the last write!
2119          */
2120         torture_comment(tctx, "Close the file handle\n");
2121         smbcli_close(cli->tree, fnum1);
2122         fnum1 = -1;
2123
2124         GET_INFO_PATH(pinfo4);
2125         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2126
2127         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2128                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2129         }
2130
2131  done:
2132         if (fnum1 != -1)
2133                 smbcli_close(cli->tree, fnum1);
2134         smbcli_unlink(cli->tree, fname);
2135         smbcli_deltree(cli->tree, BASEDIR);
2136
2137         return ret;
2138 }
2139
2140 /*
2141  * Show only the first write updates the timestamp, and a close
2142  * after writes updates to current (I think this is the same
2143  * as test 3b. JRA).
2144  */
2145
2146 static bool test_delayed_write_update4(struct torture_context *tctx,
2147                                        struct smbcli_state *cli,
2148                                        struct smbcli_state *cli2)
2149 {
2150         union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
2151         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
2152         const char *fname = BASEDIR "\\torture_file4.txt";
2153         int fnum1 = -1;
2154         bool ret = true;
2155         ssize_t written;
2156         struct timeval start;
2157         struct timeval end;
2158         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2159         int normal_delay = 2000000;
2160         double sec = ((double)used_delay) / ((double)normal_delay);
2161         int msec = 1000 * sec;
2162
2163         torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
2164
2165         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2166
2167         torture_comment(tctx, "Open the file handle\n");
2168         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2169         if (fnum1 == -1) {
2170                 ret = false;
2171                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2172                 goto done;
2173         }
2174
2175         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2176         finfo0.basic_info.in.file.fnum = fnum1;
2177         finfo1 = finfo0;
2178         finfo2 = finfo0;
2179         finfo3 = finfo0;
2180         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2181         pinfo0.basic_info.in.file.path = fname;
2182         pinfo1 = pinfo0;
2183         pinfo2 = pinfo0;
2184         pinfo3 = pinfo0;
2185         pinfo4 = pinfo0;
2186
2187         /* get the initial times */
2188         GET_INFO_BOTH(finfo0,pinfo0);
2189
2190         /* sleep a bit */
2191         smb_msleep(5 * msec);
2192
2193         /* do a write */
2194         torture_comment(tctx, "Do a write on the file handle\n");
2195         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2196         if (written != 1) {
2197                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2198                 ret = false;
2199                 goto done;
2200         }
2201
2202         GET_INFO_BOTH(finfo1,pinfo1);
2203         COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
2204
2205         /*
2206          * make sure the write time is updated 2 seconds later
2207          * calcuated from the first write
2208          * (but expect upto 3 seconds extra time for a busy server)
2209          */
2210         start = timeval_current();
2211         end = timeval_add(&start, 5 * sec, 0);
2212         while (!timeval_expired(&end)) {
2213                 /* get the times after the first write */
2214                 GET_INFO_FILE(finfo1);
2215
2216                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
2217                         double diff = timeval_elapsed(&start);
2218                         if (diff < (used_delay / (double)1000000)) {
2219                                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
2220                                                 "(expected > %.2f) (wrong!)\n",
2221                                                 diff, used_delay / (double)1000000);
2222                                 ret = false;
2223                                 break;
2224                         }
2225
2226                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
2227                                         "(write time update delay == %.2f) (correct)\n",
2228                                         diff, used_delay / (double)1000000);
2229                         break;
2230                 }
2231                 smb_msleep(0.5 * msec);
2232         }
2233
2234         GET_INFO_BOTH(finfo1,pinfo1);
2235         COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
2236
2237         /* sure any further write doesn't update the write time */
2238         start = timeval_current();
2239         end = timeval_add(&start, 15 * sec, 0);
2240         while (!timeval_expired(&end)) {
2241                 /* do a write */
2242                 torture_comment(tctx, "Do a write on the file handle\n");
2243                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2244                 if (written != 1) {
2245                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2246                         ret = false;
2247                         goto done;
2248                 }
2249                 /* get the times after the write */
2250                 GET_INFO_BOTH(finfo2,pinfo2);
2251
2252                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
2253                         double diff = timeval_elapsed(&start);
2254                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2255                                         "(wrong!)\n",
2256                                         diff);
2257                         ret = false;
2258                         break;
2259                 }
2260                 smb_msleep(1 * msec);
2261         }
2262
2263         GET_INFO_BOTH(finfo2,pinfo2);
2264         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
2265         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
2266                 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
2267         }
2268
2269         /* sleep */
2270         smb_msleep(5 * msec);
2271
2272         GET_INFO_BOTH(finfo3,pinfo3);
2273         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2274
2275         /*
2276          * the close updates the write time to the time of the close
2277          * and not to the time of the last write!
2278          */
2279         torture_comment(tctx, "Close the file handle\n");
2280         smbcli_close(cli->tree, fnum1);
2281         fnum1 = -1;
2282
2283         GET_INFO_PATH(pinfo4);
2284         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
2285
2286         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
2287                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2288         }
2289
2290  done:
2291         if (fnum1 != -1)
2292                 smbcli_close(cli->tree, fnum1);
2293         smbcli_unlink(cli->tree, fname);
2294         smbcli_deltree(cli->tree, BASEDIR);
2295
2296         return ret;
2297 }
2298
2299 /*
2300  * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
2301  */
2302
2303 static bool test_delayed_write_update5(struct torture_context *tctx,
2304                                        struct smbcli_state *cli,
2305                                        struct smbcli_state *cli2)
2306 {
2307         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2308         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2309         const char *fname = BASEDIR "\\torture_file5.txt";
2310         int fnum1 = -1;
2311         bool ret = true;
2312         ssize_t written;
2313         struct timeval start;
2314         struct timeval end;
2315         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2316         int normal_delay = 2000000;
2317         double sec = ((double)used_delay) / ((double)normal_delay);
2318         int msec = 1000 * sec;
2319
2320         torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
2321
2322         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2323
2324         torture_comment(tctx, "Open the file handle\n");
2325         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2326         if (fnum1 == -1) {
2327                 ret = false;
2328                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2329                 goto done;
2330         }
2331
2332         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2333         finfo0.basic_info.in.file.fnum = fnum1;
2334         finfo1 = finfo0;
2335         finfo2 = finfo0;
2336         finfo3 = finfo0;
2337         finfo4 = finfo0;
2338         finfo5 = finfo0;
2339         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2340         pinfo0.basic_info.in.file.path = fname;
2341         pinfo1 = pinfo0;
2342         pinfo2 = pinfo0;
2343         pinfo3 = pinfo0;
2344         pinfo4 = pinfo0;
2345         pinfo5 = pinfo0;
2346         pinfo6 = pinfo0;
2347
2348         /* get the initial times */
2349         GET_INFO_BOTH(finfo0,pinfo0);
2350
2351         /* do a write */
2352         torture_comment(tctx, "Do a write on the file handle\n");
2353         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2354         if (written != 1) {
2355                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2356                 ret = false;
2357                 goto done;
2358         }
2359
2360         GET_INFO_BOTH(finfo1,pinfo1);
2361         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2362
2363         torture_comment(tctx, "Set write time in the future on the file handle\n");
2364         SET_INFO_FILE(finfo0, time(NULL) + 86400);
2365         GET_INFO_BOTH(finfo2,pinfo2);
2366         COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2367
2368         torture_comment(tctx, "Set write time in the past on the file handle\n");
2369         SET_INFO_FILE(finfo0, time(NULL) - 86400);
2370         GET_INFO_BOTH(finfo2,pinfo2);
2371         COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2372
2373         /* make sure the 2 second delay from the first write are canceled */
2374         start = timeval_current();
2375         end = timeval_add(&start, 15 * sec, 0);
2376         while (!timeval_expired(&end)) {
2377
2378                 /* get the times after the first write */
2379                 GET_INFO_BOTH(finfo3,pinfo3);
2380
2381                 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2382                         double diff = timeval_elapsed(&start);
2383                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2384                                         "(wrong!)\n",
2385                                         diff);
2386                         ret = false;
2387                         break;
2388                 }
2389                 smb_msleep(1 * msec);
2390         }
2391
2392         GET_INFO_BOTH(finfo3,pinfo3);
2393         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2394         if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2395                 torture_comment(tctx, "Server did not update write_time (correct)\n");
2396         }
2397
2398         /* sure any further write doesn't update the write time */
2399         start = timeval_current();
2400         end = timeval_add(&start, 15 * sec, 0);
2401         while (!timeval_expired(&end)) {
2402                 /* do a write */
2403                 torture_comment(tctx, "Do a write on the file handle\n");
2404                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2405                 if (written != 1) {
2406                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2407                         ret = false;
2408                         goto done;
2409                 }
2410                 /* get the times after the write */
2411                 GET_INFO_BOTH(finfo4,pinfo4);
2412
2413                 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2414                         double diff = timeval_elapsed(&start);
2415                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2416                                         "(wrong!)\n",
2417                                         diff);
2418                         ret = false;
2419                         break;
2420                 }
2421                 smb_msleep(1 * msec);
2422         }
2423
2424         GET_INFO_BOTH(finfo4,pinfo4);
2425         COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2426         if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2427                 torture_comment(tctx, "Server did not update write_time (correct)\n");
2428         }
2429
2430         /* sleep */
2431         smb_msleep(5 * msec);
2432
2433         GET_INFO_BOTH(finfo5,pinfo5);
2434         COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2435
2436         /*
2437          * the close doesn't update the write time
2438          */
2439         torture_comment(tctx, "Close the file handle\n");
2440         smbcli_close(cli->tree, fnum1);
2441         fnum1 = -1;
2442
2443         GET_INFO_PATH(pinfo6);
2444         COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2445
2446         if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2447                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2448         }
2449
2450  done:
2451         if (fnum1 != -1)
2452                 smbcli_close(cli->tree, fnum1);
2453         smbcli_unlink(cli->tree, fname);
2454         smbcli_deltree(cli->tree, BASEDIR);
2455
2456         return ret;
2457 }
2458
2459 /*
2460  * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
2461  */
2462
2463 static bool test_delayed_write_update5b(struct torture_context *tctx,
2464                                         struct smbcli_state *cli,
2465                                         struct smbcli_state *cli2)
2466 {
2467         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2468         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2469         const char *fname = BASEDIR "\\torture_fileb.txt";
2470         int fnum1 = -1;
2471         bool ret = true;
2472         ssize_t written;
2473         struct timeval start;
2474         struct timeval end;
2475         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2476         int normal_delay = 2000000;
2477         double sec = ((double)used_delay) / ((double)normal_delay);
2478         int msec = 1000 * sec;
2479
2480         torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
2481
2482         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2483
2484         torture_comment(tctx, "Open the file handle\n");
2485         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2486         if (fnum1 == -1) {
2487                 ret = false;
2488                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2489                 goto done;
2490         }
2491
2492         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2493         finfo0.basic_info.in.file.fnum = fnum1;
2494         finfo1 = finfo0;
2495         finfo2 = finfo0;
2496         finfo3 = finfo0;
2497         finfo4 = finfo0;
2498         finfo5 = finfo0;
2499         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2500         pinfo0.basic_info.in.file.path = fname;
2501         pinfo1 = pinfo0;
2502         pinfo2 = pinfo0;
2503         pinfo3 = pinfo0;
2504         pinfo4 = pinfo0;
2505         pinfo5 = pinfo0;
2506         pinfo6 = pinfo0;
2507
2508         /* get the initial times */
2509         GET_INFO_BOTH(finfo0,pinfo0);
2510
2511         /* do a write */
2512         torture_comment(tctx, "Do a write on the file handle\n");
2513         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2514         if (written != 1) {
2515                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2516                 ret = false;
2517                 goto done;
2518         }
2519
2520         GET_INFO_BOTH(finfo1,pinfo1);
2521         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2522
2523         torture_comment(tctx, "Set write time in the future on the file handle\n");
2524         SET_INFO_FILE(finfo0, time(NULL) + 86400);
2525         GET_INFO_BOTH(finfo2,pinfo2);
2526         COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2527
2528         torture_comment(tctx, "Set write time in the past on the file handle\n");
2529         SET_INFO_FILE(finfo0, time(NULL) - 86400);
2530         GET_INFO_BOTH(finfo2,pinfo2);
2531         COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2532
2533         /* make sure the 2 second delay from the first write are canceled */
2534         start = timeval_current();
2535         end = timeval_add(&start, 15 * sec, 0);
2536         while (!timeval_expired(&end)) {
2537
2538                 /* get the times after the first write */
2539                 GET_INFO_BOTH(finfo3,pinfo3);
2540
2541                 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2542                         double diff = timeval_elapsed(&start);
2543                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2544                                         "(wrong!)\n",
2545                                         diff);
2546                         ret = false;
2547                         break;
2548                 }
2549                 smb_msleep(1 * msec);
2550         }
2551
2552         GET_INFO_BOTH(finfo3,pinfo3);
2553         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2554         if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2555                 torture_comment(tctx, "Server did not update write_time (correct)\n");
2556         }
2557
2558         /* Do any further write (truncates) update the write time ? */
2559         start = timeval_current();
2560         end = timeval_add(&start, 15 * sec, 0);
2561         while (!timeval_expired(&end)) {
2562                 /* do a write */
2563                 torture_comment(tctx, "Do a truncate write on the file handle\n");
2564                 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
2565                 if (written != 0) {
2566                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2567                         ret = false;
2568                         goto done;
2569                 }
2570                 /* get the times after the write */
2571                 GET_INFO_BOTH(finfo4,pinfo4);
2572
2573                 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2574                         double diff = timeval_elapsed(&start);
2575                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2576                                         "(wrong!)\n",
2577                                         diff);
2578                         ret = false;
2579                         break;
2580                 }
2581                 smb_msleep(1 * msec);
2582         }
2583
2584         GET_INFO_BOTH(finfo4,pinfo4);
2585         COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2586         if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2587                 torture_comment(tctx, "Server did not update write_time (correct)\n");
2588         }
2589
2590         /* sleep */
2591         smb_msleep(5 * msec);
2592
2593         GET_INFO_BOTH(finfo5,pinfo5);
2594         COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2595
2596         /*
2597          * the close doesn't update the write time
2598          */
2599         torture_comment(tctx, "Close the file handle\n");
2600         smbcli_close(cli->tree, fnum1);
2601         fnum1 = -1;
2602
2603         GET_INFO_PATH(pinfo6);
2604         COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2605
2606         if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2607                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2608         }
2609
2610  done:
2611         if (fnum1 != -1)
2612                 smbcli_close(cli->tree, fnum1);
2613         smbcli_unlink(cli->tree, fname);
2614         smbcli_deltree(cli->tree, BASEDIR);
2615
2616         return ret;
2617 }
2618
2619 /*
2620  * Open 2 handles on a file. Write one one and then set the
2621  * WRITE TIME explicitly on the other. Ensure the write time
2622  * update is cancelled. Ensure the write time is updated to
2623  * the close time when the non-explicit set handle is closed.
2624  *
2625  */
2626
2627 static bool test_delayed_write_update6(struct torture_context *tctx,
2628                                        struct smbcli_state *cli,
2629                                        struct smbcli_state *cli2)
2630 {
2631         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2632         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2633         const char *fname = BASEDIR "\\torture_file6.txt";
2634         int fnum1 = -1;
2635         int fnum2 = -1;
2636         bool ret = true;
2637         ssize_t written;
2638         struct timeval start;
2639         struct timeval end;
2640         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2641         int normal_delay = 2000000;
2642         double sec = ((double)used_delay) / ((double)normal_delay);
2643         int msec = 1000 * sec;
2644         bool first = true;
2645
2646         torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
2647
2648         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2649 again:
2650         torture_comment(tctx, "Open the file handle\n");
2651         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2652         if (fnum1 == -1) {
2653                 ret = false;
2654                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2655                 goto done;
2656         }
2657
2658         if (fnum2 == -1) {
2659                 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2660                 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2661                 if (fnum2 == -1) {
2662                         ret = false;
2663                         torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2664                         goto done;
2665                 }
2666         }
2667
2668         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2669         finfo0.basic_info.in.file.fnum = fnum1;
2670         finfo1 = finfo0;
2671         finfo2 = finfo0;
2672         finfo3 = finfo0;
2673         finfo4 = finfo0;
2674         finfo5 = finfo0;
2675         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2676         pinfo0.basic_info.in.file.path = fname;
2677         pinfo1 = pinfo0;
2678         pinfo2 = pinfo0;
2679         pinfo3 = pinfo0;
2680         pinfo4 = pinfo0;
2681         pinfo5 = pinfo0;
2682         pinfo6 = pinfo0;
2683         pinfo7 = pinfo0;
2684
2685         /* get the initial times */
2686         GET_INFO_BOTH(finfo0,pinfo0);
2687
2688         /* do a write */
2689         torture_comment(tctx, "Do a write on the file handle\n");
2690         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2691         if (written != 1) {
2692                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2693                 ret = false;
2694                 goto done;
2695         }
2696
2697         GET_INFO_BOTH(finfo1,pinfo1);
2698         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2699
2700         torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2701         SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2702         GET_INFO_BOTH(finfo2,pinfo2);
2703         COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2704
2705         torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2706         SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2707         GET_INFO_BOTH(finfo2,pinfo2);
2708         COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2709
2710         /* make sure the 2 second delay from the first write are canceled */
2711         start = timeval_current();
2712         end = timeval_add(&start, 10 * sec, 0);
2713         while (!timeval_expired(&end)) {
2714
2715                 /* get the times after the first write */
2716                 GET_INFO_BOTH(finfo3,pinfo3);
2717
2718                 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2719                         double diff = timeval_elapsed(&start);
2720                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2721                                         "(wrong!)\n",
2722                                         diff);
2723                         ret = false;
2724                         break;
2725                 }
2726                 smb_msleep(1 * msec);
2727         }
2728
2729         GET_INFO_BOTH(finfo3,pinfo3);
2730         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2731         if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2732                 torture_comment(tctx, "Server did not update write_time (correct)\n");
2733         }
2734
2735         /* sure any further write doesn't update the write time */
2736         start = timeval_current();
2737         end = timeval_add(&start, 10 * sec, 0);
2738         while (!timeval_expired(&end)) {
2739                 /* do a write */
2740                 torture_comment(tctx, "Do a write on the file handle\n");
2741                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2742                 if (written != 1) {
2743                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2744                         ret = false;
2745                         goto done;
2746                 }
2747                 /* get the times after the write */
2748                 GET_INFO_BOTH(finfo4,pinfo4);
2749
2750                 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2751                         double diff = timeval_elapsed(&start);
2752                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2753                                         "(wrong!)\n",
2754                                         diff);
2755                         ret = false;
2756                         break;
2757                 }
2758                 smb_msleep(1 * msec);
2759         }
2760
2761         GET_INFO_BOTH(finfo4,pinfo4);
2762         COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2763         if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2764                 torture_comment(tctx, "Server did not update write_time (correct)\n");
2765         }
2766
2767         /* sleep */
2768         smb_msleep(5 * msec);
2769
2770         GET_INFO_BOTH(finfo5,pinfo5);
2771         COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2772
2773         /*
2774          * the close updates the write time to the time of the close
2775          * as the write time was set on the 2nd handle
2776          */
2777         torture_comment(tctx, "Close the file handle\n");
2778         smbcli_close(cli->tree, fnum1);
2779         fnum1 = -1;
2780
2781         GET_INFO_PATH(pinfo6);
2782         COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2783
2784         if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2785                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2786         }
2787
2788         /* See what the second write handle thinks the time is ? */
2789         finfo5.basic_info.in.file.fnum = fnum2;
2790         GET_INFO_FILE2(finfo5);
2791         COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
2792
2793         /* See if we have lost the sticky write time on handle2 */
2794         smb_msleep(3 * msec);
2795         torture_comment(tctx, "Have we lost the sticky write time ?\n");
2796
2797         /* Make sure any further normal write doesn't update the write time */
2798         start = timeval_current();
2799         end = timeval_add(&start, 10 * sec, 0);
2800         while (!timeval_expired(&end)) {
2801                 /* do a write */
2802                 torture_comment(tctx, "Do a write on the second file handle\n");
2803                 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
2804                 if (written != 1) {
2805                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2806                         ret = false;
2807                         goto done;
2808                 }
2809                 /* get the times after the write */
2810                 GET_INFO_FILE2(finfo5);
2811                 GET_INFO_PATH(pinfo6);
2812
2813                 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2814                         double diff = timeval_elapsed(&start);
2815                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2816                                         "(wrong!)\n",
2817                                         diff);
2818                         ret = false;
2819                         break;
2820                 }
2821                 smb_msleep(1 * msec);
2822         }
2823
2824         /* What about a truncate write ? */
2825         start = timeval_current();
2826         end = timeval_add(&start, 10 * sec, 0);
2827         while (!timeval_expired(&end)) {
2828                 /* do a write */
2829                 torture_comment(tctx, "Do a truncate write on the second file handle\n");
2830                 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
2831                 if (written != 0) {
2832                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2833                         ret = false;
2834                         goto done;
2835                 }
2836                 /* get the times after the write */
2837                 GET_INFO_FILE2(finfo5);
2838                 GET_INFO_PATH(pinfo6);
2839
2840                 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
2841                         double diff = timeval_elapsed(&start);
2842                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
2843                                         "(wrong!)\n",
2844                                         diff);
2845                         ret = false;
2846                         break;
2847                 }
2848                 smb_msleep(1 * msec);
2849         }
2850
2851
2852         /* keep the 2nd handle open and rerun tests */
2853         if (first) {
2854                 first = false;
2855                 goto again;
2856         }
2857
2858         /*
2859          * closing the 2nd handle will cause no write time update
2860          * as the write time was explicit set on this handle
2861          */
2862         torture_comment(tctx, "Close the 2nd file handle\n");
2863         smbcli_close(cli2->tree, fnum2);
2864         fnum2 = -1;
2865
2866         GET_INFO_PATH(pinfo7);
2867         COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2868
2869         if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2870                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2871         }
2872
2873  done:
2874         if (fnum1 != -1)
2875                 smbcli_close(cli->tree, fnum1);
2876         if (fnum2 != -1)
2877                 smbcli_close(cli2->tree, fnum2);
2878         smbcli_unlink(cli->tree, fname);
2879         smbcli_deltree(cli->tree, BASEDIR);
2880
2881         return ret;
2882 }
2883
2884 static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
2885 {
2886         union smb_open open_parms;
2887         union smb_fileinfo finfo1, finfo2, finfo3;
2888         const char *fname = BASEDIR "\\torture_file7.txt";
2889         NTSTATUS status;
2890         int fnum1 = -1;
2891         bool ret = true;
2892         TALLOC_CTX *mem_ctx; 
2893
2894         torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
2895
2896         mem_ctx = talloc_init("test_delayed_write_update7");
2897         if (!mem_ctx) return false;
2898
2899         ZERO_STRUCT(finfo1);
2900         ZERO_STRUCT(finfo2);
2901         ZERO_STRUCT(finfo3);
2902         ZERO_STRUCT(open_parms);
2903
2904         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
2905
2906         /* Create the file. */
2907         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2908         if (fnum1 == -1) {
2909                 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
2910                 return false;
2911         }
2912
2913         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2914         finfo1.basic_info.in.file.fnum = fnum1;
2915         finfo2 = finfo1;
2916         finfo3 = finfo1;
2917
2918         /* Get the initial timestamps. */
2919         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
2920
2921         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2922         
2923         /* Set the pending write time to a value with ns. */
2924         SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
2925
2926         /* Get the current pending write time by fnum. */
2927         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
2928
2929         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
2930
2931         /* Ensure the time is actually different. */
2932         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2933                 torture_result(tctx, TORTURE_FAIL,
2934                         "setfileinfo time matches original fileinfo time");
2935                 ret = false;
2936         }
2937
2938         /* Get the current pending write time by path. */
2939         finfo3.basic_info.in.file.path = fname;
2940         status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
2941
2942         if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
2943                 torture_result(tctx, TORTURE_FAIL, 
2944                         "qpathinfo time doens't match fileinfo time");
2945                 ret = false;
2946         }
2947
2948         /* Now close the file. Re-open and check that the write
2949            time is identical to the one we wrote. */
2950
2951         smbcli_close(cli->tree, fnum1);
2952
2953         open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
2954         open_parms.ntcreatex.in.flags = 0;
2955         open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
2956         open_parms.ntcreatex.in.file_attr = 0;
2957         open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
2958                                         NTCREATEX_SHARE_ACCESS_READ|
2959                                         NTCREATEX_SHARE_ACCESS_WRITE;
2960         open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
2961         open_parms.ntcreatex.in.create_options = 0;
2962         open_parms.ntcreatex.in.fname = fname;
2963
2964         status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
2965         talloc_free(mem_ctx);
2966
2967         if (!NT_STATUS_IS_OK(status)) {
2968                 torture_result(tctx, TORTURE_FAIL,
2969                         "setfileinfo time matches original fileinfo time");
2970                 ret = false;
2971         }
2972
2973         fnum1 = open_parms.ntcreatex.out.file.fnum;
2974
2975         /* Check the returned time matches. */
2976         if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
2977                 torture_result(tctx, TORTURE_FAIL,
2978                         "final open time does not match set time");
2979                 ret = false;
2980         }
2981
2982  done:
2983
2984         smbcli_close(cli->tree, fnum1);
2985
2986         smbcli_unlink(cli->tree, fname);
2987         smbcli_deltree(cli->tree, BASEDIR);
2988         return ret;
2989 }
2990
2991 /*
2992    Test if creating a file in a directory with an open handle updates the
2993    write timestamp (it should).
2994 */
2995 static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
2996 {
2997         union smb_fileinfo dir_info1, dir_info2;
2998         union smb_open open_parms;
2999         const char *fname = BASEDIR "\\torture_file.txt";
3000         NTSTATUS status;
3001         int fnum1 = -1;
3002         int fnum2 = -1;
3003         bool ret = true;
3004         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
3005         int normal_delay = 2000000;
3006         double sec = ((double)used_delay) / ((double)normal_delay);
3007         int msec = 1000 * sec;
3008         TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
3009
3010         if (!mem_ctx) return false;
3011
3012         torture_comment(tctx, "\nRunning test directory write update\n");
3013
3014         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
3015
3016         /* Open a handle on the directory - and leave it open. */
3017         ZERO_STRUCT(open_parms);
3018         open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
3019         open_parms.ntcreatex.in.flags = 0;
3020         open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
3021         open_parms.ntcreatex.in.file_attr = 0;
3022         open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
3023                                         NTCREATEX_SHARE_ACCESS_READ|
3024                                         NTCREATEX_SHARE_ACCESS_WRITE;
3025         open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
3026         open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
3027         open_parms.ntcreatex.in.fname = BASEDIR;
3028
3029         status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
3030         talloc_free(mem_ctx);
3031
3032         if (!NT_STATUS_IS_OK(status)) {
3033                 torture_result(tctx, TORTURE_FAIL,
3034                         "failed to open directory handle");
3035                 ret = false;
3036                 goto done;
3037         }
3038
3039         fnum1 = open_parms.ntcreatex.out.file.fnum;
3040
3041         /* Store the returned write time. */
3042         ZERO_STRUCT(dir_info1);
3043         dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
3044
3045         torture_comment(tctx, "Initial write time %s\n",
3046                nt_time_string(tctx, dir_info1.basic_info.out.write_time));
3047
3048         /* sleep */
3049         smb_msleep(3 * msec);
3050
3051         /* Now create a file within the directory. */
3052         fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
3053         if (fnum2 == -1) {
3054                 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
3055                 ret = false;
3056                 goto done;
3057         }
3058         smbcli_close(cli->tree, fnum2);
3059
3060         /* Read the directory write time again. */
3061         ZERO_STRUCT(dir_info2);
3062         dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
3063         dir_info2.basic_info.in.file.fnum = fnum1;
3064
3065         status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
3066
3067         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
3068
3069         /* Ensure it's been incremented. */
3070         COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
3071
3072         torture_comment(tctx, "Updated write time %s\n",
3073                nt_time_string(tctx, dir_info2.basic_info.out.write_time));
3074
3075  done:
3076
3077         if (fnum1 != -1)
3078                 smbcli_close(cli->tree, fnum1);
3079         smbcli_unlink(cli->tree, fname);
3080         smbcli_deltree(cli->tree, BASEDIR);
3081
3082         return ret;
3083 }
3084
3085 /*
3086    testing of delayed update of write_time
3087 */
3088 struct torture_suite *torture_delay_write(void)
3089 {
3090         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "delaywrite");
3091
3092         torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
3093         torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
3094         torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
3095         torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
3096         torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
3097         torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
3098         torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
3099         torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
3100         torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
3101         torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
3102         torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
3103         torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
3104         torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
3105         torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
3106         torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
3107         torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3108         torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
3109         torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);
3110
3111         return suite;
3112 }