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