~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/torture/raw/notify.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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