dns: Use new DNS debugclass in DNS server
[kai/samba.git] / source4 / torture / raw / write.c
1 /*
2    Unix SMB/CIFS implementation.
3    test suite for various write operations
4
5    Copyright (C) Andrew Tridgell 2003
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "libcli/raw/libcliraw.h"
23 #include "system/time.h"
24 #include "system/filesys.h"
25 #include "libcli/libcli.h"
26 #include "torture/util.h"
27 #include "torture/raw/proto.h"
28
29 #define CHECK_STATUS(status, correct) do { \
30         if (!NT_STATUS_EQUAL(status, correct)) { \
31                 torture_fail(tctx, talloc_asprintf(tctx, "(%s) Incorrect status %s - should be %s\n", \
32                        __location__, nt_errstr(status), nt_errstr(correct))); \
33                 ret = false; \
34                 goto done; \
35         }} while (0)
36
37 #define CHECK_VALUE(v, correct) do { \
38         if ((v) != (correct)) { \
39                 torture_fail(tctx, talloc_asprintf(tctx, "(%s) Incorrect value %s=%d - should be %d\n", \
40                        __location__, #v, v, correct)); \
41                 ret = false; \
42                 goto done; \
43         }} while (0)
44
45 #define CHECK_BUFFER(buf, seed, len) do { \
46         if (!check_buffer(tctx, buf, seed, len, __location__)) { \
47                 ret = false; \
48                 goto done; \
49         }} while (0)
50
51 #define CHECK_ALL_INFO(v, field) do { \
52         finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
53         finfo.all_info.in.file.path = fname; \
54         status = smb_raw_pathinfo(cli->tree, tctx, &finfo); \
55         CHECK_STATUS(status, NT_STATUS_OK); \
56         if ((v) != finfo.all_info.out.field) { \
57                 torture_comment(tctx, "(%s) wrong value for field %s  %.0f - %.0f\n", \
58                        __location__, #field, (double)v, (double)finfo.all_info.out.field); \
59                 dump_all_info(tctx, &finfo); \
60                 ret = false; \
61         }} while (0)
62
63
64 #define BASEDIR "\\testwrite"
65
66
67 /*
68   setup a random buffer based on a seed
69 */
70 static void setup_buffer(uint8_t *buf, unsigned int seed, int len)
71 {
72         int i;
73         srandom(seed);
74         for (i=0;i<len;i++) buf[i] = random();
75 }
76
77 /*
78   check a random buffer based on a seed
79 */
80 static bool check_buffer(struct torture_context *tctx,
81                          uint8_t *buf, unsigned int seed, int len, const char *location)
82 {
83         int i;
84         srandom(seed);
85         for (i=0;i<len;i++) {
86                 uint8_t v = random();
87                 if (buf[i] != v) {
88                         torture_fail(tctx, talloc_asprintf(tctx, "Buffer incorrect at %s! ofs=%d buf=0x%x correct=0x%x\n",
89                                location, i, buf[i], v));
90                         return false;
91                 }
92         }
93         return true;
94 }
95
96 /*
97   test write ops
98 */
99 static bool test_write(struct torture_context *tctx,
100                        struct smbcli_state *cli)
101 {
102         union smb_write io;
103         NTSTATUS status;
104         bool ret = true;
105         int fnum;
106         uint8_t *buf;
107         const int maxsize = 90000;
108         const char *fname = BASEDIR "\\test.txt";
109         unsigned int seed = time(NULL);
110         union smb_fileinfo finfo;
111
112         buf = talloc_zero_array(tctx, uint8_t, maxsize);
113
114         if (!torture_setup_dir(cli, BASEDIR)) {
115                 torture_fail(tctx, "failed to setup basedir");
116         }
117
118         torture_comment(tctx, "Testing RAW_WRITE_WRITE\n");
119         io.generic.level = RAW_WRITE_WRITE;
120
121         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
122         if (fnum == -1) {
123                 ret = false;
124                 torture_fail_goto(tctx, done,
125                         talloc_asprintf(tctx, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)));
126         }
127
128         torture_comment(tctx, "Trying zero write\n");
129         io.write.in.file.fnum = fnum;
130         io.write.in.count = 0;
131         io.write.in.offset = 0;
132         io.write.in.remaining = 0;
133         io.write.in.data = buf;
134         status = smb_raw_write(cli->tree, &io);
135         CHECK_STATUS(status, NT_STATUS_OK);
136         CHECK_VALUE(io.write.out.nwritten, 0);
137
138         setup_buffer(buf, seed, maxsize);
139
140         torture_comment(tctx, "Trying small write\n");
141         io.write.in.count = 9;
142         io.write.in.offset = 4;
143         io.write.in.data = buf;
144         status = smb_raw_write(cli->tree, &io);
145         CHECK_STATUS(status, NT_STATUS_OK);
146         CHECK_VALUE(io.write.out.nwritten, io.write.in.count);
147
148         memset(buf, 0, maxsize);
149         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
150                 ret = false;
151                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
152         }
153         CHECK_BUFFER(buf+4, seed, 9);
154         CHECK_VALUE(IVAL(buf,0), 0);
155
156         setup_buffer(buf, seed, maxsize);
157
158         torture_comment(tctx, "Trying large write\n");
159         io.write.in.count = 4000;
160         io.write.in.offset = 0;
161         io.write.in.data = buf;
162         status = smb_raw_write(cli->tree, &io);
163         CHECK_STATUS(status, NT_STATUS_OK);
164         CHECK_VALUE(io.write.out.nwritten, 4000);
165
166         memset(buf, 0, maxsize);
167         if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
168                 ret = false;
169                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
170         }
171         CHECK_BUFFER(buf, seed, 4000);
172
173         torture_comment(tctx, "Trying bad fnum\n");
174         io.write.in.file.fnum = fnum+1;
175         io.write.in.count = 4000;
176         io.write.in.offset = 0;
177         io.write.in.data = buf;
178         status = smb_raw_write(cli->tree, &io);
179         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
180
181         torture_comment(tctx, "Setting file as sparse\n");
182         status = torture_set_sparse(cli->tree, fnum);
183         CHECK_STATUS(status, NT_STATUS_OK);
184
185         if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
186                 torture_comment(tctx, "skipping large file tests - CAP_LARGE_FILES not set\n");
187                 goto done;
188         }
189
190         torture_comment(tctx, "Trying 2^32 offset\n");
191         setup_buffer(buf, seed, maxsize);
192         io.write.in.file.fnum = fnum;
193         io.write.in.count = 4000;
194         io.write.in.offset = 0xFFFFFFFF - 2000;
195         io.write.in.data = buf;
196         status = smb_raw_write(cli->tree, &io);
197         CHECK_STATUS(status, NT_STATUS_OK);
198         CHECK_VALUE(io.write.out.nwritten, 4000);
199         CHECK_ALL_INFO(io.write.in.count + (uint64_t)io.write.in.offset, size);
200
201         memset(buf, 0, maxsize);
202         if (smbcli_read(cli->tree, fnum, buf, io.write.in.offset, 4000) != 4000) {
203                 ret = false;
204                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
205         }
206         CHECK_BUFFER(buf, seed, 4000);
207
208 done:
209         smbcli_close(cli->tree, fnum);
210         smb_raw_exit(cli->session);
211         smbcli_deltree(cli->tree, BASEDIR);
212         return ret;
213 }
214
215
216 /*
217   test writex ops
218 */
219 static bool test_writex(struct torture_context *tctx,
220                         struct smbcli_state *cli)
221 {
222         union smb_write io;
223         NTSTATUS status;
224         bool ret = true;
225         int fnum, i;
226         uint8_t *buf;
227         const int maxsize = 90000;
228         const char *fname = BASEDIR "\\test.txt";
229         unsigned int seed = time(NULL);
230         union smb_fileinfo finfo;
231         int max_bits=63;
232
233         if (!torture_setting_bool(tctx, "dangerous", false)) {
234                 max_bits=33;
235                 torture_comment(tctx, "dangerous not set - limiting range of test to 2^%d\n", max_bits);
236         }
237
238         buf = talloc_zero_array(tctx, uint8_t, maxsize);
239
240         if (!cli->transport->negotiate.lockread_supported) {
241                 torture_comment(tctx, "Server does not support writeunlock - skipping\n");
242                 return true;
243         }
244
245         if (!torture_setup_dir(cli, BASEDIR)) {
246                 torture_fail(tctx, "failed to setup basedir");
247         }
248
249         torture_comment(tctx, "Testing RAW_WRITE_WRITEX\n");
250         io.generic.level = RAW_WRITE_WRITEX;
251
252         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
253         if (fnum == -1) {
254                 ret = false;
255                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)));
256         }
257
258         torture_comment(tctx, "Trying zero write\n");
259         io.writex.in.file.fnum = fnum;
260         io.writex.in.offset = 0;
261         io.writex.in.wmode = 0;
262         io.writex.in.remaining = 0;
263         io.writex.in.count = 0;
264         io.writex.in.data = buf;
265         status = smb_raw_write(cli->tree, &io);
266         CHECK_STATUS(status, NT_STATUS_OK);
267         CHECK_VALUE(io.writex.out.nwritten, 0);
268
269         setup_buffer(buf, seed, maxsize);
270
271         torture_comment(tctx, "Trying small write\n");
272         io.writex.in.count = 9;
273         io.writex.in.offset = 4;
274         io.writex.in.data = buf;
275         status = smb_raw_write(cli->tree, &io);
276         CHECK_STATUS(status, NT_STATUS_OK);
277         CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
278
279         memset(buf, 0, maxsize);
280         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
281                 ret = false;
282                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
283         }
284         CHECK_BUFFER(buf+4, seed, 9);
285         CHECK_VALUE(IVAL(buf,0), 0);
286
287         setup_buffer(buf, seed, maxsize);
288
289         torture_comment(tctx, "Trying large write\n");
290         io.writex.in.count = 4000;
291         io.writex.in.offset = 0;
292         io.writex.in.data = buf;
293         status = smb_raw_write(cli->tree, &io);
294         CHECK_STATUS(status, NT_STATUS_OK);
295         CHECK_VALUE(io.writex.out.nwritten, 4000);
296
297         memset(buf, 0, maxsize);
298         if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
299                 ret = false;
300                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
301         }
302         CHECK_BUFFER(buf, seed, 4000);
303
304         torture_comment(tctx, "Trying bad fnum\n");
305         io.writex.in.file.fnum = fnum+1;
306         io.writex.in.count = 4000;
307         io.writex.in.offset = 0;
308         io.writex.in.data = buf;
309         status = smb_raw_write(cli->tree, &io);
310         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
311
312         torture_comment(tctx, "Testing wmode\n");
313         io.writex.in.file.fnum = fnum;
314         io.writex.in.count = 1;
315         io.writex.in.offset = 0;
316         io.writex.in.wmode = 1;
317         io.writex.in.data = buf;
318         status = smb_raw_write(cli->tree, &io);
319         CHECK_STATUS(status, NT_STATUS_OK);
320         CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
321
322         io.writex.in.wmode = 2;
323         status = smb_raw_write(cli->tree, &io);
324         CHECK_STATUS(status, NT_STATUS_OK);
325         CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
326
327
328         torture_comment(tctx, "Trying locked region\n");
329         cli->session->pid++;
330         if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 3, 1, 0, WRITE_LOCK))) {
331                 ret = false;
332                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "Failed to lock file at %s\n", __location__));
333         }
334         cli->session->pid--;
335         io.writex.in.wmode = 0;
336         io.writex.in.count = 4;
337         io.writex.in.offset = 0;
338         status = smb_raw_write(cli->tree, &io);
339         CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
340
341         torture_comment(tctx, "Setting file as sparse\n");
342         status = torture_set_sparse(cli->tree, fnum);
343         CHECK_STATUS(status, NT_STATUS_OK);
344
345         if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
346                 torture_skip(tctx, "skipping large file tests - CAP_LARGE_FILES not set\n");
347         }
348
349         torture_comment(tctx, "Trying 2^32 offset\n");
350         setup_buffer(buf, seed, maxsize);
351         io.writex.in.file.fnum = fnum;
352         io.writex.in.count = 4000;
353         io.writex.in.offset = 0xFFFFFFFF - 2000;
354         io.writex.in.data = buf;
355         status = smb_raw_write(cli->tree, &io);
356         CHECK_STATUS(status, NT_STATUS_OK);
357         CHECK_VALUE(io.writex.out.nwritten, 4000);
358         CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
359
360         memset(buf, 0, maxsize);
361         if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
362                 ret = false;
363                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
364         }
365         CHECK_BUFFER(buf, seed, 4000);
366
367         for (i=33;i<max_bits;i++) {
368                 torture_comment(tctx, "Trying 2^%d offset\n", i);
369                 setup_buffer(buf, seed+1, maxsize);
370                 io.writex.in.file.fnum = fnum;
371                 io.writex.in.count = 4000;
372                 io.writex.in.offset = ((uint64_t)1) << i;
373                 io.writex.in.data = buf;
374                 status = smb_raw_write(cli->tree, &io);
375                 if (i>33 &&
376                     NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
377                         break;
378                 }
379                 CHECK_STATUS(status, NT_STATUS_OK);
380                 CHECK_VALUE(io.writex.out.nwritten, 4000);
381                 CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
382
383                 memset(buf, 0, maxsize);
384                 if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
385                         ret = false;
386                         torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
387                 }
388                 CHECK_BUFFER(buf, seed+1, 4000);
389         }
390         torture_comment(tctx, "limit is 2^%d\n", i);
391
392         setup_buffer(buf, seed, maxsize);
393
394 done:
395         smbcli_close(cli->tree, fnum);
396         smb_raw_exit(cli->session);
397         smbcli_deltree(cli->tree, BASEDIR);
398         return ret;
399 }
400
401
402 /*
403   test write unlock ops
404 */
405 static bool test_writeunlock(struct torture_context *tctx,
406                              struct smbcli_state *cli)
407 {
408         union smb_write io;
409         NTSTATUS status;
410         bool ret = true;
411         int fnum;
412         uint8_t *buf;
413         const int maxsize = 90000;
414         const char *fname = BASEDIR "\\test.txt";
415         unsigned int seed = time(NULL);
416         union smb_fileinfo finfo;
417
418         buf = talloc_zero_array(tctx, uint8_t, maxsize);
419
420         if (!cli->transport->negotiate.lockread_supported) {
421                 torture_skip(tctx, "Server does not support writeunlock - skipping\n");
422         }
423
424         if (!torture_setup_dir(cli, BASEDIR)) {
425                 torture_fail(tctx, "failed to setup basedir");
426         }
427
428         torture_comment(tctx, "Testing RAW_WRITE_WRITEUNLOCK\n");
429         io.generic.level = RAW_WRITE_WRITEUNLOCK;
430
431         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
432         if (fnum == -1) {
433                 ret = false;
434                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)));
435         }
436
437         torture_comment(tctx, "Trying zero write\n");
438         io.writeunlock.in.file.fnum = fnum;
439         io.writeunlock.in.count = 0;
440         io.writeunlock.in.offset = 0;
441         io.writeunlock.in.remaining = 0;
442         io.writeunlock.in.data = buf;
443         status = smb_raw_write(cli->tree, &io);
444         CHECK_STATUS(status, NT_STATUS_OK);
445         CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
446
447         setup_buffer(buf, seed, maxsize);
448
449         torture_comment(tctx, "Trying small write\n");
450         io.writeunlock.in.count = 9;
451         io.writeunlock.in.offset = 4;
452         io.writeunlock.in.data = buf;
453         status = smb_raw_write(cli->tree, &io);
454         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
455         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
456                 ret = false;
457                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
458         }
459         CHECK_BUFFER(buf+4, seed, 9);
460         CHECK_VALUE(IVAL(buf,0), 0);
461
462         setup_buffer(buf, seed, maxsize);
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, io.writeunlock.in.count);
468
469         memset(buf, 0, maxsize);
470         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
471                 ret = false;
472                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
473         }
474         CHECK_BUFFER(buf+4, seed, 9);
475         CHECK_VALUE(IVAL(buf,0), 0);
476
477         setup_buffer(buf, seed, maxsize);
478
479         torture_comment(tctx, "Trying large write\n");
480         io.writeunlock.in.count = 4000;
481         io.writeunlock.in.offset = 0;
482         io.writeunlock.in.data = buf;
483         smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
484                  0, WRITE_LOCK);
485         status = smb_raw_write(cli->tree, &io);
486         CHECK_STATUS(status, NT_STATUS_OK);
487         CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
488
489         status = smb_raw_write(cli->tree, &io);
490         CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
491
492         memset(buf, 0, maxsize);
493         if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
494                 ret = false;
495                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
496         }
497         CHECK_BUFFER(buf, seed, 4000);
498
499         torture_comment(tctx, "Trying bad fnum\n");
500         io.writeunlock.in.file.fnum = fnum+1;
501         io.writeunlock.in.count = 4000;
502         io.writeunlock.in.offset = 0;
503         io.writeunlock.in.data = buf;
504         status = smb_raw_write(cli->tree, &io);
505         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
506
507         torture_comment(tctx, "Setting file as sparse\n");
508         status = torture_set_sparse(cli->tree, fnum);
509         CHECK_STATUS(status, NT_STATUS_OK);
510
511         if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
512                 torture_skip(tctx, "skipping large file tests - CAP_LARGE_FILES not set\n");
513         }
514
515         torture_comment(tctx, "Trying 2^32 offset\n");
516         setup_buffer(buf, seed, maxsize);
517         io.writeunlock.in.file.fnum = fnum;
518         io.writeunlock.in.count = 4000;
519         io.writeunlock.in.offset = 0xFFFFFFFF - 2000;
520         io.writeunlock.in.data = buf;
521         smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
522                  0, WRITE_LOCK);
523         status = smb_raw_write(cli->tree, &io);
524         CHECK_STATUS(status, NT_STATUS_OK);
525         CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
526         CHECK_ALL_INFO(io.writeunlock.in.count + (uint64_t)io.writeunlock.in.offset, size);
527
528         memset(buf, 0, maxsize);
529         if (smbcli_read(cli->tree, fnum, buf, io.writeunlock.in.offset, 4000) != 4000) {
530                 ret = false;
531                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
532         }
533         CHECK_BUFFER(buf, seed, 4000);
534
535 done:
536         smbcli_close(cli->tree, fnum);
537         smb_raw_exit(cli->session);
538         smbcli_deltree(cli->tree, BASEDIR);
539         return ret;
540 }
541
542
543 /*
544   test write close ops
545 */
546 static bool test_writeclose(struct torture_context *tctx,
547                             struct smbcli_state *cli)
548 {
549         union smb_write io;
550         NTSTATUS status;
551         bool ret = true;
552         int fnum;
553         uint8_t *buf;
554         const int maxsize = 90000;
555         const char *fname = BASEDIR "\\test.txt";
556         unsigned int seed = time(NULL);
557         union smb_fileinfo finfo;
558
559         buf = talloc_zero_array(tctx, uint8_t, maxsize);
560
561         if (!torture_setting_bool(tctx, "writeclose_support", true)) {
562                 torture_skip(tctx, "Server does not support writeclose - skipping\n");
563         }
564
565         if (!torture_setup_dir(cli, BASEDIR)) {
566                 torture_fail(tctx, "failed to setup basedir");
567         }
568
569         torture_comment(tctx, "Testing RAW_WRITE_WRITECLOSE\n");
570         io.generic.level = RAW_WRITE_WRITECLOSE;
571
572         fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
573         if (fnum == -1) {
574                 ret = false;
575                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)));
576         }
577
578         torture_comment(tctx, "Trying zero write\n");
579         io.writeclose.in.file.fnum = fnum;
580         io.writeclose.in.count = 0;
581         io.writeclose.in.offset = 0;
582         io.writeclose.in.mtime = 0;
583         io.writeclose.in.data = buf;
584         status = smb_raw_write(cli->tree, &io);
585         CHECK_STATUS(status, NT_STATUS_OK);
586         CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
587
588         status = smb_raw_write(cli->tree, &io);
589         CHECK_STATUS(status, NT_STATUS_OK);
590         CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
591
592         setup_buffer(buf, seed, maxsize);
593
594         torture_comment(tctx, "Trying small write\n");
595         io.writeclose.in.count = 9;
596         io.writeclose.in.offset = 4;
597         io.writeclose.in.data = buf;
598         status = smb_raw_write(cli->tree, &io);
599         CHECK_STATUS(status, NT_STATUS_OK);
600
601         status = smb_raw_write(cli->tree, &io);
602         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
603
604         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
605         io.writeclose.in.file.fnum = fnum;
606
607         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
608                 ret = false;
609                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
610         }
611         CHECK_BUFFER(buf+4, seed, 9);
612         CHECK_VALUE(IVAL(buf,0), 0);
613
614         setup_buffer(buf, seed, maxsize);
615         status = smb_raw_write(cli->tree, &io);
616         CHECK_STATUS(status, NT_STATUS_OK);
617         CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
618
619         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
620         io.writeclose.in.file.fnum = fnum;
621
622         memset(buf, 0, maxsize);
623         if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
624                 ret = false;
625                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
626         }
627         CHECK_BUFFER(buf+4, seed, 9);
628         CHECK_VALUE(IVAL(buf,0), 0);
629
630         setup_buffer(buf, seed, maxsize);
631
632         torture_comment(tctx, "Trying large write\n");
633         io.writeclose.in.count = 4000;
634         io.writeclose.in.offset = 0;
635         io.writeclose.in.data = buf;
636         status = smb_raw_write(cli->tree, &io);
637         CHECK_STATUS(status, NT_STATUS_OK);
638         CHECK_VALUE(io.writeclose.out.nwritten, 4000);
639
640         status = smb_raw_write(cli->tree, &io);
641         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
642
643         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
644         io.writeclose.in.file.fnum = fnum;
645
646         memset(buf, 0, maxsize);
647         if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
648                 ret = false;
649                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
650         }
651         CHECK_BUFFER(buf, seed, 4000);
652
653         torture_comment(tctx, "Trying bad fnum\n");
654         io.writeclose.in.file.fnum = fnum+1;
655         io.writeclose.in.count = 4000;
656         io.writeclose.in.offset = 0;
657         io.writeclose.in.data = buf;
658         status = smb_raw_write(cli->tree, &io);
659         CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
660
661         torture_comment(tctx, "Setting file as sparse\n");
662         status = torture_set_sparse(cli->tree, fnum);
663         CHECK_STATUS(status, NT_STATUS_OK);
664
665         if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
666                 torture_skip(tctx, "skipping large file tests - CAP_LARGE_FILES not set\n");
667         }
668
669         torture_comment(tctx, "Trying 2^32 offset\n");
670         setup_buffer(buf, seed, maxsize);
671         io.writeclose.in.file.fnum = fnum;
672         io.writeclose.in.count = 4000;
673         io.writeclose.in.offset = 0xFFFFFFFF - 2000;
674         io.writeclose.in.data = buf;
675         status = smb_raw_write(cli->tree, &io);
676         CHECK_STATUS(status, NT_STATUS_OK);
677         CHECK_VALUE(io.writeclose.out.nwritten, 4000);
678         CHECK_ALL_INFO(io.writeclose.in.count + (uint64_t)io.writeclose.in.offset, size);
679
680         fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
681         io.writeclose.in.file.fnum = fnum;
682
683         memset(buf, 0, maxsize);
684         if (smbcli_read(cli->tree, fnum, buf, io.writeclose.in.offset, 4000) != 4000) {
685                 ret = false;
686                 torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
687         }
688         CHECK_BUFFER(buf, seed, 4000);
689
690 done:
691         smbcli_close(cli->tree, fnum);
692         smb_raw_exit(cli->session);
693         smbcli_deltree(cli->tree, BASEDIR);
694         return ret;
695 }
696
697 /*
698    basic testing of write calls
699 */
700 struct torture_suite *torture_raw_write(TALLOC_CTX *mem_ctx)
701 {
702         struct torture_suite *suite = torture_suite_create(mem_ctx, "write");
703
704         torture_suite_add_1smb_test(suite, "write", test_write);
705         torture_suite_add_1smb_test(suite, "write unlock", test_writeunlock);
706         torture_suite_add_1smb_test(suite, "write close", test_writeclose);
707         torture_suite_add_1smb_test(suite, "writex", test_writex);
708
709         return suite;
710 }