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"
26 #include "../libcli/smb/smbXcli_base.h"
28 #include "torture/torture.h"
29 #include "torture/smb2/proto.h"
30 #include "librpc/gen_ndr/ndr_security.h"
31 #include "libcli/security/security.h"
32 #include "torture/util.h"
34 #include "system/filesys.h"
35 #include "auth/credentials/credentials.h"
36 #include "lib/cmdline/popt_common.h"
37 #include "librpc/gen_ndr/security.h"
39 #include "lib/events/events.h"
41 #include "libcli/raw/libcliraw.h"
42 #include "libcli/raw/raw_proto.h"
43 #include "libcli/libcli.h"
45 #define CHECK_STATUS(status, correct) do { \
46 if (!NT_STATUS_EQUAL(status, correct)) { \
47 torture_result(torture, TORTURE_FAIL, \
48 "(%s) Incorrect status %s - should be %s\n", \
49 __location__, nt_errstr(status), nt_errstr(correct)); \
54 #define CHECK_VAL(v, correct) do { \
55 if ((v) != (correct)) { \
56 torture_result(torture, TORTURE_FAIL, \
57 "(%s) wrong value for %s 0x%x should be 0x%x\n", \
58 __location__, #v, (int)v, (int)correct); \
63 #define CHECK_WIRE_STR(field, value) do { \
64 if (!field.s || strcmp(field.s, value)) { \
65 torture_result(torture, TORTURE_FAIL, \
66 "(%s) %s [%s] != %s\n", __location__, #field, \
72 #define WAIT_FOR_ASYNC_RESPONSE(req) \
73 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \
74 if (tevent_loop_once(torture->ev) != 0) { \
79 #define BASEDIR "test_notify"
80 #define FNAME "smb2-notify01.dat"
82 static bool test_valid_request(struct torture_context
*torture
,
83 struct smb2_tree
*tree
)
87 struct smb2_handle dh
;
89 struct smb2_request
*req
;
90 uint32_t max_buffer_size
;
92 torture_comment(torture
, "TESTING VALIDITY OF CHANGE NOTIFY REQUEST\n");
94 smb2_util_unlink(tree
, FNAME
);
96 status
= smb2_util_roothandle(tree
, &dh
);
97 CHECK_STATUS(status
, NT_STATUS_OK
);
99 /* 0x00080000 is the default max buffer size for Windows servers
101 max_buffer_size
= torture_setting_ulong(torture
, "cn_max_buffer_size",
104 n
.in
.recursive
= 0x0000;
105 n
.in
.buffer_size
= max_buffer_size
;
106 n
.in
.file
.handle
= dh
;
107 n
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ALL
;
108 n
.in
.unknown
= 0x00000000;
109 req
= smb2_notify_send(tree
, &n
);
111 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
112 if (tevent_loop_once(torture
->ev
) != 0) {
117 status
= torture_setup_complex_file(tree
, FNAME
);
118 CHECK_STATUS(status
, NT_STATUS_OK
);
120 status
= smb2_notify_recv(req
, torture
, &n
);
121 CHECK_STATUS(status
, NT_STATUS_OK
);
122 CHECK_VAL(n
.out
.num_changes
, 1);
123 CHECK_VAL(n
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
124 CHECK_WIRE_STR(n
.out
.changes
[0].name
, FNAME
);
127 * if the change response doesn't fit in the buffer
128 * NOTIFY_ENUM_DIR is returned.
130 n
.in
.buffer_size
= 0x00000000;
131 req
= smb2_notify_send(tree
, &n
);
133 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
134 if (tevent_loop_once(torture
->ev
) != 0) {
139 status
= torture_setup_complex_file(tree
, FNAME
);
140 CHECK_STATUS(status
, NT_STATUS_OK
);
142 status
= smb2_notify_recv(req
, torture
, &n
);
143 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
146 * if the change response fits in the buffer we get
149 n
.in
.buffer_size
= max_buffer_size
;
150 req
= smb2_notify_send(tree
, &n
);
152 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
153 if (tevent_loop_once(torture
->ev
) != 0) {
158 status
= torture_setup_complex_file(tree
, FNAME
);
159 CHECK_STATUS(status
, NT_STATUS_OK
);
161 status
= smb2_notify_recv(req
, torture
, &n
);
162 CHECK_STATUS(status
, NT_STATUS_OK
);
163 CHECK_VAL(n
.out
.num_changes
, 3);
164 CHECK_VAL(n
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
165 CHECK_WIRE_STR(n
.out
.changes
[0].name
, FNAME
);
166 CHECK_VAL(n
.out
.changes
[1].action
, NOTIFY_ACTION_ADDED
);
167 CHECK_WIRE_STR(n
.out
.changes
[1].name
, FNAME
);
168 CHECK_VAL(n
.out
.changes
[2].action
, NOTIFY_ACTION_MODIFIED
);
169 CHECK_WIRE_STR(n
.out
.changes
[2].name
, FNAME
);
171 /* if the first notify returns NOTIFY_ENUM_DIR, all do */
172 status
= smb2_util_close(tree
, dh
);
173 CHECK_STATUS(status
, NT_STATUS_OK
);
174 status
= smb2_util_roothandle(tree
, &dh
);
175 CHECK_STATUS(status
, NT_STATUS_OK
);
177 n
.in
.recursive
= 0x0000;
178 n
.in
.buffer_size
= 0x00000001;
179 n
.in
.file
.handle
= dh
;
180 n
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ALL
;
181 n
.in
.unknown
= 0x00000000;
182 req
= smb2_notify_send(tree
, &n
);
184 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
185 if (tevent_loop_once(torture
->ev
) != 0) {
190 status
= torture_setup_complex_file(tree
, FNAME
);
191 CHECK_STATUS(status
, NT_STATUS_OK
);
193 status
= smb2_notify_recv(req
, torture
, &n
);
194 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
196 n
.in
.buffer_size
= max_buffer_size
;
197 req
= smb2_notify_send(tree
, &n
);
198 while (!req
->cancel
.can_cancel
&& req
->state
<= SMB2_REQUEST_RECV
) {
199 if (tevent_loop_once(torture
->ev
) != 0) {
204 status
= torture_setup_complex_file(tree
, FNAME
);
205 CHECK_STATUS(status
, NT_STATUS_OK
);
207 status
= smb2_notify_recv(req
, torture
, &n
);
208 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
210 /* if the buffer size is too large, we get invalid parameter */
211 n
.in
.recursive
= 0x0000;
212 n
.in
.buffer_size
= max_buffer_size
+ 1;
213 n
.in
.file
.handle
= dh
;
214 n
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ALL
;
215 n
.in
.unknown
= 0x00000000;
216 req
= smb2_notify_send(tree
, &n
);
217 status
= smb2_notify_recv(req
, torture
, &n
);
218 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
225 basic testing of change notify on directories
227 static bool torture_smb2_notify_dir(struct torture_context
*torture
,
228 struct smb2_tree
*tree1
,
229 struct smb2_tree
*tree2
)
233 union smb_notify notify
;
237 struct smb2_handle h1
, h2
;
238 struct smb2_request
*req
, *req2
;
239 const char *fname
= BASEDIR
"\\subdir-name";
240 extern int torture_numops
;
242 torture_comment(torture
, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
244 smb2_deltree(tree1
, BASEDIR
);
245 smb2_util_rmdir(tree1
, BASEDIR
);
247 get a handle on the directory
249 ZERO_STRUCT(io
.smb2
);
250 io
.generic
.level
= RAW_OPEN_SMB2
;
251 io
.smb2
.in
.create_flags
= 0;
252 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
253 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
254 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
255 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
256 NTCREATEX_SHARE_ACCESS_WRITE
;
257 io
.smb2
.in
.alloc_size
= 0;
258 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
259 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
260 io
.smb2
.in
.security_flags
= 0;
261 io
.smb2
.in
.fname
= BASEDIR
;
263 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
264 CHECK_STATUS(status
, NT_STATUS_OK
);
265 h1
= io
.smb2
.out
.file
.handle
;
267 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
268 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
;
269 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
270 CHECK_STATUS(status
, NT_STATUS_OK
);
271 h2
= io
.smb2
.out
.file
.handle
;
273 /* ask for a change notify,
274 on file or directory name changes */
275 ZERO_STRUCT(notify
.smb2
);
276 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
277 notify
.smb2
.in
.buffer_size
= 1000;
278 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
279 notify
.smb2
.in
.file
.handle
= h1
;
280 notify
.smb2
.in
.recursive
= true;
282 torture_comment(torture
, "Testing notify cancel\n");
284 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
286 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
287 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
289 torture_comment(torture
, "Testing notify mkdir\n");
291 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
292 smb2_util_mkdir(tree2
, fname
);
294 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
295 CHECK_STATUS(status
, NT_STATUS_OK
);
297 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
298 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
299 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
301 torture_comment(torture
, "Testing notify rmdir\n");
303 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
304 smb2_util_rmdir(tree2
, fname
);
306 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
307 CHECK_STATUS(status
, NT_STATUS_OK
);
308 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
309 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
310 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
312 torture_comment(torture
,
313 "Testing notify mkdir - rmdir - mkdir - rmdir\n");
315 smb2_util_mkdir(tree2
, fname
);
316 smb2_util_rmdir(tree2
, fname
);
317 smb2_util_mkdir(tree2
, fname
);
318 smb2_util_rmdir(tree2
, fname
);
320 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
321 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
322 CHECK_STATUS(status
, NT_STATUS_OK
);
323 CHECK_VAL(notify
.smb2
.out
.num_changes
, 4);
324 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
325 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
326 CHECK_VAL(notify
.smb2
.out
.changes
[1].action
, NOTIFY_ACTION_REMOVED
);
327 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[1].name
, "subdir-name");
328 CHECK_VAL(notify
.smb2
.out
.changes
[2].action
, NOTIFY_ACTION_ADDED
);
329 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[2].name
, "subdir-name");
330 CHECK_VAL(notify
.smb2
.out
.changes
[3].action
, NOTIFY_ACTION_REMOVED
);
331 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[3].name
, "subdir-name");
333 count
= torture_numops
;
334 torture_comment(torture
,
335 "Testing buffered notify on create of %d files\n", count
);
336 for (i
=0;i
<count
;i
++) {
337 struct smb2_handle h12
;
338 char *fname2
= talloc_asprintf(torture
, BASEDIR
"\\test%d.txt",
341 ZERO_STRUCT(io
.smb2
);
342 io
.generic
.level
= RAW_OPEN_SMB2
;
343 io
.smb2
.in
.create_flags
= 0;
344 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
345 io
.smb2
.in
.create_options
=
346 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
347 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
348 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
349 NTCREATEX_SHARE_ACCESS_WRITE
;
350 io
.smb2
.in
.alloc_size
= 0;
351 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
352 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
353 io
.smb2
.in
.security_flags
= 0;
354 io
.smb2
.in
.fname
= fname2
;
356 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
357 if (!NT_STATUS_EQUAL(status
, NT_STATUS_OK
)) {
358 torture_comment(torture
, "Failed to create %s \n",
363 h12
= io
.smb2
.out
.file
.handle
;
365 smb2_util_close(tree1
, h12
);
368 /* (1st notify) setup a new notify on a different directory handle.
369 This new notify won't see the events above. */
370 notify
.smb2
.in
.file
.handle
= h2
;
371 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
373 /* (2nd notify) whereas this notify will see the above buffered events,
374 and it directly returns the buffered events */
375 notify
.smb2
.in
.file
.handle
= h1
;
376 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
378 status
= smb2_util_unlink(tree1
, BASEDIR
"\\nonexistent.txt");
379 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
381 /* (1st unlink) as the 2nd notify directly returns,
382 this unlink is only seen by the 1st notify and
383 the 3rd notify (later) */
384 torture_comment(torture
,
385 "Testing notify on unlink for the first file\n");
386 status
= smb2_util_unlink(tree2
, BASEDIR
"\\test0.txt");
387 CHECK_STATUS(status
, NT_STATUS_OK
);
389 /* receive the reply from the 2nd notify */
390 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
391 CHECK_STATUS(status
, NT_STATUS_OK
);
393 CHECK_VAL(notify
.smb2
.out
.num_changes
, count
);
394 for (i
=1;i
<count
;i
++) {
395 CHECK_VAL(notify
.smb2
.out
.changes
[i
].action
,
396 NOTIFY_ACTION_ADDED
);
398 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "test0.txt");
400 torture_comment(torture
, "and now from the 1st notify\n");
401 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
402 CHECK_STATUS(status
, NT_STATUS_OK
);
403 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
404 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
405 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "test0.txt");
407 torture_comment(torture
,
408 "(3rd notify) this notify will only see the 1st unlink\n");
409 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
411 status
= smb2_util_unlink(tree1
, BASEDIR
"\\nonexistent.txt");
412 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
414 for (i
=1;i
<count
;i
++) {
415 char *fname2
= talloc_asprintf(torture
,
416 BASEDIR
"\\test%d.txt", i
);
417 status
= smb2_util_unlink(tree2
, fname2
);
418 CHECK_STATUS(status
, NT_STATUS_OK
);
422 /* receive the 3rd notify */
423 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
424 CHECK_STATUS(status
, NT_STATUS_OK
);
425 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
426 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
427 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "test0.txt");
429 /* and we now see the rest of the unlink calls on both
430 * directory handles */
431 notify
.smb2
.in
.file
.handle
= h1
;
433 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
434 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
435 CHECK_STATUS(status
, NT_STATUS_OK
);
436 CHECK_VAL(notify
.smb2
.out
.num_changes
, count
-1);
437 for (i
=0;i
<notify
.smb2
.out
.num_changes
;i
++) {
438 CHECK_VAL(notify
.smb2
.out
.changes
[i
].action
,
439 NOTIFY_ACTION_REMOVED
);
441 notify
.smb2
.in
.file
.handle
= h2
;
442 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
443 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
444 CHECK_STATUS(status
, NT_STATUS_OK
);
445 CHECK_VAL(notify
.smb2
.out
.num_changes
, count
-1);
446 for (i
=0;i
<notify
.smb2
.out
.num_changes
;i
++) {
447 CHECK_VAL(notify
.smb2
.out
.changes
[i
].action
,
448 NOTIFY_ACTION_REMOVED
);
451 torture_comment(torture
,
452 "Testing if a close() on the dir handle triggers the notify reply\n");
454 notify
.smb2
.in
.file
.handle
= h1
;
455 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
457 ZERO_STRUCT(cl
.smb2
);
458 cl
.smb2
.level
= RAW_CLOSE_SMB2
;
459 cl
.smb2
.in
.file
.handle
= h1
;
460 status
= smb2_close(tree1
, &(cl
.smb2
));
461 CHECK_STATUS(status
, NT_STATUS_OK
);
463 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
464 CHECK_STATUS(status
, STATUS_NOTIFY_CLEANUP
);
465 CHECK_VAL(notify
.smb2
.out
.num_changes
, 9);
468 smb2_util_close(tree1
, h1
);
469 smb2_util_close(tree1
, h2
);
470 smb2_deltree(tree1
, BASEDIR
);
474 static struct smb2_handle
custom_smb2_create(struct smb2_tree
*tree
,
475 struct torture_context
*torture
,
476 struct smb2_create
*smb2
)
478 struct smb2_handle h1
;
481 smb2_deltree(tree
, smb2
->in
.fname
);
482 status
= smb2_create(tree
, torture
, smb2
);
483 CHECK_STATUS(status
, NT_STATUS_OK
);
484 h1
= smb2
->out
.file
.handle
;
487 h1
= (struct smb2_handle
) {
495 testing of recursive change notify
498 static bool torture_smb2_notify_recursive(struct torture_context
*torture
,
499 struct smb2_tree
*tree1
,
500 struct smb2_tree
*tree2
)
504 union smb_notify notify
;
505 union smb_open io
, io1
;
506 union smb_setfileinfo sinfo
;
507 struct smb2_handle h1
;
508 struct smb2_request
*req1
, *req2
;
510 smb2_deltree(tree1
, BASEDIR
);
511 smb2_util_rmdir(tree1
, BASEDIR
);
513 torture_comment(torture
, "TESTING CHANGE NOTIFY WITH RECURSION\n");
516 get a handle on the directory
518 ZERO_STRUCT(io
.smb2
);
519 io
.generic
.level
= RAW_OPEN_SMB2
;
520 io
.smb2
.in
.create_flags
= 0;
521 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
522 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
523 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
524 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
525 NTCREATEX_SHARE_ACCESS_WRITE
;
526 io
.smb2
.in
.alloc_size
= 0;
527 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
528 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
529 io
.smb2
.in
.security_flags
= 0;
530 io
.smb2
.in
.fname
= BASEDIR
;
532 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
533 CHECK_STATUS(status
, NT_STATUS_OK
);
534 h1
= io
.smb2
.out
.file
.handle
;
536 /* ask for a change notify, on file or directory name
537 changes. Setup both with and without recursion */
538 ZERO_STRUCT(notify
.smb2
);
539 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
540 notify
.smb2
.in
.buffer_size
= 1000;
541 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
|
542 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
543 FILE_NOTIFY_CHANGE_CREATION
;
544 notify
.smb2
.in
.file
.handle
= h1
;
546 notify
.smb2
.in
.recursive
= true;
547 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
549 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
550 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
552 notify
.smb2
.in
.recursive
= false;
553 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
555 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
556 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
558 ZERO_STRUCT(io1
.smb2
);
559 io1
.generic
.level
= RAW_OPEN_SMB2
;
560 io1
.smb2
.in
.create_flags
= NTCREATEX_FLAGS_EXTENDED
;
561 io1
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
562 SEC_RIGHTS_FILE_WRITE
|
564 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
565 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
566 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
567 NTCREATEX_SHARE_ACCESS_WRITE
|
568 NTCREATEX_SHARE_ACCESS_DELETE
;
569 io1
.smb2
.in
.alloc_size
= 0;
570 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
571 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
572 io1
.smb2
.in
.security_flags
= 0;
573 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name";
574 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
575 CHECK_STATUS(status
, NT_STATUS_OK
);
576 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
578 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname1";
579 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
580 CHECK_STATUS(status
, NT_STATUS_OK
);
582 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
583 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
584 sinfo
.rename_information
.in
.overwrite
= 0;
585 sinfo
.rename_information
.in
.root_fid
= 0;
586 sinfo
.rename_information
.in
.new_name
=
587 BASEDIR
"\\subdir-name\\subname1-r";
588 status
= smb2_setinfo_file(tree2
, &sinfo
);
589 CHECK_STATUS(status
, NT_STATUS_OK
);
591 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
592 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname2";
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
"\\subname2-r";
601 status
= smb2_setinfo_file(tree2
, &sinfo
);
602 CHECK_STATUS(status
, NT_STATUS_OK
);
604 io1
.smb2
.in
.fname
= BASEDIR
"\\subname2-r";
605 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
606 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
607 CHECK_STATUS(status
, NT_STATUS_OK
);
609 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
610 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
611 sinfo
.rename_information
.in
.overwrite
= true;
612 sinfo
.rename_information
.in
.root_fid
= 0;
613 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname3-r";
614 status
= smb2_setinfo_file(tree2
, &sinfo
);
615 CHECK_STATUS(status
, NT_STATUS_OK
);
617 notify
.smb2
.in
.completion_filter
= 0;
618 notify
.smb2
.in
.recursive
= true;
620 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
622 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name\\subname1-r");
623 CHECK_STATUS(status
, NT_STATUS_OK
);
624 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name");
625 CHECK_STATUS(status
, NT_STATUS_OK
);
626 status
= smb2_util_unlink(tree2
, BASEDIR
"\\subname3-r");
627 CHECK_STATUS(status
, NT_STATUS_OK
);
629 notify
.smb2
.in
.recursive
= false;
630 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
632 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
633 CHECK_STATUS(status
, NT_STATUS_OK
);
635 CHECK_VAL(notify
.smb2
.out
.num_changes
, 9);
636 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
637 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
638 CHECK_VAL(notify
.smb2
.out
.changes
[1].action
, NOTIFY_ACTION_ADDED
);
639 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[1].name
, "subdir-name\\subname1");
640 CHECK_VAL(notify
.smb2
.out
.changes
[2].action
, NOTIFY_ACTION_OLD_NAME
);
641 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[2].name
, "subdir-name\\subname1");
642 CHECK_VAL(notify
.smb2
.out
.changes
[3].action
, NOTIFY_ACTION_NEW_NAME
);
643 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[3].name
, "subdir-name\\subname1-r");
644 CHECK_VAL(notify
.smb2
.out
.changes
[4].action
, NOTIFY_ACTION_ADDED
);
645 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[4].name
, "subdir-name\\subname2");
646 CHECK_VAL(notify
.smb2
.out
.changes
[5].action
, NOTIFY_ACTION_REMOVED
);
647 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[5].name
, "subdir-name\\subname2");
648 CHECK_VAL(notify
.smb2
.out
.changes
[6].action
, NOTIFY_ACTION_ADDED
);
649 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[6].name
, "subname2-r");
650 CHECK_VAL(notify
.smb2
.out
.changes
[7].action
, NOTIFY_ACTION_OLD_NAME
);
651 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[7].name
, "subname2-r");
652 CHECK_VAL(notify
.smb2
.out
.changes
[8].action
, NOTIFY_ACTION_NEW_NAME
);
653 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[8].name
, "subname3-r");
656 smb2_deltree(tree1
, BASEDIR
);
661 testing of change notify mask change
664 static bool torture_smb2_notify_mask_change(struct torture_context
*torture
,
665 struct smb2_tree
*tree1
,
666 struct smb2_tree
*tree2
)
670 union smb_notify notify
;
671 union smb_open io
, io1
;
672 struct smb2_handle h1
;
673 struct smb2_request
*req1
, *req2
;
674 union smb_setfileinfo sinfo
;
676 smb2_deltree(tree1
, BASEDIR
);
677 smb2_util_rmdir(tree1
, BASEDIR
);
679 torture_comment(torture
, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
682 get a handle on the directory
684 ZERO_STRUCT(io
.smb2
);
685 io
.generic
.level
= RAW_OPEN_SMB2
;
686 io
.smb2
.in
.create_flags
= 0;
687 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
688 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
689 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
690 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
691 NTCREATEX_SHARE_ACCESS_WRITE
;
692 io
.smb2
.in
.alloc_size
= 0;
693 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
694 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
695 io
.smb2
.in
.security_flags
= 0;
696 io
.smb2
.in
.fname
= BASEDIR
;
698 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
699 CHECK_STATUS(status
, NT_STATUS_OK
);
700 h1
= io
.smb2
.out
.file
.handle
;
702 /* ask for a change notify, on file or directory name
703 changes. Setup both with and without recursion */
704 ZERO_STRUCT(notify
.smb2
);
705 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
706 notify
.smb2
.in
.buffer_size
= 1000;
707 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
708 notify
.smb2
.in
.file
.handle
= h1
;
710 notify
.smb2
.in
.recursive
= true;
711 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
714 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
715 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
718 notify
.smb2
.in
.recursive
= false;
719 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
722 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
723 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
725 notify
.smb2
.in
.recursive
= true;
726 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
728 /* Set to hidden then back again. */
729 ZERO_STRUCT(io1
.smb2
);
730 io1
.generic
.level
= RAW_OPEN_SMB2
;
731 io1
.smb2
.in
.create_flags
= 0;
732 io1
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
733 SEC_RIGHTS_FILE_WRITE
|
735 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
736 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
737 NTCREATEX_SHARE_ACCESS_WRITE
|
738 NTCREATEX_SHARE_ACCESS_DELETE
;
739 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
740 io1
.smb2
.in
.security_flags
= 0;
741 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
742 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
743 io1
.smb2
.in
.fname
= BASEDIR
"\\tname1";
745 smb2_util_close(tree1
,
746 custom_smb2_create(tree1
, torture
, &(io1
.smb2
)));
747 status
= smb2_util_setatr(tree1
, BASEDIR
"\\tname1",
748 FILE_ATTRIBUTE_HIDDEN
);
749 CHECK_STATUS(status
, NT_STATUS_OK
);
750 smb2_util_unlink(tree1
, BASEDIR
"\\tname1");
752 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
753 CHECK_STATUS(status
, NT_STATUS_OK
);
755 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
756 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
757 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "tname1");
759 /* Now try and change the mask to include other events.
760 * This should not work - once the mask is set on a directory
761 * h1 it seems to be fixed until the fnum is closed. */
763 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
|
764 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
765 FILE_NOTIFY_CHANGE_CREATION
;
766 notify
.smb2
.in
.recursive
= true;
767 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
769 notify
.smb2
.in
.recursive
= false;
770 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
772 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
773 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
774 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name";
775 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
776 CHECK_STATUS(status
, NT_STATUS_OK
);
777 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
780 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname1";
781 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
782 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
783 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
784 CHECK_STATUS(status
, NT_STATUS_OK
);
785 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
786 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
787 sinfo
.rename_information
.in
.overwrite
= true;
788 sinfo
.rename_information
.in
.root_fid
= 0;
789 sinfo
.rename_information
.in
.new_name
=
790 BASEDIR
"\\subdir-name\\subname1-r";
791 status
= smb2_setinfo_file(tree2
, &sinfo
);
792 CHECK_STATUS(status
, NT_STATUS_OK
);
794 io1
.smb2
.in
.fname
= BASEDIR
"\\subdir-name\\subname2";
795 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
796 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
797 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
798 CHECK_STATUS(status
, NT_STATUS_OK
);
799 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
800 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname2-r";
801 status
= smb2_setinfo_file(tree2
, &sinfo
);
802 CHECK_STATUS(status
, NT_STATUS_OK
);
803 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
805 io1
.smb2
.in
.fname
= BASEDIR
"\\subname2-r";
806 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
807 status
= smb2_create(tree2
, torture
, &(io1
.smb2
));
808 CHECK_STATUS(status
, NT_STATUS_OK
);
809 sinfo
.rename_information
.in
.file
.handle
= io1
.smb2
.out
.file
.handle
;
810 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\subname3-r";
811 status
= smb2_setinfo_file(tree2
, &sinfo
);
812 CHECK_STATUS(status
, NT_STATUS_OK
);
813 smb2_util_close(tree2
, io1
.smb2
.out
.file
.handle
);
815 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name\\subname1-r");
816 CHECK_STATUS(status
, NT_STATUS_OK
);
817 status
= smb2_util_rmdir(tree2
, BASEDIR
"\\subdir-name");
818 CHECK_STATUS(status
, NT_STATUS_OK
);
819 status
= smb2_util_unlink(tree2
, BASEDIR
"\\subname3-r");
820 CHECK_STATUS(status
, NT_STATUS_OK
);
822 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
823 CHECK_STATUS(status
, NT_STATUS_OK
);
825 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
826 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
827 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subname2-r");
829 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
830 CHECK_STATUS(status
, NT_STATUS_OK
);
832 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
833 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
834 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subname3-r");
841 smb2_deltree(tree1
, BASEDIR
);
846 testing of mask bits for change notify
849 static bool torture_smb2_notify_mask(struct torture_context
*torture
,
850 struct smb2_tree
*tree1
,
851 struct smb2_tree
*tree2
)
855 union smb_notify notify
;
856 union smb_open io
, io1
;
857 struct smb2_handle h1
, h2
;
861 union smb_setfileinfo sinfo
;
863 smb2_deltree(tree1
, BASEDIR
);
864 smb2_util_rmdir(tree1
, BASEDIR
);
866 torture_comment(torture
, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
870 get a handle on the directory
872 ZERO_STRUCT(io
.smb2
);
873 io
.generic
.level
= RAW_OPEN_SMB2
;
874 io
.smb2
.in
.create_flags
= 0;
875 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
876 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
877 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
878 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
879 NTCREATEX_SHARE_ACCESS_WRITE
;
880 io
.smb2
.in
.alloc_size
= 0;
881 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
882 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
883 io
.smb2
.in
.security_flags
= 0;
884 io
.smb2
.in
.fname
= BASEDIR
;
886 ZERO_STRUCT(notify
.smb2
);
887 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
888 notify
.smb2
.in
.buffer_size
= 1000;
889 notify
.smb2
.in
.recursive
= true;
891 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
892 expected, nchanges) \
894 do { for (mask=i=0;i<32;i++) { \
895 struct smb2_request *req; \
896 status = smb2_create(tree1, torture, &(io.smb2)); \
897 CHECK_STATUS(status, NT_STATUS_OK); \
898 h1 = io.smb2.out.file.handle; \
900 notify.smb2.in.file.handle = h1; \
901 notify.smb2.in.completion_filter = (1<<i); \
902 /* cancel initial requests so the buffer is setup */ \
903 req = smb2_notify_send(tree1, &(notify.smb2)); \
905 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
906 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
907 /* send the change notify request */ \
908 req = smb2_notify_send(tree1, &(notify.smb2)); \
910 smb_msleep(200); smb2_cancel(req); \
911 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
913 smb2_util_close(tree1, h1); \
914 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
915 CHECK_STATUS(status, NT_STATUS_OK); \
916 /* special case to cope with file rename behaviour */ \
917 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
918 notify.smb2.out.changes[0].action == \
919 NOTIFY_ACTION_MODIFIED && \
920 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
921 Action == NOTIFY_ACTION_OLD_NAME) { \
922 torture_comment(torture, \
923 "(rename file special handling OK)\n"); \
924 } else if (nchanges != notify.smb2.out.num_changes) { \
925 torture_result(torture, TORTURE_FAIL, \
926 "ERROR: nchanges=%d expected=%d "\
927 "action=%d filter=0x%08x\n", \
928 notify.smb2.out.num_changes, \
930 notify.smb2.out.changes[0].action, \
931 notify.smb2.in.completion_filter); \
933 } else if (notify.smb2.out.changes[0].action != Action) { \
934 torture_result(torture, TORTURE_FAIL, \
935 "ERROR: nchanges=%d action=%d " \
936 "expectedAction=%d filter=0x%08x\n", \
937 notify.smb2.out.num_changes, \
938 notify.smb2.out.changes[0].action, \
940 notify.smb2.in.completion_filter); \
942 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
944 torture_result(torture, TORTURE_FAIL, \
945 "ERROR: nchanges=%d action=%d " \
946 "filter=0x%08x name=%s\n", \
947 notify.smb2.out.num_changes, \
948 notify.smb2.out.changes[0].action, \
949 notify.smb2.in.completion_filter, \
950 notify.smb2.out.changes[0].name.s); \
958 torture_comment(torture
, "Testing mkdir\n");
959 NOTIFY_MASK_TEST("Testing mkdir",;,
960 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
961 smb2_util_rmdir(tree2
, BASEDIR
"\\tname1");,
963 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
965 torture_comment(torture
, "Testing create file\n");
966 ZERO_STRUCT(io1
.smb2
);
967 io1
.generic
.level
= RAW_OPEN_SMB2
;
968 io1
.smb2
.in
.create_flags
= 0;
969 io1
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
970 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
971 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
972 NTCREATEX_SHARE_ACCESS_WRITE
;
973 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
974 io1
.smb2
.in
.security_flags
= 0;
975 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
976 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
977 io1
.smb2
.in
.fname
= BASEDIR
"\\tname1";
979 NOTIFY_MASK_TEST("Testing create file",;,
980 smb2_util_close(tree2
, custom_smb2_create(tree2
,
981 torture
, &(io1
.smb2
)));,
982 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
984 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
986 torture_comment(torture
, "Testing unlink\n");
987 NOTIFY_MASK_TEST("Testing unlink",
988 smb2_util_close(tree2
, custom_smb2_create(tree2
,
989 torture
, &(io1
.smb2
)));,
990 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
992 NOTIFY_ACTION_REMOVED
,
993 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
995 torture_comment(torture
, "Testing rmdir\n");
996 NOTIFY_MASK_TEST("Testing rmdir",
997 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
998 smb2_util_rmdir(tree2
, BASEDIR
"\\tname1");,
1000 NOTIFY_ACTION_REMOVED
,
1001 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
1003 torture_comment(torture
, "Testing rename file\n");
1005 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1006 sinfo
.rename_information
.in
.file
.handle
= h1
;
1007 sinfo
.rename_information
.in
.overwrite
= true;
1008 sinfo
.rename_information
.in
.root_fid
= 0;
1009 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\tname2";
1010 NOTIFY_MASK_TEST("Testing rename file",
1011 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1012 torture
, &(io1
.smb2
)));,
1013 smb2_setinfo_file(tree2
, &sinfo
);,
1014 smb2_util_unlink(tree2
, BASEDIR
"\\tname2");,
1015 NOTIFY_ACTION_OLD_NAME
,
1016 FILE_NOTIFY_CHANGE_FILE_NAME
, 2);
1018 torture_comment(torture
, "Testing rename dir\n");
1020 sinfo
.rename_information
.level
= RAW_SFILEINFO_RENAME_INFORMATION
;
1021 sinfo
.rename_information
.in
.file
.handle
= h1
;
1022 sinfo
.rename_information
.in
.overwrite
= true;
1023 sinfo
.rename_information
.in
.root_fid
= 0;
1024 sinfo
.rename_information
.in
.new_name
= BASEDIR
"\\tname2";
1025 NOTIFY_MASK_TEST("Testing rename dir",
1026 smb2_util_mkdir(tree2
, BASEDIR
"\\tname1");,
1027 smb2_setinfo_file(tree2
, &sinfo
);,
1028 smb2_util_rmdir(tree2
, BASEDIR
"\\tname2");,
1029 NOTIFY_ACTION_OLD_NAME
,
1030 FILE_NOTIFY_CHANGE_DIR_NAME
, 2);
1032 torture_comment(torture
, "Testing set path attribute\n");
1033 NOTIFY_MASK_TEST("Testing set path attribute",
1034 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1035 torture
, &(io
.smb2
)));,
1036 smb2_util_setatr(tree2
, BASEDIR
"\\tname1",
1037 FILE_ATTRIBUTE_HIDDEN
);,
1038 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
1039 NOTIFY_ACTION_MODIFIED
,
1040 FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
1042 torture_comment(torture
, "Testing set path write time\n");
1044 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1045 sinfo
.generic
.in
.file
.handle
= h1
;
1046 sinfo
.basic_info
.in
.write_time
= 1000;
1047 NOTIFY_MASK_TEST("Testing set path write time",
1048 smb2_util_close(tree2
, custom_smb2_create(tree2
,
1049 torture
, &(io1
.smb2
)));,
1050 smb2_setinfo_file(tree2
, &sinfo
);,
1051 smb2_util_unlink(tree2
, BASEDIR
"\\tname1");,
1052 NOTIFY_ACTION_MODIFIED
,
1053 FILE_NOTIFY_CHANGE_LAST_WRITE
, 1);
1055 if (torture_setting_bool(torture
, "samba3", false)) {
1056 torture_comment(torture
,
1057 "Samba3 does not yet support create times "
1062 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1063 sinfo
.generic
.in
.file
.handle
= h1
;
1064 sinfo
.basic_info
.in
.create_time
= 0;
1065 torture_comment(torture
, "Testing set file create time\n");
1066 NOTIFY_MASK_TEST("Testing set file create time",
1067 smb2_create_complex_file(tree2
,
1068 BASEDIR
"\\tname1", &h2
);,
1069 smb2_setinfo_file(tree2
, &sinfo
);,
1070 (smb2_util_close(tree2
, h2
),
1071 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1072 NOTIFY_ACTION_MODIFIED
,
1073 FILE_NOTIFY_CHANGE_CREATION
, 1);
1077 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1078 sinfo
.generic
.in
.file
.handle
= h1
;
1079 sinfo
.basic_info
.in
.access_time
= 0;
1080 torture_comment(torture
, "Testing set file access time\n");
1081 NOTIFY_MASK_TEST("Testing set file access 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
,
1087 FILE_NOTIFY_CHANGE_LAST_ACCESS
, 1);
1090 sinfo
.generic
.level
= RAW_SFILEINFO_BASIC_INFORMATION
;
1091 sinfo
.generic
.in
.file
.handle
= h1
;
1092 sinfo
.basic_info
.in
.change_time
= 0;
1093 torture_comment(torture
, "Testing set file change time\n");
1094 NOTIFY_MASK_TEST("Testing set file change time",
1095 smb2_create_complex_file(tree2
, BASEDIR
"\\tname1", &h2
);,
1096 smb2_setinfo_file(tree2
, &sinfo
);,
1097 (smb2_util_close(tree2
, h2
),
1098 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1099 NOTIFY_ACTION_MODIFIED
,
1103 torture_comment(torture
, "Testing write\n");
1104 NOTIFY_MASK_TEST("Testing write",
1105 smb2_create_complex_file(tree2
, BASEDIR
"\\tname1", &h2
);,
1106 smb2_util_write(tree2
, h2
, &c
, 10000, 1);,
1107 (smb2_util_close(tree2
, h2
),
1108 smb2_util_unlink(tree2
, BASEDIR
"\\tname1"));,
1109 NOTIFY_ACTION_MODIFIED
,
1113 smb2_deltree(tree1
, BASEDIR
);
1118 basic testing of change notify on files
1120 static bool torture_smb2_notify_file(struct torture_context
*torture
,
1121 struct smb2_tree
*tree
)
1127 union smb_notify notify
;
1128 struct smb2_request
*req
;
1129 struct smb2_handle h1
;
1130 const char *fname
= BASEDIR
"\\file.txt";
1132 smb2_deltree(tree
, BASEDIR
);
1133 smb2_util_rmdir(tree
, BASEDIR
);
1135 torture_comment(torture
, "TESTING CHANGE NOTIFY ON FILES\n");
1136 status
= torture_smb2_testdir(tree
, BASEDIR
, &h1
);
1137 CHECK_STATUS(status
, NT_STATUS_OK
);
1139 ZERO_STRUCT(io
.smb2
);
1140 io
.generic
.level
= RAW_OPEN_SMB2
;
1141 io
.smb2
.in
.create_flags
= 0;
1142 io
.smb2
.in
.desired_access
= SEC_FLAG_MAXIMUM_ALLOWED
;
1143 io
.smb2
.in
.create_options
= 0;
1144 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1145 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1146 NTCREATEX_SHARE_ACCESS_WRITE
;
1147 io
.smb2
.in
.alloc_size
= 0;
1148 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1149 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1150 io
.smb2
.in
.security_flags
= 0;
1151 io
.smb2
.in
.fname
= fname
;
1152 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1153 CHECK_STATUS(status
, NT_STATUS_OK
);
1154 h1
= io
.smb2
.out
.file
.handle
;
1156 /* ask for a change notify,
1157 on file or directory name changes */
1158 ZERO_STRUCT(notify
.smb2
);
1159 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1160 notify
.smb2
.in
.file
.handle
= h1
;
1161 notify
.smb2
.in
.buffer_size
= 1000;
1162 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_STREAM_NAME
;
1163 notify
.smb2
.in
.recursive
= false;
1165 torture_comment(torture
,
1166 "Testing if notifies on file handles are invalid (should be)\n");
1168 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1169 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1170 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
1172 ZERO_STRUCT(cl
.smb2
);
1173 cl
.close
.level
= RAW_CLOSE_SMB2
;
1174 cl
.close
.in
.file
.handle
= h1
;
1175 status
= smb2_close(tree
, &(cl
.smb2
));
1176 CHECK_STATUS(status
, NT_STATUS_OK
);
1178 status
= smb2_util_unlink(tree
, fname
);
1179 CHECK_STATUS(status
, NT_STATUS_OK
);
1182 smb2_deltree(tree
, BASEDIR
);
1186 basic testing of change notifies followed by a tdis
1189 static bool torture_smb2_notify_tree_disconnect(
1190 struct torture_context
*torture
,
1191 struct smb2_tree
*tree
)
1195 union smb_notify notify
;
1197 struct smb2_handle h1
;
1198 struct smb2_request
*req
;
1200 smb2_deltree(tree
, BASEDIR
);
1201 smb2_util_rmdir(tree
, BASEDIR
);
1203 torture_comment(torture
, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY "
1204 "TREE-DISCONNECT\n");
1207 get a handle on the directory
1209 ZERO_STRUCT(io
.smb2
);
1210 io
.generic
.level
= RAW_OPEN_SMB2
;
1211 io
.smb2
.in
.create_flags
= 0;
1212 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1213 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1214 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1215 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1216 NTCREATEX_SHARE_ACCESS_WRITE
;
1217 io
.smb2
.in
.alloc_size
= 0;
1218 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1219 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1220 io
.smb2
.in
.security_flags
= 0;
1221 io
.smb2
.in
.fname
= BASEDIR
;
1223 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1224 CHECK_STATUS(status
, NT_STATUS_OK
);
1225 h1
= io
.smb2
.out
.file
.handle
;
1227 /* ask for a change notify,
1228 on file or directory name changes */
1229 ZERO_STRUCT(notify
.smb2
);
1230 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1231 notify
.smb2
.in
.buffer_size
= 1000;
1232 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1233 notify
.smb2
.in
.file
.handle
= h1
;
1234 notify
.smb2
.in
.recursive
= true;
1236 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1238 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1240 status
= smb2_tdis(tree
);
1241 CHECK_STATUS(status
, NT_STATUS_OK
);
1243 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1245 smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1246 CHECK_STATUS(status
, NT_STATUS_OK
);
1247 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1250 smb2_deltree(tree
, BASEDIR
);
1255 testing of change notifies followed by a tdis - no cancel
1258 static bool torture_smb2_notify_tree_disconnect_1(
1259 struct torture_context
*torture
,
1260 struct smb2_tree
*tree
)
1264 union smb_notify notify
;
1266 struct smb2_handle h1
;
1267 struct smb2_request
*req
;
1269 smb2_deltree(tree
, BASEDIR
);
1270 smb2_util_rmdir(tree
, BASEDIR
);
1272 torture_comment(torture
, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY "
1273 "TREE-DISCONNECT\n");
1276 get a handle on the directory
1278 ZERO_STRUCT(io
.smb2
);
1279 io
.generic
.level
= RAW_OPEN_SMB2
;
1280 io
.smb2
.in
.create_flags
= 0;
1281 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1282 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1283 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1284 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1285 NTCREATEX_SHARE_ACCESS_WRITE
;
1286 io
.smb2
.in
.alloc_size
= 0;
1287 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1288 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1289 io
.smb2
.in
.security_flags
= 0;
1290 io
.smb2
.in
.fname
= BASEDIR
;
1292 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1293 CHECK_STATUS(status
, NT_STATUS_OK
);
1294 h1
= io
.smb2
.out
.file
.handle
;
1296 /* ask for a change notify,
1297 on file or directory name changes */
1298 ZERO_STRUCT(notify
.smb2
);
1299 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1300 notify
.smb2
.in
.buffer_size
= 1000;
1301 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1302 notify
.smb2
.in
.file
.handle
= h1
;
1303 notify
.smb2
.in
.recursive
= true;
1305 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1306 WAIT_FOR_ASYNC_RESPONSE(req
);
1308 status
= smb2_tdis(tree
);
1309 CHECK_STATUS(status
, NT_STATUS_OK
);
1311 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1312 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1315 smb2_deltree(tree
, BASEDIR
);
1320 basic testing of change notifies followed by a ulogoff
1323 static bool torture_smb2_notify_ulogoff(struct torture_context
*torture
,
1324 struct smb2_tree
*tree1
)
1328 union smb_notify notify
;
1330 struct smb2_handle h1
;
1331 struct smb2_request
*req
;
1333 smb2_deltree(tree1
, BASEDIR
);
1334 smb2_util_rmdir(tree1
, BASEDIR
);
1336 torture_comment(torture
, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\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_CREATE
;
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(tree1
, torture
, &(io
.smb2
));
1356 CHECK_STATUS(status
, NT_STATUS_OK
);
1358 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
1359 status
= smb2_create(tree1
, 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(tree1
, &(notify
.smb2
));
1374 WAIT_FOR_ASYNC_RESPONSE(req
);
1376 status
= smb2_logoff(tree1
->session
);
1377 CHECK_STATUS(status
, NT_STATUS_OK
);
1379 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1380 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1383 smb2_deltree(tree1
, BASEDIR
);
1387 static void tcp_dis_handler(struct smb2_transport
*t
, void *p
)
1389 struct smb2_tree
*tree
= (struct smb2_tree
*)p
;
1390 smb2_transport_dead(tree
->session
->transport
,
1391 NT_STATUS_LOCAL_DISCONNECT
);
1397 basic testing of change notifies followed by tcp disconnect
1400 static bool torture_smb2_notify_tcp_disconnect(
1401 struct torture_context
*torture
,
1402 struct smb2_tree
*tree
)
1406 union smb_notify notify
;
1408 struct smb2_handle h1
;
1409 struct smb2_request
*req
;
1411 smb2_deltree(tree
, BASEDIR
);
1412 smb2_util_rmdir(tree
, BASEDIR
);
1414 torture_comment(torture
,
1415 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1418 get a handle on the directory
1420 ZERO_STRUCT(io
.smb2
);
1421 io
.generic
.level
= RAW_OPEN_SMB2
;
1422 io
.smb2
.in
.create_flags
= 0;
1423 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1424 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1425 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1426 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1427 NTCREATEX_SHARE_ACCESS_WRITE
;
1428 io
.smb2
.in
.alloc_size
= 0;
1429 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1430 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1431 io
.smb2
.in
.security_flags
= 0;
1432 io
.smb2
.in
.fname
= BASEDIR
;
1434 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1435 CHECK_STATUS(status
, NT_STATUS_OK
);
1436 h1
= io
.smb2
.out
.file
.handle
;
1438 /* ask for a change notify,
1439 on file or directory name changes */
1440 ZERO_STRUCT(notify
.smb2
);
1441 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1442 notify
.smb2
.in
.buffer_size
= 1000;
1443 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1444 notify
.smb2
.in
.file
.handle
= h1
;
1445 notify
.smb2
.in
.recursive
= true;
1447 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1449 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1450 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1452 notify
.smb2
.in
.recursive
= true;
1453 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1454 smb2_transport_idle_handler(tree
->session
->transport
,
1455 tcp_dis_handler
, 250, tree
);
1457 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1458 CHECK_STATUS(status
, NT_STATUS_LOCAL_DISCONNECT
);
1465 test setting up two change notify requests on one handle
1468 static bool torture_smb2_notify_double(struct torture_context
*torture
,
1469 struct smb2_tree
*tree1
,
1470 struct smb2_tree
*tree2
)
1474 union smb_notify notify
;
1476 struct smb2_handle h1
;
1477 struct smb2_request
*req1
, *req2
;
1479 smb2_deltree(tree1
, BASEDIR
);
1480 smb2_util_rmdir(tree1
, BASEDIR
);
1482 torture_comment(torture
,
1483 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1486 get a handle on the directory
1488 ZERO_STRUCT(io
.smb2
);
1489 io
.generic
.level
= RAW_OPEN_SMB2
;
1490 io
.smb2
.in
.create_flags
= 0;
1491 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_READ
|
1492 SEC_RIGHTS_FILE_WRITE
|
1493 SEC_RIGHTS_FILE_ALL
;
1494 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1495 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1496 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1497 NTCREATEX_SHARE_ACCESS_WRITE
;
1498 io
.smb2
.in
.alloc_size
= 0;
1499 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1500 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1501 io
.smb2
.in
.security_flags
= 0;
1502 io
.smb2
.in
.fname
= BASEDIR
;
1504 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1505 CHECK_STATUS(status
, NT_STATUS_OK
);
1506 h1
= io
.smb2
.out
.file
.handle
;
1508 /* ask for a change notify,
1509 on file or directory name changes */
1510 ZERO_STRUCT(notify
.smb2
);
1511 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1512 notify
.smb2
.in
.buffer_size
= 1000;
1513 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1514 notify
.smb2
.in
.file
.handle
= h1
;
1515 notify
.smb2
.in
.recursive
= true;
1517 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1519 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1520 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1522 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
1524 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
1525 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1527 smb2_util_mkdir(tree2
, BASEDIR
"\\subdir-name");
1528 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1529 req2
= smb2_notify_send(tree1
, &(notify
.smb2
));
1531 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1532 CHECK_STATUS(status
, NT_STATUS_OK
);
1533 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1534 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1536 smb2_util_mkdir(tree2
, BASEDIR
"\\subdir-name2");
1538 status
= smb2_notify_recv(req2
, torture
, &(notify
.smb2
));
1539 CHECK_STATUS(status
, NT_STATUS_OK
);
1540 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1541 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name2");
1544 smb2_deltree(tree1
, BASEDIR
);
1550 test multiple change notifies at different depths and with/without recursion
1553 static bool torture_smb2_notify_tree(struct torture_context
*torture
,
1554 struct smb2_tree
*tree
)
1557 union smb_notify notify
;
1559 struct smb2_request
*req
;
1566 struct smb2_handle h1
;
1569 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 30 },
1570 {BASEDIR
"\\zqy", true, FILE_NOTIFY_CHANGE_NAME
, 8 },
1571 {BASEDIR
"\\atsy", true, FILE_NOTIFY_CHANGE_NAME
, 4 },
1572 {BASEDIR
"\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1573 {BASEDIR
"\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME
, 13 },
1574 {BASEDIR
"\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME
, 7 },
1575 {BASEDIR
"\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1576 {BASEDIR
"\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1577 {BASEDIR
"\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1578 {BASEDIR
"\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1579 {BASEDIR
"\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1580 {BASEDIR
"\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1581 {BASEDIR
"\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME
, 40 },
1582 {BASEDIR
, true, FILE_NOTIFY_CHANGE_NAME
, 40 },
1583 {BASEDIR
, false,FILE_NOTIFY_CHANGE_NAME
, 6 },
1584 {BASEDIR
"\\atsy", false,FILE_NOTIFY_CHANGE_NAME
, 4 },
1585 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 24 },
1586 {BASEDIR
"\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1587 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1588 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 24 },
1592 bool all_done
= false;
1594 smb2_deltree(tree
, BASEDIR
);
1595 smb2_util_rmdir(tree
, BASEDIR
);
1597 torture_comment(torture
, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1599 ZERO_STRUCT(io
.smb2
);
1600 io
.generic
.level
= RAW_OPEN_SMB2
;
1601 io
.smb2
.in
.create_flags
= 0;
1602 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1603 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1604 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1605 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1606 NTCREATEX_SHARE_ACCESS_WRITE
;
1607 io
.smb2
.in
.alloc_size
= 0;
1608 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1609 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1610 io
.smb2
.in
.security_flags
= 0;
1611 io
.smb2
.in
.fname
= BASEDIR
;
1612 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1613 CHECK_STATUS(status
, NT_STATUS_OK
);
1615 ZERO_STRUCT(notify
.smb2
);
1616 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1617 notify
.smb2
.in
.buffer_size
= 20000;
1620 setup the directory tree, and the notify buffer on each directory
1622 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1623 io
.smb2
.in
.fname
= dirs
[i
].path
;
1624 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1625 CHECK_STATUS(status
, NT_STATUS_OK
);
1626 dirs
[i
].h1
= io
.smb2
.out
.file
.handle
;
1628 notify
.smb2
.in
.completion_filter
= dirs
[i
].filter
;
1629 notify
.smb2
.in
.file
.handle
= dirs
[i
].h1
;
1630 notify
.smb2
.in
.recursive
= dirs
[i
].recursive
;
1631 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1633 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1634 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1637 /* trigger 2 events in each dir */
1638 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1639 char *path
= talloc_asprintf(torture
, "%s\\test.dir",
1641 smb2_util_mkdir(tree
, path
);
1642 smb2_util_rmdir(tree
, path
);
1646 /* give a bit of time for the events to propogate */
1647 tv
= timeval_current();
1650 /* count events that have happened in each dir */
1651 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1652 notify
.smb2
.in
.file
.handle
= dirs
[i
].h1
;
1653 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1655 notify
.smb2
.out
.num_changes
= 0;
1656 status
= smb2_notify_recv(req
, torture
,
1658 dirs
[i
].counted
+= notify
.smb2
.out
.num_changes
;
1663 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1664 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1668 } while (!all_done
&& timeval_elapsed(&tv
) < 20);
1670 torture_comment(torture
, "took %.4f seconds to propogate all events\n",
1671 timeval_elapsed(&tv
));
1673 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1674 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1675 torture_comment(torture
,
1676 "ERROR: i=%d expected %d got %d for '%s'\n",
1677 i
, dirs
[i
].expected
, dirs
[i
].counted
,
1684 run from the back, closing and deleting
1686 for (i
=ARRAY_SIZE(dirs
)-1;i
>=0;i
--) {
1687 smb2_util_close(tree
, dirs
[i
].h1
);
1688 smb2_util_rmdir(tree
, dirs
[i
].path
);
1692 smb2_deltree(tree
, BASEDIR
);
1693 smb2_util_rmdir(tree
, BASEDIR
);
1698 Test response when cached server events exceed single NT NOTFIY response
1702 static bool torture_smb2_notify_overflow(struct torture_context
*torture
,
1703 struct smb2_tree
*tree
)
1707 union smb_notify notify
;
1709 struct smb2_handle h1
, h2
;
1711 struct smb2_request
*req1
;
1714 smb2_deltree(tree
, BASEDIR
);
1715 smb2_util_rmdir(tree
, BASEDIR
);
1717 torture_comment(torture
, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1719 /* get a handle on the directory */
1720 ZERO_STRUCT(io
.smb2
);
1721 io
.generic
.level
= RAW_OPEN_SMB2
;
1722 io
.smb2
.in
.create_flags
= 0;
1723 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1724 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1725 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1726 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1727 NTCREATEX_SHARE_ACCESS_WRITE
;
1728 io
.smb2
.in
.alloc_size
= 0;
1729 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1730 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1731 io
.smb2
.in
.security_flags
= 0;
1732 io
.smb2
.in
.fname
= BASEDIR
;
1734 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1735 CHECK_STATUS(status
, NT_STATUS_OK
);
1736 h1
= io
.smb2
.out
.file
.handle
;
1738 /* ask for a change notify, on name changes. */
1739 ZERO_STRUCT(notify
.smb2
);
1740 notify
.smb2
.level
= RAW_NOTIFY_NTTRANS
;
1741 notify
.smb2
.in
.buffer_size
= 1000;
1742 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1743 notify
.smb2
.in
.file
.handle
= h1
;
1745 notify
.smb2
.in
.recursive
= true;
1746 req1
= smb2_notify_send(tree
, &(notify
.smb2
));
1748 /* cancel initial requests so the buffer is setup */
1750 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1751 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1753 /* open a lot of files, filling up the server side notify buffer */
1754 torture_comment(torture
,
1755 "Testing overflowed buffer notify on create of %d files\n",
1758 for (i
=0;i
<count
;i
++) {
1759 char *fname
= talloc_asprintf(torture
,
1760 BASEDIR
"\\test%d.txt", i
);
1762 ZERO_STRUCT(io1
.smb2
);
1763 io1
.generic
.level
= RAW_OPEN_SMB2
;
1764 io1
.smb2
.in
.create_flags
= 0;
1765 io1
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1766 io1
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1767 io1
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1768 io1
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1769 NTCREATEX_SHARE_ACCESS_WRITE
;
1770 io1
.smb2
.in
.alloc_size
= 0;
1771 io1
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
1772 io1
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1773 io1
.smb2
.in
.security_flags
= 0;
1774 io1
.smb2
.in
.fname
= fname
;
1776 h2
= custom_smb2_create(tree
, torture
, &(io1
.smb2
));
1778 smb2_util_close(tree
, h2
);
1781 req1
= smb2_notify_send(tree
, &(notify
.smb2
));
1782 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1783 CHECK_STATUS(status
, STATUS_NOTIFY_ENUM_DIR
);
1784 CHECK_VAL(notify
.smb2
.out
.num_changes
, 0);
1787 smb2_deltree(tree
, BASEDIR
);
1792 Test if notifications are returned for changes to the base directory.
1796 static bool torture_smb2_notify_basedir(struct torture_context
*torture
,
1797 struct smb2_tree
*tree1
,
1798 struct smb2_tree
*tree2
)
1802 union smb_notify notify
;
1804 struct smb2_handle h1
;
1805 struct smb2_request
*req1
;
1807 smb2_deltree(tree1
, BASEDIR
);
1808 smb2_util_rmdir(tree1
, BASEDIR
);
1810 torture_comment(torture
, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1812 /* get a handle on the directory */
1813 ZERO_STRUCT(io
.smb2
);
1814 io
.generic
.level
= RAW_OPEN_SMB2
;
1815 io
.smb2
.in
.create_flags
= 0;
1816 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
1817 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1818 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
1819 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1820 NTCREATEX_SHARE_ACCESS_WRITE
;
1821 io
.smb2
.in
.alloc_size
= 0;
1822 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1823 io
.smb2
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1824 io
.smb2
.in
.security_flags
= 0;
1825 io
.smb2
.in
.fname
= BASEDIR
;
1827 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
1828 CHECK_STATUS(status
, NT_STATUS_OK
);
1829 h1
= io
.smb2
.out
.file
.handle
;
1831 /* create a test file that will also be modified */
1832 io
.smb2
.in
.fname
= BASEDIR
"\\tname1";
1833 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_NON_DIRECTORY_FILE
;
1834 status
= smb2_create(tree2
, torture
, &(io
.smb2
));
1835 CHECK_STATUS(status
,NT_STATUS_OK
);
1836 smb2_util_close(tree2
, io
.smb2
.out
.file
.handle
);
1838 /* ask for a change notify, on attribute changes. */
1839 ZERO_STRUCT(notify
.smb2
);
1840 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1841 notify
.smb2
.in
.buffer_size
= 1000;
1842 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
1843 notify
.smb2
.in
.file
.handle
= h1
;
1844 notify
.smb2
.in
.recursive
= true;
1846 req1
= smb2_notify_send(tree1
, &(notify
.smb2
));
1848 /* set attribute on the base dir */
1849 smb2_util_setatr(tree2
, BASEDIR
, FILE_ATTRIBUTE_HIDDEN
);
1851 /* set attribute on a file to assure we receive a notification */
1852 smb2_util_setatr(tree2
, BASEDIR
"\\tname1", FILE_ATTRIBUTE_HIDDEN
);
1855 /* check how many responses were given, expect only 1 for the file */
1856 status
= smb2_notify_recv(req1
, torture
, &(notify
.smb2
));
1857 CHECK_STATUS(status
, NT_STATUS_OK
);
1858 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1859 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
1860 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "tname1");
1863 smb2_deltree(tree1
, BASEDIR
);
1868 very simple change notify test
1870 static bool torture_smb2_notify_tcon(struct torture_context
*torture
,
1871 struct smb2_tree
*tree
)
1875 union smb_notify notify
;
1877 struct smb2_handle h1
;
1878 struct smb2_request
*req
= NULL
;
1879 struct smb2_tree
*tree1
= NULL
;
1880 const char *fname
= BASEDIR
"\\subdir-name";
1882 smb2_deltree(tree
, BASEDIR
);
1883 smb2_util_rmdir(tree
, BASEDIR
);
1885 torture_comment(torture
, "TESTING SIMPLE CHANGE NOTIFY\n");
1888 get a handle on the directory
1891 ZERO_STRUCT(io
.smb2
);
1892 io
.generic
.level
= RAW_OPEN_SMB2
;
1893 io
.smb2
.in
.create_flags
= 0;
1894 io
.smb2
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
1895 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1896 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
|
1897 FILE_ATTRIBUTE_DIRECTORY
;
1898 io
.smb2
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1899 NTCREATEX_SHARE_ACCESS_WRITE
;
1900 io
.smb2
.in
.alloc_size
= 0;
1901 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
1902 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
1903 io
.smb2
.in
.security_flags
= 0;
1904 io
.smb2
.in
.fname
= BASEDIR
;
1906 status
= smb2_create(tree
, torture
, &(io
.smb2
));
1907 CHECK_STATUS(status
, NT_STATUS_OK
);
1908 h1
= io
.smb2
.out
.file
.handle
;
1910 /* ask for a change notify,
1911 on file or directory name changes */
1912 ZERO_STRUCT(notify
.smb2
);
1913 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
1914 notify
.smb2
.in
.buffer_size
= 1000;
1915 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1916 notify
.smb2
.in
.file
.handle
= h1
;
1917 notify
.smb2
.in
.recursive
= true;
1919 torture_comment(torture
, "Testing notify mkdir\n");
1920 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1922 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1923 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1925 notify
.smb2
.in
.recursive
= true;
1926 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1927 status
= smb2_util_mkdir(tree
, fname
);
1928 CHECK_STATUS(status
, NT_STATUS_OK
);
1930 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1931 CHECK_STATUS(status
, NT_STATUS_OK
);
1933 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1934 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
1935 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1937 torture_comment(torture
, "Testing notify rmdir\n");
1938 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1939 status
= smb2_util_rmdir(tree
, fname
);
1940 CHECK_STATUS(status
, NT_STATUS_OK
);
1942 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1943 CHECK_STATUS(status
, NT_STATUS_OK
);
1944 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1945 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
1946 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1948 torture_comment(torture
, "SIMPLE CHANGE NOTIFY OK\n");
1950 torture_comment(torture
, "TESTING WITH SECONDARY TCON\n");
1951 if (!torture_smb2_tree_connect(torture
, tree
->session
, tree
, &tree1
)) {
1952 torture_warning(torture
, "couldn't reconnect to share, bailing\n");
1957 torture_comment(torture
, "tid1=%d tid2=%d\n",
1958 smb2cli_tcon_current_id(tree
->smbXcli
),
1959 smb2cli_tcon_current_id(tree1
->smbXcli
));
1961 torture_comment(torture
, "Testing notify mkdir\n");
1962 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1963 smb2_util_mkdir(tree1
, fname
);
1965 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1966 CHECK_STATUS(status
, NT_STATUS_OK
);
1968 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1969 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
1970 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1972 torture_comment(torture
, "Testing notify rmdir\n");
1973 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1974 smb2_util_rmdir(tree
, fname
);
1976 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1977 CHECK_STATUS(status
, NT_STATUS_OK
);
1978 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1979 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
1980 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
1982 torture_comment(torture
, "CHANGE NOTIFY WITH TCON OK\n");
1984 torture_comment(torture
, "Disconnecting secondary tree\n");
1985 status
= smb2_tdis(tree1
);
1986 CHECK_STATUS(status
, NT_STATUS_OK
);
1989 torture_comment(torture
, "Testing notify mkdir\n");
1990 req
= smb2_notify_send(tree
, &(notify
.smb2
));
1991 smb2_util_mkdir(tree
, fname
);
1993 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
1994 CHECK_STATUS(status
, NT_STATUS_OK
);
1996 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
1997 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
1998 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2000 torture_comment(torture
, "Testing notify rmdir\n");
2001 req
= smb2_notify_send(tree
, &(notify
.smb2
));
2002 smb2_util_rmdir(tree
, fname
);
2004 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2005 CHECK_STATUS(status
, NT_STATUS_OK
);
2006 CHECK_VAL(notify
.smb2
.out
.num_changes
, 1);
2007 CHECK_VAL(notify
.smb2
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
2008 CHECK_WIRE_STR(notify
.smb2
.out
.changes
[0].name
, "subdir-name");
2010 torture_comment(torture
, "CHANGE NOTIFY WITH TDIS OK\n");
2012 smb2_util_close(tree
, h1
);
2013 smb2_deltree(tree
, BASEDIR
);
2018 static bool torture_smb2_notify_rmdir(struct torture_context
*torture
,
2019 struct smb2_tree
*tree1
,
2020 struct smb2_tree
*tree2
,
2021 bool initial_delete_on_close
)
2025 union smb_notify notify
= {};
2026 union smb_setfileinfo sfinfo
= {};
2027 union smb_open io
= {};
2028 struct smb2_handle h
= {};
2029 struct smb2_request
*req
;
2031 torture_comment(torture
, "TESTING NOTIFY CANCEL FOR DELETED DIR\n");
2033 smb2_deltree(tree1
, BASEDIR
);
2034 smb2_util_rmdir(tree1
, BASEDIR
);
2036 ZERO_STRUCT(io
.smb2
);
2037 io
.generic
.level
= RAW_OPEN_SMB2
;
2038 io
.smb2
.in
.create_flags
= 0;
2039 io
.smb2
.in
.desired_access
= SEC_FILE_ALL
;
2040 io
.smb2
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2041 io
.smb2
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
2042 io
.smb2
.in
.share_access
=
2043 NTCREATEX_SHARE_ACCESS_READ
|
2044 NTCREATEX_SHARE_ACCESS_WRITE
|
2045 NTCREATEX_SHARE_ACCESS_DELETE
;
2046 io
.smb2
.in
.alloc_size
= 0;
2047 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_CREATE
;
2048 io
.smb2
.in
.impersonation_level
= SMB2_IMPERSONATION_ANONYMOUS
;
2049 io
.smb2
.in
.security_flags
= 0;
2050 io
.smb2
.in
.fname
= BASEDIR
;
2052 status
= smb2_create(tree1
, torture
, &(io
.smb2
));
2053 CHECK_STATUS(status
, NT_STATUS_OK
);
2054 h
= io
.smb2
.out
.file
.handle
;
2056 ZERO_STRUCT(notify
.smb2
);
2057 notify
.smb2
.level
= RAW_NOTIFY_SMB2
;
2058 notify
.smb2
.in
.buffer_size
= 1000;
2059 notify
.smb2
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
2060 notify
.smb2
.in
.file
.handle
= h
;
2061 notify
.smb2
.in
.recursive
= false;
2063 io
.smb2
.in
.desired_access
|= SEC_STD_DELETE
;
2064 io
.smb2
.in
.create_disposition
= NTCREATEX_DISP_OPEN
;
2065 req
= smb2_notify_send(tree1
, &(notify
.smb2
));
2067 if (initial_delete_on_close
) {
2068 status
= smb2_util_rmdir(tree2
, BASEDIR
);
2069 CHECK_STATUS(status
, NT_STATUS_OK
);
2071 status
= smb2_create(tree2
, torture
, &(io
.smb2
));
2072 CHECK_STATUS(status
, NT_STATUS_OK
);
2074 sfinfo
.generic
.level
= RAW_SFILEINFO_DISPOSITION_INFORMATION
;
2075 sfinfo
.generic
.in
.file
.handle
= io
.smb2
.out
.file
.handle
;
2076 sfinfo
.disposition_info
.in
.delete_on_close
= 1;
2077 status
= smb2_setinfo_file(tree2
, &sfinfo
);
2078 CHECK_STATUS(status
, NT_STATUS_OK
);
2080 smb2_util_close(tree2
, io
.smb2
.out
.file
.handle
);
2083 status
= smb2_notify_recv(req
, torture
, &(notify
.smb2
));
2084 CHECK_STATUS(status
, NT_STATUS_DELETE_PENDING
);
2088 smb2_util_close(tree1
, h
);
2089 smb2_deltree(tree1
, BASEDIR
);
2094 static bool torture_smb2_notify_rmdir1(struct torture_context
*torture
,
2095 struct smb2_tree
*tree
)
2097 return torture_smb2_notify_rmdir(torture
, tree
, tree
, false);
2100 static bool torture_smb2_notify_rmdir2(struct torture_context
*torture
,
2101 struct smb2_tree
*tree
)
2103 return torture_smb2_notify_rmdir(torture
, tree
, tree
, true);
2106 static bool torture_smb2_notify_rmdir3(struct torture_context
*torture
,
2107 struct smb2_tree
*tree1
,
2108 struct smb2_tree
*tree2
)
2110 return torture_smb2_notify_rmdir(torture
, tree1
, tree2
, false);
2113 static bool torture_smb2_notify_rmdir4(struct torture_context
*torture
,
2114 struct smb2_tree
*tree1
,
2115 struct smb2_tree
*tree2
)
2117 return torture_smb2_notify_rmdir(torture
, tree1
, tree2
, true);
2121 basic testing of SMB2 change notify
2123 struct torture_suite
*torture_smb2_notify_init(void)
2125 struct torture_suite
*suite
= torture_suite_create(talloc_autofree_context(), "notify");
2127 torture_suite_add_1smb2_test(suite
, "valid-req", test_valid_request
);
2128 torture_suite_add_1smb2_test(suite
, "tcon", torture_smb2_notify_tcon
);
2129 torture_suite_add_2smb2_test(suite
, "dir", torture_smb2_notify_dir
);
2130 torture_suite_add_2smb2_test(suite
, "mask", torture_smb2_notify_mask
);
2131 torture_suite_add_1smb2_test(suite
, "tdis", torture_smb2_notify_tree_disconnect
);
2132 torture_suite_add_1smb2_test(suite
, "tdis1", torture_smb2_notify_tree_disconnect_1
);
2133 torture_suite_add_2smb2_test(suite
, "mask-change", torture_smb2_notify_mask_change
);
2134 torture_suite_add_1smb2_test(suite
, "logoff", torture_smb2_notify_ulogoff
);
2135 torture_suite_add_1smb2_test(suite
, "tree", torture_smb2_notify_tree
);
2136 torture_suite_add_2smb2_test(suite
, "basedir", torture_smb2_notify_basedir
);
2137 torture_suite_add_2smb2_test(suite
, "double", torture_smb2_notify_double
);
2138 torture_suite_add_1smb2_test(suite
, "file", torture_smb2_notify_file
);
2139 torture_suite_add_1smb2_test(suite
, "tcp", torture_smb2_notify_tcp_disconnect
);
2140 torture_suite_add_2smb2_test(suite
, "rec", torture_smb2_notify_recursive
);
2141 torture_suite_add_1smb2_test(suite
, "overflow", torture_smb2_notify_overflow
);
2142 torture_suite_add_1smb2_test(suite
, "rmdir1",
2143 torture_smb2_notify_rmdir1
);
2144 torture_suite_add_1smb2_test(suite
, "rmdir2",
2145 torture_smb2_notify_rmdir2
);
2146 torture_suite_add_2smb2_test(suite
, "rmdir3",
2147 torture_smb2_notify_rmdir3
);
2148 torture_suite_add_2smb2_test(suite
, "rmdir4",
2149 torture_smb2_notify_rmdir4
);
2151 suite
->description
= talloc_strdup(suite
, "SMB2-NOTIFY tests");