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