Line data Source code
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 3 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, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
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"
29 :
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))); \
34 : ret = false; \
35 : goto done; \
36 : }} while (0)
37 :
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)); \
42 : ret = false; \
43 : goto done; \
44 : }} while (0)
45 :
46 : #define CHECK_BUFFER(buf, seed, len) do { \
47 : if (!check_buffer(tctx, 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, 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); \
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 : */
71 90 : static void setup_buffer(uint8_t *buf, unsigned int seed, int len)
72 : {
73 15 : int i;
74 90 : srandom(seed);
75 8100105 : for (i=0;i<len;i++) buf[i] = random();
76 90 : }
77 :
78 : /*
79 : check a random buffer based on a seed
80 : */
81 84 : static bool check_buffer(struct torture_context *tctx,
82 : uint8_t *buf, unsigned int seed, int len, const char *location)
83 : {
84 14 : int i;
85 84 : srandom(seed);
86 192422 : for (i=0;i<len;i++) {
87 192324 : uint8_t v = random();
88 192324 : if (buf[i] != v) {
89 0 : 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));
91 : return false;
92 : }
93 : }
94 70 : return true;
95 : }
96 :
97 : /*
98 : test write ops
99 : */
100 6 : static bool test_write(struct torture_context *tctx,
101 : struct smbcli_state *cli)
102 : {
103 1 : union smb_write io;
104 1 : NTSTATUS status;
105 6 : bool ret = true;
106 1 : int fnum;
107 1 : uint8_t *buf;
108 6 : const int maxsize = 90000;
109 6 : const char *fname = BASEDIR "\\test.txt";
110 6 : unsigned int seed = time(NULL);
111 1 : union smb_fileinfo finfo;
112 :
113 6 : buf = talloc_zero_array(tctx, uint8_t, maxsize);
114 :
115 6 : if (!torture_setup_dir(cli, BASEDIR)) {
116 0 : torture_fail(tctx, "failed to setup basedir");
117 : }
118 :
119 6 : torture_comment(tctx, "Testing RAW_WRITE_WRITE\n");
120 6 : io.generic.level = RAW_WRITE_WRITE;
121 :
122 6 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
123 6 : if (fnum == -1) {
124 0 : ret = false;
125 0 : torture_fail_goto(tctx, done,
126 : talloc_asprintf(tctx, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)));
127 : }
128 :
129 6 : torture_comment(tctx, "Trying zero write\n");
130 6 : io.write.in.file.fnum = fnum;
131 6 : io.write.in.count = 0;
132 6 : io.write.in.offset = 0;
133 6 : io.write.in.remaining = 0;
134 6 : io.write.in.data = buf;
135 6 : status = smb_raw_write(cli->tree, &io);
136 6 : CHECK_STATUS(status, NT_STATUS_OK);
137 6 : CHECK_VALUE(io.write.out.nwritten, 0);
138 :
139 6 : setup_buffer(buf, seed, maxsize);
140 :
141 6 : torture_comment(tctx, "Trying small write\n");
142 6 : io.write.in.count = 9;
143 6 : io.write.in.offset = 4;
144 6 : io.write.in.data = buf;
145 6 : status = smb_raw_write(cli->tree, &io);
146 6 : CHECK_STATUS(status, NT_STATUS_OK);
147 6 : CHECK_VALUE(io.write.out.nwritten, io.write.in.count);
148 :
149 6 : memset(buf, 0, maxsize);
150 6 : if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
151 0 : ret = false;
152 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
153 : }
154 6 : CHECK_BUFFER(buf+4, seed, 9);
155 6 : CHECK_VALUE(IVAL(buf,0), 0);
156 :
157 6 : setup_buffer(buf, seed, maxsize);
158 :
159 6 : torture_comment(tctx, "Trying large write\n");
160 6 : io.write.in.count = 4000;
161 6 : io.write.in.offset = 0;
162 6 : io.write.in.data = buf;
163 6 : status = smb_raw_write(cli->tree, &io);
164 6 : CHECK_STATUS(status, NT_STATUS_OK);
165 6 : CHECK_VALUE(io.write.out.nwritten, 4000);
166 :
167 6 : memset(buf, 0, maxsize);
168 6 : if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
169 0 : ret = false;
170 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
171 : }
172 6 : CHECK_BUFFER(buf, seed, 4000);
173 :
174 6 : torture_comment(tctx, "Trying bad fnum\n");
175 6 : io.write.in.file.fnum = fnum+1;
176 6 : io.write.in.count = 4000;
177 6 : io.write.in.offset = 0;
178 6 : io.write.in.data = buf;
179 6 : status = smb_raw_write(cli->tree, &io);
180 6 : CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
181 :
182 6 : torture_comment(tctx, "Setting file as sparse\n");
183 6 : status = torture_set_sparse(cli->tree, fnum);
184 6 : CHECK_STATUS(status, NT_STATUS_OK);
185 :
186 6 : if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
187 0 : torture_comment(tctx, "skipping large file tests - CAP_LARGE_FILES not set\n");
188 0 : goto done;
189 : }
190 :
191 6 : torture_comment(tctx, "Trying 2^32 offset\n");
192 6 : setup_buffer(buf, seed, maxsize);
193 6 : io.write.in.file.fnum = fnum;
194 6 : io.write.in.count = 4000;
195 6 : io.write.in.offset = 0xFFFFFFFF - 2000;
196 6 : io.write.in.data = buf;
197 6 : status = smb_raw_write(cli->tree, &io);
198 6 : CHECK_STATUS(status, NT_STATUS_OK);
199 6 : CHECK_VALUE(io.write.out.nwritten, 4000);
200 6 : CHECK_ALL_INFO(io.write.in.count + (uint64_t)io.write.in.offset, size);
201 :
202 6 : memset(buf, 0, maxsize);
203 6 : if (smbcli_read(cli->tree, fnum, buf, io.write.in.offset, 4000) != 4000) {
204 0 : ret = false;
205 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
206 : }
207 6 : CHECK_BUFFER(buf, seed, 4000);
208 :
209 6 : done:
210 6 : smbcli_close(cli->tree, fnum);
211 6 : smb_raw_exit(cli->session);
212 6 : smbcli_deltree(cli->tree, BASEDIR);
213 6 : return ret;
214 : }
215 :
216 :
217 : /*
218 : test writex ops
219 : */
220 6 : static bool test_writex(struct torture_context *tctx,
221 : struct smbcli_state *cli)
222 : {
223 1 : union smb_write io;
224 1 : NTSTATUS status;
225 6 : bool ret = true;
226 1 : int fnum, i;
227 1 : uint8_t *buf;
228 6 : const int maxsize = 90000;
229 6 : const char *fname = BASEDIR "\\test.txt";
230 6 : unsigned int seed = time(NULL);
231 1 : union smb_fileinfo finfo;
232 6 : int max_bits=63;
233 :
234 6 : if (!torture_setting_bool(tctx, "dangerous", false)) {
235 6 : max_bits=33;
236 6 : torture_comment(tctx, "dangerous not set - limiting range of test to 2^%d\n", max_bits);
237 : }
238 :
239 6 : buf = talloc_zero_array(tctx, uint8_t, maxsize);
240 :
241 6 : if (!cli->transport->negotiate.lockread_supported) {
242 0 : torture_comment(tctx, "Server does not support writeunlock - skipping\n");
243 0 : return true;
244 : }
245 :
246 6 : if (!torture_setup_dir(cli, BASEDIR)) {
247 0 : torture_fail(tctx, "failed to setup basedir");
248 : }
249 :
250 6 : torture_comment(tctx, "Testing RAW_WRITE_WRITEX\n");
251 6 : io.generic.level = RAW_WRITE_WRITEX;
252 :
253 6 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
254 6 : if (fnum == -1) {
255 0 : ret = false;
256 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)));
257 : }
258 :
259 6 : torture_comment(tctx, "Trying zero write\n");
260 6 : io.writex.in.file.fnum = fnum;
261 6 : io.writex.in.offset = 0;
262 6 : io.writex.in.wmode = 0;
263 6 : io.writex.in.remaining = 0;
264 6 : io.writex.in.count = 0;
265 6 : io.writex.in.data = buf;
266 6 : status = smb_raw_write(cli->tree, &io);
267 6 : CHECK_STATUS(status, NT_STATUS_OK);
268 6 : CHECK_VALUE(io.writex.out.nwritten, 0);
269 :
270 6 : setup_buffer(buf, seed, maxsize);
271 :
272 6 : torture_comment(tctx, "Trying small write\n");
273 6 : io.writex.in.count = 9;
274 6 : io.writex.in.offset = 4;
275 6 : io.writex.in.data = buf;
276 6 : status = smb_raw_write(cli->tree, &io);
277 6 : CHECK_STATUS(status, NT_STATUS_OK);
278 6 : CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
279 :
280 6 : memset(buf, 0, maxsize);
281 6 : if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
282 0 : ret = false;
283 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
284 : }
285 6 : CHECK_BUFFER(buf+4, seed, 9);
286 6 : CHECK_VALUE(IVAL(buf,0), 0);
287 :
288 6 : setup_buffer(buf, seed, maxsize);
289 :
290 6 : torture_comment(tctx, "Trying large write\n");
291 6 : io.writex.in.count = 4000;
292 6 : io.writex.in.offset = 0;
293 6 : io.writex.in.data = buf;
294 6 : status = smb_raw_write(cli->tree, &io);
295 6 : CHECK_STATUS(status, NT_STATUS_OK);
296 6 : CHECK_VALUE(io.writex.out.nwritten, 4000);
297 :
298 6 : memset(buf, 0, maxsize);
299 6 : if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
300 0 : ret = false;
301 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
302 : }
303 6 : CHECK_BUFFER(buf, seed, 4000);
304 :
305 6 : torture_comment(tctx, "Trying bad fnum\n");
306 6 : io.writex.in.file.fnum = fnum+1;
307 6 : io.writex.in.count = 4000;
308 6 : io.writex.in.offset = 0;
309 6 : io.writex.in.data = buf;
310 6 : status = smb_raw_write(cli->tree, &io);
311 6 : CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
312 :
313 6 : torture_comment(tctx, "Testing wmode\n");
314 6 : io.writex.in.file.fnum = fnum;
315 6 : io.writex.in.count = 1;
316 6 : io.writex.in.offset = 0;
317 6 : io.writex.in.wmode = 1;
318 6 : io.writex.in.data = buf;
319 6 : status = smb_raw_write(cli->tree, &io);
320 6 : CHECK_STATUS(status, NT_STATUS_OK);
321 6 : CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
322 :
323 6 : io.writex.in.wmode = 2;
324 6 : status = smb_raw_write(cli->tree, &io);
325 6 : CHECK_STATUS(status, NT_STATUS_OK);
326 6 : CHECK_VALUE(io.writex.out.nwritten, io.writex.in.count);
327 :
328 :
329 6 : torture_comment(tctx, "Trying locked region\n");
330 6 : cli->session->pid++;
331 6 : if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 3, 1, 0, WRITE_LOCK))) {
332 0 : ret = false;
333 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "Failed to lock file at %s\n", __location__));
334 : }
335 6 : cli->session->pid--;
336 6 : io.writex.in.wmode = 0;
337 6 : io.writex.in.count = 4;
338 6 : io.writex.in.offset = 0;
339 6 : status = smb_raw_write(cli->tree, &io);
340 6 : CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
341 :
342 6 : torture_comment(tctx, "Setting file as sparse\n");
343 6 : status = torture_set_sparse(cli->tree, fnum);
344 6 : CHECK_STATUS(status, NT_STATUS_OK);
345 :
346 6 : if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
347 0 : torture_skip(tctx, "skipping large file tests - CAP_LARGE_FILES not set\n");
348 : }
349 :
350 6 : torture_comment(tctx, "Trying 2^32 offset\n");
351 6 : setup_buffer(buf, seed, maxsize);
352 6 : io.writex.in.file.fnum = fnum;
353 6 : io.writex.in.count = 4000;
354 6 : io.writex.in.offset = 0xFFFFFFFF - 2000;
355 6 : io.writex.in.data = buf;
356 6 : status = smb_raw_write(cli->tree, &io);
357 6 : CHECK_STATUS(status, NT_STATUS_OK);
358 6 : CHECK_VALUE(io.writex.out.nwritten, 4000);
359 6 : CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
360 :
361 6 : memset(buf, 0, maxsize);
362 6 : if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
363 0 : ret = false;
364 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
365 : }
366 6 : CHECK_BUFFER(buf, seed, 4000);
367 :
368 6 : for (i=33;i<max_bits;i++) {
369 0 : torture_comment(tctx, "Trying 2^%d offset\n", i);
370 0 : setup_buffer(buf, seed+1, maxsize);
371 0 : io.writex.in.file.fnum = fnum;
372 0 : io.writex.in.count = 4000;
373 0 : io.writex.in.offset = ((uint64_t)1) << i;
374 0 : io.writex.in.data = buf;
375 0 : status = smb_raw_write(cli->tree, &io);
376 0 : if (i>33 &&
377 0 : NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
378 0 : break;
379 : }
380 0 : CHECK_STATUS(status, NT_STATUS_OK);
381 0 : CHECK_VALUE(io.writex.out.nwritten, 4000);
382 0 : CHECK_ALL_INFO(io.writex.in.count + (uint64_t)io.writex.in.offset, size);
383 :
384 0 : memset(buf, 0, maxsize);
385 0 : if (smbcli_read(cli->tree, fnum, buf, io.writex.in.offset, 4000) != 4000) {
386 0 : ret = false;
387 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
388 : }
389 0 : CHECK_BUFFER(buf, seed+1, 4000);
390 : }
391 6 : torture_comment(tctx, "limit is 2^%d\n", i);
392 :
393 6 : setup_buffer(buf, seed, maxsize);
394 :
395 6 : done:
396 6 : smbcli_close(cli->tree, fnum);
397 6 : smb_raw_exit(cli->session);
398 6 : smbcli_deltree(cli->tree, BASEDIR);
399 6 : return ret;
400 : }
401 :
402 :
403 : /*
404 : test write unlock ops
405 : */
406 6 : static bool test_writeunlock(struct torture_context *tctx,
407 : struct smbcli_state *cli)
408 : {
409 1 : union smb_write io;
410 1 : NTSTATUS status;
411 6 : bool ret = true;
412 1 : int fnum;
413 1 : uint8_t *buf;
414 6 : const int maxsize = 90000;
415 6 : const char *fname = BASEDIR "\\test.txt";
416 6 : unsigned int seed = time(NULL);
417 1 : union smb_fileinfo finfo;
418 :
419 6 : buf = talloc_zero_array(tctx, uint8_t, maxsize);
420 :
421 6 : if (!cli->transport->negotiate.lockread_supported) {
422 0 : torture_skip(tctx, "Server does not support writeunlock - skipping\n");
423 : }
424 :
425 6 : if (!torture_setup_dir(cli, BASEDIR)) {
426 0 : torture_fail(tctx, "failed to setup basedir");
427 : }
428 :
429 6 : torture_comment(tctx, "Testing RAW_WRITE_WRITEUNLOCK\n");
430 6 : io.generic.level = RAW_WRITE_WRITEUNLOCK;
431 :
432 6 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
433 6 : if (fnum == -1) {
434 0 : ret = false;
435 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)));
436 : }
437 :
438 6 : torture_comment(tctx, "Trying zero write\n");
439 6 : io.writeunlock.in.file.fnum = fnum;
440 6 : io.writeunlock.in.count = 0;
441 6 : io.writeunlock.in.offset = 0;
442 6 : io.writeunlock.in.remaining = 0;
443 6 : io.writeunlock.in.data = buf;
444 6 : status = smb_raw_write(cli->tree, &io);
445 6 : CHECK_STATUS(status, NT_STATUS_OK);
446 6 : CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
447 :
448 6 : setup_buffer(buf, seed, maxsize);
449 :
450 6 : torture_comment(tctx, "Trying small write\n");
451 6 : io.writeunlock.in.count = 9;
452 6 : io.writeunlock.in.offset = 4;
453 6 : io.writeunlock.in.data = buf;
454 6 : status = smb_raw_write(cli->tree, &io);
455 6 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
456 6 : if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
457 0 : ret = false;
458 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
459 : }
460 6 : CHECK_BUFFER(buf+4, seed, 9);
461 6 : CHECK_VALUE(IVAL(buf,0), 0);
462 :
463 6 : setup_buffer(buf, seed, maxsize);
464 6 : smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
465 : 0, WRITE_LOCK);
466 6 : status = smb_raw_write(cli->tree, &io);
467 6 : CHECK_STATUS(status, NT_STATUS_OK);
468 6 : CHECK_VALUE(io.writeunlock.out.nwritten, io.writeunlock.in.count);
469 :
470 6 : memset(buf, 0, maxsize);
471 6 : if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
472 0 : ret = false;
473 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
474 : }
475 6 : CHECK_BUFFER(buf+4, seed, 9);
476 6 : CHECK_VALUE(IVAL(buf,0), 0);
477 :
478 6 : setup_buffer(buf, seed, maxsize);
479 :
480 6 : torture_comment(tctx, "Trying large write\n");
481 6 : io.writeunlock.in.count = 4000;
482 6 : io.writeunlock.in.offset = 0;
483 6 : io.writeunlock.in.data = buf;
484 6 : smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
485 : 0, WRITE_LOCK);
486 6 : status = smb_raw_write(cli->tree, &io);
487 6 : CHECK_STATUS(status, NT_STATUS_OK);
488 6 : CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
489 :
490 6 : status = smb_raw_write(cli->tree, &io);
491 6 : CHECK_STATUS(status, NT_STATUS_RANGE_NOT_LOCKED);
492 :
493 6 : memset(buf, 0, maxsize);
494 6 : if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
495 0 : ret = false;
496 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
497 : }
498 6 : CHECK_BUFFER(buf, seed, 4000);
499 :
500 6 : torture_comment(tctx, "Trying bad fnum\n");
501 6 : io.writeunlock.in.file.fnum = fnum+1;
502 6 : io.writeunlock.in.count = 4000;
503 6 : io.writeunlock.in.offset = 0;
504 6 : io.writeunlock.in.data = buf;
505 6 : status = smb_raw_write(cli->tree, &io);
506 6 : CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
507 :
508 6 : torture_comment(tctx, "Setting file as sparse\n");
509 6 : status = torture_set_sparse(cli->tree, fnum);
510 6 : CHECK_STATUS(status, NT_STATUS_OK);
511 :
512 6 : if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
513 0 : torture_skip(tctx, "skipping large file tests - CAP_LARGE_FILES not set\n");
514 : }
515 :
516 6 : torture_comment(tctx, "Trying 2^32 offset\n");
517 6 : setup_buffer(buf, seed, maxsize);
518 6 : io.writeunlock.in.file.fnum = fnum;
519 6 : io.writeunlock.in.count = 4000;
520 6 : io.writeunlock.in.offset = 0xFFFFFFFF - 2000;
521 6 : io.writeunlock.in.data = buf;
522 6 : smbcli_lock(cli->tree, fnum, io.writeunlock.in.offset, io.writeunlock.in.count,
523 : 0, WRITE_LOCK);
524 6 : status = smb_raw_write(cli->tree, &io);
525 6 : CHECK_STATUS(status, NT_STATUS_OK);
526 6 : CHECK_VALUE(io.writeunlock.out.nwritten, 4000);
527 6 : CHECK_ALL_INFO(io.writeunlock.in.count + (uint64_t)io.writeunlock.in.offset, size);
528 :
529 6 : memset(buf, 0, maxsize);
530 6 : if (smbcli_read(cli->tree, fnum, buf, io.writeunlock.in.offset, 4000) != 4000) {
531 0 : ret = false;
532 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
533 : }
534 6 : CHECK_BUFFER(buf, seed, 4000);
535 :
536 6 : done:
537 6 : smbcli_close(cli->tree, fnum);
538 6 : smb_raw_exit(cli->session);
539 6 : smbcli_deltree(cli->tree, BASEDIR);
540 6 : return ret;
541 : }
542 :
543 :
544 : /*
545 : test write close ops
546 : */
547 6 : static bool test_writeclose(struct torture_context *tctx,
548 : struct smbcli_state *cli)
549 : {
550 1 : union smb_write io;
551 1 : NTSTATUS status;
552 6 : bool ret = true;
553 1 : int fnum;
554 1 : uint8_t *buf;
555 6 : const int maxsize = 90000;
556 6 : const char *fname = BASEDIR "\\test.txt";
557 6 : unsigned int seed = time(NULL);
558 1 : union smb_fileinfo finfo;
559 :
560 6 : buf = talloc_zero_array(tctx, uint8_t, maxsize);
561 :
562 6 : if (!torture_setting_bool(tctx, "writeclose_support", true)) {
563 0 : torture_skip(tctx, "Server does not support writeclose - skipping\n");
564 : }
565 :
566 6 : if (!torture_setup_dir(cli, BASEDIR)) {
567 0 : torture_fail(tctx, "failed to setup basedir");
568 : }
569 :
570 6 : torture_comment(tctx, "Testing RAW_WRITE_WRITECLOSE\n");
571 6 : io.generic.level = RAW_WRITE_WRITECLOSE;
572 :
573 6 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
574 6 : if (fnum == -1) {
575 0 : ret = false;
576 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree)));
577 : }
578 :
579 6 : torture_comment(tctx, "Trying zero write\n");
580 6 : io.writeclose.in.file.fnum = fnum;
581 6 : io.writeclose.in.count = 0;
582 6 : io.writeclose.in.offset = 0;
583 6 : io.writeclose.in.mtime = 0;
584 6 : io.writeclose.in.data = buf;
585 6 : status = smb_raw_write(cli->tree, &io);
586 6 : CHECK_STATUS(status, NT_STATUS_OK);
587 6 : CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
588 :
589 6 : status = smb_raw_write(cli->tree, &io);
590 6 : CHECK_STATUS(status, NT_STATUS_OK);
591 6 : CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
592 :
593 6 : setup_buffer(buf, seed, maxsize);
594 :
595 6 : torture_comment(tctx, "Trying small write\n");
596 6 : io.writeclose.in.count = 9;
597 6 : io.writeclose.in.offset = 4;
598 6 : io.writeclose.in.data = buf;
599 6 : status = smb_raw_write(cli->tree, &io);
600 6 : CHECK_STATUS(status, NT_STATUS_OK);
601 :
602 6 : status = smb_raw_write(cli->tree, &io);
603 6 : CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
604 :
605 6 : fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
606 6 : io.writeclose.in.file.fnum = fnum;
607 :
608 6 : if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
609 0 : ret = false;
610 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
611 : }
612 6 : CHECK_BUFFER(buf+4, seed, 9);
613 6 : CHECK_VALUE(IVAL(buf,0), 0);
614 :
615 6 : setup_buffer(buf, seed, maxsize);
616 6 : status = smb_raw_write(cli->tree, &io);
617 6 : CHECK_STATUS(status, NT_STATUS_OK);
618 6 : CHECK_VALUE(io.writeclose.out.nwritten, io.writeclose.in.count);
619 :
620 6 : fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
621 6 : io.writeclose.in.file.fnum = fnum;
622 :
623 6 : memset(buf, 0, maxsize);
624 6 : if (smbcli_read(cli->tree, fnum, buf, 0, 13) != 13) {
625 0 : ret = false;
626 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
627 : }
628 6 : CHECK_BUFFER(buf+4, seed, 9);
629 6 : CHECK_VALUE(IVAL(buf,0), 0);
630 :
631 6 : setup_buffer(buf, seed, maxsize);
632 :
633 6 : torture_comment(tctx, "Trying large write\n");
634 6 : io.writeclose.in.count = 4000;
635 6 : io.writeclose.in.offset = 0;
636 6 : io.writeclose.in.data = buf;
637 6 : status = smb_raw_write(cli->tree, &io);
638 6 : CHECK_STATUS(status, NT_STATUS_OK);
639 6 : CHECK_VALUE(io.writeclose.out.nwritten, 4000);
640 :
641 6 : status = smb_raw_write(cli->tree, &io);
642 6 : CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
643 :
644 6 : fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
645 6 : io.writeclose.in.file.fnum = fnum;
646 :
647 6 : memset(buf, 0, maxsize);
648 6 : if (smbcli_read(cli->tree, fnum, buf, 0, 4000) != 4000) {
649 0 : ret = false;
650 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
651 : }
652 6 : CHECK_BUFFER(buf, seed, 4000);
653 :
654 6 : torture_comment(tctx, "Trying bad fnum\n");
655 6 : io.writeclose.in.file.fnum = fnum+1;
656 6 : io.writeclose.in.count = 4000;
657 6 : io.writeclose.in.offset = 0;
658 6 : io.writeclose.in.data = buf;
659 6 : status = smb_raw_write(cli->tree, &io);
660 6 : CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
661 :
662 6 : torture_comment(tctx, "Setting file as sparse\n");
663 6 : status = torture_set_sparse(cli->tree, fnum);
664 6 : CHECK_STATUS(status, NT_STATUS_OK);
665 :
666 6 : if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
667 0 : torture_skip(tctx, "skipping large file tests - CAP_LARGE_FILES not set\n");
668 : }
669 :
670 6 : torture_comment(tctx, "Trying 2^32 offset\n");
671 6 : setup_buffer(buf, seed, maxsize);
672 6 : io.writeclose.in.file.fnum = fnum;
673 6 : io.writeclose.in.count = 4000;
674 6 : io.writeclose.in.offset = 0xFFFFFFFF - 2000;
675 6 : io.writeclose.in.data = buf;
676 6 : status = smb_raw_write(cli->tree, &io);
677 6 : CHECK_STATUS(status, NT_STATUS_OK);
678 6 : CHECK_VALUE(io.writeclose.out.nwritten, 4000);
679 6 : CHECK_ALL_INFO(io.writeclose.in.count + (uint64_t)io.writeclose.in.offset, size);
680 :
681 6 : fnum = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
682 6 : io.writeclose.in.file.fnum = fnum;
683 :
684 6 : memset(buf, 0, maxsize);
685 6 : if (smbcli_read(cli->tree, fnum, buf, io.writeclose.in.offset, 4000) != 4000) {
686 0 : ret = false;
687 0 : torture_fail_goto(tctx, done, talloc_asprintf(tctx, "read failed at %s\n", __location__));
688 : }
689 6 : CHECK_BUFFER(buf, seed, 4000);
690 :
691 6 : done:
692 6 : smbcli_close(cli->tree, fnum);
693 6 : smb_raw_exit(cli->session);
694 6 : smbcli_deltree(cli->tree, BASEDIR);
695 6 : return ret;
696 : }
697 :
698 : /*
699 : test a deliberately bad SMB1 write.
700 : */
701 6 : static bool test_bad_write(struct torture_context *tctx,
702 : struct smbcli_state *cli)
703 : {
704 6 : bool ret = false;
705 6 : int fnum = -1;
706 6 : struct smbcli_request *req = NULL;
707 6 : const char *fname = BASEDIR "\\badwrite.txt";
708 6 : bool ok = false;
709 :
710 6 : if (!torture_setup_dir(cli, BASEDIR)) {
711 0 : torture_fail(tctx, "failed to setup basedir");
712 : }
713 :
714 6 : torture_comment(tctx, "Testing RAW_BAD_WRITE\n");
715 :
716 6 : fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
717 6 : if (fnum == -1) {
718 0 : torture_fail_goto(tctx,
719 : done,
720 : talloc_asprintf(tctx,
721 : "Failed to create %s - %s\n",
722 : fname,
723 : smbcli_errstr(cli->tree)));
724 : }
725 :
726 6 : req = smbcli_request_setup(cli->tree,
727 : SMBwrite,
728 : 5,
729 : 0);
730 6 : if (req == NULL) {
731 0 : torture_fail_goto(tctx,
732 : done,
733 : talloc_asprintf(tctx, "talloc fail\n"));
734 : }
735 :
736 6 : SSVAL(req->out.vwv, VWV(0), fnum);
737 6 : SSVAL(req->out.vwv, VWV(1), 65535); /* bad write length. */
738 6 : SIVAL(req->out.vwv, VWV(2), 0); /* offset */
739 6 : SSVAL(req->out.vwv, VWV(4), 0); /* remaining. */
740 :
741 6 : if (!smbcli_request_send(req)) {
742 0 : torture_fail_goto(tctx,
743 : done,
744 : talloc_asprintf(tctx, "Send failed\n"));
745 : }
746 :
747 6 : if (!smbcli_request_receive(req)) {
748 0 : torture_fail_goto(tctx,
749 : done,
750 : talloc_asprintf(tctx, "Receive failed\n"));
751 : }
752 :
753 : /*
754 : * Check for expected error codes.
755 : * ntvfs returns NT_STATUS_UNSUCCESSFUL.
756 : */
757 7 : ok = (NT_STATUS_EQUAL(req->status, NT_STATUS_INVALID_PARAMETER) ||
758 1 : NT_STATUS_EQUAL(req->status, NT_STATUS_UNSUCCESSFUL));
759 :
760 6 : if (!ok) {
761 0 : torture_fail_goto(tctx,
762 : done,
763 : talloc_asprintf(tctx,
764 : "Should have returned "
765 : "NT_STATUS_INVALID_PARAMETER or "
766 : "NT_STATUS_UNSUCCESSFUL "
767 : "got %s\n",
768 : nt_errstr(req->status)));
769 : }
770 :
771 5 : ret = true;
772 :
773 6 : done:
774 6 : if (req != NULL) {
775 6 : smbcli_request_destroy(req);
776 : }
777 6 : if (fnum != -1) {
778 6 : smbcli_close(cli->tree, fnum);
779 : }
780 6 : smb_raw_exit(cli->session);
781 6 : smbcli_deltree(cli->tree, BASEDIR);
782 6 : return ret;
783 : }
784 :
785 : /*
786 : basic testing of write calls
787 : */
788 2354 : struct torture_suite *torture_raw_write(TALLOC_CTX *mem_ctx)
789 : {
790 2354 : struct torture_suite *suite = torture_suite_create(mem_ctx, "write");
791 :
792 2354 : torture_suite_add_1smb_test(suite, "write", test_write);
793 2354 : torture_suite_add_1smb_test(suite, "write unlock", test_writeunlock);
794 2354 : torture_suite_add_1smb_test(suite, "write close", test_writeclose);
795 2354 : torture_suite_add_1smb_test(suite, "writex", test_writex);
796 2354 : torture_suite_add_1smb_test(suite, "bad-write", test_bad_write);
797 :
798 2354 : return suite;
799 : }
|