s3: smbd: Fix schedule_smb2_aio_read() to allow the last read in a compound to go...
[Samba.git] / source4 / torture / smb2 / read_write.c
blob707a49b6b1c4e2ae65d6de9040cc321251e28a3c
1 /*
2 Unix SMB/CIFS implementation.
3 SMB read/write torture tester
4 Copyright (C) Andrew Tridgell 1997-2003
5 Copyright (C) Jelmer Vernooij 2006
6 Copyright (C) David Mulder 2019
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "torture/smbtorture.h"
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
25 #include "torture/torture.h"
26 #include "torture/util.h"
27 #include "torture/smb2/proto.h"
29 #define CHECK_STATUS(_status, _expected) \
30 torture_assert_ntstatus_equal_goto(torture, _status, _expected, \
31 ret, done, "Incorrect status")
33 #define CHECK_VALUE(v, correct) \
34 torture_assert_int_equal_goto(torture, v, correct, \
35 ret, done, "Incorrect value")
37 #define FNAME "smb2_writetest.dat"
39 static bool run_smb2_readwritetest(struct torture_context *tctx,
40 struct smb2_tree *t1, struct smb2_tree *t2)
42 const char *lockfname = "torture2.lck";
43 struct smb2_create f1 = {0};
44 struct smb2_create f2 = {0};
45 struct smb2_handle h1 = {{0}};
46 struct smb2_handle h2 = {{0}};
47 int i;
48 uint8_t buf[131072];
49 bool correct = true;
50 NTSTATUS status;
51 int ret = 0;
53 ret = smb2_deltree(t1, lockfname);
54 torture_assert(tctx, ret != -1, "unlink failed");
56 f1.in.desired_access = SEC_FILE_ALL;
57 f1.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
58 NTCREATEX_SHARE_ACCESS_WRITE;
59 f1.in.create_disposition = FILE_CREATE;
60 f1.in.fname = lockfname;
62 status = smb2_create(t1, tctx, &f1);
63 torture_assert_ntstatus_ok_goto(tctx, status, correct, done,
64 talloc_asprintf(tctx, "first open read/write of %s failed (%s)",
65 lockfname, nt_errstr(status)));
66 h1 = f1.out.file.handle;
68 f2.in.desired_access = SEC_FILE_READ_DATA;
69 f2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
70 NTCREATEX_SHARE_ACCESS_WRITE;
71 f2.in.create_disposition = FILE_OPEN;
72 f2.in.fname = lockfname;
74 status = smb2_create(t2, tctx, &f2);
75 torture_assert_ntstatus_ok_goto(tctx, status, correct, done,
76 talloc_asprintf(tctx, "second open read-only of %s failed (%s)",
77 lockfname, nt_errstr(status)));
78 h2 = f2.out.file.handle;
80 torture_comment(tctx, "Checking data integrity over %d ops\n",
81 torture_numops);
83 for (i = 0; i < torture_numops; i++) {
84 struct smb2_write w = {0};
85 struct smb2_read r = {0};
86 size_t buf_size = ((unsigned int)random()%(sizeof(buf)-1))+ 1;
88 if (i % 10 == 0) {
89 if (torture_setting_bool(tctx, "progress", true)) {
90 torture_comment(tctx, "%d\r", i); fflush(stdout);
94 generate_random_buffer(buf, buf_size);
96 w.in.file.handle = h1;
97 w.in.offset = 0;
98 w.in.data.data = buf;
99 w.in.data.length = buf_size;
101 status = smb2_write(t1, &w);
102 if (!NT_STATUS_IS_OK(status) || w.out.nwritten != buf_size) {
103 torture_comment(tctx, "write failed (%s)\n",
104 nt_errstr(status));
105 torture_result(tctx, TORTURE_FAIL,
106 "wrote %d, expected %d\n",
107 (int)w.out.nwritten, (int)buf_size);
108 correct = false;
109 goto done;
112 r.in.file.handle = h2;
113 r.in.offset = 0;
114 r.in.length = buf_size;
115 status = smb2_read(t2, tctx, &r);
116 if (!NT_STATUS_IS_OK(status) || r.out.data.length != buf_size) {
117 torture_comment(tctx, "read failed (%s)\n",
118 nt_errstr(status));
119 torture_result(tctx, TORTURE_FAIL,
120 "read %d, expected %d\n",
121 (int)r.out.data.length, (int)buf_size);
122 correct = false;
123 goto done;
126 torture_assert_mem_equal_goto(tctx, r.out.data.data, buf,
127 buf_size, correct, done, "read/write compare failed\n");
130 status = smb2_util_close(t2, h2);
131 torture_assert_ntstatus_ok_goto(tctx, status, correct, done,
132 talloc_asprintf(tctx, "close failed (%s)", nt_errstr(status)));
133 ZERO_STRUCT(h2);
135 status = smb2_util_close(t1, h1);
136 torture_assert_ntstatus_ok_goto(tctx, status, correct, done,
137 talloc_asprintf(tctx, "close failed (%s)", nt_errstr(status)));
138 ZERO_STRUCT(h1);
140 done:
141 if (!smb2_util_handle_empty(h2)) {
142 smb2_util_close(t2, h2);
144 if (!smb2_util_handle_empty(h1)) {
145 smb2_util_close(t1, h1);
148 status = smb2_util_unlink(t1, lockfname);
149 if (!NT_STATUS_IS_OK(status)) {
150 torture_comment(tctx, "unlink failed (%s)", nt_errstr(status));
153 return correct;
157 static bool run_smb2_wrap_readwritetest(struct torture_context *tctx,
158 struct smb2_tree *tree1,
159 struct smb2_tree *tree2)
161 return run_smb2_readwritetest(tctx, tree1, tree1);
164 static bool test_rw_invalid(struct torture_context *torture, struct smb2_tree *tree)
166 bool ret = true;
167 NTSTATUS status;
168 struct smb2_handle h;
169 uint8_t buf[64*1024];
170 struct smb2_read rd;
171 struct smb2_write w = {0};
172 union smb_setfileinfo sfinfo;
173 TALLOC_CTX *tmp_ctx = talloc_new(tree);
175 ZERO_STRUCT(buf);
177 smb2_util_unlink(tree, FNAME);
179 status = torture_smb2_testfile(tree, FNAME, &h);
180 CHECK_STATUS(status, NT_STATUS_OK);
182 /* set delete-on-close */
183 ZERO_STRUCT(sfinfo);
184 sfinfo.generic.level = RAW_SFILEINFO_DISPOSITION_INFORMATION;
185 sfinfo.disposition_info.in.delete_on_close = 1;
186 sfinfo.generic.in.file.handle = h;
187 status = smb2_setinfo_file(tree, &sfinfo);
188 CHECK_STATUS(status, NT_STATUS_OK);
190 status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
191 CHECK_STATUS(status, NT_STATUS_OK);
193 ZERO_STRUCT(rd);
194 rd.in.file.handle = h;
195 rd.in.length = 10;
196 rd.in.offset = 0;
197 rd.in.min_count = 1;
199 status = smb2_read(tree, tmp_ctx, &rd);
200 CHECK_STATUS(status, NT_STATUS_OK);
201 CHECK_VALUE(rd.out.data.length, 10);
203 rd.in.min_count = 0;
204 rd.in.length = 10;
205 rd.in.offset = sizeof(buf);
206 status = smb2_read(tree, tmp_ctx, &rd);
207 CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
209 rd.in.min_count = 0;
210 rd.in.length = 0;
211 rd.in.offset = sizeof(buf);
212 status = smb2_read(tree, tmp_ctx, &rd);
213 CHECK_STATUS(status, NT_STATUS_OK);
214 CHECK_VALUE(rd.out.data.length, 0);
216 rd.in.min_count = 0;
217 rd.in.length = 1;
218 rd.in.offset = INT64_MAX - 1;
219 status = smb2_read(tree, tmp_ctx, &rd);
220 CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
222 rd.in.min_count = 0;
223 rd.in.length = 0;
224 rd.in.offset = INT64_MAX;
225 status = smb2_read(tree, tmp_ctx, &rd);
226 CHECK_STATUS(status, NT_STATUS_OK);
227 CHECK_VALUE(rd.out.data.length, 0);
229 rd.in.min_count = 0;
230 rd.in.length = 1;
231 rd.in.offset = INT64_MAX;
232 status = smb2_read(tree, tmp_ctx, &rd);
233 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
235 rd.in.min_count = 0;
236 rd.in.length = 0;
237 rd.in.offset = (uint64_t)INT64_MAX + 1;
238 status = smb2_read(tree, tmp_ctx, &rd);
239 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
241 rd.in.min_count = 0;
242 rd.in.length = 0;
243 rd.in.offset = (uint64_t)INT64_MIN;
244 status = smb2_read(tree, tmp_ctx, &rd);
245 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
247 rd.in.min_count = 0;
248 rd.in.length = 0;
249 rd.in.offset = (uint64_t)(int64_t)-1;
250 status = smb2_read(tree, tmp_ctx, &rd);
251 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
253 rd.in.min_count = 0;
254 rd.in.length = 0;
255 rd.in.offset = (uint64_t)(int64_t)-2;
256 status = smb2_read(tree, tmp_ctx, &rd);
257 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
259 rd.in.min_count = 0;
260 rd.in.length = 0;
261 rd.in.offset = (uint64_t)(int64_t)-3;
262 status = smb2_read(tree, tmp_ctx, &rd);
263 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
265 w.in.file.handle = h;
266 w.in.offset = (int64_t)-1;
267 w.in.data.data = buf;
268 w.in.data.length = ARRAY_SIZE(buf);
270 status = smb2_write(tree, &w);
271 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
273 w.in.file.handle = h;
274 w.in.offset = (int64_t)-2;
275 w.in.data.data = buf;
276 w.in.data.length = ARRAY_SIZE(buf);
278 status = smb2_write(tree, &w);
279 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
281 w.in.file.handle = h;
282 w.in.offset = INT64_MIN;
283 w.in.data.data = buf;
284 w.in.data.length = 1;
286 status = smb2_write(tree, &w);
287 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
289 w.in.file.handle = h;
290 w.in.offset = INT64_MIN;
291 w.in.data.data = buf;
292 w.in.data.length = 0;
293 status = smb2_write(tree, &w);
294 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
296 w.in.file.handle = h;
297 w.in.offset = INT64_MAX;
298 w.in.data.data = buf;
299 w.in.data.length = 0;
300 status = smb2_write(tree, &w);
301 CHECK_STATUS(status, NT_STATUS_OK);
302 CHECK_VALUE(w.out.nwritten, 0);
304 w.in.file.handle = h;
305 w.in.offset = INT64_MAX;
306 w.in.data.data = buf;
307 w.in.data.length = 1;
308 status = smb2_write(tree, &w);
309 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
311 w.in.file.handle = h;
312 w.in.offset = (uint64_t)INT64_MAX + 1;
313 w.in.data.data = buf;
314 w.in.data.length = 0;
315 status = smb2_write(tree, &w);
316 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
318 w.in.file.handle = h;
319 w.in.offset = 0xfffffff0000; /* MAXFILESIZE */
320 w.in.data.data = buf;
321 w.in.data.length = 1;
322 status = smb2_write(tree, &w);
323 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
325 w.in.file.handle = h;
326 w.in.offset = 0xfffffff0000 - 1; /* MAXFILESIZE - 1 */
327 w.in.data.data = buf;
328 w.in.data.length = 1;
329 status = smb2_write(tree, &w);
330 if (TARGET_IS_SAMBA3(torture) || TARGET_IS_SAMBA4(torture)) {
331 CHECK_STATUS(status, NT_STATUS_OK);
332 CHECK_VALUE(w.out.nwritten, 1);
333 } else {
334 CHECK_STATUS(status, NT_STATUS_DISK_FULL);
337 w.in.file.handle = h;
338 w.in.offset = 0xfffffff0000; /* MAXFILESIZE */
339 w.in.data.data = buf;
340 w.in.data.length = 0;
341 status = smb2_write(tree, &w);
342 CHECK_STATUS(status, NT_STATUS_OK);
343 CHECK_VALUE(w.out.nwritten, 0);
345 done:
346 talloc_free(tmp_ctx);
347 return ret;
350 struct torture_suite *torture_smb2_readwrite_init(TALLOC_CTX *ctx)
352 struct torture_suite *suite = torture_suite_create(ctx, "rw");
354 torture_suite_add_2smb2_test(suite, "rw1", run_smb2_readwritetest);
355 torture_suite_add_2smb2_test(suite, "rw2", run_smb2_wrap_readwritetest);
356 torture_suite_add_1smb2_test(suite, "invalid", test_rw_invalid);
358 suite->description = talloc_strdup(suite, "SMB2 Samba4 Read/Write");
360 return suite;