s3:printing: Allow to run samba-bgqd as a standalone systemd service
[Samba.git] / source4 / torture / raw / notify.c
blobd134dc9935b58b7e2429157bfab7baa60c327a68
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"
27 #include "lib/events/events.h"
29 #define BASEDIR "\\test_notify"
31 #define CHECK_WSTR(tctx, field, value, flags) \
32 do { \
33 torture_assert_str_equal(tctx, field.s, value, "values don't match"); \
34 torture_assert(tctx, \
35 !wire_bad_flags(&field, STR_UNICODE, cli->transport), \
36 "wire_bad_flags"); \
37 } while (0)
39 #define BASEDIR_CN1_DIR BASEDIR "_CN1_DIR"
42 basic testing of change notify on directories
44 static bool test_notify_dir(struct torture_context *tctx,
45 struct smbcli_state *cli,
46 struct smbcli_state *cli2)
48 bool ret = true;
49 NTSTATUS status;
50 union smb_notify notify;
51 union smb_open io;
52 union smb_close cl;
53 int i, count, fnum, fnum2;
54 struct smbcli_request *req, *req2;
55 extern int torture_numops;
57 torture_comment(tctx, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
59 torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_DIR),
60 "Failed to setup up test directory: " BASEDIR_CN1_DIR);
63 get a handle on the directory
65 io.generic.level = RAW_OPEN_NTCREATEX;
66 io.ntcreatex.in.root_fid.fnum = 0;
67 io.ntcreatex.in.flags = 0;
68 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
69 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
70 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
71 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
72 io.ntcreatex.in.alloc_size = 0;
73 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
74 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
75 io.ntcreatex.in.security_flags = 0;
76 io.ntcreatex.in.fname = BASEDIR_CN1_DIR;
78 status = smb_raw_open(cli->tree, tctx, &io);
79 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
80 "smb_raw_open");
81 fnum = io.ntcreatex.out.file.fnum;
83 status = smb_raw_open(cli->tree, tctx, &io);
84 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
85 "smb_raw_open");
86 fnum2 = io.ntcreatex.out.file.fnum;
88 /* ask for a change notify,
89 on file or directory name changes */
90 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
91 notify.nttrans.in.buffer_size = 1000;
92 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
93 notify.nttrans.in.file.fnum = fnum;
94 notify.nttrans.in.recursive = true;
96 torture_comment(tctx, "Testing notify cancel\n");
98 req = smb_raw_changenotify_send(cli->tree, &notify);
99 smb_raw_ntcancel(req);
100 status = smb_raw_changenotify_recv(req, tctx, &notify);
101 torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_CANCELLED,
102 ret, done,
103 "smb_raw_changenotify_recv");
105 torture_comment(tctx, "Testing notify mkdir\n");
107 req = smb_raw_changenotify_send(cli->tree, &notify);
108 smbcli_mkdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
110 status = smb_raw_changenotify_recv(req, tctx, &notify);
111 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
112 "smb_raw_changenotify_recv");
114 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
115 1, ret, done, "more than one change");
116 torture_assert_int_equal_goto(tctx,
117 notify.nttrans.out.changes[0].action,
118 NOTIFY_ACTION_ADDED, ret, done,
119 "wrong action (exp: ADDED)");
120 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
121 STR_UNICODE);
123 torture_comment(tctx, "Testing notify rmdir\n");
125 req = smb_raw_changenotify_send(cli->tree, &notify);
126 smbcli_rmdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
128 status = smb_raw_changenotify_recv(req, tctx, &notify);
129 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
130 "smb_raw_changenotify_recv");
131 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
132 1, ret, done, "more than one change");
133 torture_assert_int_equal_goto(tctx,
134 notify.nttrans.out.changes[0].action,
135 NOTIFY_ACTION_REMOVED, ret, done,
136 "wrong action (exp: REMOVED)");
137 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
138 STR_UNICODE);
140 torture_comment(tctx, "Testing notify mkdir - rmdir - mkdir - rmdir\n");
142 smbcli_mkdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
143 smbcli_rmdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
144 smbcli_mkdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
145 smbcli_rmdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
146 smb_msleep(200);
147 req = smb_raw_changenotify_send(cli->tree, &notify);
148 status = smb_raw_changenotify_recv(req, tctx, &notify);
149 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
150 "smb_raw_changenotify_recv");
151 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
152 4, ret, done, "wrong number of changes");
153 torture_assert_int_equal_goto(tctx,
154 notify.nttrans.out.changes[0].action,
155 NOTIFY_ACTION_ADDED, ret, done,
156 "wrong action (exp: ADDED)");
157 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
158 STR_UNICODE);
159 torture_assert_int_equal_goto(tctx,
160 notify.nttrans.out.changes[1].action,
161 NOTIFY_ACTION_REMOVED, ret, done,
162 "wrong action (exp: REMOVED)");
163 CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name, "subdir-name",
164 STR_UNICODE);
165 torture_assert_int_equal_goto(tctx,
166 notify.nttrans.out.changes[2].action,
167 NOTIFY_ACTION_ADDED, ret, done,
168 "wrong action (exp: ADDED)");
169 CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name, "subdir-name",
170 STR_UNICODE);
171 torture_assert_int_equal_goto(tctx,
172 notify.nttrans.out.changes[3].action,
173 NOTIFY_ACTION_REMOVED, ret, done,
174 "wrong action (exp: REMOVED)");
175 CHECK_WSTR(tctx, notify.nttrans.out.changes[3].name, "subdir-name",
176 STR_UNICODE);
178 count = torture_numops;
179 torture_comment(tctx, "Testing buffered notify on create of %d files\n", count);
180 for (i=0;i<count;i++) {
181 char *fname = talloc_asprintf(cli,
182 BASEDIR_CN1_DIR "\\test%d.txt",
184 int fnum3 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
185 torture_assert_int_not_equal_goto(tctx, fnum3, -1, ret, done,
186 talloc_asprintf(tctx, "Failed to create %s - %s",
187 fname, smbcli_errstr(cli->tree)));
188 talloc_free(fname);
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, &notify);
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, &notify);
202 status = smbcli_unlink(cli->tree, BASEDIR_CN1_DIR "\\nonexistent.txt");
203 torture_assert_ntstatus_equal_goto(tctx, status,
204 NT_STATUS_OBJECT_NAME_NOT_FOUND,
205 ret, done,
206 "smbcli_unlink");
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 torture_comment(tctx, "Testing notify on unlink for the first file\n");
212 status = smbcli_unlink(cli2->tree, BASEDIR_CN1_DIR "\\test0.txt");
213 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
214 "smbcli_unlink");
216 /* receive the reply from the 2nd notify */
217 status = smb_raw_changenotify_recv(req, tctx, &notify);
218 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
219 "smb_raw_changenotify_recv");
221 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
222 count, ret, done,
223 "wrong number of changes");
224 for (i=1;i<count;i++) {
225 torture_assert_int_equal_goto(tctx,
226 notify.nttrans.out.changes[i].action,
227 NOTIFY_ACTION_ADDED, ret, done,
228 "wrong action (exp: ADDED)");
230 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
231 STR_UNICODE);
233 torture_comment(tctx, "and now from the 1st notify\n");
234 status = smb_raw_changenotify_recv(req2, tctx, &notify);
235 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
236 "smb_raw_changenotify_recv");
237 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
238 1, ret, done, "wrong number of changes");
239 torture_assert_int_equal_goto(tctx,
240 notify.nttrans.out.changes[0].action,
241 NOTIFY_ACTION_REMOVED, ret, done,
242 "wrong action (exp: REMOVED)");
243 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
244 STR_UNICODE);
246 torture_comment(tctx, "(3rd notify) this notify will only see the 1st unlink\n");
247 req = smb_raw_changenotify_send(cli->tree, &notify);
249 status = smbcli_unlink(cli->tree, BASEDIR_CN1_DIR "\\nonexistent.txt");
250 torture_assert_ntstatus_equal_goto(tctx, status,
251 NT_STATUS_OBJECT_NAME_NOT_FOUND,
252 ret, done,
253 "smbcli_unlink");
255 torture_comment(tctx, "Testing notify on wildcard unlink for %d files\n", count-1);
256 /* (2nd unlink) do a wildcard unlink */
257 status = smbcli_unlink_wcard(cli2->tree, BASEDIR_CN1_DIR "\\test*.txt");
258 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
259 "smb_raw_changenotify_recv");
261 /* receive the 3rd notify */
262 status = smb_raw_changenotify_recv(req, tctx, &notify);
263 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
264 "smb_raw_changenotify_recv");
265 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
266 1, ret, done, "wrong number of changes");
267 torture_assert_int_equal_goto(tctx,
268 notify.nttrans.out.changes[0].action,
269 NOTIFY_ACTION_REMOVED, ret, done,
270 "wrong action (exp: REMOVED)");
271 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
272 STR_UNICODE);
274 /* and we now see the rest of the unlink calls on both directory handles */
275 notify.nttrans.in.file.fnum = fnum;
276 sleep(3);
277 req = smb_raw_changenotify_send(cli->tree, &notify);
278 status = smb_raw_changenotify_recv(req, tctx, &notify);
279 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
280 "smb_raw_changenotify_recv");
281 torture_assert_int_equal_goto(tctx, 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(tctx,
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, &notify);
292 status = smb_raw_changenotify_recv(req, tctx, &notify);
293 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
294 "smb_raw_changenotify_recv");
295 torture_assert_int_equal_goto(tctx, 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(tctx,
300 notify.nttrans.out.changes[i].action,
301 NOTIFY_ACTION_REMOVED, ret, done,
302 "wrong action (exp: REMOVED)");
305 torture_comment(tctx, "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, &notify);
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(tctx, status, ret, done,
315 "smb_raw_close");
317 status = smb_raw_changenotify_recv(req, tctx, &notify);
318 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
319 "smb_raw_changenotify_recv");
320 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
321 0, ret, done, "no changes expected");
323 done:
324 smb_raw_exit(cli->session);
325 smbcli_deltree(cli->tree, BASEDIR_CN1_DIR);
326 return ret;
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 torture_context *tctx,
337 struct smbcli_state *cli,
338 int line,
339 struct notify_changes *actions,
340 uint32_t action, const char *name)
342 int i;
344 for (i=0; i<3; i++) {
345 if (actions[i].action == action) {
346 CHECK_WSTR(tctx, actions[i].name, name, STR_UNICODE);
347 return true;
351 torture_result(tctx, TORTURE_FAIL,
352 __location__": (%d) expected action %d, not found\n",
353 line, action);
354 return false;
358 testing of recursive change notify
361 #define BASEDIR_CN1_RECUR BASEDIR "_CN1_RECUR"
363 static bool test_notify_recursive(struct torture_context *tctx,
364 struct smbcli_state *cli,
365 struct smbcli_state *cli2)
367 bool ret = true;
368 NTSTATUS status;
369 union smb_notify notify;
370 union smb_open io;
371 int fnum;
372 struct smbcli_request *req1, *req2;
374 torture_comment(tctx, "TESTING CHANGE NOTIFY WITH RECURSION\n");
376 torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_RECUR),
377 "Failed to setup up test directory: " BASEDIR_CN1_RECUR);
380 get a handle on the directory
382 io.generic.level = RAW_OPEN_NTCREATEX;
383 io.ntcreatex.in.root_fid.fnum = 0;
384 io.ntcreatex.in.flags = 0;
385 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
386 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
387 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
388 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
389 io.ntcreatex.in.alloc_size = 0;
390 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
391 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
392 io.ntcreatex.in.security_flags = 0;
393 io.ntcreatex.in.fname = BASEDIR_CN1_RECUR;
395 status = smb_raw_open(cli->tree, tctx, &io);
396 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
397 "smb_raw_open");
398 fnum = io.ntcreatex.out.file.fnum;
400 /* ask for a change notify, on file or directory name
401 changes. Setup both with and without recursion */
402 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
403 notify.nttrans.in.buffer_size = 1000;
404 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
405 notify.nttrans.in.file.fnum = fnum;
407 notify.nttrans.in.recursive = true;
408 req1 = smb_raw_changenotify_send(cli->tree, &notify);
410 notify.nttrans.in.recursive = false;
411 req2 = smb_raw_changenotify_send(cli->tree, &notify);
413 /* cancel initial requests so the buffer is setup */
414 smb_raw_ntcancel(req1);
415 status = smb_raw_changenotify_recv(req1, tctx, &notify);
416 torture_assert_ntstatus_equal_goto(tctx, status,
417 NT_STATUS_CANCELLED,
418 ret, done,
419 "smb_raw_changenotify_recv");
421 smb_raw_ntcancel(req2);
422 status = smb_raw_changenotify_recv(req2, tctx, &notify);
423 torture_assert_ntstatus_equal_goto(tctx, status,
424 NT_STATUS_CANCELLED,
425 ret, done,
426 "smb_raw_changenotify_recv");
429 * Make notifies a bit more interesting in a cluster by doing
430 * the changes against different nodes with --unclist
432 smbcli_mkdir(cli->tree, BASEDIR_CN1_RECUR "\\subdir-name");
433 smbcli_mkdir(cli2->tree, BASEDIR_CN1_RECUR "\\subdir-name\\subname1");
434 smbcli_close(cli->tree,
435 smbcli_open(cli->tree,
436 BASEDIR_CN1_RECUR "\\subdir-name\\subname2",
437 O_CREAT, 0));
438 smbcli_rename(cli2->tree, BASEDIR_CN1_RECUR "\\subdir-name\\subname1",
439 BASEDIR_CN1_RECUR "\\subdir-name\\subname1-r");
440 smbcli_rename(cli->tree,
441 BASEDIR_CN1_RECUR "\\subdir-name\\subname2",
442 BASEDIR_CN1_RECUR "\\subname2-r");
443 smbcli_rename(cli2->tree, BASEDIR_CN1_RECUR "\\subname2-r",
444 BASEDIR_CN1_RECUR "\\subname3-r");
446 notify.nttrans.in.completion_filter = 0;
447 notify.nttrans.in.recursive = true;
448 smb_msleep(200);
449 req1 = smb_raw_changenotify_send(cli->tree, &notify);
451 smbcli_rmdir(cli->tree, BASEDIR_CN1_RECUR "\\subdir-name\\subname1-r");
452 smbcli_rmdir(cli2->tree, BASEDIR_CN1_RECUR "\\subdir-name");
453 smbcli_unlink(cli->tree, BASEDIR_CN1_RECUR "\\subname3-r");
455 smb_msleep(200);
456 notify.nttrans.in.recursive = false;
457 req2 = smb_raw_changenotify_send(cli->tree, &notify);
459 status = smb_raw_changenotify_recv(req1, tctx, &notify);
460 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
461 "smb_raw_changenotify_recv");
463 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
464 11, ret, done, "wrong number of changes");
465 torture_assert_int_equal_goto(tctx,
466 notify.nttrans.out.changes[0].action,
467 NOTIFY_ACTION_ADDED, ret, done,
468 "wrong action (exp: ADDED)");
469 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
470 STR_UNICODE);
471 torture_assert_int_equal_goto(tctx,
472 notify.nttrans.out.changes[1].action,
473 NOTIFY_ACTION_ADDED, ret, done,
474 "wrong action (exp: ADDED)");
475 CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name,
476 "subdir-name\\subname1", STR_UNICODE);
477 torture_assert_int_equal_goto(tctx,
478 notify.nttrans.out.changes[2].action,
479 NOTIFY_ACTION_ADDED, ret, done,
480 "wrong action (exp: ADDED)");
481 CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name,
482 "subdir-name\\subname2", STR_UNICODE);
483 torture_assert_int_equal_goto(tctx,
484 notify.nttrans.out.changes[3].action,
485 NOTIFY_ACTION_OLD_NAME, ret, done,
486 "wrong action (exp: OLD_NAME)");
487 CHECK_WSTR(tctx, notify.nttrans.out.changes[3].name,
488 "subdir-name\\subname1", STR_UNICODE);
489 torture_assert_int_equal_goto(tctx,
490 notify.nttrans.out.changes[4].action,
491 NOTIFY_ACTION_NEW_NAME, ret, done,
492 "wrong action (exp: NEW_NAME)");
493 CHECK_WSTR(tctx, notify.nttrans.out.changes[4].name,
494 "subdir-name\\subname1-r", STR_UNICODE);
496 ret &= check_rename_reply(tctx,
497 cli, __LINE__, &notify.nttrans.out.changes[5],
498 NOTIFY_ACTION_ADDED, "subname2-r");
499 ret &= check_rename_reply(tctx,
500 cli, __LINE__, &notify.nttrans.out.changes[5],
501 NOTIFY_ACTION_REMOVED, "subdir-name\\subname2");
502 ret &= check_rename_reply(tctx,
503 cli, __LINE__, &notify.nttrans.out.changes[5],
504 NOTIFY_ACTION_MODIFIED, "subname2-r");
506 ret &= check_rename_reply(tctx,
507 cli, __LINE__, &notify.nttrans.out.changes[8],
508 NOTIFY_ACTION_OLD_NAME, "subname2-r");
509 ret &= check_rename_reply(tctx,
510 cli, __LINE__, &notify.nttrans.out.changes[8],
511 NOTIFY_ACTION_NEW_NAME, "subname3-r");
512 ret &= check_rename_reply(tctx,
513 cli, __LINE__, &notify.nttrans.out.changes[8],
514 NOTIFY_ACTION_MODIFIED, "subname3-r");
516 if (!ret) {
517 goto done;
520 status = smb_raw_changenotify_recv(req2, tctx, &notify);
521 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
522 "smb_raw_changenotify_recv");
524 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
525 3, ret, done, "wrong number of changes");
526 torture_assert_int_equal_goto(tctx,
527 notify.nttrans.out.changes[0].action,
528 NOTIFY_ACTION_REMOVED, ret, done,
529 "wrong action (exp: REMOVED)");
530 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name,
531 "subdir-name\\subname1-r", STR_UNICODE);
532 torture_assert_int_equal_goto(tctx,
533 notify.nttrans.out.changes[1].action,
534 NOTIFY_ACTION_REMOVED, ret, done,
535 "wrong action (exp: REMOVED)");
536 CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name, "subdir-name",
537 STR_UNICODE);
538 torture_assert_int_equal_goto(tctx,
539 notify.nttrans.out.changes[2].action,
540 NOTIFY_ACTION_REMOVED, ret, done,
541 "wrong action (exp: REMOVED)");
542 CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name, "subname3-r",
543 STR_UNICODE);
545 done:
546 smb_raw_exit(cli->session);
547 smbcli_deltree(cli->tree, BASEDIR_CN1_RECUR);
548 return ret;
552 testing of change notify mask change
555 #define BASEDIR_CN1_CNMC BASEDIR "_CN1_CNMC"
557 static bool test_notify_mask_change(struct torture_context *tctx,
558 struct smbcli_state *cli)
560 bool ret = true;
561 NTSTATUS status;
562 union smb_notify notify;
563 union smb_open io;
564 int fnum;
565 struct smbcli_request *req1, *req2;
567 torture_comment(tctx, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
569 torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_CNMC),
570 "Failed to setup up test directory: " BASEDIR_CN1_CNMC);
573 get a handle on the directory
575 io.generic.level = RAW_OPEN_NTCREATEX;
576 io.ntcreatex.in.root_fid.fnum = 0;
577 io.ntcreatex.in.flags = 0;
578 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
579 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
580 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
581 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
582 io.ntcreatex.in.alloc_size = 0;
583 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
584 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
585 io.ntcreatex.in.security_flags = 0;
586 io.ntcreatex.in.fname = BASEDIR_CN1_CNMC;
588 status = smb_raw_open(cli->tree, tctx, &io);
589 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
590 "smb_raw_open");
591 fnum = io.ntcreatex.out.file.fnum;
593 /* ask for a change notify, on file or directory name
594 changes. Setup both with and without recursion */
595 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
596 notify.nttrans.in.buffer_size = 1000;
597 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
598 notify.nttrans.in.file.fnum = fnum;
600 notify.nttrans.in.recursive = true;
601 req1 = smb_raw_changenotify_send(cli->tree, &notify);
603 notify.nttrans.in.recursive = false;
604 req2 = smb_raw_changenotify_send(cli->tree, &notify);
606 /* cancel initial requests so the buffer is setup */
607 smb_raw_ntcancel(req1);
608 status = smb_raw_changenotify_recv(req1, tctx, &notify);
609 torture_assert_ntstatus_equal_goto(tctx, status,
610 NT_STATUS_CANCELLED,
611 ret, done,
612 "smb_raw_changenotify_recv");
614 smb_raw_ntcancel(req2);
615 status = smb_raw_changenotify_recv(req2, tctx, &notify);
616 torture_assert_ntstatus_equal_goto(tctx, status,
617 NT_STATUS_CANCELLED,
618 ret, done,
619 "smb_raw_changenotify_recv");
621 notify.nttrans.in.recursive = true;
622 req1 = smb_raw_changenotify_send(cli->tree, &notify);
624 /* Set to hidden then back again. */
625 smbcli_close(cli->tree,
626 smbcli_open(cli->tree,BASEDIR_CN1_CNMC "\\tname1", O_CREAT, 0));
627 smbcli_setatr(cli->tree, BASEDIR_CN1_CNMC "\\tname1",
628 FILE_ATTRIBUTE_HIDDEN, 0);
629 smbcli_unlink(cli->tree, BASEDIR_CN1_CNMC "\\tname1");
631 status = smb_raw_changenotify_recv(req1, tctx, &notify);
632 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
633 "smb_raw_changenotify_recv");
635 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
636 1, ret, done, "wrong number of changes");
637 torture_assert_int_equal_goto(tctx,
638 notify.nttrans.out.changes[0].action,
639 NOTIFY_ACTION_MODIFIED, ret, done,
640 "wrong action (exp: MODIFIED)");
641 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "tname1",
642 STR_UNICODE);
644 /* Now try and change the mask to include other events.
645 * This should not work - once the mask is set on a directory
646 * fnum it seems to be fixed until the fnum is closed. */
648 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
649 notify.nttrans.in.recursive = true;
650 req1 = smb_raw_changenotify_send(cli->tree, &notify);
652 notify.nttrans.in.recursive = false;
653 req2 = smb_raw_changenotify_send(cli->tree, &notify);
655 smbcli_mkdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name");
656 smbcli_mkdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name\\subname1");
657 smbcli_close(cli->tree,
658 smbcli_open(cli->tree,
659 BASEDIR_CN1_CNMC "\\subdir-name\\subname2",
660 O_CREAT, 0));
661 smbcli_rename(cli->tree,
662 BASEDIR_CN1_CNMC "\\subdir-name\\subname1",
663 BASEDIR_CN1_CNMC "\\subdir-name\\subname1-r");
664 smbcli_rename(cli->tree,
665 BASEDIR_CN1_CNMC "\\subdir-name\\subname2",
666 BASEDIR_CN1_CNMC "\\subname2-r");
667 smbcli_rename(cli->tree,
668 BASEDIR_CN1_CNMC "\\subname2-r",
669 BASEDIR_CN1_CNMC "\\subname3-r");
671 smbcli_rmdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name\\subname1-r");
672 smbcli_rmdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name");
673 smbcli_unlink(cli->tree, BASEDIR_CN1_CNMC "\\subname3-r");
675 status = smb_raw_changenotify_recv(req1, tctx, &notify);
676 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
677 "smb_raw_changenotify_recv");
679 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
680 1, ret, done, "wrong number of changes");
681 torture_assert_int_equal_goto(tctx,
682 notify.nttrans.out.changes[0].action,
683 NOTIFY_ACTION_MODIFIED, ret, done,
684 "wrong action (exp: MODIFIED)");
685 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subname2-r",
686 STR_UNICODE);
688 status = smb_raw_changenotify_recv(req2, tctx, &notify);
689 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
690 "smb_raw_changenotify_recv");
692 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
693 1, ret, done, "wrong number of changes");
694 torture_assert_int_equal_goto(tctx,
695 notify.nttrans.out.changes[0].action,
696 NOTIFY_ACTION_MODIFIED, ret, done,
697 "wrong action (exp: MODIFIED)");
698 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subname3-r",
699 STR_UNICODE);
701 done:
702 smb_raw_exit(cli->session);
703 smbcli_deltree(cli->tree, BASEDIR_CN1_CNMC);
704 return ret;
709 testing of mask bits for change notify
712 #define BASEDIR_CN1_NOTM BASEDIR "_CN1_NOTM"
714 static bool test_notify_mask(struct torture_context *tctx,
715 struct smbcli_state *cli,
716 struct smbcli_state *cli2)
718 bool ret = true;
719 NTSTATUS status;
720 union smb_notify notify;
721 union smb_open io;
722 union smb_chkpath chkpath;
723 int fnum, fnum2;
724 uint32_t mask;
725 int i;
726 char c = 1;
727 struct timeval tv;
728 NTTIME t;
730 torture_comment(tctx, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
732 torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NOTM),
733 "Failed to setup up test directory: " BASEDIR_CN1_NOTM);
735 tv = timeval_current_ofs(1000, 0);
736 t = timeval_to_nttime(&tv);
739 get a handle on the directory
741 io.generic.level = RAW_OPEN_NTCREATEX;
742 io.ntcreatex.in.root_fid.fnum = 0;
743 io.ntcreatex.in.flags = 0;
744 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
745 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
746 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
747 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
748 io.ntcreatex.in.alloc_size = 0;
749 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
750 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
751 io.ntcreatex.in.security_flags = 0;
752 io.ntcreatex.in.fname = BASEDIR_CN1_NOTM;
754 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
755 notify.nttrans.in.buffer_size = 1000;
756 notify.nttrans.in.recursive = true;
758 chkpath.chkpath.in.path = "\\";
760 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, expected, nchanges) \
761 do { \
762 smbcli_getatr(cli->tree, test_name, NULL, NULL, NULL); \
763 for (mask=i=0;i<32;i++) { \
764 struct smbcli_request *req; \
765 status = smb_raw_open(cli->tree, tctx, &io); \
766 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
767 "smb_raw_open"); \
768 fnum = io.ntcreatex.out.file.fnum; \
769 setup \
770 notify.nttrans.in.file.fnum = fnum; \
771 notify.nttrans.in.completion_filter = ((uint32_t)1<<i); \
772 req = smb_raw_changenotify_send(cli->tree, &notify); \
773 smb_raw_chkpath(cli->tree, &chkpath); \
774 op \
775 smb_msleep(200); smb_raw_ntcancel(req); \
776 status = smb_raw_changenotify_recv(req, tctx, &notify); \
777 cleanup \
778 smbcli_close(cli->tree, fnum); \
779 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
780 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
781 "smbcli_close"); \
782 /* special case to cope with file rename behaviour */ \
783 if (nchanges == 2 && notify.nttrans.out.num_changes == 1 && \
784 notify.nttrans.out.changes[0].action == NOTIFY_ACTION_MODIFIED && \
785 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
786 Action == NOTIFY_ACTION_OLD_NAME) { \
787 torture_comment(tctx, "(rename file special handling OK)\n"); \
788 } else { \
789 torture_assert_int_equal_goto(tctx, \
790 notify.nttrans.out.num_changes,\
791 nchanges, ret, done, \
792 talloc_asprintf(tctx, \
793 "nchanges=%d expected=%d action=%d " \
794 "filter=0x%08x\n", \
795 notify.nttrans.out.num_changes, \
796 nchanges, \
797 notify.nttrans.out.changes[0].action, \
798 notify.nttrans.in.completion_filter)); \
799 torture_assert_int_equal_goto(tctx, \
800 notify.nttrans.out.changes[0].action, \
801 Action, ret, done, \
802 talloc_asprintf(tctx, \
803 "nchanges=%d action=%d " \
804 "expectedAction=%d filter=0x%08x\n", \
805 notify.nttrans.out.num_changes, \
806 notify.nttrans.out.changes[0].action, \
807 Action, \
808 notify.nttrans.in.completion_filter)); \
809 torture_assert_str_equal_goto(tctx, \
810 notify.nttrans.out.changes[0].name.s, \
811 "tname1", ret, done, \
812 talloc_asprintf(tctx, \
813 "nchanges=%d action=%d filter=0x%08x " \
814 "name=%s expected_name=tname1\n", \
815 notify.nttrans.out.num_changes, \
816 notify.nttrans.out.changes[0].action, \
817 notify.nttrans.in.completion_filter, \
818 notify.nttrans.out.changes[0].name.s));\
820 mask |= ((uint32_t)1<<i); \
822 if ((expected) != mask) { \
823 torture_assert_int_not_equal_goto(tctx, ((expected) & ~mask), \
824 0, ret, done, "Too few bits"); \
825 torture_comment(tctx, "WARNING: trigger on too many bits. mask=0x%08x expected=0x%08x\n", \
826 mask, expected); \
828 } while (0);
830 torture_comment(tctx, "Testing mkdir\n");
831 NOTIFY_MASK_TEST("Testing mkdir",;,
832 smbcli_mkdir(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
833 smbcli_rmdir(cli2->tree, BASEDIR_CN1_NOTM "\\tname1");,
834 NOTIFY_ACTION_ADDED,
835 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
837 torture_comment(tctx, "Testing create file\n");
838 NOTIFY_MASK_TEST("Testing create file",;,
839 smbcli_close(cli->tree,
840 smbcli_open(cli->tree,
841 BASEDIR_CN1_NOTM "\\tname1",
842 O_CREAT, 0));,
843 smbcli_unlink(cli2->tree,
844 BASEDIR_CN1_NOTM "\\tname1");,
845 NOTIFY_ACTION_ADDED,
846 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
848 torture_comment(tctx, "Testing unlink\n");
849 NOTIFY_MASK_TEST("Testing unlink",
850 smbcli_close(cli->tree,
851 smbcli_open(cli->tree,
852 BASEDIR_CN1_NOTM "\\tname1",
853 O_CREAT, 0));,
854 smbcli_unlink(cli2->tree,
855 BASEDIR_CN1_NOTM "\\tname1");,
857 NOTIFY_ACTION_REMOVED,
858 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
860 torture_comment(tctx, "Testing rmdir\n");
861 NOTIFY_MASK_TEST("Testing rmdir",
862 smbcli_mkdir(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
863 smbcli_rmdir(cli2->tree, BASEDIR_CN1_NOTM "\\tname1");,
865 NOTIFY_ACTION_REMOVED,
866 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
868 torture_comment(tctx, "Testing rename file\n");
869 NOTIFY_MASK_TEST("Testing rename file",
870 smbcli_close(cli->tree,
871 smbcli_open(cli->tree,
872 BASEDIR_CN1_NOTM "\\tname1",
873 O_CREAT, 0));,
874 smbcli_rename(cli2->tree,
875 BASEDIR_CN1_NOTM "\\tname1",
876 BASEDIR_CN1_NOTM "\\tname2");,
877 smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname2");,
878 NOTIFY_ACTION_OLD_NAME,
879 FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_CREATION, 2);
881 torture_comment(tctx, "Testing rename dir\n");
882 NOTIFY_MASK_TEST("Testing rename dir",
883 smbcli_mkdir(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
884 smbcli_rename(cli2->tree,
885 BASEDIR_CN1_NOTM "\\tname1",
886 BASEDIR_CN1_NOTM "\\tname2");,
887 smbcli_rmdir(cli->tree, BASEDIR_CN1_NOTM "\\tname2");,
888 NOTIFY_ACTION_OLD_NAME,
889 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
891 torture_comment(tctx, "Testing set path attribute\n");
892 NOTIFY_MASK_TEST("Testing set path attribute",
893 smbcli_close(cli->tree,
894 smbcli_open(cli->tree,
895 BASEDIR_CN1_NOTM "\\tname1", O_CREAT, 0));,
896 smbcli_setatr(cli2->tree,
897 BASEDIR_CN1_NOTM "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);,
898 smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
899 NOTIFY_ACTION_MODIFIED,
900 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
902 torture_comment(tctx, "Testing set path write time\n");
903 NOTIFY_MASK_TEST("Testing set path write time",
904 smbcli_close(cli->tree, smbcli_open(cli->tree,
905 BASEDIR_CN1_NOTM "\\tname1", O_CREAT, 0));,
906 smbcli_setatr(cli2->tree,
907 BASEDIR_CN1_NOTM "\\tname1",
908 FILE_ATTRIBUTE_NORMAL, 1000);,
909 smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
910 NOTIFY_ACTION_MODIFIED,
911 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
913 torture_comment(tctx, "Testing set file attribute\n");
914 NOTIFY_MASK_TEST("Testing set file attribute",
915 fnum2 = create_complex_file(cli2, tctx,
916 BASEDIR_CN1_NOTM "\\tname1");,
917 smbcli_fsetatr(cli2->tree, fnum2, FILE_ATTRIBUTE_HIDDEN, 0, 0, 0, 0);,
918 (smbcli_close(cli2->tree, fnum2),
919 smbcli_unlink(cli2->tree, BASEDIR_CN1_NOTM "\\tname1"));,
920 NOTIFY_ACTION_MODIFIED,
921 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
923 if (torture_setting_bool(tctx, "samba3", false)) {
924 torture_comment(tctx, "Samba3 does not yet support create times "
925 "everywhere\n");
927 else {
928 torture_comment(tctx, "Testing set file create time\n");
929 NOTIFY_MASK_TEST("Testing set file create time",
930 fnum2 = create_complex_file(cli, tctx,
931 BASEDIR_CN1_NOTM "\\tname1");,
932 smbcli_fsetatr(cli->tree, fnum2, 0, t, 0, 0, 0);,
933 (smbcli_close(cli->tree, fnum2),
934 smbcli_unlink(cli->tree,
935 BASEDIR_CN1_NOTM "\\tname1"));,
936 NOTIFY_ACTION_MODIFIED,
937 FILE_NOTIFY_CHANGE_CREATION, 1);
940 torture_comment(tctx, "Testing set file access time\n");
941 NOTIFY_MASK_TEST("Testing set file access time",
942 fnum2 = create_complex_file(cli, tctx,
943 BASEDIR_CN1_NOTM "\\tname1");,
944 smbcli_fsetatr(cli->tree, fnum2, 0, 0, t, 0, 0);,
945 (smbcli_close(cli->tree, fnum2),
946 smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
947 NOTIFY_ACTION_MODIFIED,
948 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
950 torture_comment(tctx, "Testing set file write time\n");
951 NOTIFY_MASK_TEST("Testing set file write time",
952 fnum2 = create_complex_file(cli, tctx,
953 BASEDIR_CN1_NOTM "\\tname1");,
954 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, t, 0);,
955 (smbcli_close(cli->tree, fnum2),
956 smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
957 NOTIFY_ACTION_MODIFIED,
958 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
960 torture_comment(tctx, "Testing set file change time\n");
961 NOTIFY_MASK_TEST("Testing set file change time",
962 fnum2 = create_complex_file(cli, tctx,
963 BASEDIR_CN1_NOTM "\\tname1");,
964 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, 0, t);,
965 (smbcli_close(cli->tree, fnum2),
966 smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
967 NOTIFY_ACTION_MODIFIED,
968 0, 1);
971 torture_comment(tctx, "Testing write\n");
972 NOTIFY_MASK_TEST("Testing write",
973 fnum2 = create_complex_file(cli2, tctx,
974 BASEDIR_CN1_NOTM "\\tname1");,
975 smbcli_write(cli2->tree, fnum2, 1, &c, 10000, 1);,
976 (smbcli_close(cli2->tree, fnum2),
977 smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
978 NOTIFY_ACTION_MODIFIED,
979 0, 1);
981 torture_comment(tctx, "Testing truncate\n");
982 NOTIFY_MASK_TEST("Testing truncate",
983 fnum2 = create_complex_file(cli2, tctx,
984 BASEDIR_CN1_NOTM "\\tname1");,
985 smbcli_ftruncate(cli2->tree, fnum2, 10000);,
986 (smbcli_close(cli2->tree, fnum2),
987 smbcli_unlink(cli2->tree, BASEDIR_CN1_NOTM "\\tname1"));,
988 NOTIFY_ACTION_MODIFIED,
989 FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
991 done:
992 smb_raw_exit(cli->session);
993 smbcli_deltree(cli->tree, BASEDIR_CN1_NOTM);
994 return ret;
998 basic testing of change notify on files
1001 #define BASEDIR_CN1_FILE BASEDIR "_CN1_FILE"
1003 static bool test_notify_file(struct torture_context *tctx,
1004 struct smbcli_state *cli)
1006 NTSTATUS status;
1007 bool ret = true;
1008 union smb_open io;
1009 union smb_close cl;
1010 union smb_notify notify;
1011 struct smbcli_request *req;
1012 int fnum;
1013 const char *fname = BASEDIR_CN1_FILE "\\file.txt";
1015 torture_comment(tctx, "TESTING CHANGE NOTIFY ON FILES\n");
1017 torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_FILE),
1018 "Failed to setup up test directory: " BASEDIR_CN1_FILE);
1020 io.generic.level = RAW_OPEN_NTCREATEX;
1021 io.ntcreatex.in.root_fid.fnum = 0;
1022 io.ntcreatex.in.flags = 0;
1023 io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
1024 io.ntcreatex.in.create_options = 0;
1025 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1026 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1027 io.ntcreatex.in.alloc_size = 0;
1028 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1029 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1030 io.ntcreatex.in.security_flags = 0;
1031 io.ntcreatex.in.fname = fname;
1032 status = smb_raw_open(cli->tree, tctx, &io);
1033 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1034 "smb_raw_open");
1035 fnum = io.ntcreatex.out.file.fnum;
1037 /* ask for a change notify,
1038 on file or directory name changes */
1039 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1040 notify.nttrans.in.file.fnum = fnum;
1041 notify.nttrans.in.buffer_size = 1000;
1042 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
1043 notify.nttrans.in.recursive = false;
1045 torture_comment(tctx, "Testing if notifies on file handles are invalid (should be)\n");
1047 req = smb_raw_changenotify_send(cli->tree, &notify);
1048 status = smb_raw_changenotify_recv(req, tctx, &notify);
1049 torture_assert_ntstatus_equal_goto(tctx, status,
1050 NT_STATUS_INVALID_PARAMETER,
1051 ret, done,
1052 "smb_raw_changenotify_recv");
1054 cl.close.level = RAW_CLOSE_CLOSE;
1055 cl.close.in.file.fnum = fnum;
1056 cl.close.in.write_time = 0;
1057 status = smb_raw_close(cli->tree, &cl);
1058 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1059 "smb_raw_close");
1061 status = smbcli_unlink(cli->tree, fname);
1062 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1063 "smbcli_unlink");
1065 done:
1066 smb_raw_exit(cli->session);
1067 smbcli_deltree(cli->tree, BASEDIR_CN1_FILE);
1068 return ret;
1072 basic testing of change notifies followed by a tdis
1074 #define BASEDIR_CN1_TDIS BASEDIR "_CN1_TDIS"
1076 static bool test_notify_tdis(struct torture_context *tctx,
1077 struct smbcli_state *cli1)
1079 bool ret = true;
1080 NTSTATUS status;
1081 union smb_notify notify;
1082 union smb_open io;
1083 int fnum;
1084 struct smbcli_request *req;
1085 struct smbcli_state *cli = NULL;
1087 torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY TDIS\n");
1089 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_TDIS),
1090 "Failed to setup up test directory: " BASEDIR_CN1_TDIS);
1092 torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1093 "Failed to open connection.");
1096 get a handle on the directory
1098 io.generic.level = RAW_OPEN_NTCREATEX;
1099 io.ntcreatex.in.root_fid.fnum = 0;
1100 io.ntcreatex.in.flags = 0;
1101 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1102 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1103 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1104 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1105 io.ntcreatex.in.alloc_size = 0;
1106 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1107 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1108 io.ntcreatex.in.security_flags = 0;
1109 io.ntcreatex.in.fname = BASEDIR_CN1_TDIS;
1111 status = smb_raw_open(cli->tree, tctx, &io);
1112 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1113 "smb_raw_open");
1114 fnum = io.ntcreatex.out.file.fnum;
1116 /* ask for a change notify,
1117 on file or directory name changes */
1118 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1119 notify.nttrans.in.buffer_size = 1000;
1120 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1121 notify.nttrans.in.file.fnum = fnum;
1122 notify.nttrans.in.recursive = true;
1124 req = smb_raw_changenotify_send(cli->tree, &notify);
1126 status = smbcli_tdis(cli);
1127 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1128 "smbcli_tdis");
1129 cli->tree = NULL;
1131 status = smb_raw_changenotify_recv(req, tctx, &notify);
1132 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1133 "smb_raw_changenotify_recv");
1134 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1135 0, ret, done, "no changes expected");
1137 done:
1138 torture_close_connection(cli);
1139 smbcli_deltree(cli1->tree, BASEDIR_CN1_TDIS);
1140 return ret;
1144 basic testing of change notifies followed by a exit
1147 #define BASEDIR_CN1_EX BASEDIR "_CN1_EX"
1149 static bool test_notify_exit(struct torture_context *tctx,
1150 struct smbcli_state *cli1)
1152 bool ret = true;
1153 NTSTATUS status;
1154 union smb_notify notify;
1155 union smb_open io;
1156 int fnum;
1157 struct smbcli_request *req;
1158 struct smbcli_state *cli = NULL;
1160 torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY EXIT\n");
1162 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_EX),
1163 "Failed to setup up test directory: " BASEDIR_CN1_EX);
1165 torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1166 "Failed to open connection.");
1169 get a handle on the directory
1171 io.generic.level = RAW_OPEN_NTCREATEX;
1172 io.ntcreatex.in.root_fid.fnum = 0;
1173 io.ntcreatex.in.flags = 0;
1174 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1175 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1176 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1177 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1178 io.ntcreatex.in.alloc_size = 0;
1179 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1180 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1181 io.ntcreatex.in.security_flags = 0;
1182 io.ntcreatex.in.fname = BASEDIR_CN1_EX;
1184 status = smb_raw_open(cli->tree, tctx, &io);
1185 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1186 "smb_raw_open");
1187 fnum = io.ntcreatex.out.file.fnum;
1189 /* ask for a change notify,
1190 on file or directory name changes */
1191 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1192 notify.nttrans.in.buffer_size = 1000;
1193 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1194 notify.nttrans.in.file.fnum = fnum;
1195 notify.nttrans.in.recursive = true;
1197 req = smb_raw_changenotify_send(cli->tree, &notify);
1199 status = smb_raw_exit(cli->session);
1200 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1201 "smb_raw_exit");
1203 status = smb_raw_changenotify_recv(req, tctx, &notify);
1204 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1205 "smb_raw_changenotify_recv");
1206 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1207 0, ret, done, "no changes expected");
1209 done:
1210 torture_close_connection(cli);
1211 smbcli_deltree(cli1->tree, BASEDIR_CN1_EX);
1212 return ret;
1216 basic testing of change notifies followed by a ulogoff
1219 #define BASEDIR_CN1_UL BASEDIR "_CN1_UL"
1221 static bool test_notify_ulogoff(struct torture_context *tctx,
1222 struct smbcli_state *cli1)
1224 bool ret = true;
1225 NTSTATUS status;
1226 union smb_notify notify;
1227 union smb_open io;
1228 int fnum;
1229 struct smbcli_request *req;
1230 struct smbcli_state *cli = NULL;
1232 torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1234 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_UL),
1235 "Failed to setup up test directory: " BASEDIR_CN1_UL);
1237 torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1238 "Failed to open connection.");
1241 get a handle on the directory
1243 io.generic.level = RAW_OPEN_NTCREATEX;
1244 io.ntcreatex.in.root_fid.fnum = 0;
1245 io.ntcreatex.in.flags = 0;
1246 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1247 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1248 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1249 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1250 io.ntcreatex.in.alloc_size = 0;
1251 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1252 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1253 io.ntcreatex.in.security_flags = 0;
1254 io.ntcreatex.in.fname = BASEDIR_CN1_UL;
1256 status = smb_raw_open(cli->tree, tctx, &io);
1257 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1258 "smb_raw_open");
1259 fnum = io.ntcreatex.out.file.fnum;
1261 /* ask for a change notify,
1262 on file or directory name changes */
1263 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1264 notify.nttrans.in.buffer_size = 1000;
1265 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1266 notify.nttrans.in.file.fnum = fnum;
1267 notify.nttrans.in.recursive = true;
1269 req = smb_raw_changenotify_send(cli->tree, &notify);
1271 status = smb_raw_ulogoff(cli->session);
1272 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1273 "smb_raw_ulogoff");
1275 status = smb_raw_changenotify_recv(req, tctx, &notify);
1276 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1277 "smb_raw_changenotify_recv");
1278 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1279 0, ret, done, "no changes expected");
1281 done:
1282 torture_close_connection(cli);
1283 smbcli_deltree(cli1->tree, BASEDIR_CN1_UL);
1284 return ret;
1287 static void tcp_dis_handler(struct smbcli_transport *t, void *p)
1289 struct smbcli_state *cli = (struct smbcli_state *)p;
1290 smbcli_transport_dead(cli->transport, NT_STATUS_LOCAL_DISCONNECT);
1291 cli->transport = NULL;
1292 cli->tree = NULL;
1295 basic testing of change notifies followed by tcp disconnect
1298 #define BASEDIR_CN1_TCPDIS BASEDIR "_CN1_TCPDIS"
1300 static bool test_notify_tcp_dis(struct torture_context *tctx,
1301 struct smbcli_state *cli1)
1303 bool ret = true;
1304 NTSTATUS status;
1305 union smb_notify notify;
1306 union smb_open io;
1307 int fnum;
1308 struct smbcli_request *req;
1309 struct smbcli_state *cli = NULL;
1311 torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1313 torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_TCPDIS),
1314 "Failed to setup up test directory: "
1315 BASEDIR_CN1_TCPDIS);
1317 torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1318 "Failed to open connection.");
1321 get a handle on the directory
1323 io.generic.level = RAW_OPEN_NTCREATEX;
1324 io.ntcreatex.in.root_fid.fnum = 0;
1325 io.ntcreatex.in.flags = 0;
1326 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1327 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1328 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1329 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1330 io.ntcreatex.in.alloc_size = 0;
1331 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1332 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1333 io.ntcreatex.in.security_flags = 0;
1334 io.ntcreatex.in.fname = BASEDIR_CN1_TCPDIS;
1336 status = smb_raw_open(cli->tree, tctx, &io);
1337 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1338 "smb_raw_open");
1339 fnum = io.ntcreatex.out.file.fnum;
1341 /* ask for a change notify,
1342 on file or directory name changes */
1343 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1344 notify.nttrans.in.buffer_size = 1000;
1345 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1346 notify.nttrans.in.file.fnum = fnum;
1347 notify.nttrans.in.recursive = true;
1349 req = smb_raw_changenotify_send(cli->tree, &notify);
1351 smbcli_transport_idle_handler(cli->transport, tcp_dis_handler, 250000, cli);
1353 status = smb_raw_changenotify_recv(req, tctx, &notify);
1354 torture_assert_ntstatus_equal_goto(tctx, status,
1355 NT_STATUS_LOCAL_DISCONNECT,
1356 ret, done,
1357 "smb_raw_changenotify_recv");
1359 done:
1360 torture_close_connection(cli);
1361 smbcli_deltree(cli1->tree, BASEDIR_CN1_TCPDIS);
1362 return ret;
1366 test setting up two change notify requests on one handle
1369 #define BASEDIR_CN1_DBL BASEDIR "_CN1_DBL"
1371 static bool test_notify_double(struct torture_context *tctx,
1372 struct smbcli_state *cli)
1374 bool ret = true;
1375 NTSTATUS status;
1376 union smb_notify notify;
1377 union smb_open io;
1378 int fnum;
1379 struct smbcli_request *req1, *req2;
1381 torture_comment(tctx, "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1383 torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_DBL),
1384 "Failed to setup up test directory: " BASEDIR_CN1_DBL);
1387 get a handle on the directory
1389 io.generic.level = RAW_OPEN_NTCREATEX;
1390 io.ntcreatex.in.root_fid.fnum = 0;
1391 io.ntcreatex.in.flags = 0;
1392 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1393 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1394 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1395 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1396 io.ntcreatex.in.alloc_size = 0;
1397 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1398 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1399 io.ntcreatex.in.security_flags = 0;
1400 io.ntcreatex.in.fname = BASEDIR_CN1_DBL;
1402 status = smb_raw_open(cli->tree, tctx, &io);
1403 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1404 "smb_raw_open");
1405 fnum = io.ntcreatex.out.file.fnum;
1407 /* ask for a change notify,
1408 on file or directory name changes */
1409 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1410 notify.nttrans.in.buffer_size = 1000;
1411 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1412 notify.nttrans.in.file.fnum = fnum;
1413 notify.nttrans.in.recursive = true;
1415 req1 = smb_raw_changenotify_send(cli->tree, &notify);
1416 req2 = smb_raw_changenotify_send(cli->tree, &notify);
1418 smbcli_mkdir(cli->tree, BASEDIR_CN1_DBL "\\subdir-name");
1420 status = smb_raw_changenotify_recv(req1, tctx, &notify);
1421 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1422 "smb_raw_changenotify_recv");
1423 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1424 1, ret, done, "wrong number of changes");
1425 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1426 STR_UNICODE);
1428 smbcli_mkdir(cli->tree, BASEDIR_CN1_DBL "\\subdir-name2");
1430 status = smb_raw_changenotify_recv(req2, tctx, &notify);
1431 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1432 "smb_raw_changenotify_recv");
1433 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1434 1, ret, done, "wrong number of changes");
1435 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name2",
1436 STR_UNICODE);
1438 done:
1439 smb_raw_exit(cli->session);
1440 smbcli_deltree(cli->tree, BASEDIR_CN1_DBL);
1441 return ret;
1446 test multiple change notifies at different depths and with/without recursion
1449 #define BASEDIR_CN1_TNT BASEDIR "_CN1_TNT"
1451 static bool test_notify_tree(struct torture_context *tctx,
1452 struct smbcli_state *cli,
1453 struct smbcli_state *cli2)
1455 bool ret = true;
1456 union smb_notify notify;
1457 union smb_open io;
1458 struct smbcli_request *req;
1459 struct timeval tv;
1460 struct {
1461 const char *path;
1462 bool recursive;
1463 uint32_t filter;
1464 int expected;
1465 int fnum;
1466 int counted;
1467 } dirs[] = {
1469 .path = BASEDIR_CN1_TNT "\\abc",
1470 .recursive = true,
1471 .filter = FILE_NOTIFY_CHANGE_NAME,
1472 .expected = 30,
1475 .path = BASEDIR_CN1_TNT "\\zqy",
1476 .recursive = true,
1477 .filter = FILE_NOTIFY_CHANGE_NAME,
1478 .expected = 8,
1481 .path = BASEDIR_CN1_TNT "\\atsy",
1482 .recursive = true,
1483 .filter = FILE_NOTIFY_CHANGE_NAME,
1484 .expected = 4,
1487 .path = BASEDIR_CN1_TNT "\\abc\\foo",
1488 .recursive = true,
1489 .filter = FILE_NOTIFY_CHANGE_NAME,
1490 .expected = 2,
1493 .path = BASEDIR_CN1_TNT "\\abc\\blah",
1494 .recursive = true,
1495 .filter = FILE_NOTIFY_CHANGE_NAME,
1496 .expected = 13,
1499 .path = BASEDIR_CN1_TNT "\\abc\\blah",
1500 .recursive = false,
1501 .filter = FILE_NOTIFY_CHANGE_NAME,
1502 .expected = 7,
1505 .path = BASEDIR_CN1_TNT "\\abc\\blah\\a",
1506 .recursive = true,
1507 .filter = FILE_NOTIFY_CHANGE_NAME,
1508 .expected = 2,
1511 .path = BASEDIR_CN1_TNT "\\abc\\blah\\b",
1512 .recursive = true,
1513 .filter = FILE_NOTIFY_CHANGE_NAME,
1514 .expected = 2,
1517 .path = BASEDIR_CN1_TNT "\\abc\\blah\\c",
1518 .recursive = true,
1519 .filter = FILE_NOTIFY_CHANGE_NAME,
1520 .expected = 2,
1523 .path = BASEDIR_CN1_TNT "\\abc\\fooblah",
1524 .recursive = true,
1525 .filter = FILE_NOTIFY_CHANGE_NAME,
1526 .expected = 2,
1529 .path = BASEDIR_CN1_TNT "\\zqy\\xx",
1530 .recursive = true,
1531 .filter = FILE_NOTIFY_CHANGE_NAME,
1532 .expected = 2,
1535 .path = BASEDIR_CN1_TNT "\\zqy\\yyy",
1536 .recursive = true,
1537 .filter = FILE_NOTIFY_CHANGE_NAME,
1538 .expected = 2,
1541 .path = BASEDIR_CN1_TNT "\\zqy\\..",
1542 .recursive = true,
1543 .filter = FILE_NOTIFY_CHANGE_NAME,
1544 .expected = 40,
1547 .path = BASEDIR_CN1_TNT,
1548 .recursive = true,
1549 .filter = FILE_NOTIFY_CHANGE_NAME,
1550 .expected = 40,
1553 .path = BASEDIR_CN1_TNT,
1554 .recursive = false,
1555 .filter = FILE_NOTIFY_CHANGE_NAME,
1556 .expected = 6,
1559 .path = BASEDIR_CN1_TNT "\\atsy",
1560 .recursive = false,
1561 .filter = FILE_NOTIFY_CHANGE_NAME,
1562 .expected = 4,
1565 .path = BASEDIR_CN1_TNT "\\abc",
1566 .recursive = true,
1567 .filter = FILE_NOTIFY_CHANGE_NAME,
1568 .expected = 24,
1571 .path = BASEDIR_CN1_TNT "\\abc",
1572 .recursive = false,
1573 .filter = FILE_NOTIFY_CHANGE_FILE_NAME,
1574 .expected = 0,
1577 .path = BASEDIR_CN1_TNT "\\abc",
1578 .recursive = true,
1579 .filter = FILE_NOTIFY_CHANGE_FILE_NAME,
1580 .expected = 0,
1583 .path = BASEDIR_CN1_TNT "\\abc",
1584 .recursive = true,
1585 .filter = FILE_NOTIFY_CHANGE_NAME,
1586 .expected = 24,
1589 int i;
1590 NTSTATUS status;
1591 bool all_done = false;
1593 torture_comment(tctx, "TESTING CHANGE NOTIFY FOR DIFFERENT DEPTHS\n");
1595 torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_TNT),
1596 "Failed to setup up test directory: " BASEDIR_CN1_TNT);
1598 io.generic.level = RAW_OPEN_NTCREATEX;
1599 io.ntcreatex.in.root_fid.fnum = 0;
1600 io.ntcreatex.in.flags = 0;
1601 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1602 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1603 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1604 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1605 io.ntcreatex.in.alloc_size = 0;
1606 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1607 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1608 io.ntcreatex.in.security_flags = 0;
1610 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1611 notify.nttrans.in.buffer_size = 20000;
1614 setup the directory tree, and the notify buffer on each directory
1616 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1617 io.ntcreatex.in.fname = dirs[i].path;
1618 status = smb_raw_open(cli->tree, tctx, &io);
1619 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1620 "smb_raw_open");
1621 dirs[i].fnum = io.ntcreatex.out.file.fnum;
1623 notify.nttrans.in.completion_filter = dirs[i].filter;
1624 notify.nttrans.in.file.fnum = dirs[i].fnum;
1625 notify.nttrans.in.recursive = dirs[i].recursive;
1626 req = smb_raw_changenotify_send(cli->tree, &notify);
1627 smb_raw_ntcancel(req);
1628 status = smb_raw_changenotify_recv(req, tctx, &notify);
1629 torture_assert_ntstatus_equal_goto(tctx, status,
1630 NT_STATUS_CANCELLED,
1631 ret, done,
1632 "smb_raw_changenotify_recv");
1635 /* trigger 2 events in each dir */
1636 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1637 char *path = talloc_asprintf(tctx, "%s\\test.dir", dirs[i].path);
1639 * Make notifies a bit more interesting in a cluster
1640 * by doing the changes against different nodes with
1641 * --unclist
1643 smbcli_mkdir(cli->tree, path);
1644 smbcli_rmdir(cli2->tree, path);
1645 talloc_free(path);
1648 /* give a bit of time for the events to propagate */
1649 tv = timeval_current();
1651 do {
1652 /* count events that have happened in each dir */
1653 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1654 notify.nttrans.in.file.fnum = dirs[i].fnum;
1655 req = smb_raw_changenotify_send(cli->tree, &notify);
1656 smb_raw_ntcancel(req);
1657 notify.nttrans.out.num_changes = 0;
1658 status = smb_raw_changenotify_recv(req, tctx, &notify);
1659 dirs[i].counted += notify.nttrans.out.num_changes;
1662 all_done = true;
1664 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1665 if (dirs[i].counted != dirs[i].expected) {
1666 all_done = false;
1669 } while (!all_done && timeval_elapsed(&tv) < 20);
1671 torture_comment(tctx, "took %.4f seconds to propagate all events\n", timeval_elapsed(&tv));
1673 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1674 torture_assert_int_equal_goto(tctx,
1675 dirs[i].counted, dirs[i].expected, ret, done,
1676 talloc_asprintf(tctx,
1677 "unexpected number of events for '%s'",
1678 dirs[i].path));
1682 run from the back, closing and deleting
1684 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1685 smbcli_close(cli->tree, dirs[i].fnum);
1686 smbcli_rmdir(cli->tree, dirs[i].path);
1689 done:
1690 smb_raw_exit(cli->session);
1691 smbcli_deltree(cli->tree, BASEDIR_CN1_TNT);
1692 return ret;
1696 Test response when cached server events exceed single NT NOTFIY response
1697 packet size.
1700 #define BASEDIR_CN1_NO BASEDIR "_CN1_NO"
1702 static bool test_notify_overflow(struct torture_context *tctx,
1703 struct smbcli_state *cli)
1705 bool ret = true;
1706 NTSTATUS status;
1707 union smb_notify notify;
1708 union smb_open io;
1709 int fnum;
1710 int count = 100;
1711 struct smbcli_request *req1;
1712 int i;
1714 torture_comment(tctx, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1716 torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NO),
1717 "Failed to setup up test directory: " BASEDIR_CN1_NO);
1719 /* get a handle on the directory */
1720 io.generic.level = RAW_OPEN_NTCREATEX;
1721 io.ntcreatex.in.root_fid.fnum = 0;
1722 io.ntcreatex.in.flags = 0;
1723 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1724 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1725 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1726 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1727 NTCREATEX_SHARE_ACCESS_WRITE;
1728 io.ntcreatex.in.alloc_size = 0;
1729 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1730 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1731 io.ntcreatex.in.security_flags = 0;
1732 io.ntcreatex.in.fname = BASEDIR_CN1_NO;
1734 status = smb_raw_open(cli->tree, tctx, &io);
1735 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1736 "smb_raw_open");
1737 fnum = io.ntcreatex.out.file.fnum;
1739 /* ask for a change notify, on name changes. */
1740 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1741 notify.nttrans.in.buffer_size = 1000;
1742 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1743 notify.nttrans.in.file.fnum = fnum;
1745 notify.nttrans.in.recursive = true;
1746 req1 = smb_raw_changenotify_send(cli->tree, &notify);
1748 /* cancel initial requests so the buffer is setup */
1749 smb_raw_ntcancel(req1);
1750 status = smb_raw_changenotify_recv(req1, tctx, &notify);
1751 torture_assert_ntstatus_equal_goto(tctx, status,
1752 NT_STATUS_CANCELLED,
1753 ret, done,
1754 "smb_raw_changenotify_recv");
1756 /* open a lot of files, filling up the server side notify buffer */
1757 torture_comment(tctx, "Testing overflowed buffer notify on create of %d files\n",
1758 count);
1759 for (i=0;i<count;i++) {
1760 char *fname = talloc_asprintf(cli,
1761 BASEDIR_CN1_NO "\\test%d.txt", i);
1762 int fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR,
1763 DENY_NONE);
1764 torture_assert_int_not_equal_goto(tctx, fnum2, -1, ret, done,
1765 talloc_asprintf(tctx, "Failed to create %s - %s",
1766 fname, smbcli_errstr(cli->tree)));
1767 talloc_free(fname);
1768 smbcli_close(cli->tree, fnum2);
1771 /* expect that 0 events will be returned with NT_STATUS_OK */
1772 req1 = smb_raw_changenotify_send(cli->tree, &notify);
1773 status = smb_raw_changenotify_recv(req1, tctx, &notify);
1774 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1775 "smb_raw_changenotify_recv");
1776 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1777 0, ret, done, "no changes expected");
1779 done:
1780 smb_raw_exit(cli->session);
1781 smbcli_deltree(cli->tree, BASEDIR_CN1_NO);
1782 return ret;
1786 Test if notifications are returned for changes to the base directory.
1787 They shouldn't be.
1790 #define BASEDIR_CN1_NBASE BASEDIR "_CN1_NBASE"
1792 static bool test_notify_basedir(struct torture_context *tctx,
1793 struct smbcli_state *cli)
1795 bool ret = true;
1796 NTSTATUS status;
1797 union smb_notify notify;
1798 union smb_open io;
1799 int fnum;
1800 struct smbcli_request *req1;
1802 torture_comment(tctx, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1804 torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NBASE),
1805 "Failed to setup up test directory: " BASEDIR_CN1_NBASE);
1807 /* get a handle on the directory */
1808 io.generic.level = RAW_OPEN_NTCREATEX;
1809 io.ntcreatex.in.root_fid.fnum = 0;
1810 io.ntcreatex.in.flags = 0;
1811 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1812 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1813 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1814 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1815 NTCREATEX_SHARE_ACCESS_WRITE;
1816 io.ntcreatex.in.alloc_size = 0;
1817 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1818 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1819 io.ntcreatex.in.security_flags = 0;
1820 io.ntcreatex.in.fname = BASEDIR_CN1_NBASE;
1822 status = smb_raw_open(cli->tree, tctx, &io);
1823 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1824 "smb_raw_open");
1825 fnum = io.ntcreatex.out.file.fnum;
1827 /* create a test file that will also be modified */
1828 smbcli_close(cli->tree, smbcli_open(cli->tree,
1829 BASEDIR_CN1_NBASE "\\tname1",
1830 O_CREAT, 0));
1832 /* ask for a change notify, on attribute changes. */
1833 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1834 notify.nttrans.in.buffer_size = 1000;
1835 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
1836 notify.nttrans.in.file.fnum = fnum;
1837 notify.nttrans.in.recursive = true;
1839 req1 = smb_raw_changenotify_send(cli->tree, &notify);
1841 /* set attribute on the base dir */
1842 smbcli_setatr(cli->tree, BASEDIR_CN1_NBASE, FILE_ATTRIBUTE_HIDDEN, 0);
1844 /* set attribute on a file to assure we receive a notification */
1845 smbcli_setatr(cli->tree, BASEDIR_CN1_NBASE "\\tname1",
1846 FILE_ATTRIBUTE_HIDDEN, 0);
1847 smb_msleep(200);
1849 /* check how many responses were given, expect only 1 for the file */
1850 status = smb_raw_changenotify_recv(req1, tctx, &notify);
1851 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1852 "smb_raw_changenotify_recv");
1853 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1854 1, ret, done, "wrong number of changes");
1855 torture_assert_int_equal_goto(tctx,
1856 notify.nttrans.out.changes[0].action,
1857 NOTIFY_ACTION_MODIFIED, ret, done,
1858 "wrong action (exp: MODIFIED)");
1859 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "tname1",
1860 STR_UNICODE);
1862 done:
1863 smb_raw_exit(cli->session);
1864 smbcli_deltree(cli->tree, BASEDIR_CN1_NBASE);
1865 return ret;
1870 create a secondary tree connect - used to test for a bug in Samba3 messaging
1871 with change notify
1874 static struct smbcli_tree *secondary_tcon(struct smbcli_state *cli,
1875 struct torture_context *tctx)
1877 NTSTATUS status;
1878 const char *share, *host;
1879 struct smbcli_tree *tree;
1880 union smb_tcon tcon;
1882 share = torture_setting_string(tctx, "share", NULL);
1883 host = torture_setting_string(tctx, "host", NULL);
1885 torture_comment(tctx, "create a second tree context on the same session\n");
1886 tree = smbcli_tree_init(cli->session, tctx, false);
1888 tcon.generic.level = RAW_TCON_TCONX;
1889 tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
1890 tcon.tconx.in.password = data_blob(NULL, 0);
1891 tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
1892 tcon.tconx.in.device = "A:";
1893 status = smb_raw_tcon(tree, tctx, &tcon);
1894 if (!NT_STATUS_IS_OK(status)) {
1895 talloc_free(tree);
1896 torture_comment(tctx, "Failed to create secondary tree\n");
1897 return NULL;
1900 tree->tid = tcon.tconx.out.tid;
1901 torture_comment(tctx, "tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
1903 return tree;
1908 very simple change notify test
1911 #define BASEDIR_CN1_NTCON BASEDIR "_CN1_NTCON"
1913 static bool test_notify_tcon(struct torture_context *tctx,
1914 struct smbcli_state *cli)
1916 bool ret = true;
1917 NTSTATUS status;
1918 union smb_notify notify;
1919 union smb_open io;
1920 int fnum;
1921 struct smbcli_request *req;
1922 extern int torture_numops;
1923 struct smbcli_tree *tree = NULL;
1925 torture_comment(tctx, "TESTING SIMPLE CHANGE NOTIFY\n");
1927 torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NTCON),
1928 "Failed to setup up test directory: " BASEDIR_CN1_NTCON);
1931 get a handle on the directory
1933 io.generic.level = RAW_OPEN_NTCREATEX;
1934 io.ntcreatex.in.root_fid.fnum = 0;
1935 io.ntcreatex.in.flags = 0;
1936 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1937 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1938 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1939 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1940 io.ntcreatex.in.alloc_size = 0;
1941 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1942 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1943 io.ntcreatex.in.security_flags = 0;
1944 io.ntcreatex.in.fname = BASEDIR_CN1_NTCON;
1946 status = smb_raw_open(cli->tree, tctx, &io);
1947 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1948 "smb_raw_open");
1949 fnum = io.ntcreatex.out.file.fnum;
1951 status = smb_raw_open(cli->tree, tctx, &io);
1952 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1953 "smb_raw_open");
1955 /* ask for a change notify,
1956 on file or directory name changes */
1957 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1958 notify.nttrans.in.buffer_size = 1000;
1959 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1960 notify.nttrans.in.file.fnum = fnum;
1961 notify.nttrans.in.recursive = true;
1963 torture_comment(tctx, "Testing notify mkdir\n");
1964 req = smb_raw_changenotify_send(cli->tree, &notify);
1965 smbcli_mkdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
1967 status = smb_raw_changenotify_recv(req, tctx, &notify);
1968 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1969 "smb_raw_changenotify_recv");
1971 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1972 1, ret, done, "wrong number of changes");
1973 torture_assert_int_equal_goto(tctx,
1974 notify.nttrans.out.changes[0].action,
1975 NOTIFY_ACTION_ADDED, ret, done,
1976 "wrong action (exp: ADDED)");
1977 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1978 STR_UNICODE);
1980 torture_comment(tctx, "Testing notify rmdir\n");
1981 req = smb_raw_changenotify_send(cli->tree, &notify);
1982 smbcli_rmdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
1984 status = smb_raw_changenotify_recv(req, tctx, &notify);
1985 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1986 "smb_raw_changenotify_recv");
1987 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1988 1, ret, done, "wrong number of changes");
1989 torture_assert_int_equal_goto(tctx,
1990 notify.nttrans.out.changes[0].action,
1991 NOTIFY_ACTION_REMOVED, ret, done,
1992 "wrong action (exp: REMOVED)");
1993 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1994 STR_UNICODE);
1996 torture_comment(tctx, "SIMPLE CHANGE NOTIFY OK\n");
1998 torture_comment(tctx, "TESTING WITH SECONDARY TCON\n");
1999 tree = secondary_tcon(cli, tctx);
2000 torture_assert_not_null_goto(tctx, tree, ret, done,
2001 "failed to create secondary tcon");
2003 torture_comment(tctx, "Testing notify mkdir\n");
2004 req = smb_raw_changenotify_send(cli->tree, &notify);
2005 smbcli_mkdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
2007 status = smb_raw_changenotify_recv(req, tctx, &notify);
2008 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2009 "smb_raw_changenotify_recv");
2011 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
2012 1, ret, done, "wrong number of changes");
2013 torture_assert_int_equal_goto(tctx,
2014 notify.nttrans.out.changes[0].action,
2015 NOTIFY_ACTION_ADDED, ret, done,
2016 "wrong action (exp: ADDED)");
2017 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
2018 STR_UNICODE);
2020 torture_comment(tctx, "Testing notify rmdir\n");
2021 req = smb_raw_changenotify_send(cli->tree, &notify);
2022 smbcli_rmdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
2024 status = smb_raw_changenotify_recv(req, tctx, &notify);
2025 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2026 "smb_raw_changenotify_recv");
2027 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
2028 1, ret, done, "wrong number of changes");
2029 torture_assert_int_equal_goto(tctx,
2030 notify.nttrans.out.changes[0].action,
2031 NOTIFY_ACTION_REMOVED, ret, done,
2032 "wrong action (exp: REMOVED)");
2033 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
2034 STR_UNICODE);
2036 torture_comment(tctx, "CHANGE NOTIFY WITH TCON OK\n");
2038 torture_comment(tctx, "Disconnecting secondary tree\n");
2039 status = smb_tree_disconnect(tree);
2040 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2041 "smb_tree_disconnect");
2042 talloc_free(tree);
2044 torture_comment(tctx, "Testing notify mkdir\n");
2045 req = smb_raw_changenotify_send(cli->tree, &notify);
2046 smbcli_mkdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
2048 status = smb_raw_changenotify_recv(req, tctx, &notify);
2049 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2050 "smb_raw_changenotify_recv");
2052 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
2053 1, ret, done, "wrong number of changes");
2054 torture_assert_int_equal_goto(tctx,
2055 notify.nttrans.out.changes[0].action,
2056 NOTIFY_ACTION_ADDED, ret, done,
2057 "wrong action (exp: ADDED)");
2058 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
2059 STR_UNICODE);
2061 torture_comment(tctx, "Testing notify rmdir\n");
2062 req = smb_raw_changenotify_send(cli->tree, &notify);
2063 smbcli_rmdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
2065 status = smb_raw_changenotify_recv(req, tctx, &notify);
2066 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
2067 "smb_raw_changenotify_recv");
2068 torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
2069 1, ret, done, "wrong number of changes");
2070 torture_assert_int_equal_goto(tctx,
2071 notify.nttrans.out.changes[0].action,
2072 NOTIFY_ACTION_REMOVED, ret, done,
2073 "wrong action (exp: REMOVED)");
2074 CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
2075 STR_UNICODE);
2077 torture_comment(tctx, "CHANGE NOTIFY WITH TDIS OK\n");
2078 done:
2079 smb_raw_exit(cli->session);
2080 smbcli_deltree(cli->tree, BASEDIR_CN1_NTCON);
2081 return ret;
2084 struct cb_data {
2085 struct smbcli_request *req;
2086 bool timed_out;
2089 static void timeout_cb(struct tevent_context *ev,
2090 struct tevent_timer *te,
2091 struct timeval current_time,
2092 void *private_data)
2094 struct cb_data *cbp = (struct cb_data *)private_data;
2095 cbp->req->state = SMBCLI_REQUEST_ERROR;
2096 cbp->timed_out = true;
2100 testing alignment of multiple change notify infos
2103 #define BASEDIR_CN1_NALIGN BASEDIR "_CN1_NALIGN"
2105 static bool test_notify_alignment(struct torture_context *tctx,
2106 struct smbcli_state *cli)
2108 NTSTATUS status;
2109 union smb_notify notify;
2110 union smb_open io;
2111 int fnum, fnum2;
2112 struct smbcli_request *req;
2113 const char *fname = BASEDIR_CN1_NALIGN "\\starter";
2114 const char *fnames[] = { "a",
2115 "ab",
2116 "abc",
2117 "abcd" };
2118 bool fnames_received[] = {false,
2119 false,
2120 false,
2121 false};
2122 size_t total_names_received = 0;
2123 size_t num_names = ARRAY_SIZE(fnames);
2124 size_t i;
2125 char *fpath = NULL;
2127 torture_comment(tctx, "TESTING CHANGE NOTIFY REPLY ALIGNMENT\n");
2129 torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NALIGN),
2130 "Failed to setup up test directory: " BASEDIR_CN1_NALIGN);
2132 /* get a handle on the directory */
2133 io.generic.level = RAW_OPEN_NTCREATEX;
2134 io.ntcreatex.in.root_fid.fnum = 0;
2135 io.ntcreatex.in.flags = 0;
2136 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
2137 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2138 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
2139 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2140 NTCREATEX_SHARE_ACCESS_WRITE;
2141 io.ntcreatex.in.alloc_size = 0;
2142 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
2143 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
2144 io.ntcreatex.in.security_flags = 0;
2145 io.ntcreatex.in.fname = BASEDIR_CN1_NALIGN;
2147 status = smb_raw_open(cli->tree, tctx, &io);
2148 torture_assert_ntstatus_ok(tctx, status, "smb_raw_open");
2149 fnum = io.ntcreatex.out.file.fnum;
2151 /* ask for a change notify, on file creation */
2152 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
2153 notify.nttrans.in.buffer_size = 1000;
2154 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_FILE_NAME;
2155 notify.nttrans.in.file.fnum = fnum;
2156 notify.nttrans.in.recursive = false;
2158 /* start change tracking */
2159 req = smb_raw_changenotify_send(cli->tree, &notify);
2161 fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
2162 torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
2163 smbcli_close(cli->tree, fnum2);
2165 status = smb_raw_changenotify_recv(req, tctx, &notify);
2166 torture_assert_ntstatus_ok(tctx, status, "smb_raw_changenotify_recv");
2168 /* create 4 files that will cause CHANGE_NOTIFY_INFO structures
2169 * to be returned in the same packet with all possible 4-byte padding
2170 * permutations. As per MS-CIFS 2.2.7.4.2 these structures should be
2171 * 4-byte aligned. */
2173 for (i = 0; i < num_names; i++) {
2174 fpath = talloc_asprintf(tctx, "%s\\%s",
2175 BASEDIR_CN1_NALIGN, fnames[i]);
2176 fnum2 = smbcli_open(cli->tree, fpath,
2177 O_CREAT|O_RDWR, DENY_NONE);
2178 torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
2179 smbcli_close(cli->tree, fnum2);
2180 talloc_free(fpath);
2184 * Slow cloud filesystems mean we might
2185 * not get everything in one go. Keep going
2186 * until we get them all.
2188 while (total_names_received < num_names) {
2189 struct tevent_timer *te = NULL;
2190 struct cb_data to_data = {0};
2193 * We send a notify packet, and let
2194 * smb_raw_changenotify_recv() do
2195 * the alignment checking for us.
2197 req = smb_raw_changenotify_send(cli->tree, &notify);
2198 torture_assert(tctx,
2199 req != NULL,
2200 "smb_raw_changenotify_send failed\n");
2202 /* Ensure we don't wait more than 30 seconds. */
2203 to_data.req = req;
2204 to_data.timed_out = false;
2206 te = tevent_add_timer(tctx->ev,
2207 req,
2208 tevent_timeval_current_ofs(30, 0),
2209 timeout_cb,
2210 &to_data);
2211 if (te == NULL) {
2212 torture_fail(tctx, "tevent_add_timer fail\n");
2215 status = smb_raw_changenotify_recv(req, tctx, &notify);
2216 if (!NT_STATUS_IS_OK(status)) {
2217 if (to_data.timed_out == true) {
2218 torture_fail(tctx, "smb_raw_changenotify_recv "
2219 "timed out\n");
2223 torture_assert_ntstatus_ok(tctx, status,
2224 "smb_raw_changenotify_recv");
2226 for (i = 0; i < notify.nttrans.out.num_changes; i++) {
2227 size_t j;
2229 /* Ensure it was an 'add'. */
2230 torture_assert(tctx,
2231 notify.nttrans.out.changes[i].action ==
2232 NOTIFY_ACTION_ADDED,
2233 "");
2235 for (j = 0; j < num_names; j++) {
2236 if (strcmp(notify.nttrans.out.changes[i].name.s,
2237 fnames[j]) == 0) {
2238 if (fnames_received[j] == true) {
2239 const char *err =
2240 talloc_asprintf(tctx,
2241 "Duplicate "
2242 "name %s\n",
2243 fnames[j]);
2244 if (err == NULL) {
2245 torture_fail(tctx,
2246 "talloc "
2247 "fail\n");
2249 /* already got this. */
2250 torture_fail(tctx, err);
2252 fnames_received[j] = true;
2253 break;
2256 if (j == num_names) {
2257 /* No name match. */
2258 const char *err = talloc_asprintf(tctx,
2259 "Unexpected name %s\n",
2260 notify.nttrans.out.changes[i].name.s);
2261 if (err == NULL) {
2262 torture_fail(tctx, "talloc fail\n");
2264 torture_fail(tctx, err);
2266 total_names_received++;
2270 smb_raw_exit(cli->session);
2271 smbcli_deltree(cli->tree, BASEDIR_CN1_NALIGN);
2272 return true;
2275 struct torture_suite *torture_raw_notify(TALLOC_CTX *mem_ctx)
2277 struct torture_suite *suite = torture_suite_create(mem_ctx, "notify");
2279 torture_suite_add_1smb_test(suite, "tcon", test_notify_tcon);
2280 torture_suite_add_2smb_test(suite, "dir", test_notify_dir);
2281 torture_suite_add_2smb_test(suite, "mask", test_notify_mask);
2282 torture_suite_add_2smb_test(suite, "recursive", test_notify_recursive);
2283 torture_suite_add_1smb_test(suite, "mask_change",
2284 test_notify_mask_change);
2285 torture_suite_add_1smb_test(suite, "file", test_notify_file);
2286 torture_suite_add_1smb_test(suite, "tdis", test_notify_tdis);
2287 torture_suite_add_1smb_test(suite, "exit", test_notify_exit);
2288 torture_suite_add_1smb_test(suite, "ulogoff", test_notify_ulogoff);
2289 torture_suite_add_1smb_test(suite, "tcp_dis", test_notify_tcp_dis);
2290 torture_suite_add_1smb_test(suite, "double", test_notify_double);
2291 torture_suite_add_2smb_test(suite, "tree", test_notify_tree);
2292 torture_suite_add_1smb_test(suite, "overflow", test_notify_overflow);
2293 torture_suite_add_1smb_test(suite, "basedir", test_notify_basedir);
2294 torture_suite_add_1smb_test(suite, "alignment", test_notify_alignment);
2296 return suite;