9a993f5bd8818b0e737f97adc3a03d8a75d0185a
[kai/samba-autobuild/.git] / source4 / torture / raw / notify.c
1 /* 
2    Unix SMB/CIFS implementation.
3    basic raw test suite for change notify
4    Copyright (C) Andrew Tridgell 2003
5    
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.
10    
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.
15    
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/>.
18 */
19
20 #include "includes.h"
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
28 #define BASEDIR "\\test_notify"
29
30 #define CHECK_WSTR(tctx, field, value, flags) \
31 do { \
32         torture_assert_str_equal(tctx, field.s, value, "values don't match"); \
33         torture_assert(tctx, \
34                        !wire_bad_flags(&field, STR_UNICODE, cli->transport), \
35                        "wire_bad_flags"); \
36 } while (0)
37
38 #define BASEDIR_CN1_DIR BASEDIR "_CN1_DIR"
39
40 /* 
41    basic testing of change notify on directories
42 */
43 static bool test_notify_dir(struct torture_context *tctx,
44                             struct smbcli_state *cli,
45                             struct smbcli_state *cli2)
46 {
47         bool ret = true;
48         NTSTATUS status;
49         union smb_notify notify;
50         union smb_open io;
51         union smb_close cl;
52         int i, count, fnum, fnum2;
53         struct smbcli_request *req, *req2;
54         extern int torture_numops;
55
56         torture_comment(tctx, "TESTING CHANGE NOTIFY ON DIRECTORIES\n");
57
58         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_DIR),
59                        "Failed to setup up test directory: " BASEDIR_CN1_DIR);
60
61         /*
62           get a handle on the directory
63         */
64         io.generic.level = RAW_OPEN_NTCREATEX;
65         io.ntcreatex.in.root_fid.fnum = 0;
66         io.ntcreatex.in.flags = 0;
67         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
68         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
69         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
70         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
71         io.ntcreatex.in.alloc_size = 0;
72         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
73         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
74         io.ntcreatex.in.security_flags = 0;
75         io.ntcreatex.in.fname = BASEDIR_CN1_DIR;
76
77         status = smb_raw_open(cli->tree, tctx, &io);
78         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
79                                         "smb_raw_open");
80         fnum = io.ntcreatex.out.file.fnum;
81
82         status = smb_raw_open(cli->tree, tctx, &io);
83         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
84                                         "smb_raw_open");
85         fnum2 = io.ntcreatex.out.file.fnum;
86
87         /* ask for a change notify,
88            on file or directory name changes */
89         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
90         notify.nttrans.in.buffer_size = 1000;
91         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
92         notify.nttrans.in.file.fnum = fnum;
93         notify.nttrans.in.recursive = true;
94
95         torture_comment(tctx, "Testing notify cancel\n");
96
97         req = smb_raw_changenotify_send(cli->tree, &notify);
98         smb_raw_ntcancel(req);
99         status = smb_raw_changenotify_recv(req, tctx, &notify);
100         torture_assert_ntstatus_equal_goto(tctx, status, NT_STATUS_CANCELLED,
101                                            ret, done,
102                                            "smb_raw_changenotify_recv");
103
104         torture_comment(tctx, "Testing notify mkdir\n");
105
106         req = smb_raw_changenotify_send(cli->tree, &notify);
107         smbcli_mkdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
108
109         status = smb_raw_changenotify_recv(req, tctx, &notify);
110         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
111                                         "smb_raw_changenotify_recv");
112
113         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
114                                       1, ret, done, "more than one change");
115         torture_assert_int_equal_goto(tctx,
116                                       notify.nttrans.out.changes[0].action,
117                                       NOTIFY_ACTION_ADDED, ret, done,
118                                       "wrong action (exp: ADDED)");
119         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
120                    STR_UNICODE);
121
122         torture_comment(tctx, "Testing notify rmdir\n");
123
124         req = smb_raw_changenotify_send(cli->tree, &notify);
125         smbcli_rmdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
126
127         status = smb_raw_changenotify_recv(req, tctx, &notify);
128         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
129                                         "smb_raw_changenotify_recv");
130         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
131                                       1, ret, done, "more than one change");
132         torture_assert_int_equal_goto(tctx,
133                                       notify.nttrans.out.changes[0].action,
134                                       NOTIFY_ACTION_REMOVED, ret, done,
135                                       "wrong action (exp: REMOVED)");
136         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
137                    STR_UNICODE);
138
139         torture_comment(tctx, "Testing notify mkdir - rmdir - mkdir - rmdir\n");
140
141         smbcli_mkdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
142         smbcli_rmdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
143         smbcli_mkdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
144         smbcli_rmdir(cli2->tree, BASEDIR_CN1_DIR "\\subdir-name");
145         smb_msleep(200);
146         req = smb_raw_changenotify_send(cli->tree, &notify);
147         status = smb_raw_changenotify_recv(req, tctx, &notify);
148         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
149                                         "smb_raw_changenotify_recv");
150         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
151                                       4, ret, done, "wrong number of changes");
152         torture_assert_int_equal_goto(tctx,
153                                       notify.nttrans.out.changes[0].action,
154                                       NOTIFY_ACTION_ADDED, ret, done,
155                                       "wrong action (exp: ADDED)");
156         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
157                    STR_UNICODE);
158         torture_assert_int_equal_goto(tctx,
159                                       notify.nttrans.out.changes[1].action,
160                                       NOTIFY_ACTION_REMOVED, ret, done,
161                                       "wrong action (exp: REMOVED)");
162         CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name, "subdir-name",
163                    STR_UNICODE);
164         torture_assert_int_equal_goto(tctx,
165                                       notify.nttrans.out.changes[2].action,
166                                       NOTIFY_ACTION_ADDED, ret, done,
167                                       "wrong action (exp: ADDED)");
168         CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name, "subdir-name",
169                    STR_UNICODE);
170         torture_assert_int_equal_goto(tctx,
171                                       notify.nttrans.out.changes[3].action,
172                                       NOTIFY_ACTION_REMOVED, ret, done,
173                                       "wrong action (exp: REMOVED)");
174         CHECK_WSTR(tctx, notify.nttrans.out.changes[3].name, "subdir-name",
175                    STR_UNICODE);
176
177         count = torture_numops;
178         torture_comment(tctx, "Testing buffered notify on create of %d files\n", count);
179         for (i=0;i<count;i++) {
180                 char *fname = talloc_asprintf(cli,
181                                 BASEDIR_CN1_DIR "\\test%d.txt",
182                                 i);
183                 int fnum3 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
184                 torture_assert_int_not_equal_goto(tctx, fnum3, -1, ret, done,
185                         talloc_asprintf(tctx, "Failed to create %s - %s",
186                                         fname, smbcli_errstr(cli->tree)));
187                 talloc_free(fname);
188                 smbcli_close(cli->tree, fnum3);
189         }
190
191         /* (1st notify) setup a new notify on a different directory handle.
192            This new notify won't see the events above. */
193         notify.nttrans.in.file.fnum = fnum2;
194         req2 = smb_raw_changenotify_send(cli->tree, &notify);
195
196         /* (2nd notify) whereas this notify will see the above buffered events,
197            and it directly returns the buffered events */
198         notify.nttrans.in.file.fnum = fnum;
199         req = smb_raw_changenotify_send(cli->tree, &notify);
200
201         status = smbcli_unlink(cli->tree, BASEDIR_CN1_DIR "\\nonexistent.txt");
202         torture_assert_ntstatus_equal_goto(tctx, status,
203                                            NT_STATUS_OBJECT_NAME_NOT_FOUND,
204                                            ret, done,
205                                            "smbcli_unlink");
206
207         /* (1st unlink) as the 2nd notify directly returns,
208            this unlink is only seen by the 1st notify and 
209            the 3rd notify (later) */
210         torture_comment(tctx, "Testing notify on unlink for the first file\n");
211         status = smbcli_unlink(cli2->tree, BASEDIR_CN1_DIR "\\test0.txt");
212         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
213                                         "smbcli_unlink");
214
215         /* receive the reply from the 2nd notify */
216         status = smb_raw_changenotify_recv(req, tctx, &notify);
217         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
218                                         "smb_raw_changenotify_recv");
219
220         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
221                                       count, ret, done,
222                                       "wrong number of changes");
223         for (i=1;i<count;i++) {
224                 torture_assert_int_equal_goto(tctx,
225                                         notify.nttrans.out.changes[i].action,
226                                         NOTIFY_ACTION_ADDED, ret, done,
227                                         "wrong action (exp: ADDED)");
228         }
229         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
230                    STR_UNICODE);
231
232         torture_comment(tctx, "and now from the 1st notify\n");
233         status = smb_raw_changenotify_recv(req2, tctx, &notify);
234         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
235                                         "smb_raw_changenotify_recv");
236         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
237                                       1, ret, done, "wrong number of changes");
238         torture_assert_int_equal_goto(tctx,
239                                       notify.nttrans.out.changes[0].action,
240                                       NOTIFY_ACTION_REMOVED, ret, done,
241                                       "wrong action (exp: REMOVED)");
242         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
243                    STR_UNICODE);
244
245         torture_comment(tctx, "(3rd notify) this notify will only see the 1st unlink\n");
246         req = smb_raw_changenotify_send(cli->tree, &notify);
247
248         status = smbcli_unlink(cli->tree, BASEDIR_CN1_DIR "\\nonexistent.txt");
249         torture_assert_ntstatus_equal_goto(tctx, status,
250                                            NT_STATUS_OBJECT_NAME_NOT_FOUND,
251                                            ret, done,
252                                            "smbcli_unlink");
253
254         torture_comment(tctx, "Testing notify on wildcard unlink for %d files\n", count-1);
255         /* (2nd unlink) do a wildcard unlink */
256         status = smbcli_unlink(cli2->tree, BASEDIR_CN1_DIR "\\test*.txt");
257         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
258                                         "smb_raw_changenotify_recv");
259
260         /* receive the 3rd notify */
261         status = smb_raw_changenotify_recv(req, tctx, &notify);
262         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
263                                         "smb_raw_changenotify_recv");
264         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
265                                       1, ret, done, "wrong number of changes");
266         torture_assert_int_equal_goto(tctx,
267                                       notify.nttrans.out.changes[0].action,
268                                       NOTIFY_ACTION_REMOVED, ret, done,
269                                       "wrong action (exp: REMOVED)");
270         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "test0.txt",
271                    STR_UNICODE);
272
273         /* and we now see the rest of the unlink calls on both directory handles */
274         notify.nttrans.in.file.fnum = fnum;
275         sleep(3);
276         req = smb_raw_changenotify_send(cli->tree, &notify);
277         status = smb_raw_changenotify_recv(req, tctx, &notify);
278         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
279                                         "smb_raw_changenotify_recv");
280         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
281                                       count - 1, ret, done,
282                                       "wrong number of changes");
283         for (i=0;i<notify.nttrans.out.num_changes;i++) {
284                 torture_assert_int_equal_goto(tctx,
285                                         notify.nttrans.out.changes[i].action,
286                                         NOTIFY_ACTION_REMOVED, ret, done,
287                                         "wrong action (exp: REMOVED)");
288         }
289         notify.nttrans.in.file.fnum = fnum2;
290         req = smb_raw_changenotify_send(cli->tree, &notify);
291         status = smb_raw_changenotify_recv(req, tctx, &notify);
292         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
293                                         "smb_raw_changenotify_recv");
294         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
295                                       count - 1, ret, done,
296                                       "wrong number of changes");
297         for (i=0;i<notify.nttrans.out.num_changes;i++) {
298                 torture_assert_int_equal_goto(tctx,
299                                         notify.nttrans.out.changes[i].action,
300                                         NOTIFY_ACTION_REMOVED, ret, done,
301                                         "wrong action (exp: REMOVED)");
302         }
303
304         torture_comment(tctx, "Testing if a close() on the dir handle triggers the notify reply\n");
305
306         notify.nttrans.in.file.fnum = fnum;
307         req = smb_raw_changenotify_send(cli->tree, &notify);
308
309         cl.close.level = RAW_CLOSE_CLOSE;
310         cl.close.in.file.fnum = fnum;
311         cl.close.in.write_time = 0;
312         status = smb_raw_close(cli->tree, &cl);
313         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
314                                         "smb_raw_close");
315
316         status = smb_raw_changenotify_recv(req, tctx, &notify);
317         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
318                                         "smb_raw_changenotify_recv");
319         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
320                                       0, ret, done, "no changes expected");
321
322 done:
323         smb_raw_exit(cli->session);
324         smbcli_deltree(cli->tree, BASEDIR_CN1_DIR);
325         return ret;
326 }
327
328 /*
329  * Check notify reply for a rename action. Not sure if this is a valid thing
330  * to do, but depending on timing between inotify and messaging we get the
331  * add/remove/modify in any order. This routines tries to find the action/name
332  * pair in any of the three following notify_changes.
333  */
334
335 static bool check_rename_reply(struct torture_context *tctx,
336                                struct smbcli_state *cli,
337                                int line,
338                                struct notify_changes *actions,
339                                uint32_t action, const char *name)
340 {
341         int i;
342
343         for (i=0; i<3; i++) {
344                 if (actions[i].action == action) {
345                         CHECK_WSTR(tctx, actions[i].name, name, STR_UNICODE);
346                         return true;
347                 }
348         }
349
350         torture_result(tctx, TORTURE_FAIL,
351                        __location__": (%d) expected action %d, not found\n",
352                        line, action);
353         return false;
354 }
355
356 /* 
357    testing of recursive change notify
358 */
359
360 #define BASEDIR_CN1_RECUR BASEDIR "_CN1_RECUR"
361
362 static bool test_notify_recursive(struct torture_context *tctx,
363                                   struct smbcli_state *cli,
364                                   struct smbcli_state *cli2)
365 {
366         bool ret = true;
367         NTSTATUS status;
368         union smb_notify notify;
369         union smb_open io;
370         int fnum;
371         struct smbcli_request *req1, *req2;
372
373         torture_comment(tctx, "TESTING CHANGE NOTIFY WITH RECURSION\n");
374
375         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_RECUR),
376                        "Failed to setup up test directory: " BASEDIR_CN1_RECUR);
377
378         /*
379           get a handle on the directory
380         */
381         io.generic.level = RAW_OPEN_NTCREATEX;
382         io.ntcreatex.in.root_fid.fnum = 0;
383         io.ntcreatex.in.flags = 0;
384         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
385         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
386         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
387         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
388         io.ntcreatex.in.alloc_size = 0;
389         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
390         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
391         io.ntcreatex.in.security_flags = 0;
392         io.ntcreatex.in.fname = BASEDIR_CN1_RECUR;
393
394         status = smb_raw_open(cli->tree, tctx, &io);
395         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
396                                         "smb_raw_open");
397         fnum = io.ntcreatex.out.file.fnum;
398
399         /* ask for a change notify, on file or directory name
400            changes. Setup both with and without recursion */
401         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
402         notify.nttrans.in.buffer_size = 1000;
403         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
404         notify.nttrans.in.file.fnum = fnum;
405
406         notify.nttrans.in.recursive = true;
407         req1 = smb_raw_changenotify_send(cli->tree, &notify);
408
409         notify.nttrans.in.recursive = false;
410         req2 = smb_raw_changenotify_send(cli->tree, &notify);
411
412         /* cancel initial requests so the buffer is setup */
413         smb_raw_ntcancel(req1);
414         status = smb_raw_changenotify_recv(req1, tctx, &notify);
415         torture_assert_ntstatus_equal_goto(tctx, status,
416                                            NT_STATUS_CANCELLED,
417                                            ret, done,
418                                            "smb_raw_changenotify_recv");
419
420         smb_raw_ntcancel(req2);
421         status = smb_raw_changenotify_recv(req2, tctx, &notify);
422         torture_assert_ntstatus_equal_goto(tctx, status,
423                                            NT_STATUS_CANCELLED,
424                                            ret, done,
425                                            "smb_raw_changenotify_recv");
426
427         /*
428          * Make notifies a bit more interesting in a cluster by doing
429          * the changes against different nodes with --unclist
430          */
431         smbcli_mkdir(cli->tree, BASEDIR_CN1_RECUR "\\subdir-name");
432         smbcli_mkdir(cli2->tree, BASEDIR_CN1_RECUR "\\subdir-name\\subname1");
433         smbcli_close(cli->tree, 
434                      smbcli_open(cli->tree,
435                                 BASEDIR_CN1_RECUR "\\subdir-name\\subname2",
436                                 O_CREAT, 0));
437         smbcli_rename(cli2->tree, BASEDIR_CN1_RECUR "\\subdir-name\\subname1",
438                       BASEDIR_CN1_RECUR "\\subdir-name\\subname1-r");
439         smbcli_rename(cli->tree,
440                 BASEDIR_CN1_RECUR "\\subdir-name\\subname2",
441                 BASEDIR_CN1_RECUR "\\subname2-r");
442         smbcli_rename(cli2->tree, BASEDIR_CN1_RECUR "\\subname2-r",
443                       BASEDIR_CN1_RECUR "\\subname3-r");
444
445         notify.nttrans.in.completion_filter = 0;
446         notify.nttrans.in.recursive = true;
447         smb_msleep(200);
448         req1 = smb_raw_changenotify_send(cli->tree, &notify);
449
450         smbcli_rmdir(cli->tree, BASEDIR_CN1_RECUR "\\subdir-name\\subname1-r");
451         smbcli_rmdir(cli2->tree, BASEDIR_CN1_RECUR "\\subdir-name");
452         smbcli_unlink(cli->tree, BASEDIR_CN1_RECUR "\\subname3-r");
453
454         smb_msleep(200);
455         notify.nttrans.in.recursive = false;
456         req2 = smb_raw_changenotify_send(cli->tree, &notify);
457
458         status = smb_raw_changenotify_recv(req1, tctx, &notify);
459         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
460                                         "smb_raw_changenotify_recv");
461
462         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
463                                       11, ret, done, "wrong number of changes");
464         torture_assert_int_equal_goto(tctx,
465                                       notify.nttrans.out.changes[0].action,
466                                       NOTIFY_ACTION_ADDED, ret, done,
467                                       "wrong action (exp: ADDED)");
468         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
469                    STR_UNICODE);
470         torture_assert_int_equal_goto(tctx,
471                                       notify.nttrans.out.changes[1].action,
472                                       NOTIFY_ACTION_ADDED, ret, done,
473                                       "wrong action (exp: ADDED)");
474         CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name,
475                    "subdir-name\\subname1", STR_UNICODE);
476         torture_assert_int_equal_goto(tctx,
477                                       notify.nttrans.out.changes[2].action,
478                                       NOTIFY_ACTION_ADDED, ret, done,
479                                       "wrong action (exp: ADDED)");
480         CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name,
481                    "subdir-name\\subname2", STR_UNICODE);
482         torture_assert_int_equal_goto(tctx,
483                                       notify.nttrans.out.changes[3].action,
484                                       NOTIFY_ACTION_OLD_NAME, ret, done,
485                                       "wrong action (exp: OLD_NAME)");
486         CHECK_WSTR(tctx, notify.nttrans.out.changes[3].name,
487                    "subdir-name\\subname1", STR_UNICODE);
488         torture_assert_int_equal_goto(tctx,
489                                       notify.nttrans.out.changes[4].action,
490                                       NOTIFY_ACTION_NEW_NAME, ret, done,
491                                       "wrong action (exp: NEW_NAME)");
492         CHECK_WSTR(tctx, notify.nttrans.out.changes[4].name,
493                    "subdir-name\\subname1-r", STR_UNICODE);
494
495         ret &= check_rename_reply(tctx,
496                 cli, __LINE__, &notify.nttrans.out.changes[5],
497                 NOTIFY_ACTION_ADDED, "subname2-r");
498         ret &= check_rename_reply(tctx,
499                 cli, __LINE__, &notify.nttrans.out.changes[5],
500                 NOTIFY_ACTION_REMOVED, "subdir-name\\subname2");
501         ret &= check_rename_reply(tctx,
502                 cli, __LINE__, &notify.nttrans.out.changes[5],
503                 NOTIFY_ACTION_MODIFIED, "subname2-r");
504                 
505         ret &= check_rename_reply(tctx,
506                 cli, __LINE__, &notify.nttrans.out.changes[8],
507                 NOTIFY_ACTION_OLD_NAME, "subname2-r");
508         ret &= check_rename_reply(tctx,
509                 cli, __LINE__, &notify.nttrans.out.changes[8],
510                 NOTIFY_ACTION_NEW_NAME, "subname3-r");
511         ret &= check_rename_reply(tctx,
512                 cli, __LINE__, &notify.nttrans.out.changes[8],
513                 NOTIFY_ACTION_MODIFIED, "subname3-r");
514
515         if (!ret) {
516                 goto done;
517         }
518
519         status = smb_raw_changenotify_recv(req2, tctx, &notify);
520         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
521                                         "smb_raw_changenotify_recv");
522
523         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
524                                       3, ret, done, "wrong number of changes");
525         torture_assert_int_equal_goto(tctx,
526                                       notify.nttrans.out.changes[0].action,
527                                       NOTIFY_ACTION_REMOVED, ret, done,
528                                       "wrong action (exp: REMOVED)");
529         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name,
530                    "subdir-name\\subname1-r", STR_UNICODE);
531         torture_assert_int_equal_goto(tctx,
532                                       notify.nttrans.out.changes[1].action,
533                                       NOTIFY_ACTION_REMOVED, ret, done,
534                                       "wrong action (exp: REMOVED)");
535         CHECK_WSTR(tctx, notify.nttrans.out.changes[1].name, "subdir-name",
536                    STR_UNICODE);
537         torture_assert_int_equal_goto(tctx,
538                                       notify.nttrans.out.changes[2].action,
539                                       NOTIFY_ACTION_REMOVED, ret, done,
540                                       "wrong action (exp: REMOVED)");
541         CHECK_WSTR(tctx, notify.nttrans.out.changes[2].name, "subname3-r",
542                    STR_UNICODE);
543
544 done:
545         smb_raw_exit(cli->session);
546         smbcli_deltree(cli->tree, BASEDIR_CN1_RECUR);
547         return ret;
548 }
549
550 /* 
551    testing of change notify mask change
552 */
553
554 #define BASEDIR_CN1_CNMC BASEDIR "_CN1_CNMC"
555
556 static bool test_notify_mask_change(struct torture_context *tctx,
557                                     struct smbcli_state *cli)
558 {
559         bool ret = true;
560         NTSTATUS status;
561         union smb_notify notify;
562         union smb_open io;
563         int fnum;
564         struct smbcli_request *req1, *req2;
565
566         torture_comment(tctx, "TESTING CHANGE NOTIFY WITH MASK CHANGE\n");
567
568         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_CNMC),
569                        "Failed to setup up test directory: " BASEDIR_CN1_CNMC);
570
571         /*
572           get a handle on the directory
573         */
574         io.generic.level = RAW_OPEN_NTCREATEX;
575         io.ntcreatex.in.root_fid.fnum = 0;
576         io.ntcreatex.in.flags = 0;
577         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
578         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
579         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
580         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
581         io.ntcreatex.in.alloc_size = 0;
582         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
583         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
584         io.ntcreatex.in.security_flags = 0;
585         io.ntcreatex.in.fname = BASEDIR_CN1_CNMC;
586
587         status = smb_raw_open(cli->tree, tctx, &io);
588         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
589                                         "smb_raw_open");
590         fnum = io.ntcreatex.out.file.fnum;
591
592         /* ask for a change notify, on file or directory name
593            changes. Setup both with and without recursion */
594         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
595         notify.nttrans.in.buffer_size = 1000;
596         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
597         notify.nttrans.in.file.fnum = fnum;
598
599         notify.nttrans.in.recursive = true;
600         req1 = smb_raw_changenotify_send(cli->tree, &notify);
601
602         notify.nttrans.in.recursive = false;
603         req2 = smb_raw_changenotify_send(cli->tree, &notify);
604
605         /* cancel initial requests so the buffer is setup */
606         smb_raw_ntcancel(req1);
607         status = smb_raw_changenotify_recv(req1, tctx, &notify);
608         torture_assert_ntstatus_equal_goto(tctx, status,
609                                            NT_STATUS_CANCELLED,
610                                            ret, done,
611                                            "smb_raw_changenotify_recv");
612
613         smb_raw_ntcancel(req2);
614         status = smb_raw_changenotify_recv(req2, tctx, &notify);
615         torture_assert_ntstatus_equal_goto(tctx, status,
616                                            NT_STATUS_CANCELLED,
617                                            ret, done,
618                                            "smb_raw_changenotify_recv");
619
620         notify.nttrans.in.recursive = true;
621         req1 = smb_raw_changenotify_send(cli->tree, &notify);
622
623         /* Set to hidden then back again. */
624         smbcli_close(cli->tree,
625                 smbcli_open(cli->tree,BASEDIR_CN1_CNMC "\\tname1", O_CREAT, 0));
626         smbcli_setatr(cli->tree, BASEDIR_CN1_CNMC "\\tname1",
627                 FILE_ATTRIBUTE_HIDDEN, 0);
628         smbcli_unlink(cli->tree, BASEDIR_CN1_CNMC "\\tname1");
629
630         status = smb_raw_changenotify_recv(req1, tctx, &notify);
631         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
632                                         "smb_raw_changenotify_recv");
633
634         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
635                                       1, ret, done, "wrong number of changes");
636         torture_assert_int_equal_goto(tctx,
637                                       notify.nttrans.out.changes[0].action,
638                                       NOTIFY_ACTION_MODIFIED, ret, done,
639                                       "wrong action (exp: MODIFIED)");
640         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "tname1",
641                    STR_UNICODE);
642
643         /* Now try and change the mask to include other events.
644          * This should not work - once the mask is set on a directory
645          * fnum it seems to be fixed until the fnum is closed. */
646
647         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_CREATION;
648         notify.nttrans.in.recursive = true;
649         req1 = smb_raw_changenotify_send(cli->tree, &notify);
650
651         notify.nttrans.in.recursive = false;
652         req2 = smb_raw_changenotify_send(cli->tree, &notify);
653
654         smbcli_mkdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name");
655         smbcli_mkdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name\\subname1");
656         smbcli_close(cli->tree, 
657                      smbcli_open(cli->tree,
658                         BASEDIR_CN1_CNMC "\\subdir-name\\subname2",
659                         O_CREAT, 0));
660         smbcli_rename(cli->tree,
661                         BASEDIR_CN1_CNMC "\\subdir-name\\subname1",
662                         BASEDIR_CN1_CNMC "\\subdir-name\\subname1-r");
663         smbcli_rename(cli->tree,
664                         BASEDIR_CN1_CNMC "\\subdir-name\\subname2",
665                         BASEDIR_CN1_CNMC "\\subname2-r");
666         smbcli_rename(cli->tree,
667                         BASEDIR_CN1_CNMC "\\subname2-r",
668                         BASEDIR_CN1_CNMC "\\subname3-r");
669
670         smbcli_rmdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name\\subname1-r");
671         smbcli_rmdir(cli->tree, BASEDIR_CN1_CNMC "\\subdir-name");
672         smbcli_unlink(cli->tree, BASEDIR_CN1_CNMC "\\subname3-r");
673
674         status = smb_raw_changenotify_recv(req1, tctx, &notify);
675         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
676                                         "smb_raw_changenotify_recv");
677
678         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
679                                       1, ret, done, "wrong number of changes");
680         torture_assert_int_equal_goto(tctx,
681                                       notify.nttrans.out.changes[0].action,
682                                       NOTIFY_ACTION_MODIFIED, ret, done,
683                                       "wrong action (exp: MODIFIED)");
684         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subname2-r",
685                    STR_UNICODE);
686
687         status = smb_raw_changenotify_recv(req2, tctx, &notify);
688         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
689                                         "smb_raw_changenotify_recv");
690
691         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
692                                       1, ret, done, "wrong number of changes");
693         torture_assert_int_equal_goto(tctx,
694                                       notify.nttrans.out.changes[0].action,
695                                       NOTIFY_ACTION_MODIFIED, ret, done,
696                                       "wrong action (exp: MODIFIED)");
697         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subname3-r",
698                    STR_UNICODE);
699
700 done:
701         smb_raw_exit(cli->session);
702         smbcli_deltree(cli->tree, BASEDIR_CN1_CNMC);
703         return ret;
704 }
705
706
707 /* 
708    testing of mask bits for change notify
709 */
710
711 #define BASEDIR_CN1_NOTM BASEDIR "_CN1_NOTM"
712
713 static bool test_notify_mask(struct torture_context *tctx,
714                              struct smbcli_state *cli,
715                              struct smbcli_state *cli2)
716 {
717         bool ret = true;
718         NTSTATUS status;
719         union smb_notify notify;
720         union smb_open io;
721         union smb_chkpath chkpath;
722         int fnum, fnum2;
723         uint32_t mask;
724         int i;
725         char c = 1;
726         struct timeval tv;
727         NTTIME t;
728
729         torture_comment(tctx, "TESTING CHANGE NOTIFY COMPLETION FILTERS\n");
730
731         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NOTM),
732                        "Failed to setup up test directory: " BASEDIR_CN1_NOTM);
733
734         tv = timeval_current_ofs(1000, 0);
735         t = timeval_to_nttime(&tv);
736
737         /*
738           get a handle on the directory
739         */
740         io.generic.level = RAW_OPEN_NTCREATEX;
741         io.ntcreatex.in.root_fid.fnum = 0;
742         io.ntcreatex.in.flags = 0;
743         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
744         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
745         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
746         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
747         io.ntcreatex.in.alloc_size = 0;
748         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
749         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
750         io.ntcreatex.in.security_flags = 0;
751         io.ntcreatex.in.fname = BASEDIR_CN1_NOTM;
752
753         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
754         notify.nttrans.in.buffer_size = 1000;
755         notify.nttrans.in.recursive = true;
756
757         chkpath.chkpath.in.path = "\\";
758
759 #define NOTIFY_MASK_TEST(test_name, setup, op, cleanup, Action, expected, nchanges) \
760         do { \
761         smbcli_getatr(cli->tree, test_name, NULL, NULL, NULL); \
762         for (mask=i=0;i<32;i++) { \
763                 struct smbcli_request *req; \
764                 status = smb_raw_open(cli->tree, tctx, &io); \
765                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
766                                                 "smb_raw_open"); \
767                 fnum = io.ntcreatex.out.file.fnum; \
768                 setup \
769                 notify.nttrans.in.file.fnum = fnum;     \
770                 notify.nttrans.in.completion_filter = (1<<i); \
771                 req = smb_raw_changenotify_send(cli->tree, &notify); \
772                 smb_raw_chkpath(cli->tree, &chkpath); \
773                 op \
774                 smb_msleep(200); smb_raw_ntcancel(req); \
775                 status = smb_raw_changenotify_recv(req, tctx, &notify); \
776                 cleanup \
777                 smbcli_close(cli->tree, fnum); \
778                 if (NT_STATUS_EQUAL(status, NT_STATUS_CANCELLED)) continue; \
779                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done, \
780                                                 "smbcli_close"); \
781                 /* special case to cope with file rename behaviour */ \
782                 if (nchanges == 2 && notify.nttrans.out.num_changes == 1 && \
783                     notify.nttrans.out.changes[0].action == NOTIFY_ACTION_MODIFIED && \
784                     ((expected) & FILE_NOTIFY_CHANGE_ATTRIBUTES) && \
785                     Action == NOTIFY_ACTION_OLD_NAME) { \
786                         torture_comment(tctx, "(rename file special handling OK)\n"); \
787                 } else { \
788                         torture_assert_int_equal_goto(tctx, \
789                                 notify.nttrans.out.num_changes,\
790                                 nchanges, ret, done, \
791                                 talloc_asprintf(tctx, \
792                                         "nchanges=%d expected=%d action=%d " \
793                                         "filter=0x%08x\n", \
794                                         notify.nttrans.out.num_changes, \
795                                         nchanges, \
796                                         notify.nttrans.out.changes[0].action, \
797                                         notify.nttrans.in.completion_filter)); \
798                         torture_assert_int_equal_goto(tctx, \
799                                 notify.nttrans.out.changes[0].action, \
800                                 Action, ret, done, \
801                                 talloc_asprintf(tctx, \
802                                         "nchanges=%d action=%d " \
803                                         "expectedAction=%d filter=0x%08x\n", \
804                                         notify.nttrans.out.num_changes, \
805                                         notify.nttrans.out.changes[0].action, \
806                                         Action, \
807                                         notify.nttrans.in.completion_filter)); \
808                         torture_assert_str_equal_goto(tctx, \
809                                 notify.nttrans.out.changes[0].name.s, \
810                                 "tname1", ret, done, \
811                                 talloc_asprintf(tctx, \
812                                         "nchanges=%d action=%d filter=0x%08x " \
813                                         "name=%s expected_name=tname1\n", \
814                                         notify.nttrans.out.num_changes, \
815                                         notify.nttrans.out.changes[0].action, \
816                                         notify.nttrans.in.completion_filter, \
817                                         notify.nttrans.out.changes[0].name.s));\
818                 } \
819                 mask |= (1<<i); \
820         } \
821         if ((expected) != mask) { \
822                 torture_assert_int_not_equal_goto(tctx, ((expected) & ~mask), \
823                                 0, ret, done, "Too few bits"); \
824                 torture_comment(tctx, "WARNING: trigger on too many bits. mask=0x%08x expected=0x%08x\n", \
825                        mask, expected); \
826         } \
827         } while (0);
828
829         torture_comment(tctx, "Testing mkdir\n");
830         NOTIFY_MASK_TEST("Testing mkdir",;,
831                          smbcli_mkdir(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
832                          smbcli_rmdir(cli2->tree, BASEDIR_CN1_NOTM "\\tname1");,
833                          NOTIFY_ACTION_ADDED,
834                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
835
836         torture_comment(tctx, "Testing create file\n");
837         NOTIFY_MASK_TEST("Testing create file",;,
838                          smbcli_close(cli->tree,
839                                 smbcli_open(cli->tree,
840                                         BASEDIR_CN1_NOTM "\\tname1",
841                                         O_CREAT, 0));,
842                          smbcli_unlink(cli2->tree,
843                                 BASEDIR_CN1_NOTM "\\tname1");,
844                          NOTIFY_ACTION_ADDED,
845                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
846
847         torture_comment(tctx, "Testing unlink\n");
848         NOTIFY_MASK_TEST("Testing unlink",
849                          smbcli_close(cli->tree,
850                                 smbcli_open(cli->tree,
851                                         BASEDIR_CN1_NOTM "\\tname1",
852                                         O_CREAT, 0));,
853                          smbcli_unlink(cli2->tree,
854                                 BASEDIR_CN1_NOTM "\\tname1");,
855                          ;,
856                          NOTIFY_ACTION_REMOVED,
857                          FILE_NOTIFY_CHANGE_FILE_NAME, 1);
858
859         torture_comment(tctx, "Testing rmdir\n");
860         NOTIFY_MASK_TEST("Testing rmdir",
861                          smbcli_mkdir(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
862                          smbcli_rmdir(cli2->tree, BASEDIR_CN1_NOTM "\\tname1");,
863                          ;,
864                          NOTIFY_ACTION_REMOVED,
865                          FILE_NOTIFY_CHANGE_DIR_NAME, 1);
866
867         torture_comment(tctx, "Testing rename file\n");
868         NOTIFY_MASK_TEST("Testing rename file",
869                          smbcli_close(cli->tree,
870                                 smbcli_open(cli->tree,
871                                         BASEDIR_CN1_NOTM "\\tname1",
872                                         O_CREAT, 0));,
873                          smbcli_rename(cli2->tree,
874                                 BASEDIR_CN1_NOTM "\\tname1",
875                                 BASEDIR_CN1_NOTM "\\tname2");,
876                          smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname2");,
877                          NOTIFY_ACTION_OLD_NAME,
878                          FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_CREATION, 2);
879
880         torture_comment(tctx, "Testing rename dir\n");
881         NOTIFY_MASK_TEST("Testing rename dir",
882                 smbcli_mkdir(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
883                 smbcli_rename(cli2->tree,
884                         BASEDIR_CN1_NOTM "\\tname1",
885                         BASEDIR_CN1_NOTM "\\tname2");,
886                 smbcli_rmdir(cli->tree, BASEDIR_CN1_NOTM "\\tname2");,
887                 NOTIFY_ACTION_OLD_NAME,
888                 FILE_NOTIFY_CHANGE_DIR_NAME, 2);
889
890         torture_comment(tctx, "Testing set path attribute\n");
891         NOTIFY_MASK_TEST("Testing set path attribute",
892                 smbcli_close(cli->tree,
893                         smbcli_open(cli->tree,
894                                 BASEDIR_CN1_NOTM "\\tname1", O_CREAT, 0));,
895                 smbcli_setatr(cli2->tree,
896                         BASEDIR_CN1_NOTM "\\tname1", FILE_ATTRIBUTE_HIDDEN, 0);,
897                 smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
898                 NOTIFY_ACTION_MODIFIED,
899                 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
900
901         torture_comment(tctx, "Testing set path write time\n");
902         NOTIFY_MASK_TEST("Testing set path write time",
903                 smbcli_close(cli->tree, smbcli_open(cli->tree,
904                         BASEDIR_CN1_NOTM "\\tname1", O_CREAT, 0));,
905                 smbcli_setatr(cli2->tree,
906                         BASEDIR_CN1_NOTM "\\tname1",
907                         FILE_ATTRIBUTE_NORMAL, 1000);,
908                 smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1");,
909                 NOTIFY_ACTION_MODIFIED,
910                 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
911
912         torture_comment(tctx, "Testing set file attribute\n");
913         NOTIFY_MASK_TEST("Testing set file attribute",
914                 fnum2 = create_complex_file(cli2, tctx,
915                         BASEDIR_CN1_NOTM "\\tname1");,
916                 smbcli_fsetatr(cli2->tree, fnum2, FILE_ATTRIBUTE_HIDDEN, 0, 0, 0, 0);,
917                 (smbcli_close(cli2->tree, fnum2),
918                 smbcli_unlink(cli2->tree, BASEDIR_CN1_NOTM "\\tname1"));,
919                 NOTIFY_ACTION_MODIFIED,
920                 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
921
922         if (torture_setting_bool(tctx, "samba3", false)) {
923                 torture_comment(tctx, "Samba3 does not yet support create times "
924                        "everywhere\n");
925         }
926         else {
927                 torture_comment(tctx, "Testing set file create time\n");
928                 NOTIFY_MASK_TEST("Testing set file create time",
929                         fnum2 = create_complex_file(cli, tctx,
930                                             BASEDIR_CN1_NOTM "\\tname1");,
931                         smbcli_fsetatr(cli->tree, fnum2, 0, t, 0, 0, 0);,
932                         (smbcli_close(cli->tree, fnum2),
933                          smbcli_unlink(cli->tree,
934                                         BASEDIR_CN1_NOTM "\\tname1"));,
935                         NOTIFY_ACTION_MODIFIED,
936                         FILE_NOTIFY_CHANGE_CREATION, 1);
937         }
938
939         torture_comment(tctx, "Testing set file access time\n");
940         NOTIFY_MASK_TEST("Testing set file access time",
941                 fnum2 = create_complex_file(cli, tctx,
942                                 BASEDIR_CN1_NOTM "\\tname1");,
943                 smbcli_fsetatr(cli->tree, fnum2, 0, 0, t, 0, 0);,
944                 (smbcli_close(cli->tree, fnum2),
945                         smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
946                 NOTIFY_ACTION_MODIFIED,
947                 FILE_NOTIFY_CHANGE_LAST_ACCESS, 1);
948
949         torture_comment(tctx, "Testing set file write time\n");
950         NOTIFY_MASK_TEST("Testing set file write time",
951                 fnum2 = create_complex_file(cli, tctx,
952                         BASEDIR_CN1_NOTM "\\tname1");,
953                 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, t, 0);,
954                 (smbcli_close(cli->tree, fnum2),
955                 smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
956                 NOTIFY_ACTION_MODIFIED,
957                 FILE_NOTIFY_CHANGE_LAST_WRITE, 1);
958
959         torture_comment(tctx, "Testing set file change time\n");
960         NOTIFY_MASK_TEST("Testing set file change time",
961                 fnum2 = create_complex_file(cli, tctx,
962                         BASEDIR_CN1_NOTM "\\tname1");,
963                 smbcli_fsetatr(cli->tree, fnum2, 0, 0, 0, 0, t);,
964                 (smbcli_close(cli->tree, fnum2),
965                 smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
966                 NOTIFY_ACTION_MODIFIED,
967                 0, 1);
968
969
970         torture_comment(tctx, "Testing write\n");
971         NOTIFY_MASK_TEST("Testing write",
972                 fnum2 = create_complex_file(cli2, tctx,
973                         BASEDIR_CN1_NOTM "\\tname1");,
974                 smbcli_write(cli2->tree, fnum2, 1, &c, 10000, 1);,
975                 (smbcli_close(cli2->tree, fnum2),
976                         smbcli_unlink(cli->tree, BASEDIR_CN1_NOTM "\\tname1"));,
977                 NOTIFY_ACTION_MODIFIED,
978                 0, 1);
979
980         torture_comment(tctx, "Testing truncate\n");
981         NOTIFY_MASK_TEST("Testing truncate",
982                 fnum2 = create_complex_file(cli2, tctx,
983                         BASEDIR_CN1_NOTM "\\tname1");,
984                 smbcli_ftruncate(cli2->tree, fnum2, 10000);,
985                 (smbcli_close(cli2->tree, fnum2),
986                 smbcli_unlink(cli2->tree, BASEDIR_CN1_NOTM "\\tname1"));,
987                 NOTIFY_ACTION_MODIFIED,
988                 FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_ATTRIBUTES, 1);
989
990 done:
991         smb_raw_exit(cli->session);
992         smbcli_deltree(cli->tree, BASEDIR_CN1_NOTM);
993         return ret;
994 }
995
996 /*
997   basic testing of change notify on files
998 */
999
1000 #define BASEDIR_CN1_FILE BASEDIR "_CN1_FILE"
1001
1002 static bool test_notify_file(struct torture_context *tctx,
1003                              struct smbcli_state *cli)
1004 {
1005         NTSTATUS status;
1006         bool ret = true;
1007         union smb_open io;
1008         union smb_close cl;
1009         union smb_notify notify;
1010         struct smbcli_request *req;
1011         int fnum;
1012         const char *fname = BASEDIR_CN1_FILE "\\file.txt";
1013
1014         torture_comment(tctx, "TESTING CHANGE NOTIFY ON FILES\n");
1015
1016         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_FILE),
1017                        "Failed to setup up test directory: " BASEDIR_CN1_FILE);
1018
1019         io.generic.level = RAW_OPEN_NTCREATEX;
1020         io.ntcreatex.in.root_fid.fnum = 0;
1021         io.ntcreatex.in.flags = 0;
1022         io.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
1023         io.ntcreatex.in.create_options = 0;
1024         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1025         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1026         io.ntcreatex.in.alloc_size = 0;
1027         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
1028         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1029         io.ntcreatex.in.security_flags = 0;
1030         io.ntcreatex.in.fname = fname;
1031         status = smb_raw_open(cli->tree, tctx, &io);
1032         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1033                                         "smb_raw_open");
1034         fnum = io.ntcreatex.out.file.fnum;
1035
1036         /* ask for a change notify,
1037            on file or directory name changes */
1038         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1039         notify.nttrans.in.file.fnum = fnum;
1040         notify.nttrans.in.buffer_size = 1000;
1041         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_STREAM_NAME;
1042         notify.nttrans.in.recursive = false;
1043
1044         torture_comment(tctx, "Testing if notifies on file handles are invalid (should be)\n");
1045
1046         req = smb_raw_changenotify_send(cli->tree, &notify);
1047         status = smb_raw_changenotify_recv(req, tctx, &notify);
1048         torture_assert_ntstatus_equal_goto(tctx, status,
1049                                            NT_STATUS_INVALID_PARAMETER,
1050                                            ret, done,
1051                                            "smb_raw_changenotify_recv");
1052
1053         cl.close.level = RAW_CLOSE_CLOSE;
1054         cl.close.in.file.fnum = fnum;
1055         cl.close.in.write_time = 0;
1056         status = smb_raw_close(cli->tree, &cl);
1057         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1058                                         "smb_raw_close");
1059
1060         status = smbcli_unlink(cli->tree, fname);
1061         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1062                                         "smbcli_unlink");
1063
1064 done:
1065         smb_raw_exit(cli->session);
1066         smbcli_deltree(cli->tree, BASEDIR_CN1_FILE);
1067         return ret;
1068 }
1069
1070 /*
1071   basic testing of change notifies followed by a tdis
1072 */
1073 #define BASEDIR_CN1_TDIS BASEDIR "_CN1_TDIS"
1074
1075 static bool test_notify_tdis(struct torture_context *tctx,
1076                              struct smbcli_state *cli1)
1077 {
1078         bool ret = true;
1079         NTSTATUS status;
1080         union smb_notify notify;
1081         union smb_open io;
1082         int fnum;
1083         struct smbcli_request *req;
1084         struct smbcli_state *cli = NULL;
1085
1086         torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY TDIS\n");
1087
1088         torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_TDIS),
1089                        "Failed to setup up test directory: " BASEDIR_CN1_TDIS);
1090
1091         torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1092                        "Failed to open connection.");
1093
1094         /*
1095           get a handle on the directory
1096         */
1097         io.generic.level = RAW_OPEN_NTCREATEX;
1098         io.ntcreatex.in.root_fid.fnum = 0;
1099         io.ntcreatex.in.flags = 0;
1100         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1101         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1102         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1103         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1104         io.ntcreatex.in.alloc_size = 0;
1105         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1106         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1107         io.ntcreatex.in.security_flags = 0;
1108         io.ntcreatex.in.fname = BASEDIR_CN1_TDIS;
1109
1110         status = smb_raw_open(cli->tree, tctx, &io);
1111         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1112                                         "smb_raw_open");
1113         fnum = io.ntcreatex.out.file.fnum;
1114
1115         /* ask for a change notify,
1116            on file or directory name changes */
1117         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1118         notify.nttrans.in.buffer_size = 1000;
1119         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1120         notify.nttrans.in.file.fnum = fnum;
1121         notify.nttrans.in.recursive = true;
1122
1123         req = smb_raw_changenotify_send(cli->tree, &notify);
1124
1125         status = smbcli_tdis(cli);
1126         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1127                                         "smbcli_tdis");
1128         cli->tree = NULL;
1129
1130         status = smb_raw_changenotify_recv(req, tctx, &notify);
1131         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1132                                         "smb_raw_changenotify_recv");
1133         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1134                                       0, ret, done, "no changes expected");
1135
1136 done:
1137         torture_close_connection(cli);
1138         smbcli_deltree(cli1->tree, BASEDIR_CN1_TDIS);
1139         return ret;
1140 }
1141
1142 /*
1143   basic testing of change notifies followed by a exit
1144 */
1145
1146 #define BASEDIR_CN1_EX BASEDIR "_CN1_EX"
1147
1148 static bool test_notify_exit(struct torture_context *tctx,
1149                              struct smbcli_state *cli1)
1150 {
1151         bool ret = true;
1152         NTSTATUS status;
1153         union smb_notify notify;
1154         union smb_open io;
1155         int fnum;
1156         struct smbcli_request *req;
1157         struct smbcli_state *cli = NULL;
1158
1159         torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY EXIT\n");
1160
1161         torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_EX),
1162                        "Failed to setup up test directory: " BASEDIR_CN1_EX);
1163
1164         torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1165                        "Failed to open connection.");
1166
1167         /*
1168           get a handle on the directory
1169         */
1170         io.generic.level = RAW_OPEN_NTCREATEX;
1171         io.ntcreatex.in.root_fid.fnum = 0;
1172         io.ntcreatex.in.flags = 0;
1173         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1174         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1175         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1176         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1177         io.ntcreatex.in.alloc_size = 0;
1178         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1179         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1180         io.ntcreatex.in.security_flags = 0;
1181         io.ntcreatex.in.fname = BASEDIR_CN1_EX;
1182
1183         status = smb_raw_open(cli->tree, tctx, &io);
1184         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1185                                         "smb_raw_open");
1186         fnum = io.ntcreatex.out.file.fnum;
1187
1188         /* ask for a change notify,
1189            on file or directory name changes */
1190         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1191         notify.nttrans.in.buffer_size = 1000;
1192         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1193         notify.nttrans.in.file.fnum = fnum;
1194         notify.nttrans.in.recursive = true;
1195
1196         req = smb_raw_changenotify_send(cli->tree, &notify);
1197
1198         status = smb_raw_exit(cli->session);
1199         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1200                                         "smb_raw_exit");
1201
1202         status = smb_raw_changenotify_recv(req, tctx, &notify);
1203         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1204                                         "smb_raw_changenotify_recv");
1205         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1206                                       0, ret, done, "no changes expected");
1207
1208 done:
1209         torture_close_connection(cli);
1210         smbcli_deltree(cli1->tree, BASEDIR_CN1_EX);
1211         return ret;
1212 }
1213
1214 /*
1215   basic testing of change notifies followed by a ulogoff
1216 */
1217
1218 #define BASEDIR_CN1_UL BASEDIR "_CN1_UL"
1219
1220 static bool test_notify_ulogoff(struct torture_context *tctx,
1221                                 struct smbcli_state *cli1)
1222 {
1223         bool ret = true;
1224         NTSTATUS status;
1225         union smb_notify notify;
1226         union smb_open io;
1227         int fnum;
1228         struct smbcli_request *req;
1229         struct smbcli_state *cli = NULL;
1230
1231         torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY ULOGOFF\n");
1232
1233         torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_UL),
1234                        "Failed to setup up test directory: " BASEDIR_CN1_UL);
1235
1236         torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1237                        "Failed to open connection.");
1238
1239         /*
1240           get a handle on the directory
1241         */
1242         io.generic.level = RAW_OPEN_NTCREATEX;
1243         io.ntcreatex.in.root_fid.fnum = 0;
1244         io.ntcreatex.in.flags = 0;
1245         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1246         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1247         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1248         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1249         io.ntcreatex.in.alloc_size = 0;
1250         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1251         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1252         io.ntcreatex.in.security_flags = 0;
1253         io.ntcreatex.in.fname = BASEDIR_CN1_UL;
1254
1255         status = smb_raw_open(cli->tree, tctx, &io);
1256         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1257                                         "smb_raw_open");
1258         fnum = io.ntcreatex.out.file.fnum;
1259
1260         /* ask for a change notify,
1261            on file or directory name changes */
1262         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1263         notify.nttrans.in.buffer_size = 1000;
1264         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1265         notify.nttrans.in.file.fnum = fnum;
1266         notify.nttrans.in.recursive = true;
1267
1268         req = smb_raw_changenotify_send(cli->tree, &notify);
1269
1270         status = smb_raw_ulogoff(cli->session);
1271         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1272                                         "smb_raw_ulogoff");
1273
1274         status = smb_raw_changenotify_recv(req, tctx, &notify);
1275         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1276                                         "smb_raw_changenotify_recv");
1277         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1278                                       0, ret, done, "no changes expected");
1279
1280 done:
1281         torture_close_connection(cli);
1282         smbcli_deltree(cli1->tree, BASEDIR_CN1_UL);
1283         return ret;
1284 }
1285
1286 static void tcp_dis_handler(struct smbcli_transport *t, void *p)
1287 {
1288         struct smbcli_state *cli = (struct smbcli_state *)p;
1289         smbcli_transport_dead(cli->transport, NT_STATUS_LOCAL_DISCONNECT);
1290         cli->transport = NULL;
1291         cli->tree = NULL;
1292 }
1293 /*
1294   basic testing of change notifies followed by tcp disconnect
1295 */
1296
1297 #define BASEDIR_CN1_TCPDIS BASEDIR "_CN1_TCPDIS"
1298
1299 static bool test_notify_tcp_dis(struct torture_context *tctx,
1300                                 struct smbcli_state *cli1)
1301 {
1302         bool ret = true;
1303         NTSTATUS status;
1304         union smb_notify notify;
1305         union smb_open io;
1306         int fnum;
1307         struct smbcli_request *req;
1308         struct smbcli_state *cli = NULL;
1309
1310         torture_comment(tctx, "TESTING CHANGE NOTIFY FOLLOWED BY TCP DISCONNECT\n");
1311
1312         torture_assert(tctx, torture_setup_dir(cli1, BASEDIR_CN1_TCPDIS),
1313                        "Failed to setup up test directory: "
1314                         BASEDIR_CN1_TCPDIS);
1315
1316         torture_assert(tctx, torture_open_connection(&cli, tctx, 0),
1317                        "Failed to open connection.");
1318
1319         /*
1320           get a handle on the directory
1321         */
1322         io.generic.level = RAW_OPEN_NTCREATEX;
1323         io.ntcreatex.in.root_fid.fnum = 0;
1324         io.ntcreatex.in.flags = 0;
1325         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1326         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1327         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1328         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1329         io.ntcreatex.in.alloc_size = 0;
1330         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1331         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1332         io.ntcreatex.in.security_flags = 0;
1333         io.ntcreatex.in.fname = BASEDIR_CN1_TCPDIS;
1334
1335         status = smb_raw_open(cli->tree, tctx, &io);
1336         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1337                                         "smb_raw_open");
1338         fnum = io.ntcreatex.out.file.fnum;
1339
1340         /* ask for a change notify,
1341            on file or directory name changes */
1342         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1343         notify.nttrans.in.buffer_size = 1000;
1344         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1345         notify.nttrans.in.file.fnum = fnum;
1346         notify.nttrans.in.recursive = true;
1347
1348         req = smb_raw_changenotify_send(cli->tree, &notify);
1349
1350         smbcli_transport_idle_handler(cli->transport, tcp_dis_handler, 250, cli);
1351
1352         status = smb_raw_changenotify_recv(req, tctx, &notify);
1353         torture_assert_ntstatus_equal_goto(tctx, status,
1354                                            NT_STATUS_LOCAL_DISCONNECT,
1355                                            ret, done,
1356                                            "smb_raw_changenotify_recv");
1357
1358 done:
1359         torture_close_connection(cli);
1360         smbcli_deltree(cli1->tree, BASEDIR_CN1_TCPDIS);
1361         return ret;
1362 }
1363
1364 /* 
1365    test setting up two change notify requests on one handle
1366 */
1367
1368 #define BASEDIR_CN1_DBL BASEDIR "_CN1_DBL"
1369
1370 static bool test_notify_double(struct torture_context *tctx,
1371                                struct smbcli_state *cli)
1372 {
1373         bool ret = true;
1374         NTSTATUS status;
1375         union smb_notify notify;
1376         union smb_open io;
1377         int fnum;
1378         struct smbcli_request *req1, *req2;
1379
1380         torture_comment(tctx, "TESTING CHANGE NOTIFY TWICE ON ONE DIRECTORY\n");
1381
1382         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_DBL),
1383                        "Failed to setup up test directory: " BASEDIR_CN1_DBL);
1384
1385         /*
1386           get a handle on the directory
1387         */
1388         io.generic.level = RAW_OPEN_NTCREATEX;
1389         io.ntcreatex.in.root_fid.fnum = 0;
1390         io.ntcreatex.in.flags = 0;
1391         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1392         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1393         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1394         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1395         io.ntcreatex.in.alloc_size = 0;
1396         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1397         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1398         io.ntcreatex.in.security_flags = 0;
1399         io.ntcreatex.in.fname = BASEDIR_CN1_DBL;
1400
1401         status = smb_raw_open(cli->tree, tctx, &io);
1402         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1403                                         "smb_raw_open");
1404         fnum = io.ntcreatex.out.file.fnum;
1405
1406         /* ask for a change notify,
1407            on file or directory name changes */
1408         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1409         notify.nttrans.in.buffer_size = 1000;
1410         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1411         notify.nttrans.in.file.fnum = fnum;
1412         notify.nttrans.in.recursive = true;
1413
1414         req1 = smb_raw_changenotify_send(cli->tree, &notify);
1415         req2 = smb_raw_changenotify_send(cli->tree, &notify);
1416
1417         smbcli_mkdir(cli->tree, BASEDIR_CN1_DBL "\\subdir-name");
1418
1419         status = smb_raw_changenotify_recv(req1, tctx, &notify);
1420         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1421                                         "smb_raw_changenotify_recv");
1422         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1423                                       1, ret, done, "wrong number of changes");
1424         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1425                    STR_UNICODE);
1426
1427         smbcli_mkdir(cli->tree, BASEDIR_CN1_DBL "\\subdir-name2");
1428
1429         status = smb_raw_changenotify_recv(req2, tctx, &notify);
1430         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1431                                         "smb_raw_changenotify_recv");
1432         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1433                                       1, ret, done, "wrong number of changes");
1434         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name2",
1435                    STR_UNICODE);
1436
1437 done:
1438         smb_raw_exit(cli->session);
1439         smbcli_deltree(cli->tree, BASEDIR_CN1_DBL);
1440         return ret;
1441 }
1442
1443
1444 /* 
1445    test multiple change notifies at different depths and with/without recursion
1446 */
1447
1448 #define BASEDIR_CN1_TNT BASEDIR "_CN1_TNT"
1449
1450 static bool test_notify_tree(struct torture_context *tctx,
1451                              struct smbcli_state *cli,
1452                              struct smbcli_state *cli2)
1453 {
1454         bool ret = true;
1455         union smb_notify notify;
1456         union smb_open io;
1457         struct smbcli_request *req;
1458         struct timeval tv;
1459         struct {
1460                 const char *path;
1461                 bool recursive;
1462                 uint32_t filter;
1463                 int expected;
1464                 int fnum;
1465                 int counted;
1466         } dirs[] = {
1467                 {BASEDIR_CN1_TNT "\\abc",
1468                         true, FILE_NOTIFY_CHANGE_NAME, 30 },
1469                 {BASEDIR_CN1_TNT "\\zqy",
1470                         true, FILE_NOTIFY_CHANGE_NAME, 8 },
1471                 {BASEDIR_CN1_TNT "\\atsy",
1472                         true, FILE_NOTIFY_CHANGE_NAME, 4 },
1473                 {BASEDIR_CN1_TNT "\\abc\\foo",
1474                         true,  FILE_NOTIFY_CHANGE_NAME, 2 },
1475                 {BASEDIR_CN1_TNT "\\abc\\blah",
1476                         true,  FILE_NOTIFY_CHANGE_NAME, 13 },
1477                 {BASEDIR_CN1_TNT "\\abc\\blah",
1478                         false, FILE_NOTIFY_CHANGE_NAME, 7 },
1479                 {BASEDIR_CN1_TNT "\\abc\\blah\\a",
1480                         true, FILE_NOTIFY_CHANGE_NAME, 2 },
1481                 {BASEDIR_CN1_TNT "\\abc\\blah\\b",
1482                         true, FILE_NOTIFY_CHANGE_NAME, 2 },
1483                 {BASEDIR_CN1_TNT "\\abc\\blah\\c",
1484                         true, FILE_NOTIFY_CHANGE_NAME, 2 },
1485                 {BASEDIR_CN1_TNT "\\abc\\fooblah",
1486                         true, FILE_NOTIFY_CHANGE_NAME, 2 },
1487                 {BASEDIR_CN1_TNT "\\zqy\\xx",
1488                         true, FILE_NOTIFY_CHANGE_NAME, 2 },
1489                 {BASEDIR_CN1_TNT "\\zqy\\yyy",
1490                         true, FILE_NOTIFY_CHANGE_NAME, 2 },
1491                 {BASEDIR_CN1_TNT "\\zqy\\..",
1492                         true, FILE_NOTIFY_CHANGE_NAME, 40 },
1493                 {BASEDIR_CN1_TNT,
1494                         true, FILE_NOTIFY_CHANGE_NAME, 40 },
1495                 {BASEDIR_CN1_TNT,
1496                         false,FILE_NOTIFY_CHANGE_NAME, 6 },
1497                 {BASEDIR_CN1_TNT "\\atsy",
1498                         false,FILE_NOTIFY_CHANGE_NAME, 4 },
1499                 {BASEDIR_CN1_TNT "\\abc",
1500                         true, FILE_NOTIFY_CHANGE_NAME, 24 },
1501                 {BASEDIR_CN1_TNT "\\abc",
1502                         false,FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1503                 {BASEDIR_CN1_TNT "\\abc",
1504                         true, FILE_NOTIFY_CHANGE_FILE_NAME, 0 },
1505                 {BASEDIR_CN1_TNT "\\abc",
1506                         true, FILE_NOTIFY_CHANGE_NAME, 24 },
1507         };
1508         int i;
1509         NTSTATUS status;
1510         bool all_done = false;
1511
1512         torture_comment(tctx, "TESTING CHANGE NOTIFY FOR DIFFERENT DEPTHS\n");
1513
1514         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_TNT),
1515                        "Failed to setup up test directory: " BASEDIR_CN1_TNT);
1516
1517         io.generic.level = RAW_OPEN_NTCREATEX;
1518         io.ntcreatex.in.root_fid.fnum = 0;
1519         io.ntcreatex.in.flags = 0;
1520         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1521         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1522         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1523         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1524         io.ntcreatex.in.alloc_size = 0;
1525         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
1526         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1527         io.ntcreatex.in.security_flags = 0;
1528
1529         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1530         notify.nttrans.in.buffer_size = 20000;
1531
1532         /*
1533           setup the directory tree, and the notify buffer on each directory
1534         */
1535         for (i=0;i<ARRAY_SIZE(dirs);i++) {
1536                 io.ntcreatex.in.fname = dirs[i].path;
1537                 status = smb_raw_open(cli->tree, tctx, &io);
1538                 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1539                                                 "smb_raw_open");
1540                 dirs[i].fnum = io.ntcreatex.out.file.fnum;
1541
1542                 notify.nttrans.in.completion_filter = dirs[i].filter;
1543                 notify.nttrans.in.file.fnum = dirs[i].fnum;
1544                 notify.nttrans.in.recursive = dirs[i].recursive;
1545                 req = smb_raw_changenotify_send(cli->tree, &notify);
1546                 smb_raw_ntcancel(req);
1547                 status = smb_raw_changenotify_recv(req, tctx, &notify);
1548                 torture_assert_ntstatus_equal_goto(tctx, status,
1549                                                    NT_STATUS_CANCELLED,
1550                                                    ret, done,
1551                                                    "smb_raw_changenotify_recv");
1552         }
1553
1554         /* trigger 2 events in each dir */
1555         for (i=0;i<ARRAY_SIZE(dirs);i++) {
1556                 char *path = talloc_asprintf(tctx, "%s\\test.dir", dirs[i].path);
1557                 /*
1558                  * Make notifies a bit more interesting in a cluster
1559                  * by doing the changes against different nodes with
1560                  * --unclist
1561                  */
1562                 smbcli_mkdir(cli->tree, path);
1563                 smbcli_rmdir(cli2->tree, path);
1564                 talloc_free(path);
1565         }
1566
1567         /* give a bit of time for the events to propagate */
1568         tv = timeval_current();
1569
1570         do {
1571                 /* count events that have happened in each dir */
1572                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1573                         notify.nttrans.in.file.fnum = dirs[i].fnum;
1574                         req = smb_raw_changenotify_send(cli->tree, &notify);
1575                         smb_raw_ntcancel(req);
1576                         notify.nttrans.out.num_changes = 0;
1577                         status = smb_raw_changenotify_recv(req, tctx, &notify);
1578                         dirs[i].counted += notify.nttrans.out.num_changes;
1579                 }
1580                 
1581                 all_done = true;
1582
1583                 for (i=0;i<ARRAY_SIZE(dirs);i++) {
1584                         if (dirs[i].counted != dirs[i].expected) {
1585                                 all_done = false;
1586                         }
1587                 }
1588         } while (!all_done && timeval_elapsed(&tv) < 20);
1589
1590         torture_comment(tctx, "took %.4f seconds to propagate all events\n", timeval_elapsed(&tv));
1591
1592         for (i=0;i<ARRAY_SIZE(dirs);i++) {
1593                 torture_assert_int_equal_goto(tctx,
1594                         dirs[i].counted, dirs[i].expected, ret, done,
1595                         talloc_asprintf(tctx,
1596                                         "unexpected number of events for '%s'",
1597                                         dirs[i].path));
1598         }
1599
1600         /*
1601           run from the back, closing and deleting
1602         */
1603         for (i=ARRAY_SIZE(dirs)-1;i>=0;i--) {
1604                 smbcli_close(cli->tree, dirs[i].fnum);
1605                 smbcli_rmdir(cli->tree, dirs[i].path);
1606         }
1607
1608 done:
1609         smb_raw_exit(cli->session);
1610         smbcli_deltree(cli->tree, BASEDIR_CN1_TNT);
1611         return ret;
1612 }
1613
1614 /*
1615    Test response when cached server events exceed single NT NOTFIY response
1616    packet size.
1617 */
1618
1619 #define BASEDIR_CN1_NO BASEDIR "_CN1_NO"
1620
1621 static bool test_notify_overflow(struct torture_context *tctx,
1622                                  struct smbcli_state *cli)
1623 {
1624         bool ret = true;
1625         NTSTATUS status;
1626         union smb_notify notify;
1627         union smb_open io;
1628         int fnum;
1629         int count = 100;
1630         struct smbcli_request *req1;
1631         int i;
1632
1633         torture_comment(tctx, "TESTING CHANGE NOTIFY EVENT OVERFLOW\n");
1634
1635         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NO),
1636                        "Failed to setup up test directory: " BASEDIR_CN1_NO);
1637
1638         /* get a handle on the directory */
1639         io.generic.level = RAW_OPEN_NTCREATEX;
1640         io.ntcreatex.in.root_fid.fnum = 0;
1641         io.ntcreatex.in.flags = 0;
1642         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1643         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1644         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1645         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1646             NTCREATEX_SHARE_ACCESS_WRITE;
1647         io.ntcreatex.in.alloc_size = 0;
1648         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1649         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1650         io.ntcreatex.in.security_flags = 0;
1651         io.ntcreatex.in.fname = BASEDIR_CN1_NO;
1652
1653         status = smb_raw_open(cli->tree, tctx, &io);
1654         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1655                                         "smb_raw_open");
1656         fnum = io.ntcreatex.out.file.fnum;
1657
1658         /* ask for a change notify, on name changes. */
1659         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1660         notify.nttrans.in.buffer_size = 1000;
1661         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1662         notify.nttrans.in.file.fnum = fnum;
1663
1664         notify.nttrans.in.recursive = true;
1665         req1 = smb_raw_changenotify_send(cli->tree, &notify);
1666
1667         /* cancel initial requests so the buffer is setup */
1668         smb_raw_ntcancel(req1);
1669         status = smb_raw_changenotify_recv(req1, tctx, &notify);
1670         torture_assert_ntstatus_equal_goto(tctx, status,
1671                                            NT_STATUS_CANCELLED,
1672                                            ret, done,
1673                                            "smb_raw_changenotify_recv");
1674
1675         /* open a lot of files, filling up the server side notify buffer */
1676         torture_comment(tctx, "Testing overflowed buffer notify on create of %d files\n",
1677                count);
1678         for (i=0;i<count;i++) {
1679                 char *fname = talloc_asprintf(cli,
1680                                 BASEDIR_CN1_NO "\\test%d.txt", i);
1681                 int fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR,
1682                                         DENY_NONE);
1683                 torture_assert_int_not_equal_goto(tctx, fnum2, -1, ret, done,
1684                         talloc_asprintf(tctx, "Failed to create %s - %s",
1685                                         fname, smbcli_errstr(cli->tree)));
1686                 talloc_free(fname);
1687                 smbcli_close(cli->tree, fnum2);
1688         }
1689
1690         /* expect that 0 events will be returned with NT_STATUS_OK */
1691         req1 = smb_raw_changenotify_send(cli->tree, &notify);
1692         status = smb_raw_changenotify_recv(req1, tctx, &notify);
1693         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1694                                         "smb_raw_changenotify_recv");
1695         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1696                                       0, ret, done, "no changes expected");
1697
1698 done:
1699         smb_raw_exit(cli->session);
1700         smbcli_deltree(cli->tree, BASEDIR_CN1_NO);
1701         return ret;
1702 }
1703
1704 /*
1705    Test if notifications are returned for changes to the base directory.
1706    They shouldn't be.
1707 */
1708
1709 #define BASEDIR_CN1_NBASE BASEDIR "_CN1_NBASE"
1710
1711 static bool test_notify_basedir(struct torture_context *tctx,
1712                                 struct smbcli_state *cli)
1713 {
1714         bool ret = true;
1715         NTSTATUS status;
1716         union smb_notify notify;
1717         union smb_open io;
1718         int fnum;
1719         struct smbcli_request *req1;
1720
1721         torture_comment(tctx, "TESTING CHANGE NOTIFY BASEDIR EVENTS\n");
1722
1723         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NBASE),
1724                        "Failed to setup up test directory: " BASEDIR_CN1_NBASE);
1725
1726         /* get a handle on the directory */
1727         io.generic.level = RAW_OPEN_NTCREATEX;
1728         io.ntcreatex.in.root_fid.fnum = 0;
1729         io.ntcreatex.in.flags = 0;
1730         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1731         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1732         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1733         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
1734             NTCREATEX_SHARE_ACCESS_WRITE;
1735         io.ntcreatex.in.alloc_size = 0;
1736         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1737         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1738         io.ntcreatex.in.security_flags = 0;
1739         io.ntcreatex.in.fname = BASEDIR_CN1_NBASE;
1740
1741         status = smb_raw_open(cli->tree, tctx, &io);
1742         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1743                                         "smb_raw_open");
1744         fnum = io.ntcreatex.out.file.fnum;
1745
1746         /* create a test file that will also be modified */
1747         smbcli_close(cli->tree, smbcli_open(cli->tree,
1748                                 BASEDIR_CN1_NBASE "\\tname1",
1749                                             O_CREAT, 0));
1750
1751         /* ask for a change notify, on attribute changes. */
1752         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1753         notify.nttrans.in.buffer_size = 1000;
1754         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_ATTRIBUTES;
1755         notify.nttrans.in.file.fnum = fnum;
1756         notify.nttrans.in.recursive = true;
1757
1758         req1 = smb_raw_changenotify_send(cli->tree, &notify);
1759
1760         /* set attribute on the base dir */
1761         smbcli_setatr(cli->tree, BASEDIR_CN1_NBASE, FILE_ATTRIBUTE_HIDDEN, 0);
1762
1763         /* set attribute on a file to assure we receive a notification */
1764         smbcli_setatr(cli->tree, BASEDIR_CN1_NBASE "\\tname1",
1765                         FILE_ATTRIBUTE_HIDDEN, 0);
1766         smb_msleep(200);
1767
1768         /* check how many responses were given, expect only 1 for the file */
1769         status = smb_raw_changenotify_recv(req1, tctx, &notify);
1770         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1771                                         "smb_raw_changenotify_recv");
1772         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1773                                       1, ret, done, "wrong number of  changes");
1774         torture_assert_int_equal_goto(tctx,
1775                                       notify.nttrans.out.changes[0].action,
1776                                       NOTIFY_ACTION_MODIFIED, ret, done,
1777                                       "wrong action (exp: MODIFIED)");
1778         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "tname1",
1779                    STR_UNICODE);
1780
1781 done:
1782         smb_raw_exit(cli->session);
1783         smbcli_deltree(cli->tree, BASEDIR_CN1_NBASE);
1784         return ret;
1785 }
1786
1787
1788 /*
1789   create a secondary tree connect - used to test for a bug in Samba3 messaging
1790   with change notify
1791 */
1792
1793 static struct smbcli_tree *secondary_tcon(struct smbcli_state *cli, 
1794                                           struct torture_context *tctx)
1795 {
1796         NTSTATUS status;
1797         const char *share, *host;
1798         struct smbcli_tree *tree;
1799         union smb_tcon tcon;
1800
1801         share = torture_setting_string(tctx, "share", NULL);
1802         host  = torture_setting_string(tctx, "host", NULL);
1803         
1804         torture_comment(tctx, "create a second tree context on the same session\n");
1805         tree = smbcli_tree_init(cli->session, tctx, false);
1806
1807         tcon.generic.level = RAW_TCON_TCONX;
1808         tcon.tconx.in.flags = TCONX_FLAG_EXTENDED_RESPONSE;
1809         tcon.tconx.in.password = data_blob(NULL, 0);
1810         tcon.tconx.in.path = talloc_asprintf(tctx, "\\\\%s\\%s", host, share);
1811         tcon.tconx.in.device = "A:";    
1812         status = smb_raw_tcon(tree, tctx, &tcon);
1813         if (!NT_STATUS_IS_OK(status)) {
1814                 talloc_free(tree);
1815                 torture_comment(tctx, "Failed to create secondary tree\n");
1816                 return NULL;
1817         }
1818
1819         tree->tid = tcon.tconx.out.tid;
1820         torture_comment(tctx, "tid1=%d tid2=%d\n", cli->tree->tid, tree->tid);
1821
1822         return tree;
1823 }
1824
1825
1826 /* 
1827    very simple change notify test
1828 */
1829
1830 #define BASEDIR_CN1_NTCON BASEDIR "_CN1_NTCON"
1831
1832 static bool test_notify_tcon(struct torture_context *tctx,
1833                              struct smbcli_state *cli)
1834 {
1835         bool ret = true;
1836         NTSTATUS status;
1837         union smb_notify notify;
1838         union smb_open io;
1839         int fnum;
1840         struct smbcli_request *req;
1841         extern int torture_numops;
1842         struct smbcli_tree *tree = NULL;
1843                 
1844         torture_comment(tctx, "TESTING SIMPLE CHANGE NOTIFY\n");
1845
1846         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NTCON),
1847                        "Failed to setup up test directory: " BASEDIR_CN1_NTCON);
1848
1849         /*
1850           get a handle on the directory
1851         */
1852         io.generic.level = RAW_OPEN_NTCREATEX;
1853         io.ntcreatex.in.root_fid.fnum = 0;
1854         io.ntcreatex.in.flags = 0;
1855         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
1856         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
1857         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
1858         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
1859         io.ntcreatex.in.alloc_size = 0;
1860         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
1861         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
1862         io.ntcreatex.in.security_flags = 0;
1863         io.ntcreatex.in.fname = BASEDIR_CN1_NTCON;
1864
1865         status = smb_raw_open(cli->tree, tctx, &io);
1866         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1867                                         "smb_raw_open");
1868         fnum = io.ntcreatex.out.file.fnum;
1869
1870         status = smb_raw_open(cli->tree, tctx, &io);
1871         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1872                                         "smb_raw_open");
1873
1874         /* ask for a change notify,
1875            on file or directory name changes */
1876         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
1877         notify.nttrans.in.buffer_size = 1000;
1878         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_NAME;
1879         notify.nttrans.in.file.fnum = fnum;
1880         notify.nttrans.in.recursive = true;
1881
1882         torture_comment(tctx, "Testing notify mkdir\n");
1883         req = smb_raw_changenotify_send(cli->tree, &notify);
1884         smbcli_mkdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
1885
1886         status = smb_raw_changenotify_recv(req, tctx, &notify);
1887         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1888                                         "smb_raw_changenotify_recv");
1889
1890         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1891                                       1, ret, done, "wrong number of changes");
1892         torture_assert_int_equal_goto(tctx,
1893                                       notify.nttrans.out.changes[0].action,
1894                                       NOTIFY_ACTION_ADDED, ret, done,
1895                                       "wrong action (exp: ADDED)");
1896         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1897                    STR_UNICODE);
1898
1899         torture_comment(tctx, "Testing notify rmdir\n");
1900         req = smb_raw_changenotify_send(cli->tree, &notify);
1901         smbcli_rmdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
1902
1903         status = smb_raw_changenotify_recv(req, tctx, &notify);
1904         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1905                                         "smb_raw_changenotify_recv");
1906         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1907                                       1, ret, done, "wrong number of changes");
1908         torture_assert_int_equal_goto(tctx,
1909                                       notify.nttrans.out.changes[0].action,
1910                                       NOTIFY_ACTION_REMOVED, ret, done,
1911                                       "wrong action (exp: REMOVED)");
1912         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1913                    STR_UNICODE);
1914
1915         torture_comment(tctx, "SIMPLE CHANGE NOTIFY OK\n");
1916
1917         torture_comment(tctx, "TESTING WITH SECONDARY TCON\n");
1918         tree = secondary_tcon(cli, tctx);
1919         torture_assert_not_null_goto(tctx, tree, ret, done,
1920                                      "failed to create secondary tcon");
1921
1922         torture_comment(tctx, "Testing notify mkdir\n");
1923         req = smb_raw_changenotify_send(cli->tree, &notify);
1924         smbcli_mkdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
1925
1926         status = smb_raw_changenotify_recv(req, tctx, &notify);
1927         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1928                                         "smb_raw_changenotify_recv");
1929
1930         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1931                                       1, ret, done, "wrong number of changes");
1932         torture_assert_int_equal_goto(tctx,
1933                                       notify.nttrans.out.changes[0].action,
1934                                       NOTIFY_ACTION_ADDED, ret, done,
1935                                       "wrong action (exp: ADDED)");
1936         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1937                    STR_UNICODE);
1938
1939         torture_comment(tctx, "Testing notify rmdir\n");
1940         req = smb_raw_changenotify_send(cli->tree, &notify);
1941         smbcli_rmdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
1942
1943         status = smb_raw_changenotify_recv(req, tctx, &notify);
1944         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1945                                         "smb_raw_changenotify_recv");
1946         torture_assert_int_equal_goto(tctx, notify.nttrans.out.num_changes,
1947                                       1, ret, done, "wrong number of changes");
1948         torture_assert_int_equal_goto(tctx,
1949                                       notify.nttrans.out.changes[0].action,
1950                                       NOTIFY_ACTION_REMOVED, ret, done,
1951                                       "wrong action (exp: REMOVED)");
1952         CHECK_WSTR(tctx, notify.nttrans.out.changes[0].name, "subdir-name",
1953                    STR_UNICODE);
1954
1955         torture_comment(tctx, "CHANGE NOTIFY WITH TCON OK\n");
1956
1957         torture_comment(tctx, "Disconnecting secondary tree\n");
1958         status = smb_tree_disconnect(tree);
1959         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1960                                         "smb_tree_disconnect");
1961         talloc_free(tree);
1962
1963         torture_comment(tctx, "Testing notify mkdir\n");
1964         req = smb_raw_changenotify_send(cli->tree, &notify);
1965         smbcli_mkdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
1966
1967         status = smb_raw_changenotify_recv(req, tctx, &notify);
1968         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
1969                                         "smb_raw_changenotify_recv");
1970
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",
1978                    STR_UNICODE);
1979
1980         torture_comment(tctx, "Testing notify rmdir\n");
1981         req = smb_raw_changenotify_send(cli->tree, &notify);
1982         smbcli_rmdir(cli->tree, BASEDIR_CN1_NTCON "\\subdir-name");
1983
1984         status = smb_raw_changenotify_recv(req, tctx, &notify);
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",
1994                    STR_UNICODE);
1995
1996         torture_comment(tctx, "CHANGE NOTIFY WITH TDIS OK\n");
1997 done:
1998         smb_raw_exit(cli->session);
1999         smbcli_deltree(cli->tree, BASEDIR_CN1_NTCON);
2000         return ret;
2001 }
2002
2003
2004 /*
2005    testing alignment of multiple change notify infos
2006 */
2007
2008 #define BASEDIR_CN1_NALIGN BASEDIR "_CN1_NALIGN"
2009
2010 static bool test_notify_alignment(struct torture_context *tctx,
2011                                   struct smbcli_state *cli)
2012 {
2013         NTSTATUS status;
2014         union smb_notify notify;
2015         union smb_open io;
2016         int i, fnum, fnum2;
2017         struct smbcli_request *req;
2018         const char *fname = BASEDIR_CN1_NALIGN "\\starter";
2019         const char *fnames[] = { "a",
2020                                  "ab",
2021                                  "abc",
2022                                  "abcd" };
2023         int num_names = ARRAY_SIZE(fnames);
2024         char *fpath = NULL;
2025
2026         torture_comment(tctx, "TESTING CHANGE NOTIFY REPLY ALIGNMENT\n");
2027
2028         torture_assert(tctx, torture_setup_dir(cli, BASEDIR_CN1_NALIGN),
2029                 "Failed to setup up test directory: " BASEDIR_CN1_NALIGN);
2030
2031         /* get a handle on the directory */
2032         io.generic.level = RAW_OPEN_NTCREATEX;
2033         io.ntcreatex.in.root_fid.fnum = 0;
2034         io.ntcreatex.in.flags = 0;
2035         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
2036         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
2037         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
2038         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
2039                                        NTCREATEX_SHARE_ACCESS_WRITE;
2040         io.ntcreatex.in.alloc_size = 0;
2041         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
2042         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
2043         io.ntcreatex.in.security_flags = 0;
2044         io.ntcreatex.in.fname = BASEDIR_CN1_NALIGN;
2045
2046         status = smb_raw_open(cli->tree, tctx, &io);
2047         torture_assert_ntstatus_ok(tctx, status, "smb_raw_open");
2048         fnum = io.ntcreatex.out.file.fnum;
2049
2050         /* ask for a change notify, on file creation */
2051         notify.nttrans.level = RAW_NOTIFY_NTTRANS;
2052         notify.nttrans.in.buffer_size = 1000;
2053         notify.nttrans.in.completion_filter = FILE_NOTIFY_CHANGE_FILE_NAME;
2054         notify.nttrans.in.file.fnum = fnum;
2055         notify.nttrans.in.recursive = false;
2056
2057         /* start change tracking */
2058         req = smb_raw_changenotify_send(cli->tree, &notify);
2059
2060         fnum2 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
2061         torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
2062         smbcli_close(cli->tree, fnum2);
2063
2064         status = smb_raw_changenotify_recv(req, tctx, &notify);
2065         torture_assert_ntstatus_ok(tctx, status, "smb_raw_changenotify_recv");
2066
2067         /* create 4 files that will cause CHANGE_NOTIFY_INFO structures
2068          * to be returned in the same packet with all possible 4-byte padding
2069          * permutations.  As per MS-CIFS 2.2.7.4.2 these structures should be
2070          * 4-byte aligned. */
2071
2072         for (i = 0; i < num_names; i++) {
2073                 fpath = talloc_asprintf(tctx, "%s\\%s",
2074                                 BASEDIR_CN1_NALIGN, fnames[i]);
2075                 fnum2 = smbcli_open(cli->tree, fpath,
2076                     O_CREAT|O_RDWR, DENY_NONE);
2077                 torture_assert(tctx, fnum2 != -1, smbcli_errstr(cli->tree));
2078                 smbcli_close(cli->tree, fnum2);
2079                 talloc_free(fpath);
2080         }
2081
2082         /* We send a notify packet, and let smb_raw_changenotify_recv() do
2083          * the alignment checking for us. */
2084         req = smb_raw_changenotify_send(cli->tree, &notify);
2085         status = smb_raw_changenotify_recv(req, tctx, &notify);
2086         torture_assert_ntstatus_ok(tctx, status, "smb_raw_changenotify_recv");
2087
2088         /* Do basic checking for correctness. */
2089         torture_assert(tctx, notify.nttrans.out.num_changes == num_names, "");
2090         for (i = 0; i < num_names; i++) {
2091                 torture_assert(tctx, notify.nttrans.out.changes[i].action ==
2092                     NOTIFY_ACTION_ADDED, "");
2093                 CHECK_WSTR(tctx, notify.nttrans.out.changes[i].name, fnames[i],
2094                     STR_UNICODE);
2095         }
2096
2097         smb_raw_exit(cli->session);
2098         smbcli_deltree(cli->tree, BASEDIR_CN1_NALIGN);
2099         return true;
2100 }
2101
2102 struct torture_suite *torture_raw_notify(TALLOC_CTX *mem_ctx)
2103 {
2104         struct torture_suite *suite = torture_suite_create(mem_ctx, "notify");
2105
2106         torture_suite_add_1smb_test(suite, "tcon", test_notify_tcon);
2107         torture_suite_add_2smb_test(suite, "dir", test_notify_dir);
2108         torture_suite_add_2smb_test(suite, "mask", test_notify_mask);
2109         torture_suite_add_2smb_test(suite, "recursive", test_notify_recursive);
2110         torture_suite_add_1smb_test(suite, "mask_change",
2111                                     test_notify_mask_change);
2112         torture_suite_add_1smb_test(suite, "file", test_notify_file);
2113         torture_suite_add_1smb_test(suite, "tdis", test_notify_tdis);
2114         torture_suite_add_1smb_test(suite, "exit", test_notify_exit);
2115         torture_suite_add_1smb_test(suite, "ulogoff", test_notify_ulogoff);
2116         torture_suite_add_1smb_test(suite, "tcp_dis", test_notify_tcp_dis);
2117         torture_suite_add_1smb_test(suite, "double", test_notify_double);
2118         torture_suite_add_2smb_test(suite, "tree", test_notify_tree);
2119         torture_suite_add_1smb_test(suite, "overflow", test_notify_overflow);
2120         torture_suite_add_1smb_test(suite, "basedir", test_notify_basedir);
2121         torture_suite_add_1smb_test(suite, "alignment", test_notify_alignment);
2122
2123         return suite;
2124 }