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) \
587 smbcli_unlink(cli->tree, test_name); \
588 do { for (mask=i=0;i<32;i++) { \
589 struct smbcli_request *req; \
590 status = smb_raw_open(cli->tree, tctx, &io); \
591 CHECK_STATUS(status, NT_STATUS_OK); \
592 fnum = io.ntcreatex.out.file.fnum; \
594 notify.nttrans.in.file.fnum = fnum; \
595 notify.nttrans.in.completion_filter = (1<<i); \
596 req = smb_raw_changenotify_send(cli->tree, ¬ify); \
598 msleep(200); smb_raw_ntcancel(req); \
599 status = smb_raw_changenotify_recv(req, tctx, ¬ify); \
601 smbcli_close(cli->tree, fnum); \
602 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
603 CHECK_STATUS(status, NT_STATUS_OK); \
604 /* special case to cope with file rename behaviour */ \
605 if (nchanges == 2 && notify.nttrans.out.num_changes == 1 && \
606 notify.nttrans.out.changes[0].action == NOTIFY_ACTION_MODIFIED && \
607 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
608 Action == NOTIFY_ACTION_OLD_NAME) { \
609 printf("(rename file special handling OK)\n"); \
610 } else if (nchanges != notify.nttrans.out.num_changes) { \
611 printf("ERROR: nchanges=%d expected=%d action=%d filter=0x%08x\n", \
612 notify.nttrans.out.num_changes, \
614 notify.nttrans.out.changes[0].action, \
615 notify.nttrans.in.completion_filter); \
617 } else if (notify.nttrans.out.changes[0].action != Action) { \
618 printf("ERROR: nchanges=%d action=%d expectedAction=%d filter=0x%08x\n", \
619 notify.nttrans.out.num_changes, \
620 notify.nttrans.out.changes[0].action, \
622 notify.nttrans.in.completion_filter); \
624 } else if (strcmp(notify.nttrans.out.changes[0].name.s, "tname1") != 0) { \
625 printf("ERROR: nchanges=%d action=%d filter=0x%08x name=%s\n", \
626 notify.nttrans.out.num_changes, \
627 notify.nttrans.out.changes[0].action, \
628 notify.nttrans.in.completion_filter, \
629 notify.nttrans.out.changes[0].name.s); \
634 if ((expected) != mask) { \
635 if (((expected) & ~mask) != 0) { \
636 printf("ERROR: trigger on too few bits. mask=0x%08x expected=0x%08x\n", \
640 printf("WARNING: trigger on too many bits. mask=0x%08x expected=0x%08x\n", \
646 printf("testing mkdir\n");
647 NOTIFY_MASK_TEST("testing mkdir",;,
648 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
649 smbcli_rmdir(cli->tree, BASEDIR "\\tname1");,
651 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
653 printf("testing create file\n");
654 NOTIFY_MASK_TEST("testing create file",;,
655 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
656 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
658 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
660 printf("testing unlink\n");
661 NOTIFY_MASK_TEST("testing unlink",
662 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
663 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
665 NOTIFY_ACTION_REMOVED,
666 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
668 printf("testing rmdir\n");
669 NOTIFY_MASK_TEST("testing rmdir",
670 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
671 smbcli_rmdir(cli->tree, BASEDIR "\\tname1");,
673 NOTIFY_ACTION_REMOVED,
674 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
676 printf("testing rename file\n");
677 NOTIFY_MASK_TEST("testing rename file",
678 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
679 smbcli_rename(cli->tree, BASEDIR "\\tname1", BASEDIR "\\tname2");,
680 smbcli_unlink(cli->tree, BASEDIR "\\tname2");,
681 NOTIFY_ACTION_OLD_NAME,
682 FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_CREATION, 2);
684 printf("testing rename dir\n");
685 NOTIFY_MASK_TEST("testing rename dir",
686 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
687 smbcli_rename(cli->tree, BASEDIR "\\tname1", BASEDIR "\\tname2");,
688 smbcli_rmdir(cli->tree, BASEDIR "\\tname2");,
689 NOTIFY_ACTION_OLD_NAME,
690 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
692 printf("testing set path attribute\n");
693 NOTIFY_MASK_TEST("testing set path attribute",
694 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
695 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);,
696 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
697 NOTIFY_ACTION_MODIFIED,
698 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
700 printf("testing set path write time\n");
701 NOTIFY_MASK_TEST("testing set path write time",
702 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
703 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_NORMAL, 1000);,
704 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
705 NOTIFY_ACTION_MODIFIED,
706 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
708 printf("testing set file attribute\n");
709 NOTIFY_MASK_TEST("testing set file attribute",
710 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
711 smbcli_fsetatr(cli->tree, fnum2, FILE_ATTRIBUTE_HIDDEN, 0, 0, 0, 0);,
712 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
713 NOTIFY_ACTION_MODIFIED,
714 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
716 if (torture_setting_bool(tctx, "samba3", false)) {
717 printf("Samba3 does not yet support create times "
721 printf("testing set file create time\n");
722 NOTIFY_MASK_TEST("testing set file create time",
723 fnum2 = create_complex_file(cli, tctx,
724 BASEDIR "\\tname1");,
725 smbcli_fsetatr(cli->tree, fnum2, 0, t, 0, 0, 0);,
726 (smbcli_close(cli->tree, fnum2),
727 smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
728 NOTIFY_ACTION_MODIFIED,
729 FILE_NOTIFY_CHANGE_CREATION, 1);
732 printf("testing set file access time\n");
733 NOTIFY_MASK_TEST("testing set file access time",
734 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
735 smbcli_fsetatr(cli->tree, fnum2, 0, 0, t, 0, 0);,
736 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
737 NOTIFY_ACTION_MODIFIED,
738 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
740 printf("testing set file write time\n");
741 NOTIFY_MASK_TEST("testing set file write time",
742 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
743 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, t, 0);,
744 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
745 NOTIFY_ACTION_MODIFIED,
746 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
748 printf("testing set file change time\n");
749 NOTIFY_MASK_TEST("testing set file change time",
750 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
751 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, 0, t);,
752 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
753 NOTIFY_ACTION_MODIFIED,
757 printf("testing write\n");
758 NOTIFY_MASK_TEST("testing write",
759 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
760 smbcli_write(cli->tree, fnum2, 1, &c, 10000, 1);,
761 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
762 NOTIFY_ACTION_MODIFIED,
765 printf("testing truncate\n");
766 NOTIFY_MASK_TEST("testing truncate",
767 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
768 smbcli_ftruncate(cli->tree, fnum2, 10000);,
769 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
770 NOTIFY_ACTION_MODIFIED,
771 FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
774 smb_raw_exit(cli->session);
779 basic testing of change notify on files
781 static bool test_notify_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
787 union smb_notify notify;
788 struct smbcli_request *req;
790 const char *fname = BASEDIR "\\file.txt";
792 printf("TESTING CHANGE NOTIFY ON FILES\n");
794 io.generic.level = RAW_OPEN_NTCREATEX;
795 io.ntcreatex.in.root_fid = 0;
796 io.ntcreatex.in.flags = 0;
797 io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
798 io.ntcreatex.in.create_options = 0;
799 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
800 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
801 io.ntcreatex.in.alloc_size = 0;
802 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
803 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
804 io.ntcreatex.in.security_flags = 0;
805 io.ntcreatex.in.fname = fname;
806 status = smb_raw_open(cli->tree, mem_ctx, &io);
807 CHECK_STATUS(status, NT_STATUS_OK);
808 fnum = io.ntcreatex.out.file.fnum;
810 /* ask for a change notify,
811 on file or directory name changes */
812 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
813 notify.nttrans.in.file.fnum = fnum;
814 notify.nttrans.in.buffer_size = 1000;
815 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
816 notify.nttrans.in.recursive = false;
818 printf("testing if notifies on file handles are invalid (should be)\n");
820 req = smb_raw_changenotify_send(cli->tree, ¬ify);
821 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
822 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
824 cl.close.level = RAW_CLOSE_CLOSE;
825 cl.close.in.file.fnum = fnum;
826 cl.close.in.write_time = 0;
827 status = smb_raw_close(cli->tree, &cl);
828 CHECK_STATUS(status, NT_STATUS_OK);
830 status = smbcli_unlink(cli->tree, fname);
831 CHECK_STATUS(status, NT_STATUS_OK);
834 smb_raw_exit(cli->session);
839 basic testing of change notifies followed by a tdis
841 static bool test_notify_tdis(struct torture_context *tctx)
845 union smb_notify notify;
848 struct smbcli_request *req;
849 struct smbcli_state *cli = NULL;
851 printf("TESTING CHANGE NOTIFY FOLLOWED BY TDIS\n");
853 if (!torture_open_connection(&cli, tctx, 0)) {
858 get a handle on the directory
860 io.generic.level = RAW_OPEN_NTCREATEX;
861 io.ntcreatex.in.root_fid = 0;
862 io.ntcreatex.in.flags = 0;
863 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
864 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
865 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
866 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
867 io.ntcreatex.in.alloc_size = 0;
868 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
869 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
870 io.ntcreatex.in.security_flags = 0;
871 io.ntcreatex.in.fname = BASEDIR;
873 status = smb_raw_open(cli->tree, tctx, &io);
874 CHECK_STATUS(status, NT_STATUS_OK);
875 fnum = io.ntcreatex.out.file.fnum;
877 /* ask for a change notify,
878 on file or directory name changes */
879 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
880 notify.nttrans.in.buffer_size = 1000;
881 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
882 notify.nttrans.in.file.fnum = fnum;
883 notify.nttrans.in.recursive = true;
885 req = smb_raw_changenotify_send(cli->tree, ¬ify);
887 status = smbcli_tdis(cli);
888 CHECK_STATUS(status, NT_STATUS_OK);
891 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
892 CHECK_STATUS(status, NT_STATUS_OK);
893 CHECK_VAL(notify.nttrans.out.num_changes, 0);
896 torture_close_connection(cli);
901 basic testing of change notifies followed by a exit
903 static bool test_notify_exit(struct torture_context *tctx)
907 union smb_notify notify;
910 struct smbcli_request *req;
911 struct smbcli_state *cli = NULL;
913 printf("TESTING CHANGE NOTIFY FOLLOWED BY EXIT\n");
915 if (!torture_open_connection(&cli, tctx, 0)) {
920 get a handle on the directory
922 io.generic.level = RAW_OPEN_NTCREATEX;
923 io.ntcreatex.in.root_fid = 0;
924 io.ntcreatex.in.flags = 0;
925 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
926 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
927 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
928 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
929 io.ntcreatex.in.alloc_size = 0;
930 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
931 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
932 io.ntcreatex.in.security_flags = 0;
933 io.ntcreatex.in.fname = BASEDIR;
935 status = smb_raw_open(cli->tree, tctx, &io);
936 CHECK_STATUS(status, NT_STATUS_OK);
937 fnum = io.ntcreatex.out.file.fnum;
939 /* ask for a change notify,
940 on file or directory name changes */
941 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
942 notify.nttrans.in.buffer_size = 1000;
943 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
944 notify.nttrans.in.file.fnum = fnum;
945 notify.nttrans.in.recursive = true;
947 req = smb_raw_changenotify_send(cli->tree, ¬ify);
949 status = smb_raw_exit(cli->session);
950 CHECK_STATUS(status, NT_STATUS_OK);
952 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
953 CHECK_STATUS(status, NT_STATUS_OK);
954 CHECK_VAL(notify.nttrans.out.num_changes, 0);
957 torture_close_connection(cli);
962 basic testing of change notifies followed by a ulogoff
964 static bool test_notify_ulogoff(struct torture_context *tctx)
968 union smb_notify notify;
971 struct smbcli_request *req;
972 struct smbcli_state *cli = NULL;
974 printf("TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
976 if (!torture_open_connection(&cli, tctx, 0)) {
981 get a handle on the directory
983 io.generic.level = RAW_OPEN_NTCREATEX;
984 io.ntcreatex.in.root_fid = 0;
985 io.ntcreatex.in.flags = 0;
986 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
987 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
988 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
989 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
990 io.ntcreatex.in.alloc_size = 0;
991 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
992 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
993 io.ntcreatex.in.security_flags = 0;
994 io.ntcreatex.in.fname = BASEDIR;
996 status = smb_raw_open(cli->tree, tctx, &io);
997 CHECK_STATUS(status, NT_STATUS_OK);
998 fnum = io.ntcreatex.out.file.fnum;
1000 /* ask for a change notify,
1001 on file or directory name changes */
1002 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1003 notify.nttrans.in.buffer_size = 1000;
1004 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1005 notify.nttrans.in.file.fnum = fnum;
1006 notify.nttrans.in.recursive = true;
1008 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1010 status = smb_raw_ulogoff(cli->session);
1011 CHECK_STATUS(status, NT_STATUS_OK);
1013 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1014 CHECK_STATUS(status, NT_STATUS_OK);
1015 CHECK_VAL(notify.nttrans.out.num_changes, 0);
1018 torture_close_connection(cli);
1022 static void tcp_dis_handler(struct smbcli_transport *t, void *p)
1024 struct smbcli_state *cli = (struct smbcli_state *)p;
1025 smbcli_transport_dead(cli->transport, NT_STATUS_LOCAL_DISCONNECT);
1026 cli->transport = NULL;
1030 basic testing of change notifies followed by tcp disconnect
1032 static bool test_notify_tcp_dis(struct torture_context *tctx)
1036 union smb_notify notify;
1039 struct smbcli_request *req;
1040 struct smbcli_state *cli = NULL;
1042 printf("TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1044 if (!torture_open_connection(&cli, tctx, 0)) {
1049 get a handle on the directory
1051 io.generic.level = RAW_OPEN_NTCREATEX;
1052 io.ntcreatex.in.root_fid = 0;
1053 io.ntcreatex.in.flags = 0;
1054 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1055 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1056 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1057 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1058 io.ntcreatex.in.alloc_size = 0;
1059 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1060 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1061 io.ntcreatex.in.security_flags = 0;
1062 io.ntcreatex.in.fname = BASEDIR;
1064 status = smb_raw_open(cli->tree, tctx, &io);
1065 CHECK_STATUS(status, NT_STATUS_OK);
1066 fnum = io.ntcreatex.out.file.fnum;
1068 /* ask for a change notify,
1069 on file or directory name changes */
1070 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1071 notify.nttrans.in.buffer_size = 1000;
1072 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1073 notify.nttrans.in.file.fnum = fnum;
1074 notify.nttrans.in.recursive = true;
1076 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1078 smbcli_transport_idle_handler(cli->transport, tcp_dis_handler, 250, cli);
1080 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1081 CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1084 torture_close_connection(cli);
1089 test setting up two change notify requests on one handle
1091 static bool test_notify_double(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
1095 union smb_notify notify;
1098 struct smbcli_request *req1, *req2;
1100 printf("TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1103 get a handle on the directory
1105 io.generic.level = RAW_OPEN_NTCREATEX;
1106 io.ntcreatex.in.root_fid = 0;
1107 io.ntcreatex.in.flags = 0;
1108 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1109 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1110 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1111 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1112 io.ntcreatex.in.alloc_size = 0;
1113 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1114 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1115 io.ntcreatex.in.security_flags = 0;
1116 io.ntcreatex.in.fname = BASEDIR;
1118 status = smb_raw_open(cli->tree, mem_ctx, &io);
1119 CHECK_STATUS(status, NT_STATUS_OK);
1120 fnum = io.ntcreatex.out.file.fnum;
1122 /* ask for a change notify,
1123 on file or directory name changes */
1124 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1125 notify.nttrans.in.buffer_size = 1000;
1126 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1127 notify.nttrans.in.file.fnum = fnum;
1128 notify.nttrans.in.recursive = true;
1130 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1131 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
1133 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1135 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
1136 CHECK_STATUS(status, NT_STATUS_OK);
1137 CHECK_VAL(notify.nttrans.out.num_changes, 1);
1138 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
1140 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name2");
1142 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
1143 CHECK_STATUS(status, NT_STATUS_OK);
1144 CHECK_VAL(notify.nttrans.out.num_changes, 1);
1145 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name2", STR_UNICODE);
1148 smb_raw_exit(cli->session);
1154 test multiple change notifies at different depths and with/without recursion
1156 static bool test_notify_tree(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
1159 union smb_notify notify;
1161 struct smbcli_request *req;
1171 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 30 },
1172 {BASEDIR "\\zqy", true, FILE_NOTIFY_CHANGE_NAME, 8 },
1173 {BASEDIR "\\atsy", true, FILE_NOTIFY_CHANGE_NAME, 4 },
1174 {BASEDIR "\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1175 {BASEDIR "\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME, 13 },
1176 {BASEDIR "\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME, 7 },
1177 {BASEDIR "\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1178 {BASEDIR "\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1179 {BASEDIR "\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1180 {BASEDIR "\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1181 {BASEDIR "\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1182 {BASEDIR "\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1183 {BASEDIR "\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME, 40 },
1184 {BASEDIR, true, FILE_NOTIFY_CHANGE_NAME, 40 },
1185 {BASEDIR, false,FILE_NOTIFY_CHANGE_NAME, 6 },
1186 {BASEDIR "\\atsy", false,FILE_NOTIFY_CHANGE_NAME, 4 },
1187 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1188 {BASEDIR "\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1189 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1190 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1194 bool all_done = false;
1196 printf("TESTING CHANGE NOTIFY FOR DIFFERENT DEPTHS\n");
1198 io.generic.level = RAW_OPEN_NTCREATEX;
1199 io.ntcreatex.in.root_fid = 0;
1200 io.ntcreatex.in.flags = 0;
1201 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1202 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1203 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1204 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1205 io.ntcreatex.in.alloc_size = 0;
1206 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1207 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1208 io.ntcreatex.in.security_flags = 0;
1210 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1211 notify.nttrans.in.buffer_size = 20000;
1214 setup the directory tree, and the notify buffer on each directory
1216 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1217 io.ntcreatex.in.fname = dirs[i].path;
1218 status = smb_raw_open(cli->tree, mem_ctx, &io);
1219 CHECK_STATUS(status, NT_STATUS_OK);
1220 dirs[i].fnum = io.ntcreatex.out.file.fnum;
1222 notify.nttrans.in.completion_filter = dirs[i].filter;
1223 notify.nttrans.in.file.fnum = dirs[i].fnum;
1224 notify.nttrans.in.recursive = dirs[i].recursive;
1225 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1226 smb_raw_ntcancel(req);
1227 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
1228 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1231 /* trigger 2 events in each dir */
1232 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1233 char *path = talloc_asprintf(mem_ctx, "%s\\test.dir", dirs[i].path);
1234 smbcli_mkdir(cli->tree, path);
1235 smbcli_rmdir(cli->tree, path);
1239 /* give a bit of time for the events to propogate */
1240 tv = timeval_current();
1243 /* count events that have happened in each dir */
1244 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1245 notify.nttrans.in.file.fnum = dirs[i].fnum;
1246 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1247 smb_raw_ntcancel(req);
1248 notify.nttrans.out.num_changes = 0;
1249 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
1250 dirs[i].counted += notify.nttrans.out.num_changes;
1255 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1256 if (dirs[i].counted != dirs[i].expected) {
1260 } while (!all_done && timeval_elapsed(&tv) < 20);
1262 printf("took %.4f seconds to propogate all events\n", timeval_elapsed(&tv));
1264 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1265 if (dirs[i].counted != dirs[i].expected) {
1266 printf("ERROR: i=%d expected %d got %d for '%s'\n",
1267 i, dirs[i].expected, dirs[i].counted, dirs[i].path);
1273 run from the back, closing and deleting
1275 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1276 smbcli_close(cli->tree, dirs[i].fnum);
1277 smbcli_rmdir(cli->tree, dirs[i].path);
1281 smb_raw_exit(cli->session);
1286 basic testing of change notify
1288 bool torture_raw_notify(struct torture_context *torture,
1289 struct smbcli_state *cli,
1290 struct smbcli_state *cli2)
1294 if (!torture_setup_dir(cli, BASEDIR)) {
1298 ret &= test_notify_dir(cli, cli2, torture);
1299 ret &= test_notify_mask(cli, torture);
1300 ret &= test_notify_recursive(cli, torture);
1301 ret &= test_notify_mask_change(cli, torture);
1302 ret &= test_notify_file(cli, torture);
1303 ret &= test_notify_tdis(torture);
1304 ret &= test_notify_exit(torture);
1305 ret &= test_notify_ulogoff(torture);
1306 ret &= test_notify_tcp_dis(torture);
1307 ret &= test_notify_double(cli, torture);
1308 ret &= test_notify_tree(cli, torture);
1310 smb_raw_exit(cli->session);
1311 smbcli_deltree(cli->tree, BASEDIR);