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 (event_loop_once(req
->transport
->socket
->event
.ctx
) != 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 (event_loop_once(req
->transport
->socket
->event
.ctx
) != 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 (event_loop_once(req
->transport
->socket
->event
.ctx
) != 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 (event_loop_once(req
->transport
->socket
->event
.ctx
) != 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 (event_loop_once(req
->transport
->socket
->event
.ctx
) != 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
;
850 union smb_setfileinfo sinfo
;
852 smb2_deltree(tree1
, BASEDIR
);
853 smb2_util_rmdir(tree1
, BASEDIR
);
855 torture_comment(torture
, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
857 tv
= timeval_current_ofs(1000, 0);
858 t
= timeval_to_nttime(&tv
);
861 get a handle on the directory
863 ZERO_STRUCT(io
.smb2
);
864 io
.generic
.level
= RAW_OPEN_SMB2
;
865 io
.smb2
.in
.create_flags
= 0;
866 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
867 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
868 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
869 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
870 NTCREATEX_SHARE_ACCESS_WRITE
;
871 io
.smb2
.in
.alloc_size
= 0;
872 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
873 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
874 io
.smb2
.in
.security_flags
= 0;
875 io
.smb2
.in
.fname
= BASEDIR
;
877 ZERO_STRUCT(notify
.smb2
);
878 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
879 notify
.smb2
.in
.buffer_size
= 1000;
880 notify
.smb2
.in
.recursive
= true;
882 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
883 expected, nchanges) \
885 do { for (mask=i=0;i<32;i++) { \
886 struct smb2_request *req; \
887 status = smb2_create(tree1, torture, &(io.smb2)); \
888 CHECK_STATUS(status, NT_STATUS_OK); \
889 h1 = io.smb2.out.file.handle; \
891 notify.smb2.in.file.handle = h1; \
892 notify.smb2.in.completion_filter = (1<<i); \
893 /* cancel initial requests so the buffer is setup */ \
894 req = smb2_notify_send(tree1, &(notify.smb2)); \
896 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
897 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
898 /* send the change notify request */ \
899 req = smb2_notify_send(tree1, &(notify.smb2)); \
901 smb_msleep(200); smb2_cancel(req); \
902 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
904 smb2_util_close(tree1, h1); \
905 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
906 CHECK_STATUS(status, NT_STATUS_OK); \
907 /* special case to cope with file rename behaviour */ \
908 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
909 notify.smb2.out.changes[0].action == \
910 NOTIFY_ACTION_MODIFIED && \
911 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
912 Action == NOTIFY_ACTION_OLD_NAME) { \
913 torture_comment(torture, \
914 "(rename file special handling OK)\n"); \
915 } else if (nchanges != notify.smb2.out.num_changes) { \
916 torture_result(torture, TORTURE_FAIL, \
917 "ERROR: nchanges=%d expected=%d "\
918 "action=%d filter=0x%08x\n", \
919 notify.smb2.out.num_changes, \
921 notify.smb2.out.changes[0].action, \
922 notify.smb2.in.completion_filter); \
924 } else if (notify.smb2.out.changes[0].action != Action) { \
925 torture_result(torture, TORTURE_FAIL, \
926 "ERROR: nchanges=%d action=%d " \
927 "expectedAction=%d filter=0x%08x\n", \
928 notify.smb2.out.num_changes, \
929 notify.smb2.out.changes[0].action, \
931 notify.smb2.in.completion_filter); \
933 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
935 torture_result(torture, TORTURE_FAIL, \
936 "ERROR: nchanges=%d action=%d " \
937 "filter=0x%08x name=%s\n", \
938 notify.smb2.out.num_changes, \
939 notify.smb2.out.changes[0].action, \
940 notify.smb2.in.completion_filter, \
941 notify.smb2.out.changes[0].name.s); \
949 torture_comment(torture
, "Testing mkdir\n");
950 NOTIFY_MASK_TEST("Testing mkdir",;,
951 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
952 smb2_util_rmdir(tree2
, BASEDIR
"\\tname1");,
954 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
956 torture_comment(torture
, "Testing create file\n");
957 ZERO_STRUCT(io1
.smb2
);
958 io1
.generic
.level
= RAW_OPEN_SMB2
;
959 io1
.smb2
.in
.create_flags
= 0;
960 io1
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
961 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
962 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
963 NTCREATEX_SHARE_ACCESS_WRITE
;
964 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
965 io1
.smb2
.in
.security_flags
= 0;
966 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
967 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
968 io1
.smb2
.in
.fname
= BASEDIR
"\\tname1";
970 NOTIFY_MASK_TEST("Testing create file",;,
971 smb2_util_close(tree2
, custom_smb2_create(tree2
,
972 torture
, &(io1
.smb2
)));,
973 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
975 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
977 torture_comment(torture
, "Testing unlink\n");
978 NOTIFY_MASK_TEST("Testing unlink",
979 smb2_util_close(tree2
, custom_smb2_create(tree2
,
980 torture
, &(io1
.smb2
)));,
981 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
983 NOTIFY_ACTION_REMOVED
,
984 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
986 torture_comment(torture
, "Testing rmdir\n");
987 NOTIFY_MASK_TEST("Testing rmdir",
988 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
989 smb2_util_rmdir(tree2
, BASEDIR
"\\tname1");,
991 NOTIFY_ACTION_REMOVED
,
992 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
994 torture_comment(torture
, "Testing rename file\n");
996 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
997 sinfo
.rename_information
.in
.file
.handle
= h1
;
998 sinfo
.rename_information
.in
.overwrite
= true;
999 sinfo
.rename_information
.in
.root_fid
= 0;
1000 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\tname2";
1001 NOTIFY_MASK_TEST("Testing rename file",
1002 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1003 torture
, &(io1
.smb2
)));,
1004 smb2_setinfo_file(tree2
, &sinfo
);,
1005 smb2_util_unlink(tree2
, BASEDIR
"\\tname2");,
1006 NOTIFY_ACTION_OLD_NAME
,
1007 FILE_NOTIFY_CHANGE_FILE_NAME
, 2);
1009 torture_comment(torture
, "Testing rename dir\n");
1011 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1012 sinfo
.rename_information
.in
.file
.handle
= h1
;
1013 sinfo
.rename_information
.in
.overwrite
= true;
1014 sinfo
.rename_information
.in
.root_fid
= 0;
1015 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\tname2";
1016 NOTIFY_MASK_TEST("Testing rename dir",
1017 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
1018 smb2_setinfo_file(tree2
, &sinfo
);,
1019 smb2_util_rmdir(tree2
, BASEDIR
"\\tname2");,
1020 NOTIFY_ACTION_OLD_NAME
,
1021 FILE_NOTIFY_CHANGE_DIR_NAME
, 2);
1023 torture_comment(torture
, "Testing set path attribute\n");
1024 NOTIFY_MASK_TEST("Testing set path attribute",
1025 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1026 torture
, &(io
.smb2
)));,
1027 smb2_util_setatr(tree2
, BASEDIR
"\\tname1",
1028 FILE_ATTRIBUTE_HIDDEN
);,
1029 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
1030 NOTIFY_ACTION_MODIFIED
,
1031 FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
1033 torture_comment(torture
, "Testing set path write time\n");
1035 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1036 sinfo
.generic
.in
.file
.handle
= h1
;
1037 sinfo
.basic_info
.in
.write_time
= 1000;
1038 NOTIFY_MASK_TEST("Testing set path write time",
1039 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1040 torture
, &(io1
.smb2
)));,
1041 smb2_setinfo_file(tree2
, &sinfo
);,
1042 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
1043 NOTIFY_ACTION_MODIFIED
,
1044 FILE_NOTIFY_CHANGE_LAST_WRITE
, 1);
1046 if (torture_setting_bool(torture
, "samba3", false)) {
1047 torture_comment(torture
,
1048 "Samba3 does not yet support create times "
1053 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1054 sinfo
.generic
.in
.file
.handle
= h1
;
1055 sinfo
.basic_info
.in
.create_time
= 0;
1056 torture_comment(torture
, "Testing set file create time\n");
1057 NOTIFY_MASK_TEST("Testing set file create time",
1058 smb2_create_complex_file(tree2
,
1059 BASEDIR
"\\tname1", &h2
);,
1060 smb2_setinfo_file(tree2
, &sinfo
);,
1061 (smb2_util_close(tree2
, h2
),
1062 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1063 NOTIFY_ACTION_MODIFIED
,
1064 FILE_NOTIFY_CHANGE_CREATION
, 1);
1068 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1069 sinfo
.generic
.in
.file
.handle
= h1
;
1070 sinfo
.basic_info
.in
.access_time
= 0;
1071 torture_comment(torture
, "Testing set file access time\n");
1072 NOTIFY_MASK_TEST("Testing set file access time",
1073 smb2_create_complex_file(tree2
, BASEDIR
"\\tname1", &h2
);,
1074 smb2_setinfo_file(tree2
, &sinfo
);,
1075 (smb2_util_close(tree2
, h2
),
1076 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1077 NOTIFY_ACTION_MODIFIED
,
1078 FILE_NOTIFY_CHANGE_LAST_ACCESS
, 1);
1081 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1082 sinfo
.generic
.in
.file
.handle
= h1
;
1083 sinfo
.basic_info
.in
.change_time
= 0;
1084 torture_comment(torture
, "Testing set file change time\n");
1085 NOTIFY_MASK_TEST("Testing set file change time",
1086 smb2_create_complex_file(tree2
, BASEDIR
"\\tname1", &h2
);,
1087 smb2_setinfo_file(tree2
, &sinfo
);,
1088 (smb2_util_close(tree2
, h2
),
1089 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1090 NOTIFY_ACTION_MODIFIED
,
1094 torture_comment(torture
, "Testing write\n");
1095 NOTIFY_MASK_TEST("Testing write",
1096 smb2_create_complex_file(tree2
, BASEDIR
"\\tname1", &h2
);,
1097 smb2_util_write(tree2
, h2
, &c
, 10000, 1);,
1098 (smb2_util_close(tree2
, h2
),
1099 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1100 NOTIFY_ACTION_MODIFIED
,
1104 smb2_deltree(tree1
, BASEDIR
);
1109 basic testing of change notify on files
1111 static bool torture_smb2_notify_file(struct torture_context
*torture
,
1112 struct smb2_tree
*tree
)
1118 union smb_notify notify
;
1119 struct smb2_request
*req
;
1120 struct smb2_handle h1
;
1121 const char *fname
= BASEDIR
"\\file.txt";
1123 smb2_deltree(tree
, BASEDIR
);
1124 smb2_util_rmdir(tree
, BASEDIR
);
1126 torture_comment(torture
, "TESTING CHANGE NOTIFY ON FILES\n");
1127 status
= torture_smb2_testdir(tree
, BASEDIR
, &h1
);
1128 CHECK_STATUS(status
, NT_STATUS_OK
);
1130 ZERO_STRUCT(io
.smb2
);
1131 io
.generic
.level
= RAW_OPEN_SMB2
;
1132 io
.smb2
.in
.create_flags
= 0;
1133 io
.smb2
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
1134 io
.smb2
.in
.create_options
= 0;
1135 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1136 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1137 NTCREATEX_SHARE_ACCESS_WRITE
;
1138 io
.smb2
.in
.alloc_size
= 0;
1139 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1140 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1141 io
.smb2
.in
.security_flags
= 0;
1142 io
.smb2
.in
.fname
= fname
;
1143 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1144 CHECK_STATUS(status
, NT_STATUS_OK
);
1145 h1
= io
.smb2
.out
.file
.handle
;
1147 /* ask for a change notify,
1148 on file or directory name changes */
1149 ZERO_STRUCT(notify
.smb2
);
1150 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1151 notify
.smb2
.in
.file
.handle
= h1
;
1152 notify
.smb2
.in
.buffer_size
= 1000;
1153 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_STREAM_NAME
;
1154 notify
.smb2
.in
.recursive
= false;
1156 torture_comment(torture
,
1157 "Testing if notifies on file handles are invalid (should be)\n");
1159 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1160 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1161 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1163 ZERO_STRUCT(cl
.smb2
);
1164 cl
.close
.level
= RAW_CLOSE_SMB2
;
1165 cl
.close
.in
.file
.handle
= h1
;
1166 status
= smb2_close(tree
, &(cl
.smb2
));
1167 CHECK_STATUS(status
, NT_STATUS_OK
);
1169 status
= smb2_util_unlink(tree
, fname
);
1170 CHECK_STATUS(status
, NT_STATUS_OK
);
1173 smb2_deltree(tree
, BASEDIR
);
1177 basic testing of change notifies followed by a tdis
1180 static bool torture_smb2_notify_tree_disconnect(
1181 struct torture_context
*torture
,
1182 struct smb2_tree
*tree
)
1186 union smb_notify notify
;
1188 struct smb2_handle h1
;
1189 struct smb2_request
*req
;
1191 smb2_deltree(tree
, BASEDIR
);
1192 smb2_util_rmdir(tree
, BASEDIR
);
1194 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY "
1195 "TREE-DISCONNECT\n");
1198 get a handle on the directory
1200 ZERO_STRUCT(io
.smb2
);
1201 io
.generic
.level
= RAW_OPEN_SMB2
;
1202 io
.smb2
.in
.create_flags
= 0;
1203 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1204 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1205 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1206 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1207 NTCREATEX_SHARE_ACCESS_WRITE
;
1208 io
.smb2
.in
.alloc_size
= 0;
1209 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1210 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1211 io
.smb2
.in
.security_flags
= 0;
1212 io
.smb2
.in
.fname
= BASEDIR
;
1214 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1215 CHECK_STATUS(status
, NT_STATUS_OK
);
1216 h1
= io
.smb2
.out
.file
.handle
;
1218 /* ask for a change notify,
1219 on file or directory name changes */
1220 ZERO_STRUCT(notify
.smb2
);
1221 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1222 notify
.smb2
.in
.buffer_size
= 1000;
1223 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1224 notify
.smb2
.in
.file
.handle
= h1
;
1225 notify
.smb2
.in
.recursive
= true;
1227 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1229 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1231 status
= smb2_tdis(tree
);
1232 CHECK_STATUS(status
, NT_STATUS_OK
);
1234 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1236 smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1237 CHECK_STATUS(status
, NT_STATUS_OK
);
1238 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1241 smb2_deltree(tree
, BASEDIR
);
1246 basic testing of change notifies followed by a ulogoff
1249 static bool torture_smb2_notify_ulogoff(struct torture_context
*torture
,
1250 struct smb2_tree
*tree1
,
1251 struct smb2_tree
*tree2
)
1255 union smb_notify notify
;
1257 struct smb2_handle h1
;
1258 struct smb2_request
*req
;
1260 smb2_deltree(tree1
, BASEDIR
);
1261 smb2_util_rmdir(tree1
, BASEDIR
);
1263 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1266 get a handle on the directory
1268 ZERO_STRUCT(io
.smb2
);
1269 io
.generic
.level
= RAW_OPEN_SMB2
;
1270 io
.smb2
.in
.create_flags
= 0;
1271 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1272 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1273 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1274 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1275 NTCREATEX_SHARE_ACCESS_WRITE
;
1276 io
.smb2
.in
.alloc_size
= 0;
1277 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1278 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1279 io
.smb2
.in
.security_flags
= 0;
1280 io
.smb2
.in
.fname
= BASEDIR
;
1282 status
= smb2_create(tree2
, torture
, &(io
.smb2
));
1283 CHECK_STATUS(status
, NT_STATUS_OK
);
1285 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1286 status
= smb2_create(tree2
, torture
, &(io
.smb2
));
1287 CHECK_STATUS(status
, NT_STATUS_OK
);
1288 h1
= io
.smb2
.out
.file
.handle
;
1290 /* ask for a change notify,
1291 on file or directory name changes */
1292 ZERO_STRUCT(notify
.smb2
);
1293 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1294 notify
.smb2
.in
.buffer_size
= 1000;
1295 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1296 notify
.smb2
.in
.file
.handle
= h1
;
1297 notify
.smb2
.in
.recursive
= true;
1299 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
1301 status
= smb2_logoff(tree2
->session
);
1302 CHECK_STATUS(status
, NT_STATUS_OK
);
1304 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1305 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1308 smb2_deltree(tree1
, BASEDIR
);
1312 static void tcp_dis_handler(struct smb2_transport
*t
, void *p
)
1314 struct smb2_tree
*tree
= (struct smb2_tree
*)p
;
1315 smb2_transport_dead(tree
->session
->transport
,
1316 NT_STATUS_LOCAL_DISCONNECT
);
1322 basic testing of change notifies followed by tcp disconnect
1325 static bool torture_smb2_notify_tcp_disconnect(
1326 struct torture_context
*torture
,
1327 struct smb2_tree
*tree
)
1331 union smb_notify notify
;
1333 struct smb2_handle h1
;
1334 struct smb2_request
*req
;
1336 smb2_deltree(tree
, BASEDIR
);
1337 smb2_util_rmdir(tree
, BASEDIR
);
1339 torture_comment(torture
,
1340 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1343 get a handle on the directory
1345 ZERO_STRUCT(io
.smb2
);
1346 io
.generic
.level
= RAW_OPEN_SMB2
;
1347 io
.smb2
.in
.create_flags
= 0;
1348 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1349 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1350 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1351 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1352 NTCREATEX_SHARE_ACCESS_WRITE
;
1353 io
.smb2
.in
.alloc_size
= 0;
1354 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1355 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1356 io
.smb2
.in
.security_flags
= 0;
1357 io
.smb2
.in
.fname
= BASEDIR
;
1359 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1360 CHECK_STATUS(status
, NT_STATUS_OK
);
1361 h1
= io
.smb2
.out
.file
.handle
;
1363 /* ask for a change notify,
1364 on file or directory name changes */
1365 ZERO_STRUCT(notify
.smb2
);
1366 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1367 notify
.smb2
.in
.buffer_size
= 1000;
1368 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1369 notify
.smb2
.in
.file
.handle
= h1
;
1370 notify
.smb2
.in
.recursive
= true;
1372 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1374 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1375 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1377 notify
.smb2
.in
.recursive
= true;
1378 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1379 smb2_transport_idle_handler(tree
->session
->transport
,
1380 tcp_dis_handler
, 250, tree
);
1382 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1383 CHECK_STATUS(status
, NT_STATUS_LOCAL_DISCONNECT
);
1390 test setting up two change notify requests on one handle
1393 static bool torture_smb2_notify_double(struct torture_context
*torture
,
1394 struct smb2_tree
*tree1
,
1395 struct smb2_tree
*tree2
)
1399 union smb_notify notify
;
1401 struct smb2_handle h1
;
1402 struct smb2_request
*req1
, *req2
;
1404 smb2_deltree(tree1
, BASEDIR
);
1405 smb2_util_rmdir(tree1
, BASEDIR
);
1407 torture_comment(torture
,
1408 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1411 get a handle on the directory
1413 ZERO_STRUCT(io
.smb2
);
1414 io
.generic
.level
= RAW_OPEN_SMB2
;
1415 io
.smb2
.in
.create_flags
= 0;
1416 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
1417 SEC_RIGHTS_FILE_WRITE
|
1418 SEC_RIGHTS_FILE_ALL
;
1419 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1420 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1421 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1422 NTCREATEX_SHARE_ACCESS_WRITE
;
1423 io
.smb2
.in
.alloc_size
= 0;
1424 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1425 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1426 io
.smb2
.in
.security_flags
= 0;
1427 io
.smb2
.in
.fname
= BASEDIR
;
1429 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1430 CHECK_STATUS(status
, NT_STATUS_OK
);
1431 h1
= io
.smb2
.out
.file
.handle
;
1433 /* ask for a change notify,
1434 on file or directory name changes */
1435 ZERO_STRUCT(notify
.smb2
);
1436 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1437 notify
.smb2
.in
.buffer_size
= 1000;
1438 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1439 notify
.smb2
.in
.file
.handle
= h1
;
1440 notify
.smb2
.in
.recursive
= true;
1442 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1444 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1445 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1447 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
1449 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
1450 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1452 smb2_util_mkdir(tree2
, BASEDIR
"\\subdir-name");
1453 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1454 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
1456 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1457 CHECK_STATUS(status
, NT_STATUS_OK
);
1458 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1459 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1461 smb2_util_mkdir(tree2
, BASEDIR
"\\subdir-name2");
1463 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
1464 CHECK_STATUS(status
, NT_STATUS_OK
);
1465 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1466 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name2");
1469 smb2_deltree(tree1
, BASEDIR
);
1475 test multiple change notifies at different depths and with/without recursion
1478 static bool torture_smb2_notify_tree(struct torture_context
*torture
,
1479 struct smb2_tree
*tree
)
1482 union smb_notify notify
;
1484 struct smb2_request
*req
;
1491 struct smb2_handle h1
;
1494 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 30 },
1495 {BASEDIR
"\\zqy", true, FILE_NOTIFY_CHANGE_NAME
, 8 },
1496 {BASEDIR
"\\atsy", true, FILE_NOTIFY_CHANGE_NAME
, 4 },
1497 {BASEDIR
"\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1498 {BASEDIR
"\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME
, 13 },
1499 {BASEDIR
"\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME
, 7 },
1500 {BASEDIR
"\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1501 {BASEDIR
"\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1502 {BASEDIR
"\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1503 {BASEDIR
"\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1504 {BASEDIR
"\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1505 {BASEDIR
"\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1506 {BASEDIR
"\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME
, 40 },
1507 {BASEDIR
, true, FILE_NOTIFY_CHANGE_NAME
, 40 },
1508 {BASEDIR
, false,FILE_NOTIFY_CHANGE_NAME
, 6 },
1509 {BASEDIR
"\\atsy", false,FILE_NOTIFY_CHANGE_NAME
, 4 },
1510 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 24 },
1511 {BASEDIR
"\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1512 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1513 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 24 },
1517 bool all_done
= false;
1519 smb2_deltree(tree
, BASEDIR
);
1520 smb2_util_rmdir(tree
, BASEDIR
);
1522 torture_comment(torture
, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1524 ZERO_STRUCT(io
.smb2
);
1525 io
.generic
.level
= RAW_OPEN_SMB2
;
1526 io
.smb2
.in
.create_flags
= 0;
1527 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1528 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1529 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1530 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1531 NTCREATEX_SHARE_ACCESS_WRITE
;
1532 io
.smb2
.in
.alloc_size
= 0;
1533 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1534 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1535 io
.smb2
.in
.security_flags
= 0;
1536 io
.smb2
.in
.fname
= BASEDIR
;
1537 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1538 CHECK_STATUS(status
, NT_STATUS_OK
);
1540 ZERO_STRUCT(notify
.smb2
);
1541 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1542 notify
.smb2
.in
.buffer_size
= 20000;
1545 setup the directory tree, and the notify buffer on each directory
1547 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1548 io
.smb2
.in
.fname
= dirs
[i
].path
;
1549 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1550 CHECK_STATUS(status
, NT_STATUS_OK
);
1551 dirs
[i
].h1
= io
.smb2
.out
.file
.handle
;
1553 notify
.smb2
.in
.completion_filter
= dirs
[i
].filter
;
1554 notify
.smb2
.in
.file
.handle
= dirs
[i
].h1
;
1555 notify
.smb2
.in
.recursive
= dirs
[i
].recursive
;
1556 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1558 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1559 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1562 /* trigger 2 events in each dir */
1563 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1564 char *path
= talloc_asprintf(torture
, "%s\\test.dir",
1566 smb2_util_mkdir(tree
, path
);
1567 smb2_util_rmdir(tree
, path
);
1571 /* give a bit of time for the events to propogate */
1572 tv
= timeval_current();
1575 /* count events that have happened in each dir */
1576 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1577 notify
.smb2
.in
.file
.handle
= dirs
[i
].h1
;
1578 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1580 notify
.smb2
.out
.num_changes
= 0;
1581 status
= smb2_notify_recv(req
, torture
,
1583 dirs
[i
].counted
+= notify
.smb2
.out
.num_changes
;
1588 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1589 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1593 } while (!all_done
&& timeval_elapsed(&tv
) < 20);
1595 torture_comment(torture
, "took %.4f seconds to propogate all events\n",
1596 timeval_elapsed(&tv
));
1598 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1599 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1600 torture_comment(torture
,
1601 "ERROR: i=%d expected %d got %d for '%s'\n",
1602 i
, dirs
[i
].expected
, dirs
[i
].counted
,
1609 run from the back, closing and deleting
1611 for (i
=ARRAY_SIZE(dirs
)-1;i
>=0;i
--) {
1612 smb2_util_close(tree
, dirs
[i
].h1
);
1613 smb2_util_rmdir(tree
, dirs
[i
].path
);
1617 smb2_deltree(tree
, BASEDIR
);
1618 smb2_util_rmdir(tree
, BASEDIR
);
1623 Test response when cached server events exceed single NT NOTFIY response
1627 static bool torture_smb2_notify_overflow(struct torture_context
*torture
,
1628 struct smb2_tree
*tree
)
1632 union smb_notify notify
;
1634 struct smb2_handle h1
, h2
;
1636 struct smb2_request
*req1
;
1639 smb2_deltree(tree
, BASEDIR
);
1640 smb2_util_rmdir(tree
, BASEDIR
);
1642 torture_comment(torture
, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1644 /* get a handle on the directory */
1645 ZERO_STRUCT(io
.smb2
);
1646 io
.generic
.level
= RAW_OPEN_SMB2
;
1647 io
.smb2
.in
.create_flags
= 0;
1648 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1649 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1650 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1651 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1652 NTCREATEX_SHARE_ACCESS_WRITE
;
1653 io
.smb2
.in
.alloc_size
= 0;
1654 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1655 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1656 io
.smb2
.in
.security_flags
= 0;
1657 io
.smb2
.in
.fname
= BASEDIR
;
1659 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1660 CHECK_STATUS(status
, NT_STATUS_OK
);
1661 h1
= io
.smb2
.out
.file
.handle
;
1663 /* ask for a change notify, on name changes. */
1664 ZERO_STRUCT(notify
.smb2
);
1665 notify
.smb2
.level
= RAW_NOTIFY_NTTRANS
;
1666 notify
.smb2
.in
.buffer_size
= 1000;
1667 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1668 notify
.smb2
.in
.file
.handle
= h1
;
1670 notify
.smb2
.in
.recursive
= true;
1671 req1
= smb2_notify_send(tree
, &(notify
.smb2
));
1673 /* cancel initial requests so the buffer is setup */
1675 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1676 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1678 /* open a lot of files, filling up the server side notify buffer */
1679 torture_comment(torture
,
1680 "Testing overflowed buffer notify on create of %d files\n",
1683 for (i
=0;i
<count
;i
++) {
1684 char *fname
= talloc_asprintf(torture
,
1685 BASEDIR
"\\test%d.txt", i
);
1687 ZERO_STRUCT(io1
.smb2
);
1688 io1
.generic
.level
= RAW_OPEN_SMB2
;
1689 io1
.smb2
.in
.create_flags
= 0;
1690 io1
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1691 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1692 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1693 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1694 NTCREATEX_SHARE_ACCESS_WRITE
;
1695 io1
.smb2
.in
.alloc_size
= 0;
1696 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1697 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1698 io1
.smb2
.in
.security_flags
= 0;
1699 io1
.smb2
.in
.fname
= fname
;
1701 h2
= custom_smb2_create(tree
, torture
, &(io1
.smb2
));
1703 smb2_util_close(tree
, h2
);
1706 req1
= smb2_notify_send(tree
, &(notify
.smb2
));
1707 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1708 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
1709 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1712 smb2_deltree(tree
, BASEDIR
);
1717 Test if notifications are returned for changes to the base directory.
1721 static bool torture_smb2_notify_basedir(struct torture_context
*torture
,
1722 struct smb2_tree
*tree1
,
1723 struct smb2_tree
*tree2
)
1727 union smb_notify notify
;
1729 struct smb2_handle h1
;
1730 struct smb2_request
*req1
;
1732 smb2_deltree(tree1
, BASEDIR
);
1733 smb2_util_rmdir(tree1
, BASEDIR
);
1735 torture_comment(torture
, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1737 /* get a handle on the directory */
1738 ZERO_STRUCT(io
.smb2
);
1739 io
.generic
.level
= RAW_OPEN_SMB2
;
1740 io
.smb2
.in
.create_flags
= 0;
1741 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1742 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1743 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1744 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1745 NTCREATEX_SHARE_ACCESS_WRITE
;
1746 io
.smb2
.in
.alloc_size
= 0;
1747 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1748 io
.smb2
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1749 io
.smb2
.in
.security_flags
= 0;
1750 io
.smb2
.in
.fname
= BASEDIR
;
1752 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1753 CHECK_STATUS(status
, NT_STATUS_OK
);
1754 h1
= io
.smb2
.out
.file
.handle
;
1756 /* create a test file that will also be modified */
1757 io
.smb2
.in
.fname
= BASEDIR
"\\tname1";
1758 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
1759 status
= smb2_create(tree2
, torture
, &(io
.smb2
));
1760 CHECK_STATUS(status
,NT_STATUS_OK
);
1761 smb2_util_close(tree2
, io
.smb2
.out
.file
.handle
);
1763 /* ask for a change notify, on attribute changes. */
1764 ZERO_STRUCT(notify
.smb2
);
1765 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1766 notify
.smb2
.in
.buffer_size
= 1000;
1767 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
1768 notify
.smb2
.in
.file
.handle
= h1
;
1769 notify
.smb2
.in
.recursive
= true;
1771 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1773 /* set attribute on the base dir */
1774 smb2_util_setatr(tree2
, BASEDIR
, FILE_ATTRIBUTE_HIDDEN
);
1776 /* set attribute on a file to assure we receive a notification */
1777 smb2_util_setatr(tree2
, BASEDIR
"\\tname1", FILE_ATTRIBUTE_HIDDEN
);
1780 /* check how many responses were given, expect only 1 for the file */
1781 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1782 CHECK_STATUS(status
, NT_STATUS_OK
);
1783 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1784 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
1785 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "tname1");
1788 smb2_deltree(tree1
, BASEDIR
);
1794 create a secondary tree connect - used to test for a bug in Samba3 messaging
1797 static struct smb2_tree
*secondary_tcon(struct smb2_tree
*tree
,
1798 struct torture_context
*tctx
)
1801 const char *share
, *host
;
1802 struct smb2_tree
*tree1
;
1803 union smb_tcon tcon
;
1805 share
= torture_setting_string(tctx
, "share", NULL
);
1806 host
= torture_setting_string(tctx
, "host", NULL
);
1808 torture_comment(tctx
,
1809 "create a second tree context on the same session\n");
1810 tree1
= smb2_tree_init(tree
->session
, tctx
, false);
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
, &(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");