2 Unix SMB/CIFS implementation.
3 basic raw test suite for change notify
4 Copyright (C) Andrew Tridgell 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "libcli/raw/libcliraw.h"
22 #include "libcli/raw/raw_proto.h"
23 #include "libcli/libcli.h"
24 #include "system/filesys.h"
25 #include "torture/util.h"
26 #include "torture/raw/proto.h"
28 #define BASEDIR "\\test_notify"
30 #define CHECK_STATUS(status, correct) do { \
31 if (!NT_STATUS_EQUAL(status, correct)) { \
32 printf("(%d) Incorrect status %s - should be %s\n", \
33 __LINE__, nt_errstr(status), nt_errstr(correct)); \
39 #define CHECK_VAL(v, correct) do { \
40 if ((v) != (correct)) { \
41 printf("(%d) wrong value for %s 0x%x should be 0x%x\n", \
42 __LINE__, #v, (int)v, (int)correct); \
47 #define CHECK_WSTR(field, value, flags) do { \
48 if (!field.s || strcmp(field.s, value) || wire_bad_flags(&field, flags, cli->transport)) { \
49 printf("(%d) %s [%s] != %s\n", __LINE__, #field, field.s, value); \
54 #define CHECK_WSTR2(tctx, field, value, flags) \
56 if (!field.s || strcmp(field.s, value) || \
57 wire_bad_flags(&field, flags, cli->transport)) { \
58 torture_result(tctx, TORTURE_FAIL, \
59 "(%d) %s [%s] != %s\n", __LINE__, #field, field.s, value); \
64 basic testing of change notify on directories
66 static bool test_notify_dir(struct torture_context *mem_ctx,
67 struct smbcli_state *cli,
68 struct smbcli_state *cli2)
72 union smb_notify notify;
75 int i, count, fnum, fnum2;
76 struct smbcli_request *req, *req2;
77 extern int torture_numops;
79 printf("TESTING CHANGE NOTIFY ON DIRECTORIES\n");
81 if (!torture_setup_dir(cli, BASEDIR)) {
86 get a handle on the directory
88 io.generic.level = RAW_OPEN_NTCREATEX;
89 io.ntcreatex.in.root_fid.fnum = 0;
90 io.ntcreatex.in.flags = 0;
91 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
92 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
93 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
94 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
95 io.ntcreatex.in.alloc_size = 0;
96 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
97 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
98 io.ntcreatex.in.security_flags = 0;
99 io.ntcreatex.in.fname = BASEDIR;
101 status = smb_raw_open(cli->tree, mem_ctx, &io);
102 CHECK_STATUS(status, NT_STATUS_OK);
103 fnum = io.ntcreatex.out.file.fnum;
105 status = smb_raw_open(cli->tree, mem_ctx, &io);
106 CHECK_STATUS(status, NT_STATUS_OK);
107 fnum2 = io.ntcreatex.out.file.fnum;
109 /* ask for a change notify,
110 on file or directory name changes */
111 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
112 notify.nttrans.in.buffer_size = 1000;
113 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
114 notify.nttrans.in.file.fnum = fnum;
115 notify.nttrans.in.recursive = true;
117 printf("Testing notify cancel\n");
119 req = smb_raw_changenotify_send(cli->tree, ¬ify);
120 smb_raw_ntcancel(req);
121 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
122 CHECK_STATUS(status, NT_STATUS_CANCELLED);
124 printf("Testing notify mkdir\n");
126 req = smb_raw_changenotify_send(cli->tree, ¬ify);
127 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name");
129 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
130 CHECK_STATUS(status, NT_STATUS_OK);
132 CHECK_VAL(notify.nttrans.out.num_changes, 1);
133 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_ADDED);
134 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
136 printf("Testing notify rmdir\n");
138 req = smb_raw_changenotify_send(cli->tree, ¬ify);
139 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
141 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
142 CHECK_STATUS(status, NT_STATUS_OK);
143 CHECK_VAL(notify.nttrans.out.num_changes, 1);
144 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_REMOVED);
145 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
147 printf("Testing notify mkdir - rmdir - mkdir - rmdir\n");
149 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name");
150 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
151 smbcli_mkdir(cli2->tree, BASEDIR "\\subdir-name");
152 smbcli_rmdir(cli2->tree, BASEDIR "\\subdir-name");
154 req = smb_raw_changenotify_send(cli->tree, ¬ify);
155 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
156 CHECK_STATUS(status, NT_STATUS_OK);
157 CHECK_VAL(notify.nttrans.out.num_changes, 4);
158 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_ADDED);
159 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
160 CHECK_VAL(notify.nttrans.out.changes[1].action, NOTIFY_ACTION_REMOVED);
161 CHECK_WSTR(notify.nttrans.out.changes[1].name, "subdir-name", STR_UNICODE);
162 CHECK_VAL(notify.nttrans.out.changes[2].action, NOTIFY_ACTION_ADDED);
163 CHECK_WSTR(notify.nttrans.out.changes[2].name, "subdir-name", STR_UNICODE);
164 CHECK_VAL(notify.nttrans.out.changes[3].action, NOTIFY_ACTION_REMOVED);
165 CHECK_WSTR(notify.nttrans.out.changes[3].name, "subdir-name", STR_UNICODE);
167 count = torture_numops;
168 printf("Testing buffered notify on create of %d files\n", count);
169 for (i=0;i<count;i++) {
170 char *fname = talloc_asprintf(cli, BASEDIR "\\test%d.txt", i);
171 int fnum3 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
173 printf("Failed to create %s - %s\n",
174 fname, smbcli_errstr(cli->tree));
179 smbcli_close(cli->tree, fnum3);
182 /* (1st notify) setup a new notify on a different directory handle.
183 This new notify won't see the events above. */
184 notify.nttrans.in.file.fnum = fnum2;
185 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
187 /* (2nd notify) whereas this notify will see the above buffered events,
188 and it directly returns the buffered events */
189 notify.nttrans.in.file.fnum = fnum;
190 req = smb_raw_changenotify_send(cli->tree, ¬ify);
192 status = smbcli_unlink(cli->tree, BASEDIR "\\nonexistant.txt");
193 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
195 /* (1st unlink) as the 2nd notify directly returns,
196 this unlink is only seen by the 1st notify and
197 the 3rd notify (later) */
198 printf("Testing notify on unlink for the first file\n");
199 status = smbcli_unlink(cli2->tree, BASEDIR "\\test0.txt");
200 CHECK_STATUS(status, NT_STATUS_OK);
202 /* receive the reply from the 2nd notify */
203 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
204 CHECK_STATUS(status, NT_STATUS_OK);
206 CHECK_VAL(notify.nttrans.out.num_changes, count);
207 for (i=1;i<count;i++) {
208 CHECK_VAL(notify.nttrans.out.changes[i].action, NOTIFY_ACTION_ADDED);
210 CHECK_WSTR(notify.nttrans.out.changes[0].name, "test0.txt", STR_UNICODE);
212 printf("and now from the 1st notify\n");
213 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
214 CHECK_STATUS(status, NT_STATUS_OK);
215 CHECK_VAL(notify.nttrans.out.num_changes, 1);
216 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_REMOVED);
217 CHECK_WSTR(notify.nttrans.out.changes[0].name, "test0.txt", STR_UNICODE);
219 printf("(3rd notify) this notify will only see the 1st unlink\n");
220 req = smb_raw_changenotify_send(cli->tree, ¬ify);
222 status = smbcli_unlink(cli->tree, BASEDIR "\\nonexistant.txt");
223 CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
225 printf("Testing notify on wildcard unlink for %d files\n", count-1);
226 /* (2nd unlink) do a wildcard unlink */
227 status = smbcli_unlink(cli2->tree, BASEDIR "\\test*.txt");
228 CHECK_STATUS(status, NT_STATUS_OK);
230 /* receive the 3rd notify */
231 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
232 CHECK_STATUS(status, NT_STATUS_OK);
233 CHECK_VAL(notify.nttrans.out.num_changes, 1);
234 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_REMOVED);
235 CHECK_WSTR(notify.nttrans.out.changes[0].name, "test0.txt", STR_UNICODE);
237 /* and we now see the rest of the unlink calls on both directory handles */
238 notify.nttrans.in.file.fnum = fnum;
240 req = smb_raw_changenotify_send(cli->tree, ¬ify);
241 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
242 CHECK_STATUS(status, NT_STATUS_OK);
243 CHECK_VAL(notify.nttrans.out.num_changes, count-1);
244 for (i=0;i<notify.nttrans.out.num_changes;i++) {
245 CHECK_VAL(notify.nttrans.out.changes[i].action, NOTIFY_ACTION_REMOVED);
247 notify.nttrans.in.file.fnum = fnum2;
248 req = smb_raw_changenotify_send(cli->tree, ¬ify);
249 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
250 CHECK_STATUS(status, NT_STATUS_OK);
251 CHECK_VAL(notify.nttrans.out.num_changes, count-1);
252 for (i=0;i<notify.nttrans.out.num_changes;i++) {
253 CHECK_VAL(notify.nttrans.out.changes[i].action, NOTIFY_ACTION_REMOVED);
256 printf("Testing if a close() on the dir handle triggers the notify reply\n");
258 notify.nttrans.in.file.fnum = fnum;
259 req = smb_raw_changenotify_send(cli->tree, ¬ify);
261 cl.close.level = RAW_CLOSE_CLOSE;
262 cl.close.in.file.fnum = fnum;
263 cl.close.in.write_time = 0;
264 status = smb_raw_close(cli->tree, &cl);
265 CHECK_STATUS(status, NT_STATUS_OK);
267 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
268 CHECK_STATUS(status, NT_STATUS_OK);
269 CHECK_VAL(notify.nttrans.out.num_changes, 0);
272 smb_raw_exit(cli->session);
273 smbcli_deltree(cli->tree, BASEDIR);
278 * Check notify reply for a rename action. Not sure if this is a valid thing
279 * to do, but depending on timing between inotify and messaging we get the
280 * add/remove/modify in any order. This routines tries to find the action/name
281 * pair in any of the three following notify_changes.
284 static bool check_rename_reply(struct smbcli_state *cli,
286 struct notify_changes *actions,
287 uint32_t action, const char *name)
291 for (i=0; i<3; i++) {
292 if (actions[i].action == action) {
293 if ((actions[i].name.s == NULL)
294 || (strcmp(actions[i].name.s, name) != 0)
295 || (wire_bad_flags(&actions[i].name, STR_UNICODE,
297 printf("(%d) name [%s] != %s\n", line,
298 actions[i].name.s, name);
305 printf("(%d) expected action %d, not found\n", line, action);
310 testing of recursive change notify
312 static bool test_notify_recursive(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
316 union smb_notify notify;
319 struct smbcli_request *req1, *req2;
321 printf("TESTING CHANGE NOTIFY WITH RECURSION\n");
324 get a handle on the directory
326 io.generic.level = RAW_OPEN_NTCREATEX;
327 io.ntcreatex.in.root_fid.fnum = 0;
328 io.ntcreatex.in.flags = 0;
329 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
330 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
331 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
332 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
333 io.ntcreatex.in.alloc_size = 0;
334 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
335 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
336 io.ntcreatex.in.security_flags = 0;
337 io.ntcreatex.in.fname = BASEDIR;
339 status = smb_raw_open(cli->tree, mem_ctx, &io);
340 CHECK_STATUS(status, NT_STATUS_OK);
341 fnum = io.ntcreatex.out.file.fnum;
343 /* ask for a change notify, on file or directory name
344 changes. Setup both with and without recursion */
345 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
346 notify.nttrans.in.buffer_size = 1000;
347 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
348 notify.nttrans.in.file.fnum = fnum;
350 notify.nttrans.in.recursive = true;
351 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
353 notify.nttrans.in.recursive = false;
354 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
356 /* cancel initial requests so the buffer is setup */
357 smb_raw_ntcancel(req1);
358 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
359 CHECK_STATUS(status, NT_STATUS_CANCELLED);
361 smb_raw_ntcancel(req2);
362 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
363 CHECK_STATUS(status, NT_STATUS_CANCELLED);
365 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
366 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name\\subname1");
367 smbcli_close(cli->tree,
368 smbcli_open(cli->tree, BASEDIR "\\subdir-name\\subname2", O_CREAT, 0));
369 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname1", BASEDIR "\\subdir-name\\subname1-r");
370 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname2", BASEDIR "\\subname2-r");
371 smbcli_rename(cli->tree, BASEDIR "\\subname2-r", BASEDIR "\\subname3-r");
373 notify.nttrans.in.completion_filter = 0;
374 notify.nttrans.in.recursive = true;
376 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
378 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name\\subname1-r");
379 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
380 smbcli_unlink(cli->tree, BASEDIR "\\subname3-r");
382 notify.nttrans.in.recursive = false;
383 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
385 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
386 CHECK_STATUS(status, NT_STATUS_OK);
388 CHECK_VAL(notify.nttrans.out.num_changes, 11);
389 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_ADDED);
390 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
391 CHECK_VAL(notify.nttrans.out.changes[1].action, NOTIFY_ACTION_ADDED);
392 CHECK_WSTR(notify.nttrans.out.changes[1].name, "subdir-name\\subname1", STR_UNICODE);
393 CHECK_VAL(notify.nttrans.out.changes[2].action, NOTIFY_ACTION_ADDED);
394 CHECK_WSTR(notify.nttrans.out.changes[2].name, "subdir-name\\subname2", STR_UNICODE);
395 CHECK_VAL(notify.nttrans.out.changes[3].action, NOTIFY_ACTION_OLD_NAME);
396 CHECK_WSTR(notify.nttrans.out.changes[3].name, "subdir-name\\subname1", STR_UNICODE);
397 CHECK_VAL(notify.nttrans.out.changes[4].action, NOTIFY_ACTION_NEW_NAME);
398 CHECK_WSTR(notify.nttrans.out.changes[4].name, "subdir-name\\subname1-r", STR_UNICODE);
400 ret &= check_rename_reply(
401 cli, __LINE__, ¬ify.nttrans.out.changes[5],
402 NOTIFY_ACTION_ADDED, "subname2-r");
403 ret &= check_rename_reply(
404 cli, __LINE__, ¬ify.nttrans.out.changes[5],
405 NOTIFY_ACTION_REMOVED, "subdir-name\\subname2");
406 ret &= check_rename_reply(
407 cli, __LINE__, ¬ify.nttrans.out.changes[5],
408 NOTIFY_ACTION_MODIFIED, "subname2-r");
410 ret &= check_rename_reply(
411 cli, __LINE__, ¬ify.nttrans.out.changes[8],
412 NOTIFY_ACTION_OLD_NAME, "subname2-r");
413 ret &= check_rename_reply(
414 cli, __LINE__, ¬ify.nttrans.out.changes[8],
415 NOTIFY_ACTION_NEW_NAME, "subname3-r");
416 ret &= check_rename_reply(
417 cli, __LINE__, ¬ify.nttrans.out.changes[8],
418 NOTIFY_ACTION_MODIFIED, "subname3-r");
424 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
425 CHECK_STATUS(status, NT_STATUS_OK);
427 CHECK_VAL(notify.nttrans.out.num_changes, 3);
428 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_REMOVED);
429 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name\\subname1-r", STR_UNICODE);
430 CHECK_VAL(notify.nttrans.out.changes[1].action, NOTIFY_ACTION_REMOVED);
431 CHECK_WSTR(notify.nttrans.out.changes[1].name, "subdir-name", STR_UNICODE);
432 CHECK_VAL(notify.nttrans.out.changes[2].action, NOTIFY_ACTION_REMOVED);
433 CHECK_WSTR(notify.nttrans.out.changes[2].name, "subname3-r", STR_UNICODE);
436 smb_raw_exit(cli->session);
441 testing of change notify mask change
443 static bool test_notify_mask_change(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
447 union smb_notify notify;
450 struct smbcli_request *req1, *req2;
452 printf("TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
455 get a handle on the directory
457 io.generic.level = RAW_OPEN_NTCREATEX;
458 io.ntcreatex.in.root_fid.fnum = 0;
459 io.ntcreatex.in.flags = 0;
460 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
461 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
462 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
463 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
464 io.ntcreatex.in.alloc_size = 0;
465 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
466 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
467 io.ntcreatex.in.security_flags = 0;
468 io.ntcreatex.in.fname = BASEDIR;
470 status = smb_raw_open(cli->tree, mem_ctx, &io);
471 CHECK_STATUS(status, NT_STATUS_OK);
472 fnum = io.ntcreatex.out.file.fnum;
474 /* ask for a change notify, on file or directory name
475 changes. Setup both with and without recursion */
476 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
477 notify.nttrans.in.buffer_size = 1000;
478 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
479 notify.nttrans.in.file.fnum = fnum;
481 notify.nttrans.in.recursive = true;
482 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
484 notify.nttrans.in.recursive = false;
485 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
487 /* cancel initial requests so the buffer is setup */
488 smb_raw_ntcancel(req1);
489 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
490 CHECK_STATUS(status, NT_STATUS_CANCELLED);
492 smb_raw_ntcancel(req2);
493 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
494 CHECK_STATUS(status, NT_STATUS_CANCELLED);
496 notify.nttrans.in.recursive = true;
497 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
499 /* Set to hidden then back again. */
500 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));
501 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);
502 smbcli_unlink(cli->tree, BASEDIR "\\tname1");
504 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
505 CHECK_STATUS(status, NT_STATUS_OK);
507 CHECK_VAL(notify.nttrans.out.num_changes, 1);
508 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
509 CHECK_WSTR(notify.nttrans.out.changes[0].name, "tname1", STR_UNICODE);
511 /* Now try and change the mask to include other events.
512 * This should not work - once the mask is set on a directory
513 * fnum it seems to be fixed until the fnum is closed. */
515 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
516 notify.nttrans.in.recursive = true;
517 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
519 notify.nttrans.in.recursive = false;
520 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
522 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
523 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name\\subname1");
524 smbcli_close(cli->tree,
525 smbcli_open(cli->tree, BASEDIR "\\subdir-name\\subname2", O_CREAT, 0));
526 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname1", BASEDIR "\\subdir-name\\subname1-r");
527 smbcli_rename(cli->tree, BASEDIR "\\subdir-name\\subname2", BASEDIR "\\subname2-r");
528 smbcli_rename(cli->tree, BASEDIR "\\subname2-r", BASEDIR "\\subname3-r");
530 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name\\subname1-r");
531 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
532 smbcli_unlink(cli->tree, BASEDIR "\\subname3-r");
534 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
535 CHECK_STATUS(status, NT_STATUS_OK);
537 CHECK_VAL(notify.nttrans.out.num_changes, 1);
538 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
539 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subname2-r", STR_UNICODE);
541 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
542 CHECK_STATUS(status, NT_STATUS_OK);
544 CHECK_VAL(notify.nttrans.out.num_changes, 1);
545 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
546 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subname3-r", STR_UNICODE);
553 smb_raw_exit(cli->session);
559 testing of mask bits for change notify
561 static bool test_notify_mask(struct smbcli_state *cli, struct torture_context *tctx)
565 union smb_notify notify;
574 printf("TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
576 tv = timeval_current_ofs(1000, 0);
577 t = timeval_to_nttime(&tv);
580 get a handle on the directory
582 io.generic.level = RAW_OPEN_NTCREATEX;
583 io.ntcreatex.in.root_fid.fnum = 0;
584 io.ntcreatex.in.flags = 0;
585 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
586 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
587 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
588 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
589 io.ntcreatex.in.alloc_size = 0;
590 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
591 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
592 io.ntcreatex.in.security_flags = 0;
593 io.ntcreatex.in.fname = BASEDIR;
595 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
596 notify.nttrans.in.buffer_size = 1000;
597 notify.nttrans.in.recursive = true;
599 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, expected, nchanges) \
601 smbcli_getatr(cli->tree, test_name, NULL, NULL, NULL); \
602 do { for (mask=i=0;i<32;i++) { \
603 struct smbcli_request *req; \
604 status = smb_raw_open(cli->tree, tctx, &io); \
605 CHECK_STATUS(status, NT_STATUS_OK); \
606 fnum = io.ntcreatex.out.file.fnum; \
608 notify.nttrans.in.file.fnum = fnum; \
609 notify.nttrans.in.completion_filter = (1<<i); \
610 req = smb_raw_changenotify_send(cli->tree, ¬ify); \
612 smb_msleep(200); smb_raw_ntcancel(req); \
613 status = smb_raw_changenotify_recv(req, tctx, ¬ify); \
615 smbcli_close(cli->tree, fnum); \
616 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
617 CHECK_STATUS(status, NT_STATUS_OK); \
618 /* special case to cope with file rename behaviour */ \
619 if (nchanges == 2 && notify.nttrans.out.num_changes == 1 && \
620 notify.nttrans.out.changes[0].action == NOTIFY_ACTION_MODIFIED && \
621 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
622 Action == NOTIFY_ACTION_OLD_NAME) { \
623 printf("(rename file special handling OK)\n"); \
624 } else if (nchanges != notify.nttrans.out.num_changes) { \
625 printf("ERROR: nchanges=%d expected=%d action=%d filter=0x%08x\n", \
626 notify.nttrans.out.num_changes, \
628 notify.nttrans.out.changes[0].action, \
629 notify.nttrans.in.completion_filter); \
631 } else if (notify.nttrans.out.changes[0].action != Action) { \
632 printf("ERROR: nchanges=%d action=%d expectedAction=%d filter=0x%08x\n", \
633 notify.nttrans.out.num_changes, \
634 notify.nttrans.out.changes[0].action, \
636 notify.nttrans.in.completion_filter); \
638 } else if (strcmp(notify.nttrans.out.changes[0].name.s, "tname1") != 0) { \
639 printf("ERROR: nchanges=%d action=%d filter=0x%08x name=%s\n", \
640 notify.nttrans.out.num_changes, \
641 notify.nttrans.out.changes[0].action, \
642 notify.nttrans.in.completion_filter, \
643 notify.nttrans.out.changes[0].name.s); \
648 if ((expected) != mask) { \
649 if (((expected) & ~mask) != 0) { \
650 printf("ERROR: trigger on too few bits. mask=0x%08x expected=0x%08x\n", \
654 printf("WARNING: trigger on too many bits. mask=0x%08x expected=0x%08x\n", \
661 printf("Testing mkdir\n");
662 NOTIFY_MASK_TEST("Testing mkdir",;,
663 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
664 smbcli_rmdir(cli->tree, BASEDIR "\\tname1");,
666 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
668 printf("Testing create file\n");
669 NOTIFY_MASK_TEST("Testing create file",;,
670 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
671 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
673 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
675 printf("Testing unlink\n");
676 NOTIFY_MASK_TEST("Testing unlink",
677 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
678 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
680 NOTIFY_ACTION_REMOVED,
681 FILE_NOTIFY_CHANGE_FILE_NAME, 1);
683 printf("Testing rmdir\n");
684 NOTIFY_MASK_TEST("Testing rmdir",
685 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
686 smbcli_rmdir(cli->tree, BASEDIR "\\tname1");,
688 NOTIFY_ACTION_REMOVED,
689 FILE_NOTIFY_CHANGE_DIR_NAME, 1);
691 printf("Testing rename file\n");
692 NOTIFY_MASK_TEST("Testing rename file",
693 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
694 smbcli_rename(cli->tree, BASEDIR "\\tname1", BASEDIR "\\tname2");,
695 smbcli_unlink(cli->tree, BASEDIR "\\tname2");,
696 NOTIFY_ACTION_OLD_NAME,
697 FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_CREATION, 2);
699 printf("Testing rename dir\n");
700 NOTIFY_MASK_TEST("Testing rename dir",
701 smbcli_mkdir(cli->tree, BASEDIR "\\tname1");,
702 smbcli_rename(cli->tree, BASEDIR "\\tname1", BASEDIR "\\tname2");,
703 smbcli_rmdir(cli->tree, BASEDIR "\\tname2");,
704 NOTIFY_ACTION_OLD_NAME,
705 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
707 printf("Testing set path attribute\n");
708 NOTIFY_MASK_TEST("Testing set path attribute",
709 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
710 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);,
711 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
712 NOTIFY_ACTION_MODIFIED,
713 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
715 printf("Testing set path write time\n");
716 NOTIFY_MASK_TEST("Testing set path write time",
717 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1", O_CREAT, 0));,
718 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_NORMAL, 1000);,
719 smbcli_unlink(cli->tree, BASEDIR "\\tname1");,
720 NOTIFY_ACTION_MODIFIED,
721 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
723 printf("Testing set file attribute\n");
724 NOTIFY_MASK_TEST("Testing set file attribute",
725 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
726 smbcli_fsetatr(cli->tree, fnum2, FILE_ATTRIBUTE_HIDDEN, 0, 0, 0, 0);,
727 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
728 NOTIFY_ACTION_MODIFIED,
729 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
731 if (torture_setting_bool(tctx, "samba3", false)) {
732 printf("Samba3 does not yet support create times "
736 printf("Testing set file create time\n");
737 NOTIFY_MASK_TEST("Testing set file create time",
738 fnum2 = create_complex_file(cli, tctx,
739 BASEDIR "\\tname1");,
740 smbcli_fsetatr(cli->tree, fnum2, 0, t, 0, 0, 0);,
741 (smbcli_close(cli->tree, fnum2),
742 smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
743 NOTIFY_ACTION_MODIFIED,
744 FILE_NOTIFY_CHANGE_CREATION, 1);
747 printf("Testing set file access time\n");
748 NOTIFY_MASK_TEST("Testing set file access time",
749 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
750 smbcli_fsetatr(cli->tree, fnum2, 0, 0, t, 0, 0);,
751 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
752 NOTIFY_ACTION_MODIFIED,
753 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
755 printf("Testing set file write time\n");
756 NOTIFY_MASK_TEST("Testing set file write time",
757 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
758 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, t, 0);,
759 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
760 NOTIFY_ACTION_MODIFIED,
761 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
763 printf("Testing set file change time\n");
764 NOTIFY_MASK_TEST("Testing set file change time",
765 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
766 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, 0, t);,
767 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
768 NOTIFY_ACTION_MODIFIED,
772 printf("Testing write\n");
773 NOTIFY_MASK_TEST("Testing write",
774 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
775 smbcli_write(cli->tree, fnum2, 1, &c, 10000, 1);,
776 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
777 NOTIFY_ACTION_MODIFIED,
780 printf("Testing truncate\n");
781 NOTIFY_MASK_TEST("Testing truncate",
782 fnum2 = create_complex_file(cli, tctx, BASEDIR "\\tname1");,
783 smbcli_ftruncate(cli->tree, fnum2, 10000);,
784 (smbcli_close(cli->tree, fnum2), smbcli_unlink(cli->tree, BASEDIR "\\tname1"));,
785 NOTIFY_ACTION_MODIFIED,
786 FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
789 smb_raw_exit(cli->session);
794 basic testing of change notify on files
796 static bool test_notify_file(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
802 union smb_notify notify;
803 struct smbcli_request *req;
805 const char *fname = BASEDIR "\\file.txt";
807 printf("TESTING CHANGE NOTIFY ON FILES\n");
809 io.generic.level = RAW_OPEN_NTCREATEX;
810 io.ntcreatex.in.root_fid.fnum = 0;
811 io.ntcreatex.in.flags = 0;
812 io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
813 io.ntcreatex.in.create_options = 0;
814 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
815 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
816 io.ntcreatex.in.alloc_size = 0;
817 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
818 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
819 io.ntcreatex.in.security_flags = 0;
820 io.ntcreatex.in.fname = fname;
821 status = smb_raw_open(cli->tree, mem_ctx, &io);
822 CHECK_STATUS(status, NT_STATUS_OK);
823 fnum = io.ntcreatex.out.file.fnum;
825 /* ask for a change notify,
826 on file or directory name changes */
827 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
828 notify.nttrans.in.file.fnum = fnum;
829 notify.nttrans.in.buffer_size = 1000;
830 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
831 notify.nttrans.in.recursive = false;
833 printf("Testing if notifies on file handles are invalid (should be)\n");
835 req = smb_raw_changenotify_send(cli->tree, ¬ify);
836 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
837 CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER);
839 cl.close.level = RAW_CLOSE_CLOSE;
840 cl.close.in.file.fnum = fnum;
841 cl.close.in.write_time = 0;
842 status = smb_raw_close(cli->tree, &cl);
843 CHECK_STATUS(status, NT_STATUS_OK);
845 status = smbcli_unlink(cli->tree, fname);
846 CHECK_STATUS(status, NT_STATUS_OK);
849 smb_raw_exit(cli->session);
854 basic testing of change notifies followed by a tdis
856 static bool test_notify_tdis(struct torture_context *tctx)
860 union smb_notify notify;
863 struct smbcli_request *req;
864 struct smbcli_state *cli = NULL;
866 printf("TESTING CHANGE NOTIFY FOLLOWED BY TDIS\n");
868 if (!torture_open_connection(&cli, tctx, 0)) {
873 get a handle on the directory
875 io.generic.level = RAW_OPEN_NTCREATEX;
876 io.ntcreatex.in.root_fid.fnum = 0;
877 io.ntcreatex.in.flags = 0;
878 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
879 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
880 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
881 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
882 io.ntcreatex.in.alloc_size = 0;
883 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
884 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
885 io.ntcreatex.in.security_flags = 0;
886 io.ntcreatex.in.fname = BASEDIR;
888 status = smb_raw_open(cli->tree, tctx, &io);
889 CHECK_STATUS(status, NT_STATUS_OK);
890 fnum = io.ntcreatex.out.file.fnum;
892 /* ask for a change notify,
893 on file or directory name changes */
894 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
895 notify.nttrans.in.buffer_size = 1000;
896 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
897 notify.nttrans.in.file.fnum = fnum;
898 notify.nttrans.in.recursive = true;
900 req = smb_raw_changenotify_send(cli->tree, ¬ify);
902 status = smbcli_tdis(cli);
903 CHECK_STATUS(status, NT_STATUS_OK);
906 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
907 CHECK_STATUS(status, NT_STATUS_OK);
908 CHECK_VAL(notify.nttrans.out.num_changes, 0);
911 torture_close_connection(cli);
916 basic testing of change notifies followed by a exit
918 static bool test_notify_exit(struct torture_context *tctx)
922 union smb_notify notify;
925 struct smbcli_request *req;
926 struct smbcli_state *cli = NULL;
928 printf("TESTING CHANGE NOTIFY FOLLOWED BY EXIT\n");
930 if (!torture_open_connection(&cli, tctx, 0)) {
935 get a handle on the directory
937 io.generic.level = RAW_OPEN_NTCREATEX;
938 io.ntcreatex.in.root_fid.fnum = 0;
939 io.ntcreatex.in.flags = 0;
940 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
941 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
942 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
943 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
944 io.ntcreatex.in.alloc_size = 0;
945 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
946 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
947 io.ntcreatex.in.security_flags = 0;
948 io.ntcreatex.in.fname = BASEDIR;
950 status = smb_raw_open(cli->tree, tctx, &io);
951 CHECK_STATUS(status, NT_STATUS_OK);
952 fnum = io.ntcreatex.out.file.fnum;
954 /* ask for a change notify,
955 on file or directory name changes */
956 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
957 notify.nttrans.in.buffer_size = 1000;
958 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
959 notify.nttrans.in.file.fnum = fnum;
960 notify.nttrans.in.recursive = true;
962 req = smb_raw_changenotify_send(cli->tree, ¬ify);
964 status = smb_raw_exit(cli->session);
965 CHECK_STATUS(status, NT_STATUS_OK);
967 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
968 CHECK_STATUS(status, NT_STATUS_OK);
969 CHECK_VAL(notify.nttrans.out.num_changes, 0);
972 torture_close_connection(cli);
977 basic testing of change notifies followed by a ulogoff
979 static bool test_notify_ulogoff(struct torture_context *tctx)
983 union smb_notify notify;
986 struct smbcli_request *req;
987 struct smbcli_state *cli = NULL;
989 printf("TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
991 if (!torture_open_connection(&cli, tctx, 0)) {
996 get a handle on the directory
998 io.generic.level = RAW_OPEN_NTCREATEX;
999 io.ntcreatex.in.root_fid.fnum = 0;
1000 io.ntcreatex.in.flags = 0;
1001 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1002 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1003 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1004 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1005 io.ntcreatex.in.alloc_size = 0;
1006 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1007 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1008 io.ntcreatex.in.security_flags = 0;
1009 io.ntcreatex.in.fname = BASEDIR;
1011 status = smb_raw_open(cli->tree, tctx, &io);
1012 CHECK_STATUS(status, NT_STATUS_OK);
1013 fnum = io.ntcreatex.out.file.fnum;
1015 /* ask for a change notify,
1016 on file or directory name changes */
1017 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1018 notify.nttrans.in.buffer_size = 1000;
1019 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1020 notify.nttrans.in.file.fnum = fnum;
1021 notify.nttrans.in.recursive = true;
1023 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1025 status = smb_raw_ulogoff(cli->session);
1026 CHECK_STATUS(status, NT_STATUS_OK);
1028 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1029 CHECK_STATUS(status, NT_STATUS_OK);
1030 CHECK_VAL(notify.nttrans.out.num_changes, 0);
1033 torture_close_connection(cli);
1037 static void tcp_dis_handler(struct smbcli_transport *t, void *p)
1039 struct smbcli_state *cli = (struct smbcli_state *)p;
1040 smbcli_transport_dead(cli->transport, NT_STATUS_LOCAL_DISCONNECT);
1041 cli->transport = NULL;
1045 basic testing of change notifies followed by tcp disconnect
1047 static bool test_notify_tcp_dis(struct torture_context *tctx)
1051 union smb_notify notify;
1054 struct smbcli_request *req;
1055 struct smbcli_state *cli = NULL;
1057 printf("TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1059 if (!torture_open_connection(&cli, tctx, 0)) {
1064 get a handle on the directory
1066 io.generic.level = RAW_OPEN_NTCREATEX;
1067 io.ntcreatex.in.root_fid.fnum = 0;
1068 io.ntcreatex.in.flags = 0;
1069 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1070 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1071 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1072 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1073 io.ntcreatex.in.alloc_size = 0;
1074 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1075 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1076 io.ntcreatex.in.security_flags = 0;
1077 io.ntcreatex.in.fname = BASEDIR;
1079 status = smb_raw_open(cli->tree, tctx, &io);
1080 CHECK_STATUS(status, NT_STATUS_OK);
1081 fnum = io.ntcreatex.out.file.fnum;
1083 /* ask for a change notify,
1084 on file or directory name changes */
1085 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1086 notify.nttrans.in.buffer_size = 1000;
1087 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1088 notify.nttrans.in.file.fnum = fnum;
1089 notify.nttrans.in.recursive = true;
1091 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1093 smbcli_transport_idle_handler(cli->transport, tcp_dis_handler, 250, cli);
1095 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1096 CHECK_STATUS(status, NT_STATUS_LOCAL_DISCONNECT);
1099 torture_close_connection(cli);
1104 test setting up two change notify requests on one handle
1106 static bool test_notify_double(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
1110 union smb_notify notify;
1113 struct smbcli_request *req1, *req2;
1115 printf("TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1118 get a handle on the directory
1120 io.generic.level = RAW_OPEN_NTCREATEX;
1121 io.ntcreatex.in.root_fid.fnum = 0;
1122 io.ntcreatex.in.flags = 0;
1123 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1124 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1125 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1126 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1127 io.ntcreatex.in.alloc_size = 0;
1128 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1129 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1130 io.ntcreatex.in.security_flags = 0;
1131 io.ntcreatex.in.fname = BASEDIR;
1133 status = smb_raw_open(cli->tree, mem_ctx, &io);
1134 CHECK_STATUS(status, NT_STATUS_OK);
1135 fnum = io.ntcreatex.out.file.fnum;
1137 /* ask for a change notify,
1138 on file or directory name changes */
1139 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1140 notify.nttrans.in.buffer_size = 1000;
1141 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1142 notify.nttrans.in.file.fnum = fnum;
1143 notify.nttrans.in.recursive = true;
1145 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1146 req2 = smb_raw_changenotify_send(cli->tree, ¬ify);
1148 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1150 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
1151 CHECK_STATUS(status, NT_STATUS_OK);
1152 CHECK_VAL(notify.nttrans.out.num_changes, 1);
1153 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
1155 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name2");
1157 status = smb_raw_changenotify_recv(req2, mem_ctx, ¬ify);
1158 CHECK_STATUS(status, NT_STATUS_OK);
1159 CHECK_VAL(notify.nttrans.out.num_changes, 1);
1160 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name2", STR_UNICODE);
1163 smb_raw_exit(cli->session);
1169 test multiple change notifies at different depths and with/without recursion
1171 static bool test_notify_tree(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
1174 union smb_notify notify;
1176 struct smbcli_request *req;
1186 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 30 },
1187 {BASEDIR "\\zqy", true, FILE_NOTIFY_CHANGE_NAME, 8 },
1188 {BASEDIR "\\atsy", true, FILE_NOTIFY_CHANGE_NAME, 4 },
1189 {BASEDIR "\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1190 {BASEDIR "\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME, 13 },
1191 {BASEDIR "\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME, 7 },
1192 {BASEDIR "\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1193 {BASEDIR "\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1194 {BASEDIR "\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1195 {BASEDIR "\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1196 {BASEDIR "\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1197 {BASEDIR "\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME, 2 },
1198 {BASEDIR "\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME, 40 },
1199 {BASEDIR, true, FILE_NOTIFY_CHANGE_NAME, 40 },
1200 {BASEDIR, false,FILE_NOTIFY_CHANGE_NAME, 6 },
1201 {BASEDIR "\\atsy", false,FILE_NOTIFY_CHANGE_NAME, 4 },
1202 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1203 {BASEDIR "\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1204 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1205 {BASEDIR "\\abc", true, FILE_NOTIFY_CHANGE_NAME, 24 },
1209 bool all_done = false;
1211 printf("TESTING CHANGE NOTIFY FOR DIFFERENT DEPTHS\n");
1213 io.generic.level = RAW_OPEN_NTCREATEX;
1214 io.ntcreatex.in.root_fid.fnum = 0;
1215 io.ntcreatex.in.flags = 0;
1216 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1217 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1218 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1219 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1220 io.ntcreatex.in.alloc_size = 0;
1221 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1222 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1223 io.ntcreatex.in.security_flags = 0;
1225 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1226 notify.nttrans.in.buffer_size = 20000;
1229 setup the directory tree, and the notify buffer on each directory
1231 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1232 io.ntcreatex.in.fname = dirs[i].path;
1233 status = smb_raw_open(cli->tree, mem_ctx, &io);
1234 CHECK_STATUS(status, NT_STATUS_OK);
1235 dirs[i].fnum = io.ntcreatex.out.file.fnum;
1237 notify.nttrans.in.completion_filter = dirs[i].filter;
1238 notify.nttrans.in.file.fnum = dirs[i].fnum;
1239 notify.nttrans.in.recursive = dirs[i].recursive;
1240 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1241 smb_raw_ntcancel(req);
1242 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
1243 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1246 /* trigger 2 events in each dir */
1247 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1248 char *path = talloc_asprintf(mem_ctx, "%s\\test.dir", dirs[i].path);
1249 smbcli_mkdir(cli->tree, path);
1250 smbcli_rmdir(cli->tree, path);
1254 /* give a bit of time for the events to propogate */
1255 tv = timeval_current();
1258 /* count events that have happened in each dir */
1259 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1260 notify.nttrans.in.file.fnum = dirs[i].fnum;
1261 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1262 smb_raw_ntcancel(req);
1263 notify.nttrans.out.num_changes = 0;
1264 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify);
1265 dirs[i].counted += notify.nttrans.out.num_changes;
1270 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1271 if (dirs[i].counted != dirs[i].expected) {
1275 } while (!all_done && timeval_elapsed(&tv) < 20);
1277 printf("took %.4f seconds to propogate all events\n", timeval_elapsed(&tv));
1279 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1280 if (dirs[i].counted != dirs[i].expected) {
1281 printf("ERROR: i=%d expected %d got %d for '%s'\n",
1282 i, dirs[i].expected, dirs[i].counted, dirs[i].path);
1288 run from the back, closing and deleting
1290 for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1291 smbcli_close(cli->tree, dirs[i].fnum);
1292 smbcli_rmdir(cli->tree, dirs[i].path);
1296 smb_raw_exit(cli->session);
1301 Test response when cached server events exceed single NT NOTFIY response
1304 static bool test_notify_overflow(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
1308 union smb_notify notify;
1312 struct smbcli_request *req1;
1315 printf("TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1317 /* get a handle on the directory */
1318 io.generic.level = RAW_OPEN_NTCREATEX;
1319 io.ntcreatex.in.root_fid.fnum = 0;
1320 io.ntcreatex.in.flags = 0;
1321 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1322 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1323 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1324 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1325 NTCREATEX_SHARE_ACCESS_WRITE;
1326 io.ntcreatex.in.alloc_size = 0;
1327 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1328 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1329 io.ntcreatex.in.security_flags = 0;
1330 io.ntcreatex.in.fname = BASEDIR;
1332 status = smb_raw_open(cli->tree, mem_ctx, &io);
1333 CHECK_STATUS(status, NT_STATUS_OK);
1334 fnum = io.ntcreatex.out.file.fnum;
1336 /* ask for a change notify, on name changes. */
1337 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1338 notify.nttrans.in.buffer_size = 1000;
1339 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1340 notify.nttrans.in.file.fnum = fnum;
1342 notify.nttrans.in.recursive = true;
1343 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1345 /* cancel initial requests so the buffer is setup */
1346 smb_raw_ntcancel(req1);
1347 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
1348 CHECK_STATUS(status, NT_STATUS_CANCELLED);
1350 /* open a lot of files, filling up the server side notify buffer */
1351 printf("Testing overflowed buffer notify on create of %d files\n",
1353 for (i=0;i<count;i++) {
1354 char *fname = talloc_asprintf(cli, BASEDIR "\\test%d.txt", i);
1355 int fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR,
1358 printf("Failed to create %s - %s\n",
1359 fname, smbcli_errstr(cli->tree));
1364 smbcli_close(cli->tree, fnum2);
1367 /* expect that 0 events will be returned with NT_STATUS_OK */
1368 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1369 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
1370 CHECK_STATUS(status, NT_STATUS_OK);
1371 CHECK_VAL(notify.nttrans.out.num_changes, 0);
1374 smb_raw_exit(cli->session);
1379 Test if notifications are returned for changes to the base directory.
1382 static bool test_notify_basedir(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
1386 union smb_notify notify;
1389 struct smbcli_request *req1;
1391 printf("TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1393 /* get a handle on the directory */
1394 io.generic.level = RAW_OPEN_NTCREATEX;
1395 io.ntcreatex.in.root_fid.fnum = 0;
1396 io.ntcreatex.in.flags = 0;
1397 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1398 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1399 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1400 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1401 NTCREATEX_SHARE_ACCESS_WRITE;
1402 io.ntcreatex.in.alloc_size = 0;
1403 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1404 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1405 io.ntcreatex.in.security_flags = 0;
1406 io.ntcreatex.in.fname = BASEDIR;
1408 status = smb_raw_open(cli->tree, mem_ctx, &io);
1409 CHECK_STATUS(status, NT_STATUS_OK);
1410 fnum = io.ntcreatex.out.file.fnum;
1412 /* create a test file that will also be modified */
1413 smbcli_close(cli->tree, smbcli_open(cli->tree, BASEDIR "\\tname1",
1416 /* ask for a change notify, on attribute changes. */
1417 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1418 notify.nttrans.in.buffer_size = 1000;
1419 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
1420 notify.nttrans.in.file.fnum = fnum;
1421 notify.nttrans.in.recursive = true;
1423 req1 = smb_raw_changenotify_send(cli->tree, ¬ify);
1425 /* set attribute on the base dir */
1426 smbcli_setatr(cli->tree, BASEDIR, FILE_ATTRIBUTE_HIDDEN, 0);
1428 /* set attribute on a file to assure we receive a notification */
1429 smbcli_setatr(cli->tree, BASEDIR "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);
1432 /* check how many responses were given, expect only 1 for the file */
1433 status = smb_raw_changenotify_recv(req1, mem_ctx, ¬ify);
1434 CHECK_STATUS(status, NT_STATUS_OK);
1435 CHECK_VAL(notify.nttrans.out.num_changes, 1);
1436 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_MODIFIED);
1437 CHECK_WSTR(notify.nttrans.out.changes[0].name, "tname1", STR_UNICODE);
1440 smb_raw_exit(cli->session);
1446 create a secondary tree connect - used to test for a bug in Samba3 messaging
1449 static struct smbcli_tree *secondary_tcon(struct smbcli_state *cli,
1450 struct torture_context *tctx)
1453 const char *share, *host;
1454 struct smbcli_tree *tree;
1455 union smb_tcon tcon;
1457 share = torture_setting_string(tctx, "share", NULL);
1458 host = torture_setting_string(tctx, "host", NULL);
1460 printf("create a second tree context on the same session\n");
1461 tree = smbcli_tree_init(cli->session, tctx, false);
1463 tcon.generic.level = RAW_TCON_TCONX;
1464 tcon.tconx.in.flags = 0;
1465 tcon.tconx.in.password = data_blob(NULL, 0);
1466 tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
1467 tcon.tconx.in.device = "A:";
1468 status = smb_raw_tcon(tree, tctx, &tcon);
1469 if (!NT_STATUS_IS_OK(status)) {
1471 printf("Failed to create secondary tree\n");
1475 tree->tid = tcon.tconx.out.tid;
1476 printf("tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
1483 very simple change notify test
1485 static bool test_notify_tcon(struct torture_context *torture,
1486 struct smbcli_state *cli)
1490 union smb_notify notify;
1493 struct smbcli_request *req;
1494 extern int torture_numops;
1495 struct smbcli_tree *tree = NULL;
1497 printf("TESTING SIMPLE CHANGE NOTIFY\n");
1499 if (!torture_setup_dir(cli, BASEDIR)) {
1504 get a handle on the directory
1506 io.generic.level = RAW_OPEN_NTCREATEX;
1507 io.ntcreatex.in.root_fid.fnum = 0;
1508 io.ntcreatex.in.flags = 0;
1509 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1510 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1511 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1512 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1513 io.ntcreatex.in.alloc_size = 0;
1514 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1515 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1516 io.ntcreatex.in.security_flags = 0;
1517 io.ntcreatex.in.fname = BASEDIR;
1519 status = smb_raw_open(cli->tree, torture, &io);
1520 CHECK_STATUS(status, NT_STATUS_OK);
1521 fnum = io.ntcreatex.out.file.fnum;
1523 status = smb_raw_open(cli->tree, torture, &io);
1524 CHECK_STATUS(status, NT_STATUS_OK);
1526 /* ask for a change notify,
1527 on file or directory name changes */
1528 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1529 notify.nttrans.in.buffer_size = 1000;
1530 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1531 notify.nttrans.in.file.fnum = fnum;
1532 notify.nttrans.in.recursive = true;
1534 printf("Testing notify mkdir\n");
1535 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1536 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1538 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1539 CHECK_STATUS(status, NT_STATUS_OK);
1541 CHECK_VAL(notify.nttrans.out.num_changes, 1);
1542 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_ADDED);
1543 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
1545 printf("Testing notify rmdir\n");
1546 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1547 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
1549 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1550 CHECK_STATUS(status, NT_STATUS_OK);
1551 CHECK_VAL(notify.nttrans.out.num_changes, 1);
1552 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1553 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
1555 printf("SIMPLE CHANGE NOTIFY OK\n");
1557 printf("TESTING WITH SECONDARY TCON\n");
1558 tree = secondary_tcon(cli, torture);
1560 printf("Testing notify mkdir\n");
1561 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1562 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1564 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1565 CHECK_STATUS(status, NT_STATUS_OK);
1567 CHECK_VAL(notify.nttrans.out.num_changes, 1);
1568 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_ADDED);
1569 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
1571 printf("Testing notify rmdir\n");
1572 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1573 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
1575 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1576 CHECK_STATUS(status, NT_STATUS_OK);
1577 CHECK_VAL(notify.nttrans.out.num_changes, 1);
1578 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1579 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
1581 printf("CHANGE NOTIFY WITH TCON OK\n");
1583 printf("Disconnecting secondary tree\n");
1584 status = smb_tree_disconnect(tree);
1585 CHECK_STATUS(status, NT_STATUS_OK);
1588 printf("Testing notify mkdir\n");
1589 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1590 smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
1592 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1593 CHECK_STATUS(status, NT_STATUS_OK);
1595 CHECK_VAL(notify.nttrans.out.num_changes, 1);
1596 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_ADDED);
1597 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
1599 printf("Testing notify rmdir\n");
1600 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1601 smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
1603 status = smb_raw_changenotify_recv(req, torture, ¬ify);
1604 CHECK_STATUS(status, NT_STATUS_OK);
1605 CHECK_VAL(notify.nttrans.out.num_changes, 1);
1606 CHECK_VAL(notify.nttrans.out.changes[0].action, NOTIFY_ACTION_REMOVED);
1607 CHECK_WSTR(notify.nttrans.out.changes[0].name, "subdir-name", STR_UNICODE);
1609 printf("CHANGE NOTIFY WITH TDIS OK\n");
1611 smb_raw_exit(cli->session);
1612 smbcli_deltree(cli->tree, BASEDIR);
1618 testing alignment of multiple change notify infos
1620 static bool test_notify_alignment(struct smbcli_state *cli,
1621 struct torture_context *tctx)
1624 union smb_notify notify;
1627 struct smbcli_request *req;
1628 const char *fname = BASEDIR "\\starter";
1629 const char *fnames[] = { "a",
1633 int num_names = ARRAY_SIZE(fnames);
1636 torture_comment(tctx, "TESTING CHANGE NOTIFY REPLY ALIGNMENT\n");
1638 /* get a handle on the directory */
1639 io.generic.level = RAW_OPEN_NTCREATEX;
1640 io.ntcreatex.in.root_fid.fnum = 0;
1641 io.ntcreatex.in.flags = 0;
1642 io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1643 io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1644 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1645 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1646 NTCREATEX_SHARE_ACCESS_WRITE;
1647 io.ntcreatex.in.alloc_size = 0;
1648 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1649 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1650 io.ntcreatex.in.security_flags = 0;
1651 io.ntcreatex.in.fname = BASEDIR;
1653 status = smb_raw_open(cli->tree, tctx, &io);
1654 torture_assert_ntstatus_ok(tctx, status, "");
1655 fnum = io.ntcreatex.out.file.fnum;
1657 /* ask for a change notify, on file creation */
1658 notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1659 notify.nttrans.in.buffer_size = 1000;
1660 notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_FILE_NAME;
1661 notify.nttrans.in.file.fnum = fnum;
1662 notify.nttrans.in.recursive = false;
1664 /* start change tracking */
1665 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1667 fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
1668 torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
1669 smbcli_close(cli->tree, fnum2);
1671 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1672 torture_assert_ntstatus_ok(tctx, status, "");
1674 /* create 4 files that will cause CHANGE_NOTIFY_INFO structures
1675 * to be returned in the same packet with all possible 4-byte padding
1676 * permutations. As per MS-CIFS 2.2.7.4.2 these structures should be
1677 * 4-byte aligned. */
1679 for (i = 0; i < num_names; i++) {
1680 fpath = talloc_asprintf(tctx, "%s\\%s", BASEDIR, fnames[i]);
1681 fnum2 = smbcli_open(cli->tree, fpath,
1682 O_CREAT|O_RDWR, DENY_NONE);
1683 torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
1684 smbcli_close(cli->tree, fnum2);
1688 /* We send a notify packet, and let smb_raw_changenotify_recv() do
1689 * the alignment checking for us. */
1690 req = smb_raw_changenotify_send(cli->tree, ¬ify);
1691 status = smb_raw_changenotify_recv(req, tctx, ¬ify);
1692 torture_assert_ntstatus_ok(tctx, status, "");
1694 /* Do basic checking for correctness. */
1695 torture_assert(tctx, notify.nttrans.out.num_changes == num_names, "");
1696 for (i = 0; i < num_names; i++) {
1697 torture_assert(tctx, notify.nttrans.out.changes[i].action ==
1698 NOTIFY_ACTION_ADDED, "");
1699 CHECK_WSTR2(tctx, notify.nttrans.out.changes[i].name, fnames[i],
1707 basic testing of change notify
1709 static bool test_raw_notify_all(struct torture_context *torture,
1710 struct smbcli_state *cli,
1711 struct smbcli_state *cli2)
1715 if (!torture_setup_dir(cli, BASEDIR)) {
1719 ret &= test_notify_mask(cli, torture);
1720 ret &= test_notify_recursive(cli, torture);
1721 ret &= test_notify_mask_change(cli, torture);
1722 ret &= test_notify_file(cli, torture);
1723 ret &= test_notify_tdis(torture);
1724 ret &= test_notify_exit(torture);
1725 ret &= test_notify_ulogoff(torture);
1726 ret &= test_notify_tcp_dis(torture);
1727 ret &= test_notify_double(cli, torture);
1728 ret &= test_notify_tree(cli, torture);
1729 ret &= test_notify_overflow(cli, torture);
1730 ret &= test_notify_basedir(cli, torture);
1731 ret &= test_notify_alignment(cli, torture);
1733 smb_raw_exit(cli->session);
1734 smbcli_deltree(cli->tree, BASEDIR);
1738 struct torture_suite *torture_raw_notify(TALLOC_CTX *mem_ctx)
1740 struct torture_suite *suite = torture_suite_create(mem_ctx, "notify");
1742 torture_suite_add_1smb_test(suite, "tcon", test_notify_tcon);
1743 torture_suite_add_2smb_test(suite, "dir", test_notify_dir);
1744 torture_suite_add_2smb_test(suite, "all", test_raw_notify_all);