r26220: BASE-DELAYWRITE: add more subtests to explore write time update details
[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 "system/time.h"
28 #include "system/filesys.h"
29 #include "libcli/libcli.h"
30 #include "torture/util.h"
31
32 #define BASEDIR "\\delaywrite"
33
34 static bool test_delayed_write_update(struct torture_context *tctx, struct smbcli_state *cli)
35 {
36         union smb_fileinfo finfo1, finfo2;
37         const char *fname = BASEDIR "\\torture_file.txt";
38         NTSTATUS status;
39         int fnum1 = -1;
40         bool ret = true;
41         ssize_t written;
42         time_t t;
43
44         if (!torture_setup_dir(cli, BASEDIR)) {
45                 return false;
46         }
47
48         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
49         if (fnum1 == -1) {
50                 torture_comment(tctx, "Failed to open %s\n", fname);
51                 return false;
52         }
53
54         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
55         finfo1.basic_info.in.file.fnum = fnum1;
56         finfo2 = finfo1;
57
58         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
59
60         if (!NT_STATUS_IS_OK(status)) {
61                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
62                 return false;
63         }
64         
65         torture_comment(tctx, "Initial write time %s\n", 
66                nt_time_string(tctx, finfo1.basic_info.out.write_time));
67
68         /* 3 second delay to ensure we get past any 2 second time
69            granularity (older systems may have that) */
70         sleep(3);
71
72         written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
73
74         if (written != 1) {
75                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
76                        (int)written, __location__);
77                 return false;
78         }
79
80         t = time(NULL);
81
82         while (time(NULL) < t+120) {
83                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
84
85                 if (!NT_STATUS_IS_OK(status)) {
86                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
87                         ret = false;
88                         break;
89                 }
90                 torture_comment(tctx, "write time %s\n", 
91                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
92                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
93                         int diff = time(NULL) - t;
94                         if (diff < 2) {
95                                 torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
96                                                 diff);
97                                 ret = false;
98                                 break;
99                         }
100
101                         torture_comment(tctx, "Server updated write_time after %d seconds (correct)\n",
102                                         diff);
103                         break;
104                 }
105                 sleep(1);
106                 fflush(stdout);
107         }
108         
109         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
110                 torture_comment(tctx, "Server did not update write time (wrong!)\n");
111                 ret = false;
112         }
113
114
115         if (fnum1 != -1)
116                 smbcli_close(cli->tree, fnum1);
117         smbcli_unlink(cli->tree, fname);
118         smbcli_deltree(cli->tree, BASEDIR);
119
120         return ret;
121 }
122
123 /* 
124  * Do as above, but using 2 connections.
125  */
126
127 static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli, 
128                                                                            struct smbcli_state *cli2)
129 {
130         union smb_fileinfo finfo1, finfo2;
131         const char *fname = BASEDIR "\\torture_file.txt";
132         NTSTATUS status;
133         int fnum1 = -1;
134         int fnum2 = -1;
135         bool ret = true;
136         ssize_t written;
137         time_t t;
138         union smb_flush flsh;
139
140         if (!torture_setup_dir(cli, BASEDIR)) {
141                 return false;
142         }
143
144         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
145         if (fnum1 == -1) {
146                 torture_comment(tctx, "Failed to open %s\n", fname);
147                 return false;
148         }
149
150         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
151         finfo1.basic_info.in.file.fnum = fnum1;
152         finfo2 = finfo1;
153
154         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
155
156         if (!NT_STATUS_IS_OK(status)) {
157                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
158                 return false;
159         }
160         
161         torture_comment(tctx, "Initial write time %s\n", 
162                nt_time_string(tctx, finfo1.basic_info.out.write_time));
163
164         /* 3 second delay to ensure we get past any 2 second time
165            granularity (older systems may have that) */
166         sleep(3);
167
168         {
169                 /* Try using setfileinfo instead of write to update write time. */
170                 union smb_setfileinfo sfinfo;
171                 time_t t_set = time(NULL);
172                 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
173                 sfinfo.basic_info.in.file.fnum = fnum1;
174                 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
175                 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
176
177                 /* I tried this with both + and - ve to see if it makes a different.
178                    It doesn't - once the filetime is set via setfileinfo it stays that way. */
179 #if 1
180                 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
181 #else
182                 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
183 #endif
184                 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
185                 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
186
187                 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
188
189                 if (!NT_STATUS_IS_OK(status)) {
190                         DEBUG(0, ("sfileinfo failed: %s\n", nt_errstr(status)));
191                         return false;
192                 }
193         }
194
195         finfo2.basic_info.in.file.path = fname;
196         
197         status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
198
199         if (!NT_STATUS_IS_OK(status)) {
200                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
201                 return false;
202         }
203         torture_comment(tctx, "write time %s\n",
204                nt_time_string(tctx, finfo2.basic_info.out.write_time));
205
206         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
207                 torture_comment(tctx, "Server updated write_time (correct)\n");
208         } else {
209                 torture_comment(tctx, "Server did not update write time (wrong!)\n");
210                 ret = false;
211         }
212
213         /* Now try a write to see if the write time gets reset. */
214
215         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
216         finfo1.basic_info.in.file.fnum = fnum1;
217         finfo2 = finfo1;
218
219         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
220
221         if (!NT_STATUS_IS_OK(status)) {
222                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
223                 return false;
224         }
225         
226         torture_comment(tctx, "Modified write time %s\n", 
227                nt_time_string(tctx, finfo1.basic_info.out.write_time));
228
229
230         torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
231
232         written =  smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
233
234         if (written != 10) {
235                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
236                        (int)written, __location__);
237                 return false;
238         }
239
240         /* Just to prove to tridge that the an smbflush has no effect on
241            the write time :-). The setfileinfo IS STICKY. JRA. */
242
243         torture_comment(tctx, "Doing flush after write\n");
244
245         flsh.flush.level        = RAW_FLUSH_FLUSH;
246         flsh.flush.in.file.fnum = fnum1;
247         status = smb_raw_flush(cli->tree, &flsh);
248         if (!NT_STATUS_IS_OK(status)) {
249                 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
250                 return false;
251         }
252
253         t = time(NULL);
254
255         /* Once the time was set using setfileinfo then it stays set - writes
256            don't have any effect. But make sure. */
257
258         while (time(NULL) < t+15) {
259                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
260
261                 if (!NT_STATUS_IS_OK(status)) {
262                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
263                         ret = false;
264                         break;
265                 }
266                 torture_comment(tctx, "write time %s\n", 
267                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
268                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
269                         torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
270                                (int)(time(NULL) - t));
271                         ret = false;
272                         break;
273                 }
274                 sleep(1);
275                 fflush(stdout);
276         }
277         
278         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
279                 torture_comment(tctx, "Server did not update write time (correct)\n");
280         }
281
282         fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
283         if (fnum2 == -1) {
284                 torture_comment(tctx, "Failed to open %s\n", fname);
285                 return false;
286         }
287         
288         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");
289
290         written =  smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
291
292         if (written != 10) {
293                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
294                        (int)written, __location__);
295                 return false;
296         }
297
298         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
299
300         if (!NT_STATUS_IS_OK(status)) {
301                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
302                 return false;
303         }
304         torture_comment(tctx, "write time %s\n", 
305                nt_time_string(tctx, finfo2.basic_info.out.write_time));
306         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
307                 torture_comment(tctx, "Server updated write_time (wrong!)\n");
308                 ret = false;
309         }
310
311         torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
312         smbcli_close(cli->tree, fnum1);
313         fnum1 = -1;
314
315         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");
316
317         written =  smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
318
319         if (written != 10) {
320                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
321                        (int)written, __location__);
322                 return false;
323         }
324
325         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
326         finfo1.basic_info.in.file.fnum = fnum2;
327         finfo2 = finfo1;
328         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
329
330         if (!NT_STATUS_IS_OK(status)) {
331                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
332                 return false;
333         }
334         torture_comment(tctx, "write time %s\n", 
335                nt_time_string(tctx, finfo2.basic_info.out.write_time));
336         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
337                 torture_comment(tctx, "Server updated write_time (wrong!)\n");
338                 ret = false;
339         }
340
341         t = time(NULL);
342
343         /* Once the time was set using setfileinfo then it stays set - writes
344            don't have any effect. But make sure. */
345
346         while (time(NULL) < t+15) {
347                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
348
349                 if (!NT_STATUS_IS_OK(status)) {
350                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
351                         ret = false;
352                         break;
353                 }
354                 torture_comment(tctx, "write time %s\n", 
355                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
356                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
357                         torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
358                                (int)(time(NULL) - t));
359                         ret = false;
360                         break;
361                 }
362                 sleep(1);
363                 fflush(stdout);
364         }
365         
366         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
367                 torture_comment(tctx, "Server did not update write time (correct)\n");
368         }
369
370         torture_comment(tctx, "Closing second fd to see if write time updated.\n");
371
372         smbcli_close(cli->tree, fnum2);
373         fnum2 = -1;
374
375         fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
376         if (fnum1 == -1) {
377                 torture_comment(tctx, "Failed to open %s\n", fname);
378                 return false;
379         }
380
381         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
382         finfo1.basic_info.in.file.fnum = fnum1;
383         finfo2 = finfo1;
384
385         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
386
387         if (!NT_STATUS_IS_OK(status)) {
388                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
389                 return false;
390         }
391         
392         torture_comment(tctx, "Second open initial write time %s\n", 
393                nt_time_string(tctx, finfo1.basic_info.out.write_time));
394
395         sleep(10);
396         torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
397
398         written =  smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
399
400         if (written != 10) {
401                 torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
402                        (int)written, __location__);
403                 return false;
404         }
405
406         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
407         finfo1.basic_info.in.file.fnum = fnum1;
408         finfo2 = finfo1;
409         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
410
411         if (!NT_STATUS_IS_OK(status)) {
412                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
413                 return false;
414         }
415         torture_comment(tctx, "write time %s\n", 
416                nt_time_string(tctx, finfo2.basic_info.out.write_time));
417         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
418                 torture_comment(tctx, "Server updated write_time (wrong!)\n");
419                 ret = false;
420         }
421
422         t = time(NULL);
423
424         /* Now the write time should be updated again */
425
426         while (time(NULL) < t+15) {
427                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
428
429                 if (!NT_STATUS_IS_OK(status)) {
430                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
431                         ret = false;
432                         break;
433                 }
434                 torture_comment(tctx, "write time %s\n", 
435                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
436                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
437                         int diff = time(NULL) - t;
438                         if (diff < 2) {
439                                 torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
440                                                 diff);
441                                 ret = false;
442                                 break;
443                         }
444
445                         torture_comment(tctx, "Server updated write_time after %d seconds (correct)\n",
446                                         diff);
447                         break;
448                 }
449                 sleep(1);
450                 fflush(stdout);
451         }
452         
453         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
454                 torture_comment(tctx, "Server did not update write time (wrong!)\n");
455                 ret = false;
456         }
457
458
459         /* One more test to do. We should read the filetime via findfirst on the
460            second connection to ensure it's the same. This is very easy for a Windows
461            server but a bastard to get right on a POSIX server. JRA. */
462
463         if (fnum1 != -1)
464                 smbcli_close(cli->tree, fnum1);
465         smbcli_unlink(cli->tree, fname);
466         smbcli_deltree(cli->tree, BASEDIR);
467
468         return ret;
469 }
470
471
472 /* Windows does obviously not update the stat info during a write call. I
473  * *think* this is the problem causing a spurious Excel 2003 on XP error
474  * message when saving a file. Excel does a setfileinfo, writes, and then does
475  * a getpath(!)info. Or so... For Samba sometimes it displays an error message
476  * that the file might have been changed in between. What i've been able to
477  * trace down is that this happens if the getpathinfo after the write shows a
478  * different last write time than the setfileinfo showed. This is really
479  * nasty....
480  */
481
482 static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli, 
483                                                                    struct smbcli_state *cli2)
484 {
485         union smb_fileinfo finfo1, finfo2;
486         const char *fname = BASEDIR "\\torture_file.txt";
487         NTSTATUS status;
488         int fnum1 = -1;
489         int fnum2;
490         bool ret = true;
491         ssize_t written;
492
493         if (!torture_setup_dir(cli, BASEDIR)) {
494                 return false;
495         }
496
497         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
498         if (fnum1 == -1) {
499                 ret = false;
500                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
501                 goto done;
502         }
503
504         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
505         finfo1.basic_info.in.file.fnum = fnum1;
506
507         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
508
509         if (!NT_STATUS_IS_OK(status)) {
510                 ret = false;
511                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
512                 goto done;
513         }
514
515         msleep(1000);
516
517         written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
518
519         if (written != 1) {
520                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
521                 ret = false;
522                 goto done;
523         }
524
525         fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
526         if (fnum2 == -1) {
527                 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s", 
528                        smbcli_errstr(cli2->tree));
529                 ret = false;
530                 goto done;
531         }
532         
533         written =  smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
534         
535         if (written != 1) {
536                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", 
537                        (int)written);
538                 ret = false;
539                 goto done;
540         }
541         
542         finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
543         finfo2.basic_info.in.file.path = fname;
544         
545         status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
546         
547         if (!NT_STATUS_IS_OK(status)) {
548                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", 
549                           nt_errstr(status));
550                 ret = false;
551                 goto done;
552         }
553         
554         if (finfo1.basic_info.out.create_time !=
555             finfo2.basic_info.out.create_time) {
556                 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
557                 ret = false;
558                 goto done;
559         }
560         
561         if (finfo1.basic_info.out.access_time !=
562             finfo2.basic_info.out.access_time) {
563                 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
564                 ret = false;
565                 goto done;
566         }
567         
568         if (finfo1.basic_info.out.write_time !=
569             finfo2.basic_info.out.write_time) {
570                 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
571                                            "write time conn 1 = %s, conn 2 = %s", 
572                        nt_time_string(tctx, finfo1.basic_info.out.write_time),
573                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
574                 ret = false;
575                 goto done;
576         }
577         
578         if (finfo1.basic_info.out.change_time !=
579             finfo2.basic_info.out.change_time) {
580                 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
581                 ret = false;
582                 goto done;
583         }
584         
585         /* One of the two following calls updates the qpathinfo. */
586         
587         /* If you had skipped the smbcli_write on fnum2, it would
588          * *not* have updated the stat on disk */
589         
590         smbcli_close(cli2->tree, fnum2);
591         cli2 = NULL;
592
593         /* This call is only for the people looking at ethereal :-) */
594         finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
595         finfo2.basic_info.in.file.path = fname;
596
597         status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
598
599         if (!NT_STATUS_IS_OK(status)) {
600                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
601                 ret = false;
602                 goto done;
603         }
604
605  done:
606         if (fnum1 != -1)
607                 smbcli_close(cli->tree, fnum1);
608         smbcli_unlink(cli->tree, fname);
609         smbcli_deltree(cli->tree, BASEDIR);
610
611         return ret;
612 }
613
614 #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
615         NTTIME g = (given).basic_info.out.write_time; \
616         NTTIME c = (correct).basic_info.out.write_time; \
617         if (g cmp c) { \
618                 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s %s (%s)%s", \
619                                 #given, nt_time_string(tctx, g), \
620                                 #cmp, #correct, nt_time_string(tctx, c)); \
621                 ret = false; \
622                 goto done; \
623         } \
624 } while (0)
625 #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
626         COMPARE_WRITE_TIME_CMP(given,correct,!=)
627 #define COMPARE_WRITE_TIME_GREATER(given,correct) \
628         COMPARE_WRITE_TIME_CMP(given,correct,<=)
629 #define COMPARE_WRITE_TIME_LESS(given,correct) \
630         COMPARE_WRITE_TIME_CMP(given,correct,>=)
631
632 #define GET_INFO_FILE(finfo) do { \
633         NTSTATUS _status; \
634         _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
635         if (!NT_STATUS_IS_OK(_status)) { \
636                 ret = false; \
637                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
638                                nt_errstr(_status)); \
639                 goto done; \
640         } \
641         torture_comment(tctx, "fileinfo: Write time (%s)\n", \
642                         nt_time_string(tctx, finfo.basic_info.out.write_time)); \
643 } while (0)
644 #define GET_INFO_PATH(pinfo) do { \
645         NTSTATUS _status; \
646         _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
647         if (!NT_STATUS_IS_OK(_status)) { \
648                 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
649                                nt_errstr(_status)); \
650                 ret = false; \
651                 goto done; \
652         } \
653         torture_comment(tctx, "pathinfo: Write time (%s)\n", \
654                         nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
655 } while (0)
656 #define GET_INFO_BOTH(finfo,pinfo) do { \
657         GET_INFO_FILE(finfo); \
658         GET_INFO_PATH(pinfo); \
659         COMPARE_WRITE_TIME_EQUAL(finfo,pinfo); \
660 } while (0)
661
662 #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
663         NTSTATUS _status; \
664         union smb_setfileinfo sfinfo; \
665         sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
666         sfinfo.basic_info.in.file.fnum = tfnum; \
667         sfinfo.basic_info.in.create_time = (finfo).basic_info.out.create_time; \
668         sfinfo.basic_info.in.access_time = (finfo).basic_info.out.access_time; \
669         unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
670         sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time; \
671         sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
672         _status = smb_raw_setfileinfo(tree, &sfinfo); \
673         if (!NT_STATUS_IS_OK(_status)) { \
674                 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
675                                nt_errstr(_status)); \
676                 ret = false; \
677                 goto done; \
678         } \
679 } while (0)
680 #define SET_INFO_FILE(finfo, wrtime) \
681         SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
682
683 static bool test_delayed_write_update3(struct torture_context *tctx,
684                                        struct smbcli_state *cli,
685                                        struct smbcli_state *cli2)
686 {
687         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
688         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
689         const char *fname = BASEDIR "\\torture_file.txt";
690         int fnum1 = -1;
691         bool ret = true;
692         ssize_t written;
693         time_t t;
694
695         if (!torture_setup_dir(cli, BASEDIR)) {
696                 return false;
697         }
698
699         torture_comment(tctx, "Open the file handle\n");
700         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
701         if (fnum1 == -1) {
702                 ret = false;
703                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
704                 goto done;
705         }
706
707         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
708         finfo0.basic_info.in.file.fnum = fnum1;
709         finfo1 = finfo0;
710         finfo2 = finfo0;
711         finfo3 = finfo0;
712         finfo4 = finfo0;
713         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
714         pinfo0.basic_info.in.file.path = fname;
715         pinfo1 = pinfo0;
716         pinfo2 = pinfo0;
717         pinfo3 = pinfo0;
718         pinfo4 = pinfo0;
719         pinfo5 = pinfo0;
720
721         /* get the initial times */
722         GET_INFO_BOTH(finfo0,pinfo0);
723
724         /*
725          * make sure the write time is updated 2 seconds later
726          * calcuated from the first write
727          * (but expect upto 5 seconds extra time for a busy server)
728          */
729         t = time(NULL);
730         while (time(NULL) < t+7) {
731                 /* do a write */
732                 torture_comment(tctx, "Do a write on the file handle\n");
733                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
734                 if (written != 1) {
735                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
736                         ret = false;
737                         goto done;
738                 }
739                 /* get the times after the write */
740                 GET_INFO_FILE(finfo1);
741
742                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
743                         int diff = time(NULL) - t;
744                         if (diff < 2) {
745                                 torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
746                                                 diff);
747                                 ret = false;
748                                 break;
749                         }
750
751                         torture_comment(tctx, "Server updated write_time after %d seconds (correct)\n",
752                                         diff);
753                         break;
754                 }
755                 msleep(500);
756         }
757
758         GET_INFO_BOTH(finfo1,pinfo1);
759
760         /* sure any further write doesn't update the write time */
761         t = time(NULL);
762         while (time(NULL) < t+15) {
763                 /* do a write */
764                 torture_comment(tctx, "Do a write on the file handle\n");
765                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
766                 if (written != 1) {
767                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
768                         ret = false;
769                         goto done;
770                 }
771                 /* get the times after the write */
772                 GET_INFO_BOTH(finfo2,pinfo2);
773
774                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
775                         torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
776                                (int)(time(NULL) - t));
777                         ret = false;
778                         break;
779                 }
780                 msleep(2000);
781         }
782
783         GET_INFO_BOTH(finfo2,pinfo2);
784         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
785         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
786                 torture_comment(tctx, "Server did not update write_time (correct)\n");
787         }
788
789         /* sleep */
790         msleep(5000);
791
792         GET_INFO_BOTH(finfo3,pinfo3);
793         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
794
795         /*
796          * the close updates the write time to the time of the close
797          * and not to the time of the last write!
798          */
799         torture_comment(tctx, "Close the file handle\n");
800         smbcli_close(cli->tree, fnum1);
801         fnum1 = -1;
802
803         GET_INFO_PATH(pinfo4);
804         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
805
806         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
807                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
808         }
809
810  done:
811         if (fnum1 != -1)
812                 smbcli_close(cli->tree, fnum1);
813         smbcli_unlink(cli->tree, fname);
814         smbcli_deltree(cli->tree, BASEDIR);
815
816         return ret;
817 }
818
819 static bool test_delayed_write_update4(struct torture_context *tctx,
820                                        struct smbcli_state *cli,
821                                        struct smbcli_state *cli2)
822 {
823         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
824         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
825         const char *fname = BASEDIR "\\torture_file.txt";
826         int fnum1 = -1;
827         bool ret = true;
828         ssize_t written;
829         time_t t;
830
831         if (!torture_setup_dir(cli, BASEDIR)) {
832                 return false;
833         }
834
835         torture_comment(tctx, "Open the file handle\n");
836         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
837         if (fnum1 == -1) {
838                 ret = false;
839                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
840                 goto done;
841         }
842
843         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
844         finfo0.basic_info.in.file.fnum = fnum1;
845         finfo1 = finfo0;
846         finfo2 = finfo0;
847         finfo3 = finfo0;
848         finfo4 = finfo0;
849         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
850         pinfo0.basic_info.in.file.path = fname;
851         pinfo1 = pinfo0;
852         pinfo2 = pinfo0;
853         pinfo3 = pinfo0;
854         pinfo4 = pinfo0;
855         pinfo5 = pinfo0;
856
857         /* get the initial times */
858         GET_INFO_BOTH(finfo0,pinfo0);
859
860         /* sleep a bit */
861         msleep(5000);
862
863         /* do a write */
864         torture_comment(tctx, "Do a write on the file handle\n");
865         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
866         if (written != 1) {
867                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
868                 ret = false;
869                 goto done;
870         }
871
872         GET_INFO_BOTH(finfo1,pinfo1);
873         COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
874
875         /*
876          * make sure the write time is updated 2 seconds later
877          * calcuated from the first write
878          * (but expect upto 3 seconds extra time for a busy server)
879          */
880         t = time(NULL);
881         while (time(NULL) < t+5) {
882                 /* get the times after the first write */
883                 GET_INFO_FILE(finfo1);
884
885                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
886                         int diff = time(NULL) - t;
887                         if (diff < 2) {
888                                 torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
889                                                 diff);
890                                 ret = false;
891                                 break;
892                         }
893
894                         torture_comment(tctx, "Server updated write_time after %d seconds (correct)\n",
895                                         diff);
896                         break;
897                 }
898                 msleep(500);
899         }
900
901         GET_INFO_BOTH(finfo1,pinfo1);
902
903         /* sure any further write doesn't update the write time */
904         t = time(NULL);
905         while (time(NULL) < t+15) {
906                 /* do a write */
907                 torture_comment(tctx, "Do a write on the file handle\n");
908                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
909                 if (written != 1) {
910                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
911                         ret = false;
912                         goto done;
913                 }
914                 /* get the times after the write */
915                 GET_INFO_BOTH(finfo2,pinfo2);
916
917                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
918                         torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
919                                (int)(time(NULL) - t));
920                         ret = false;
921                         break;
922                 }
923                 msleep(2000);
924         }
925
926         GET_INFO_BOTH(finfo2,pinfo2);
927         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
928         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
929                 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
930         }
931
932         /* sleep */
933         msleep(5000);
934
935         GET_INFO_BOTH(finfo3,pinfo3);
936         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
937
938         /*
939          * the close updates the write time to the time of the close
940          * and not to the time of the last write!
941          */
942         torture_comment(tctx, "Close the file handle\n");
943         smbcli_close(cli->tree, fnum1);
944         fnum1 = -1;
945
946         GET_INFO_PATH(pinfo4);
947         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
948
949         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
950                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
951         }
952
953  done:
954         if (fnum1 != -1)
955                 smbcli_close(cli->tree, fnum1);
956         smbcli_unlink(cli->tree, fname);
957         smbcli_deltree(cli->tree, BASEDIR);
958
959         return ret;
960 }
961
962 static bool test_delayed_write_update5(struct torture_context *tctx,
963                                        struct smbcli_state *cli,
964                                        struct smbcli_state *cli2)
965 {
966         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
967         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
968         const char *fname = BASEDIR "\\torture_file.txt";
969         int fnum1 = -1;
970         bool ret = true;
971         ssize_t written;
972         time_t t;
973
974         if (!torture_setup_dir(cli, BASEDIR)) {
975                 return false;
976         }
977
978         torture_comment(tctx, "Open the file handle\n");
979         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
980         if (fnum1 == -1) {
981                 ret = false;
982                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
983                 goto done;
984         }
985
986         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
987         finfo0.basic_info.in.file.fnum = fnum1;
988         finfo1 = finfo0;
989         finfo2 = finfo0;
990         finfo3 = finfo0;
991         finfo4 = finfo0;
992         finfo5 = finfo0;
993         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
994         pinfo0.basic_info.in.file.path = fname;
995         pinfo1 = pinfo0;
996         pinfo2 = pinfo0;
997         pinfo3 = pinfo0;
998         pinfo4 = pinfo0;
999         pinfo5 = pinfo0;
1000         pinfo6 = pinfo0;
1001
1002         /* get the initial times */
1003         GET_INFO_BOTH(finfo0,pinfo0);
1004
1005         /* do a write */
1006         torture_comment(tctx, "Do a write on the file handle\n");
1007         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1008         if (written != 1) {
1009                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1010                 ret = false;
1011                 goto done;
1012         }
1013
1014         GET_INFO_BOTH(finfo1,pinfo1);
1015         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1016
1017         torture_comment(tctx, "Set write time in the future on the file handle\n");
1018         SET_INFO_FILE(finfo0, time(NULL) + 86400);
1019         GET_INFO_BOTH(finfo2,pinfo2);
1020         COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1021
1022         torture_comment(tctx, "Set write time in the past on the file handle\n");
1023         SET_INFO_FILE(finfo0, time(NULL) - 86400);
1024         GET_INFO_BOTH(finfo2,pinfo2);
1025         COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
1026
1027         /* make sure the 2 second delay from the first write are canceled */
1028         t = time(NULL);
1029         while (time(NULL) < t+15) {
1030
1031                 /* get the times after the first write */
1032                 GET_INFO_BOTH(finfo3,pinfo3);
1033
1034                 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
1035                         torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
1036                                (int)(time(NULL) - t));
1037                         ret = false;
1038                         break;
1039                 }
1040                 msleep(2000);
1041         }
1042
1043         GET_INFO_BOTH(finfo3,pinfo3);
1044         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1045         if (finfo3.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
1046                 torture_comment(tctx, "Server did not update write_time (correct)\n");
1047         }
1048
1049         /* sure any further write doesn't update the write time */
1050         t = time(NULL);
1051         while (time(NULL) < t+15) {
1052                 /* do a write */
1053                 torture_comment(tctx, "Do a write on the file handle\n");
1054                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1055                 if (written != 1) {
1056                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1057                         ret = false;
1058                         goto done;
1059                 }
1060                 /* get the times after the write */
1061                 GET_INFO_BOTH(finfo4,pinfo4);
1062
1063                 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
1064                         torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
1065                                (int)(time(NULL) - t));
1066                         ret = false;
1067                         break;
1068                 }
1069                 msleep(2000);
1070         }
1071
1072         GET_INFO_BOTH(finfo4,pinfo4);
1073         COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
1074         if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
1075                 torture_comment(tctx, "Server did not update write_time (correct)\n");
1076         }
1077
1078         /* sleep */
1079         msleep(5000);
1080
1081         GET_INFO_BOTH(finfo5,pinfo5);
1082         COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
1083
1084         /*
1085          * the close doesn't update the write time
1086          */
1087         torture_comment(tctx, "Close the file handle\n");
1088         smbcli_close(cli->tree, fnum1);
1089         fnum1 = -1;
1090
1091         GET_INFO_PATH(pinfo6);
1092         COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
1093
1094         if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
1095                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1096         }
1097
1098  done:
1099         if (fnum1 != -1)
1100                 smbcli_close(cli->tree, fnum1);
1101         smbcli_unlink(cli->tree, fname);
1102         smbcli_deltree(cli->tree, BASEDIR);
1103
1104         return ret;
1105 }
1106
1107 static bool test_delayed_write_update6(struct torture_context *tctx,
1108                                        struct smbcli_state *cli,
1109                                        struct smbcli_state *cli2)
1110 {
1111         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
1112         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
1113         const char *fname = BASEDIR "\\torture_file.txt";
1114         int fnum1 = -1;
1115         int fnum2 = -1;
1116         bool ret = true;
1117         ssize_t written;
1118         time_t t;
1119         bool first = true;
1120
1121         if (!torture_setup_dir(cli, BASEDIR)) {
1122                 return false;
1123         }
1124 again:
1125         torture_comment(tctx, "Open the file handle\n");
1126         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1127         if (fnum1 == -1) {
1128                 ret = false;
1129                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1130                 goto done;
1131         }
1132
1133         if (fnum2 == -1) {
1134                 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
1135                 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
1136                 if (fnum2 == -1) {
1137                         ret = false;
1138                         torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
1139                         goto done;
1140                 }
1141         }
1142
1143         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1144         finfo0.basic_info.in.file.fnum = fnum1;
1145         finfo1 = finfo0;
1146         finfo2 = finfo0;
1147         finfo3 = finfo0;
1148         finfo4 = finfo0;
1149         finfo5 = finfo0;
1150         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
1151         pinfo0.basic_info.in.file.path = fname;
1152         pinfo1 = pinfo0;
1153         pinfo2 = pinfo0;
1154         pinfo3 = pinfo0;
1155         pinfo4 = pinfo0;
1156         pinfo5 = pinfo0;
1157         pinfo6 = pinfo0;
1158         pinfo7 = pinfo0;
1159
1160         /* get the initial times */
1161         GET_INFO_BOTH(finfo0,pinfo0);
1162
1163         /* do a write */
1164         torture_comment(tctx, "Do a write on the file handle\n");
1165         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1166         if (written != 1) {
1167                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1168                 ret = false;
1169                 goto done;
1170         }
1171
1172         GET_INFO_BOTH(finfo1,pinfo1);
1173         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
1174
1175         torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
1176         SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
1177         GET_INFO_BOTH(finfo2,pinfo2);
1178         COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
1179
1180         torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
1181         SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
1182         GET_INFO_BOTH(finfo2,pinfo2);
1183         COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
1184
1185         /* make sure the 2 second delay from the first write are canceled */
1186         t = time(NULL);
1187         while (time(NULL) < t+15) {
1188
1189                 /* get the times after the first write */
1190                 GET_INFO_BOTH(finfo3,pinfo3);
1191
1192                 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
1193                         torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
1194                                (int)(time(NULL) - t));
1195                         ret = false;
1196                         break;
1197                 }
1198                 msleep(2000);
1199         }
1200
1201         GET_INFO_BOTH(finfo3,pinfo3);
1202         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
1203         if (finfo3.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
1204                 torture_comment(tctx, "Server did not update write_time (correct)\n");
1205         }
1206
1207         /* sure any further write doesn't update the write time */
1208         t = time(NULL);
1209         while (time(NULL) < t+15) {
1210                 /* do a write */
1211                 torture_comment(tctx, "Do a write on the file handle\n");
1212                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
1213                 if (written != 1) {
1214                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
1215                         ret = false;
1216                         goto done;
1217                 }
1218                 /* get the times after the write */
1219                 GET_INFO_BOTH(finfo4,pinfo4);
1220
1221                 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
1222                         torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
1223                                (int)(time(NULL) - t));
1224                         ret = false;
1225                         break;
1226                 }
1227                 msleep(2000);
1228         }
1229
1230         GET_INFO_BOTH(finfo4,pinfo4);
1231         COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
1232         if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
1233                 torture_comment(tctx, "Server did not update write_time (correct)\n");
1234         }
1235
1236         /* sleep */
1237         msleep(5000);
1238
1239         GET_INFO_BOTH(finfo5,pinfo5);
1240         COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
1241
1242         /*
1243          * the close updates the write time to the time of the close
1244          * as the write time was set on the 2nd handle
1245          */
1246         torture_comment(tctx, "Close the file handle\n");
1247         smbcli_close(cli->tree, fnum1);
1248         fnum1 = -1;
1249
1250         GET_INFO_PATH(pinfo6);
1251         COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
1252
1253         if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
1254                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
1255         }
1256
1257         /* keep the 2nd handle open and rerun tests */
1258         if (first) {
1259                 first = false;
1260                 goto again;
1261         }
1262
1263         /*
1264          * closing the 2nd handle will cause no write time update
1265          * as the write time was explicit set on this handle
1266          */
1267         torture_comment(tctx, "Close the 2nd file handle\n");
1268         smbcli_close(cli2->tree, fnum2);
1269         fnum2 = -1;
1270
1271         GET_INFO_PATH(pinfo7);
1272         COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
1273
1274         if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
1275                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
1276         }
1277
1278  done:
1279         if (fnum1 != -1)
1280                 smbcli_close(cli->tree, fnum1);
1281         if (fnum2 != -1)
1282                 smbcli_close(cli2->tree, fnum2);
1283         smbcli_unlink(cli->tree, fname);
1284         smbcli_deltree(cli->tree, BASEDIR);
1285
1286         return ret;
1287 }
1288
1289
1290 /* 
1291    testing of delayed update of write_time
1292 */
1293 struct torture_suite *torture_delay_write(void)
1294 {
1295         struct torture_suite *suite = torture_suite_create(talloc_autofree_context(), "DELAYWRITE");
1296
1297         torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
1298         torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
1299         torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
1300         torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
1301         torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
1302         torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
1303         torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
1304
1305         return suite;
1306 }