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