r14173: change smb interface structures to always use
[gd/samba-autobuild/.git] / source4 / torture / raw / notify.c
1 /* 
2    Unix SMB/CIFS implementation.
3    basic raw test suite for change notify
4    Copyright (C) Andrew Tridgell 2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "torture/torture.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/libcli.h"
25 #include "system/filesys.h"
26
27 #define BASEDIR "\\test_notify"
28
29 #define CHECK_STATUS(status, correct) do { \
30         if (!NT_STATUS_EQUAL(status, correct)) { \
31                 printf("(%d) Incorrect status %s - should be %s\n", \
32                        __LINE__, nt_errstr(status), nt_errstr(correct)); \
33                 ret = False; \
34                 goto done; \
35         }} while (0)
36
37
38 #define CHECK_VAL(v, correct) do { \
39         if ((v) != (correct)) { \
40                 printf("(%d) wrong value for %s  0x%x should be 0x%x\n", \
41                        __LINE__, #v, (int)v, (int)correct); \
42                 ret = False; \
43                 goto done; \
44         }} while (0)
45
46 #define CHECK_WSTR(field, value, flags) do { \
47         if (!field.s || strcmp(field.s, value) || wire_bad_flags(&field, flags, cli)) { \
48                 printf("(%d) %s [%s] != %s\n",  __LINE__, #field, field.s, value); \
49                         ret = False; \
50                 goto done; \
51         }} while (0)
52
53
54 /* 
55    basic testing of change notify
56 */
57 BOOL torture_raw_notify(void)
58 {
59         struct smbcli_state *cli;
60         BOOL ret = True;
61         TALLOC_CTX *mem_ctx;
62         NTSTATUS status;
63         union smb_notify notify;
64         union smb_open io;
65         int i, count, fnum, fnum2;
66         struct smbcli_request *req, *req2;
67         extern int torture_numops;
68                 
69         if (!torture_open_connection(&cli)) {
70                 return False;
71         }
72
73         mem_ctx = talloc_init("torture_raw_notify");
74
75         if (!torture_setup_dir(cli, BASEDIR)) {
76                 return False;
77         }
78
79         /*
80           get a handle on the directory
81         */
82         io.generic.level = RAW_OPEN_NTCREATEX;
83         io.ntcreatex.in.root_fid = 0;
84         io.ntcreatex.in.flags = 0;
85         io.ntcreatex.in.access_mask = SEC_FILE_ALL;
86         io.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
87         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
88         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
89         io.ntcreatex.in.alloc_size = 0;
90         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
91         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
92         io.ntcreatex.in.security_flags = 0;
93         io.ntcreatex.in.fname = BASEDIR;
94
95         status = smb_raw_open(cli->tree, mem_ctx, &io);
96         CHECK_STATUS(status, NT_STATUS_OK);
97         fnum = io.ntcreatex.file.fnum;
98
99         status = smb_raw_open(cli->tree, mem_ctx, &io);
100         CHECK_STATUS(status, NT_STATUS_OK);
101         fnum2 = io.ntcreatex.file.fnum;
102
103         /* ask for a change notify */
104         notify.notify.in.buffer_size = 1000;
105         notify.notify.in.completion_filter = 0x3;
106         notify.notify.file.fnum = fnum;
107         notify.notify.in.recursive = True;
108
109         printf("testing notify mkdir\n");
110
111         req = smb_raw_changenotify_send(cli->tree, &notify);
112         smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
113
114         status = smb_raw_changenotify_recv(req, mem_ctx, &notify);
115         CHECK_STATUS(status, NT_STATUS_OK);
116
117         CHECK_VAL(notify.notify.out.num_changes, 1);
118         CHECK_VAL(notify.notify.out.changes[0].action, NOTIFY_ACTION_ADDED);
119         CHECK_WSTR(notify.notify.out.changes[0].name, "subdir-name", STR_UNICODE);
120
121         printf("testing notify rmdir\n");
122
123         req = smb_raw_changenotify_send(cli->tree, &notify);
124         smbcli_rmdir(cli->tree, BASEDIR "\\subdir-name");
125
126         status = smb_raw_changenotify_recv(req, mem_ctx, &notify);
127         CHECK_STATUS(status, NT_STATUS_OK);
128         CHECK_VAL(notify.notify.out.num_changes, 1);
129         CHECK_VAL(notify.notify.out.changes[0].action, NOTIFY_ACTION_REMOVED);
130         CHECK_WSTR(notify.notify.out.changes[0].name, "subdir-name", STR_UNICODE);
131
132         printf("testing notify cancel\n");
133
134         req = smb_raw_changenotify_send(cli->tree, &notify);
135         smb_raw_ntcancel(req);
136         smbcli_mkdir(cli->tree, BASEDIR "\\subdir-name");
137         status = smb_raw_changenotify_recv(req, mem_ctx, &notify);
138         CHECK_STATUS(status, NT_STATUS_CANCELLED);
139
140         count = torture_numops;
141         printf("testing buffered notify on create of %d files\n", count);
142         for (i=0;i<count;i++) {
143                 char *fname = talloc_asprintf(cli, BASEDIR "\\test%d.txt", i);
144                 int fnum3 = smbcli_open(cli->tree, fname, O_CREAT|O_RDWR, DENY_NONE);
145                 if (fnum3 == -1) {
146                         printf("Failed to create %s - %s\n", 
147                                fname, smbcli_errstr(cli->tree));
148                         ret = False;
149                         goto done;
150                 }
151                 talloc_free(fname);
152                 smbcli_close(cli->tree, fnum3);
153         }
154
155         /* setup a new notify on a different directory handle. This
156            new notify won't see the events above. */
157         notify.notify.file.fnum = fnum2;
158         req2 = smb_raw_changenotify_send(cli->tree, &notify);
159
160         /* whereas this notify will see the above buffered events as
161            well */
162         notify.notify.file.fnum = fnum;
163         req = smb_raw_changenotify_send(cli->tree, &notify);
164
165         status = smbcli_unlink(cli->tree, BASEDIR "\\test0.txt");
166         CHECK_STATUS(status, NT_STATUS_OK);
167
168         /* receive the reply from the 2nd notify */
169         status = smb_raw_changenotify_recv(req, mem_ctx, &notify);
170         CHECK_STATUS(status, NT_STATUS_OK);
171
172         CHECK_VAL(notify.notify.out.num_changes, count+1);
173         for (i=0;i<notify.notify.out.num_changes;i++) {
174                 CHECK_VAL(notify.notify.out.changes[i].action, NOTIFY_ACTION_ADDED);
175         }
176         CHECK_WSTR(notify.notify.out.changes[0].name, "subdir-name", STR_UNICODE);
177
178         /* and now from the 1st notify */
179         status = smb_raw_changenotify_recv(req2, mem_ctx, &notify);
180         CHECK_STATUS(status, NT_STATUS_OK);
181         CHECK_VAL(notify.notify.out.num_changes, 1);
182
183         printf("testing notify on wildcard unlink for %d files\n", count);
184
185         req = smb_raw_changenotify_send(cli->tree, &notify);
186         status = smbcli_unlink(cli->tree, BASEDIR "\\test*.txt");
187         CHECK_STATUS(status, NT_STATUS_OK);
188
189         status = smb_raw_changenotify_recv(req, mem_ctx, &notify);
190         CHECK_STATUS(status, NT_STATUS_OK);
191
192         CHECK_VAL(notify.notify.out.num_changes, 1);
193         CHECK_VAL(notify.notify.out.changes[0].action, NOTIFY_ACTION_REMOVED);
194         CHECK_WSTR(notify.notify.out.changes[0].name, "test0.txt", STR_UNICODE);
195
196         /* and we now see the rest of the unlink calls */
197         req = smb_raw_changenotify_send(cli->tree, &notify);
198         status = smb_raw_changenotify_recv(req, mem_ctx, &notify);
199         CHECK_STATUS(status, NT_STATUS_OK);
200         CHECK_VAL(notify.notify.out.num_changes, count-1);
201         for (i=0;i<notify.notify.out.num_changes;i++) {
202                 CHECK_VAL(notify.notify.out.changes[i].action, NOTIFY_ACTION_REMOVED);
203         }
204
205         notify.notify.file.fnum = fnum2;
206         req = smb_raw_changenotify_send(cli->tree, &notify);
207         status = smb_raw_changenotify_recv(req, mem_ctx, &notify);
208         CHECK_STATUS(status, NT_STATUS_OK);
209         CHECK_VAL(notify.notify.out.num_changes, count-1);
210         for (i=0;i<notify.notify.out.num_changes;i++) {
211                 CHECK_VAL(notify.notify.out.changes[i].action, NOTIFY_ACTION_REMOVED);
212         }
213
214 done:
215         smb_raw_exit(cli->session);
216         smbcli_deltree(cli->tree, BASEDIR);
217         torture_close_connection(cli);
218         talloc_free(mem_ctx);
219         return ret;
220 }