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 *tctx,
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(tctx, 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, tctx, &io);
76 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
78 fnum = io.ntcreatex.out.file.fnum;
80 status = smb_raw_open(cli->tree, tctx, &io);
81 torture_assert_ntstatus_ok_goto(tctx, 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, tctx, ¬ify);
98 torture_assert_ntstatus_equal_goto(tctx, 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, tctx, ¬ify);
108 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
109 "smb_raw_changenotify_recv");
111 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
112 1, ret, done, "more than one change");
113 torture_assert_int_equal_goto(tctx,
114 notify.nttrans.out.changes[0].action,
115 NOTIFY_ACTION_ADDED, ret, done,
116 "wrong action (exp: ADDED)");
117 CHECK_WSTR(tctx, 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, tctx, ¬ify);
126 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
127 "smb_raw_changenotify_recv");
128 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
129 1, ret, done, "more than one change");
130 torture_assert_int_equal_goto(tctx,
131 notify.nttrans.out.changes[0].action,
132 NOTIFY_ACTION_REMOVED, ret, done,
133 "wrong action (exp: REMOVED)");
134 CHECK_WSTR(tctx, 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, tctx, ¬ify);
146 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
147 "smb_raw_changenotify_recv");
148 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
149 4, ret, done, "wrong number of changes");
150 torture_assert_int_equal_goto(tctx,
151 notify.nttrans.out.changes[0].action,
152 NOTIFY_ACTION_ADDED, ret, done,
153 "wrong action (exp: ADDED)");
154 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
156 torture_assert_int_equal_goto(tctx,
157 notify.nttrans.out.changes[1].action,
158 NOTIFY_ACTION_REMOVED, ret, done,
159 "wrong action (exp: REMOVED)");
160 CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name, "subdir-name",
162 torture_assert_int_equal_goto(tctx,
163 notify.nttrans.out.changes[2].action,
164 NOTIFY_ACTION_ADDED, ret, done,
165 "wrong action (exp: ADDED)");
166 CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name, "subdir-name",
168 torture_assert_int_equal_goto(tctx,
169 notify.nttrans.out.changes[3].action,
170 NOTIFY_ACTION_REMOVED, ret, done,
171 "wrong action (exp: REMOVED)");
172 CHECK_WSTR(tctx, 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);
180 torture_assert_int_not_equal_goto(tctx, fnum3, -1, ret, done,
181 talloc_asprintf(tctx, "Failed to create %s - %s",
182 fname, smbcli_errstr(cli->tree)));
184 smbcli_close(cli->tree, fnum3);
187 /* (1st notify) setup a new notify on a different directory handle.
188 This new notify won't see the events above. */
189 notify.nttrans.in.file.fnum = fnum2;
190 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
192 /* (2nd notify) whereas this notify will see the above buffered events,
193 and it directly returns the buffered events */
194 notify.nttrans.in.file.fnum = fnum;
195 req = smb_raw_changenotify_send(cli->tree, ¬ify);
197 status = smbcli_unlink(cli->tree, BASEDIR "\\nonexistent.txt");
198 torture_assert_ntstatus_equal_goto(tctx, status,
199 NT_STATUS_OBJECT_NAME_NOT_FOUND,
203 /* (1st unlink) as the 2nd notify directly returns,
204 this unlink is only seen by the 1st notify and
205 the 3rd notify (later) */
206 printf("Testing notify on unlink for the first file\n");
207 status = smbcli_unlink(cli2->tree, BASEDIR "\\test0.txt");
208 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
211 /* receive the reply from the 2nd notify */
212 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
213 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
214 "smb_raw_changenotify_recv");
216 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
218 "wrong number of changes");
219 for (i=1;i<count;i++) {
220 torture_assert_int_equal_goto(tctx,
221 notify.nttrans.out.changes[i].action,
222 NOTIFY_ACTION_ADDED, ret, done,
223 "wrong action (exp: ADDED)");
225 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
228 printf("and now from the 1st notify\n");
229 status = smb_raw_changenotify_recv(req2, tctx, ¬ify);
230 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
231 "smb_raw_changenotify_recv");
232 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
233 1, ret, done, "wrong number of changes");
234 torture_assert_int_equal_goto(tctx,
235 notify.nttrans.out.changes[0].action,
236 NOTIFY_ACTION_REMOVED, ret, done,
237 "wrong action (exp: REMOVED)");
238 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
241 printf("(3rd notify) this notify will only see the 1st unlink\n");
242 req = smb_raw_changenotify_send(cli->tree, ¬ify);
244 status = smbcli_unlink(cli->tree, BASEDIR "\\nonexistent.txt");
245 torture_assert_ntstatus_equal_goto(tctx, status,
246 NT_STATUS_OBJECT_NAME_NOT_FOUND,
250 printf("Testing notify on wildcard unlink for %d files\n", count-1);
251 /* (2nd unlink) do a wildcard unlink */
252 status = smbcli_unlink(cli2->tree, BASEDIR "\\test*.txt");
253 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
254 "smb_raw_changenotify_recv");
256 /* receive the 3rd notify */
257 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
258 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
259 "smb_raw_changenotify_recv");
260 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
261 1, ret, done, "wrong number of changes");
262 torture_assert_int_equal_goto(tctx,
263 notify.nttrans.out.changes[0].action,
264 NOTIFY_ACTION_REMOVED, ret, done,
265 "wrong action (exp: REMOVED)");
266 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
269 /* and we now see the rest of the unlink calls on both directory handles */
270 notify.nttrans.in.file.fnum = fnum;
272 req = smb_raw_changenotify_send(cli->tree, ¬ify);
273 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
274 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
275 "smb_raw_changenotify_recv");
276 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
277 count - 1, ret, done,
278 "wrong number of changes");
279 for (i=0;i<notify.nttrans.out.num_changes;i++) {
280 torture_assert_int_equal_goto(tctx,
281 notify.nttrans.out.changes[i].action,
282 NOTIFY_ACTION_REMOVED, ret, done,
283 "wrong action (exp: REMOVED)");
285 notify.nttrans.in.file.fnum = fnum2;
286 req = smb_raw_changenotify_send(cli->tree, ¬ify);
287 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
288 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
289 "smb_raw_changenotify_recv");
290 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
291 count - 1, ret, done,
292 "wrong number of changes");
293 for (i=0;i<notify.nttrans.out.num_changes;i++) {
294 torture_assert_int_equal_goto(tctx,
295 notify.nttrans.out.changes[i].action,
296 NOTIFY_ACTION_REMOVED, ret, done,
297 "wrong action (exp: REMOVED)");
300 printf("Testing if a close() on the dir handle triggers the notify reply\n");
302 notify.nttrans.in.file.fnum = fnum;
303 req = smb_raw_changenotify_send(cli->tree, ¬ify);
305 cl.close.level = RAW_CLOSE_CLOSE;
306 cl.close.in.file.fnum = fnum;
307 cl.close.in.write_time = 0;
308 status = smb_raw_close(cli->tree, &cl);
309 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
312 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
313 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
314 "smb_raw_changenotify_recv");
315 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
316 0, ret, done, "no changes expected");
319 smb_raw_exit(cli->session);
320 smbcli_deltree(cli->tree, BASEDIR);
325 * Check notify reply for a rename action. Not sure if this is a valid thing
326 * to do, but depending on timing between inotify and messaging we get the
327 * add/remove/modify in any order. This routines tries to find the action/name
328 * pair in any of the three following notify_changes.
331 static bool check_rename_reply(struct torture_context *tctx,
332 struct smbcli_state *cli,
334 struct notify_changes *actions,
335 uint32_t action, const char *name)
339 for (i=0; i<3; i++) {
340 if (actions[i].action == action) {
341 CHECK_WSTR(tctx, actions[i].name, name, STR_UNICODE);
346 torture_result(tctx, TORTURE_FAIL,
347 __location__": (%d) expected action %d, not found\n",
353 testing of recursive change notify
355 static bool test_notify_recursive(struct torture_context *tctx,
356 struct smbcli_state *cli,
357 struct smbcli_state *cli2)
361 union smb_notify notify;
364 struct smbcli_request *req1, *req2;
366 printf("TESTING CHANGE NOTIFY WITH RECURSION\n");
368 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
369 "Failed to setup up test directory: " BASEDIR);
372 get a handle on the directory
374 io.generic.level = RAW_OPEN_NTCREATEX;
375 io.ntcreatex.in.root_fid.fnum = 0;
376 io.ntcreatex.in.flags = 0;
377 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
378 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
379 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
380 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
381 io.ntcreatex.in.alloc_size = 0;
382 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
383 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
384 io.ntcreatex.in.security_flags = 0;
385 io.ntcreatex.in.fname = BASEDIR;
387 status = smb_raw_open(cli->tree, tctx, &io);
388 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
390 fnum = io.ntcreatex.out.file.fnum;
392 /* ask for a change notify, on file or directory name
393 changes. Setup both with and without recursion */
394 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
395 notify.nttrans.in.buffer_size = 1000;
396 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
397 notify.nttrans.in.file.fnum = fnum;
399 notify.nttrans.in.recursive = true;
400 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
402 notify.nttrans.in.recursive = false;
403 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
405 /* cancel initial requests so the buffer is setup */
406 smb_raw_ntcancel(req1);
407 status = smb_raw_changenotify_recv(req1, tctx, ¬ify);
408 torture_assert_ntstatus_equal_goto(tctx, status,
411 "smb_raw_changenotify_recv");
413 smb_raw_ntcancel(req2);
414 status = smb_raw_changenotify_recv(req2, tctx, ¬ify);
415 torture_assert_ntstatus_equal_goto(tctx, status,
418 "smb_raw_changenotify_recv");
421 * Make notifies a bit more interesting in a cluster by doing
422 * the changes against different nodes with --unclist
424 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
425 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name\\subname1");
426 smbcli_close(cli->tree,
427 smbcli_open(cli->tree, BASEDIR "\\subdir-name\\subname2", O_CREAT, 0));
428 smbcli_rename(cli2->tree, BASEDIR "\\subdir-name\\subname1",
429 BASEDIR "\\subdir-name\\subname1-r");
430 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname2", BASEDIR "\\subname2-r");
431 smbcli_rename(cli2->tree, BASEDIR "\\subname2-r",
432 BASEDIR "\\subname3-r");
434 notify.nttrans.in.completion_filter = 0;
435 notify.nttrans.in.recursive = true;
437 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
439 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name\\subname1-r");
440 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
441 smbcli_unlink(cli->tree, BASEDIR "\\subname3-r");
443 notify.nttrans.in.recursive = false;
444 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
446 status = smb_raw_changenotify_recv(req1, tctx, ¬ify);
447 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
448 "smb_raw_changenotify_recv");
450 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
451 11, ret, done, "wrong number of changes");
452 torture_assert_int_equal_goto(tctx,
453 notify.nttrans.out.changes[0].action,
454 NOTIFY_ACTION_ADDED, ret, done,
455 "wrong action (exp: ADDED)");
456 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
458 torture_assert_int_equal_goto(tctx,
459 notify.nttrans.out.changes[1].action,
460 NOTIFY_ACTION_ADDED, ret, done,
461 "wrong action (exp: ADDED)");
462 CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name,
463 "subdir-name\\subname1", STR_UNICODE);
464 torture_assert_int_equal_goto(tctx,
465 notify.nttrans.out.changes[2].action,
466 NOTIFY_ACTION_ADDED, ret, done,
467 "wrong action (exp: ADDED)");
468 CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name,
469 "subdir-name\\subname2", STR_UNICODE);
470 torture_assert_int_equal_goto(tctx,
471 notify.nttrans.out.changes[3].action,
472 NOTIFY_ACTION_OLD_NAME, ret, done,
473 "wrong action (exp: OLD_NAME)");
474 CHECK_WSTR(tctx, notify.nttrans.out.changes[3].name,
475 "subdir-name\\subname1", STR_UNICODE);
476 torture_assert_int_equal_goto(tctx,
477 notify.nttrans.out.changes[4].action,
478 NOTIFY_ACTION_NEW_NAME, ret, done,
479 "wrong action (exp: NEW_NAME)");
480 CHECK_WSTR(tctx, notify.nttrans.out.changes[4].name,
481 "subdir-name\\subname1-r", STR_UNICODE);
483 ret &= check_rename_reply(tctx,
484 cli, __LINE__, ¬ify.nttrans.out.changes[5],
485 NOTIFY_ACTION_ADDED, "subname2-r");
486 ret &= check_rename_reply(tctx,
487 cli, __LINE__, ¬ify.nttrans.out.changes[5],
488 NOTIFY_ACTION_REMOVED, "subdir-name\\subname2");
489 ret &= check_rename_reply(tctx,
490 cli, __LINE__, ¬ify.nttrans.out.changes[5],
491 NOTIFY_ACTION_MODIFIED, "subname2-r");
493 ret &= check_rename_reply(tctx,
494 cli, __LINE__, ¬ify.nttrans.out.changes[8],
495 NOTIFY_ACTION_OLD_NAME, "subname2-r");
496 ret &= check_rename_reply(tctx,
497 cli, __LINE__, ¬ify.nttrans.out.changes[8],
498 NOTIFY_ACTION_NEW_NAME, "subname3-r");
499 ret &= check_rename_reply(tctx,
500 cli, __LINE__, ¬ify.nttrans.out.changes[8],
501 NOTIFY_ACTION_MODIFIED, "subname3-r");
507 status = smb_raw_changenotify_recv(req2, tctx, ¬ify);
508 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
509 "smb_raw_changenotify_recv");
511 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
512 3, ret, done, "wrong number of changes");
513 torture_assert_int_equal_goto(tctx,
514 notify.nttrans.out.changes[0].action,
515 NOTIFY_ACTION_REMOVED, ret, done,
516 "wrong action (exp: REMOVED)");
517 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name,
518 "subdir-name\\subname1-r", STR_UNICODE);
519 torture_assert_int_equal_goto(tctx,
520 notify.nttrans.out.changes[1].action,
521 NOTIFY_ACTION_REMOVED, ret, done,
522 "wrong action (exp: REMOVED)");
523 CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name, "subdir-name",
525 torture_assert_int_equal_goto(tctx,
526 notify.nttrans.out.changes[2].action,
527 NOTIFY_ACTION_REMOVED, ret, done,
528 "wrong action (exp: REMOVED)");
529 CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name, "subname3-r",
533 smb_raw_exit(cli->session);
534 smbcli_deltree(cli->tree, BASEDIR);
539 testing of change notify mask change
541 static bool test_notify_mask_change(struct torture_context *tctx,
542 struct smbcli_state *cli)
546 union smb_notify notify;
549 struct smbcli_request *req1, *req2;
551 printf("TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
553 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
554 "Failed to setup up test directory: " BASEDIR);
557 get a handle on the directory
559 io.generic.level = RAW_OPEN_NTCREATEX;
560 io.ntcreatex.in.root_fid.fnum = 0;
561 io.ntcreatex.in.flags = 0;
562 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
563 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
564 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
565 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
566 io.ntcreatex.in.alloc_size = 0;
567 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
568 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
569 io.ntcreatex.in.security_flags = 0;
570 io.ntcreatex.in.fname = BASEDIR;
572 status = smb_raw_open(cli->tree, tctx, &io);
573 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
575 fnum = io.ntcreatex.out.file.fnum;
577 /* ask for a change notify, on file or directory name
578 changes. Setup both with and without recursion */
579 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
580 notify.nttrans.in.buffer_size = 1000;
581 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
582 notify.nttrans.in.file.fnum = fnum;
584 notify.nttrans.in.recursive = true;
585 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
587 notify.nttrans.in.recursive = false;
588 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
590 /* cancel initial requests so the buffer is setup */
591 smb_raw_ntcancel(req1);
592 status = smb_raw_changenotify_recv(req1, tctx, ¬ify);
593 torture_assert_ntstatus_equal_goto(tctx, status,
596 "smb_raw_changenotify_recv");
598 smb_raw_ntcancel(req2);
599 status = smb_raw_changenotify_recv(req2, tctx, ¬ify);
600 torture_assert_ntstatus_equal_goto(tctx, status,
603 "smb_raw_changenotify_recv");
605 notify.nttrans.in.recursive = true;
606 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
608 /* Set to hidden then back again. */
609 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));
610 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);
611 smbcli_unlink(cli->tree, BASEDIR "\\tname1");
613 status = smb_raw_changenotify_recv(req1, tctx, ¬ify);
614 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
615 "smb_raw_changenotify_recv");
617 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
618 1, ret, done, "wrong number of changes");
619 torture_assert_int_equal_goto(tctx,
620 notify.nttrans.out.changes[0].action,
621 NOTIFY_ACTION_MODIFIED, ret, done,
622 "wrong action (exp: MODIFIED)");
623 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "tname1",
626 /* Now try and change the mask to include other events.
627 * This should not work - once the mask is set on a directory
628 * fnum it seems to be fixed until the fnum is closed. */
630 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
631 notify.nttrans.in.recursive = true;
632 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
634 notify.nttrans.in.recursive = false;
635 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
637 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
638 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name\\subname1");
639 smbcli_close(cli->tree,
640 smbcli_open(cli->tree, BASEDIR "\\subdir-name\\subname2", O_CREAT, 0));
641 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname1", BASEDIR "\\subdir-name\\subname1-r");
642 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname2", BASEDIR "\\subname2-r");
643 smbcli_rename(cli->tree, BASEDIR "\\subname2-r", BASEDIR "\\subname3-r");
645 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name\\subname1-r");
646 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
647 smbcli_unlink(cli->tree, BASEDIR "\\subname3-r");
649 status = smb_raw_changenotify_recv(req1, tctx, ¬ify);
650 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
651 "smb_raw_changenotify_recv");
653 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
654 1, ret, done, "wrong number of changes");
655 torture_assert_int_equal_goto(tctx,
656 notify.nttrans.out.changes[0].action,
657 NOTIFY_ACTION_MODIFIED, ret, done,
658 "wrong action (exp: MODIFIED)");
659 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subname2-r",
662 status = smb_raw_changenotify_recv(req2, tctx, ¬ify);
663 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
664 "smb_raw_changenotify_recv");
666 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
667 1, ret, done, "wrong number of changes");
668 torture_assert_int_equal_goto(tctx,
669 notify.nttrans.out.changes[0].action,
670 NOTIFY_ACTION_MODIFIED, ret, done,
671 "wrong action (exp: MODIFIED)");
672 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subname3-r",
676 smb_raw_exit(cli->session);
677 smbcli_deltree(cli->tree, BASEDIR);
683 testing of mask bits for change notify
685 static bool test_notify_mask(struct torture_context *tctx,
686 struct smbcli_state *cli,
687 struct smbcli_state *cli2)
691 union smb_notify notify;
693 union smb_chkpath chkpath;
701 printf("TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
703 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
704 "Failed to setup up test directory: " BASEDIR);
706 tv = timeval_current_ofs(1000, 0);
707 t = timeval_to_nttime(&tv);
710 get a handle on the directory
712 io.generic.level = RAW_OPEN_NTCREATEX;
713 io.ntcreatex.in.root_fid.fnum = 0;
714 io.ntcreatex.in.flags = 0;
715 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
716 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
717 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
718 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
719 io.ntcreatex.in.alloc_size = 0;
720 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
721 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
722 io.ntcreatex.in.security_flags = 0;
723 io.ntcreatex.in.fname = BASEDIR;
725 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
726 notify.nttrans.in.buffer_size = 1000;
727 notify.nttrans.in.recursive = true;
729 chkpath.chkpath.in.path = "\\";
731 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, expected, nchanges) \
733 smbcli_getatr(cli->tree, test_name, NULL, NULL, NULL); \
734 for (mask=i=0;i<32;i++) { \
735 struct smbcli_request *req; \
736 status = smb_raw_open(cli->tree, tctx, &io); \
737 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
739 fnum = io.ntcreatex.out.file.fnum; \
741 notify.nttrans.in.file.fnum = fnum; \
742 notify.nttrans.in.completion_filter = (1<<i); \
743 req = smb_raw_changenotify_send(cli->tree, ¬ify); \
744 smb_raw_chkpath(cli->tree, &chkpath); \
746 smb_msleep(200); smb_raw_ntcancel(req); \
747 status = smb_raw_changenotify_recv(req, tctx, ¬ify); \
749 smbcli_close(cli->tree, fnum); \
750 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
751 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
753 /* special case to cope with file rename behaviour */ \
754 if (nchanges == 2 && notify.nttrans.out.num_changes == 1 && \
755 notify.nttrans.out.changes[0].action == NOTIFY_ACTION_MODIFIED && \
756 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
757 Action == NOTIFY_ACTION_OLD_NAME) { \
758 printf("(rename file special handling OK)\n"); \
760 torture_assert_int_equal_goto(tctx, \
761 notify.nttrans.out.num_changes,\
762 nchanges, ret, done, \
763 talloc_asprintf(tctx, \
764 "nchanges=%d expected=%d action=%d " \
766 notify.nttrans.out.num_changes, \
768 notify.nttrans.out.changes[0].action, \
769 notify.nttrans.in.completion_filter)); \
770 torture_assert_int_equal_goto(tctx, \
771 notify.nttrans.out.changes[0].action, \
773 talloc_asprintf(tctx, \
774 "nchanges=%d action=%d " \
775 "expectedAction=%d filter=0x%08x\n", \
776 notify.nttrans.out.num_changes, \
777 notify.nttrans.out.changes[0].action, \
779 notify.nttrans.in.completion_filter)); \
780 torture_assert_str_equal_goto(tctx, \
781 notify.nttrans.out.changes[0].name.s, \
782 "tname1", ret, done, \
783 talloc_asprintf(tctx, \
784 "nchanges=%d action=%d filter=0x%08x " \
785 "name=%s expected_name=tname1\n", \
786 notify.nttrans.out.num_changes, \
787 notify.nttrans.out.changes[0].action, \
788 notify.nttrans.in.completion_filter, \
789 notify.nttrans.out.changes[0].name.s));\
793 if ((expected) != mask) { \
794 torture_assert_int_not_equal_goto(tctx, ((expected) & ~mask), \
795 0, ret, done, "Too few bits"); \
796 printf("WARNING: trigger on too many bits. mask=0x%08x expected=0x%08x\n", \
801 printf("Testing mkdir\n");
802 NOTIFY_MASK_TEST("Testing mkdir",;,
803 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
804 smbcli_rmdir(cli2->tree, BASEDIR "\\tname1");,
806 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
808 printf("Testing create file\n");
809 NOTIFY_MASK_TEST("Testing create file",;,
810 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
811 smbcli_unlink(cli2->tree, BASEDIR "\\tname1");,
813 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
815 printf("Testing unlink\n");
816 NOTIFY_MASK_TEST("Testing unlink",
817 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
818 smbcli_unlink(cli2->tree, BASEDIR "\\tname1");,
820 NOTIFY_ACTION_REMOVED,
821 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
823 printf("Testing rmdir\n");
824 NOTIFY_MASK_TEST("Testing rmdir",
825 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
826 smbcli_rmdir(cli2->tree, BASEDIR "\\tname1");,
828 NOTIFY_ACTION_REMOVED,
829 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
831 printf("Testing rename file\n");
832 NOTIFY_MASK_TEST("Testing rename file",
833 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
834 smbcli_rename(cli2->tree, BASEDIR "\\tname1", BASEDIR "\\tname2");,
835 smbcli_unlink(cli->tree, BASEDIR "\\tname2");,
836 NOTIFY_ACTION_OLD_NAME,
837 FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_CREATION, 2);
839 printf("Testing rename dir\n");
840 NOTIFY_MASK_TEST("Testing rename dir",
841 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
842 smbcli_rename(cli2->tree, BASEDIR "\\tname1", BASEDIR "\\tname2");,
843 smbcli_rmdir(cli->tree, BASEDIR "\\tname2");,
844 NOTIFY_ACTION_OLD_NAME,
845 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
847 printf("Testing set path attribute\n");
848 NOTIFY_MASK_TEST("Testing set path attribute",
849 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
850 smbcli_setatr(cli2->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);,
851 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
852 NOTIFY_ACTION_MODIFIED,
853 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
855 printf("Testing set path write time\n");
856 NOTIFY_MASK_TEST("Testing set path write time",
857 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
858 smbcli_setatr(cli2->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_NORMAL, 1000);,
859 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
860 NOTIFY_ACTION_MODIFIED,
861 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
863 printf("Testing set file attribute\n");
864 NOTIFY_MASK_TEST("Testing set file attribute",
865 fnum2 = create_complex_file(cli2, tctx, BASEDIR "\\tname1");,
866 smbcli_fsetatr(cli2->tree, fnum2, FILE_ATTRIBUTE_HIDDEN, 0, 0, 0, 0);,
867 (smbcli_close(cli2->tree, fnum2), smbcli_unlink(cli2->tree, BASEDIR "\\tname1"));,
868 NOTIFY_ACTION_MODIFIED,
869 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
871 if (torture_setting_bool(tctx, "samba3", false)) {
872 printf("Samba3 does not yet support create times "
876 printf("Testing set file create time\n");
877 NOTIFY_MASK_TEST("Testing set file create time",
878 fnum2 = create_complex_file(cli, tctx,
879 BASEDIR "\\tname1");,
880 smbcli_fsetatr(cli->tree, fnum2, 0, t, 0, 0, 0);,
881 (smbcli_close(cli->tree, fnum2),
882 smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
883 NOTIFY_ACTION_MODIFIED,
884 FILE_NOTIFY_CHANGE_CREATION, 1);
887 printf("Testing set file access time\n");
888 NOTIFY_MASK_TEST("Testing set file access time",
889 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
890 smbcli_fsetatr(cli->tree, fnum2, 0, 0, t, 0, 0);,
891 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
892 NOTIFY_ACTION_MODIFIED,
893 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
895 printf("Testing set file write time\n");
896 NOTIFY_MASK_TEST("Testing set file write time",
897 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
898 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, t, 0);,
899 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
900 NOTIFY_ACTION_MODIFIED,
901 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
903 printf("Testing set file change time\n");
904 NOTIFY_MASK_TEST("Testing set file change time",
905 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
906 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, 0, t);,
907 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
908 NOTIFY_ACTION_MODIFIED,
912 printf("Testing write\n");
913 NOTIFY_MASK_TEST("Testing write",
914 fnum2 = create_complex_file(cli2, tctx, BASEDIR "\\tname1");,
915 smbcli_write(cli2->tree, fnum2, 1, &c, 10000, 1);,
916 (smbcli_close(cli2->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
917 NOTIFY_ACTION_MODIFIED,
920 printf("Testing truncate\n");
921 NOTIFY_MASK_TEST("Testing truncate",
922 fnum2 = create_complex_file(cli2, tctx, BASEDIR "\\tname1");,
923 smbcli_ftruncate(cli2->tree, fnum2, 10000);,
924 (smbcli_close(cli2->tree, fnum2), smbcli_unlink(cli2->tree, BASEDIR "\\tname1"));,
925 NOTIFY_ACTION_MODIFIED,
926 FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
929 smb_raw_exit(cli->session);
930 smbcli_deltree(cli->tree, BASEDIR);
935 basic testing of change notify on files
937 static bool test_notify_file(struct torture_context *tctx,
938 struct smbcli_state *cli)
944 union smb_notify notify;
945 struct smbcli_request *req;
947 const char *fname = BASEDIR "\\file.txt";
949 printf("TESTING CHANGE NOTIFY ON FILES\n");
951 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
952 "Failed to setup up test directory: " BASEDIR);
954 io.generic.level = RAW_OPEN_NTCREATEX;
955 io.ntcreatex.in.root_fid.fnum = 0;
956 io.ntcreatex.in.flags = 0;
957 io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
958 io.ntcreatex.in.create_options = 0;
959 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
960 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
961 io.ntcreatex.in.alloc_size = 0;
962 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
963 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
964 io.ntcreatex.in.security_flags = 0;
965 io.ntcreatex.in.fname = fname;
966 status = smb_raw_open(cli->tree, tctx, &io);
967 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
969 fnum = io.ntcreatex.out.file.fnum;
971 /* ask for a change notify,
972 on file or directory name changes */
973 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
974 notify.nttrans.in.file.fnum = fnum;
975 notify.nttrans.in.buffer_size = 1000;
976 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
977 notify.nttrans.in.recursive = false;
979 printf("Testing if notifies on file handles are invalid (should be)\n");
981 req = smb_raw_changenotify_send(cli->tree, ¬ify);
982 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
983 torture_assert_ntstatus_equal_goto(tctx, status,
984 NT_STATUS_INVALID_PARAMETER,
986 "smb_raw_changenotify_recv");
988 cl.close.level = RAW_CLOSE_CLOSE;
989 cl.close.in.file.fnum = fnum;
990 cl.close.in.write_time = 0;
991 status = smb_raw_close(cli->tree, &cl);
992 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
995 status = smbcli_unlink(cli->tree, fname);
996 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1000 smb_raw_exit(cli->session);
1001 smbcli_deltree(cli->tree, BASEDIR);
1006 basic testing of change notifies followed by a tdis
1008 static bool test_notify_tdis(struct torture_context *tctx,
1009 struct smbcli_state *cli1)
1013 union smb_notify notify;
1016 struct smbcli_request *req;
1017 struct smbcli_state *cli = NULL;
1019 printf("TESTING CHANGE NOTIFY FOLLOWED BY TDIS\n");
1021 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
1022 "Failed to setup up test directory: " BASEDIR);
1024 torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1025 "Failed to open connection.");
1028 get a handle on the directory
1030 io.generic.level = RAW_OPEN_NTCREATEX;
1031 io.ntcreatex.in.root_fid.fnum = 0;
1032 io.ntcreatex.in.flags = 0;
1033 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1034 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1035 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1036 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1037 io.ntcreatex.in.alloc_size = 0;
1038 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1039 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1040 io.ntcreatex.in.security_flags = 0;
1041 io.ntcreatex.in.fname = BASEDIR;
1043 status = smb_raw_open(cli->tree, tctx, &io);
1044 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1046 fnum = io.ntcreatex.out.file.fnum;
1048 /* ask for a change notify,
1049 on file or directory name changes */
1050 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1051 notify.nttrans.in.buffer_size = 1000;
1052 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1053 notify.nttrans.in.file.fnum = fnum;
1054 notify.nttrans.in.recursive = true;
1056 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1058 status = smbcli_tdis(cli);
1059 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1063 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1064 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1065 "smb_raw_changenotify_recv");
1066 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1067 0, ret, done, "no changes expected");
1070 torture_close_connection(cli);
1071 smbcli_deltree(cli1->tree, BASEDIR);
1076 basic testing of change notifies followed by a exit
1078 static bool test_notify_exit(struct torture_context *tctx,
1079 struct smbcli_state *cli1)
1083 union smb_notify notify;
1086 struct smbcli_request *req;
1087 struct smbcli_state *cli = NULL;
1089 printf("TESTING CHANGE NOTIFY FOLLOWED BY EXIT\n");
1091 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
1092 "Failed to setup up test directory: " BASEDIR);
1094 torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1095 "Failed to open connection.");
1098 get a handle on the directory
1100 io.generic.level = RAW_OPEN_NTCREATEX;
1101 io.ntcreatex.in.root_fid.fnum = 0;
1102 io.ntcreatex.in.flags = 0;
1103 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1104 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1105 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1106 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1107 io.ntcreatex.in.alloc_size = 0;
1108 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1109 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1110 io.ntcreatex.in.security_flags = 0;
1111 io.ntcreatex.in.fname = BASEDIR;
1113 status = smb_raw_open(cli->tree, tctx, &io);
1114 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1116 fnum = io.ntcreatex.out.file.fnum;
1118 /* ask for a change notify,
1119 on file or directory name changes */
1120 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1121 notify.nttrans.in.buffer_size = 1000;
1122 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1123 notify.nttrans.in.file.fnum = fnum;
1124 notify.nttrans.in.recursive = true;
1126 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1128 status = smb_raw_exit(cli->session);
1129 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1132 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1133 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1134 "smb_raw_changenotify_recv");
1135 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1136 0, ret, done, "no changes expected");
1139 torture_close_connection(cli);
1140 smbcli_deltree(cli1->tree, BASEDIR);
1145 basic testing of change notifies followed by a ulogoff
1147 static bool test_notify_ulogoff(struct torture_context *tctx,
1148 struct smbcli_state *cli1)
1152 union smb_notify notify;
1155 struct smbcli_request *req;
1156 struct smbcli_state *cli = NULL;
1158 printf("TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1160 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
1161 "Failed to setup up test directory: " BASEDIR);
1163 torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1164 "Failed to open connection.");
1167 get a handle on the directory
1169 io.generic.level = RAW_OPEN_NTCREATEX;
1170 io.ntcreatex.in.root_fid.fnum = 0;
1171 io.ntcreatex.in.flags = 0;
1172 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1173 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1174 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1175 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1176 io.ntcreatex.in.alloc_size = 0;
1177 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1178 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1179 io.ntcreatex.in.security_flags = 0;
1180 io.ntcreatex.in.fname = BASEDIR;
1182 status = smb_raw_open(cli->tree, tctx, &io);
1183 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1185 fnum = io.ntcreatex.out.file.fnum;
1187 /* ask for a change notify,
1188 on file or directory name changes */
1189 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1190 notify.nttrans.in.buffer_size = 1000;
1191 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1192 notify.nttrans.in.file.fnum = fnum;
1193 notify.nttrans.in.recursive = true;
1195 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1197 status = smb_raw_ulogoff(cli->session);
1198 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1201 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1202 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1203 "smb_raw_changenotify_recv");
1204 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1205 0, ret, done, "no changes expected");
1208 torture_close_connection(cli);
1209 smbcli_deltree(cli1->tree, BASEDIR);
1213 static void tcp_dis_handler(struct smbcli_transport *t, void *p)
1215 struct smbcli_state *cli = (struct smbcli_state *)p;
1216 smbcli_transport_dead(cli->transport, NT_STATUS_LOCAL_DISCONNECT);
1217 cli->transport = NULL;
1221 basic testing of change notifies followed by tcp disconnect
1223 static bool test_notify_tcp_dis(struct torture_context *tctx,
1224 struct smbcli_state *cli1)
1228 union smb_notify notify;
1231 struct smbcli_request *req;
1232 struct smbcli_state *cli = NULL;
1234 printf("TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1236 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
1237 "Failed to setup up test directory: " BASEDIR);
1239 torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1240 "Failed to open connection.");
1243 get a handle on the directory
1245 io.generic.level = RAW_OPEN_NTCREATEX;
1246 io.ntcreatex.in.root_fid.fnum = 0;
1247 io.ntcreatex.in.flags = 0;
1248 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1249 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1250 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1251 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1252 io.ntcreatex.in.alloc_size = 0;
1253 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1254 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1255 io.ntcreatex.in.security_flags = 0;
1256 io.ntcreatex.in.fname = BASEDIR;
1258 status = smb_raw_open(cli->tree, tctx, &io);
1259 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1261 fnum = io.ntcreatex.out.file.fnum;
1263 /* ask for a change notify,
1264 on file or directory name changes */
1265 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1266 notify.nttrans.in.buffer_size = 1000;
1267 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1268 notify.nttrans.in.file.fnum = fnum;
1269 notify.nttrans.in.recursive = true;
1271 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1273 smbcli_transport_idle_handler(cli->transport, tcp_dis_handler, 250, cli);
1275 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1276 torture_assert_ntstatus_equal_goto(tctx, status,
1277 NT_STATUS_LOCAL_DISCONNECT,
1279 "smb_raw_changenotify_recv");
1282 torture_close_connection(cli);
1283 smbcli_deltree(cli1->tree, BASEDIR);
1288 test setting up two change notify requests on one handle
1290 static bool test_notify_double(struct torture_context *tctx,
1291 struct smbcli_state *cli)
1295 union smb_notify notify;
1298 struct smbcli_request *req1, *req2;
1300 printf("TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1302 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
1303 "Failed to setup up test directory: " BASEDIR);
1306 get a handle on the directory
1308 io.generic.level = RAW_OPEN_NTCREATEX;
1309 io.ntcreatex.in.root_fid.fnum = 0;
1310 io.ntcreatex.in.flags = 0;
1311 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1312 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1313 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1314 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1315 io.ntcreatex.in.alloc_size = 0;
1316 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1317 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1318 io.ntcreatex.in.security_flags = 0;
1319 io.ntcreatex.in.fname = BASEDIR;
1321 status = smb_raw_open(cli->tree, tctx, &io);
1322 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1324 fnum = io.ntcreatex.out.file.fnum;
1326 /* ask for a change notify,
1327 on file or directory name changes */
1328 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1329 notify.nttrans.in.buffer_size = 1000;
1330 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1331 notify.nttrans.in.file.fnum = fnum;
1332 notify.nttrans.in.recursive = true;
1334 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1335 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
1337 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1339 status = smb_raw_changenotify_recv(req1, tctx, ¬ify);
1340 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1341 "smb_raw_changenotify_recv");
1342 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1343 1, ret, done, "wrong number of changes");
1344 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1347 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name2");
1349 status = smb_raw_changenotify_recv(req2, tctx, ¬ify);
1350 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1351 "smb_raw_changenotify_recv");
1352 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1353 1, ret, done, "wrong number of changes");
1354 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name2",
1358 smb_raw_exit(cli->session);
1359 smbcli_deltree(cli->tree, BASEDIR);
1365 test multiple change notifies at different depths and with/without recursion
1367 static bool test_notify_tree(struct torture_context *tctx,
1368 struct smbcli_state *cli,
1369 struct smbcli_state *cli2)
1372 union smb_notify notify;
1374 struct smbcli_request *req;
1384 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 30 },
1385 {BASEDIR "\\zqy", true, FILE_NOTIFY_CHANGE_NAME, 8 },
1386 {BASEDIR "\\atsy", true, FILE_NOTIFY_CHANGE_NAME, 4 },
1387 {BASEDIR "\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1388 {BASEDIR "\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME, 13 },
1389 {BASEDIR "\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME, 7 },
1390 {BASEDIR "\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1391 {BASEDIR "\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1392 {BASEDIR "\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1393 {BASEDIR "\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1394 {BASEDIR "\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1395 {BASEDIR "\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1396 {BASEDIR "\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME, 40 },
1397 {BASEDIR, true, FILE_NOTIFY_CHANGE_NAME, 40 },
1398 {BASEDIR, false,FILE_NOTIFY_CHANGE_NAME, 6 },
1399 {BASEDIR "\\atsy", false,FILE_NOTIFY_CHANGE_NAME, 4 },
1400 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1401 {BASEDIR "\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1402 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1403 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1407 bool all_done = false;
1409 printf("TESTING CHANGE NOTIFY FOR DIFFERENT DEPTHS\n");
1411 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
1412 "Failed to setup up test directory: " BASEDIR);
1414 io.generic.level = RAW_OPEN_NTCREATEX;
1415 io.ntcreatex.in.root_fid.fnum = 0;
1416 io.ntcreatex.in.flags = 0;
1417 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1418 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1419 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1420 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1421 io.ntcreatex.in.alloc_size = 0;
1422 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1423 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1424 io.ntcreatex.in.security_flags = 0;
1426 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1427 notify.nttrans.in.buffer_size = 20000;
1430 setup the directory tree, and the notify buffer on each directory
1432 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1433 io.ntcreatex.in.fname = dirs[i].path;
1434 status = smb_raw_open(cli->tree, tctx, &io);
1435 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1437 dirs[i].fnum = io.ntcreatex.out.file.fnum;
1439 notify.nttrans.in.completion_filter = dirs[i].filter;
1440 notify.nttrans.in.file.fnum = dirs[i].fnum;
1441 notify.nttrans.in.recursive = dirs[i].recursive;
1442 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1443 smb_raw_ntcancel(req);
1444 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1445 torture_assert_ntstatus_equal_goto(tctx, status,
1446 NT_STATUS_CANCELLED,
1448 "smb_raw_changenotify_recv");
1451 /* trigger 2 events in each dir */
1452 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1453 char *path = talloc_asprintf(tctx, "%s\\test.dir", dirs[i].path);
1455 * Make notifies a bit more interesting in a cluster
1456 * by doing the changes against different nodes with
1459 smbcli_mkdir(cli->tree, path);
1460 smbcli_rmdir(cli2->tree, path);
1464 /* give a bit of time for the events to propogate */
1465 tv = timeval_current();
1468 /* count events that have happened in each dir */
1469 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1470 notify.nttrans.in.file.fnum = dirs[i].fnum;
1471 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1472 smb_raw_ntcancel(req);
1473 notify.nttrans.out.num_changes = 0;
1474 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1475 dirs[i].counted += notify.nttrans.out.num_changes;
1480 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1481 if (dirs[i].counted != dirs[i].expected) {
1485 } while (!all_done && timeval_elapsed(&tv) < 20);
1487 printf("took %.4f seconds to propogate all events\n", timeval_elapsed(&tv));
1489 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1490 torture_assert_int_equal_goto(tctx,
1491 dirs[i].counted, dirs[i].expected, ret, done,
1492 talloc_asprintf(tctx,
1493 "unexpected number of events for '%s'",
1498 run from the back, closing and deleting
1500 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1501 smbcli_close(cli->tree, dirs[i].fnum);
1502 smbcli_rmdir(cli->tree, dirs[i].path);
1506 smb_raw_exit(cli->session);
1507 smbcli_deltree(cli->tree, BASEDIR);
1512 Test response when cached server events exceed single NT NOTFIY response
1515 static bool test_notify_overflow(struct torture_context *tctx,
1516 struct smbcli_state *cli)
1520 union smb_notify notify;
1524 struct smbcli_request *req1;
1527 printf("TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1529 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
1530 "Failed to setup up test directory: " BASEDIR);
1532 /* get a handle on the directory */
1533 io.generic.level = RAW_OPEN_NTCREATEX;
1534 io.ntcreatex.in.root_fid.fnum = 0;
1535 io.ntcreatex.in.flags = 0;
1536 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1537 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1538 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1539 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1540 NTCREATEX_SHARE_ACCESS_WRITE;
1541 io.ntcreatex.in.alloc_size = 0;
1542 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1543 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1544 io.ntcreatex.in.security_flags = 0;
1545 io.ntcreatex.in.fname = BASEDIR;
1547 status = smb_raw_open(cli->tree, tctx, &io);
1548 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1550 fnum = io.ntcreatex.out.file.fnum;
1552 /* ask for a change notify, on name changes. */
1553 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1554 notify.nttrans.in.buffer_size = 1000;
1555 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1556 notify.nttrans.in.file.fnum = fnum;
1558 notify.nttrans.in.recursive = true;
1559 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1561 /* cancel initial requests so the buffer is setup */
1562 smb_raw_ntcancel(req1);
1563 status = smb_raw_changenotify_recv(req1, tctx, ¬ify);
1564 torture_assert_ntstatus_equal_goto(tctx, status,
1565 NT_STATUS_CANCELLED,
1567 "smb_raw_changenotify_recv");
1569 /* open a lot of files, filling up the server side notify buffer */
1570 printf("Testing overflowed buffer notify on create of %d files\n",
1572 for (i=0;i<count;i++) {
1573 char *fname = talloc_asprintf(cli, BASEDIR "\\test%d.txt", i);
1574 int fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR,
1576 torture_assert_int_not_equal_goto(tctx, fnum2, -1, ret, done,
1577 talloc_asprintf(tctx, "Failed to create %s - %s",
1578 fname, smbcli_errstr(cli->tree)));
1580 smbcli_close(cli->tree, fnum2);
1583 /* expect that 0 events will be returned with NT_STATUS_OK */
1584 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1585 status = smb_raw_changenotify_recv(req1, tctx, ¬ify);
1586 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1587 "smb_raw_changenotify_recv");
1588 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1589 0, ret, done, "no changes expected");
1592 smb_raw_exit(cli->session);
1593 smbcli_deltree(cli->tree, BASEDIR);
1598 Test if notifications are returned for changes to the base directory.
1601 static bool test_notify_basedir(struct torture_context *tctx,
1602 struct smbcli_state *cli)
1606 union smb_notify notify;
1609 struct smbcli_request *req1;
1611 printf("TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1613 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
1614 "Failed to setup up test directory: " BASEDIR);
1616 /* get a handle on the directory */
1617 io.generic.level = RAW_OPEN_NTCREATEX;
1618 io.ntcreatex.in.root_fid.fnum = 0;
1619 io.ntcreatex.in.flags = 0;
1620 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1621 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1622 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1623 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1624 NTCREATEX_SHARE_ACCESS_WRITE;
1625 io.ntcreatex.in.alloc_size = 0;
1626 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1627 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1628 io.ntcreatex.in.security_flags = 0;
1629 io.ntcreatex.in.fname = BASEDIR;
1631 status = smb_raw_open(cli->tree, tctx, &io);
1632 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1634 fnum = io.ntcreatex.out.file.fnum;
1636 /* create a test file that will also be modified */
1637 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1",
1640 /* ask for a change notify, on attribute changes. */
1641 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1642 notify.nttrans.in.buffer_size = 1000;
1643 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
1644 notify.nttrans.in.file.fnum = fnum;
1645 notify.nttrans.in.recursive = true;
1647 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1649 /* set attribute on the base dir */
1650 smbcli_setatr(cli->tree, BASEDIR, FILE_ATTRIBUTE_HIDDEN, 0);
1652 /* set attribute on a file to assure we receive a notification */
1653 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);
1656 /* check how many responses were given, expect only 1 for the file */
1657 status = smb_raw_changenotify_recv(req1, tctx, ¬ify);
1658 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1659 "smb_raw_changenotify_recv");
1660 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1661 1, ret, done, "wrong number of changes");
1662 torture_assert_int_equal_goto(tctx,
1663 notify.nttrans.out.changes[0].action,
1664 NOTIFY_ACTION_MODIFIED, ret, done,
1665 "wrong action (exp: MODIFIED)");
1666 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "tname1",
1670 smb_raw_exit(cli->session);
1671 smbcli_deltree(cli->tree, BASEDIR);
1677 create a secondary tree connect - used to test for a bug in Samba3 messaging
1680 static struct smbcli_tree *secondary_tcon(struct smbcli_state *cli,
1681 struct torture_context *tctx)
1684 const char *share, *host;
1685 struct smbcli_tree *tree;
1686 union smb_tcon tcon;
1688 share = torture_setting_string(tctx, "share", NULL);
1689 host = torture_setting_string(tctx, "host", NULL);
1691 printf("create a second tree context on the same session\n");
1692 tree = smbcli_tree_init(cli->session, tctx, false);
1694 tcon.generic.level = RAW_TCON_TCONX;
1695 tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
1696 tcon.tconx.in.password = data_blob(NULL, 0);
1697 tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
1698 tcon.tconx.in.device = "A:";
1699 status = smb_raw_tcon(tree, tctx, &tcon);
1700 if (!NT_STATUS_IS_OK(status)) {
1702 printf("Failed to create secondary tree\n");
1706 tree->tid = tcon.tconx.out.tid;
1707 printf("tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
1714 very simple change notify test
1716 static bool test_notify_tcon(struct torture_context *tctx,
1717 struct smbcli_state *cli)
1721 union smb_notify notify;
1724 struct smbcli_request *req;
1725 extern int torture_numops;
1726 struct smbcli_tree *tree = NULL;
1728 printf("TESTING SIMPLE CHANGE NOTIFY\n");
1730 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
1731 "Failed to setup up test directory: " BASEDIR);
1734 get a handle on the directory
1736 io.generic.level = RAW_OPEN_NTCREATEX;
1737 io.ntcreatex.in.root_fid.fnum = 0;
1738 io.ntcreatex.in.flags = 0;
1739 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1740 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1741 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1742 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1743 io.ntcreatex.in.alloc_size = 0;
1744 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1745 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1746 io.ntcreatex.in.security_flags = 0;
1747 io.ntcreatex.in.fname = BASEDIR;
1749 status = smb_raw_open(cli->tree, tctx, &io);
1750 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1752 fnum = io.ntcreatex.out.file.fnum;
1754 status = smb_raw_open(cli->tree, tctx, &io);
1755 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1758 /* ask for a change notify,
1759 on file or directory name changes */
1760 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1761 notify.nttrans.in.buffer_size = 1000;
1762 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1763 notify.nttrans.in.file.fnum = fnum;
1764 notify.nttrans.in.recursive = true;
1766 printf("Testing notify mkdir\n");
1767 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1768 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1770 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1771 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1772 "smb_raw_changenotify_recv");
1774 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1775 1, ret, done, "wrong number of changes");
1776 torture_assert_int_equal_goto(tctx,
1777 notify.nttrans.out.changes[0].action,
1778 NOTIFY_ACTION_ADDED, ret, done,
1779 "wrong action (exp: ADDED)");
1780 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1783 printf("Testing notify rmdir\n");
1784 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1785 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
1787 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1788 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1789 "smb_raw_changenotify_recv");
1790 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1791 1, ret, done, "wrong number of changes");
1792 torture_assert_int_equal_goto(tctx,
1793 notify.nttrans.out.changes[0].action,
1794 NOTIFY_ACTION_REMOVED, ret, done,
1795 "wrong action (exp: REMOVED)");
1796 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1799 printf("SIMPLE CHANGE NOTIFY OK\n");
1801 printf("TESTING WITH SECONDARY TCON\n");
1802 tree = secondary_tcon(cli, tctx);
1803 torture_assert_not_null_goto(tctx, tree, ret, done,
1804 "failed to create secondary tcon");
1806 printf("Testing notify mkdir\n");
1807 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1808 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1810 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1811 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1812 "smb_raw_changenotify_recv");
1814 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1815 1, ret, done, "wrong number of changes");
1816 torture_assert_int_equal_goto(tctx,
1817 notify.nttrans.out.changes[0].action,
1818 NOTIFY_ACTION_ADDED, ret, done,
1819 "wrong action (exp: ADDED)");
1820 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1823 printf("Testing notify rmdir\n");
1824 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1825 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
1827 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1828 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1829 "smb_raw_changenotify_recv");
1830 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1831 1, ret, done, "wrong number of changes");
1832 torture_assert_int_equal_goto(tctx,
1833 notify.nttrans.out.changes[0].action,
1834 NOTIFY_ACTION_REMOVED, ret, done,
1835 "wrong action (exp: REMOVED)");
1836 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1839 printf("CHANGE NOTIFY WITH TCON OK\n");
1841 printf("Disconnecting secondary tree\n");
1842 status = smb_tree_disconnect(tree);
1843 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1844 "smb_tree_disconnect");
1847 printf("Testing notify mkdir\n");
1848 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1849 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1851 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1852 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1853 "smb_raw_changenotify_recv");
1855 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1856 1, ret, done, "wrong number of changes");
1857 torture_assert_int_equal_goto(tctx,
1858 notify.nttrans.out.changes[0].action,
1859 NOTIFY_ACTION_ADDED, ret, done,
1860 "wrong action (exp: ADDED)");
1861 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1864 printf("Testing notify rmdir\n");
1865 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1866 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
1868 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1869 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1870 "smb_raw_changenotify_recv");
1871 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1872 1, ret, done, "wrong number of changes");
1873 torture_assert_int_equal_goto(tctx,
1874 notify.nttrans.out.changes[0].action,
1875 NOTIFY_ACTION_REMOVED, ret, done,
1876 "wrong action (exp: REMOVED)");
1877 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1880 printf("CHANGE NOTIFY WITH TDIS OK\n");
1882 smb_raw_exit(cli->session);
1883 smbcli_deltree(cli->tree, BASEDIR);
1889 testing alignment of multiple change notify infos
1891 static bool test_notify_alignment(struct torture_context *tctx,
1892 struct smbcli_state *cli)
1895 union smb_notify notify;
1898 struct smbcli_request *req;
1899 const char *fname = BASEDIR "\\starter";
1900 const char *fnames[] = { "a",
1904 int num_names = ARRAY_SIZE(fnames);
1907 torture_comment(tctx, "TESTING CHANGE NOTIFY REPLY ALIGNMENT\n");
1909 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
1910 "Failed to setup up test directory: " BASEDIR);
1912 /* get a handle on the directory */
1913 io.generic.level = RAW_OPEN_NTCREATEX;
1914 io.ntcreatex.in.root_fid.fnum = 0;
1915 io.ntcreatex.in.flags = 0;
1916 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1917 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1918 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1919 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1920 NTCREATEX_SHARE_ACCESS_WRITE;
1921 io.ntcreatex.in.alloc_size = 0;
1922 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1923 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1924 io.ntcreatex.in.security_flags = 0;
1925 io.ntcreatex.in.fname = BASEDIR;
1927 status = smb_raw_open(cli->tree, tctx, &io);
1928 torture_assert_ntstatus_ok(tctx, status, "smb_raw_open");
1929 fnum = io.ntcreatex.out.file.fnum;
1931 /* ask for a change notify, on file creation */
1932 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1933 notify.nttrans.in.buffer_size = 1000;
1934 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_FILE_NAME;
1935 notify.nttrans.in.file.fnum = fnum;
1936 notify.nttrans.in.recursive = false;
1938 /* start change tracking */
1939 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1941 fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
1942 torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
1943 smbcli_close(cli->tree, fnum2);
1945 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1946 torture_assert_ntstatus_ok(tctx, status, "smb_raw_changenotify_recv");
1948 /* create 4 files that will cause CHANGE_NOTIFY_INFO structures
1949 * to be returned in the same packet with all possible 4-byte padding
1950 * permutations. As per MS-CIFS 2.2.7.4.2 these structures should be
1951 * 4-byte aligned. */
1953 for (i = 0; i < num_names; i++) {
1954 fpath = talloc_asprintf(tctx, "%s\\%s", BASEDIR, fnames[i]);
1955 fnum2 = smbcli_open(cli->tree, fpath,
1956 O_CREAT|O_RDWR, DENY_NONE);
1957 torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
1958 smbcli_close(cli->tree, fnum2);
1962 /* We send a notify packet, and let smb_raw_changenotify_recv() do
1963 * the alignment checking for us. */
1964 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1965 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1966 torture_assert_ntstatus_ok(tctx, status, "smb_raw_changenotify_recv");
1968 /* Do basic checking for correctness. */
1969 torture_assert(tctx, notify.nttrans.out.num_changes == num_names, "");
1970 for (i = 0; i < num_names; i++) {
1971 torture_assert(tctx, notify.nttrans.out.changes[i].action ==
1972 NOTIFY_ACTION_ADDED, "");
1973 CHECK_WSTR(tctx, notify.nttrans.out.changes[i].name, fnames[i],
1977 smb_raw_exit(cli->session);
1978 smbcli_deltree(cli->tree, BASEDIR);
1982 struct torture_suite *torture_raw_notify(TALLOC_CTX *mem_ctx)
1984 struct torture_suite *suite = torture_suite_create(mem_ctx, "notify");
1986 torture_suite_add_1smb_test(suite, "tcon", test_notify_tcon);
1987 torture_suite_add_2smb_test(suite, "dir", test_notify_dir);
1988 torture_suite_add_2smb_test(suite, "mask", test_notify_mask);
1989 torture_suite_add_2smb_test(suite, "recursive", test_notify_recursive);
1990 torture_suite_add_1smb_test(suite, "mask_change",
1991 test_notify_mask_change);
1992 torture_suite_add_1smb_test(suite, "file", test_notify_file);
1993 torture_suite_add_1smb_test(suite, "tdis", test_notify_tdis);
1994 torture_suite_add_1smb_test(suite, "exit", test_notify_exit);
1995 torture_suite_add_1smb_test(suite, "ulogoff", test_notify_ulogoff);
1996 torture_suite_add_1smb_test(suite, "tcp_dis", test_notify_tcp_dis);
1997 torture_suite_add_1smb_test(suite, "double", test_notify_double);
1998 torture_suite_add_2smb_test(suite, "tree", test_notify_tree);
1999 torture_suite_add_1smb_test(suite, "overflow", test_notify_overflow);
2000 torture_suite_add_1smb_test(suite, "basedir", test_notify_basedir);
2001 torture_suite_add_1smb_test(suite, "alignment", test_notify_alignment);