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