WHATSNEW: Update release notes.
[Samba/bb.git] / source4 / torture / smb2 / durable_open.c
blob1b86f2c46e1b88d8007798f395ab4b71f32aad0f
1 /*
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/>.
22 #include "includes.h"
23 #include "librpc/gen_ndr/security.h"
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
26 #include "torture/torture.h"
27 #include "torture/smb2/proto.h"
29 #define CHECK_VAL(v, correct) do { \
30 if ((v) != (correct)) { \
31 torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
32 __location__, #v, (int)v, (int)correct); \
33 ret = false; \
34 }} while (0)
36 #define CHECK_STATUS(status, correct) do { \
37 if (!NT_STATUS_EQUAL(status, correct)) { \
38 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
39 nt_errstr(status), nt_errstr(correct)); \
40 ret = false; \
41 goto done; \
42 }} while (0)
44 #define CHECK_CREATED(__io, __created, __attribute) \
45 do { \
46 CHECK_VAL((__io)->out.create_action, NTCREATEX_ACTION_ ## __created); \
47 CHECK_VAL((__io)->out.alloc_size, 0); \
48 CHECK_VAL((__io)->out.size, 0); \
49 CHECK_VAL((__io)->out.file_attr, (__attribute)); \
50 CHECK_VAL((__io)->out.reserved2, 0); \
51 } while(0)
54 basic testing of SMB2 durable opens
55 regarding the position information on the handle
57 bool test_durable_open_file_position(struct torture_context *tctx,
58 struct smb2_tree *tree1,
59 struct smb2_tree *tree2)
61 TALLOC_CTX *mem_ctx = talloc_new(tctx);
62 struct smb2_handle h1, h2;
63 struct smb2_create io1, io2;
64 NTSTATUS status;
65 const char *fname = "durable_open_position.dat";
66 union smb_fileinfo qfinfo;
67 union smb_setfileinfo sfinfo;
68 bool ret = true;
69 uint64_t pos;
71 smb2_util_unlink(tree1, fname);
73 ZERO_STRUCT(io1);
74 io1.in.security_flags = 0x00;
75 io1.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
76 io1.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
77 io1.in.create_flags = 0x00000000;
78 io1.in.reserved = 0x00000000;
79 io1.in.desired_access = SEC_RIGHTS_FILE_ALL;
80 io1.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
81 io1.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
82 NTCREATEX_SHARE_ACCESS_WRITE |
83 NTCREATEX_SHARE_ACCESS_DELETE;
84 io1.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
85 io1.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
86 NTCREATEX_OPTIONS_ASYNC_ALERT |
87 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
88 0x00200000;
89 io1.in.durable_open = true;
90 io1.in.fname = fname;
92 status = smb2_create(tree1, mem_ctx, &io1);
93 CHECK_STATUS(status, NT_STATUS_OK);
94 h1 = io1.out.file.handle;
95 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
96 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
98 /* TODO: check extra blob content */
100 ZERO_STRUCT(qfinfo);
101 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
102 qfinfo.generic.in.file.handle = h1;
103 status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
104 CHECK_STATUS(status, NT_STATUS_OK);
105 CHECK_VAL(qfinfo.position_information.out.position, 0);
106 pos = qfinfo.position_information.out.position;
107 torture_comment(tctx, "position: %llu\n",
108 (unsigned long long)pos);
110 ZERO_STRUCT(sfinfo);
111 sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION;
112 sfinfo.generic.in.file.handle = h1;
113 sfinfo.position_information.in.position = 0x1000;
114 status = smb2_setinfo_file(tree1, &sfinfo);
115 CHECK_STATUS(status, NT_STATUS_OK);
117 ZERO_STRUCT(qfinfo);
118 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
119 qfinfo.generic.in.file.handle = h1;
120 status = smb2_getinfo_file(tree1, mem_ctx, &qfinfo);
121 CHECK_STATUS(status, NT_STATUS_OK);
122 CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
123 pos = qfinfo.position_information.out.position;
124 torture_comment(tctx, "position: %llu\n",
125 (unsigned long long)pos);
127 talloc_free(tree1);
128 tree1 = NULL;
130 ZERO_STRUCT(qfinfo);
131 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
132 qfinfo.generic.in.file.handle = h1;
133 status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo);
134 CHECK_STATUS(status, NT_STATUS_FILE_CLOSED);
136 ZERO_STRUCT(io2);
137 io2.in.fname = fname;
138 io2.in.durable_handle = &h1;
140 status = smb2_create(tree2, mem_ctx, &io2);
141 CHECK_STATUS(status, NT_STATUS_OK);
142 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
143 CHECK_VAL(io2.out.reserved, 0x00);
144 CHECK_VAL(io2.out.create_action, NTCREATEX_ACTION_EXISTED);
145 CHECK_VAL(io2.out.alloc_size, 0);
146 CHECK_VAL(io2.out.size, 0);
147 CHECK_VAL(io2.out.file_attr, FILE_ATTRIBUTE_ARCHIVE);
148 CHECK_VAL(io2.out.reserved2, 0);
150 h2 = io2.out.file.handle;
152 ZERO_STRUCT(qfinfo);
153 qfinfo.generic.level = RAW_FILEINFO_POSITION_INFORMATION;
154 qfinfo.generic.in.file.handle = h2;
155 status = smb2_getinfo_file(tree2, mem_ctx, &qfinfo);
156 CHECK_STATUS(status, NT_STATUS_OK);
157 CHECK_VAL(qfinfo.position_information.out.position, 0x1000);
158 pos = qfinfo.position_information.out.position;
159 torture_comment(tctx, "position: %llu\n",
160 (unsigned long long)pos);
162 smb2_util_close(tree2, h2);
164 talloc_free(mem_ctx);
166 smb2_util_unlink(tree2, fname);
167 done:
168 return ret;
172 Open, disconnect, oplock break, reconnect.
174 bool test_durable_open_oplock(struct torture_context *tctx,
175 struct smb2_tree *tree1,
176 struct smb2_tree *tree2)
178 TALLOC_CTX *mem_ctx = talloc_new(tctx);
179 struct smb2_create io1, io2;
180 struct smb2_handle h1, h2;
181 NTSTATUS status;
182 char fname[256];
183 bool ret = true;
185 /* Choose a random name in case the state is left a little funky. */
186 snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
188 /* Clean slate */
189 smb2_util_unlink(tree1, fname);
191 /* Create with batch oplock */
192 ZERO_STRUCT(io1);
193 io1.in.security_flags = 0x00;
194 io1.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
195 io1.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
196 io1.in.create_flags = 0x00000000;
197 io1.in.reserved = 0x00000000;
198 io1.in.desired_access = SEC_RIGHTS_FILE_ALL;
199 io1.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
200 io1.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
201 NTCREATEX_SHARE_ACCESS_WRITE |
202 NTCREATEX_SHARE_ACCESS_DELETE;
203 io1.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
204 io1.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
205 NTCREATEX_OPTIONS_ASYNC_ALERT |
206 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
207 0x00200000;
208 io1.in.fname = fname;
209 io1.in.durable_open = true;
211 io2 = io1;
212 io2.in.create_disposition = NTCREATEX_DISP_OPEN;
214 status = smb2_create(tree1, mem_ctx, &io1);
215 CHECK_STATUS(status, NT_STATUS_OK);
216 h1 = io1.out.file.handle;
217 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
218 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
220 /* Disconnect after getting the batch */
221 talloc_free(tree1);
222 tree1 = NULL;
225 * Windows7 (build 7000) will break a batch oplock immediately if the
226 * original client is gone. (ZML: This seems like a bug. It should give
227 * some time for the client to reconnect!)
229 status = smb2_create(tree2, mem_ctx, &io2);
230 CHECK_STATUS(status, NT_STATUS_OK);
231 h2 = io2.out.file.handle;
232 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
233 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_BATCH);
235 /* What if tree1 tries to come back and reclaim? */
236 if (!torture_smb2_connection(tctx, &tree1)) {
237 torture_warning(tctx, "couldn't reconnect, bailing\n");
238 ret = false;
239 goto done;
242 ZERO_STRUCT(io1);
243 io1.in.fname = fname;
244 io1.in.durable_handle = &h1;
246 status = smb2_create(tree1, mem_ctx, &io1);
247 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
249 done:
250 smb2_util_close(tree2, h2);
251 smb2_util_unlink(tree2, fname);
253 return ret;
257 Open, disconnect, lease break, reconnect.
259 bool test_durable_open_lease(struct torture_context *tctx,
260 struct smb2_tree *tree1,
261 struct smb2_tree *tree2)
263 TALLOC_CTX *mem_ctx = talloc_new(tctx);
264 struct smb2_create io1, io2;
265 struct smb2_lease ls1, ls2;
266 struct smb2_handle h1, h2;
267 NTSTATUS status;
268 char fname[256];
269 bool ret = true;
270 uint64_t lease1, lease2;
273 * Choose a random name and random lease in case the state is left a
274 * little funky.
276 lease1 = random();
277 lease2 = random();
278 snprintf(fname, 256, "durable_open_lease_%s.dat", generate_random_str(tctx, 8));
280 /* Clean slate */
281 smb2_util_unlink(tree1, fname);
283 /* Create with lease */
284 ZERO_STRUCT(io1);
285 io1.in.security_flags = 0x00;
286 io1.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
287 io1.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
288 io1.in.create_flags = 0x00000000;
289 io1.in.reserved = 0x00000000;
290 io1.in.desired_access = SEC_RIGHTS_FILE_ALL;
291 io1.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
292 io1.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
293 NTCREATEX_SHARE_ACCESS_WRITE |
294 NTCREATEX_SHARE_ACCESS_DELETE;
295 io1.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
296 io1.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
297 NTCREATEX_OPTIONS_ASYNC_ALERT |
298 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
299 0x00200000;
300 io1.in.fname = fname;
301 io1.in.durable_open = true;
303 ZERO_STRUCT(ls1);
304 ls1.lease_key.data[0] = lease1;
305 ls1.lease_key.data[1] = ~lease1;
306 ls1.lease_state = SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE;
307 io1.in.lease_request = &ls1;
309 io2 = io1;
310 ls2 = ls1;
311 ls2.lease_key.data[0] = lease2;
312 ls2.lease_key.data[1] = ~lease2;
313 io2.in.lease_request = &ls2;
314 io2.in.create_disposition = NTCREATEX_DISP_OPEN;
316 status = smb2_create(tree1, mem_ctx, &io1);
317 CHECK_STATUS(status, NT_STATUS_OK);
318 h1 = io1.out.file.handle;
319 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
321 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
322 CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease1);
323 CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease1);
324 CHECK_VAL(io1.out.lease_response.lease_state,
325 SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
327 /* Disconnect after getting the lease */
328 talloc_free(tree1);
329 tree1 = NULL;
332 * Windows7 (build 7000) will grant an RH lease immediate (not an RHW?)
333 * even if the original client is gone. (ZML: This seems like a bug. It
334 * should give some time for the client to reconnect! And why RH?)
336 status = smb2_create(tree2, mem_ctx, &io2);
337 CHECK_STATUS(status, NT_STATUS_OK);
338 h2 = io2.out.file.handle;
339 CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
341 CHECK_VAL(io2.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
342 CHECK_VAL(io2.out.lease_response.lease_key.data[0], lease2);
343 CHECK_VAL(io2.out.lease_response.lease_key.data[1], ~lease2);
344 CHECK_VAL(io2.out.lease_response.lease_state,
345 SMB2_LEASE_READ|SMB2_LEASE_HANDLE);
347 /* What if tree1 tries to come back and reclaim? */
348 if (!torture_smb2_connection(tctx, &tree1)) {
349 torture_warning(tctx, "couldn't reconnect, bailing\n");
350 ret = false;
351 goto done;
354 ZERO_STRUCT(io1);
355 io1.in.fname = fname;
356 io1.in.durable_handle = &h1;
357 io1.in.lease_request = &ls1;
359 status = smb2_create(tree1, mem_ctx, &io1);
360 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
362 done:
363 smb2_util_close(tree2, h2);
364 smb2_util_unlink(tree2, fname);
366 return ret;
370 Open, take BRL, disconnect, reconnect.
372 bool test_durable_open_lock(struct torture_context *tctx,
373 struct smb2_tree *tree)
375 TALLOC_CTX *mem_ctx = talloc_new(tctx);
376 struct smb2_create io;
377 struct smb2_lease ls;
378 struct smb2_handle h;
379 struct smb2_lock lck;
380 struct smb2_lock_element el[2];
381 NTSTATUS status;
382 char fname[256];
383 bool ret = true;
384 uint64_t lease;
387 * Choose a random name and random lease in case the state is left a
388 * little funky.
390 lease = random();
391 snprintf(fname, 256, "durable_open_lock_%s.dat", generate_random_str(tctx, 8));
393 /* Clean slate */
394 smb2_util_unlink(tree, fname);
396 /* Create with lease */
397 ZERO_STRUCT(io);
398 io.in.security_flags = 0x00;
399 io.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
400 io.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
401 io.in.create_flags = 0x00000000;
402 io.in.reserved = 0x00000000;
403 io.in.desired_access = SEC_RIGHTS_FILE_ALL;
404 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
405 io.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
406 NTCREATEX_SHARE_ACCESS_WRITE |
407 NTCREATEX_SHARE_ACCESS_DELETE;
408 io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
409 io.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
410 NTCREATEX_OPTIONS_ASYNC_ALERT |
411 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
412 0x00200000;
413 io.in.fname = fname;
414 io.in.durable_open = true;
416 ZERO_STRUCT(ls);
417 ls.lease_key.data[0] = lease;
418 ls.lease_key.data[1] = ~lease;
419 ls.lease_state = SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE;
420 io.in.lease_request = &ls;
422 status = smb2_create(tree, mem_ctx, &io);
423 CHECK_STATUS(status, NT_STATUS_OK);
424 h = io.out.file.handle;
425 CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
427 CHECK_VAL(io.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
428 CHECK_VAL(io.out.lease_response.lease_key.data[0], lease);
429 CHECK_VAL(io.out.lease_response.lease_key.data[1], ~lease);
430 CHECK_VAL(io.out.lease_response.lease_state,
431 SMB2_LEASE_READ|SMB2_LEASE_HANDLE|SMB2_LEASE_WRITE);
433 ZERO_STRUCT(lck);
434 ZERO_STRUCT(el);
435 lck.in.locks = el;
436 lck.in.lock_count = 0x0001;
437 lck.in.reserved = 0x00000000;
438 lck.in.file.handle = h;
439 el[0].offset = 0;
440 el[0].length = 1;
441 el[0].reserved = 0x00000000;
442 el[0].flags = SMB2_LOCK_FLAG_EXCLUSIVE;
443 status = smb2_lock(tree, &lck);
444 CHECK_STATUS(status, NT_STATUS_OK);
446 /* Disconnect/Reconnect. */
447 talloc_free(tree);
448 tree = NULL;
450 if (!torture_smb2_connection(tctx, &tree)) {
451 torture_warning(tctx, "couldn't reconnect, bailing\n");
452 ret = false;
453 goto done;
456 ZERO_STRUCT(io);
457 io.in.fname = fname;
458 io.in.durable_handle = &h;
459 io.in.lease_request = &ls;
461 status = smb2_create(tree, mem_ctx, &io);
462 CHECK_STATUS(status, NT_STATUS_OK);
463 h = io.out.file.handle;
465 lck.in.file.handle = h;
466 el[0].flags = SMB2_LOCK_FLAG_UNLOCK;
467 status = smb2_lock(tree, &lck);
468 CHECK_STATUS(status, NT_STATUS_OK);
470 done:
471 smb2_util_close(tree, h);
472 smb2_util_unlink(tree, fname);
474 return ret;
478 Open, disconnect, open in another tree, reconnect.
480 This test actually demonstrates a minimum level of respect for the durable
481 open in the face of another open. As long as this test shows an inability to
482 reconnect after an open, the oplock/lease tests above will certainly
483 demonstrate an error on reconnect.
485 bool test_durable_open_open(struct torture_context *tctx,
486 struct smb2_tree *tree1,
487 struct smb2_tree *tree2)
489 TALLOC_CTX *mem_ctx = talloc_new(tctx);
490 struct smb2_create io1, io2;
491 struct smb2_lease ls;
492 struct smb2_handle h1, h2;
493 NTSTATUS status;
494 char fname[256];
495 bool ret = true;
496 uint64_t lease;
499 * Choose a random name and random lease in case the state is left a
500 * little funky.
502 lease = random();
503 snprintf(fname, 256, "durable_open_lock_%s.dat", generate_random_str(tctx, 8));
505 /* Clean slate */
506 smb2_util_unlink(tree1, fname);
508 /* Create with lease */
509 ZERO_STRUCT(io1);
510 io1.in.security_flags = 0x00;
511 io1.in.oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
512 io1.in.impersonation_level = NTCREATEX_IMPERSONATION_IMPERSONATION;
513 io1.in.create_flags = 0x00000000;
514 io1.in.reserved = 0x00000000;
515 io1.in.desired_access = SEC_RIGHTS_FILE_ALL;
516 io1.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
517 io1.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
518 io1.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
519 io1.in.create_options = NTCREATEX_OPTIONS_SEQUENTIAL_ONLY |
520 NTCREATEX_OPTIONS_ASYNC_ALERT |
521 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE |
522 0x00200000;
523 io1.in.fname = fname;
524 io1.in.durable_open = true;
526 io2 = io1;
527 io2.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
528 io2.in.durable_open = false;
530 ZERO_STRUCT(ls);
531 ls.lease_key.data[0] = lease;
532 ls.lease_key.data[1] = ~lease;
533 ls.lease_state = SMB2_LEASE_READ|SMB2_LEASE_HANDLE;
534 io1.in.lease_request = &ls;
536 status = smb2_create(tree1, mem_ctx, &io1);
537 CHECK_STATUS(status, NT_STATUS_OK);
538 h1 = io1.out.file.handle;
539 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
541 CHECK_VAL(io1.out.oplock_level, SMB2_OPLOCK_LEVEL_LEASE);
542 CHECK_VAL(io1.out.lease_response.lease_key.data[0], lease);
543 CHECK_VAL(io1.out.lease_response.lease_key.data[1], ~lease);
544 CHECK_VAL(io1.out.lease_response.lease_state,
545 SMB2_LEASE_READ|SMB2_LEASE_HANDLE);
547 /* Disconnect */
548 talloc_free(tree1);
549 tree1 = NULL;
551 /* Open the file in tree2 */
552 status = smb2_create(tree2, mem_ctx, &io2);
553 CHECK_STATUS(status, NT_STATUS_OK);
554 h2 = io2.out.file.handle;
555 CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
557 /* Reconnect */
558 if (!torture_smb2_connection(tctx, &tree1)) {
559 torture_warning(tctx, "couldn't reconnect, bailing\n");
560 ret = false;
561 goto done;
564 ZERO_STRUCT(io1);
565 io1.in.fname = fname;
566 io1.in.durable_handle = &h1;
567 io1.in.lease_request = &ls;
570 * Windows7 (build 7000) will give away an open immediately if the
571 * original client is gone. (ZML: This seems like a bug. It should give
572 * some time for the client to reconnect!)
574 status = smb2_create(tree1, mem_ctx, &io1);
575 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
576 h1 = io1.out.file.handle;
578 done:
579 smb2_util_close(tree2, h2);
580 smb2_util_unlink(tree2, fname);
581 smb2_util_close(tree1, h1);
582 smb2_util_unlink(tree1, fname);
584 return ret;
587 struct torture_suite *torture_smb2_durable_open_init(void)
589 struct torture_suite *suite =
590 torture_suite_create(talloc_autofree_context(), "DURABLE-OPEN");
592 torture_suite_add_2smb2_test(suite, "FILE-POSITION",
593 test_durable_open_file_position);
594 torture_suite_add_2smb2_test(suite, "OPLOCK", test_durable_open_oplock);
595 torture_suite_add_2smb2_test(suite, "LEASE", test_durable_open_lease);
596 torture_suite_add_1smb2_test(suite, "LOCK", test_durable_open_lock);
597 torture_suite_add_2smb2_test(suite, "OPEN", test_durable_open_open);
599 suite->description = talloc_strdup(suite, "SMB2-DURABLE-OPEN tests");
601 return suite;