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