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