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