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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "torture/torture.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/libcli.h"
25 #include "system/filesys.h"
26 #include "torture/util.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); \
56 basic testing of change notify on directories
58 static BOOL
test_notify_dir(struct smbcli_state
*cli
, struct smbcli_state
*cli2
,
63 union smb_notify notify
;
66 int i
, count
, fnum
, fnum2
;
67 struct smbcli_request
*req
, *req2
;
68 extern int torture_numops
;
70 printf("TESTING CHANGE NOTIFY ON DIRECTRIES\n");
73 get a handle on the directory
75 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
76 io
.ntcreatex
.in
.root_fid
= 0;
77 io
.ntcreatex
.in
.flags
= 0;
78 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
79 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
80 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
81 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
82 io
.ntcreatex
.in
.alloc_size
= 0;
83 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
84 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
85 io
.ntcreatex
.in
.security_flags
= 0;
86 io
.ntcreatex
.in
.fname
= BASEDIR
;
88 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
89 CHECK_STATUS(status
, NT_STATUS_OK
);
90 fnum
= io
.ntcreatex
.out
.file
.fnum
;
92 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
93 CHECK_STATUS(status
, NT_STATUS_OK
);
94 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
96 /* ask for a change notify,
97 on file or directory name changes */
98 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
99 notify
.nttrans
.in
.buffer_size
= 1000;
100 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
101 notify
.nttrans
.in
.file
.fnum
= fnum
;
102 notify
.nttrans
.in
.recursive
= True
;
104 printf("testing notify cancel\n");
106 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
107 smb_raw_ntcancel(req
);
108 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
109 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
111 printf("testing notify mkdir\n");
113 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
114 smbcli_mkdir(cli2
->tree
, BASEDIR
"\\subdir-name");
116 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
117 CHECK_STATUS(status
, NT_STATUS_OK
);
119 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
120 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
121 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subdir-name", STR_UNICODE
);
123 printf("testing notify rmdir\n");
125 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
126 smbcli_rmdir(cli2
->tree
, BASEDIR
"\\subdir-name");
128 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
129 CHECK_STATUS(status
, NT_STATUS_OK
);
130 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
131 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
132 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subdir-name", STR_UNICODE
);
134 printf("testing notify mkdir - rmdir - mkdir - rmdir\n");
136 smbcli_mkdir(cli2
->tree
, BASEDIR
"\\subdir-name");
137 smbcli_rmdir(cli2
->tree
, BASEDIR
"\\subdir-name");
138 smbcli_mkdir(cli2
->tree
, BASEDIR
"\\subdir-name");
139 smbcli_rmdir(cli2
->tree
, BASEDIR
"\\subdir-name");
140 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
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
, 4);
144 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
145 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subdir-name", STR_UNICODE
);
146 CHECK_VAL(notify
.nttrans
.out
.changes
[1].action
, NOTIFY_ACTION_REMOVED
);
147 CHECK_WSTR(notify
.nttrans
.out
.changes
[1].name
, "subdir-name", STR_UNICODE
);
148 CHECK_VAL(notify
.nttrans
.out
.changes
[2].action
, NOTIFY_ACTION_ADDED
);
149 CHECK_WSTR(notify
.nttrans
.out
.changes
[2].name
, "subdir-name", STR_UNICODE
);
150 CHECK_VAL(notify
.nttrans
.out
.changes
[3].action
, NOTIFY_ACTION_REMOVED
);
151 CHECK_WSTR(notify
.nttrans
.out
.changes
[3].name
, "subdir-name", STR_UNICODE
);
153 count
= torture_numops
;
154 printf("testing buffered notify on create of %d files\n", count
);
155 for (i
=0;i
<count
;i
++) {
156 char *fname
= talloc_asprintf(cli
, BASEDIR
"\\test%d.txt", i
);
157 int fnum3
= smbcli_open(cli
->tree
, fname
, O_CREAT
|O_RDWR
, DENY_NONE
);
159 printf("Failed to create %s - %s\n",
160 fname
, smbcli_errstr(cli
->tree
));
165 smbcli_close(cli
->tree
, fnum3
);
168 /* (1st notify) setup a new notify on a different directory handle.
169 This new notify won't see the events above. */
170 notify
.nttrans
.in
.file
.fnum
= fnum2
;
171 req2
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
173 /* (2nd notify) whereas this notify will see the above buffered events,
174 and it directly returns the buffered events */
175 notify
.nttrans
.in
.file
.fnum
= fnum
;
176 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
178 status
= smbcli_unlink(cli
->tree
, BASEDIR
"\\nonexistant.txt");
179 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
181 /* (1st unlink) as the 2nd notify directly returns,
182 this unlink is only seen by the 1st notify and
183 the 3rd notify (later) */
184 printf("testing notify on unlink for the first file\n");
185 status
= smbcli_unlink(cli2
->tree
, BASEDIR
"\\test0.txt");
186 CHECK_STATUS(status
, NT_STATUS_OK
);
188 /* receive the reply from the 2nd notify */
189 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
190 CHECK_STATUS(status
, NT_STATUS_OK
);
192 CHECK_VAL(notify
.nttrans
.out
.num_changes
, count
);
193 for (i
=1;i
<count
;i
++) {
194 CHECK_VAL(notify
.nttrans
.out
.changes
[i
].action
, NOTIFY_ACTION_ADDED
);
196 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "test0.txt", STR_UNICODE
);
198 printf("and now from the 1st notify\n");
199 status
= smb_raw_changenotify_recv(req2
, mem_ctx
, ¬ify
);
200 CHECK_STATUS(status
, NT_STATUS_OK
);
201 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
202 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
203 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "test0.txt", STR_UNICODE
);
205 printf("(3rd notify) this notify will only see the 1st unlink\n");
206 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
208 status
= smbcli_unlink(cli
->tree
, BASEDIR
"\\nonexistant.txt");
209 CHECK_STATUS(status
, NT_STATUS_OBJECT_NAME_NOT_FOUND
);
211 printf("testing notify on wildcard unlink for %d files\n", count
-1);
212 /* (2nd unlink) do a wildcard unlink */
213 status
= smbcli_unlink(cli2
->tree
, BASEDIR
"\\test*.txt");
214 CHECK_STATUS(status
, NT_STATUS_OK
);
216 /* receive the 3rd notify */
217 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
218 CHECK_STATUS(status
, NT_STATUS_OK
);
219 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
220 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
221 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "test0.txt", STR_UNICODE
);
223 /* and we now see the rest of the unlink calls on both directory handles */
224 notify
.nttrans
.in
.file
.fnum
= fnum
;
226 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
227 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
228 CHECK_STATUS(status
, NT_STATUS_OK
);
229 CHECK_VAL(notify
.nttrans
.out
.num_changes
, count
-1);
230 for (i
=0;i
<notify
.nttrans
.out
.num_changes
;i
++) {
231 CHECK_VAL(notify
.nttrans
.out
.changes
[i
].action
, NOTIFY_ACTION_REMOVED
);
233 notify
.nttrans
.in
.file
.fnum
= fnum2
;
234 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
235 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
236 CHECK_STATUS(status
, NT_STATUS_OK
);
237 CHECK_VAL(notify
.nttrans
.out
.num_changes
, count
-1);
238 for (i
=0;i
<notify
.nttrans
.out
.num_changes
;i
++) {
239 CHECK_VAL(notify
.nttrans
.out
.changes
[i
].action
, NOTIFY_ACTION_REMOVED
);
242 printf("testing if a close() on the dir handle triggers the notify reply\n");
244 notify
.nttrans
.in
.file
.fnum
= fnum
;
245 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
247 cl
.close
.level
= RAW_CLOSE_CLOSE
;
248 cl
.close
.in
.file
.fnum
= fnum
;
249 cl
.close
.in
.write_time
= 0;
250 status
= smb_raw_close(cli
->tree
, &cl
);
251 CHECK_STATUS(status
, NT_STATUS_OK
);
253 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
254 CHECK_STATUS(status
, NT_STATUS_OK
);
255 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 0);
258 smb_raw_exit(cli
->session
);
263 * Check notify reply for a rename action. Not sure if this is a valid thing
264 * to do, but depending on timing between inotify and messaging we get the
265 * add/remove/modify in any order. This routines tries to find the action/name
266 * pair in any of the three following notify_changes.
269 static BOOL
check_rename_reply(struct smbcli_state
*cli
,
271 struct notify_changes
*actions
,
272 uint32_t action
, const char *name
)
276 for (i
=0; i
<3; i
++) {
277 if (actions
[i
].action
== action
) {
278 if ((actions
[i
].name
.s
== NULL
)
279 || (strcmp(actions
[i
].name
.s
, name
) != 0)
280 || (wire_bad_flags(&actions
[i
].name
, STR_UNICODE
,
282 printf("(%d) name [%s] != %s\n", line
,
283 actions
[i
].name
.s
, name
);
290 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
);
429 testing of mask bits for change notify
431 static BOOL
test_notify_mask(struct smbcli_state
*cli
, TALLOC_CTX
*mem_ctx
)
435 union smb_notify notify
;
444 printf("TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
446 tv
= timeval_current_ofs(1000, 0);
447 t
= timeval_to_nttime(&tv
);
450 get a handle on the directory
452 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
453 io
.ntcreatex
.in
.root_fid
= 0;
454 io
.ntcreatex
.in
.flags
= 0;
455 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
456 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
457 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
458 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
459 io
.ntcreatex
.in
.alloc_size
= 0;
460 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
461 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
462 io
.ntcreatex
.in
.security_flags
= 0;
463 io
.ntcreatex
.in
.fname
= BASEDIR
;
465 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
466 notify
.nttrans
.in
.buffer_size
= 1000;
467 notify
.nttrans
.in
.recursive
= True
;
469 #define NOTIFY_MASK_TEST(setup, op, cleanup, Action, expected, nchanges) \
470 do { for (mask=i=0;i<32;i++) { \
471 struct smbcli_request *req; \
472 status = smb_raw_open(cli->tree, mem_ctx, &io); \
473 CHECK_STATUS(status, NT_STATUS_OK); \
474 fnum = io.ntcreatex.out.file.fnum; \
476 notify.nttrans.in.file.fnum = fnum; \
477 notify.nttrans.in.completion_filter = (1<<i); \
478 req = smb_raw_changenotify_send(cli->tree, ¬ify); \
480 msleep(200); smb_raw_ntcancel(req); \
481 status = smb_raw_changenotify_recv(req, mem_ctx, ¬ify); \
483 smbcli_close(cli->tree, fnum); \
484 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
485 CHECK_STATUS(status, NT_STATUS_OK); \
486 /* special case to cope with file rename behaviour */ \
487 if (nchanges == 2 && notify.nttrans.out.num_changes == 1 && \
488 notify.nttrans.out.changes[0].action == NOTIFY_ACTION_MODIFIED && \
489 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
490 Action == NOTIFY_ACTION_OLD_NAME) { \
491 printf("(rename file special handling OK)\n"); \
492 } else if (nchanges != notify.nttrans.out.num_changes) { \
493 printf("ERROR: nchanges=%d expected=%d action=%d filter=0x%08x\n", \
494 notify.nttrans.out.num_changes, \
496 notify.nttrans.out.changes[0].action, \
497 notify.nttrans.in.completion_filter); \
499 } else if (notify.nttrans.out.changes[0].action != Action) { \
500 printf("ERROR: nchanges=%d action=%d expectedAction=%d filter=0x%08x\n", \
501 notify.nttrans.out.num_changes, \
502 notify.nttrans.out.changes[0].action, \
504 notify.nttrans.in.completion_filter); \
506 } else if (strcmp(notify.nttrans.out.changes[0].name.s, "tname1") != 0) { \
507 printf("ERROR: nchanges=%d action=%d filter=0x%08x name=%s\n", \
508 notify.nttrans.out.num_changes, \
509 notify.nttrans.out.changes[0].action, \
510 notify.nttrans.in.completion_filter, \
511 notify.nttrans.out.changes[0].name.s); \
516 if ((expected) != mask) { \
517 if (((expected) & ~mask) != 0) { \
518 printf("ERROR: trigger on too few bits. mask=0x%08x expected=0x%08x\n", \
522 printf("WARNING: trigger on too many bits. mask=0x%08x expected=0x%08x\n", \
528 printf("testing mkdir\n");
530 smbcli_mkdir(cli
->tree
, BASEDIR
"\\tname1");,
531 smbcli_rmdir(cli
->tree
, BASEDIR
"\\tname1");,
533 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
535 printf("testing create file\n");
537 smbcli_close(cli
->tree
, smbcli_open(cli
->tree
, BASEDIR
"\\tname1", O_CREAT
, 0));,
538 smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1");,
540 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
542 printf("testing unlink\n");
544 smbcli_close(cli
->tree
, smbcli_open(cli
->tree
, BASEDIR
"\\tname1", O_CREAT
, 0));,
545 smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1");,
547 NOTIFY_ACTION_REMOVED
,
548 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
550 printf("testing rmdir\n");
552 smbcli_mkdir(cli
->tree
, BASEDIR
"\\tname1");,
553 smbcli_rmdir(cli
->tree
, BASEDIR
"\\tname1");,
555 NOTIFY_ACTION_REMOVED
,
556 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
558 printf("testing rename file\n");
560 smbcli_close(cli
->tree
, smbcli_open(cli
->tree
, BASEDIR
"\\tname1", O_CREAT
, 0));,
561 smbcli_rename(cli
->tree
, BASEDIR
"\\tname1", BASEDIR
"\\tname2");,
562 smbcli_unlink(cli
->tree
, BASEDIR
"\\tname2");,
563 NOTIFY_ACTION_OLD_NAME
,
564 FILE_NOTIFY_CHANGE_FILE_NAME
|FILE_NOTIFY_CHANGE_ATTRIBUTES
|FILE_NOTIFY_CHANGE_CREATION
, 2);
566 printf("testing rename dir\n");
568 smbcli_mkdir(cli
->tree
, BASEDIR
"\\tname1");,
569 smbcli_rename(cli
->tree
, BASEDIR
"\\tname1", BASEDIR
"\\tname2");,
570 smbcli_rmdir(cli
->tree
, BASEDIR
"\\tname2");,
571 NOTIFY_ACTION_OLD_NAME
,
572 FILE_NOTIFY_CHANGE_DIR_NAME
, 2);
574 printf("testing set path attribute\n");
576 smbcli_close(cli
->tree
, smbcli_open(cli
->tree
, BASEDIR
"\\tname1", O_CREAT
, 0));,
577 smbcli_setatr(cli
->tree
, BASEDIR
"\\tname1", FILE_ATTRIBUTE_HIDDEN
, 0);,
578 smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1");,
579 NOTIFY_ACTION_MODIFIED
,
580 FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
582 printf("testing set path write time\n");
584 smbcli_close(cli
->tree
, smbcli_open(cli
->tree
, BASEDIR
"\\tname1", O_CREAT
, 0));,
585 smbcli_setatr(cli
->tree
, BASEDIR
"\\tname1", FILE_ATTRIBUTE_NORMAL
, 1000);,
586 smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1");,
587 NOTIFY_ACTION_MODIFIED
,
588 FILE_NOTIFY_CHANGE_LAST_WRITE
, 1);
590 printf("testing set file attribute\n");
592 fnum2
= create_complex_file(cli
, mem_ctx
, BASEDIR
"\\tname1");,
593 smbcli_fsetatr(cli
->tree
, fnum2
, FILE_ATTRIBUTE_HIDDEN
, 0, 0, 0, 0);,
594 (smbcli_close(cli
->tree
, fnum2
), smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1"));,
595 NOTIFY_ACTION_MODIFIED
,
596 FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
598 if (lp_parm_bool(-1, "torture", "samba3", False
)) {
599 printf("Samba3 does not yet support create times "
603 printf("testing set file create time\n");
605 fnum2
= create_complex_file(cli
, mem_ctx
,
606 BASEDIR
"\\tname1");,
607 smbcli_fsetatr(cli
->tree
, fnum2
, 0, t
, 0, 0, 0);,
608 (smbcli_close(cli
->tree
, fnum2
),
609 smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1"));,
610 NOTIFY_ACTION_MODIFIED
,
611 FILE_NOTIFY_CHANGE_CREATION
, 1);
614 printf("testing set file access time\n");
616 fnum2
= create_complex_file(cli
, mem_ctx
, BASEDIR
"\\tname1");,
617 smbcli_fsetatr(cli
->tree
, fnum2
, 0, 0, t
, 0, 0);,
618 (smbcli_close(cli
->tree
, fnum2
), smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1"));,
619 NOTIFY_ACTION_MODIFIED
,
620 FILE_NOTIFY_CHANGE_LAST_ACCESS
, 1);
622 printf("testing set file write time\n");
624 fnum2
= create_complex_file(cli
, mem_ctx
, BASEDIR
"\\tname1");,
625 smbcli_fsetatr(cli
->tree
, fnum2
, 0, 0, 0, t
, 0);,
626 (smbcli_close(cli
->tree
, fnum2
), smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1"));,
627 NOTIFY_ACTION_MODIFIED
,
628 FILE_NOTIFY_CHANGE_LAST_WRITE
, 1);
630 printf("testing set file change time\n");
632 fnum2
= create_complex_file(cli
, mem_ctx
, BASEDIR
"\\tname1");,
633 smbcli_fsetatr(cli
->tree
, fnum2
, 0, 0, 0, 0, t
);,
634 (smbcli_close(cli
->tree
, fnum2
), smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1"));,
635 NOTIFY_ACTION_MODIFIED
,
639 printf("testing write\n");
641 fnum2
= create_complex_file(cli
, mem_ctx
, BASEDIR
"\\tname1");,
642 smbcli_write(cli
->tree
, fnum2
, 1, &c
, 10000, 1);,
643 (smbcli_close(cli
->tree
, fnum2
), smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1"));,
644 NOTIFY_ACTION_MODIFIED
,
647 printf("testing truncate\n");
649 fnum2
= create_complex_file(cli
, mem_ctx
, BASEDIR
"\\tname1");,
650 smbcli_ftruncate(cli
->tree
, fnum2
, 10000);,
651 (smbcli_close(cli
->tree
, fnum2
), smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1"));,
652 NOTIFY_ACTION_MODIFIED
,
653 FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
656 smb_raw_exit(cli
->session
);
661 basic testing of change notify on files
663 static BOOL
test_notify_file(struct smbcli_state
*cli
, TALLOC_CTX
*mem_ctx
)
669 union smb_notify notify
;
670 struct smbcli_request
*req
;
672 const char *fname
= BASEDIR
"\\file.txt";
674 printf("TESTING CHANGE NOTIFY ON FILES\n");
676 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
677 io
.ntcreatex
.in
.root_fid
= 0;
678 io
.ntcreatex
.in
.flags
= 0;
679 io
.ntcreatex
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
680 io
.ntcreatex
.in
.create_options
= 0;
681 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
682 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
683 io
.ntcreatex
.in
.alloc_size
= 0;
684 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
685 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
686 io
.ntcreatex
.in
.security_flags
= 0;
687 io
.ntcreatex
.in
.fname
= fname
;
688 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
689 CHECK_STATUS(status
, NT_STATUS_OK
);
690 fnum
= io
.ntcreatex
.out
.file
.fnum
;
692 /* ask for a change notify,
693 on file or directory name changes */
694 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
695 notify
.nttrans
.in
.file
.fnum
= fnum
;
696 notify
.nttrans
.in
.buffer_size
= 1000;
697 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_STREAM_NAME
;
698 notify
.nttrans
.in
.recursive
= False
;
700 printf("testing if notifies on file handles are invalid (should be)\n");
702 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
703 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
704 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
706 cl
.close
.level
= RAW_CLOSE_CLOSE
;
707 cl
.close
.in
.file
.fnum
= fnum
;
708 cl
.close
.in
.write_time
= 0;
709 status
= smb_raw_close(cli
->tree
, &cl
);
710 CHECK_STATUS(status
, NT_STATUS_OK
);
712 status
= smbcli_unlink(cli
->tree
, fname
);
713 CHECK_STATUS(status
, NT_STATUS_OK
);
716 smb_raw_exit(cli
->session
);
721 basic testing of change notifies followed by a tdis
723 static BOOL
test_notify_tdis(TALLOC_CTX
*mem_ctx
)
727 union smb_notify notify
;
730 struct smbcli_request
*req
;
731 struct smbcli_state
*cli
= NULL
;
733 printf("TESTING CHANGE NOTIFY FOLLOWED BY TDIS\n");
735 if (!torture_open_connection(&cli
, 0)) {
740 get a handle on the directory
742 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
743 io
.ntcreatex
.in
.root_fid
= 0;
744 io
.ntcreatex
.in
.flags
= 0;
745 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
746 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
747 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
748 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
749 io
.ntcreatex
.in
.alloc_size
= 0;
750 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
751 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
752 io
.ntcreatex
.in
.security_flags
= 0;
753 io
.ntcreatex
.in
.fname
= BASEDIR
;
755 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
756 CHECK_STATUS(status
, NT_STATUS_OK
);
757 fnum
= io
.ntcreatex
.out
.file
.fnum
;
759 /* ask for a change notify,
760 on file or directory name changes */
761 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
762 notify
.nttrans
.in
.buffer_size
= 1000;
763 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
764 notify
.nttrans
.in
.file
.fnum
= fnum
;
765 notify
.nttrans
.in
.recursive
= True
;
767 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
769 status
= smbcli_tdis(cli
);
770 CHECK_STATUS(status
, NT_STATUS_OK
);
773 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
774 CHECK_STATUS(status
, NT_STATUS_OK
);
775 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 0);
778 torture_close_connection(cli
);
783 basic testing of change notifies followed by a exit
785 static BOOL
test_notify_exit(TALLOC_CTX
*mem_ctx
)
789 union smb_notify notify
;
792 struct smbcli_request
*req
;
793 struct smbcli_state
*cli
= NULL
;
795 printf("TESTING CHANGE NOTIFY FOLLOWED BY EXIT\n");
797 if (!torture_open_connection(&cli
, 0)) {
802 get a handle on the directory
804 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
805 io
.ntcreatex
.in
.root_fid
= 0;
806 io
.ntcreatex
.in
.flags
= 0;
807 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
808 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
809 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
810 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
811 io
.ntcreatex
.in
.alloc_size
= 0;
812 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
813 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
814 io
.ntcreatex
.in
.security_flags
= 0;
815 io
.ntcreatex
.in
.fname
= BASEDIR
;
817 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
818 CHECK_STATUS(status
, NT_STATUS_OK
);
819 fnum
= io
.ntcreatex
.out
.file
.fnum
;
821 /* ask for a change notify,
822 on file or directory name changes */
823 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
824 notify
.nttrans
.in
.buffer_size
= 1000;
825 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
826 notify
.nttrans
.in
.file
.fnum
= fnum
;
827 notify
.nttrans
.in
.recursive
= True
;
829 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
831 status
= smb_raw_exit(cli
->session
);
832 CHECK_STATUS(status
, NT_STATUS_OK
);
834 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
835 CHECK_STATUS(status
, NT_STATUS_OK
);
836 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 0);
839 torture_close_connection(cli
);
844 basic testing of change notifies followed by a ulogoff
846 static BOOL
test_notify_ulogoff(TALLOC_CTX
*mem_ctx
)
850 union smb_notify notify
;
853 struct smbcli_request
*req
;
854 struct smbcli_state
*cli
= NULL
;
856 printf("TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
858 if (!torture_open_connection(&cli
, 0)) {
863 get a handle on the directory
865 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
866 io
.ntcreatex
.in
.root_fid
= 0;
867 io
.ntcreatex
.in
.flags
= 0;
868 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
869 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
870 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
871 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
872 io
.ntcreatex
.in
.alloc_size
= 0;
873 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
874 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
875 io
.ntcreatex
.in
.security_flags
= 0;
876 io
.ntcreatex
.in
.fname
= BASEDIR
;
878 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
879 CHECK_STATUS(status
, NT_STATUS_OK
);
880 fnum
= io
.ntcreatex
.out
.file
.fnum
;
882 /* ask for a change notify,
883 on file or directory name changes */
884 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
885 notify
.nttrans
.in
.buffer_size
= 1000;
886 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
887 notify
.nttrans
.in
.file
.fnum
= fnum
;
888 notify
.nttrans
.in
.recursive
= True
;
890 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
892 status
= smb_raw_ulogoff(cli
->session
);
893 CHECK_STATUS(status
, NT_STATUS_OK
);
895 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
896 CHECK_STATUS(status
, NT_STATUS_OK
);
897 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 0);
900 torture_close_connection(cli
);
904 static void tcp_dis_handler(struct smbcli_transport
*t
, void *p
)
906 struct smbcli_state
*cli
= p
;
907 smbcli_transport_dead(cli
->transport
, NT_STATUS_LOCAL_DISCONNECT
);
908 cli
->transport
= NULL
;
912 basic testing of change notifies followed by tcp disconnect
914 static BOOL
test_notify_tcp_dis(TALLOC_CTX
*mem_ctx
)
918 union smb_notify notify
;
921 struct smbcli_request
*req
;
922 struct smbcli_state
*cli
= NULL
;
924 printf("TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
926 if (!torture_open_connection(&cli
, 0)) {
931 get a handle on the directory
933 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
934 io
.ntcreatex
.in
.root_fid
= 0;
935 io
.ntcreatex
.in
.flags
= 0;
936 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
937 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
938 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
939 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
940 io
.ntcreatex
.in
.alloc_size
= 0;
941 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
942 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
943 io
.ntcreatex
.in
.security_flags
= 0;
944 io
.ntcreatex
.in
.fname
= BASEDIR
;
946 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
947 CHECK_STATUS(status
, NT_STATUS_OK
);
948 fnum
= io
.ntcreatex
.out
.file
.fnum
;
950 /* ask for a change notify,
951 on file or directory name changes */
952 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
953 notify
.nttrans
.in
.buffer_size
= 1000;
954 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
955 notify
.nttrans
.in
.file
.fnum
= fnum
;
956 notify
.nttrans
.in
.recursive
= True
;
958 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
960 smbcli_transport_idle_handler(cli
->transport
, tcp_dis_handler
, 250, cli
);
962 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
963 CHECK_STATUS(status
, NT_STATUS_LOCAL_DISCONNECT
);
966 torture_close_connection(cli
);
971 test setting up two change notify requests on one handle
973 static BOOL
test_notify_double(struct smbcli_state
*cli
, TALLOC_CTX
*mem_ctx
)
977 union smb_notify notify
;
980 struct smbcli_request
*req1
, *req2
;
982 printf("TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
985 get a handle on the directory
987 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
988 io
.ntcreatex
.in
.root_fid
= 0;
989 io
.ntcreatex
.in
.flags
= 0;
990 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
991 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
992 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
993 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
994 io
.ntcreatex
.in
.alloc_size
= 0;
995 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
996 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
997 io
.ntcreatex
.in
.security_flags
= 0;
998 io
.ntcreatex
.in
.fname
= BASEDIR
;
1000 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
1001 CHECK_STATUS(status
, NT_STATUS_OK
);
1002 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1004 /* ask for a change notify,
1005 on file or directory name changes */
1006 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1007 notify
.nttrans
.in
.buffer_size
= 1000;
1008 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1009 notify
.nttrans
.in
.file
.fnum
= fnum
;
1010 notify
.nttrans
.in
.recursive
= True
;
1012 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1013 req2
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1015 smbcli_mkdir(cli
->tree
, BASEDIR
"\\subdir-name");
1017 status
= smb_raw_changenotify_recv(req1
, mem_ctx
, ¬ify
);
1018 CHECK_STATUS(status
, NT_STATUS_OK
);
1019 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
1020 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subdir-name", STR_UNICODE
);
1022 smbcli_mkdir(cli
->tree
, BASEDIR
"\\subdir-name2");
1024 status
= smb_raw_changenotify_recv(req2
, mem_ctx
, ¬ify
);
1025 CHECK_STATUS(status
, NT_STATUS_OK
);
1026 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
1027 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subdir-name2", STR_UNICODE
);
1030 smb_raw_exit(cli
->session
);
1036 test multiple change notifies at different depths and with/without recursion
1038 static BOOL
test_notify_tree(struct smbcli_state
*cli
, TALLOC_CTX
*mem_ctx
)
1041 union smb_notify notify
;
1043 struct smbcli_request
*req
;
1053 {BASEDIR
"\\abc", True
, FILE_NOTIFY_CHANGE_NAME
, 30 },
1054 {BASEDIR
"\\zqy", True
, FILE_NOTIFY_CHANGE_NAME
, 8 },
1055 {BASEDIR
"\\atsy", True
, FILE_NOTIFY_CHANGE_NAME
, 4 },
1056 {BASEDIR
"\\abc\\foo", True
, FILE_NOTIFY_CHANGE_NAME
, 2 },
1057 {BASEDIR
"\\abc\\blah", True
, FILE_NOTIFY_CHANGE_NAME
, 13 },
1058 {BASEDIR
"\\abc\\blah", False
, FILE_NOTIFY_CHANGE_NAME
, 7 },
1059 {BASEDIR
"\\abc\\blah\\a", True
, FILE_NOTIFY_CHANGE_NAME
, 2 },
1060 {BASEDIR
"\\abc\\blah\\b", True
, FILE_NOTIFY_CHANGE_NAME
, 2 },
1061 {BASEDIR
"\\abc\\blah\\c", True
, FILE_NOTIFY_CHANGE_NAME
, 2 },
1062 {BASEDIR
"\\abc\\fooblah", True
, FILE_NOTIFY_CHANGE_NAME
, 2 },
1063 {BASEDIR
"\\zqy\\xx", True
, FILE_NOTIFY_CHANGE_NAME
, 2 },
1064 {BASEDIR
"\\zqy\\yyy", True
, FILE_NOTIFY_CHANGE_NAME
, 2 },
1065 {BASEDIR
"\\zqy\\..", True
, FILE_NOTIFY_CHANGE_NAME
, 40 },
1066 {BASEDIR
, True
, FILE_NOTIFY_CHANGE_NAME
, 40 },
1067 {BASEDIR
, False
,FILE_NOTIFY_CHANGE_NAME
, 6 },
1068 {BASEDIR
"\\atsy", False
,FILE_NOTIFY_CHANGE_NAME
, 4 },
1069 {BASEDIR
"\\abc", True
, FILE_NOTIFY_CHANGE_NAME
, 24 },
1070 {BASEDIR
"\\abc", False
,FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1071 {BASEDIR
"\\abc", True
, FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1072 {BASEDIR
"\\abc", True
, FILE_NOTIFY_CHANGE_NAME
, 24 },
1076 BOOL all_done
= False
;
1078 printf("TESTING CHANGE NOTIFY FOR DIFFERENT DEPTHS\n");
1080 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1081 io
.ntcreatex
.in
.root_fid
= 0;
1082 io
.ntcreatex
.in
.flags
= 0;
1083 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1084 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1085 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1086 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
1087 io
.ntcreatex
.in
.alloc_size
= 0;
1088 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1089 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1090 io
.ntcreatex
.in
.security_flags
= 0;
1092 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1093 notify
.nttrans
.in
.buffer_size
= 20000;
1096 setup the directory tree, and the notify buffer on each directory
1098 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1099 io
.ntcreatex
.in
.fname
= dirs
[i
].path
;
1100 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
1101 CHECK_STATUS(status
, NT_STATUS_OK
);
1102 dirs
[i
].fnum
= io
.ntcreatex
.out
.file
.fnum
;
1104 notify
.nttrans
.in
.completion_filter
= dirs
[i
].filter
;
1105 notify
.nttrans
.in
.file
.fnum
= dirs
[i
].fnum
;
1106 notify
.nttrans
.in
.recursive
= dirs
[i
].recursive
;
1107 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1108 smb_raw_ntcancel(req
);
1109 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
1110 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1113 /* trigger 2 events in each dir */
1114 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1115 char *path
= talloc_asprintf(mem_ctx
, "%s\\test.dir", dirs
[i
].path
);
1116 smbcli_mkdir(cli
->tree
, path
);
1117 smbcli_rmdir(cli
->tree
, path
);
1121 /* give a bit of time for the events to propogate */
1122 tv
= timeval_current();
1125 /* count events that have happened in each dir */
1126 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1127 notify
.nttrans
.in
.file
.fnum
= dirs
[i
].fnum
;
1128 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1129 smb_raw_ntcancel(req
);
1130 notify
.nttrans
.out
.num_changes
= 0;
1131 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
1132 dirs
[i
].counted
+= notify
.nttrans
.out
.num_changes
;
1137 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1138 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1142 } while (!all_done
&& timeval_elapsed(&tv
) < 20);
1144 printf("took %.4f seconds to propogate all events\n", timeval_elapsed(&tv
));
1146 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1147 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1148 printf("ERROR: i=%d expected %d got %d for '%s'\n",
1149 i
, dirs
[i
].expected
, dirs
[i
].counted
, dirs
[i
].path
);
1155 run from the back, closing and deleting
1157 for (i
=ARRAY_SIZE(dirs
)-1;i
>=0;i
--) {
1158 smbcli_close(cli
->tree
, dirs
[i
].fnum
);
1159 smbcli_rmdir(cli
->tree
, dirs
[i
].path
);
1163 smb_raw_exit(cli
->session
);
1168 basic testing of change notify
1170 BOOL
torture_raw_notify(struct torture_context
*torture
)
1172 struct smbcli_state
*cli
, *cli2
;
1174 TALLOC_CTX
*mem_ctx
;
1176 if (!torture_open_connection(&cli
, 0)) {
1179 if (!torture_open_connection(&cli2
, 0)) {
1183 mem_ctx
= talloc_init("torture_raw_notify");
1185 if (!torture_setup_dir(cli
, BASEDIR
)) {
1189 ret
&= test_notify_dir(cli
, cli2
, mem_ctx
);
1190 ret
&= test_notify_mask(cli
, mem_ctx
);
1191 ret
&= test_notify_recursive(cli
, mem_ctx
);
1192 ret
&= test_notify_file(cli
, mem_ctx
);
1193 ret
&= test_notify_tdis(mem_ctx
);
1194 ret
&= test_notify_exit(mem_ctx
);
1195 ret
&= test_notify_ulogoff(mem_ctx
);
1196 ret
&= test_notify_tcp_dis(mem_ctx
);
1197 ret
&= test_notify_double(cli
, mem_ctx
);
1198 ret
&= test_notify_tree(cli
, mem_ctx
);
1200 smb_raw_exit(cli
->session
);
1201 smbcli_deltree(cli
->tree
, BASEDIR
);
1202 torture_close_connection(cli
);
1203 torture_close_connection(cli2
);
1204 talloc_free(mem_ctx
);