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 2 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, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 
22 #include "includes.h"
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"
29 
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)); \
34 		ret = False; \
35 		goto done; \
36 	}} while (0)
37 
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); \
42 		ret = False; \
43 		goto done; \
44 	}} while (0)
45 
46 #define CHECK_BUFFER(buf, seed, len) do { \
47 	if (!check_buffer(buf, seed, len, __location__)) { \
48 		ret = False; \
49 		goto done; \
50 	}} while (0)
51 
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); \
61 		ret = False; \
62 	}} while (0)
63 
64 
65 #define BASEDIR "\\testwrite"
66 
67 
68 /*
69   setup a random buffer based on a seed
70 */
setup_buffer(uint8_t * buf,uint_t seed,int len)71 static void setup_buffer(uint8_t *buf, uint_t seed, int len)
72 {
73 	int i;
74 	srandom(seed);
75 	for (i=0;i<len;i++) buf[i] = random();
76 }
77 
78 /*
79   check a random buffer based on a seed
80 */
check_buffer(uint8_t * buf,uint_t seed,int len,const char * location)81 static BOOL check_buffer(uint8_t *buf, uint_t 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 			printf("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 */
test_write(struct smbcli_state * cli,TALLOC_CTX * mem_ctx)99 static BOOL test_write(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
100 {
101 	union smb_write io;
102 	NTSTATUS status;
103 	BOOL ret = True;
104 	int fnum;
105 	uint8_t *buf;
106 	const int maxsize = 90000;
107 	const char *fname = BASEDIR "\\test.txt";
108 	uint_t seed = time(NULL);
109 	union smb_fileinfo finfo;
110 
111 	buf = talloc_zero_size(mem_ctx, maxsize);
112 
113 	if (!torture_setup_dir(cli, BASEDIR)) {
114 		return False;
115 	}
116 
117 	printf("Testing RAW_WRITE_WRITE\n");
118 	io.generic.level = RAW_WRITE_WRITE;
119 
120 	fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
121 	if (fnum == -1) {
122 		printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
123 		ret = False;
124 		goto done;
125 	}
126 
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);
136 
137 	setup_buffer(buf, seed, maxsize);
138 
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);
146 
147 	memset(buf, 0, maxsize);
148 	if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
149 		printf("read failed at %s\n", __location__);
150 		ret = False;
151 		goto done;
152 	}
153 	CHECK_BUFFER(buf+4, seed, 9);
154 	CHECK_VALUE(IVAL(buf,0), 0);
155 
156 	setup_buffer(buf, seed, maxsize);
157 
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);
165 
166 	memset(buf, 0, maxsize);
167 	if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
168 		printf("read failed at %s\n", __location__);
169 		ret = False;
170 		goto done;
171 	}
172 	CHECK_BUFFER(buf, seed, 4000);
173 
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);
181 
182 	printf("Setting file as sparse\n");
183 	status = torture_set_sparse(cli->tree, fnum);
184 	CHECK_STATUS(status, NT_STATUS_OK);
185 
186 	if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
187 		printf("skipping large file tests - CAP_LARGE_FILES not set\n");
188 		goto done;
189 	}
190 
191 	if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
192 		printf("skipping large file tests - CAP_LARGE_FILES not set\n");
193 		goto done;
194 	}
195 
196 	printf("Trying 2^32 offset\n");
197 	setup_buffer(buf, seed, maxsize);
198 	io.write.in.file.fnum = fnum;
199 	io.write.in.count = 4000;
200 	io.write.in.offset = 0xFFFFFFFF - 2000;
201 	io.write.in.data = buf;
202 	status = smb_raw_write(cli->tree, &io);
203 	CHECK_STATUS(status, NT_STATUS_OK);
204 	CHECK_VALUE(io.write.out.nwritten, 4000);
205 	CHECK_ALL_INFO(io.write.in.count + (uint64_t)io.write.in.offset, size);
206 
207 	memset(buf, 0, maxsize);
208 	if (smbcli_read(cli->tree, fnum, buf, io.write.in.offset, 4000) != 4000) {
209 		printf("read failed at %s\n", __location__);
210 		ret = False;
211 		goto done;
212 	}
213 	CHECK_BUFFER(buf, seed, 4000);
214 
215 done:
216 	smbcli_close(cli->tree, fnum);
217 	smb_raw_exit(cli->session);
218 	smbcli_deltree(cli->tree, BASEDIR);
219 	return ret;
220 }
221 
222 
223 /*
224   test writex ops
225 */
test_writex(struct smbcli_state * cli,TALLOC_CTX * mem_ctx)226 static BOOL test_writex(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
227 {
228 	union smb_write io;
229 	NTSTATUS status;
230 	BOOL ret = True;
231 	int fnum, i;
232 	uint8_t *buf;
233 	const int maxsize = 90000;
234 	const char *fname = BASEDIR "\\test.txt";
235 	uint_t seed = time(NULL);
236 	union smb_fileinfo finfo;
237 	int max_bits=63;
238 
239 	if (!lp_parm_bool(-1, "torture", "dangerous", False)) {
240 		max_bits=33;
241 		printf("dangerous not set - limiting range of test to 2^%d\n", max_bits);
242 	}
243 
244 	buf = talloc_zero_size(mem_ctx, maxsize);
245 
246 	if (!torture_setup_dir(cli, BASEDIR)) {
247 		return False;
248 	}
249 
250 	printf("Testing RAW_WRITE_WRITEX\n");
251 	io.generic.level = RAW_WRITE_WRITEX;
252 
253 	fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
254 	if (fnum == -1) {
255 		printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
256 		ret = False;
257 		goto done;
258 	}
259 
260 	printf("Trying zero write\n");
261 	io.writex.in.file.fnum = fnum;
262 	io.writex.in.offset = 0;
263 	io.writex.in.wmode = 0;
264 	io.writex.in.remaining = 0;
265 	io.writex.in.count = 0;
266 	io.writex.in.data = buf;
267 	status = smb_raw_write(cli->tree, &io);
268 	CHECK_STATUS(status, NT_STATUS_OK);
269 	CHECK_VALUE(io.writex.out.nwritten, 0);
270 
271 	setup_buffer(buf, seed, maxsize);
272 
273 	printf("Trying small write\n");
274 	io.writex.in.count = 9;
275 	io.writex.in.offset = 4;
276 	io.writex.in.data = buf;
277 	status = smb_raw_write(cli->tree, &io);
278 	CHECK_STATUS(status, NT_STATUS_OK);
279 	CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
280 
281 	memset(buf, 0, maxsize);
282 	if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
283 		printf("read failed at %s\n", __location__);
284 		ret = False;
285 		goto done;
286 	}
287 	CHECK_BUFFER(buf+4, seed, 9);
288 	CHECK_VALUE(IVAL(buf,0), 0);
289 
290 	setup_buffer(buf, seed, maxsize);
291 
292 	printf("Trying large write\n");
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_OK);
298 	CHECK_VALUE(io.writex.out.nwritten, 4000);
299 
300 	memset(buf, 0, maxsize);
301 	if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
302 		printf("read failed at %s\n", __location__);
303 		ret = False;
304 		goto done;
305 	}
306 	CHECK_BUFFER(buf, seed, 4000);
307 
308 	printf("Trying bad fnum\n");
309 	io.writex.in.file.fnum = fnum+1;
310 	io.writex.in.count = 4000;
311 	io.writex.in.offset = 0;
312 	io.writex.in.data = buf;
313 	status = smb_raw_write(cli->tree, &io);
314 	CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
315 
316 	printf("Testing wmode\n");
317 	io.writex.in.file.fnum = fnum;
318 	io.writex.in.count = 1;
319 	io.writex.in.offset = 0;
320 	io.writex.in.wmode = 1;
321 	io.writex.in.data = buf;
322 	status = smb_raw_write(cli->tree, &io);
323 	CHECK_STATUS(status, NT_STATUS_OK);
324 	CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
325 
326 	io.writex.in.wmode = 2;
327 	status = smb_raw_write(cli->tree, &io);
328 	CHECK_STATUS(status, NT_STATUS_OK);
329 	CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
330 
331 
332 	printf("Trying locked region\n");
333 	cli->session->pid++;
334 	if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 3, 1, 0, WRITE_LOCK))) {
335 		printf("Failed to lock file at %s\n", __location__);
336 		ret = False;
337 		goto done;
338 	}
339 	cli->session->pid--;
340 	io.writex.in.wmode = 0;
341 	io.writex.in.count = 4;
342 	io.writex.in.offset = 0;
343 	status = smb_raw_write(cli->tree, &io);
344 	CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
345 
346 	printf("Setting file as sparse\n");
347 	status = torture_set_sparse(cli->tree, fnum);
348 	CHECK_STATUS(status, NT_STATUS_OK);
349 
350 	if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
351 		printf("skipping large file tests - CAP_LARGE_FILES not set\n");
352 		goto done;
353 	}
354 
355 	printf("Trying 2^32 offset\n");
356 	setup_buffer(buf, seed, maxsize);
357 	io.writex.in.file.fnum = fnum;
358 	io.writex.in.count = 4000;
359 	io.writex.in.offset = 0xFFFFFFFF - 2000;
360 	io.writex.in.data = buf;
361 	status = smb_raw_write(cli->tree, &io);
362 	CHECK_STATUS(status, NT_STATUS_OK);
363 	CHECK_VALUE(io.writex.out.nwritten, 4000);
364 	CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
365 
366 	memset(buf, 0, maxsize);
367 	if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
368 		printf("read failed at %s\n", __location__);
369 		ret = False;
370 		goto done;
371 	}
372 	CHECK_BUFFER(buf, seed, 4000);
373 
374 	for (i=33;i<max_bits;i++) {
375 		printf("Trying 2^%d offset\n", i);
376 		setup_buffer(buf, seed+1, maxsize);
377 		io.writex.in.file.fnum = fnum;
378 		io.writex.in.count = 4000;
379 		io.writex.in.offset = ((uint64_t)1) << i;
380 		io.writex.in.data = buf;
381 		status = smb_raw_write(cli->tree, &io);
382 		if (i>33 &&
383 		    NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
384 			break;
385 		}
386 		CHECK_STATUS(status, NT_STATUS_OK);
387 		CHECK_VALUE(io.writex.out.nwritten, 4000);
388 		CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
389 
390 		memset(buf, 0, maxsize);
391 		if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
392 			printf("read failed at %s\n", __location__);
393 			ret = False;
394 			goto done;
395 		}
396 		CHECK_BUFFER(buf, seed+1, 4000);
397 	}
398 	printf("limit is 2^%d\n", i);
399 
400 	setup_buffer(buf, seed, maxsize);
401 
402 done:
403 	smbcli_close(cli->tree, fnum);
404 	smb_raw_exit(cli->session);
405 	smbcli_deltree(cli->tree, BASEDIR);
406 	return ret;
407 }
408 
409 
410 /*
411   test write unlock ops
412 */
test_writeunlock(struct smbcli_state * cli,TALLOC_CTX * mem_ctx)413 static BOOL test_writeunlock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
414 {
415 	union smb_write io;
416 	NTSTATUS status;
417 	BOOL ret = True;
418 	int fnum;
419 	uint8_t *buf;
420 	const int maxsize = 90000;
421 	const char *fname = BASEDIR "\\test.txt";
422 	uint_t seed = time(NULL);
423 	union smb_fileinfo finfo;
424 
425 	buf = talloc_zero_size(mem_ctx, maxsize);
426 
427 	if (!torture_setup_dir(cli, BASEDIR)) {
428 		return False;
429 	}
430 
431 	printf("Testing RAW_WRITE_WRITEUNLOCK\n");
432 	io.generic.level = RAW_WRITE_WRITEUNLOCK;
433 
434 	fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
435 	if (fnum == -1) {
436 		printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
437 		ret = False;
438 		goto done;
439 	}
440 
441 	printf("Trying zero write\n");
442 	io.writeunlock.in.file.fnum = fnum;
443 	io.writeunlock.in.count = 0;
444 	io.writeunlock.in.offset = 0;
445 	io.writeunlock.in.remaining = 0;
446 	io.writeunlock.in.data = buf;
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);
450 
451 	setup_buffer(buf, seed, maxsize);
452 
453 	printf("Trying small write\n");
454 	io.writeunlock.in.count = 9;
455 	io.writeunlock.in.offset = 4;
456 	io.writeunlock.in.data = buf;
457 	status = smb_raw_write(cli->tree, &io);
458 	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
459 	if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
460 		printf("read failed at %s\n", __location__);
461 		ret = False;
462 		goto done;
463 	}
464 	CHECK_BUFFER(buf+4, seed, 9);
465 	CHECK_VALUE(IVAL(buf,0), 0);
466 
467 	setup_buffer(buf, seed, maxsize);
468 	smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
469 		 0, WRITE_LOCK);
470 	status = smb_raw_write(cli->tree, &io);
471 	CHECK_STATUS(status, NT_STATUS_OK);
472 	CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
473 
474 	memset(buf, 0, maxsize);
475 	if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
476 		printf("read failed at %s\n", __location__);
477 		ret = False;
478 		goto done;
479 	}
480 	CHECK_BUFFER(buf+4, seed, 9);
481 	CHECK_VALUE(IVAL(buf,0), 0);
482 
483 	setup_buffer(buf, seed, maxsize);
484 
485 	printf("Trying large write\n");
486 	io.writeunlock.in.count = 4000;
487 	io.writeunlock.in.offset = 0;
488 	io.writeunlock.in.data = buf;
489 	smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
490 		 0, WRITE_LOCK);
491 	status = smb_raw_write(cli->tree, &io);
492 	CHECK_STATUS(status, NT_STATUS_OK);
493 	CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
494 
495 	status = smb_raw_write(cli->tree, &io);
496 	CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
497 
498 	memset(buf, 0, maxsize);
499 	if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
500 		printf("read failed at %s\n", __location__);
501 		ret = False;
502 		goto done;
503 	}
504 	CHECK_BUFFER(buf, seed, 4000);
505 
506 	printf("Trying bad fnum\n");
507 	io.writeunlock.in.file.fnum = fnum+1;
508 	io.writeunlock.in.count = 4000;
509 	io.writeunlock.in.offset = 0;
510 	io.writeunlock.in.data = buf;
511 	status = smb_raw_write(cli->tree, &io);
512 	CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
513 
514 	printf("Setting file as sparse\n");
515 	status = torture_set_sparse(cli->tree, fnum);
516 	CHECK_STATUS(status, NT_STATUS_OK);
517 
518 	if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
519 		printf("skipping large file tests - CAP_LARGE_FILES not set\n");
520 		goto done;
521 	}
522 
523 	printf("Trying 2^32 offset\n");
524 	setup_buffer(buf, seed, maxsize);
525 	io.writeunlock.in.file.fnum = fnum;
526 	io.writeunlock.in.count = 4000;
527 	io.writeunlock.in.offset = 0xFFFFFFFF - 2000;
528 	io.writeunlock.in.data = buf;
529 	smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
530 		 0, WRITE_LOCK);
531 	status = smb_raw_write(cli->tree, &io);
532 	CHECK_STATUS(status, NT_STATUS_OK);
533 	CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
534 	CHECK_ALL_INFO(io.writeunlock.in.count + (uint64_t)io.writeunlock.in.offset, size);
535 
536 	memset(buf, 0, maxsize);
537 	if (smbcli_read(cli->tree, fnum, buf, io.writeunlock.in.offset, 4000) != 4000) {
538 		printf("read failed at %s\n", __location__);
539 		ret = False;
540 		goto done;
541 	}
542 	CHECK_BUFFER(buf, seed, 4000);
543 
544 done:
545 	smbcli_close(cli->tree, fnum);
546 	smb_raw_exit(cli->session);
547 	smbcli_deltree(cli->tree, BASEDIR);
548 	return ret;
549 }
550 
551 
552 /*
553   test write close ops
554 */
test_writeclose(struct smbcli_state * cli,TALLOC_CTX * mem_ctx)555 static BOOL test_writeclose(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
556 {
557 	union smb_write io;
558 	NTSTATUS status;
559 	BOOL ret = True;
560 	int fnum;
561 	uint8_t *buf;
562 	const int maxsize = 90000;
563 	const char *fname = BASEDIR "\\test.txt";
564 	uint_t seed = time(NULL);
565 	union smb_fileinfo finfo;
566 
567 	buf = talloc_zero_size(mem_ctx, maxsize);
568 
569 	if (!torture_setup_dir(cli, BASEDIR)) {
570 		return False;
571 	}
572 
573 	printf("Testing RAW_WRITE_WRITECLOSE\n");
574 	io.generic.level = RAW_WRITE_WRITECLOSE;
575 
576 	fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
577 	if (fnum == -1) {
578 		printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
579 		ret = False;
580 		goto done;
581 	}
582 
583 	printf("Trying zero write\n");
584 	io.writeclose.in.file.fnum = fnum;
585 	io.writeclose.in.count = 0;
586 	io.writeclose.in.offset = 0;
587 	io.writeclose.in.mtime = 0;
588 	io.writeclose.in.data = buf;
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);
592 
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);
596 
597 	setup_buffer(buf, seed, maxsize);
598 
599 	printf("Trying small write\n");
600 	io.writeclose.in.count = 9;
601 	io.writeclose.in.offset = 4;
602 	io.writeclose.in.data = buf;
603 	status = smb_raw_write(cli->tree, &io);
604 	CHECK_STATUS(status, NT_STATUS_OK);
605 
606 	status = smb_raw_write(cli->tree, &io);
607 	CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
608 
609 	fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
610 	io.writeclose.in.file.fnum = fnum;
611 
612 	if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
613 		printf("read failed at %s\n", __location__);
614 		ret = False;
615 		goto done;
616 	}
617 	CHECK_BUFFER(buf+4, seed, 9);
618 	CHECK_VALUE(IVAL(buf,0), 0);
619 
620 	setup_buffer(buf, seed, maxsize);
621 	status = smb_raw_write(cli->tree, &io);
622 	CHECK_STATUS(status, NT_STATUS_OK);
623 	CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
624 
625 	fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
626 	io.writeclose.in.file.fnum = fnum;
627 
628 	memset(buf, 0, maxsize);
629 	if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
630 		printf("read failed at %s\n", __location__);
631 		ret = False;
632 		goto done;
633 	}
634 	CHECK_BUFFER(buf+4, seed, 9);
635 	CHECK_VALUE(IVAL(buf,0), 0);
636 
637 	setup_buffer(buf, seed, maxsize);
638 
639 	printf("Trying large write\n");
640 	io.writeclose.in.count = 4000;
641 	io.writeclose.in.offset = 0;
642 	io.writeclose.in.data = buf;
643 	status = smb_raw_write(cli->tree, &io);
644 	CHECK_STATUS(status, NT_STATUS_OK);
645 	CHECK_VALUE(io.writeclose.out.nwritten, 4000);
646 
647 	status = smb_raw_write(cli->tree, &io);
648 	CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
649 
650 	fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
651 	io.writeclose.in.file.fnum = fnum;
652 
653 	memset(buf, 0, maxsize);
654 	if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
655 		printf("read failed at %s\n", __location__);
656 		ret = False;
657 		goto done;
658 	}
659 	CHECK_BUFFER(buf, seed, 4000);
660 
661 	printf("Trying bad fnum\n");
662 	io.writeclose.in.file.fnum = fnum+1;
663 	io.writeclose.in.count = 4000;
664 	io.writeclose.in.offset = 0;
665 	io.writeclose.in.data = buf;
666 	status = smb_raw_write(cli->tree, &io);
667 	CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
668 
669 	printf("Setting file as sparse\n");
670 	status = torture_set_sparse(cli->tree, fnum);
671 	CHECK_STATUS(status, NT_STATUS_OK);
672 
673 	if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
674 		printf("skipping large file tests - CAP_LARGE_FILES not set\n");
675 		goto done;
676 	}
677 
678 	printf("Trying 2^32 offset\n");
679 	setup_buffer(buf, seed, maxsize);
680 	io.writeclose.in.file.fnum = fnum;
681 	io.writeclose.in.count = 4000;
682 	io.writeclose.in.offset = 0xFFFFFFFF - 2000;
683 	io.writeclose.in.data = buf;
684 	status = smb_raw_write(cli->tree, &io);
685 	CHECK_STATUS(status, NT_STATUS_OK);
686 	CHECK_VALUE(io.writeclose.out.nwritten, 4000);
687 	CHECK_ALL_INFO(io.writeclose.in.count + (uint64_t)io.writeclose.in.offset, size);
688 
689 	fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
690 	io.writeclose.in.file.fnum = fnum;
691 
692 	memset(buf, 0, maxsize);
693 	if (smbcli_read(cli->tree, fnum, buf, io.writeclose.in.offset, 4000) != 4000) {
694 		printf("read failed at %s\n", __location__);
695 		ret = False;
696 		goto done;
697 	}
698 	CHECK_BUFFER(buf, seed, 4000);
699 
700 done:
701 	smbcli_close(cli->tree, fnum);
702 	smb_raw_exit(cli->session);
703 	smbcli_deltree(cli->tree, BASEDIR);
704 	return ret;
705 }
706 
707 /*
708    basic testing of write calls
709 */
torture_raw_write(struct torture_context * torture)710 BOOL torture_raw_write(struct torture_context *torture)
711 {
712 	struct smbcli_state *cli;
713 	BOOL ret = True;
714 	TALLOC_CTX *mem_ctx;
715 
716 	if (!torture_open_connection(&cli, 0)) {
717 		return False;
718 	}
719 
720 	mem_ctx = talloc_init("torture_raw_write");
721 
722 	ret &= test_write(cli, mem_ctx);
723 	ret &= test_writeunlock(cli, mem_ctx);
724 	ret &= test_writeclose(cli, mem_ctx);
725 	ret &= test_writex(cli, mem_ctx);
726 
727 	torture_close_connection(cli);
728 	talloc_free(mem_ctx);
729 	return ret;
730 }
731