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 if (!field.s || strcmp(field.s, value) || \
33 wire_bad_flags(&field, flags, cli->transport)) { \
34 torture_result(tctx, TORTURE_FAIL, \
35 "(%d) %s [%s] != %s\n", __LINE__, #field, field.s, value); \
40 basic testing of change notify on directories
42 static bool test_notify_dir(struct torture_context *mem_ctx,
43 struct smbcli_state *cli,
44 struct smbcli_state *cli2)
48 union smb_notify notify;
51 int i, count, fnum, fnum2;
52 struct smbcli_request *req, *req2;
53 extern int torture_numops;
55 printf("TESTING CHANGE NOTIFY ON DIRECTORIES\n");
57 if (!torture_setup_dir(cli, BASEDIR)) {
62 get a handle on the directory
64 io.generic.level = RAW_OPEN_NTCREATEX;
65 io.ntcreatex.in.root_fid.fnum = 0;
66 io.ntcreatex.in.flags = 0;
67 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
68 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
69 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
70 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
71 io.ntcreatex.in.alloc_size = 0;
72 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
73 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
74 io.ntcreatex.in.security_flags = 0;
75 io.ntcreatex.in.fname = BASEDIR;
77 status = smb_raw_open(cli->tree, mem_ctx, &io);
78 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
80 fnum = io.ntcreatex.out.file.fnum;
82 status = smb_raw_open(cli->tree, mem_ctx, &io);
83 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
85 fnum2 = io.ntcreatex.out.file.fnum;
87 /* ask for a change notify,
88 on file or directory name changes */
89 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
90 notify.nttrans.in.buffer_size = 1000;
91 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
92 notify.nttrans.in.file.fnum = fnum;
93 notify.nttrans.in.recursive = true;
95 printf("Testing notify cancel\n");
97 req = smb_raw_changenotify_send(cli->tree, ¬ify);
98 smb_raw_ntcancel(req);
99 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
100 torture_assert_ntstatus_equal_goto(mem_ctx, status, NT_STATUS_CANCELLED,
102 "smb_raw_changenotify_recv");
104 printf("Testing notify mkdir\n");
106 req = smb_raw_changenotify_send(cli->tree, ¬ify);
107 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name");
109 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
110 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
111 "smb_raw_changenotify_recv");
113 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
114 1, ret, done, "more than one change");
115 torture_assert_int_equal_goto(mem_ctx,
116 notify.nttrans.out.changes[0].action,
117 NOTIFY_ACTION_ADDED, ret, done,
118 "wrong action (exp: ADDED)");
119 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subdir-name",
122 printf("Testing notify rmdir\n");
124 req = smb_raw_changenotify_send(cli->tree, ¬ify);
125 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
127 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
128 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
129 "smb_raw_changenotify_recv");
130 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
131 1, ret, done, "more than one change");
132 torture_assert_int_equal_goto(mem_ctx,
133 notify.nttrans.out.changes[0].action,
134 NOTIFY_ACTION_REMOVED, ret, done,
135 "wrong action (exp: REMOVED)");
136 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subdir-name",
139 printf("Testing notify mkdir - rmdir - mkdir - rmdir\n");
141 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name");
142 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
143 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name");
144 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
146 req = smb_raw_changenotify_send(cli->tree, ¬ify);
147 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
148 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
149 "smb_raw_changenotify_recv");
150 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
151 4, ret, done, "wrong number of changes");
152 torture_assert_int_equal_goto(mem_ctx,
153 notify.nttrans.out.changes[0].action,
154 NOTIFY_ACTION_ADDED, ret, done,
155 "wrong action (exp: ADDED)");
156 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subdir-name",
158 torture_assert_int_equal_goto(mem_ctx,
159 notify.nttrans.out.changes[1].action,
160 NOTIFY_ACTION_REMOVED, ret, done,
161 "wrong action (exp: REMOVED)");
162 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[1].name, "subdir-name",
164 torture_assert_int_equal_goto(mem_ctx,
165 notify.nttrans.out.changes[2].action,
166 NOTIFY_ACTION_ADDED, ret, done,
167 "wrong action (exp: ADDED)");
168 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[2].name, "subdir-name",
170 torture_assert_int_equal_goto(mem_ctx,
171 notify.nttrans.out.changes[3].action,
172 NOTIFY_ACTION_REMOVED, ret, done,
173 "wrong action (exp: REMOVED)");
174 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[3].name, "subdir-name",
177 count = torture_numops;
178 printf("Testing buffered notify on create of %d files\n", count);
179 for (i=0;i<count;i++) {
180 char *fname = talloc_asprintf(cli, BASEDIR "\\test%d.txt", i);
181 int fnum3 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
183 printf("Failed to create %s - %s\n",
184 fname, smbcli_errstr(cli->tree));
189 smbcli_close(cli->tree, fnum3);
192 /* (1st notify) setup a new notify on a different directory handle.
193 This new notify won't see the events above. */
194 notify.nttrans.in.file.fnum = fnum2;
195 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
197 /* (2nd notify) whereas this notify will see the above buffered events,
198 and it directly returns the buffered events */
199 notify.nttrans.in.file.fnum = fnum;
200 req = smb_raw_changenotify_send(cli->tree, ¬ify);
202 status = smbcli_unlink(cli->tree, BASEDIR "\\nonexistent.txt");
203 torture_assert_ntstatus_equal_goto(mem_ctx, status,
204 NT_STATUS_OBJECT_NAME_NOT_FOUND,
208 /* (1st unlink) as the 2nd notify directly returns,
209 this unlink is only seen by the 1st notify and
210 the 3rd notify (later) */
211 printf("Testing notify on unlink for the first file\n");
212 status = smbcli_unlink(cli2->tree, BASEDIR "\\test0.txt");
213 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
216 /* receive the reply from the 2nd notify */
217 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
218 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
219 "smb_raw_changenotify_recv");
221 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
223 "wrong number of changes");
224 for (i=1;i<count;i++) {
225 torture_assert_int_equal_goto(mem_ctx,
226 notify.nttrans.out.changes[i].action,
227 NOTIFY_ACTION_ADDED, ret, done,
228 "wrong action (exp: ADDED)");
230 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "test0.txt",
233 printf("and now from the 1st notify\n");
234 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
235 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
236 "smb_raw_changenotify_recv");
237 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
238 1, ret, done, "wrong number of changes");
239 torture_assert_int_equal_goto(mem_ctx,
240 notify.nttrans.out.changes[0].action,
241 NOTIFY_ACTION_REMOVED, ret, done,
242 "wrong action (exp: REMOVED)");
243 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "test0.txt",
246 printf("(3rd notify) this notify will only see the 1st unlink\n");
247 req = smb_raw_changenotify_send(cli->tree, ¬ify);
249 status = smbcli_unlink(cli->tree, BASEDIR "\\nonexistent.txt");
250 torture_assert_ntstatus_equal_goto(mem_ctx, status,
251 NT_STATUS_OBJECT_NAME_NOT_FOUND,
255 printf("Testing notify on wildcard unlink for %d files\n", count-1);
256 /* (2nd unlink) do a wildcard unlink */
257 status = smbcli_unlink(cli2->tree, BASEDIR "\\test*.txt");
258 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
259 "smb_raw_changenotify_recv");
261 /* receive the 3rd notify */
262 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
263 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
264 "smb_raw_changenotify_recv");
265 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
266 1, ret, done, "wrong number of changes");
267 torture_assert_int_equal_goto(mem_ctx,
268 notify.nttrans.out.changes[0].action,
269 NOTIFY_ACTION_REMOVED, ret, done,
270 "wrong action (exp: REMOVED)");
271 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "test0.txt",
274 /* and we now see the rest of the unlink calls on both directory handles */
275 notify.nttrans.in.file.fnum = fnum;
277 req = smb_raw_changenotify_send(cli->tree, ¬ify);
278 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
279 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
280 "smb_raw_changenotify_recv");
281 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
282 count - 1, ret, done,
283 "wrong number of changes");
284 for (i=0;i<notify.nttrans.out.num_changes;i++) {
285 torture_assert_int_equal_goto(mem_ctx,
286 notify.nttrans.out.changes[i].action,
287 NOTIFY_ACTION_REMOVED, ret, done,
288 "wrong action (exp: REMOVED)");
290 notify.nttrans.in.file.fnum = fnum2;
291 req = smb_raw_changenotify_send(cli->tree, ¬ify);
292 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
293 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
294 "smb_raw_changenotify_recv");
295 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
296 count - 1, ret, done,
297 "wrong number of changes");
298 for (i=0;i<notify.nttrans.out.num_changes;i++) {
299 torture_assert_int_equal_goto(mem_ctx,
300 notify.nttrans.out.changes[i].action,
301 NOTIFY_ACTION_REMOVED, ret, done,
302 "wrong action (exp: REMOVED)");
305 printf("Testing if a close() on the dir handle triggers the notify reply\n");
307 notify.nttrans.in.file.fnum = fnum;
308 req = smb_raw_changenotify_send(cli->tree, ¬ify);
310 cl.close.level = RAW_CLOSE_CLOSE;
311 cl.close.in.file.fnum = fnum;
312 cl.close.in.write_time = 0;
313 status = smb_raw_close(cli->tree, &cl);
314 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
317 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
318 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
319 "smb_raw_changenotify_recv");
320 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
321 0, ret, done, "no changes expected");
324 smb_raw_exit(cli->session);
325 smbcli_deltree(cli->tree, BASEDIR);
330 * Check notify reply for a rename action. Not sure if this is a valid thing
331 * to do, but depending on timing between inotify and messaging we get the
332 * add/remove/modify in any order. This routines tries to find the action/name
333 * pair in any of the three following notify_changes.
336 static bool check_rename_reply(struct smbcli_state *cli,
338 struct notify_changes *actions,
339 uint32_t action, const char *name)
343 for (i=0; i<3; i++) {
344 if (actions[i].action == action) {
345 if ((actions[i].name.s == NULL)
346 || (strcmp(actions[i].name.s, name) != 0)
347 || (wire_bad_flags(&actions[i].name, STR_UNICODE,
349 printf("(%d) name [%s] != %s\n", line,
350 actions[i].name.s, name);
357 printf("(%d) expected action %d, not found\n", line, action);
362 testing of recursive change notify
364 static bool test_notify_recursive(struct torture_context *mem_ctx,
365 struct smbcli_state *cli,
366 struct smbcli_state *cli2)
370 union smb_notify notify;
373 struct smbcli_request *req1, *req2;
375 printf("TESTING CHANGE NOTIFY WITH RECURSION\n");
377 if (!torture_setup_dir(cli, BASEDIR)) {
382 get a handle on the directory
384 io.generic.level = RAW_OPEN_NTCREATEX;
385 io.ntcreatex.in.root_fid.fnum = 0;
386 io.ntcreatex.in.flags = 0;
387 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
388 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
389 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
390 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
391 io.ntcreatex.in.alloc_size = 0;
392 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
393 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
394 io.ntcreatex.in.security_flags = 0;
395 io.ntcreatex.in.fname = BASEDIR;
397 status = smb_raw_open(cli->tree, mem_ctx, &io);
398 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
400 fnum = io.ntcreatex.out.file.fnum;
402 /* ask for a change notify, on file or directory name
403 changes. Setup both with and without recursion */
404 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
405 notify.nttrans.in.buffer_size = 1000;
406 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
407 notify.nttrans.in.file.fnum = fnum;
409 notify.nttrans.in.recursive = true;
410 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
412 notify.nttrans.in.recursive = false;
413 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
415 /* cancel initial requests so the buffer is setup */
416 smb_raw_ntcancel(req1);
417 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
418 torture_assert_ntstatus_equal_goto(mem_ctx, status,
421 "smb_raw_changenotify_recv");
423 smb_raw_ntcancel(req2);
424 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
425 torture_assert_ntstatus_equal_goto(mem_ctx, status,
428 "smb_raw_changenotify_recv");
431 * Make notifies a bit more interesting in a cluster by doing
432 * the changes against different nodes with --unclist
434 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
435 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name\\subname1");
436 smbcli_close(cli->tree,
437 smbcli_open(cli->tree, BASEDIR "\\subdir-name\\subname2", O_CREAT, 0));
438 smbcli_rename(cli2->tree, BASEDIR "\\subdir-name\\subname1",
439 BASEDIR "\\subdir-name\\subname1-r");
440 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname2", BASEDIR "\\subname2-r");
441 smbcli_rename(cli2->tree, BASEDIR "\\subname2-r",
442 BASEDIR "\\subname3-r");
444 notify.nttrans.in.completion_filter = 0;
445 notify.nttrans.in.recursive = true;
447 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
449 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name\\subname1-r");
450 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
451 smbcli_unlink(cli->tree, BASEDIR "\\subname3-r");
453 notify.nttrans.in.recursive = false;
454 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
456 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
457 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
458 "smb_raw_changenotify_recv");
460 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
461 11, ret, done, "wrong number of changes");
462 torture_assert_int_equal_goto(mem_ctx,
463 notify.nttrans.out.changes[0].action,
464 NOTIFY_ACTION_ADDED, ret, done,
465 "wrong action (exp: ADDED)");
466 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subdir-name",
468 torture_assert_int_equal_goto(mem_ctx,
469 notify.nttrans.out.changes[1].action,
470 NOTIFY_ACTION_ADDED, ret, done,
471 "wrong action (exp: ADDED)");
472 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[1].name,
473 "subdir-name\\subname1", STR_UNICODE);
474 torture_assert_int_equal_goto(mem_ctx,
475 notify.nttrans.out.changes[2].action,
476 NOTIFY_ACTION_ADDED, ret, done,
477 "wrong action (exp: ADDED)");
478 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[2].name,
479 "subdir-name\\subname2", STR_UNICODE);
480 torture_assert_int_equal_goto(mem_ctx,
481 notify.nttrans.out.changes[3].action,
482 NOTIFY_ACTION_OLD_NAME, ret, done,
483 "wrong action (exp: OLD_NAME)");
484 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[3].name,
485 "subdir-name\\subname1", STR_UNICODE);
486 torture_assert_int_equal_goto(mem_ctx,
487 notify.nttrans.out.changes[4].action,
488 NOTIFY_ACTION_NEW_NAME, ret, done,
489 "wrong action (exp: NEW_NAME)");
490 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[4].name,
491 "subdir-name\\subname1-r", STR_UNICODE);
493 ret &= check_rename_reply(
494 cli, __LINE__, ¬ify.nttrans.out.changes[5],
495 NOTIFY_ACTION_ADDED, "subname2-r");
496 ret &= check_rename_reply(
497 cli, __LINE__, ¬ify.nttrans.out.changes[5],
498 NOTIFY_ACTION_REMOVED, "subdir-name\\subname2");
499 ret &= check_rename_reply(
500 cli, __LINE__, ¬ify.nttrans.out.changes[5],
501 NOTIFY_ACTION_MODIFIED, "subname2-r");
503 ret &= check_rename_reply(
504 cli, __LINE__, ¬ify.nttrans.out.changes[8],
505 NOTIFY_ACTION_OLD_NAME, "subname2-r");
506 ret &= check_rename_reply(
507 cli, __LINE__, ¬ify.nttrans.out.changes[8],
508 NOTIFY_ACTION_NEW_NAME, "subname3-r");
509 ret &= check_rename_reply(
510 cli, __LINE__, ¬ify.nttrans.out.changes[8],
511 NOTIFY_ACTION_MODIFIED, "subname3-r");
517 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
518 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
519 "smb_raw_changenotify_recv");
521 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
522 3, ret, done, "wrong number of changes");
523 torture_assert_int_equal_goto(mem_ctx,
524 notify.nttrans.out.changes[0].action,
525 NOTIFY_ACTION_REMOVED, ret, done,
526 "wrong action (exp: REMOVED)");
527 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name,
528 "subdir-name\\subname1-r", STR_UNICODE);
529 torture_assert_int_equal_goto(mem_ctx,
530 notify.nttrans.out.changes[1].action,
531 NOTIFY_ACTION_REMOVED, ret, done,
532 "wrong action (exp: REMOVED)");
533 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[1].name, "subdir-name",
535 torture_assert_int_equal_goto(mem_ctx,
536 notify.nttrans.out.changes[2].action,
537 NOTIFY_ACTION_REMOVED, ret, done,
538 "wrong action (exp: REMOVED)");
539 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[2].name, "subname3-r",
543 smb_raw_exit(cli->session);
544 smbcli_deltree(cli->tree, BASEDIR);
549 testing of change notify mask change
551 static bool test_notify_mask_change(struct torture_context *mem_ctx,
552 struct smbcli_state *cli)
556 union smb_notify notify;
559 struct smbcli_request *req1, *req2;
561 printf("TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
563 if (!torture_setup_dir(cli, BASEDIR)) {
568 get a handle on the directory
570 io.generic.level = RAW_OPEN_NTCREATEX;
571 io.ntcreatex.in.root_fid.fnum = 0;
572 io.ntcreatex.in.flags = 0;
573 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
574 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
575 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
576 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
577 io.ntcreatex.in.alloc_size = 0;
578 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
579 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
580 io.ntcreatex.in.security_flags = 0;
581 io.ntcreatex.in.fname = BASEDIR;
583 status = smb_raw_open(cli->tree, mem_ctx, &io);
584 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
586 fnum = io.ntcreatex.out.file.fnum;
588 /* ask for a change notify, on file or directory name
589 changes. Setup both with and without recursion */
590 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
591 notify.nttrans.in.buffer_size = 1000;
592 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
593 notify.nttrans.in.file.fnum = fnum;
595 notify.nttrans.in.recursive = true;
596 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
598 notify.nttrans.in.recursive = false;
599 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
601 /* cancel initial requests so the buffer is setup */
602 smb_raw_ntcancel(req1);
603 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
604 torture_assert_ntstatus_equal_goto(mem_ctx, status,
607 "smb_raw_changenotify_recv");
609 smb_raw_ntcancel(req2);
610 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
611 torture_assert_ntstatus_equal_goto(mem_ctx, status,
614 "smb_raw_changenotify_recv");
616 notify.nttrans.in.recursive = true;
617 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
619 /* Set to hidden then back again. */
620 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));
621 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);
622 smbcli_unlink(cli->tree, BASEDIR "\\tname1");
624 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
625 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
626 "smb_raw_changenotify_recv");
628 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
629 1, ret, done, "wrong number of changes");
630 torture_assert_int_equal_goto(mem_ctx,
631 notify.nttrans.out.changes[0].action,
632 NOTIFY_ACTION_MODIFIED, ret, done,
633 "wrong action (exp: MODIFIED)");
634 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "tname1",
637 /* Now try and change the mask to include other events.
638 * This should not work - once the mask is set on a directory
639 * fnum it seems to be fixed until the fnum is closed. */
641 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
642 notify.nttrans.in.recursive = true;
643 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
645 notify.nttrans.in.recursive = false;
646 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
648 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
649 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name\\subname1");
650 smbcli_close(cli->tree,
651 smbcli_open(cli->tree, BASEDIR "\\subdir-name\\subname2", O_CREAT, 0));
652 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname1", BASEDIR "\\subdir-name\\subname1-r");
653 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname2", BASEDIR "\\subname2-r");
654 smbcli_rename(cli->tree, BASEDIR "\\subname2-r", BASEDIR "\\subname3-r");
656 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name\\subname1-r");
657 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
658 smbcli_unlink(cli->tree, BASEDIR "\\subname3-r");
660 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
661 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
662 "smb_raw_changenotify_recv");
664 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
665 1, ret, done, "wrong number of changes");
666 torture_assert_int_equal_goto(mem_ctx,
667 notify.nttrans.out.changes[0].action,
668 NOTIFY_ACTION_MODIFIED, ret, done,
669 "wrong action (exp: MODIFIED)");
670 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subname2-r",
673 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
674 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
675 "smb_raw_changenotify_recv");
677 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
678 1, ret, done, "wrong number of changes");
679 torture_assert_int_equal_goto(mem_ctx,
680 notify.nttrans.out.changes[0].action,
681 NOTIFY_ACTION_MODIFIED, ret, done,
682 "wrong action (exp: MODIFIED)");
683 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subname3-r",
691 smb_raw_exit(cli->session);
692 smbcli_deltree(cli->tree, BASEDIR);
698 testing of mask bits for change notify
700 static bool test_notify_mask(struct torture_context *tctx,
701 struct smbcli_state *cli,
702 struct smbcli_state *cli2)
706 union smb_notify notify;
708 union smb_chkpath chkpath;
716 printf("TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
718 if (!torture_setup_dir(cli, BASEDIR)) {
722 tv = timeval_current_ofs(1000, 0);
723 t = timeval_to_nttime(&tv);
726 get a handle on the directory
728 io.generic.level = RAW_OPEN_NTCREATEX;
729 io.ntcreatex.in.root_fid.fnum = 0;
730 io.ntcreatex.in.flags = 0;
731 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
732 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
733 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
734 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
735 io.ntcreatex.in.alloc_size = 0;
736 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
737 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
738 io.ntcreatex.in.security_flags = 0;
739 io.ntcreatex.in.fname = BASEDIR;
741 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
742 notify.nttrans.in.buffer_size = 1000;
743 notify.nttrans.in.recursive = true;
745 chkpath.chkpath.in.path = "\\";
747 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, expected, nchanges) \
749 smbcli_getatr(cli->tree, test_name, NULL, NULL, NULL); \
750 do { for (mask=i=0;i<32;i++) { \
751 struct smbcli_request *req; \
752 status = smb_raw_open(cli->tree, tctx, &io); \
753 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
755 fnum = io.ntcreatex.out.file.fnum; \
757 notify.nttrans.in.file.fnum = fnum; \
758 notify.nttrans.in.completion_filter = (1<<i); \
759 req = smb_raw_changenotify_send(cli->tree, ¬ify); \
760 smb_raw_chkpath(cli->tree, &chkpath); \
762 smb_msleep(200); smb_raw_ntcancel(req); \
763 status = smb_raw_changenotify_recv(req, tctx, ¬ify); \
765 smbcli_close(cli->tree, fnum); \
766 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
767 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
769 /* special case to cope with file rename behaviour */ \
770 if (nchanges == 2 && notify.nttrans.out.num_changes == 1 && \
771 notify.nttrans.out.changes[0].action == NOTIFY_ACTION_MODIFIED && \
772 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
773 Action == NOTIFY_ACTION_OLD_NAME) { \
774 printf("(rename file special handling OK)\n"); \
775 } else if (nchanges != notify.nttrans.out.num_changes) { \
776 printf("ERROR: nchanges=%d expected=%d action=%d filter=0x%08x\n", \
777 notify.nttrans.out.num_changes, \
779 notify.nttrans.out.changes[0].action, \
780 notify.nttrans.in.completion_filter); \
782 } else if (notify.nttrans.out.changes[0].action != Action) { \
783 printf("ERROR: nchanges=%d action=%d expectedAction=%d filter=0x%08x\n", \
784 notify.nttrans.out.num_changes, \
785 notify.nttrans.out.changes[0].action, \
787 notify.nttrans.in.completion_filter); \
789 } else if (strcmp(notify.nttrans.out.changes[0].name.s, "tname1") != 0) { \
790 printf("ERROR: nchanges=%d action=%d filter=0x%08x name=%s\n", \
791 notify.nttrans.out.num_changes, \
792 notify.nttrans.out.changes[0].action, \
793 notify.nttrans.in.completion_filter, \
794 notify.nttrans.out.changes[0].name.s); \
799 if ((expected) != mask) { \
800 if (((expected) & ~mask) != 0) { \
801 printf("ERROR: trigger on too few bits. mask=0x%08x expected=0x%08x\n", \
805 printf("WARNING: trigger on too many bits. mask=0x%08x expected=0x%08x\n", \
812 printf("Testing mkdir\n");
813 NOTIFY_MASK_TEST("Testing mkdir",;,
814 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
815 smbcli_rmdir(cli2->tree, BASEDIR "\\tname1");,
817 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
819 printf("Testing create file\n");
820 NOTIFY_MASK_TEST("Testing create file",;,
821 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
822 smbcli_unlink(cli2->tree, BASEDIR "\\tname1");,
824 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
826 printf("Testing unlink\n");
827 NOTIFY_MASK_TEST("Testing unlink",
828 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
829 smbcli_unlink(cli2->tree, BASEDIR "\\tname1");,
831 NOTIFY_ACTION_REMOVED,
832 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
834 printf("Testing rmdir\n");
835 NOTIFY_MASK_TEST("Testing rmdir",
836 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
837 smbcli_rmdir(cli2->tree, BASEDIR "\\tname1");,
839 NOTIFY_ACTION_REMOVED,
840 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
842 printf("Testing rename file\n");
843 NOTIFY_MASK_TEST("Testing rename file",
844 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
845 smbcli_rename(cli2->tree, BASEDIR "\\tname1", BASEDIR "\\tname2");,
846 smbcli_unlink(cli->tree, BASEDIR "\\tname2");,
847 NOTIFY_ACTION_OLD_NAME,
848 FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_CREATION, 2);
850 printf("Testing rename dir\n");
851 NOTIFY_MASK_TEST("Testing rename dir",
852 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
853 smbcli_rename(cli2->tree, BASEDIR "\\tname1", BASEDIR "\\tname2");,
854 smbcli_rmdir(cli->tree, BASEDIR "\\tname2");,
855 NOTIFY_ACTION_OLD_NAME,
856 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
858 printf("Testing set path attribute\n");
859 NOTIFY_MASK_TEST("Testing set path attribute",
860 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
861 smbcli_setatr(cli2->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);,
862 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
863 NOTIFY_ACTION_MODIFIED,
864 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
866 printf("Testing set path write time\n");
867 NOTIFY_MASK_TEST("Testing set path write time",
868 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
869 smbcli_setatr(cli2->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_NORMAL, 1000);,
870 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
871 NOTIFY_ACTION_MODIFIED,
872 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
874 printf("Testing set file attribute\n");
875 NOTIFY_MASK_TEST("Testing set file attribute",
876 fnum2 = create_complex_file(cli2, tctx, BASEDIR "\\tname1");,
877 smbcli_fsetatr(cli2->tree, fnum2, FILE_ATTRIBUTE_HIDDEN, 0, 0, 0, 0);,
878 (smbcli_close(cli2->tree, fnum2), smbcli_unlink(cli2->tree, BASEDIR "\\tname1"));,
879 NOTIFY_ACTION_MODIFIED,
880 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
882 if (torture_setting_bool(tctx, "samba3", false)) {
883 printf("Samba3 does not yet support create times "
887 printf("Testing set file create time\n");
888 NOTIFY_MASK_TEST("Testing set file create time",
889 fnum2 = create_complex_file(cli, tctx,
890 BASEDIR "\\tname1");,
891 smbcli_fsetatr(cli->tree, fnum2, 0, t, 0, 0, 0);,
892 (smbcli_close(cli->tree, fnum2),
893 smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
894 NOTIFY_ACTION_MODIFIED,
895 FILE_NOTIFY_CHANGE_CREATION, 1);
898 printf("Testing set file access time\n");
899 NOTIFY_MASK_TEST("Testing set file access time",
900 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
901 smbcli_fsetatr(cli->tree, fnum2, 0, 0, t, 0, 0);,
902 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
903 NOTIFY_ACTION_MODIFIED,
904 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
906 printf("Testing set file write time\n");
907 NOTIFY_MASK_TEST("Testing set file write time",
908 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
909 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, t, 0);,
910 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
911 NOTIFY_ACTION_MODIFIED,
912 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
914 printf("Testing set file change time\n");
915 NOTIFY_MASK_TEST("Testing set file change time",
916 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
917 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, 0, t);,
918 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
919 NOTIFY_ACTION_MODIFIED,
923 printf("Testing write\n");
924 NOTIFY_MASK_TEST("Testing write",
925 fnum2 = create_complex_file(cli2, tctx, BASEDIR "\\tname1");,
926 smbcli_write(cli2->tree, fnum2, 1, &c, 10000, 1);,
927 (smbcli_close(cli2->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
928 NOTIFY_ACTION_MODIFIED,
931 printf("Testing truncate\n");
932 NOTIFY_MASK_TEST("Testing truncate",
933 fnum2 = create_complex_file(cli2, tctx, BASEDIR "\\tname1");,
934 smbcli_ftruncate(cli2->tree, fnum2, 10000);,
935 (smbcli_close(cli2->tree, fnum2), smbcli_unlink(cli2->tree, BASEDIR "\\tname1"));,
936 NOTIFY_ACTION_MODIFIED,
937 FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
940 smb_raw_exit(cli->session);
941 smbcli_deltree(cli->tree, BASEDIR);
946 basic testing of change notify on files
948 static bool test_notify_file(struct torture_context *mem_ctx,
949 struct smbcli_state *cli)
955 union smb_notify notify;
956 struct smbcli_request *req;
958 const char *fname = BASEDIR "\\file.txt";
960 printf("TESTING CHANGE NOTIFY ON FILES\n");
962 if (!torture_setup_dir(cli, BASEDIR)) {
966 io.generic.level = RAW_OPEN_NTCREATEX;
967 io.ntcreatex.in.root_fid.fnum = 0;
968 io.ntcreatex.in.flags = 0;
969 io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
970 io.ntcreatex.in.create_options = 0;
971 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
972 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
973 io.ntcreatex.in.alloc_size = 0;
974 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
975 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
976 io.ntcreatex.in.security_flags = 0;
977 io.ntcreatex.in.fname = fname;
978 status = smb_raw_open(cli->tree, mem_ctx, &io);
979 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
981 fnum = io.ntcreatex.out.file.fnum;
983 /* ask for a change notify,
984 on file or directory name changes */
985 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
986 notify.nttrans.in.file.fnum = fnum;
987 notify.nttrans.in.buffer_size = 1000;
988 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
989 notify.nttrans.in.recursive = false;
991 printf("Testing if notifies on file handles are invalid (should be)\n");
993 req = smb_raw_changenotify_send(cli->tree, ¬ify);
994 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
995 torture_assert_ntstatus_equal_goto(mem_ctx, status,
996 NT_STATUS_INVALID_PARAMETER,
998 "smb_raw_changenotify_recv");
1000 cl.close.level = RAW_CLOSE_CLOSE;
1001 cl.close.in.file.fnum = fnum;
1002 cl.close.in.write_time = 0;
1003 status = smb_raw_close(cli->tree, &cl);
1004 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1007 status = smbcli_unlink(cli->tree, fname);
1008 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1012 smb_raw_exit(cli->session);
1013 smbcli_deltree(cli->tree, BASEDIR);
1018 basic testing of change notifies followed by a tdis
1020 static bool test_notify_tdis(struct torture_context *tctx,
1021 struct smbcli_state *cli1)
1025 union smb_notify notify;
1028 struct smbcli_request *req;
1029 struct smbcli_state *cli = NULL;
1031 printf("TESTING CHANGE NOTIFY FOLLOWED BY TDIS\n");
1033 if (!torture_setup_dir(cli1, BASEDIR)) {
1037 if (!torture_open_connection(&cli, tctx, 0)) {
1042 get a handle on the directory
1044 io.generic.level = RAW_OPEN_NTCREATEX;
1045 io.ntcreatex.in.root_fid.fnum = 0;
1046 io.ntcreatex.in.flags = 0;
1047 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1048 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1049 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1050 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1051 io.ntcreatex.in.alloc_size = 0;
1052 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1053 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1054 io.ntcreatex.in.security_flags = 0;
1055 io.ntcreatex.in.fname = BASEDIR;
1057 status = smb_raw_open(cli->tree, tctx, &io);
1058 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1060 fnum = io.ntcreatex.out.file.fnum;
1062 /* ask for a change notify,
1063 on file or directory name changes */
1064 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1065 notify.nttrans.in.buffer_size = 1000;
1066 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1067 notify.nttrans.in.file.fnum = fnum;
1068 notify.nttrans.in.recursive = true;
1070 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1072 status = smbcli_tdis(cli);
1073 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1077 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1078 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1079 "smb_raw_changenotify_recv");
1080 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1081 0, ret, done, "no changes expected");
1084 torture_close_connection(cli);
1085 smbcli_deltree(cli1->tree, BASEDIR);
1090 basic testing of change notifies followed by a exit
1092 static bool test_notify_exit(struct torture_context *tctx,
1093 struct smbcli_state *cli1)
1097 union smb_notify notify;
1100 struct smbcli_request *req;
1101 struct smbcli_state *cli = NULL;
1103 printf("TESTING CHANGE NOTIFY FOLLOWED BY EXIT\n");
1105 if (!torture_setup_dir(cli1, BASEDIR)) {
1109 if (!torture_open_connection(&cli, tctx, 0)) {
1114 get a handle on the directory
1116 io.generic.level = RAW_OPEN_NTCREATEX;
1117 io.ntcreatex.in.root_fid.fnum = 0;
1118 io.ntcreatex.in.flags = 0;
1119 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1120 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1121 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1122 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1123 io.ntcreatex.in.alloc_size = 0;
1124 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1125 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1126 io.ntcreatex.in.security_flags = 0;
1127 io.ntcreatex.in.fname = BASEDIR;
1129 status = smb_raw_open(cli->tree, tctx, &io);
1130 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1132 fnum = io.ntcreatex.out.file.fnum;
1134 /* ask for a change notify,
1135 on file or directory name changes */
1136 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1137 notify.nttrans.in.buffer_size = 1000;
1138 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1139 notify.nttrans.in.file.fnum = fnum;
1140 notify.nttrans.in.recursive = true;
1142 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1144 status = smb_raw_exit(cli->session);
1145 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1148 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1149 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1150 "smb_raw_changenotify_recv");
1151 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1152 0, ret, done, "no changes expected");
1155 torture_close_connection(cli);
1156 smbcli_deltree(cli1->tree, BASEDIR);
1161 basic testing of change notifies followed by a ulogoff
1163 static bool test_notify_ulogoff(struct torture_context *tctx,
1164 struct smbcli_state *cli1)
1168 union smb_notify notify;
1171 struct smbcli_request *req;
1172 struct smbcli_state *cli = NULL;
1174 printf("TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1176 if (!torture_setup_dir(cli1, BASEDIR)) {
1180 if (!torture_open_connection(&cli, tctx, 0)) {
1185 get a handle on the directory
1187 io.generic.level = RAW_OPEN_NTCREATEX;
1188 io.ntcreatex.in.root_fid.fnum = 0;
1189 io.ntcreatex.in.flags = 0;
1190 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1191 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1192 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1193 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1194 io.ntcreatex.in.alloc_size = 0;
1195 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1196 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1197 io.ntcreatex.in.security_flags = 0;
1198 io.ntcreatex.in.fname = BASEDIR;
1200 status = smb_raw_open(cli->tree, tctx, &io);
1201 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1203 fnum = io.ntcreatex.out.file.fnum;
1205 /* ask for a change notify,
1206 on file or directory name changes */
1207 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1208 notify.nttrans.in.buffer_size = 1000;
1209 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1210 notify.nttrans.in.file.fnum = fnum;
1211 notify.nttrans.in.recursive = true;
1213 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1215 status = smb_raw_ulogoff(cli->session);
1216 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1219 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1220 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1221 "smb_raw_changenotify_recv");
1222 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1223 0, ret, done, "no changes expected");
1226 torture_close_connection(cli);
1227 smbcli_deltree(cli1->tree, BASEDIR);
1231 static void tcp_dis_handler(struct smbcli_transport *t, void *p)
1233 struct smbcli_state *cli = (struct smbcli_state *)p;
1234 smbcli_transport_dead(cli->transport, NT_STATUS_LOCAL_DISCONNECT);
1235 cli->transport = NULL;
1239 basic testing of change notifies followed by tcp disconnect
1241 static bool test_notify_tcp_dis(struct torture_context *tctx,
1242 struct smbcli_state *cli1)
1246 union smb_notify notify;
1249 struct smbcli_request *req;
1250 struct smbcli_state *cli = NULL;
1252 printf("TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1254 if (!torture_setup_dir(cli1, BASEDIR)) {
1258 if (!torture_open_connection(&cli, tctx, 0)) {
1263 get a handle on the directory
1265 io.generic.level = RAW_OPEN_NTCREATEX;
1266 io.ntcreatex.in.root_fid.fnum = 0;
1267 io.ntcreatex.in.flags = 0;
1268 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1269 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1270 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1271 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1272 io.ntcreatex.in.alloc_size = 0;
1273 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1274 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1275 io.ntcreatex.in.security_flags = 0;
1276 io.ntcreatex.in.fname = BASEDIR;
1278 status = smb_raw_open(cli->tree, tctx, &io);
1279 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1281 fnum = io.ntcreatex.out.file.fnum;
1283 /* ask for a change notify,
1284 on file or directory name changes */
1285 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1286 notify.nttrans.in.buffer_size = 1000;
1287 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1288 notify.nttrans.in.file.fnum = fnum;
1289 notify.nttrans.in.recursive = true;
1291 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1293 smbcli_transport_idle_handler(cli->transport, tcp_dis_handler, 250, cli);
1295 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1296 torture_assert_ntstatus_equal_goto(tctx, status,
1297 NT_STATUS_LOCAL_DISCONNECT,
1299 "smb_raw_changenotify_recv");
1302 torture_close_connection(cli);
1303 smbcli_deltree(cli1->tree, BASEDIR);
1308 test setting up two change notify requests on one handle
1310 static bool test_notify_double(struct torture_context *mem_ctx,
1311 struct smbcli_state *cli)
1315 union smb_notify notify;
1318 struct smbcli_request *req1, *req2;
1320 printf("TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1322 if (!torture_setup_dir(cli, BASEDIR)) {
1326 get a handle on the directory
1328 io.generic.level = RAW_OPEN_NTCREATEX;
1329 io.ntcreatex.in.root_fid.fnum = 0;
1330 io.ntcreatex.in.flags = 0;
1331 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1332 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1333 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1334 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1335 io.ntcreatex.in.alloc_size = 0;
1336 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1337 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1338 io.ntcreatex.in.security_flags = 0;
1339 io.ntcreatex.in.fname = BASEDIR;
1341 status = smb_raw_open(cli->tree, mem_ctx, &io);
1342 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1344 fnum = io.ntcreatex.out.file.fnum;
1346 /* ask for a change notify,
1347 on file or directory name changes */
1348 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1349 notify.nttrans.in.buffer_size = 1000;
1350 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1351 notify.nttrans.in.file.fnum = fnum;
1352 notify.nttrans.in.recursive = true;
1354 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1355 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
1357 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1359 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
1360 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1361 "smb_raw_changenotify_recv");
1362 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
1363 1, ret, done, "wrong number of changes");
1364 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subdir-name",
1367 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name2");
1369 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
1370 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1371 "smb_raw_changenotify_recv");
1372 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
1373 1, ret, done, "wrong number of changes");
1374 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "subdir-name2",
1378 smb_raw_exit(cli->session);
1379 smbcli_deltree(cli->tree, BASEDIR);
1385 test multiple change notifies at different depths and with/without recursion
1387 static bool test_notify_tree(struct torture_context *mem_ctx,
1388 struct smbcli_state *cli,
1389 struct smbcli_state *cli2)
1392 union smb_notify notify;
1394 struct smbcli_request *req;
1404 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 30 },
1405 {BASEDIR "\\zqy", true, FILE_NOTIFY_CHANGE_NAME, 8 },
1406 {BASEDIR "\\atsy", true, FILE_NOTIFY_CHANGE_NAME, 4 },
1407 {BASEDIR "\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1408 {BASEDIR "\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME, 13 },
1409 {BASEDIR "\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME, 7 },
1410 {BASEDIR "\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1411 {BASEDIR "\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1412 {BASEDIR "\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1413 {BASEDIR "\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1414 {BASEDIR "\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1415 {BASEDIR "\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1416 {BASEDIR "\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME, 40 },
1417 {BASEDIR, true, FILE_NOTIFY_CHANGE_NAME, 40 },
1418 {BASEDIR, false,FILE_NOTIFY_CHANGE_NAME, 6 },
1419 {BASEDIR "\\atsy", false,FILE_NOTIFY_CHANGE_NAME, 4 },
1420 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1421 {BASEDIR "\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1422 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1423 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1427 bool all_done = false;
1429 printf("TESTING CHANGE NOTIFY FOR DIFFERENT DEPTHS\n");
1431 if (!torture_setup_dir(cli, BASEDIR)) {
1435 io.generic.level = RAW_OPEN_NTCREATEX;
1436 io.ntcreatex.in.root_fid.fnum = 0;
1437 io.ntcreatex.in.flags = 0;
1438 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1439 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1440 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1441 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1442 io.ntcreatex.in.alloc_size = 0;
1443 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1444 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1445 io.ntcreatex.in.security_flags = 0;
1447 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1448 notify.nttrans.in.buffer_size = 20000;
1451 setup the directory tree, and the notify buffer on each directory
1453 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1454 io.ntcreatex.in.fname = dirs[i].path;
1455 status = smb_raw_open(cli->tree, mem_ctx, &io);
1456 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1458 dirs[i].fnum = io.ntcreatex.out.file.fnum;
1460 notify.nttrans.in.completion_filter = dirs[i].filter;
1461 notify.nttrans.in.file.fnum = dirs[i].fnum;
1462 notify.nttrans.in.recursive = dirs[i].recursive;
1463 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1464 smb_raw_ntcancel(req);
1465 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
1466 torture_assert_ntstatus_equal_goto(mem_ctx, status,
1467 NT_STATUS_CANCELLED,
1469 "smb_raw_changenotify_recv");
1472 /* trigger 2 events in each dir */
1473 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1474 char *path = talloc_asprintf(mem_ctx, "%s\\test.dir", dirs[i].path);
1476 * Make notifies a bit more interesting in a cluster
1477 * by doing the changes against different nodes with
1480 smbcli_mkdir(cli->tree, path);
1481 smbcli_rmdir(cli2->tree, path);
1485 /* give a bit of time for the events to propogate */
1486 tv = timeval_current();
1489 /* count events that have happened in each dir */
1490 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1491 notify.nttrans.in.file.fnum = dirs[i].fnum;
1492 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1493 smb_raw_ntcancel(req);
1494 notify.nttrans.out.num_changes = 0;
1495 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
1496 dirs[i].counted += notify.nttrans.out.num_changes;
1501 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1502 if (dirs[i].counted != dirs[i].expected) {
1506 } while (!all_done && timeval_elapsed(&tv) < 20);
1508 printf("took %.4f seconds to propogate all events\n", timeval_elapsed(&tv));
1510 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1511 if (dirs[i].counted != dirs[i].expected) {
1512 printf("ERROR: i=%d expected %d got %d for '%s'\n",
1513 i, dirs[i].expected, dirs[i].counted, dirs[i].path);
1519 run from the back, closing and deleting
1521 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1522 smbcli_close(cli->tree, dirs[i].fnum);
1523 smbcli_rmdir(cli->tree, dirs[i].path);
1527 smb_raw_exit(cli->session);
1528 smbcli_deltree(cli->tree, BASEDIR);
1533 Test response when cached server events exceed single NT NOTFIY response
1536 static bool test_notify_overflow(struct torture_context *mem_ctx,
1537 struct smbcli_state *cli)
1541 union smb_notify notify;
1545 struct smbcli_request *req1;
1548 printf("TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1550 if (!torture_setup_dir(cli, BASEDIR)) {
1554 /* get a handle on the directory */
1555 io.generic.level = RAW_OPEN_NTCREATEX;
1556 io.ntcreatex.in.root_fid.fnum = 0;
1557 io.ntcreatex.in.flags = 0;
1558 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1559 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1560 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1561 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1562 NTCREATEX_SHARE_ACCESS_WRITE;
1563 io.ntcreatex.in.alloc_size = 0;
1564 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1565 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1566 io.ntcreatex.in.security_flags = 0;
1567 io.ntcreatex.in.fname = BASEDIR;
1569 status = smb_raw_open(cli->tree, mem_ctx, &io);
1570 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1572 fnum = io.ntcreatex.out.file.fnum;
1574 /* ask for a change notify, on name changes. */
1575 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1576 notify.nttrans.in.buffer_size = 1000;
1577 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1578 notify.nttrans.in.file.fnum = fnum;
1580 notify.nttrans.in.recursive = true;
1581 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1583 /* cancel initial requests so the buffer is setup */
1584 smb_raw_ntcancel(req1);
1585 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
1586 torture_assert_ntstatus_equal_goto(mem_ctx, status,
1587 NT_STATUS_CANCELLED,
1589 "smb_raw_changenotify_recv");
1591 /* open a lot of files, filling up the server side notify buffer */
1592 printf("Testing overflowed buffer notify on create of %d files\n",
1594 for (i=0;i<count;i++) {
1595 char *fname = talloc_asprintf(cli, BASEDIR "\\test%d.txt", i);
1596 int fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR,
1599 printf("Failed to create %s - %s\n",
1600 fname, smbcli_errstr(cli->tree));
1605 smbcli_close(cli->tree, fnum2);
1608 /* expect that 0 events will be returned with NT_STATUS_OK */
1609 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1610 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
1611 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1612 "smb_raw_changenotify_recv");
1613 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
1614 0, ret, done, "no changes expected");
1617 smb_raw_exit(cli->session);
1618 smbcli_deltree(cli->tree, BASEDIR);
1623 Test if notifications are returned for changes to the base directory.
1626 static bool test_notify_basedir(struct torture_context *mem_ctx,
1627 struct smbcli_state *cli)
1631 union smb_notify notify;
1634 struct smbcli_request *req1;
1636 printf("TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1638 if (!torture_setup_dir(cli, BASEDIR)) {
1642 /* get a handle on the directory */
1643 io.generic.level = RAW_OPEN_NTCREATEX;
1644 io.ntcreatex.in.root_fid.fnum = 0;
1645 io.ntcreatex.in.flags = 0;
1646 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1647 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1648 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1649 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1650 NTCREATEX_SHARE_ACCESS_WRITE;
1651 io.ntcreatex.in.alloc_size = 0;
1652 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1653 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1654 io.ntcreatex.in.security_flags = 0;
1655 io.ntcreatex.in.fname = BASEDIR;
1657 status = smb_raw_open(cli->tree, mem_ctx, &io);
1658 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1660 fnum = io.ntcreatex.out.file.fnum;
1662 /* create a test file that will also be modified */
1663 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1",
1666 /* ask for a change notify, on attribute changes. */
1667 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1668 notify.nttrans.in.buffer_size = 1000;
1669 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
1670 notify.nttrans.in.file.fnum = fnum;
1671 notify.nttrans.in.recursive = true;
1673 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1675 /* set attribute on the base dir */
1676 smbcli_setatr(cli->tree, BASEDIR, FILE_ATTRIBUTE_HIDDEN, 0);
1678 /* set attribute on a file to assure we receive a notification */
1679 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);
1682 /* check how many responses were given, expect only 1 for the file */
1683 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
1684 torture_assert_ntstatus_ok_goto(mem_ctx, status, ret, done,
1685 "smb_raw_changenotify_recv");
1686 torture_assert_int_equal_goto(mem_ctx, notify.nttrans.out.num_changes,
1687 1, ret, done, "wrong number of changes");
1688 torture_assert_int_equal_goto(mem_ctx,
1689 notify.nttrans.out.changes[0].action,
1690 NOTIFY_ACTION_MODIFIED, ret, done,
1691 "wrong action (exp: MODIFIED)");
1692 CHECK_WSTR(mem_ctx, notify.nttrans.out.changes[0].name, "tname1",
1696 smb_raw_exit(cli->session);
1697 smbcli_deltree(cli->tree, BASEDIR);
1703 create a secondary tree connect - used to test for a bug in Samba3 messaging
1706 static struct smbcli_tree *secondary_tcon(struct smbcli_state *cli,
1707 struct torture_context *tctx)
1710 const char *share, *host;
1711 struct smbcli_tree *tree;
1712 union smb_tcon tcon;
1714 share = torture_setting_string(tctx, "share", NULL);
1715 host = torture_setting_string(tctx, "host", NULL);
1717 printf("create a second tree context on the same session\n");
1718 tree = smbcli_tree_init(cli->session, tctx, false);
1720 tcon.generic.level = RAW_TCON_TCONX;
1721 tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
1722 tcon.tconx.in.password = data_blob(NULL, 0);
1723 tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
1724 tcon.tconx.in.device = "A:";
1725 status = smb_raw_tcon(tree, tctx, &tcon);
1726 if (!NT_STATUS_IS_OK(status)) {
1728 printf("Failed to create secondary tree\n");
1732 tree->tid = tcon.tconx.out.tid;
1733 printf("tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
1740 very simple change notify test
1742 static bool test_notify_tcon(struct torture_context *torture,
1743 struct smbcli_state *cli)
1747 union smb_notify notify;
1750 struct smbcli_request *req;
1751 extern int torture_numops;
1752 struct smbcli_tree *tree = NULL;
1754 printf("TESTING SIMPLE CHANGE NOTIFY\n");
1756 if (!torture_setup_dir(cli, BASEDIR)) {
1761 get a handle on the directory
1763 io.generic.level = RAW_OPEN_NTCREATEX;
1764 io.ntcreatex.in.root_fid.fnum = 0;
1765 io.ntcreatex.in.flags = 0;
1766 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1767 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1768 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1769 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1770 io.ntcreatex.in.alloc_size = 0;
1771 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1772 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1773 io.ntcreatex.in.security_flags = 0;
1774 io.ntcreatex.in.fname = BASEDIR;
1776 status = smb_raw_open(cli->tree, torture, &io);
1777 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1779 fnum = io.ntcreatex.out.file.fnum;
1781 status = smb_raw_open(cli->tree, torture, &io);
1782 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1785 /* ask for a change notify,
1786 on file or directory name changes */
1787 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1788 notify.nttrans.in.buffer_size = 1000;
1789 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1790 notify.nttrans.in.file.fnum = fnum;
1791 notify.nttrans.in.recursive = true;
1793 printf("Testing notify mkdir\n");
1794 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1795 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1797 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1798 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1799 "smb_raw_changenotify_recv");
1801 torture_assert_int_equal_goto(torture, notify.nttrans.out.num_changes,
1802 1, ret, done, "wrong number of changes");
1803 torture_assert_int_equal_goto(torture,
1804 notify.nttrans.out.changes[0].action,
1805 NOTIFY_ACTION_ADDED, ret, done,
1806 "wrong action (exp: ADDED)");
1807 CHECK_WSTR(torture, notify.nttrans.out.changes[0].name, "subdir-name",
1810 printf("Testing notify rmdir\n");
1811 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1812 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
1814 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1815 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1816 "smb_raw_changenotify_recv");
1817 torture_assert_int_equal_goto(torture, notify.nttrans.out.num_changes,
1818 1, ret, done, "wrong number of changes");
1819 torture_assert_int_equal_goto(torture,
1820 notify.nttrans.out.changes[0].action,
1821 NOTIFY_ACTION_REMOVED, ret, done,
1822 "wrong action (exp: REMOVED)");
1823 CHECK_WSTR(torture, notify.nttrans.out.changes[0].name, "subdir-name",
1826 printf("SIMPLE CHANGE NOTIFY OK\n");
1828 printf("TESTING WITH SECONDARY TCON\n");
1829 tree = secondary_tcon(cli, torture);
1831 printf("Testing notify mkdir\n");
1832 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1833 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1835 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1836 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1837 "smb_raw_changenotify_recv");
1839 torture_assert_int_equal_goto(torture, notify.nttrans.out.num_changes,
1840 1, ret, done, "wrong number of changes");
1841 torture_assert_int_equal_goto(torture,
1842 notify.nttrans.out.changes[0].action,
1843 NOTIFY_ACTION_ADDED, ret, done,
1844 "wrong action (exp: ADDED)");
1845 CHECK_WSTR(torture, notify.nttrans.out.changes[0].name, "subdir-name",
1848 printf("Testing notify rmdir\n");
1849 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1850 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
1852 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1853 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1854 "smb_raw_changenotify_recv");
1855 torture_assert_int_equal_goto(torture, notify.nttrans.out.num_changes,
1856 1, ret, done, "wrong number of changes");
1857 torture_assert_int_equal_goto(torture,
1858 notify.nttrans.out.changes[0].action,
1859 NOTIFY_ACTION_REMOVED, ret, done,
1860 "wrong action (exp: REMOVED)");
1861 CHECK_WSTR(torture, notify.nttrans.out.changes[0].name, "subdir-name",
1864 printf("CHANGE NOTIFY WITH TCON OK\n");
1866 printf("Disconnecting secondary tree\n");
1867 status = smb_tree_disconnect(tree);
1868 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1869 "smb_tree_disconnect");
1872 printf("Testing notify mkdir\n");
1873 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1874 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1876 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1877 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1878 "smb_raw_changenotify_recv");
1880 torture_assert_int_equal_goto(torture, notify.nttrans.out.num_changes,
1881 1, ret, done, "wrong number of changes");
1882 torture_assert_int_equal_goto(torture,
1883 notify.nttrans.out.changes[0].action,
1884 NOTIFY_ACTION_ADDED, ret, done,
1885 "wrong action (exp: ADDED)");
1886 CHECK_WSTR(torture, notify.nttrans.out.changes[0].name, "subdir-name",
1889 printf("Testing notify rmdir\n");
1890 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1891 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
1893 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1894 torture_assert_ntstatus_ok_goto(torture, status, ret, done,
1895 "smb_raw_changenotify_recv");
1896 torture_assert_int_equal_goto(torture, notify.nttrans.out.num_changes,
1897 1, ret, done, "wrong number of changes");
1898 torture_assert_int_equal_goto(torture,
1899 notify.nttrans.out.changes[0].action,
1900 NOTIFY_ACTION_REMOVED, ret, done,
1901 "wrong action (exp: REMOVED)");
1902 CHECK_WSTR(torture, notify.nttrans.out.changes[0].name, "subdir-name",
1905 printf("CHANGE NOTIFY WITH TDIS OK\n");
1907 smb_raw_exit(cli->session);
1908 smbcli_deltree(cli->tree, BASEDIR);
1914 testing alignment of multiple change notify infos
1916 static bool test_notify_alignment(struct torture_context *tctx,
1917 struct smbcli_state *cli)
1920 union smb_notify notify;
1923 struct smbcli_request *req;
1924 const char *fname = BASEDIR "\\starter";
1925 const char *fnames[] = { "a",
1929 int num_names = ARRAY_SIZE(fnames);
1932 torture_comment(tctx, "TESTING CHANGE NOTIFY REPLY ALIGNMENT\n");
1934 if (!torture_setup_dir(cli, BASEDIR)) {
1938 /* get a handle on the directory */
1939 io.generic.level = RAW_OPEN_NTCREATEX;
1940 io.ntcreatex.in.root_fid.fnum = 0;
1941 io.ntcreatex.in.flags = 0;
1942 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1943 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1944 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1945 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1946 NTCREATEX_SHARE_ACCESS_WRITE;
1947 io.ntcreatex.in.alloc_size = 0;
1948 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1949 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1950 io.ntcreatex.in.security_flags = 0;
1951 io.ntcreatex.in.fname = BASEDIR;
1953 status = smb_raw_open(cli->tree, tctx, &io);
1954 torture_assert_ntstatus_ok(tctx, status, "");
1955 fnum = io.ntcreatex.out.file.fnum;
1957 /* ask for a change notify, on file creation */
1958 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1959 notify.nttrans.in.buffer_size = 1000;
1960 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_FILE_NAME;
1961 notify.nttrans.in.file.fnum = fnum;
1962 notify.nttrans.in.recursive = false;
1964 /* start change tracking */
1965 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1967 fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
1968 torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
1969 smbcli_close(cli->tree, fnum2);
1971 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1972 torture_assert_ntstatus_ok(tctx, status, "");
1974 /* create 4 files that will cause CHANGE_NOTIFY_INFO structures
1975 * to be returned in the same packet with all possible 4-byte padding
1976 * permutations. As per MS-CIFS 2.2.7.4.2 these structures should be
1977 * 4-byte aligned. */
1979 for (i = 0; i < num_names; i++) {
1980 fpath = talloc_asprintf(tctx, "%s\\%s", BASEDIR, fnames[i]);
1981 fnum2 = smbcli_open(cli->tree, fpath,
1982 O_CREAT|O_RDWR, DENY_NONE);
1983 torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
1984 smbcli_close(cli->tree, fnum2);
1988 /* We send a notify packet, and let smb_raw_changenotify_recv() do
1989 * the alignment checking for us. */
1990 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1991 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1992 torture_assert_ntstatus_ok(tctx, status, "");
1994 /* Do basic checking for correctness. */
1995 torture_assert(tctx, notify.nttrans.out.num_changes == num_names, "");
1996 for (i = 0; i < num_names; i++) {
1997 torture_assert(tctx, notify.nttrans.out.changes[i].action ==
1998 NOTIFY_ACTION_ADDED, "");
1999 CHECK_WSTR(tctx, notify.nttrans.out.changes[i].name, fnames[i],
2003 smb_raw_exit(cli->session);
2004 smbcli_deltree(cli->tree, BASEDIR);
2008 struct torture_suite *torture_raw_notify(TALLOC_CTX *mem_ctx)
2010 struct torture_suite *suite = torture_suite_create(mem_ctx, "notify");
2012 torture_suite_add_1smb_test(suite, "tcon", test_notify_tcon);
2013 torture_suite_add_2smb_test(suite, "dir", test_notify_dir);
2014 torture_suite_add_2smb_test(suite, "mask", test_notify_mask);
2015 torture_suite_add_2smb_test(suite, "recursive", test_notify_recursive);
2016 torture_suite_add_1smb_test(suite, "mask_change",
2017 test_notify_mask_change);
2018 torture_suite_add_1smb_test(suite, "file", test_notify_file);
2019 torture_suite_add_1smb_test(suite, "tdis", test_notify_tdis);
2020 torture_suite_add_1smb_test(suite, "exit", test_notify_exit);
2021 torture_suite_add_1smb_test(suite, "ulogoff", test_notify_ulogoff);
2022 torture_suite_add_1smb_test(suite, "tcp_dis", test_notify_tcp_dis);
2023 torture_suite_add_1smb_test(suite, "double", test_notify_double);
2024 torture_suite_add_2smb_test(suite, "tree", test_notify_tree);
2025 torture_suite_add_1smb_test(suite, "overflow", test_notify_overflow);
2026 torture_suite_add_1smb_test(suite, "basedir", test_notify_basedir);
2027 torture_suite_add_1smb_test(suite, "alignment", test_notify_alignment);