2 Unix SMB/CIFS implementation.
6 Copyright (C) Stefan Metzmacher 2006
7 Copyright (C) Andrew Tridgell 2009
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/>.
24 #include "libcli/smb2/smb2.h"
25 #include "libcli/smb2/smb2_calls.h"
27 #include "torture/torture.h"
28 #include "torture/smb2/proto.h"
29 #include "librpc/gen_ndr/ndr_security.h"
30 #include "libcli/security/security.h"
31 #include "torture/util.h"
33 #include "system/filesys.h"
34 #include "auth/credentials/credentials.h"
35 #include "lib/cmdline/popt_common.h"
36 #include "librpc/gen_ndr/security.h"
38 #include "lib/events/events.h"
40 #include "libcli/raw/libcliraw.h"
41 #include "libcli/raw/raw_proto.h"
42 #include "libcli/libcli.h"
44 #define CHECK_STATUS(status, correct) do { \
45 if (!NT_STATUS_EQUAL(status, correct)) { \
46 torture_result(torture, TORTURE_FAIL, \
47 "(%s) Incorrect status %s - should be %s\n", \
48 __location__, nt_errstr(status), nt_errstr(correct)); \
53 #define CHECK_VAL(v, correct) do { \
54 if ((v) != (correct)) { \
55 torture_result(torture, TORTURE_FAIL, \
56 "(%s) wrong value for %s 0x%x should be 0x%x\n", \
57 __location__, #v, (int)v, (int)correct); \
62 #define CHECK_WIRE_STR(field, value) do { \
63 if (!field.s || strcmp(field.s, value)) { \
64 torture_result(torture, TORTURE_FAIL, \
65 "(%s) %s [%s] != %s\n", __location__, #field, \
71 #define BASEDIR "test_notify"
72 #define FNAME "smb2-notify01.dat"
74 static bool test_valid_request(struct torture_context
*torture
,
75 struct smb2_tree
*tree
)
79 struct smb2_handle dh
;
81 struct smb2_request
*req
;
82 uint32_t max_buffer_size
;
84 torture_comment(torture
, "TESTING VALIDITY OF CHANGE NOTIFY REQUEST\n");
86 smb2_util_unlink(tree
, FNAME
);
88 status
= smb2_util_roothandle(tree
, &dh
);
89 CHECK_STATUS(status
, NT_STATUS_OK
);
91 /* 0x00080000 is the default max buffer size for Windows servers
93 max_buffer_size
= torture_setting_ulong(torture
, "cn_max_buffer_size",
96 n
.in
.recursive
= 0x0000;
97 n
.in
.buffer_size
= max_buffer_size
;
98 n
.in
.file
.handle
= dh
;
99 n
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ALL
;
100 n
.in
.unknown
= 0x00000000;
101 req
= smb2_notify_send(tree
, &n
);
103 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
104 if (tevent_loop_once(torture
->ev
) != 0) {
109 status
= torture_setup_complex_file(tree
, FNAME
);
110 CHECK_STATUS(status
, NT_STATUS_OK
);
112 status
= smb2_notify_recv(req
, torture
, &n
);
113 CHECK_STATUS(status
, NT_STATUS_OK
);
114 CHECK_VAL(n
.out
.num_changes
, 1);
115 CHECK_VAL(n
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
116 CHECK_WIRE_STR(n
.out
.changes
[0].name
, FNAME
);
119 * if the change response doesn't fit in the buffer
120 * NOTIFY_ENUM_DIR is returned.
122 n
.in
.buffer_size
= 0x00000000;
123 req
= smb2_notify_send(tree
, &n
);
125 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
126 if (tevent_loop_once(torture
->ev
) != 0) {
131 status
= torture_setup_complex_file(tree
, FNAME
);
132 CHECK_STATUS(status
, NT_STATUS_OK
);
134 status
= smb2_notify_recv(req
, torture
, &n
);
135 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
138 * if the change response fits in the buffer we get
141 n
.in
.buffer_size
= max_buffer_size
;
142 req
= smb2_notify_send(tree
, &n
);
144 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
145 if (tevent_loop_once(torture
->ev
) != 0) {
150 status
= torture_setup_complex_file(tree
, FNAME
);
151 CHECK_STATUS(status
, NT_STATUS_OK
);
153 status
= smb2_notify_recv(req
, torture
, &n
);
154 CHECK_STATUS(status
, NT_STATUS_OK
);
155 CHECK_VAL(n
.out
.num_changes
, 3);
156 CHECK_VAL(n
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
157 CHECK_WIRE_STR(n
.out
.changes
[0].name
, FNAME
);
158 CHECK_VAL(n
.out
.changes
[1].action
, NOTIFY_ACTION_ADDED
);
159 CHECK_WIRE_STR(n
.out
.changes
[1].name
, FNAME
);
160 CHECK_VAL(n
.out
.changes
[2].action
, NOTIFY_ACTION_MODIFIED
);
161 CHECK_WIRE_STR(n
.out
.changes
[2].name
, FNAME
);
163 /* if the first notify returns NOTIFY_ENUM_DIR, all do */
164 status
= smb2_util_close(tree
, dh
);
165 CHECK_STATUS(status
, NT_STATUS_OK
);
166 status
= smb2_util_roothandle(tree
, &dh
);
167 CHECK_STATUS(status
, NT_STATUS_OK
);
169 n
.in
.recursive
= 0x0000;
170 n
.in
.buffer_size
= 0x00000001;
171 n
.in
.file
.handle
= dh
;
172 n
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ALL
;
173 n
.in
.unknown
= 0x00000000;
174 req
= smb2_notify_send(tree
, &n
);
176 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
177 if (tevent_loop_once(torture
->ev
) != 0) {
182 status
= torture_setup_complex_file(tree
, FNAME
);
183 CHECK_STATUS(status
, NT_STATUS_OK
);
185 status
= smb2_notify_recv(req
, torture
, &n
);
186 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
188 n
.in
.buffer_size
= max_buffer_size
;
189 req
= smb2_notify_send(tree
, &n
);
190 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
191 if (tevent_loop_once(torture
->ev
) != 0) {
196 status
= torture_setup_complex_file(tree
, FNAME
);
197 CHECK_STATUS(status
, NT_STATUS_OK
);
199 status
= smb2_notify_recv(req
, torture
, &n
);
200 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
202 /* if the buffer size is too large, we get invalid parameter */
203 n
.in
.recursive
= 0x0000;
204 n
.in
.buffer_size
= max_buffer_size
+ 1;
205 n
.in
.file
.handle
= dh
;
206 n
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ALL
;
207 n
.in
.unknown
= 0x00000000;
208 req
= smb2_notify_send(tree
, &n
);
209 status
= smb2_notify_recv(req
, torture
, &n
);
210 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
217 basic testing of change notify on directories
219 static bool torture_smb2_notify_dir(struct torture_context
*torture
,
220 struct smb2_tree
*tree1
,
221 struct smb2_tree
*tree2
)
225 union smb_notify notify
;
229 struct smb2_handle h1
, h2
;
230 struct smb2_request
*req
, *req2
;
231 const char *fname
= BASEDIR
"\\subdir-name";
232 extern int torture_numops
;
234 torture_comment(torture
, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
236 smb2_deltree(tree1
, BASEDIR
);
237 smb2_util_rmdir(tree1
, BASEDIR
);
239 get a handle on the directory
241 ZERO_STRUCT(io
.smb2
);
242 io
.generic
.level
= RAW_OPEN_SMB2
;
243 io
.smb2
.in
.create_flags
= 0;
244 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
245 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
246 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
247 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
248 NTCREATEX_SHARE_ACCESS_WRITE
;
249 io
.smb2
.in
.alloc_size
= 0;
250 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
251 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
252 io
.smb2
.in
.security_flags
= 0;
253 io
.smb2
.in
.fname
= BASEDIR
;
255 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
256 CHECK_STATUS(status
, NT_STATUS_OK
);
257 h1
= io
.smb2
.out
.file
.handle
;
259 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
260 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
;
261 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
262 CHECK_STATUS(status
, NT_STATUS_OK
);
263 h2
= io
.smb2
.out
.file
.handle
;
265 /* ask for a change notify,
266 on file or directory name changes */
267 ZERO_STRUCT(notify
.smb2
);
268 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
269 notify
.smb2
.in
.buffer_size
= 1000;
270 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
271 notify
.smb2
.in
.file
.handle
= h1
;
272 notify
.smb2
.in
.recursive
= true;
274 torture_comment(torture
, "Testing notify cancel\n");
276 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
278 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
279 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
281 torture_comment(torture
, "Testing notify mkdir\n");
283 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
284 smb2_util_mkdir(tree2
, fname
);
286 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
287 CHECK_STATUS(status
, NT_STATUS_OK
);
289 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
290 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
291 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
293 torture_comment(torture
, "Testing notify rmdir\n");
295 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
296 smb2_util_rmdir(tree2
, fname
);
298 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
299 CHECK_STATUS(status
, NT_STATUS_OK
);
300 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
301 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
302 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
304 torture_comment(torture
,
305 "Testing notify mkdir - rmdir - mkdir - rmdir\n");
307 smb2_util_mkdir(tree2
, fname
);
308 smb2_util_rmdir(tree2
, fname
);
309 smb2_util_mkdir(tree2
, fname
);
310 smb2_util_rmdir(tree2
, fname
);
312 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
313 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
314 CHECK_STATUS(status
, NT_STATUS_OK
);
315 CHECK_VAL(notify
.smb2
.out
.num_changes
, 4);
316 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
317 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
318 CHECK_VAL(notify
.smb2
.out
.changes
[1].action
, NOTIFY_ACTION_REMOVED
);
319 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[1].name
, "subdir-name");
320 CHECK_VAL(notify
.smb2
.out
.changes
[2].action
, NOTIFY_ACTION_ADDED
);
321 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[2].name
, "subdir-name");
322 CHECK_VAL(notify
.smb2
.out
.changes
[3].action
, NOTIFY_ACTION_REMOVED
);
323 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[3].name
, "subdir-name");
325 count
= torture_numops
;
326 torture_comment(torture
,
327 "Testing buffered notify on create of %d files\n", count
);
328 for (i
=0;i
<count
;i
++) {
329 struct smb2_handle h12
;
330 char *fname2
= talloc_asprintf(torture
, BASEDIR
"\\test%d.txt",
333 ZERO_STRUCT(io
.smb2
);
334 io
.generic
.level
= RAW_OPEN_SMB2
;
335 io
.smb2
.in
.create_flags
= 0;
336 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
337 io
.smb2
.in
.create_options
=
338 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
339 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
340 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
341 NTCREATEX_SHARE_ACCESS_WRITE
;
342 io
.smb2
.in
.alloc_size
= 0;
343 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
344 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
345 io
.smb2
.in
.security_flags
= 0;
346 io
.smb2
.in
.fname
= fname2
;
348 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
349 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
350 torture_comment(torture
, "Failed to create %s \n",
355 h12
= io
.smb2
.out
.file
.handle
;
357 smb2_util_close(tree1
, h12
);
360 /* (1st notify) setup a new notify on a different directory handle.
361 This new notify won't see the events above. */
362 notify
.smb2
.in
.file
.handle
= h2
;
363 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
365 /* (2nd notify) whereas this notify will see the above buffered events,
366 and it directly returns the buffered events */
367 notify
.smb2
.in
.file
.handle
= h1
;
368 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
370 status
= smb2_util_unlink(tree1
, BASEDIR
"\\nonexistant.txt");
371 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
373 /* (1st unlink) as the 2nd notify directly returns,
374 this unlink is only seen by the 1st notify and
375 the 3rd notify (later) */
376 torture_comment(torture
,
377 "Testing notify on unlink for the first file\n");
378 status
= smb2_util_unlink(tree2
, BASEDIR
"\\test0.txt");
379 CHECK_STATUS(status
, NT_STATUS_OK
);
381 /* receive the reply from the 2nd notify */
382 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
383 CHECK_STATUS(status
, NT_STATUS_OK
);
385 CHECK_VAL(notify
.smb2
.out
.num_changes
, count
);
386 for (i
=1;i
<count
;i
++) {
387 CHECK_VAL(notify
.smb2
.out
.changes
[i
].action
,
388 NOTIFY_ACTION_ADDED
);
390 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "test0.txt");
392 torture_comment(torture
, "and now from the 1st notify\n");
393 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
394 CHECK_STATUS(status
, NT_STATUS_OK
);
395 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
396 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
397 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "test0.txt");
399 torture_comment(torture
,
400 "(3rd notify) this notify will only see the 1st unlink\n");
401 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
403 status
= smb2_util_unlink(tree1
, BASEDIR
"\\nonexistant.txt");
404 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
406 for (i
=1;i
<count
;i
++) {
407 char *fname2
= talloc_asprintf(torture
,
408 BASEDIR
"\\test%d.txt", i
);
409 status
= smb2_util_unlink(tree2
, fname2
);
410 CHECK_STATUS(status
, NT_STATUS_OK
);
414 /* receive the 3rd notify */
415 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
416 CHECK_STATUS(status
, NT_STATUS_OK
);
417 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
418 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
419 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "test0.txt");
421 /* and we now see the rest of the unlink calls on both
422 * directory handles */
423 notify
.smb2
.in
.file
.handle
= h1
;
425 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
426 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
427 CHECK_STATUS(status
, NT_STATUS_OK
);
428 CHECK_VAL(notify
.smb2
.out
.num_changes
, count
-1);
429 for (i
=0;i
<notify
.smb2
.out
.num_changes
;i
++) {
430 CHECK_VAL(notify
.smb2
.out
.changes
[i
].action
,
431 NOTIFY_ACTION_REMOVED
);
433 notify
.smb2
.in
.file
.handle
= h2
;
434 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
435 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
436 CHECK_STATUS(status
, NT_STATUS_OK
);
437 CHECK_VAL(notify
.smb2
.out
.num_changes
, count
-1);
438 for (i
=0;i
<notify
.smb2
.out
.num_changes
;i
++) {
439 CHECK_VAL(notify
.smb2
.out
.changes
[i
].action
,
440 NOTIFY_ACTION_REMOVED
);
443 torture_comment(torture
,
444 "Testing if a close() on the dir handle triggers the notify reply\n");
446 notify
.smb2
.in
.file
.handle
= h1
;
447 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
449 ZERO_STRUCT(cl
.smb2
);
450 cl
.smb2
.level
= RAW_CLOSE_SMB2
;
451 cl
.smb2
.in
.file
.handle
= h1
;
452 status
= smb2_close(tree1
, &(cl
.smb2
));
453 CHECK_STATUS(status
, NT_STATUS_OK
);
455 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
456 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
457 CHECK_VAL(notify
.smb2
.out
.num_changes
, 9);
460 smb2_util_close(tree1
, h1
);
461 smb2_util_close(tree1
, h2
);
462 smb2_deltree(tree1
, BASEDIR
);
466 static struct smb2_handle
custom_smb2_create(struct smb2_tree
*tree
,
467 struct torture_context
*torture
,
468 struct smb2_create
*smb2
)
470 struct smb2_handle h1
;
473 smb2_deltree(tree
, smb2
->in
.fname
);
474 status
= smb2_create(tree
, torture
, smb2
);
475 CHECK_STATUS(status
, NT_STATUS_OK
);
476 h1
= smb2
->out
.file
.handle
;
482 testing of recursive change notify
485 static bool torture_smb2_notify_recursive(struct torture_context
*torture
,
486 struct smb2_tree
*tree1
,
487 struct smb2_tree
*tree2
)
491 union smb_notify notify
;
492 union smb_open io
, io1
;
493 union smb_setfileinfo sinfo
;
494 struct smb2_handle h1
;
495 struct smb2_request
*req1
, *req2
;
497 smb2_deltree(tree1
, BASEDIR
);
498 smb2_util_rmdir(tree1
, BASEDIR
);
500 torture_comment(torture
, "TESTING CHANGE NOTIFY WITH RECURSION\n");
503 get a handle on the directory
505 ZERO_STRUCT(io
.smb2
);
506 io
.generic
.level
= RAW_OPEN_SMB2
;
507 io
.smb2
.in
.create_flags
= 0;
508 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
509 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
510 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
511 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
512 NTCREATEX_SHARE_ACCESS_WRITE
;
513 io
.smb2
.in
.alloc_size
= 0;
514 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
515 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
516 io
.smb2
.in
.security_flags
= 0;
517 io
.smb2
.in
.fname
= BASEDIR
;
519 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
520 CHECK_STATUS(status
, NT_STATUS_OK
);
521 h1
= io
.smb2
.out
.file
.handle
;
523 /* ask for a change notify, on file or directory name
524 changes. Setup both with and without recursion */
525 ZERO_STRUCT(notify
.smb2
);
526 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
527 notify
.smb2
.in
.buffer_size
= 1000;
528 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
|
529 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
530 FILE_NOTIFY_CHANGE_CREATION
;
531 notify
.smb2
.in
.file
.handle
= h1
;
533 notify
.smb2
.in
.recursive
= true;
534 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
536 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
537 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
539 notify
.smb2
.in
.recursive
= false;
540 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
542 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
543 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
545 ZERO_STRUCT(io1
.smb2
);
546 io1
.generic
.level
= RAW_OPEN_SMB2
;
547 io1
.smb2
.in
.create_flags
= NTCREATEX_FLAGS_EXTENDED
;
548 io1
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
549 SEC_RIGHTS_FILE_WRITE
|
551 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
552 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
553 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
554 NTCREATEX_SHARE_ACCESS_WRITE
|
555 NTCREATEX_SHARE_ACCESS_DELETE
;
556 io1
.smb2
.in
.alloc_size
= 0;
557 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
558 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
559 io1
.smb2
.in
.security_flags
= 0;
560 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name";
561 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
562 CHECK_STATUS(status
, NT_STATUS_OK
);
563 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
565 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname1";
566 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
567 CHECK_STATUS(status
, NT_STATUS_OK
);
569 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
570 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
571 sinfo
.rename_information
.in
.overwrite
= 0;
572 sinfo
.rename_information
.in
.root_fid
= 0;
573 sinfo
.rename_information
.in
.new_name
=
574 BASEDIR
"\\subdir-name\\subname1-r";
575 status
= smb2_setinfo_file(tree2
, &sinfo
);
576 CHECK_STATUS(status
, NT_STATUS_OK
);
578 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
579 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname2";
580 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
581 CHECK_STATUS(status
, NT_STATUS_OK
);
583 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
584 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
585 sinfo
.rename_information
.in
.overwrite
= true;
586 sinfo
.rename_information
.in
.root_fid
= 0;
587 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname2-r";
588 status
= smb2_setinfo_file(tree2
, &sinfo
);
589 CHECK_STATUS(status
, NT_STATUS_OK
);
591 io1
.smb2
.in
.fname
= BASEDIR
"\\subname2-r";
592 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
593 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
594 CHECK_STATUS(status
, NT_STATUS_OK
);
596 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
597 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
598 sinfo
.rename_information
.in
.overwrite
= true;
599 sinfo
.rename_information
.in
.root_fid
= 0;
600 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname3-r";
601 status
= smb2_setinfo_file(tree2
, &sinfo
);
602 CHECK_STATUS(status
, NT_STATUS_OK
);
604 notify
.smb2
.in
.completion_filter
= 0;
605 notify
.smb2
.in
.recursive
= true;
607 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
609 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name\\subname1-r");
610 CHECK_STATUS(status
, NT_STATUS_OK
);
611 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name");
612 CHECK_STATUS(status
, NT_STATUS_OK
);
613 status
= smb2_util_unlink(tree2
, BASEDIR
"\\subname3-r");
614 CHECK_STATUS(status
, NT_STATUS_OK
);
616 notify
.smb2
.in
.recursive
= false;
617 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
619 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
620 CHECK_STATUS(status
, NT_STATUS_OK
);
622 CHECK_VAL(notify
.smb2
.out
.num_changes
, 9);
623 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
624 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
625 CHECK_VAL(notify
.smb2
.out
.changes
[1].action
, NOTIFY_ACTION_ADDED
);
626 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[1].name
, "subdir-name\\subname1");
627 CHECK_VAL(notify
.smb2
.out
.changes
[2].action
, NOTIFY_ACTION_OLD_NAME
);
628 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[2].name
, "subdir-name\\subname1");
629 CHECK_VAL(notify
.smb2
.out
.changes
[3].action
, NOTIFY_ACTION_NEW_NAME
);
630 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[3].name
, "subdir-name\\subname1-r");
631 CHECK_VAL(notify
.smb2
.out
.changes
[4].action
, NOTIFY_ACTION_ADDED
);
632 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[4].name
, "subdir-name\\subname2");
633 CHECK_VAL(notify
.smb2
.out
.changes
[5].action
, NOTIFY_ACTION_REMOVED
);
634 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[5].name
, "subdir-name\\subname2");
635 CHECK_VAL(notify
.smb2
.out
.changes
[6].action
, NOTIFY_ACTION_ADDED
);
636 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[6].name
, "subname2-r");
637 CHECK_VAL(notify
.smb2
.out
.changes
[7].action
, NOTIFY_ACTION_OLD_NAME
);
638 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[7].name
, "subname2-r");
639 CHECK_VAL(notify
.smb2
.out
.changes
[8].action
, NOTIFY_ACTION_NEW_NAME
);
640 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[8].name
, "subname3-r");
643 smb2_deltree(tree1
, BASEDIR
);
648 testing of change notify mask change
651 static bool torture_smb2_notify_mask_change(struct torture_context
*torture
,
652 struct smb2_tree
*tree1
,
653 struct smb2_tree
*tree2
)
657 union smb_notify notify
;
658 union smb_open io
, io1
;
659 struct smb2_handle h1
;
660 struct smb2_request
*req1
, *req2
;
661 union smb_setfileinfo sinfo
;
663 smb2_deltree(tree1
, BASEDIR
);
664 smb2_util_rmdir(tree1
, BASEDIR
);
666 torture_comment(torture
, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
669 get a handle on the directory
671 ZERO_STRUCT(io
.smb2
);
672 io
.generic
.level
= RAW_OPEN_SMB2
;
673 io
.smb2
.in
.create_flags
= 0;
674 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
675 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
676 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
677 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
678 NTCREATEX_SHARE_ACCESS_WRITE
;
679 io
.smb2
.in
.alloc_size
= 0;
680 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
681 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
682 io
.smb2
.in
.security_flags
= 0;
683 io
.smb2
.in
.fname
= BASEDIR
;
685 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
686 CHECK_STATUS(status
, NT_STATUS_OK
);
687 h1
= io
.smb2
.out
.file
.handle
;
689 /* ask for a change notify, on file or directory name
690 changes. Setup both with and without recursion */
691 ZERO_STRUCT(notify
.smb2
);
692 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
693 notify
.smb2
.in
.buffer_size
= 1000;
694 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
695 notify
.smb2
.in
.file
.handle
= h1
;
697 notify
.smb2
.in
.recursive
= true;
698 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
701 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
702 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
705 notify
.smb2
.in
.recursive
= false;
706 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
709 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
710 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
712 notify
.smb2
.in
.recursive
= true;
713 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
715 /* Set to hidden then back again. */
716 ZERO_STRUCT(io1
.smb2
);
717 io1
.generic
.level
= RAW_OPEN_SMB2
;
718 io1
.smb2
.in
.create_flags
= 0;
719 io1
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
720 SEC_RIGHTS_FILE_WRITE
|
722 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
723 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
724 NTCREATEX_SHARE_ACCESS_WRITE
|
725 NTCREATEX_SHARE_ACCESS_DELETE
;
726 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
727 io1
.smb2
.in
.security_flags
= 0;
728 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
729 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
730 io1
.smb2
.in
.fname
= BASEDIR
"\\tname1";
732 smb2_util_close(tree1
,
733 custom_smb2_create(tree1
, torture
, &(io1
.smb2
)));
734 status
= smb2_util_setatr(tree1
, BASEDIR
"\\tname1",
735 FILE_ATTRIBUTE_HIDDEN
);
736 CHECK_STATUS(status
, NT_STATUS_OK
);
737 smb2_util_unlink(tree1
, BASEDIR
"\\tname1");
739 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
740 CHECK_STATUS(status
, NT_STATUS_OK
);
742 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
743 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
744 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "tname1");
746 /* Now try and change the mask to include other events.
747 * This should not work - once the mask is set on a directory
748 * h1 it seems to be fixed until the fnum is closed. */
750 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
|
751 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
752 FILE_NOTIFY_CHANGE_CREATION
;
753 notify
.smb2
.in
.recursive
= true;
754 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
756 notify
.smb2
.in
.recursive
= false;
757 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
759 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
760 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
761 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name";
762 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
763 CHECK_STATUS(status
, NT_STATUS_OK
);
764 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
767 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname1";
768 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
769 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
770 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
771 CHECK_STATUS(status
, NT_STATUS_OK
);
772 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
773 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
774 sinfo
.rename_information
.in
.overwrite
= true;
775 sinfo
.rename_information
.in
.root_fid
= 0;
776 sinfo
.rename_information
.in
.new_name
=
777 BASEDIR
"\\subdir-name\\subname1-r";
778 status
= smb2_setinfo_file(tree2
, &sinfo
);
779 CHECK_STATUS(status
, NT_STATUS_OK
);
781 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname2";
782 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
783 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
784 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
785 CHECK_STATUS(status
, NT_STATUS_OK
);
786 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
787 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname2-r";
788 status
= smb2_setinfo_file(tree2
, &sinfo
);
789 CHECK_STATUS(status
, NT_STATUS_OK
);
790 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
792 io1
.smb2
.in
.fname
= BASEDIR
"\\subname2-r";
793 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
794 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
795 CHECK_STATUS(status
, NT_STATUS_OK
);
796 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
797 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname3-r";
798 status
= smb2_setinfo_file(tree2
, &sinfo
);
799 CHECK_STATUS(status
, NT_STATUS_OK
);
800 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
802 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name\\subname1-r");
803 CHECK_STATUS(status
, NT_STATUS_OK
);
804 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name");
805 CHECK_STATUS(status
, NT_STATUS_OK
);
806 status
= smb2_util_unlink(tree2
, BASEDIR
"\\subname3-r");
807 CHECK_STATUS(status
, NT_STATUS_OK
);
809 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
810 CHECK_STATUS(status
, NT_STATUS_OK
);
812 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
813 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
814 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subname2-r");
816 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
817 CHECK_STATUS(status
, NT_STATUS_OK
);
819 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
820 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
821 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subname3-r");
828 smb2_deltree(tree1
, BASEDIR
);
833 testing of mask bits for change notify
836 static bool torture_smb2_notify_mask(struct torture_context
*torture
,
837 struct smb2_tree
*tree1
,
838 struct smb2_tree
*tree2
)
842 union smb_notify notify
;
843 union smb_open io
, io1
;
844 struct smb2_handle h1
, h2
;
848 union smb_setfileinfo sinfo
;
850 smb2_deltree(tree1
, BASEDIR
);
851 smb2_util_rmdir(tree1
, BASEDIR
);
853 torture_comment(torture
, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
857 get a handle on the directory
859 ZERO_STRUCT(io
.smb2
);
860 io
.generic
.level
= RAW_OPEN_SMB2
;
861 io
.smb2
.in
.create_flags
= 0;
862 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
863 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
864 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
865 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
866 NTCREATEX_SHARE_ACCESS_WRITE
;
867 io
.smb2
.in
.alloc_size
= 0;
868 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
869 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
870 io
.smb2
.in
.security_flags
= 0;
871 io
.smb2
.in
.fname
= BASEDIR
;
873 ZERO_STRUCT(notify
.smb2
);
874 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
875 notify
.smb2
.in
.buffer_size
= 1000;
876 notify
.smb2
.in
.recursive
= true;
878 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
879 expected, nchanges) \
881 do { for (mask=i=0;i<32;i++) { \
882 struct smb2_request *req; \
883 status = smb2_create(tree1, torture, &(io.smb2)); \
884 CHECK_STATUS(status, NT_STATUS_OK); \
885 h1 = io.smb2.out.file.handle; \
887 notify.smb2.in.file.handle = h1; \
888 notify.smb2.in.completion_filter = (1<<i); \
889 /* cancel initial requests so the buffer is setup */ \
890 req = smb2_notify_send(tree1, &(notify.smb2)); \
892 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
893 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
894 /* send the change notify request */ \
895 req = smb2_notify_send(tree1, &(notify.smb2)); \
897 smb_msleep(200); smb2_cancel(req); \
898 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
900 smb2_util_close(tree1, h1); \
901 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
902 CHECK_STATUS(status, NT_STATUS_OK); \
903 /* special case to cope with file rename behaviour */ \
904 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
905 notify.smb2.out.changes[0].action == \
906 NOTIFY_ACTION_MODIFIED && \
907 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
908 Action == NOTIFY_ACTION_OLD_NAME) { \
909 torture_comment(torture, \
910 "(rename file special handling OK)\n"); \
911 } else if (nchanges != notify.smb2.out.num_changes) { \
912 torture_result(torture, TORTURE_FAIL, \
913 "ERROR: nchanges=%d expected=%d "\
914 "action=%d filter=0x%08x\n", \
915 notify.smb2.out.num_changes, \
917 notify.smb2.out.changes[0].action, \
918 notify.smb2.in.completion_filter); \
920 } else if (notify.smb2.out.changes[0].action != Action) { \
921 torture_result(torture, TORTURE_FAIL, \
922 "ERROR: nchanges=%d action=%d " \
923 "expectedAction=%d filter=0x%08x\n", \
924 notify.smb2.out.num_changes, \
925 notify.smb2.out.changes[0].action, \
927 notify.smb2.in.completion_filter); \
929 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
931 torture_result(torture, TORTURE_FAIL, \
932 "ERROR: nchanges=%d action=%d " \
933 "filter=0x%08x name=%s\n", \
934 notify.smb2.out.num_changes, \
935 notify.smb2.out.changes[0].action, \
936 notify.smb2.in.completion_filter, \
937 notify.smb2.out.changes[0].name.s); \
945 torture_comment(torture
, "Testing mkdir\n");
946 NOTIFY_MASK_TEST("Testing mkdir",;,
947 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
948 smb2_util_rmdir(tree2
, BASEDIR
"\\tname1");,
950 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
952 torture_comment(torture
, "Testing create file\n");
953 ZERO_STRUCT(io1
.smb2
);
954 io1
.generic
.level
= RAW_OPEN_SMB2
;
955 io1
.smb2
.in
.create_flags
= 0;
956 io1
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
957 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
958 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
959 NTCREATEX_SHARE_ACCESS_WRITE
;
960 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
961 io1
.smb2
.in
.security_flags
= 0;
962 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
963 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
964 io1
.smb2
.in
.fname
= BASEDIR
"\\tname1";
966 NOTIFY_MASK_TEST("Testing create file",;,
967 smb2_util_close(tree2
, custom_smb2_create(tree2
,
968 torture
, &(io1
.smb2
)));,
969 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
971 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
973 torture_comment(torture
, "Testing unlink\n");
974 NOTIFY_MASK_TEST("Testing unlink",
975 smb2_util_close(tree2
, custom_smb2_create(tree2
,
976 torture
, &(io1
.smb2
)));,
977 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
979 NOTIFY_ACTION_REMOVED
,
980 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
982 torture_comment(torture
, "Testing rmdir\n");
983 NOTIFY_MASK_TEST("Testing rmdir",
984 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
985 smb2_util_rmdir(tree2
, BASEDIR
"\\tname1");,
987 NOTIFY_ACTION_REMOVED
,
988 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
990 torture_comment(torture
, "Testing rename file\n");
992 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
993 sinfo
.rename_information
.in
.file
.handle
= h1
;
994 sinfo
.rename_information
.in
.overwrite
= true;
995 sinfo
.rename_information
.in
.root_fid
= 0;
996 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\tname2";
997 NOTIFY_MASK_TEST("Testing rename file",
998 smb2_util_close(tree2
, custom_smb2_create(tree2
,
999 torture
, &(io1
.smb2
)));,
1000 smb2_setinfo_file(tree2
, &sinfo
);,
1001 smb2_util_unlink(tree2
, BASEDIR
"\\tname2");,
1002 NOTIFY_ACTION_OLD_NAME
,
1003 FILE_NOTIFY_CHANGE_FILE_NAME
, 2);
1005 torture_comment(torture
, "Testing rename dir\n");
1007 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1008 sinfo
.rename_information
.in
.file
.handle
= h1
;
1009 sinfo
.rename_information
.in
.overwrite
= true;
1010 sinfo
.rename_information
.in
.root_fid
= 0;
1011 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\tname2";
1012 NOTIFY_MASK_TEST("Testing rename dir",
1013 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
1014 smb2_setinfo_file(tree2
, &sinfo
);,
1015 smb2_util_rmdir(tree2
, BASEDIR
"\\tname2");,
1016 NOTIFY_ACTION_OLD_NAME
,
1017 FILE_NOTIFY_CHANGE_DIR_NAME
, 2);
1019 torture_comment(torture
, "Testing set path attribute\n");
1020 NOTIFY_MASK_TEST("Testing set path attribute",
1021 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1022 torture
, &(io
.smb2
)));,
1023 smb2_util_setatr(tree2
, BASEDIR
"\\tname1",
1024 FILE_ATTRIBUTE_HIDDEN
);,
1025 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
1026 NOTIFY_ACTION_MODIFIED
,
1027 FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
1029 torture_comment(torture
, "Testing set path write time\n");
1031 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1032 sinfo
.generic
.in
.file
.handle
= h1
;
1033 sinfo
.basic_info
.in
.write_time
= 1000;
1034 NOTIFY_MASK_TEST("Testing set path write time",
1035 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1036 torture
, &(io1
.smb2
)));,
1037 smb2_setinfo_file(tree2
, &sinfo
);,
1038 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
1039 NOTIFY_ACTION_MODIFIED
,
1040 FILE_NOTIFY_CHANGE_LAST_WRITE
, 1);
1042 if (torture_setting_bool(torture
, "samba3", false)) {
1043 torture_comment(torture
,
1044 "Samba3 does not yet support create times "
1049 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1050 sinfo
.generic
.in
.file
.handle
= h1
;
1051 sinfo
.basic_info
.in
.create_time
= 0;
1052 torture_comment(torture
, "Testing set file create time\n");
1053 NOTIFY_MASK_TEST("Testing set file create time",
1054 smb2_create_complex_file(tree2
,
1055 BASEDIR
"\\tname1", &h2
);,
1056 smb2_setinfo_file(tree2
, &sinfo
);,
1057 (smb2_util_close(tree2
, h2
),
1058 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1059 NOTIFY_ACTION_MODIFIED
,
1060 FILE_NOTIFY_CHANGE_CREATION
, 1);
1064 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1065 sinfo
.generic
.in
.file
.handle
= h1
;
1066 sinfo
.basic_info
.in
.access_time
= 0;
1067 torture_comment(torture
, "Testing set file access time\n");
1068 NOTIFY_MASK_TEST("Testing set file access time",
1069 smb2_create_complex_file(tree2
, BASEDIR
"\\tname1", &h2
);,
1070 smb2_setinfo_file(tree2
, &sinfo
);,
1071 (smb2_util_close(tree2
, h2
),
1072 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1073 NOTIFY_ACTION_MODIFIED
,
1074 FILE_NOTIFY_CHANGE_LAST_ACCESS
, 1);
1077 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1078 sinfo
.generic
.in
.file
.handle
= h1
;
1079 sinfo
.basic_info
.in
.change_time
= 0;
1080 torture_comment(torture
, "Testing set file change time\n");
1081 NOTIFY_MASK_TEST("Testing set file change time",
1082 smb2_create_complex_file(tree2
, BASEDIR
"\\tname1", &h2
);,
1083 smb2_setinfo_file(tree2
, &sinfo
);,
1084 (smb2_util_close(tree2
, h2
),
1085 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1086 NOTIFY_ACTION_MODIFIED
,
1090 torture_comment(torture
, "Testing write\n");
1091 NOTIFY_MASK_TEST("Testing write",
1092 smb2_create_complex_file(tree2
, BASEDIR
"\\tname1", &h2
);,
1093 smb2_util_write(tree2
, h2
, &c
, 10000, 1);,
1094 (smb2_util_close(tree2
, h2
),
1095 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1096 NOTIFY_ACTION_MODIFIED
,
1100 smb2_deltree(tree1
, BASEDIR
);
1105 basic testing of change notify on files
1107 static bool torture_smb2_notify_file(struct torture_context
*torture
,
1108 struct smb2_tree
*tree
)
1114 union smb_notify notify
;
1115 struct smb2_request
*req
;
1116 struct smb2_handle h1
;
1117 const char *fname
= BASEDIR
"\\file.txt";
1119 smb2_deltree(tree
, BASEDIR
);
1120 smb2_util_rmdir(tree
, BASEDIR
);
1122 torture_comment(torture
, "TESTING CHANGE NOTIFY ON FILES\n");
1123 status
= torture_smb2_testdir(tree
, BASEDIR
, &h1
);
1124 CHECK_STATUS(status
, NT_STATUS_OK
);
1126 ZERO_STRUCT(io
.smb2
);
1127 io
.generic
.level
= RAW_OPEN_SMB2
;
1128 io
.smb2
.in
.create_flags
= 0;
1129 io
.smb2
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
1130 io
.smb2
.in
.create_options
= 0;
1131 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1132 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1133 NTCREATEX_SHARE_ACCESS_WRITE
;
1134 io
.smb2
.in
.alloc_size
= 0;
1135 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1136 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1137 io
.smb2
.in
.security_flags
= 0;
1138 io
.smb2
.in
.fname
= fname
;
1139 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1140 CHECK_STATUS(status
, NT_STATUS_OK
);
1141 h1
= io
.smb2
.out
.file
.handle
;
1143 /* ask for a change notify,
1144 on file or directory name changes */
1145 ZERO_STRUCT(notify
.smb2
);
1146 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1147 notify
.smb2
.in
.file
.handle
= h1
;
1148 notify
.smb2
.in
.buffer_size
= 1000;
1149 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_STREAM_NAME
;
1150 notify
.smb2
.in
.recursive
= false;
1152 torture_comment(torture
,
1153 "Testing if notifies on file handles are invalid (should be)\n");
1155 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1156 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1157 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1159 ZERO_STRUCT(cl
.smb2
);
1160 cl
.close
.level
= RAW_CLOSE_SMB2
;
1161 cl
.close
.in
.file
.handle
= h1
;
1162 status
= smb2_close(tree
, &(cl
.smb2
));
1163 CHECK_STATUS(status
, NT_STATUS_OK
);
1165 status
= smb2_util_unlink(tree
, fname
);
1166 CHECK_STATUS(status
, NT_STATUS_OK
);
1169 smb2_deltree(tree
, BASEDIR
);
1173 basic testing of change notifies followed by a tdis
1176 static bool torture_smb2_notify_tree_disconnect(
1177 struct torture_context
*torture
,
1178 struct smb2_tree
*tree
)
1182 union smb_notify notify
;
1184 struct smb2_handle h1
;
1185 struct smb2_request
*req
;
1187 smb2_deltree(tree
, BASEDIR
);
1188 smb2_util_rmdir(tree
, BASEDIR
);
1190 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY "
1191 "TREE-DISCONNECT\n");
1194 get a handle on the directory
1196 ZERO_STRUCT(io
.smb2
);
1197 io
.generic
.level
= RAW_OPEN_SMB2
;
1198 io
.smb2
.in
.create_flags
= 0;
1199 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1200 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1201 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1202 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1203 NTCREATEX_SHARE_ACCESS_WRITE
;
1204 io
.smb2
.in
.alloc_size
= 0;
1205 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1206 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1207 io
.smb2
.in
.security_flags
= 0;
1208 io
.smb2
.in
.fname
= BASEDIR
;
1210 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1211 CHECK_STATUS(status
, NT_STATUS_OK
);
1212 h1
= io
.smb2
.out
.file
.handle
;
1214 /* ask for a change notify,
1215 on file or directory name changes */
1216 ZERO_STRUCT(notify
.smb2
);
1217 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1218 notify
.smb2
.in
.buffer_size
= 1000;
1219 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1220 notify
.smb2
.in
.file
.handle
= h1
;
1221 notify
.smb2
.in
.recursive
= true;
1223 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1225 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1227 status
= smb2_tdis(tree
);
1228 CHECK_STATUS(status
, NT_STATUS_OK
);
1230 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1232 smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1233 CHECK_STATUS(status
, NT_STATUS_OK
);
1234 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1237 smb2_deltree(tree
, BASEDIR
);
1242 basic testing of change notifies followed by a ulogoff
1245 static bool torture_smb2_notify_ulogoff(struct torture_context
*torture
,
1246 struct smb2_tree
*tree1
,
1247 struct smb2_tree
*tree2
)
1251 union smb_notify notify
;
1253 struct smb2_handle h1
;
1254 struct smb2_request
*req
;
1256 smb2_deltree(tree1
, BASEDIR
);
1257 smb2_util_rmdir(tree1
, BASEDIR
);
1259 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1262 get a handle on the directory
1264 ZERO_STRUCT(io
.smb2
);
1265 io
.generic
.level
= RAW_OPEN_SMB2
;
1266 io
.smb2
.in
.create_flags
= 0;
1267 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1268 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1269 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1270 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1271 NTCREATEX_SHARE_ACCESS_WRITE
;
1272 io
.smb2
.in
.alloc_size
= 0;
1273 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1274 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1275 io
.smb2
.in
.security_flags
= 0;
1276 io
.smb2
.in
.fname
= BASEDIR
;
1278 status
= smb2_create(tree2
, torture
, &(io
.smb2
));
1279 CHECK_STATUS(status
, NT_STATUS_OK
);
1281 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1282 status
= smb2_create(tree2
, torture
, &(io
.smb2
));
1283 CHECK_STATUS(status
, NT_STATUS_OK
);
1284 h1
= io
.smb2
.out
.file
.handle
;
1286 /* ask for a change notify,
1287 on file or directory name changes */
1288 ZERO_STRUCT(notify
.smb2
);
1289 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1290 notify
.smb2
.in
.buffer_size
= 1000;
1291 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1292 notify
.smb2
.in
.file
.handle
= h1
;
1293 notify
.smb2
.in
.recursive
= true;
1295 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1297 status
= smb2_logoff(tree2
->session
);
1298 CHECK_STATUS(status
, NT_STATUS_OK
);
1300 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1301 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1304 smb2_deltree(tree1
, BASEDIR
);
1308 static void tcp_dis_handler(struct smb2_transport
*t
, void *p
)
1310 struct smb2_tree
*tree
= (struct smb2_tree
*)p
;
1311 smb2_transport_dead(tree
->session
->transport
,
1312 NT_STATUS_LOCAL_DISCONNECT
);
1318 basic testing of change notifies followed by tcp disconnect
1321 static bool torture_smb2_notify_tcp_disconnect(
1322 struct torture_context
*torture
,
1323 struct smb2_tree
*tree
)
1327 union smb_notify notify
;
1329 struct smb2_handle h1
;
1330 struct smb2_request
*req
;
1332 smb2_deltree(tree
, BASEDIR
);
1333 smb2_util_rmdir(tree
, BASEDIR
);
1335 torture_comment(torture
,
1336 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1339 get a handle on the directory
1341 ZERO_STRUCT(io
.smb2
);
1342 io
.generic
.level
= RAW_OPEN_SMB2
;
1343 io
.smb2
.in
.create_flags
= 0;
1344 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1345 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1346 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1347 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1348 NTCREATEX_SHARE_ACCESS_WRITE
;
1349 io
.smb2
.in
.alloc_size
= 0;
1350 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1351 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1352 io
.smb2
.in
.security_flags
= 0;
1353 io
.smb2
.in
.fname
= BASEDIR
;
1355 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1356 CHECK_STATUS(status
, NT_STATUS_OK
);
1357 h1
= io
.smb2
.out
.file
.handle
;
1359 /* ask for a change notify,
1360 on file or directory name changes */
1361 ZERO_STRUCT(notify
.smb2
);
1362 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1363 notify
.smb2
.in
.buffer_size
= 1000;
1364 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1365 notify
.smb2
.in
.file
.handle
= h1
;
1366 notify
.smb2
.in
.recursive
= true;
1368 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1370 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1371 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1373 notify
.smb2
.in
.recursive
= true;
1374 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1375 smb2_transport_idle_handler(tree
->session
->transport
,
1376 tcp_dis_handler
, 250, tree
);
1378 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1379 CHECK_STATUS(status
, NT_STATUS_LOCAL_DISCONNECT
);
1386 test setting up two change notify requests on one handle
1389 static bool torture_smb2_notify_double(struct torture_context
*torture
,
1390 struct smb2_tree
*tree1
,
1391 struct smb2_tree
*tree2
)
1395 union smb_notify notify
;
1397 struct smb2_handle h1
;
1398 struct smb2_request
*req1
, *req2
;
1400 smb2_deltree(tree1
, BASEDIR
);
1401 smb2_util_rmdir(tree1
, BASEDIR
);
1403 torture_comment(torture
,
1404 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1407 get a handle on the directory
1409 ZERO_STRUCT(io
.smb2
);
1410 io
.generic
.level
= RAW_OPEN_SMB2
;
1411 io
.smb2
.in
.create_flags
= 0;
1412 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
1413 SEC_RIGHTS_FILE_WRITE
|
1414 SEC_RIGHTS_FILE_ALL
;
1415 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1416 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1417 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1418 NTCREATEX_SHARE_ACCESS_WRITE
;
1419 io
.smb2
.in
.alloc_size
= 0;
1420 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1421 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1422 io
.smb2
.in
.security_flags
= 0;
1423 io
.smb2
.in
.fname
= BASEDIR
;
1425 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1426 CHECK_STATUS(status
, NT_STATUS_OK
);
1427 h1
= io
.smb2
.out
.file
.handle
;
1429 /* ask for a change notify,
1430 on file or directory name changes */
1431 ZERO_STRUCT(notify
.smb2
);
1432 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1433 notify
.smb2
.in
.buffer_size
= 1000;
1434 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1435 notify
.smb2
.in
.file
.handle
= h1
;
1436 notify
.smb2
.in
.recursive
= true;
1438 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1440 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1441 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1443 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
1445 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
1446 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1448 smb2_util_mkdir(tree2
, BASEDIR
"\\subdir-name");
1449 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1450 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
1452 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1453 CHECK_STATUS(status
, NT_STATUS_OK
);
1454 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1455 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1457 smb2_util_mkdir(tree2
, BASEDIR
"\\subdir-name2");
1459 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
1460 CHECK_STATUS(status
, NT_STATUS_OK
);
1461 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1462 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name2");
1465 smb2_deltree(tree1
, BASEDIR
);
1471 test multiple change notifies at different depths and with/without recursion
1474 static bool torture_smb2_notify_tree(struct torture_context
*torture
,
1475 struct smb2_tree
*tree
)
1478 union smb_notify notify
;
1480 struct smb2_request
*req
;
1487 struct smb2_handle h1
;
1490 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 30 },
1491 {BASEDIR
"\\zqy", true, FILE_NOTIFY_CHANGE_NAME
, 8 },
1492 {BASEDIR
"\\atsy", true, FILE_NOTIFY_CHANGE_NAME
, 4 },
1493 {BASEDIR
"\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1494 {BASEDIR
"\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME
, 13 },
1495 {BASEDIR
"\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME
, 7 },
1496 {BASEDIR
"\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1497 {BASEDIR
"\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1498 {BASEDIR
"\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1499 {BASEDIR
"\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1500 {BASEDIR
"\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1501 {BASEDIR
"\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1502 {BASEDIR
"\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME
, 40 },
1503 {BASEDIR
, true, FILE_NOTIFY_CHANGE_NAME
, 40 },
1504 {BASEDIR
, false,FILE_NOTIFY_CHANGE_NAME
, 6 },
1505 {BASEDIR
"\\atsy", false,FILE_NOTIFY_CHANGE_NAME
, 4 },
1506 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 24 },
1507 {BASEDIR
"\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1508 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1509 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 24 },
1513 bool all_done
= false;
1515 smb2_deltree(tree
, BASEDIR
);
1516 smb2_util_rmdir(tree
, BASEDIR
);
1518 torture_comment(torture
, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1520 ZERO_STRUCT(io
.smb2
);
1521 io
.generic
.level
= RAW_OPEN_SMB2
;
1522 io
.smb2
.in
.create_flags
= 0;
1523 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1524 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1525 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1526 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1527 NTCREATEX_SHARE_ACCESS_WRITE
;
1528 io
.smb2
.in
.alloc_size
= 0;
1529 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1530 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1531 io
.smb2
.in
.security_flags
= 0;
1532 io
.smb2
.in
.fname
= BASEDIR
;
1533 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1534 CHECK_STATUS(status
, NT_STATUS_OK
);
1536 ZERO_STRUCT(notify
.smb2
);
1537 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1538 notify
.smb2
.in
.buffer_size
= 20000;
1541 setup the directory tree, and the notify buffer on each directory
1543 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1544 io
.smb2
.in
.fname
= dirs
[i
].path
;
1545 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1546 CHECK_STATUS(status
, NT_STATUS_OK
);
1547 dirs
[i
].h1
= io
.smb2
.out
.file
.handle
;
1549 notify
.smb2
.in
.completion_filter
= dirs
[i
].filter
;
1550 notify
.smb2
.in
.file
.handle
= dirs
[i
].h1
;
1551 notify
.smb2
.in
.recursive
= dirs
[i
].recursive
;
1552 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1554 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1555 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1558 /* trigger 2 events in each dir */
1559 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1560 char *path
= talloc_asprintf(torture
, "%s\\test.dir",
1562 smb2_util_mkdir(tree
, path
);
1563 smb2_util_rmdir(tree
, path
);
1567 /* give a bit of time for the events to propogate */
1568 tv
= timeval_current();
1571 /* count events that have happened in each dir */
1572 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1573 notify
.smb2
.in
.file
.handle
= dirs
[i
].h1
;
1574 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1576 notify
.smb2
.out
.num_changes
= 0;
1577 status
= smb2_notify_recv(req
, torture
,
1579 dirs
[i
].counted
+= notify
.smb2
.out
.num_changes
;
1584 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1585 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1589 } while (!all_done
&& timeval_elapsed(&tv
) < 20);
1591 torture_comment(torture
, "took %.4f seconds to propogate all events\n",
1592 timeval_elapsed(&tv
));
1594 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1595 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1596 torture_comment(torture
,
1597 "ERROR: i=%d expected %d got %d for '%s'\n",
1598 i
, dirs
[i
].expected
, dirs
[i
].counted
,
1605 run from the back, closing and deleting
1607 for (i
=ARRAY_SIZE(dirs
)-1;i
>=0;i
--) {
1608 smb2_util_close(tree
, dirs
[i
].h1
);
1609 smb2_util_rmdir(tree
, dirs
[i
].path
);
1613 smb2_deltree(tree
, BASEDIR
);
1614 smb2_util_rmdir(tree
, BASEDIR
);
1619 Test response when cached server events exceed single NT NOTFIY response
1623 static bool torture_smb2_notify_overflow(struct torture_context
*torture
,
1624 struct smb2_tree
*tree
)
1628 union smb_notify notify
;
1630 struct smb2_handle h1
, h2
;
1632 struct smb2_request
*req1
;
1635 smb2_deltree(tree
, BASEDIR
);
1636 smb2_util_rmdir(tree
, BASEDIR
);
1638 torture_comment(torture
, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1640 /* get a handle on the directory */
1641 ZERO_STRUCT(io
.smb2
);
1642 io
.generic
.level
= RAW_OPEN_SMB2
;
1643 io
.smb2
.in
.create_flags
= 0;
1644 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1645 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1646 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1647 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1648 NTCREATEX_SHARE_ACCESS_WRITE
;
1649 io
.smb2
.in
.alloc_size
= 0;
1650 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1651 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1652 io
.smb2
.in
.security_flags
= 0;
1653 io
.smb2
.in
.fname
= BASEDIR
;
1655 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1656 CHECK_STATUS(status
, NT_STATUS_OK
);
1657 h1
= io
.smb2
.out
.file
.handle
;
1659 /* ask for a change notify, on name changes. */
1660 ZERO_STRUCT(notify
.smb2
);
1661 notify
.smb2
.level
= RAW_NOTIFY_NTTRANS
;
1662 notify
.smb2
.in
.buffer_size
= 1000;
1663 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1664 notify
.smb2
.in
.file
.handle
= h1
;
1666 notify
.smb2
.in
.recursive
= true;
1667 req1
= smb2_notify_send(tree
, &(notify
.smb2
));
1669 /* cancel initial requests so the buffer is setup */
1671 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1672 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1674 /* open a lot of files, filling up the server side notify buffer */
1675 torture_comment(torture
,
1676 "Testing overflowed buffer notify on create of %d files\n",
1679 for (i
=0;i
<count
;i
++) {
1680 char *fname
= talloc_asprintf(torture
,
1681 BASEDIR
"\\test%d.txt", i
);
1683 ZERO_STRUCT(io1
.smb2
);
1684 io1
.generic
.level
= RAW_OPEN_SMB2
;
1685 io1
.smb2
.in
.create_flags
= 0;
1686 io1
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1687 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1688 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1689 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1690 NTCREATEX_SHARE_ACCESS_WRITE
;
1691 io1
.smb2
.in
.alloc_size
= 0;
1692 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1693 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1694 io1
.smb2
.in
.security_flags
= 0;
1695 io1
.smb2
.in
.fname
= fname
;
1697 h2
= custom_smb2_create(tree
, torture
, &(io1
.smb2
));
1699 smb2_util_close(tree
, h2
);
1702 req1
= smb2_notify_send(tree
, &(notify
.smb2
));
1703 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1704 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
1705 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1708 smb2_deltree(tree
, BASEDIR
);
1713 Test if notifications are returned for changes to the base directory.
1717 static bool torture_smb2_notify_basedir(struct torture_context
*torture
,
1718 struct smb2_tree
*tree1
,
1719 struct smb2_tree
*tree2
)
1723 union smb_notify notify
;
1725 struct smb2_handle h1
;
1726 struct smb2_request
*req1
;
1728 smb2_deltree(tree1
, BASEDIR
);
1729 smb2_util_rmdir(tree1
, BASEDIR
);
1731 torture_comment(torture
, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1733 /* get a handle on the directory */
1734 ZERO_STRUCT(io
.smb2
);
1735 io
.generic
.level
= RAW_OPEN_SMB2
;
1736 io
.smb2
.in
.create_flags
= 0;
1737 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1738 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1739 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1740 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1741 NTCREATEX_SHARE_ACCESS_WRITE
;
1742 io
.smb2
.in
.alloc_size
= 0;
1743 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1744 io
.smb2
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1745 io
.smb2
.in
.security_flags
= 0;
1746 io
.smb2
.in
.fname
= BASEDIR
;
1748 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1749 CHECK_STATUS(status
, NT_STATUS_OK
);
1750 h1
= io
.smb2
.out
.file
.handle
;
1752 /* create a test file that will also be modified */
1753 io
.smb2
.in
.fname
= BASEDIR
"\\tname1";
1754 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
1755 status
= smb2_create(tree2
, torture
, &(io
.smb2
));
1756 CHECK_STATUS(status
,NT_STATUS_OK
);
1757 smb2_util_close(tree2
, io
.smb2
.out
.file
.handle
);
1759 /* ask for a change notify, on attribute changes. */
1760 ZERO_STRUCT(notify
.smb2
);
1761 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1762 notify
.smb2
.in
.buffer_size
= 1000;
1763 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
1764 notify
.smb2
.in
.file
.handle
= h1
;
1765 notify
.smb2
.in
.recursive
= true;
1767 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1769 /* set attribute on the base dir */
1770 smb2_util_setatr(tree2
, BASEDIR
, FILE_ATTRIBUTE_HIDDEN
);
1772 /* set attribute on a file to assure we receive a notification */
1773 smb2_util_setatr(tree2
, BASEDIR
"\\tname1", FILE_ATTRIBUTE_HIDDEN
);
1776 /* check how many responses were given, expect only 1 for the file */
1777 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1778 CHECK_STATUS(status
, NT_STATUS_OK
);
1779 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1780 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
1781 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "tname1");
1784 smb2_deltree(tree1
, BASEDIR
);
1790 create a secondary tree connect - used to test for a bug in Samba3 messaging
1793 static struct smb2_tree
*secondary_tcon(struct smb2_tree
*tree
,
1794 struct torture_context
*tctx
)
1797 const char *share
, *host
;
1798 struct smb2_tree
*tree1
;
1799 union smb_tcon tcon
;
1801 share
= torture_setting_string(tctx
, "share", NULL
);
1802 host
= torture_setting_string(tctx
, "host", NULL
);
1804 torture_comment(tctx
,
1805 "create a second tree context on the same session\n");
1806 tree1
= smb2_tree_init(tree
->session
, tctx
, false);
1807 if (tree1
== NULL
) {
1808 torture_comment(tctx
, "Out of memory\n");
1812 ZERO_STRUCT(tcon
.smb2
);
1813 tcon
.generic
.level
= RAW_TCON_SMB2
;
1814 tcon
.smb2
.in
.path
= talloc_asprintf(tctx
, "\\\\%s\\%s", host
, share
);
1815 status
= smb2_tree_connect(tree
->session
, &(tcon
.smb2
));
1816 if (!NT_STATUS_IS_OK(status
)) {
1818 torture_comment(tctx
,"Failed to create secondary tree\n");
1822 tree1
->tid
= tcon
.smb2
.out
.tid
;
1823 torture_comment(tctx
,"tid1=%d tid2=%d\n", tree
->tid
, tree1
->tid
);
1830 very simple change notify test
1832 static bool torture_smb2_notify_tcon(struct torture_context
*torture
,
1833 struct smb2_tree
*tree
)
1837 union smb_notify notify
;
1839 struct smb2_handle h1
;
1840 struct smb2_request
*req
= NULL
;
1841 struct smb2_tree
*tree1
= NULL
;
1842 const char *fname
= BASEDIR
"\\subdir-name";
1844 smb2_deltree(tree
, BASEDIR
);
1845 smb2_util_rmdir(tree
, BASEDIR
);
1847 torture_comment(torture
, "TESTING SIMPLE CHANGE NOTIFY\n");
1850 get a handle on the directory
1853 ZERO_STRUCT(io
.smb2
);
1854 io
.generic
.level
= RAW_OPEN_SMB2
;
1855 io
.smb2
.in
.create_flags
= 0;
1856 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1857 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1858 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
|
1859 FILE_ATTRIBUTE_DIRECTORY
;
1860 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1861 NTCREATEX_SHARE_ACCESS_WRITE
;
1862 io
.smb2
.in
.alloc_size
= 0;
1863 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1864 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1865 io
.smb2
.in
.security_flags
= 0;
1866 io
.smb2
.in
.fname
= BASEDIR
;
1868 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1869 CHECK_STATUS(status
, NT_STATUS_OK
);
1870 h1
= io
.smb2
.out
.file
.handle
;
1872 /* ask for a change notify,
1873 on file or directory name changes */
1874 ZERO_STRUCT(notify
.smb2
);
1875 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1876 notify
.smb2
.in
.buffer_size
= 1000;
1877 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1878 notify
.smb2
.in
.file
.handle
= h1
;
1879 notify
.smb2
.in
.recursive
= true;
1881 torture_comment(torture
, "Testing notify mkdir\n");
1882 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1884 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1885 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1887 notify
.smb2
.in
.recursive
= true;
1888 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1889 status
= smb2_util_mkdir(tree
, fname
);
1890 CHECK_STATUS(status
, NT_STATUS_OK
);
1892 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1893 CHECK_STATUS(status
, NT_STATUS_OK
);
1895 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1896 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
1897 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1899 torture_comment(torture
, "Testing notify rmdir\n");
1900 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1901 status
= smb2_util_rmdir(tree
, fname
);
1902 CHECK_STATUS(status
, NT_STATUS_OK
);
1904 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1905 CHECK_STATUS(status
, NT_STATUS_OK
);
1906 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1907 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
1908 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1910 torture_comment(torture
, "SIMPLE CHANGE NOTIFY OK\n");
1912 torture_comment(torture
, "TESTING WITH SECONDARY TCON\n");
1913 tree1
= secondary_tcon(tree
, torture
);
1915 torture_comment(torture
, "Testing notify mkdir\n");
1916 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1917 smb2_util_mkdir(tree1
, fname
);
1919 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1920 CHECK_STATUS(status
, NT_STATUS_OK
);
1922 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1923 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
1924 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1926 torture_comment(torture
, "Testing notify rmdir\n");
1927 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1928 smb2_util_rmdir(tree
, fname
);
1930 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1931 CHECK_STATUS(status
, NT_STATUS_OK
);
1932 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1933 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
1934 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1936 torture_comment(torture
, "CHANGE NOTIFY WITH TCON OK\n");
1938 torture_comment(torture
, "Disconnecting secondary tree\n");
1939 status
= smb2_tdis(tree1
);
1940 CHECK_STATUS(status
, NT_STATUS_OK
);
1943 torture_comment(torture
, "Testing notify mkdir\n");
1944 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1945 smb2_util_mkdir(tree
, fname
);
1947 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1948 CHECK_STATUS(status
, NT_STATUS_OK
);
1950 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1951 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
1952 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1954 torture_comment(torture
, "Testing notify rmdir\n");
1955 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1956 smb2_util_rmdir(tree
, fname
);
1958 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1959 CHECK_STATUS(status
, NT_STATUS_OK
);
1960 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1961 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
1962 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1964 torture_comment(torture
, "CHANGE NOTIFY WITH TDIS OK\n");
1966 smb2_util_close(tree
, h1
);
1967 smb2_deltree(tree
, BASEDIR
);
1973 basic testing of SMB2 change notify
1975 struct torture_suite
*torture_smb2_notify_init(void)
1977 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "notify");
1979 torture_suite_add_1smb2_test(suite
, "valid-req", test_valid_request
);
1980 torture_suite_add_1smb2_test(suite
, "tcon", torture_smb2_notify_tcon
);
1981 torture_suite_add_2smb2_test(suite
, "dir", torture_smb2_notify_dir
);
1982 torture_suite_add_2smb2_test(suite
, "mask", torture_smb2_notify_mask
);
1983 torture_suite_add_1smb2_test(suite
, "tdis", torture_smb2_notify_tree_disconnect
);
1984 torture_suite_add_2smb2_test(suite
, "mask-change", torture_smb2_notify_mask_change
);
1985 torture_suite_add_2smb2_test(suite
, "logoff", torture_smb2_notify_ulogoff
);
1986 torture_suite_add_1smb2_test(suite
, "tree", torture_smb2_notify_tree
);
1987 torture_suite_add_2smb2_test(suite
, "basedir", torture_smb2_notify_basedir
);
1988 torture_suite_add_2smb2_test(suite
, "double", torture_smb2_notify_double
);
1989 torture_suite_add_1smb2_test(suite
, "file", torture_smb2_notify_file
);
1990 torture_suite_add_1smb2_test(suite
, "tcp", torture_smb2_notify_tcp_disconnect
);
1991 torture_suite_add_2smb2_test(suite
, "rec", torture_smb2_notify_recursive
);
1992 torture_suite_add_1smb2_test(suite
, "overflow", torture_smb2_notify_overflow
);
1994 suite
->description
= talloc_strdup(suite
, "SMB2-NOTIFY tests");