2 Unix SMB/CIFS implementation.
3 basic raw test suite for change notify
4 Copyright (C) Andrew Tridgell 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "libcli/raw/libcliraw.h"
22 #include "libcli/raw/raw_proto.h"
23 #include "libcli/libcli.h"
24 #include "system/filesys.h"
25 #include "torture/util.h"
26 #include "torture/raw/proto.h"
28 #define BASEDIR "\\test_notify"
30 #define CHECK_WSTR(tctx, field, value, flags) \
32 torture_assert_str_equal(tctx, field.s, value, "values don't match"); \
33 torture_assert(tctx, \
34 !wire_bad_flags(&field, STR_UNICODE, cli->transport), \
39 basic testing of change notify on directories
41 static bool test_notify_dir(struct torture_context *mem_ctx,
42 struct smbcli_state *cli,
43 struct smbcli_state *cli2)
47 union smb_notify notify;
50 int i, count, fnum, fnum2;
51 struct smbcli_request *req, *req2;
52 extern int torture_numops;
54 printf("TESTING CHANGE NOTIFY ON DIRECTORIES\n");
56 torture_assert(mem_ctx, torture_setup_dir(cli, BASEDIR),
57 "Failed to setup up test directory: " BASEDIR);
60 get a handle on the directory
62 io.generic.level = RAW_OPEN_NTCREATEX;
63 io.ntcreatex.in.root_fid.fnum = 0;
64 io.ntcreatex.in.flags = 0;
65 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
66 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
67 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
68 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
69 io.ntcreatex.in.alloc_size = 0;
70 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
71 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
72 io.ntcreatex.in.security_flags = 0;
73 io.ntcreatex.in.fname = BASEDIR;
75 status = smb_raw_open(cli->tree, mem_ctx, &io);
76 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
78 fnum = io.ntcreatex.out.file.fnum;
80 status = smb_raw_open(cli->tree, mem_ctx, &io);
81 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
83 fnum2 = io.ntcreatex.out.file.fnum;
85 /* ask for a change notify,
86 on file or directory name changes */
87 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
88 notify.nttrans.in.buffer_size = 1000;
89 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
90 notify.nttrans.in.file.fnum = fnum;
91 notify.nttrans.in.recursive = true;
93 printf("Testing notify cancel\n");
95 req = smb_raw_changenotify_send(cli->tree, ¬ify);
96 smb_raw_ntcancel(req);
97 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
98 torture_assert_ntstatus_equal_goto(mem_ctx, status, NT_STATUS_CANCELLED,
100 "smb_raw_changenotify_recv");
102 printf("Testing notify mkdir\n");
104 req = smb_raw_changenotify_send(cli->tree, ¬ify);
105 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name");
107 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
108 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
109 "smb_raw_changenotify_recv");
111 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
112 1, ret, done, "more than one change");
113 torture_assert_int_equal_goto(mem_ctx,
114 notify.nttrans.out.changes[0].action,
115 NOTIFY_ACTION_ADDED, ret, done,
116 "wrong action (exp: ADDED)");
117 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subdir-name",
120 printf("Testing notify rmdir\n");
122 req = smb_raw_changenotify_send(cli->tree, ¬ify);
123 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
125 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
126 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
127 "smb_raw_changenotify_recv");
128 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
129 1, ret, done, "more than one change");
130 torture_assert_int_equal_goto(mem_ctx,
131 notify.nttrans.out.changes[0].action,
132 NOTIFY_ACTION_REMOVED, ret, done,
133 "wrong action (exp: REMOVED)");
134 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subdir-name",
137 printf("Testing notify mkdir - rmdir - mkdir - rmdir\n");
139 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name");
140 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
141 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name");
142 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
144 req = smb_raw_changenotify_send(cli->tree, ¬ify);
145 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
146 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
147 "smb_raw_changenotify_recv");
148 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
149 4, ret, done, "wrong number of changes");
150 torture_assert_int_equal_goto(mem_ctx,
151 notify.nttrans.out.changes[0].action,
152 NOTIFY_ACTION_ADDED, ret, done,
153 "wrong action (exp: ADDED)");
154 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subdir-name",
156 torture_assert_int_equal_goto(mem_ctx,
157 notify.nttrans.out.changes[1].action,
158 NOTIFY_ACTION_REMOVED, ret, done,
159 "wrong action (exp: REMOVED)");
160 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[1].name, "subdir-name",
162 torture_assert_int_equal_goto(mem_ctx,
163 notify.nttrans.out.changes[2].action,
164 NOTIFY_ACTION_ADDED, ret, done,
165 "wrong action (exp: ADDED)");
166 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[2].name, "subdir-name",
168 torture_assert_int_equal_goto(mem_ctx,
169 notify.nttrans.out.changes[3].action,
170 NOTIFY_ACTION_REMOVED, ret, done,
171 "wrong action (exp: REMOVED)");
172 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[3].name, "subdir-name",
175 count = torture_numops;
176 printf("Testing buffered notify on create of %d files\n", count);
177 for (i=0;i<count;i++) {
178 char *fname = talloc_asprintf(cli, BASEDIR "\\test%d.txt", i);
179 int fnum3 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
181 printf("Failed to create %s - %s\n",
182 fname, smbcli_errstr(cli->tree));
187 smbcli_close(cli->tree, fnum3);
190 /* (1st notify) setup a new notify on a different directory handle.
191 This new notify won't see the events above. */
192 notify.nttrans.in.file.fnum = fnum2;
193 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
195 /* (2nd notify) whereas this notify will see the above buffered events,
196 and it directly returns the buffered events */
197 notify.nttrans.in.file.fnum = fnum;
198 req = smb_raw_changenotify_send(cli->tree, ¬ify);
200 status = smbcli_unlink(cli->tree, BASEDIR "\\nonexistent.txt");
201 torture_assert_ntstatus_equal_goto(mem_ctx, status,
202 NT_STATUS_OBJECT_NAME_NOT_FOUND,
206 /* (1st unlink) as the 2nd notify directly returns,
207 this unlink is only seen by the 1st notify and
208 the 3rd notify (later) */
209 printf("Testing notify on unlink for the first file\n");
210 status = smbcli_unlink(cli2->tree, BASEDIR "\\test0.txt");
211 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
214 /* receive the reply from the 2nd notify */
215 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
216 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
217 "smb_raw_changenotify_recv");
219 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
221 "wrong number of changes");
222 for (i=1;i<count;i++) {
223 torture_assert_int_equal_goto(mem_ctx,
224 notify.nttrans.out.changes[i].action,
225 NOTIFY_ACTION_ADDED, ret, done,
226 "wrong action (exp: ADDED)");
228 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "test0.txt",
231 printf("and now from the 1st notify\n");
232 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
233 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
234 "smb_raw_changenotify_recv");
235 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
236 1, ret, done, "wrong number of changes");
237 torture_assert_int_equal_goto(mem_ctx,
238 notify.nttrans.out.changes[0].action,
239 NOTIFY_ACTION_REMOVED, ret, done,
240 "wrong action (exp: REMOVED)");
241 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "test0.txt",
244 printf("(3rd notify) this notify will only see the 1st unlink\n");
245 req = smb_raw_changenotify_send(cli->tree, ¬ify);
247 status = smbcli_unlink(cli->tree, BASEDIR "\\nonexistent.txt");
248 torture_assert_ntstatus_equal_goto(mem_ctx, status,
249 NT_STATUS_OBJECT_NAME_NOT_FOUND,
253 printf("Testing notify on wildcard unlink for %d files\n", count-1);
254 /* (2nd unlink) do a wildcard unlink */
255 status = smbcli_unlink(cli2->tree, BASEDIR "\\test*.txt");
256 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
257 "smb_raw_changenotify_recv");
259 /* receive the 3rd notify */
260 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
261 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
262 "smb_raw_changenotify_recv");
263 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
264 1, ret, done, "wrong number of changes");
265 torture_assert_int_equal_goto(mem_ctx,
266 notify.nttrans.out.changes[0].action,
267 NOTIFY_ACTION_REMOVED, ret, done,
268 "wrong action (exp: REMOVED)");
269 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "test0.txt",
272 /* and we now see the rest of the unlink calls on both directory handles */
273 notify.nttrans.in.file.fnum = fnum;
275 req = smb_raw_changenotify_send(cli->tree, ¬ify);
276 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
277 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
278 "smb_raw_changenotify_recv");
279 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
280 count - 1, ret, done,
281 "wrong number of changes");
282 for (i=0;i<notify.nttrans.out.num_changes;i++) {
283 torture_assert_int_equal_goto(mem_ctx,
284 notify.nttrans.out.changes[i].action,
285 NOTIFY_ACTION_REMOVED, ret, done,
286 "wrong action (exp: REMOVED)");
288 notify.nttrans.in.file.fnum = fnum2;
289 req = smb_raw_changenotify_send(cli->tree, ¬ify);
290 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
291 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
292 "smb_raw_changenotify_recv");
293 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
294 count - 1, ret, done,
295 "wrong number of changes");
296 for (i=0;i<notify.nttrans.out.num_changes;i++) {
297 torture_assert_int_equal_goto(mem_ctx,
298 notify.nttrans.out.changes[i].action,
299 NOTIFY_ACTION_REMOVED, ret, done,
300 "wrong action (exp: REMOVED)");
303 printf("Testing if a close() on the dir handle triggers the notify reply\n");
305 notify.nttrans.in.file.fnum = fnum;
306 req = smb_raw_changenotify_send(cli->tree, ¬ify);
308 cl.close.level = RAW_CLOSE_CLOSE;
309 cl.close.in.file.fnum = fnum;
310 cl.close.in.write_time = 0;
311 status = smb_raw_close(cli->tree, &cl);
312 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
315 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
316 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
317 "smb_raw_changenotify_recv");
318 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
319 0, ret, done, "no changes expected");
322 smb_raw_exit(cli->session);
323 smbcli_deltree(cli->tree, BASEDIR);
328 * Check notify reply for a rename action. Not sure if this is a valid thing
329 * to do, but depending on timing between inotify and messaging we get the
330 * add/remove/modify in any order. This routines tries to find the action/name
331 * pair in any of the three following notify_changes.
334 static bool check_rename_reply(struct torture_context *tctx,
335 struct smbcli_state *cli,
337 struct notify_changes *actions,
338 uint32_t action, const char *name)
342 for (i=0; i<3; i++) {
343 if (actions[i].action == action) {
344 CHECK_WSTR(tctx, actions[i].name, name, STR_UNICODE);
349 torture_result(tctx, TORTURE_FAIL,
350 __location__": (%d) expected action %d, not found\n",
356 testing of recursive change notify
358 static bool test_notify_recursive(struct torture_context *mem_ctx,
359 struct smbcli_state *cli,
360 struct smbcli_state *cli2)
364 union smb_notify notify;
367 struct smbcli_request *req1, *req2;
369 printf("TESTING CHANGE NOTIFY WITH RECURSION\n");
371 torture_assert(mem_ctx, torture_setup_dir(cli, BASEDIR),
372 "Failed to setup up test directory: " BASEDIR);
375 get a handle on the directory
377 io.generic.level = RAW_OPEN_NTCREATEX;
378 io.ntcreatex.in.root_fid.fnum = 0;
379 io.ntcreatex.in.flags = 0;
380 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
381 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
382 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
383 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
384 io.ntcreatex.in.alloc_size = 0;
385 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
386 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
387 io.ntcreatex.in.security_flags = 0;
388 io.ntcreatex.in.fname = BASEDIR;
390 status = smb_raw_open(cli->tree, mem_ctx, &io);
391 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
393 fnum = io.ntcreatex.out.file.fnum;
395 /* ask for a change notify, on file or directory name
396 changes. Setup both with and without recursion */
397 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
398 notify.nttrans.in.buffer_size = 1000;
399 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
400 notify.nttrans.in.file.fnum = fnum;
402 notify.nttrans.in.recursive = true;
403 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
405 notify.nttrans.in.recursive = false;
406 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
408 /* cancel initial requests so the buffer is setup */
409 smb_raw_ntcancel(req1);
410 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
411 torture_assert_ntstatus_equal_goto(mem_ctx, status,
414 "smb_raw_changenotify_recv");
416 smb_raw_ntcancel(req2);
417 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
418 torture_assert_ntstatus_equal_goto(mem_ctx, status,
421 "smb_raw_changenotify_recv");
424 * Make notifies a bit more interesting in a cluster by doing
425 * the changes against different nodes with --unclist
427 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
428 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name\\subname1");
429 smbcli_close(cli->tree,
430 smbcli_open(cli->tree, BASEDIR "\\subdir-name\\subname2", O_CREAT, 0));
431 smbcli_rename(cli2->tree, BASEDIR "\\subdir-name\\subname1",
432 BASEDIR "\\subdir-name\\subname1-r");
433 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname2", BASEDIR "\\subname2-r");
434 smbcli_rename(cli2->tree, BASEDIR "\\subname2-r",
435 BASEDIR "\\subname3-r");
437 notify.nttrans.in.completion_filter = 0;
438 notify.nttrans.in.recursive = true;
440 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
442 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name\\subname1-r");
443 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
444 smbcli_unlink(cli->tree, BASEDIR "\\subname3-r");
446 notify.nttrans.in.recursive = false;
447 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
449 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
450 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
451 "smb_raw_changenotify_recv");
453 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
454 11, ret, done, "wrong number of changes");
455 torture_assert_int_equal_goto(mem_ctx,
456 notify.nttrans.out.changes[0].action,
457 NOTIFY_ACTION_ADDED, ret, done,
458 "wrong action (exp: ADDED)");
459 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subdir-name",
461 torture_assert_int_equal_goto(mem_ctx,
462 notify.nttrans.out.changes[1].action,
463 NOTIFY_ACTION_ADDED, ret, done,
464 "wrong action (exp: ADDED)");
465 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[1].name,
466 "subdir-name\\subname1", STR_UNICODE);
467 torture_assert_int_equal_goto(mem_ctx,
468 notify.nttrans.out.changes[2].action,
469 NOTIFY_ACTION_ADDED, ret, done,
470 "wrong action (exp: ADDED)");
471 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[2].name,
472 "subdir-name\\subname2", STR_UNICODE);
473 torture_assert_int_equal_goto(mem_ctx,
474 notify.nttrans.out.changes[3].action,
475 NOTIFY_ACTION_OLD_NAME, ret, done,
476 "wrong action (exp: OLD_NAME)");
477 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[3].name,
478 "subdir-name\\subname1", STR_UNICODE);
479 torture_assert_int_equal_goto(mem_ctx,
480 notify.nttrans.out.changes[4].action,
481 NOTIFY_ACTION_NEW_NAME, ret, done,
482 "wrong action (exp: NEW_NAME)");
483 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[4].name,
484 "subdir-name\\subname1-r", STR_UNICODE);
486 ret &= check_rename_reply(mem_ctx,
487 cli, __LINE__, ¬ify.nttrans.out.changes[5],
488 NOTIFY_ACTION_ADDED, "subname2-r");
489 ret &= check_rename_reply(mem_ctx,
490 cli, __LINE__, ¬ify.nttrans.out.changes[5],
491 NOTIFY_ACTION_REMOVED, "subdir-name\\subname2");
492 ret &= check_rename_reply(mem_ctx,
493 cli, __LINE__, ¬ify.nttrans.out.changes[5],
494 NOTIFY_ACTION_MODIFIED, "subname2-r");
496 ret &= check_rename_reply(mem_ctx,
497 cli, __LINE__, ¬ify.nttrans.out.changes[8],
498 NOTIFY_ACTION_OLD_NAME, "subname2-r");
499 ret &= check_rename_reply(mem_ctx,
500 cli, __LINE__, ¬ify.nttrans.out.changes[8],
501 NOTIFY_ACTION_NEW_NAME, "subname3-r");
502 ret &= check_rename_reply(mem_ctx,
503 cli, __LINE__, ¬ify.nttrans.out.changes[8],
504 NOTIFY_ACTION_MODIFIED, "subname3-r");
510 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
511 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
512 "smb_raw_changenotify_recv");
514 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
515 3, ret, done, "wrong number of changes");
516 torture_assert_int_equal_goto(mem_ctx,
517 notify.nttrans.out.changes[0].action,
518 NOTIFY_ACTION_REMOVED, ret, done,
519 "wrong action (exp: REMOVED)");
520 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name,
521 "subdir-name\\subname1-r", STR_UNICODE);
522 torture_assert_int_equal_goto(mem_ctx,
523 notify.nttrans.out.changes[1].action,
524 NOTIFY_ACTION_REMOVED, ret, done,
525 "wrong action (exp: REMOVED)");
526 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[1].name, "subdir-name",
528 torture_assert_int_equal_goto(mem_ctx,
529 notify.nttrans.out.changes[2].action,
530 NOTIFY_ACTION_REMOVED, ret, done,
531 "wrong action (exp: REMOVED)");
532 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[2].name, "subname3-r",
536 smb_raw_exit(cli->session);
537 smbcli_deltree(cli->tree, BASEDIR);
542 testing of change notify mask change
544 static bool test_notify_mask_change(struct torture_context *mem_ctx,
545 struct smbcli_state *cli)
549 union smb_notify notify;
552 struct smbcli_request *req1, *req2;
554 printf("TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
556 torture_assert(mem_ctx, torture_setup_dir(cli, BASEDIR),
557 "Failed to setup up test directory: " BASEDIR);
560 get a handle on the directory
562 io.generic.level = RAW_OPEN_NTCREATEX;
563 io.ntcreatex.in.root_fid.fnum = 0;
564 io.ntcreatex.in.flags = 0;
565 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
566 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
567 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
568 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
569 io.ntcreatex.in.alloc_size = 0;
570 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
571 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
572 io.ntcreatex.in.security_flags = 0;
573 io.ntcreatex.in.fname = BASEDIR;
575 status = smb_raw_open(cli->tree, mem_ctx, &io);
576 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
578 fnum = io.ntcreatex.out.file.fnum;
580 /* ask for a change notify, on file or directory name
581 changes. Setup both with and without recursion */
582 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
583 notify.nttrans.in.buffer_size = 1000;
584 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
585 notify.nttrans.in.file.fnum = fnum;
587 notify.nttrans.in.recursive = true;
588 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
590 notify.nttrans.in.recursive = false;
591 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
593 /* cancel initial requests so the buffer is setup */
594 smb_raw_ntcancel(req1);
595 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
596 torture_assert_ntstatus_equal_goto(mem_ctx, status,
599 "smb_raw_changenotify_recv");
601 smb_raw_ntcancel(req2);
602 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
603 torture_assert_ntstatus_equal_goto(mem_ctx, status,
606 "smb_raw_changenotify_recv");
608 notify.nttrans.in.recursive = true;
609 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
611 /* Set to hidden then back again. */
612 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));
613 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);
614 smbcli_unlink(cli->tree, BASEDIR "\\tname1");
616 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
617 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
618 "smb_raw_changenotify_recv");
620 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
621 1, ret, done, "wrong number of changes");
622 torture_assert_int_equal_goto(mem_ctx,
623 notify.nttrans.out.changes[0].action,
624 NOTIFY_ACTION_MODIFIED, ret, done,
625 "wrong action (exp: MODIFIED)");
626 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "tname1",
629 /* Now try and change the mask to include other events.
630 * This should not work - once the mask is set on a directory
631 * fnum it seems to be fixed until the fnum is closed. */
633 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
634 notify.nttrans.in.recursive = true;
635 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
637 notify.nttrans.in.recursive = false;
638 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
640 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
641 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name\\subname1");
642 smbcli_close(cli->tree,
643 smbcli_open(cli->tree, BASEDIR "\\subdir-name\\subname2", O_CREAT, 0));
644 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname1", BASEDIR "\\subdir-name\\subname1-r");
645 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname2", BASEDIR "\\subname2-r");
646 smbcli_rename(cli->tree, BASEDIR "\\subname2-r", BASEDIR "\\subname3-r");
648 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name\\subname1-r");
649 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
650 smbcli_unlink(cli->tree, BASEDIR "\\subname3-r");
652 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
653 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
654 "smb_raw_changenotify_recv");
656 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
657 1, ret, done, "wrong number of changes");
658 torture_assert_int_equal_goto(mem_ctx,
659 notify.nttrans.out.changes[0].action,
660 NOTIFY_ACTION_MODIFIED, ret, done,
661 "wrong action (exp: MODIFIED)");
662 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subname2-r",
665 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
666 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
667 "smb_raw_changenotify_recv");
669 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
670 1, ret, done, "wrong number of changes");
671 torture_assert_int_equal_goto(mem_ctx,
672 notify.nttrans.out.changes[0].action,
673 NOTIFY_ACTION_MODIFIED, ret, done,
674 "wrong action (exp: MODIFIED)");
675 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subname3-r",
683 smb_raw_exit(cli->session);
684 smbcli_deltree(cli->tree, BASEDIR);
690 testing of mask bits for change notify
692 static bool test_notify_mask(struct torture_context *tctx,
693 struct smbcli_state *cli,
694 struct smbcli_state *cli2)
698 union smb_notify notify;
700 union smb_chkpath chkpath;
708 printf("TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
710 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
711 "Failed to setup up test directory: " BASEDIR);
713 tv = timeval_current_ofs(1000, 0);
714 t = timeval_to_nttime(&tv);
717 get a handle on the directory
719 io.generic.level = RAW_OPEN_NTCREATEX;
720 io.ntcreatex.in.root_fid.fnum = 0;
721 io.ntcreatex.in.flags = 0;
722 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
723 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
724 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
725 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
726 io.ntcreatex.in.alloc_size = 0;
727 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
728 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
729 io.ntcreatex.in.security_flags = 0;
730 io.ntcreatex.in.fname = BASEDIR;
732 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
733 notify.nttrans.in.buffer_size = 1000;
734 notify.nttrans.in.recursive = true;
736 chkpath.chkpath.in.path = "\\";
738 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, expected, nchanges) \
740 smbcli_getatr(cli->tree, test_name, NULL, NULL, NULL); \
741 do { for (mask=i=0;i<32;i++) { \
742 struct smbcli_request *req; \
743 status = smb_raw_open(cli->tree, tctx, &io); \
744 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
746 fnum = io.ntcreatex.out.file.fnum; \
748 notify.nttrans.in.file.fnum = fnum; \
749 notify.nttrans.in.completion_filter = (1<<i); \
750 req = smb_raw_changenotify_send(cli->tree, ¬ify); \
751 smb_raw_chkpath(cli->tree, &chkpath); \
753 smb_msleep(200); smb_raw_ntcancel(req); \
754 status = smb_raw_changenotify_recv(req, tctx, ¬ify); \
756 smbcli_close(cli->tree, fnum); \
757 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
758 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
760 /* special case to cope with file rename behaviour */ \
761 if (nchanges == 2 && notify.nttrans.out.num_changes == 1 && \
762 notify.nttrans.out.changes[0].action == NOTIFY_ACTION_MODIFIED && \
763 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
764 Action == NOTIFY_ACTION_OLD_NAME) { \
765 printf("(rename file special handling OK)\n"); \
766 } else if (nchanges != notify.nttrans.out.num_changes) { \
767 printf("ERROR: nchanges=%d expected=%d action=%d filter=0x%08x\n", \
768 notify.nttrans.out.num_changes, \
770 notify.nttrans.out.changes[0].action, \
771 notify.nttrans.in.completion_filter); \
773 } else if (notify.nttrans.out.changes[0].action != Action) { \
774 printf("ERROR: nchanges=%d action=%d expectedAction=%d filter=0x%08x\n", \
775 notify.nttrans.out.num_changes, \
776 notify.nttrans.out.changes[0].action, \
778 notify.nttrans.in.completion_filter); \
780 } else if (strcmp(notify.nttrans.out.changes[0].name.s, "tname1") != 0) { \
781 printf("ERROR: nchanges=%d action=%d filter=0x%08x name=%s\n", \
782 notify.nttrans.out.num_changes, \
783 notify.nttrans.out.changes[0].action, \
784 notify.nttrans.in.completion_filter, \
785 notify.nttrans.out.changes[0].name.s); \
790 if ((expected) != mask) { \
791 if (((expected) & ~mask) != 0) { \
792 printf("ERROR: trigger on too few bits. mask=0x%08x expected=0x%08x\n", \
796 printf("WARNING: trigger on too many bits. mask=0x%08x expected=0x%08x\n", \
803 printf("Testing mkdir\n");
804 NOTIFY_MASK_TEST("Testing mkdir",;,
805 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
806 smbcli_rmdir(cli2->tree, BASEDIR "\\tname1");,
808 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
810 printf("Testing create file\n");
811 NOTIFY_MASK_TEST("Testing create file",;,
812 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
813 smbcli_unlink(cli2->tree, BASEDIR "\\tname1");,
815 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
817 printf("Testing unlink\n");
818 NOTIFY_MASK_TEST("Testing unlink",
819 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
820 smbcli_unlink(cli2->tree, BASEDIR "\\tname1");,
822 NOTIFY_ACTION_REMOVED,
823 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
825 printf("Testing rmdir\n");
826 NOTIFY_MASK_TEST("Testing rmdir",
827 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
828 smbcli_rmdir(cli2->tree, BASEDIR "\\tname1");,
830 NOTIFY_ACTION_REMOVED,
831 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
833 printf("Testing rename file\n");
834 NOTIFY_MASK_TEST("Testing rename file",
835 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
836 smbcli_rename(cli2->tree, BASEDIR "\\tname1", BASEDIR "\\tname2");,
837 smbcli_unlink(cli->tree, BASEDIR "\\tname2");,
838 NOTIFY_ACTION_OLD_NAME,
839 FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_CREATION, 2);
841 printf("Testing rename dir\n");
842 NOTIFY_MASK_TEST("Testing rename dir",
843 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
844 smbcli_rename(cli2->tree, BASEDIR "\\tname1", BASEDIR "\\tname2");,
845 smbcli_rmdir(cli->tree, BASEDIR "\\tname2");,
846 NOTIFY_ACTION_OLD_NAME,
847 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
849 printf("Testing set path attribute\n");
850 NOTIFY_MASK_TEST("Testing set path attribute",
851 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
852 smbcli_setatr(cli2->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);,
853 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
854 NOTIFY_ACTION_MODIFIED,
855 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
857 printf("Testing set path write time\n");
858 NOTIFY_MASK_TEST("Testing set path write time",
859 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
860 smbcli_setatr(cli2->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_NORMAL, 1000);,
861 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
862 NOTIFY_ACTION_MODIFIED,
863 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
865 printf("Testing set file attribute\n");
866 NOTIFY_MASK_TEST("Testing set file attribute",
867 fnum2 = create_complex_file(cli2, tctx, BASEDIR "\\tname1");,
868 smbcli_fsetatr(cli2->tree, fnum2, FILE_ATTRIBUTE_HIDDEN, 0, 0, 0, 0);,
869 (smbcli_close(cli2->tree, fnum2), smbcli_unlink(cli2->tree, BASEDIR "\\tname1"));,
870 NOTIFY_ACTION_MODIFIED,
871 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
873 if (torture_setting_bool(tctx, "samba3", false)) {
874 printf("Samba3 does not yet support create times "
878 printf("Testing set file create time\n");
879 NOTIFY_MASK_TEST("Testing set file create time",
880 fnum2 = create_complex_file(cli, tctx,
881 BASEDIR "\\tname1");,
882 smbcli_fsetatr(cli->tree, fnum2, 0, t, 0, 0, 0);,
883 (smbcli_close(cli->tree, fnum2),
884 smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
885 NOTIFY_ACTION_MODIFIED,
886 FILE_NOTIFY_CHANGE_CREATION, 1);
889 printf("Testing set file access time\n");
890 NOTIFY_MASK_TEST("Testing set file access time",
891 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
892 smbcli_fsetatr(cli->tree, fnum2, 0, 0, t, 0, 0);,
893 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
894 NOTIFY_ACTION_MODIFIED,
895 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
897 printf("Testing set file write time\n");
898 NOTIFY_MASK_TEST("Testing set file write time",
899 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
900 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, t, 0);,
901 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
902 NOTIFY_ACTION_MODIFIED,
903 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
905 printf("Testing set file change time\n");
906 NOTIFY_MASK_TEST("Testing set file change time",
907 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
908 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, 0, t);,
909 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
910 NOTIFY_ACTION_MODIFIED,
914 printf("Testing write\n");
915 NOTIFY_MASK_TEST("Testing write",
916 fnum2 = create_complex_file(cli2, tctx, BASEDIR "\\tname1");,
917 smbcli_write(cli2->tree, fnum2, 1, &c, 10000, 1);,
918 (smbcli_close(cli2->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
919 NOTIFY_ACTION_MODIFIED,
922 printf("Testing truncate\n");
923 NOTIFY_MASK_TEST("Testing truncate",
924 fnum2 = create_complex_file(cli2, tctx, BASEDIR "\\tname1");,
925 smbcli_ftruncate(cli2->tree, fnum2, 10000);,
926 (smbcli_close(cli2->tree, fnum2), smbcli_unlink(cli2->tree, BASEDIR "\\tname1"));,
927 NOTIFY_ACTION_MODIFIED,
928 FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
931 smb_raw_exit(cli->session);
932 smbcli_deltree(cli->tree, BASEDIR);
937 basic testing of change notify on files
939 static bool test_notify_file(struct torture_context *mem_ctx,
940 struct smbcli_state *cli)
946 union smb_notify notify;
947 struct smbcli_request *req;
949 const char *fname = BASEDIR "\\file.txt";
951 printf("TESTING CHANGE NOTIFY ON FILES\n");
953 torture_assert(mem_ctx, torture_setup_dir(cli, BASEDIR),
954 "Failed to setup up test directory: " BASEDIR);
956 io.generic.level = RAW_OPEN_NTCREATEX;
957 io.ntcreatex.in.root_fid.fnum = 0;
958 io.ntcreatex.in.flags = 0;
959 io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
960 io.ntcreatex.in.create_options = 0;
961 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
962 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
963 io.ntcreatex.in.alloc_size = 0;
964 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
965 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
966 io.ntcreatex.in.security_flags = 0;
967 io.ntcreatex.in.fname = fname;
968 status = smb_raw_open(cli->tree, mem_ctx, &io);
969 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
971 fnum = io.ntcreatex.out.file.fnum;
973 /* ask for a change notify,
974 on file or directory name changes */
975 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
976 notify.nttrans.in.file.fnum = fnum;
977 notify.nttrans.in.buffer_size = 1000;
978 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
979 notify.nttrans.in.recursive = false;
981 printf("Testing if notifies on file handles are invalid (should be)\n");
983 req = smb_raw_changenotify_send(cli->tree, ¬ify);
984 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
985 torture_assert_ntstatus_equal_goto(mem_ctx, status,
986 NT_STATUS_INVALID_PARAMETER,
988 "smb_raw_changenotify_recv");
990 cl.close.level = RAW_CLOSE_CLOSE;
991 cl.close.in.file.fnum = fnum;
992 cl.close.in.write_time = 0;
993 status = smb_raw_close(cli->tree, &cl);
994 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
997 status = smbcli_unlink(cli->tree, fname);
998 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1002 smb_raw_exit(cli->session);
1003 smbcli_deltree(cli->tree, BASEDIR);
1008 basic testing of change notifies followed by a tdis
1010 static bool test_notify_tdis(struct torture_context *tctx,
1011 struct smbcli_state *cli1)
1015 union smb_notify notify;
1018 struct smbcli_request *req;
1019 struct smbcli_state *cli = NULL;
1021 printf("TESTING CHANGE NOTIFY FOLLOWED BY TDIS\n");
1023 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
1024 "Failed to setup up test directory: " BASEDIR);
1026 if (!torture_open_connection(&cli, tctx, 0)) {
1031 get a handle on the directory
1033 io.generic.level = RAW_OPEN_NTCREATEX;
1034 io.ntcreatex.in.root_fid.fnum = 0;
1035 io.ntcreatex.in.flags = 0;
1036 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1037 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1038 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1039 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1040 io.ntcreatex.in.alloc_size = 0;
1041 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1042 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1043 io.ntcreatex.in.security_flags = 0;
1044 io.ntcreatex.in.fname = BASEDIR;
1046 status = smb_raw_open(cli->tree, tctx, &io);
1047 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1049 fnum = io.ntcreatex.out.file.fnum;
1051 /* ask for a change notify,
1052 on file or directory name changes */
1053 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1054 notify.nttrans.in.buffer_size = 1000;
1055 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1056 notify.nttrans.in.file.fnum = fnum;
1057 notify.nttrans.in.recursive = true;
1059 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1061 status = smbcli_tdis(cli);
1062 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1066 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1067 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1068 "smb_raw_changenotify_recv");
1069 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1070 0, ret, done, "no changes expected");
1073 torture_close_connection(cli);
1074 smbcli_deltree(cli1->tree, BASEDIR);
1079 basic testing of change notifies followed by a exit
1081 static bool test_notify_exit(struct torture_context *tctx,
1082 struct smbcli_state *cli1)
1086 union smb_notify notify;
1089 struct smbcli_request *req;
1090 struct smbcli_state *cli = NULL;
1092 printf("TESTING CHANGE NOTIFY FOLLOWED BY EXIT\n");
1094 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
1095 "Failed to setup up test directory: " BASEDIR);
1097 if (!torture_open_connection(&cli, tctx, 0)) {
1102 get a handle on the directory
1104 io.generic.level = RAW_OPEN_NTCREATEX;
1105 io.ntcreatex.in.root_fid.fnum = 0;
1106 io.ntcreatex.in.flags = 0;
1107 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1108 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1109 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1110 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1111 io.ntcreatex.in.alloc_size = 0;
1112 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1113 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1114 io.ntcreatex.in.security_flags = 0;
1115 io.ntcreatex.in.fname = BASEDIR;
1117 status = smb_raw_open(cli->tree, tctx, &io);
1118 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1120 fnum = io.ntcreatex.out.file.fnum;
1122 /* ask for a change notify,
1123 on file or directory name changes */
1124 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1125 notify.nttrans.in.buffer_size = 1000;
1126 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1127 notify.nttrans.in.file.fnum = fnum;
1128 notify.nttrans.in.recursive = true;
1130 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1132 status = smb_raw_exit(cli->session);
1133 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1136 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1137 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1138 "smb_raw_changenotify_recv");
1139 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1140 0, ret, done, "no changes expected");
1143 torture_close_connection(cli);
1144 smbcli_deltree(cli1->tree, BASEDIR);
1149 basic testing of change notifies followed by a ulogoff
1151 static bool test_notify_ulogoff(struct torture_context *tctx,
1152 struct smbcli_state *cli1)
1156 union smb_notify notify;
1159 struct smbcli_request *req;
1160 struct smbcli_state *cli = NULL;
1162 printf("TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1164 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
1165 "Failed to setup up test directory: " BASEDIR);
1167 if (!torture_open_connection(&cli, tctx, 0)) {
1172 get a handle on the directory
1174 io.generic.level = RAW_OPEN_NTCREATEX;
1175 io.ntcreatex.in.root_fid.fnum = 0;
1176 io.ntcreatex.in.flags = 0;
1177 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1178 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1179 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1180 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1181 io.ntcreatex.in.alloc_size = 0;
1182 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1183 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1184 io.ntcreatex.in.security_flags = 0;
1185 io.ntcreatex.in.fname = BASEDIR;
1187 status = smb_raw_open(cli->tree, tctx, &io);
1188 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1190 fnum = io.ntcreatex.out.file.fnum;
1192 /* ask for a change notify,
1193 on file or directory name changes */
1194 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1195 notify.nttrans.in.buffer_size = 1000;
1196 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1197 notify.nttrans.in.file.fnum = fnum;
1198 notify.nttrans.in.recursive = true;
1200 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1202 status = smb_raw_ulogoff(cli->session);
1203 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1206 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1207 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1208 "smb_raw_changenotify_recv");
1209 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1210 0, ret, done, "no changes expected");
1213 torture_close_connection(cli);
1214 smbcli_deltree(cli1->tree, BASEDIR);
1218 static void tcp_dis_handler(struct smbcli_transport *t, void *p)
1220 struct smbcli_state *cli = (struct smbcli_state *)p;
1221 smbcli_transport_dead(cli->transport, NT_STATUS_LOCAL_DISCONNECT);
1222 cli->transport = NULL;
1226 basic testing of change notifies followed by tcp disconnect
1228 static bool test_notify_tcp_dis(struct torture_context *tctx,
1229 struct smbcli_state *cli1)
1233 union smb_notify notify;
1236 struct smbcli_request *req;
1237 struct smbcli_state *cli = NULL;
1239 printf("TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1241 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
1242 "Failed to setup up test directory: " BASEDIR);
1244 if (!torture_open_connection(&cli, tctx, 0)) {
1249 get a handle on the directory
1251 io.generic.level = RAW_OPEN_NTCREATEX;
1252 io.ntcreatex.in.root_fid.fnum = 0;
1253 io.ntcreatex.in.flags = 0;
1254 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1255 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1256 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1257 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1258 io.ntcreatex.in.alloc_size = 0;
1259 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1260 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1261 io.ntcreatex.in.security_flags = 0;
1262 io.ntcreatex.in.fname = BASEDIR;
1264 status = smb_raw_open(cli->tree, tctx, &io);
1265 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1267 fnum = io.ntcreatex.out.file.fnum;
1269 /* ask for a change notify,
1270 on file or directory name changes */
1271 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1272 notify.nttrans.in.buffer_size = 1000;
1273 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1274 notify.nttrans.in.file.fnum = fnum;
1275 notify.nttrans.in.recursive = true;
1277 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1279 smbcli_transport_idle_handler(cli->transport, tcp_dis_handler, 250, cli);
1281 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1282 torture_assert_ntstatus_equal_goto(tctx, status,
1283 NT_STATUS_LOCAL_DISCONNECT,
1285 "smb_raw_changenotify_recv");
1288 torture_close_connection(cli);
1289 smbcli_deltree(cli1->tree, BASEDIR);
1294 test setting up two change notify requests on one handle
1296 static bool test_notify_double(struct torture_context *mem_ctx,
1297 struct smbcli_state *cli)
1301 union smb_notify notify;
1304 struct smbcli_request *req1, *req2;
1306 printf("TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1308 torture_assert(mem_ctx, torture_setup_dir(cli, BASEDIR),
1309 "Failed to setup up test directory: " BASEDIR);
1312 get a handle on the directory
1314 io.generic.level = RAW_OPEN_NTCREATEX;
1315 io.ntcreatex.in.root_fid.fnum = 0;
1316 io.ntcreatex.in.flags = 0;
1317 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1318 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1319 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1320 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1321 io.ntcreatex.in.alloc_size = 0;
1322 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1323 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1324 io.ntcreatex.in.security_flags = 0;
1325 io.ntcreatex.in.fname = BASEDIR;
1327 status = smb_raw_open(cli->tree, mem_ctx, &io);
1328 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1330 fnum = io.ntcreatex.out.file.fnum;
1332 /* ask for a change notify,
1333 on file or directory name changes */
1334 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1335 notify.nttrans.in.buffer_size = 1000;
1336 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1337 notify.nttrans.in.file.fnum = fnum;
1338 notify.nttrans.in.recursive = true;
1340 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1341 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
1343 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1345 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
1346 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1347 "smb_raw_changenotify_recv");
1348 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
1349 1, ret, done, "wrong number of changes");
1350 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subdir-name",
1353 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name2");
1355 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
1356 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1357 "smb_raw_changenotify_recv");
1358 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
1359 1, ret, done, "wrong number of changes");
1360 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subdir-name2",
1364 smb_raw_exit(cli->session);
1365 smbcli_deltree(cli->tree, BASEDIR);
1371 test multiple change notifies at different depths and with/without recursion
1373 static bool test_notify_tree(struct torture_context *mem_ctx,
1374 struct smbcli_state *cli,
1375 struct smbcli_state *cli2)
1378 union smb_notify notify;
1380 struct smbcli_request *req;
1390 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 30 },
1391 {BASEDIR "\\zqy", true, FILE_NOTIFY_CHANGE_NAME, 8 },
1392 {BASEDIR "\\atsy", true, FILE_NOTIFY_CHANGE_NAME, 4 },
1393 {BASEDIR "\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1394 {BASEDIR "\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME, 13 },
1395 {BASEDIR "\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME, 7 },
1396 {BASEDIR "\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1397 {BASEDIR "\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1398 {BASEDIR "\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1399 {BASEDIR "\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1400 {BASEDIR "\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1401 {BASEDIR "\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1402 {BASEDIR "\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME, 40 },
1403 {BASEDIR, true, FILE_NOTIFY_CHANGE_NAME, 40 },
1404 {BASEDIR, false,FILE_NOTIFY_CHANGE_NAME, 6 },
1405 {BASEDIR "\\atsy", false,FILE_NOTIFY_CHANGE_NAME, 4 },
1406 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1407 {BASEDIR "\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1408 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1409 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1413 bool all_done = false;
1415 printf("TESTING CHANGE NOTIFY FOR DIFFERENT DEPTHS\n");
1417 torture_assert(mem_ctx, torture_setup_dir(cli, BASEDIR),
1418 "Failed to setup up test directory: " BASEDIR);
1420 io.generic.level = RAW_OPEN_NTCREATEX;
1421 io.ntcreatex.in.root_fid.fnum = 0;
1422 io.ntcreatex.in.flags = 0;
1423 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1424 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1425 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1426 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1427 io.ntcreatex.in.alloc_size = 0;
1428 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1429 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1430 io.ntcreatex.in.security_flags = 0;
1432 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1433 notify.nttrans.in.buffer_size = 20000;
1436 setup the directory tree, and the notify buffer on each directory
1438 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1439 io.ntcreatex.in.fname = dirs[i].path;
1440 status = smb_raw_open(cli->tree, mem_ctx, &io);
1441 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1443 dirs[i].fnum = io.ntcreatex.out.file.fnum;
1445 notify.nttrans.in.completion_filter = dirs[i].filter;
1446 notify.nttrans.in.file.fnum = dirs[i].fnum;
1447 notify.nttrans.in.recursive = dirs[i].recursive;
1448 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1449 smb_raw_ntcancel(req);
1450 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
1451 torture_assert_ntstatus_equal_goto(mem_ctx, status,
1452 NT_STATUS_CANCELLED,
1454 "smb_raw_changenotify_recv");
1457 /* trigger 2 events in each dir */
1458 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1459 char *path = talloc_asprintf(mem_ctx, "%s\\test.dir", dirs[i].path);
1461 * Make notifies a bit more interesting in a cluster
1462 * by doing the changes against different nodes with
1465 smbcli_mkdir(cli->tree, path);
1466 smbcli_rmdir(cli2->tree, path);
1470 /* give a bit of time for the events to propogate */
1471 tv = timeval_current();
1474 /* count events that have happened in each dir */
1475 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1476 notify.nttrans.in.file.fnum = dirs[i].fnum;
1477 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1478 smb_raw_ntcancel(req);
1479 notify.nttrans.out.num_changes = 0;
1480 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
1481 dirs[i].counted += notify.nttrans.out.num_changes;
1486 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1487 if (dirs[i].counted != dirs[i].expected) {
1491 } while (!all_done && timeval_elapsed(&tv) < 20);
1493 printf("took %.4f seconds to propogate all events\n", timeval_elapsed(&tv));
1495 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1496 if (dirs[i].counted != dirs[i].expected) {
1497 printf("ERROR: i=%d expected %d got %d for '%s'\n",
1498 i, dirs[i].expected, dirs[i].counted, dirs[i].path);
1504 run from the back, closing and deleting
1506 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1507 smbcli_close(cli->tree, dirs[i].fnum);
1508 smbcli_rmdir(cli->tree, dirs[i].path);
1512 smb_raw_exit(cli->session);
1513 smbcli_deltree(cli->tree, BASEDIR);
1518 Test response when cached server events exceed single NT NOTFIY response
1521 static bool test_notify_overflow(struct torture_context *mem_ctx,
1522 struct smbcli_state *cli)
1526 union smb_notify notify;
1530 struct smbcli_request *req1;
1533 printf("TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1535 torture_assert(mem_ctx, torture_setup_dir(cli, BASEDIR),
1536 "Failed to setup up test directory: " BASEDIR);
1538 /* get a handle on the directory */
1539 io.generic.level = RAW_OPEN_NTCREATEX;
1540 io.ntcreatex.in.root_fid.fnum = 0;
1541 io.ntcreatex.in.flags = 0;
1542 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1543 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1544 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1545 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1546 NTCREATEX_SHARE_ACCESS_WRITE;
1547 io.ntcreatex.in.alloc_size = 0;
1548 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1549 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1550 io.ntcreatex.in.security_flags = 0;
1551 io.ntcreatex.in.fname = BASEDIR;
1553 status = smb_raw_open(cli->tree, mem_ctx, &io);
1554 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1556 fnum = io.ntcreatex.out.file.fnum;
1558 /* ask for a change notify, on name changes. */
1559 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1560 notify.nttrans.in.buffer_size = 1000;
1561 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1562 notify.nttrans.in.file.fnum = fnum;
1564 notify.nttrans.in.recursive = true;
1565 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1567 /* cancel initial requests so the buffer is setup */
1568 smb_raw_ntcancel(req1);
1569 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
1570 torture_assert_ntstatus_equal_goto(mem_ctx, status,
1571 NT_STATUS_CANCELLED,
1573 "smb_raw_changenotify_recv");
1575 /* open a lot of files, filling up the server side notify buffer */
1576 printf("Testing overflowed buffer notify on create of %d files\n",
1578 for (i=0;i<count;i++) {
1579 char *fname = talloc_asprintf(cli, BASEDIR "\\test%d.txt", i);
1580 int fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR,
1583 printf("Failed to create %s - %s\n",
1584 fname, smbcli_errstr(cli->tree));
1589 smbcli_close(cli->tree, fnum2);
1592 /* expect that 0 events will be returned with NT_STATUS_OK */
1593 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1594 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
1595 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1596 "smb_raw_changenotify_recv");
1597 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
1598 0, ret, done, "no changes expected");
1601 smb_raw_exit(cli->session);
1602 smbcli_deltree(cli->tree, BASEDIR);
1607 Test if notifications are returned for changes to the base directory.
1610 static bool test_notify_basedir(struct torture_context *mem_ctx,
1611 struct smbcli_state *cli)
1615 union smb_notify notify;
1618 struct smbcli_request *req1;
1620 printf("TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1622 torture_assert(mem_ctx, torture_setup_dir(cli, BASEDIR),
1623 "Failed to setup up test directory: " BASEDIR);
1625 /* get a handle on the directory */
1626 io.generic.level = RAW_OPEN_NTCREATEX;
1627 io.ntcreatex.in.root_fid.fnum = 0;
1628 io.ntcreatex.in.flags = 0;
1629 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1630 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1631 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1632 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1633 NTCREATEX_SHARE_ACCESS_WRITE;
1634 io.ntcreatex.in.alloc_size = 0;
1635 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1636 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1637 io.ntcreatex.in.security_flags = 0;
1638 io.ntcreatex.in.fname = BASEDIR;
1640 status = smb_raw_open(cli->tree, mem_ctx, &io);
1641 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1643 fnum = io.ntcreatex.out.file.fnum;
1645 /* create a test file that will also be modified */
1646 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1",
1649 /* ask for a change notify, on attribute changes. */
1650 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1651 notify.nttrans.in.buffer_size = 1000;
1652 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
1653 notify.nttrans.in.file.fnum = fnum;
1654 notify.nttrans.in.recursive = true;
1656 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1658 /* set attribute on the base dir */
1659 smbcli_setatr(cli->tree, BASEDIR, FILE_ATTRIBUTE_HIDDEN, 0);
1661 /* set attribute on a file to assure we receive a notification */
1662 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);
1665 /* check how many responses were given, expect only 1 for the file */
1666 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
1667 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1668 "smb_raw_changenotify_recv");
1669 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
1670 1, ret, done, "wrong number of changes");
1671 torture_assert_int_equal_goto(mem_ctx,
1672 notify.nttrans.out.changes[0].action,
1673 NOTIFY_ACTION_MODIFIED, ret, done,
1674 "wrong action (exp: MODIFIED)");
1675 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "tname1",
1679 smb_raw_exit(cli->session);
1680 smbcli_deltree(cli->tree, BASEDIR);
1686 create a secondary tree connect - used to test for a bug in Samba3 messaging
1689 static struct smbcli_tree *secondary_tcon(struct smbcli_state *cli,
1690 struct torture_context *tctx)
1693 const char *share, *host;
1694 struct smbcli_tree *tree;
1695 union smb_tcon tcon;
1697 share = torture_setting_string(tctx, "share", NULL);
1698 host = torture_setting_string(tctx, "host", NULL);
1700 printf("create a second tree context on the same session\n");
1701 tree = smbcli_tree_init(cli->session, tctx, false);
1703 tcon.generic.level = RAW_TCON_TCONX;
1704 tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
1705 tcon.tconx.in.password = data_blob(NULL, 0);
1706 tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
1707 tcon.tconx.in.device = "A:";
1708 status = smb_raw_tcon(tree, tctx, &tcon);
1709 if (!NT_STATUS_IS_OK(status)) {
1711 printf("Failed to create secondary tree\n");
1715 tree->tid = tcon.tconx.out.tid;
1716 printf("tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
1723 very simple change notify test
1725 static bool test_notify_tcon(struct torture_context *torture,
1726 struct smbcli_state *cli)
1730 union smb_notify notify;
1733 struct smbcli_request *req;
1734 extern int torture_numops;
1735 struct smbcli_tree *tree = NULL;
1737 printf("TESTING SIMPLE CHANGE NOTIFY\n");
1739 torture_assert(torture, torture_setup_dir(cli, BASEDIR),
1740 "Failed to setup up test directory: " BASEDIR);
1743 get a handle on the directory
1745 io.generic.level = RAW_OPEN_NTCREATEX;
1746 io.ntcreatex.in.root_fid.fnum = 0;
1747 io.ntcreatex.in.flags = 0;
1748 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1749 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1750 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1751 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1752 io.ntcreatex.in.alloc_size = 0;
1753 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1754 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1755 io.ntcreatex.in.security_flags = 0;
1756 io.ntcreatex.in.fname = BASEDIR;
1758 status = smb_raw_open(cli->tree, torture, &io);
1759 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1761 fnum = io.ntcreatex.out.file.fnum;
1763 status = smb_raw_open(cli->tree, torture, &io);
1764 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1767 /* ask for a change notify,
1768 on file or directory name changes */
1769 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1770 notify.nttrans.in.buffer_size = 1000;
1771 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1772 notify.nttrans.in.file.fnum = fnum;
1773 notify.nttrans.in.recursive = true;
1775 printf("Testing notify mkdir\n");
1776 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1777 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1779 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1780 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1781 "smb_raw_changenotify_recv");
1783 torture_assert_int_equal_goto(torture, notify.nttrans.out.num_changes,
1784 1, ret, done, "wrong number of changes");
1785 torture_assert_int_equal_goto(torture,
1786 notify.nttrans.out.changes[0].action,
1787 NOTIFY_ACTION_ADDED, ret, done,
1788 "wrong action (exp: ADDED)");
1789 CHECK_WSTR(torture, notify.nttrans.out.changes[0].name, "subdir-name",
1792 printf("Testing notify rmdir\n");
1793 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1794 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
1796 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1797 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1798 "smb_raw_changenotify_recv");
1799 torture_assert_int_equal_goto(torture, notify.nttrans.out.num_changes,
1800 1, ret, done, "wrong number of changes");
1801 torture_assert_int_equal_goto(torture,
1802 notify.nttrans.out.changes[0].action,
1803 NOTIFY_ACTION_REMOVED, ret, done,
1804 "wrong action (exp: REMOVED)");
1805 CHECK_WSTR(torture, notify.nttrans.out.changes[0].name, "subdir-name",
1808 printf("SIMPLE CHANGE NOTIFY OK\n");
1810 printf("TESTING WITH SECONDARY TCON\n");
1811 tree = secondary_tcon(cli, torture);
1813 printf("Testing notify mkdir\n");
1814 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1815 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1817 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1818 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1819 "smb_raw_changenotify_recv");
1821 torture_assert_int_equal_goto(torture, notify.nttrans.out.num_changes,
1822 1, ret, done, "wrong number of changes");
1823 torture_assert_int_equal_goto(torture,
1824 notify.nttrans.out.changes[0].action,
1825 NOTIFY_ACTION_ADDED, ret, done,
1826 "wrong action (exp: ADDED)");
1827 CHECK_WSTR(torture, notify.nttrans.out.changes[0].name, "subdir-name",
1830 printf("Testing notify rmdir\n");
1831 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1832 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
1834 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1835 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1836 "smb_raw_changenotify_recv");
1837 torture_assert_int_equal_goto(torture, notify.nttrans.out.num_changes,
1838 1, ret, done, "wrong number of changes");
1839 torture_assert_int_equal_goto(torture,
1840 notify.nttrans.out.changes[0].action,
1841 NOTIFY_ACTION_REMOVED, ret, done,
1842 "wrong action (exp: REMOVED)");
1843 CHECK_WSTR(torture, notify.nttrans.out.changes[0].name, "subdir-name",
1846 printf("CHANGE NOTIFY WITH TCON OK\n");
1848 printf("Disconnecting secondary tree\n");
1849 status = smb_tree_disconnect(tree);
1850 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1851 "smb_tree_disconnect");
1854 printf("Testing notify mkdir\n");
1855 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1856 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1858 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1859 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1860 "smb_raw_changenotify_recv");
1862 torture_assert_int_equal_goto(torture, notify.nttrans.out.num_changes,
1863 1, ret, done, "wrong number of changes");
1864 torture_assert_int_equal_goto(torture,
1865 notify.nttrans.out.changes[0].action,
1866 NOTIFY_ACTION_ADDED, ret, done,
1867 "wrong action (exp: ADDED)");
1868 CHECK_WSTR(torture, notify.nttrans.out.changes[0].name, "subdir-name",
1871 printf("Testing notify rmdir\n");
1872 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1873 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
1875 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1876 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1877 "smb_raw_changenotify_recv");
1878 torture_assert_int_equal_goto(torture, notify.nttrans.out.num_changes,
1879 1, ret, done, "wrong number of changes");
1880 torture_assert_int_equal_goto(torture,
1881 notify.nttrans.out.changes[0].action,
1882 NOTIFY_ACTION_REMOVED, ret, done,
1883 "wrong action (exp: REMOVED)");
1884 CHECK_WSTR(torture, notify.nttrans.out.changes[0].name, "subdir-name",
1887 printf("CHANGE NOTIFY WITH TDIS OK\n");
1889 smb_raw_exit(cli->session);
1890 smbcli_deltree(cli->tree, BASEDIR);
1896 testing alignment of multiple change notify infos
1898 static bool test_notify_alignment(struct torture_context *tctx,
1899 struct smbcli_state *cli)
1902 union smb_notify notify;
1905 struct smbcli_request *req;
1906 const char *fname = BASEDIR "\\starter";
1907 const char *fnames[] = { "a",
1911 int num_names = ARRAY_SIZE(fnames);
1914 torture_comment(tctx, "TESTING CHANGE NOTIFY REPLY ALIGNMENT\n");
1916 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
1917 "Failed to setup up test directory: " BASEDIR);
1919 /* get a handle on the directory */
1920 io.generic.level = RAW_OPEN_NTCREATEX;
1921 io.ntcreatex.in.root_fid.fnum = 0;
1922 io.ntcreatex.in.flags = 0;
1923 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1924 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1925 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1926 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1927 NTCREATEX_SHARE_ACCESS_WRITE;
1928 io.ntcreatex.in.alloc_size = 0;
1929 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1930 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1931 io.ntcreatex.in.security_flags = 0;
1932 io.ntcreatex.in.fname = BASEDIR;
1934 status = smb_raw_open(cli->tree, tctx, &io);
1935 torture_assert_ntstatus_ok(tctx, status, "smb_raw_open");
1936 fnum = io.ntcreatex.out.file.fnum;
1938 /* ask for a change notify, on file creation */
1939 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1940 notify.nttrans.in.buffer_size = 1000;
1941 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_FILE_NAME;
1942 notify.nttrans.in.file.fnum = fnum;
1943 notify.nttrans.in.recursive = false;
1945 /* start change tracking */
1946 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1948 fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
1949 torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
1950 smbcli_close(cli->tree, fnum2);
1952 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1953 torture_assert_ntstatus_ok(tctx, status, "smb_raw_changenotify_recv");
1955 /* create 4 files that will cause CHANGE_NOTIFY_INFO structures
1956 * to be returned in the same packet with all possible 4-byte padding
1957 * permutations. As per MS-CIFS 2.2.7.4.2 these structures should be
1958 * 4-byte aligned. */
1960 for (i = 0; i < num_names; i++) {
1961 fpath = talloc_asprintf(tctx, "%s\\%s", BASEDIR, fnames[i]);
1962 fnum2 = smbcli_open(cli->tree, fpath,
1963 O_CREAT|O_RDWR, DENY_NONE);
1964 torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
1965 smbcli_close(cli->tree, fnum2);
1969 /* We send a notify packet, and let smb_raw_changenotify_recv() do
1970 * the alignment checking for us. */
1971 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1972 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1973 torture_assert_ntstatus_ok(tctx, status, "smb_raw_changenotify_recv");
1975 /* Do basic checking for correctness. */
1976 torture_assert(tctx, notify.nttrans.out.num_changes == num_names, "");
1977 for (i = 0; i < num_names; i++) {
1978 torture_assert(tctx, notify.nttrans.out.changes[i].action ==
1979 NOTIFY_ACTION_ADDED, "");
1980 CHECK_WSTR(tctx, notify.nttrans.out.changes[i].name, fnames[i],
1984 smb_raw_exit(cli->session);
1985 smbcli_deltree(cli->tree, BASEDIR);
1989 struct torture_suite *torture_raw_notify(TALLOC_CTX *mem_ctx)
1991 struct torture_suite *suite = torture_suite_create(mem_ctx, "notify");
1993 torture_suite_add_1smb_test(suite, "tcon", test_notify_tcon);
1994 torture_suite_add_2smb_test(suite, "dir", test_notify_dir);
1995 torture_suite_add_2smb_test(suite, "mask", test_notify_mask);
1996 torture_suite_add_2smb_test(suite, "recursive", test_notify_recursive);
1997 torture_suite_add_1smb_test(suite, "mask_change",
1998 test_notify_mask_change);
1999 torture_suite_add_1smb_test(suite, "file", test_notify_file);
2000 torture_suite_add_1smb_test(suite, "tdis", test_notify_tdis);
2001 torture_suite_add_1smb_test(suite, "exit", test_notify_exit);
2002 torture_suite_add_1smb_test(suite, "ulogoff", test_notify_ulogoff);
2003 torture_suite_add_1smb_test(suite, "tcp_dis", test_notify_tcp_dis);
2004 torture_suite_add_1smb_test(suite, "double", test_notify_double);
2005 torture_suite_add_2smb_test(suite, "tree", test_notify_tree);
2006 torture_suite_add_1smb_test(suite, "overflow", test_notify_overflow);
2007 torture_suite_add_1smb_test(suite, "basedir", test_notify_basedir);
2008 torture_suite_add_1smb_test(suite, "alignment", test_notify_alignment);