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"
28 #include "torture/util.h"
30 #define CHECK_STATUS(status, correct) do { \
31 if (!NT_STATUS_EQUAL(status, correct)) { \
32 printf("(%s) Incorrect status %s - should be %s\n", \
33 __location__, nt_errstr(status), nt_errstr(correct)); \
38 #define CHECK_VALUE(v, correct) do { \
39 if ((v) != (correct)) { \
40 printf("(%s) Incorrect value %s=%d - should be %d\n", \
41 __location__, #v, v, correct); \
46 #define CHECK_BUFFER(buf, seed, len) do { \
47 if (!check_buffer(buf, seed, len, __location__)) { \
52 #define CHECK_ALL_INFO(v, field) do { \
53 finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
54 finfo.all_info.in.file.path = fname; \
55 status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
56 CHECK_STATUS(status, NT_STATUS_OK); \
57 if ((v) != finfo.all_info.out.field) { \
58 printf("(%s) wrong value for field %s %.0f - %.0f\n", \
59 __location__, #field, (double)v, (double)finfo.all_info.out.field); \
60 dump_all_info(mem_ctx, &finfo); \
65 #define BASEDIR "\\testwrite"
69 setup a random buffer based on a seed
71 static void setup_buffer(uint8_t *buf, uint_t seed, int len)
75 for (i=0;i<len;i++) buf[i] = random();
79 check a random buffer based on a seed
81 static BOOL check_buffer(uint8_t *buf, uint_t seed, int len, const char *location)
88 printf("Buffer incorrect at %s! ofs=%d buf=0x%x correct=0x%x\n",
89 location, i, buf[i], v);
99 static BOOL test_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
106 const int maxsize = 90000;
107 const char *fname = BASEDIR "\\test.txt";
108 uint_t seed = time(NULL);
109 union smb_fileinfo finfo;
111 buf = talloc_zero_size(mem_ctx, maxsize);
113 if (!torture_setup_dir(cli, BASEDIR)) {
117 printf("Testing RAW_WRITE_WRITE\n");
118 io.generic.level = RAW_WRITE_WRITE;
120 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
122 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
127 printf("Trying zero write\n");
128 io.write.in.file.fnum = fnum;
129 io.write.in.count = 0;
130 io.write.in.offset = 0;
131 io.write.in.remaining = 0;
132 io.write.in.data = buf;
133 status = smb_raw_write(cli->tree, &io);
134 CHECK_STATUS(status, NT_STATUS_OK);
135 CHECK_VALUE(io.write.out.nwritten, 0);
137 setup_buffer(buf, seed, maxsize);
139 printf("Trying small write\n");
140 io.write.in.count = 9;
141 io.write.in.offset = 4;
142 io.write.in.data = buf;
143 status = smb_raw_write(cli->tree, &io);
144 CHECK_STATUS(status, NT_STATUS_OK);
145 CHECK_VALUE(io.write.out.nwritten, io.write.in.count);
147 memset(buf, 0, maxsize);
148 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
149 printf("read failed at %s\n", __location__);
153 CHECK_BUFFER(buf+4, seed, 9);
154 CHECK_VALUE(IVAL(buf,0), 0);
156 setup_buffer(buf, seed, maxsize);
158 printf("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);
166 memset(buf, 0, maxsize);
167 if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
168 printf("read failed at %s\n", __location__);
172 CHECK_BUFFER(buf, seed, 4000);
174 printf("Trying bad fnum\n");
175 io.write.in.file.fnum = fnum+1;
176 io.write.in.count = 4000;
177 io.write.in.offset = 0;
178 io.write.in.data = buf;
179 status = smb_raw_write(cli->tree, &io);
180 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
182 printf("Setting file as sparse\n");
183 status = torture_set_sparse(cli->tree, fnum);
184 CHECK_STATUS(status, NT_STATUS_OK);
186 printf("Trying 2^32 offset\n");
187 setup_buffer(buf, seed, maxsize);
188 io.write.in.file.fnum = fnum;
189 io.write.in.count = 4000;
190 io.write.in.offset = 0xFFFFFFFF - 2000;
191 io.write.in.data = buf;
192 status = smb_raw_write(cli->tree, &io);
193 CHECK_STATUS(status, NT_STATUS_OK);
194 CHECK_VALUE(io.write.out.nwritten, 4000);
195 CHECK_ALL_INFO(io.write.in.count + (uint64_t)io.write.in.offset, size);
197 memset(buf, 0, maxsize);
198 if (smbcli_read(cli->tree, fnum, buf, io.write.in.offset, 4000) != 4000) {
199 printf("read failed at %s\n", __location__);
203 CHECK_BUFFER(buf, seed, 4000);
206 smbcli_close(cli->tree, fnum);
207 smb_raw_exit(cli->session);
208 smbcli_deltree(cli->tree, BASEDIR);
216 static BOOL test_writex(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
223 const int maxsize = 90000;
224 const char *fname = BASEDIR "\\test.txt";
225 uint_t seed = time(NULL);
226 union smb_fileinfo finfo;
228 buf = talloc_zero_size(mem_ctx, maxsize);
230 if (!torture_setup_dir(cli, BASEDIR)) {
234 printf("Testing RAW_WRITE_WRITEX\n");
235 io.generic.level = RAW_WRITE_WRITEX;
237 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
239 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
244 printf("Trying zero write\n");
245 io.writex.in.file.fnum = fnum;
246 io.writex.in.offset = 0;
247 io.writex.in.wmode = 0;
248 io.writex.in.remaining = 0;
249 io.writex.in.count = 0;
250 io.writex.in.data = buf;
251 status = smb_raw_write(cli->tree, &io);
252 CHECK_STATUS(status, NT_STATUS_OK);
253 CHECK_VALUE(io.writex.out.nwritten, 0);
255 setup_buffer(buf, seed, maxsize);
257 printf("Trying small write\n");
258 io.writex.in.count = 9;
259 io.writex.in.offset = 4;
260 io.writex.in.data = buf;
261 status = smb_raw_write(cli->tree, &io);
262 CHECK_STATUS(status, NT_STATUS_OK);
263 CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
265 memset(buf, 0, maxsize);
266 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
267 printf("read failed at %s\n", __location__);
271 CHECK_BUFFER(buf+4, seed, 9);
272 CHECK_VALUE(IVAL(buf,0), 0);
274 setup_buffer(buf, seed, maxsize);
276 printf("Trying large write\n");
277 io.writex.in.count = 4000;
278 io.writex.in.offset = 0;
279 io.writex.in.data = buf;
280 status = smb_raw_write(cli->tree, &io);
281 CHECK_STATUS(status, NT_STATUS_OK);
282 CHECK_VALUE(io.writex.out.nwritten, 4000);
284 memset(buf, 0, maxsize);
285 if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
286 printf("read failed at %s\n", __location__);
290 CHECK_BUFFER(buf, seed, 4000);
292 printf("Trying bad fnum\n");
293 io.writex.in.file.fnum = fnum+1;
294 io.writex.in.count = 4000;
295 io.writex.in.offset = 0;
296 io.writex.in.data = buf;
297 status = smb_raw_write(cli->tree, &io);
298 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
300 printf("Testing wmode\n");
301 io.writex.in.file.fnum = fnum;
302 io.writex.in.count = 1;
303 io.writex.in.offset = 0;
304 io.writex.in.wmode = 1;
305 io.writex.in.data = buf;
306 status = smb_raw_write(cli->tree, &io);
307 CHECK_STATUS(status, NT_STATUS_OK);
308 CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
310 io.writex.in.wmode = 2;
311 status = smb_raw_write(cli->tree, &io);
312 CHECK_STATUS(status, NT_STATUS_OK);
313 CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
316 printf("Trying locked region\n");
318 if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 3, 1, 0, WRITE_LOCK))) {
319 printf("Failed to lock file at %s\n", __location__);
324 io.writex.in.wmode = 0;
325 io.writex.in.count = 4;
326 io.writex.in.offset = 0;
327 status = smb_raw_write(cli->tree, &io);
328 CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
330 printf("Setting file as sparse\n");
331 status = torture_set_sparse(cli->tree, fnum);
332 CHECK_STATUS(status, NT_STATUS_OK);
334 printf("Trying 2^32 offset\n");
335 setup_buffer(buf, seed, maxsize);
336 io.writex.in.file.fnum = fnum;
337 io.writex.in.count = 4000;
338 io.writex.in.offset = 0xFFFFFFFF - 2000;
339 io.writex.in.data = buf;
340 status = smb_raw_write(cli->tree, &io);
341 CHECK_STATUS(status, NT_STATUS_OK);
342 CHECK_VALUE(io.writex.out.nwritten, 4000);
343 CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
345 memset(buf, 0, maxsize);
346 if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
347 printf("read failed at %s\n", __location__);
351 CHECK_BUFFER(buf, seed, 4000);
353 for (i=33;i<64;i++) {
354 printf("Trying 2^%d offset\n", i);
355 setup_buffer(buf, seed+1, maxsize);
356 io.writex.in.file.fnum = fnum;
357 io.writex.in.count = 4000;
358 io.writex.in.offset = ((uint64_t)1) << i;
359 io.writex.in.data = buf;
360 status = smb_raw_write(cli->tree, &io);
362 NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
365 CHECK_STATUS(status, NT_STATUS_OK);
366 CHECK_VALUE(io.writex.out.nwritten, 4000);
367 CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
369 memset(buf, 0, maxsize);
370 if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
371 printf("read failed at %s\n", __location__);
375 CHECK_BUFFER(buf, seed+1, 4000);
377 printf("limit is 2^%d\n", i);
379 setup_buffer(buf, seed, maxsize);
382 smbcli_close(cli->tree, fnum);
383 smb_raw_exit(cli->session);
384 smbcli_deltree(cli->tree, BASEDIR);
390 test write unlock ops
392 static BOOL test_writeunlock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
399 const int maxsize = 90000;
400 const char *fname = BASEDIR "\\test.txt";
401 uint_t seed = time(NULL);
402 union smb_fileinfo finfo;
404 buf = talloc_zero_size(mem_ctx, maxsize);
406 if (!torture_setup_dir(cli, BASEDIR)) {
410 printf("Testing RAW_WRITE_WRITEUNLOCK\n");
411 io.generic.level = RAW_WRITE_WRITEUNLOCK;
413 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
415 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
420 printf("Trying zero write\n");
421 io.writeunlock.in.file.fnum = fnum;
422 io.writeunlock.in.count = 0;
423 io.writeunlock.in.offset = 0;
424 io.writeunlock.in.remaining = 0;
425 io.writeunlock.in.data = buf;
426 status = smb_raw_write(cli->tree, &io);
427 CHECK_STATUS(status, NT_STATUS_OK);
428 CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
430 setup_buffer(buf, seed, maxsize);
432 printf("Trying small write\n");
433 io.writeunlock.in.count = 9;
434 io.writeunlock.in.offset = 4;
435 io.writeunlock.in.data = buf;
436 status = smb_raw_write(cli->tree, &io);
437 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
438 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
439 printf("read failed at %s\n", __location__);
443 CHECK_BUFFER(buf+4, seed, 9);
444 CHECK_VALUE(IVAL(buf,0), 0);
446 setup_buffer(buf, seed, maxsize);
447 smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
449 status = smb_raw_write(cli->tree, &io);
450 CHECK_STATUS(status, NT_STATUS_OK);
451 CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
453 memset(buf, 0, maxsize);
454 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
455 printf("read failed at %s\n", __location__);
459 CHECK_BUFFER(buf+4, seed, 9);
460 CHECK_VALUE(IVAL(buf,0), 0);
462 setup_buffer(buf, seed, maxsize);
464 printf("Trying large write\n");
465 io.writeunlock.in.count = 4000;
466 io.writeunlock.in.offset = 0;
467 io.writeunlock.in.data = buf;
468 smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
470 status = smb_raw_write(cli->tree, &io);
471 CHECK_STATUS(status, NT_STATUS_OK);
472 CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
474 status = smb_raw_write(cli->tree, &io);
475 CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
477 memset(buf, 0, maxsize);
478 if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
479 printf("read failed at %s\n", __location__);
483 CHECK_BUFFER(buf, seed, 4000);
485 printf("Trying bad fnum\n");
486 io.writeunlock.in.file.fnum = fnum+1;
487 io.writeunlock.in.count = 4000;
488 io.writeunlock.in.offset = 0;
489 io.writeunlock.in.data = buf;
490 status = smb_raw_write(cli->tree, &io);
491 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
493 printf("Setting file as sparse\n");
494 status = torture_set_sparse(cli->tree, fnum);
495 CHECK_STATUS(status, NT_STATUS_OK);
497 printf("Trying 2^32 offset\n");
498 setup_buffer(buf, seed, maxsize);
499 io.writeunlock.in.file.fnum = fnum;
500 io.writeunlock.in.count = 4000;
501 io.writeunlock.in.offset = 0xFFFFFFFF - 2000;
502 io.writeunlock.in.data = buf;
503 smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
505 status = smb_raw_write(cli->tree, &io);
506 CHECK_STATUS(status, NT_STATUS_OK);
507 CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
508 CHECK_ALL_INFO(io.writeunlock.in.count + (uint64_t)io.writeunlock.in.offset, size);
510 memset(buf, 0, maxsize);
511 if (smbcli_read(cli->tree, fnum, buf, io.writeunlock.in.offset, 4000) != 4000) {
512 printf("read failed at %s\n", __location__);
516 CHECK_BUFFER(buf, seed, 4000);
519 smbcli_close(cli->tree, fnum);
520 smb_raw_exit(cli->session);
521 smbcli_deltree(cli->tree, BASEDIR);
529 static BOOL test_writeclose(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
536 const int maxsize = 90000;
537 const char *fname = BASEDIR "\\test.txt";
538 uint_t seed = time(NULL);
539 union smb_fileinfo finfo;
541 buf = talloc_zero_size(mem_ctx, maxsize);
543 if (!torture_setup_dir(cli, BASEDIR)) {
547 printf("Testing RAW_WRITE_WRITECLOSE\n");
548 io.generic.level = RAW_WRITE_WRITECLOSE;
550 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
552 printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
557 printf("Trying zero write\n");
558 io.writeclose.in.file.fnum = fnum;
559 io.writeclose.in.count = 0;
560 io.writeclose.in.offset = 0;
561 io.writeclose.in.mtime = 0;
562 io.writeclose.in.data = buf;
563 status = smb_raw_write(cli->tree, &io);
564 CHECK_STATUS(status, NT_STATUS_OK);
565 CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
567 status = smb_raw_write(cli->tree, &io);
568 CHECK_STATUS(status, NT_STATUS_OK);
569 CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
571 setup_buffer(buf, seed, maxsize);
573 printf("Trying small write\n");
574 io.writeclose.in.count = 9;
575 io.writeclose.in.offset = 4;
576 io.writeclose.in.data = buf;
577 status = smb_raw_write(cli->tree, &io);
578 CHECK_STATUS(status, NT_STATUS_OK);
580 status = smb_raw_write(cli->tree, &io);
581 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
583 fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
584 io.writeclose.in.file.fnum = fnum;
586 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
587 printf("read failed at %s\n", __location__);
591 CHECK_BUFFER(buf+4, seed, 9);
592 CHECK_VALUE(IVAL(buf,0), 0);
594 setup_buffer(buf, seed, maxsize);
595 status = smb_raw_write(cli->tree, &io);
596 CHECK_STATUS(status, NT_STATUS_OK);
597 CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
599 fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
600 io.writeclose.in.file.fnum = fnum;
602 memset(buf, 0, maxsize);
603 if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
604 printf("read failed at %s\n", __location__);
608 CHECK_BUFFER(buf+4, seed, 9);
609 CHECK_VALUE(IVAL(buf,0), 0);
611 setup_buffer(buf, seed, maxsize);
613 printf("Trying large write\n");
614 io.writeclose.in.count = 4000;
615 io.writeclose.in.offset = 0;
616 io.writeclose.in.data = buf;
617 status = smb_raw_write(cli->tree, &io);
618 CHECK_STATUS(status, NT_STATUS_OK);
619 CHECK_VALUE(io.writeclose.out.nwritten, 4000);
621 status = smb_raw_write(cli->tree, &io);
622 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
624 fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
625 io.writeclose.in.file.fnum = fnum;
627 memset(buf, 0, maxsize);
628 if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
629 printf("read failed at %s\n", __location__);
633 CHECK_BUFFER(buf, seed, 4000);
635 printf("Trying bad fnum\n");
636 io.writeclose.in.file.fnum = fnum+1;
637 io.writeclose.in.count = 4000;
638 io.writeclose.in.offset = 0;
639 io.writeclose.in.data = buf;
640 status = smb_raw_write(cli->tree, &io);
641 CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
643 printf("Setting file as sparse\n");
644 status = torture_set_sparse(cli->tree, fnum);
645 CHECK_STATUS(status, NT_STATUS_OK);
647 printf("Trying 2^32 offset\n");
648 setup_buffer(buf, seed, maxsize);
649 io.writeclose.in.file.fnum = fnum;
650 io.writeclose.in.count = 4000;
651 io.writeclose.in.offset = 0xFFFFFFFF - 2000;
652 io.writeclose.in.data = buf;
653 status = smb_raw_write(cli->tree, &io);
654 CHECK_STATUS(status, NT_STATUS_OK);
655 CHECK_VALUE(io.writeclose.out.nwritten, 4000);
656 CHECK_ALL_INFO(io.writeclose.in.count + (uint64_t)io.writeclose.in.offset, size);
658 fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
659 io.writeclose.in.file.fnum = fnum;
661 memset(buf, 0, maxsize);
662 if (smbcli_read(cli->tree, fnum, buf, io.writeclose.in.offset, 4000) != 4000) {
663 printf("read failed at %s\n", __location__);
667 CHECK_BUFFER(buf, seed, 4000);
670 smbcli_close(cli->tree, fnum);
671 smb_raw_exit(cli->session);
672 smbcli_deltree(cli->tree, BASEDIR);
677 basic testing of write calls
679 BOOL torture_raw_write(struct torture_context *torture)
681 struct smbcli_state *cli;
685 if (!torture_open_connection(&cli, 0)) {
689 mem_ctx = talloc_init("torture_raw_write");
691 ret &= test_write(cli, mem_ctx);
692 ret &= test_writeunlock(cli, mem_ctx);
693 ret &= test_writeclose(cli, mem_ctx);
694 ret &= test_writex(cli, mem_ctx);
696 torture_close_connection(cli);
697 talloc_free(mem_ctx);