r2983: report a failure if a server doesn't update the write time at all
[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
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 /*
62   setup a random buffer based on a seed
63 */
64 static void setup_buffer(char *buf, uint_t seed, int len)
65 {
66         int i;
67         srandom(seed);
68         for (i=0;i<len;i++) buf[i] = random();
69 }
70
71 /*
72   check a random buffer based on a seed
73 */
74 static BOOL check_buffer(char *buf, uint_t seed, int len, int line)
75 {
76         int i;
77         srandom(seed);
78         for (i=0;i<len;i++) {
79                 char v = random();
80                 if (buf[i] != v) {
81                         printf("Buffer incorrect at line %d! ofs=%d buf=0x%x correct=0x%x\n", 
82                                line, i, buf[i], v);
83                         return False;
84                 }
85         }
86         return True;
87 }
88
89 /*
90   test write ops
91 */
92 static BOOL test_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
93 {
94         union smb_write io;
95         NTSTATUS status;
96         BOOL ret = True;
97         int fnum;
98         char *buf;
99         const int maxsize = 90000;
100         const char *fname = BASEDIR "\\test.txt";
101         uint_t seed = time(NULL);
102         union smb_fileinfo finfo;
103
104         buf = talloc_zero(mem_ctx, maxsize);
105
106         if (smbcli_deltree(cli->tree, BASEDIR) == -1 ||
107             NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR))) {
108                 printf("Unable to setup %s - %s\n", BASEDIR, smbcli_errstr(cli->tree));
109                 return False;
110         }
111
112         printf("Testing RAW_WRITE_WRITE\n");
113         io.generic.level = RAW_WRITE_WRITE;
114         
115         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
116         if (fnum == -1) {
117                 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
118                 ret = False;
119                 goto done;
120         }
121
122         printf("Trying zero write\n");
123         io.write.in.fnum = fnum;
124         io.write.in.count = 0;
125         io.write.in.offset = 0;
126         io.write.in.remaining = 0;
127         io.write.in.data = buf;
128         status = smb_raw_write(cli->tree, &io);
129         CHECK_STATUS(status, NT_STATUS_OK);
130         CHECK_VALUE(io.write.out.nwritten, 0);
131
132         setup_buffer(buf, seed, maxsize);
133
134         printf("Trying small write\n");
135         io.write.in.count = 9;
136         io.write.in.offset = 4;
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, io.write.in.count);
141
142         memset(buf, 0, maxsize);
143         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
144                 printf("read failed at %d\n", __LINE__);
145                 ret = False;
146                 goto done;
147         }
148         CHECK_BUFFER(buf+4, seed, 9);
149         CHECK_VALUE(IVAL(buf,0), 0);
150
151         setup_buffer(buf, seed, maxsize);
152
153         printf("Trying large write\n");
154         io.write.in.count = 4000;
155         io.write.in.offset = 0;
156         io.write.in.data = buf;
157         status = smb_raw_write(cli->tree, &io);
158         CHECK_STATUS(status, NT_STATUS_OK);
159         CHECK_VALUE(io.write.out.nwritten, 4000);
160
161         memset(buf, 0, maxsize);
162         if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
163                 printf("read failed at %d\n", __LINE__);
164                 ret = False;
165                 goto done;
166         }
167         CHECK_BUFFER(buf, seed, 4000);
168
169         printf("Trying bad fnum\n");
170         io.write.in.fnum = fnum+1;
171         io.write.in.count = 4000;
172         io.write.in.offset = 0;
173         io.write.in.data = buf;
174         status = smb_raw_write(cli->tree, &io);
175         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
176
177         printf("Setting file as sparse\n");
178         status = torture_set_sparse(cli->tree, fnum);
179         CHECK_STATUS(status, NT_STATUS_OK);
180         
181         printf("Trying 2^32 offset\n");
182         setup_buffer(buf, seed, maxsize);
183         io.write.in.fnum = fnum;
184         io.write.in.count = 4000;
185         io.write.in.offset = 0xFFFFFFFF - 2000;
186         io.write.in.data = buf;
187         status = smb_raw_write(cli->tree, &io);
188         CHECK_STATUS(status, NT_STATUS_OK);
189         CHECK_VALUE(io.write.out.nwritten, 4000);
190         CHECK_ALL_INFO(io.write.in.count + (uint64_t)io.write.in.offset, size);
191
192         memset(buf, 0, maxsize);
193         if (smbcli_read(cli->tree, fnum, buf, io.write.in.offset, 4000) != 4000) {
194                 printf("read failed at %d\n", __LINE__);
195                 ret = False;
196                 goto done;
197         }
198         CHECK_BUFFER(buf, seed, 4000);
199
200 done:
201         smbcli_close(cli->tree, fnum);
202         smb_raw_exit(cli->session);
203         smbcli_deltree(cli->tree, BASEDIR);
204         return ret;
205 }
206
207
208 /*
209   test writex ops
210 */
211 static BOOL test_writex(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
212 {
213         union smb_write io;
214         NTSTATUS status;
215         BOOL ret = True;
216         int fnum, i;
217         char *buf;
218         const int maxsize = 90000;
219         const char *fname = BASEDIR "\\test.txt";
220         uint_t seed = time(NULL);
221         union smb_fileinfo finfo;
222
223         buf = talloc_zero(mem_ctx, maxsize);
224
225         if (smbcli_deltree(cli->tree, BASEDIR) == -1 ||
226             NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR))) {
227                 printf("Unable to setup %s - %s\n", BASEDIR, smbcli_errstr(cli->tree));
228                 return False;
229         }
230
231         printf("Testing RAW_WRITE_WRITEX\n");
232         io.generic.level = RAW_WRITE_WRITEX;
233         
234         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
235         if (fnum == -1) {
236                 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
237                 ret = False;
238                 goto done;
239         }
240
241         printf("Trying zero write\n");
242         io.writex.in.fnum = fnum;
243         io.writex.in.offset = 0;
244         io.writex.in.wmode = 0;
245         io.writex.in.remaining = 0;
246         io.writex.in.count = 0;
247         io.writex.in.data = buf;
248         status = smb_raw_write(cli->tree, &io);
249         CHECK_STATUS(status, NT_STATUS_OK);
250         CHECK_VALUE(io.writex.out.nwritten, 0);
251
252         setup_buffer(buf, seed, maxsize);
253
254         printf("Trying small write\n");
255         io.writex.in.count = 9;
256         io.writex.in.offset = 4;
257         io.writex.in.data = buf;
258         status = smb_raw_write(cli->tree, &io);
259         CHECK_STATUS(status, NT_STATUS_OK);
260         CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
261
262         memset(buf, 0, maxsize);
263         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
264                 printf("read failed at %d\n", __LINE__);
265                 ret = False;
266                 goto done;
267         }
268         CHECK_BUFFER(buf+4, seed, 9);
269         CHECK_VALUE(IVAL(buf,0), 0);
270
271         setup_buffer(buf, seed, maxsize);
272
273         printf("Trying large write\n");
274         io.writex.in.count = 4000;
275         io.writex.in.offset = 0;
276         io.writex.in.data = buf;
277         status = smb_raw_write(cli->tree, &io);
278         CHECK_STATUS(status, NT_STATUS_OK);
279         CHECK_VALUE(io.writex.out.nwritten, 4000);
280
281         memset(buf, 0, maxsize);
282         if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
283                 printf("read failed at %d\n", __LINE__);
284                 ret = False;
285                 goto done;
286         }
287         CHECK_BUFFER(buf, seed, 4000);
288
289         printf("Trying bad fnum\n");
290         io.writex.in.fnum = fnum+1;
291         io.writex.in.count = 4000;
292         io.writex.in.offset = 0;
293         io.writex.in.data = buf;
294         status = smb_raw_write(cli->tree, &io);
295         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
296
297         printf("Testing wmode\n");
298         io.writex.in.fnum = fnum;
299         io.writex.in.count = 1;
300         io.writex.in.offset = 0;
301         io.writex.in.wmode = 1;
302         io.writex.in.data = buf;
303         status = smb_raw_write(cli->tree, &io);
304         CHECK_STATUS(status, NT_STATUS_OK);
305         CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
306
307         io.writex.in.wmode = 2;
308         status = smb_raw_write(cli->tree, &io);
309         CHECK_STATUS(status, NT_STATUS_OK);
310         CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
311
312
313         printf("Trying locked region\n");
314         cli->session->pid++;
315         if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 3, 1, 0, WRITE_LOCK))) {
316                 printf("Failed to lock file at %d\n", __LINE__);
317                 ret = False;
318                 goto done;
319         }
320         cli->session->pid--;
321         io.writex.in.wmode = 0;
322         io.writex.in.count = 4;
323         io.writex.in.offset = 0;
324         status = smb_raw_write(cli->tree, &io);
325         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
326
327         printf("Setting file as sparse\n");
328         status = torture_set_sparse(cli->tree, fnum);
329         CHECK_STATUS(status, NT_STATUS_OK);
330         
331         printf("Trying 2^32 offset\n");
332         setup_buffer(buf, seed, maxsize);
333         io.writex.in.fnum = fnum;
334         io.writex.in.count = 4000;
335         io.writex.in.offset = 0xFFFFFFFF - 2000;
336         io.writex.in.data = buf;
337         status = smb_raw_write(cli->tree, &io);
338         CHECK_STATUS(status, NT_STATUS_OK);
339         CHECK_VALUE(io.writex.out.nwritten, 4000);
340         CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
341
342         memset(buf, 0, maxsize);
343         if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
344                 printf("read failed at %d\n", __LINE__);
345                 ret = False;
346                 goto done;
347         }
348         CHECK_BUFFER(buf, seed, 4000);
349
350         for (i=33;i<64;i++) {
351                 printf("Trying 2^%d offset\n", i);
352                 setup_buffer(buf, seed+1, maxsize);
353                 io.writex.in.fnum = fnum;
354                 io.writex.in.count = 4000;
355                 io.writex.in.offset = ((uint64_t)1) << i;
356                 io.writex.in.data = buf;
357                 status = smb_raw_write(cli->tree, &io);
358                 CHECK_STATUS(status, NT_STATUS_OK);
359                 CHECK_VALUE(io.writex.out.nwritten, 4000);
360                 CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
361
362                 memset(buf, 0, maxsize);
363                 if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
364                         printf("read failed at %d\n", __LINE__);
365                         ret = False;
366                         goto done;
367                 }
368                 CHECK_BUFFER(buf, seed+1, 4000);
369         }
370
371
372         setup_buffer(buf, seed, maxsize);
373
374 done:
375         smbcli_close(cli->tree, fnum);
376         smb_raw_exit(cli->session);
377         smbcli_deltree(cli->tree, BASEDIR);
378         return ret;
379 }
380
381
382 /*
383   test write unlock ops
384 */
385 static BOOL test_writeunlock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
386 {
387         union smb_write io;
388         NTSTATUS status;
389         BOOL ret = True;
390         int fnum;
391         char *buf;
392         const int maxsize = 90000;
393         const char *fname = BASEDIR "\\test.txt";
394         uint_t seed = time(NULL);
395         union smb_fileinfo finfo;
396
397         buf = talloc_zero(mem_ctx, maxsize);
398
399         if (smbcli_deltree(cli->tree, BASEDIR) == -1 ||
400             NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR))) {
401                 printf("Unable to setup %s - %s\n", BASEDIR, smbcli_errstr(cli->tree));
402                 return False;
403         }
404
405         printf("Testing RAW_WRITE_WRITEUNLOCK\n");
406         io.generic.level = RAW_WRITE_WRITEUNLOCK;
407         
408         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
409         if (fnum == -1) {
410                 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
411                 ret = False;
412                 goto done;
413         }
414
415         printf("Trying zero write\n");
416         io.writeunlock.in.fnum = fnum;
417         io.writeunlock.in.count = 0;
418         io.writeunlock.in.offset = 0;
419         io.writeunlock.in.remaining = 0;
420         io.writeunlock.in.data = buf;
421         status = smb_raw_write(cli->tree, &io);
422         CHECK_STATUS(status, NT_STATUS_OK);
423         CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
424
425         setup_buffer(buf, seed, maxsize);
426
427         printf("Trying small write\n");
428         io.writeunlock.in.count = 9;
429         io.writeunlock.in.offset = 4;
430         io.writeunlock.in.data = buf;
431         status = smb_raw_write(cli->tree, &io);
432         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
433         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
434                 printf("read failed at %d\n", __LINE__);
435                 ret = False;
436                 goto done;
437         }
438         CHECK_BUFFER(buf+4, seed, 9);
439         CHECK_VALUE(IVAL(buf,0), 0);
440
441         setup_buffer(buf, seed, maxsize);
442         smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count, 
443                  0, WRITE_LOCK);
444         status = smb_raw_write(cli->tree, &io);
445         CHECK_STATUS(status, NT_STATUS_OK);
446         CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
447
448         memset(buf, 0, maxsize);
449         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
450                 printf("read failed at %d\n", __LINE__);
451                 ret = False;
452                 goto done;
453         }
454         CHECK_BUFFER(buf+4, seed, 9);
455         CHECK_VALUE(IVAL(buf,0), 0);
456
457         setup_buffer(buf, seed, maxsize);
458
459         printf("Trying large write\n");
460         io.writeunlock.in.count = 4000;
461         io.writeunlock.in.offset = 0;
462         io.writeunlock.in.data = buf;
463         smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count, 
464                  0, WRITE_LOCK);
465         status = smb_raw_write(cli->tree, &io);
466         CHECK_STATUS(status, NT_STATUS_OK);
467         CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
468
469         status = smb_raw_write(cli->tree, &io);
470         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
471
472         memset(buf, 0, maxsize);
473         if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
474                 printf("read failed at %d\n", __LINE__);
475                 ret = False;
476                 goto done;
477         }
478         CHECK_BUFFER(buf, seed, 4000);
479
480         printf("Trying bad fnum\n");
481         io.writeunlock.in.fnum = fnum+1;
482         io.writeunlock.in.count = 4000;
483         io.writeunlock.in.offset = 0;
484         io.writeunlock.in.data = buf;
485         status = smb_raw_write(cli->tree, &io);
486         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
487
488         printf("Setting file as sparse\n");
489         status = torture_set_sparse(cli->tree, fnum);
490         CHECK_STATUS(status, NT_STATUS_OK);
491         
492         printf("Trying 2^32 offset\n");
493         setup_buffer(buf, seed, maxsize);
494         io.writeunlock.in.fnum = fnum;
495         io.writeunlock.in.count = 4000;
496         io.writeunlock.in.offset = 0xFFFFFFFF - 2000;
497         io.writeunlock.in.data = buf;
498         smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count, 
499                  0, WRITE_LOCK);
500         status = smb_raw_write(cli->tree, &io);
501         CHECK_STATUS(status, NT_STATUS_OK);
502         CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
503         CHECK_ALL_INFO(io.writeunlock.in.count + (uint64_t)io.writeunlock.in.offset, size);
504
505         memset(buf, 0, maxsize);
506         if (smbcli_read(cli->tree, fnum, buf, io.writeunlock.in.offset, 4000) != 4000) {
507                 printf("read failed at %d\n", __LINE__);
508                 ret = False;
509                 goto done;
510         }
511         CHECK_BUFFER(buf, seed, 4000);
512
513 done:
514         smbcli_close(cli->tree, fnum);
515         smb_raw_exit(cli->session);
516         smbcli_deltree(cli->tree, BASEDIR);
517         return ret;
518 }
519
520
521 /*
522   test write close ops
523 */
524 static BOOL test_writeclose(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
525 {
526         union smb_write io;
527         NTSTATUS status;
528         BOOL ret = True;
529         int fnum;
530         char *buf;
531         const int maxsize = 90000;
532         const char *fname = BASEDIR "\\test.txt";
533         uint_t seed = time(NULL);
534         union smb_fileinfo finfo;
535
536         buf = talloc_zero(mem_ctx, maxsize);
537
538         if (smbcli_deltree(cli->tree, BASEDIR) == -1 ||
539             NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR))) {
540                 printf("Unable to setup %s - %s\n", BASEDIR, smbcli_errstr(cli->tree));
541                 return False;
542         }
543
544         printf("Testing RAW_WRITE_WRITECLOSE\n");
545         io.generic.level = RAW_WRITE_WRITECLOSE;
546         
547         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
548         if (fnum == -1) {
549                 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
550                 ret = False;
551                 goto done;
552         }
553
554         printf("Trying zero write\n");
555         io.writeclose.in.fnum = fnum;
556         io.writeclose.in.count = 0;
557         io.writeclose.in.offset = 0;
558         io.writeclose.in.mtime = 0;
559         io.writeclose.in.data = buf;
560         status = smb_raw_write(cli->tree, &io);
561         CHECK_STATUS(status, NT_STATUS_OK);
562         CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
563
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         setup_buffer(buf, seed, maxsize);
569
570         printf("Trying small write\n");
571         io.writeclose.in.count = 9;
572         io.writeclose.in.offset = 4;
573         io.writeclose.in.data = buf;
574         status = smb_raw_write(cli->tree, &io);
575         CHECK_STATUS(status, NT_STATUS_OK);
576
577         status = smb_raw_write(cli->tree, &io);
578         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
579
580         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
581         io.writeclose.in.fnum = fnum;
582
583         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
584                 printf("read failed at %d\n", __LINE__);
585                 ret = False;
586                 goto done;
587         }
588         CHECK_BUFFER(buf+4, seed, 9);
589         CHECK_VALUE(IVAL(buf,0), 0);
590
591         setup_buffer(buf, seed, maxsize);
592         status = smb_raw_write(cli->tree, &io);
593         CHECK_STATUS(status, NT_STATUS_OK);
594         CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
595
596         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
597         io.writeclose.in.fnum = fnum;
598
599         memset(buf, 0, maxsize);
600         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
601                 printf("read failed at %d\n", __LINE__);
602                 ret = False;
603                 goto done;
604         }
605         CHECK_BUFFER(buf+4, seed, 9);
606         CHECK_VALUE(IVAL(buf,0), 0);
607
608         setup_buffer(buf, seed, maxsize);
609
610         printf("Trying large write\n");
611         io.writeclose.in.count = 4000;
612         io.writeclose.in.offset = 0;
613         io.writeclose.in.data = buf;
614         status = smb_raw_write(cli->tree, &io);
615         CHECK_STATUS(status, NT_STATUS_OK);
616         CHECK_VALUE(io.writeclose.out.nwritten, 4000);
617
618         status = smb_raw_write(cli->tree, &io);
619         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
620
621         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
622         io.writeclose.in.fnum = fnum;
623
624         memset(buf, 0, maxsize);
625         if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
626                 printf("read failed at %d\n", __LINE__);
627                 ret = False;
628                 goto done;
629         }
630         CHECK_BUFFER(buf, seed, 4000);
631
632         printf("Trying bad fnum\n");
633         io.writeclose.in.fnum = fnum+1;
634         io.writeclose.in.count = 4000;
635         io.writeclose.in.offset = 0;
636         io.writeclose.in.data = buf;
637         status = smb_raw_write(cli->tree, &io);
638         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
639
640         printf("Setting file as sparse\n");
641         status = torture_set_sparse(cli->tree, fnum);
642         CHECK_STATUS(status, NT_STATUS_OK);
643         
644         printf("Trying 2^32 offset\n");
645         setup_buffer(buf, seed, maxsize);
646         io.writeclose.in.fnum = fnum;
647         io.writeclose.in.count = 4000;
648         io.writeclose.in.offset = 0xFFFFFFFF - 2000;
649         io.writeclose.in.data = buf;
650         status = smb_raw_write(cli->tree, &io);
651         CHECK_STATUS(status, NT_STATUS_OK);
652         CHECK_VALUE(io.writeclose.out.nwritten, 4000);
653         CHECK_ALL_INFO(io.writeclose.in.count + (uint64_t)io.writeclose.in.offset, size);
654
655         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
656         io.writeclose.in.fnum = fnum;
657
658         memset(buf, 0, maxsize);
659         if (smbcli_read(cli->tree, fnum, buf, io.writeclose.in.offset, 4000) != 4000) {
660                 printf("read failed at %d\n", __LINE__);
661                 ret = False;
662                 goto done;
663         }
664         CHECK_BUFFER(buf, seed, 4000);
665
666 done:
667         smbcli_close(cli->tree, fnum);
668         smb_raw_exit(cli->session);
669         smbcli_deltree(cli->tree, BASEDIR);
670         return ret;
671 }
672
673 static BOOL test_delayed_write_update(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
674 {
675         union smb_fileinfo finfo1, finfo2;
676         const char *fname = BASEDIR "\\torture_file.txt";
677         NTSTATUS status;
678         int fnum1 = -1;
679         BOOL ret = True;
680         ssize_t written;
681         time_t t;
682
683         printf("Testing delayed update of write time\n");
684
685         if (smbcli_deltree(cli->tree, BASEDIR) == -1 ||
686             NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR))) {
687                 printf("Unable to setup %s - %s\n", BASEDIR, smbcli_errstr(cli->tree));
688                 return False;
689         }
690
691         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
692         if (fnum1 == -1) {
693                 printf("Failed to open %s\n", fname);
694                 return False;
695         }
696
697         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
698         finfo1.basic_info.in.fnum = fnum1;
699         finfo2 = finfo1;
700
701         status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo1);
702
703         if (!NT_STATUS_IS_OK(status)) {
704                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
705                 return False;
706         }
707         
708         printf("Initial write time %s\n", 
709                nt_time_string(mem_ctx, finfo1.basic_info.out.write_time));
710
711         /* 3 second delay to ensure we get past any 2 second time
712            granularity (older systems may have that) */
713         sleep(3);
714
715         written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
716
717         if (written != 1) {
718                 printf("write failed - wrote %d bytes\n", written);
719                 return False;
720         }
721
722         t = time(NULL);
723
724         while (time(NULL) < t+120) {
725                 status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo2);
726
727                 if (!NT_STATUS_IS_OK(status)) {
728                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
729                         ret = False;
730                         break;
731                 }
732                 printf("write time %s\n", 
733                        nt_time_string(mem_ctx, finfo2.basic_info.out.write_time));
734                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
735                         printf("Server updated write_time after %d seconds\n",
736                                (int)(time(NULL) - t));
737                         break;
738                 }
739                 sleep(1);
740                 fflush(stdout);
741         }
742         
743         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
744                 printf("Server did not update write time?!\n");
745                 ret = False;
746         }
747
748
749         if (fnum1 != -1)
750                 smbcli_close(cli->tree, fnum1);
751         smbcli_unlink(cli->tree, fname);
752         smbcli_deltree(cli->tree, BASEDIR);
753
754         return ret;
755 }
756
757
758 /* Windows does obviously not update the stat info during a write call. I
759  * *think* this is the problem causing a spurious Excel 2003 on XP error
760  * message when saving a file. Excel does a setfileinfo, writes, and then does
761  * a getpath(!)info. Or so... For Samba sometimes it displays an error message
762  * that the file might have been changed in between. What i've been able to
763  * trace down is that this happens if the getpathinfo after the write shows a
764  * different last write time than the setfileinfo showed. This is really
765  * nasty....
766  */
767
768 static BOOL test_finfo_after_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
769 {
770         union smb_fileinfo finfo1, finfo2;
771         const char *fname = BASEDIR "\\torture_file.txt";
772         NTSTATUS status;
773         int fnum1 = -1;
774         BOOL ret = True;
775         ssize_t written;
776
777         printf("Testing finfo update on close\n");
778
779         if (smbcli_deltree(cli->tree, BASEDIR) == -1 ||
780             NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR))) {
781                 printf("Unable to setup %s - %s\n", BASEDIR, smbcli_errstr(cli->tree));
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 }