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"
27 #include "lib/events/events.h"
29 #define BASEDIR "\\test_notify"
31 #define CHECK_WSTR(tctx, field, value, flags) \
33 torture_assert_str_equal(tctx, field.s, value, "values don't match"); \
34 torture_assert(tctx, \
35 !wire_bad_flags(&field, STR_UNICODE, cli->transport), \
39 #define BASEDIR_CN1_DIR BASEDIR "_CN1_DIR"
42 basic testing of change notify on directories
44 static bool test_notify_dir(struct torture_context
*tctx
,
45 struct smbcli_state
*cli
,
46 struct smbcli_state
*cli2
)
50 union smb_notify notify
;
53 int i
, count
, fnum
, fnum2
;
54 struct smbcli_request
*req
, *req2
;
55 extern int torture_numops
;
57 torture_comment(tctx
, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
59 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR_CN1_DIR
),
60 "Failed to setup up test directory: " BASEDIR_CN1_DIR
);
63 get a handle on the directory
65 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
66 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
67 io
.ntcreatex
.in
.flags
= 0;
68 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
69 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
70 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
71 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
72 io
.ntcreatex
.in
.alloc_size
= 0;
73 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
74 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
75 io
.ntcreatex
.in
.security_flags
= 0;
76 io
.ntcreatex
.in
.fname
= BASEDIR_CN1_DIR
;
78 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
79 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
81 fnum
= io
.ntcreatex
.out
.file
.fnum
;
83 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
84 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
86 fnum2
= io
.ntcreatex
.out
.file
.fnum
;
88 /* ask for a change notify,
89 on file or directory name changes */
90 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
91 notify
.nttrans
.in
.buffer_size
= 1000;
92 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
93 notify
.nttrans
.in
.file
.fnum
= fnum
;
94 notify
.nttrans
.in
.recursive
= true;
96 torture_comment(tctx
, "Testing notify cancel\n");
98 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
99 smb_raw_ntcancel(req
);
100 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
101 torture_assert_ntstatus_equal_goto(tctx
, status
, NT_STATUS_CANCELLED
,
103 "smb_raw_changenotify_recv");
105 torture_comment(tctx
, "Testing notify mkdir\n");
107 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
108 smbcli_mkdir(cli2
->tree
, BASEDIR_CN1_DIR
"\\subdir-name");
110 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
111 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
112 "smb_raw_changenotify_recv");
114 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
115 1, ret
, done
, "more than one change");
116 torture_assert_int_equal_goto(tctx
,
117 notify
.nttrans
.out
.changes
[0].action
,
118 NOTIFY_ACTION_ADDED
, ret
, done
,
119 "wrong action (exp: ADDED)");
120 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "subdir-name",
123 torture_comment(tctx
, "Testing notify rmdir\n");
125 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
126 smbcli_rmdir(cli2
->tree
, BASEDIR_CN1_DIR
"\\subdir-name");
128 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
129 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
130 "smb_raw_changenotify_recv");
131 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
132 1, ret
, done
, "more than one change");
133 torture_assert_int_equal_goto(tctx
,
134 notify
.nttrans
.out
.changes
[0].action
,
135 NOTIFY_ACTION_REMOVED
, ret
, done
,
136 "wrong action (exp: REMOVED)");
137 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "subdir-name",
140 torture_comment(tctx
, "Testing notify mkdir - rmdir - mkdir - rmdir\n");
142 smbcli_mkdir(cli2
->tree
, BASEDIR_CN1_DIR
"\\subdir-name");
143 smbcli_rmdir(cli2
->tree
, BASEDIR_CN1_DIR
"\\subdir-name");
144 smbcli_mkdir(cli2
->tree
, BASEDIR_CN1_DIR
"\\subdir-name");
145 smbcli_rmdir(cli2
->tree
, BASEDIR_CN1_DIR
"\\subdir-name");
147 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
148 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
149 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
150 "smb_raw_changenotify_recv");
151 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
152 4, ret
, done
, "wrong number of changes");
153 torture_assert_int_equal_goto(tctx
,
154 notify
.nttrans
.out
.changes
[0].action
,
155 NOTIFY_ACTION_ADDED
, ret
, done
,
156 "wrong action (exp: ADDED)");
157 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "subdir-name",
159 torture_assert_int_equal_goto(tctx
,
160 notify
.nttrans
.out
.changes
[1].action
,
161 NOTIFY_ACTION_REMOVED
, ret
, done
,
162 "wrong action (exp: REMOVED)");
163 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[1].name
, "subdir-name",
165 torture_assert_int_equal_goto(tctx
,
166 notify
.nttrans
.out
.changes
[2].action
,
167 NOTIFY_ACTION_ADDED
, ret
, done
,
168 "wrong action (exp: ADDED)");
169 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[2].name
, "subdir-name",
171 torture_assert_int_equal_goto(tctx
,
172 notify
.nttrans
.out
.changes
[3].action
,
173 NOTIFY_ACTION_REMOVED
, ret
, done
,
174 "wrong action (exp: REMOVED)");
175 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[3].name
, "subdir-name",
178 count
= torture_numops
;
179 torture_comment(tctx
, "Testing buffered notify on create of %d files\n", count
);
180 for (i
=0;i
<count
;i
++) {
181 char *fname
= talloc_asprintf(cli
,
182 BASEDIR_CN1_DIR
"\\test%d.txt",
184 int fnum3
= smbcli_open(cli
->tree
, fname
, O_CREAT
|O_RDWR
, DENY_NONE
);
185 torture_assert_int_not_equal_goto(tctx
, fnum3
, -1, ret
, done
,
186 talloc_asprintf(tctx
, "Failed to create %s - %s",
187 fname
, smbcli_errstr(cli
->tree
)));
189 smbcli_close(cli
->tree
, fnum3
);
192 /* (1st notify) setup a new notify on a different directory handle.
193 This new notify won't see the events above. */
194 notify
.nttrans
.in
.file
.fnum
= fnum2
;
195 req2
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
197 /* (2nd notify) whereas this notify will see the above buffered events,
198 and it directly returns the buffered events */
199 notify
.nttrans
.in
.file
.fnum
= fnum
;
200 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
202 status
= smbcli_unlink(cli
->tree
, BASEDIR_CN1_DIR
"\\nonexistent.txt");
203 torture_assert_ntstatus_equal_goto(tctx
, status
,
204 NT_STATUS_OBJECT_NAME_NOT_FOUND
,
208 /* (1st unlink) as the 2nd notify directly returns,
209 this unlink is only seen by the 1st notify and
210 the 3rd notify (later) */
211 torture_comment(tctx
, "Testing notify on unlink for the first file\n");
212 status
= smbcli_unlink(cli2
->tree
, BASEDIR_CN1_DIR
"\\test0.txt");
213 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
216 /* receive the reply from the 2nd notify */
217 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
218 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
219 "smb_raw_changenotify_recv");
221 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
223 "wrong number of changes");
224 for (i
=1;i
<count
;i
++) {
225 torture_assert_int_equal_goto(tctx
,
226 notify
.nttrans
.out
.changes
[i
].action
,
227 NOTIFY_ACTION_ADDED
, ret
, done
,
228 "wrong action (exp: ADDED)");
230 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "test0.txt",
233 torture_comment(tctx
, "and now from the 1st notify\n");
234 status
= smb_raw_changenotify_recv(req2
, tctx
, ¬ify
);
235 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
236 "smb_raw_changenotify_recv");
237 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
238 1, ret
, done
, "wrong number of changes");
239 torture_assert_int_equal_goto(tctx
,
240 notify
.nttrans
.out
.changes
[0].action
,
241 NOTIFY_ACTION_REMOVED
, ret
, done
,
242 "wrong action (exp: REMOVED)");
243 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "test0.txt",
246 torture_comment(tctx
, "(3rd notify) this notify will only see the 1st unlink\n");
247 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
249 status
= smbcli_unlink(cli
->tree
, BASEDIR_CN1_DIR
"\\nonexistent.txt");
250 torture_assert_ntstatus_equal_goto(tctx
, status
,
251 NT_STATUS_OBJECT_NAME_NOT_FOUND
,
255 torture_comment(tctx
, "Testing notify on wildcard unlink for %d files\n", count
-1);
256 /* (2nd unlink) do a wildcard unlink */
257 status
= smbcli_unlink_wcard(cli2
->tree
, BASEDIR_CN1_DIR
"\\test*.txt");
258 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
259 "smb_raw_changenotify_recv");
261 /* receive the 3rd notify */
262 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
263 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
264 "smb_raw_changenotify_recv");
265 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
266 1, ret
, done
, "wrong number of changes");
267 torture_assert_int_equal_goto(tctx
,
268 notify
.nttrans
.out
.changes
[0].action
,
269 NOTIFY_ACTION_REMOVED
, ret
, done
,
270 "wrong action (exp: REMOVED)");
271 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "test0.txt",
274 /* and we now see the rest of the unlink calls on both directory handles */
275 notify
.nttrans
.in
.file
.fnum
= fnum
;
277 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
278 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
279 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
280 "smb_raw_changenotify_recv");
281 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
282 count
- 1, ret
, done
,
283 "wrong number of changes");
284 for (i
=0;i
<notify
.nttrans
.out
.num_changes
;i
++) {
285 torture_assert_int_equal_goto(tctx
,
286 notify
.nttrans
.out
.changes
[i
].action
,
287 NOTIFY_ACTION_REMOVED
, ret
, done
,
288 "wrong action (exp: REMOVED)");
290 notify
.nttrans
.in
.file
.fnum
= fnum2
;
291 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
292 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
293 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
294 "smb_raw_changenotify_recv");
295 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
296 count
- 1, ret
, done
,
297 "wrong number of changes");
298 for (i
=0;i
<notify
.nttrans
.out
.num_changes
;i
++) {
299 torture_assert_int_equal_goto(tctx
,
300 notify
.nttrans
.out
.changes
[i
].action
,
301 NOTIFY_ACTION_REMOVED
, ret
, done
,
302 "wrong action (exp: REMOVED)");
305 torture_comment(tctx
, "Testing if a close() on the dir handle triggers the notify reply\n");
307 notify
.nttrans
.in
.file
.fnum
= fnum
;
308 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
310 cl
.close
.level
= RAW_CLOSE_CLOSE
;
311 cl
.close
.in
.file
.fnum
= fnum
;
312 cl
.close
.in
.write_time
= 0;
313 status
= smb_raw_close(cli
->tree
, &cl
);
314 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
317 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
318 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
319 "smb_raw_changenotify_recv");
320 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
321 0, ret
, done
, "no changes expected");
324 smb_raw_exit(cli
->session
);
325 smbcli_deltree(cli
->tree
, BASEDIR_CN1_DIR
);
330 * Check notify reply for a rename action. Not sure if this is a valid thing
331 * to do, but depending on timing between inotify and messaging we get the
332 * add/remove/modify in any order. This routines tries to find the action/name
333 * pair in any of the three following notify_changes.
336 static bool check_rename_reply(struct torture_context
*tctx
,
337 struct smbcli_state
*cli
,
339 struct notify_changes
*actions
,
340 uint32_t action
, const char *name
)
344 for (i
=0; i
<3; i
++) {
345 if (actions
[i
].action
== action
) {
346 CHECK_WSTR(tctx
, actions
[i
].name
, name
, STR_UNICODE
);
351 torture_result(tctx
, TORTURE_FAIL
,
352 __location__
": (%d) expected action %d, not found\n",
358 testing of recursive change notify
361 #define BASEDIR_CN1_RECUR BASEDIR "_CN1_RECUR"
363 static bool test_notify_recursive(struct torture_context
*tctx
,
364 struct smbcli_state
*cli
,
365 struct smbcli_state
*cli2
)
369 union smb_notify notify
;
372 struct smbcli_request
*req1
, *req2
;
374 torture_comment(tctx
, "TESTING CHANGE NOTIFY WITH RECURSION\n");
376 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR_CN1_RECUR
),
377 "Failed to setup up test directory: " BASEDIR_CN1_RECUR
);
380 get a handle on the directory
382 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
383 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
384 io
.ntcreatex
.in
.flags
= 0;
385 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
386 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
387 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
388 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
389 io
.ntcreatex
.in
.alloc_size
= 0;
390 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
391 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
392 io
.ntcreatex
.in
.security_flags
= 0;
393 io
.ntcreatex
.in
.fname
= BASEDIR_CN1_RECUR
;
395 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
396 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
398 fnum
= io
.ntcreatex
.out
.file
.fnum
;
400 /* ask for a change notify, on file or directory name
401 changes. Setup both with and without recursion */
402 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
403 notify
.nttrans
.in
.buffer_size
= 1000;
404 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
| FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_CREATION
;
405 notify
.nttrans
.in
.file
.fnum
= fnum
;
407 notify
.nttrans
.in
.recursive
= true;
408 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
410 notify
.nttrans
.in
.recursive
= false;
411 req2
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
413 /* cancel initial requests so the buffer is setup */
414 smb_raw_ntcancel(req1
);
415 status
= smb_raw_changenotify_recv(req1
, tctx
, ¬ify
);
416 torture_assert_ntstatus_equal_goto(tctx
, status
,
419 "smb_raw_changenotify_recv");
421 smb_raw_ntcancel(req2
);
422 status
= smb_raw_changenotify_recv(req2
, tctx
, ¬ify
);
423 torture_assert_ntstatus_equal_goto(tctx
, status
,
426 "smb_raw_changenotify_recv");
429 * Make notifies a bit more interesting in a cluster by doing
430 * the changes against different nodes with --unclist
432 smbcli_mkdir(cli
->tree
, BASEDIR_CN1_RECUR
"\\subdir-name");
433 smbcli_mkdir(cli2
->tree
, BASEDIR_CN1_RECUR
"\\subdir-name\\subname1");
434 smbcli_close(cli
->tree
,
435 smbcli_open(cli
->tree
,
436 BASEDIR_CN1_RECUR
"\\subdir-name\\subname2",
438 smbcli_rename(cli2
->tree
, BASEDIR_CN1_RECUR
"\\subdir-name\\subname1",
439 BASEDIR_CN1_RECUR
"\\subdir-name\\subname1-r");
440 smbcli_rename(cli
->tree
,
441 BASEDIR_CN1_RECUR
"\\subdir-name\\subname2",
442 BASEDIR_CN1_RECUR
"\\subname2-r");
443 smbcli_rename(cli2
->tree
, BASEDIR_CN1_RECUR
"\\subname2-r",
444 BASEDIR_CN1_RECUR
"\\subname3-r");
446 notify
.nttrans
.in
.completion_filter
= 0;
447 notify
.nttrans
.in
.recursive
= true;
449 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
451 smbcli_rmdir(cli
->tree
, BASEDIR_CN1_RECUR
"\\subdir-name\\subname1-r");
452 smbcli_rmdir(cli2
->tree
, BASEDIR_CN1_RECUR
"\\subdir-name");
453 smbcli_unlink(cli
->tree
, BASEDIR_CN1_RECUR
"\\subname3-r");
456 notify
.nttrans
.in
.recursive
= false;
457 req2
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
459 status
= smb_raw_changenotify_recv(req1
, tctx
, ¬ify
);
460 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
461 "smb_raw_changenotify_recv");
463 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
464 11, ret
, done
, "wrong number of changes");
465 torture_assert_int_equal_goto(tctx
,
466 notify
.nttrans
.out
.changes
[0].action
,
467 NOTIFY_ACTION_ADDED
, ret
, done
,
468 "wrong action (exp: ADDED)");
469 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "subdir-name",
471 torture_assert_int_equal_goto(tctx
,
472 notify
.nttrans
.out
.changes
[1].action
,
473 NOTIFY_ACTION_ADDED
, ret
, done
,
474 "wrong action (exp: ADDED)");
475 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[1].name
,
476 "subdir-name\\subname1", STR_UNICODE
);
477 torture_assert_int_equal_goto(tctx
,
478 notify
.nttrans
.out
.changes
[2].action
,
479 NOTIFY_ACTION_ADDED
, ret
, done
,
480 "wrong action (exp: ADDED)");
481 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[2].name
,
482 "subdir-name\\subname2", STR_UNICODE
);
483 torture_assert_int_equal_goto(tctx
,
484 notify
.nttrans
.out
.changes
[3].action
,
485 NOTIFY_ACTION_OLD_NAME
, ret
, done
,
486 "wrong action (exp: OLD_NAME)");
487 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[3].name
,
488 "subdir-name\\subname1", STR_UNICODE
);
489 torture_assert_int_equal_goto(tctx
,
490 notify
.nttrans
.out
.changes
[4].action
,
491 NOTIFY_ACTION_NEW_NAME
, ret
, done
,
492 "wrong action (exp: NEW_NAME)");
493 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[4].name
,
494 "subdir-name\\subname1-r", STR_UNICODE
);
496 ret
&= check_rename_reply(tctx
,
497 cli
, __LINE__
, ¬ify
.nttrans
.out
.changes
[5],
498 NOTIFY_ACTION_ADDED
, "subname2-r");
499 ret
&= check_rename_reply(tctx
,
500 cli
, __LINE__
, ¬ify
.nttrans
.out
.changes
[5],
501 NOTIFY_ACTION_REMOVED
, "subdir-name\\subname2");
502 ret
&= check_rename_reply(tctx
,
503 cli
, __LINE__
, ¬ify
.nttrans
.out
.changes
[5],
504 NOTIFY_ACTION_MODIFIED
, "subname2-r");
506 ret
&= check_rename_reply(tctx
,
507 cli
, __LINE__
, ¬ify
.nttrans
.out
.changes
[8],
508 NOTIFY_ACTION_OLD_NAME
, "subname2-r");
509 ret
&= check_rename_reply(tctx
,
510 cli
, __LINE__
, ¬ify
.nttrans
.out
.changes
[8],
511 NOTIFY_ACTION_NEW_NAME
, "subname3-r");
512 ret
&= check_rename_reply(tctx
,
513 cli
, __LINE__
, ¬ify
.nttrans
.out
.changes
[8],
514 NOTIFY_ACTION_MODIFIED
, "subname3-r");
520 status
= smb_raw_changenotify_recv(req2
, tctx
, ¬ify
);
521 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
522 "smb_raw_changenotify_recv");
524 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
525 3, ret
, done
, "wrong number of changes");
526 torture_assert_int_equal_goto(tctx
,
527 notify
.nttrans
.out
.changes
[0].action
,
528 NOTIFY_ACTION_REMOVED
, ret
, done
,
529 "wrong action (exp: REMOVED)");
530 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
,
531 "subdir-name\\subname1-r", STR_UNICODE
);
532 torture_assert_int_equal_goto(tctx
,
533 notify
.nttrans
.out
.changes
[1].action
,
534 NOTIFY_ACTION_REMOVED
, ret
, done
,
535 "wrong action (exp: REMOVED)");
536 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[1].name
, "subdir-name",
538 torture_assert_int_equal_goto(tctx
,
539 notify
.nttrans
.out
.changes
[2].action
,
540 NOTIFY_ACTION_REMOVED
, ret
, done
,
541 "wrong action (exp: REMOVED)");
542 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[2].name
, "subname3-r",
546 smb_raw_exit(cli
->session
);
547 smbcli_deltree(cli
->tree
, BASEDIR_CN1_RECUR
);
552 testing of change notify mask change
555 #define BASEDIR_CN1_CNMC BASEDIR "_CN1_CNMC"
557 static bool test_notify_mask_change(struct torture_context
*tctx
,
558 struct smbcli_state
*cli
)
562 union smb_notify notify
;
565 struct smbcli_request
*req1
, *req2
;
567 torture_comment(tctx
, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
569 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR_CN1_CNMC
),
570 "Failed to setup up test directory: " BASEDIR_CN1_CNMC
);
573 get a handle on the directory
575 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
576 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
577 io
.ntcreatex
.in
.flags
= 0;
578 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
579 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
580 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
581 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
582 io
.ntcreatex
.in
.alloc_size
= 0;
583 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
584 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
585 io
.ntcreatex
.in
.security_flags
= 0;
586 io
.ntcreatex
.in
.fname
= BASEDIR_CN1_CNMC
;
588 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
589 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
591 fnum
= io
.ntcreatex
.out
.file
.fnum
;
593 /* ask for a change notify, on file or directory name
594 changes. Setup both with and without recursion */
595 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
596 notify
.nttrans
.in
.buffer_size
= 1000;
597 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
598 notify
.nttrans
.in
.file
.fnum
= fnum
;
600 notify
.nttrans
.in
.recursive
= true;
601 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
603 notify
.nttrans
.in
.recursive
= false;
604 req2
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
606 /* cancel initial requests so the buffer is setup */
607 smb_raw_ntcancel(req1
);
608 status
= smb_raw_changenotify_recv(req1
, tctx
, ¬ify
);
609 torture_assert_ntstatus_equal_goto(tctx
, status
,
612 "smb_raw_changenotify_recv");
614 smb_raw_ntcancel(req2
);
615 status
= smb_raw_changenotify_recv(req2
, tctx
, ¬ify
);
616 torture_assert_ntstatus_equal_goto(tctx
, status
,
619 "smb_raw_changenotify_recv");
621 notify
.nttrans
.in
.recursive
= true;
622 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
624 /* Set to hidden then back again. */
625 smbcli_close(cli
->tree
,
626 smbcli_open(cli
->tree
,BASEDIR_CN1_CNMC
"\\tname1", O_CREAT
, 0));
627 smbcli_setatr(cli
->tree
, BASEDIR_CN1_CNMC
"\\tname1",
628 FILE_ATTRIBUTE_HIDDEN
, 0);
629 smbcli_unlink(cli
->tree
, BASEDIR_CN1_CNMC
"\\tname1");
631 status
= smb_raw_changenotify_recv(req1
, tctx
, ¬ify
);
632 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
633 "smb_raw_changenotify_recv");
635 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
636 1, ret
, done
, "wrong number of changes");
637 torture_assert_int_equal_goto(tctx
,
638 notify
.nttrans
.out
.changes
[0].action
,
639 NOTIFY_ACTION_MODIFIED
, ret
, done
,
640 "wrong action (exp: MODIFIED)");
641 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "tname1",
644 /* Now try and change the mask to include other events.
645 * This should not work - once the mask is set on a directory
646 * fnum it seems to be fixed until the fnum is closed. */
648 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
| FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_CREATION
;
649 notify
.nttrans
.in
.recursive
= true;
650 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
652 notify
.nttrans
.in
.recursive
= false;
653 req2
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
655 smbcli_mkdir(cli
->tree
, BASEDIR_CN1_CNMC
"\\subdir-name");
656 smbcli_mkdir(cli
->tree
, BASEDIR_CN1_CNMC
"\\subdir-name\\subname1");
657 smbcli_close(cli
->tree
,
658 smbcli_open(cli
->tree
,
659 BASEDIR_CN1_CNMC
"\\subdir-name\\subname2",
661 smbcli_rename(cli
->tree
,
662 BASEDIR_CN1_CNMC
"\\subdir-name\\subname1",
663 BASEDIR_CN1_CNMC
"\\subdir-name\\subname1-r");
664 smbcli_rename(cli
->tree
,
665 BASEDIR_CN1_CNMC
"\\subdir-name\\subname2",
666 BASEDIR_CN1_CNMC
"\\subname2-r");
667 smbcli_rename(cli
->tree
,
668 BASEDIR_CN1_CNMC
"\\subname2-r",
669 BASEDIR_CN1_CNMC
"\\subname3-r");
671 smbcli_rmdir(cli
->tree
, BASEDIR_CN1_CNMC
"\\subdir-name\\subname1-r");
672 smbcli_rmdir(cli
->tree
, BASEDIR_CN1_CNMC
"\\subdir-name");
673 smbcli_unlink(cli
->tree
, BASEDIR_CN1_CNMC
"\\subname3-r");
675 status
= smb_raw_changenotify_recv(req1
, tctx
, ¬ify
);
676 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
677 "smb_raw_changenotify_recv");
679 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
680 1, ret
, done
, "wrong number of changes");
681 torture_assert_int_equal_goto(tctx
,
682 notify
.nttrans
.out
.changes
[0].action
,
683 NOTIFY_ACTION_MODIFIED
, ret
, done
,
684 "wrong action (exp: MODIFIED)");
685 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "subname2-r",
688 status
= smb_raw_changenotify_recv(req2
, tctx
, ¬ify
);
689 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
690 "smb_raw_changenotify_recv");
692 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
693 1, ret
, done
, "wrong number of changes");
694 torture_assert_int_equal_goto(tctx
,
695 notify
.nttrans
.out
.changes
[0].action
,
696 NOTIFY_ACTION_MODIFIED
, ret
, done
,
697 "wrong action (exp: MODIFIED)");
698 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "subname3-r",
702 smb_raw_exit(cli
->session
);
703 smbcli_deltree(cli
->tree
, BASEDIR_CN1_CNMC
);
709 testing of mask bits for change notify
712 #define BASEDIR_CN1_NOTM BASEDIR "_CN1_NOTM"
714 static bool test_notify_mask(struct torture_context
*tctx
,
715 struct smbcli_state
*cli
,
716 struct smbcli_state
*cli2
)
720 union smb_notify notify
;
722 union smb_chkpath chkpath
;
730 torture_comment(tctx
, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
732 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR_CN1_NOTM
),
733 "Failed to setup up test directory: " BASEDIR_CN1_NOTM
);
735 tv
= timeval_current_ofs(1000, 0);
736 t
= timeval_to_nttime(&tv
);
739 get a handle on the directory
741 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
742 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
743 io
.ntcreatex
.in
.flags
= 0;
744 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
745 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
746 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
747 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
748 io
.ntcreatex
.in
.alloc_size
= 0;
749 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
750 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
751 io
.ntcreatex
.in
.security_flags
= 0;
752 io
.ntcreatex
.in
.fname
= BASEDIR_CN1_NOTM
;
754 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
755 notify
.nttrans
.in
.buffer_size
= 1000;
756 notify
.nttrans
.in
.recursive
= true;
758 chkpath
.chkpath
.in
.path
= "\\";
760 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, expected, nchanges) \
762 smbcli_getatr(cli->tree, test_name, NULL, NULL, NULL); \
763 for (mask=i=0;i<32;i++) { \
764 struct smbcli_request *req; \
765 status = smb_raw_open(cli->tree, tctx, &io); \
766 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
768 fnum = io.ntcreatex.out.file.fnum; \
770 notify.nttrans.in.file.fnum = fnum; \
771 notify.nttrans.in.completion_filter = ((uint32_t)1<<i); \
772 req = smb_raw_changenotify_send(cli->tree, ¬ify); \
773 smb_raw_chkpath(cli->tree, &chkpath); \
775 smb_msleep(200); smb_raw_ntcancel(req); \
776 status = smb_raw_changenotify_recv(req, tctx, ¬ify); \
778 smbcli_close(cli->tree, fnum); \
779 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
780 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
782 /* special case to cope with file rename behaviour */ \
783 if (nchanges == 2 && notify.nttrans.out.num_changes == 1 && \
784 notify.nttrans.out.changes[0].action == NOTIFY_ACTION_MODIFIED && \
785 ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
786 Action == NOTIFY_ACTION_OLD_NAME) { \
787 torture_comment(tctx, "(rename file special handling OK)\n"); \
789 torture_assert_int_equal_goto(tctx, \
790 notify.nttrans.out.num_changes,\
791 nchanges, ret, done, \
792 talloc_asprintf(tctx, \
793 "nchanges=%d expected=%d action=%d " \
795 notify.nttrans.out.num_changes, \
797 notify.nttrans.out.changes[0].action, \
798 notify.nttrans.in.completion_filter)); \
799 torture_assert_int_equal_goto(tctx, \
800 notify.nttrans.out.changes[0].action, \
802 talloc_asprintf(tctx, \
803 "nchanges=%d action=%d " \
804 "expectedAction=%d filter=0x%08x\n", \
805 notify.nttrans.out.num_changes, \
806 notify.nttrans.out.changes[0].action, \
808 notify.nttrans.in.completion_filter)); \
809 torture_assert_str_equal_goto(tctx, \
810 notify.nttrans.out.changes[0].name.s, \
811 "tname1", ret, done, \
812 talloc_asprintf(tctx, \
813 "nchanges=%d action=%d filter=0x%08x " \
814 "name=%s expected_name=tname1\n", \
815 notify.nttrans.out.num_changes, \
816 notify.nttrans.out.changes[0].action, \
817 notify.nttrans.in.completion_filter, \
818 notify.nttrans.out.changes[0].name.s));\
820 mask |= ((uint32_t)1<<i); \
822 if ((expected) != mask) { \
823 torture_assert_int_not_equal_goto(tctx, ((expected) & ~mask), \
824 0, ret, done, "Too few bits"); \
825 torture_comment(tctx, "WARNING: trigger on too many bits. mask=0x%08x expected=0x%08x\n", \
830 torture_comment(tctx
, "Testing mkdir\n");
831 NOTIFY_MASK_TEST("Testing mkdir",;,
832 smbcli_mkdir(cli
->tree
, BASEDIR_CN1_NOTM
"\\tname1");,
833 smbcli_rmdir(cli2
->tree
, BASEDIR_CN1_NOTM
"\\tname1");,
835 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
837 torture_comment(tctx
, "Testing create file\n");
838 NOTIFY_MASK_TEST("Testing create file",;,
839 smbcli_close(cli
->tree
,
840 smbcli_open(cli
->tree
,
841 BASEDIR_CN1_NOTM
"\\tname1",
843 smbcli_unlink(cli2
->tree
,
844 BASEDIR_CN1_NOTM
"\\tname1");,
846 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
848 torture_comment(tctx
, "Testing unlink\n");
849 NOTIFY_MASK_TEST("Testing unlink",
850 smbcli_close(cli
->tree
,
851 smbcli_open(cli
->tree
,
852 BASEDIR_CN1_NOTM
"\\tname1",
854 smbcli_unlink(cli2
->tree
,
855 BASEDIR_CN1_NOTM
"\\tname1");,
857 NOTIFY_ACTION_REMOVED
,
858 FILE_NOTIFY_CHANGE_FILE_NAME
, 1);
860 torture_comment(tctx
, "Testing rmdir\n");
861 NOTIFY_MASK_TEST("Testing rmdir",
862 smbcli_mkdir(cli
->tree
, BASEDIR_CN1_NOTM
"\\tname1");,
863 smbcli_rmdir(cli2
->tree
, BASEDIR_CN1_NOTM
"\\tname1");,
865 NOTIFY_ACTION_REMOVED
,
866 FILE_NOTIFY_CHANGE_DIR_NAME
, 1);
868 torture_comment(tctx
, "Testing rename file\n");
869 NOTIFY_MASK_TEST("Testing rename file",
870 smbcli_close(cli
->tree
,
871 smbcli_open(cli
->tree
,
872 BASEDIR_CN1_NOTM
"\\tname1",
874 smbcli_rename(cli2
->tree
,
875 BASEDIR_CN1_NOTM
"\\tname1",
876 BASEDIR_CN1_NOTM
"\\tname2");,
877 smbcli_unlink(cli
->tree
, BASEDIR_CN1_NOTM
"\\tname2");,
878 NOTIFY_ACTION_OLD_NAME
,
879 FILE_NOTIFY_CHANGE_FILE_NAME
|FILE_NOTIFY_CHANGE_ATTRIBUTES
|FILE_NOTIFY_CHANGE_CREATION
, 2);
881 torture_comment(tctx
, "Testing rename dir\n");
882 NOTIFY_MASK_TEST("Testing rename dir",
883 smbcli_mkdir(cli
->tree
, BASEDIR_CN1_NOTM
"\\tname1");,
884 smbcli_rename(cli2
->tree
,
885 BASEDIR_CN1_NOTM
"\\tname1",
886 BASEDIR_CN1_NOTM
"\\tname2");,
887 smbcli_rmdir(cli
->tree
, BASEDIR_CN1_NOTM
"\\tname2");,
888 NOTIFY_ACTION_OLD_NAME
,
889 FILE_NOTIFY_CHANGE_DIR_NAME
, 2);
891 torture_comment(tctx
, "Testing set path attribute\n");
892 NOTIFY_MASK_TEST("Testing set path attribute",
893 smbcli_close(cli
->tree
,
894 smbcli_open(cli
->tree
,
895 BASEDIR_CN1_NOTM
"\\tname1", O_CREAT
, 0));,
896 smbcli_setatr(cli2
->tree
,
897 BASEDIR_CN1_NOTM
"\\tname1", FILE_ATTRIBUTE_HIDDEN
, 0);,
898 smbcli_unlink(cli
->tree
, BASEDIR_CN1_NOTM
"\\tname1");,
899 NOTIFY_ACTION_MODIFIED
,
900 FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
902 torture_comment(tctx
, "Testing set path write time\n");
903 NOTIFY_MASK_TEST("Testing set path write time",
904 smbcli_close(cli
->tree
, smbcli_open(cli
->tree
,
905 BASEDIR_CN1_NOTM
"\\tname1", O_CREAT
, 0));,
906 smbcli_setatr(cli2
->tree
,
907 BASEDIR_CN1_NOTM
"\\tname1",
908 FILE_ATTRIBUTE_NORMAL
, 1000);,
909 smbcli_unlink(cli
->tree
, BASEDIR_CN1_NOTM
"\\tname1");,
910 NOTIFY_ACTION_MODIFIED
,
911 FILE_NOTIFY_CHANGE_LAST_WRITE
, 1);
913 torture_comment(tctx
, "Testing set file attribute\n");
914 NOTIFY_MASK_TEST("Testing set file attribute",
915 fnum2
= create_complex_file(cli2
, tctx
,
916 BASEDIR_CN1_NOTM
"\\tname1");,
917 smbcli_fsetatr(cli2
->tree
, fnum2
, FILE_ATTRIBUTE_HIDDEN
, 0, 0, 0, 0);,
918 (smbcli_close(cli2
->tree
, fnum2
),
919 smbcli_unlink(cli2
->tree
, BASEDIR_CN1_NOTM
"\\tname1"));,
920 NOTIFY_ACTION_MODIFIED
,
921 FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
923 if (torture_setting_bool(tctx
, "samba3", false)) {
924 torture_comment(tctx
, "Samba3 does not yet support create times "
928 torture_comment(tctx
, "Testing set file create time\n");
929 NOTIFY_MASK_TEST("Testing set file create time",
930 fnum2
= create_complex_file(cli
, tctx
,
931 BASEDIR_CN1_NOTM
"\\tname1");,
932 smbcli_fsetatr(cli
->tree
, fnum2
, 0, t
, 0, 0, 0);,
933 (smbcli_close(cli
->tree
, fnum2
),
934 smbcli_unlink(cli
->tree
,
935 BASEDIR_CN1_NOTM
"\\tname1"));,
936 NOTIFY_ACTION_MODIFIED
,
937 FILE_NOTIFY_CHANGE_CREATION
, 1);
940 torture_comment(tctx
, "Testing set file access time\n");
941 NOTIFY_MASK_TEST("Testing set file access time",
942 fnum2
= create_complex_file(cli
, tctx
,
943 BASEDIR_CN1_NOTM
"\\tname1");,
944 smbcli_fsetatr(cli
->tree
, fnum2
, 0, 0, t
, 0, 0);,
945 (smbcli_close(cli
->tree
, fnum2
),
946 smbcli_unlink(cli
->tree
, BASEDIR_CN1_NOTM
"\\tname1"));,
947 NOTIFY_ACTION_MODIFIED
,
948 FILE_NOTIFY_CHANGE_LAST_ACCESS
, 1);
950 torture_comment(tctx
, "Testing set file write time\n");
951 NOTIFY_MASK_TEST("Testing set file write time",
952 fnum2
= create_complex_file(cli
, tctx
,
953 BASEDIR_CN1_NOTM
"\\tname1");,
954 smbcli_fsetatr(cli
->tree
, fnum2
, 0, 0, 0, t
, 0);,
955 (smbcli_close(cli
->tree
, fnum2
),
956 smbcli_unlink(cli
->tree
, BASEDIR_CN1_NOTM
"\\tname1"));,
957 NOTIFY_ACTION_MODIFIED
,
958 FILE_NOTIFY_CHANGE_LAST_WRITE
, 1);
960 torture_comment(tctx
, "Testing set file change time\n");
961 NOTIFY_MASK_TEST("Testing set file change time",
962 fnum2
= create_complex_file(cli
, tctx
,
963 BASEDIR_CN1_NOTM
"\\tname1");,
964 smbcli_fsetatr(cli
->tree
, fnum2
, 0, 0, 0, 0, t
);,
965 (smbcli_close(cli
->tree
, fnum2
),
966 smbcli_unlink(cli
->tree
, BASEDIR_CN1_NOTM
"\\tname1"));,
967 NOTIFY_ACTION_MODIFIED
,
971 torture_comment(tctx
, "Testing write\n");
972 NOTIFY_MASK_TEST("Testing write",
973 fnum2
= create_complex_file(cli2
, tctx
,
974 BASEDIR_CN1_NOTM
"\\tname1");,
975 smbcli_write(cli2
->tree
, fnum2
, 1, &c
, 10000, 1);,
976 (smbcli_close(cli2
->tree
, fnum2
),
977 smbcli_unlink(cli
->tree
, BASEDIR_CN1_NOTM
"\\tname1"));,
978 NOTIFY_ACTION_MODIFIED
,
981 torture_comment(tctx
, "Testing truncate\n");
982 NOTIFY_MASK_TEST("Testing truncate",
983 fnum2
= create_complex_file(cli2
, tctx
,
984 BASEDIR_CN1_NOTM
"\\tname1");,
985 smbcli_ftruncate(cli2
->tree
, fnum2
, 10000);,
986 (smbcli_close(cli2
->tree
, fnum2
),
987 smbcli_unlink(cli2
->tree
, BASEDIR_CN1_NOTM
"\\tname1"));,
988 NOTIFY_ACTION_MODIFIED
,
989 FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_ATTRIBUTES
, 1);
992 smb_raw_exit(cli
->session
);
993 smbcli_deltree(cli
->tree
, BASEDIR_CN1_NOTM
);
998 basic testing of change notify on files
1001 #define BASEDIR_CN1_FILE BASEDIR "_CN1_FILE"
1003 static bool test_notify_file(struct torture_context
*tctx
,
1004 struct smbcli_state
*cli
)
1010 union smb_notify notify
;
1011 struct smbcli_request
*req
;
1013 const char *fname
= BASEDIR_CN1_FILE
"\\file.txt";
1015 torture_comment(tctx
, "TESTING CHANGE NOTIFY ON FILES\n");
1017 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR_CN1_FILE
),
1018 "Failed to setup up test directory: " BASEDIR_CN1_FILE
);
1020 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1021 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1022 io
.ntcreatex
.in
.flags
= 0;
1023 io
.ntcreatex
.in
.access_mask
= SEC_FLAG_MAXIMUM_ALLOWED
;
1024 io
.ntcreatex
.in
.create_options
= 0;
1025 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1026 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
1027 io
.ntcreatex
.in
.alloc_size
= 0;
1028 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_CREATE
;
1029 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1030 io
.ntcreatex
.in
.security_flags
= 0;
1031 io
.ntcreatex
.in
.fname
= fname
;
1032 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1033 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1035 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1037 /* ask for a change notify,
1038 on file or directory name changes */
1039 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1040 notify
.nttrans
.in
.file
.fnum
= fnum
;
1041 notify
.nttrans
.in
.buffer_size
= 1000;
1042 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_STREAM_NAME
;
1043 notify
.nttrans
.in
.recursive
= false;
1045 torture_comment(tctx
, "Testing if notifies on file handles are invalid (should be)\n");
1047 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1048 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
1049 torture_assert_ntstatus_equal_goto(tctx
, status
,
1050 NT_STATUS_INVALID_PARAMETER
,
1052 "smb_raw_changenotify_recv");
1054 cl
.close
.level
= RAW_CLOSE_CLOSE
;
1055 cl
.close
.in
.file
.fnum
= fnum
;
1056 cl
.close
.in
.write_time
= 0;
1057 status
= smb_raw_close(cli
->tree
, &cl
);
1058 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1061 status
= smbcli_unlink(cli
->tree
, fname
);
1062 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1066 smb_raw_exit(cli
->session
);
1067 smbcli_deltree(cli
->tree
, BASEDIR_CN1_FILE
);
1072 basic testing of change notifies followed by a tdis
1074 #define BASEDIR_CN1_TDIS BASEDIR "_CN1_TDIS"
1076 static bool test_notify_tdis(struct torture_context
*tctx
,
1077 struct smbcli_state
*cli1
)
1081 union smb_notify notify
;
1084 struct smbcli_request
*req
;
1085 struct smbcli_state
*cli
= NULL
;
1087 torture_comment(tctx
, "TESTING CHANGE NOTIFY FOLLOWED BY TDIS\n");
1089 torture_assert(tctx
, torture_setup_dir(cli1
, BASEDIR_CN1_TDIS
),
1090 "Failed to setup up test directory: " BASEDIR_CN1_TDIS
);
1092 torture_assert(tctx
, torture_open_connection(&cli
, tctx
, 0),
1093 "Failed to open connection.");
1096 get a handle on the directory
1098 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1099 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1100 io
.ntcreatex
.in
.flags
= 0;
1101 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1102 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1103 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1104 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
1105 io
.ntcreatex
.in
.alloc_size
= 0;
1106 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1107 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1108 io
.ntcreatex
.in
.security_flags
= 0;
1109 io
.ntcreatex
.in
.fname
= BASEDIR_CN1_TDIS
;
1111 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1112 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1114 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1116 /* ask for a change notify,
1117 on file or directory name changes */
1118 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1119 notify
.nttrans
.in
.buffer_size
= 1000;
1120 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1121 notify
.nttrans
.in
.file
.fnum
= fnum
;
1122 notify
.nttrans
.in
.recursive
= true;
1124 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1126 status
= smbcli_tdis(cli
);
1127 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1131 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
1132 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1133 "smb_raw_changenotify_recv");
1134 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
1135 0, ret
, done
, "no changes expected");
1138 torture_close_connection(cli
);
1139 smbcli_deltree(cli1
->tree
, BASEDIR_CN1_TDIS
);
1144 basic testing of change notifies followed by a exit
1147 #define BASEDIR_CN1_EX BASEDIR "_CN1_EX"
1149 static bool test_notify_exit(struct torture_context
*tctx
,
1150 struct smbcli_state
*cli1
)
1154 union smb_notify notify
;
1157 struct smbcli_request
*req
;
1158 struct smbcli_state
*cli
= NULL
;
1160 torture_comment(tctx
, "TESTING CHANGE NOTIFY FOLLOWED BY EXIT\n");
1162 torture_assert(tctx
, torture_setup_dir(cli1
, BASEDIR_CN1_EX
),
1163 "Failed to setup up test directory: " BASEDIR_CN1_EX
);
1165 torture_assert(tctx
, torture_open_connection(&cli
, tctx
, 0),
1166 "Failed to open connection.");
1169 get a handle on the directory
1171 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1172 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1173 io
.ntcreatex
.in
.flags
= 0;
1174 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1175 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1176 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1177 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
1178 io
.ntcreatex
.in
.alloc_size
= 0;
1179 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1180 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1181 io
.ntcreatex
.in
.security_flags
= 0;
1182 io
.ntcreatex
.in
.fname
= BASEDIR_CN1_EX
;
1184 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1185 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1187 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1189 /* ask for a change notify,
1190 on file or directory name changes */
1191 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1192 notify
.nttrans
.in
.buffer_size
= 1000;
1193 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1194 notify
.nttrans
.in
.file
.fnum
= fnum
;
1195 notify
.nttrans
.in
.recursive
= true;
1197 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1199 status
= smb_raw_exit(cli
->session
);
1200 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1203 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
1204 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1205 "smb_raw_changenotify_recv");
1206 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
1207 0, ret
, done
, "no changes expected");
1210 torture_close_connection(cli
);
1211 smbcli_deltree(cli1
->tree
, BASEDIR_CN1_EX
);
1216 basic testing of change notifies followed by a ulogoff
1219 #define BASEDIR_CN1_UL BASEDIR "_CN1_UL"
1221 static bool test_notify_ulogoff(struct torture_context
*tctx
,
1222 struct smbcli_state
*cli1
)
1226 union smb_notify notify
;
1229 struct smbcli_request
*req
;
1230 struct smbcli_state
*cli
= NULL
;
1232 torture_comment(tctx
, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1234 torture_assert(tctx
, torture_setup_dir(cli1
, BASEDIR_CN1_UL
),
1235 "Failed to setup up test directory: " BASEDIR_CN1_UL
);
1237 torture_assert(tctx
, torture_open_connection(&cli
, tctx
, 0),
1238 "Failed to open connection.");
1241 get a handle on the directory
1243 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1244 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1245 io
.ntcreatex
.in
.flags
= 0;
1246 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1247 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1248 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1249 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
1250 io
.ntcreatex
.in
.alloc_size
= 0;
1251 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1252 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1253 io
.ntcreatex
.in
.security_flags
= 0;
1254 io
.ntcreatex
.in
.fname
= BASEDIR_CN1_UL
;
1256 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1257 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1259 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1261 /* ask for a change notify,
1262 on file or directory name changes */
1263 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1264 notify
.nttrans
.in
.buffer_size
= 1000;
1265 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1266 notify
.nttrans
.in
.file
.fnum
= fnum
;
1267 notify
.nttrans
.in
.recursive
= true;
1269 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1271 status
= smb_raw_ulogoff(cli
->session
);
1272 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1275 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
1276 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1277 "smb_raw_changenotify_recv");
1278 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
1279 0, ret
, done
, "no changes expected");
1282 torture_close_connection(cli
);
1283 smbcli_deltree(cli1
->tree
, BASEDIR_CN1_UL
);
1287 static void tcp_dis_handler(struct smbcli_transport
*t
, void *p
)
1289 struct smbcli_state
*cli
= (struct smbcli_state
*)p
;
1290 smbcli_transport_dead(cli
->transport
, NT_STATUS_LOCAL_DISCONNECT
);
1291 cli
->transport
= NULL
;
1295 basic testing of change notifies followed by tcp disconnect
1298 #define BASEDIR_CN1_TCPDIS BASEDIR "_CN1_TCPDIS"
1300 static bool test_notify_tcp_dis(struct torture_context
*tctx
,
1301 struct smbcli_state
*cli1
)
1305 union smb_notify notify
;
1308 struct smbcli_request
*req
;
1309 struct smbcli_state
*cli
= NULL
;
1311 torture_comment(tctx
, "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1313 torture_assert(tctx
, torture_setup_dir(cli1
, BASEDIR_CN1_TCPDIS
),
1314 "Failed to setup up test directory: "
1315 BASEDIR_CN1_TCPDIS
);
1317 torture_assert(tctx
, torture_open_connection(&cli
, tctx
, 0),
1318 "Failed to open connection.");
1321 get a handle on the directory
1323 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1324 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1325 io
.ntcreatex
.in
.flags
= 0;
1326 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1327 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1328 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1329 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
1330 io
.ntcreatex
.in
.alloc_size
= 0;
1331 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1332 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1333 io
.ntcreatex
.in
.security_flags
= 0;
1334 io
.ntcreatex
.in
.fname
= BASEDIR_CN1_TCPDIS
;
1336 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1337 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1339 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1341 /* ask for a change notify,
1342 on file or directory name changes */
1343 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1344 notify
.nttrans
.in
.buffer_size
= 1000;
1345 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1346 notify
.nttrans
.in
.file
.fnum
= fnum
;
1347 notify
.nttrans
.in
.recursive
= true;
1349 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1351 smbcli_transport_idle_handler(cli
->transport
, tcp_dis_handler
, 250000, cli
);
1353 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
1354 torture_assert_ntstatus_equal_goto(tctx
, status
,
1355 NT_STATUS_LOCAL_DISCONNECT
,
1357 "smb_raw_changenotify_recv");
1360 torture_close_connection(cli
);
1361 smbcli_deltree(cli1
->tree
, BASEDIR_CN1_TCPDIS
);
1366 test setting up two change notify requests on one handle
1369 #define BASEDIR_CN1_DBL BASEDIR "_CN1_DBL"
1371 static bool test_notify_double(struct torture_context
*tctx
,
1372 struct smbcli_state
*cli
)
1376 union smb_notify notify
;
1379 struct smbcli_request
*req1
, *req2
;
1381 torture_comment(tctx
, "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1383 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR_CN1_DBL
),
1384 "Failed to setup up test directory: " BASEDIR_CN1_DBL
);
1387 get a handle on the directory
1389 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1390 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1391 io
.ntcreatex
.in
.flags
= 0;
1392 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1393 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1394 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1395 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
1396 io
.ntcreatex
.in
.alloc_size
= 0;
1397 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1398 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1399 io
.ntcreatex
.in
.security_flags
= 0;
1400 io
.ntcreatex
.in
.fname
= BASEDIR_CN1_DBL
;
1402 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1403 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1405 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1407 /* ask for a change notify,
1408 on file or directory name changes */
1409 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1410 notify
.nttrans
.in
.buffer_size
= 1000;
1411 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1412 notify
.nttrans
.in
.file
.fnum
= fnum
;
1413 notify
.nttrans
.in
.recursive
= true;
1415 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1416 req2
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1418 smbcli_mkdir(cli
->tree
, BASEDIR_CN1_DBL
"\\subdir-name");
1420 status
= smb_raw_changenotify_recv(req1
, tctx
, ¬ify
);
1421 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1422 "smb_raw_changenotify_recv");
1423 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
1424 1, ret
, done
, "wrong number of changes");
1425 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "subdir-name",
1428 smbcli_mkdir(cli
->tree
, BASEDIR_CN1_DBL
"\\subdir-name2");
1430 status
= smb_raw_changenotify_recv(req2
, tctx
, ¬ify
);
1431 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1432 "smb_raw_changenotify_recv");
1433 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
1434 1, ret
, done
, "wrong number of changes");
1435 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "subdir-name2",
1439 smb_raw_exit(cli
->session
);
1440 smbcli_deltree(cli
->tree
, BASEDIR_CN1_DBL
);
1446 test multiple change notifies at different depths and with/without recursion
1449 #define BASEDIR_CN1_TNT BASEDIR "_CN1_TNT"
1451 static bool test_notify_tree(struct torture_context
*tctx
,
1452 struct smbcli_state
*cli
,
1453 struct smbcli_state
*cli2
)
1456 union smb_notify notify
;
1458 struct smbcli_request
*req
;
1469 .path
= BASEDIR_CN1_TNT
"\\abc",
1471 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1475 .path
= BASEDIR_CN1_TNT
"\\zqy",
1477 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1481 .path
= BASEDIR_CN1_TNT
"\\atsy",
1483 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1487 .path
= BASEDIR_CN1_TNT
"\\abc\\foo",
1489 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1493 .path
= BASEDIR_CN1_TNT
"\\abc\\blah",
1495 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1499 .path
= BASEDIR_CN1_TNT
"\\abc\\blah",
1501 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1505 .path
= BASEDIR_CN1_TNT
"\\abc\\blah\\a",
1507 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1511 .path
= BASEDIR_CN1_TNT
"\\abc\\blah\\b",
1513 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1517 .path
= BASEDIR_CN1_TNT
"\\abc\\blah\\c",
1519 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1523 .path
= BASEDIR_CN1_TNT
"\\abc\\fooblah",
1525 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1529 .path
= BASEDIR_CN1_TNT
"\\zqy\\xx",
1531 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1535 .path
= BASEDIR_CN1_TNT
"\\zqy\\yyy",
1537 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1541 .path
= BASEDIR_CN1_TNT
"\\zqy\\..",
1543 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1547 .path
= BASEDIR_CN1_TNT
,
1549 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1553 .path
= BASEDIR_CN1_TNT
,
1555 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1559 .path
= BASEDIR_CN1_TNT
"\\atsy",
1561 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1565 .path
= BASEDIR_CN1_TNT
"\\abc",
1567 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1571 .path
= BASEDIR_CN1_TNT
"\\abc",
1573 .filter
= FILE_NOTIFY_CHANGE_FILE_NAME
,
1577 .path
= BASEDIR_CN1_TNT
"\\abc",
1579 .filter
= FILE_NOTIFY_CHANGE_FILE_NAME
,
1583 .path
= BASEDIR_CN1_TNT
"\\abc",
1585 .filter
= FILE_NOTIFY_CHANGE_NAME
,
1591 bool all_done
= false;
1593 torture_comment(tctx
, "TESTING CHANGE NOTIFY FOR DIFFERENT DEPTHS\n");
1595 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR_CN1_TNT
),
1596 "Failed to setup up test directory: " BASEDIR_CN1_TNT
);
1598 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1599 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1600 io
.ntcreatex
.in
.flags
= 0;
1601 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1602 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1603 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1604 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
1605 io
.ntcreatex
.in
.alloc_size
= 0;
1606 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN_IF
;
1607 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1608 io
.ntcreatex
.in
.security_flags
= 0;
1610 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1611 notify
.nttrans
.in
.buffer_size
= 20000;
1614 setup the directory tree, and the notify buffer on each directory
1616 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1617 io
.ntcreatex
.in
.fname
= dirs
[i
].path
;
1618 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1619 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1621 dirs
[i
].fnum
= io
.ntcreatex
.out
.file
.fnum
;
1623 notify
.nttrans
.in
.completion_filter
= dirs
[i
].filter
;
1624 notify
.nttrans
.in
.file
.fnum
= dirs
[i
].fnum
;
1625 notify
.nttrans
.in
.recursive
= dirs
[i
].recursive
;
1626 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1627 smb_raw_ntcancel(req
);
1628 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
1629 torture_assert_ntstatus_equal_goto(tctx
, status
,
1630 NT_STATUS_CANCELLED
,
1632 "smb_raw_changenotify_recv");
1635 /* trigger 2 events in each dir */
1636 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1637 char *path
= talloc_asprintf(tctx
, "%s\\test.dir", dirs
[i
].path
);
1639 * Make notifies a bit more interesting in a cluster
1640 * by doing the changes against different nodes with
1643 smbcli_mkdir(cli
->tree
, path
);
1644 smbcli_rmdir(cli2
->tree
, path
);
1648 /* give a bit of time for the events to propagate */
1649 tv
= timeval_current();
1652 /* count events that have happened in each dir */
1653 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1654 notify
.nttrans
.in
.file
.fnum
= dirs
[i
].fnum
;
1655 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1656 smb_raw_ntcancel(req
);
1657 notify
.nttrans
.out
.num_changes
= 0;
1658 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
1659 dirs
[i
].counted
+= notify
.nttrans
.out
.num_changes
;
1664 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1665 if (dirs
[i
].counted
!= dirs
[i
].expected
) {
1669 } while (!all_done
&& timeval_elapsed(&tv
) < 20);
1671 torture_comment(tctx
, "took %.4f seconds to propagate all events\n", timeval_elapsed(&tv
));
1673 for (i
=0;i
<ARRAY_SIZE(dirs
);i
++) {
1674 torture_assert_int_equal_goto(tctx
,
1675 dirs
[i
].counted
, dirs
[i
].expected
, ret
, done
,
1676 talloc_asprintf(tctx
,
1677 "unexpected number of events for '%s'",
1682 run from the back, closing and deleting
1684 for (i
=ARRAY_SIZE(dirs
)-1;i
>=0;i
--) {
1685 smbcli_close(cli
->tree
, dirs
[i
].fnum
);
1686 smbcli_rmdir(cli
->tree
, dirs
[i
].path
);
1690 smb_raw_exit(cli
->session
);
1691 smbcli_deltree(cli
->tree
, BASEDIR_CN1_TNT
);
1696 Test response when cached server events exceed single NT NOTFIY response
1700 #define BASEDIR_CN1_NO BASEDIR "_CN1_NO"
1702 static bool test_notify_overflow(struct torture_context
*tctx
,
1703 struct smbcli_state
*cli
)
1707 union smb_notify notify
;
1711 struct smbcli_request
*req1
;
1714 torture_comment(tctx
, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1716 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR_CN1_NO
),
1717 "Failed to setup up test directory: " BASEDIR_CN1_NO
);
1719 /* get a handle on the directory */
1720 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1721 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1722 io
.ntcreatex
.in
.flags
= 0;
1723 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1724 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1725 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1726 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1727 NTCREATEX_SHARE_ACCESS_WRITE
;
1728 io
.ntcreatex
.in
.alloc_size
= 0;
1729 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1730 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1731 io
.ntcreatex
.in
.security_flags
= 0;
1732 io
.ntcreatex
.in
.fname
= BASEDIR_CN1_NO
;
1734 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1735 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1737 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1739 /* ask for a change notify, on name changes. */
1740 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1741 notify
.nttrans
.in
.buffer_size
= 1000;
1742 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1743 notify
.nttrans
.in
.file
.fnum
= fnum
;
1745 notify
.nttrans
.in
.recursive
= true;
1746 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1748 /* cancel initial requests so the buffer is setup */
1749 smb_raw_ntcancel(req1
);
1750 status
= smb_raw_changenotify_recv(req1
, tctx
, ¬ify
);
1751 torture_assert_ntstatus_equal_goto(tctx
, status
,
1752 NT_STATUS_CANCELLED
,
1754 "smb_raw_changenotify_recv");
1756 /* open a lot of files, filling up the server side notify buffer */
1757 torture_comment(tctx
, "Testing overflowed buffer notify on create of %d files\n",
1759 for (i
=0;i
<count
;i
++) {
1760 char *fname
= talloc_asprintf(cli
,
1761 BASEDIR_CN1_NO
"\\test%d.txt", i
);
1762 int fnum2
= smbcli_open(cli
->tree
, fname
, O_CREAT
|O_RDWR
,
1764 torture_assert_int_not_equal_goto(tctx
, fnum2
, -1, ret
, done
,
1765 talloc_asprintf(tctx
, "Failed to create %s - %s",
1766 fname
, smbcli_errstr(cli
->tree
)));
1768 smbcli_close(cli
->tree
, fnum2
);
1771 /* expect that 0 events will be returned with NT_STATUS_OK */
1772 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1773 status
= smb_raw_changenotify_recv(req1
, tctx
, ¬ify
);
1774 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1775 "smb_raw_changenotify_recv");
1776 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
1777 0, ret
, done
, "no changes expected");
1780 smb_raw_exit(cli
->session
);
1781 smbcli_deltree(cli
->tree
, BASEDIR_CN1_NO
);
1786 Test if notifications are returned for changes to the base directory.
1790 #define BASEDIR_CN1_NBASE BASEDIR "_CN1_NBASE"
1792 static bool test_notify_basedir(struct torture_context
*tctx
,
1793 struct smbcli_state
*cli
)
1797 union smb_notify notify
;
1800 struct smbcli_request
*req1
;
1802 torture_comment(tctx
, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1804 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR_CN1_NBASE
),
1805 "Failed to setup up test directory: " BASEDIR_CN1_NBASE
);
1807 /* get a handle on the directory */
1808 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1809 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1810 io
.ntcreatex
.in
.flags
= 0;
1811 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1812 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1813 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1814 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
1815 NTCREATEX_SHARE_ACCESS_WRITE
;
1816 io
.ntcreatex
.in
.alloc_size
= 0;
1817 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1818 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1819 io
.ntcreatex
.in
.security_flags
= 0;
1820 io
.ntcreatex
.in
.fname
= BASEDIR_CN1_NBASE
;
1822 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1823 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1825 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1827 /* create a test file that will also be modified */
1828 smbcli_close(cli
->tree
, smbcli_open(cli
->tree
,
1829 BASEDIR_CN1_NBASE
"\\tname1",
1832 /* ask for a change notify, on attribute changes. */
1833 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1834 notify
.nttrans
.in
.buffer_size
= 1000;
1835 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
1836 notify
.nttrans
.in
.file
.fnum
= fnum
;
1837 notify
.nttrans
.in
.recursive
= true;
1839 req1
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1841 /* set attribute on the base dir */
1842 smbcli_setatr(cli
->tree
, BASEDIR_CN1_NBASE
, FILE_ATTRIBUTE_HIDDEN
, 0);
1844 /* set attribute on a file to assure we receive a notification */
1845 smbcli_setatr(cli
->tree
, BASEDIR_CN1_NBASE
"\\tname1",
1846 FILE_ATTRIBUTE_HIDDEN
, 0);
1849 /* check how many responses were given, expect only 1 for the file */
1850 status
= smb_raw_changenotify_recv(req1
, tctx
, ¬ify
);
1851 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1852 "smb_raw_changenotify_recv");
1853 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
1854 1, ret
, done
, "wrong number of changes");
1855 torture_assert_int_equal_goto(tctx
,
1856 notify
.nttrans
.out
.changes
[0].action
,
1857 NOTIFY_ACTION_MODIFIED
, ret
, done
,
1858 "wrong action (exp: MODIFIED)");
1859 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "tname1",
1863 smb_raw_exit(cli
->session
);
1864 smbcli_deltree(cli
->tree
, BASEDIR_CN1_NBASE
);
1870 create a secondary tree connect - used to test for a bug in Samba3 messaging
1874 static struct smbcli_tree
*secondary_tcon(struct smbcli_state
*cli
,
1875 struct torture_context
*tctx
)
1878 const char *share
, *host
;
1879 struct smbcli_tree
*tree
;
1880 union smb_tcon tcon
;
1882 share
= torture_setting_string(tctx
, "share", NULL
);
1883 host
= torture_setting_string(tctx
, "host", NULL
);
1885 torture_comment(tctx
, "create a second tree context on the same session\n");
1886 tree
= smbcli_tree_init(cli
->session
, tctx
, false);
1888 tcon
.generic
.level
= RAW_TCON_TCONX
;
1889 tcon
.tconx
.in
.flags
= TCONX_FLAG_EXTENDED_RESPONSE
;
1890 tcon
.tconx
.in
.password
= data_blob(NULL
, 0);
1891 tcon
.tconx
.in
.path
= talloc_asprintf(tctx
, "\\\\%s\\%s", host
, share
);
1892 tcon
.tconx
.in
.device
= "A:";
1893 status
= smb_raw_tcon(tree
, tctx
, &tcon
);
1894 if (!NT_STATUS_IS_OK(status
)) {
1896 torture_comment(tctx
, "Failed to create secondary tree\n");
1900 tree
->tid
= tcon
.tconx
.out
.tid
;
1901 torture_comment(tctx
, "tid1=%d tid2=%d\n", cli
->tree
->tid
, tree
->tid
);
1908 very simple change notify test
1911 #define BASEDIR_CN1_NTCON BASEDIR "_CN1_NTCON"
1913 static bool test_notify_tcon(struct torture_context
*tctx
,
1914 struct smbcli_state
*cli
)
1918 union smb_notify notify
;
1921 struct smbcli_request
*req
;
1922 extern int torture_numops
;
1923 struct smbcli_tree
*tree
= NULL
;
1925 torture_comment(tctx
, "TESTING SIMPLE CHANGE NOTIFY\n");
1927 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR_CN1_NTCON
),
1928 "Failed to setup up test directory: " BASEDIR_CN1_NTCON
);
1931 get a handle on the directory
1933 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
1934 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
1935 io
.ntcreatex
.in
.flags
= 0;
1936 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
1937 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
1938 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
1939 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
| NTCREATEX_SHARE_ACCESS_WRITE
;
1940 io
.ntcreatex
.in
.alloc_size
= 0;
1941 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
1942 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
1943 io
.ntcreatex
.in
.security_flags
= 0;
1944 io
.ntcreatex
.in
.fname
= BASEDIR_CN1_NTCON
;
1946 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1947 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1949 fnum
= io
.ntcreatex
.out
.file
.fnum
;
1951 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
1952 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1955 /* ask for a change notify,
1956 on file or directory name changes */
1957 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
1958 notify
.nttrans
.in
.buffer_size
= 1000;
1959 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_NAME
;
1960 notify
.nttrans
.in
.file
.fnum
= fnum
;
1961 notify
.nttrans
.in
.recursive
= true;
1963 torture_comment(tctx
, "Testing notify mkdir\n");
1964 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1965 smbcli_mkdir(cli
->tree
, BASEDIR_CN1_NTCON
"\\subdir-name");
1967 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
1968 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1969 "smb_raw_changenotify_recv");
1971 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
1972 1, ret
, done
, "wrong number of changes");
1973 torture_assert_int_equal_goto(tctx
,
1974 notify
.nttrans
.out
.changes
[0].action
,
1975 NOTIFY_ACTION_ADDED
, ret
, done
,
1976 "wrong action (exp: ADDED)");
1977 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "subdir-name",
1980 torture_comment(tctx
, "Testing notify rmdir\n");
1981 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
1982 smbcli_rmdir(cli
->tree
, BASEDIR_CN1_NTCON
"\\subdir-name");
1984 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
1985 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
1986 "smb_raw_changenotify_recv");
1987 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
1988 1, ret
, done
, "wrong number of changes");
1989 torture_assert_int_equal_goto(tctx
,
1990 notify
.nttrans
.out
.changes
[0].action
,
1991 NOTIFY_ACTION_REMOVED
, ret
, done
,
1992 "wrong action (exp: REMOVED)");
1993 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "subdir-name",
1996 torture_comment(tctx
, "SIMPLE CHANGE NOTIFY OK\n");
1998 torture_comment(tctx
, "TESTING WITH SECONDARY TCON\n");
1999 tree
= secondary_tcon(cli
, tctx
);
2000 torture_assert_not_null_goto(tctx
, tree
, ret
, done
,
2001 "failed to create secondary tcon");
2003 torture_comment(tctx
, "Testing notify mkdir\n");
2004 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
2005 smbcli_mkdir(cli
->tree
, BASEDIR_CN1_NTCON
"\\subdir-name");
2007 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
2008 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2009 "smb_raw_changenotify_recv");
2011 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
2012 1, ret
, done
, "wrong number of changes");
2013 torture_assert_int_equal_goto(tctx
,
2014 notify
.nttrans
.out
.changes
[0].action
,
2015 NOTIFY_ACTION_ADDED
, ret
, done
,
2016 "wrong action (exp: ADDED)");
2017 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "subdir-name",
2020 torture_comment(tctx
, "Testing notify rmdir\n");
2021 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
2022 smbcli_rmdir(cli
->tree
, BASEDIR_CN1_NTCON
"\\subdir-name");
2024 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
2025 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2026 "smb_raw_changenotify_recv");
2027 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
2028 1, ret
, done
, "wrong number of changes");
2029 torture_assert_int_equal_goto(tctx
,
2030 notify
.nttrans
.out
.changes
[0].action
,
2031 NOTIFY_ACTION_REMOVED
, ret
, done
,
2032 "wrong action (exp: REMOVED)");
2033 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "subdir-name",
2036 torture_comment(tctx
, "CHANGE NOTIFY WITH TCON OK\n");
2038 torture_comment(tctx
, "Disconnecting secondary tree\n");
2039 status
= smb_tree_disconnect(tree
);
2040 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2041 "smb_tree_disconnect");
2044 torture_comment(tctx
, "Testing notify mkdir\n");
2045 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
2046 smbcli_mkdir(cli
->tree
, BASEDIR_CN1_NTCON
"\\subdir-name");
2048 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
2049 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2050 "smb_raw_changenotify_recv");
2052 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
2053 1, ret
, done
, "wrong number of changes");
2054 torture_assert_int_equal_goto(tctx
,
2055 notify
.nttrans
.out
.changes
[0].action
,
2056 NOTIFY_ACTION_ADDED
, ret
, done
,
2057 "wrong action (exp: ADDED)");
2058 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "subdir-name",
2061 torture_comment(tctx
, "Testing notify rmdir\n");
2062 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
2063 smbcli_rmdir(cli
->tree
, BASEDIR_CN1_NTCON
"\\subdir-name");
2065 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
2066 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
2067 "smb_raw_changenotify_recv");
2068 torture_assert_int_equal_goto(tctx
, notify
.nttrans
.out
.num_changes
,
2069 1, ret
, done
, "wrong number of changes");
2070 torture_assert_int_equal_goto(tctx
,
2071 notify
.nttrans
.out
.changes
[0].action
,
2072 NOTIFY_ACTION_REMOVED
, ret
, done
,
2073 "wrong action (exp: REMOVED)");
2074 CHECK_WSTR(tctx
, notify
.nttrans
.out
.changes
[0].name
, "subdir-name",
2077 torture_comment(tctx
, "CHANGE NOTIFY WITH TDIS OK\n");
2079 smb_raw_exit(cli
->session
);
2080 smbcli_deltree(cli
->tree
, BASEDIR_CN1_NTCON
);
2085 struct smbcli_request
*req
;
2089 static void timeout_cb(struct tevent_context
*ev
,
2090 struct tevent_timer
*te
,
2091 struct timeval current_time
,
2094 struct cb_data
*cbp
= (struct cb_data
*)private_data
;
2095 cbp
->req
->state
= SMBCLI_REQUEST_ERROR
;
2096 cbp
->timed_out
= true;
2100 testing alignment of multiple change notify infos
2103 #define BASEDIR_CN1_NALIGN BASEDIR "_CN1_NALIGN"
2105 static bool test_notify_alignment(struct torture_context
*tctx
,
2106 struct smbcli_state
*cli
)
2109 union smb_notify notify
;
2112 struct smbcli_request
*req
;
2113 const char *fname
= BASEDIR_CN1_NALIGN
"\\starter";
2114 const char *fnames
[] = { "a",
2118 bool fnames_received
[] = {false,
2122 size_t total_names_received
= 0;
2123 size_t num_names
= ARRAY_SIZE(fnames
);
2127 torture_comment(tctx
, "TESTING CHANGE NOTIFY REPLY ALIGNMENT\n");
2129 torture_assert(tctx
, torture_setup_dir(cli
, BASEDIR_CN1_NALIGN
),
2130 "Failed to setup up test directory: " BASEDIR_CN1_NALIGN
);
2132 /* get a handle on the directory */
2133 io
.generic
.level
= RAW_OPEN_NTCREATEX
;
2134 io
.ntcreatex
.in
.root_fid
.fnum
= 0;
2135 io
.ntcreatex
.in
.flags
= 0;
2136 io
.ntcreatex
.in
.access_mask
= SEC_FILE_ALL
;
2137 io
.ntcreatex
.in
.create_options
= NTCREATEX_OPTIONS_DIRECTORY
;
2138 io
.ntcreatex
.in
.file_attr
= FILE_ATTRIBUTE_NORMAL
;
2139 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|
2140 NTCREATEX_SHARE_ACCESS_WRITE
;
2141 io
.ntcreatex
.in
.alloc_size
= 0;
2142 io
.ntcreatex
.in
.open_disposition
= NTCREATEX_DISP_OPEN
;
2143 io
.ntcreatex
.in
.impersonation
= NTCREATEX_IMPERSONATION_ANONYMOUS
;
2144 io
.ntcreatex
.in
.security_flags
= 0;
2145 io
.ntcreatex
.in
.fname
= BASEDIR_CN1_NALIGN
;
2147 status
= smb_raw_open(cli
->tree
, tctx
, &io
);
2148 torture_assert_ntstatus_ok(tctx
, status
, "smb_raw_open");
2149 fnum
= io
.ntcreatex
.out
.file
.fnum
;
2151 /* ask for a change notify, on file creation */
2152 notify
.nttrans
.level
= RAW_NOTIFY_NTTRANS
;
2153 notify
.nttrans
.in
.buffer_size
= 1000;
2154 notify
.nttrans
.in
.completion_filter
= FILE_NOTIFY_CHANGE_FILE_NAME
;
2155 notify
.nttrans
.in
.file
.fnum
= fnum
;
2156 notify
.nttrans
.in
.recursive
= false;
2158 /* start change tracking */
2159 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
2161 fnum2
= smbcli_open(cli
->tree
, fname
, O_CREAT
|O_RDWR
, DENY_NONE
);
2162 torture_assert(tctx
, fnum2
!= -1, smbcli_errstr(cli
->tree
));
2163 smbcli_close(cli
->tree
, fnum2
);
2165 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
2166 torture_assert_ntstatus_ok(tctx
, status
, "smb_raw_changenotify_recv");
2168 /* create 4 files that will cause CHANGE_NOTIFY_INFO structures
2169 * to be returned in the same packet with all possible 4-byte padding
2170 * permutations. As per MS-CIFS 2.2.7.4.2 these structures should be
2171 * 4-byte aligned. */
2173 for (i
= 0; i
< num_names
; i
++) {
2174 fpath
= talloc_asprintf(tctx
, "%s\\%s",
2175 BASEDIR_CN1_NALIGN
, fnames
[i
]);
2176 fnum2
= smbcli_open(cli
->tree
, fpath
,
2177 O_CREAT
|O_RDWR
, DENY_NONE
);
2178 torture_assert(tctx
, fnum2
!= -1, smbcli_errstr(cli
->tree
));
2179 smbcli_close(cli
->tree
, fnum2
);
2184 * Slow cloud filesystems mean we might
2185 * not get everything in one go. Keep going
2186 * until we get them all.
2188 while (total_names_received
< num_names
) {
2189 struct tevent_timer
*te
= NULL
;
2190 struct cb_data to_data
= {0};
2193 * We send a notify packet, and let
2194 * smb_raw_changenotify_recv() do
2195 * the alignment checking for us.
2197 req
= smb_raw_changenotify_send(cli
->tree
, ¬ify
);
2198 torture_assert(tctx
,
2200 "smb_raw_changenotify_send failed\n");
2202 /* Ensure we don't wait more than 30 seconds. */
2204 to_data
.timed_out
= false;
2206 te
= tevent_add_timer(tctx
->ev
,
2208 tevent_timeval_current_ofs(30, 0),
2212 torture_fail(tctx
, "tevent_add_timer fail\n");
2215 status
= smb_raw_changenotify_recv(req
, tctx
, ¬ify
);
2216 if (!NT_STATUS_IS_OK(status
)) {
2217 if (to_data
.timed_out
== true) {
2218 torture_fail(tctx
, "smb_raw_changenotify_recv "
2223 torture_assert_ntstatus_ok(tctx
, status
,
2224 "smb_raw_changenotify_recv");
2226 for (i
= 0; i
< notify
.nttrans
.out
.num_changes
; i
++) {
2229 /* Ensure it was an 'add'. */
2230 torture_assert(tctx
,
2231 notify
.nttrans
.out
.changes
[i
].action
==
2232 NOTIFY_ACTION_ADDED
,
2235 for (j
= 0; j
< num_names
; j
++) {
2236 if (strcmp(notify
.nttrans
.out
.changes
[i
].name
.s
,
2238 if (fnames_received
[j
] == true) {
2240 talloc_asprintf(tctx
,
2249 /* already got this. */
2250 torture_fail(tctx
, err
);
2252 fnames_received
[j
] = true;
2256 if (j
== num_names
) {
2257 /* No name match. */
2258 const char *err
= talloc_asprintf(tctx
,
2259 "Unexpected name %s\n",
2260 notify
.nttrans
.out
.changes
[i
].name
.s
);
2262 torture_fail(tctx
, "talloc fail\n");
2264 torture_fail(tctx
, err
);
2266 total_names_received
++;
2270 smb_raw_exit(cli
->session
);
2271 smbcli_deltree(cli
->tree
, BASEDIR_CN1_NALIGN
);
2275 struct torture_suite
*torture_raw_notify(TALLOC_CTX
*mem_ctx
)
2277 struct torture_suite
*suite
= torture_suite_create(mem_ctx
, "notify");
2279 torture_suite_add_1smb_test(suite
, "tcon", test_notify_tcon
);
2280 torture_suite_add_2smb_test(suite
, "dir", test_notify_dir
);
2281 torture_suite_add_2smb_test(suite
, "mask", test_notify_mask
);
2282 torture_suite_add_2smb_test(suite
, "recursive", test_notify_recursive
);
2283 torture_suite_add_1smb_test(suite
, "mask_change",
2284 test_notify_mask_change
);
2285 torture_suite_add_1smb_test(suite
, "file", test_notify_file
);
2286 torture_suite_add_1smb_test(suite
, "tdis", test_notify_tdis
);
2287 torture_suite_add_1smb_test(suite
, "exit", test_notify_exit
);
2288 torture_suite_add_1smb_test(suite
, "ulogoff", test_notify_ulogoff
);
2289 torture_suite_add_1smb_test(suite
, "tcp_dis", test_notify_tcp_dis
);
2290 torture_suite_add_1smb_test(suite
, "double", test_notify_double
);
2291 torture_suite_add_2smb_test(suite
, "tree", test_notify_tree
);
2292 torture_suite_add_1smb_test(suite
, "overflow", test_notify_overflow
);
2293 torture_suite_add_1smb_test(suite
, "basedir", test_notify_basedir
);
2294 torture_suite_add_1smb_test(suite
, "alignment", test_notify_alignment
);