s4:torture/smb2/read: add test for cancelling SMB aio
[nivanova/samba-autobuild/.git] / source4 / torture / smb2 / read.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    SMB2 read test suite
5
6    Copyright (C) Andrew Tridgell 2008
7    
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.
12    
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.
17    
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/>.
20 */
21
22 #include "includes.h"
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
25 #include <tevent.h>
26
27 #include "torture/torture.h"
28 #include "torture/smb2/proto.h"
29
30
31 #define CHECK_STATUS(_status, _expected) \
32         torture_assert_ntstatus_equal_goto(torture, _status, _expected, \
33                  ret, done, "Incorrect status")
34
35 #define CHECK_VALUE(v, correct) \
36         torture_assert_int_equal_goto(torture, v, correct, \
37                  ret, done, "Incorrect value")
38
39 #define FNAME "smb2_readtest.dat"
40 #define DNAME "smb2_readtest.dir"
41
42 static bool test_read_eof(struct torture_context *torture, struct smb2_tree *tree)
43 {
44         bool ret = true;
45         NTSTATUS status;
46         struct smb2_handle h;
47         uint8_t buf[64*1024];
48         struct smb2_read rd;
49         TALLOC_CTX *tmp_ctx = talloc_new(tree);
50
51         ZERO_STRUCT(buf);
52
53         smb2_util_unlink(tree, FNAME);
54
55         status = torture_smb2_testfile(tree, FNAME, &h);
56         CHECK_STATUS(status, NT_STATUS_OK);
57
58         ZERO_STRUCT(rd);
59         rd.in.file.handle = h;
60         rd.in.length      = 5;
61         rd.in.offset      = 0;
62         status = smb2_read(tree, tree, &rd);
63         CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
64
65         status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
66         CHECK_STATUS(status, NT_STATUS_OK);
67
68         ZERO_STRUCT(rd);
69         rd.in.file.handle = h;
70         rd.in.length = 10;
71         rd.in.offset = 0;
72         rd.in.min_count = 1;
73
74         status = smb2_read(tree, tmp_ctx, &rd);
75         CHECK_STATUS(status, NT_STATUS_OK);
76         CHECK_VALUE(rd.out.data.length, 10);
77
78         rd.in.min_count = 0;
79         rd.in.length = 10;
80         rd.in.offset = sizeof(buf);
81         status = smb2_read(tree, tmp_ctx, &rd);
82         CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
83
84         rd.in.min_count = 0;
85         rd.in.length = 0;
86         rd.in.offset = sizeof(buf);
87         status = smb2_read(tree, tmp_ctx, &rd);
88         CHECK_STATUS(status, NT_STATUS_OK);
89         CHECK_VALUE(rd.out.data.length, 0);
90
91         rd.in.min_count = 1;
92         rd.in.length = 0;
93         rd.in.offset = sizeof(buf);
94         status = smb2_read(tree, tmp_ctx, &rd);
95         CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
96
97         rd.in.min_count = 0;
98         rd.in.length = 2;
99         rd.in.offset = sizeof(buf) - 1;
100         status = smb2_read(tree, tmp_ctx, &rd);
101         CHECK_STATUS(status, NT_STATUS_OK);
102         CHECK_VALUE(rd.out.data.length, 1);
103
104         rd.in.min_count = 2;
105         rd.in.length = 1;
106         rd.in.offset = sizeof(buf) - 1;
107         status = smb2_read(tree, tmp_ctx, &rd);
108         CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
109
110         rd.in.min_count = 0x10000;
111         rd.in.length = 1;
112         rd.in.offset = 0;
113         status = smb2_read(tree, tmp_ctx, &rd);
114         CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
115
116         rd.in.min_count = 0x10000 - 2;
117         rd.in.length = 1;
118         rd.in.offset = 0;
119         status = smb2_read(tree, tmp_ctx, &rd);
120         CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
121
122         rd.in.min_count = 10;
123         rd.in.length = 5;
124         rd.in.offset = 0;
125         status = smb2_read(tree, tmp_ctx, &rd);
126         CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
127
128 done:
129         talloc_free(tmp_ctx);
130         return ret;
131 }
132
133
134 static bool test_read_position(struct torture_context *torture, struct smb2_tree *tree)
135 {
136         bool ret = true;
137         NTSTATUS status;
138         struct smb2_handle h;
139         uint8_t buf[64*1024];
140         struct smb2_read rd;
141         TALLOC_CTX *tmp_ctx = talloc_new(tree);
142         union smb_fileinfo info;
143
144         ZERO_STRUCT(buf);
145
146         status = torture_smb2_testfile(tree, FNAME, &h);
147         CHECK_STATUS(status, NT_STATUS_OK);
148
149         status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
150         CHECK_STATUS(status, NT_STATUS_OK);
151
152         ZERO_STRUCT(rd);
153         rd.in.file.handle = h;
154         rd.in.length = 10;
155         rd.in.offset = 0;
156         rd.in.min_count = 1;
157
158         status = smb2_read(tree, tmp_ctx, &rd);
159         CHECK_STATUS(status, NT_STATUS_OK);
160         CHECK_VALUE(rd.out.data.length, 10);
161
162         info.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
163         info.generic.in.file.handle = h;
164
165         status = smb2_getinfo_file(tree, tmp_ctx, &info);
166         CHECK_STATUS(status, NT_STATUS_OK);
167         if (torture_setting_bool(torture, "windows", false)) {
168                 CHECK_VALUE(info.all_info2.out.position, 0);
169         } else {
170                 CHECK_VALUE(info.all_info2.out.position, 10);
171         }
172
173         
174 done:
175         talloc_free(tmp_ctx);
176         return ret;
177 }
178
179 static bool test_read_dir(struct torture_context *torture, struct smb2_tree *tree)
180 {
181         bool ret = true;
182         NTSTATUS status;
183         struct smb2_handle h;
184         struct smb2_read rd;
185         TALLOC_CTX *tmp_ctx = talloc_new(tree);
186
187         status = torture_smb2_testdir(tree, DNAME, &h);
188         if (!NT_STATUS_IS_OK(status)) {
189                 printf(__location__ " Unable to create test directory '%s' - %s\n", DNAME, nt_errstr(status));
190                 return false;
191         }
192
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;
198
199         status = smb2_read(tree, tmp_ctx, &rd);
200         CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST);
201         
202         rd.in.min_count = 11;
203         status = smb2_read(tree, tmp_ctx, &rd);
204         CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST);
205
206         rd.in.length = 0;
207         rd.in.min_count = 2592;
208         status = smb2_read(tree, tmp_ctx, &rd);
209         if (torture_setting_bool(torture, "windows", false)) {
210                 CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
211         } else {
212                 CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST);
213         }
214
215         rd.in.length = 0;
216         rd.in.min_count = 0;
217         rd.in.channel = 0;
218         status = smb2_read(tree, tmp_ctx, &rd);
219         if (torture_setting_bool(torture, "windows", false)) {
220                 CHECK_STATUS(status, NT_STATUS_OK);
221         } else {
222                 CHECK_STATUS(status, NT_STATUS_INVALID_DEVICE_REQUEST);
223         }
224         
225 done:
226         talloc_free(tmp_ctx);
227         return ret;
228 }
229
230 static bool test_read_access(struct torture_context *torture,
231                              struct smb2_tree *tree)
232 {
233         bool ret = true;
234         NTSTATUS status;
235         struct smb2_handle h;
236         uint8_t buf[64 * 1024];
237         struct smb2_read rd;
238         TALLOC_CTX *tmp_ctx = talloc_new(tree);
239
240         ZERO_STRUCT(buf);
241
242         /* create a file */
243         smb2_util_unlink(tree, FNAME);
244
245         status = torture_smb2_testfile(tree, FNAME, &h);
246         CHECK_STATUS(status, NT_STATUS_OK);
247
248         status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
249         CHECK_STATUS(status, NT_STATUS_OK);
250
251         status = smb2_util_close(tree, h);
252         CHECK_STATUS(status, NT_STATUS_OK);
253
254         /* open w/ READ access - success */
255         status = torture_smb2_testfile_access(
256             tree, FNAME, &h, SEC_FILE_READ_ATTRIBUTE | SEC_FILE_READ_DATA);
257         CHECK_STATUS(status, NT_STATUS_OK);
258
259         ZERO_STRUCT(rd);
260         rd.in.file.handle = h;
261         rd.in.length = 5;
262         rd.in.offset = 0;
263         status = smb2_read(tree, tree, &rd);
264         CHECK_STATUS(status, NT_STATUS_OK);
265
266         status = smb2_util_close(tree, h);
267         CHECK_STATUS(status, NT_STATUS_OK);
268
269         /* open w/ EXECUTE access - success */
270         status = torture_smb2_testfile_access(
271             tree, FNAME, &h, SEC_FILE_READ_ATTRIBUTE | SEC_FILE_EXECUTE);
272         CHECK_STATUS(status, NT_STATUS_OK);
273
274         ZERO_STRUCT(rd);
275         rd.in.file.handle = h;
276         rd.in.length = 5;
277         rd.in.offset = 0;
278         status = smb2_read(tree, tree, &rd);
279         CHECK_STATUS(status, NT_STATUS_OK);
280
281         status = smb2_util_close(tree, h);
282         CHECK_STATUS(status, NT_STATUS_OK);
283
284         /* open without READ or EXECUTE access - access denied */
285         status = torture_smb2_testfile_access(tree, FNAME, &h,
286                                               SEC_FILE_READ_ATTRIBUTE);
287         CHECK_STATUS(status, NT_STATUS_OK);
288
289         ZERO_STRUCT(rd);
290         rd.in.file.handle = h;
291         rd.in.length = 5;
292         rd.in.offset = 0;
293         status = smb2_read(tree, tree, &rd);
294         CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
295
296         status = smb2_util_close(tree, h);
297         CHECK_STATUS(status, NT_STATUS_OK);
298
299 done:
300         talloc_free(tmp_ctx);
301         return ret;
302 }
303
304 /* 
305    basic testing of SMB2 read
306 */
307 struct torture_suite *torture_smb2_read_init(TALLOC_CTX *ctx)
308 {
309         struct torture_suite *suite = torture_suite_create(ctx, "read");
310
311         torture_suite_add_1smb2_test(suite, "eof", test_read_eof);
312         torture_suite_add_1smb2_test(suite, "position", test_read_position);
313         torture_suite_add_1smb2_test(suite, "dir", test_read_dir);
314         torture_suite_add_1smb2_test(suite, "access", test_read_access);
315
316         suite->description = talloc_strdup(suite, "SMB2-READ tests");
317
318         return suite;
319 }
320
321 static bool test_aio_cancel(struct torture_context *tctx,
322                             struct smb2_tree *tree)
323 {
324         struct smb2_handle h;
325         uint8_t buf[64 * 1024];
326         struct smb2_read r;
327         struct smb2_request *req = NULL;
328         int rc;
329         NTSTATUS status;
330         bool ret = true;
331
332         ZERO_STRUCT(buf);
333
334         smb2_util_unlink(tree, FNAME);
335
336         status = torture_smb2_testfile(tree, FNAME, &h);
337         torture_assert_ntstatus_ok_goto(
338                 tctx,
339                 status,
340                 ret,
341                 done,
342                 "torture_smb2_testfile failed\n");
343
344         status = smb2_util_write(tree, h, buf, 0, ARRAY_SIZE(buf));
345         torture_assert_ntstatus_ok_goto(
346                 tctx,
347                 status,
348                 ret,
349                 done,
350                 "smb2_util_write failed\n");
351
352         status = smb2_util_close(tree, h);
353         torture_assert_ntstatus_ok_goto(
354                 tctx,
355                 status,
356                 ret,
357                 done,
358                 "smb2_util_close failed\n");
359
360         status = torture_smb2_testfile_access(
361                 tree, FNAME, &h, SEC_RIGHTS_FILE_ALL);
362         torture_assert_ntstatus_ok_goto(
363                 tctx,
364                 status,
365                 ret,
366                 done,
367                 "torture_smb2_testfile_access failed\n");
368
369         r = (struct smb2_read) {
370                 .in.file.handle = h,
371                 .in.length      = 1,
372                 .in.offset      = 0,
373                 .in.min_count   = 1,
374         };
375
376         req = smb2_read_send(tree, &r);
377         torture_assert_goto(
378                 tctx,
379                 req != NULL,
380                 ret,
381                 done,
382                 "smb2_read_send failed\n");
383
384         while (!req->cancel.can_cancel) {
385                 rc = tevent_loop_once(tctx->ev);
386                 torture_assert_goto(
387                         tctx,
388                         rc == 0,
389                         ret,
390                         done,
391                         "tevent_loop_once failed\n");
392         }
393
394         status = smb2_cancel(req);
395         torture_assert_ntstatus_ok_goto(
396                 tctx,
397                 status,
398                 ret,
399                 done,
400                 "smb2_cancel failed\n");
401
402         status = smb2_read_recv(req, tree, &r);
403         torture_assert_ntstatus_ok_goto(
404                 tctx,
405                 status,
406                 ret,
407                 done,
408                 "smb2_read_recv failed\n");
409
410         status = smb2_util_close(tree, h);
411         torture_assert_ntstatus_ok_goto(
412                 tctx,
413                 status,
414                 ret,
415                 done,
416                 "smb2_util_close failed\n");
417
418 done:
419         smb2_util_unlink(tree, FNAME);
420         return ret;
421 }
422
423 /*
424  * aio testing against share with VFS module "delay_inject"
425  */
426 struct torture_suite *torture_smb2_aio_delay_init(TALLOC_CTX *ctx)
427 {
428         struct torture_suite *suite = torture_suite_create(ctx, "aio_delay");
429
430         torture_suite_add_1smb2_test(suite, "aio_cancel", test_aio_cancel);
431
432         suite->description = talloc_strdup(suite, "SMB2 delayed aio tests");
433
434         return suite;
435 }