BASE-DELAYWRITE: demonstrate that a truncate write doesn't update the write time...
[nivanova/samba-autobuild/.git] / source4 / torture / basic / delaywrite.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    test suite for delayed write update 
5
6    Copyright (C) Volker Lendecke 2004
7    Copyright (C) Andrew Tridgell 2004
8    Copyright (C) Jeremy Allison 2004
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "includes.h"
25 #include "torture/torture.h"
26 #include "libcli/raw/libcliraw.h"
27 #include "libcli/raw/raw_proto.h"
28 #include "system/time.h"
29 #include "system/filesys.h"
30 #include "libcli/libcli.h"
31 #include "torture/util.h"
32
33 #define BASEDIR "\\delaywrite"
34
35 static bool test_delayed_write_update(struct torture_context *tctx, struct smbcli_state *cli)
36 {
37         union smb_fileinfo finfo1, finfo2;
38         const char *fname = BASEDIR "\\torture_file.txt";
39         NTSTATUS status;
40         int fnum1 = -1;
41         bool ret = true;
42         ssize_t written;
43         struct timeval start;
44         struct timeval end;
45         int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
46         int normal_delay = 2000000;
47         double sec = ((double)used_delay) / ((double)normal_delay);
48         int msec = 1000 * sec;
49
50         if (!torture_setup_dir(cli, BASEDIR)) {
51                 return false;
52         }
53
54         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
55         if (fnum1 == -1) {
56                 torture_comment(tctx, "Failed to open %s\n", fname);
57                 return false;
58         }
59
60         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
61         finfo1.basic_info.in.file.fnum = fnum1;
62         finfo2 = finfo1;
63
64         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
65
66         if (!NT_STATUS_IS_OK(status)) {
67                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
68                 return false;
69         }
70         
71         torture_comment(tctx, "Initial write time %s\n", 
72                nt_time_string(tctx, finfo1.basic_info.out.write_time));
73
74         /* 3 second delay to ensure we get past any 2 second time
75            granularity (older systems may have that) */
76         msleep(3 * msec);
77
78         written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
79
80         if (written != 1) {
81                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
82                        (int)written, __location__);
83                 return false;
84         }
85
86         start = timeval_current();
87         end = timeval_add(&start, (120*sec), 0);
88         while (!timeval_expired(&end)) {
89                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
90
91                 if (!NT_STATUS_IS_OK(status)) {
92                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
93                         ret = false;
94                         break;
95                 }
96                 torture_comment(tctx, "write time %s\n", 
97                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
98                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
99                         double diff = timeval_elapsed(&start);
100                         if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
101                                 torture_comment(tctx, "Server updated write_time after %.2f seconds"
102                                                 "(1 sec == %.2f)(wrong!)\n",
103                                                 diff, sec);
104                                 ret = false;
105                                 break;
106                         }
107
108                         torture_comment(tctx, "Server updated write_time after %.2f seconds"
109                                         "(1 sec == %.2f)(correct)\n",
110                                         diff, sec);
111                         break;
112                 }
113                 fflush(stdout);
114                 msleep(1 * msec);
115         }
116         
117         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
118                 torture_comment(tctx, "Server did not update write time (wrong!)\n");
119                 ret = false;
120         }
121
122
123         if (fnum1 != -1)
124                 smbcli_close(cli->tree, fnum1);
125         smbcli_unlink(cli->tree, fname);
126         smbcli_deltree(cli->tree, BASEDIR);
127
128         return ret;
129 }
130
131 static bool test_delayed_write_update1(struct torture_context *tctx, struct smbcli_state *cli)
132 {
133         union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
134         const char *fname = BASEDIR "\\torture_file1.txt";
135         NTSTATUS status;
136         int fnum1 = -1;
137         bool ret = true;
138         ssize_t written;
139         struct timeval start;
140         struct timeval end;
141         int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
142         int normal_delay = 2000000;
143         double sec = ((double)used_delay) / ((double)normal_delay);
144         int msec = 1000 * sec;
145         char buf[2048];
146
147         if (!torture_setup_dir(cli, BASEDIR)) {
148                 return false;
149         }
150
151         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
152         if (fnum1 == -1) {
153                 torture_comment(tctx, "Failed to open %s\n", fname);
154                 return false;
155         }
156
157         memset(buf, 'x', 2048);
158         written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
159
160         /* 3 second delay to ensure we get past any 2 second time
161            granularity (older systems may have that) */
162         msleep(3 * msec);
163
164         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
165         finfo1.all_info.in.file.fnum = fnum1;
166         finfo2 = finfo1;
167         finfo3 = finfo1;
168         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
169         pinfo4.all_info.in.file.path = fname;
170
171         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
172
173         if (!NT_STATUS_IS_OK(status)) {
174                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
175                 return false;
176         }
177
178         torture_comment(tctx, "Initial write time %s\n", 
179                nt_time_string(tctx, finfo1.all_info.out.write_time));
180
181         /* Do a zero length SMBwrite call to truncate. */
182         written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
183
184         if (written != 0) {
185                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
186                        (int)written, __location__);
187                 return false;
188         }
189
190         start = timeval_current();
191         end = timeval_add(&start, (120*sec), 0);
192         while (!timeval_expired(&end)) {
193                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
194
195                 if (!NT_STATUS_IS_OK(status)) {
196                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
197                         ret = false;
198                         break;
199                 }
200
201                 if (finfo2.all_info.out.size != 1024) {
202                         DEBUG(0, ("file not truncated\n"));
203                         ret = false;
204                         break;
205                 }
206
207                 torture_comment(tctx, "write time %s\n",
208                        nt_time_string(tctx, finfo2.all_info.out.write_time));
209                 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
210                         double diff = timeval_elapsed(&start);
211                         if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
212                                 torture_comment(tctx, "After SMBwrite truncate "
213                                         "server updated write_time after %.2f seconds"
214                                         "(1 sec == %.2f)(wrong!)\n",
215                                         diff, sec);
216                                 ret = false;
217                                 break;
218                         }
219
220                         torture_comment(tctx, "After SMBwrite truncate "
221                                         "server updated write_time after %.2f seconds"
222                                         "(1 sec == %.2f)(correct)\n",
223                                         diff, sec);
224                         break;
225                 }
226                 fflush(stdout);
227                 msleep(1 * msec);
228         }
229
230         if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
231                 torture_comment(tctx, "Server did not update write time (wrong!)\n");
232                 ret = false;
233         }
234
235         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
236         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
237
238         if (written != 1) {
239                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
240                        (int)written, __location__);
241                 return false;
242         }
243
244         start = timeval_current();
245         end = timeval_add(&start, (10*sec), 0);
246         while (!timeval_expired(&end)) {
247                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
248
249                 if (!NT_STATUS_IS_OK(status)) {
250                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
251                         ret = false;
252                         break;
253                 }
254
255                 if (finfo3.all_info.out.size != 1024) {
256                         DEBUG(0, ("file not truncated\n"));
257                         ret = false;
258                         break;
259                 }
260
261                 torture_comment(tctx, "write time %s\n",
262                        nt_time_string(tctx, finfo3.all_info.out.write_time));
263                 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
264                         double diff = timeval_elapsed(&start);
265
266                         torture_comment(tctx, "server updated write_time after %.2f seconds"
267                                         "(1 sec == %.2f)(correct)\n",
268                                         diff, sec);
269                         break;
270                 }
271                 fflush(stdout);
272                 msleep(1 * msec);
273         }
274
275         if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
276                 torture_comment(tctx, "Server updated write time (wrong!)\n");
277                 ret = false;
278         }
279
280         /* the close should trigger an write time update */
281         smbcli_close(cli->tree, fnum1);
282         fnum1 = -1;
283
284         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
285         if (!NT_STATUS_IS_OK(status)) {
286                 DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
287                 return false;
288         }
289
290         if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
291                 torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
292                 ret = false;
293         } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
294                 torture_comment(tctx, "Server updated write time on close (correct)\n");
295         }
296
297         if (fnum1 != -1)
298                 smbcli_close(cli->tree, fnum1);
299         smbcli_unlink(cli->tree, fname);
300         smbcli_deltree(cli->tree, BASEDIR);
301
302         return ret;
303 }
304
305 /* Updating with a SMBwrite of zero length
306  * changes the write time immediately - even on expand. */
307
308 static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
309 {
310         union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
311         const char *fname = BASEDIR "\\torture_file1a.txt";
312         NTSTATUS status;
313         int fnum1 = -1;
314         bool ret = true;
315         ssize_t written;
316         struct timeval start;
317         struct timeval end;
318         int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
319         int normal_delay = 2000000;
320         double sec = ((double)used_delay) / ((double)normal_delay);
321         int msec = 1000 * sec;
322         char buf[2048];
323
324         if (!torture_setup_dir(cli, BASEDIR)) {
325                 return false;
326         }
327
328         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
329         if (fnum1 == -1) {
330                 torture_comment(tctx, "Failed to open %s\n", fname);
331                 return false;
332         }
333
334         memset(buf, 'x', 2048);
335         written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
336
337         /* 3 second delay to ensure we get past any 2 second time
338            granularity (older systems may have that) */
339         msleep(3 * msec);
340
341         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
342         finfo1.all_info.in.file.fnum = fnum1;
343         finfo2 = finfo1;
344         finfo3 = finfo1;
345         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
346         pinfo4.all_info.in.file.path = fname;
347
348         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
349
350         if (!NT_STATUS_IS_OK(status)) {
351                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
352                 return false;
353         }
354
355         torture_comment(tctx, "Initial write time %s\n", 
356                nt_time_string(tctx, finfo1.all_info.out.write_time));
357
358         /* Do a zero length SMBwrite call to truncate. */
359         written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
360
361         if (written != 0) {
362                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
363                        (int)written, __location__);
364                 return false;
365         }
366
367         start = timeval_current();
368         end = timeval_add(&start, (120*sec), 0);
369         while (!timeval_expired(&end)) {
370                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
371
372                 if (!NT_STATUS_IS_OK(status)) {
373                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
374                         ret = false;
375                         break;
376                 }
377
378                 if (finfo2.all_info.out.size != 10240) {
379                         DEBUG(0, ("file not truncated\n"));
380                         ret = false;
381                         break;
382                 }
383
384                 torture_comment(tctx, "write time %s\n",
385                        nt_time_string(tctx, finfo2.all_info.out.write_time));
386                 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
387                         double diff = timeval_elapsed(&start);
388                         if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
389                                 torture_comment(tctx, "After SMBwrite truncate "
390                                         "server updated write_time after %.2f seconds"
391                                         "(1 sec == %.2f)(wrong!)\n",
392                                         diff, sec);
393                                 ret = false;
394                                 break;
395                         }
396
397                         torture_comment(tctx, "After SMBwrite truncate "
398                                         "server updated write_time after %.2f seconds"
399                                         "(1 sec == %.2f)(correct)\n",
400                                         diff, sec);
401                         break;
402                 }
403                 fflush(stdout);
404                 msleep(1 * msec);
405         }
406
407         if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
408                 torture_comment(tctx, "Server did not update write time (wrong!)\n");
409                 ret = false;
410         }
411
412         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
413         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
414
415         if (written != 1) {
416                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
417                        (int)written, __location__);
418                 return false;
419         }
420
421         start = timeval_current();
422         end = timeval_add(&start, (10*sec), 0);
423         while (!timeval_expired(&end)) {
424                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
425
426                 if (!NT_STATUS_IS_OK(status)) {
427                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
428                         ret = false;
429                         break;
430                 }
431
432                 if (finfo3.all_info.out.size != 10240) {
433                         DEBUG(0, ("file not truncated\n"));
434                         ret = false;
435                         break;
436                 }
437
438                 torture_comment(tctx, "write time %s\n",
439                        nt_time_string(tctx, finfo3.all_info.out.write_time));
440                 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
441                         double diff = timeval_elapsed(&start);
442
443                         torture_comment(tctx, "server updated write_time after %.2f seconds"
444                                         "(1 sec == %.2f)(correct)\n",
445                                         diff, sec);
446                         break;
447                 }
448                 fflush(stdout);
449                 msleep(1 * msec);
450         }
451
452         if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
453                 torture_comment(tctx, "Server updated write time (wrong!)\n");
454                 ret = false;
455         }
456
457         /* the close should trigger an write time update */
458         smbcli_close(cli->tree, fnum1);
459         fnum1 = -1;
460
461         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
462         if (!NT_STATUS_IS_OK(status)) {
463                 DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
464                 return false;
465         }
466
467         if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
468                 torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
469                 ret = false;
470         } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
471                 torture_comment(tctx, "Server updated write time on close (correct)\n");
472         }
473
474         if (fnum1 != -1)
475                 smbcli_close(cli->tree, fnum1);
476         smbcli_unlink(cli->tree, fname);
477         smbcli_deltree(cli->tree, BASEDIR);
478
479         return ret;
480 }
481
482 /* Updating with a SET_FILE_END_OF_FILE_INFO
483  * changes the write time immediately - even on expand. */
484
485 static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
486 {
487         union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
488         const char *fname = BASEDIR "\\torture_file1b.txt";
489         NTSTATUS status;
490         int fnum1 = -1;
491         bool ret = true;
492         ssize_t written;
493         struct timeval start;
494         struct timeval end;
495         int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
496         int normal_delay = 2000000;
497         double sec = ((double)used_delay) / ((double)normal_delay);
498         int msec = 1000 * sec;
499         char buf[2048];
500
501         if (!torture_setup_dir(cli, BASEDIR)) {
502                 return false;
503         }
504
505         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
506         if (fnum1 == -1) {
507                 torture_comment(tctx, "Failed to open %s\n", fname);
508                 return false;
509         }
510
511         memset(buf, 'x', 2048);
512         written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
513
514         /* 3 second delay to ensure we get past any 2 second time
515            granularity (older systems may have that) */
516         msleep(3 * msec);
517
518         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
519         finfo1.all_info.in.file.fnum = fnum1;
520         finfo2 = finfo1;
521         finfo3 = finfo1;
522         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
523         pinfo4.all_info.in.file.path = fname;
524
525         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
526
527         if (!NT_STATUS_IS_OK(status)) {
528                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
529                 return false;
530         }
531
532         torture_comment(tctx, "Initial write time %s\n",
533                nt_time_string(tctx, finfo1.all_info.out.write_time));
534
535         /* Do a SET_END_OF_FILE_INFO call to truncate. */
536         status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
537
538         if (!NT_STATUS_IS_OK(status)) {
539                 torture_comment(tctx, "SET_END_OF_FILE failed (%s)\n",
540                        nt_errstr(status));
541                 return false;
542         }
543
544         start = timeval_current();
545         end = timeval_add(&start, (120*sec), 0);
546         while (!timeval_expired(&end)) {
547                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
548
549                 if (!NT_STATUS_IS_OK(status)) {
550                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
551                         ret = false;
552                         break;
553                 }
554
555                 if (finfo2.all_info.out.size != 10240) {
556                         DEBUG(0, ("file not truncated\n"));
557                         ret = false;
558                         break;
559                 }
560
561                 torture_comment(tctx, "write time %s\n",
562                        nt_time_string(tctx, finfo2.all_info.out.write_time));
563                 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
564                         double diff = timeval_elapsed(&start);
565                         if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
566                                 torture_comment(tctx, "After SET_END_OF_FILE truncate "
567                                         "server updated write_time after %.2f seconds"
568                                         "(1 sec == %.2f)(wrong!)\n",
569                                         diff, sec);
570                                 ret = false;
571                                 break;
572                         }
573
574                         torture_comment(tctx, "After SET_END_OF_FILE truncate "
575                                         "server updated write_time after %.2f seconds"
576                                         "(1 sec == %.2f)(correct)\n",
577                                         diff, sec);
578                         break;
579                 }
580                 fflush(stdout);
581                 msleep(1 * msec);
582         }
583
584         if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
585                 torture_comment(tctx, "Server did not update write time (wrong!)\n");
586                 ret = false;
587         }
588
589         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
590         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
591
592         if (written != 1) {
593                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
594                        (int)written, __location__);
595                 return false;
596         }
597
598         start = timeval_current();
599         end = timeval_add(&start, (10*sec), 0);
600         while (!timeval_expired(&end)) {
601                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
602
603                 if (!NT_STATUS_IS_OK(status)) {
604                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
605                         ret = false;
606                         break;
607                 }
608
609                 if (finfo3.all_info.out.size != 10240) {
610                         DEBUG(0, ("file not truncated\n"));
611                         ret = false;
612                         break;
613                 }
614
615                 torture_comment(tctx, "write time %s\n",
616                        nt_time_string(tctx, finfo3.all_info.out.write_time));
617                 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
618                         double diff = timeval_elapsed(&start);
619
620                         torture_comment(tctx, "server updated write_time after %.2f seconds"
621                                         "(1 sec == %.2f)(correct)\n",
622                                         diff, sec);
623                         break;
624                 }
625                 fflush(stdout);
626                 msleep(1 * msec);
627         }
628
629         if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
630                 torture_comment(tctx, "Server updated write time (wrong!)\n");
631                 ret = false;
632         }
633
634         /* the close should trigger an write time update */
635         smbcli_close(cli->tree, fnum1);
636         fnum1 = -1;
637
638         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
639         if (!NT_STATUS_IS_OK(status)) {
640                 DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
641                 return false;
642         }
643
644         if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
645                 torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
646                 ret = false;
647         } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
648                 torture_comment(tctx, "Server updated write time on close (correct)\n");
649         }
650
651         if (fnum1 != -1)
652                 smbcli_close(cli->tree, fnum1);
653         smbcli_unlink(cli->tree, fname);
654         smbcli_deltree(cli->tree, BASEDIR);
655
656         return ret;
657 }
658
659 /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
660
661 static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
662 {
663         union smb_setfileinfo parms;
664         union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
665         const char *fname = BASEDIR "\\torture_file1c.txt";
666         NTSTATUS status;
667         int fnum1 = -1;
668         bool ret = true;
669         ssize_t written;
670         struct timeval start;
671         struct timeval end;
672         int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
673         int normal_delay = 2000000;
674         double sec = ((double)used_delay) / ((double)normal_delay);
675         int msec = 1000 * sec;
676         char buf[2048];
677
678         if (!torture_setup_dir(cli, BASEDIR)) {
679                 return false;
680         }
681
682         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
683         if (fnum1 == -1) {
684                 torture_comment(tctx, "Failed to open %s\n", fname);
685                 return false;
686         }
687
688         memset(buf, 'x', 2048);
689         written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
690
691         /* 3 second delay to ensure we get past any 2 second time
692            granularity (older systems may have that) */
693         msleep(3 * msec);
694
695         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
696         finfo1.all_info.in.file.fnum = fnum1;
697         finfo2 = finfo1;
698         finfo3 = finfo1;
699         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
700         pinfo4.all_info.in.file.path = fname;
701
702         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
703
704         if (!NT_STATUS_IS_OK(status)) {
705                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
706                 return false;
707         }
708
709         torture_comment(tctx, "Initial write time %s\n",
710                nt_time_string(tctx, finfo1.all_info.out.write_time));
711
712         /* Do a SET_ALLOCATION_SIZE call to truncate. */
713         parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
714         parms.allocation_info.in.file.fnum = fnum1;
715         parms.allocation_info.in.alloc_size = 0;
716
717         status = smb_raw_setfileinfo(cli->tree, &parms);
718
719         if (!NT_STATUS_IS_OK(status)) {
720                 torture_comment(tctx, "RAW_SFILEINFO_ALLOCATION_INFO failed (%s)\n",
721                        nt_errstr(status));
722                 return false;
723         }
724
725         start = timeval_current();
726         end = timeval_add(&start, (120*sec), 0);
727         while (!timeval_expired(&end)) {
728                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
729
730                 if (!NT_STATUS_IS_OK(status)) {
731                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
732                         ret = false;
733                         break;
734                 }
735
736                 if (finfo2.all_info.out.size != 0) {
737                         DEBUG(0, ("file not truncated\n"));
738                         ret = false;
739                         break;
740                 }
741
742                 torture_comment(tctx, "write time %s\n",
743                        nt_time_string(tctx, finfo2.all_info.out.write_time));
744                 if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
745                         double diff = timeval_elapsed(&start);
746                         if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
747                                 torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
748                                         "server updated write_time after %.2f seconds"
749                                         "(1 sec == %.2f)(wrong!)\n",
750                                         diff, sec);
751                                 ret = false;
752                                 break;
753                         }
754
755                         torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
756                                         "server updated write_time after %.2f seconds"
757                                         "(1 sec == %.2f)(correct)\n",
758                                         diff, sec);
759                         break;
760                 }
761                 fflush(stdout);
762                 msleep(1 * msec);
763         }
764
765         if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
766                 torture_comment(tctx, "Server did not update write time (wrong!)\n");
767                 ret = false;
768         }
769
770         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
771         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
772
773         if (written != 1) {
774                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
775                        (int)written, __location__);
776                 return false;
777         }
778
779         start = timeval_current();
780         end = timeval_add(&start, (10*sec), 0);
781         while (!timeval_expired(&end)) {
782                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
783
784                 if (!NT_STATUS_IS_OK(status)) {
785                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
786                         ret = false;
787                         break;
788                 }
789
790                 if (finfo3.all_info.out.size != 1) {
791                         DEBUG(0, ("file not expanded\n"));
792                         ret = false;
793                         break;
794                 }
795
796                 torture_comment(tctx, "write time %s\n",
797                        nt_time_string(tctx, finfo3.all_info.out.write_time));
798                 if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
799                         double diff = timeval_elapsed(&start);
800
801                         torture_comment(tctx, "server updated write_time after %.2f seconds"
802                                         "(1 sec == %.2f)(correct)\n",
803                                         diff, sec);
804                         break;
805                 }
806                 fflush(stdout);
807                 msleep(1 * msec);
808         }
809
810         if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
811                 torture_comment(tctx, "Server updated write time (wrong!)\n");
812                 ret = false;
813         }
814
815         /* the close should trigger an write time update */
816         smbcli_close(cli->tree, fnum1);
817         fnum1 = -1;
818
819         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
820         if (!NT_STATUS_IS_OK(status)) {
821                 DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
822                 return false;
823         }
824
825         if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
826                 torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
827                 ret = false;
828         } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
829                 torture_comment(tctx, "Server updated write time on close (correct)\n");
830         }
831
832         if (fnum1 != -1)
833                 smbcli_close(cli->tree, fnum1);
834         smbcli_unlink(cli->tree, fname);
835         smbcli_deltree(cli->tree, BASEDIR);
836
837         return ret;
838 }
839
840 /*
841  * Do as above, but using 2 connections.
842  */
843
844 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli, 
845                                                                            struct smbcli_state *cli2)
846 {
847         union smb_fileinfo finfo1, finfo2;
848         const char *fname = BASEDIR "\\torture_file.txt";
849         NTSTATUS status;
850         int fnum1 = -1;
851         int fnum2 = -1;
852         bool ret = true;
853         ssize_t written;
854         struct timeval start;
855         struct timeval end;
856         int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
857         int normal_delay = 2000000;
858         double sec = ((double)used_delay) / ((double)normal_delay);
859         int msec = 1000 * sec;
860         union smb_flush flsh;
861
862         if (!torture_setup_dir(cli, BASEDIR)) {
863                 return false;
864         }
865
866         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
867         if (fnum1 == -1) {
868                 torture_comment(tctx, "Failed to open %s\n", fname);
869                 return false;
870         }
871
872         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
873         finfo1.basic_info.in.file.fnum = fnum1;
874         finfo2 = finfo1;
875
876         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
877
878         if (!NT_STATUS_IS_OK(status)) {
879                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
880                 return false;
881         }
882         
883         torture_comment(tctx, "Initial write time %s\n", 
884                nt_time_string(tctx, finfo1.basic_info.out.write_time));
885
886         /* 3 second delay to ensure we get past any 2 second time
887            granularity (older systems may have that) */
888         msleep(3 * msec);
889
890         {
891                 /* Try using setfileinfo instead of write to update write time. */
892                 union smb_setfileinfo sfinfo;
893                 time_t t_set = time(NULL);
894                 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
895                 sfinfo.basic_info.in.file.fnum = fnum1;
896                 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
897                 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
898
899                 /* I tried this with both + and - ve to see if it makes a different.
900                    It doesn't - once the filetime is set via setfileinfo it stays that way. */
901 #if 1
902                 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
903 #else
904                 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
905 #endif
906                 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
907                 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
908
909                 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
910
911                 if (!NT_STATUS_IS_OK(status)) {
912                         DEBUG(0, ("sfileinfo failed: %s\n", nt_errstr(status)));
913                         return false;
914                 }
915         }
916
917         finfo2.basic_info.in.file.path = fname;
918         
919         status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
920
921         if (!NT_STATUS_IS_OK(status)) {
922                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
923                 return false;
924         }
925         torture_comment(tctx, "write time %s\n",
926                nt_time_string(tctx, finfo2.basic_info.out.write_time));
927
928         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
929                 torture_comment(tctx, "Server updated write_time (correct)\n");
930         } else {
931                 torture_comment(tctx, "Server did not update write time (wrong!)\n");
932                 ret = false;
933         }
934
935         /* Now try a write to see if the write time gets reset. */
936
937         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
938         finfo1.basic_info.in.file.fnum = fnum1;
939         finfo2 = finfo1;
940
941         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
942
943         if (!NT_STATUS_IS_OK(status)) {
944                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
945                 return false;
946         }
947         
948         torture_comment(tctx, "Modified write time %s\n", 
949                nt_time_string(tctx, finfo1.basic_info.out.write_time));
950
951
952         torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
953
954         written =  smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
955
956         if (written != 10) {
957                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
958                        (int)written, __location__);
959                 return false;
960         }
961
962         /* Just to prove to tridge that the an smbflush has no effect on
963            the write time :-). The setfileinfo IS STICKY. JRA. */
964
965         torture_comment(tctx, "Doing flush after write\n");
966
967         flsh.flush.level        = RAW_FLUSH_FLUSH;
968         flsh.flush.in.file.fnum = fnum1;
969         status = smb_raw_flush(cli->tree, &flsh);
970         if (!NT_STATUS_IS_OK(status)) {
971                 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
972                 return false;
973         }
974
975         /* Once the time was set using setfileinfo then it stays set - writes
976            don't have any effect. But make sure. */
977         start = timeval_current();
978         end = timeval_add(&start, (15*sec), 0);
979         while (!timeval_expired(&end)) {
980                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
981
982                 if (!NT_STATUS_IS_OK(status)) {
983                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
984                         ret = false;
985                         break;
986                 }
987                 torture_comment(tctx, "write time %s\n", 
988                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
989                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
990                         double diff = timeval_elapsed(&start);
991                         torture_comment(tctx, "Server updated write_time after %.2f seconds"
992                                         "(1sec == %.2f) (wrong!)\n",
993                                         diff, sec);
994                         ret = false;
995                         break;
996                 }
997                 fflush(stdout);
998                 msleep(1 * msec);
999         }
1000         
1001         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1002                 torture_comment(tctx, "Server did not update write time (correct)\n");
1003         }
1004
1005         fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1006         if (fnum2 == -1) {
1007                 torture_comment(tctx, "Failed to open %s\n", fname);
1008                 return false;
1009         }
1010         
1011         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");
1012
1013         written =  smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
1014
1015         if (written != 10) {
1016                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
1017                        (int)written, __location__);
1018                 return false;
1019         }
1020
1021         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1022
1023         if (!NT_STATUS_IS_OK(status)) {
1024                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1025                 return false;
1026         }
1027         torture_comment(tctx, "write time %s\n", 
1028                nt_time_string(tctx, finfo2.basic_info.out.write_time));
1029         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1030                 torture_comment(tctx, "Server updated write_time (wrong!)\n");
1031                 ret = false;
1032         }
1033
1034         torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
1035         smbcli_close(cli->tree, fnum1);
1036         fnum1 = -1;
1037
1038         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");
1039
1040         written =  smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
1041
1042         if (written != 10) {
1043                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
1044                        (int)written, __location__);
1045                 return false;
1046         }
1047
1048         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1049         finfo1.basic_info.in.file.fnum = fnum2;
1050         finfo2 = finfo1;
1051         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1052
1053         if (!NT_STATUS_IS_OK(status)) {
1054                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1055                 return false;
1056         }
1057         torture_comment(tctx, "write time %s\n", 
1058                nt_time_string(tctx, finfo2.basic_info.out.write_time));
1059         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1060                 torture_comment(tctx, "Server updated write_time (wrong!)\n");
1061                 ret = false;
1062         }
1063
1064         /* Once the time was set using setfileinfo then it stays set - writes
1065            don't have any effect. But make sure. */
1066         start = timeval_current();
1067         end = timeval_add(&start, (15*sec), 0);
1068         while (!timeval_expired(&end)) {
1069                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1070
1071                 if (!NT_STATUS_IS_OK(status)) {
1072                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1073                         ret = false;
1074                         break;
1075                 }
1076                 torture_comment(tctx, "write time %s\n", 
1077                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
1078                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1079                         double diff = timeval_elapsed(&start);
1080                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
1081                                         "(1sec == %.2f) (wrong!)\n",
1082                                         diff, sec);
1083                         ret = false;
1084                         break;
1085                 }
1086                 fflush(stdout);
1087                 msleep(1 * msec);
1088         }
1089         
1090         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1091                 torture_comment(tctx, "Server did not update write time (correct)\n");
1092         }
1093
1094         torture_comment(tctx, "Closing second fd to see if write time updated.\n");
1095
1096         smbcli_close(cli->tree, fnum2);
1097         fnum2 = -1;
1098
1099         fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
1100         if (fnum1 == -1) {
1101                 torture_comment(tctx, "Failed to open %s\n", fname);
1102                 return false;
1103         }
1104
1105         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1106         finfo1.basic_info.in.file.fnum = fnum1;
1107         finfo2 = finfo1;
1108
1109         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1110
1111         if (!NT_STATUS_IS_OK(status)) {
1112                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1113                 return false;
1114         }
1115         
1116         torture_comment(tctx, "Second open initial write time %s\n", 
1117                nt_time_string(tctx, finfo1.basic_info.out.write_time));
1118
1119         msleep(10 * msec);
1120         torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
1121
1122         written =  smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
1123
1124         if (written != 10) {
1125                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
1126                        (int)written, __location__);
1127                 return false;
1128         }
1129
1130         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1131         finfo1.basic_info.in.file.fnum = fnum1;
1132         finfo2 = finfo1;
1133         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1134
1135         if (!NT_STATUS_IS_OK(status)) {
1136                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1137                 return false;
1138         }
1139         torture_comment(tctx, "write time %s\n", 
1140                nt_time_string(tctx, finfo2.basic_info.out.write_time));
1141         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1142                 torture_comment(tctx, "Server updated write_time (wrong!)\n");
1143                 ret = false;
1144         }
1145
1146         /* Now the write time should be updated again */
1147         start = timeval_current();
1148         end = timeval_add(&start, (15*sec), 0);
1149         while (!timeval_expired(&end)) {
1150                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
1151
1152                 if (!NT_STATUS_IS_OK(status)) {
1153                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
1154                         ret = false;
1155                         break;
1156                 }
1157                 torture_comment(tctx, "write time %s\n", 
1158                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
1159                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
1160                         double diff = timeval_elapsed(&start);
1161                         if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1162                                 torture_comment(tctx, "Server updated write_time after %.2f seconds"
1163                                                 "(1sec == %.2f) (wrong!)\n",
1164                                                 diff, sec);
1165                                 ret = false;
1166                                 break;
1167                         }
1168
1169                         torture_comment(tctx, "Server updated write_time after %.2f seconds"
1170                                         "(1sec == %.2f) (correct)\n",
1171                                         diff, sec);
1172                         break;
1173                 }
1174                 fflush(stdout);
1175                 msleep(1*msec);
1176         }
1177         
1178         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1179                 torture_comment(tctx, "Server did not update write time (wrong!)\n");
1180                 ret = false;
1181         }
1182
1183
1184         /* One more test to do. We should read the filetime via findfirst on the
1185            second connection to ensure it's the same. This is very easy for a Windows
1186            server but a bastard to get right on a POSIX server. JRA. */
1187
1188         if (fnum1 != -1)
1189                 smbcli_close(cli->tree, fnum1);
1190         smbcli_unlink(cli->tree, fname);
1191         smbcli_deltree(cli->tree, BASEDIR);
1192
1193         return ret;
1194 }
1195
1196
1197 /* Windows does obviously not update the stat info during a write call. I
1198  * *think* this is the problem causing a spurious Excel 2003 on XP error
1199  * message when saving a file. Excel does a setfileinfo, writes, and then does
1200  * a getpath(!)info. Or so... For Samba sometimes it displays an error message
1201  * that the file might have been changed in between. What i've been able to
1202  * trace down is that this happens if the getpathinfo after the write shows a
1203  * different last write time than the setfileinfo showed. This is really
1204  * nasty....
1205  */
1206
1207 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli, 
1208                                                                    struct smbcli_state *cli2)
1209 {
1210         union smb_fileinfo finfo1, finfo2;
1211         const char *fname = BASEDIR "\\torture_file.txt";
1212         NTSTATUS status;
1213         int fnum1 = -1;
1214         int fnum2;
1215         bool ret = true;
1216         ssize_t written;
1217         int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1218         int normal_delay = 2000000;
1219         double sec = ((double)used_delay) / ((double)normal_delay);
1220         int msec = 1000 * sec;
1221
1222         if (!torture_setup_dir(cli, BASEDIR)) {
1223                 return false;
1224         }
1225
1226         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1227         if (fnum1 == -1) {
1228                 ret = false;
1229                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1230                 goto done;
1231         }
1232
1233         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1234         finfo1.basic_info.in.file.fnum = fnum1;
1235
1236         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
1237
1238         if (!NT_STATUS_IS_OK(status)) {
1239                 ret = false;
1240                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1241                 goto done;
1242         }
1243
1244         msleep(1 * msec);
1245
1246         written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1247
1248         if (written != 1) {
1249                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1250                 ret = false;
1251                 goto done;
1252         }
1253
1254         fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
1255         if (fnum2 == -1) {
1256                 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s", 
1257                        smbcli_errstr(cli2->tree));
1258                 ret = false;
1259                 goto done;
1260         }
1261         
1262         written =  smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
1263         
1264         if (written != 1) {
1265                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", 
1266                        (int)written);
1267                 ret = false;
1268                 goto done;
1269         }
1270         
1271         finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1272         finfo2.basic_info.in.file.path = fname;
1273         
1274         status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
1275         
1276         if (!NT_STATUS_IS_OK(status)) {
1277                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", 
1278                           nt_errstr(status));
1279                 ret = false;
1280                 goto done;
1281         }
1282         
1283         if (finfo1.basic_info.out.create_time !=
1284             finfo2.basic_info.out.create_time) {
1285                 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
1286                 ret = false;
1287                 goto done;
1288         }
1289         
1290         if (finfo1.basic_info.out.access_time !=
1291             finfo2.basic_info.out.access_time) {
1292                 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
1293                 ret = false;
1294                 goto done;
1295         }
1296         
1297         if (finfo1.basic_info.out.write_time !=
1298             finfo2.basic_info.out.write_time) {
1299                 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
1300                                            "write time conn 1 = %s, conn 2 = %s", 
1301                        nt_time_string(tctx, finfo1.basic_info.out.write_time),
1302                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
1303                 ret = false;
1304                 goto done;
1305         }
1306         
1307         if (finfo1.basic_info.out.change_time !=
1308             finfo2.basic_info.out.change_time) {
1309                 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
1310                 ret = false;
1311                 goto done;
1312         }
1313         
1314         /* One of the two following calls updates the qpathinfo. */
1315         
1316         /* If you had skipped the smbcli_write on fnum2, it would
1317          * *not* have updated the stat on disk */
1318         
1319         smbcli_close(cli2->tree, fnum2);
1320         cli2 = NULL;
1321
1322         /* This call is only for the people looking at ethereal :-) */
1323         finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1324         finfo2.basic_info.in.file.path = fname;
1325
1326         status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
1327
1328         if (!NT_STATUS_IS_OK(status)) {
1329                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
1330                 ret = false;
1331                 goto done;
1332         }
1333
1334  done:
1335         if (fnum1 != -1)
1336                 smbcli_close(cli->tree, fnum1);
1337         smbcli_unlink(cli->tree, fname);
1338         smbcli_deltree(cli->tree, BASEDIR);
1339
1340         return ret;
1341 }
1342
1343 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
1344         uint64_t r = 10*1000*1000; \
1345         NTTIME g = (given).basic_info.out.write_time; \
1346         NTTIME gr = (g / r) * r; \
1347         NTTIME c = (correct).basic_info.out.write_time; \
1348         NTTIME cr = (c / r) * r; \
1349         bool strict = torture_setting_bool(tctx, "strict mode", false); \
1350         bool err = false; \
1351         if (strict && (g cmp c)) { \
1352                 err = true; \
1353         } else if ((g cmp c) && (gr cmp cr)) { \
1354                 /* handle filesystem without high resolution timestamps */ \
1355                 err = true; \
1356         } \
1357         if (err) { \
1358                 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
1359                                 #given, nt_time_string(tctx, g), (unsigned long long)g, \
1360                                 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
1361                 ret = false; \
1362                 goto done; \
1363         } \
1364 } while (0)
1365 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
1366         COMPARE_WRITE_TIME_CMP(given,correct,!=)
1367 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
1368         COMPARE_WRITE_TIME_CMP(given,correct,<=)
1369 #define COMPARE_WRITE_TIME_LESS(given,correct) \
1370         COMPARE_WRITE_TIME_CMP(given,correct,>=)
1371
1372 #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
1373         NTTIME g = (given).basic_info.out.access_time; \
1374         NTTIME c = (correct).basic_info.out.access_time; \
1375         if (g cmp c) { \
1376                 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
1377                                 #given, nt_time_string(tctx, g), \
1378                                 #cmp, #correct, nt_time_string(tctx, c)); \
1379                 ret = false; \
1380                 goto done; \
1381         } \
1382 } while (0)
1383 #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
1384         COMPARE_ACCESS_TIME_CMP(given,correct,!=)
1385
1386 #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
1387         COMPARE_ACCESS_TIME_EQUAL(given,correct); \
1388         COMPARE_WRITE_TIME_EQUAL(given,correct); \
1389 } while (0)
1390
1391 #define GET_INFO_FILE(finfo) do { \
1392         NTSTATUS _status; \
1393         _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
1394         if (!NT_STATUS_IS_OK(_status)) { \
1395                 ret = false; \
1396                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
1397                                nt_errstr(_status)); \
1398                 goto done; \
1399         } \
1400         torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
1401                         nt_time_string(tctx, finfo.basic_info.out.access_time), \
1402                         nt_time_string(tctx, finfo.basic_info.out.write_time)); \
1403 } while (0)
1404 #define GET_INFO_PATH(pinfo) do { \
1405         NTSTATUS _status; \
1406         _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
1407         if (!NT_STATUS_IS_OK(_status)) { \
1408                 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
1409                                nt_errstr(_status)); \
1410                 ret = false; \
1411                 goto done; \
1412         } \
1413         torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
1414                         nt_time_string(tctx, pinfo.basic_info.out.access_time), \
1415                         nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
1416 } while (0)
1417 #define GET_INFO_BOTH(finfo,pinfo) do { \
1418         GET_INFO_FILE(finfo); \
1419         GET_INFO_PATH(pinfo); \
1420         COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
1421 } while (0)
1422
1423 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
1424         NTSTATUS _status; \
1425         union smb_setfileinfo sfinfo; \
1426         sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
1427         sfinfo.basic_info.in.file.fnum = tfnum; \
1428         sfinfo.basic_info.in.create_time = 0; \
1429         sfinfo.basic_info.in.access_time = 0; \
1430         unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
1431         sfinfo.basic_info.in.change_time = 0; \
1432         sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
1433         _status = smb_raw_setfileinfo(tree, &sfinfo); \
1434         if (!NT_STATUS_IS_OK(_status)) { \
1435                 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
1436                                nt_errstr(_status)); \
1437                 ret = false; \
1438                 goto done; \
1439         } \
1440 } while (0)
1441 #define SET_INFO_FILE(finfo, wrtime) \
1442         SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
1443
1444 static bool test_delayed_write_update3(struct torture_context *tctx,
1445                                        struct smbcli_state *cli,
1446                                        struct smbcli_state *cli2)
1447 {
1448         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1449         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1450         const char *fname = BASEDIR "\\torture_file.txt";
1451         int fnum1 = -1;
1452         bool ret = true;
1453         ssize_t written;
1454         struct timeval start;
1455         struct timeval end;
1456         int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1457         int normal_delay = 2000000;
1458         double sec = ((double)used_delay) / ((double)normal_delay);
1459         int msec = 1000 * sec;
1460
1461         if (!torture_setup_dir(cli, BASEDIR)) {
1462                 return false;
1463         }
1464
1465         torture_comment(tctx, "Open the file handle\n");
1466         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1467         if (fnum1 == -1) {
1468                 ret = false;
1469                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1470                 goto done;
1471         }
1472
1473         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1474         finfo0.basic_info.in.file.fnum = fnum1;
1475         finfo1 = finfo0;
1476         finfo2 = finfo0;
1477         finfo3 = finfo0;
1478         finfo4 = finfo0;
1479         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1480         pinfo0.basic_info.in.file.path = fname;
1481         pinfo1 = pinfo0;
1482         pinfo2 = pinfo0;
1483         pinfo3 = pinfo0;
1484         pinfo4 = pinfo0;
1485         pinfo5 = pinfo0;
1486
1487         /* get the initial times */
1488         GET_INFO_BOTH(finfo0,pinfo0);
1489
1490         /*
1491          * make sure the write time is updated 2 seconds later
1492          * calcuated from the first write
1493          * (but expect upto 5 seconds extra time for a busy server)
1494          */
1495         start = timeval_current();
1496         end = timeval_add(&start, 7 * sec, 0);
1497         while (!timeval_expired(&end)) {
1498                 /* do a write */
1499                 torture_comment(tctx, "Do a write on the file handle\n");
1500                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1501                 if (written != 1) {
1502                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1503                         ret = false;
1504                         goto done;
1505                 }
1506                 /* get the times after the write */
1507                 GET_INFO_FILE(finfo1);
1508
1509                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1510                         double diff = timeval_elapsed(&start);
1511                         if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1512                                 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1513                                                 "(1sec == %.2f) (wrong!)\n",
1514                                                 diff, sec);
1515                                 ret = false;
1516                                 break;
1517                         }
1518
1519                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
1520                                         "(1sec == %.2f) (correct)\n",
1521                                         diff, sec);
1522                         break;
1523                 }
1524                 msleep(0.5 * msec);
1525         }
1526
1527         GET_INFO_BOTH(finfo1,pinfo1);
1528         COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1529
1530         /* sure any further write doesn't update the write time */
1531         start = timeval_current();
1532         end = timeval_add(&start, 15 * 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_BOTH(finfo2,pinfo2);
1544
1545                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1546                         double diff = timeval_elapsed(&start);
1547                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
1548                                         "(1sec == %.2f) (wrong!)\n",
1549                                         diff, sec);
1550                         ret = false;
1551                         break;
1552                 }
1553                 msleep(2 * msec);
1554         }
1555
1556         GET_INFO_BOTH(finfo2,pinfo2);
1557         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1558         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1559                 torture_comment(tctx, "Server did not update write_time (correct)\n");
1560         }
1561
1562         /* sleep */
1563         msleep(5 * msec);
1564
1565         GET_INFO_BOTH(finfo3,pinfo3);
1566         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1567
1568         /*
1569          * the close updates the write time to the time of the close
1570          * and not to the time of the last write!
1571          */
1572         torture_comment(tctx, "Close the file handle\n");
1573         smbcli_close(cli->tree, fnum1);
1574         fnum1 = -1;
1575
1576         GET_INFO_PATH(pinfo4);
1577         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1578
1579         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1580                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1581         }
1582
1583  done:
1584         if (fnum1 != -1)
1585                 smbcli_close(cli->tree, fnum1);
1586         smbcli_unlink(cli->tree, fname);
1587         smbcli_deltree(cli->tree, BASEDIR);
1588
1589         return ret;
1590 }
1591
1592 static bool test_delayed_write_update3b(struct torture_context *tctx,
1593                                         struct smbcli_state *cli,
1594                                         struct smbcli_state *cli2)
1595 {
1596         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1597         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1598         const char *fname = BASEDIR "\\torture_file.txt";
1599         int fnum1 = -1;
1600         bool ret = true;
1601         ssize_t written;
1602         struct timeval start;
1603         struct timeval end;
1604         int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1605         int normal_delay = 2000000;
1606         double sec = ((double)used_delay) / ((double)normal_delay);
1607         int msec = 1000 * sec;
1608
1609         if (!torture_setup_dir(cli, BASEDIR)) {
1610                 return false;
1611         }
1612
1613         torture_comment(tctx, "Open the file handle\n");
1614         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1615         if (fnum1 == -1) {
1616                 ret = false;
1617                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1618                 goto done;
1619         }
1620
1621         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1622         finfo0.basic_info.in.file.fnum = fnum1;
1623         finfo1 = finfo0;
1624         finfo2 = finfo0;
1625         finfo3 = finfo0;
1626         finfo4 = finfo0;
1627         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1628         pinfo0.basic_info.in.file.path = fname;
1629         pinfo1 = pinfo0;
1630         pinfo2 = pinfo0;
1631         pinfo3 = pinfo0;
1632         pinfo4 = pinfo0;
1633         pinfo5 = pinfo0;
1634
1635         /* get the initial times */
1636         GET_INFO_BOTH(finfo0,pinfo0);
1637
1638         /*
1639          * sleep some time, to demonstrate the handling of write times
1640          * doesn't depend on the time since the open
1641          */
1642         msleep(5 * msec);
1643
1644         /* get the initial times */
1645         GET_INFO_BOTH(finfo1,pinfo1);
1646         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1647
1648         /*
1649          * make sure the write time is updated 2 seconds later
1650          * calcuated from the first write
1651          * (but expect upto 5 seconds extra time for a busy server)
1652          */
1653         start = timeval_current();
1654         end = timeval_add(&start, 7 * sec, 0);
1655         while (!timeval_expired(&end)) {
1656                 /* do a write */
1657                 torture_comment(tctx, "Do a write on the file handle\n");
1658                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1659                 if (written != 1) {
1660                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1661                         ret = false;
1662                         goto done;
1663                 }
1664                 /* get the times after the write */
1665                 GET_INFO_FILE(finfo1);
1666
1667                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1668                         double diff = timeval_elapsed(&start);
1669                         if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1670                                 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1671                                                 "(1sec == %.2f) (wrong!)\n",
1672                                                 diff, sec);
1673                                 ret = false;
1674                                 break;
1675                         }
1676
1677                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
1678                                         "(1sec == %.2f) (correct)\n",
1679                                         diff, sec);
1680                         break;
1681                 }
1682                 msleep(0.5 * msec);
1683         }
1684
1685         GET_INFO_BOTH(finfo1,pinfo1);
1686         COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1687
1688         /* sure any further write doesn't update the write time */
1689         start = timeval_current();
1690         end = timeval_add(&start, 15 * sec, 0);
1691         while (!timeval_expired(&end)) {
1692                 /* do a write */
1693                 torture_comment(tctx, "Do a write on the file handle\n");
1694                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1695                 if (written != 1) {
1696                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1697                         ret = false;
1698                         goto done;
1699                 }
1700                 /* get the times after the write */
1701                 GET_INFO_BOTH(finfo2,pinfo2);
1702
1703                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1704                         double diff = timeval_elapsed(&start);
1705                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
1706                                         "(1sec == %.2f) (wrong!)\n",
1707                                         diff, sec);
1708                         ret = false;
1709                         break;
1710                 }
1711                 msleep(2 * msec);
1712         }
1713
1714         GET_INFO_BOTH(finfo2,pinfo2);
1715         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1716         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1717                 torture_comment(tctx, "Server did not update write_time (correct)\n");
1718         }
1719
1720         /* sleep */
1721         msleep(5 * msec);
1722
1723         GET_INFO_BOTH(finfo3,pinfo3);
1724         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1725
1726         /*
1727          * the close updates the write time to the time of the close
1728          * and not to the time of the last write!
1729          */
1730         torture_comment(tctx, "Close the file handle\n");
1731         smbcli_close(cli->tree, fnum1);
1732         fnum1 = -1;
1733
1734         GET_INFO_PATH(pinfo4);
1735         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1736
1737         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1738                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1739         }
1740
1741  done:
1742         if (fnum1 != -1)
1743                 smbcli_close(cli->tree, fnum1);
1744         smbcli_unlink(cli->tree, fname);
1745         smbcli_deltree(cli->tree, BASEDIR);
1746
1747         return ret;
1748 }
1749
1750 static bool test_delayed_write_update4(struct torture_context *tctx,
1751                                        struct smbcli_state *cli,
1752                                        struct smbcli_state *cli2)
1753 {
1754         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
1755         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
1756         const char *fname = BASEDIR "\\torture_file.txt";
1757         int fnum1 = -1;
1758         bool ret = true;
1759         ssize_t written;
1760         struct timeval start;
1761         struct timeval end;
1762         int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1763         int normal_delay = 2000000;
1764         double sec = ((double)used_delay) / ((double)normal_delay);
1765         int msec = 1000 * sec;
1766
1767         if (!torture_setup_dir(cli, BASEDIR)) {
1768                 return false;
1769         }
1770
1771         torture_comment(tctx, "Open the file handle\n");
1772         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1773         if (fnum1 == -1) {
1774                 ret = false;
1775                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1776                 goto done;
1777         }
1778
1779         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1780         finfo0.basic_info.in.file.fnum = fnum1;
1781         finfo1 = finfo0;
1782         finfo2 = finfo0;
1783         finfo3 = finfo0;
1784         finfo4 = finfo0;
1785         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1786         pinfo0.basic_info.in.file.path = fname;
1787         pinfo1 = pinfo0;
1788         pinfo2 = pinfo0;
1789         pinfo3 = pinfo0;
1790         pinfo4 = pinfo0;
1791         pinfo5 = pinfo0;
1792
1793         /* get the initial times */
1794         GET_INFO_BOTH(finfo0,pinfo0);
1795
1796         /* sleep a bit */
1797         msleep(5 * msec);
1798
1799         /* do a write */
1800         torture_comment(tctx, "Do a write on the file handle\n");
1801         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1802         if (written != 1) {
1803                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1804                 ret = false;
1805                 goto done;
1806         }
1807
1808         GET_INFO_BOTH(finfo1,pinfo1);
1809         COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
1810
1811         /*
1812          * make sure the write time is updated 2 seconds later
1813          * calcuated from the first write
1814          * (but expect upto 3 seconds extra time for a busy server)
1815          */
1816         start = timeval_current();
1817         end = timeval_add(&start, 5 * sec, 0);
1818         while (!timeval_expired(&end)) {
1819                 /* get the times after the first write */
1820                 GET_INFO_FILE(finfo1);
1821
1822                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
1823                         double diff = timeval_elapsed(&start);
1824                         if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
1825                                 torture_comment(tctx, "Server updated write_time after %.2f seconds "
1826                                                 "(1sec == %.2f) (wrong!)\n",
1827                                                 diff, sec);
1828                                 ret = false;
1829                                 break;
1830                         }
1831
1832                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
1833                                         "(1sec == %.2f) (correct)\n",
1834                                         diff, sec);
1835                         break;
1836                 }
1837                 msleep(0.5 * msec);
1838         }
1839
1840         GET_INFO_BOTH(finfo1,pinfo1);
1841         COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
1842
1843         /* sure any further write doesn't update the write time */
1844         start = timeval_current();
1845         end = timeval_add(&start, 15 * sec, 0);
1846         while (!timeval_expired(&end)) {
1847                 /* do a write */
1848                 torture_comment(tctx, "Do a write on the file handle\n");
1849                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1850                 if (written != 1) {
1851                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1852                         ret = false;
1853                         goto done;
1854                 }
1855                 /* get the times after the write */
1856                 GET_INFO_BOTH(finfo2,pinfo2);
1857
1858                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
1859                         double diff = timeval_elapsed(&start);
1860                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
1861                                         "(1sec == %.2f) (wrong!)\n",
1862                                         diff, sec);
1863                         ret = false;
1864                         break;
1865                 }
1866                 msleep(2 * msec);
1867         }
1868
1869         GET_INFO_BOTH(finfo2,pinfo2);
1870         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
1871         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
1872                 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
1873         }
1874
1875         /* sleep */
1876         msleep(5 * msec);
1877
1878         GET_INFO_BOTH(finfo3,pinfo3);
1879         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1880
1881         /*
1882          * the close updates the write time to the time of the close
1883          * and not to the time of the last write!
1884          */
1885         torture_comment(tctx, "Close the file handle\n");
1886         smbcli_close(cli->tree, fnum1);
1887         fnum1 = -1;
1888
1889         GET_INFO_PATH(pinfo4);
1890         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
1891
1892         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
1893                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1894         }
1895
1896  done:
1897         if (fnum1 != -1)
1898                 smbcli_close(cli->tree, fnum1);
1899         smbcli_unlink(cli->tree, fname);
1900         smbcli_deltree(cli->tree, BASEDIR);
1901
1902         return ret;
1903 }
1904
1905 static bool test_delayed_write_update5(struct torture_context *tctx,
1906                                        struct smbcli_state *cli,
1907                                        struct smbcli_state *cli2)
1908 {
1909         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
1910         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
1911         const char *fname = BASEDIR "\\torture_file.txt";
1912         int fnum1 = -1;
1913         bool ret = true;
1914         ssize_t written;
1915         struct timeval start;
1916         struct timeval end;
1917         int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
1918         int normal_delay = 2000000;
1919         double sec = ((double)used_delay) / ((double)normal_delay);
1920         int msec = 1000 * sec;
1921
1922         if (!torture_setup_dir(cli, BASEDIR)) {
1923                 return false;
1924         }
1925
1926         torture_comment(tctx, "Open the file handle\n");
1927         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1928         if (fnum1 == -1) {
1929                 ret = false;
1930                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1931                 goto done;
1932         }
1933
1934         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1935         finfo0.basic_info.in.file.fnum = fnum1;
1936         finfo1 = finfo0;
1937         finfo2 = finfo0;
1938         finfo3 = finfo0;
1939         finfo4 = finfo0;
1940         finfo5 = finfo0;
1941         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1942         pinfo0.basic_info.in.file.path = fname;
1943         pinfo1 = pinfo0;
1944         pinfo2 = pinfo0;
1945         pinfo3 = pinfo0;
1946         pinfo4 = pinfo0;
1947         pinfo5 = pinfo0;
1948         pinfo6 = pinfo0;
1949
1950         /* get the initial times */
1951         GET_INFO_BOTH(finfo0,pinfo0);
1952
1953         /* do a write */
1954         torture_comment(tctx, "Do a write on the file handle\n");
1955         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1956         if (written != 1) {
1957                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1958                 ret = false;
1959                 goto done;
1960         }
1961
1962         GET_INFO_BOTH(finfo1,pinfo1);
1963         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1964
1965         torture_comment(tctx, "Set write time in the future on the file handle\n");
1966         SET_INFO_FILE(finfo0, time(NULL) + 86400);
1967         GET_INFO_BOTH(finfo2,pinfo2);
1968         COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1969
1970         torture_comment(tctx, "Set write time in the past on the file handle\n");
1971         SET_INFO_FILE(finfo0, time(NULL) - 86400);
1972         GET_INFO_BOTH(finfo2,pinfo2);
1973         COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
1974
1975         /* make sure the 2 second delay from the first write are canceled */
1976         start = timeval_current();
1977         end = timeval_add(&start, 15 * sec, 0);
1978         while (!timeval_expired(&end)) {
1979
1980                 /* get the times after the first write */
1981                 GET_INFO_BOTH(finfo3,pinfo3);
1982
1983                 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
1984                         double diff = timeval_elapsed(&start);
1985                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
1986                                         "(1sec == %.2f) (wrong!)\n",
1987                                         diff, sec);
1988                         ret = false;
1989                         break;
1990                 }
1991                 msleep(2 * msec);
1992         }
1993
1994         GET_INFO_BOTH(finfo3,pinfo3);
1995         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1996         if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
1997                 torture_comment(tctx, "Server did not update write_time (correct)\n");
1998         }
1999
2000         /* sure any further write doesn't update the write time */
2001         start = timeval_current();
2002         end = timeval_add(&start, 15 * sec, 0);
2003         while (!timeval_expired(&end)) {
2004                 /* do a write */
2005                 torture_comment(tctx, "Do a write on the file handle\n");
2006                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2007                 if (written != 1) {
2008                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2009                         ret = false;
2010                         goto done;
2011                 }
2012                 /* get the times after the write */
2013                 GET_INFO_BOTH(finfo4,pinfo4);
2014
2015                 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2016                         double diff = timeval_elapsed(&start);
2017                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
2018                                         "(1sec == %.2f) (wrong!)\n",
2019                                         diff, sec);
2020                         ret = false;
2021                         break;
2022                 }
2023                 msleep(2 * msec);
2024         }
2025
2026         GET_INFO_BOTH(finfo4,pinfo4);
2027         COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2028         if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2029                 torture_comment(tctx, "Server did not update write_time (correct)\n");
2030         }
2031
2032         /* sleep */
2033         msleep(5 * msec);
2034
2035         GET_INFO_BOTH(finfo5,pinfo5);
2036         COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2037
2038         /*
2039          * the close doesn't update the write time
2040          */
2041         torture_comment(tctx, "Close the file handle\n");
2042         smbcli_close(cli->tree, fnum1);
2043         fnum1 = -1;
2044
2045         GET_INFO_PATH(pinfo6);
2046         COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2047
2048         if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2049                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2050         }
2051
2052  done:
2053         if (fnum1 != -1)
2054                 smbcli_close(cli->tree, fnum1);
2055         smbcli_unlink(cli->tree, fname);
2056         smbcli_deltree(cli->tree, BASEDIR);
2057
2058         return ret;
2059 }
2060
2061 static bool test_delayed_write_update5b(struct torture_context *tctx,
2062                                         struct smbcli_state *cli,
2063                                         struct smbcli_state *cli2)
2064 {
2065         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2066         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
2067         const char *fname = BASEDIR "\\torture_file.txt";
2068         int fnum1 = -1;
2069         bool ret = true;
2070         ssize_t written;
2071         struct timeval start;
2072         struct timeval end;
2073         int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2074         int normal_delay = 2000000;
2075         double sec = ((double)used_delay) / ((double)normal_delay);
2076         int msec = 1000 * sec;
2077
2078         if (!torture_setup_dir(cli, BASEDIR)) {
2079                 return false;
2080         }
2081
2082         torture_comment(tctx, "Open the file handle\n");
2083         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2084         if (fnum1 == -1) {
2085                 ret = false;
2086                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2087                 goto done;
2088         }
2089
2090         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2091         finfo0.basic_info.in.file.fnum = fnum1;
2092         finfo1 = finfo0;
2093         finfo2 = finfo0;
2094         finfo3 = finfo0;
2095         finfo4 = finfo0;
2096         finfo5 = finfo0;
2097         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2098         pinfo0.basic_info.in.file.path = fname;
2099         pinfo1 = pinfo0;
2100         pinfo2 = pinfo0;
2101         pinfo3 = pinfo0;
2102         pinfo4 = pinfo0;
2103         pinfo5 = pinfo0;
2104         pinfo6 = pinfo0;
2105
2106         /* get the initial times */
2107         GET_INFO_BOTH(finfo0,pinfo0);
2108
2109         /* do a write */
2110         torture_comment(tctx, "Do a write on the file handle\n");
2111         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2112         if (written != 1) {
2113                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2114                 ret = false;
2115                 goto done;
2116         }
2117
2118         GET_INFO_BOTH(finfo1,pinfo1);
2119         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2120
2121         torture_comment(tctx, "Set write time in the future on the file handle\n");
2122         SET_INFO_FILE(finfo0, time(NULL) + 86400);
2123         GET_INFO_BOTH(finfo2,pinfo2);
2124         COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2125
2126         torture_comment(tctx, "Set write time in the past on the file handle\n");
2127         SET_INFO_FILE(finfo0, time(NULL) - 86400);
2128         GET_INFO_BOTH(finfo2,pinfo2);
2129         COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2130
2131         /* make sure the 2 second delay from the first write are canceled */
2132         start = timeval_current();
2133         end = timeval_add(&start, 15 * sec, 0);
2134         while (!timeval_expired(&end)) {
2135
2136                 /* get the times after the first write */
2137                 GET_INFO_BOTH(finfo3,pinfo3);
2138
2139                 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2140                         double diff = timeval_elapsed(&start);
2141                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
2142                                         "(1sec == %.2f) (wrong!)\n",
2143                                         diff, sec);
2144                         ret = false;
2145                         break;
2146                 }
2147                 msleep(2 * msec);
2148         }
2149
2150         GET_INFO_BOTH(finfo3,pinfo3);
2151         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2152         if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2153                 torture_comment(tctx, "Server did not update write_time (correct)\n");
2154         }
2155
2156         /* sure any further write (truncates) update the write time */
2157         start = timeval_current();
2158         end = timeval_add(&start, 15 * sec, 0);
2159         while (!timeval_expired(&end)) {
2160                 /* do a write */
2161                 torture_comment(tctx, "Do a truncate write on the file handle\n");
2162                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 0);
2163                 if (written != 0) {
2164                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2165                         ret = false;
2166                         goto done;
2167                 }
2168                 /* get the times after the write */
2169                 GET_INFO_BOTH(finfo4,pinfo4);
2170
2171                 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2172                         double diff = timeval_elapsed(&start);
2173                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
2174                                         "(1sec == %.2f) (wrong!)\n",
2175                                         diff, sec);
2176                         ret = false;
2177                         break;
2178                 }
2179                 msleep(2 * msec);
2180         }
2181
2182         GET_INFO_BOTH(finfo4,pinfo4);
2183         COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2184         if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2185                 torture_comment(tctx, "Server did not update write_time (correct)\n");
2186         }
2187
2188         /* sleep */
2189         msleep(5 * msec);
2190
2191         GET_INFO_BOTH(finfo5,pinfo5);
2192         COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2193
2194         /*
2195          * the close doesn't update the write time
2196          */
2197         torture_comment(tctx, "Close the file handle\n");
2198         smbcli_close(cli->tree, fnum1);
2199         fnum1 = -1;
2200
2201         GET_INFO_PATH(pinfo6);
2202         COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
2203
2204         if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
2205                 torture_comment(tctx, "Server did not update 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 static bool test_delayed_write_update6(struct torture_context *tctx,
2218                                        struct smbcli_state *cli,
2219                                        struct smbcli_state *cli2)
2220 {
2221         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
2222         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
2223         const char *fname = BASEDIR "\\torture_file.txt";
2224         int fnum1 = -1;
2225         int fnum2 = -1;
2226         bool ret = true;
2227         ssize_t written;
2228         struct timeval start;
2229         struct timeval end;
2230         int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
2231         int normal_delay = 2000000;
2232         double sec = ((double)used_delay) / ((double)normal_delay);
2233         int msec = 1000 * sec;
2234         bool first = true;
2235
2236         if (!torture_setup_dir(cli, BASEDIR)) {
2237                 return false;
2238         }
2239 again:
2240         torture_comment(tctx, "Open the file handle\n");
2241         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2242         if (fnum1 == -1) {
2243                 ret = false;
2244                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2245                 goto done;
2246         }
2247
2248         if (fnum2 == -1) {
2249                 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
2250                 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
2251                 if (fnum2 == -1) {
2252                         ret = false;
2253                         torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
2254                         goto done;
2255                 }
2256         }
2257
2258         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2259         finfo0.basic_info.in.file.fnum = fnum1;
2260         finfo1 = finfo0;
2261         finfo2 = finfo0;
2262         finfo3 = finfo0;
2263         finfo4 = finfo0;
2264         finfo5 = finfo0;
2265         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
2266         pinfo0.basic_info.in.file.path = fname;
2267         pinfo1 = pinfo0;
2268         pinfo2 = pinfo0;
2269         pinfo3 = pinfo0;
2270         pinfo4 = pinfo0;
2271         pinfo5 = pinfo0;
2272         pinfo6 = pinfo0;
2273         pinfo7 = pinfo0;
2274
2275         /* get the initial times */
2276         GET_INFO_BOTH(finfo0,pinfo0);
2277
2278         /* do a write */
2279         torture_comment(tctx, "Do a write on the file handle\n");
2280         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2281         if (written != 1) {
2282                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2283                 ret = false;
2284                 goto done;
2285         }
2286
2287         GET_INFO_BOTH(finfo1,pinfo1);
2288         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
2289
2290         torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
2291         SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
2292         GET_INFO_BOTH(finfo2,pinfo2);
2293         COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
2294
2295         torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
2296         SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
2297         GET_INFO_BOTH(finfo2,pinfo2);
2298         COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
2299
2300         /* make sure the 2 second delay from the first write are canceled */
2301         start = timeval_current();
2302         end = timeval_add(&start, 15 * sec, 0);
2303         while (!timeval_expired(&end)) {
2304
2305                 /* get the times after the first write */
2306                 GET_INFO_BOTH(finfo3,pinfo3);
2307
2308                 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
2309                         double diff = timeval_elapsed(&start);
2310                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
2311                                         "(1sec == %.2f) (wrong!)\n",
2312                                         diff, sec);
2313                         ret = false;
2314                         break;
2315                 }
2316                 msleep(2 * msec);
2317         }
2318
2319         GET_INFO_BOTH(finfo3,pinfo3);
2320         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
2321         if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
2322                 torture_comment(tctx, "Server did not update write_time (correct)\n");
2323         }
2324
2325         /* sure any further write doesn't update the write time */
2326         start = timeval_current();
2327         end = timeval_add(&start, 15 * sec, 0);
2328         while (!timeval_expired(&end)) {
2329                 /* do a write */
2330                 torture_comment(tctx, "Do a write on the file handle\n");
2331                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
2332                 if (written != 1) {
2333                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
2334                         ret = false;
2335                         goto done;
2336                 }
2337                 /* get the times after the write */
2338                 GET_INFO_BOTH(finfo4,pinfo4);
2339
2340                 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
2341                         double diff = timeval_elapsed(&start);
2342                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
2343                                         "(1sec == %.2f) (wrong!)\n",
2344                                         diff, sec);
2345                         ret = false;
2346                         break;
2347                 }
2348                 msleep(2 * msec);
2349         }
2350
2351         GET_INFO_BOTH(finfo4,pinfo4);
2352         COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
2353         if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
2354                 torture_comment(tctx, "Server did not update write_time (correct)\n");
2355         }
2356
2357         /* sleep */
2358         msleep(5 * msec);
2359
2360         GET_INFO_BOTH(finfo5,pinfo5);
2361         COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
2362
2363         /*
2364          * the close updates the write time to the time of the close
2365          * as the write time was set on the 2nd handle
2366          */
2367         torture_comment(tctx, "Close the file handle\n");
2368         smbcli_close(cli->tree, fnum1);
2369         fnum1 = -1;
2370
2371         GET_INFO_PATH(pinfo6);
2372         COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
2373
2374         if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
2375                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
2376         }
2377
2378         /* keep the 2nd handle open and rerun tests */
2379         if (first) {
2380                 first = false;
2381                 goto again;
2382         }
2383
2384         /*
2385          * closing the 2nd handle will cause no write time update
2386          * as the write time was explicit set on this handle
2387          */
2388         torture_comment(tctx, "Close the 2nd file handle\n");
2389         smbcli_close(cli2->tree, fnum2);
2390         fnum2 = -1;
2391
2392         GET_INFO_PATH(pinfo7);
2393         COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
2394
2395         if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
2396                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
2397         }
2398
2399  done:
2400         if (fnum1 != -1)
2401                 smbcli_close(cli->tree, fnum1);
2402         if (fnum2 != -1)
2403                 smbcli_close(cli2->tree, fnum2);
2404         smbcli_unlink(cli->tree, fname);
2405         smbcli_deltree(cli->tree, BASEDIR);
2406
2407         return ret;
2408 }
2409
2410
2411 /* 
2412    testing of delayed update of write_time
2413 */
2414 struct torture_suite *torture_delay_write(void)
2415 {
2416         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "DELAYWRITE");
2417
2418         torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
2419         torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
2420         torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate ", test_delayed_write_update1);
2421         torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
2422         torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
2423         torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
2424         torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
2425         torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
2426         torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
2427         torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
2428         torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
2429         torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
2430         torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
2431
2432         return suite;
2433 }