r3085: make the RAW-WRITE tests more robust to errors in previous parts of the test
[gd/samba-autobuild/.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("(%d) Incorrect status %s - should be %s\n", \
26                        __LINE__, 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("(%d) Incorrect value %s=%d - should be %d\n", \
34                        __LINE__, #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, __LINE__)) { \
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("(%d) wrong value for field %s  %.0f - %.0f\n", \
52                        __LINE__, #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, int line)
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 line %d! ofs=%d buf=0x%x correct=0x%x\n", 
94                                line, 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 %d\n", __LINE__);
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 %d\n", __LINE__);
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 %d\n", __LINE__);
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 %d\n", __LINE__);
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 %d\n", __LINE__);
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 %d\n", __LINE__);
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 %d\n", __LINE__);
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                 CHECK_STATUS(status, NT_STATUS_OK);
367                 CHECK_VALUE(io.writex.out.nwritten, 4000);
368                 CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
369
370                 memset(buf, 0, maxsize);
371                 if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
372                         printf("read failed at %d\n", __LINE__);
373                         ret = False;
374                         goto done;
375                 }
376                 CHECK_BUFFER(buf, seed+1, 4000);
377         }
378
379
380         setup_buffer(buf, seed, maxsize);
381
382 done:
383         smbcli_close(cli->tree, fnum);
384         smb_raw_exit(cli->session);
385         smbcli_deltree(cli->tree, BASEDIR);
386         return ret;
387 }
388
389
390 /*
391   test write unlock ops
392 */
393 static BOOL test_writeunlock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
394 {
395         union smb_write io;
396         NTSTATUS status;
397         BOOL ret = True;
398         int fnum;
399         char *buf;
400         const int maxsize = 90000;
401         const char *fname = BASEDIR "\\test.txt";
402         uint_t seed = time(NULL);
403         union smb_fileinfo finfo;
404
405         buf = talloc_zero(mem_ctx, maxsize);
406
407         if (!setup_dir(cli, BASEDIR)) {
408                 return False;
409         }
410
411         printf("Testing RAW_WRITE_WRITEUNLOCK\n");
412         io.generic.level = RAW_WRITE_WRITEUNLOCK;
413         
414         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
415         if (fnum == -1) {
416                 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
417                 ret = False;
418                 goto done;
419         }
420
421         printf("Trying zero write\n");
422         io.writeunlock.in.fnum = fnum;
423         io.writeunlock.in.count = 0;
424         io.writeunlock.in.offset = 0;
425         io.writeunlock.in.remaining = 0;
426         io.writeunlock.in.data = buf;
427         status = smb_raw_write(cli->tree, &io);
428         CHECK_STATUS(status, NT_STATUS_OK);
429         CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
430
431         setup_buffer(buf, seed, maxsize);
432
433         printf("Trying small write\n");
434         io.writeunlock.in.count = 9;
435         io.writeunlock.in.offset = 4;
436         io.writeunlock.in.data = buf;
437         status = smb_raw_write(cli->tree, &io);
438         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
439         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
440                 printf("read failed at %d\n", __LINE__);
441                 ret = False;
442                 goto done;
443         }
444         CHECK_BUFFER(buf+4, seed, 9);
445         CHECK_VALUE(IVAL(buf,0), 0);
446
447         setup_buffer(buf, seed, maxsize);
448         smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count, 
449                  0, WRITE_LOCK);
450         status = smb_raw_write(cli->tree, &io);
451         CHECK_STATUS(status, NT_STATUS_OK);
452         CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
453
454         memset(buf, 0, maxsize);
455         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
456                 printf("read failed at %d\n", __LINE__);
457                 ret = False;
458                 goto done;
459         }
460         CHECK_BUFFER(buf+4, seed, 9);
461         CHECK_VALUE(IVAL(buf,0), 0);
462
463         setup_buffer(buf, seed, maxsize);
464
465         printf("Trying large write\n");
466         io.writeunlock.in.count = 4000;
467         io.writeunlock.in.offset = 0;
468         io.writeunlock.in.data = buf;
469         smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count, 
470                  0, WRITE_LOCK);
471         status = smb_raw_write(cli->tree, &io);
472         CHECK_STATUS(status, NT_STATUS_OK);
473         CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
474
475         status = smb_raw_write(cli->tree, &io);
476         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
477
478         memset(buf, 0, maxsize);
479         if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
480                 printf("read failed at %d\n", __LINE__);
481                 ret = False;
482                 goto done;
483         }
484         CHECK_BUFFER(buf, seed, 4000);
485
486         printf("Trying bad fnum\n");
487         io.writeunlock.in.fnum = fnum+1;
488         io.writeunlock.in.count = 4000;
489         io.writeunlock.in.offset = 0;
490         io.writeunlock.in.data = buf;
491         status = smb_raw_write(cli->tree, &io);
492         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
493
494         printf("Setting file as sparse\n");
495         status = torture_set_sparse(cli->tree, fnum);
496         CHECK_STATUS(status, NT_STATUS_OK);
497         
498         printf("Trying 2^32 offset\n");
499         setup_buffer(buf, seed, maxsize);
500         io.writeunlock.in.fnum = fnum;
501         io.writeunlock.in.count = 4000;
502         io.writeunlock.in.offset = 0xFFFFFFFF - 2000;
503         io.writeunlock.in.data = buf;
504         smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count, 
505                  0, WRITE_LOCK);
506         status = smb_raw_write(cli->tree, &io);
507         CHECK_STATUS(status, NT_STATUS_OK);
508         CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
509         CHECK_ALL_INFO(io.writeunlock.in.count + (uint64_t)io.writeunlock.in.offset, size);
510
511         memset(buf, 0, maxsize);
512         if (smbcli_read(cli->tree, fnum, buf, io.writeunlock.in.offset, 4000) != 4000) {
513                 printf("read failed at %d\n", __LINE__);
514                 ret = False;
515                 goto done;
516         }
517         CHECK_BUFFER(buf, seed, 4000);
518
519 done:
520         smbcli_close(cli->tree, fnum);
521         smb_raw_exit(cli->session);
522         smbcli_deltree(cli->tree, BASEDIR);
523         return ret;
524 }
525
526
527 /*
528   test write close ops
529 */
530 static BOOL test_writeclose(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
531 {
532         union smb_write io;
533         NTSTATUS status;
534         BOOL ret = True;
535         int fnum;
536         char *buf;
537         const int maxsize = 90000;
538         const char *fname = BASEDIR "\\test.txt";
539         uint_t seed = time(NULL);
540         union smb_fileinfo finfo;
541
542         buf = talloc_zero(mem_ctx, maxsize);
543
544         if (!setup_dir(cli, BASEDIR)) {
545                 return False;
546         }
547
548         printf("Testing RAW_WRITE_WRITECLOSE\n");
549         io.generic.level = RAW_WRITE_WRITECLOSE;
550         
551         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
552         if (fnum == -1) {
553                 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
554                 ret = False;
555                 goto done;
556         }
557
558         printf("Trying zero write\n");
559         io.writeclose.in.fnum = fnum;
560         io.writeclose.in.count = 0;
561         io.writeclose.in.offset = 0;
562         io.writeclose.in.mtime = 0;
563         io.writeclose.in.data = buf;
564         status = smb_raw_write(cli->tree, &io);
565         CHECK_STATUS(status, NT_STATUS_OK);
566         CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
567
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         setup_buffer(buf, seed, maxsize);
573
574         printf("Trying small write\n");
575         io.writeclose.in.count = 9;
576         io.writeclose.in.offset = 4;
577         io.writeclose.in.data = buf;
578         status = smb_raw_write(cli->tree, &io);
579         CHECK_STATUS(status, NT_STATUS_OK);
580
581         status = smb_raw_write(cli->tree, &io);
582         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
583
584         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
585         io.writeclose.in.fnum = fnum;
586
587         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
588                 printf("read failed at %d\n", __LINE__);
589                 ret = False;
590                 goto done;
591         }
592         CHECK_BUFFER(buf+4, seed, 9);
593         CHECK_VALUE(IVAL(buf,0), 0);
594
595         setup_buffer(buf, seed, maxsize);
596         status = smb_raw_write(cli->tree, &io);
597         CHECK_STATUS(status, NT_STATUS_OK);
598         CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
599
600         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
601         io.writeclose.in.fnum = fnum;
602
603         memset(buf, 0, maxsize);
604         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
605                 printf("read failed at %d\n", __LINE__);
606                 ret = False;
607                 goto done;
608         }
609         CHECK_BUFFER(buf+4, seed, 9);
610         CHECK_VALUE(IVAL(buf,0), 0);
611
612         setup_buffer(buf, seed, maxsize);
613
614         printf("Trying large write\n");
615         io.writeclose.in.count = 4000;
616         io.writeclose.in.offset = 0;
617         io.writeclose.in.data = buf;
618         status = smb_raw_write(cli->tree, &io);
619         CHECK_STATUS(status, NT_STATUS_OK);
620         CHECK_VALUE(io.writeclose.out.nwritten, 4000);
621
622         status = smb_raw_write(cli->tree, &io);
623         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
624
625         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
626         io.writeclose.in.fnum = fnum;
627
628         memset(buf, 0, maxsize);
629         if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
630                 printf("read failed at %d\n", __LINE__);
631                 ret = False;
632                 goto done;
633         }
634         CHECK_BUFFER(buf, seed, 4000);
635
636         printf("Trying bad fnum\n");
637         io.writeclose.in.fnum = fnum+1;
638         io.writeclose.in.count = 4000;
639         io.writeclose.in.offset = 0;
640         io.writeclose.in.data = buf;
641         status = smb_raw_write(cli->tree, &io);
642         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
643
644         printf("Setting file as sparse\n");
645         status = torture_set_sparse(cli->tree, fnum);
646         CHECK_STATUS(status, NT_STATUS_OK);
647         
648         printf("Trying 2^32 offset\n");
649         setup_buffer(buf, seed, maxsize);
650         io.writeclose.in.fnum = fnum;
651         io.writeclose.in.count = 4000;
652         io.writeclose.in.offset = 0xFFFFFFFF - 2000;
653         io.writeclose.in.data = buf;
654         status = smb_raw_write(cli->tree, &io);
655         CHECK_STATUS(status, NT_STATUS_OK);
656         CHECK_VALUE(io.writeclose.out.nwritten, 4000);
657         CHECK_ALL_INFO(io.writeclose.in.count + (uint64_t)io.writeclose.in.offset, size);
658
659         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
660         io.writeclose.in.fnum = fnum;
661
662         memset(buf, 0, maxsize);
663         if (smbcli_read(cli->tree, fnum, buf, io.writeclose.in.offset, 4000) != 4000) {
664                 printf("read failed at %d\n", __LINE__);
665                 ret = False;
666                 goto done;
667         }
668         CHECK_BUFFER(buf, seed, 4000);
669
670 done:
671         smbcli_close(cli->tree, fnum);
672         smb_raw_exit(cli->session);
673         smbcli_deltree(cli->tree, BASEDIR);
674         return ret;
675 }
676
677 static BOOL test_delayed_write_update(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
678 {
679         union smb_fileinfo finfo1, finfo2;
680         const char *fname = BASEDIR "\\torture_file.txt";
681         NTSTATUS status;
682         int fnum1 = -1;
683         BOOL ret = True;
684         ssize_t written;
685         time_t t;
686
687         printf("Testing delayed update of write time\n");
688
689         if (!setup_dir(cli, BASEDIR)) {
690                 return False;
691         }
692
693         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
694         if (fnum1 == -1) {
695                 printf("Failed to open %s\n", fname);
696                 return False;
697         }
698
699         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
700         finfo1.basic_info.in.fnum = fnum1;
701         finfo2 = finfo1;
702
703         status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo1);
704
705         if (!NT_STATUS_IS_OK(status)) {
706                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
707                 return False;
708         }
709         
710         printf("Initial write time %s\n", 
711                nt_time_string(mem_ctx, finfo1.basic_info.out.write_time));
712
713         /* 3 second delay to ensure we get past any 2 second time
714            granularity (older systems may have that) */
715         sleep(3);
716
717         written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
718
719         if (written != 1) {
720                 printf("write failed - wrote %d bytes (%s)\n", written, __location__);
721                 return False;
722         }
723
724         t = time(NULL);
725
726         while (time(NULL) < t+120) {
727                 status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo2);
728
729                 if (!NT_STATUS_IS_OK(status)) {
730                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
731                         ret = False;
732                         break;
733                 }
734                 printf("write time %s\n", 
735                        nt_time_string(mem_ctx, finfo2.basic_info.out.write_time));
736                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
737                         printf("Server updated write_time after %d seconds\n",
738                                (int)(time(NULL) - t));
739                         break;
740                 }
741                 sleep(1);
742                 fflush(stdout);
743         }
744         
745         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
746                 printf("Server did not update write time?!\n");
747                 ret = False;
748         }
749
750
751         if (fnum1 != -1)
752                 smbcli_close(cli->tree, fnum1);
753         smbcli_unlink(cli->tree, fname);
754         smbcli_deltree(cli->tree, BASEDIR);
755
756         return ret;
757 }
758
759
760 /* Windows does obviously not update the stat info during a write call. I
761  * *think* this is the problem causing a spurious Excel 2003 on XP error
762  * message when saving a file. Excel does a setfileinfo, writes, and then does
763  * a getpath(!)info. Or so... For Samba sometimes it displays an error message
764  * that the file might have been changed in between. What i've been able to
765  * trace down is that this happens if the getpathinfo after the write shows a
766  * different last write time than the setfileinfo showed. This is really
767  * nasty....
768  */
769
770 static BOOL test_finfo_after_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
771 {
772         union smb_fileinfo finfo1, finfo2;
773         const char *fname = BASEDIR "\\torture_file.txt";
774         NTSTATUS status;
775         int fnum1 = -1;
776         BOOL ret = True;
777         ssize_t written;
778
779         printf("Testing finfo update on close\n");
780
781         if (!setup_dir(cli, BASEDIR)) {
782                 return False;
783         }
784
785         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
786         if (fnum1 == -1) {
787                 ret = False;
788                 goto done;
789         }
790
791         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
792         finfo1.basic_info.in.fnum = fnum1;
793
794         status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo1);
795
796         if (!NT_STATUS_IS_OK(status)) {
797                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
798                 ret = False;
799                 goto done;
800         }
801
802         msleep(1000);
803
804         written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
805
806         if (written != 1) {
807                 ret = False;
808                 goto done;
809         }
810
811         {
812                 struct smbcli_state *cli2;
813                 int fnum2;
814
815                 if (!torture_open_connection(&cli2)) {
816                         return False;
817                 }
818
819                 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
820                 if (fnum2 == -1) {
821                         ret = False;
822                         goto done;
823                 }
824
825                 written =  smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
826
827                 if (written != 1) {
828                         ret = False;
829                         goto done;
830                 }
831
832                 finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
833                 finfo2.basic_info.in.fname = fname;
834
835                 status = smb_raw_pathinfo(cli2->tree, mem_ctx, &finfo2);
836
837                 if (!NT_STATUS_IS_OK(status)) {
838                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
839                         ret = False;
840                         goto done;
841                 }
842
843                 if (finfo1.basic_info.out.create_time !=
844                     finfo2.basic_info.out.create_time) {
845                         ret = False;
846                         goto done;
847                 }
848                 
849                 if (finfo1.basic_info.out.access_time !=
850                     finfo2.basic_info.out.access_time) {
851                         ret = False;
852                         goto done;
853                 }
854                 
855                 if (finfo1.basic_info.out.write_time !=
856                     finfo2.basic_info.out.write_time) {
857                         ret = False;
858                         goto done;
859                 }
860                 
861                 if (finfo1.basic_info.out.change_time !=
862                     finfo2.basic_info.out.change_time) {
863                         ret = False;
864                         goto done;
865                 }
866
867                 /* One of the two following calls updates the qpathinfo. */
868
869                 /* If you had skipped the smbcli_write on fnum2, it would
870                  * *not* have updated the stat on disk */
871
872                 smbcli_close(cli2->tree, fnum2);
873                 torture_close_connection(cli2);
874         }
875
876         /* This call is only for the people looking at ethereal :-) */
877
878         finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
879         finfo2.basic_info.in.fname = fname;
880
881         status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo2);
882
883         if (!NT_STATUS_IS_OK(status)) {
884                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
885                 ret = False;
886                 goto done;
887         }
888
889  done:
890         if (fnum1 != -1)
891                 smbcli_close(cli->tree, fnum1);
892         smbcli_unlink(cli->tree, fname);
893         smbcli_deltree(cli->tree, BASEDIR);
894
895         return ret;
896 }
897
898 /* 
899    basic testing of write calls
900 */
901 BOOL torture_raw_write(int dummy)
902 {
903         struct smbcli_state *cli;
904         BOOL ret = True;
905         TALLOC_CTX *mem_ctx;
906
907         if (!torture_open_connection(&cli)) {
908                 return False;
909         }
910
911         mem_ctx = talloc_init("torture_raw_write");
912
913         if (!test_finfo_after_write(cli, mem_ctx)) {
914                 ret = False;
915         }
916
917         if (!test_delayed_write_update(cli, mem_ctx)) {
918                 ret = False;
919         }
920
921         if (!test_write(cli, mem_ctx)) {
922                 ret = False;
923         }
924
925         if (!test_writeunlock(cli, mem_ctx)) {
926                 ret = False;
927         }
928
929         if (!test_writeclose(cli, mem_ctx)) {
930                 ret = False;
931         }
932
933         if (!test_writex(cli, mem_ctx)) {
934                 ret = False;
935         }
936
937         torture_close_connection(cli);
938         talloc_destroy(mem_ctx);
939         return ret;
940 }