2 Unix SMB/CIFS implementation.
4 test suite for SMB2 durable opens
6 Copyright (C) Stefan Metzmacher 2008
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "libcli/smb2/smb2.h"
24 #include "libcli/smb2/smb2_calls.h"
25 #include "torture/torture.h"
26 #include "torture/smb2/proto.h"
28 #define CHECK_VAL(v, correct) do { \
29 if ((v) != (correct)) { \
30 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
31 __location__, #v, (int)v, (int)correct); \
35 #define CHECK_STATUS(status, correct) do { \
36 if (!NT_STATUS_EQUAL(status, correct)) { \
37 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
38 nt_errstr(status), nt_errstr(correct)); \
43 #define CHECK_CREATED(__io, __created, __attribute) \
45 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
46 CHECK_VAL((__io)->out.alloc_size, 0); \
47 CHECK_VAL((__io)->out.size, 0); \
48 CHECK_VAL((__io)->out.file_attr, (__attribute)); \
49 CHECK_VAL((__io)->out.reserved2, 0); \
54 * basic durable_open test.
55 * durable state should only be granted when requested
56 * along with a batch oplock or a handle lease.
58 * This test tests durable open with all possible oplock types.
61 struct durable_open_vs_oplock {
63 const char *share_mode;
67 #define NUM_OPLOCK_TYPES 4
68 #define NUM_SHARE_MODES 8
69 #define NUM_OPLOCK_OPEN_TESTS ( NUM_OPLOCK_TYPES * NUM_SHARE_MODES )
70 struct durable_open_vs_oplock durable_open_vs_oplock_table[NUM_OPLOCK_OPEN_TESTS] =
88 { "s", "RWD", false },
97 { "x", "RWD", false },
106 { "b", "RWD", true },
109 static bool test_one_durable_open_open1(struct torture_context *tctx,
110 struct smb2_tree *tree,
112 struct durable_open_vs_oplock test)
115 TALLOC_CTX *mem_ctx = talloc_new(tctx);
116 struct smb2_handle _h;
117 struct smb2_handle *h = NULL;
119 struct smb2_create io;
121 smb2_util_unlink(tree, fname);
123 smb2_oplock_create_share(&io, fname,
124 smb2_util_share_access(test.share_mode),
125 smb2_util_oplock_level(test.level));
126 io.in.durable_open = true;
128 status = smb2_create(tree, mem_ctx, &io);
129 CHECK_STATUS(status, NT_STATUS_OK);
130 _h = io.out.file.handle;
132 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
133 CHECK_VAL(io.out.durable_open, test.expected);
134 CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(test.level));
138 smb2_util_close(tree, *h);
140 smb2_util_unlink(tree, fname);
141 talloc_free(mem_ctx);
146 bool test_durable_open_open1(struct torture_context *tctx,
147 struct smb2_tree *tree)
149 TALLOC_CTX *mem_ctx = talloc_new(tctx);
154 /* Choose a random name in case the state is left a little funky. */
155 snprintf(fname, 256, "durable_open_open1_%s.dat", generate_random_str(tctx, 8));
157 smb2_util_unlink(tree, fname);
159 /* test various oplock levels with durable open */
161 for (i = 0; i < NUM_OPLOCK_OPEN_TESTS; i++) {
162 ret = test_one_durable_open_open1(tctx,
165 durable_open_vs_oplock_table[i]);
172 smb2_util_unlink(tree, fname);
174 talloc_free(mem_ctx);
180 * basic durable_open test.
181 * durable state should only be granted when requested
182 * along with a batch oplock or a handle lease.
184 * This test tests durable open with all valid lease types.
187 struct durable_open_vs_lease {
189 const char *share_mode;
193 #define NUM_LEASE_TYPES 5
194 #define NUM_LEASE_OPEN_TESTS ( NUM_LEASE_TYPES * NUM_SHARE_MODES )
195 struct durable_open_vs_lease durable_open_vs_lease_table[NUM_LEASE_OPEN_TESTS] =
204 { "", "RWD", false },
210 { "R", "RW", false },
211 { "R", "RD", false },
212 { "R", "DW", false },
213 { "R", "RWD", false },
216 { "RW", "R", false },
217 { "RW", "W", false },
218 { "RW", "D", false },
219 { "RW", "RW", false },
220 { "RW", "RD", false },
221 { "RW", "WD", false },
222 { "RW", "RWD", false },
228 { "RH", "RW", true },
229 { "RH", "RD", true },
230 { "RH", "WD", true },
231 { "RH", "RWD", true },
234 { "RHW", "R", true },
235 { "RHW", "W", true },
236 { "RHW", "D", true },
237 { "RHW", "RW", true },
238 { "RHW", "RD", true },
239 { "RHW", "WD", true },
240 { "RHW", "RWD", true },
243 static bool test_one_durable_open_open2(struct torture_context *tctx,
244 struct smb2_tree *tree,
246 struct durable_open_vs_lease test)
249 TALLOC_CTX *mem_ctx = talloc_new(tctx);
250 struct smb2_handle _h;
251 struct smb2_handle *h = NULL;
253 struct smb2_create io;
254 struct smb2_lease ls;
257 smb2_util_unlink(tree, fname);
261 smb2_lease_create_share(&io, &ls, false /* dir */, fname,
262 smb2_util_share_access(test.share_mode),
264 smb2_util_lease_state(test.type));
265 io.in.durable_open = true;
267 status = smb2_create(tree, mem_ctx, &io);
268 CHECK_STATUS(status, NT_STATUS_OK);
269 _h = io.out.file.handle;
271 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
272 CHECK_VAL(io.out.durable_open, test.expected);
273 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
274 CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
275 CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
276 CHECK_VAL(io.out.lease_response.lease_state,
277 smb2_util_lease_state(test.type));
280 smb2_util_close(tree, *h);
282 smb2_util_unlink(tree, fname);
283 talloc_free(mem_ctx);
288 bool test_durable_open_open2(struct torture_context *tctx,
289 struct smb2_tree *tree)
291 TALLOC_CTX *mem_ctx = talloc_new(tctx);
296 /* Choose a random name in case the state is left a little funky. */
297 snprintf(fname, 256, "durable_open_open2_%s.dat", generate_random_str(tctx, 8));
299 smb2_util_unlink(tree, fname);
302 /* test various oplock levels with durable open */
304 for (i = 0; i < NUM_LEASE_OPEN_TESTS; i++) {
305 ret = test_one_durable_open_open2(tctx,
308 durable_open_vs_lease_table[i]);
315 smb2_util_unlink(tree, fname);
317 talloc_free(mem_ctx);
323 basic testing of SMB2 durable opens
324 regarding the position information on the handle
326 bool test_durable_open_file_position(struct torture_context *tctx,
327 struct smb2_tree *tree1,
328 struct smb2_tree *tree2)
330 TALLOC_CTX *mem_ctx = talloc_new(tctx);
331 struct smb2_handle h1, h2;
332 struct smb2_create io1, io2;
334 const char *fname = "durable_open_position.dat";
335 union smb_fileinfo qfinfo;
336 union smb_setfileinfo sfinfo;
340 smb2_util_unlink(tree1, fname);
342 smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
343 io1.in.durable_open = true;
345 status = smb2_create(tree1, mem_ctx, &io1);
346 CHECK_STATUS(status, NT_STATUS_OK);
347 h1 = io1.out.file.handle;
348 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
349 CHECK_VAL(io1.out.durable_open, true);
350 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
352 /* TODO: check extra blob content */
355 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
356 qfinfo.generic.in.file.handle = h1;
357 status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
358 CHECK_STATUS(status, NT_STATUS_OK);
359 CHECK_VAL(qfinfo.position_information.out.position, 0);
360 pos = qfinfo.position_information.out.position;
361 torture_comment(tctx, "position: %llu\n",
362 (unsigned long long)pos);
365 sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
366 sfinfo.generic.in.file.handle = h1;
367 sfinfo.position_information.in.position = 0x1000;
368 status = smb2_setinfo_file(tree1, &sfinfo);
369 CHECK_STATUS(status, NT_STATUS_OK);
372 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
373 qfinfo.generic.in.file.handle = h1;
374 status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
375 CHECK_STATUS(status, NT_STATUS_OK);
376 CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
377 pos = qfinfo.position_information.out.position;
378 torture_comment(tctx, "position: %llu\n",
379 (unsigned long long)pos);
385 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
386 qfinfo.generic.in.file.handle = h1;
387 status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo);
388 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
391 io2.in.fname = fname;
392 io2.in.durable_handle = &h1;
394 status = smb2_create(tree2, mem_ctx, &io2);
395 CHECK_STATUS(status, NT_STATUS_OK);
396 CHECK_VAL(io2.out.durable_open, true);
397 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
398 CHECK_VAL(io2.out.reserved, 0x00);
399 CHECK_VAL(io2.out.create_action, NTCREATEX_ACTION_EXISTED);
400 CHECK_VAL(io2.out.alloc_size, 0);
401 CHECK_VAL(io2.out.size, 0);
402 CHECK_VAL(io2.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
403 CHECK_VAL(io2.out.reserved2, 0);
405 h2 = io2.out.file.handle;
408 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
409 qfinfo.generic.in.file.handle = h2;
410 status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo);
411 CHECK_STATUS(status, NT_STATUS_OK);
412 CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
413 pos = qfinfo.position_information.out.position;
414 torture_comment(tctx, "position: %llu\n",
415 (unsigned long long)pos);
417 smb2_util_close(tree2, h2);
419 talloc_free(mem_ctx);
421 smb2_util_unlink(tree2, fname);
430 Open, disconnect, oplock break, reconnect.
432 bool test_durable_open_oplock(struct torture_context *tctx,
433 struct smb2_tree *tree1,
434 struct smb2_tree *tree2)
436 TALLOC_CTX *mem_ctx = talloc_new(tctx);
437 struct smb2_create io1, io2;
438 struct smb2_handle h1, h2;
443 /* Choose a random name in case the state is left a little funky. */
444 snprintf(fname, 256, "durable_open_oplock_%s.dat", generate_random_str(tctx, 8));
447 smb2_util_unlink(tree1, fname);
449 /* Create with batch oplock */
450 smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
451 io1.in.durable_open = true;
454 io2.in.create_disposition = NTCREATEX_DISP_OPEN;
456 status = smb2_create(tree1, mem_ctx, &io1);
457 CHECK_STATUS(status, NT_STATUS_OK);
458 h1 = io1.out.file.handle;
459 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
460 CHECK_VAL(io1.out.durable_open, true);
461 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
463 /* Disconnect after getting the batch */
468 * Windows7 (build 7000) will break a batch oplock immediately if the
469 * original client is gone. (ZML: This seems like a bug. It should give
470 * some time for the client to reconnect!)
472 status = smb2_create(tree2, mem_ctx, &io2);
473 CHECK_STATUS(status, NT_STATUS_OK);
474 h2 = io2.out.file.handle;
475 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
476 CHECK_VAL(io2.out.durable_open, true);
477 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
479 /* What if tree1 tries to come back and reclaim? */
480 if (!torture_smb2_connection(tctx, &tree1)) {
481 torture_warning(tctx, "couldn't reconnect, bailing\n");
487 io1.in.fname = fname;
488 io1.in.durable_handle = &h1;
490 status = smb2_create(tree1, mem_ctx, &io1);
491 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
494 smb2_util_close(tree2, h2);
495 smb2_util_unlink(tree2, fname);
504 Open, disconnect, lease break, reconnect.
506 bool test_durable_open_lease(struct torture_context *tctx,
507 struct smb2_tree *tree1,
508 struct smb2_tree *tree2)
510 TALLOC_CTX *mem_ctx = talloc_new(tctx);
511 struct smb2_create io1, io2;
512 struct smb2_lease ls1, ls2;
513 struct smb2_handle h1, h2;
517 uint64_t lease1, lease2;
520 * Choose a random name and random lease in case the state is left a
525 snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
528 smb2_util_unlink(tree1, fname);
530 /* Create with lease */
531 smb2_lease_create(&io1, &ls1, false /* dir */, fname,
532 lease1, smb2_util_lease_state("RHW"));
533 io1.in.durable_open = true;
535 smb2_lease_create(&io2, &ls2, false /* dir */, fname,
536 lease2, smb2_util_lease_state("RHW"));
537 io2.in.durable_open = true;
538 io2.in.create_disposition = NTCREATEX_DISP_OPEN;
540 status = smb2_create(tree1, mem_ctx, &io1);
541 CHECK_STATUS(status, NT_STATUS_OK);
542 h1 = io1.out.file.handle;
543 CHECK_VAL(io1.out.durable_open, true);
544 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
546 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
547 CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease1);
548 CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease1);
549 CHECK_VAL(io1.out.lease_response.lease_state,
550 SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
552 /* Disconnect after getting the lease */
557 * Windows7 (build 7000) will grant an RH lease immediate (not an RHW?)
558 * even if the original client is gone. (ZML: This seems like a bug. It
559 * should give some time for the client to reconnect! And why RH?)
561 * obnox: Current windows 7 and w2k8r2 grant RHW instead of RH.
562 * Test is adapted accordingly.
564 status = smb2_create(tree2, mem_ctx, &io2);
565 CHECK_STATUS(status, NT_STATUS_OK);
566 h2 = io2.out.file.handle;
567 CHECK_VAL(io2.out.durable_open, true);
568 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
570 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
571 CHECK_VAL(io2.out.lease_response.lease_key.data[0], lease2);
572 CHECK_VAL(io2.out.lease_response.lease_key.data[1], ~lease2);
573 CHECK_VAL(io2.out.lease_response.lease_state,
574 SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
576 /* What if tree1 tries to come back and reclaim? */
577 if (!torture_smb2_connection(tctx, &tree1)) {
578 torture_warning(tctx, "couldn't reconnect, bailing\n");
584 io1.in.fname = fname;
585 io1.in.durable_handle = &h1;
586 io1.in.lease_request = &ls1;
588 status = smb2_create(tree1, mem_ctx, &io1);
589 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
592 smb2_util_close(tree2, h2);
593 smb2_util_unlink(tree2, fname);
602 Open, take BRL, disconnect, reconnect.
604 bool test_durable_open_lock(struct torture_context *tctx,
605 struct smb2_tree *tree)
607 TALLOC_CTX *mem_ctx = talloc_new(tctx);
608 struct smb2_create io;
609 struct smb2_lease ls;
610 struct smb2_handle h;
611 struct smb2_lock lck;
612 struct smb2_lock_element el[2];
619 * Choose a random name and random lease in case the state is left a
623 snprintf(fname, 256, "durable_open_lock_%s.dat", generate_random_str(tctx, 8));
626 smb2_util_unlink(tree, fname);
628 /* Create with lease */
630 io.in.security_flags = 0x00;
631 io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
632 io.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
633 io.in.create_flags = 0x00000000;
634 io.in.reserved = 0x00000000;
635 io.in.desired_access = SEC_RIGHTS_FILE_ALL;
636 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
637 io.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
638 NTCREATEX_SHARE_ACCESS_WRITE |
639 NTCREATEX_SHARE_ACCESS_DELETE;
640 io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
641 io.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
642 NTCREATEX_OPTIONS_ASYNC_ALERT |
643 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
646 io.in.durable_open = true;
649 ls.lease_key.data[0] = lease;
650 ls.lease_key.data[1] = ~lease;
651 ls.lease_state = SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE;
652 io.in.lease_request = &ls;
654 status = smb2_create(tree, mem_ctx, &io);
655 CHECK_STATUS(status, NT_STATUS_OK);
656 h = io.out.file.handle;
657 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
659 CHECK_VAL(io.out.durable_open, true);
660 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
661 CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
662 CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
663 CHECK_VAL(io.out.lease_response.lease_state,
664 SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
669 lck.in.lock_count = 0x0001;
670 lck.in.lock_sequence = 0x00000000;
671 lck.in.file.handle = h;
674 el[0].reserved = 0x00000000;
675 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
676 status = smb2_lock(tree, &lck);
677 CHECK_STATUS(status, NT_STATUS_OK);
679 /* Disconnect/Reconnect. */
683 if (!torture_smb2_connection(tctx, &tree)) {
684 torture_warning(tctx, "couldn't reconnect, bailing\n");
691 io.in.durable_handle = &h;
692 io.in.lease_request = &ls;
694 status = smb2_create(tree, mem_ctx, &io);
695 CHECK_STATUS(status, NT_STATUS_OK);
696 h = io.out.file.handle;
698 lck.in.file.handle = h;
699 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
700 status = smb2_lock(tree, &lck);
701 CHECK_STATUS(status, NT_STATUS_OK);
704 smb2_util_close(tree, h);
705 smb2_util_unlink(tree, fname);
712 Open, disconnect, open in another tree, reconnect.
714 This test actually demonstrates a minimum level of respect for the durable
715 open in the face of another open. As long as this test shows an inability to
716 reconnect after an open, the oplock/lease tests above will certainly
717 demonstrate an error on reconnect.
719 bool test_durable_open_open(struct torture_context *tctx,
720 struct smb2_tree *tree1,
721 struct smb2_tree *tree2)
723 TALLOC_CTX *mem_ctx = talloc_new(tctx);
724 struct smb2_create io1, io2;
725 struct smb2_lease ls;
726 struct smb2_handle h1, h2;
733 * Choose a random name and random lease in case the state is left a
737 snprintf(fname, 256, "durable_open_lock_%s.dat", generate_random_str(tctx, 8));
740 smb2_util_unlink(tree1, fname);
742 /* Create with lease */
744 io1.in.security_flags = 0x00;
745 io1.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
746 io1.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
747 io1.in.create_flags = 0x00000000;
748 io1.in.reserved = 0x00000000;
749 io1.in.desired_access = SEC_RIGHTS_FILE_ALL;
750 io1.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
751 io1.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
752 io1.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
753 io1.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
754 NTCREATEX_OPTIONS_ASYNC_ALERT |
755 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
757 io1.in.fname = fname;
758 io1.in.durable_open = true;
761 io2.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
762 io2.in.durable_open = false;
765 ls.lease_key.data[0] = lease;
766 ls.lease_key.data[1] = ~lease;
767 ls.lease_state = SMB2_LEASE_READ|SMB2_LEASE_HANDLE;
768 io1.in.lease_request = &ls;
770 status = smb2_create(tree1, mem_ctx, &io1);
771 CHECK_STATUS(status, NT_STATUS_OK);
772 h1 = io1.out.file.handle;
773 CHECK_VAL(io1.out.durable_open, true);
774 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
776 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
777 CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease);
778 CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease);
779 CHECK_VAL(io1.out.lease_response.lease_state,
780 SMB2_LEASE_READ|SMB2_LEASE_HANDLE);
786 /* Open the file in tree2 */
787 status = smb2_create(tree2, mem_ctx, &io2);
788 CHECK_STATUS(status, NT_STATUS_OK);
789 h2 = io2.out.file.handle;
790 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
793 if (!torture_smb2_connection(tctx, &tree1)) {
794 torture_warning(tctx, "couldn't reconnect, bailing\n");
800 io1.in.fname = fname;
801 io1.in.durable_handle = &h1;
802 io1.in.lease_request = &ls;
805 * Windows7 (build 7000) will give away an open immediately if the
806 * original client is gone. (ZML: This seems like a bug. It should give
807 * some time for the client to reconnect!)
809 status = smb2_create(tree1, mem_ctx, &io1);
810 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
811 h1 = io1.out.file.handle;
814 smb2_util_close(tree2, h2);
815 smb2_util_unlink(tree2, fname);
816 smb2_util_close(tree1, h1);
817 smb2_util_unlink(tree1, fname);
825 struct torture_suite *torture_smb2_durable_open_init(void)
827 struct torture_suite *suite =
828 torture_suite_create(talloc_autofree_context(), "durable-open");
830 torture_suite_add_1smb2_test(suite, "open1", test_durable_open_open1);
831 torture_suite_add_1smb2_test(suite, "open2", test_durable_open_open2);
832 torture_suite_add_2smb2_test(suite, "file-position",
833 test_durable_open_file_position);
834 torture_suite_add_2smb2_test(suite, "oplock", test_durable_open_oplock);
835 torture_suite_add_2smb2_test(suite, "lease", test_durable_open_lease);
836 torture_suite_add_1smb2_test(suite, "lock", test_durable_open_lock);
837 torture_suite_add_2smb2_test(suite, "open", test_durable_open_open);
839 suite->description = talloc_strdup(suite, "SMB2-DURABLE-OPEN tests");