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 test for doing a durable open
324 * and do a durable reopen on the same connection
326 bool test_durable_open_reopen1(struct torture_context *tctx,
327 struct smb2_tree *tree)
330 TALLOC_CTX *mem_ctx = talloc_new(tctx);
332 struct smb2_handle _h;
333 struct smb2_handle *h = NULL;
334 struct smb2_create io1, io2;
337 /* Choose a random name in case the state is left a little funky. */
338 snprintf(fname, 256, "durable_open_reopen1_%s.dat",
339 generate_random_str(tctx, 8));
341 smb2_util_unlink(tree, fname);
343 smb2_oplock_create_share(&io1, fname,
344 smb2_util_share_access(""),
345 smb2_util_oplock_level("b"));
346 io1.in.durable_open = true;
348 status = smb2_create(tree, mem_ctx, &io1);
349 CHECK_STATUS(status, NT_STATUS_OK);
350 _h = io1.out.file.handle;
352 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
353 CHECK_VAL(io1.out.durable_open, true);
354 CHECK_VAL(io1.out.oplock_level, smb2_util_oplock_level("b"));
356 /* try a durable reconnect while the file is still open */
358 io2.in.fname = fname;
359 io2.in.durable_handle = h;
361 status = smb2_create(tree, mem_ctx, &io2);
362 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
366 smb2_util_close(tree, *h);
369 smb2_util_unlink(tree, fname);
373 talloc_free(mem_ctx);
379 basic testing of SMB2 durable opens
380 regarding the position information on the handle
382 bool test_durable_open_file_position(struct torture_context *tctx,
383 struct smb2_tree *tree1,
384 struct smb2_tree *tree2)
386 TALLOC_CTX *mem_ctx = talloc_new(tctx);
387 struct smb2_handle h1, h2;
388 struct smb2_create io1, io2;
390 const char *fname = "durable_open_position.dat";
391 union smb_fileinfo qfinfo;
392 union smb_setfileinfo sfinfo;
396 smb2_util_unlink(tree1, fname);
398 smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
399 io1.in.durable_open = true;
401 status = smb2_create(tree1, mem_ctx, &io1);
402 CHECK_STATUS(status, NT_STATUS_OK);
403 h1 = io1.out.file.handle;
404 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
405 CHECK_VAL(io1.out.durable_open, true);
406 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
408 /* TODO: check extra blob content */
411 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
412 qfinfo.generic.in.file.handle = h1;
413 status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
414 CHECK_STATUS(status, NT_STATUS_OK);
415 CHECK_VAL(qfinfo.position_information.out.position, 0);
416 pos = qfinfo.position_information.out.position;
417 torture_comment(tctx, "position: %llu\n",
418 (unsigned long long)pos);
421 sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
422 sfinfo.generic.in.file.handle = h1;
423 sfinfo.position_information.in.position = 0x1000;
424 status = smb2_setinfo_file(tree1, &sfinfo);
425 CHECK_STATUS(status, NT_STATUS_OK);
428 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
429 qfinfo.generic.in.file.handle = h1;
430 status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
431 CHECK_STATUS(status, NT_STATUS_OK);
432 CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
433 pos = qfinfo.position_information.out.position;
434 torture_comment(tctx, "position: %llu\n",
435 (unsigned long long)pos);
441 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
442 qfinfo.generic.in.file.handle = h1;
443 status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo);
444 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
447 io2.in.fname = fname;
448 io2.in.durable_handle = &h1;
450 status = smb2_create(tree2, mem_ctx, &io2);
451 CHECK_STATUS(status, NT_STATUS_OK);
452 CHECK_VAL(io2.out.durable_open, true);
453 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
454 CHECK_VAL(io2.out.reserved, 0x00);
455 CHECK_VAL(io2.out.create_action, NTCREATEX_ACTION_EXISTED);
456 CHECK_VAL(io2.out.alloc_size, 0);
457 CHECK_VAL(io2.out.size, 0);
458 CHECK_VAL(io2.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
459 CHECK_VAL(io2.out.reserved2, 0);
461 h2 = io2.out.file.handle;
464 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
465 qfinfo.generic.in.file.handle = h2;
466 status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo);
467 CHECK_STATUS(status, NT_STATUS_OK);
468 CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
469 pos = qfinfo.position_information.out.position;
470 torture_comment(tctx, "position: %llu\n",
471 (unsigned long long)pos);
473 smb2_util_close(tree2, h2);
475 talloc_free(mem_ctx);
477 smb2_util_unlink(tree2, fname);
486 Open, disconnect, oplock break, reconnect.
488 bool test_durable_open_oplock(struct torture_context *tctx,
489 struct smb2_tree *tree1,
490 struct smb2_tree *tree2)
492 TALLOC_CTX *mem_ctx = talloc_new(tctx);
493 struct smb2_create io1, io2;
494 struct smb2_handle h1, h2;
499 /* Choose a random name in case the state is left a little funky. */
500 snprintf(fname, 256, "durable_open_oplock_%s.dat", generate_random_str(tctx, 8));
503 smb2_util_unlink(tree1, fname);
505 /* Create with batch oplock */
506 smb2_oplock_create(&io1, fname, SMB2_OPLOCK_LEVEL_BATCH);
507 io1.in.durable_open = true;
510 io2.in.create_disposition = NTCREATEX_DISP_OPEN;
512 status = smb2_create(tree1, mem_ctx, &io1);
513 CHECK_STATUS(status, NT_STATUS_OK);
514 h1 = io1.out.file.handle;
515 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
516 CHECK_VAL(io1.out.durable_open, true);
517 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
519 /* Disconnect after getting the batch */
524 * Windows7 (build 7000) will break a batch oplock immediately if the
525 * original client is gone. (ZML: This seems like a bug. It should give
526 * some time for the client to reconnect!)
528 status = smb2_create(tree2, mem_ctx, &io2);
529 CHECK_STATUS(status, NT_STATUS_OK);
530 h2 = io2.out.file.handle;
531 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
532 CHECK_VAL(io2.out.durable_open, true);
533 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
535 /* What if tree1 tries to come back and reclaim? */
536 if (!torture_smb2_connection(tctx, &tree1)) {
537 torture_warning(tctx, "couldn't reconnect, bailing\n");
543 io1.in.fname = fname;
544 io1.in.durable_handle = &h1;
546 status = smb2_create(tree1, mem_ctx, &io1);
547 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
550 smb2_util_close(tree2, h2);
551 smb2_util_unlink(tree2, fname);
560 Open, disconnect, lease break, reconnect.
562 bool test_durable_open_lease(struct torture_context *tctx,
563 struct smb2_tree *tree1,
564 struct smb2_tree *tree2)
566 TALLOC_CTX *mem_ctx = talloc_new(tctx);
567 struct smb2_create io1, io2;
568 struct smb2_lease ls1, ls2;
569 struct smb2_handle h1, h2;
573 uint64_t lease1, lease2;
576 * Choose a random name and random lease in case the state is left a
581 snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
584 smb2_util_unlink(tree1, fname);
586 /* Create with lease */
587 smb2_lease_create(&io1, &ls1, false /* dir */, fname,
588 lease1, smb2_util_lease_state("RHW"));
589 io1.in.durable_open = true;
591 smb2_lease_create(&io2, &ls2, false /* dir */, fname,
592 lease2, smb2_util_lease_state("RHW"));
593 io2.in.durable_open = true;
594 io2.in.create_disposition = NTCREATEX_DISP_OPEN;
596 status = smb2_create(tree1, mem_ctx, &io1);
597 CHECK_STATUS(status, NT_STATUS_OK);
598 h1 = io1.out.file.handle;
599 CHECK_VAL(io1.out.durable_open, true);
600 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
602 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
603 CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease1);
604 CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease1);
605 CHECK_VAL(io1.out.lease_response.lease_state,
606 SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
608 /* Disconnect after getting the lease */
613 * Windows7 (build 7000) will grant an RH lease immediate (not an RHW?)
614 * even if the original client is gone. (ZML: This seems like a bug. It
615 * should give some time for the client to reconnect! And why RH?)
617 * obnox: Current windows 7 and w2k8r2 grant RHW instead of RH.
618 * Test is adapted accordingly.
620 status = smb2_create(tree2, mem_ctx, &io2);
621 CHECK_STATUS(status, NT_STATUS_OK);
622 h2 = io2.out.file.handle;
623 CHECK_VAL(io2.out.durable_open, true);
624 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
626 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
627 CHECK_VAL(io2.out.lease_response.lease_key.data[0], lease2);
628 CHECK_VAL(io2.out.lease_response.lease_key.data[1], ~lease2);
629 CHECK_VAL(io2.out.lease_response.lease_state,
630 SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
632 /* What if tree1 tries to come back and reclaim? */
633 if (!torture_smb2_connection(tctx, &tree1)) {
634 torture_warning(tctx, "couldn't reconnect, bailing\n");
640 io1.in.fname = fname;
641 io1.in.durable_handle = &h1;
642 io1.in.lease_request = &ls1;
644 status = smb2_create(tree1, mem_ctx, &io1);
645 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
648 smb2_util_close(tree2, h2);
649 smb2_util_unlink(tree2, fname);
658 Open, take BRL, disconnect, reconnect.
660 bool test_durable_open_lock(struct torture_context *tctx,
661 struct smb2_tree *tree)
663 TALLOC_CTX *mem_ctx = talloc_new(tctx);
664 struct smb2_create io;
665 struct smb2_lease ls;
666 struct smb2_handle h;
667 struct smb2_lock lck;
668 struct smb2_lock_element el[2];
675 * Choose a random name and random lease in case the state is left a
679 snprintf(fname, 256, "durable_open_lock_%s.dat", generate_random_str(tctx, 8));
682 smb2_util_unlink(tree, fname);
684 /* Create with lease */
686 smb2_lease_create(&io, &ls, false /* dir */, fname, lease,
687 smb2_util_lease_state("RWH"));
688 io.in.durable_open = true;
690 status = smb2_create(tree, mem_ctx, &io);
691 CHECK_STATUS(status, NT_STATUS_OK);
692 h = io.out.file.handle;
693 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
695 CHECK_VAL(io.out.durable_open, true);
696 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
697 CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
698 CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
699 CHECK_VAL(io.out.lease_response.lease_state,
700 SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
705 lck.in.lock_count = 0x0001;
706 lck.in.lock_sequence = 0x00000000;
707 lck.in.file.handle = h;
710 el[0].reserved = 0x00000000;
711 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
712 status = smb2_lock(tree, &lck);
713 CHECK_STATUS(status, NT_STATUS_OK);
715 /* Disconnect/Reconnect. */
719 if (!torture_smb2_connection(tctx, &tree)) {
720 torture_warning(tctx, "couldn't reconnect, bailing\n");
727 io.in.durable_handle = &h;
728 io.in.lease_request = &ls;
730 status = smb2_create(tree, mem_ctx, &io);
731 CHECK_STATUS(status, NT_STATUS_OK);
732 h = io.out.file.handle;
734 lck.in.file.handle = h;
735 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
736 status = smb2_lock(tree, &lck);
737 CHECK_STATUS(status, NT_STATUS_OK);
740 smb2_util_close(tree, h);
741 smb2_util_unlink(tree, fname);
748 Open, disconnect, open in another tree, reconnect.
750 This test actually demonstrates a minimum level of respect for the durable
751 open in the face of another open. As long as this test shows an inability to
752 reconnect after an open, the oplock/lease tests above will certainly
753 demonstrate an error on reconnect.
755 bool test_durable_open_open(struct torture_context *tctx,
756 struct smb2_tree *tree1,
757 struct smb2_tree *tree2)
759 TALLOC_CTX *mem_ctx = talloc_new(tctx);
760 struct smb2_create io1, io2;
761 struct smb2_lease ls;
762 struct smb2_handle h1, h2;
769 * Choose a random name and random lease in case the state is left a
773 snprintf(fname, 256, "durable_open_lock_%s.dat", generate_random_str(tctx, 8));
776 smb2_util_unlink(tree1, fname);
778 /* Create with lease */
779 smb2_lease_create_share(&io1, &ls, false /* dir */, fname,
780 smb2_util_share_access(""),
782 smb2_util_lease_state("RH"));
783 io1.in.durable_open = true;
785 smb2_oplock_create(&io2, fname, SMB2_OPLOCK_LEVEL_NONE);
787 status = smb2_create(tree1, mem_ctx, &io1);
788 CHECK_STATUS(status, NT_STATUS_OK);
789 h1 = io1.out.file.handle;
790 CHECK_VAL(io1.out.durable_open, true);
791 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
793 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
794 CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease);
795 CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease);
796 CHECK_VAL(io1.out.lease_response.lease_state,
797 smb2_util_lease_state("RH"));
803 /* Open the file in tree2 */
804 status = smb2_create(tree2, mem_ctx, &io2);
805 CHECK_STATUS(status, NT_STATUS_OK);
806 h2 = io2.out.file.handle;
807 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
810 if (!torture_smb2_connection(tctx, &tree1)) {
811 torture_warning(tctx, "couldn't reconnect, bailing\n");
817 io1.in.fname = fname;
818 io1.in.durable_handle = &h1;
819 io1.in.lease_request = &ls;
822 * Windows7 (build 7000) will give away an open immediately if the
823 * original client is gone. (ZML: This seems like a bug. It should give
824 * some time for the client to reconnect!)
826 status = smb2_create(tree1, mem_ctx, &io1);
827 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
828 h1 = io1.out.file.handle;
831 smb2_util_close(tree2, h2);
832 smb2_util_unlink(tree2, fname);
833 smb2_util_close(tree1, h1);
834 smb2_util_unlink(tree1, fname);
842 struct torture_suite *torture_smb2_durable_open_init(void)
844 struct torture_suite *suite =
845 torture_suite_create(talloc_autofree_context(), "durable-open");
847 torture_suite_add_1smb2_test(suite, "open1", test_durable_open_open1);
848 torture_suite_add_1smb2_test(suite, "open2", test_durable_open_open2);
849 torture_suite_add_1smb2_test(suite, "reopen1", test_durable_open_reopen1);
850 torture_suite_add_2smb2_test(suite, "file-position",
851 test_durable_open_file_position);
852 torture_suite_add_2smb2_test(suite, "oplock", test_durable_open_oplock);
853 torture_suite_add_2smb2_test(suite, "lease", test_durable_open_lease);
854 torture_suite_add_1smb2_test(suite, "lock", test_durable_open_lock);
855 torture_suite_add_2smb2_test(suite, "open", test_durable_open_open);
857 suite->description = talloc_strdup(suite, "SMB2-DURABLE-OPEN tests");