Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Make sure that for offline files pread and pwrite trigger a notify
4 : Copyright (C) Volker Lendecke 2011
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/proto.h"
22 : #include "libcli/security/security.h"
23 : #include "lib/util/tevent_ntstatus.h"
24 : #include "libsmb/libsmb.h"
25 :
26 : extern char *test_filename;
27 :
28 : struct notify_online_state {
29 : struct tevent_context *ev;
30 : struct cli_state *cli;
31 : uint16_t dnum;
32 : const char *fname;
33 : uint16_t fnum;
34 : bool got_notify;
35 : };
36 :
37 : static void notify_online_opened_dir(struct tevent_req *subreq);
38 : static void notify_online_notify_callback(struct tevent_req *subreq);
39 : static void notify_online_opened_file(struct tevent_req *subreq);
40 : static void notify_online_sent_read(struct tevent_req *subreq);
41 : static void notify_online_sent_closefile(struct tevent_req *subreq);
42 : static void notify_online_waited(struct tevent_req *subreq);
43 : static void notify_online_sent_closedir(struct tevent_req *subreq);
44 :
45 0 : static struct tevent_req *notify_online_send(
46 : TALLOC_CTX *mem_ctx, struct tevent_context *ev,
47 : struct cli_state *cli, const char *dname, const char *fname)
48 : {
49 0 : struct tevent_req *req, *subreq;
50 0 : struct notify_online_state *state;
51 :
52 0 : req = tevent_req_create(mem_ctx, &state, struct notify_online_state);
53 0 : if (req == NULL) {
54 0 : return NULL;
55 : }
56 0 : state->ev = ev;
57 0 : state->cli = cli;
58 0 : state->fname = fname;
59 :
60 0 : subreq = cli_ntcreate_send(
61 : state, ev, cli, dname, EXTENDED_RESPONSE_REQUIRED,
62 : SEC_FILE_READ_DATA, 0,
63 : FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
64 : FILE_OPEN, 0, SMB2_IMPERSONATION_IMPERSONATION, 0);
65 0 : if (tevent_req_nomem(subreq, req)) {
66 0 : return tevent_req_post(req, ev);
67 : }
68 0 : tevent_req_set_callback(subreq, notify_online_opened_dir, req);
69 0 : return req;
70 : }
71 :
72 0 : static void notify_online_opened_dir(struct tevent_req *subreq)
73 : {
74 0 : struct tevent_req *req = tevent_req_callback_data(
75 : subreq, struct tevent_req);
76 0 : struct notify_online_state *state = tevent_req_data(
77 : req, struct notify_online_state);
78 0 : NTSTATUS status;
79 :
80 0 : status = cli_ntcreate_recv(subreq, &state->dnum, NULL);
81 0 : TALLOC_FREE(subreq);
82 0 : if (tevent_req_nterror(req, status)) {
83 0 : return;
84 : }
85 0 : subreq = cli_notify_send(state, state->ev, state->cli, state->dnum,
86 : 128, FILE_NOTIFY_CHANGE_ATTRIBUTES, false);
87 0 : if (tevent_req_nomem(subreq, req)) {
88 0 : return;
89 : }
90 0 : tevent_req_set_callback(subreq, notify_online_notify_callback, req);
91 :
92 0 : subreq = cli_ntcreate_send(
93 : state, state->ev, state->cli, state->fname, 0,
94 : GENERIC_READ_ACCESS, FILE_ATTRIBUTE_NORMAL,
95 : FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
96 : FILE_OPEN, FILE_NON_DIRECTORY_FILE,
97 : SMB2_IMPERSONATION_IMPERSONATION, 0);
98 0 : if (tevent_req_nomem(subreq, req)) {
99 0 : return;
100 : }
101 0 : tevent_req_set_callback(subreq, notify_online_opened_file, req);
102 : }
103 :
104 0 : static void notify_online_notify_callback(struct tevent_req *subreq)
105 : {
106 0 : struct tevent_req *req = tevent_req_callback_data(
107 : subreq, struct tevent_req);
108 0 : struct notify_online_state *state = tevent_req_data(
109 : req, struct notify_online_state);
110 0 : NTSTATUS status;
111 0 : uint32_t num_changes;
112 0 : struct notify_change *changes;
113 :
114 0 : status = cli_notify_recv(subreq, state, &num_changes, &changes);
115 0 : TALLOC_FREE(subreq);
116 0 : if (tevent_req_nterror(req, status)) {
117 0 : return;
118 : }
119 0 : if ((num_changes == 1)
120 0 : && (changes[0].action == NOTIFY_ACTION_MODIFIED)
121 0 : && (strcmp(changes[0].name, state->fname) == 0)) {
122 0 : state->got_notify = true;
123 : }
124 0 : tevent_req_done(req);
125 : }
126 :
127 0 : static void notify_online_opened_file(struct tevent_req *subreq)
128 : {
129 0 : struct tevent_req *req = tevent_req_callback_data(
130 : subreq, struct tevent_req);
131 0 : struct notify_online_state *state = tevent_req_data(
132 : req, struct notify_online_state);
133 0 : NTSTATUS status;
134 :
135 0 : status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
136 0 : TALLOC_FREE(subreq);
137 0 : if (tevent_req_nterror(req, status)) {
138 0 : return;
139 : }
140 0 : subreq = cli_read_andx_send(
141 0 : state, state->ev, state->cli, state->fnum, 0, 1);
142 0 : if (tevent_req_nomem(subreq, req)) {
143 0 : return;
144 : }
145 0 : tevent_req_set_callback(subreq, notify_online_sent_read, req);
146 : }
147 :
148 0 : static void notify_online_sent_read(struct tevent_req *subreq)
149 : {
150 0 : struct tevent_req *req = tevent_req_callback_data(
151 : subreq, struct tevent_req);
152 0 : struct notify_online_state *state = tevent_req_data(
153 : req, struct notify_online_state);
154 0 : NTSTATUS status;
155 0 : ssize_t received;
156 0 : uint8_t *buf;
157 :
158 0 : status = cli_read_andx_recv(subreq, &received, &buf);
159 0 : TALLOC_FREE(subreq);
160 0 : if (tevent_req_nterror(req, status)) {
161 0 : return;
162 : }
163 0 : subreq = cli_close_send(state, state->ev, state->cli, state->fnum, 0);
164 0 : if (tevent_req_nomem(subreq, req)) {
165 0 : return;
166 : }
167 0 : tevent_req_set_callback(subreq, notify_online_sent_closefile, req);
168 : }
169 :
170 0 : static void notify_online_sent_closefile(struct tevent_req *subreq)
171 : {
172 0 : struct tevent_req *req = tevent_req_callback_data(
173 : subreq, struct tevent_req);
174 0 : struct notify_online_state *state = tevent_req_data(
175 : req, struct notify_online_state);
176 0 : NTSTATUS status;
177 :
178 0 : status = cli_close_recv(subreq);
179 0 : TALLOC_FREE(subreq);
180 0 : if (tevent_req_nterror(req, status)) {
181 0 : return;
182 : }
183 0 : subreq = tevent_wakeup_send(
184 : state, state->ev, timeval_current_ofs(10, 0));
185 0 : if (tevent_req_nomem(subreq, req)) {
186 0 : return;
187 : }
188 0 : tevent_req_set_callback(subreq, notify_online_waited, req);
189 : }
190 :
191 0 : static void notify_online_waited(struct tevent_req *subreq)
192 : {
193 0 : struct tevent_req *req = tevent_req_callback_data(
194 : subreq, struct tevent_req);
195 0 : struct notify_online_state *state = tevent_req_data(
196 : req, struct notify_online_state);
197 :
198 0 : tevent_wakeup_recv(subreq);
199 0 : TALLOC_FREE(subreq);
200 0 : subreq = cli_close_send(state, state->ev, state->cli, state->dnum, 0);
201 0 : if (tevent_req_nomem(subreq, req)) {
202 0 : return;
203 : }
204 0 : tevent_req_set_callback(subreq, notify_online_sent_closedir, req);
205 : }
206 :
207 0 : static void notify_online_sent_closedir(struct tevent_req *subreq)
208 : {
209 0 : struct tevent_req *req = tevent_req_callback_data(
210 : subreq, struct tevent_req);
211 0 : NTSTATUS status;
212 :
213 0 : status = cli_close_recv(subreq);
214 0 : TALLOC_FREE(subreq);
215 0 : if (tevent_req_nterror(req, status)) {
216 0 : return;
217 : }
218 : }
219 :
220 0 : static NTSTATUS notify_online_recv(struct tevent_req *req, bool *got_notify)
221 : {
222 0 : struct notify_online_state *state = tevent_req_data(
223 : req, struct notify_online_state);
224 0 : NTSTATUS status;
225 :
226 0 : if (tevent_req_is_nterror(req, &status)) {
227 0 : return status;
228 : }
229 0 : *got_notify = state->got_notify;
230 0 : return NT_STATUS_OK;
231 : }
232 :
233 0 : static NTSTATUS notify_online(struct cli_state *cli,
234 : const char *dirname, const char *filename,
235 : bool *got_notify)
236 : {
237 0 : TALLOC_CTX *frame = talloc_stackframe();
238 0 : struct tevent_context *ev;
239 0 : struct tevent_req *req;
240 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
241 :
242 0 : ev = samba_tevent_context_init(frame);
243 0 : if (ev == NULL) {
244 0 : goto fail;
245 : }
246 0 : req = notify_online_send(frame, ev, cli, dirname, filename);
247 0 : if (req == NULL) {
248 0 : goto fail;
249 : }
250 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
251 0 : goto fail;
252 : }
253 0 : status = notify_online_recv(req, got_notify);
254 0 : fail:
255 0 : TALLOC_FREE(frame);
256 0 : return status;
257 : }
258 :
259 0 : bool run_notify_online(int dummy)
260 : {
261 0 : struct cli_state *cli;
262 0 : NTSTATUS status;
263 0 : char *p;
264 0 : const char *dir;
265 0 : const char *file;
266 0 : bool got_notify = false;
267 :
268 0 : printf("Starting NOTIFY_ONLINE\n");
269 :
270 0 : if (test_filename == NULL) {
271 0 : fprintf(stderr, "<-f filename> missing\n");
272 0 : return false;
273 : }
274 :
275 0 : if (!torture_open_connection(&cli, 0)) {
276 0 : return false;
277 : }
278 :
279 0 : p = strrchr(test_filename, '/');
280 0 : if (p != NULL) {
281 0 : dir = SMB_STRNDUP(test_filename, p-test_filename);
282 0 : file = SMB_STRDUP(p+1);
283 : } else {
284 0 : dir = "";
285 0 : file = test_filename;
286 : }
287 :
288 0 : status = notify_online(cli, dir, file, &got_notify);
289 0 : d_printf("notify_online returned %s (%d)\n", nt_errstr(status),
290 : (int)got_notify);
291 0 : torture_close_connection(cli);
292 0 : return NT_STATUS_IS_OK(status) && got_notify;
293 : }
|