Convert mtime from a time_t to a struct timespec.
[Samba.git] / source4 / torture / smb2 / oplock.c
blobec263acf58f6fbbffcfd6d60a42fd572bd4e443a
1 /*
2 Unix SMB/CIFS implementation.
4 test suite for SMB2 oplocks
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Stefan Metzmacher 2008
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
25 #include "libcli/smb2/smb2.h"
26 #include "libcli/smb2/smb2_calls.h"
27 #include "libcli/smb_composite/smb_composite.h"
28 #include "libcli/resolve/resolve.h"
30 #include "lib/cmdline/popt_common.h"
31 #include "lib/events/events.h"
33 #include "param/param.h"
34 #include "system/filesys.h"
36 #include "torture/torture.h"
37 #include "torture/smb2/proto.h"
39 #define CHECK_RANGE(v, min, max) do { \
40 if ((v) < (min) || (v) > (max)) { \
41 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
42 "got %d - should be between %d and %d\n", \
43 __location__, #v, (int)v, (int)min, (int)max); \
44 ret = false; \
45 }} while (0)
47 #define CHECK_STRMATCH(v, correct) do { \
48 if (!v || strstr((v),(correct)) == NULL) { \
49 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s "\
50 "got '%s' - should be '%s'\n", \
51 __location__, #v, v?v:"NULL", correct); \
52 ret = false; \
53 }} while (0)
55 #define CHECK_VAL(v, correct) do { \
56 if ((v) != (correct)) { \
57 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s " \
58 "got 0x%x - should be 0x%x\n", \
59 __location__, #v, (int)v, (int)correct); \
60 ret = false; \
61 }} while (0)
63 #define BASEDIR "oplock_test"
65 static struct {
66 struct smb2_handle handle;
67 uint8_t level;
68 struct smb2_break br;
69 int count;
70 int failures;
71 NTSTATUS failure_status;
72 } break_info;
74 static void torture_oplock_break_callback(struct smb2_request *req)
76 NTSTATUS status;
77 struct smb2_break br;
79 ZERO_STRUCT(br);
80 status = smb2_break_recv(req, &break_info.br);
81 if (!NT_STATUS_IS_OK(status)) {
82 break_info.failures++;
83 break_info.failure_status = status;
86 return;
89 /* A general oplock break notification handler. This should be used when a
90 * test expects to break from batch or exclusive to a lower level. */
91 static bool torture_oplock_handler(struct smb2_transport *transport,
92 const struct smb2_handle *handle,
93 uint8_t level,
94 void *private_data)
96 struct smb2_tree *tree = private_data;
97 const char *name;
98 struct smb2_request *req;
99 ZERO_STRUCT(break_info.br);
101 break_info.handle = *handle;
102 break_info.level = level;
103 break_info.count++;
105 switch (level) {
106 case SMB2_OPLOCK_LEVEL_II:
107 name = "level II";
108 break;
109 case SMB2_OPLOCK_LEVEL_NONE:
110 name = "none";
111 break;
112 default:
113 name = "unknown";
114 break_info.failures++;
116 printf("Acking to %s [0x%02X] in oplock handler\n", name, level);
118 break_info.br.in.file.handle = *handle;
119 break_info.br.in.oplock_level = level;
120 break_info.br.in.reserved = 0;
121 break_info.br.in.reserved2 = 0;
123 req = smb2_break_send(tree, &break_info.br);
124 req->async.fn = torture_oplock_break_callback;
125 req->async.private_data = NULL;
126 return true;
130 A handler function for oplock break notifications. Send a break to none
131 request.
133 static bool torture_oplock_handler_ack_to_none(struct smb2_transport *transport,
134 const struct smb2_handle *handle,
135 uint8_t level,
136 void *private_data)
138 struct smb2_tree *tree = private_data;
139 struct smb2_request *req;
141 break_info.handle = *handle;
142 break_info.level = level;
143 break_info.count++;
145 printf("Acking to none in oplock handler\n");
147 ZERO_STRUCT(break_info.br);
148 break_info.br.in.file.handle = *handle;
149 break_info.br.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
150 break_info.br.in.reserved = 0;
151 break_info.br.in.reserved2 = 0;
153 req = smb2_break_send(tree, &break_info.br);
154 req->async.fn = torture_oplock_break_callback;
155 req->async.private_data = NULL;
157 return true;
161 A handler function for oplock break notifications. Break from level II to
162 none. SMB2 requires that the client does not send an oplock break request to
163 the server in this case.
165 static bool torture_oplock_handler_level2_to_none(
166 struct smb2_transport *transport,
167 const struct smb2_handle *handle,
168 uint8_t level,
169 void *private_data)
171 break_info.handle = *handle;
172 break_info.level = level;
173 break_info.count++;
175 printf("Break from level II to none in oplock handler\n");
177 return true;
180 /* A handler function for oplock break notifications. This should be used when
181 * test expects two break notifications, first to level II, then to none. */
182 static bool torture_oplock_handler_two_notifications(
183 struct smb2_transport *transport,
184 const struct smb2_handle *handle,
185 uint8_t level,
186 void *private_data)
188 struct smb2_tree *tree = private_data;
189 const char *name;
190 struct smb2_request *req;
191 ZERO_STRUCT(break_info.br);
193 break_info.handle = *handle;
194 break_info.level = level;
195 break_info.count++;
197 switch (level) {
198 case SMB2_OPLOCK_LEVEL_II:
199 name = "level II";
200 break;
201 case SMB2_OPLOCK_LEVEL_NONE:
202 name = "none";
203 break;
204 default:
205 name = "unknown";
206 break_info.failures++;
208 printf("Breaking to %s [0x%02X] in oplock handler\n", name, level);
210 if (level == SMB2_OPLOCK_LEVEL_NONE)
211 return true;
213 break_info.br.in.file.handle = *handle;
214 break_info.br.in.oplock_level = level;
215 break_info.br.in.reserved = 0;
216 break_info.br.in.reserved2 = 0;
218 req = smb2_break_send(tree, &break_info.br);
219 req->async.fn = torture_oplock_break_callback;
220 req->async.private_data = NULL;
221 return true;
223 static void torture_oplock_handler_close_recv(struct smb2_request *req)
225 if (!smb2_request_receive(req)) {
226 printf("close failed in oplock_handler_close\n");
227 break_info.failures++;
232 a handler function for oplock break requests - close the file
234 static bool torture_oplock_handler_close(struct smb2_transport *transport,
235 const struct smb2_handle *handle,
236 uint8_t level,
237 void *private_data)
239 struct smb2_close io;
240 struct smb2_tree *tree = private_data;
241 struct smb2_request *req;
243 break_info.handle = *handle;
244 break_info.level = level;
245 break_info.count++;
247 ZERO_STRUCT(io);
248 io.in.file.handle = *handle;
249 io.in.flags = RAW_CLOSE_SMB2;
250 req = smb2_close_send(tree, &io);
251 if (req == NULL) {
252 printf("failed to send close in oplock_handler_close\n");
253 return false;
256 req->async.fn = torture_oplock_handler_close_recv;
257 req->async.private_data = NULL;
259 return true;
263 a handler function for oplock break requests. Let it timeout
265 static bool torture_oplock_handler_timeout(struct smb2_transport *transport,
266 const struct smb2_handle *handle,
267 uint8_t level,
268 void *private_data)
270 break_info.handle = *handle;
271 break_info.level = level;
272 break_info.count++;
274 printf("Let oplock break timeout\n");
275 return true;
278 static bool open_smb2_connection_no_level2_oplocks(struct torture_context *tctx,
279 struct smb2_tree **tree)
281 NTSTATUS status;
282 const char *host = torture_setting_string(tctx, "host", NULL);
283 const char *share = torture_setting_string(tctx, "share", NULL);
284 struct cli_credentials *credentials = cmdline_credentials;
285 struct smbcli_options options;
287 lpcfg_smbcli_options(tctx->lp_ctx, &options);
288 options.use_level2_oplocks = false;
290 status = smb2_connect(tctx, host,
291 lpcfg_smb_ports(tctx->lp_ctx), share,
292 lpcfg_resolve_context(tctx->lp_ctx),
293 credentials, tree, tctx->ev, &options,
294 lpcfg_socket_options(tctx->lp_ctx),
295 lpcfg_gensec_settings(tctx, tctx->lp_ctx));
296 if (!NT_STATUS_IS_OK(status)) {
297 torture_comment(tctx, "Failed to connect to SMB2 share "
298 "\\\\%s\\%s - %s\n", host, share,
299 nt_errstr(status));
300 return false;
302 return true;
306 Timer handler function notifies the registering function that time is up
308 static void timeout_cb(struct tevent_context *ev,
309 struct tevent_timer *te,
310 struct timeval current_time,
311 void *private_data)
313 bool *timesup = (bool *)private_data;
314 *timesup = true;
315 return;
319 Wait a short period of time to receive a single oplock break request
321 static void torture_wait_for_oplock_break(struct torture_context *tctx)
323 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
324 struct tevent_timer *te = NULL;
325 struct timeval ne;
326 bool timesup = false;
327 int old_count = break_info.count;
329 /* Wait .1 seconds for an oplock break */
330 ne = tevent_timeval_current_ofs(0, 100000);
332 if ((te = event_add_timed(tctx->ev, tmp_ctx, ne, timeout_cb, &timesup))
333 == NULL)
335 torture_comment(tctx, "Failed to wait for an oplock break. "
336 "test results may not be accurate.");
337 goto done;
340 while (!timesup && break_info.count < old_count + 1) {
341 if (event_loop_once(tctx->ev) != 0) {
342 torture_comment(tctx, "Failed to wait for an oplock "
343 "break. test results may not be "
344 "accurate.");
345 goto done;
349 done:
350 /* We don't know if the timed event fired and was freed, we received
351 * our oplock break, or some other event triggered the loop. Thus,
352 * we create a tmp_ctx to be able to safely free/remove the timed
353 * event in all 3 cases. */
354 talloc_free(tmp_ctx);
356 return;
359 static bool test_smb2_oplock_exclusive1(struct torture_context *tctx,
360 struct smb2_tree *tree1,
361 struct smb2_tree *tree2)
363 const char *fname = BASEDIR "\\test_exclusive1.dat";
364 NTSTATUS status;
365 bool ret = true;
366 union smb_open io;
367 union smb_unlink unl;
368 struct smb2_handle h1;
369 struct smb2_handle h;
371 status = torture_smb2_testdir(tree1, BASEDIR, &h);
372 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
374 /* cleanup */
375 smb2_util_unlink(tree1, fname);
377 tree1->session->transport->oplock.handler = torture_oplock_handler;
378 tree1->session->transport->oplock.private_data = tree1;
381 base ntcreatex parms
383 ZERO_STRUCT(io.smb2);
384 io.generic.level = RAW_OPEN_SMB2;
385 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
386 io.smb2.in.alloc_size = 0;
387 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
388 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
389 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
390 io.smb2.in.create_options = 0;
391 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
392 io.smb2.in.security_flags = 0;
393 io.smb2.in.fname = fname;
395 torture_comment(tctx, "EXCLUSIVE1: open a file with an exclusive "
396 "oplock (share mode: none)\n");
397 ZERO_STRUCT(break_info);
398 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
400 status = smb2_create(tree1, tctx, &(io.smb2));
401 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
402 h1 = io.smb2.out.file.handle;
403 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
405 torture_comment(tctx, "a 2nd open should not cause a break\n");
406 status = smb2_create(tree2, tctx, &(io.smb2));
407 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
408 "Incorrect status");
409 torture_wait_for_oplock_break(tctx);
410 CHECK_VAL(break_info.count, 0);
411 CHECK_VAL(break_info.failures, 0);
413 torture_comment(tctx, "unlink it - should also be no break\n");
414 unl.unlink.in.pattern = fname;
415 unl.unlink.in.attrib = 0;
416 status = smb2_util_unlink(tree2, fname);
417 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
418 "Incorrect status");
419 torture_wait_for_oplock_break(tctx);
420 CHECK_VAL(break_info.count, 0);
421 CHECK_VAL(break_info.failures, 0);
423 smb2_util_close(tree1, h1);
424 smb2_util_close(tree1, h);
426 smb2_deltree(tree1, BASEDIR);
427 return ret;
430 static bool test_smb2_oplock_exclusive2(struct torture_context *tctx,
431 struct smb2_tree *tree1,
432 struct smb2_tree *tree2)
434 const char *fname = BASEDIR "\\test_exclusive2.dat";
435 NTSTATUS status;
436 bool ret = true;
437 union smb_open io;
438 union smb_unlink unl;
439 struct smb2_handle h, h1, h2;
441 status = torture_smb2_testdir(tree1, BASEDIR, &h);
442 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
444 /* cleanup */
445 smb2_util_unlink(tree1, fname);
447 tree1->session->transport->oplock.handler = torture_oplock_handler;
448 tree1->session->transport->oplock.private_data = tree1;
451 base ntcreatex parms
453 ZERO_STRUCT(io.smb2);
454 io.generic.level = RAW_OPEN_SMB2;
455 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
456 io.smb2.in.alloc_size = 0;
457 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
458 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
459 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
460 io.smb2.in.create_options = 0;
461 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
462 io.smb2.in.security_flags = 0;
463 io.smb2.in.fname = fname;
465 torture_comment(tctx, "EXCLUSIVE2: open a file with an exclusive "
466 "oplock (share mode: all)\n");
467 ZERO_STRUCT(break_info);
468 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
469 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
470 NTCREATEX_SHARE_ACCESS_WRITE|
471 NTCREATEX_SHARE_ACCESS_DELETE;
472 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
474 status = smb2_create(tree1, tctx, &(io.smb2));
475 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
476 h1 = io.smb2.out.file.handle;
477 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
479 torture_comment(tctx, "a 2nd open should cause a break to level 2\n");
480 status = smb2_create(tree2, tctx, &(io.smb2));
481 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
482 h2 = io.smb2.out.file.handle;
483 torture_wait_for_oplock_break(tctx);
484 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
485 CHECK_VAL(break_info.count, 1);
486 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
487 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
488 CHECK_VAL(break_info.failures, 0);
489 ZERO_STRUCT(break_info);
491 /* now we have 2 level II oplocks... */
492 torture_comment(tctx, "try to unlink it - should cause a break\n");
493 unl.unlink.in.pattern = fname;
494 unl.unlink.in.attrib = 0;
495 status = smb2_util_unlink(tree2, fname);
496 torture_assert_ntstatus_ok(tctx, status, "Error unlinking the file");
497 torture_wait_for_oplock_break(tctx);
498 CHECK_VAL(break_info.count, 0);
499 CHECK_VAL(break_info.failures, 0);
501 torture_comment(tctx, "close both handles\n");
502 smb2_util_close(tree1, h1);
503 smb2_util_close(tree1, h2);
504 smb2_util_close(tree1, h);
506 smb2_deltree(tree1, BASEDIR);
507 return ret;
510 static bool test_smb2_oplock_exclusive3(struct torture_context *tctx,
511 struct smb2_tree *tree1,
512 struct smb2_tree *tree2)
514 const char *fname = BASEDIR "\\test_exclusive3.dat";
515 NTSTATUS status;
516 bool ret = true;
517 union smb_open io;
518 union smb_setfileinfo sfi;
519 struct smb2_handle h, h1;
521 status = torture_smb2_testdir(tree1, BASEDIR, &h);
522 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
524 /* cleanup */
525 smb2_util_unlink(tree1, fname);
527 tree1->session->transport->oplock.handler = torture_oplock_handler;
528 tree1->session->transport->oplock.private_data = tree1;
531 base ntcreatex parms
533 ZERO_STRUCT(io.smb2);
534 io.generic.level = RAW_OPEN_SMB2;
535 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
536 io.smb2.in.alloc_size = 0;
537 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
538 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
539 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
540 io.smb2.in.create_options = 0;
541 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
542 io.smb2.in.security_flags = 0;
543 io.smb2.in.fname = fname;
545 torture_comment(tctx, "EXCLUSIVE3: open a file with an exclusive "
546 "oplock (share mode: none)\n");
548 ZERO_STRUCT(break_info);
549 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
550 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
552 status = smb2_create(tree1, tctx, &(io.smb2));
553 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
554 h1 = io.smb2.out.file.handle;
555 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
557 torture_comment(tctx, "setpathinfo EOF should trigger a break to "
558 "none\n");
559 ZERO_STRUCT(sfi);
560 sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
561 sfi.generic.in.file.path = fname;
562 sfi.end_of_file_info.in.size = 100;
564 status = smb2_composite_setpathinfo(tree2, &sfi);
566 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
567 "Incorrect status");
568 torture_wait_for_oplock_break(tctx);
569 CHECK_VAL(break_info.count, 0);
570 CHECK_VAL(break_info.failures, 0);
571 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
573 smb2_util_close(tree1, h1);
574 smb2_util_close(tree1, h);
576 smb2_deltree(tree1, BASEDIR);
577 return ret;
580 static bool test_smb2_oplock_exclusive4(struct torture_context *tctx,
581 struct smb2_tree *tree1,
582 struct smb2_tree *tree2)
584 const char *fname = BASEDIR "\\test_exclusive4.dat";
585 NTSTATUS status;
586 bool ret = true;
587 union smb_open io;
588 struct smb2_handle h, h1, h2;
590 status = torture_smb2_testdir(tree1, BASEDIR, &h);
591 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
593 /* cleanup */
594 smb2_util_unlink(tree1, fname);
596 tree1->session->transport->oplock.handler = torture_oplock_handler;
597 tree1->session->transport->oplock.private_data = tree1;
600 base ntcreatex parms
602 ZERO_STRUCT(io.smb2);
603 io.generic.level = RAW_OPEN_SMB2;
604 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
605 io.smb2.in.alloc_size = 0;
606 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
607 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
608 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
609 io.smb2.in.create_options = 0;
610 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
611 io.smb2.in.security_flags = 0;
612 io.smb2.in.fname = fname;
614 torture_comment(tctx, "EXCLUSIVE4: open with exclusive oplock\n");
615 ZERO_STRUCT(break_info);
617 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
618 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
619 status = smb2_create(tree1, tctx, &(io.smb2));
620 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
621 h1 = io.smb2.out.file.handle;
622 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
624 ZERO_STRUCT(break_info);
625 torture_comment(tctx, "second open with attributes only shouldn't "
626 "cause oplock break\n");
628 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
629 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
630 SEC_FILE_WRITE_ATTRIBUTE |
631 SEC_STD_SYNCHRONIZE;
632 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
633 status = smb2_create(tree2, tctx, &(io.smb2));
634 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
635 h2 = io.smb2.out.file.handle;
636 CHECK_VAL(io.smb2.out.oplock_level, NO_OPLOCK_RETURN);
637 torture_wait_for_oplock_break(tctx);
638 CHECK_VAL(break_info.count, 0);
639 CHECK_VAL(break_info.failures, 0);
641 smb2_util_close(tree1, h1);
642 smb2_util_close(tree2, h2);
643 smb2_util_close(tree1, h);
645 smb2_deltree(tree1, BASEDIR);
646 return ret;
649 static bool test_smb2_oplock_exclusive5(struct torture_context *tctx,
650 struct smb2_tree *tree1,
651 struct smb2_tree *tree2)
653 const char *fname = BASEDIR "\\test_exclusive5.dat";
654 NTSTATUS status;
655 bool ret = true;
656 union smb_open io;
657 struct smb2_handle h, h1, h2;
659 status = torture_smb2_testdir(tree1, BASEDIR, &h);
660 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
662 /* cleanup */
663 smb2_util_unlink(tree1, fname);
665 tree1->session->transport->oplock.handler = torture_oplock_handler;
666 tree1->session->transport->oplock.private_data = tree1;
668 tree2->session->transport->oplock.handler = torture_oplock_handler;
669 tree2->session->transport->oplock.private_data = tree2;
672 base ntcreatex parms
674 ZERO_STRUCT(io.smb2);
675 io.generic.level = RAW_OPEN_SMB2;
676 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
677 io.smb2.in.alloc_size = 0;
678 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
679 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
680 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
681 io.smb2.in.create_options = 0;
682 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
683 io.smb2.in.security_flags = 0;
684 io.smb2.in.fname = fname;
686 torture_comment(tctx, "EXCLUSIVE5: open with exclusive oplock\n");
687 ZERO_STRUCT(break_info);
689 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
690 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
691 NTCREATEX_SHARE_ACCESS_WRITE|
692 NTCREATEX_SHARE_ACCESS_DELETE;
693 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
694 status = smb2_create(tree1, tctx, &(io.smb2));
695 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
696 h1 = io.smb2.out.file.handle;
697 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
699 ZERO_STRUCT(break_info);
701 torture_comment(tctx, "second open with attributes only and "
702 "NTCREATEX_DISP_OVERWRITE_IF dispostion causes "
703 "oplock break\n");
705 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
706 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
707 SEC_FILE_WRITE_ATTRIBUTE |
708 SEC_STD_SYNCHRONIZE;
709 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
710 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
711 status = smb2_create(tree2, tctx, &(io.smb2));
712 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
713 h2 = io.smb2.out.file.handle;
714 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
715 torture_wait_for_oplock_break(tctx);
716 CHECK_VAL(break_info.count, 1);
717 CHECK_VAL(break_info.failures, 0);
719 smb2_util_close(tree1, h1);
720 smb2_util_close(tree2, h2);
721 smb2_util_close(tree1, h);
723 smb2_deltree(tree1, BASEDIR);
724 return ret;
727 static bool test_smb2_oplock_exclusive6(struct torture_context *tctx,
728 struct smb2_tree *tree1,
729 struct smb2_tree *tree2)
731 const char *fname1 = BASEDIR "\\test_exclusive6_1.dat";
732 const char *fname2 = BASEDIR "\\test_exclusive6_2.dat";
733 NTSTATUS status;
734 bool ret = true;
735 union smb_open io;
736 union smb_setfileinfo sinfo;
737 struct smb2_handle h, h1;
739 status = torture_smb2_testdir(tree1, BASEDIR, &h);
740 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
742 /* cleanup */
743 smb2_util_unlink(tree1, fname1);
744 smb2_util_unlink(tree2, fname2);
746 tree1->session->transport->oplock.handler = torture_oplock_handler;
747 tree1->session->transport->oplock.private_data = tree1;
750 base ntcreatex parms
752 ZERO_STRUCT(io.smb2);
753 io.generic.level = RAW_OPEN_SMB2;
754 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
755 io.smb2.in.alloc_size = 0;
756 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
757 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
758 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
759 io.smb2.in.create_options = 0;
760 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
761 io.smb2.in.security_flags = 0;
762 io.smb2.in.fname = fname1;
764 torture_comment(tctx, "EXCLUSIVE6: open a file with an exclusive "
765 "oplock (share mode: none)\n");
766 ZERO_STRUCT(break_info);
767 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
768 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
770 status = smb2_create(tree1, tctx, &(io.smb2));
771 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
772 h1 = io.smb2.out.file.handle;
773 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
775 torture_comment(tctx, "rename should not generate a break but get "
776 "a sharing violation\n");
777 ZERO_STRUCT(sinfo);
778 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
779 sinfo.rename_information.in.file.handle = h1;
780 sinfo.rename_information.in.overwrite = true;
781 sinfo.rename_information.in.new_name = fname2;
782 status = smb2_setinfo_file(tree1, &sinfo);
784 torture_comment(tctx, "trying rename while first file open\n");
785 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
786 "Incorrect status");
787 torture_wait_for_oplock_break(tctx);
788 CHECK_VAL(break_info.count, 0);
789 CHECK_VAL(break_info.failures, 0);
791 smb2_util_close(tree1, h1);
792 smb2_util_close(tree1, h);
794 smb2_deltree(tree1, BASEDIR);
795 return ret;
798 static bool test_smb2_oplock_batch1(struct torture_context *tctx,
799 struct smb2_tree *tree1,
800 struct smb2_tree *tree2)
802 const char *fname = BASEDIR "\\test_batch1.dat";
803 NTSTATUS status;
804 bool ret = true;
805 union smb_open io;
806 struct smb2_handle h, h1;
807 char c = 0;
809 status = torture_smb2_testdir(tree1, BASEDIR, &h);
810 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
812 /* cleanup */
813 smb2_util_unlink(tree1, fname);
815 tree1->session->transport->oplock.handler = torture_oplock_handler;
816 tree1->session->transport->oplock.private_data = tree1;
819 base ntcreatex parms
821 ZERO_STRUCT(io.smb2);
822 io.generic.level = RAW_OPEN_SMB2;
823 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
824 io.smb2.in.alloc_size = 0;
825 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
826 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
827 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
828 io.smb2.in.create_options = 0;
829 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
830 io.smb2.in.security_flags = 0;
831 io.smb2.in.fname = fname;
834 with a batch oplock we get a break
836 torture_comment(tctx, "BATCH1: open with batch oplock\n");
837 ZERO_STRUCT(break_info);
838 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
839 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
840 status = smb2_create(tree1, tctx, &(io.smb2));
841 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
842 h1 = io.smb2.out.file.handle;
843 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
845 torture_comment(tctx, "unlink should generate a break\n");
846 status = smb2_util_unlink(tree2, fname);
847 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
848 "Incorrect status");
850 torture_wait_for_oplock_break(tctx);
851 CHECK_VAL(break_info.count, 1);
852 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
853 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
854 CHECK_VAL(break_info.failures, 0);
856 torture_comment(tctx, "2nd unlink should not generate a break\n");
857 ZERO_STRUCT(break_info);
858 status = smb2_util_unlink(tree2, fname);
859 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
860 "Incorrect status");
862 torture_wait_for_oplock_break(tctx);
863 CHECK_VAL(break_info.count, 0);
865 torture_comment(tctx, "writing should generate a self break to none\n");
866 tree1->session->transport->oplock.handler =
867 torture_oplock_handler_level2_to_none;
868 smb2_util_write(tree1, h1, &c, 0, 1);
870 torture_wait_for_oplock_break(tctx);
872 CHECK_VAL(break_info.count, 1);
873 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
874 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
875 CHECK_VAL(break_info.failures, 0);
877 smb2_util_close(tree1, h1);
878 smb2_util_close(tree1, h);
880 smb2_deltree(tree1, BASEDIR);
881 return ret;
884 static bool test_smb2_oplock_batch2(struct torture_context *tctx,
885 struct smb2_tree *tree1,
886 struct smb2_tree *tree2)
888 const char *fname = BASEDIR "\\test_batch2.dat";
889 NTSTATUS status;
890 bool ret = true;
891 union smb_open io;
892 char c = 0;
893 struct smb2_handle h, h1;
895 status = torture_smb2_testdir(tree1, BASEDIR, &h);
896 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
898 /* cleanup */
899 smb2_util_unlink(tree1, fname);
901 tree1->session->transport->oplock.handler = torture_oplock_handler;
902 tree1->session->transport->oplock.private_data = tree1;
905 base ntcreatex parms
907 ZERO_STRUCT(io.smb2);
908 io.generic.level = RAW_OPEN_SMB2;
909 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
910 io.smb2.in.alloc_size = 0;
911 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
912 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
913 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
914 io.smb2.in.create_options = 0;
915 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
916 io.smb2.in.security_flags = 0;
917 io.smb2.in.fname = fname;
919 torture_comment(tctx, "BATCH2: open with batch oplock\n");
920 ZERO_STRUCT(break_info);
921 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
922 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
923 status = smb2_create(tree1, tctx, &(io.smb2));
924 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
925 h1 = io.smb2.out.file.handle;
926 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
928 torture_comment(tctx, "unlink should generate a break, which we ack "
929 "as break to none\n");
930 tree1->session->transport->oplock.handler =
931 torture_oplock_handler_ack_to_none;
932 tree1->session->transport->oplock.private_data = tree1;
933 status = smb2_util_unlink(tree2, fname);
934 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
935 "Incorrect status");
937 torture_wait_for_oplock_break(tctx);
938 CHECK_VAL(break_info.count, 1);
939 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
940 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
941 CHECK_VAL(break_info.failures, 0);
943 torture_comment(tctx, "2nd unlink should not generate a break\n");
944 ZERO_STRUCT(break_info);
945 status = smb2_util_unlink(tree2, fname);
946 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
947 "Incorrect status");
949 torture_wait_for_oplock_break(tctx);
950 CHECK_VAL(break_info.count, 0);
952 torture_comment(tctx, "writing should not generate a break\n");
953 smb2_util_write(tree1, h1, &c, 0, 1);
955 torture_wait_for_oplock_break(tctx);
956 CHECK_VAL(break_info.count, 0);
958 smb2_util_close(tree1, h1);
959 smb2_util_close(tree1, h);
961 smb2_deltree(tree1, BASEDIR);
962 return ret;
965 static bool test_smb2_oplock_batch3(struct torture_context *tctx,
966 struct smb2_tree *tree1,
967 struct smb2_tree *tree2)
969 const char *fname = BASEDIR "\\test_batch3.dat";
970 NTSTATUS status;
971 bool ret = true;
972 union smb_open io;
973 struct smb2_handle h, h1;
975 status = torture_smb2_testdir(tree1, BASEDIR, &h);
976 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
978 /* cleanup */
979 smb2_util_unlink(tree1, fname);
980 tree1->session->transport->oplock.handler = torture_oplock_handler;
981 tree1->session->transport->oplock.private_data = tree1;
984 base ntcreatex parms
986 ZERO_STRUCT(io.smb2);
987 io.generic.level = RAW_OPEN_SMB2;
988 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
989 io.smb2.in.alloc_size = 0;
990 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
991 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
992 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
993 io.smb2.in.create_options = 0;
994 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
995 io.smb2.in.security_flags = 0;
996 io.smb2.in.fname = fname;
998 torture_comment(tctx, "BATCH3: if we close on break then the unlink "
999 "can succeed\n");
1000 ZERO_STRUCT(break_info);
1001 tree1->session->transport->oplock.handler =
1002 torture_oplock_handler_close;
1003 tree1->session->transport->oplock.private_data = tree1;
1005 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1006 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1007 status = smb2_create(tree1, tctx, &(io.smb2));
1008 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1009 h1 = io.smb2.out.file.handle;
1010 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1012 ZERO_STRUCT(break_info);
1013 status = smb2_util_unlink(tree2, fname);
1014 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1016 torture_wait_for_oplock_break(tctx);
1017 CHECK_VAL(break_info.count, 1);
1018 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1019 CHECK_VAL(break_info.level, 1);
1020 CHECK_VAL(break_info.failures, 0);
1022 smb2_util_close(tree1, h1);
1023 smb2_util_close(tree1, h);
1025 smb2_deltree(tree1, BASEDIR);
1026 return ret;
1029 static bool test_smb2_oplock_batch4(struct torture_context *tctx,
1030 struct smb2_tree *tree1,
1031 struct smb2_tree *tree2)
1033 const char *fname = BASEDIR "\\test_batch4.dat";
1034 NTSTATUS status;
1035 bool ret = true;
1036 union smb_open io;
1037 struct smb2_read r;
1038 struct smb2_handle h, h1;
1040 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1041 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1043 /* cleanup */
1044 smb2_util_unlink(tree1, fname);
1046 tree1->session->transport->oplock.handler = torture_oplock_handler;
1047 tree1->session->transport->oplock.private_data = tree1;
1050 base ntcreatex parms
1052 ZERO_STRUCT(io.smb2);
1053 io.generic.level = RAW_OPEN_SMB2;
1054 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1055 io.smb2.in.alloc_size = 0;
1056 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1057 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1058 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1059 io.smb2.in.create_options = 0;
1060 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1061 io.smb2.in.security_flags = 0;
1062 io.smb2.in.fname = fname;
1064 torture_comment(tctx, "BATCH4: a self read should not cause a break\n");
1065 ZERO_STRUCT(break_info);
1067 tree1->session->transport->oplock.handler = torture_oplock_handler;
1068 tree1->session->transport->oplock.private_data = tree1;
1070 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1071 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1072 status = smb2_create(tree1, tctx, &(io.smb2));
1073 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1074 h1 = io.smb2.out.file.handle;
1075 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1077 ZERO_STRUCT(r);
1078 r.in.file.handle = h1;
1079 r.in.offset = 0;
1081 status = smb2_read(tree1, tree1, &r);
1082 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1083 torture_wait_for_oplock_break(tctx);
1084 CHECK_VAL(break_info.count, 0);
1085 CHECK_VAL(break_info.failures, 0);
1087 smb2_util_close(tree1, h1);
1088 smb2_util_close(tree1, h);
1090 smb2_deltree(tree1, BASEDIR);
1091 return ret;
1094 static bool test_smb2_oplock_batch5(struct torture_context *tctx,
1095 struct smb2_tree *tree1,
1096 struct smb2_tree *tree2)
1098 const char *fname = BASEDIR "\\test_batch5.dat";
1099 NTSTATUS status;
1100 bool ret = true;
1101 union smb_open io;
1102 struct smb2_handle h, h1;
1104 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1105 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1107 /* cleanup */
1108 smb2_util_unlink(tree1, fname);
1110 tree1->session->transport->oplock.handler = torture_oplock_handler;
1111 tree1->session->transport->oplock.private_data = tree1;
1114 base ntcreatex parms
1116 ZERO_STRUCT(io.smb2);
1117 io.generic.level = RAW_OPEN_SMB2;
1118 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1119 io.smb2.in.alloc_size = 0;
1120 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1121 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1122 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1123 io.smb2.in.create_options = 0;
1124 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1125 io.smb2.in.security_flags = 0;
1126 io.smb2.in.fname = fname;
1128 torture_comment(tctx, "BATCH5: a 2nd open should give a break\n");
1129 ZERO_STRUCT(break_info);
1131 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1132 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1133 status = smb2_create(tree1, tctx, &(io.smb2));
1134 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1135 h1 = io.smb2.out.file.handle;
1136 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1138 ZERO_STRUCT(break_info);
1140 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1141 status = smb2_create(tree2, tctx, &(io.smb2));
1142 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
1143 "Incorrect status");
1145 torture_wait_for_oplock_break(tctx);
1146 CHECK_VAL(break_info.count, 1);
1147 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1148 CHECK_VAL(break_info.level, 1);
1149 CHECK_VAL(break_info.failures, 0);
1151 smb2_util_close(tree1, h1);
1152 smb2_util_close(tree1, h);
1154 smb2_deltree(tree1, BASEDIR);
1155 return ret;
1158 static bool test_smb2_oplock_batch6(struct torture_context *tctx,
1159 struct smb2_tree *tree1,
1160 struct smb2_tree *tree2)
1162 const char *fname = BASEDIR "\\test_batch6.dat";
1163 NTSTATUS status;
1164 bool ret = true;
1165 union smb_open io;
1166 struct smb2_handle h, h1, h2;
1167 char c = 0;
1169 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1170 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1172 /* cleanup */
1173 smb2_util_unlink(tree1, fname);
1175 tree1->session->transport->oplock.handler = torture_oplock_handler;
1176 tree1->session->transport->oplock.private_data = tree1;
1179 base ntcreatex parms
1181 ZERO_STRUCT(io.smb2);
1182 io.generic.level = RAW_OPEN_SMB2;
1183 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1184 io.smb2.in.alloc_size = 0;
1185 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1186 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1187 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1188 io.smb2.in.create_options = 0;
1189 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1190 io.smb2.in.security_flags = 0;
1191 io.smb2.in.fname = fname;
1193 torture_comment(tctx, "BATCH6: a 2nd open should give a break to "
1194 "level II if the first open allowed shared read\n");
1195 ZERO_STRUCT(break_info);
1196 tree2->session->transport->oplock.handler = torture_oplock_handler;
1197 tree2->session->transport->oplock.private_data = tree2;
1199 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
1200 SEC_RIGHTS_FILE_WRITE;
1201 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1202 NTCREATEX_SHARE_ACCESS_WRITE;
1203 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1204 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1205 status = smb2_create(tree1, tctx, &(io.smb2));
1206 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1207 h1 = io.smb2.out.file.handle;
1208 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1210 ZERO_STRUCT(break_info);
1212 status = smb2_create(tree2, tctx, &(io.smb2));
1213 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1214 h2 = io.smb2.out.file.handle;
1215 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1217 torture_wait_for_oplock_break(tctx);
1218 CHECK_VAL(break_info.count, 1);
1219 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1220 CHECK_VAL(break_info.level, 1);
1221 CHECK_VAL(break_info.failures, 0);
1222 ZERO_STRUCT(break_info);
1224 torture_comment(tctx, "write should trigger a break to none on both\n");
1225 tree1->session->transport->oplock.handler =
1226 torture_oplock_handler_level2_to_none;
1227 tree2->session->transport->oplock.handler =
1228 torture_oplock_handler_level2_to_none;
1229 smb2_util_write(tree1, h1, &c, 0, 1);
1231 /* We expect two breaks */
1232 torture_wait_for_oplock_break(tctx);
1233 torture_wait_for_oplock_break(tctx);
1235 CHECK_VAL(break_info.count, 2);
1236 CHECK_VAL(break_info.level, 0);
1237 CHECK_VAL(break_info.failures, 0);
1239 smb2_util_close(tree1, h1);
1240 smb2_util_close(tree2, h2);
1241 smb2_util_close(tree1, h);
1243 smb2_deltree(tree1, BASEDIR);
1244 return ret;
1247 static bool test_smb2_oplock_batch7(struct torture_context *tctx,
1248 struct smb2_tree *tree1,
1249 struct smb2_tree *tree2)
1251 const char *fname = BASEDIR "\\test_batch7.dat";
1252 NTSTATUS status;
1253 bool ret = true;
1254 union smb_open io;
1255 struct smb2_handle h, h1, h2;
1257 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1258 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1260 /* cleanup */
1261 smb2_util_unlink(tree1, fname);
1263 tree1->session->transport->oplock.handler = torture_oplock_handler;
1264 tree1->session->transport->oplock.private_data = tree1;
1267 base ntcreatex parms
1269 ZERO_STRUCT(io.smb2);
1270 io.generic.level = RAW_OPEN_SMB2;
1271 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1272 io.smb2.in.alloc_size = 0;
1273 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1274 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1275 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1276 io.smb2.in.create_options = 0;
1277 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1278 io.smb2.in.security_flags = 0;
1279 io.smb2.in.fname = fname;
1281 torture_comment(tctx, "BATCH7: a 2nd open should get an oplock when "
1282 "we close instead of ack\n");
1283 ZERO_STRUCT(break_info);
1284 tree1->session->transport->oplock.handler =
1285 torture_oplock_handler_close;
1286 tree1->session->transport->oplock.private_data = tree1;
1288 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1289 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1290 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1291 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1292 status = smb2_create(tree1, tctx, &(io.smb2));
1293 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1294 h2 = io.smb2.out.file.handle;
1295 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1297 ZERO_STRUCT(break_info);
1299 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1300 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1301 status = smb2_create(tree2, tctx, &(io.smb2));
1302 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1303 h1 = io.smb2.out.file.handle;
1304 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1306 torture_wait_for_oplock_break(tctx);
1307 CHECK_VAL(break_info.count, 1);
1308 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1309 CHECK_VAL(break_info.level, 1);
1310 CHECK_VAL(break_info.failures, 0);
1312 smb2_util_close(tree2, h1);
1313 smb2_util_close(tree2, h);
1315 smb2_deltree(tree1, BASEDIR);
1316 return ret;
1319 static bool test_smb2_oplock_batch8(struct torture_context *tctx,
1320 struct smb2_tree *tree1,
1321 struct smb2_tree *tree2)
1323 const char *fname = BASEDIR "\\test_batch8.dat";
1324 NTSTATUS status;
1325 bool ret = true;
1326 union smb_open io;
1327 struct smb2_handle h, h1, h2;
1329 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1330 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1332 /* cleanup */
1333 smb2_util_unlink(tree1, fname);
1335 tree1->session->transport->oplock.handler = torture_oplock_handler;
1336 tree1->session->transport->oplock.private_data = tree1;
1339 base ntcreatex parms
1341 ZERO_STRUCT(io.smb2);
1342 io.generic.level = RAW_OPEN_SMB2;
1343 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1344 io.smb2.in.alloc_size = 0;
1345 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1346 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1347 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1348 io.smb2.in.create_options = 0;
1349 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1350 io.smb2.in.security_flags = 0;
1351 io.smb2.in.fname = fname;
1353 torture_comment(tctx, "BATCH8: open with batch oplock\n");
1354 ZERO_STRUCT(break_info);
1356 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1357 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1358 status = smb2_create(tree1, tctx, &(io.smb2));
1359 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1360 h1 = io.smb2.out.file.handle;
1361 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1363 ZERO_STRUCT(break_info);
1364 torture_comment(tctx, "second open with attributes only shouldn't "
1365 "cause oplock break\n");
1367 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1368 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1369 SEC_FILE_WRITE_ATTRIBUTE |
1370 SEC_STD_SYNCHRONIZE;
1371 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1372 status = smb2_create(tree2, tctx, &(io.smb2));
1373 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1374 h2 = io.smb2.out.file.handle;
1375 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_NONE);
1376 torture_wait_for_oplock_break(tctx);
1377 CHECK_VAL(break_info.count, 0);
1378 CHECK_VAL(break_info.failures, 0);
1380 smb2_util_close(tree1, h1);
1381 smb2_util_close(tree2, h2);
1382 smb2_util_close(tree1, h);
1384 smb2_deltree(tree1, BASEDIR);
1385 return ret;
1388 static bool test_smb2_oplock_batch9(struct torture_context *tctx,
1389 struct smb2_tree *tree1,
1390 struct smb2_tree *tree2)
1392 const char *fname = BASEDIR "\\test_batch9.dat";
1393 NTSTATUS status;
1394 bool ret = true;
1395 union smb_open io;
1396 struct smb2_handle h, h1, h2;
1397 char c = 0;
1399 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1400 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1402 /* cleanup */
1403 smb2_util_unlink(tree1, fname);
1405 tree1->session->transport->oplock.handler = torture_oplock_handler;
1406 tree1->session->transport->oplock.private_data = tree1;
1409 base ntcreatex parms
1411 ZERO_STRUCT(io.smb2);
1412 io.generic.level = RAW_OPEN_SMB2;
1413 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1414 io.smb2.in.alloc_size = 0;
1415 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1416 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1417 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1418 io.smb2.in.create_options = 0;
1419 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1420 io.smb2.in.security_flags = 0;
1421 io.smb2.in.fname = fname;
1423 torture_comment(tctx, "BATCH9: open with attributes only can create "
1424 "file\n");
1426 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1427 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1428 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1429 SEC_FILE_WRITE_ATTRIBUTE |
1430 SEC_STD_SYNCHRONIZE;
1431 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1432 status = smb2_create(tree1, tctx, &(io.smb2));
1433 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1434 h1 = io.smb2.out.file.handle;
1435 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1437 torture_comment(tctx, "Subsequent normal open should break oplock on "
1438 "attribute only open to level II\n");
1440 ZERO_STRUCT(break_info);
1442 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1443 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1444 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1445 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1446 status = smb2_create(tree2, tctx, &(io.smb2));
1447 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1448 h2 = io.smb2.out.file.handle;
1449 torture_wait_for_oplock_break(tctx);
1450 CHECK_VAL(break_info.count, 1);
1451 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
1452 CHECK_VAL(break_info.failures, 0);
1453 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
1454 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1455 smb2_util_close(tree2, h2);
1457 torture_comment(tctx, "third oplocked open should grant level2 without "
1458 "break\n");
1459 ZERO_STRUCT(break_info);
1461 tree2->session->transport->oplock.handler = torture_oplock_handler;
1462 tree2->session->transport->oplock.private_data = tree2;
1464 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1465 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1466 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1467 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1468 status = smb2_create(tree2, tctx, &(io.smb2));
1469 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1470 h2 = io.smb2.out.file.handle;
1471 torture_wait_for_oplock_break(tctx);
1472 CHECK_VAL(break_info.count, 0);
1473 CHECK_VAL(break_info.failures, 0);
1474 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1476 ZERO_STRUCT(break_info);
1478 torture_comment(tctx, "write should trigger a break to none on both\n");
1479 tree1->session->transport->oplock.handler =
1480 torture_oplock_handler_level2_to_none;
1481 tree2->session->transport->oplock.handler =
1482 torture_oplock_handler_level2_to_none;
1483 smb2_util_write(tree2, h2, &c, 0, 1);
1485 /* We expect two breaks */
1486 torture_wait_for_oplock_break(tctx);
1487 torture_wait_for_oplock_break(tctx);
1489 CHECK_VAL(break_info.count, 2);
1490 CHECK_VAL(break_info.level, 0);
1491 CHECK_VAL(break_info.failures, 0);
1493 smb2_util_close(tree1, h1);
1494 smb2_util_close(tree2, h2);
1495 smb2_util_close(tree1, h);
1497 smb2_deltree(tree1, BASEDIR);
1498 return ret;
1501 static bool test_smb2_oplock_batch10(struct torture_context *tctx,
1502 struct smb2_tree *tree1,
1503 struct smb2_tree *tree2)
1505 const char *fname = BASEDIR "\\test_batch10.dat";
1506 NTSTATUS status;
1507 bool ret = true;
1508 union smb_open io;
1509 struct smb2_handle h, h1, h2;
1511 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1512 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1514 /* cleanup */
1515 smb2_util_unlink(tree1, fname);
1517 tree1->session->transport->oplock.handler = torture_oplock_handler;
1518 tree1->session->transport->oplock.private_data = tree1;
1521 base ntcreatex parms
1523 ZERO_STRUCT(io.smb2);
1524 io.generic.level = RAW_OPEN_SMB2;
1525 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1526 io.smb2.in.alloc_size = 0;
1527 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1528 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1529 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1530 io.smb2.in.create_options = 0;
1531 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1532 io.smb2.in.security_flags = 0;
1533 io.smb2.in.fname = fname;
1535 torture_comment(tctx, "BATCH10: Open with oplock after a non-oplock "
1536 "open should grant level2\n");
1537 ZERO_STRUCT(break_info);
1538 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1539 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1540 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1541 NTCREATEX_SHARE_ACCESS_WRITE|
1542 NTCREATEX_SHARE_ACCESS_DELETE;
1543 status = smb2_create(tree1, tctx, &(io.smb2));
1544 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1545 h1 = io.smb2.out.file.handle;
1546 torture_wait_for_oplock_break(tctx);
1547 CHECK_VAL(break_info.count, 0);
1548 CHECK_VAL(break_info.failures, 0);
1549 CHECK_VAL(io.smb2.out.oplock_level, 0);
1551 tree2->session->transport->oplock.handler =
1552 torture_oplock_handler_level2_to_none;
1553 tree2->session->transport->oplock.private_data = tree2;
1555 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1556 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1557 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1558 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1559 NTCREATEX_SHARE_ACCESS_WRITE|
1560 NTCREATEX_SHARE_ACCESS_DELETE;
1561 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1562 status = smb2_create(tree2, tctx, &(io.smb2));
1563 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1564 h2 = io.smb2.out.file.handle;
1565 torture_wait_for_oplock_break(tctx);
1566 CHECK_VAL(break_info.count, 0);
1567 CHECK_VAL(break_info.failures, 0);
1568 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1570 torture_comment(tctx, "write should trigger a break to none\n");
1572 struct smb2_write wr;
1573 DATA_BLOB data;
1574 data = data_blob_talloc(tree1, NULL, UINT16_MAX);
1575 data.data[0] = (const uint8_t)'x';
1576 ZERO_STRUCT(wr);
1577 wr.in.file.handle = h1;
1578 wr.in.offset = 0;
1579 wr.in.data = data;
1580 status = smb2_write(tree1, &wr);
1581 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1584 torture_wait_for_oplock_break(tctx);
1586 CHECK_VAL(break_info.count, 1);
1587 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
1588 CHECK_VAL(break_info.level, 0);
1589 CHECK_VAL(break_info.failures, 0);
1591 smb2_util_close(tree1, h1);
1592 smb2_util_close(tree2, h2);
1593 smb2_util_close(tree1, h);
1595 smb2_deltree(tree1, BASEDIR);
1596 return ret;
1599 static bool test_smb2_oplock_batch11(struct torture_context *tctx,
1600 struct smb2_tree *tree1,
1601 struct smb2_tree *tree2)
1603 const char *fname = BASEDIR "\\test_batch11.dat";
1604 NTSTATUS status;
1605 bool ret = true;
1606 union smb_open io;
1607 union smb_setfileinfo sfi;
1608 struct smb2_handle h, h1;
1610 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1611 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1613 /* cleanup */
1614 smb2_util_unlink(tree1, fname);
1616 tree1->session->transport->oplock.handler =
1617 torture_oplock_handler_two_notifications;
1618 tree1->session->transport->oplock.private_data = tree1;
1621 base ntcreatex parms
1623 ZERO_STRUCT(io.smb2);
1624 io.generic.level = RAW_OPEN_SMB2;
1625 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1626 io.smb2.in.alloc_size = 0;
1627 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1628 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1629 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1630 io.smb2.in.create_options = 0;
1631 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1632 io.smb2.in.security_flags = 0;
1633 io.smb2.in.fname = fname;
1635 /* Test if a set-eof on pathname breaks an exclusive oplock. */
1636 torture_comment(tctx, "BATCH11: Test if setpathinfo set EOF breaks "
1637 "oplocks.\n");
1639 ZERO_STRUCT(break_info);
1641 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1642 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1643 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1644 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1645 NTCREATEX_SHARE_ACCESS_WRITE|
1646 NTCREATEX_SHARE_ACCESS_DELETE;
1647 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1648 status = smb2_create(tree1, tctx, &(io.smb2));
1649 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1650 h1 = io.smb2.out.file.handle;
1651 torture_wait_for_oplock_break(tctx);
1652 CHECK_VAL(break_info.count, 0);
1653 CHECK_VAL(break_info.failures, 0);
1654 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1656 ZERO_STRUCT(sfi);
1657 sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
1658 sfi.generic.in.file.path = fname;
1659 sfi.end_of_file_info.in.size = 100;
1661 status = smb2_composite_setpathinfo(tree2, &sfi);
1662 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1664 /* We expect two breaks */
1665 torture_wait_for_oplock_break(tctx);
1666 torture_wait_for_oplock_break(tctx);
1668 CHECK_VAL(break_info.count, 2);
1669 CHECK_VAL(break_info.failures, 0);
1670 CHECK_VAL(break_info.level, 0);
1672 smb2_util_close(tree1, h1);
1673 smb2_util_close(tree1, h);
1675 smb2_deltree(tree1, BASEDIR);
1676 return ret;
1679 static bool test_smb2_oplock_batch12(struct torture_context *tctx,
1680 struct smb2_tree *tree1,
1681 struct smb2_tree *tree2)
1683 const char *fname = BASEDIR "\\test_batch12.dat";
1684 NTSTATUS status;
1685 bool ret = true;
1686 union smb_open io;
1687 union smb_setfileinfo sfi;
1688 struct smb2_handle h, h1;
1690 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1691 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1693 /* cleanup */
1694 smb2_util_unlink(tree1, fname);
1696 tree1->session->transport->oplock.handler =
1697 torture_oplock_handler_two_notifications;
1698 tree1->session->transport->oplock.private_data = tree1;
1701 base ntcreatex parms
1703 ZERO_STRUCT(io.smb2);
1704 io.generic.level = RAW_OPEN_SMB2;
1705 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1706 io.smb2.in.alloc_size = 0;
1707 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1708 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1709 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1710 io.smb2.in.create_options = 0;
1711 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1712 io.smb2.in.security_flags = 0;
1713 io.smb2.in.fname = fname;
1715 /* Test if a set-allocation size on pathname breaks an exclusive
1716 * oplock. */
1717 torture_comment(tctx, "BATCH12: Test if setpathinfo allocation size "
1718 "breaks oplocks.\n");
1720 ZERO_STRUCT(break_info);
1722 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1723 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1724 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1725 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1726 NTCREATEX_SHARE_ACCESS_WRITE|
1727 NTCREATEX_SHARE_ACCESS_DELETE;
1728 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1729 status = smb2_create(tree1, tctx, &(io.smb2));
1730 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1731 h1 = io.smb2.out.file.handle;
1732 torture_wait_for_oplock_break(tctx);
1733 CHECK_VAL(break_info.count, 0);
1734 CHECK_VAL(break_info.failures, 0);
1735 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1737 ZERO_STRUCT(sfi);
1738 sfi.generic.level = RAW_SFILEINFO_ALLOCATION_INFORMATION;
1739 sfi.generic.in.file.path = fname;
1740 sfi.allocation_info.in.alloc_size = 65536 * 8;
1742 status = smb2_composite_setpathinfo(tree2, &sfi);
1743 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1745 /* We expect two breaks */
1746 torture_wait_for_oplock_break(tctx);
1747 torture_wait_for_oplock_break(tctx);
1749 CHECK_VAL(break_info.count, 2);
1750 CHECK_VAL(break_info.failures, 0);
1751 CHECK_VAL(break_info.level, 0);
1753 smb2_util_close(tree1, h1);
1754 smb2_util_close(tree1, h);
1756 smb2_deltree(tree1, BASEDIR);
1757 return ret;
1760 static bool test_smb2_oplock_batch13(struct torture_context *tctx,
1761 struct smb2_tree *tree1,
1762 struct smb2_tree *tree2)
1764 const char *fname = BASEDIR "\\test_batch13.dat";
1765 NTSTATUS status;
1766 bool ret = true;
1767 union smb_open io;
1768 struct smb2_handle h, h1, h2;
1770 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1771 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1773 /* cleanup */
1774 smb2_util_unlink(tree1, fname);
1776 tree1->session->transport->oplock.handler = torture_oplock_handler;
1777 tree1->session->transport->oplock.private_data = tree1;
1779 tree2->session->transport->oplock.handler = torture_oplock_handler;
1780 tree2->session->transport->oplock.private_data = tree2;
1783 base ntcreatex parms
1785 ZERO_STRUCT(io.smb2);
1786 io.generic.level = RAW_OPEN_SMB2;
1787 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1788 io.smb2.in.alloc_size = 0;
1789 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1790 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1791 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1792 io.smb2.in.create_options = 0;
1793 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1794 io.smb2.in.security_flags = 0;
1795 io.smb2.in.fname = fname;
1797 torture_comment(tctx, "BATCH13: open with batch oplock\n");
1798 ZERO_STRUCT(break_info);
1800 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1801 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1802 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1803 NTCREATEX_SHARE_ACCESS_WRITE|
1804 NTCREATEX_SHARE_ACCESS_DELETE;
1805 status = smb2_create(tree1, tctx, &(io.smb2));
1806 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1807 h1 = io.smb2.out.file.handle;
1808 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1810 ZERO_STRUCT(break_info);
1812 torture_comment(tctx, "second open with attributes only and "
1813 "NTCREATEX_DISP_OVERWRITE dispostion causes "
1814 "oplock break\n");
1816 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1817 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1818 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1819 SEC_FILE_WRITE_ATTRIBUTE |
1820 SEC_STD_SYNCHRONIZE;
1821 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1822 NTCREATEX_SHARE_ACCESS_WRITE|
1823 NTCREATEX_SHARE_ACCESS_DELETE;
1824 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
1825 status = smb2_create(tree2, tctx, &(io.smb2));
1826 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1827 h2 = io.smb2.out.file.handle;
1828 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1829 torture_wait_for_oplock_break(tctx);
1830 CHECK_VAL(break_info.count, 1);
1831 CHECK_VAL(break_info.failures, 0);
1833 smb2_util_close(tree1, h1);
1834 smb2_util_close(tree2, h2);
1835 smb2_util_close(tree1, h);
1837 smb2_deltree(tree1, BASEDIR);
1839 return ret;
1842 static bool test_smb2_oplock_batch14(struct torture_context *tctx,
1843 struct smb2_tree *tree1,
1844 struct smb2_tree *tree2)
1846 const char *fname = BASEDIR "\\test_batch14.dat";
1847 NTSTATUS status;
1848 bool ret = true;
1849 union smb_open io;
1850 struct smb2_handle h, h1, h2;
1852 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1853 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1855 /* cleanup */
1856 smb2_util_unlink(tree1, fname);
1858 tree1->session->transport->oplock.handler = torture_oplock_handler;
1859 tree1->session->transport->oplock.private_data = tree1;
1862 base ntcreatex parms
1864 ZERO_STRUCT(io.smb2);
1865 io.generic.level = RAW_OPEN_SMB2;
1866 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1867 io.smb2.in.alloc_size = 0;
1868 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1869 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1870 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1871 io.smb2.in.create_options = 0;
1872 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1873 io.smb2.in.security_flags = 0;
1874 io.smb2.in.fname = fname;
1876 torture_comment(tctx, "BATCH14: open with batch oplock\n");
1877 ZERO_STRUCT(break_info);
1879 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1880 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1881 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1882 NTCREATEX_SHARE_ACCESS_WRITE|
1883 NTCREATEX_SHARE_ACCESS_DELETE;
1884 status = smb2_create(tree1, tctx, &(io.smb2));
1885 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1886 h1 = io.smb2.out.file.handle;
1887 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1889 ZERO_STRUCT(break_info);
1891 torture_comment(tctx, "second open with attributes only and "
1892 "NTCREATEX_DISP_SUPERSEDE dispostion causes "
1893 "oplock break\n");
1895 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1896 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1897 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
1898 SEC_FILE_WRITE_ATTRIBUTE |
1899 SEC_STD_SYNCHRONIZE;
1900 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1901 NTCREATEX_SHARE_ACCESS_WRITE|
1902 NTCREATEX_SHARE_ACCESS_DELETE;
1903 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE;
1904 status = smb2_create(tree2, tctx, &(io.smb2));
1905 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
1906 h2 = io.smb2.out.file.handle;
1907 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
1909 torture_wait_for_oplock_break(tctx);
1910 CHECK_VAL(break_info.count, 1);
1911 CHECK_VAL(break_info.failures, 0);
1913 smb2_util_close(tree1, h1);
1914 smb2_util_close(tree2, h2);
1915 smb2_util_close(tree1, h);
1917 smb2_deltree(tree1, BASEDIR);
1918 return ret;
1921 static bool test_smb2_oplock_batch15(struct torture_context *tctx,
1922 struct smb2_tree *tree1,
1923 struct smb2_tree *tree2)
1925 const char *fname = BASEDIR "\\test_batch15.dat";
1926 NTSTATUS status;
1927 bool ret = true;
1928 union smb_open io;
1929 union smb_fileinfo qfi;
1930 struct smb2_handle h, h1;
1932 status = torture_smb2_testdir(tree1, BASEDIR, &h);
1933 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
1935 /* cleanup */
1936 smb2_util_unlink(tree1, fname);
1938 tree1->session->transport->oplock.handler = torture_oplock_handler;
1939 tree1->session->transport->oplock.private_data = tree1;
1942 base ntcreatex parms
1944 ZERO_STRUCT(io.smb2);
1945 io.generic.level = RAW_OPEN_SMB2;
1946 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1947 io.smb2.in.alloc_size = 0;
1948 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1949 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
1950 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1951 io.smb2.in.create_options = 0;
1952 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1953 io.smb2.in.security_flags = 0;
1954 io.smb2.in.fname = fname;
1956 /* Test if a qpathinfo all info on pathname breaks a batch oplock. */
1957 torture_comment(tctx, "BATCH15: Test if qpathinfo all info breaks "
1958 "a batch oplock (should not).\n");
1960 ZERO_STRUCT(break_info);
1962 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
1963 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
1964 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
1965 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
1966 NTCREATEX_SHARE_ACCESS_WRITE|
1967 NTCREATEX_SHARE_ACCESS_DELETE;
1968 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1969 status = smb2_create(tree1, tctx, &(io.smb2));
1970 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
1971 h1 = io.smb2.out.file.handle;
1973 torture_wait_for_oplock_break(tctx);
1974 CHECK_VAL(break_info.count, 0);
1975 CHECK_VAL(break_info.failures, 0);
1976 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
1978 ZERO_STRUCT(qfi);
1979 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
1980 qfi.generic.in.file.handle = h1;
1981 status = smb2_getinfo_file(tree2, tctx, &qfi);
1983 torture_wait_for_oplock_break(tctx);
1984 CHECK_VAL(break_info.count, 0);
1986 smb2_util_close(tree1, h1);
1987 smb2_util_close(tree1, h);
1989 smb2_deltree(tree1, BASEDIR);
1990 return ret;
1993 static bool test_smb2_oplock_batch16(struct torture_context *tctx,
1994 struct smb2_tree *tree1,
1995 struct smb2_tree *tree2)
1997 const char *fname = BASEDIR "\\test_batch16.dat";
1998 NTSTATUS status;
1999 bool ret = true;
2000 union smb_open io;
2001 struct smb2_handle h, h1, h2;
2003 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2004 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2006 /* cleanup */
2007 smb2_util_unlink(tree1, fname);
2009 tree1->session->transport->oplock.handler = torture_oplock_handler;
2010 tree1->session->transport->oplock.private_data = tree1;
2012 tree2->session->transport->oplock.handler = torture_oplock_handler;
2013 tree2->session->transport->oplock.private_data = tree2;
2016 base ntcreatex parms
2018 ZERO_STRUCT(io.smb2);
2019 io.generic.level = RAW_OPEN_SMB2;
2020 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2021 io.smb2.in.alloc_size = 0;
2022 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2023 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2024 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2025 io.smb2.in.create_options = 0;
2026 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2027 io.smb2.in.security_flags = 0;
2028 io.smb2.in.fname = fname;
2030 torture_comment(tctx, "BATCH16: open with batch oplock\n");
2031 ZERO_STRUCT(break_info);
2033 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2034 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2035 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2036 NTCREATEX_SHARE_ACCESS_WRITE|
2037 NTCREATEX_SHARE_ACCESS_DELETE;
2038 status = smb2_create(tree1, tctx, &(io.smb2));
2039 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2040 h1 = io.smb2.out.file.handle;
2041 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2043 ZERO_STRUCT(break_info);
2045 torture_comment(tctx, "second open with attributes only and "
2046 "NTCREATEX_DISP_OVERWRITE_IF dispostion causes "
2047 "oplock break\n");
2049 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2050 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2051 io.smb2.in.desired_access = SEC_FILE_READ_ATTRIBUTE |
2052 SEC_FILE_WRITE_ATTRIBUTE |
2053 SEC_STD_SYNCHRONIZE;
2054 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2055 NTCREATEX_SHARE_ACCESS_WRITE|
2056 NTCREATEX_SHARE_ACCESS_DELETE;
2057 io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE_IF;
2058 status = smb2_create(tree2, tctx, &(io.smb2));
2059 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2060 h2 = io.smb2.out.file.handle;
2061 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2063 torture_wait_for_oplock_break(tctx);
2064 CHECK_VAL(break_info.count, 1);
2065 CHECK_VAL(break_info.failures, 0);
2067 smb2_util_close(tree1, h1);
2068 smb2_util_close(tree2, h2);
2069 smb2_util_close(tree1, h);
2071 smb2_deltree(tree1, BASEDIR);
2072 return ret;
2075 /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH17 test. Since
2076 * SMB2 doesn't have a RENAME command this test isn't applicable. However,
2077 * it's much less confusing, when comparing test, to keep the SMB1 and SMB2
2078 * test numbers in sync. */
2079 #if 0
2080 static bool test_raw_oplock_batch17(struct torture_context *tctx,
2081 struct smb2_tree *tree1,
2082 struct smb2_tree *tree2)
2084 return true;
2086 #endif
2088 /* This function is a placeholder for the SMB1 RAW-OPLOCK-BATCH18 test. Since
2089 * SMB2 doesn't have an NTRENAME command this test isn't applicable. However,
2090 * it's much less confusing, when comparing tests, to keep the SMB1 and SMB2
2091 * test numbers in sync. */
2092 #if 0
2093 static bool test_raw_oplock_batch18(struct torture_context *tctx,
2094 struct smb2_tree *tree1,
2095 struct smb2_tree *tree2)
2097 return true;
2099 #endif
2101 static bool test_smb2_oplock_batch19(struct torture_context *tctx,
2102 struct smb2_tree *tree1)
2104 const char *fname1 = BASEDIR "\\test_batch19_1.dat";
2105 const char *fname2 = BASEDIR "\\test_batch19_2.dat";
2106 NTSTATUS status;
2107 bool ret = true;
2108 union smb_open io;
2109 union smb_fileinfo qfi;
2110 union smb_setfileinfo sfi;
2111 struct smb2_handle h, h1;
2113 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2114 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2116 /* cleanup */
2117 smb2_util_unlink(tree1, fname1);
2118 smb2_util_unlink(tree1, fname2);
2120 tree1->session->transport->oplock.handler = torture_oplock_handler;
2121 tree1->session->transport->oplock.private_data = tree1;
2124 base ntcreatex parms
2126 ZERO_STRUCT(io.smb2);
2127 io.generic.level = RAW_OPEN_SMB2;
2128 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2129 io.smb2.in.alloc_size = 0;
2130 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2131 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2132 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2133 io.smb2.in.create_options = 0;
2134 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2135 io.smb2.in.security_flags = 0;
2136 io.smb2.in.fname = fname1;
2138 torture_comment(tctx, "BATCH19: open a file with an batch oplock "
2139 "(share mode: none)\n");
2140 ZERO_STRUCT(break_info);
2141 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2142 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2143 status = smb2_create(tree1, tctx, &(io.smb2));
2144 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2145 h1 = io.smb2.out.file.handle;
2146 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2148 torture_comment(tctx, "setfileinfo rename info should not trigger "
2149 "a break but should cause a sharing violation\n");
2150 ZERO_STRUCT(sfi);
2151 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2152 sfi.generic.in.file.path = fname1;
2153 sfi.rename_information.in.file.handle = h1;
2154 sfi.rename_information.in.overwrite = 0;
2155 sfi.rename_information.in.root_fid = 0;
2156 sfi.rename_information.in.new_name = fname2;
2158 status = smb2_setinfo_file(tree1, &sfi);
2160 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2161 "Incorrect status");
2163 torture_wait_for_oplock_break(tctx);
2164 CHECK_VAL(break_info.count, 0);
2166 ZERO_STRUCT(qfi);
2167 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2168 qfi.generic.in.file.handle = h1;
2170 status = smb2_getinfo_file(tree1, tctx, &qfi);
2171 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2172 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2174 smb2_util_close(tree1, h1);
2175 smb2_util_close(tree1, h);
2177 smb2_deltree(tree1, fname1);
2178 smb2_deltree(tree1, fname2);
2179 return ret;
2182 static bool test_smb2_oplock_batch20(struct torture_context *tctx,
2183 struct smb2_tree *tree1,
2184 struct smb2_tree *tree2)
2186 const char *fname1 = BASEDIR "\\test_batch20_1.dat";
2187 const char *fname2 = BASEDIR "\\test_batch20_2.dat";
2188 NTSTATUS status;
2189 bool ret = true;
2190 union smb_open io;
2191 union smb_fileinfo qfi;
2192 union smb_setfileinfo sfi;
2193 struct smb2_handle h, h1, h2;
2195 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2196 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2198 /* cleanup */
2199 smb2_util_unlink(tree1, fname1);
2200 smb2_util_unlink(tree1, fname2);
2202 tree1->session->transport->oplock.handler = torture_oplock_handler;
2203 tree1->session->transport->oplock.private_data = tree1;
2206 base ntcreatex parms
2208 ZERO_STRUCT(io.smb2);
2209 io.generic.level = RAW_OPEN_SMB2;
2210 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2211 io.smb2.in.alloc_size = 0;
2212 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2213 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2214 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2215 io.smb2.in.create_options = 0;
2216 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2217 io.smb2.in.security_flags = 0;
2218 io.smb2.in.fname = fname1;
2220 torture_comment(tctx, "BATCH20: open a file with an batch oplock "
2221 "(share mode: all)\n");
2222 ZERO_STRUCT(break_info);
2223 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2224 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2225 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2226 NTCREATEX_SHARE_ACCESS_WRITE|
2227 NTCREATEX_SHARE_ACCESS_DELETE;
2228 status = smb2_create(tree1, tctx, &(io.smb2));
2229 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2230 h1 = io.smb2.out.file.handle;
2231 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2233 torture_comment(tctx, "setfileinfo rename info should not trigger "
2234 "a break but should cause a sharing violation\n");
2235 ZERO_STRUCT(sfi);
2236 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2237 sfi.rename_information.in.file.handle = h1;
2238 sfi.rename_information.in.overwrite = 0;
2239 sfi.rename_information.in.new_name = fname2;
2241 status = smb2_setinfo_file(tree1, &sfi);
2242 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2243 "Incorrect status");
2245 torture_wait_for_oplock_break(tctx);
2246 CHECK_VAL(break_info.count, 0);
2248 ZERO_STRUCT(qfi);
2249 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2250 qfi.generic.in.file.handle = h1;
2252 status = smb2_getinfo_file(tree1, tctx, &qfi);
2253 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2254 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2256 torture_comment(tctx, "open the file a second time requesting batch "
2257 "(share mode: all)\n");
2258 ZERO_STRUCT(break_info);
2259 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2260 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2261 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2262 NTCREATEX_SHARE_ACCESS_WRITE|
2263 NTCREATEX_SHARE_ACCESS_DELETE;
2264 io.smb2.in.fname = fname1;
2265 status = smb2_create(tree2, tctx, &(io.smb2));
2266 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2267 h2 = io.smb2.out.file.handle;
2268 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2270 torture_wait_for_oplock_break(tctx);
2271 CHECK_VAL(break_info.count, 1);
2272 CHECK_VAL(break_info.failures, 0);
2273 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2275 torture_comment(tctx, "setfileinfo rename info should not trigger "
2276 "a break but should cause a sharing violation\n");
2277 ZERO_STRUCT(break_info);
2278 ZERO_STRUCT(sfi);
2279 sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
2280 sfi.rename_information.in.file.handle = h2;
2281 sfi.rename_information.in.overwrite = 0;
2282 sfi.rename_information.in.new_name = fname2;
2284 status = smb2_setinfo_file(tree2, &sfi);
2285 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2286 "Incorrect status");
2288 torture_wait_for_oplock_break(tctx);
2289 CHECK_VAL(break_info.count, 0);
2291 ZERO_STRUCT(qfi);
2292 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2293 qfi.generic.in.file.handle = h1;
2295 status = smb2_getinfo_file(tree1, tctx, &qfi);
2296 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2297 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2299 ZERO_STRUCT(qfi);
2300 qfi.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION;
2301 qfi.generic.in.file.handle = h2;
2303 status = smb2_getinfo_file(tree2, tctx, &qfi);
2304 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2305 CHECK_STRMATCH(qfi.all_info2.out.fname.s, fname1);
2307 smb2_util_close(tree1, h1);
2308 smb2_util_close(tree2, h2);
2309 smb2_util_close(tree1, h);
2311 smb2_deltree(tree1, fname1);
2312 return ret;
2315 static bool test_smb2_oplock_batch21(struct torture_context *tctx,
2316 struct smb2_tree *tree1)
2318 const char *fname = BASEDIR "\\test_batch21.dat";
2319 NTSTATUS status;
2320 bool ret = true;
2321 union smb_open io;
2322 struct smb2_handle h, h1;
2323 char c = 0;
2325 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2326 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2328 /* cleanup */
2329 smb2_util_unlink(tree1, fname);
2331 tree1->session->transport->oplock.handler = torture_oplock_handler;
2332 tree1->session->transport->oplock.private_data = tree1;
2335 base ntcreatex parms
2337 ZERO_STRUCT(io.smb2);
2338 io.generic.level = RAW_OPEN_SMB2;
2339 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2340 io.smb2.in.alloc_size = 0;
2341 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2342 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2343 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2344 io.smb2.in.create_options = 0;
2345 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2346 io.smb2.in.security_flags = 0;
2347 io.smb2.in.fname = fname;
2350 with a batch oplock we get a break
2352 torture_comment(tctx, "BATCH21: open with batch oplock\n");
2353 ZERO_STRUCT(break_info);
2354 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2355 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2356 status = smb2_create(tree1, tctx, &(io.smb2));
2357 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2358 h1 = io.smb2.out.file.handle;
2359 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2361 torture_comment(tctx, "writing should not generate a break\n");
2362 status = smb2_util_write(tree1, h1, &c, 0, 1);
2363 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2365 torture_wait_for_oplock_break(tctx);
2366 CHECK_VAL(break_info.count, 0);
2368 smb2_util_close(tree1, h1);
2369 smb2_util_close(tree1, h);
2371 smb2_deltree(tree1, BASEDIR);
2372 return ret;
2375 static bool test_smb2_oplock_batch22(struct torture_context *tctx,
2376 struct smb2_tree *tree1)
2378 const char *fname = BASEDIR "\\test_batch22.dat";
2379 NTSTATUS status;
2380 bool ret = true;
2381 union smb_open io;
2382 struct smb2_handle h, h1, h2;
2383 struct timeval tv;
2384 int timeout = torture_setting_int(tctx, "oplocktimeout", 30);
2385 int te;
2387 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2388 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2390 /* cleanup */
2391 smb2_util_unlink(tree1, fname);
2393 tree1->session->transport->oplock.handler = torture_oplock_handler;
2394 tree1->session->transport->oplock.private_data = tree1;
2396 base ntcreatex parms
2398 ZERO_STRUCT(io.smb2);
2399 io.generic.level = RAW_OPEN_SMB2;
2400 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2401 io.smb2.in.alloc_size = 0;
2402 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2403 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2404 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2405 io.smb2.in.create_options = 0;
2406 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2407 io.smb2.in.security_flags = 0;
2408 io.smb2.in.fname = fname;
2411 with a batch oplock we get a break
2413 torture_comment(tctx, "BATCH22: open with batch oplock\n");
2414 ZERO_STRUCT(break_info);
2415 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2416 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2417 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
2418 NTCREATEX_SHARE_ACCESS_WRITE|
2419 NTCREATEX_SHARE_ACCESS_DELETE;
2420 status = smb2_create(tree1, tctx, &(io.smb2));
2421 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2422 h1 = io.smb2.out.file.handle;
2423 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2425 torture_comment(tctx, "a 2nd open should succeed after the oplock "
2426 "break timeout\n");
2427 tv = timeval_current();
2428 tree1->session->transport->oplock.handler =
2429 torture_oplock_handler_timeout;
2430 status = smb2_create(tree1, tctx, &(io.smb2));
2431 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2432 h2 = io.smb2.out.file.handle;
2433 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2435 torture_wait_for_oplock_break(tctx);
2436 te = (int)timeval_elapsed(&tv);
2437 CHECK_RANGE(te, timeout - 1, timeout + 15);
2438 torture_comment(tctx, "waited %d seconds for oplock timeout\n", te);
2440 CHECK_VAL(break_info.count, 1);
2441 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2442 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2443 CHECK_VAL(break_info.failures, 0);
2445 smb2_util_close(tree1, h1);
2446 smb2_util_close(tree1, h2);
2447 smb2_util_close(tree1, h);
2449 smb2_deltree(tree1, BASEDIR);
2450 return ret;
2453 static bool test_smb2_oplock_batch23(struct torture_context *tctx,
2454 struct smb2_tree *tree1,
2455 struct smb2_tree *tree2)
2457 const char *fname = BASEDIR "\\test_batch23.dat";
2458 NTSTATUS status;
2459 bool ret = true;
2460 union smb_open io;
2461 struct smb2_handle h, h1, h2, h3;
2462 struct smb2_tree *tree3 = NULL;
2464 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2465 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2467 /* cleanup */
2468 smb2_util_unlink(tree1, fname);
2470 ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2471 CHECK_VAL(ret, true);
2473 tree1->session->transport->oplock.handler = torture_oplock_handler;
2474 tree1->session->transport->oplock.private_data = tree1;
2476 tree2->session->transport->oplock.handler = torture_oplock_handler;
2477 tree2->session->transport->oplock.private_data = tree2;
2479 tree3->session->transport->oplock.handler = torture_oplock_handler;
2480 tree3->session->transport->oplock.private_data = tree3;
2483 base ntcreatex parms
2485 ZERO_STRUCT(io.smb2);
2486 io.generic.level = RAW_OPEN_SMB2;
2487 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2488 io.smb2.in.alloc_size = 0;
2489 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2490 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2491 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2492 io.smb2.in.create_options = 0;
2493 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2494 io.smb2.in.security_flags = 0;
2495 io.smb2.in.fname = fname;
2497 torture_comment(tctx, "BATCH23: an open and ask for a batch oplock\n");
2498 ZERO_STRUCT(break_info);
2500 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2501 SEC_RIGHTS_FILE_WRITE;
2502 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2503 NTCREATEX_SHARE_ACCESS_WRITE;
2504 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2505 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2506 status = smb2_create(tree1, tctx, &(io.smb2));
2507 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2508 h1 = io.smb2.out.file.handle;
2509 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2511 ZERO_STRUCT(break_info);
2513 torture_comment(tctx, "a 2nd open without level2 oplock support "
2514 "should generate a break to level2\n");
2515 status = smb2_create(tree3, tctx, &(io.smb2));
2516 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2517 h3 = io.smb2.out.file.handle;
2519 torture_wait_for_oplock_break(tctx);
2520 CHECK_VAL(break_info.count, 1);
2521 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2522 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2523 CHECK_VAL(break_info.failures, 0);
2525 ZERO_STRUCT(break_info);
2527 torture_comment(tctx, "a 3rd open with level2 oplock support should "
2528 "not generate a break\n");
2529 status = smb2_create(tree2, tctx, &(io.smb2));
2530 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2531 h2 = io.smb2.out.file.handle;
2532 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2534 torture_wait_for_oplock_break(tctx);
2535 CHECK_VAL(break_info.count, 0);
2537 smb2_util_close(tree1, h1);
2538 smb2_util_close(tree2, h2);
2539 smb2_util_close(tree3, h3);
2540 smb2_util_close(tree1, h);
2542 smb2_deltree(tree1, BASEDIR);
2543 return ret;
2546 static bool test_smb2_oplock_batch24(struct torture_context *tctx,
2547 struct smb2_tree *tree1,
2548 struct smb2_tree *tree2)
2550 const char *fname = BASEDIR "\\test_batch24.dat";
2551 NTSTATUS status;
2552 bool ret = true;
2553 union smb_open io;
2554 struct smb2_handle h, h1, h2;
2555 struct smb2_tree *tree3 = NULL;
2557 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2558 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2560 /* cleanup */
2561 smb2_util_unlink(tree1, fname);
2563 ret = open_smb2_connection_no_level2_oplocks(tctx, &tree3);
2564 CHECK_VAL(ret, true);
2566 tree1->session->transport->oplock.handler = torture_oplock_handler;
2567 tree1->session->transport->oplock.private_data = tree1;
2569 tree2->session->transport->oplock.handler = torture_oplock_handler;
2570 tree2->session->transport->oplock.private_data = tree2;
2572 tree3->session->transport->oplock.handler = torture_oplock_handler;
2573 tree3->session->transport->oplock.private_data = tree3;
2576 base ntcreatex parms
2578 ZERO_STRUCT(io.smb2);
2579 io.generic.level = RAW_OPEN_SMB2;
2580 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2581 io.smb2.in.alloc_size = 0;
2582 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2583 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2584 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2585 io.smb2.in.create_options = 0;
2586 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2587 io.smb2.in.security_flags = 0;
2588 io.smb2.in.fname = fname;
2590 torture_comment(tctx, "BATCH24: a open without level support and "
2591 "ask for a batch oplock\n");
2592 ZERO_STRUCT(break_info);
2594 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2595 SEC_RIGHTS_FILE_WRITE;
2596 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2597 NTCREATEX_SHARE_ACCESS_WRITE;
2598 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2599 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2601 status = smb2_create(tree3, tctx, &(io.smb2));
2602 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2603 h2 = io.smb2.out.file.handle;
2604 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2606 ZERO_STRUCT(break_info);
2608 torture_comment(tctx, "a 2nd open with level2 oplock support should "
2609 "generate a break\n");
2610 status = smb2_create(tree2, tctx, &(io.smb2));
2611 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2612 h1 = io.smb2.out.file.handle;
2613 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2615 torture_wait_for_oplock_break(tctx);
2616 CHECK_VAL(break_info.count, 1);
2617 CHECK_VAL(break_info.handle.data[0], h2.data[0]);
2618 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2619 CHECK_VAL(break_info.failures, 0);
2621 smb2_util_close(tree3, h2);
2622 smb2_util_close(tree2, h1);
2623 smb2_util_close(tree1, h);
2625 smb2_deltree(tree1, BASEDIR);
2626 return ret;
2629 static bool test_smb2_oplock_batch25(struct torture_context *tctx,
2630 struct smb2_tree *tree1)
2632 const char *fname = BASEDIR "\\test_batch25.dat";
2633 NTSTATUS status;
2634 bool ret = true;
2635 union smb_open io;
2636 struct smb2_handle h, h1;
2638 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2639 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2641 /* cleanup */
2642 smb2_util_unlink(tree1, fname);
2644 tree1->session->transport->oplock.handler = torture_oplock_handler;
2645 tree1->session->transport->oplock.private_data = tree1;
2648 base ntcreatex parms
2650 ZERO_STRUCT(io.smb2);
2651 io.generic.level = RAW_OPEN_SMB2;
2652 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2653 io.smb2.in.alloc_size = 0;
2654 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2655 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2656 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2657 io.smb2.in.create_options = 0;
2658 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2659 io.smb2.in.security_flags = 0;
2660 io.smb2.in.fname = fname;
2662 torture_comment(tctx, "BATCH25: open a file with an batch oplock "
2663 "(share mode: none)\n");
2665 ZERO_STRUCT(break_info);
2666 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2667 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2669 status = smb2_create(tree1, tctx, &(io.smb2));
2670 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2671 h1 = io.smb2.out.file.handle;
2672 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2674 torture_comment(tctx, "changing the file attribute info should trigger "
2675 "a break and a violation\n");
2677 status = smb2_util_setatr(tree1, fname, FILE_ATTRIBUTE_HIDDEN);
2678 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_SHARING_VIOLATION,
2679 "Incorrect status");
2681 torture_wait_for_oplock_break(tctx);
2682 CHECK_VAL(break_info.count, 1);
2684 smb2_util_close(tree1, h1);
2685 smb2_util_close(tree1, h);
2687 smb2_deltree(tree1, fname);
2688 return ret;
2691 /* Test how oplocks work on streams. */
2692 static bool test_raw_oplock_stream1(struct torture_context *tctx,
2693 struct smb2_tree *tree1,
2694 struct smb2_tree *tree2)
2696 NTSTATUS status;
2697 union smb_open io;
2698 const char *fname_base = BASEDIR "\\test_stream1.txt";
2699 const char *fname_stream, *fname_default_stream;
2700 const char *default_stream = "::$DATA";
2701 const char *stream = "Stream One:$DATA";
2702 bool ret = true;
2703 struct smb2_handle h, h_base, h_stream;
2704 int i;
2706 #define NSTREAM_OPLOCK_RESULTS 8
2707 struct {
2708 const char **fname;
2709 bool open_base_file;
2710 uint32_t oplock_req;
2711 uint32_t oplock_granted;
2712 } stream_oplock_results[NSTREAM_OPLOCK_RESULTS] = {
2713 /* Request oplock on stream without the base file open. */
2714 {&fname_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
2715 {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
2716 {&fname_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
2717 {&fname_default_stream, false, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
2719 /* Request oplock on stream with the base file open. */
2720 {&fname_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_BATCH},
2721 {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_BATCH, SMB2_OPLOCK_LEVEL_II},
2722 {&fname_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_EXCLUSIVE},
2723 {&fname_default_stream, true, SMB2_OPLOCK_LEVEL_EXCLUSIVE, SMB2_OPLOCK_LEVEL_II},
2726 fname_stream = talloc_asprintf(tctx, "%s:%s", fname_base, stream);
2727 fname_default_stream = talloc_asprintf(tctx, "%s%s", fname_base,
2728 default_stream);
2730 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2731 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2733 /* Initialize handles to "closed". Using -1 in the first 64-bytes
2734 * as the sentry for this */
2735 h_stream.data[0] = -1;
2737 /* cleanup */
2738 smb2_util_unlink(tree1, fname_base);
2740 tree1->session->transport->oplock.handler = torture_oplock_handler;
2741 tree1->session->transport->oplock.private_data = tree1;
2743 tree2->session->transport->oplock.handler = torture_oplock_handler;
2744 tree2->session->transport->oplock.private_data = tree2;
2746 /* Setup generic open parameters. */
2747 ZERO_STRUCT(io.smb2);
2748 io.generic.level = RAW_OPEN_SMB2;
2749 io.smb2.in.desired_access = (SEC_FILE_READ_DATA |
2750 SEC_FILE_WRITE_DATA |
2751 SEC_FILE_APPEND_DATA |
2752 SEC_STD_READ_CONTROL);
2753 io.smb2.in.alloc_size = 0;
2754 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2755 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2756 NTCREATEX_SHARE_ACCESS_WRITE;
2757 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2758 io.smb2.in.create_options = 0;
2759 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2760 io.smb2.in.security_flags = 0;
2762 /* Create the file with a stream */
2763 io.smb2.in.fname = fname_stream;
2764 io.smb2.in.create_flags = 0;
2765 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
2766 status = smb2_create(tree1, tctx, &(io.smb2));
2767 torture_assert_ntstatus_ok(tctx, status, "Error creating file");
2768 smb2_util_close(tree1, io.smb2.out.file.handle);
2770 /* Change the disposition to open now that the file has been created. */
2771 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
2773 /* Try some permutations of taking oplocks on streams. */
2774 for (i = 0; i < NSTREAM_OPLOCK_RESULTS; i++) {
2775 const char *fname = *stream_oplock_results[i].fname;
2776 bool open_base_file = stream_oplock_results[i].open_base_file;
2777 uint32_t oplock_req = stream_oplock_results[i].oplock_req;
2778 uint32_t oplock_granted =
2779 stream_oplock_results[i].oplock_granted;
2781 if (open_base_file) {
2782 torture_comment(tctx, "Opening base file: %s with "
2783 "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
2784 io.smb2.in.fname = fname_base;
2785 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2786 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2787 status = smb2_create(tree2, tctx, &(io.smb2));
2788 torture_assert_ntstatus_ok(tctx, status,
2789 "Error opening file");
2790 CHECK_VAL(io.smb2.out.oplock_level,
2791 SMB2_OPLOCK_LEVEL_BATCH);
2792 h_base = io.smb2.out.file.handle;
2795 torture_comment(tctx, "%d: Opening stream: %s with %d\n", i,
2796 fname, oplock_req);
2797 io.smb2.in.fname = fname;
2798 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2799 io.smb2.in.oplock_level = oplock_req;
2801 /* Do the open with the desired oplock on the stream. */
2802 status = smb2_create(tree1, tctx, &(io.smb2));
2803 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2804 CHECK_VAL(io.smb2.out.oplock_level, oplock_granted);
2805 smb2_util_close(tree1, io.smb2.out.file.handle);
2807 /* Cleanup the base file if it was opened. */
2808 if (open_base_file)
2809 smb2_util_close(tree2, h_base);
2812 /* Open the stream with an exclusive oplock. */
2813 torture_comment(tctx, "Opening stream: %s with %d\n",
2814 fname_stream, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
2815 io.smb2.in.fname = fname_stream;
2816 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2817 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
2818 status = smb2_create(tree1, tctx, &(io.smb2));
2819 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2820 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_EXCLUSIVE);
2821 h_stream = io.smb2.out.file.handle;
2823 /* Open the base file and see if it contends. */
2824 ZERO_STRUCT(break_info);
2825 torture_comment(tctx, "Opening base file: %s with %d\n",
2826 fname_base, SMB2_OPLOCK_LEVEL_BATCH);
2827 io.smb2.in.fname = fname_base;
2828 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2829 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2830 status = smb2_create(tree2, tctx, &(io.smb2));
2831 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2832 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2833 smb2_util_close(tree2, io.smb2.out.file.handle);
2835 torture_wait_for_oplock_break(tctx);
2836 CHECK_VAL(break_info.count, 0);
2837 CHECK_VAL(break_info.failures, 0);
2839 /* Open the stream again to see if it contends. */
2840 ZERO_STRUCT(break_info);
2841 torture_comment(tctx, "Opening stream again: %s with "
2842 "%d\n", fname_base, SMB2_OPLOCK_LEVEL_BATCH);
2843 io.smb2.in.fname = fname_stream;
2844 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2845 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
2846 status = smb2_create(tree2, tctx, &(io.smb2));
2847 torture_assert_ntstatus_ok(tctx, status, "Error opening file");
2848 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
2849 smb2_util_close(tree2, io.smb2.out.file.handle);
2851 torture_wait_for_oplock_break(tctx);
2852 CHECK_VAL(break_info.count, 1);
2853 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
2854 CHECK_VAL(break_info.failures, 0);
2856 /* Close the stream. */
2857 if (h_stream.data[0] != -1) {
2858 smb2_util_close(tree1, h_stream);
2861 smb2_util_close(tree1, h);
2863 smb2_deltree(tree1, BASEDIR);
2864 return ret;
2867 static bool test_smb2_oplock_doc(struct torture_context *tctx, struct smb2_tree *tree)
2869 const char *fname = BASEDIR "\\test_oplock_doc.dat";
2870 NTSTATUS status;
2871 bool ret = true;
2872 union smb_open io;
2873 struct smb2_handle h, h1;
2875 status = torture_smb2_testdir(tree, BASEDIR, &h);
2876 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2878 /* cleanup */
2879 smb2_util_unlink(tree, fname);
2880 tree->session->transport->oplock.handler = torture_oplock_handler;
2881 tree->session->transport->oplock.private_data = tree;
2884 base ntcreatex parms
2886 ZERO_STRUCT(io.smb2);
2887 io.generic.level = RAW_OPEN_SMB2;
2888 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
2889 io.smb2.in.alloc_size = 0;
2890 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2891 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
2892 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2893 io.smb2.in.create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
2894 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2895 io.smb2.in.security_flags = 0;
2896 io.smb2.in.fname = fname;
2898 torture_comment(tctx, "open a delete-on-close file with a batch "
2899 "oplock\n");
2900 ZERO_STRUCT(break_info);
2901 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2902 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2904 status = smb2_create(tree, tctx, &(io.smb2));
2905 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2906 h1 = io.smb2.out.file.handle;
2907 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2909 smb2_util_close(tree, h1);
2911 smb2_util_unlink(tree, fname);
2912 smb2_deltree(tree, BASEDIR);
2913 return ret;
2916 /* Open a file with a batch oplock, then open it again from a second client
2917 * requesting no oplock. Having two open file handles should break our own
2918 * oplock during BRL acquisition.
2920 static bool test_smb2_oplock_brl1(struct torture_context *tctx,
2921 struct smb2_tree *tree1,
2922 struct smb2_tree *tree2)
2924 const char *fname = BASEDIR "\\test_batch_brl.dat";
2925 /*int fname, f;*/
2926 bool ret = true;
2927 uint8_t buf[1000];
2928 bool correct = true;
2929 union smb_open io;
2930 NTSTATUS status;
2931 struct smb2_lock lck;
2932 struct smb2_lock_element lock[1];
2933 struct smb2_handle h, h1, h2;
2935 status = torture_smb2_testdir(tree1, BASEDIR, &h);
2936 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
2938 /* cleanup */
2939 smb2_util_unlink(tree1, fname);
2941 tree1->session->transport->oplock.handler =
2942 torture_oplock_handler_two_notifications;
2943 tree1->session->transport->oplock.private_data = tree1;
2946 base ntcreatex parms
2948 ZERO_STRUCT(io.smb2);
2949 io.generic.level = RAW_OPEN_SMB2;
2950 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
2951 SEC_RIGHTS_FILE_WRITE;
2952 io.smb2.in.alloc_size = 0;
2953 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
2954 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2955 NTCREATEX_SHARE_ACCESS_WRITE;
2956 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
2957 io.smb2.in.create_options = 0;
2958 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
2959 io.smb2.in.security_flags = 0;
2960 io.smb2.in.fname = fname;
2963 with a batch oplock we get a break
2965 torture_comment(tctx, "open with batch oplock\n");
2966 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2967 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
2969 status = smb2_create(tree1, tctx, &(io.smb2));
2970 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
2971 h1 = io.smb2.out.file.handle;
2972 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
2974 /* create a file with bogus data */
2975 memset(buf, 0, sizeof(buf));
2977 status = smb2_util_write(tree1, h1,buf, 0, sizeof(buf));
2978 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
2979 torture_comment(tctx, "Failed to create file\n");
2980 correct = false;
2981 goto done;
2984 torture_comment(tctx, "a 2nd open should give a break\n");
2985 ZERO_STRUCT(break_info);
2987 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
2988 io.smb2.in.oplock_level = 0;
2989 status = smb2_create(tree2, tctx, &(io.smb2));
2990 h2 = io.smb2.out.file.handle;
2991 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
2993 torture_wait_for_oplock_break(tctx);
2994 CHECK_VAL(break_info.count, 1);
2995 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
2996 CHECK_VAL(break_info.failures, 0);
2997 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
2999 ZERO_STRUCT(break_info);
3001 torture_comment(tctx, "a self BRL acquisition should break to none\n");
3002 lock[0].offset = 0;
3003 lock[0].length = 4;
3004 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3005 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3007 ZERO_STRUCT(lck);
3008 lck.in.file.handle = h1;
3009 lck.in.locks = &lock[0];
3010 lck.in.lock_count = 1;
3011 status = smb2_lock(tree1, &lck);
3012 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3014 torture_wait_for_oplock_break(tctx);
3015 CHECK_VAL(break_info.count, 1);
3016 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3017 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3018 CHECK_VAL(break_info.failures, 0);
3020 /* expect no oplock break */
3021 ZERO_STRUCT(break_info);
3022 lock[0].offset = 2;
3023 status = smb2_lock(tree1, &lck);
3024 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3025 "Incorrect status");
3027 torture_wait_for_oplock_break(tctx);
3028 CHECK_VAL(break_info.count, 0);
3029 CHECK_VAL(break_info.level, 0);
3030 CHECK_VAL(break_info.failures, 0);
3032 smb2_util_close(tree1, h1);
3033 smb2_util_close(tree2, h2);
3034 smb2_util_close(tree1, h);
3036 done:
3037 smb2_deltree(tree1, BASEDIR);
3038 return ret;
3042 /* Open a file with a batch oplock on one tree and then acquire a brl.
3043 * We should not contend our own oplock.
3045 static bool test_smb2_oplock_brl2(struct torture_context *tctx, struct smb2_tree *tree1)
3047 const char *fname = BASEDIR "\\test_batch_brl.dat";
3048 /*int fname, f;*/
3049 bool ret = true;
3050 uint8_t buf[1000];
3051 bool correct = true;
3052 union smb_open io;
3053 NTSTATUS status;
3054 struct smb2_handle h, h1;
3055 struct smb2_lock lck;
3056 struct smb2_lock_element lock[1];
3058 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3059 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3061 /* cleanup */
3062 smb2_util_unlink(tree1, fname);
3064 tree1->session->transport->oplock.handler = torture_oplock_handler;
3065 tree1->session->transport->oplock.private_data = tree1;
3068 base ntcreatex parms
3070 ZERO_STRUCT(io.smb2);
3071 io.generic.level = RAW_OPEN_SMB2;
3072 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3073 SEC_RIGHTS_FILE_WRITE;
3074 io.smb2.in.alloc_size = 0;
3075 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3076 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3077 NTCREATEX_SHARE_ACCESS_WRITE;
3078 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3079 io.smb2.in.create_options = 0;
3080 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3081 io.smb2.in.security_flags = 0;
3082 io.smb2.in.fname = fname;
3085 with a batch oplock we get a break
3087 torture_comment(tctx, "open with batch oplock\n");
3088 ZERO_STRUCT(break_info);
3089 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3090 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3092 status = smb2_create(tree1, tctx, &(io.smb2));
3093 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3094 h1 = io.smb2.out.file.handle;
3095 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3097 /* create a file with bogus data */
3098 memset(buf, 0, sizeof(buf));
3100 status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3101 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3102 torture_comment(tctx, "Failed to create file\n");
3103 correct = false;
3104 goto done;
3107 ZERO_STRUCT(break_info);
3109 torture_comment(tctx, "a self BRL acquisition should not break to "
3110 "none\n");
3112 lock[0].offset = 0;
3113 lock[0].length = 4;
3114 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3115 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3117 ZERO_STRUCT(lck);
3118 lck.in.file.handle = h1;
3119 lck.in.locks = &lock[0];
3120 lck.in.lock_count = 1;
3121 status = smb2_lock(tree1, &lck);
3122 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3124 lock[0].offset = 2;
3125 status = smb2_lock(tree1, &lck);
3126 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3127 "Incorrect status");
3129 /* With one file handle open a BRL should not contend our oplock.
3130 * Thus, no oplock break will be received and the entire break_info
3131 * struct will be 0 */
3132 torture_wait_for_oplock_break(tctx);
3133 CHECK_VAL(break_info.count, 0);
3134 CHECK_VAL(break_info.level, 0);
3135 CHECK_VAL(break_info.failures, 0);
3137 smb2_util_close(tree1, h1);
3138 smb2_util_close(tree1, h);
3140 done:
3141 smb2_deltree(tree1, BASEDIR);
3142 return ret;
3145 /* Open a file with a batch oplock twice from one tree and then acquire a
3146 * brl. BRL acquisition should break our own oplock.
3148 static bool test_smb2_oplock_brl3(struct torture_context *tctx, struct smb2_tree *tree1)
3150 const char *fname = BASEDIR "\\test_batch_brl.dat";
3151 bool ret = true;
3152 uint8_t buf[1000];
3153 bool correct = true;
3154 union smb_open io;
3155 NTSTATUS status;
3156 struct smb2_handle h, h1, h2;
3157 struct smb2_lock lck;
3158 struct smb2_lock_element lock[1];
3160 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3161 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3163 /* cleanup */
3164 smb2_util_unlink(tree1, fname);
3165 tree1->session->transport->oplock.handler =
3166 torture_oplock_handler_two_notifications;
3167 tree1->session->transport->oplock.private_data = tree1;
3170 base ntcreatex parms
3172 ZERO_STRUCT(io.smb2);
3173 io.generic.level = RAW_OPEN_SMB2;
3174 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3175 SEC_RIGHTS_FILE_WRITE;
3176 io.smb2.in.alloc_size = 0;
3177 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3178 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3179 NTCREATEX_SHARE_ACCESS_WRITE;
3180 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3181 io.smb2.in.create_options = 0;
3182 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3183 io.smb2.in.security_flags = 0;
3184 io.smb2.in.fname = fname;
3187 with a batch oplock we get a break
3189 torture_comment(tctx, "open with batch oplock\n");
3190 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3191 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3193 status = smb2_create(tree1, tctx, &(io.smb2));
3194 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3195 h1 = io.smb2.out.file.handle;
3196 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
3198 /* create a file with bogus data */
3199 memset(buf, 0, sizeof(buf));
3200 status = smb2_util_write(tree1, h1, buf, 0, sizeof(buf));
3202 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3203 torture_comment(tctx, "Failed to create file\n");
3204 correct = false;
3205 goto done;
3208 torture_comment(tctx, "a 2nd open should give a break\n");
3209 ZERO_STRUCT(break_info);
3211 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3212 io.smb2.in.oplock_level = 0;
3213 status = smb2_create(tree1, tctx, &(io.smb2));
3214 h2 = io.smb2.out.file.handle;
3215 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3216 CHECK_VAL(break_info.count, 1);
3217 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_II);
3218 CHECK_VAL(break_info.failures, 0);
3219 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3221 ZERO_STRUCT(break_info);
3223 torture_comment(tctx, "a self BRL acquisition should break to none\n");
3225 lock[0].offset = 0;
3226 lock[0].length = 4;
3227 lock[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE |
3228 SMB2_LOCK_FLAG_FAIL_IMMEDIATELY;
3230 ZERO_STRUCT(lck);
3231 lck.in.file.handle = h1;
3232 lck.in.locks = &lock[0];
3233 lck.in.lock_count = 1;
3234 status = smb2_lock(tree1, &lck);
3235 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3237 torture_wait_for_oplock_break(tctx);
3238 CHECK_VAL(break_info.count, 1);
3239 CHECK_VAL(break_info.level, SMB2_OPLOCK_LEVEL_NONE);
3240 CHECK_VAL(break_info.handle.data[0], h1.data[0]);
3241 CHECK_VAL(break_info.failures, 0);
3243 /* expect no oplock break */
3244 ZERO_STRUCT(break_info);
3245 lock[0].offset = 2;
3246 status = smb2_lock(tree1, &lck);
3247 torture_assert_ntstatus_equal(tctx, status, NT_STATUS_LOCK_NOT_GRANTED,
3248 "Incorrect status");
3250 torture_wait_for_oplock_break(tctx);
3251 CHECK_VAL(break_info.count, 0);
3252 CHECK_VAL(break_info.level, 0);
3253 CHECK_VAL(break_info.failures, 0);
3255 smb2_util_close(tree1, h1);
3256 smb2_util_close(tree1, h2);
3257 smb2_util_close(tree1, h);
3259 done:
3260 smb2_deltree(tree1, BASEDIR);
3261 return ret;
3265 /* Starting the SMB2 specific oplock tests at 500 so we can keep the SMB1
3266 * tests in sync with an identically numbered SMB2 test */
3268 /* Test whether the server correctly returns an error when we send
3269 * a response to a levelII to none oplock notification. */
3270 static bool test_smb2_oplock_levelII500(struct torture_context *tctx,
3271 struct smb2_tree *tree1)
3273 const char *fname = BASEDIR "\\test_levelII500.dat";
3274 NTSTATUS status;
3275 bool ret = true;
3276 union smb_open io;
3277 struct smb2_handle h, h1;
3278 char c = 0;
3280 status = torture_smb2_testdir(tree1, BASEDIR, &h);
3281 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3283 /* cleanup */
3284 smb2_util_unlink(tree1, fname);
3286 tree1->session->transport->oplock.handler = torture_oplock_handler;
3287 tree1->session->transport->oplock.private_data = tree1;
3290 base ntcreatex parms
3292 ZERO_STRUCT(io.smb2);
3293 io.generic.level = RAW_OPEN_SMB2;
3294 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3295 io.smb2.in.alloc_size = 0;
3296 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3297 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3298 io.smb2.in.create_options = 0;
3299 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3300 io.smb2.in.security_flags = 0;
3301 io.smb2.in.fname = fname;
3303 torture_comment(tctx, "LEVELII500: acknowledging a break from II to "
3304 "none should return an error\n");
3305 ZERO_STRUCT(break_info);
3307 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ |
3308 SEC_RIGHTS_FILE_WRITE;
3309 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
3310 NTCREATEX_SHARE_ACCESS_WRITE;
3311 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3312 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II;
3313 status = smb2_create(tree1, tctx, &(io.smb2));
3314 torture_assert_ntstatus_ok(tctx, status, "Error opening the file");
3315 h1 = io.smb2.out.file.handle;
3316 CHECK_VAL(io.smb2.out.oplock_level, SMB2_OPLOCK_LEVEL_II);
3318 ZERO_STRUCT(break_info);
3320 torture_comment(tctx, "write should trigger a break to none and when "
3321 "we reply, an oplock break failure\n");
3322 smb2_util_write(tree1, h1, &c, 0, 1);
3324 /* Wait several times to receive both the break notification, and the
3325 * NT_STATUS_INVALID_OPLOCK_PROTOCOL error in the break response */
3326 torture_wait_for_oplock_break(tctx);
3327 torture_wait_for_oplock_break(tctx);
3328 torture_wait_for_oplock_break(tctx);
3329 torture_wait_for_oplock_break(tctx);
3331 /* There appears to be a race condition in W2K8 and W2K8R2 where
3332 * sometimes the server will happily reply to our break response with
3333 * NT_STATUS_OK, and sometimes it will return the OPLOCK_PROTOCOL
3334 * error. As the MS-SMB2 doc states that a client should not reply to
3335 * a level2 to none break notification, I'm leaving the protocol error
3336 * as the expected behavior. */
3337 CHECK_VAL(break_info.count, 1);
3338 CHECK_VAL(break_info.level, 0);
3339 CHECK_VAL(break_info.failures, 1);
3340 torture_assert_ntstatus_equal(tctx, break_info.failure_status,
3341 NT_STATUS_INVALID_OPLOCK_PROTOCOL,
3342 "Incorrect status");
3344 smb2_util_close(tree1, h1);
3345 smb2_util_close(tree1, h);
3347 smb2_deltree(tree1, BASEDIR);
3348 return ret;
3351 struct torture_suite *torture_smb2_oplocks_init(void)
3353 struct torture_suite *suite =
3354 torture_suite_create(talloc_autofree_context(), "oplock");
3356 torture_suite_add_2smb2_test(suite, "exclusive1", test_smb2_oplock_exclusive1);
3357 torture_suite_add_2smb2_test(suite, "exclusive2", test_smb2_oplock_exclusive2);
3358 torture_suite_add_2smb2_test(suite, "exclusive3", test_smb2_oplock_exclusive3);
3359 torture_suite_add_2smb2_test(suite, "exclusive4", test_smb2_oplock_exclusive4);
3360 torture_suite_add_2smb2_test(suite, "exclusive5", test_smb2_oplock_exclusive5);
3361 torture_suite_add_2smb2_test(suite, "exclusive6", test_smb2_oplock_exclusive6);
3362 torture_suite_add_2smb2_test(suite, "batch1", test_smb2_oplock_batch1);
3363 torture_suite_add_2smb2_test(suite, "batch2", test_smb2_oplock_batch2);
3364 torture_suite_add_2smb2_test(suite, "batch3", test_smb2_oplock_batch3);
3365 torture_suite_add_2smb2_test(suite, "batch4", test_smb2_oplock_batch4);
3366 torture_suite_add_2smb2_test(suite, "batch5", test_smb2_oplock_batch5);
3367 torture_suite_add_2smb2_test(suite, "batch6", test_smb2_oplock_batch6);
3368 torture_suite_add_2smb2_test(suite, "batch7", test_smb2_oplock_batch7);
3369 torture_suite_add_2smb2_test(suite, "batch8", test_smb2_oplock_batch8);
3370 torture_suite_add_2smb2_test(suite, "batch9", test_smb2_oplock_batch9);
3371 torture_suite_add_2smb2_test(suite, "batch10", test_smb2_oplock_batch10);
3372 torture_suite_add_2smb2_test(suite, "batch11", test_smb2_oplock_batch11);
3373 torture_suite_add_2smb2_test(suite, "batch12", test_smb2_oplock_batch12);
3374 torture_suite_add_2smb2_test(suite, "batch13", test_smb2_oplock_batch13);
3375 torture_suite_add_2smb2_test(suite, "batch14", test_smb2_oplock_batch14);
3376 torture_suite_add_2smb2_test(suite, "batch15", test_smb2_oplock_batch15);
3377 torture_suite_add_2smb2_test(suite, "batch16", test_smb2_oplock_batch16);
3378 torture_suite_add_1smb2_test(suite, "batch19", test_smb2_oplock_batch19);
3379 torture_suite_add_2smb2_test(suite, "batch20", test_smb2_oplock_batch20);
3380 torture_suite_add_1smb2_test(suite, "batch21", test_smb2_oplock_batch21);
3381 torture_suite_add_1smb2_test(suite, "batch22", test_smb2_oplock_batch22);
3382 torture_suite_add_2smb2_test(suite, "batch23", test_smb2_oplock_batch23);
3383 torture_suite_add_2smb2_test(suite, "batch24", test_smb2_oplock_batch24);
3384 torture_suite_add_1smb2_test(suite, "batch25", test_smb2_oplock_batch25);
3385 torture_suite_add_2smb2_test(suite, "stream1", test_raw_oplock_stream1);
3386 torture_suite_add_1smb2_test(suite, "doc", test_smb2_oplock_doc);
3387 torture_suite_add_2smb2_test(suite, "brl1", test_smb2_oplock_brl1);
3388 torture_suite_add_1smb2_test(suite, "brl2", test_smb2_oplock_brl2);
3389 torture_suite_add_1smb2_test(suite, "brl3", test_smb2_oplock_brl3);
3390 torture_suite_add_1smb2_test(suite, "levelii500", test_smb2_oplock_levelII500);
3392 suite->description = talloc_strdup(suite, "SMB2-OPLOCK tests");
3394 return suite;
3398 stress testing of oplocks
3400 bool test_smb2_bench_oplock(struct torture_context *tctx,
3401 struct smb2_tree *tree)
3403 struct smb2_tree **trees;
3404 bool ret = true;
3405 NTSTATUS status;
3406 TALLOC_CTX *mem_ctx = talloc_new(tctx);
3407 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
3408 int i, count=0;
3409 int timelimit = torture_setting_int(tctx, "timelimit", 10);
3410 union smb_open io;
3411 struct timeval tv;
3412 struct smb2_handle h;
3414 trees = talloc_array(mem_ctx, struct smb2_tree *, torture_nprocs);
3416 torture_comment(tctx, "Opening %d connections\n", torture_nprocs);
3417 for (i=0;i<torture_nprocs;i++) {
3418 if (!torture_smb2_connection(tctx, &trees[i])) {
3419 return false;
3421 talloc_steal(mem_ctx, trees[i]);
3422 trees[i]->session->transport->oplock.handler =
3423 torture_oplock_handler_close;
3424 trees[i]->session->transport->oplock.private_data = trees[i];
3427 status = torture_smb2_testdir(trees[0], BASEDIR, &h);
3428 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3430 ZERO_STRUCT(io.smb2);
3431 io.smb2.level = RAW_OPEN_SMB2;
3432 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3433 io.smb2.in.alloc_size = 0;
3434 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3435 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
3436 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3437 io.smb2.in.create_options = 0;
3438 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3439 io.smb2.in.security_flags = 0;
3440 io.smb2.in.fname = BASEDIR "\\test.dat";
3441 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3442 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3444 tv = timeval_current();
3447 we open the same file with SHARE_ACCESS_NONE from all the
3448 connections in a round robin fashion. Each open causes an
3449 oplock break on the previous connection, which is answered
3450 by the oplock_handler_close() to close the file.
3452 This measures how fast we can pass on oplocks, and stresses
3453 the oplock handling code
3455 torture_comment(tctx, "Running for %d seconds\n", timelimit);
3456 while (timeval_elapsed(&tv) < timelimit) {
3457 for (i=0;i<torture_nprocs;i++) {
3458 status = smb2_create(trees[i], mem_ctx, &(io.smb2));
3459 torture_assert_ntstatus_ok(tctx, status, "Incorrect status");
3460 count++;
3463 if (torture_setting_bool(tctx, "progress", true)) {
3464 torture_comment(tctx, "%.2f ops/second\r",
3465 count/timeval_elapsed(&tv));
3469 torture_comment(tctx, "%.2f ops/second\n", count/timeval_elapsed(&tv));
3470 smb2_util_close(trees[0], io.smb2.out.file.handle);
3471 smb2_util_unlink(trees[0], BASEDIR "\\test.dat");
3472 smb2_deltree(trees[0], BASEDIR);
3473 talloc_free(mem_ctx);
3474 return ret;
3477 static struct hold_oplock_info {
3478 const char *fname;
3479 bool close_on_break;
3480 uint32_t share_access;
3481 struct smb2_handle handle;
3482 } hold_info[] = {
3483 { BASEDIR "\\notshared_close", true,
3484 NTCREATEX_SHARE_ACCESS_NONE, },
3485 { BASEDIR "\\notshared_noclose", false,
3486 NTCREATEX_SHARE_ACCESS_NONE, },
3487 { BASEDIR "\\shared_close", true,
3488 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, },
3489 { BASEDIR "\\shared_noclose", false,
3490 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE|NTCREATEX_SHARE_ACCESS_DELETE, },
3493 static bool torture_oplock_handler_hold(struct smb2_transport *transport,
3494 const struct smb2_handle *handle,
3495 uint8_t level, void *private_data)
3497 struct hold_oplock_info *info;
3498 int i;
3500 for (i=0;i<ARRAY_SIZE(hold_info);i++) {
3501 if (smb2_util_handle_equal(hold_info[i].handle, *handle))
3502 break;
3505 if (i == ARRAY_SIZE(hold_info)) {
3506 printf("oplock break for unknown handle 0x%llx%llx\n",
3507 (unsigned long long) handle->data[0],
3508 (unsigned long long) handle->data[1]);
3509 return false;
3512 info = &hold_info[i];
3514 if (info->close_on_break) {
3515 printf("oplock break on %s - closing\n", info->fname);
3516 torture_oplock_handler_close(transport, handle,
3517 level, private_data);
3518 return true;
3521 printf("oplock break on %s - acking break\n", info->fname);
3522 printf("Acking to none in oplock handler\n");
3524 torture_oplock_handler_ack_to_none(transport, handle,
3525 level, private_data);
3526 return true;
3530 used for manual testing of oplocks - especially interaction with
3531 other filesystems (such as NFS and local access)
3533 bool test_smb2_hold_oplock(struct torture_context *tctx,
3534 struct smb2_tree *tree)
3536 struct torture_context *mem_ctx = talloc_new(tctx);
3537 struct tevent_context *ev =
3538 (struct tevent_context *)tree->session->transport->socket->event.ctx;
3539 int i;
3540 struct smb2_handle h;
3541 NTSTATUS status;
3543 torture_comment(tctx, "Setting up open files with oplocks in %s\n",
3544 BASEDIR);
3546 status = torture_smb2_testdir(tree, BASEDIR, &h);
3547 torture_assert_ntstatus_ok(tctx, status, "Error creating directory");
3549 tree->session->transport->oplock.handler = torture_oplock_handler_hold;
3550 tree->session->transport->oplock.private_data = tree;
3552 /* setup the files */
3553 for (i=0;i<ARRAY_SIZE(hold_info);i++) {
3554 union smb_open io;
3555 char c = 1;
3557 ZERO_STRUCT(io.smb2);
3558 io.generic.level = RAW_OPEN_SMB2;
3559 io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL;
3560 io.smb2.in.alloc_size = 0;
3561 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
3562 io.smb2.in.share_access = hold_info[i].share_access;
3563 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
3564 io.smb2.in.create_options = 0;
3565 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
3566 io.smb2.in.security_flags = 0;
3567 io.smb2.in.fname = hold_info[i].fname;
3568 io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
3569 io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
3571 torture_comment(tctx, "opening %s\n", hold_info[i].fname);
3573 status = smb2_create(tree, mem_ctx, &(io.smb2));
3574 if (!NT_STATUS_IS_OK(status)) {
3575 torture_comment(tctx, "Failed to open %s - %s\n",
3576 hold_info[i].fname, nt_errstr(status));
3577 return false;
3580 if (io.smb2.out.oplock_level != SMB2_OPLOCK_LEVEL_BATCH) {
3581 torture_comment(tctx, "Oplock not granted for %s - "
3582 "expected %d but got %d\n",
3583 hold_info[i].fname,
3584 SMB2_OPLOCK_LEVEL_BATCH,
3585 io.smb2.out.oplock_level);
3586 return false;
3588 hold_info[i].handle = io.smb2.out.file.handle;
3590 /* make the file non-zero size */
3591 status = smb2_util_write(tree, hold_info[i].handle, &c, 0, 1);
3592 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
3593 torture_comment(tctx, "Failed to write to file\n");
3594 return false;
3598 torture_comment(tctx, "Waiting for oplock events\n");
3599 event_loop_wait(ev);
3600 smb2_deltree(tree, BASEDIR);
3601 talloc_free(mem_ctx);
3602 return true;