s3-selftest: Remove some unnecessary comma
[Samba/gebeck_regimport.git] / source4 / torture / smb2 / notify.c
blobe4e26365e3c223070126ee23a7b171e7f1516d25
1 /*
2 Unix SMB/CIFS implementation.
4 SMB2 notify test suite
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/>.
23 #include "includes.h"
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)); \
49 ret = false; \
50 goto done; \
51 }} while (0)
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); \
58 ret = false; \
59 goto done; \
60 }} while (0)
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, \
66 field.s, value); \
67 ret = false; \
68 goto done; \
69 }} while (0)
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)
77 bool ret = true;
78 NTSTATUS status;
79 struct smb2_handle dh;
80 struct smb2_notify n;
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
92 * pre-Win7 */
93 max_buffer_size = torture_setting_ulong(torture, "cn_max_buffer_size",
94 0x00080000);
96 n.in.recursive = 0x0000;
97 n.in.buffer_size = max_buffer_size;
98 n.in.file.handle = dh;
99 n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
100 n.in.unknown = 0x00000000;
101 req = smb2_notify_send(tree, &n);
103 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
104 if (tevent_loop_once(torture->ev) != 0) {
105 break;
109 status = torture_setup_complex_file(tree, FNAME);
110 CHECK_STATUS(status, NT_STATUS_OK);
112 status = smb2_notify_recv(req, torture, &n);
113 CHECK_STATUS(status, NT_STATUS_OK);
114 CHECK_VAL(n.out.num_changes, 1);
115 CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_ADDED);
116 CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
119 * if the change response doesn't fit in the buffer
120 * NOTIFY_ENUM_DIR is returned.
122 n.in.buffer_size = 0x00000000;
123 req = smb2_notify_send(tree, &n);
125 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
126 if (tevent_loop_once(torture->ev) != 0) {
127 break;
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
139 * NT_STATUS_OK again
141 n.in.buffer_size = max_buffer_size;
142 req = smb2_notify_send(tree, &n);
144 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
145 if (tevent_loop_once(torture->ev) != 0) {
146 break;
150 status = torture_setup_complex_file(tree, FNAME);
151 CHECK_STATUS(status, NT_STATUS_OK);
153 status = smb2_notify_recv(req, torture, &n);
154 CHECK_STATUS(status, NT_STATUS_OK);
155 CHECK_VAL(n.out.num_changes, 3);
156 CHECK_VAL(n.out.changes[0].action, NOTIFY_ACTION_REMOVED);
157 CHECK_WIRE_STR(n.out.changes[0].name, FNAME);
158 CHECK_VAL(n.out.changes[1].action, NOTIFY_ACTION_ADDED);
159 CHECK_WIRE_STR(n.out.changes[1].name, FNAME);
160 CHECK_VAL(n.out.changes[2].action, NOTIFY_ACTION_MODIFIED);
161 CHECK_WIRE_STR(n.out.changes[2].name, FNAME);
163 /* if the first notify returns NOTIFY_ENUM_DIR, all do */
164 status = smb2_util_close(tree, dh);
165 CHECK_STATUS(status, NT_STATUS_OK);
166 status = smb2_util_roothandle(tree, &dh);
167 CHECK_STATUS(status, NT_STATUS_OK);
169 n.in.recursive = 0x0000;
170 n.in.buffer_size = 0x00000001;
171 n.in.file.handle = dh;
172 n.in.completion_filter = FILE_NOTIFY_CHANGE_ALL;
173 n.in.unknown = 0x00000000;
174 req = smb2_notify_send(tree, &n);
176 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
177 if (tevent_loop_once(torture->ev) != 0) {
178 break;
182 status = torture_setup_complex_file(tree, FNAME);
183 CHECK_STATUS(status, NT_STATUS_OK);
185 status = smb2_notify_recv(req, torture, &n);
186 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
188 n.in.buffer_size = max_buffer_size;
189 req = smb2_notify_send(tree, &n);
190 while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) {
191 if (tevent_loop_once(torture->ev) != 0) {
192 break;
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);
212 done:
213 return ret;
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)
223 bool ret = true;
224 NTSTATUS status;
225 union smb_notify notify;
226 union smb_open io;
227 union smb_close cl;
228 int i, count;
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));
277 smb2_cancel(req);
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);
311 smb_msleep(200);
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",
351 fname);
352 ret = false;
353 goto done;
355 h12 = io.smb2.out.file.handle;
356 talloc_free(fname2);
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);
411 talloc_free(fname2);
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;
424 sleep(3);
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);
459 done:
460 smb2_util_close(tree1, h1);
461 smb2_util_close(tree1, h2);
462 smb2_deltree(tree1, BASEDIR);
463 return ret;
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;
471 bool ret = true;
472 NTSTATUS status;
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;
477 done:
478 return h1;
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)
489 bool ret = true;
490 NTSTATUS status;
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));
535 smb2_cancel(req1);
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));
541 smb2_cancel(req2);
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|
550 SEC_RIGHTS_FILE_ALL;
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);
568 ZERO_STRUCT(sinfo);
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);
582 ZERO_STRUCT(sinfo);
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);
595 ZERO_STRUCT(sinfo);
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;
606 smb_msleep(200);
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");
642 done:
643 smb2_deltree(tree1, BASEDIR);
644 return ret;
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)
655 bool ret = true;
656 NTSTATUS status;
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));
700 smb2_cancel(req1);
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));
708 smb2_cancel(req2);
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|
721 SEC_RIGHTS_FILE_ALL;
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);
766 ZERO_STRUCT(sinfo);
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");
823 if (!ret) {
824 goto done;
827 done:
828 smb2_deltree(tree1, BASEDIR);
829 return ret;
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)
840 bool ret = true;
841 NTSTATUS status;
842 union smb_notify notify;
843 union smb_open io, io1;
844 struct smb2_handle h1, h2;
845 uint32_t mask;
846 int i;
847 char c = 1;
848 union smb_setfileinfo sinfo;
850 smb2_deltree(tree1, BASEDIR);
851 smb2_util_rmdir(tree1, BASEDIR);
853 torture_comment(torture, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
857 get a handle on the directory
859 ZERO_STRUCT(io.smb2);
860 io.generic.level = RAW_OPEN_SMB2;
861 io.smb2.in.create_flags = 0;
862 io.smb2.in.desired_access = SEC_FILE_ALL;
863 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
864 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
865 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
866 NTCREATEX_SHARE_ACCESS_WRITE;
867 io.smb2.in.alloc_size = 0;
868 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
869 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
870 io.smb2.in.security_flags = 0;
871 io.smb2.in.fname = BASEDIR;
873 ZERO_STRUCT(notify.smb2);
874 notify.smb2.level = RAW_NOTIFY_SMB2;
875 notify.smb2.in.buffer_size = 1000;
876 notify.smb2.in.recursive = true;
878 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, \
879 expected, nchanges) \
880 do { \
881 do { for (mask=i=0;i<32;i++) { \
882 struct smb2_request *req; \
883 status = smb2_create(tree1, torture, &(io.smb2)); \
884 CHECK_STATUS(status, NT_STATUS_OK); \
885 h1 = io.smb2.out.file.handle; \
886 setup \
887 notify.smb2.in.file.handle = h1; \
888 notify.smb2.in.completion_filter = (1<<i); \
889 /* cancel initial requests so the buffer is setup */ \
890 req = smb2_notify_send(tree1, &(notify.smb2)); \
891 smb2_cancel(req); \
892 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
893 CHECK_STATUS(status, NT_STATUS_CANCELLED); \
894 /* send the change notify request */ \
895 req = smb2_notify_send(tree1, &(notify.smb2)); \
896 op \
897 smb_msleep(200); smb2_cancel(req); \
898 status = smb2_notify_recv(req, torture, &(notify.smb2)); \
899 cleanup \
900 smb2_util_close(tree1, h1); \
901 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
902 CHECK_STATUS(status, NT_STATUS_OK); \
903 /* special case to cope with file rename behaviour */ \
904 if (nchanges == 2 && notify.smb2.out.num_changes == 1 && \
905 notify.smb2.out.changes[0].action == \
906 NOTIFY_ACTION_MODIFIED && \
907 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
908 Action == NOTIFY_ACTION_OLD_NAME) { \
909 torture_comment(torture, \
910 "(rename file special handling OK)\n"); \
911 } else if (nchanges != notify.smb2.out.num_changes) { \
912 torture_result(torture, TORTURE_FAIL, \
913 "ERROR: nchanges=%d expected=%d "\
914 "action=%d filter=0x%08x\n", \
915 notify.smb2.out.num_changes, \
916 nchanges, \
917 notify.smb2.out.changes[0].action, \
918 notify.smb2.in.completion_filter); \
919 ret = false; \
920 } else if (notify.smb2.out.changes[0].action != Action) { \
921 torture_result(torture, TORTURE_FAIL, \
922 "ERROR: nchanges=%d action=%d " \
923 "expectedAction=%d filter=0x%08x\n", \
924 notify.smb2.out.num_changes, \
925 notify.smb2.out.changes[0].action, \
926 Action, \
927 notify.smb2.in.completion_filter); \
928 ret = false; \
929 } else if (strcmp(notify.smb2.out.changes[0].name.s, \
930 "tname1") != 0) { \
931 torture_result(torture, TORTURE_FAIL, \
932 "ERROR: nchanges=%d action=%d " \
933 "filter=0x%08x name=%s\n", \
934 notify.smb2.out.num_changes, \
935 notify.smb2.out.changes[0].action, \
936 notify.smb2.in.completion_filter, \
937 notify.smb2.out.changes[0].name.s); \
938 ret = false; \
940 mask |= (1<<i); \
942 } while (0); \
943 } while (0);
945 torture_comment(torture, "Testing mkdir\n");
946 NOTIFY_MASK_TEST("Testing mkdir",;,
947 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
948 smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
949 NOTIFY_ACTION_ADDED,
950 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
952 torture_comment(torture, "Testing create file\n");
953 ZERO_STRUCT(io1.smb2);
954 io1.generic.level = RAW_OPEN_SMB2;
955 io1.smb2.in.create_flags = 0;
956 io1.smb2.in.desired_access = SEC_FILE_ALL;
957 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
958 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
959 NTCREATEX_SHARE_ACCESS_WRITE;
960 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
961 io1.smb2.in.security_flags = 0;
962 io1.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
963 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
964 io1.smb2.in.fname = BASEDIR "\\tname1";
966 NOTIFY_MASK_TEST("Testing create file",;,
967 smb2_util_close(tree2, custom_smb2_create(tree2,
968 torture, &(io1.smb2)));,
969 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
970 NOTIFY_ACTION_ADDED,
971 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
973 torture_comment(torture, "Testing unlink\n");
974 NOTIFY_MASK_TEST("Testing unlink",
975 smb2_util_close(tree2, custom_smb2_create(tree2,
976 torture, &(io1.smb2)));,
977 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
979 NOTIFY_ACTION_REMOVED,
980 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
982 torture_comment(torture, "Testing rmdir\n");
983 NOTIFY_MASK_TEST("Testing rmdir",
984 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
985 smb2_util_rmdir(tree2, BASEDIR "\\tname1");,
987 NOTIFY_ACTION_REMOVED,
988 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
990 torture_comment(torture, "Testing rename file\n");
991 ZERO_STRUCT(sinfo);
992 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
993 sinfo.rename_information.in.file.handle = h1;
994 sinfo.rename_information.in.overwrite = true;
995 sinfo.rename_information.in.root_fid = 0;
996 sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
997 NOTIFY_MASK_TEST("Testing rename file",
998 smb2_util_close(tree2, custom_smb2_create(tree2,
999 torture, &(io1.smb2)));,
1000 smb2_setinfo_file(tree2, &sinfo);,
1001 smb2_util_unlink(tree2, BASEDIR "\\tname2");,
1002 NOTIFY_ACTION_OLD_NAME,
1003 FILE_NOTIFY_CHANGE_FILE_NAME, 2);
1005 torture_comment(torture, "Testing rename dir\n");
1006 ZERO_STRUCT(sinfo);
1007 sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
1008 sinfo.rename_information.in.file.handle = h1;
1009 sinfo.rename_information.in.overwrite = true;
1010 sinfo.rename_information.in.root_fid = 0;
1011 sinfo.rename_information.in.new_name = BASEDIR "\\tname2";
1012 NOTIFY_MASK_TEST("Testing rename dir",
1013 smb2_util_mkdir(tree2, BASEDIR "\\tname1");,
1014 smb2_setinfo_file(tree2, &sinfo);,
1015 smb2_util_rmdir(tree2, BASEDIR "\\tname2");,
1016 NOTIFY_ACTION_OLD_NAME,
1017 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
1019 torture_comment(torture, "Testing set path attribute\n");
1020 NOTIFY_MASK_TEST("Testing set path attribute",
1021 smb2_util_close(tree2, custom_smb2_create(tree2,
1022 torture, &(io.smb2)));,
1023 smb2_util_setatr(tree2, BASEDIR "\\tname1",
1024 FILE_ATTRIBUTE_HIDDEN);,
1025 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1026 NOTIFY_ACTION_MODIFIED,
1027 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
1029 torture_comment(torture, "Testing set path write time\n");
1030 ZERO_STRUCT(sinfo);
1031 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1032 sinfo.generic.in.file.handle = h1;
1033 sinfo.basic_info.in.write_time = 1000;
1034 NOTIFY_MASK_TEST("Testing set path write time",
1035 smb2_util_close(tree2, custom_smb2_create(tree2,
1036 torture, &(io1.smb2)));,
1037 smb2_setinfo_file(tree2, &sinfo);,
1038 smb2_util_unlink(tree2, BASEDIR "\\tname1");,
1039 NOTIFY_ACTION_MODIFIED,
1040 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
1042 if (torture_setting_bool(torture, "samba3", false)) {
1043 torture_comment(torture,
1044 "Samba3 does not yet support create times "
1045 "everywhere\n");
1047 else {
1048 ZERO_STRUCT(sinfo);
1049 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1050 sinfo.generic.in.file.handle = h1;
1051 sinfo.basic_info.in.create_time = 0;
1052 torture_comment(torture, "Testing set file create time\n");
1053 NOTIFY_MASK_TEST("Testing set file create time",
1054 smb2_create_complex_file(tree2,
1055 BASEDIR "\\tname1", &h2);,
1056 smb2_setinfo_file(tree2, &sinfo);,
1057 (smb2_util_close(tree2, h2),
1058 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1059 NOTIFY_ACTION_MODIFIED,
1060 FILE_NOTIFY_CHANGE_CREATION, 1);
1063 ZERO_STRUCT(sinfo);
1064 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1065 sinfo.generic.in.file.handle = h1;
1066 sinfo.basic_info.in.access_time = 0;
1067 torture_comment(torture, "Testing set file access time\n");
1068 NOTIFY_MASK_TEST("Testing set file access time",
1069 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1070 smb2_setinfo_file(tree2, &sinfo);,
1071 (smb2_util_close(tree2, h2),
1072 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1073 NOTIFY_ACTION_MODIFIED,
1074 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
1076 ZERO_STRUCT(sinfo);
1077 sinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION;
1078 sinfo.generic.in.file.handle = h1;
1079 sinfo.basic_info.in.change_time = 0;
1080 torture_comment(torture, "Testing set file change time\n");
1081 NOTIFY_MASK_TEST("Testing set file change time",
1082 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1083 smb2_setinfo_file(tree2, &sinfo);,
1084 (smb2_util_close(tree2, h2),
1085 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1086 NOTIFY_ACTION_MODIFIED,
1087 0, 1);
1090 torture_comment(torture, "Testing write\n");
1091 NOTIFY_MASK_TEST("Testing write",
1092 smb2_create_complex_file(tree2, BASEDIR "\\tname1", &h2);,
1093 smb2_util_write(tree2, h2, &c, 10000, 1);,
1094 (smb2_util_close(tree2, h2),
1095 smb2_util_unlink(tree2, BASEDIR "\\tname1"));,
1096 NOTIFY_ACTION_MODIFIED,
1097 0, 1);
1099 done:
1100 smb2_deltree(tree1, BASEDIR);
1101 return ret;
1105 basic testing of change notify on files
1107 static bool torture_smb2_notify_file(struct torture_context *torture,
1108 struct smb2_tree *tree)
1110 NTSTATUS status;
1111 bool ret = true;
1112 union smb_open io;
1113 union smb_close cl;
1114 union smb_notify notify;
1115 struct smb2_request *req;
1116 struct smb2_handle h1;
1117 const char *fname = BASEDIR "\\file.txt";
1119 smb2_deltree(tree, BASEDIR);
1120 smb2_util_rmdir(tree, BASEDIR);
1122 torture_comment(torture, "TESTING CHANGE NOTIFY ON FILES\n");
1123 status = torture_smb2_testdir(tree, BASEDIR, &h1);
1124 CHECK_STATUS(status, NT_STATUS_OK);
1126 ZERO_STRUCT(io.smb2);
1127 io.generic.level = RAW_OPEN_SMB2;
1128 io.smb2.in.create_flags = 0;
1129 io.smb2.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
1130 io.smb2.in.create_options = 0;
1131 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1132 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1133 NTCREATEX_SHARE_ACCESS_WRITE;
1134 io.smb2.in.alloc_size = 0;
1135 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1136 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1137 io.smb2.in.security_flags = 0;
1138 io.smb2.in.fname = fname;
1139 status = smb2_create(tree, torture, &(io.smb2));
1140 CHECK_STATUS(status, NT_STATUS_OK);
1141 h1 = io.smb2.out.file.handle;
1143 /* ask for a change notify,
1144 on file or directory name changes */
1145 ZERO_STRUCT(notify.smb2);
1146 notify.smb2.level = RAW_NOTIFY_SMB2;
1147 notify.smb2.in.file.handle = h1;
1148 notify.smb2.in.buffer_size = 1000;
1149 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
1150 notify.smb2.in.recursive = false;
1152 torture_comment(torture,
1153 "Testing if notifies on file handles are invalid (should be)\n");
1155 req = smb2_notify_send(tree, &(notify.smb2));
1156 status = smb2_notify_recv(req, torture, &(notify.smb2));
1157 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
1159 ZERO_STRUCT(cl.smb2);
1160 cl.close.level = RAW_CLOSE_SMB2;
1161 cl.close.in.file.handle = h1;
1162 status = smb2_close(tree, &(cl.smb2));
1163 CHECK_STATUS(status, NT_STATUS_OK);
1165 status = smb2_util_unlink(tree, fname);
1166 CHECK_STATUS(status, NT_STATUS_OK);
1168 done:
1169 smb2_deltree(tree, BASEDIR);
1170 return ret;
1173 basic testing of change notifies followed by a tdis
1176 static bool torture_smb2_notify_tree_disconnect(
1177 struct torture_context *torture,
1178 struct smb2_tree *tree)
1180 bool ret = true;
1181 NTSTATUS status;
1182 union smb_notify notify;
1183 union smb_open io;
1184 struct smb2_handle h1;
1185 struct smb2_request *req;
1187 smb2_deltree(tree, BASEDIR);
1188 smb2_util_rmdir(tree, BASEDIR);
1190 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY "
1191 "TREE-DISCONNECT\n");
1194 get a handle on the directory
1196 ZERO_STRUCT(io.smb2);
1197 io.generic.level = RAW_OPEN_SMB2;
1198 io.smb2.in.create_flags = 0;
1199 io.smb2.in.desired_access = SEC_FILE_ALL;
1200 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1201 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1202 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1203 NTCREATEX_SHARE_ACCESS_WRITE;
1204 io.smb2.in.alloc_size = 0;
1205 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1206 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1207 io.smb2.in.security_flags = 0;
1208 io.smb2.in.fname = BASEDIR;
1210 status = smb2_create(tree, torture, &(io.smb2));
1211 CHECK_STATUS(status, NT_STATUS_OK);
1212 h1 = io.smb2.out.file.handle;
1214 /* ask for a change notify,
1215 on file or directory name changes */
1216 ZERO_STRUCT(notify.smb2);
1217 notify.smb2.level = RAW_NOTIFY_SMB2;
1218 notify.smb2.in.buffer_size = 1000;
1219 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1220 notify.smb2.in.file.handle = h1;
1221 notify.smb2.in.recursive = true;
1223 req = smb2_notify_send(tree, &(notify.smb2));
1224 smb2_cancel(req);
1225 status = smb2_notify_recv(req, torture, &(notify.smb2));
1227 status = smb2_tdis(tree);
1228 CHECK_STATUS(status, NT_STATUS_OK);
1230 req = smb2_notify_send(tree, &(notify.smb2));
1232 smb2_notify_recv(req, torture, &(notify.smb2));
1233 CHECK_STATUS(status, NT_STATUS_OK);
1234 CHECK_VAL(notify.smb2.out.num_changes, 0);
1236 done:
1237 smb2_deltree(tree, BASEDIR);
1238 return ret;
1242 basic testing of change notifies followed by a ulogoff
1245 static bool torture_smb2_notify_ulogoff(struct torture_context *torture,
1246 struct smb2_tree *tree1,
1247 struct smb2_tree *tree2)
1249 bool ret = true;
1250 NTSTATUS status;
1251 union smb_notify notify;
1252 union smb_open io;
1253 struct smb2_handle h1;
1254 struct smb2_request *req;
1256 smb2_deltree(tree1, BASEDIR);
1257 smb2_util_rmdir(tree1, BASEDIR);
1259 torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1262 get a handle on the directory
1264 ZERO_STRUCT(io.smb2);
1265 io.generic.level = RAW_OPEN_SMB2;
1266 io.smb2.in.create_flags = 0;
1267 io.smb2.in.desired_access = SEC_FILE_ALL;
1268 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1269 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1270 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1271 NTCREATEX_SHARE_ACCESS_WRITE;
1272 io.smb2.in.alloc_size = 0;
1273 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1274 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1275 io.smb2.in.security_flags = 0;
1276 io.smb2.in.fname = BASEDIR;
1278 status = smb2_create(tree2, torture, &(io.smb2));
1279 CHECK_STATUS(status, NT_STATUS_OK);
1281 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
1282 status = smb2_create(tree2, torture, &(io.smb2));
1283 CHECK_STATUS(status, NT_STATUS_OK);
1284 h1 = io.smb2.out.file.handle;
1286 /* ask for a change notify,
1287 on file or directory name changes */
1288 ZERO_STRUCT(notify.smb2);
1289 notify.smb2.level = RAW_NOTIFY_SMB2;
1290 notify.smb2.in.buffer_size = 1000;
1291 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1292 notify.smb2.in.file.handle = h1;
1293 notify.smb2.in.recursive = true;
1295 req = smb2_notify_send(tree1, &(notify.smb2));
1297 status = smb2_logoff(tree2->session);
1298 CHECK_STATUS(status, NT_STATUS_OK);
1300 status = smb2_notify_recv(req, torture, &(notify.smb2));
1301 CHECK_VAL(notify.smb2.out.num_changes, 0);
1303 done:
1304 smb2_deltree(tree1, BASEDIR);
1305 return ret;
1308 static void tcp_dis_handler(struct smb2_transport *t, void *p)
1310 struct smb2_tree *tree = (struct smb2_tree *)p;
1311 smb2_transport_dead(tree->session->transport,
1312 NT_STATUS_LOCAL_DISCONNECT);
1313 t = NULL;
1314 tree = NULL;
1318 basic testing of change notifies followed by tcp disconnect
1321 static bool torture_smb2_notify_tcp_disconnect(
1322 struct torture_context *torture,
1323 struct smb2_tree *tree)
1325 bool ret = true;
1326 NTSTATUS status;
1327 union smb_notify notify;
1328 union smb_open io;
1329 struct smb2_handle h1;
1330 struct smb2_request *req;
1332 smb2_deltree(tree, BASEDIR);
1333 smb2_util_rmdir(tree, BASEDIR);
1335 torture_comment(torture,
1336 "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1339 get a handle on the directory
1341 ZERO_STRUCT(io.smb2);
1342 io.generic.level = RAW_OPEN_SMB2;
1343 io.smb2.in.create_flags = 0;
1344 io.smb2.in.desired_access = SEC_FILE_ALL;
1345 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1346 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1347 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1348 NTCREATEX_SHARE_ACCESS_WRITE;
1349 io.smb2.in.alloc_size = 0;
1350 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1351 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1352 io.smb2.in.security_flags = 0;
1353 io.smb2.in.fname = BASEDIR;
1355 status = smb2_create(tree, torture, &(io.smb2));
1356 CHECK_STATUS(status, NT_STATUS_OK);
1357 h1 = io.smb2.out.file.handle;
1359 /* ask for a change notify,
1360 on file or directory name changes */
1361 ZERO_STRUCT(notify.smb2);
1362 notify.smb2.level = RAW_NOTIFY_SMB2;
1363 notify.smb2.in.buffer_size = 1000;
1364 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1365 notify.smb2.in.file.handle = h1;
1366 notify.smb2.in.recursive = true;
1368 req = smb2_notify_send(tree, &(notify.smb2));
1369 smb2_cancel(req);
1370 status = smb2_notify_recv(req, torture, &(notify.smb2));
1371 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1373 notify.smb2.in.recursive = true;
1374 req = smb2_notify_send(tree, &(notify.smb2));
1375 smb2_transport_idle_handler(tree->session->transport,
1376 tcp_dis_handler, 250, tree);
1377 tree = NULL;
1378 status = smb2_notify_recv(req, torture, &(notify.smb2));
1379 CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1381 done:
1382 return ret;
1386 test setting up two change notify requests on one handle
1389 static bool torture_smb2_notify_double(struct torture_context *torture,
1390 struct smb2_tree *tree1,
1391 struct smb2_tree *tree2)
1393 bool ret = true;
1394 NTSTATUS status;
1395 union smb_notify notify;
1396 union smb_open io;
1397 struct smb2_handle h1;
1398 struct smb2_request *req1, *req2;
1400 smb2_deltree(tree1, BASEDIR);
1401 smb2_util_rmdir(tree1, BASEDIR);
1403 torture_comment(torture,
1404 "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1407 get a handle on the directory
1409 ZERO_STRUCT(io.smb2);
1410 io.generic.level = RAW_OPEN_SMB2;
1411 io.smb2.in.create_flags = 0;
1412 io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ|
1413 SEC_RIGHTS_FILE_WRITE|
1414 SEC_RIGHTS_FILE_ALL;
1415 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1416 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1417 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1418 NTCREATEX_SHARE_ACCESS_WRITE;
1419 io.smb2.in.alloc_size = 0;
1420 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1421 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1422 io.smb2.in.security_flags = 0;
1423 io.smb2.in.fname = BASEDIR;
1425 status = smb2_create(tree1, torture, &(io.smb2));
1426 CHECK_STATUS(status, NT_STATUS_OK);
1427 h1 = io.smb2.out.file.handle;
1429 /* ask for a change notify,
1430 on file or directory name changes */
1431 ZERO_STRUCT(notify.smb2);
1432 notify.smb2.level = RAW_NOTIFY_SMB2;
1433 notify.smb2.in.buffer_size = 1000;
1434 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1435 notify.smb2.in.file.handle = h1;
1436 notify.smb2.in.recursive = true;
1438 req1 = smb2_notify_send(tree1, &(notify.smb2));
1439 smb2_cancel(req1);
1440 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1441 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1443 req2 = smb2_notify_send(tree1, &(notify.smb2));
1444 smb2_cancel(req2);
1445 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1446 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1448 smb2_util_mkdir(tree2, BASEDIR "\\subdir-name");
1449 req1 = smb2_notify_send(tree1, &(notify.smb2));
1450 req2 = smb2_notify_send(tree1, &(notify.smb2));
1452 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1453 CHECK_STATUS(status, NT_STATUS_OK);
1454 CHECK_VAL(notify.smb2.out.num_changes, 1);
1455 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name");
1457 smb2_util_mkdir(tree2, BASEDIR "\\subdir-name2");
1459 status = smb2_notify_recv(req2, torture, &(notify.smb2));
1460 CHECK_STATUS(status, NT_STATUS_OK);
1461 CHECK_VAL(notify.smb2.out.num_changes, 1);
1462 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "subdir-name2");
1464 done:
1465 smb2_deltree(tree1, BASEDIR);
1466 return ret;
1471 test multiple change notifies at different depths and with/without recursion
1474 static bool torture_smb2_notify_tree(struct torture_context *torture,
1475 struct smb2_tree *tree)
1477 bool ret = true;
1478 union smb_notify notify;
1479 union smb_open io;
1480 struct smb2_request *req;
1481 struct timeval tv;
1482 struct {
1483 const char *path;
1484 bool recursive;
1485 uint32_t filter;
1486 int expected;
1487 struct smb2_handle h1;
1488 int counted;
1489 } dirs[] = {
1490 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 30 },
1491 {BASEDIR "\\zqy", true, FILE_NOTIFY_CHANGE_NAME, 8 },
1492 {BASEDIR "\\atsy", true, FILE_NOTIFY_CHANGE_NAME, 4 },
1493 {BASEDIR "\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1494 {BASEDIR "\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME, 13 },
1495 {BASEDIR "\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME, 7 },
1496 {BASEDIR "\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1497 {BASEDIR "\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1498 {BASEDIR "\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1499 {BASEDIR "\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1500 {BASEDIR "\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1501 {BASEDIR "\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1502 {BASEDIR "\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME, 40 },
1503 {BASEDIR, true, FILE_NOTIFY_CHANGE_NAME, 40 },
1504 {BASEDIR, false,FILE_NOTIFY_CHANGE_NAME, 6 },
1505 {BASEDIR "\\atsy", false,FILE_NOTIFY_CHANGE_NAME, 4 },
1506 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1507 {BASEDIR "\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1508 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1509 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1511 int i;
1512 NTSTATUS status;
1513 bool all_done = false;
1515 smb2_deltree(tree, BASEDIR);
1516 smb2_util_rmdir(tree, BASEDIR);
1518 torture_comment(torture, "TESTING NOTIFY FOR DIFFERENT DEPTHS\n");
1520 ZERO_STRUCT(io.smb2);
1521 io.generic.level = RAW_OPEN_SMB2;
1522 io.smb2.in.create_flags = 0;
1523 io.smb2.in.desired_access = SEC_FILE_ALL;
1524 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1525 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1526 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1527 NTCREATEX_SHARE_ACCESS_WRITE;
1528 io.smb2.in.alloc_size = 0;
1529 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1530 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1531 io.smb2.in.security_flags = 0;
1532 io.smb2.in.fname = BASEDIR;
1533 status = smb2_create(tree, torture, &(io.smb2));
1534 CHECK_STATUS(status, NT_STATUS_OK);
1536 ZERO_STRUCT(notify.smb2);
1537 notify.smb2.level = RAW_NOTIFY_SMB2;
1538 notify.smb2.in.buffer_size = 20000;
1541 setup the directory tree, and the notify buffer on each directory
1543 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1544 io.smb2.in.fname = dirs[i].path;
1545 status = smb2_create(tree, torture, &(io.smb2));
1546 CHECK_STATUS(status, NT_STATUS_OK);
1547 dirs[i].h1 = io.smb2.out.file.handle;
1549 notify.smb2.in.completion_filter = dirs[i].filter;
1550 notify.smb2.in.file.handle = dirs[i].h1;
1551 notify.smb2.in.recursive = dirs[i].recursive;
1552 req = smb2_notify_send(tree, &(notify.smb2));
1553 smb2_cancel(req);
1554 status = smb2_notify_recv(req, torture, &(notify.smb2));
1555 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1558 /* trigger 2 events in each dir */
1559 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1560 char *path = talloc_asprintf(torture, "%s\\test.dir",
1561 dirs[i].path);
1562 smb2_util_mkdir(tree, path);
1563 smb2_util_rmdir(tree, path);
1564 talloc_free(path);
1567 /* give a bit of time for the events to propogate */
1568 tv = timeval_current();
1570 do {
1571 /* count events that have happened in each dir */
1572 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1573 notify.smb2.in.file.handle = dirs[i].h1;
1574 req = smb2_notify_send(tree, &(notify.smb2));
1575 smb2_cancel(req);
1576 notify.smb2.out.num_changes = 0;
1577 status = smb2_notify_recv(req, torture,
1578 &(notify.smb2));
1579 dirs[i].counted += notify.smb2.out.num_changes;
1582 all_done = true;
1584 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1585 if (dirs[i].counted != dirs[i].expected) {
1586 all_done = false;
1589 } while (!all_done && timeval_elapsed(&tv) < 20);
1591 torture_comment(torture, "took %.4f seconds to propogate all events\n",
1592 timeval_elapsed(&tv));
1594 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1595 if (dirs[i].counted != dirs[i].expected) {
1596 torture_comment(torture,
1597 "ERROR: i=%d expected %d got %d for '%s'\n",
1598 i, dirs[i].expected, dirs[i].counted,
1599 dirs[i].path);
1600 ret = false;
1605 run from the back, closing and deleting
1607 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1608 smb2_util_close(tree, dirs[i].h1);
1609 smb2_util_rmdir(tree, dirs[i].path);
1612 done:
1613 smb2_deltree(tree, BASEDIR);
1614 smb2_util_rmdir(tree, BASEDIR);
1615 return ret;
1619 Test response when cached server events exceed single NT NOTFIY response
1620 packet size.
1623 static bool torture_smb2_notify_overflow(struct torture_context *torture,
1624 struct smb2_tree *tree)
1626 bool ret = true;
1627 NTSTATUS status;
1628 union smb_notify notify;
1629 union smb_open io;
1630 struct smb2_handle h1, h2;
1631 int count = 100;
1632 struct smb2_request *req1;
1633 int i;
1635 smb2_deltree(tree, BASEDIR);
1636 smb2_util_rmdir(tree, BASEDIR);
1638 torture_comment(torture, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1640 /* get a handle on the directory */
1641 ZERO_STRUCT(io.smb2);
1642 io.generic.level = RAW_OPEN_SMB2;
1643 io.smb2.in.create_flags = 0;
1644 io.smb2.in.desired_access = SEC_FILE_ALL;
1645 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1646 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1647 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1648 NTCREATEX_SHARE_ACCESS_WRITE;
1649 io.smb2.in.alloc_size = 0;
1650 io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1651 io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1652 io.smb2.in.security_flags = 0;
1653 io.smb2.in.fname = BASEDIR;
1655 status = smb2_create(tree, torture, &(io.smb2));
1656 CHECK_STATUS(status, NT_STATUS_OK);
1657 h1 = io.smb2.out.file.handle;
1659 /* ask for a change notify, on name changes. */
1660 ZERO_STRUCT(notify.smb2);
1661 notify.smb2.level = RAW_NOTIFY_NTTRANS;
1662 notify.smb2.in.buffer_size = 1000;
1663 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1664 notify.smb2.in.file.handle = h1;
1666 notify.smb2.in.recursive = true;
1667 req1 = smb2_notify_send(tree, &(notify.smb2));
1669 /* cancel initial requests so the buffer is setup */
1670 smb2_cancel(req1);
1671 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1672 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1674 /* open a lot of files, filling up the server side notify buffer */
1675 torture_comment(torture,
1676 "Testing overflowed buffer notify on create of %d files\n",
1677 count);
1679 for (i=0;i<count;i++) {
1680 char *fname = talloc_asprintf(torture,
1681 BASEDIR "\\test%d.txt", i);
1682 union smb_open io1;
1683 ZERO_STRUCT(io1.smb2);
1684 io1.generic.level = RAW_OPEN_SMB2;
1685 io1.smb2.in.create_flags = 0;
1686 io1.smb2.in.desired_access = SEC_FILE_ALL;
1687 io1.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1688 io1.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1689 io1.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1690 NTCREATEX_SHARE_ACCESS_WRITE;
1691 io1.smb2.in.alloc_size = 0;
1692 io1.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
1693 io1.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
1694 io1.smb2.in.security_flags = 0;
1695 io1.smb2.in.fname = fname;
1697 h2 = custom_smb2_create(tree, torture, &(io1.smb2));
1698 talloc_free(fname);
1699 smb2_util_close(tree, h2);
1702 req1 = smb2_notify_send(tree, &(notify.smb2));
1703 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1704 CHECK_STATUS(status, STATUS_NOTIFY_ENUM_DIR);
1705 CHECK_VAL(notify.smb2.out.num_changes, 0);
1707 done:
1708 smb2_deltree(tree, BASEDIR);
1709 return ret;
1713 Test if notifications are returned for changes to the base directory.
1714 They shouldn't be.
1717 static bool torture_smb2_notify_basedir(struct torture_context *torture,
1718 struct smb2_tree *tree1,
1719 struct smb2_tree *tree2)
1721 bool ret = true;
1722 NTSTATUS status;
1723 union smb_notify notify;
1724 union smb_open io;
1725 struct smb2_handle h1;
1726 struct smb2_request *req1;
1728 smb2_deltree(tree1, BASEDIR);
1729 smb2_util_rmdir(tree1, BASEDIR);
1731 torture_comment(torture, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1733 /* get a handle on the directory */
1734 ZERO_STRUCT(io.smb2);
1735 io.generic.level = RAW_OPEN_SMB2;
1736 io.smb2.in.create_flags = 0;
1737 io.smb2.in.desired_access = SEC_FILE_ALL;
1738 io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1739 io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
1740 io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1741 NTCREATEX_SHARE_ACCESS_WRITE;
1742 io.smb2.in.alloc_size = 0;
1743 io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
1744 io.smb2.in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS;
1745 io.smb2.in.security_flags = 0;
1746 io.smb2.in.fname = BASEDIR;
1748 status = smb2_create(tree1, torture, &(io.smb2));
1749 CHECK_STATUS(status, NT_STATUS_OK);
1750 h1 = io.smb2.out.file.handle;
1752 /* create a test file that will also be modified */
1753 io.smb2.in.fname = BASEDIR "\\tname1";
1754 io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
1755 status = smb2_create(tree2, torture, &(io.smb2));
1756 CHECK_STATUS(status,NT_STATUS_OK);
1757 smb2_util_close(tree2, io.smb2.out.file.handle);
1759 /* ask for a change notify, on attribute changes. */
1760 ZERO_STRUCT(notify.smb2);
1761 notify.smb2.level = RAW_NOTIFY_SMB2;
1762 notify.smb2.in.buffer_size = 1000;
1763 notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
1764 notify.smb2.in.file.handle = h1;
1765 notify.smb2.in.recursive = true;
1767 req1 = smb2_notify_send(tree1, &(notify.smb2));
1769 /* set attribute on the base dir */
1770 smb2_util_setatr(tree2, BASEDIR, FILE_ATTRIBUTE_HIDDEN);
1772 /* set attribute on a file to assure we receive a notification */
1773 smb2_util_setatr(tree2, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN);
1774 smb_msleep(200);
1776 /* check how many responses were given, expect only 1 for the file */
1777 status = smb2_notify_recv(req1, torture, &(notify.smb2));
1778 CHECK_STATUS(status, NT_STATUS_OK);
1779 CHECK_VAL(notify.smb2.out.num_changes, 1);
1780 CHECK_VAL(notify.smb2.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
1781 CHECK_WIRE_STR(notify.smb2.out.changes[0].name, "tname1");
1783 done:
1784 smb2_deltree(tree1, BASEDIR);
1785 return ret;
1790 create a secondary tree connect - used to test for a bug in Samba3 messaging
1791 with change notify
1793 static struct smb2_tree *secondary_tcon(struct smb2_tree *tree,
1794 struct torture_context *tctx)
1796 NTSTATUS status;
1797 const char *share, *host;
1798 struct smb2_tree *tree1;
1799 union smb_tcon tcon;
1801 share = torture_setting_string(tctx, "share", NULL);
1802 host = torture_setting_string(tctx, "host", NULL);
1804 torture_comment(tctx,
1805 "create a second tree context on the same session\n");
1806 tree1 = smb2_tree_init(tree->session, tctx, false);
1807 if (tree1 == NULL) {
1808 torture_comment(tctx, "Out of memory\n");
1809 return NULL;
1812 ZERO_STRUCT(tcon.smb2);
1813 tcon.generic.level = RAW_TCON_SMB2;
1814 tcon.smb2.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
1815 status = smb2_tree_connect(tree->session, &(tcon.smb2));
1816 if (!NT_STATUS_IS_OK(status)) {
1817 talloc_free(tree1);
1818 torture_comment(tctx,"Failed to create secondary tree\n");
1819 return NULL;
1822 tree1->tid = tcon.smb2.out.tid;
1823 torture_comment(tctx,"tid1=%d tid2=%d\n", tree->tid, tree1->tid);
1825 return tree1;
1830 very simple change notify test
1832 static bool torture_smb2_notify_tcon(struct torture_context *torture,
1833 struct smb2_tree *tree)
1835 bool ret = true;
1836 NTSTATUS status;
1837 union smb_notify notify;
1838 union smb_open io;
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));
1883 smb2_cancel(req);
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);
1941 talloc_free(tree1);
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");
1965 done:
1966 smb2_util_close(tree, h1);
1967 smb2_deltree(tree, BASEDIR);
1969 return ret;
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");
1996 return suite;