2 Unix SMB/CIFS implementation.
3 test suite for various write operations
5 Copyright (C) Andrew Tridgell 2003
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 2 of the License, or
10 (at your option) any later version.
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.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "torture/torture.h"
24 #include "libcli/raw/libcliraw.h"
25 #include "system/time.h"
26 #include "system/filesys.h"
28 #define CHECK_STATUS(status, correct) do { \
29 if (!NT_STATUS_EQUAL(status, correct)) { \
30 printf("(%s) Incorrect status %s - should be %s\n", \
31 __location__, nt_errstr(status), nt_errstr(correct)); \
36 #define CHECK_VALUE(v, correct) do { \
37 if ((v) != (correct)) { \
38 printf("(%s) Incorrect value %s=%d - should be %d\n", \
39 __location__, #v, v, correct); \
44 #define CHECK_BUFFER(buf, seed, len) do { \
45 if (!check_buffer(buf, seed, len, __location__)) { \
50 #define CHECK_ALL_INFO(v, field) do { \
51 finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
52 finfo.all_info.in.fname = fname; \
53 status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
54 CHECK_STATUS(status, NT_STATUS_OK); \
55 if ((v) != finfo.all_info.out.field) { \
56 printf("(%s) wrong value for field %s %.0f - %.0f\n", \
57 __location__, #field, (double)v, (double)finfo.all_info.out.field); \
58 dump_all_info(mem_ctx, &finfo); \
63 #define BASEDIR "\\testwrite"
67 setup a random buffer based on a seed
69 static void setup_buffer(uint8_t *buf, uint_t seed, int len)
73 for (i=0;i<len;i++) buf[i] = random();
77 check a random buffer based on a seed
79 static BOOL check_buffer(uint8_t *buf, uint_t seed, int len, const char *location)
86 printf("Buffer incorrect at %s! ofs=%d buf=0x%x correct=0x%x\n",
87 location, i, buf[i], v);
97 static BOOL test_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
104 const int maxsize = 90000;
105 const char *fname = BASEDIR "\\test.txt";
106 uint_t seed = time(NULL);
107 union smb_fileinfo finfo;
109 buf = talloc_zero_size(mem_ctx, maxsize);
111 if (!torture_setup_dir(cli, BASEDIR)) {
115 printf("Testing RAW_WRITE_WRITE\n");
116 io.generic.level = RAW_WRITE_WRITE;
118 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
120 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
125 printf("Trying zero write\n");
126 io.write.in.fnum = fnum;
127 io.write.in.count = 0;
128 io.write.in.offset = 0;
129 io.write.in.remaining = 0;
130 io.write.in.data = buf;
131 status = smb_raw_write(cli->tree, &io);
132 CHECK_STATUS(status, NT_STATUS_OK);
133 CHECK_VALUE(io.write.out.nwritten, 0);
135 setup_buffer(buf, seed, maxsize);
137 printf("Trying small write\n");
138 io.write.in.count = 9;
139 io.write.in.offset = 4;
140 io.write.in.data = buf;
141 status = smb_raw_write(cli->tree, &io);
142 CHECK_STATUS(status, NT_STATUS_OK);
143 CHECK_VALUE(io.write.out.nwritten, io.write.in.count);
145 memset(buf, 0, maxsize);
146 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
147 printf("read failed at %s\n", __location__);
151 CHECK_BUFFER(buf+4, seed, 9);
152 CHECK_VALUE(IVAL(buf,0), 0);
154 setup_buffer(buf, seed, maxsize);
156 printf("Trying large write\n");
157 io.write.in.count = 4000;
158 io.write.in.offset = 0;
159 io.write.in.data = buf;
160 status = smb_raw_write(cli->tree, &io);
161 CHECK_STATUS(status, NT_STATUS_OK);
162 CHECK_VALUE(io.write.out.nwritten, 4000);
164 memset(buf, 0, maxsize);
165 if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
166 printf("read failed at %s\n", __location__);
170 CHECK_BUFFER(buf, seed, 4000);
172 printf("Trying bad fnum\n");
173 io.write.in.fnum = fnum+1;
174 io.write.in.count = 4000;
175 io.write.in.offset = 0;
176 io.write.in.data = buf;
177 status = smb_raw_write(cli->tree, &io);
178 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
180 printf("Setting file as sparse\n");
181 status = torture_set_sparse(cli->tree, fnum);
182 CHECK_STATUS(status, NT_STATUS_OK);
184 printf("Trying 2^32 offset\n");
185 setup_buffer(buf, seed, maxsize);
186 io.write.in.fnum = fnum;
187 io.write.in.count = 4000;
188 io.write.in.offset = 0xFFFFFFFF - 2000;
189 io.write.in.data = buf;
190 status = smb_raw_write(cli->tree, &io);
191 CHECK_STATUS(status, NT_STATUS_OK);
192 CHECK_VALUE(io.write.out.nwritten, 4000);
193 CHECK_ALL_INFO(io.write.in.count + (uint64_t)io.write.in.offset, size);
195 memset(buf, 0, maxsize);
196 if (smbcli_read(cli->tree, fnum, buf, io.write.in.offset, 4000) != 4000) {
197 printf("read failed at %s\n", __location__);
201 CHECK_BUFFER(buf, seed, 4000);
204 smbcli_close(cli->tree, fnum);
205 smb_raw_exit(cli->session);
206 smbcli_deltree(cli->tree, BASEDIR);
214 static BOOL test_writex(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
221 const int maxsize = 90000;
222 const char *fname = BASEDIR "\\test.txt";
223 uint_t seed = time(NULL);
224 union smb_fileinfo finfo;
226 buf = talloc_zero_size(mem_ctx, maxsize);
228 if (!torture_setup_dir(cli, BASEDIR)) {
232 printf("Testing RAW_WRITE_WRITEX\n");
233 io.generic.level = RAW_WRITE_WRITEX;
235 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
237 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
242 printf("Trying zero write\n");
243 io.writex.in.fnum = fnum;
244 io.writex.in.offset = 0;
245 io.writex.in.wmode = 0;
246 io.writex.in.remaining = 0;
247 io.writex.in.count = 0;
248 io.writex.in.data = buf;
249 status = smb_raw_write(cli->tree, &io);
250 CHECK_STATUS(status, NT_STATUS_OK);
251 CHECK_VALUE(io.writex.out.nwritten, 0);
253 setup_buffer(buf, seed, maxsize);
255 printf("Trying small write\n");
256 io.writex.in.count = 9;
257 io.writex.in.offset = 4;
258 io.writex.in.data = buf;
259 status = smb_raw_write(cli->tree, &io);
260 CHECK_STATUS(status, NT_STATUS_OK);
261 CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
263 memset(buf, 0, maxsize);
264 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
265 printf("read failed at %s\n", __location__);
269 CHECK_BUFFER(buf+4, seed, 9);
270 CHECK_VALUE(IVAL(buf,0), 0);
272 setup_buffer(buf, seed, maxsize);
274 printf("Trying large write\n");
275 io.writex.in.count = 4000;
276 io.writex.in.offset = 0;
277 io.writex.in.data = buf;
278 status = smb_raw_write(cli->tree, &io);
279 CHECK_STATUS(status, NT_STATUS_OK);
280 CHECK_VALUE(io.writex.out.nwritten, 4000);
282 memset(buf, 0, maxsize);
283 if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
284 printf("read failed at %s\n", __location__);
288 CHECK_BUFFER(buf, seed, 4000);
290 printf("Trying bad fnum\n");
291 io.writex.in.fnum = fnum+1;
292 io.writex.in.count = 4000;
293 io.writex.in.offset = 0;
294 io.writex.in.data = buf;
295 status = smb_raw_write(cli->tree, &io);
296 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
298 printf("Testing wmode\n");
299 io.writex.in.fnum = fnum;
300 io.writex.in.count = 1;
301 io.writex.in.offset = 0;
302 io.writex.in.wmode = 1;
303 io.writex.in.data = buf;
304 status = smb_raw_write(cli->tree, &io);
305 CHECK_STATUS(status, NT_STATUS_OK);
306 CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
308 io.writex.in.wmode = 2;
309 status = smb_raw_write(cli->tree, &io);
310 CHECK_STATUS(status, NT_STATUS_OK);
311 CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
314 printf("Trying locked region\n");
316 if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 3, 1, 0, WRITE_LOCK))) {
317 printf("Failed to lock file at %s\n", __location__);
322 io.writex.in.wmode = 0;
323 io.writex.in.count = 4;
324 io.writex.in.offset = 0;
325 status = smb_raw_write(cli->tree, &io);
326 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
328 printf("Setting file as sparse\n");
329 status = torture_set_sparse(cli->tree, fnum);
330 CHECK_STATUS(status, NT_STATUS_OK);
332 printf("Trying 2^32 offset\n");
333 setup_buffer(buf, seed, maxsize);
334 io.writex.in.fnum = fnum;
335 io.writex.in.count = 4000;
336 io.writex.in.offset = 0xFFFFFFFF - 2000;
337 io.writex.in.data = buf;
338 status = smb_raw_write(cli->tree, &io);
339 CHECK_STATUS(status, NT_STATUS_OK);
340 CHECK_VALUE(io.writex.out.nwritten, 4000);
341 CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
343 memset(buf, 0, maxsize);
344 if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
345 printf("read failed at %s\n", __location__);
349 CHECK_BUFFER(buf, seed, 4000);
351 for (i=33;i<64;i++) {
352 printf("Trying 2^%d offset\n", i);
353 setup_buffer(buf, seed+1, maxsize);
354 io.writex.in.fnum = fnum;
355 io.writex.in.count = 4000;
356 io.writex.in.offset = ((uint64_t)1) << i;
357 io.writex.in.data = buf;
358 status = smb_raw_write(cli->tree, &io);
360 NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
363 CHECK_STATUS(status, NT_STATUS_OK);
364 CHECK_VALUE(io.writex.out.nwritten, 4000);
365 CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
367 memset(buf, 0, maxsize);
368 if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
369 printf("read failed at %s\n", __location__);
373 CHECK_BUFFER(buf, seed+1, 4000);
375 printf("limit is 2^%d\n", i);
377 setup_buffer(buf, seed, maxsize);
380 smbcli_close(cli->tree, fnum);
381 smb_raw_exit(cli->session);
382 smbcli_deltree(cli->tree, BASEDIR);
388 test write unlock ops
390 static BOOL test_writeunlock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
397 const int maxsize = 90000;
398 const char *fname = BASEDIR "\\test.txt";
399 uint_t seed = time(NULL);
400 union smb_fileinfo finfo;
402 buf = talloc_zero_size(mem_ctx, maxsize);
404 if (!torture_setup_dir(cli, BASEDIR)) {
408 printf("Testing RAW_WRITE_WRITEUNLOCK\n");
409 io.generic.level = RAW_WRITE_WRITEUNLOCK;
411 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
413 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
418 printf("Trying zero write\n");
419 io.writeunlock.in.fnum = fnum;
420 io.writeunlock.in.count = 0;
421 io.writeunlock.in.offset = 0;
422 io.writeunlock.in.remaining = 0;
423 io.writeunlock.in.data = buf;
424 status = smb_raw_write(cli->tree, &io);
425 CHECK_STATUS(status, NT_STATUS_OK);
426 CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
428 setup_buffer(buf, seed, maxsize);
430 printf("Trying small write\n");
431 io.writeunlock.in.count = 9;
432 io.writeunlock.in.offset = 4;
433 io.writeunlock.in.data = buf;
434 status = smb_raw_write(cli->tree, &io);
435 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
436 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
437 printf("read failed at %s\n", __location__);
441 CHECK_BUFFER(buf+4, seed, 9);
442 CHECK_VALUE(IVAL(buf,0), 0);
444 setup_buffer(buf, seed, maxsize);
445 smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
447 status = smb_raw_write(cli->tree, &io);
448 CHECK_STATUS(status, NT_STATUS_OK);
449 CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
451 memset(buf, 0, maxsize);
452 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
453 printf("read failed at %s\n", __location__);
457 CHECK_BUFFER(buf+4, seed, 9);
458 CHECK_VALUE(IVAL(buf,0), 0);
460 setup_buffer(buf, seed, maxsize);
462 printf("Trying large write\n");
463 io.writeunlock.in.count = 4000;
464 io.writeunlock.in.offset = 0;
465 io.writeunlock.in.data = buf;
466 smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
468 status = smb_raw_write(cli->tree, &io);
469 CHECK_STATUS(status, NT_STATUS_OK);
470 CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
472 status = smb_raw_write(cli->tree, &io);
473 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
475 memset(buf, 0, maxsize);
476 if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
477 printf("read failed at %s\n", __location__);
481 CHECK_BUFFER(buf, seed, 4000);
483 printf("Trying bad fnum\n");
484 io.writeunlock.in.fnum = fnum+1;
485 io.writeunlock.in.count = 4000;
486 io.writeunlock.in.offset = 0;
487 io.writeunlock.in.data = buf;
488 status = smb_raw_write(cli->tree, &io);
489 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
491 printf("Setting file as sparse\n");
492 status = torture_set_sparse(cli->tree, fnum);
493 CHECK_STATUS(status, NT_STATUS_OK);
495 printf("Trying 2^32 offset\n");
496 setup_buffer(buf, seed, maxsize);
497 io.writeunlock.in.fnum = fnum;
498 io.writeunlock.in.count = 4000;
499 io.writeunlock.in.offset = 0xFFFFFFFF - 2000;
500 io.writeunlock.in.data = buf;
501 smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
503 status = smb_raw_write(cli->tree, &io);
504 CHECK_STATUS(status, NT_STATUS_OK);
505 CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
506 CHECK_ALL_INFO(io.writeunlock.in.count + (uint64_t)io.writeunlock.in.offset, size);
508 memset(buf, 0, maxsize);
509 if (smbcli_read(cli->tree, fnum, buf, io.writeunlock.in.offset, 4000) != 4000) {
510 printf("read failed at %s\n", __location__);
514 CHECK_BUFFER(buf, seed, 4000);
517 smbcli_close(cli->tree, fnum);
518 smb_raw_exit(cli->session);
519 smbcli_deltree(cli->tree, BASEDIR);
527 static BOOL test_writeclose(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
534 const int maxsize = 90000;
535 const char *fname = BASEDIR "\\test.txt";
536 uint_t seed = time(NULL);
537 union smb_fileinfo finfo;
539 buf = talloc_zero_size(mem_ctx, maxsize);
541 if (!torture_setup_dir(cli, BASEDIR)) {
545 printf("Testing RAW_WRITE_WRITECLOSE\n");
546 io.generic.level = RAW_WRITE_WRITECLOSE;
548 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
550 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
555 printf("Trying zero write\n");
556 io.writeclose.in.fnum = fnum;
557 io.writeclose.in.count = 0;
558 io.writeclose.in.offset = 0;
559 io.writeclose.in.mtime = 0;
560 io.writeclose.in.data = buf;
561 status = smb_raw_write(cli->tree, &io);
562 CHECK_STATUS(status, NT_STATUS_OK);
563 CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
565 status = smb_raw_write(cli->tree, &io);
566 CHECK_STATUS(status, NT_STATUS_OK);
567 CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
569 setup_buffer(buf, seed, maxsize);
571 printf("Trying small write\n");
572 io.writeclose.in.count = 9;
573 io.writeclose.in.offset = 4;
574 io.writeclose.in.data = buf;
575 status = smb_raw_write(cli->tree, &io);
576 CHECK_STATUS(status, NT_STATUS_OK);
578 status = smb_raw_write(cli->tree, &io);
579 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
581 fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
582 io.writeclose.in.fnum = fnum;
584 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
585 printf("read failed at %s\n", __location__);
589 CHECK_BUFFER(buf+4, seed, 9);
590 CHECK_VALUE(IVAL(buf,0), 0);
592 setup_buffer(buf, seed, maxsize);
593 status = smb_raw_write(cli->tree, &io);
594 CHECK_STATUS(status, NT_STATUS_OK);
595 CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
597 fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
598 io.writeclose.in.fnum = fnum;
600 memset(buf, 0, maxsize);
601 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
602 printf("read failed at %s\n", __location__);
606 CHECK_BUFFER(buf+4, seed, 9);
607 CHECK_VALUE(IVAL(buf,0), 0);
609 setup_buffer(buf, seed, maxsize);
611 printf("Trying large write\n");
612 io.writeclose.in.count = 4000;
613 io.writeclose.in.offset = 0;
614 io.writeclose.in.data = buf;
615 status = smb_raw_write(cli->tree, &io);
616 CHECK_STATUS(status, NT_STATUS_OK);
617 CHECK_VALUE(io.writeclose.out.nwritten, 4000);
619 status = smb_raw_write(cli->tree, &io);
620 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
622 fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
623 io.writeclose.in.fnum = fnum;
625 memset(buf, 0, maxsize);
626 if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
627 printf("read failed at %s\n", __location__);
631 CHECK_BUFFER(buf, seed, 4000);
633 printf("Trying bad fnum\n");
634 io.writeclose.in.fnum = fnum+1;
635 io.writeclose.in.count = 4000;
636 io.writeclose.in.offset = 0;
637 io.writeclose.in.data = buf;
638 status = smb_raw_write(cli->tree, &io);
639 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
641 printf("Setting file as sparse\n");
642 status = torture_set_sparse(cli->tree, fnum);
643 CHECK_STATUS(status, NT_STATUS_OK);
645 printf("Trying 2^32 offset\n");
646 setup_buffer(buf, seed, maxsize);
647 io.writeclose.in.fnum = fnum;
648 io.writeclose.in.count = 4000;
649 io.writeclose.in.offset = 0xFFFFFFFF - 2000;
650 io.writeclose.in.data = buf;
651 status = smb_raw_write(cli->tree, &io);
652 CHECK_STATUS(status, NT_STATUS_OK);
653 CHECK_VALUE(io.writeclose.out.nwritten, 4000);
654 CHECK_ALL_INFO(io.writeclose.in.count + (uint64_t)io.writeclose.in.offset, size);
656 fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
657 io.writeclose.in.fnum = fnum;
659 memset(buf, 0, maxsize);
660 if (smbcli_read(cli->tree, fnum, buf, io.writeclose.in.offset, 4000) != 4000) {
661 printf("read failed at %s\n", __location__);
665 CHECK_BUFFER(buf, seed, 4000);
668 smbcli_close(cli->tree, fnum);
669 smb_raw_exit(cli->session);
670 smbcli_deltree(cli->tree, BASEDIR);
675 basic testing of write calls
677 BOOL torture_raw_write(void)
679 struct smbcli_state *cli;
683 if (!torture_open_connection(&cli)) {
687 mem_ctx = talloc_init("torture_raw_write");
689 ret &= test_write(cli, mem_ctx);
690 ret &= test_writeunlock(cli, mem_ctx);
691 ret &= test_writeclose(cli, mem_ctx);
692 ret &= test_writex(cli, mem_ctx);
694 torture_close_connection(cli);
695 talloc_free(mem_ctx);