ctdb-daemon: Schedule running of callback if there are no event scripts
[Samba.git] / source4 / torture / raw / notify.c
blobfdb5771bf3d9f97af78142ec9941da30f7969b06
1 /*
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/>.
20 #include "includes.h"
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) \
31 do { \
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), \
35 "wire_bad_flags"); \
36 } while (0)
38 /*
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)
45 bool ret = true;
46 NTSTATUS status;
47 union smb_notify notify;
48 union smb_open io;
49 union smb_close cl;
50 int i, count, fnum, fnum2;
51 struct smbcli_request *req, *req2;
52 extern int torture_numops;
54 torture_comment(tctx, "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,
77 "smb_raw_open");
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,
82 "smb_raw_open");
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 torture_comment(tctx, "Testing notify cancel\n");
95 req = smb_raw_changenotify_send(cli->tree, &notify);
96 smb_raw_ntcancel(req);
97 status = smb_raw_changenotify_recv(req, tctx, &notify);
98 torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_CANCELLED,
99 ret, done,
100 "smb_raw_changenotify_recv");
102 torture_comment(tctx, "Testing notify mkdir\n");
104 req = smb_raw_changenotify_send(cli->tree, &notify);
105 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name");
107 status = smb_raw_changenotify_recv(req, tctx, &notify);
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",
118 STR_UNICODE);
120 torture_comment(tctx, "Testing notify rmdir\n");
122 req = smb_raw_changenotify_send(cli->tree, &notify);
123 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
125 status = smb_raw_changenotify_recv(req, tctx, &notify);
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",
135 STR_UNICODE);
137 torture_comment(tctx, "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");
143 smb_msleep(200);
144 req = smb_raw_changenotify_send(cli->tree, &notify);
145 status = smb_raw_changenotify_recv(req, tctx, &notify);
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",
155 STR_UNICODE);
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",
161 STR_UNICODE);
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",
167 STR_UNICODE);
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",
173 STR_UNICODE);
175 count = torture_numops;
176 torture_comment(tctx, "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)));
183 talloc_free(fname);
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, &notify);
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, &notify);
197 status = smbcli_unlink(cli->tree, BASEDIR "\\nonexistent.txt");
198 torture_assert_ntstatus_equal_goto(tctx, status,
199 NT_STATUS_OBJECT_NAME_NOT_FOUND,
200 ret, done,
201 "smbcli_unlink");
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 torture_comment(tctx, "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,
209 "smbcli_unlink");
211 /* receive the reply from the 2nd notify */
212 status = smb_raw_changenotify_recv(req, tctx, &notify);
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,
217 count, ret, done,
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",
226 STR_UNICODE);
228 torture_comment(tctx, "and now from the 1st notify\n");
229 status = smb_raw_changenotify_recv(req2, tctx, &notify);
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",
239 STR_UNICODE);
241 torture_comment(tctx, "(3rd notify) this notify will only see the 1st unlink\n");
242 req = smb_raw_changenotify_send(cli->tree, &notify);
244 status = smbcli_unlink(cli->tree, BASEDIR "\\nonexistent.txt");
245 torture_assert_ntstatus_equal_goto(tctx, status,
246 NT_STATUS_OBJECT_NAME_NOT_FOUND,
247 ret, done,
248 "smbcli_unlink");
250 torture_comment(tctx, "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, &notify);
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",
267 STR_UNICODE);
269 /* and we now see the rest of the unlink calls on both directory handles */
270 notify.nttrans.in.file.fnum = fnum;
271 sleep(3);
272 req = smb_raw_changenotify_send(cli->tree, &notify);
273 status = smb_raw_changenotify_recv(req, tctx, &notify);
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, &notify);
287 status = smb_raw_changenotify_recv(req, tctx, &notify);
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 torture_comment(tctx, "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, &notify);
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,
310 "smb_raw_close");
312 status = smb_raw_changenotify_recv(req, tctx, &notify);
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");
318 done:
319 smb_raw_exit(cli->session);
320 smbcli_deltree(cli->tree, BASEDIR);
321 return ret;
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,
333 int line,
334 struct notify_changes *actions,
335 uint32_t action, const char *name)
337 int i;
339 for (i=0; i<3; i++) {
340 if (actions[i].action == action) {
341 CHECK_WSTR(tctx, actions[i].name, name, STR_UNICODE);
342 return true;
346 torture_result(tctx, TORTURE_FAIL,
347 __location__": (%d) expected action %d, not found\n",
348 line, action);
349 return false;
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)
359 bool ret = true;
360 NTSTATUS status;
361 union smb_notify notify;
362 union smb_open io;
363 int fnum;
364 struct smbcli_request *req1, *req2;
366 torture_comment(tctx, "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,
389 "smb_raw_open");
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, &notify);
402 notify.nttrans.in.recursive = false;
403 req2 = smb_raw_changenotify_send(cli->tree, &notify);
405 /* cancel initial requests so the buffer is setup */
406 smb_raw_ntcancel(req1);
407 status = smb_raw_changenotify_recv(req1, tctx, &notify);
408 torture_assert_ntstatus_equal_goto(tctx, status,
409 NT_STATUS_CANCELLED,
410 ret, done,
411 "smb_raw_changenotify_recv");
413 smb_raw_ntcancel(req2);
414 status = smb_raw_changenotify_recv(req2, tctx, &notify);
415 torture_assert_ntstatus_equal_goto(tctx, status,
416 NT_STATUS_CANCELLED,
417 ret, done,
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;
436 smb_msleep(200);
437 req1 = smb_raw_changenotify_send(cli->tree, &notify);
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 smb_msleep(200);
444 notify.nttrans.in.recursive = false;
445 req2 = smb_raw_changenotify_send(cli->tree, &notify);
447 status = smb_raw_changenotify_recv(req1, tctx, &notify);
448 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
449 "smb_raw_changenotify_recv");
451 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
452 11, ret, done, "wrong number of changes");
453 torture_assert_int_equal_goto(tctx,
454 notify.nttrans.out.changes[0].action,
455 NOTIFY_ACTION_ADDED, ret, done,
456 "wrong action (exp: ADDED)");
457 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
458 STR_UNICODE);
459 torture_assert_int_equal_goto(tctx,
460 notify.nttrans.out.changes[1].action,
461 NOTIFY_ACTION_ADDED, ret, done,
462 "wrong action (exp: ADDED)");
463 CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name,
464 "subdir-name\\subname1", STR_UNICODE);
465 torture_assert_int_equal_goto(tctx,
466 notify.nttrans.out.changes[2].action,
467 NOTIFY_ACTION_ADDED, ret, done,
468 "wrong action (exp: ADDED)");
469 CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name,
470 "subdir-name\\subname2", STR_UNICODE);
471 torture_assert_int_equal_goto(tctx,
472 notify.nttrans.out.changes[3].action,
473 NOTIFY_ACTION_OLD_NAME, ret, done,
474 "wrong action (exp: OLD_NAME)");
475 CHECK_WSTR(tctx, notify.nttrans.out.changes[3].name,
476 "subdir-name\\subname1", STR_UNICODE);
477 torture_assert_int_equal_goto(tctx,
478 notify.nttrans.out.changes[4].action,
479 NOTIFY_ACTION_NEW_NAME, ret, done,
480 "wrong action (exp: NEW_NAME)");
481 CHECK_WSTR(tctx, notify.nttrans.out.changes[4].name,
482 "subdir-name\\subname1-r", STR_UNICODE);
484 ret &= check_rename_reply(tctx,
485 cli, __LINE__, &notify.nttrans.out.changes[5],
486 NOTIFY_ACTION_ADDED, "subname2-r");
487 ret &= check_rename_reply(tctx,
488 cli, __LINE__, &notify.nttrans.out.changes[5],
489 NOTIFY_ACTION_REMOVED, "subdir-name\\subname2");
490 ret &= check_rename_reply(tctx,
491 cli, __LINE__, &notify.nttrans.out.changes[5],
492 NOTIFY_ACTION_MODIFIED, "subname2-r");
494 ret &= check_rename_reply(tctx,
495 cli, __LINE__, &notify.nttrans.out.changes[8],
496 NOTIFY_ACTION_OLD_NAME, "subname2-r");
497 ret &= check_rename_reply(tctx,
498 cli, __LINE__, &notify.nttrans.out.changes[8],
499 NOTIFY_ACTION_NEW_NAME, "subname3-r");
500 ret &= check_rename_reply(tctx,
501 cli, __LINE__, &notify.nttrans.out.changes[8],
502 NOTIFY_ACTION_MODIFIED, "subname3-r");
504 if (!ret) {
505 goto done;
508 status = smb_raw_changenotify_recv(req2, tctx, &notify);
509 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
510 "smb_raw_changenotify_recv");
512 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
513 3, ret, done, "wrong number of changes");
514 torture_assert_int_equal_goto(tctx,
515 notify.nttrans.out.changes[0].action,
516 NOTIFY_ACTION_REMOVED, ret, done,
517 "wrong action (exp: REMOVED)");
518 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name,
519 "subdir-name\\subname1-r", STR_UNICODE);
520 torture_assert_int_equal_goto(tctx,
521 notify.nttrans.out.changes[1].action,
522 NOTIFY_ACTION_REMOVED, ret, done,
523 "wrong action (exp: REMOVED)");
524 CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name, "subdir-name",
525 STR_UNICODE);
526 torture_assert_int_equal_goto(tctx,
527 notify.nttrans.out.changes[2].action,
528 NOTIFY_ACTION_REMOVED, ret, done,
529 "wrong action (exp: REMOVED)");
530 CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name, "subname3-r",
531 STR_UNICODE);
533 done:
534 smb_raw_exit(cli->session);
535 smbcli_deltree(cli->tree, BASEDIR);
536 return ret;
540 testing of change notify mask change
542 static bool test_notify_mask_change(struct torture_context *tctx,
543 struct smbcli_state *cli)
545 bool ret = true;
546 NTSTATUS status;
547 union smb_notify notify;
548 union smb_open io;
549 int fnum;
550 struct smbcli_request *req1, *req2;
552 torture_comment(tctx, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
554 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
555 "Failed to setup up test directory: " BASEDIR);
558 get a handle on the directory
560 io.generic.level = RAW_OPEN_NTCREATEX;
561 io.ntcreatex.in.root_fid.fnum = 0;
562 io.ntcreatex.in.flags = 0;
563 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
564 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
565 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
566 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
567 io.ntcreatex.in.alloc_size = 0;
568 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
569 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
570 io.ntcreatex.in.security_flags = 0;
571 io.ntcreatex.in.fname = BASEDIR;
573 status = smb_raw_open(cli->tree, tctx, &io);
574 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
575 "smb_raw_open");
576 fnum = io.ntcreatex.out.file.fnum;
578 /* ask for a change notify, on file or directory name
579 changes. Setup both with and without recursion */
580 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
581 notify.nttrans.in.buffer_size = 1000;
582 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
583 notify.nttrans.in.file.fnum = fnum;
585 notify.nttrans.in.recursive = true;
586 req1 = smb_raw_changenotify_send(cli->tree, &notify);
588 notify.nttrans.in.recursive = false;
589 req2 = smb_raw_changenotify_send(cli->tree, &notify);
591 /* cancel initial requests so the buffer is setup */
592 smb_raw_ntcancel(req1);
593 status = smb_raw_changenotify_recv(req1, tctx, &notify);
594 torture_assert_ntstatus_equal_goto(tctx, status,
595 NT_STATUS_CANCELLED,
596 ret, done,
597 "smb_raw_changenotify_recv");
599 smb_raw_ntcancel(req2);
600 status = smb_raw_changenotify_recv(req2, tctx, &notify);
601 torture_assert_ntstatus_equal_goto(tctx, status,
602 NT_STATUS_CANCELLED,
603 ret, done,
604 "smb_raw_changenotify_recv");
606 notify.nttrans.in.recursive = true;
607 req1 = smb_raw_changenotify_send(cli->tree, &notify);
609 /* Set to hidden then back again. */
610 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));
611 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);
612 smbcli_unlink(cli->tree, BASEDIR "\\tname1");
614 status = smb_raw_changenotify_recv(req1, tctx, &notify);
615 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
616 "smb_raw_changenotify_recv");
618 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
619 1, ret, done, "wrong number of changes");
620 torture_assert_int_equal_goto(tctx,
621 notify.nttrans.out.changes[0].action,
622 NOTIFY_ACTION_MODIFIED, ret, done,
623 "wrong action (exp: MODIFIED)");
624 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "tname1",
625 STR_UNICODE);
627 /* Now try and change the mask to include other events.
628 * This should not work - once the mask is set on a directory
629 * fnum it seems to be fixed until the fnum is closed. */
631 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
632 notify.nttrans.in.recursive = true;
633 req1 = smb_raw_changenotify_send(cli->tree, &notify);
635 notify.nttrans.in.recursive = false;
636 req2 = smb_raw_changenotify_send(cli->tree, &notify);
638 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
639 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name\\subname1");
640 smbcli_close(cli->tree,
641 smbcli_open(cli->tree, BASEDIR "\\subdir-name\\subname2", O_CREAT, 0));
642 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname1", BASEDIR "\\subdir-name\\subname1-r");
643 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname2", BASEDIR "\\subname2-r");
644 smbcli_rename(cli->tree, BASEDIR "\\subname2-r", BASEDIR "\\subname3-r");
646 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name\\subname1-r");
647 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
648 smbcli_unlink(cli->tree, BASEDIR "\\subname3-r");
650 status = smb_raw_changenotify_recv(req1, tctx, &notify);
651 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
652 "smb_raw_changenotify_recv");
654 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
655 1, ret, done, "wrong number of changes");
656 torture_assert_int_equal_goto(tctx,
657 notify.nttrans.out.changes[0].action,
658 NOTIFY_ACTION_MODIFIED, ret, done,
659 "wrong action (exp: MODIFIED)");
660 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subname2-r",
661 STR_UNICODE);
663 status = smb_raw_changenotify_recv(req2, tctx, &notify);
664 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
665 "smb_raw_changenotify_recv");
667 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
668 1, ret, done, "wrong number of changes");
669 torture_assert_int_equal_goto(tctx,
670 notify.nttrans.out.changes[0].action,
671 NOTIFY_ACTION_MODIFIED, ret, done,
672 "wrong action (exp: MODIFIED)");
673 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subname3-r",
674 STR_UNICODE);
676 done:
677 smb_raw_exit(cli->session);
678 smbcli_deltree(cli->tree, BASEDIR);
679 return ret;
684 testing of mask bits for change notify
686 static bool test_notify_mask(struct torture_context *tctx,
687 struct smbcli_state *cli,
688 struct smbcli_state *cli2)
690 bool ret = true;
691 NTSTATUS status;
692 union smb_notify notify;
693 union smb_open io;
694 union smb_chkpath chkpath;
695 int fnum, fnum2;
696 uint32_t mask;
697 int i;
698 char c = 1;
699 struct timeval tv;
700 NTTIME t;
702 torture_comment(tctx, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
704 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
705 "Failed to setup up test directory: " BASEDIR);
707 tv = timeval_current_ofs(1000, 0);
708 t = timeval_to_nttime(&tv);
711 get a handle on the directory
713 io.generic.level = RAW_OPEN_NTCREATEX;
714 io.ntcreatex.in.root_fid.fnum = 0;
715 io.ntcreatex.in.flags = 0;
716 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
717 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
718 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
719 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
720 io.ntcreatex.in.alloc_size = 0;
721 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
722 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
723 io.ntcreatex.in.security_flags = 0;
724 io.ntcreatex.in.fname = BASEDIR;
726 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
727 notify.nttrans.in.buffer_size = 1000;
728 notify.nttrans.in.recursive = true;
730 chkpath.chkpath.in.path = "\\";
732 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, expected, nchanges) \
733 do { \
734 smbcli_getatr(cli->tree, test_name, NULL, NULL, NULL); \
735 for (mask=i=0;i<32;i++) { \
736 struct smbcli_request *req; \
737 status = smb_raw_open(cli->tree, tctx, &io); \
738 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
739 "smb_raw_open"); \
740 fnum = io.ntcreatex.out.file.fnum; \
741 setup \
742 notify.nttrans.in.file.fnum = fnum; \
743 notify.nttrans.in.completion_filter = (1<<i); \
744 req = smb_raw_changenotify_send(cli->tree, &notify); \
745 smb_raw_chkpath(cli->tree, &chkpath); \
746 op \
747 smb_msleep(200); smb_raw_ntcancel(req); \
748 status = smb_raw_changenotify_recv(req, tctx, &notify); \
749 cleanup \
750 smbcli_close(cli->tree, fnum); \
751 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
752 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
753 "smbcli_close"); \
754 /* special case to cope with file rename behaviour */ \
755 if (nchanges == 2 && notify.nttrans.out.num_changes == 1 && \
756 notify.nttrans.out.changes[0].action == NOTIFY_ACTION_MODIFIED && \
757 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
758 Action == NOTIFY_ACTION_OLD_NAME) { \
759 torture_comment(tctx, "(rename file special handling OK)\n"); \
760 } else { \
761 torture_assert_int_equal_goto(tctx, \
762 notify.nttrans.out.num_changes,\
763 nchanges, ret, done, \
764 talloc_asprintf(tctx, \
765 "nchanges=%d expected=%d action=%d " \
766 "filter=0x%08x\n", \
767 notify.nttrans.out.num_changes, \
768 nchanges, \
769 notify.nttrans.out.changes[0].action, \
770 notify.nttrans.in.completion_filter)); \
771 torture_assert_int_equal_goto(tctx, \
772 notify.nttrans.out.changes[0].action, \
773 Action, ret, done, \
774 talloc_asprintf(tctx, \
775 "nchanges=%d action=%d " \
776 "expectedAction=%d filter=0x%08x\n", \
777 notify.nttrans.out.num_changes, \
778 notify.nttrans.out.changes[0].action, \
779 Action, \
780 notify.nttrans.in.completion_filter)); \
781 torture_assert_str_equal_goto(tctx, \
782 notify.nttrans.out.changes[0].name.s, \
783 "tname1", ret, done, \
784 talloc_asprintf(tctx, \
785 "nchanges=%d action=%d filter=0x%08x " \
786 "name=%s expected_name=tname1\n", \
787 notify.nttrans.out.num_changes, \
788 notify.nttrans.out.changes[0].action, \
789 notify.nttrans.in.completion_filter, \
790 notify.nttrans.out.changes[0].name.s));\
792 mask |= (1<<i); \
794 if ((expected) != mask) { \
795 torture_assert_int_not_equal_goto(tctx, ((expected) & ~mask), \
796 0, ret, done, "Too few bits"); \
797 torture_comment(tctx, "WARNING: trigger on too many bits. mask=0x%08x expected=0x%08x\n", \
798 mask, expected); \
800 } while (0);
802 torture_comment(tctx, "Testing mkdir\n");
803 NOTIFY_MASK_TEST("Testing mkdir",;,
804 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
805 smbcli_rmdir(cli2->tree, BASEDIR "\\tname1");,
806 NOTIFY_ACTION_ADDED,
807 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
809 torture_comment(tctx, "Testing create file\n");
810 NOTIFY_MASK_TEST("Testing create file",;,
811 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
812 smbcli_unlink(cli2->tree, BASEDIR "\\tname1");,
813 NOTIFY_ACTION_ADDED,
814 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
816 torture_comment(tctx, "Testing unlink\n");
817 NOTIFY_MASK_TEST("Testing unlink",
818 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
819 smbcli_unlink(cli2->tree, BASEDIR "\\tname1");,
821 NOTIFY_ACTION_REMOVED,
822 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
824 torture_comment(tctx, "Testing rmdir\n");
825 NOTIFY_MASK_TEST("Testing rmdir",
826 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
827 smbcli_rmdir(cli2->tree, BASEDIR "\\tname1");,
829 NOTIFY_ACTION_REMOVED,
830 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
832 torture_comment(tctx, "Testing rename file\n");
833 NOTIFY_MASK_TEST("Testing rename file",
834 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
835 smbcli_rename(cli2->tree, BASEDIR "\\tname1", BASEDIR "\\tname2");,
836 smbcli_unlink(cli->tree, BASEDIR "\\tname2");,
837 NOTIFY_ACTION_OLD_NAME,
838 FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_CREATION, 2);
840 torture_comment(tctx, "Testing rename dir\n");
841 NOTIFY_MASK_TEST("Testing rename dir",
842 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
843 smbcli_rename(cli2->tree, BASEDIR "\\tname1", BASEDIR "\\tname2");,
844 smbcli_rmdir(cli->tree, BASEDIR "\\tname2");,
845 NOTIFY_ACTION_OLD_NAME,
846 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
848 torture_comment(tctx, "Testing set path attribute\n");
849 NOTIFY_MASK_TEST("Testing set path attribute",
850 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
851 smbcli_setatr(cli2->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);,
852 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
853 NOTIFY_ACTION_MODIFIED,
854 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
856 torture_comment(tctx, "Testing set path write time\n");
857 NOTIFY_MASK_TEST("Testing set path write time",
858 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
859 smbcli_setatr(cli2->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_NORMAL, 1000);,
860 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
861 NOTIFY_ACTION_MODIFIED,
862 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
864 torture_comment(tctx, "Testing set file attribute\n");
865 NOTIFY_MASK_TEST("Testing set file attribute",
866 fnum2 = create_complex_file(cli2, tctx, BASEDIR "\\tname1");,
867 smbcli_fsetatr(cli2->tree, fnum2, FILE_ATTRIBUTE_HIDDEN, 0, 0, 0, 0);,
868 (smbcli_close(cli2->tree, fnum2), smbcli_unlink(cli2->tree, BASEDIR "\\tname1"));,
869 NOTIFY_ACTION_MODIFIED,
870 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
872 if (torture_setting_bool(tctx, "samba3", false)) {
873 torture_comment(tctx, "Samba3 does not yet support create times "
874 "everywhere\n");
876 else {
877 torture_comment(tctx, "Testing set file create time\n");
878 NOTIFY_MASK_TEST("Testing set file create time",
879 fnum2 = create_complex_file(cli, tctx,
880 BASEDIR "\\tname1");,
881 smbcli_fsetatr(cli->tree, fnum2, 0, t, 0, 0, 0);,
882 (smbcli_close(cli->tree, fnum2),
883 smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
884 NOTIFY_ACTION_MODIFIED,
885 FILE_NOTIFY_CHANGE_CREATION, 1);
888 torture_comment(tctx, "Testing set file access time\n");
889 NOTIFY_MASK_TEST("Testing set file access time",
890 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
891 smbcli_fsetatr(cli->tree, fnum2, 0, 0, t, 0, 0);,
892 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
893 NOTIFY_ACTION_MODIFIED,
894 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
896 torture_comment(tctx, "Testing set file write time\n");
897 NOTIFY_MASK_TEST("Testing set file write time",
898 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
899 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, t, 0);,
900 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
901 NOTIFY_ACTION_MODIFIED,
902 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
904 torture_comment(tctx, "Testing set file change time\n");
905 NOTIFY_MASK_TEST("Testing set file change time",
906 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
907 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, 0, t);,
908 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
909 NOTIFY_ACTION_MODIFIED,
910 0, 1);
913 torture_comment(tctx, "Testing write\n");
914 NOTIFY_MASK_TEST("Testing write",
915 fnum2 = create_complex_file(cli2, tctx, BASEDIR "\\tname1");,
916 smbcli_write(cli2->tree, fnum2, 1, &c, 10000, 1);,
917 (smbcli_close(cli2->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
918 NOTIFY_ACTION_MODIFIED,
919 0, 1);
921 torture_comment(tctx, "Testing truncate\n");
922 NOTIFY_MASK_TEST("Testing truncate",
923 fnum2 = create_complex_file(cli2, tctx, BASEDIR "\\tname1");,
924 smbcli_ftruncate(cli2->tree, fnum2, 10000);,
925 (smbcli_close(cli2->tree, fnum2), smbcli_unlink(cli2->tree, BASEDIR "\\tname1"));,
926 NOTIFY_ACTION_MODIFIED,
927 FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
929 done:
930 smb_raw_exit(cli->session);
931 smbcli_deltree(cli->tree, BASEDIR);
932 return ret;
936 basic testing of change notify on files
938 static bool test_notify_file(struct torture_context *tctx,
939 struct smbcli_state *cli)
941 NTSTATUS status;
942 bool ret = true;
943 union smb_open io;
944 union smb_close cl;
945 union smb_notify notify;
946 struct smbcli_request *req;
947 int fnum;
948 const char *fname = BASEDIR "\\file.txt";
950 torture_comment(tctx, "TESTING CHANGE NOTIFY ON FILES\n");
952 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
953 "Failed to setup up test directory: " BASEDIR);
955 io.generic.level = RAW_OPEN_NTCREATEX;
956 io.ntcreatex.in.root_fid.fnum = 0;
957 io.ntcreatex.in.flags = 0;
958 io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
959 io.ntcreatex.in.create_options = 0;
960 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
961 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
962 io.ntcreatex.in.alloc_size = 0;
963 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
964 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
965 io.ntcreatex.in.security_flags = 0;
966 io.ntcreatex.in.fname = fname;
967 status = smb_raw_open(cli->tree, tctx, &io);
968 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
969 "smb_raw_open");
970 fnum = io.ntcreatex.out.file.fnum;
972 /* ask for a change notify,
973 on file or directory name changes */
974 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
975 notify.nttrans.in.file.fnum = fnum;
976 notify.nttrans.in.buffer_size = 1000;
977 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
978 notify.nttrans.in.recursive = false;
980 torture_comment(tctx, "Testing if notifies on file handles are invalid (should be)\n");
982 req = smb_raw_changenotify_send(cli->tree, &notify);
983 status = smb_raw_changenotify_recv(req, tctx, &notify);
984 torture_assert_ntstatus_equal_goto(tctx, status,
985 NT_STATUS_INVALID_PARAMETER,
986 ret, done,
987 "smb_raw_changenotify_recv");
989 cl.close.level = RAW_CLOSE_CLOSE;
990 cl.close.in.file.fnum = fnum;
991 cl.close.in.write_time = 0;
992 status = smb_raw_close(cli->tree, &cl);
993 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
994 "smb_raw_close");
996 status = smbcli_unlink(cli->tree, fname);
997 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
998 "smbcli_unlink");
1000 done:
1001 smb_raw_exit(cli->session);
1002 smbcli_deltree(cli->tree, BASEDIR);
1003 return ret;
1007 basic testing of change notifies followed by a tdis
1009 static bool test_notify_tdis(struct torture_context *tctx,
1010 struct smbcli_state *cli1)
1012 bool ret = true;
1013 NTSTATUS status;
1014 union smb_notify notify;
1015 union smb_open io;
1016 int fnum;
1017 struct smbcli_request *req;
1018 struct smbcli_state *cli = NULL;
1020 torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY TDIS\n");
1022 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
1023 "Failed to setup up test directory: " BASEDIR);
1025 torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1026 "Failed to open connection.");
1029 get a handle on the directory
1031 io.generic.level = RAW_OPEN_NTCREATEX;
1032 io.ntcreatex.in.root_fid.fnum = 0;
1033 io.ntcreatex.in.flags = 0;
1034 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1035 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1036 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1037 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1038 io.ntcreatex.in.alloc_size = 0;
1039 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1040 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1041 io.ntcreatex.in.security_flags = 0;
1042 io.ntcreatex.in.fname = BASEDIR;
1044 status = smb_raw_open(cli->tree, tctx, &io);
1045 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1046 "smb_raw_open");
1047 fnum = io.ntcreatex.out.file.fnum;
1049 /* ask for a change notify,
1050 on file or directory name changes */
1051 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1052 notify.nttrans.in.buffer_size = 1000;
1053 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1054 notify.nttrans.in.file.fnum = fnum;
1055 notify.nttrans.in.recursive = true;
1057 req = smb_raw_changenotify_send(cli->tree, &notify);
1059 status = smbcli_tdis(cli);
1060 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1061 "smbcli_tdis");
1062 cli->tree = NULL;
1064 status = smb_raw_changenotify_recv(req, tctx, &notify);
1065 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1066 "smb_raw_changenotify_recv");
1067 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1068 0, ret, done, "no changes expected");
1070 done:
1071 torture_close_connection(cli);
1072 smbcli_deltree(cli1->tree, BASEDIR);
1073 return ret;
1077 basic testing of change notifies followed by a exit
1079 static bool test_notify_exit(struct torture_context *tctx,
1080 struct smbcli_state *cli1)
1082 bool ret = true;
1083 NTSTATUS status;
1084 union smb_notify notify;
1085 union smb_open io;
1086 int fnum;
1087 struct smbcli_request *req;
1088 struct smbcli_state *cli = NULL;
1090 torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY EXIT\n");
1092 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
1093 "Failed to setup up test directory: " BASEDIR);
1095 torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1096 "Failed to open connection.");
1099 get a handle on the directory
1101 io.generic.level = RAW_OPEN_NTCREATEX;
1102 io.ntcreatex.in.root_fid.fnum = 0;
1103 io.ntcreatex.in.flags = 0;
1104 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1105 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1106 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1107 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1108 io.ntcreatex.in.alloc_size = 0;
1109 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1110 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1111 io.ntcreatex.in.security_flags = 0;
1112 io.ntcreatex.in.fname = BASEDIR;
1114 status = smb_raw_open(cli->tree, tctx, &io);
1115 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1116 "smb_raw_open");
1117 fnum = io.ntcreatex.out.file.fnum;
1119 /* ask for a change notify,
1120 on file or directory name changes */
1121 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1122 notify.nttrans.in.buffer_size = 1000;
1123 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1124 notify.nttrans.in.file.fnum = fnum;
1125 notify.nttrans.in.recursive = true;
1127 req = smb_raw_changenotify_send(cli->tree, &notify);
1129 status = smb_raw_exit(cli->session);
1130 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1131 "smb_raw_exit");
1133 status = smb_raw_changenotify_recv(req, tctx, &notify);
1134 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1135 "smb_raw_changenotify_recv");
1136 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1137 0, ret, done, "no changes expected");
1139 done:
1140 torture_close_connection(cli);
1141 smbcli_deltree(cli1->tree, BASEDIR);
1142 return ret;
1146 basic testing of change notifies followed by a ulogoff
1148 static bool test_notify_ulogoff(struct torture_context *tctx,
1149 struct smbcli_state *cli1)
1151 bool ret = true;
1152 NTSTATUS status;
1153 union smb_notify notify;
1154 union smb_open io;
1155 int fnum;
1156 struct smbcli_request *req;
1157 struct smbcli_state *cli = NULL;
1159 torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1161 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
1162 "Failed to setup up test directory: " BASEDIR);
1164 torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1165 "Failed to open connection.");
1168 get a handle on the directory
1170 io.generic.level = RAW_OPEN_NTCREATEX;
1171 io.ntcreatex.in.root_fid.fnum = 0;
1172 io.ntcreatex.in.flags = 0;
1173 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1174 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1175 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1176 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1177 io.ntcreatex.in.alloc_size = 0;
1178 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1179 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1180 io.ntcreatex.in.security_flags = 0;
1181 io.ntcreatex.in.fname = BASEDIR;
1183 status = smb_raw_open(cli->tree, tctx, &io);
1184 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1185 "smb_raw_open");
1186 fnum = io.ntcreatex.out.file.fnum;
1188 /* ask for a change notify,
1189 on file or directory name changes */
1190 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1191 notify.nttrans.in.buffer_size = 1000;
1192 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1193 notify.nttrans.in.file.fnum = fnum;
1194 notify.nttrans.in.recursive = true;
1196 req = smb_raw_changenotify_send(cli->tree, &notify);
1198 status = smb_raw_ulogoff(cli->session);
1199 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1200 "smb_raw_ulogoff");
1202 status = smb_raw_changenotify_recv(req, tctx, &notify);
1203 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1204 "smb_raw_changenotify_recv");
1205 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1206 0, ret, done, "no changes expected");
1208 done:
1209 torture_close_connection(cli);
1210 smbcli_deltree(cli1->tree, BASEDIR);
1211 return ret;
1214 static void tcp_dis_handler(struct smbcli_transport *t, void *p)
1216 struct smbcli_state *cli = (struct smbcli_state *)p;
1217 smbcli_transport_dead(cli->transport, NT_STATUS_LOCAL_DISCONNECT);
1218 cli->transport = NULL;
1219 cli->tree = NULL;
1222 basic testing of change notifies followed by tcp disconnect
1224 static bool test_notify_tcp_dis(struct torture_context *tctx,
1225 struct smbcli_state *cli1)
1227 bool ret = true;
1228 NTSTATUS status;
1229 union smb_notify notify;
1230 union smb_open io;
1231 int fnum;
1232 struct smbcli_request *req;
1233 struct smbcli_state *cli = NULL;
1235 torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1237 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR),
1238 "Failed to setup up test directory: " BASEDIR);
1240 torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1241 "Failed to open connection.");
1244 get a handle on the directory
1246 io.generic.level = RAW_OPEN_NTCREATEX;
1247 io.ntcreatex.in.root_fid.fnum = 0;
1248 io.ntcreatex.in.flags = 0;
1249 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1250 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1251 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1252 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1253 io.ntcreatex.in.alloc_size = 0;
1254 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1255 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1256 io.ntcreatex.in.security_flags = 0;
1257 io.ntcreatex.in.fname = BASEDIR;
1259 status = smb_raw_open(cli->tree, tctx, &io);
1260 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1261 "smb_raw_open");
1262 fnum = io.ntcreatex.out.file.fnum;
1264 /* ask for a change notify,
1265 on file or directory name changes */
1266 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1267 notify.nttrans.in.buffer_size = 1000;
1268 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1269 notify.nttrans.in.file.fnum = fnum;
1270 notify.nttrans.in.recursive = true;
1272 req = smb_raw_changenotify_send(cli->tree, &notify);
1274 smbcli_transport_idle_handler(cli->transport, tcp_dis_handler, 250, cli);
1276 status = smb_raw_changenotify_recv(req, tctx, &notify);
1277 torture_assert_ntstatus_equal_goto(tctx, status,
1278 NT_STATUS_LOCAL_DISCONNECT,
1279 ret, done,
1280 "smb_raw_changenotify_recv");
1282 done:
1283 torture_close_connection(cli);
1284 smbcli_deltree(cli1->tree, BASEDIR);
1285 return ret;
1289 test setting up two change notify requests on one handle
1291 static bool test_notify_double(struct torture_context *tctx,
1292 struct smbcli_state *cli)
1294 bool ret = true;
1295 NTSTATUS status;
1296 union smb_notify notify;
1297 union smb_open io;
1298 int fnum;
1299 struct smbcli_request *req1, *req2;
1301 torture_comment(tctx, "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1303 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
1304 "Failed to setup up test directory: " BASEDIR);
1307 get a handle on the directory
1309 io.generic.level = RAW_OPEN_NTCREATEX;
1310 io.ntcreatex.in.root_fid.fnum = 0;
1311 io.ntcreatex.in.flags = 0;
1312 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1313 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1314 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1315 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1316 io.ntcreatex.in.alloc_size = 0;
1317 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1318 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1319 io.ntcreatex.in.security_flags = 0;
1320 io.ntcreatex.in.fname = BASEDIR;
1322 status = smb_raw_open(cli->tree, tctx, &io);
1323 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1324 "smb_raw_open");
1325 fnum = io.ntcreatex.out.file.fnum;
1327 /* ask for a change notify,
1328 on file or directory name changes */
1329 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1330 notify.nttrans.in.buffer_size = 1000;
1331 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1332 notify.nttrans.in.file.fnum = fnum;
1333 notify.nttrans.in.recursive = true;
1335 req1 = smb_raw_changenotify_send(cli->tree, &notify);
1336 req2 = smb_raw_changenotify_send(cli->tree, &notify);
1338 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1340 status = smb_raw_changenotify_recv(req1, tctx, &notify);
1341 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1342 "smb_raw_changenotify_recv");
1343 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1344 1, ret, done, "wrong number of changes");
1345 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1346 STR_UNICODE);
1348 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name2");
1350 status = smb_raw_changenotify_recv(req2, tctx, &notify);
1351 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1352 "smb_raw_changenotify_recv");
1353 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1354 1, ret, done, "wrong number of changes");
1355 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name2",
1356 STR_UNICODE);
1358 done:
1359 smb_raw_exit(cli->session);
1360 smbcli_deltree(cli->tree, BASEDIR);
1361 return ret;
1366 test multiple change notifies at different depths and with/without recursion
1368 static bool test_notify_tree(struct torture_context *tctx,
1369 struct smbcli_state *cli,
1370 struct smbcli_state *cli2)
1372 bool ret = true;
1373 union smb_notify notify;
1374 union smb_open io;
1375 struct smbcli_request *req;
1376 struct timeval tv;
1377 struct {
1378 const char *path;
1379 bool recursive;
1380 uint32_t filter;
1381 int expected;
1382 int fnum;
1383 int counted;
1384 } dirs[] = {
1385 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 30 },
1386 {BASEDIR "\\zqy", true, FILE_NOTIFY_CHANGE_NAME, 8 },
1387 {BASEDIR "\\atsy", true, FILE_NOTIFY_CHANGE_NAME, 4 },
1388 {BASEDIR "\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1389 {BASEDIR "\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME, 13 },
1390 {BASEDIR "\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME, 7 },
1391 {BASEDIR "\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1392 {BASEDIR "\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1393 {BASEDIR "\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1394 {BASEDIR "\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1395 {BASEDIR "\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1396 {BASEDIR "\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1397 {BASEDIR "\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME, 40 },
1398 {BASEDIR, true, FILE_NOTIFY_CHANGE_NAME, 40 },
1399 {BASEDIR, false,FILE_NOTIFY_CHANGE_NAME, 6 },
1400 {BASEDIR "\\atsy", false,FILE_NOTIFY_CHANGE_NAME, 4 },
1401 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1402 {BASEDIR "\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1403 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1404 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1406 int i;
1407 NTSTATUS status;
1408 bool all_done = false;
1410 torture_comment(tctx, "TESTING CHANGE NOTIFY FOR DIFFERENT DEPTHS\n");
1412 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
1413 "Failed to setup up test directory: " BASEDIR);
1415 io.generic.level = RAW_OPEN_NTCREATEX;
1416 io.ntcreatex.in.root_fid.fnum = 0;
1417 io.ntcreatex.in.flags = 0;
1418 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1419 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1420 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1421 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1422 io.ntcreatex.in.alloc_size = 0;
1423 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1424 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1425 io.ntcreatex.in.security_flags = 0;
1427 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1428 notify.nttrans.in.buffer_size = 20000;
1431 setup the directory tree, and the notify buffer on each directory
1433 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1434 io.ntcreatex.in.fname = dirs[i].path;
1435 status = smb_raw_open(cli->tree, tctx, &io);
1436 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1437 "smb_raw_open");
1438 dirs[i].fnum = io.ntcreatex.out.file.fnum;
1440 notify.nttrans.in.completion_filter = dirs[i].filter;
1441 notify.nttrans.in.file.fnum = dirs[i].fnum;
1442 notify.nttrans.in.recursive = dirs[i].recursive;
1443 req = smb_raw_changenotify_send(cli->tree, &notify);
1444 smb_raw_ntcancel(req);
1445 status = smb_raw_changenotify_recv(req, tctx, &notify);
1446 torture_assert_ntstatus_equal_goto(tctx, status,
1447 NT_STATUS_CANCELLED,
1448 ret, done,
1449 "smb_raw_changenotify_recv");
1452 /* trigger 2 events in each dir */
1453 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1454 char *path = talloc_asprintf(tctx, "%s\\test.dir", dirs[i].path);
1456 * Make notifies a bit more interesting in a cluster
1457 * by doing the changes against different nodes with
1458 * --unclist
1460 smbcli_mkdir(cli->tree, path);
1461 smbcli_rmdir(cli2->tree, path);
1462 talloc_free(path);
1465 /* give a bit of time for the events to propogate */
1466 tv = timeval_current();
1468 do {
1469 /* count events that have happened in each dir */
1470 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1471 notify.nttrans.in.file.fnum = dirs[i].fnum;
1472 req = smb_raw_changenotify_send(cli->tree, &notify);
1473 smb_raw_ntcancel(req);
1474 notify.nttrans.out.num_changes = 0;
1475 status = smb_raw_changenotify_recv(req, tctx, &notify);
1476 dirs[i].counted += notify.nttrans.out.num_changes;
1479 all_done = true;
1481 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1482 if (dirs[i].counted != dirs[i].expected) {
1483 all_done = false;
1486 } while (!all_done && timeval_elapsed(&tv) < 20);
1488 torture_comment(tctx, "took %.4f seconds to propogate all events\n", timeval_elapsed(&tv));
1490 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1491 torture_assert_int_equal_goto(tctx,
1492 dirs[i].counted, dirs[i].expected, ret, done,
1493 talloc_asprintf(tctx,
1494 "unexpected number of events for '%s'",
1495 dirs[i].path));
1499 run from the back, closing and deleting
1501 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1502 smbcli_close(cli->tree, dirs[i].fnum);
1503 smbcli_rmdir(cli->tree, dirs[i].path);
1506 done:
1507 smb_raw_exit(cli->session);
1508 smbcli_deltree(cli->tree, BASEDIR);
1509 return ret;
1513 Test response when cached server events exceed single NT NOTFIY response
1514 packet size.
1516 static bool test_notify_overflow(struct torture_context *tctx,
1517 struct smbcli_state *cli)
1519 bool ret = true;
1520 NTSTATUS status;
1521 union smb_notify notify;
1522 union smb_open io;
1523 int fnum;
1524 int count = 100;
1525 struct smbcli_request *req1;
1526 int i;
1528 torture_comment(tctx, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1530 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
1531 "Failed to setup up test directory: " BASEDIR);
1533 /* get a handle on the directory */
1534 io.generic.level = RAW_OPEN_NTCREATEX;
1535 io.ntcreatex.in.root_fid.fnum = 0;
1536 io.ntcreatex.in.flags = 0;
1537 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1538 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1539 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1540 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1541 NTCREATEX_SHARE_ACCESS_WRITE;
1542 io.ntcreatex.in.alloc_size = 0;
1543 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1544 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1545 io.ntcreatex.in.security_flags = 0;
1546 io.ntcreatex.in.fname = BASEDIR;
1548 status = smb_raw_open(cli->tree, tctx, &io);
1549 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1550 "smb_raw_open");
1551 fnum = io.ntcreatex.out.file.fnum;
1553 /* ask for a change notify, on name changes. */
1554 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1555 notify.nttrans.in.buffer_size = 1000;
1556 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1557 notify.nttrans.in.file.fnum = fnum;
1559 notify.nttrans.in.recursive = true;
1560 req1 = smb_raw_changenotify_send(cli->tree, &notify);
1562 /* cancel initial requests so the buffer is setup */
1563 smb_raw_ntcancel(req1);
1564 status = smb_raw_changenotify_recv(req1, tctx, &notify);
1565 torture_assert_ntstatus_equal_goto(tctx, status,
1566 NT_STATUS_CANCELLED,
1567 ret, done,
1568 "smb_raw_changenotify_recv");
1570 /* open a lot of files, filling up the server side notify buffer */
1571 torture_comment(tctx, "Testing overflowed buffer notify on create of %d files\n",
1572 count);
1573 for (i=0;i<count;i++) {
1574 char *fname = talloc_asprintf(cli, BASEDIR "\\test%d.txt", i);
1575 int fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR,
1576 DENY_NONE);
1577 torture_assert_int_not_equal_goto(tctx, fnum2, -1, ret, done,
1578 talloc_asprintf(tctx, "Failed to create %s - %s",
1579 fname, smbcli_errstr(cli->tree)));
1580 talloc_free(fname);
1581 smbcli_close(cli->tree, fnum2);
1584 /* expect that 0 events will be returned with NT_STATUS_OK */
1585 req1 = smb_raw_changenotify_send(cli->tree, &notify);
1586 status = smb_raw_changenotify_recv(req1, tctx, &notify);
1587 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1588 "smb_raw_changenotify_recv");
1589 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1590 0, ret, done, "no changes expected");
1592 done:
1593 smb_raw_exit(cli->session);
1594 smbcli_deltree(cli->tree, BASEDIR);
1595 return ret;
1599 Test if notifications are returned for changes to the base directory.
1600 They shouldn't be.
1602 static bool test_notify_basedir(struct torture_context *tctx,
1603 struct smbcli_state *cli)
1605 bool ret = true;
1606 NTSTATUS status;
1607 union smb_notify notify;
1608 union smb_open io;
1609 int fnum;
1610 struct smbcli_request *req1;
1612 torture_comment(tctx, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1614 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
1615 "Failed to setup up test directory: " BASEDIR);
1617 /* get a handle on the directory */
1618 io.generic.level = RAW_OPEN_NTCREATEX;
1619 io.ntcreatex.in.root_fid.fnum = 0;
1620 io.ntcreatex.in.flags = 0;
1621 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1622 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1623 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1624 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1625 NTCREATEX_SHARE_ACCESS_WRITE;
1626 io.ntcreatex.in.alloc_size = 0;
1627 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1628 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1629 io.ntcreatex.in.security_flags = 0;
1630 io.ntcreatex.in.fname = BASEDIR;
1632 status = smb_raw_open(cli->tree, tctx, &io);
1633 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1634 "smb_raw_open");
1635 fnum = io.ntcreatex.out.file.fnum;
1637 /* create a test file that will also be modified */
1638 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1",
1639 O_CREAT, 0));
1641 /* ask for a change notify, on attribute changes. */
1642 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1643 notify.nttrans.in.buffer_size = 1000;
1644 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
1645 notify.nttrans.in.file.fnum = fnum;
1646 notify.nttrans.in.recursive = true;
1648 req1 = smb_raw_changenotify_send(cli->tree, &notify);
1650 /* set attribute on the base dir */
1651 smbcli_setatr(cli->tree, BASEDIR, FILE_ATTRIBUTE_HIDDEN, 0);
1653 /* set attribute on a file to assure we receive a notification */
1654 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);
1655 smb_msleep(200);
1657 /* check how many responses were given, expect only 1 for the file */
1658 status = smb_raw_changenotify_recv(req1, tctx, &notify);
1659 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1660 "smb_raw_changenotify_recv");
1661 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1662 1, ret, done, "wrong number of changes");
1663 torture_assert_int_equal_goto(tctx,
1664 notify.nttrans.out.changes[0].action,
1665 NOTIFY_ACTION_MODIFIED, ret, done,
1666 "wrong action (exp: MODIFIED)");
1667 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "tname1",
1668 STR_UNICODE);
1670 done:
1671 smb_raw_exit(cli->session);
1672 smbcli_deltree(cli->tree, BASEDIR);
1673 return ret;
1678 create a secondary tree connect - used to test for a bug in Samba3 messaging
1679 with change notify
1681 static struct smbcli_tree *secondary_tcon(struct smbcli_state *cli,
1682 struct torture_context *tctx)
1684 NTSTATUS status;
1685 const char *share, *host;
1686 struct smbcli_tree *tree;
1687 union smb_tcon tcon;
1689 share = torture_setting_string(tctx, "share", NULL);
1690 host = torture_setting_string(tctx, "host", NULL);
1692 torture_comment(tctx, "create a second tree context on the same session\n");
1693 tree = smbcli_tree_init(cli->session, tctx, false);
1695 tcon.generic.level = RAW_TCON_TCONX;
1696 tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
1697 tcon.tconx.in.password = data_blob(NULL, 0);
1698 tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
1699 tcon.tconx.in.device = "A:";
1700 status = smb_raw_tcon(tree, tctx, &tcon);
1701 if (!NT_STATUS_IS_OK(status)) {
1702 talloc_free(tree);
1703 torture_comment(tctx, "Failed to create secondary tree\n");
1704 return NULL;
1707 tree->tid = tcon.tconx.out.tid;
1708 torture_comment(tctx, "tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
1710 return tree;
1715 very simple change notify test
1717 static bool test_notify_tcon(struct torture_context *tctx,
1718 struct smbcli_state *cli)
1720 bool ret = true;
1721 NTSTATUS status;
1722 union smb_notify notify;
1723 union smb_open io;
1724 int fnum;
1725 struct smbcli_request *req;
1726 extern int torture_numops;
1727 struct smbcli_tree *tree = NULL;
1729 torture_comment(tctx, "TESTING SIMPLE CHANGE NOTIFY\n");
1731 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
1732 "Failed to setup up test directory: " BASEDIR);
1735 get a handle on the directory
1737 io.generic.level = RAW_OPEN_NTCREATEX;
1738 io.ntcreatex.in.root_fid.fnum = 0;
1739 io.ntcreatex.in.flags = 0;
1740 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1741 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1742 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1743 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1744 io.ntcreatex.in.alloc_size = 0;
1745 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1746 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1747 io.ntcreatex.in.security_flags = 0;
1748 io.ntcreatex.in.fname = BASEDIR;
1750 status = smb_raw_open(cli->tree, tctx, &io);
1751 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1752 "smb_raw_open");
1753 fnum = io.ntcreatex.out.file.fnum;
1755 status = smb_raw_open(cli->tree, tctx, &io);
1756 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1757 "smb_raw_open");
1759 /* ask for a change notify,
1760 on file or directory name changes */
1761 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1762 notify.nttrans.in.buffer_size = 1000;
1763 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1764 notify.nttrans.in.file.fnum = fnum;
1765 notify.nttrans.in.recursive = true;
1767 torture_comment(tctx, "Testing notify mkdir\n");
1768 req = smb_raw_changenotify_send(cli->tree, &notify);
1769 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1771 status = smb_raw_changenotify_recv(req, tctx, &notify);
1772 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1773 "smb_raw_changenotify_recv");
1775 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1776 1, ret, done, "wrong number of changes");
1777 torture_assert_int_equal_goto(tctx,
1778 notify.nttrans.out.changes[0].action,
1779 NOTIFY_ACTION_ADDED, ret, done,
1780 "wrong action (exp: ADDED)");
1781 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1782 STR_UNICODE);
1784 torture_comment(tctx, "Testing notify rmdir\n");
1785 req = smb_raw_changenotify_send(cli->tree, &notify);
1786 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
1788 status = smb_raw_changenotify_recv(req, tctx, &notify);
1789 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1790 "smb_raw_changenotify_recv");
1791 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1792 1, ret, done, "wrong number of changes");
1793 torture_assert_int_equal_goto(tctx,
1794 notify.nttrans.out.changes[0].action,
1795 NOTIFY_ACTION_REMOVED, ret, done,
1796 "wrong action (exp: REMOVED)");
1797 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1798 STR_UNICODE);
1800 torture_comment(tctx, "SIMPLE CHANGE NOTIFY OK\n");
1802 torture_comment(tctx, "TESTING WITH SECONDARY TCON\n");
1803 tree = secondary_tcon(cli, tctx);
1804 torture_assert_not_null_goto(tctx, tree, ret, done,
1805 "failed to create secondary tcon");
1807 torture_comment(tctx, "Testing notify mkdir\n");
1808 req = smb_raw_changenotify_send(cli->tree, &notify);
1809 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1811 status = smb_raw_changenotify_recv(req, tctx, &notify);
1812 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1813 "smb_raw_changenotify_recv");
1815 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1816 1, ret, done, "wrong number of changes");
1817 torture_assert_int_equal_goto(tctx,
1818 notify.nttrans.out.changes[0].action,
1819 NOTIFY_ACTION_ADDED, ret, done,
1820 "wrong action (exp: ADDED)");
1821 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1822 STR_UNICODE);
1824 torture_comment(tctx, "Testing notify rmdir\n");
1825 req = smb_raw_changenotify_send(cli->tree, &notify);
1826 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
1828 status = smb_raw_changenotify_recv(req, tctx, &notify);
1829 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1830 "smb_raw_changenotify_recv");
1831 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1832 1, ret, done, "wrong number of changes");
1833 torture_assert_int_equal_goto(tctx,
1834 notify.nttrans.out.changes[0].action,
1835 NOTIFY_ACTION_REMOVED, ret, done,
1836 "wrong action (exp: REMOVED)");
1837 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1838 STR_UNICODE);
1840 torture_comment(tctx, "CHANGE NOTIFY WITH TCON OK\n");
1842 torture_comment(tctx, "Disconnecting secondary tree\n");
1843 status = smb_tree_disconnect(tree);
1844 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1845 "smb_tree_disconnect");
1846 talloc_free(tree);
1848 torture_comment(tctx, "Testing notify mkdir\n");
1849 req = smb_raw_changenotify_send(cli->tree, &notify);
1850 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1852 status = smb_raw_changenotify_recv(req, tctx, &notify);
1853 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1854 "smb_raw_changenotify_recv");
1856 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1857 1, ret, done, "wrong number of changes");
1858 torture_assert_int_equal_goto(tctx,
1859 notify.nttrans.out.changes[0].action,
1860 NOTIFY_ACTION_ADDED, ret, done,
1861 "wrong action (exp: ADDED)");
1862 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1863 STR_UNICODE);
1865 torture_comment(tctx, "Testing notify rmdir\n");
1866 req = smb_raw_changenotify_send(cli->tree, &notify);
1867 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
1869 status = smb_raw_changenotify_recv(req, tctx, &notify);
1870 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1871 "smb_raw_changenotify_recv");
1872 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1873 1, ret, done, "wrong number of changes");
1874 torture_assert_int_equal_goto(tctx,
1875 notify.nttrans.out.changes[0].action,
1876 NOTIFY_ACTION_REMOVED, ret, done,
1877 "wrong action (exp: REMOVED)");
1878 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1879 STR_UNICODE);
1881 torture_comment(tctx, "CHANGE NOTIFY WITH TDIS OK\n");
1882 done:
1883 smb_raw_exit(cli->session);
1884 smbcli_deltree(cli->tree, BASEDIR);
1885 return ret;
1890 testing alignment of multiple change notify infos
1892 static bool test_notify_alignment(struct torture_context *tctx,
1893 struct smbcli_state *cli)
1895 NTSTATUS status;
1896 union smb_notify notify;
1897 union smb_open io;
1898 int i, fnum, fnum2;
1899 struct smbcli_request *req;
1900 const char *fname = BASEDIR "\\starter";
1901 const char *fnames[] = { "a",
1902 "ab",
1903 "abc",
1904 "abcd" };
1905 int num_names = ARRAY_SIZE(fnames);
1906 char *fpath = NULL;
1908 torture_comment(tctx, "TESTING CHANGE NOTIFY REPLY ALIGNMENT\n");
1910 torture_assert(tctx, torture_setup_dir(cli, BASEDIR),
1911 "Failed to setup up test directory: " BASEDIR);
1913 /* get a handle on the directory */
1914 io.generic.level = RAW_OPEN_NTCREATEX;
1915 io.ntcreatex.in.root_fid.fnum = 0;
1916 io.ntcreatex.in.flags = 0;
1917 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1918 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1919 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1920 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1921 NTCREATEX_SHARE_ACCESS_WRITE;
1922 io.ntcreatex.in.alloc_size = 0;
1923 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1924 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1925 io.ntcreatex.in.security_flags = 0;
1926 io.ntcreatex.in.fname = BASEDIR;
1928 status = smb_raw_open(cli->tree, tctx, &io);
1929 torture_assert_ntstatus_ok(tctx, status, "smb_raw_open");
1930 fnum = io.ntcreatex.out.file.fnum;
1932 /* ask for a change notify, on file creation */
1933 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1934 notify.nttrans.in.buffer_size = 1000;
1935 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_FILE_NAME;
1936 notify.nttrans.in.file.fnum = fnum;
1937 notify.nttrans.in.recursive = false;
1939 /* start change tracking */
1940 req = smb_raw_changenotify_send(cli->tree, &notify);
1942 fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
1943 torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
1944 smbcli_close(cli->tree, fnum2);
1946 status = smb_raw_changenotify_recv(req, tctx, &notify);
1947 torture_assert_ntstatus_ok(tctx, status, "smb_raw_changenotify_recv");
1949 /* create 4 files that will cause CHANGE_NOTIFY_INFO structures
1950 * to be returned in the same packet with all possible 4-byte padding
1951 * permutations. As per MS-CIFS 2.2.7.4.2 these structures should be
1952 * 4-byte aligned. */
1954 for (i = 0; i < num_names; i++) {
1955 fpath = talloc_asprintf(tctx, "%s\\%s", BASEDIR, fnames[i]);
1956 fnum2 = smbcli_open(cli->tree, fpath,
1957 O_CREAT|O_RDWR, DENY_NONE);
1958 torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
1959 smbcli_close(cli->tree, fnum2);
1960 talloc_free(fpath);
1963 /* We send a notify packet, and let smb_raw_changenotify_recv() do
1964 * the alignment checking for us. */
1965 req = smb_raw_changenotify_send(cli->tree, &notify);
1966 status = smb_raw_changenotify_recv(req, tctx, &notify);
1967 torture_assert_ntstatus_ok(tctx, status, "smb_raw_changenotify_recv");
1969 /* Do basic checking for correctness. */
1970 torture_assert(tctx, notify.nttrans.out.num_changes == num_names, "");
1971 for (i = 0; i < num_names; i++) {
1972 torture_assert(tctx, notify.nttrans.out.changes[i].action ==
1973 NOTIFY_ACTION_ADDED, "");
1974 CHECK_WSTR(tctx, notify.nttrans.out.changes[i].name, fnames[i],
1975 STR_UNICODE);
1978 smb_raw_exit(cli->session);
1979 smbcli_deltree(cli->tree, BASEDIR);
1980 return true;
1983 struct torture_suite *torture_raw_notify(TALLOC_CTX *mem_ctx)
1985 struct torture_suite *suite = torture_suite_create(mem_ctx, "notify");
1987 torture_suite_add_1smb_test(suite, "tcon", test_notify_tcon);
1988 torture_suite_add_2smb_test(suite, "dir", test_notify_dir);
1989 torture_suite_add_2smb_test(suite, "mask", test_notify_mask);
1990 torture_suite_add_2smb_test(suite, "recursive", test_notify_recursive);
1991 torture_suite_add_1smb_test(suite, "mask_change",
1992 test_notify_mask_change);
1993 torture_suite_add_1smb_test(suite, "file", test_notify_file);
1994 torture_suite_add_1smb_test(suite, "tdis", test_notify_tdis);
1995 torture_suite_add_1smb_test(suite, "exit", test_notify_exit);
1996 torture_suite_add_1smb_test(suite, "ulogoff", test_notify_ulogoff);
1997 torture_suite_add_1smb_test(suite, "tcp_dis", test_notify_tcp_dis);
1998 torture_suite_add_1smb_test(suite, "double", test_notify_double);
1999 torture_suite_add_2smb_test(suite, "tree", test_notify_tree);
2000 torture_suite_add_1smb_test(suite, "overflow", test_notify_overflow);
2001 torture_suite_add_1smb_test(suite, "basedir", test_notify_basedir);
2002 torture_suite_add_1smb_test(suite, "alignment", test_notify_alignment);
2004 return suite;