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
"\\nonexistent.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
"\\nonexistent.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 torture_context
*mem_ctx
,
313 struct smbcli_state
*cli
,
314 struct smbcli_state
*cli2
)
318 union smb_notify notify
;
321 struct smbcli_request
*req1
, *req2
;
323 printf("TESTING CHANGE NOTIFY WITH RECURSION\n");
325 if (!torture_setup_dir(cli
, BASEDIR
)) {
330 get a handle on the directory
332 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
333 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
334 io
.ntcreatex
.in
.flags
= 0;
335 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
336 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
337 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
338 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
339 io
.ntcreatex
.in
.alloc_size
= 0;
340 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
341 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
342 io
.ntcreatex
.in
.security_flags
= 0;
343 io
.ntcreatex
.in
.fname
= BASEDIR
;
345 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
346 CHECK_STATUS(status
, NT_STATUS_OK
);
347 fnum
= io
.ntcreatex
.out
.file
.fnum
;
349 /* ask for a change notify, on file or directory name
350 changes. Setup both with and without recursion */
351 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
352 notify
.nttrans
.in
.buffer_size
= 1000;
353 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
| FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_CREATION
;
354 notify
.nttrans
.in
.file
.fnum
= fnum
;
356 notify
.nttrans
.in
.recursive
= true;
357 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
359 notify
.nttrans
.in
.recursive
= false;
360 req2
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
362 /* cancel initial requests so the buffer is setup */
363 smb_raw_ntcancel(req1
);
364 status
= smb_raw_changenotify_recv(req1
, mem_ctx
, ¬ify
);
365 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
367 smb_raw_ntcancel(req2
);
368 status
= smb_raw_changenotify_recv(req2
, mem_ctx
, ¬ify
);
369 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
372 * Make notifies a bit more interesting in a cluster by doing
373 * the changes against different nodes with --unclist
375 smbcli_mkdir(cli
->tree
, BASEDIR
"\\subdir-name");
376 smbcli_mkdir(cli2
->tree
, BASEDIR
"\\subdir-name\\subname1");
377 smbcli_close(cli
->tree
,
378 smbcli_open(cli
->tree
, BASEDIR
"\\subdir-name\\subname2", O_CREAT
, 0));
379 smbcli_rename(cli2
->tree
, BASEDIR
"\\subdir-name\\subname1",
380 BASEDIR
"\\subdir-name\\subname1-r");
381 smbcli_rename(cli
->tree
, BASEDIR
"\\subdir-name\\subname2", BASEDIR
"\\subname2-r");
382 smbcli_rename(cli2
->tree
, BASEDIR
"\\subname2-r",
383 BASEDIR
"\\subname3-r");
385 notify
.nttrans
.in
.completion_filter
= 0;
386 notify
.nttrans
.in
.recursive
= true;
388 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
390 smbcli_rmdir(cli
->tree
, BASEDIR
"\\subdir-name\\subname1-r");
391 smbcli_rmdir(cli2
->tree
, BASEDIR
"\\subdir-name");
392 smbcli_unlink(cli
->tree
, BASEDIR
"\\subname3-r");
394 notify
.nttrans
.in
.recursive
= false;
395 req2
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
397 status
= smb_raw_changenotify_recv(req1
, mem_ctx
, ¬ify
);
398 CHECK_STATUS(status
, NT_STATUS_OK
);
400 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 11);
401 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
402 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subdir-name", STR_UNICODE
);
403 CHECK_VAL(notify
.nttrans
.out
.changes
[1].action
, NOTIFY_ACTION_ADDED
);
404 CHECK_WSTR(notify
.nttrans
.out
.changes
[1].name
, "subdir-name\\subname1", STR_UNICODE
);
405 CHECK_VAL(notify
.nttrans
.out
.changes
[2].action
, NOTIFY_ACTION_ADDED
);
406 CHECK_WSTR(notify
.nttrans
.out
.changes
[2].name
, "subdir-name\\subname2", STR_UNICODE
);
407 CHECK_VAL(notify
.nttrans
.out
.changes
[3].action
, NOTIFY_ACTION_OLD_NAME
);
408 CHECK_WSTR(notify
.nttrans
.out
.changes
[3].name
, "subdir-name\\subname1", STR_UNICODE
);
409 CHECK_VAL(notify
.nttrans
.out
.changes
[4].action
, NOTIFY_ACTION_NEW_NAME
);
410 CHECK_WSTR(notify
.nttrans
.out
.changes
[4].name
, "subdir-name\\subname1-r", STR_UNICODE
);
412 ret
&= check_rename_reply(
413 cli
, __LINE__
, ¬ify
.nttrans
.out
.changes
[5],
414 NOTIFY_ACTION_ADDED
, "subname2-r");
415 ret
&= check_rename_reply(
416 cli
, __LINE__
, ¬ify
.nttrans
.out
.changes
[5],
417 NOTIFY_ACTION_REMOVED
, "subdir-name\\subname2");
418 ret
&= check_rename_reply(
419 cli
, __LINE__
, ¬ify
.nttrans
.out
.changes
[5],
420 NOTIFY_ACTION_MODIFIED
, "subname2-r");
422 ret
&= check_rename_reply(
423 cli
, __LINE__
, ¬ify
.nttrans
.out
.changes
[8],
424 NOTIFY_ACTION_OLD_NAME
, "subname2-r");
425 ret
&= check_rename_reply(
426 cli
, __LINE__
, ¬ify
.nttrans
.out
.changes
[8],
427 NOTIFY_ACTION_NEW_NAME
, "subname3-r");
428 ret
&= check_rename_reply(
429 cli
, __LINE__
, ¬ify
.nttrans
.out
.changes
[8],
430 NOTIFY_ACTION_MODIFIED
, "subname3-r");
436 status
= smb_raw_changenotify_recv(req2
, mem_ctx
, ¬ify
);
437 CHECK_STATUS(status
, NT_STATUS_OK
);
439 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 3);
440 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
441 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subdir-name\\subname1-r", STR_UNICODE
);
442 CHECK_VAL(notify
.nttrans
.out
.changes
[1].action
, NOTIFY_ACTION_REMOVED
);
443 CHECK_WSTR(notify
.nttrans
.out
.changes
[1].name
, "subdir-name", STR_UNICODE
);
444 CHECK_VAL(notify
.nttrans
.out
.changes
[2].action
, NOTIFY_ACTION_REMOVED
);
445 CHECK_WSTR(notify
.nttrans
.out
.changes
[2].name
, "subname3-r", STR_UNICODE
);
448 smb_raw_exit(cli
->session
);
449 smbcli_deltree(cli
->tree
, BASEDIR
);
454 testing of change notify mask change
456 static bool test_notify_mask_change(struct torture_context
*mem_ctx
,
457 struct smbcli_state
*cli
)
461 union smb_notify notify
;
464 struct smbcli_request
*req1
, *req2
;
466 printf("TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
468 if (!torture_setup_dir(cli
, BASEDIR
)) {
473 get a handle on the directory
475 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
476 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
477 io
.ntcreatex
.in
.flags
= 0;
478 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
479 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
480 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
481 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
482 io
.ntcreatex
.in
.alloc_size
= 0;
483 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
484 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
485 io
.ntcreatex
.in
.security_flags
= 0;
486 io
.ntcreatex
.in
.fname
= BASEDIR
;
488 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
489 CHECK_STATUS(status
, NT_STATUS_OK
);
490 fnum
= io
.ntcreatex
.out
.file
.fnum
;
492 /* ask for a change notify, on file or directory name
493 changes. Setup both with and without recursion */
494 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
495 notify
.nttrans
.in
.buffer_size
= 1000;
496 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
497 notify
.nttrans
.in
.file
.fnum
= fnum
;
499 notify
.nttrans
.in
.recursive
= true;
500 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
502 notify
.nttrans
.in
.recursive
= false;
503 req2
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
505 /* cancel initial requests so the buffer is setup */
506 smb_raw_ntcancel(req1
);
507 status
= smb_raw_changenotify_recv(req1
, mem_ctx
, ¬ify
);
508 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
510 smb_raw_ntcancel(req2
);
511 status
= smb_raw_changenotify_recv(req2
, mem_ctx
, ¬ify
);
512 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
514 notify
.nttrans
.in
.recursive
= true;
515 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
517 /* Set to hidden then back again. */
518 smbcli_close(cli
->tree
, smbcli_open(cli
->tree
, BASEDIR
"\\tname1", O_CREAT
, 0));
519 smbcli_setatr(cli
->tree
, BASEDIR
"\\tname1", FILE_ATTRIBUTE_HIDDEN
, 0);
520 smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1");
522 status
= smb_raw_changenotify_recv(req1
, mem_ctx
, ¬ify
);
523 CHECK_STATUS(status
, NT_STATUS_OK
);
525 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
526 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
527 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "tname1", STR_UNICODE
);
529 /* Now try and change the mask to include other events.
530 * This should not work - once the mask is set on a directory
531 * fnum it seems to be fixed until the fnum is closed. */
533 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
| FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_CREATION
;
534 notify
.nttrans
.in
.recursive
= true;
535 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
537 notify
.nttrans
.in
.recursive
= false;
538 req2
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
540 smbcli_mkdir(cli
->tree
, BASEDIR
"\\subdir-name");
541 smbcli_mkdir(cli
->tree
, BASEDIR
"\\subdir-name\\subname1");
542 smbcli_close(cli
->tree
,
543 smbcli_open(cli
->tree
, BASEDIR
"\\subdir-name\\subname2", O_CREAT
, 0));
544 smbcli_rename(cli
->tree
, BASEDIR
"\\subdir-name\\subname1", BASEDIR
"\\subdir-name\\subname1-r");
545 smbcli_rename(cli
->tree
, BASEDIR
"\\subdir-name\\subname2", BASEDIR
"\\subname2-r");
546 smbcli_rename(cli
->tree
, BASEDIR
"\\subname2-r", BASEDIR
"\\subname3-r");
548 smbcli_rmdir(cli
->tree
, BASEDIR
"\\subdir-name\\subname1-r");
549 smbcli_rmdir(cli
->tree
, BASEDIR
"\\subdir-name");
550 smbcli_unlink(cli
->tree
, BASEDIR
"\\subname3-r");
552 status
= smb_raw_changenotify_recv(req1
, mem_ctx
, ¬ify
);
553 CHECK_STATUS(status
, NT_STATUS_OK
);
555 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
556 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
557 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subname2-r", STR_UNICODE
);
559 status
= smb_raw_changenotify_recv(req2
, mem_ctx
, ¬ify
);
560 CHECK_STATUS(status
, NT_STATUS_OK
);
562 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
563 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
564 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subname3-r", STR_UNICODE
);
571 smb_raw_exit(cli
->session
);
572 smbcli_deltree(cli
->tree
, BASEDIR
);
578 testing of mask bits for change notify
580 static bool test_notify_mask(struct torture_context
*tctx
,
581 struct smbcli_state
*cli
,
582 struct smbcli_state
*cli2
)
586 union smb_notify notify
;
588 union smb_chkpath chkpath
;
596 printf("TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
598 if (!torture_setup_dir(cli
, BASEDIR
)) {
602 tv
= timeval_current_ofs(1000, 0);
603 t
= timeval_to_nttime(&tv
);
606 get a handle on the directory
608 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
609 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
610 io
.ntcreatex
.in
.flags
= 0;
611 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
612 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
613 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
614 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
615 io
.ntcreatex
.in
.alloc_size
= 0;
616 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
617 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
618 io
.ntcreatex
.in
.security_flags
= 0;
619 io
.ntcreatex
.in
.fname
= BASEDIR
;
621 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
622 notify
.nttrans
.in
.buffer_size
= 1000;
623 notify
.nttrans
.in
.recursive
= true;
625 chkpath
.chkpath
.in
.path
= "\\";
627 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, expected, nchanges) \
629 smbcli_getatr(cli->tree, test_name, NULL, NULL, NULL); \
630 do { for (mask=i=0;i<32;i++) { \
631 struct smbcli_request *req; \
632 status = smb_raw_open(cli->tree, tctx, &io); \
633 CHECK_STATUS(status, NT_STATUS_OK); \
634 fnum = io.ntcreatex.out.file.fnum; \
636 notify.nttrans.in.file.fnum = fnum; \
637 notify.nttrans.in.completion_filter = (1<<i); \
638 req = smb_raw_changenotify_send(cli->tree, ¬ify); \
639 smb_raw_chkpath(cli->tree, &chkpath); \
641 smb_msleep(200); smb_raw_ntcancel(req); \
642 status = smb_raw_changenotify_recv(req, tctx, ¬ify); \
644 smbcli_close(cli->tree, fnum); \
645 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
646 CHECK_STATUS(status, NT_STATUS_OK); \
647 /* special case to cope with file rename behaviour */ \
648 if (nchanges == 2 && notify.nttrans.out.num_changes == 1 && \
649 notify.nttrans.out.changes[0].action == NOTIFY_ACTION_MODIFIED && \
650 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
651 Action == NOTIFY_ACTION_OLD_NAME) { \
652 printf("(rename file special handling OK)\n"); \
653 } else if (nchanges != notify.nttrans.out.num_changes) { \
654 printf("ERROR: nchanges=%d expected=%d action=%d filter=0x%08x\n", \
655 notify.nttrans.out.num_changes, \
657 notify.nttrans.out.changes[0].action, \
658 notify.nttrans.in.completion_filter); \
660 } else if (notify.nttrans.out.changes[0].action != Action) { \
661 printf("ERROR: nchanges=%d action=%d expectedAction=%d filter=0x%08x\n", \
662 notify.nttrans.out.num_changes, \
663 notify.nttrans.out.changes[0].action, \
665 notify.nttrans.in.completion_filter); \
667 } else if (strcmp(notify.nttrans.out.changes[0].name.s, "tname1") != 0) { \
668 printf("ERROR: nchanges=%d action=%d filter=0x%08x name=%s\n", \
669 notify.nttrans.out.num_changes, \
670 notify.nttrans.out.changes[0].action, \
671 notify.nttrans.in.completion_filter, \
672 notify.nttrans.out.changes[0].name.s); \
677 if ((expected) != mask) { \
678 if (((expected) & ~mask) != 0) { \
679 printf("ERROR: trigger on too few bits. mask=0x%08x expected=0x%08x\n", \
683 printf("WARNING: trigger on too many bits. mask=0x%08x expected=0x%08x\n", \
690 printf("Testing mkdir\n");
691 NOTIFY_MASK_TEST("Testing mkdir",;,
692 smbcli_mkdir(cli
->tree
, BASEDIR
"\\tname1");,
693 smbcli_rmdir(cli2
->tree
, BASEDIR
"\\tname1");,
695 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
697 printf("Testing create file\n");
698 NOTIFY_MASK_TEST("Testing create file",;,
699 smbcli_close(cli
->tree
, smbcli_open(cli
->tree
, BASEDIR
"\\tname1", O_CREAT
, 0));,
700 smbcli_unlink(cli2
->tree
, BASEDIR
"\\tname1");,
702 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
704 printf("Testing unlink\n");
705 NOTIFY_MASK_TEST("Testing unlink",
706 smbcli_close(cli
->tree
, smbcli_open(cli
->tree
, BASEDIR
"\\tname1", O_CREAT
, 0));,
707 smbcli_unlink(cli2
->tree
, BASEDIR
"\\tname1");,
709 NOTIFY_ACTION_REMOVED
,
710 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
712 printf("Testing rmdir\n");
713 NOTIFY_MASK_TEST("Testing rmdir",
714 smbcli_mkdir(cli
->tree
, BASEDIR
"\\tname1");,
715 smbcli_rmdir(cli2
->tree
, BASEDIR
"\\tname1");,
717 NOTIFY_ACTION_REMOVED
,
718 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
720 printf("Testing rename file\n");
721 NOTIFY_MASK_TEST("Testing rename file",
722 smbcli_close(cli
->tree
, smbcli_open(cli
->tree
, BASEDIR
"\\tname1", O_CREAT
, 0));,
723 smbcli_rename(cli2
->tree
, BASEDIR
"\\tname1", BASEDIR
"\\tname2");,
724 smbcli_unlink(cli
->tree
, BASEDIR
"\\tname2");,
725 NOTIFY_ACTION_OLD_NAME
,
726 FILE_NOTIFY_CHANGE_FILE_NAME
|FILE_NOTIFY_CHANGE_ATTRIBUTES
|FILE_NOTIFY_CHANGE_CREATION
, 2);
728 printf("Testing rename dir\n");
729 NOTIFY_MASK_TEST("Testing rename dir",
730 smbcli_mkdir(cli
->tree
, BASEDIR
"\\tname1");,
731 smbcli_rename(cli2
->tree
, BASEDIR
"\\tname1", BASEDIR
"\\tname2");,
732 smbcli_rmdir(cli
->tree
, BASEDIR
"\\tname2");,
733 NOTIFY_ACTION_OLD_NAME
,
734 FILE_NOTIFY_CHANGE_DIR_NAME
, 2);
736 printf("Testing set path attribute\n");
737 NOTIFY_MASK_TEST("Testing set path attribute",
738 smbcli_close(cli
->tree
, smbcli_open(cli
->tree
, BASEDIR
"\\tname1", O_CREAT
, 0));,
739 smbcli_setatr(cli2
->tree
, BASEDIR
"\\tname1", FILE_ATTRIBUTE_HIDDEN
, 0);,
740 smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1");,
741 NOTIFY_ACTION_MODIFIED
,
742 FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
744 printf("Testing set path write time\n");
745 NOTIFY_MASK_TEST("Testing set path write time",
746 smbcli_close(cli
->tree
, smbcli_open(cli
->tree
, BASEDIR
"\\tname1", O_CREAT
, 0));,
747 smbcli_setatr(cli2
->tree
, BASEDIR
"\\tname1", FILE_ATTRIBUTE_NORMAL
, 1000);,
748 smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1");,
749 NOTIFY_ACTION_MODIFIED
,
750 FILE_NOTIFY_CHANGE_LAST_WRITE
, 1);
752 printf("Testing set file attribute\n");
753 NOTIFY_MASK_TEST("Testing set file attribute",
754 fnum2
= create_complex_file(cli2
, tctx
, BASEDIR
"\\tname1");,
755 smbcli_fsetatr(cli2
->tree
, fnum2
, FILE_ATTRIBUTE_HIDDEN
, 0, 0, 0, 0);,
756 (smbcli_close(cli2
->tree
, fnum2
), smbcli_unlink(cli2
->tree
, BASEDIR
"\\tname1"));,
757 NOTIFY_ACTION_MODIFIED
,
758 FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
760 if (torture_setting_bool(tctx
, "samba3", false)) {
761 printf("Samba3 does not yet support create times "
765 printf("Testing set file create time\n");
766 NOTIFY_MASK_TEST("Testing set file create time",
767 fnum2
= create_complex_file(cli
, tctx
,
768 BASEDIR
"\\tname1");,
769 smbcli_fsetatr(cli
->tree
, fnum2
, 0, t
, 0, 0, 0);,
770 (smbcli_close(cli
->tree
, fnum2
),
771 smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1"));,
772 NOTIFY_ACTION_MODIFIED
,
773 FILE_NOTIFY_CHANGE_CREATION
, 1);
776 printf("Testing set file access time\n");
777 NOTIFY_MASK_TEST("Testing set file access time",
778 fnum2
= create_complex_file(cli
, tctx
, BASEDIR
"\\tname1");,
779 smbcli_fsetatr(cli
->tree
, fnum2
, 0, 0, t
, 0, 0);,
780 (smbcli_close(cli
->tree
, fnum2
), smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1"));,
781 NOTIFY_ACTION_MODIFIED
,
782 FILE_NOTIFY_CHANGE_LAST_ACCESS
, 1);
784 printf("Testing set file write time\n");
785 NOTIFY_MASK_TEST("Testing set file write time",
786 fnum2
= create_complex_file(cli
, tctx
, BASEDIR
"\\tname1");,
787 smbcli_fsetatr(cli
->tree
, fnum2
, 0, 0, 0, t
, 0);,
788 (smbcli_close(cli
->tree
, fnum2
), smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1"));,
789 NOTIFY_ACTION_MODIFIED
,
790 FILE_NOTIFY_CHANGE_LAST_WRITE
, 1);
792 printf("Testing set file change time\n");
793 NOTIFY_MASK_TEST("Testing set file change time",
794 fnum2
= create_complex_file(cli
, tctx
, BASEDIR
"\\tname1");,
795 smbcli_fsetatr(cli
->tree
, fnum2
, 0, 0, 0, 0, t
);,
796 (smbcli_close(cli
->tree
, fnum2
), smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1"));,
797 NOTIFY_ACTION_MODIFIED
,
801 printf("Testing write\n");
802 NOTIFY_MASK_TEST("Testing write",
803 fnum2
= create_complex_file(cli2
, tctx
, BASEDIR
"\\tname1");,
804 smbcli_write(cli2
->tree
, fnum2
, 1, &c
, 10000, 1);,
805 (smbcli_close(cli2
->tree
, fnum2
), smbcli_unlink(cli
->tree
, BASEDIR
"\\tname1"));,
806 NOTIFY_ACTION_MODIFIED
,
809 printf("Testing truncate\n");
810 NOTIFY_MASK_TEST("Testing truncate",
811 fnum2
= create_complex_file(cli2
, tctx
, BASEDIR
"\\tname1");,
812 smbcli_ftruncate(cli2
->tree
, fnum2
, 10000);,
813 (smbcli_close(cli2
->tree
, fnum2
), smbcli_unlink(cli2
->tree
, BASEDIR
"\\tname1"));,
814 NOTIFY_ACTION_MODIFIED
,
815 FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
818 smb_raw_exit(cli
->session
);
819 smbcli_deltree(cli
->tree
, BASEDIR
);
824 basic testing of change notify on files
826 static bool test_notify_file(struct torture_context
*mem_ctx
,
827 struct smbcli_state
*cli
)
833 union smb_notify notify
;
834 struct smbcli_request
*req
;
836 const char *fname
= BASEDIR
"\\file.txt";
838 printf("TESTING CHANGE NOTIFY ON FILES\n");
840 if (!torture_setup_dir(cli
, BASEDIR
)) {
844 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
845 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
846 io
.ntcreatex
.in
.flags
= 0;
847 io
.ntcreatex
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
848 io
.ntcreatex
.in
.create_options
= 0;
849 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
850 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
851 io
.ntcreatex
.in
.alloc_size
= 0;
852 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
853 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
854 io
.ntcreatex
.in
.security_flags
= 0;
855 io
.ntcreatex
.in
.fname
= fname
;
856 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
857 CHECK_STATUS(status
, NT_STATUS_OK
);
858 fnum
= io
.ntcreatex
.out
.file
.fnum
;
860 /* ask for a change notify,
861 on file or directory name changes */
862 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
863 notify
.nttrans
.in
.file
.fnum
= fnum
;
864 notify
.nttrans
.in
.buffer_size
= 1000;
865 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_STREAM_NAME
;
866 notify
.nttrans
.in
.recursive
= false;
868 printf("Testing if notifies on file handles are invalid (should be)\n");
870 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
871 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
872 CHECK_STATUS(status
, NT_STATUS_INVALID_PARAMETER
);
874 cl
.close
.level
= RAW_CLOSE_CLOSE
;
875 cl
.close
.in
.file
.fnum
= fnum
;
876 cl
.close
.in
.write_time
= 0;
877 status
= smb_raw_close(cli
->tree
, &cl
);
878 CHECK_STATUS(status
, NT_STATUS_OK
);
880 status
= smbcli_unlink(cli
->tree
, fname
);
881 CHECK_STATUS(status
, NT_STATUS_OK
);
884 smb_raw_exit(cli
->session
);
885 smbcli_deltree(cli
->tree
, BASEDIR
);
890 basic testing of change notifies followed by a tdis
892 static bool test_notify_tdis(struct torture_context
*tctx
,
893 struct smbcli_state
*cli1
)
897 union smb_notify notify
;
900 struct smbcli_request
*req
;
901 struct smbcli_state
*cli
= NULL
;
903 printf("TESTING CHANGE NOTIFY FOLLOWED BY TDIS\n");
905 if (!torture_setup_dir(cli1
, BASEDIR
)) {
909 if (!torture_open_connection(&cli
, tctx
, 0)) {
914 get a handle on the directory
916 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
917 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
918 io
.ntcreatex
.in
.flags
= 0;
919 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
920 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
921 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
922 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
923 io
.ntcreatex
.in
.alloc_size
= 0;
924 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
925 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
926 io
.ntcreatex
.in
.security_flags
= 0;
927 io
.ntcreatex
.in
.fname
= BASEDIR
;
929 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
930 CHECK_STATUS(status
, NT_STATUS_OK
);
931 fnum
= io
.ntcreatex
.out
.file
.fnum
;
933 /* ask for a change notify,
934 on file or directory name changes */
935 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
936 notify
.nttrans
.in
.buffer_size
= 1000;
937 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
938 notify
.nttrans
.in
.file
.fnum
= fnum
;
939 notify
.nttrans
.in
.recursive
= true;
941 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
943 status
= smbcli_tdis(cli
);
944 CHECK_STATUS(status
, NT_STATUS_OK
);
947 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
948 CHECK_STATUS(status
, NT_STATUS_OK
);
949 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 0);
952 torture_close_connection(cli
);
953 smbcli_deltree(cli1
->tree
, BASEDIR
);
958 basic testing of change notifies followed by a exit
960 static bool test_notify_exit(struct torture_context
*tctx
,
961 struct smbcli_state
*cli1
)
965 union smb_notify notify
;
968 struct smbcli_request
*req
;
969 struct smbcli_state
*cli
= NULL
;
971 printf("TESTING CHANGE NOTIFY FOLLOWED BY EXIT\n");
973 if (!torture_setup_dir(cli1
, BASEDIR
)) {
977 if (!torture_open_connection(&cli
, tctx
, 0)) {
982 get a handle on the directory
984 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
985 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
986 io
.ntcreatex
.in
.flags
= 0;
987 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
988 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
989 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
990 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
991 io
.ntcreatex
.in
.alloc_size
= 0;
992 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
993 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
994 io
.ntcreatex
.in
.security_flags
= 0;
995 io
.ntcreatex
.in
.fname
= BASEDIR
;
997 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
998 CHECK_STATUS(status
, NT_STATUS_OK
);
999 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1001 /* ask for a change notify,
1002 on file or directory name changes */
1003 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1004 notify
.nttrans
.in
.buffer_size
= 1000;
1005 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1006 notify
.nttrans
.in
.file
.fnum
= fnum
;
1007 notify
.nttrans
.in
.recursive
= true;
1009 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1011 status
= smb_raw_exit(cli
->session
);
1012 CHECK_STATUS(status
, NT_STATUS_OK
);
1014 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
1015 CHECK_STATUS(status
, NT_STATUS_OK
);
1016 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 0);
1019 torture_close_connection(cli
);
1020 smbcli_deltree(cli1
->tree
, BASEDIR
);
1025 basic testing of change notifies followed by a ulogoff
1027 static bool test_notify_ulogoff(struct torture_context
*tctx
,
1028 struct smbcli_state
*cli1
)
1032 union smb_notify notify
;
1035 struct smbcli_request
*req
;
1036 struct smbcli_state
*cli
= NULL
;
1038 printf("TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1040 if (!torture_setup_dir(cli1
, BASEDIR
)) {
1044 if (!torture_open_connection(&cli
, tctx
, 0)) {
1049 get a handle on the directory
1051 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1052 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1053 io
.ntcreatex
.in
.flags
= 0;
1054 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1055 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1056 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1057 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
1058 io
.ntcreatex
.in
.alloc_size
= 0;
1059 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1060 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1061 io
.ntcreatex
.in
.security_flags
= 0;
1062 io
.ntcreatex
.in
.fname
= BASEDIR
;
1064 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1065 CHECK_STATUS(status
, NT_STATUS_OK
);
1066 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1068 /* ask for a change notify,
1069 on file or directory name changes */
1070 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1071 notify
.nttrans
.in
.buffer_size
= 1000;
1072 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1073 notify
.nttrans
.in
.file
.fnum
= fnum
;
1074 notify
.nttrans
.in
.recursive
= true;
1076 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1078 status
= smb_raw_ulogoff(cli
->session
);
1079 CHECK_STATUS(status
, NT_STATUS_OK
);
1081 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
1082 CHECK_STATUS(status
, NT_STATUS_OK
);
1083 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 0);
1086 torture_close_connection(cli
);
1087 smbcli_deltree(cli1
->tree
, BASEDIR
);
1091 static void tcp_dis_handler(struct smbcli_transport
*t
, void *p
)
1093 struct smbcli_state
*cli
= (struct smbcli_state
*)p
;
1094 smbcli_transport_dead(cli
->transport
, NT_STATUS_LOCAL_DISCONNECT
);
1095 cli
->transport
= NULL
;
1099 basic testing of change notifies followed by tcp disconnect
1101 static bool test_notify_tcp_dis(struct torture_context
*tctx
,
1102 struct smbcli_state
*cli1
)
1106 union smb_notify notify
;
1109 struct smbcli_request
*req
;
1110 struct smbcli_state
*cli
= NULL
;
1112 printf("TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1114 if (!torture_setup_dir(cli1
, BASEDIR
)) {
1118 if (!torture_open_connection(&cli
, tctx
, 0)) {
1123 get a handle on the directory
1125 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1126 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1127 io
.ntcreatex
.in
.flags
= 0;
1128 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1129 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1130 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1131 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
1132 io
.ntcreatex
.in
.alloc_size
= 0;
1133 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1134 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1135 io
.ntcreatex
.in
.security_flags
= 0;
1136 io
.ntcreatex
.in
.fname
= BASEDIR
;
1138 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1139 CHECK_STATUS(status
, NT_STATUS_OK
);
1140 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1142 /* ask for a change notify,
1143 on file or directory name changes */
1144 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1145 notify
.nttrans
.in
.buffer_size
= 1000;
1146 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1147 notify
.nttrans
.in
.file
.fnum
= fnum
;
1148 notify
.nttrans
.in
.recursive
= true;
1150 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1152 smbcli_transport_idle_handler(cli
->transport
, tcp_dis_handler
, 250, cli
);
1154 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
1155 CHECK_STATUS(status
, NT_STATUS_LOCAL_DISCONNECT
);
1158 torture_close_connection(cli
);
1159 smbcli_deltree(cli1
->tree
, BASEDIR
);
1164 test setting up two change notify requests on one handle
1166 static bool test_notify_double(struct torture_context
*mem_ctx
,
1167 struct smbcli_state
*cli
)
1171 union smb_notify notify
;
1174 struct smbcli_request
*req1
, *req2
;
1176 printf("TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1178 if (!torture_setup_dir(cli
, BASEDIR
)) {
1182 get a handle on the directory
1184 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1185 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1186 io
.ntcreatex
.in
.flags
= 0;
1187 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1188 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1189 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1190 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
1191 io
.ntcreatex
.in
.alloc_size
= 0;
1192 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1193 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1194 io
.ntcreatex
.in
.security_flags
= 0;
1195 io
.ntcreatex
.in
.fname
= BASEDIR
;
1197 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
1198 CHECK_STATUS(status
, NT_STATUS_OK
);
1199 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1201 /* ask for a change notify,
1202 on file or directory name changes */
1203 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1204 notify
.nttrans
.in
.buffer_size
= 1000;
1205 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1206 notify
.nttrans
.in
.file
.fnum
= fnum
;
1207 notify
.nttrans
.in
.recursive
= true;
1209 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1210 req2
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1212 smbcli_mkdir(cli
->tree
, BASEDIR
"\\subdir-name");
1214 status
= smb_raw_changenotify_recv(req1
, mem_ctx
, ¬ify
);
1215 CHECK_STATUS(status
, NT_STATUS_OK
);
1216 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
1217 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subdir-name", STR_UNICODE
);
1219 smbcli_mkdir(cli
->tree
, BASEDIR
"\\subdir-name2");
1221 status
= smb_raw_changenotify_recv(req2
, mem_ctx
, ¬ify
);
1222 CHECK_STATUS(status
, NT_STATUS_OK
);
1223 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
1224 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subdir-name2", STR_UNICODE
);
1227 smb_raw_exit(cli
->session
);
1228 smbcli_deltree(cli
->tree
, BASEDIR
);
1234 test multiple change notifies at different depths and with/without recursion
1236 static bool test_notify_tree(struct torture_context
*mem_ctx
,
1237 struct smbcli_state
*cli
,
1238 struct smbcli_state
*cli2
)
1241 union smb_notify notify
;
1243 struct smbcli_request
*req
;
1253 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 30 },
1254 {BASEDIR
"\\zqy", true, FILE_NOTIFY_CHANGE_NAME
, 8 },
1255 {BASEDIR
"\\atsy", true, FILE_NOTIFY_CHANGE_NAME
, 4 },
1256 {BASEDIR
"\\abc\\foo", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1257 {BASEDIR
"\\abc\\blah", true, FILE_NOTIFY_CHANGE_NAME
, 13 },
1258 {BASEDIR
"\\abc\\blah", false, FILE_NOTIFY_CHANGE_NAME
, 7 },
1259 {BASEDIR
"\\abc\\blah\\a", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1260 {BASEDIR
"\\abc\\blah\\b", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1261 {BASEDIR
"\\abc\\blah\\c", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1262 {BASEDIR
"\\abc\\fooblah", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1263 {BASEDIR
"\\zqy\\xx", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1264 {BASEDIR
"\\zqy\\yyy", true, FILE_NOTIFY_CHANGE_NAME
, 2 },
1265 {BASEDIR
"\\zqy\\..", true, FILE_NOTIFY_CHANGE_NAME
, 40 },
1266 {BASEDIR
, true, FILE_NOTIFY_CHANGE_NAME
, 40 },
1267 {BASEDIR
, false,FILE_NOTIFY_CHANGE_NAME
, 6 },
1268 {BASEDIR
"\\atsy", false,FILE_NOTIFY_CHANGE_NAME
, 4 },
1269 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 24 },
1270 {BASEDIR
"\\abc", false,FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1271 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_FILE_NAME
, 0 },
1272 {BASEDIR
"\\abc", true, FILE_NOTIFY_CHANGE_NAME
, 24 },
1276 bool all_done
= false;
1278 printf("TESTING CHANGE NOTIFY FOR DIFFERENT DEPTHS\n");
1280 if (!torture_setup_dir(cli
, BASEDIR
)) {
1284 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1285 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1286 io
.ntcreatex
.in
.flags
= 0;
1287 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1288 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1289 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1290 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
1291 io
.ntcreatex
.in
.alloc_size
= 0;
1292 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1293 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1294 io
.ntcreatex
.in
.security_flags
= 0;
1296 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1297 notify
.nttrans
.in
.buffer_size
= 20000;
1300 setup the directory tree, and the notify buffer on each directory
1302 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1303 io
.ntcreatex
.in
.fname
= dirs
[i
].path
;
1304 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
1305 CHECK_STATUS(status
, NT_STATUS_OK
);
1306 dirs
[i
].fnum
= io
.ntcreatex
.out
.file
.fnum
;
1308 notify
.nttrans
.in
.completion_filter
= dirs
[i
].filter
;
1309 notify
.nttrans
.in
.file
.fnum
= dirs
[i
].fnum
;
1310 notify
.nttrans
.in
.recursive
= dirs
[i
].recursive
;
1311 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1312 smb_raw_ntcancel(req
);
1313 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
1314 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1317 /* trigger 2 events in each dir */
1318 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1319 char *path
= talloc_asprintf(mem_ctx
, "%s\\test.dir", dirs
[i
].path
);
1321 * Make notifies a bit more interesting in a cluster
1322 * by doing the changes against different nodes with
1325 smbcli_mkdir(cli
->tree
, path
);
1326 smbcli_rmdir(cli2
->tree
, path
);
1330 /* give a bit of time for the events to propogate */
1331 tv
= timeval_current();
1334 /* count events that have happened in each dir */
1335 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1336 notify
.nttrans
.in
.file
.fnum
= dirs
[i
].fnum
;
1337 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1338 smb_raw_ntcancel(req
);
1339 notify
.nttrans
.out
.num_changes
= 0;
1340 status
= smb_raw_changenotify_recv(req
, mem_ctx
, ¬ify
);
1341 dirs
[i
].counted
+= notify
.nttrans
.out
.num_changes
;
1346 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1347 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1351 } while (!all_done
&& timeval_elapsed(&tv
) < 20);
1353 printf("took %.4f seconds to propogate all events\n", timeval_elapsed(&tv
));
1355 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1356 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1357 printf("ERROR: i=%d expected %d got %d for '%s'\n",
1358 i
, dirs
[i
].expected
, dirs
[i
].counted
, dirs
[i
].path
);
1364 run from the back, closing and deleting
1366 for (i
=ARRAY_SIZE(dirs
)-1;i
>=0;i
--) {
1367 smbcli_close(cli
->tree
, dirs
[i
].fnum
);
1368 smbcli_rmdir(cli
->tree
, dirs
[i
].path
);
1372 smb_raw_exit(cli
->session
);
1373 smbcli_deltree(cli
->tree
, BASEDIR
);
1378 Test response when cached server events exceed single NT NOTFIY response
1381 static bool test_notify_overflow(struct torture_context
*mem_ctx
,
1382 struct smbcli_state
*cli
)
1386 union smb_notify notify
;
1390 struct smbcli_request
*req1
;
1393 printf("TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1395 if (!torture_setup_dir(cli
, BASEDIR
)) {
1399 /* get a handle on the directory */
1400 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1401 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1402 io
.ntcreatex
.in
.flags
= 0;
1403 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1404 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1405 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1406 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1407 NTCREATEX_SHARE_ACCESS_WRITE
;
1408 io
.ntcreatex
.in
.alloc_size
= 0;
1409 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1410 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1411 io
.ntcreatex
.in
.security_flags
= 0;
1412 io
.ntcreatex
.in
.fname
= BASEDIR
;
1414 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
1415 CHECK_STATUS(status
, NT_STATUS_OK
);
1416 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1418 /* ask for a change notify, on name changes. */
1419 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1420 notify
.nttrans
.in
.buffer_size
= 1000;
1421 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1422 notify
.nttrans
.in
.file
.fnum
= fnum
;
1424 notify
.nttrans
.in
.recursive
= true;
1425 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1427 /* cancel initial requests so the buffer is setup */
1428 smb_raw_ntcancel(req1
);
1429 status
= smb_raw_changenotify_recv(req1
, mem_ctx
, ¬ify
);
1430 CHECK_STATUS(status
, NT_STATUS_CANCELLED
);
1432 /* open a lot of files, filling up the server side notify buffer */
1433 printf("Testing overflowed buffer notify on create of %d files\n",
1435 for (i
=0;i
<count
;i
++) {
1436 char *fname
= talloc_asprintf(cli
, BASEDIR
"\\test%d.txt", i
);
1437 int fnum2
= smbcli_open(cli
->tree
, fname
, O_CREAT
|O_RDWR
,
1440 printf("Failed to create %s - %s\n",
1441 fname
, smbcli_errstr(cli
->tree
));
1446 smbcli_close(cli
->tree
, fnum2
);
1449 /* expect that 0 events will be returned with NT_STATUS_OK */
1450 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1451 status
= smb_raw_changenotify_recv(req1
, mem_ctx
, ¬ify
);
1452 CHECK_STATUS(status
, NT_STATUS_OK
);
1453 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 0);
1456 smb_raw_exit(cli
->session
);
1457 smbcli_deltree(cli
->tree
, BASEDIR
);
1462 Test if notifications are returned for changes to the base directory.
1465 static bool test_notify_basedir(struct torture_context
*mem_ctx
,
1466 struct smbcli_state
*cli
)
1470 union smb_notify notify
;
1473 struct smbcli_request
*req1
;
1475 printf("TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1477 if (!torture_setup_dir(cli
, BASEDIR
)) {
1481 /* get a handle on the directory */
1482 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1483 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1484 io
.ntcreatex
.in
.flags
= 0;
1485 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1486 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1487 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1488 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1489 NTCREATEX_SHARE_ACCESS_WRITE
;
1490 io
.ntcreatex
.in
.alloc_size
= 0;
1491 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1492 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1493 io
.ntcreatex
.in
.security_flags
= 0;
1494 io
.ntcreatex
.in
.fname
= BASEDIR
;
1496 status
= smb_raw_open(cli
->tree
, mem_ctx
, &io
);
1497 CHECK_STATUS(status
, NT_STATUS_OK
);
1498 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1500 /* create a test file that will also be modified */
1501 smbcli_close(cli
->tree
, smbcli_open(cli
->tree
, BASEDIR
"\\tname1",
1504 /* ask for a change notify, on attribute changes. */
1505 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1506 notify
.nttrans
.in
.buffer_size
= 1000;
1507 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
1508 notify
.nttrans
.in
.file
.fnum
= fnum
;
1509 notify
.nttrans
.in
.recursive
= true;
1511 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1513 /* set attribute on the base dir */
1514 smbcli_setatr(cli
->tree
, BASEDIR
, FILE_ATTRIBUTE_HIDDEN
, 0);
1516 /* set attribute on a file to assure we receive a notification */
1517 smbcli_setatr(cli
->tree
, BASEDIR
"\\tname1", FILE_ATTRIBUTE_HIDDEN
, 0);
1520 /* check how many responses were given, expect only 1 for the file */
1521 status
= smb_raw_changenotify_recv(req1
, mem_ctx
, ¬ify
);
1522 CHECK_STATUS(status
, NT_STATUS_OK
);
1523 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
1524 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_MODIFIED
);
1525 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "tname1", STR_UNICODE
);
1528 smb_raw_exit(cli
->session
);
1529 smbcli_deltree(cli
->tree
, BASEDIR
);
1535 create a secondary tree connect - used to test for a bug in Samba3 messaging
1538 static struct smbcli_tree
*secondary_tcon(struct smbcli_state
*cli
,
1539 struct torture_context
*tctx
)
1542 const char *share
, *host
;
1543 struct smbcli_tree
*tree
;
1544 union smb_tcon tcon
;
1546 share
= torture_setting_string(tctx
, "share", NULL
);
1547 host
= torture_setting_string(tctx
, "host", NULL
);
1549 printf("create a second tree context on the same session\n");
1550 tree
= smbcli_tree_init(cli
->session
, tctx
, false);
1552 tcon
.generic
.level
= RAW_TCON_TCONX
;
1553 tcon
.tconx
.in
.flags
= TCONX_FLAG_EXTENDED_RESPONSE
;
1554 tcon
.tconx
.in
.password
= data_blob(NULL
, 0);
1555 tcon
.tconx
.in
.path
= talloc_asprintf(tctx
, "\\\\%s\\%s", host
, share
);
1556 tcon
.tconx
.in
.device
= "A:";
1557 status
= smb_raw_tcon(tree
, tctx
, &tcon
);
1558 if (!NT_STATUS_IS_OK(status
)) {
1560 printf("Failed to create secondary tree\n");
1564 tree
->tid
= tcon
.tconx
.out
.tid
;
1565 printf("tid1=%d tid2=%d\n", cli
->tree
->tid
, tree
->tid
);
1572 very simple change notify test
1574 static bool test_notify_tcon(struct torture_context
*torture
,
1575 struct smbcli_state
*cli
)
1579 union smb_notify notify
;
1582 struct smbcli_request
*req
;
1583 extern int torture_numops
;
1584 struct smbcli_tree
*tree
= NULL
;
1586 printf("TESTING SIMPLE CHANGE NOTIFY\n");
1588 if (!torture_setup_dir(cli
, BASEDIR
)) {
1593 get a handle on the directory
1595 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1596 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1597 io
.ntcreatex
.in
.flags
= 0;
1598 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1599 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1600 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1601 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
1602 io
.ntcreatex
.in
.alloc_size
= 0;
1603 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1604 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1605 io
.ntcreatex
.in
.security_flags
= 0;
1606 io
.ntcreatex
.in
.fname
= BASEDIR
;
1608 status
= smb_raw_open(cli
->tree
, torture
, &io
);
1609 CHECK_STATUS(status
, NT_STATUS_OK
);
1610 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1612 status
= smb_raw_open(cli
->tree
, torture
, &io
);
1613 CHECK_STATUS(status
, NT_STATUS_OK
);
1615 /* ask for a change notify,
1616 on file or directory name changes */
1617 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1618 notify
.nttrans
.in
.buffer_size
= 1000;
1619 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1620 notify
.nttrans
.in
.file
.fnum
= fnum
;
1621 notify
.nttrans
.in
.recursive
= true;
1623 printf("Testing notify mkdir\n");
1624 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1625 smbcli_mkdir(cli
->tree
, BASEDIR
"\\subdir-name");
1627 status
= smb_raw_changenotify_recv(req
, torture
, ¬ify
);
1628 CHECK_STATUS(status
, NT_STATUS_OK
);
1630 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
1631 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
1632 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subdir-name", STR_UNICODE
);
1634 printf("Testing notify rmdir\n");
1635 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1636 smbcli_rmdir(cli
->tree
, BASEDIR
"\\subdir-name");
1638 status
= smb_raw_changenotify_recv(req
, torture
, ¬ify
);
1639 CHECK_STATUS(status
, NT_STATUS_OK
);
1640 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
1641 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
1642 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subdir-name", STR_UNICODE
);
1644 printf("SIMPLE CHANGE NOTIFY OK\n");
1646 printf("TESTING WITH SECONDARY TCON\n");
1647 tree
= secondary_tcon(cli
, torture
);
1649 printf("Testing notify mkdir\n");
1650 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1651 smbcli_mkdir(cli
->tree
, BASEDIR
"\\subdir-name");
1653 status
= smb_raw_changenotify_recv(req
, torture
, ¬ify
);
1654 CHECK_STATUS(status
, NT_STATUS_OK
);
1656 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
1657 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
1658 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subdir-name", STR_UNICODE
);
1660 printf("Testing notify rmdir\n");
1661 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1662 smbcli_rmdir(cli
->tree
, BASEDIR
"\\subdir-name");
1664 status
= smb_raw_changenotify_recv(req
, torture
, ¬ify
);
1665 CHECK_STATUS(status
, NT_STATUS_OK
);
1666 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
1667 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
1668 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subdir-name", STR_UNICODE
);
1670 printf("CHANGE NOTIFY WITH TCON OK\n");
1672 printf("Disconnecting secondary tree\n");
1673 status
= smb_tree_disconnect(tree
);
1674 CHECK_STATUS(status
, NT_STATUS_OK
);
1677 printf("Testing notify mkdir\n");
1678 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1679 smbcli_mkdir(cli
->tree
, BASEDIR
"\\subdir-name");
1681 status
= smb_raw_changenotify_recv(req
, torture
, ¬ify
);
1682 CHECK_STATUS(status
, NT_STATUS_OK
);
1684 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
1685 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_ADDED
);
1686 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subdir-name", STR_UNICODE
);
1688 printf("Testing notify rmdir\n");
1689 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1690 smbcli_rmdir(cli
->tree
, BASEDIR
"\\subdir-name");
1692 status
= smb_raw_changenotify_recv(req
, torture
, ¬ify
);
1693 CHECK_STATUS(status
, NT_STATUS_OK
);
1694 CHECK_VAL(notify
.nttrans
.out
.num_changes
, 1);
1695 CHECK_VAL(notify
.nttrans
.out
.changes
[0].action
, NOTIFY_ACTION_REMOVED
);
1696 CHECK_WSTR(notify
.nttrans
.out
.changes
[0].name
, "subdir-name", STR_UNICODE
);
1698 printf("CHANGE NOTIFY WITH TDIS OK\n");
1700 smb_raw_exit(cli
->session
);
1701 smbcli_deltree(cli
->tree
, BASEDIR
);
1707 testing alignment of multiple change notify infos
1709 static bool test_notify_alignment(struct torture_context
*tctx
,
1710 struct smbcli_state
*cli
)
1713 union smb_notify notify
;
1716 struct smbcli_request
*req
;
1717 const char *fname
= BASEDIR
"\\starter";
1718 const char *fnames
[] = { "a",
1722 int num_names
= ARRAY_SIZE(fnames
);
1725 torture_comment(tctx
, "TESTING CHANGE NOTIFY REPLY ALIGNMENT\n");
1727 if (!torture_setup_dir(cli
, BASEDIR
)) {
1731 /* get a handle on the directory */
1732 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1733 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1734 io
.ntcreatex
.in
.flags
= 0;
1735 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1736 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1737 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1738 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1739 NTCREATEX_SHARE_ACCESS_WRITE
;
1740 io
.ntcreatex
.in
.alloc_size
= 0;
1741 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1742 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1743 io
.ntcreatex
.in
.security_flags
= 0;
1744 io
.ntcreatex
.in
.fname
= BASEDIR
;
1746 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1747 torture_assert_ntstatus_ok(tctx
, status
, "");
1748 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1750 /* ask for a change notify, on file creation */
1751 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1752 notify
.nttrans
.in
.buffer_size
= 1000;
1753 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_FILE_NAME
;
1754 notify
.nttrans
.in
.file
.fnum
= fnum
;
1755 notify
.nttrans
.in
.recursive
= false;
1757 /* start change tracking */
1758 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1760 fnum2
= smbcli_open(cli
->tree
, fname
, O_CREAT
|O_RDWR
, DENY_NONE
);
1761 torture_assert(tctx
, fnum2
!= -1, smbcli_errstr(cli
->tree
));
1762 smbcli_close(cli
->tree
, fnum2
);
1764 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
1765 torture_assert_ntstatus_ok(tctx
, status
, "");
1767 /* create 4 files that will cause CHANGE_NOTIFY_INFO structures
1768 * to be returned in the same packet with all possible 4-byte padding
1769 * permutations. As per MS-CIFS 2.2.7.4.2 these structures should be
1770 * 4-byte aligned. */
1772 for (i
= 0; i
< num_names
; i
++) {
1773 fpath
= talloc_asprintf(tctx
, "%s\\%s", BASEDIR
, fnames
[i
]);
1774 fnum2
= smbcli_open(cli
->tree
, fpath
,
1775 O_CREAT
|O_RDWR
, DENY_NONE
);
1776 torture_assert(tctx
, fnum2
!= -1, smbcli_errstr(cli
->tree
));
1777 smbcli_close(cli
->tree
, fnum2
);
1781 /* We send a notify packet, and let smb_raw_changenotify_recv() do
1782 * the alignment checking for us. */
1783 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1784 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
1785 torture_assert_ntstatus_ok(tctx
, status
, "");
1787 /* Do basic checking for correctness. */
1788 torture_assert(tctx
, notify
.nttrans
.out
.num_changes
== num_names
, "");
1789 for (i
= 0; i
< num_names
; i
++) {
1790 torture_assert(tctx
, notify
.nttrans
.out
.changes
[i
].action
==
1791 NOTIFY_ACTION_ADDED
, "");
1792 CHECK_WSTR2(tctx
, notify
.nttrans
.out
.changes
[i
].name
, fnames
[i
],
1796 smb_raw_exit(cli
->session
);
1797 smbcli_deltree(cli
->tree
, BASEDIR
);
1801 struct torture_suite
*torture_raw_notify(TALLOC_CTX
*mem_ctx
)
1803 struct torture_suite
*suite
= torture_suite_create(mem_ctx
, "notify");
1805 torture_suite_add_1smb_test(suite
, "tcon", test_notify_tcon
);
1806 torture_suite_add_2smb_test(suite
, "dir", test_notify_dir
);
1807 torture_suite_add_2smb_test(suite
, "mask", test_notify_mask
);
1808 torture_suite_add_2smb_test(suite
, "recursive", test_notify_recursive
);
1809 torture_suite_add_1smb_test(suite
, "mask_change",
1810 test_notify_mask_change
);
1811 torture_suite_add_1smb_test(suite
, "file", test_notify_file
);
1812 torture_suite_add_1smb_test(suite
, "tdis", test_notify_tdis
);
1813 torture_suite_add_1smb_test(suite
, "exit", test_notify_exit
);
1814 torture_suite_add_1smb_test(suite
, "ulogoff", test_notify_ulogoff
);
1815 torture_suite_add_1smb_test(suite
, "tcp_dis", test_notify_tcp_dis
);
1816 torture_suite_add_1smb_test(suite
, "double", test_notify_double
);
1817 torture_suite_add_2smb_test(suite
, "tree", test_notify_tree
);
1818 torture_suite_add_1smb_test(suite
, "overflow", test_notify_overflow
);
1819 torture_suite_add_1smb_test(suite
, "basedir", test_notify_basedir
);
1820 torture_suite_add_1smb_test(suite
, "alignment", test_notify_alignment
);