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 3 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, see <http://www.gnu.org/licenses/>.
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 #include "libcli/raw/raw_proto.h"
30 #define CHECK_STATUS(status, correct) do { \
31 if (!NT_STATUS_EQUAL(status, correct)) { \
32 torture_fail(tctx, talloc_asprintf(tctx, "(%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 torture_fail(tctx, talloc_asprintf(tctx, "(%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(tctx, 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, tctx, &finfo); \
56 CHECK_STATUS(status, NT_STATUS_OK); \
57 if ((v) != finfo.all_info.out.field) { \
58 torture_comment(tctx, "(%s) wrong value for field %s %.0f - %.0f\n", \
59 __location__, #field, (double)v, (double)finfo.all_info.out.field); \
60 dump_all_info(tctx, &finfo); \
65 #define BASEDIR "\\testwrite"
69 setup a random buffer based on a seed
71 static void setup_buffer(uint8_t *buf
, unsigned int 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(struct torture_context
*tctx
,
82 uint8_t *buf
, unsigned int seed
, int len
, const char *location
)
89 torture_fail(tctx
, talloc_asprintf(tctx
, "Buffer incorrect at %s! ofs=%d buf=0x%x correct=0x%x\n",
90 location
, i
, buf
[i
], v
));
100 static bool test_write(struct torture_context
*tctx
,
101 struct smbcli_state
*cli
)
108 const int maxsize
= 90000;
109 const char *fname
= BASEDIR
"\\test.txt";
110 unsigned int seed
= time(NULL
);
111 union smb_fileinfo finfo
;
113 buf
= talloc_zero_array(tctx
, uint8_t, maxsize
);
115 if (!torture_setup_dir(cli
, BASEDIR
)) {
116 torture_fail(tctx
, "failed to setup basedir");
119 torture_comment(tctx
, "Testing RAW_WRITE_WRITE\n");
120 io
.generic
.level
= RAW_WRITE_WRITE
;
122 fnum
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
125 torture_fail_goto(tctx
, done
,
126 talloc_asprintf(tctx
, "Failed to create %s - %s\n", fname
, smbcli_errstr(cli
->tree
)));
129 torture_comment(tctx
, "Trying zero write\n");
130 io
.write
.in
.file
.fnum
= fnum
;
131 io
.write
.in
.count
= 0;
132 io
.write
.in
.offset
= 0;
133 io
.write
.in
.remaining
= 0;
134 io
.write
.in
.data
= buf
;
135 status
= smb_raw_write(cli
->tree
, &io
);
136 CHECK_STATUS(status
, NT_STATUS_OK
);
137 CHECK_VALUE(io
.write
.out
.nwritten
, 0);
139 setup_buffer(buf
, seed
, maxsize
);
141 torture_comment(tctx
, "Trying small write\n");
142 io
.write
.in
.count
= 9;
143 io
.write
.in
.offset
= 4;
144 io
.write
.in
.data
= buf
;
145 status
= smb_raw_write(cli
->tree
, &io
);
146 CHECK_STATUS(status
, NT_STATUS_OK
);
147 CHECK_VALUE(io
.write
.out
.nwritten
, io
.write
.in
.count
);
149 memset(buf
, 0, maxsize
);
150 if (smbcli_read(cli
->tree
, fnum
, buf
, 0, 13) != 13) {
152 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "read failed at %s\n", __location__
));
154 CHECK_BUFFER(buf
+4, seed
, 9);
155 CHECK_VALUE(IVAL(buf
,0), 0);
157 setup_buffer(buf
, seed
, maxsize
);
159 torture_comment(tctx
, "Trying large write\n");
160 io
.write
.in
.count
= 4000;
161 io
.write
.in
.offset
= 0;
162 io
.write
.in
.data
= buf
;
163 status
= smb_raw_write(cli
->tree
, &io
);
164 CHECK_STATUS(status
, NT_STATUS_OK
);
165 CHECK_VALUE(io
.write
.out
.nwritten
, 4000);
167 memset(buf
, 0, maxsize
);
168 if (smbcli_read(cli
->tree
, fnum
, buf
, 0, 4000) != 4000) {
170 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "read failed at %s\n", __location__
));
172 CHECK_BUFFER(buf
, seed
, 4000);
174 torture_comment(tctx
, "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 torture_comment(tctx
, "Setting file as sparse\n");
183 status
= torture_set_sparse(cli
->tree
, fnum
);
184 CHECK_STATUS(status
, NT_STATUS_OK
);
186 if (!(cli
->transport
->negotiate
.capabilities
& CAP_LARGE_FILES
)) {
187 torture_comment(tctx
, "skipping large file tests - CAP_LARGE_FILES not set\n");
191 torture_comment(tctx
, "Trying 2^32 offset\n");
192 setup_buffer(buf
, seed
, maxsize
);
193 io
.write
.in
.file
.fnum
= fnum
;
194 io
.write
.in
.count
= 4000;
195 io
.write
.in
.offset
= 0xFFFFFFFF - 2000;
196 io
.write
.in
.data
= buf
;
197 status
= smb_raw_write(cli
->tree
, &io
);
198 CHECK_STATUS(status
, NT_STATUS_OK
);
199 CHECK_VALUE(io
.write
.out
.nwritten
, 4000);
200 CHECK_ALL_INFO(io
.write
.in
.count
+ (uint64_t)io
.write
.in
.offset
, size
);
202 memset(buf
, 0, maxsize
);
203 if (smbcli_read(cli
->tree
, fnum
, buf
, io
.write
.in
.offset
, 4000) != 4000) {
205 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "read failed at %s\n", __location__
));
207 CHECK_BUFFER(buf
, seed
, 4000);
210 smbcli_close(cli
->tree
, fnum
);
211 smb_raw_exit(cli
->session
);
212 smbcli_deltree(cli
->tree
, BASEDIR
);
220 static bool test_writex(struct torture_context
*tctx
,
221 struct smbcli_state
*cli
)
228 const int maxsize
= 90000;
229 const char *fname
= BASEDIR
"\\test.txt";
230 unsigned int seed
= time(NULL
);
231 union smb_fileinfo finfo
;
234 if (!torture_setting_bool(tctx
, "dangerous", false)) {
236 torture_comment(tctx
, "dangerous not set - limiting range of test to 2^%d\n", max_bits
);
239 buf
= talloc_zero_array(tctx
, uint8_t, maxsize
);
241 if (!cli
->transport
->negotiate
.lockread_supported
) {
242 torture_comment(tctx
, "Server does not support writeunlock - skipping\n");
246 if (!torture_setup_dir(cli
, BASEDIR
)) {
247 torture_fail(tctx
, "failed to setup basedir");
250 torture_comment(tctx
, "Testing RAW_WRITE_WRITEX\n");
251 io
.generic
.level
= RAW_WRITE_WRITEX
;
253 fnum
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
256 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "Failed to create %s - %s\n", fname
, smbcli_errstr(cli
->tree
)));
259 torture_comment(tctx
, "Trying zero write\n");
260 io
.writex
.in
.file
.fnum
= fnum
;
261 io
.writex
.in
.offset
= 0;
262 io
.writex
.in
.wmode
= 0;
263 io
.writex
.in
.remaining
= 0;
264 io
.writex
.in
.count
= 0;
265 io
.writex
.in
.data
= buf
;
266 status
= smb_raw_write(cli
->tree
, &io
);
267 CHECK_STATUS(status
, NT_STATUS_OK
);
268 CHECK_VALUE(io
.writex
.out
.nwritten
, 0);
270 setup_buffer(buf
, seed
, maxsize
);
272 torture_comment(tctx
, "Trying small write\n");
273 io
.writex
.in
.count
= 9;
274 io
.writex
.in
.offset
= 4;
275 io
.writex
.in
.data
= buf
;
276 status
= smb_raw_write(cli
->tree
, &io
);
277 CHECK_STATUS(status
, NT_STATUS_OK
);
278 CHECK_VALUE(io
.writex
.out
.nwritten
, io
.writex
.in
.count
);
280 memset(buf
, 0, maxsize
);
281 if (smbcli_read(cli
->tree
, fnum
, buf
, 0, 13) != 13) {
283 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "read failed at %s\n", __location__
));
285 CHECK_BUFFER(buf
+4, seed
, 9);
286 CHECK_VALUE(IVAL(buf
,0), 0);
288 setup_buffer(buf
, seed
, maxsize
);
290 torture_comment(tctx
, "Trying large write\n");
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_OK
);
296 CHECK_VALUE(io
.writex
.out
.nwritten
, 4000);
298 memset(buf
, 0, maxsize
);
299 if (smbcli_read(cli
->tree
, fnum
, buf
, 0, 4000) != 4000) {
301 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "read failed at %s\n", __location__
));
303 CHECK_BUFFER(buf
, seed
, 4000);
305 torture_comment(tctx
, "Trying bad fnum\n");
306 io
.writex
.in
.file
.fnum
= fnum
+1;
307 io
.writex
.in
.count
= 4000;
308 io
.writex
.in
.offset
= 0;
309 io
.writex
.in
.data
= buf
;
310 status
= smb_raw_write(cli
->tree
, &io
);
311 CHECK_STATUS(status
, NT_STATUS_INVALID_HANDLE
);
313 torture_comment(tctx
, "Testing wmode\n");
314 io
.writex
.in
.file
.fnum
= fnum
;
315 io
.writex
.in
.count
= 1;
316 io
.writex
.in
.offset
= 0;
317 io
.writex
.in
.wmode
= 1;
318 io
.writex
.in
.data
= buf
;
319 status
= smb_raw_write(cli
->tree
, &io
);
320 CHECK_STATUS(status
, NT_STATUS_OK
);
321 CHECK_VALUE(io
.writex
.out
.nwritten
, io
.writex
.in
.count
);
323 io
.writex
.in
.wmode
= 2;
324 status
= smb_raw_write(cli
->tree
, &io
);
325 CHECK_STATUS(status
, NT_STATUS_OK
);
326 CHECK_VALUE(io
.writex
.out
.nwritten
, io
.writex
.in
.count
);
329 torture_comment(tctx
, "Trying locked region\n");
331 if (NT_STATUS_IS_ERR(smbcli_lock(cli
->tree
, fnum
, 3, 1, 0, WRITE_LOCK
))) {
333 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "Failed to lock file at %s\n", __location__
));
336 io
.writex
.in
.wmode
= 0;
337 io
.writex
.in
.count
= 4;
338 io
.writex
.in
.offset
= 0;
339 status
= smb_raw_write(cli
->tree
, &io
);
340 CHECK_STATUS(status
, NT_STATUS_FILE_LOCK_CONFLICT
);
342 torture_comment(tctx
, "Setting file as sparse\n");
343 status
= torture_set_sparse(cli
->tree
, fnum
);
344 CHECK_STATUS(status
, NT_STATUS_OK
);
346 if (!(cli
->transport
->negotiate
.capabilities
& CAP_LARGE_FILES
)) {
347 torture_skip(tctx
, "skipping large file tests - CAP_LARGE_FILES not set\n");
350 torture_comment(tctx
, "Trying 2^32 offset\n");
351 setup_buffer(buf
, seed
, maxsize
);
352 io
.writex
.in
.file
.fnum
= fnum
;
353 io
.writex
.in
.count
= 4000;
354 io
.writex
.in
.offset
= 0xFFFFFFFF - 2000;
355 io
.writex
.in
.data
= buf
;
356 status
= smb_raw_write(cli
->tree
, &io
);
357 CHECK_STATUS(status
, NT_STATUS_OK
);
358 CHECK_VALUE(io
.writex
.out
.nwritten
, 4000);
359 CHECK_ALL_INFO(io
.writex
.in
.count
+ (uint64_t)io
.writex
.in
.offset
, size
);
361 memset(buf
, 0, maxsize
);
362 if (smbcli_read(cli
->tree
, fnum
, buf
, io
.writex
.in
.offset
, 4000) != 4000) {
364 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "read failed at %s\n", __location__
));
366 CHECK_BUFFER(buf
, seed
, 4000);
368 for (i
=33;i
<max_bits
;i
++) {
369 torture_comment(tctx
, "Trying 2^%d offset\n", i
);
370 setup_buffer(buf
, seed
+1, maxsize
);
371 io
.writex
.in
.file
.fnum
= fnum
;
372 io
.writex
.in
.count
= 4000;
373 io
.writex
.in
.offset
= ((uint64_t)1) << i
;
374 io
.writex
.in
.data
= buf
;
375 status
= smb_raw_write(cli
->tree
, &io
);
377 NT_STATUS_EQUAL(status
, NT_STATUS_INVALID_PARAMETER
)) {
380 CHECK_STATUS(status
, NT_STATUS_OK
);
381 CHECK_VALUE(io
.writex
.out
.nwritten
, 4000);
382 CHECK_ALL_INFO(io
.writex
.in
.count
+ (uint64_t)io
.writex
.in
.offset
, size
);
384 memset(buf
, 0, maxsize
);
385 if (smbcli_read(cli
->tree
, fnum
, buf
, io
.writex
.in
.offset
, 4000) != 4000) {
387 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "read failed at %s\n", __location__
));
389 CHECK_BUFFER(buf
, seed
+1, 4000);
391 torture_comment(tctx
, "limit is 2^%d\n", i
);
393 setup_buffer(buf
, seed
, maxsize
);
396 smbcli_close(cli
->tree
, fnum
);
397 smb_raw_exit(cli
->session
);
398 smbcli_deltree(cli
->tree
, BASEDIR
);
404 test write unlock ops
406 static bool test_writeunlock(struct torture_context
*tctx
,
407 struct smbcli_state
*cli
)
414 const int maxsize
= 90000;
415 const char *fname
= BASEDIR
"\\test.txt";
416 unsigned int seed
= time(NULL
);
417 union smb_fileinfo finfo
;
419 buf
= talloc_zero_array(tctx
, uint8_t, maxsize
);
421 if (!cli
->transport
->negotiate
.lockread_supported
) {
422 torture_skip(tctx
, "Server does not support writeunlock - skipping\n");
425 if (!torture_setup_dir(cli
, BASEDIR
)) {
426 torture_fail(tctx
, "failed to setup basedir");
429 torture_comment(tctx
, "Testing RAW_WRITE_WRITEUNLOCK\n");
430 io
.generic
.level
= RAW_WRITE_WRITEUNLOCK
;
432 fnum
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
435 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "Failed to create %s - %s\n", fname
, smbcli_errstr(cli
->tree
)));
438 torture_comment(tctx
, "Trying zero write\n");
439 io
.writeunlock
.in
.file
.fnum
= fnum
;
440 io
.writeunlock
.in
.count
= 0;
441 io
.writeunlock
.in
.offset
= 0;
442 io
.writeunlock
.in
.remaining
= 0;
443 io
.writeunlock
.in
.data
= buf
;
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
);
448 setup_buffer(buf
, seed
, maxsize
);
450 torture_comment(tctx
, "Trying small write\n");
451 io
.writeunlock
.in
.count
= 9;
452 io
.writeunlock
.in
.offset
= 4;
453 io
.writeunlock
.in
.data
= buf
;
454 status
= smb_raw_write(cli
->tree
, &io
);
455 CHECK_STATUS(status
, NT_STATUS_RANGE_NOT_LOCKED
);
456 if (smbcli_read(cli
->tree
, fnum
, buf
, 0, 13) != 13) {
458 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "read failed at %s\n", __location__
));
460 CHECK_BUFFER(buf
+4, seed
, 9);
461 CHECK_VALUE(IVAL(buf
,0), 0);
463 setup_buffer(buf
, seed
, maxsize
);
464 smbcli_lock(cli
->tree
, fnum
, io
.writeunlock
.in
.offset
, io
.writeunlock
.in
.count
,
466 status
= smb_raw_write(cli
->tree
, &io
);
467 CHECK_STATUS(status
, NT_STATUS_OK
);
468 CHECK_VALUE(io
.writeunlock
.out
.nwritten
, io
.writeunlock
.in
.count
);
470 memset(buf
, 0, maxsize
);
471 if (smbcli_read(cli
->tree
, fnum
, buf
, 0, 13) != 13) {
473 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "read failed at %s\n", __location__
));
475 CHECK_BUFFER(buf
+4, seed
, 9);
476 CHECK_VALUE(IVAL(buf
,0), 0);
478 setup_buffer(buf
, seed
, maxsize
);
480 torture_comment(tctx
, "Trying large write\n");
481 io
.writeunlock
.in
.count
= 4000;
482 io
.writeunlock
.in
.offset
= 0;
483 io
.writeunlock
.in
.data
= buf
;
484 smbcli_lock(cli
->tree
, fnum
, io
.writeunlock
.in
.offset
, io
.writeunlock
.in
.count
,
486 status
= smb_raw_write(cli
->tree
, &io
);
487 CHECK_STATUS(status
, NT_STATUS_OK
);
488 CHECK_VALUE(io
.writeunlock
.out
.nwritten
, 4000);
490 status
= smb_raw_write(cli
->tree
, &io
);
491 CHECK_STATUS(status
, NT_STATUS_RANGE_NOT_LOCKED
);
493 memset(buf
, 0, maxsize
);
494 if (smbcli_read(cli
->tree
, fnum
, buf
, 0, 4000) != 4000) {
496 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "read failed at %s\n", __location__
));
498 CHECK_BUFFER(buf
, seed
, 4000);
500 torture_comment(tctx
, "Trying bad fnum\n");
501 io
.writeunlock
.in
.file
.fnum
= fnum
+1;
502 io
.writeunlock
.in
.count
= 4000;
503 io
.writeunlock
.in
.offset
= 0;
504 io
.writeunlock
.in
.data
= buf
;
505 status
= smb_raw_write(cli
->tree
, &io
);
506 CHECK_STATUS(status
, NT_STATUS_INVALID_HANDLE
);
508 torture_comment(tctx
, "Setting file as sparse\n");
509 status
= torture_set_sparse(cli
->tree
, fnum
);
510 CHECK_STATUS(status
, NT_STATUS_OK
);
512 if (!(cli
->transport
->negotiate
.capabilities
& CAP_LARGE_FILES
)) {
513 torture_skip(tctx
, "skipping large file tests - CAP_LARGE_FILES not set\n");
516 torture_comment(tctx
, "Trying 2^32 offset\n");
517 setup_buffer(buf
, seed
, maxsize
);
518 io
.writeunlock
.in
.file
.fnum
= fnum
;
519 io
.writeunlock
.in
.count
= 4000;
520 io
.writeunlock
.in
.offset
= 0xFFFFFFFF - 2000;
521 io
.writeunlock
.in
.data
= buf
;
522 smbcli_lock(cli
->tree
, fnum
, io
.writeunlock
.in
.offset
, io
.writeunlock
.in
.count
,
524 status
= smb_raw_write(cli
->tree
, &io
);
525 CHECK_STATUS(status
, NT_STATUS_OK
);
526 CHECK_VALUE(io
.writeunlock
.out
.nwritten
, 4000);
527 CHECK_ALL_INFO(io
.writeunlock
.in
.count
+ (uint64_t)io
.writeunlock
.in
.offset
, size
);
529 memset(buf
, 0, maxsize
);
530 if (smbcli_read(cli
->tree
, fnum
, buf
, io
.writeunlock
.in
.offset
, 4000) != 4000) {
532 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "read failed at %s\n", __location__
));
534 CHECK_BUFFER(buf
, seed
, 4000);
537 smbcli_close(cli
->tree
, fnum
);
538 smb_raw_exit(cli
->session
);
539 smbcli_deltree(cli
->tree
, BASEDIR
);
547 static bool test_writeclose(struct torture_context
*tctx
,
548 struct smbcli_state
*cli
)
555 const int maxsize
= 90000;
556 const char *fname
= BASEDIR
"\\test.txt";
557 unsigned int seed
= time(NULL
);
558 union smb_fileinfo finfo
;
560 buf
= talloc_zero_array(tctx
, uint8_t, maxsize
);
562 if (!torture_setting_bool(tctx
, "writeclose_support", true)) {
563 torture_skip(tctx
, "Server does not support writeclose - skipping\n");
566 if (!torture_setup_dir(cli
, BASEDIR
)) {
567 torture_fail(tctx
, "failed to setup basedir");
570 torture_comment(tctx
, "Testing RAW_WRITE_WRITECLOSE\n");
571 io
.generic
.level
= RAW_WRITE_WRITECLOSE
;
573 fnum
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
576 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "Failed to create %s - %s\n", fname
, smbcli_errstr(cli
->tree
)));
579 torture_comment(tctx
, "Trying zero write\n");
580 io
.writeclose
.in
.file
.fnum
= fnum
;
581 io
.writeclose
.in
.count
= 0;
582 io
.writeclose
.in
.offset
= 0;
583 io
.writeclose
.in
.mtime
= 0;
584 io
.writeclose
.in
.data
= buf
;
585 status
= smb_raw_write(cli
->tree
, &io
);
586 CHECK_STATUS(status
, NT_STATUS_OK
);
587 CHECK_VALUE(io
.writeclose
.out
.nwritten
, io
.writeclose
.in
.count
);
589 status
= smb_raw_write(cli
->tree
, &io
);
590 CHECK_STATUS(status
, NT_STATUS_OK
);
591 CHECK_VALUE(io
.writeclose
.out
.nwritten
, io
.writeclose
.in
.count
);
593 setup_buffer(buf
, seed
, maxsize
);
595 torture_comment(tctx
, "Trying small write\n");
596 io
.writeclose
.in
.count
= 9;
597 io
.writeclose
.in
.offset
= 4;
598 io
.writeclose
.in
.data
= buf
;
599 status
= smb_raw_write(cli
->tree
, &io
);
600 CHECK_STATUS(status
, NT_STATUS_OK
);
602 status
= smb_raw_write(cli
->tree
, &io
);
603 CHECK_STATUS(status
, NT_STATUS_INVALID_HANDLE
);
605 fnum
= smbcli_open(cli
->tree
, fname
, O_RDWR
, DENY_NONE
);
606 io
.writeclose
.in
.file
.fnum
= fnum
;
608 if (smbcli_read(cli
->tree
, fnum
, buf
, 0, 13) != 13) {
610 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "read failed at %s\n", __location__
));
612 CHECK_BUFFER(buf
+4, seed
, 9);
613 CHECK_VALUE(IVAL(buf
,0), 0);
615 setup_buffer(buf
, seed
, maxsize
);
616 status
= smb_raw_write(cli
->tree
, &io
);
617 CHECK_STATUS(status
, NT_STATUS_OK
);
618 CHECK_VALUE(io
.writeclose
.out
.nwritten
, io
.writeclose
.in
.count
);
620 fnum
= smbcli_open(cli
->tree
, fname
, O_RDWR
, DENY_NONE
);
621 io
.writeclose
.in
.file
.fnum
= fnum
;
623 memset(buf
, 0, maxsize
);
624 if (smbcli_read(cli
->tree
, fnum
, buf
, 0, 13) != 13) {
626 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "read failed at %s\n", __location__
));
628 CHECK_BUFFER(buf
+4, seed
, 9);
629 CHECK_VALUE(IVAL(buf
,0), 0);
631 setup_buffer(buf
, seed
, maxsize
);
633 torture_comment(tctx
, "Trying large write\n");
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_OK
);
639 CHECK_VALUE(io
.writeclose
.out
.nwritten
, 4000);
641 status
= smb_raw_write(cli
->tree
, &io
);
642 CHECK_STATUS(status
, NT_STATUS_INVALID_HANDLE
);
644 fnum
= smbcli_open(cli
->tree
, fname
, O_RDWR
, DENY_NONE
);
645 io
.writeclose
.in
.file
.fnum
= fnum
;
647 memset(buf
, 0, maxsize
);
648 if (smbcli_read(cli
->tree
, fnum
, buf
, 0, 4000) != 4000) {
650 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "read failed at %s\n", __location__
));
652 CHECK_BUFFER(buf
, seed
, 4000);
654 torture_comment(tctx
, "Trying bad fnum\n");
655 io
.writeclose
.in
.file
.fnum
= fnum
+1;
656 io
.writeclose
.in
.count
= 4000;
657 io
.writeclose
.in
.offset
= 0;
658 io
.writeclose
.in
.data
= buf
;
659 status
= smb_raw_write(cli
->tree
, &io
);
660 CHECK_STATUS(status
, NT_STATUS_INVALID_HANDLE
);
662 torture_comment(tctx
, "Setting file as sparse\n");
663 status
= torture_set_sparse(cli
->tree
, fnum
);
664 CHECK_STATUS(status
, NT_STATUS_OK
);
666 if (!(cli
->transport
->negotiate
.capabilities
& CAP_LARGE_FILES
)) {
667 torture_skip(tctx
, "skipping large file tests - CAP_LARGE_FILES not set\n");
670 torture_comment(tctx
, "Trying 2^32 offset\n");
671 setup_buffer(buf
, seed
, maxsize
);
672 io
.writeclose
.in
.file
.fnum
= fnum
;
673 io
.writeclose
.in
.count
= 4000;
674 io
.writeclose
.in
.offset
= 0xFFFFFFFF - 2000;
675 io
.writeclose
.in
.data
= buf
;
676 status
= smb_raw_write(cli
->tree
, &io
);
677 CHECK_STATUS(status
, NT_STATUS_OK
);
678 CHECK_VALUE(io
.writeclose
.out
.nwritten
, 4000);
679 CHECK_ALL_INFO(io
.writeclose
.in
.count
+ (uint64_t)io
.writeclose
.in
.offset
, size
);
681 fnum
= smbcli_open(cli
->tree
, fname
, O_RDWR
, DENY_NONE
);
682 io
.writeclose
.in
.file
.fnum
= fnum
;
684 memset(buf
, 0, maxsize
);
685 if (smbcli_read(cli
->tree
, fnum
, buf
, io
.writeclose
.in
.offset
, 4000) != 4000) {
687 torture_fail_goto(tctx
, done
, talloc_asprintf(tctx
, "read failed at %s\n", __location__
));
689 CHECK_BUFFER(buf
, seed
, 4000);
692 smbcli_close(cli
->tree
, fnum
);
693 smb_raw_exit(cli
->session
);
694 smbcli_deltree(cli
->tree
, BASEDIR
);
699 test a deliberately bad SMB1 write.
701 static bool test_bad_write(struct torture_context
*tctx
,
702 struct smbcli_state
*cli
)
706 struct smbcli_request
*req
= NULL
;
707 const char *fname
= BASEDIR
"\\badwrite.txt";
710 if (!torture_setup_dir(cli
, BASEDIR
)) {
711 torture_fail(tctx
, "failed to setup basedir");
714 torture_comment(tctx
, "Testing RAW_BAD_WRITE\n");
716 fnum
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
718 torture_fail_goto(tctx
,
720 talloc_asprintf(tctx
,
721 "Failed to create %s - %s\n",
723 smbcli_errstr(cli
->tree
)));
726 req
= smbcli_request_setup(cli
->tree
,
731 torture_fail_goto(tctx
,
733 talloc_asprintf(tctx
, "talloc fail\n"));
736 SSVAL(req
->out
.vwv
, VWV(0), fnum
);
737 SSVAL(req
->out
.vwv
, VWV(1), 65535); /* bad write length. */
738 SIVAL(req
->out
.vwv
, VWV(2), 0); /* offset */
739 SSVAL(req
->out
.vwv
, VWV(4), 0); /* remaining. */
741 if (!smbcli_request_send(req
)) {
742 torture_fail_goto(tctx
,
744 talloc_asprintf(tctx
, "Send failed\n"));
747 if (!smbcli_request_receive(req
)) {
748 torture_fail_goto(tctx
,
750 talloc_asprintf(tctx
, "Receive failed\n"));
754 * Check for expected error codes.
755 * ntvfs returns NT_STATUS_UNSUCCESSFUL.
757 ok
= (NT_STATUS_EQUAL(req
->status
, NT_STATUS_INVALID_PARAMETER
) ||
758 NT_STATUS_EQUAL(req
->status
, NT_STATUS_UNSUCCESSFUL
));
761 torture_fail_goto(tctx
,
763 talloc_asprintf(tctx
,
764 "Should have returned "
765 "NT_STATUS_INVALID_PARAMETER or "
766 "NT_STATUS_UNSUCCESSFUL "
768 nt_errstr(req
->status
)));
775 smbcli_request_destroy(req
);
778 smbcli_close(cli
->tree
, fnum
);
780 smb_raw_exit(cli
->session
);
781 smbcli_deltree(cli
->tree
, BASEDIR
);
786 basic testing of write calls
788 struct torture_suite
*torture_raw_write(TALLOC_CTX
*mem_ctx
)
790 struct torture_suite
*suite
= torture_suite_create(mem_ctx
, "write");
792 torture_suite_add_1smb_test(suite
, "write", test_write
);
793 torture_suite_add_1smb_test(suite
, "write unlock", test_writeunlock
);
794 torture_suite_add_1smb_test(suite
, "write close", test_writeclose
);
795 torture_suite_add_1smb_test(suite
, "writex", test_writex
);
796 torture_suite_add_1smb_test(suite
, "bad-write", test_bad_write
);