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