28faf6b22ce033f2934d6e2e9ae0970939e64db2
[jelmer/samba4-debian.git] / source / torture / raw / write.c
1 /* 
2    Unix SMB/CIFS implementation.
3    test suite for various write operations
4    Copyright (C) Andrew Tridgell 2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "libcli/raw/libcliraw.h"
23
24 #define CHECK_STATUS(status, correct) do { \
25         if (!NT_STATUS_EQUAL(status, correct)) { \
26                 printf("(%s) Incorrect status %s - should be %s\n", \
27                        __location__, nt_errstr(status), nt_errstr(correct)); \
28                 ret = False; \
29                 goto done; \
30         }} while (0)
31
32 #define CHECK_VALUE(v, correct) do { \
33         if ((v) != (correct)) { \
34                 printf("(%s) Incorrect value %s=%d - should be %d\n", \
35                        __location__, #v, v, correct); \
36                 ret = False; \
37                 goto done; \
38         }} while (0)
39
40 #define CHECK_BUFFER(buf, seed, len) do { \
41         if (!check_buffer(buf, seed, len, __location__)) { \
42                 ret = False; \
43                 goto done; \
44         }} while (0)
45
46 #define CHECK_ALL_INFO(v, field) do { \
47         finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
48         finfo.all_info.in.fname = fname; \
49         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
50         CHECK_STATUS(status, NT_STATUS_OK); \
51         if ((v) != finfo.all_info.out.field) { \
52                 printf("(%s) wrong value for field %s  %.0f - %.0f\n", \
53                        __location__, #field, (double)v, (double)finfo.all_info.out.field); \
54                 dump_all_info(mem_ctx, &finfo); \
55                 ret = False; \
56         }} while (0)
57
58
59 #define BASEDIR "\\testwrite"
60
61
62 static BOOL setup_dir(struct smbcli_state *cli, const char *dname)
63 {
64         smb_raw_exit(cli->session);
65         if (smbcli_deltree(cli->tree, dname) == -1 ||
66             NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, dname))) {
67                 printf("Unable to setup %s - %s\n", dname, smbcli_errstr(cli->tree));
68                 return False;
69         }
70         return True;
71 }
72
73
74 /*
75   setup a random buffer based on a seed
76 */
77 static void setup_buffer(char *buf, uint_t seed, int len)
78 {
79         int i;
80         srandom(seed);
81         for (i=0;i<len;i++) buf[i] = random();
82 }
83
84 /*
85   check a random buffer based on a seed
86 */
87 static BOOL check_buffer(char *buf, uint_t seed, int len, const char *location)
88 {
89         int i;
90         srandom(seed);
91         for (i=0;i<len;i++) {
92                 char v = random();
93                 if (buf[i] != v) {
94                         printf("Buffer incorrect at %s! ofs=%d buf=0x%x correct=0x%x\n", 
95                                location, i, buf[i], v);
96                         return False;
97                 }
98         }
99         return True;
100 }
101
102 /*
103   test write ops
104 */
105 static BOOL test_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
106 {
107         union smb_write io;
108         NTSTATUS status;
109         BOOL ret = True;
110         int fnum;
111         char *buf;
112         const int maxsize = 90000;
113         const char *fname = BASEDIR "\\test.txt";
114         uint_t seed = time(NULL);
115         union smb_fileinfo finfo;
116
117         buf = talloc_zero(mem_ctx, maxsize);
118
119         if (!setup_dir(cli, BASEDIR)) {
120                 return False;
121         }
122
123         printf("Testing RAW_WRITE_WRITE\n");
124         io.generic.level = RAW_WRITE_WRITE;
125         
126         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
127         if (fnum == -1) {
128                 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
129                 ret = False;
130                 goto done;
131         }
132
133         printf("Trying zero write\n");
134         io.write.in.fnum = fnum;
135         io.write.in.count = 0;
136         io.write.in.offset = 0;
137         io.write.in.remaining = 0;
138         io.write.in.data = buf;
139         status = smb_raw_write(cli->tree, &io);
140         CHECK_STATUS(status, NT_STATUS_OK);
141         CHECK_VALUE(io.write.out.nwritten, 0);
142
143         setup_buffer(buf, seed, maxsize);
144
145         printf("Trying small write\n");
146         io.write.in.count = 9;
147         io.write.in.offset = 4;
148         io.write.in.data = buf;
149         status = smb_raw_write(cli->tree, &io);
150         CHECK_STATUS(status, NT_STATUS_OK);
151         CHECK_VALUE(io.write.out.nwritten, io.write.in.count);
152
153         memset(buf, 0, maxsize);
154         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
155                 printf("read failed at %s\n", __location__);
156                 ret = False;
157                 goto done;
158         }
159         CHECK_BUFFER(buf+4, seed, 9);
160         CHECK_VALUE(IVAL(buf,0), 0);
161
162         setup_buffer(buf, seed, maxsize);
163
164         printf("Trying large write\n");
165         io.write.in.count = 4000;
166         io.write.in.offset = 0;
167         io.write.in.data = buf;
168         status = smb_raw_write(cli->tree, &io);
169         CHECK_STATUS(status, NT_STATUS_OK);
170         CHECK_VALUE(io.write.out.nwritten, 4000);
171
172         memset(buf, 0, maxsize);
173         if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
174                 printf("read failed at %s\n", __location__);
175                 ret = False;
176                 goto done;
177         }
178         CHECK_BUFFER(buf, seed, 4000);
179
180         printf("Trying bad fnum\n");
181         io.write.in.fnum = fnum+1;
182         io.write.in.count = 4000;
183         io.write.in.offset = 0;
184         io.write.in.data = buf;
185         status = smb_raw_write(cli->tree, &io);
186         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
187
188         printf("Setting file as sparse\n");
189         status = torture_set_sparse(cli->tree, fnum);
190         CHECK_STATUS(status, NT_STATUS_OK);
191         
192         printf("Trying 2^32 offset\n");
193         setup_buffer(buf, seed, maxsize);
194         io.write.in.fnum = fnum;
195         io.write.in.count = 4000;
196         io.write.in.offset = 0xFFFFFFFF - 2000;
197         io.write.in.data = buf;
198         status = smb_raw_write(cli->tree, &io);
199         CHECK_STATUS(status, NT_STATUS_OK);
200         CHECK_VALUE(io.write.out.nwritten, 4000);
201         CHECK_ALL_INFO(io.write.in.count + (uint64_t)io.write.in.offset, size);
202
203         memset(buf, 0, maxsize);
204         if (smbcli_read(cli->tree, fnum, buf, io.write.in.offset, 4000) != 4000) {
205                 printf("read failed at %s\n", __location__);
206                 ret = False;
207                 goto done;
208         }
209         CHECK_BUFFER(buf, seed, 4000);
210
211 done:
212         smbcli_close(cli->tree, fnum);
213         smb_raw_exit(cli->session);
214         smbcli_deltree(cli->tree, BASEDIR);
215         return ret;
216 }
217
218
219 /*
220   test writex ops
221 */
222 static BOOL test_writex(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
223 {
224         union smb_write io;
225         NTSTATUS status;
226         BOOL ret = True;
227         int fnum, i;
228         char *buf;
229         const int maxsize = 90000;
230         const char *fname = BASEDIR "\\test.txt";
231         uint_t seed = time(NULL);
232         union smb_fileinfo finfo;
233
234         buf = talloc_zero(mem_ctx, maxsize);
235
236         if (!setup_dir(cli, BASEDIR)) {
237                 return False;
238         }
239
240         printf("Testing RAW_WRITE_WRITEX\n");
241         io.generic.level = RAW_WRITE_WRITEX;
242         
243         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
244         if (fnum == -1) {
245                 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
246                 ret = False;
247                 goto done;
248         }
249
250         printf("Trying zero write\n");
251         io.writex.in.fnum = fnum;
252         io.writex.in.offset = 0;
253         io.writex.in.wmode = 0;
254         io.writex.in.remaining = 0;
255         io.writex.in.count = 0;
256         io.writex.in.data = buf;
257         status = smb_raw_write(cli->tree, &io);
258         CHECK_STATUS(status, NT_STATUS_OK);
259         CHECK_VALUE(io.writex.out.nwritten, 0);
260
261         setup_buffer(buf, seed, maxsize);
262
263         printf("Trying small write\n");
264         io.writex.in.count = 9;
265         io.writex.in.offset = 4;
266         io.writex.in.data = buf;
267         status = smb_raw_write(cli->tree, &io);
268         CHECK_STATUS(status, NT_STATUS_OK);
269         CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
270
271         memset(buf, 0, maxsize);
272         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
273                 printf("read failed at %s\n", __location__);
274                 ret = False;
275                 goto done;
276         }
277         CHECK_BUFFER(buf+4, seed, 9);
278         CHECK_VALUE(IVAL(buf,0), 0);
279
280         setup_buffer(buf, seed, maxsize);
281
282         printf("Trying large write\n");
283         io.writex.in.count = 4000;
284         io.writex.in.offset = 0;
285         io.writex.in.data = buf;
286         status = smb_raw_write(cli->tree, &io);
287         CHECK_STATUS(status, NT_STATUS_OK);
288         CHECK_VALUE(io.writex.out.nwritten, 4000);
289
290         memset(buf, 0, maxsize);
291         if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
292                 printf("read failed at %s\n", __location__);
293                 ret = False;
294                 goto done;
295         }
296         CHECK_BUFFER(buf, seed, 4000);
297
298         printf("Trying bad fnum\n");
299         io.writex.in.fnum = fnum+1;
300         io.writex.in.count = 4000;
301         io.writex.in.offset = 0;
302         io.writex.in.data = buf;
303         status = smb_raw_write(cli->tree, &io);
304         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
305
306         printf("Testing wmode\n");
307         io.writex.in.fnum = fnum;
308         io.writex.in.count = 1;
309         io.writex.in.offset = 0;
310         io.writex.in.wmode = 1;
311         io.writex.in.data = buf;
312         status = smb_raw_write(cli->tree, &io);
313         CHECK_STATUS(status, NT_STATUS_OK);
314         CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
315
316         io.writex.in.wmode = 2;
317         status = smb_raw_write(cli->tree, &io);
318         CHECK_STATUS(status, NT_STATUS_OK);
319         CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
320
321
322         printf("Trying locked region\n");
323         cli->session->pid++;
324         if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 3, 1, 0, WRITE_LOCK))) {
325                 printf("Failed to lock file at %s\n", __location__);
326                 ret = False;
327                 goto done;
328         }
329         cli->session->pid--;
330         io.writex.in.wmode = 0;
331         io.writex.in.count = 4;
332         io.writex.in.offset = 0;
333         status = smb_raw_write(cli->tree, &io);
334         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
335
336         printf("Setting file as sparse\n");
337         status = torture_set_sparse(cli->tree, fnum);
338         CHECK_STATUS(status, NT_STATUS_OK);
339         
340         printf("Trying 2^32 offset\n");
341         setup_buffer(buf, seed, maxsize);
342         io.writex.in.fnum = fnum;
343         io.writex.in.count = 4000;
344         io.writex.in.offset = 0xFFFFFFFF - 2000;
345         io.writex.in.data = buf;
346         status = smb_raw_write(cli->tree, &io);
347         CHECK_STATUS(status, NT_STATUS_OK);
348         CHECK_VALUE(io.writex.out.nwritten, 4000);
349         CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
350
351         memset(buf, 0, maxsize);
352         if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
353                 printf("read failed at %s\n", __location__);
354                 ret = False;
355                 goto done;
356         }
357         CHECK_BUFFER(buf, seed, 4000);
358
359         for (i=33;i<64;i++) {
360                 printf("Trying 2^%d offset\n", i);
361                 setup_buffer(buf, seed+1, maxsize);
362                 io.writex.in.fnum = fnum;
363                 io.writex.in.count = 4000;
364                 io.writex.in.offset = ((uint64_t)1) << i;
365                 io.writex.in.data = buf;
366                 status = smb_raw_write(cli->tree, &io);
367                 if (i>40 &&
368                     NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
369                         break;
370                 }
371                 CHECK_STATUS(status, NT_STATUS_OK);
372                 CHECK_VALUE(io.writex.out.nwritten, 4000);
373                 CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
374
375                 memset(buf, 0, maxsize);
376                 if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
377                         printf("read failed at %s\n", __location__);
378                         ret = False;
379                         goto done;
380                 }
381                 CHECK_BUFFER(buf, seed+1, 4000);
382         }
383         printf("limit is 2^%d\n", i);
384
385         setup_buffer(buf, seed, maxsize);
386
387 done:
388         smbcli_close(cli->tree, fnum);
389         smb_raw_exit(cli->session);
390         smbcli_deltree(cli->tree, BASEDIR);
391         return ret;
392 }
393
394
395 /*
396   test write unlock ops
397 */
398 static BOOL test_writeunlock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
399 {
400         union smb_write io;
401         NTSTATUS status;
402         BOOL ret = True;
403         int fnum;
404         char *buf;
405         const int maxsize = 90000;
406         const char *fname = BASEDIR "\\test.txt";
407         uint_t seed = time(NULL);
408         union smb_fileinfo finfo;
409
410         buf = talloc_zero(mem_ctx, maxsize);
411
412         if (!setup_dir(cli, BASEDIR)) {
413                 return False;
414         }
415
416         printf("Testing RAW_WRITE_WRITEUNLOCK\n");
417         io.generic.level = RAW_WRITE_WRITEUNLOCK;
418         
419         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
420         if (fnum == -1) {
421                 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
422                 ret = False;
423                 goto done;
424         }
425
426         printf("Trying zero write\n");
427         io.writeunlock.in.fnum = fnum;
428         io.writeunlock.in.count = 0;
429         io.writeunlock.in.offset = 0;
430         io.writeunlock.in.remaining = 0;
431         io.writeunlock.in.data = buf;
432         status = smb_raw_write(cli->tree, &io);
433         CHECK_STATUS(status, NT_STATUS_OK);
434         CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
435
436         setup_buffer(buf, seed, maxsize);
437
438         printf("Trying small write\n");
439         io.writeunlock.in.count = 9;
440         io.writeunlock.in.offset = 4;
441         io.writeunlock.in.data = buf;
442         status = smb_raw_write(cli->tree, &io);
443         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
444         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
445                 printf("read failed at %s\n", __location__);
446                 ret = False;
447                 goto done;
448         }
449         CHECK_BUFFER(buf+4, seed, 9);
450         CHECK_VALUE(IVAL(buf,0), 0);
451
452         setup_buffer(buf, seed, maxsize);
453         smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count, 
454                  0, WRITE_LOCK);
455         status = smb_raw_write(cli->tree, &io);
456         CHECK_STATUS(status, NT_STATUS_OK);
457         CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
458
459         memset(buf, 0, maxsize);
460         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
461                 printf("read failed at %s\n", __location__);
462                 ret = False;
463                 goto done;
464         }
465         CHECK_BUFFER(buf+4, seed, 9);
466         CHECK_VALUE(IVAL(buf,0), 0);
467
468         setup_buffer(buf, seed, maxsize);
469
470         printf("Trying large write\n");
471         io.writeunlock.in.count = 4000;
472         io.writeunlock.in.offset = 0;
473         io.writeunlock.in.data = buf;
474         smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count, 
475                  0, WRITE_LOCK);
476         status = smb_raw_write(cli->tree, &io);
477         CHECK_STATUS(status, NT_STATUS_OK);
478         CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
479
480         status = smb_raw_write(cli->tree, &io);
481         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
482
483         memset(buf, 0, maxsize);
484         if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
485                 printf("read failed at %s\n", __location__);
486                 ret = False;
487                 goto done;
488         }
489         CHECK_BUFFER(buf, seed, 4000);
490
491         printf("Trying bad fnum\n");
492         io.writeunlock.in.fnum = fnum+1;
493         io.writeunlock.in.count = 4000;
494         io.writeunlock.in.offset = 0;
495         io.writeunlock.in.data = buf;
496         status = smb_raw_write(cli->tree, &io);
497         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
498
499         printf("Setting file as sparse\n");
500         status = torture_set_sparse(cli->tree, fnum);
501         CHECK_STATUS(status, NT_STATUS_OK);
502         
503         printf("Trying 2^32 offset\n");
504         setup_buffer(buf, seed, maxsize);
505         io.writeunlock.in.fnum = fnum;
506         io.writeunlock.in.count = 4000;
507         io.writeunlock.in.offset = 0xFFFFFFFF - 2000;
508         io.writeunlock.in.data = buf;
509         smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count, 
510                  0, WRITE_LOCK);
511         status = smb_raw_write(cli->tree, &io);
512         CHECK_STATUS(status, NT_STATUS_OK);
513         CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
514         CHECK_ALL_INFO(io.writeunlock.in.count + (uint64_t)io.writeunlock.in.offset, size);
515
516         memset(buf, 0, maxsize);
517         if (smbcli_read(cli->tree, fnum, buf, io.writeunlock.in.offset, 4000) != 4000) {
518                 printf("read failed at %s\n", __location__);
519                 ret = False;
520                 goto done;
521         }
522         CHECK_BUFFER(buf, seed, 4000);
523
524 done:
525         smbcli_close(cli->tree, fnum);
526         smb_raw_exit(cli->session);
527         smbcli_deltree(cli->tree, BASEDIR);
528         return ret;
529 }
530
531
532 /*
533   test write close ops
534 */
535 static BOOL test_writeclose(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
536 {
537         union smb_write io;
538         NTSTATUS status;
539         BOOL ret = True;
540         int fnum;
541         char *buf;
542         const int maxsize = 90000;
543         const char *fname = BASEDIR "\\test.txt";
544         uint_t seed = time(NULL);
545         union smb_fileinfo finfo;
546
547         buf = talloc_zero(mem_ctx, maxsize);
548
549         if (!setup_dir(cli, BASEDIR)) {
550                 return False;
551         }
552
553         printf("Testing RAW_WRITE_WRITECLOSE\n");
554         io.generic.level = RAW_WRITE_WRITECLOSE;
555         
556         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
557         if (fnum == -1) {
558                 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
559                 ret = False;
560                 goto done;
561         }
562
563         printf("Trying zero write\n");
564         io.writeclose.in.fnum = fnum;
565         io.writeclose.in.count = 0;
566         io.writeclose.in.offset = 0;
567         io.writeclose.in.mtime = 0;
568         io.writeclose.in.data = buf;
569         status = smb_raw_write(cli->tree, &io);
570         CHECK_STATUS(status, NT_STATUS_OK);
571         CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
572
573         status = smb_raw_write(cli->tree, &io);
574         CHECK_STATUS(status, NT_STATUS_OK);
575         CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
576
577         setup_buffer(buf, seed, maxsize);
578
579         printf("Trying small write\n");
580         io.writeclose.in.count = 9;
581         io.writeclose.in.offset = 4;
582         io.writeclose.in.data = buf;
583         status = smb_raw_write(cli->tree, &io);
584         CHECK_STATUS(status, NT_STATUS_OK);
585
586         status = smb_raw_write(cli->tree, &io);
587         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
588
589         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
590         io.writeclose.in.fnum = fnum;
591
592         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
593                 printf("read failed at %s\n", __location__);
594                 ret = False;
595                 goto done;
596         }
597         CHECK_BUFFER(buf+4, seed, 9);
598         CHECK_VALUE(IVAL(buf,0), 0);
599
600         setup_buffer(buf, seed, maxsize);
601         status = smb_raw_write(cli->tree, &io);
602         CHECK_STATUS(status, NT_STATUS_OK);
603         CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
604
605         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
606         io.writeclose.in.fnum = fnum;
607
608         memset(buf, 0, maxsize);
609         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
610                 printf("read failed at %s\n", __location__);
611                 ret = False;
612                 goto done;
613         }
614         CHECK_BUFFER(buf+4, seed, 9);
615         CHECK_VALUE(IVAL(buf,0), 0);
616
617         setup_buffer(buf, seed, maxsize);
618
619         printf("Trying large write\n");
620         io.writeclose.in.count = 4000;
621         io.writeclose.in.offset = 0;
622         io.writeclose.in.data = buf;
623         status = smb_raw_write(cli->tree, &io);
624         CHECK_STATUS(status, NT_STATUS_OK);
625         CHECK_VALUE(io.writeclose.out.nwritten, 4000);
626
627         status = smb_raw_write(cli->tree, &io);
628         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
629
630         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
631         io.writeclose.in.fnum = fnum;
632
633         memset(buf, 0, maxsize);
634         if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
635                 printf("read failed at %s\n", __location__);
636                 ret = False;
637                 goto done;
638         }
639         CHECK_BUFFER(buf, seed, 4000);
640
641         printf("Trying bad fnum\n");
642         io.writeclose.in.fnum = fnum+1;
643         io.writeclose.in.count = 4000;
644         io.writeclose.in.offset = 0;
645         io.writeclose.in.data = buf;
646         status = smb_raw_write(cli->tree, &io);
647         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
648
649         printf("Setting file as sparse\n");
650         status = torture_set_sparse(cli->tree, fnum);
651         CHECK_STATUS(status, NT_STATUS_OK);
652         
653         printf("Trying 2^32 offset\n");
654         setup_buffer(buf, seed, maxsize);
655         io.writeclose.in.fnum = fnum;
656         io.writeclose.in.count = 4000;
657         io.writeclose.in.offset = 0xFFFFFFFF - 2000;
658         io.writeclose.in.data = buf;
659         status = smb_raw_write(cli->tree, &io);
660         CHECK_STATUS(status, NT_STATUS_OK);
661         CHECK_VALUE(io.writeclose.out.nwritten, 4000);
662         CHECK_ALL_INFO(io.writeclose.in.count + (uint64_t)io.writeclose.in.offset, size);
663
664         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
665         io.writeclose.in.fnum = fnum;
666
667         memset(buf, 0, maxsize);
668         if (smbcli_read(cli->tree, fnum, buf, io.writeclose.in.offset, 4000) != 4000) {
669                 printf("read failed at %s\n", __location__);
670                 ret = False;
671                 goto done;
672         }
673         CHECK_BUFFER(buf, seed, 4000);
674
675 done:
676         smbcli_close(cli->tree, fnum);
677         smb_raw_exit(cli->session);
678         smbcli_deltree(cli->tree, BASEDIR);
679         return ret;
680 }
681
682 static BOOL test_delayed_write_update(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
683 {
684         union smb_fileinfo finfo1, finfo2;
685         const char *fname = BASEDIR "\\torture_file.txt";
686         NTSTATUS status;
687         int fnum1 = -1;
688         BOOL ret = True;
689         ssize_t written;
690         time_t t;
691
692         printf("Testing delayed update of write time\n");
693
694         if (!setup_dir(cli, BASEDIR)) {
695                 return False;
696         }
697
698         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
699         if (fnum1 == -1) {
700                 printf("Failed to open %s\n", fname);
701                 return False;
702         }
703
704         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
705         finfo1.basic_info.in.fnum = fnum1;
706         finfo2 = finfo1;
707
708         status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo1);
709
710         if (!NT_STATUS_IS_OK(status)) {
711                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
712                 return False;
713         }
714         
715         printf("Initial write time %s\n", 
716                nt_time_string(mem_ctx, finfo1.basic_info.out.write_time));
717
718         /* 3 second delay to ensure we get past any 2 second time
719            granularity (older systems may have that) */
720         sleep(3);
721
722         written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
723
724         if (written != 1) {
725                 printf("write failed - wrote %d bytes (%s)\n", written, __location__);
726                 return False;
727         }
728
729         t = time(NULL);
730
731         while (time(NULL) < t+120) {
732                 status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo2);
733
734                 if (!NT_STATUS_IS_OK(status)) {
735                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
736                         ret = False;
737                         break;
738                 }
739                 printf("write time %s\n", 
740                        nt_time_string(mem_ctx, finfo2.basic_info.out.write_time));
741                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
742                         printf("Server updated write_time after %d seconds\n",
743                                (int)(time(NULL) - t));
744                         break;
745                 }
746                 sleep(1);
747                 fflush(stdout);
748         }
749         
750         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
751                 printf("Server did not update write time?!\n");
752                 ret = False;
753         }
754
755
756         if (fnum1 != -1)
757                 smbcli_close(cli->tree, fnum1);
758         smbcli_unlink(cli->tree, fname);
759         smbcli_deltree(cli->tree, BASEDIR);
760
761         return ret;
762 }
763
764
765 /* Windows does obviously not update the stat info during a write call. I
766  * *think* this is the problem causing a spurious Excel 2003 on XP error
767  * message when saving a file. Excel does a setfileinfo, writes, and then does
768  * a getpath(!)info. Or so... For Samba sometimes it displays an error message
769  * that the file might have been changed in between. What i've been able to
770  * trace down is that this happens if the getpathinfo after the write shows a
771  * different last write time than the setfileinfo showed. This is really
772  * nasty....
773  */
774
775 static BOOL test_finfo_after_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
776 {
777         union smb_fileinfo finfo1, finfo2;
778         const char *fname = BASEDIR "\\torture_file.txt";
779         NTSTATUS status;
780         int fnum1 = -1;
781         int fnum2;
782         BOOL ret = True;
783         ssize_t written;
784         struct smbcli_state *cli2=NULL;
785
786         printf("Testing finfo update on close\n");
787
788         if (!setup_dir(cli, BASEDIR)) {
789                 return False;
790         }
791
792         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
793         if (fnum1 == -1) {
794                 ret = False;
795                 goto done;
796         }
797
798         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
799         finfo1.basic_info.in.fnum = fnum1;
800
801         status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo1);
802
803         if (!NT_STATUS_IS_OK(status)) {
804                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
805                 ret = False;
806                 goto done;
807         }
808
809         msleep(1000);
810
811         written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
812
813         if (written != 1) {
814                 printf("(%s) written gave %d - should have been 1\n", 
815                        __location__, written);
816                 ret = False;
817                 goto done;
818         }
819
820         if (!torture_open_connection(&cli2)) {
821                 return False;
822         }
823
824         fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
825         if (fnum2 == -1) {
826                 printf("(%s) failed to open 2nd time - %s\n", 
827                        __location__, smbcli_errstr(cli2->tree));
828                 ret = False;
829                 goto done;
830         }
831         
832         written =  smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
833         
834         if (written != 1) {
835                 printf("(%s) written gave %d - should have been 1\n", 
836                        __location__, written);
837                 ret = False;
838                 goto done;
839         }
840         
841         finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
842         finfo2.basic_info.in.fname = fname;
843         
844         status = smb_raw_pathinfo(cli2->tree, mem_ctx, &finfo2);
845         
846         if (!NT_STATUS_IS_OK(status)) {
847                 DEBUG(0, ("(%s) fileinfo failed: %s\n", 
848                           __location__, nt_errstr(status)));
849                 ret = False;
850                 goto done;
851         }
852         
853         if (finfo1.basic_info.out.create_time !=
854             finfo2.basic_info.out.create_time) {
855                 printf("(%s) create_time changed\n", __location__);
856                 ret = False;
857                 goto done;
858         }
859         
860         if (finfo1.basic_info.out.access_time !=
861             finfo2.basic_info.out.access_time) {
862                 printf("(%s) access_time changed\n", __location__);
863                 ret = False;
864                 goto done;
865         }
866         
867         if (finfo1.basic_info.out.write_time !=
868             finfo2.basic_info.out.write_time) {
869                 printf("(%s) write_time changed\n", __location__);
870                 ret = False;
871                 goto done;
872         }
873         
874         if (finfo1.basic_info.out.change_time !=
875             finfo2.basic_info.out.change_time) {
876                 printf("(%s) change_time changed\n", __location__);
877                 ret = False;
878                 goto done;
879         }
880         
881         /* One of the two following calls updates the qpathinfo. */
882         
883         /* If you had skipped the smbcli_write on fnum2, it would
884          * *not* have updated the stat on disk */
885         
886         smbcli_close(cli2->tree, fnum2);
887         torture_close_connection(cli2);
888         cli2 = NULL;
889
890         /* This call is only for the people looking at ethereal :-) */
891         finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
892         finfo2.basic_info.in.fname = fname;
893
894         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo2);
895
896         if (!NT_STATUS_IS_OK(status)) {
897                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
898                 ret = False;
899                 goto done;
900         }
901
902  done:
903         if (fnum1 != -1)
904                 smbcli_close(cli->tree, fnum1);
905         smbcli_unlink(cli->tree, fname);
906         smbcli_deltree(cli->tree, BASEDIR);
907         if (cli2 != NULL) {
908                 torture_close_connection(cli2);
909         }
910
911         return ret;
912 }
913
914 /* 
915    basic testing of write calls
916 */
917 BOOL torture_raw_write(void)
918 {
919         struct smbcli_state *cli;
920         BOOL ret = True;
921         TALLOC_CTX *mem_ctx;
922
923         if (!torture_open_connection(&cli)) {
924                 return False;
925         }
926
927         mem_ctx = talloc_init("torture_raw_write");
928
929         ret &= test_finfo_after_write(cli, mem_ctx);
930         ret &= test_delayed_write_update(cli, mem_ctx);
931         ret &= test_write(cli, mem_ctx);
932         ret &= test_writeunlock(cli, mem_ctx);
933         ret &= test_writeclose(cli, mem_ctx);
934         ret &= test_writex(cli, mem_ctx);
935
936         torture_close_connection(cli);
937         talloc_destroy(mem_ctx);
938         return ret;
939 }