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"
27 #include "libcli/libcli.h"
29 #define CHECK_STATUS(status, correct) do { \
30 if (!NT_STATUS_EQUAL(status, correct)) { \
31 printf("(%s) Incorrect status %s - should be %s\n", \
32 __location__, nt_errstr(status), nt_errstr(correct)); \
37 #define CHECK_VALUE(v, correct) do { \
38 if ((v) != (correct)) { \
39 printf("(%s) Incorrect value %s=%d - should be %d\n", \
40 __location__, #v, v, correct); \
45 #define CHECK_BUFFER(buf, seed, len) do { \
46 if (!check_buffer(buf, seed, len, __location__)) { \
51 #define CHECK_ALL_INFO(v, field) do { \
52 finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
53 finfo.all_info.in.fname = fname; \
54 status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
55 CHECK_STATUS(status, NT_STATUS_OK); \
56 if ((v) != finfo.all_info.out.field) { \
57 printf("(%s) wrong value for field %s %.0f - %.0f\n", \
58 __location__, #field, (double)v, (double)finfo.all_info.out.field); \
59 dump_all_info(mem_ctx, &finfo); \
64 #define BASEDIR "\\testwrite"
68 setup a random buffer based on a seed
70 static void setup_buffer(uint8_t *buf, uint_t seed, int len)
74 for (i=0;i<len;i++) buf[i] = random();
78 check a random buffer based on a seed
80 static BOOL check_buffer(uint8_t *buf, uint_t seed, int len, const char *location)
87 printf("Buffer incorrect at %s! ofs=%d buf=0x%x correct=0x%x\n",
88 location, i, buf[i], v);
98 static BOOL test_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
105 const int maxsize = 90000;
106 const char *fname = BASEDIR "\\test.txt";
107 uint_t seed = time(NULL);
108 union smb_fileinfo finfo;
110 buf = talloc_zero_size(mem_ctx, maxsize);
112 if (!torture_setup_dir(cli, BASEDIR)) {
116 printf("Testing RAW_WRITE_WRITE\n");
117 io.generic.level = RAW_WRITE_WRITE;
119 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
121 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
126 printf("Trying zero write\n");
127 io.write.in.fnum = fnum;
128 io.write.in.count = 0;
129 io.write.in.offset = 0;
130 io.write.in.remaining = 0;
131 io.write.in.data = buf;
132 status = smb_raw_write(cli->tree, &io);
133 CHECK_STATUS(status, NT_STATUS_OK);
134 CHECK_VALUE(io.write.out.nwritten, 0);
136 setup_buffer(buf, seed, maxsize);
138 printf("Trying small write\n");
139 io.write.in.count = 9;
140 io.write.in.offset = 4;
141 io.write.in.data = buf;
142 status = smb_raw_write(cli->tree, &io);
143 CHECK_STATUS(status, NT_STATUS_OK);
144 CHECK_VALUE(io.write.out.nwritten, io.write.in.count);
146 memset(buf, 0, maxsize);
147 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
148 printf("read failed at %s\n", __location__);
152 CHECK_BUFFER(buf+4, seed, 9);
153 CHECK_VALUE(IVAL(buf,0), 0);
155 setup_buffer(buf, seed, maxsize);
157 printf("Trying large write\n");
158 io.write.in.count = 4000;
159 io.write.in.offset = 0;
160 io.write.in.data = buf;
161 status = smb_raw_write(cli->tree, &io);
162 CHECK_STATUS(status, NT_STATUS_OK);
163 CHECK_VALUE(io.write.out.nwritten, 4000);
165 memset(buf, 0, maxsize);
166 if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
167 printf("read failed at %s\n", __location__);
171 CHECK_BUFFER(buf, seed, 4000);
173 printf("Trying bad fnum\n");
174 io.write.in.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);
181 printf("Setting file as sparse\n");
182 status = torture_set_sparse(cli->tree, fnum);
183 CHECK_STATUS(status, NT_STATUS_OK);
185 printf("Trying 2^32 offset\n");
186 setup_buffer(buf, seed, maxsize);
187 io.write.in.fnum = fnum;
188 io.write.in.count = 4000;
189 io.write.in.offset = 0xFFFFFFFF - 2000;
190 io.write.in.data = buf;
191 status = smb_raw_write(cli->tree, &io);
192 CHECK_STATUS(status, NT_STATUS_OK);
193 CHECK_VALUE(io.write.out.nwritten, 4000);
194 CHECK_ALL_INFO(io.write.in.count + (uint64_t)io.write.in.offset, size);
196 memset(buf, 0, maxsize);
197 if (smbcli_read(cli->tree, fnum, buf, io.write.in.offset, 4000) != 4000) {
198 printf("read failed at %s\n", __location__);
202 CHECK_BUFFER(buf, seed, 4000);
205 smbcli_close(cli->tree, fnum);
206 smb_raw_exit(cli->session);
207 smbcli_deltree(cli->tree, BASEDIR);
215 static BOOL test_writex(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
222 const int maxsize = 90000;
223 const char *fname = BASEDIR "\\test.txt";
224 uint_t seed = time(NULL);
225 union smb_fileinfo finfo;
227 buf = talloc_zero_size(mem_ctx, maxsize);
229 if (!torture_setup_dir(cli, BASEDIR)) {
233 printf("Testing RAW_WRITE_WRITEX\n");
234 io.generic.level = RAW_WRITE_WRITEX;
236 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
238 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
243 printf("Trying zero write\n");
244 io.writex.in.fnum = fnum;
245 io.writex.in.offset = 0;
246 io.writex.in.wmode = 0;
247 io.writex.in.remaining = 0;
248 io.writex.in.count = 0;
249 io.writex.in.data = buf;
250 status = smb_raw_write(cli->tree, &io);
251 CHECK_STATUS(status, NT_STATUS_OK);
252 CHECK_VALUE(io.writex.out.nwritten, 0);
254 setup_buffer(buf, seed, maxsize);
256 printf("Trying small write\n");
257 io.writex.in.count = 9;
258 io.writex.in.offset = 4;
259 io.writex.in.data = buf;
260 status = smb_raw_write(cli->tree, &io);
261 CHECK_STATUS(status, NT_STATUS_OK);
262 CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
264 memset(buf, 0, maxsize);
265 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
266 printf("read failed at %s\n", __location__);
270 CHECK_BUFFER(buf+4, seed, 9);
271 CHECK_VALUE(IVAL(buf,0), 0);
273 setup_buffer(buf, seed, maxsize);
275 printf("Trying large write\n");
276 io.writex.in.count = 4000;
277 io.writex.in.offset = 0;
278 io.writex.in.data = buf;
279 status = smb_raw_write(cli->tree, &io);
280 CHECK_STATUS(status, NT_STATUS_OK);
281 CHECK_VALUE(io.writex.out.nwritten, 4000);
283 memset(buf, 0, maxsize);
284 if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
285 printf("read failed at %s\n", __location__);
289 CHECK_BUFFER(buf, seed, 4000);
291 printf("Trying bad fnum\n");
292 io.writex.in.fnum = fnum+1;
293 io.writex.in.count = 4000;
294 io.writex.in.offset = 0;
295 io.writex.in.data = buf;
296 status = smb_raw_write(cli->tree, &io);
297 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
299 printf("Testing wmode\n");
300 io.writex.in.fnum = fnum;
301 io.writex.in.count = 1;
302 io.writex.in.offset = 0;
303 io.writex.in.wmode = 1;
304 io.writex.in.data = buf;
305 status = smb_raw_write(cli->tree, &io);
306 CHECK_STATUS(status, NT_STATUS_OK);
307 CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
309 io.writex.in.wmode = 2;
310 status = smb_raw_write(cli->tree, &io);
311 CHECK_STATUS(status, NT_STATUS_OK);
312 CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
315 printf("Trying locked region\n");
317 if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 3, 1, 0, WRITE_LOCK))) {
318 printf("Failed to lock file at %s\n", __location__);
323 io.writex.in.wmode = 0;
324 io.writex.in.count = 4;
325 io.writex.in.offset = 0;
326 status = smb_raw_write(cli->tree, &io);
327 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
329 printf("Setting file as sparse\n");
330 status = torture_set_sparse(cli->tree, fnum);
331 CHECK_STATUS(status, NT_STATUS_OK);
333 printf("Trying 2^32 offset\n");
334 setup_buffer(buf, seed, maxsize);
335 io.writex.in.fnum = fnum;
336 io.writex.in.count = 4000;
337 io.writex.in.offset = 0xFFFFFFFF - 2000;
338 io.writex.in.data = buf;
339 status = smb_raw_write(cli->tree, &io);
340 CHECK_STATUS(status, NT_STATUS_OK);
341 CHECK_VALUE(io.writex.out.nwritten, 4000);
342 CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
344 memset(buf, 0, maxsize);
345 if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
346 printf("read failed at %s\n", __location__);
350 CHECK_BUFFER(buf, seed, 4000);
352 for (i=33;i<64;i++) {
353 printf("Trying 2^%d offset\n", i);
354 setup_buffer(buf, seed+1, maxsize);
355 io.writex.in.fnum = fnum;
356 io.writex.in.count = 4000;
357 io.writex.in.offset = ((uint64_t)1) << i;
358 io.writex.in.data = buf;
359 status = smb_raw_write(cli->tree, &io);
361 NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
364 CHECK_STATUS(status, NT_STATUS_OK);
365 CHECK_VALUE(io.writex.out.nwritten, 4000);
366 CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
368 memset(buf, 0, maxsize);
369 if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
370 printf("read failed at %s\n", __location__);
374 CHECK_BUFFER(buf, seed+1, 4000);
376 printf("limit is 2^%d\n", i);
378 setup_buffer(buf, seed, maxsize);
381 smbcli_close(cli->tree, fnum);
382 smb_raw_exit(cli->session);
383 smbcli_deltree(cli->tree, BASEDIR);
389 test write unlock ops
391 static BOOL test_writeunlock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
398 const int maxsize = 90000;
399 const char *fname = BASEDIR "\\test.txt";
400 uint_t seed = time(NULL);
401 union smb_fileinfo finfo;
403 buf = talloc_zero_size(mem_ctx, maxsize);
405 if (!torture_setup_dir(cli, BASEDIR)) {
409 printf("Testing RAW_WRITE_WRITEUNLOCK\n");
410 io.generic.level = RAW_WRITE_WRITEUNLOCK;
412 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
414 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
419 printf("Trying zero write\n");
420 io.writeunlock.in.fnum = fnum;
421 io.writeunlock.in.count = 0;
422 io.writeunlock.in.offset = 0;
423 io.writeunlock.in.remaining = 0;
424 io.writeunlock.in.data = buf;
425 status = smb_raw_write(cli->tree, &io);
426 CHECK_STATUS(status, NT_STATUS_OK);
427 CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
429 setup_buffer(buf, seed, maxsize);
431 printf("Trying small write\n");
432 io.writeunlock.in.count = 9;
433 io.writeunlock.in.offset = 4;
434 io.writeunlock.in.data = buf;
435 status = smb_raw_write(cli->tree, &io);
436 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
437 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
438 printf("read failed at %s\n", __location__);
442 CHECK_BUFFER(buf+4, seed, 9);
443 CHECK_VALUE(IVAL(buf,0), 0);
445 setup_buffer(buf, seed, maxsize);
446 smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
448 status = smb_raw_write(cli->tree, &io);
449 CHECK_STATUS(status, NT_STATUS_OK);
450 CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
452 memset(buf, 0, maxsize);
453 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
454 printf("read failed at %s\n", __location__);
458 CHECK_BUFFER(buf+4, seed, 9);
459 CHECK_VALUE(IVAL(buf,0), 0);
461 setup_buffer(buf, seed, maxsize);
463 printf("Trying large write\n");
464 io.writeunlock.in.count = 4000;
465 io.writeunlock.in.offset = 0;
466 io.writeunlock.in.data = buf;
467 smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
469 status = smb_raw_write(cli->tree, &io);
470 CHECK_STATUS(status, NT_STATUS_OK);
471 CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
473 status = smb_raw_write(cli->tree, &io);
474 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
476 memset(buf, 0, maxsize);
477 if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
478 printf("read failed at %s\n", __location__);
482 CHECK_BUFFER(buf, seed, 4000);
484 printf("Trying bad fnum\n");
485 io.writeunlock.in.fnum = fnum+1;
486 io.writeunlock.in.count = 4000;
487 io.writeunlock.in.offset = 0;
488 io.writeunlock.in.data = buf;
489 status = smb_raw_write(cli->tree, &io);
490 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
492 printf("Setting file as sparse\n");
493 status = torture_set_sparse(cli->tree, fnum);
494 CHECK_STATUS(status, NT_STATUS_OK);
496 printf("Trying 2^32 offset\n");
497 setup_buffer(buf, seed, maxsize);
498 io.writeunlock.in.fnum = fnum;
499 io.writeunlock.in.count = 4000;
500 io.writeunlock.in.offset = 0xFFFFFFFF - 2000;
501 io.writeunlock.in.data = buf;
502 smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
504 status = smb_raw_write(cli->tree, &io);
505 CHECK_STATUS(status, NT_STATUS_OK);
506 CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
507 CHECK_ALL_INFO(io.writeunlock.in.count + (uint64_t)io.writeunlock.in.offset, size);
509 memset(buf, 0, maxsize);
510 if (smbcli_read(cli->tree, fnum, buf, io.writeunlock.in.offset, 4000) != 4000) {
511 printf("read failed at %s\n", __location__);
515 CHECK_BUFFER(buf, seed, 4000);
518 smbcli_close(cli->tree, fnum);
519 smb_raw_exit(cli->session);
520 smbcli_deltree(cli->tree, BASEDIR);
528 static BOOL test_writeclose(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
535 const int maxsize = 90000;
536 const char *fname = BASEDIR "\\test.txt";
537 uint_t seed = time(NULL);
538 union smb_fileinfo finfo;
540 buf = talloc_zero_size(mem_ctx, maxsize);
542 if (!torture_setup_dir(cli, BASEDIR)) {
546 printf("Testing RAW_WRITE_WRITECLOSE\n");
547 io.generic.level = RAW_WRITE_WRITECLOSE;
549 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
551 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
556 printf("Trying zero write\n");
557 io.writeclose.in.fnum = fnum;
558 io.writeclose.in.count = 0;
559 io.writeclose.in.offset = 0;
560 io.writeclose.in.mtime = 0;
561 io.writeclose.in.data = buf;
562 status = smb_raw_write(cli->tree, &io);
563 CHECK_STATUS(status, NT_STATUS_OK);
564 CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
566 status = smb_raw_write(cli->tree, &io);
567 CHECK_STATUS(status, NT_STATUS_OK);
568 CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
570 setup_buffer(buf, seed, maxsize);
572 printf("Trying small write\n");
573 io.writeclose.in.count = 9;
574 io.writeclose.in.offset = 4;
575 io.writeclose.in.data = buf;
576 status = smb_raw_write(cli->tree, &io);
577 CHECK_STATUS(status, NT_STATUS_OK);
579 status = smb_raw_write(cli->tree, &io);
580 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
582 fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
583 io.writeclose.in.fnum = fnum;
585 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
586 printf("read failed at %s\n", __location__);
590 CHECK_BUFFER(buf+4, seed, 9);
591 CHECK_VALUE(IVAL(buf,0), 0);
593 setup_buffer(buf, seed, maxsize);
594 status = smb_raw_write(cli->tree, &io);
595 CHECK_STATUS(status, NT_STATUS_OK);
596 CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
598 fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
599 io.writeclose.in.fnum = fnum;
601 memset(buf, 0, maxsize);
602 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
603 printf("read failed at %s\n", __location__);
607 CHECK_BUFFER(buf+4, seed, 9);
608 CHECK_VALUE(IVAL(buf,0), 0);
610 setup_buffer(buf, seed, maxsize);
612 printf("Trying large write\n");
613 io.writeclose.in.count = 4000;
614 io.writeclose.in.offset = 0;
615 io.writeclose.in.data = buf;
616 status = smb_raw_write(cli->tree, &io);
617 CHECK_STATUS(status, NT_STATUS_OK);
618 CHECK_VALUE(io.writeclose.out.nwritten, 4000);
620 status = smb_raw_write(cli->tree, &io);
621 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
623 fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
624 io.writeclose.in.fnum = fnum;
626 memset(buf, 0, maxsize);
627 if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
628 printf("read failed at %s\n", __location__);
632 CHECK_BUFFER(buf, seed, 4000);
634 printf("Trying bad fnum\n");
635 io.writeclose.in.fnum = fnum+1;
636 io.writeclose.in.count = 4000;
637 io.writeclose.in.offset = 0;
638 io.writeclose.in.data = buf;
639 status = smb_raw_write(cli->tree, &io);
640 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
642 printf("Setting file as sparse\n");
643 status = torture_set_sparse(cli->tree, fnum);
644 CHECK_STATUS(status, NT_STATUS_OK);
646 printf("Trying 2^32 offset\n");
647 setup_buffer(buf, seed, maxsize);
648 io.writeclose.in.fnum = fnum;
649 io.writeclose.in.count = 4000;
650 io.writeclose.in.offset = 0xFFFFFFFF - 2000;
651 io.writeclose.in.data = buf;
652 status = smb_raw_write(cli->tree, &io);
653 CHECK_STATUS(status, NT_STATUS_OK);
654 CHECK_VALUE(io.writeclose.out.nwritten, 4000);
655 CHECK_ALL_INFO(io.writeclose.in.count + (uint64_t)io.writeclose.in.offset, size);
657 fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
658 io.writeclose.in.fnum = fnum;
660 memset(buf, 0, maxsize);
661 if (smbcli_read(cli->tree, fnum, buf, io.writeclose.in.offset, 4000) != 4000) {
662 printf("read failed at %s\n", __location__);
666 CHECK_BUFFER(buf, seed, 4000);
669 smbcli_close(cli->tree, fnum);
670 smb_raw_exit(cli->session);
671 smbcli_deltree(cli->tree, BASEDIR);
676 basic testing of write calls
678 BOOL torture_raw_write(void)
680 struct smbcli_state *cli;
684 if (!torture_open_connection(&cli)) {
688 mem_ctx = talloc_init("torture_raw_write");
690 ret &= test_write(cli, mem_ctx);
691 ret &= test_writeunlock(cli, mem_ctx);
692 ret &= test_writeclose(cli, mem_ctx);
693 ret &= test_writex(cli, mem_ctx);
695 torture_close_connection(cli);
696 talloc_free(mem_ctx);