2 Unix SMB/CIFS implementation.
3 basic raw test suite for change notify
4 Copyright (C) Andrew Tridgell 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "torture/torture.h"
22 #include "libcli/raw/libcliraw.h"
23 #include "libcli/raw/raw_proto.h"
24 #include "libcli/libcli.h"
25 #include "system/filesys.h"
26 #include "torture/util.h"
27 #include "param/param.h"
29 #define BASEDIR "\\test_notify"
31 #define CHECK_STATUS(status, correct) do { \
32 if (!NT_STATUS_EQUAL(status, correct)) { \
33 printf("(%d) Incorrect status %s - should be %s\n", \
34 __LINE__, nt_errstr(status), nt_errstr(correct)); \
40 #define CHECK_VAL(v, correct) do { \
41 if ((v) != (correct)) { \
42 printf("(%d) wrong value for %s 0x%x should be 0x%x\n", \
43 __LINE__, #v, (int)v, (int)correct); \
48 #define CHECK_WSTR(field, value, flags) do { \
49 if (!field.s || strcmp(field.s, value) || wire_bad_flags(&field, flags, cli->transport)) { \
50 printf("(%d) %s [%s] != %s\n", __LINE__, #field, field.s, value); \
57 basic testing of change notify on directories
59 static bool test_notify_dir(struct smbcli_state *cli, struct smbcli_state *cli2,
64 union smb_notify notify;
67 int i, count, fnum, fnum2;
68 struct smbcli_request *req, *req2;
69 extern int torture_numops;
71 printf("TESTING CHANGE NOTIFY ON DIRECTRIES\n");
74 get a handle on the directory
76 io.generic.level = RAW_OPEN_NTCREATEX;
77 io.ntcreatex.in.root_fid = 0;
78 io.ntcreatex.in.flags = 0;
79 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
80 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
81 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
82 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
83 io.ntcreatex.in.alloc_size = 0;
84 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
85 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
86 io.ntcreatex.in.security_flags = 0;
87 io.ntcreatex.in.fname = BASEDIR;
89 status = smb_raw_open(cli->tree, mem_ctx, &io);
90 CHECK_STATUS(status, NT_STATUS_OK);
91 fnum = io.ntcreatex.out.file.fnum;
93 status = smb_raw_open(cli->tree, mem_ctx, &io);
94 CHECK_STATUS(status, NT_STATUS_OK);
95 fnum2 = io.ntcreatex.out.file.fnum;
97 /* ask for a change notify,
98 on file or directory name changes */
99 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
100 notify.nttrans.in.buffer_size = 1000;
101 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
102 notify.nttrans.in.file.fnum = fnum;
103 notify.nttrans.in.recursive = true;
105 printf("testing notify cancel\n");
107 req = smb_raw_changenotify_send(cli->tree, ¬ify);
108 smb_raw_ntcancel(req);
109 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
110 CHECK_STATUS(status, NT_STATUS_CANCELLED);
112 printf("testing notify mkdir\n");
114 req = smb_raw_changenotify_send(cli->tree, ¬ify);
115 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name");
117 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
118 CHECK_STATUS(status, NT_STATUS_OK);
120 CHECK_VAL(notify.nttrans.out.num_changes, 1);
121 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_ADDED);
122 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
124 printf("testing notify rmdir\n");
126 req = smb_raw_changenotify_send(cli->tree, ¬ify);
127 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
129 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
130 CHECK_STATUS(status, NT_STATUS_OK);
131 CHECK_VAL(notify.nttrans.out.num_changes, 1);
132 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_REMOVED);
133 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
135 printf("testing notify mkdir - rmdir - mkdir - rmdir\n");
137 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name");
138 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
139 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name");
140 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
142 req = smb_raw_changenotify_send(cli->tree, ¬ify);
143 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
144 CHECK_STATUS(status, NT_STATUS_OK);
145 CHECK_VAL(notify.nttrans.out.num_changes, 4);
146 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_ADDED);
147 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
148 CHECK_VAL(notify.nttrans.out.changes[1].action, NOTIFY_ACTION_REMOVED);
149 CHECK_WSTR(notify.nttrans.out.changes[1].name, "subdir-name", STR_UNICODE);
150 CHECK_VAL(notify.nttrans.out.changes[2].action, NOTIFY_ACTION_ADDED);
151 CHECK_WSTR(notify.nttrans.out.changes[2].name, "subdir-name", STR_UNICODE);
152 CHECK_VAL(notify.nttrans.out.changes[3].action, NOTIFY_ACTION_REMOVED);
153 CHECK_WSTR(notify.nttrans.out.changes[3].name, "subdir-name", STR_UNICODE);
155 count = torture_numops;
156 printf("testing buffered notify on create of %d files\n", count);
157 for (i=0;i<count;i++) {
158 char *fname = talloc_asprintf(cli, BASEDIR "\\test%d.txt", i);
159 int fnum3 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
161 printf("Failed to create %s - %s\n",
162 fname, smbcli_errstr(cli->tree));
167 smbcli_close(cli->tree, fnum3);
170 /* (1st notify) setup a new notify on a different directory handle.
171 This new notify won't see the events above. */
172 notify.nttrans.in.file.fnum = fnum2;
173 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
175 /* (2nd notify) whereas this notify will see the above buffered events,
176 and it directly returns the buffered events */
177 notify.nttrans.in.file.fnum = fnum;
178 req = smb_raw_changenotify_send(cli->tree, ¬ify);
180 status = smbcli_unlink(cli->tree, BASEDIR "\\nonexistant.txt");
181 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
183 /* (1st unlink) as the 2nd notify directly returns,
184 this unlink is only seen by the 1st notify and
185 the 3rd notify (later) */
186 printf("testing notify on unlink for the first file\n");
187 status = smbcli_unlink(cli2->tree, BASEDIR "\\test0.txt");
188 CHECK_STATUS(status, NT_STATUS_OK);
190 /* receive the reply from the 2nd notify */
191 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
192 CHECK_STATUS(status, NT_STATUS_OK);
194 CHECK_VAL(notify.nttrans.out.num_changes, count);
195 for (i=1;i<count;i++) {
196 CHECK_VAL(notify.nttrans.out.changes[i].action, NOTIFY_ACTION_ADDED);
198 CHECK_WSTR(notify.nttrans.out.changes[0].name, "test0.txt", STR_UNICODE);
200 printf("and now from the 1st notify\n");
201 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
202 CHECK_STATUS(status, NT_STATUS_OK);
203 CHECK_VAL(notify.nttrans.out.num_changes, 1);
204 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_REMOVED);
205 CHECK_WSTR(notify.nttrans.out.changes[0].name, "test0.txt", STR_UNICODE);
207 printf("(3rd notify) this notify will only see the 1st unlink\n");
208 req = smb_raw_changenotify_send(cli->tree, ¬ify);
210 status = smbcli_unlink(cli->tree, BASEDIR "\\nonexistant.txt");
211 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
213 printf("testing notify on wildcard unlink for %d files\n", count-1);
214 /* (2nd unlink) do a wildcard unlink */
215 status = smbcli_unlink(cli2->tree, BASEDIR "\\test*.txt");
216 CHECK_STATUS(status, NT_STATUS_OK);
218 /* receive the 3rd notify */
219 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
220 CHECK_STATUS(status, NT_STATUS_OK);
221 CHECK_VAL(notify.nttrans.out.num_changes, 1);
222 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_REMOVED);
223 CHECK_WSTR(notify.nttrans.out.changes[0].name, "test0.txt", STR_UNICODE);
225 /* and we now see the rest of the unlink calls on both directory handles */
226 notify.nttrans.in.file.fnum = fnum;
228 req = smb_raw_changenotify_send(cli->tree, ¬ify);
229 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
230 CHECK_STATUS(status, NT_STATUS_OK);
231 CHECK_VAL(notify.nttrans.out.num_changes, count-1);
232 for (i=0;i<notify.nttrans.out.num_changes;i++) {
233 CHECK_VAL(notify.nttrans.out.changes[i].action, NOTIFY_ACTION_REMOVED);
235 notify.nttrans.in.file.fnum = fnum2;
236 req = smb_raw_changenotify_send(cli->tree, ¬ify);
237 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
238 CHECK_STATUS(status, NT_STATUS_OK);
239 CHECK_VAL(notify.nttrans.out.num_changes, count-1);
240 for (i=0;i<notify.nttrans.out.num_changes;i++) {
241 CHECK_VAL(notify.nttrans.out.changes[i].action, NOTIFY_ACTION_REMOVED);
244 printf("testing if a close() on the dir handle triggers the notify reply\n");
246 notify.nttrans.in.file.fnum = fnum;
247 req = smb_raw_changenotify_send(cli->tree, ¬ify);
249 cl.close.level = RAW_CLOSE_CLOSE;
250 cl.close.in.file.fnum = fnum;
251 cl.close.in.write_time = 0;
252 status = smb_raw_close(cli->tree, &cl);
253 CHECK_STATUS(status, NT_STATUS_OK);
255 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
256 CHECK_STATUS(status, NT_STATUS_OK);
257 CHECK_VAL(notify.nttrans.out.num_changes, 0);
260 smb_raw_exit(cli->session);
265 * Check notify reply for a rename action. Not sure if this is a valid thing
266 * to do, but depending on timing between inotify and messaging we get the
267 * add/remove/modify in any order. This routines tries to find the action/name
268 * pair in any of the three following notify_changes.
271 static bool check_rename_reply(struct smbcli_state *cli,
273 struct notify_changes *actions,
274 uint32_t action, const char *name)
278 for (i=0; i<3; i++) {
279 if (actions[i].action == action) {
280 if ((actions[i].name.s == NULL)
281 || (strcmp(actions[i].name.s, name) != 0)
282 || (wire_bad_flags(&actions[i].name, STR_UNICODE,
284 printf("(%d) name [%s] != %s\n", line,
285 actions[i].name.s, name);
292 printf("(%d) expected action %d, not found\n", line, action);
297 testing of recursive change notify
299 static bool test_notify_recursive(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
303 union smb_notify notify;
306 struct smbcli_request *req1, *req2;
308 printf("TESTING CHANGE NOTIFY WITH RECURSION\n");
311 get a handle on the directory
313 io.generic.level = RAW_OPEN_NTCREATEX;
314 io.ntcreatex.in.root_fid = 0;
315 io.ntcreatex.in.flags = 0;
316 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
317 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
318 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
319 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
320 io.ntcreatex.in.alloc_size = 0;
321 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
322 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
323 io.ntcreatex.in.security_flags = 0;
324 io.ntcreatex.in.fname = BASEDIR;
326 status = smb_raw_open(cli->tree, mem_ctx, &io);
327 CHECK_STATUS(status, NT_STATUS_OK);
328 fnum = io.ntcreatex.out.file.fnum;
330 /* ask for a change notify, on file or directory name
331 changes. Setup both with and without recursion */
332 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
333 notify.nttrans.in.buffer_size = 1000;
334 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
335 notify.nttrans.in.file.fnum = fnum;
337 notify.nttrans.in.recursive = true;
338 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
340 notify.nttrans.in.recursive = false;
341 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
343 /* cancel initial requests so the buffer is setup */
344 smb_raw_ntcancel(req1);
345 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
346 CHECK_STATUS(status, NT_STATUS_CANCELLED);
348 smb_raw_ntcancel(req2);
349 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
350 CHECK_STATUS(status, NT_STATUS_CANCELLED);
352 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
353 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name\\subname1");
354 smbcli_close(cli->tree,
355 smbcli_open(cli->tree, BASEDIR "\\subdir-name\\subname2", O_CREAT, 0));
356 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname1", BASEDIR "\\subdir-name\\subname1-r");
357 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname2", BASEDIR "\\subname2-r");
358 smbcli_rename(cli->tree, BASEDIR "\\subname2-r", BASEDIR "\\subname3-r");
360 notify.nttrans.in.completion_filter = 0;
361 notify.nttrans.in.recursive = true;
363 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
365 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name\\subname1-r");
366 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
367 smbcli_unlink(cli->tree, BASEDIR "\\subname3-r");
369 notify.nttrans.in.recursive = false;
370 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
372 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
373 CHECK_STATUS(status, NT_STATUS_OK);
375 CHECK_VAL(notify.nttrans.out.num_changes, 11);
376 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_ADDED);
377 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
378 CHECK_VAL(notify.nttrans.out.changes[1].action, NOTIFY_ACTION_ADDED);
379 CHECK_WSTR(notify.nttrans.out.changes[1].name, "subdir-name\\subname1", STR_UNICODE);
380 CHECK_VAL(notify.nttrans.out.changes[2].action, NOTIFY_ACTION_ADDED);
381 CHECK_WSTR(notify.nttrans.out.changes[2].name, "subdir-name\\subname2", STR_UNICODE);
382 CHECK_VAL(notify.nttrans.out.changes[3].action, NOTIFY_ACTION_OLD_NAME);
383 CHECK_WSTR(notify.nttrans.out.changes[3].name, "subdir-name\\subname1", STR_UNICODE);
384 CHECK_VAL(notify.nttrans.out.changes[4].action, NOTIFY_ACTION_NEW_NAME);
385 CHECK_WSTR(notify.nttrans.out.changes[4].name, "subdir-name\\subname1-r", STR_UNICODE);
387 ret &= check_rename_reply(
388 cli, __LINE__, ¬ify.nttrans.out.changes[5],
389 NOTIFY_ACTION_ADDED, "subname2-r");
390 ret &= check_rename_reply(
391 cli, __LINE__, ¬ify.nttrans.out.changes[5],
392 NOTIFY_ACTION_REMOVED, "subdir-name\\subname2");
393 ret &= check_rename_reply(
394 cli, __LINE__, ¬ify.nttrans.out.changes[5],
395 NOTIFY_ACTION_MODIFIED, "subname2-r");
397 ret &= check_rename_reply(
398 cli, __LINE__, ¬ify.nttrans.out.changes[8],
399 NOTIFY_ACTION_OLD_NAME, "subname2-r");
400 ret &= check_rename_reply(
401 cli, __LINE__, ¬ify.nttrans.out.changes[8],
402 NOTIFY_ACTION_NEW_NAME, "subname3-r");
403 ret &= check_rename_reply(
404 cli, __LINE__, ¬ify.nttrans.out.changes[8],
405 NOTIFY_ACTION_MODIFIED, "subname3-r");
411 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
412 CHECK_STATUS(status, NT_STATUS_OK);
414 CHECK_VAL(notify.nttrans.out.num_changes, 3);
415 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_REMOVED);
416 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name\\subname1-r", STR_UNICODE);
417 CHECK_VAL(notify.nttrans.out.changes[1].action, NOTIFY_ACTION_REMOVED);
418 CHECK_WSTR(notify.nttrans.out.changes[1].name, "subdir-name", STR_UNICODE);
419 CHECK_VAL(notify.nttrans.out.changes[2].action, NOTIFY_ACTION_REMOVED);
420 CHECK_WSTR(notify.nttrans.out.changes[2].name, "subname3-r", STR_UNICODE);
423 smb_raw_exit(cli->session);
428 testing of change notify mask change
430 static bool test_notify_mask_change(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
434 union smb_notify notify;
437 struct smbcli_request *req1, *req2;
439 printf("TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
442 get a handle on the directory
444 io.generic.level = RAW_OPEN_NTCREATEX;
445 io.ntcreatex.in.root_fid = 0;
446 io.ntcreatex.in.flags = 0;
447 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
448 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
449 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
450 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
451 io.ntcreatex.in.alloc_size = 0;
452 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
453 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
454 io.ntcreatex.in.security_flags = 0;
455 io.ntcreatex.in.fname = BASEDIR;
457 status = smb_raw_open(cli->tree, mem_ctx, &io);
458 CHECK_STATUS(status, NT_STATUS_OK);
459 fnum = io.ntcreatex.out.file.fnum;
461 /* ask for a change notify, on file or directory name
462 changes. Setup both with and without recursion */
463 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
464 notify.nttrans.in.buffer_size = 1000;
465 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
466 notify.nttrans.in.file.fnum = fnum;
468 notify.nttrans.in.recursive = true;
469 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
471 notify.nttrans.in.recursive = false;
472 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
474 /* cancel initial requests so the buffer is setup */
475 smb_raw_ntcancel(req1);
476 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
477 CHECK_STATUS(status, NT_STATUS_CANCELLED);
479 smb_raw_ntcancel(req2);
480 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
481 CHECK_STATUS(status, NT_STATUS_CANCELLED);
483 notify.nttrans.in.recursive = true;
484 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
486 /* Set to hidden then back again. */
487 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));
488 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);
489 smbcli_unlink(cli->tree, BASEDIR "\\tname1");
491 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
492 CHECK_STATUS(status, NT_STATUS_OK);
494 CHECK_VAL(notify.nttrans.out.num_changes, 1);
495 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
496 CHECK_WSTR(notify.nttrans.out.changes[0].name, "tname1", STR_UNICODE);
498 /* Now try and change the mask to include other events.
499 * This should not work - once the mask is set on a directory
500 * fnum it seems to be fixed until the fnum is closed. */
502 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
503 notify.nttrans.in.recursive = true;
504 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
506 notify.nttrans.in.recursive = false;
507 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
509 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
510 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name\\subname1");
511 smbcli_close(cli->tree,
512 smbcli_open(cli->tree, BASEDIR "\\subdir-name\\subname2", O_CREAT, 0));
513 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname1", BASEDIR "\\subdir-name\\subname1-r");
514 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname2", BASEDIR "\\subname2-r");
515 smbcli_rename(cli->tree, BASEDIR "\\subname2-r", BASEDIR "\\subname3-r");
517 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name\\subname1-r");
518 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
519 smbcli_unlink(cli->tree, BASEDIR "\\subname3-r");
521 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
522 CHECK_STATUS(status, NT_STATUS_OK);
524 CHECK_VAL(notify.nttrans.out.num_changes, 1);
525 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
526 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subname2-r", STR_UNICODE);
528 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
529 CHECK_STATUS(status, NT_STATUS_OK);
531 CHECK_VAL(notify.nttrans.out.num_changes, 1);
532 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
533 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subname3-r", STR_UNICODE);
540 smb_raw_exit(cli->session);
546 testing of mask bits for change notify
548 static bool test_notify_mask(struct smbcli_state *cli, struct torture_context *tctx)
552 union smb_notify notify;
561 printf("TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
563 tv = timeval_current_ofs(1000, 0);
564 t = timeval_to_nttime(&tv);
567 get a handle on the directory
569 io.generic.level = RAW_OPEN_NTCREATEX;
570 io.ntcreatex.in.root_fid = 0;
571 io.ntcreatex.in.flags = 0;
572 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
573 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
574 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
575 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
576 io.ntcreatex.in.alloc_size = 0;
577 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
578 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
579 io.ntcreatex.in.security_flags = 0;
580 io.ntcreatex.in.fname = BASEDIR;
582 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
583 notify.nttrans.in.buffer_size = 1000;
584 notify.nttrans.in.recursive = true;
586 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, expected, nchanges) \
588 smbcli_getatr(cli->tree, test_name, NULL, NULL, NULL); \
589 do { for (mask=i=0;i<32;i++) { \
590 struct smbcli_request *req; \
591 status = smb_raw_open(cli->tree, tctx, &io); \
592 CHECK_STATUS(status, NT_STATUS_OK); \
593 fnum = io.ntcreatex.out.file.fnum; \
595 notify.nttrans.in.file.fnum = fnum; \
596 notify.nttrans.in.completion_filter = (1<<i); \
597 req = smb_raw_changenotify_send(cli->tree, ¬ify); \
599 msleep(200); smb_raw_ntcancel(req); \
600 status = smb_raw_changenotify_recv(req, tctx, ¬ify); \
602 smbcli_close(cli->tree, fnum); \
603 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
604 CHECK_STATUS(status, NT_STATUS_OK); \
605 /* special case to cope with file rename behaviour */ \
606 if (nchanges == 2 && notify.nttrans.out.num_changes == 1 && \
607 notify.nttrans.out.changes[0].action == NOTIFY_ACTION_MODIFIED && \
608 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
609 Action == NOTIFY_ACTION_OLD_NAME) { \
610 printf("(rename file special handling OK)\n"); \
611 } else if (nchanges != notify.nttrans.out.num_changes) { \
612 printf("ERROR: nchanges=%d expected=%d action=%d filter=0x%08x\n", \
613 notify.nttrans.out.num_changes, \
615 notify.nttrans.out.changes[0].action, \
616 notify.nttrans.in.completion_filter); \
618 } else if (notify.nttrans.out.changes[0].action != Action) { \
619 printf("ERROR: nchanges=%d action=%d expectedAction=%d filter=0x%08x\n", \
620 notify.nttrans.out.num_changes, \
621 notify.nttrans.out.changes[0].action, \
623 notify.nttrans.in.completion_filter); \
625 } else if (strcmp(notify.nttrans.out.changes[0].name.s, "tname1") != 0) { \
626 printf("ERROR: nchanges=%d action=%d filter=0x%08x name=%s\n", \
627 notify.nttrans.out.num_changes, \
628 notify.nttrans.out.changes[0].action, \
629 notify.nttrans.in.completion_filter, \
630 notify.nttrans.out.changes[0].name.s); \
635 if ((expected) != mask) { \
636 if (((expected) & ~mask) != 0) { \
637 printf("ERROR: trigger on too few bits. mask=0x%08x expected=0x%08x\n", \
641 printf("WARNING: trigger on too many bits. mask=0x%08x expected=0x%08x\n", \
648 printf("testing mkdir\n");
649 NOTIFY_MASK_TEST("testing mkdir",;,
650 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
651 smbcli_rmdir(cli->tree, BASEDIR "\\tname1");,
653 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
655 printf("testing create file\n");
656 NOTIFY_MASK_TEST("testing create file",;,
657 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
658 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
660 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
662 printf("testing unlink\n");
663 NOTIFY_MASK_TEST("testing unlink",
664 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
665 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
667 NOTIFY_ACTION_REMOVED,
668 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
670 printf("testing rmdir\n");
671 NOTIFY_MASK_TEST("testing rmdir",
672 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
673 smbcli_rmdir(cli->tree, BASEDIR "\\tname1");,
675 NOTIFY_ACTION_REMOVED,
676 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
678 printf("testing rename file\n");
679 NOTIFY_MASK_TEST("testing rename file",
680 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
681 smbcli_rename(cli->tree, BASEDIR "\\tname1", BASEDIR "\\tname2");,
682 smbcli_unlink(cli->tree, BASEDIR "\\tname2");,
683 NOTIFY_ACTION_OLD_NAME,
684 FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_CREATION, 2);
686 printf("testing rename dir\n");
687 NOTIFY_MASK_TEST("testing rename dir",
688 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
689 smbcli_rename(cli->tree, BASEDIR "\\tname1", BASEDIR "\\tname2");,
690 smbcli_rmdir(cli->tree, BASEDIR "\\tname2");,
691 NOTIFY_ACTION_OLD_NAME,
692 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
694 printf("testing set path attribute\n");
695 NOTIFY_MASK_TEST("testing set path attribute",
696 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
697 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);,
698 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
699 NOTIFY_ACTION_MODIFIED,
700 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
702 printf("testing set path write time\n");
703 NOTIFY_MASK_TEST("testing set path write time",
704 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
705 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_NORMAL, 1000);,
706 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
707 NOTIFY_ACTION_MODIFIED,
708 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
710 printf("testing set file attribute\n");
711 NOTIFY_MASK_TEST("testing set file attribute",
712 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
713 smbcli_fsetatr(cli->tree, fnum2, FILE_ATTRIBUTE_HIDDEN, 0, 0, 0, 0);,
714 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
715 NOTIFY_ACTION_MODIFIED,
716 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
718 if (torture_setting_bool(tctx, "samba3", false)) {
719 printf("Samba3 does not yet support create times "
723 printf("testing set file create time\n");
724 NOTIFY_MASK_TEST("testing set file create time",
725 fnum2 = create_complex_file(cli, tctx,
726 BASEDIR "\\tname1");,
727 smbcli_fsetatr(cli->tree, fnum2, 0, t, 0, 0, 0);,
728 (smbcli_close(cli->tree, fnum2),
729 smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
730 NOTIFY_ACTION_MODIFIED,
731 FILE_NOTIFY_CHANGE_CREATION, 1);
734 printf("testing set file access time\n");
735 NOTIFY_MASK_TEST("testing set file access time",
736 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
737 smbcli_fsetatr(cli->tree, fnum2, 0, 0, t, 0, 0);,
738 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
739 NOTIFY_ACTION_MODIFIED,
740 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
742 printf("testing set file write time\n");
743 NOTIFY_MASK_TEST("testing set file write time",
744 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
745 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, t, 0);,
746 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
747 NOTIFY_ACTION_MODIFIED,
748 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
750 printf("testing set file change time\n");
751 NOTIFY_MASK_TEST("testing set file change time",
752 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
753 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, 0, t);,
754 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
755 NOTIFY_ACTION_MODIFIED,
759 printf("testing write\n");
760 NOTIFY_MASK_TEST("testing write",
761 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
762 smbcli_write(cli->tree, fnum2, 1, &c, 10000, 1);,
763 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
764 NOTIFY_ACTION_MODIFIED,
767 printf("testing truncate\n");
768 NOTIFY_MASK_TEST("testing truncate",
769 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
770 smbcli_ftruncate(cli->tree, fnum2, 10000);,
771 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
772 NOTIFY_ACTION_MODIFIED,
773 FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
776 smb_raw_exit(cli->session);
781 basic testing of change notify on files
783 static bool test_notify_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
789 union smb_notify notify;
790 struct smbcli_request *req;
792 const char *fname = BASEDIR "\\file.txt";
794 printf("TESTING CHANGE NOTIFY ON FILES\n");
796 io.generic.level = RAW_OPEN_NTCREATEX;
797 io.ntcreatex.in.root_fid = 0;
798 io.ntcreatex.in.flags = 0;
799 io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
800 io.ntcreatex.in.create_options = 0;
801 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
802 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
803 io.ntcreatex.in.alloc_size = 0;
804 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
805 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
806 io.ntcreatex.in.security_flags = 0;
807 io.ntcreatex.in.fname = fname;
808 status = smb_raw_open(cli->tree, mem_ctx, &io);
809 CHECK_STATUS(status, NT_STATUS_OK);
810 fnum = io.ntcreatex.out.file.fnum;
812 /* ask for a change notify,
813 on file or directory name changes */
814 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
815 notify.nttrans.in.file.fnum = fnum;
816 notify.nttrans.in.buffer_size = 1000;
817 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
818 notify.nttrans.in.recursive = false;
820 printf("testing if notifies on file handles are invalid (should be)\n");
822 req = smb_raw_changenotify_send(cli->tree, ¬ify);
823 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
824 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
826 cl.close.level = RAW_CLOSE_CLOSE;
827 cl.close.in.file.fnum = fnum;
828 cl.close.in.write_time = 0;
829 status = smb_raw_close(cli->tree, &cl);
830 CHECK_STATUS(status, NT_STATUS_OK);
832 status = smbcli_unlink(cli->tree, fname);
833 CHECK_STATUS(status, NT_STATUS_OK);
836 smb_raw_exit(cli->session);
841 basic testing of change notifies followed by a tdis
843 static bool test_notify_tdis(struct torture_context *tctx)
847 union smb_notify notify;
850 struct smbcli_request *req;
851 struct smbcli_state *cli = NULL;
853 printf("TESTING CHANGE NOTIFY FOLLOWED BY TDIS\n");
855 if (!torture_open_connection(&cli, tctx, 0)) {
860 get a handle on the directory
862 io.generic.level = RAW_OPEN_NTCREATEX;
863 io.ntcreatex.in.root_fid = 0;
864 io.ntcreatex.in.flags = 0;
865 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
866 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
867 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
868 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
869 io.ntcreatex.in.alloc_size = 0;
870 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
871 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
872 io.ntcreatex.in.security_flags = 0;
873 io.ntcreatex.in.fname = BASEDIR;
875 status = smb_raw_open(cli->tree, tctx, &io);
876 CHECK_STATUS(status, NT_STATUS_OK);
877 fnum = io.ntcreatex.out.file.fnum;
879 /* ask for a change notify,
880 on file or directory name changes */
881 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
882 notify.nttrans.in.buffer_size = 1000;
883 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
884 notify.nttrans.in.file.fnum = fnum;
885 notify.nttrans.in.recursive = true;
887 req = smb_raw_changenotify_send(cli->tree, ¬ify);
889 status = smbcli_tdis(cli);
890 CHECK_STATUS(status, NT_STATUS_OK);
893 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
894 CHECK_STATUS(status, NT_STATUS_OK);
895 CHECK_VAL(notify.nttrans.out.num_changes, 0);
898 torture_close_connection(cli);
903 basic testing of change notifies followed by a exit
905 static bool test_notify_exit(struct torture_context *tctx)
909 union smb_notify notify;
912 struct smbcli_request *req;
913 struct smbcli_state *cli = NULL;
915 printf("TESTING CHANGE NOTIFY FOLLOWED BY EXIT\n");
917 if (!torture_open_connection(&cli, tctx, 0)) {
922 get a handle on the directory
924 io.generic.level = RAW_OPEN_NTCREATEX;
925 io.ntcreatex.in.root_fid = 0;
926 io.ntcreatex.in.flags = 0;
927 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
928 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
929 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
930 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
931 io.ntcreatex.in.alloc_size = 0;
932 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
933 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
934 io.ntcreatex.in.security_flags = 0;
935 io.ntcreatex.in.fname = BASEDIR;
937 status = smb_raw_open(cli->tree, tctx, &io);
938 CHECK_STATUS(status, NT_STATUS_OK);
939 fnum = io.ntcreatex.out.file.fnum;
941 /* ask for a change notify,
942 on file or directory name changes */
943 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
944 notify.nttrans.in.buffer_size = 1000;
945 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
946 notify.nttrans.in.file.fnum = fnum;
947 notify.nttrans.in.recursive = true;
949 req = smb_raw_changenotify_send(cli->tree, ¬ify);
951 status = smb_raw_exit(cli->session);
952 CHECK_STATUS(status, NT_STATUS_OK);
954 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
955 CHECK_STATUS(status, NT_STATUS_OK);
956 CHECK_VAL(notify.nttrans.out.num_changes, 0);
959 torture_close_connection(cli);
964 basic testing of change notifies followed by a ulogoff
966 static bool test_notify_ulogoff(struct torture_context *tctx)
970 union smb_notify notify;
973 struct smbcli_request *req;
974 struct smbcli_state *cli = NULL;
976 printf("TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
978 if (!torture_open_connection(&cli, tctx, 0)) {
983 get a handle on the directory
985 io.generic.level = RAW_OPEN_NTCREATEX;
986 io.ntcreatex.in.root_fid = 0;
987 io.ntcreatex.in.flags = 0;
988 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
989 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
990 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
991 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
992 io.ntcreatex.in.alloc_size = 0;
993 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
994 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
995 io.ntcreatex.in.security_flags = 0;
996 io.ntcreatex.in.fname = BASEDIR;
998 status = smb_raw_open(cli->tree, tctx, &io);
999 CHECK_STATUS(status, NT_STATUS_OK);
1000 fnum = io.ntcreatex.out.file.fnum;
1002 /* ask for a change notify,
1003 on file or directory name changes */
1004 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1005 notify.nttrans.in.buffer_size = 1000;
1006 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1007 notify.nttrans.in.file.fnum = fnum;
1008 notify.nttrans.in.recursive = true;
1010 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1012 status = smb_raw_ulogoff(cli->session);
1013 CHECK_STATUS(status, NT_STATUS_OK);
1015 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1016 CHECK_STATUS(status, NT_STATUS_OK);
1017 CHECK_VAL(notify.nttrans.out.num_changes, 0);
1020 torture_close_connection(cli);
1024 static void tcp_dis_handler(struct smbcli_transport *t, void *p)
1026 struct smbcli_state *cli = (struct smbcli_state *)p;
1027 smbcli_transport_dead(cli->transport, NT_STATUS_LOCAL_DISCONNECT);
1028 cli->transport = NULL;
1032 basic testing of change notifies followed by tcp disconnect
1034 static bool test_notify_tcp_dis(struct torture_context *tctx)
1038 union smb_notify notify;
1041 struct smbcli_request *req;
1042 struct smbcli_state *cli = NULL;
1044 printf("TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1046 if (!torture_open_connection(&cli, tctx, 0)) {
1051 get a handle on the directory
1053 io.generic.level = RAW_OPEN_NTCREATEX;
1054 io.ntcreatex.in.root_fid = 0;
1055 io.ntcreatex.in.flags = 0;
1056 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1057 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1058 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1059 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1060 io.ntcreatex.in.alloc_size = 0;
1061 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1062 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1063 io.ntcreatex.in.security_flags = 0;
1064 io.ntcreatex.in.fname = BASEDIR;
1066 status = smb_raw_open(cli->tree, tctx, &io);
1067 CHECK_STATUS(status, NT_STATUS_OK);
1068 fnum = io.ntcreatex.out.file.fnum;
1070 /* ask for a change notify,
1071 on file or directory name changes */
1072 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1073 notify.nttrans.in.buffer_size = 1000;
1074 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1075 notify.nttrans.in.file.fnum = fnum;
1076 notify.nttrans.in.recursive = true;
1078 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1080 smbcli_transport_idle_handler(cli->transport, tcp_dis_handler, 250, cli);
1082 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1083 CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1086 torture_close_connection(cli);
1091 test setting up two change notify requests on one handle
1093 static bool test_notify_double(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
1097 union smb_notify notify;
1100 struct smbcli_request *req1, *req2;
1102 printf("TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1105 get a handle on the directory
1107 io.generic.level = RAW_OPEN_NTCREATEX;
1108 io.ntcreatex.in.root_fid = 0;
1109 io.ntcreatex.in.flags = 0;
1110 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1111 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1112 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1113 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1114 io.ntcreatex.in.alloc_size = 0;
1115 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1116 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1117 io.ntcreatex.in.security_flags = 0;
1118 io.ntcreatex.in.fname = BASEDIR;
1120 status = smb_raw_open(cli->tree, mem_ctx, &io);
1121 CHECK_STATUS(status, NT_STATUS_OK);
1122 fnum = io.ntcreatex.out.file.fnum;
1124 /* ask for a change notify,
1125 on file or directory name changes */
1126 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1127 notify.nttrans.in.buffer_size = 1000;
1128 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1129 notify.nttrans.in.file.fnum = fnum;
1130 notify.nttrans.in.recursive = true;
1132 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1133 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
1135 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1137 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
1138 CHECK_STATUS(status, NT_STATUS_OK);
1139 CHECK_VAL(notify.nttrans.out.num_changes, 1);
1140 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
1142 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name2");
1144 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
1145 CHECK_STATUS(status, NT_STATUS_OK);
1146 CHECK_VAL(notify.nttrans.out.num_changes, 1);
1147 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name2", STR_UNICODE);
1150 smb_raw_exit(cli->session);
1156 test multiple change notifies at different depths and with/without recursion
1158 static bool test_notify_tree(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
1161 union smb_notify notify;
1163 struct smbcli_request *req;
1173 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 30 },
1174 {BASEDIR "\\zqy", true, FILE_NOTIFY_CHANGE_NAME, 8 },
1175 {BASEDIR "\\atsy", true, FILE_NOTIFY_CHANGE_NAME, 4 },
1176 {BASEDIR "\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1177 {BASEDIR "\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME, 13 },
1178 {BASEDIR "\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME, 7 },
1179 {BASEDIR "\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1180 {BASEDIR "\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1181 {BASEDIR "\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1182 {BASEDIR "\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1183 {BASEDIR "\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1184 {BASEDIR "\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1185 {BASEDIR "\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME, 40 },
1186 {BASEDIR, true, FILE_NOTIFY_CHANGE_NAME, 40 },
1187 {BASEDIR, false,FILE_NOTIFY_CHANGE_NAME, 6 },
1188 {BASEDIR "\\atsy", false,FILE_NOTIFY_CHANGE_NAME, 4 },
1189 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1190 {BASEDIR "\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1191 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1192 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1196 bool all_done = false;
1198 printf("TESTING CHANGE NOTIFY FOR DIFFERENT DEPTHS\n");
1200 io.generic.level = RAW_OPEN_NTCREATEX;
1201 io.ntcreatex.in.root_fid = 0;
1202 io.ntcreatex.in.flags = 0;
1203 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1204 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1205 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1206 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1207 io.ntcreatex.in.alloc_size = 0;
1208 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1209 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1210 io.ntcreatex.in.security_flags = 0;
1212 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1213 notify.nttrans.in.buffer_size = 20000;
1216 setup the directory tree, and the notify buffer on each directory
1218 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1219 io.ntcreatex.in.fname = dirs[i].path;
1220 status = smb_raw_open(cli->tree, mem_ctx, &io);
1221 CHECK_STATUS(status, NT_STATUS_OK);
1222 dirs[i].fnum = io.ntcreatex.out.file.fnum;
1224 notify.nttrans.in.completion_filter = dirs[i].filter;
1225 notify.nttrans.in.file.fnum = dirs[i].fnum;
1226 notify.nttrans.in.recursive = dirs[i].recursive;
1227 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1228 smb_raw_ntcancel(req);
1229 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
1230 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1233 /* trigger 2 events in each dir */
1234 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1235 char *path = talloc_asprintf(mem_ctx, "%s\\test.dir", dirs[i].path);
1236 smbcli_mkdir(cli->tree, path);
1237 smbcli_rmdir(cli->tree, path);
1241 /* give a bit of time for the events to propogate */
1242 tv = timeval_current();
1245 /* count events that have happened in each dir */
1246 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1247 notify.nttrans.in.file.fnum = dirs[i].fnum;
1248 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1249 smb_raw_ntcancel(req);
1250 notify.nttrans.out.num_changes = 0;
1251 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
1252 dirs[i].counted += notify.nttrans.out.num_changes;
1257 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1258 if (dirs[i].counted != dirs[i].expected) {
1262 } while (!all_done && timeval_elapsed(&tv) < 20);
1264 printf("took %.4f seconds to propogate all events\n", timeval_elapsed(&tv));
1266 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1267 if (dirs[i].counted != dirs[i].expected) {
1268 printf("ERROR: i=%d expected %d got %d for '%s'\n",
1269 i, dirs[i].expected, dirs[i].counted, dirs[i].path);
1275 run from the back, closing and deleting
1277 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1278 smbcli_close(cli->tree, dirs[i].fnum);
1279 smbcli_rmdir(cli->tree, dirs[i].path);
1283 smb_raw_exit(cli->session);
1288 basic testing of change notify
1290 bool torture_raw_notify(struct torture_context *torture,
1291 struct smbcli_state *cli,
1292 struct smbcli_state *cli2)
1296 if (!torture_setup_dir(cli, BASEDIR)) {
1300 ret &= test_notify_dir(cli, cli2, torture);
1301 ret &= test_notify_mask(cli, torture);
1302 ret &= test_notify_recursive(cli, torture);
1303 ret &= test_notify_mask_change(cli, torture);
1304 ret &= test_notify_file(cli, torture);
1305 ret &= test_notify_tdis(torture);
1306 ret &= test_notify_exit(torture);
1307 ret &= test_notify_ulogoff(torture);
1308 ret &= test_notify_tcp_dis(torture);
1309 ret &= test_notify_double(cli, torture);
1310 ret &= test_notify_tree(cli, torture);
1312 smb_raw_exit(cli->session);
1313 smbcli_deltree(cli->tree, BASEDIR);