2 Unix SMB/CIFS implementation.
3 Make sure that for offline files pread and pwrite trigger a notify
4 Copyright (C) Volker Lendecke 2011
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.
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.
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/>.
21 #include "torture/proto.h"
22 #include "libcli/security/security.h"
23 #include "lib/util/tevent_ntstatus.h"
25 extern char *test_filename
;
27 struct notify_online_state
{
28 struct tevent_context
*ev
;
29 struct cli_state
*cli
;
36 static void notify_online_opened_dir(struct tevent_req
*subreq
);
37 static void notify_online_notify_callback(struct tevent_req
*subreq
);
38 static void notify_online_opened_file(struct tevent_req
*subreq
);
39 static void notify_online_sent_read(struct tevent_req
*subreq
);
40 static void notify_online_sent_closefile(struct tevent_req
*subreq
);
41 static void notify_online_waited(struct tevent_req
*subreq
);
42 static void notify_online_sent_closedir(struct tevent_req
*subreq
);
44 static struct tevent_req
*notify_online_send(
45 TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
46 struct cli_state
*cli
, const char *dname
, const char *fname
)
48 struct tevent_req
*req
, *subreq
;
49 struct notify_online_state
*state
;
51 req
= tevent_req_create(mem_ctx
, &state
, struct notify_online_state
);
59 subreq
= cli_ntcreate_send(
60 state
, ev
, cli
, dname
, EXTENDED_RESPONSE_REQUIRED
,
61 SEC_FILE_READ_DATA
, 0,
62 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
64 if (tevent_req_nomem(subreq
, req
)) {
65 return tevent_req_post(req
, ev
);
67 tevent_req_set_callback(subreq
, notify_online_opened_dir
, req
);
71 static void notify_online_opened_dir(struct tevent_req
*subreq
)
73 struct tevent_req
*req
= tevent_req_callback_data(
74 subreq
, struct tevent_req
);
75 struct notify_online_state
*state
= tevent_req_data(
76 req
, struct notify_online_state
);
79 status
= cli_ntcreate_recv(subreq
, &state
->dnum
);
81 if (tevent_req_nterror(req
, status
)) {
84 subreq
= cli_notify_send(state
, state
->ev
, state
->cli
, state
->dnum
,
85 128, FILE_NOTIFY_CHANGE_ATTRIBUTES
, false);
86 if (tevent_req_nomem(subreq
, req
)) {
89 tevent_req_set_callback(subreq
, notify_online_notify_callback
, req
);
91 subreq
= cli_ntcreate_send(
92 state
, state
->ev
, state
->cli
, state
->fname
, 0,
93 GENERIC_READ_ACCESS
, FILE_ATTRIBUTE_NORMAL
,
94 FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
,
95 FILE_OPEN
, FILE_NON_DIRECTORY_FILE
, 0);
96 if (tevent_req_nomem(subreq
, req
)) {
99 tevent_req_set_callback(subreq
, notify_online_opened_file
, req
);
102 static void notify_online_notify_callback(struct tevent_req
*subreq
)
104 struct tevent_req
*req
= tevent_req_callback_data(
105 subreq
, struct tevent_req
);
106 struct notify_online_state
*state
= tevent_req_data(
107 req
, struct notify_online_state
);
109 uint32_t num_changes
;
110 struct notify_change
*changes
;
112 status
= cli_notify_recv(subreq
, state
, &num_changes
, &changes
);
114 if (tevent_req_nterror(req
, status
)) {
117 if ((num_changes
== 1)
118 && (changes
[0].action
== NOTIFY_ACTION_MODIFIED
)
119 && (strcmp(changes
[0].name
, state
->fname
) == 0)) {
120 state
->got_notify
= true;
122 tevent_req_done(req
);
125 static void notify_online_opened_file(struct tevent_req
*subreq
)
127 struct tevent_req
*req
= tevent_req_callback_data(
128 subreq
, struct tevent_req
);
129 struct notify_online_state
*state
= tevent_req_data(
130 req
, struct notify_online_state
);
133 status
= cli_ntcreate_recv(subreq
, &state
->fnum
);
135 if (tevent_req_nterror(req
, status
)) {
138 subreq
= cli_read_andx_send(
139 state
, state
->ev
, state
->cli
, state
->fnum
, 0, 1);
140 if (tevent_req_nomem(subreq
, req
)) {
143 tevent_req_set_callback(subreq
, notify_online_sent_read
, req
);
146 static void notify_online_sent_read(struct tevent_req
*subreq
)
148 struct tevent_req
*req
= tevent_req_callback_data(
149 subreq
, struct tevent_req
);
150 struct notify_online_state
*state
= tevent_req_data(
151 req
, struct notify_online_state
);
156 status
= cli_read_andx_recv(subreq
, &received
, &buf
);
158 if (tevent_req_nterror(req
, status
)) {
161 subreq
= cli_close_send(
162 state
, state
->ev
, state
->cli
, state
->fnum
);
163 if (tevent_req_nomem(subreq
, req
)) {
166 tevent_req_set_callback(subreq
, notify_online_sent_closefile
, req
);
169 static void notify_online_sent_closefile(struct tevent_req
*subreq
)
171 struct tevent_req
*req
= tevent_req_callback_data(
172 subreq
, struct tevent_req
);
173 struct notify_online_state
*state
= tevent_req_data(
174 req
, struct notify_online_state
);
177 status
= cli_close_recv(subreq
);
179 if (tevent_req_nterror(req
, status
)) {
182 subreq
= tevent_wakeup_send(
183 state
, state
->ev
, timeval_current_ofs(10, 0));
184 if (tevent_req_nomem(subreq
, req
)) {
187 tevent_req_set_callback(subreq
, notify_online_waited
, req
);
190 static void notify_online_waited(struct tevent_req
*subreq
)
192 struct tevent_req
*req
= tevent_req_callback_data(
193 subreq
, struct tevent_req
);
194 struct notify_online_state
*state
= tevent_req_data(
195 req
, struct notify_online_state
);
197 tevent_wakeup_recv(subreq
);
199 subreq
= cli_close_send(
200 state
, state
->ev
, state
->cli
, state
->dnum
);
201 if (tevent_req_nomem(subreq
, req
)) {
204 tevent_req_set_callback(subreq
, notify_online_sent_closedir
, req
);
207 static void notify_online_sent_closedir(struct tevent_req
*subreq
)
209 struct tevent_req
*req
= tevent_req_callback_data(
210 subreq
, struct tevent_req
);
213 status
= cli_close_recv(subreq
);
215 if (tevent_req_nterror(req
, status
)) {
220 static NTSTATUS
notify_online_recv(struct tevent_req
*req
, bool *got_notify
)
222 struct notify_online_state
*state
= tevent_req_data(
223 req
, struct notify_online_state
);
226 if (tevent_req_is_nterror(req
, &status
)) {
229 *got_notify
= state
->got_notify
;
233 static NTSTATUS
notify_online(struct cli_state
*cli
,
234 const char *dirname
, const char *filename
,
237 TALLOC_CTX
*frame
= talloc_stackframe();
238 struct event_context
*ev
;
239 struct tevent_req
*req
;
240 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
242 ev
= event_context_init(frame
);
246 req
= notify_online_send(frame
, ev
, cli
, dirname
, filename
);
250 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
253 status
= notify_online_recv(req
, got_notify
);
259 bool run_notify_online(int dummy
)
261 struct cli_state
*cli
;
266 bool got_notify
= false;
268 printf("Starting NOTIFY_ONLINE\n");
270 if (test_filename
== NULL
) {
271 fprintf(stderr
, "<-f filename> missing\n");
275 if (!torture_open_connection(&cli
, 0)) {
279 p
= strrchr(test_filename
, '/');
281 dir
= SMB_STRNDUP(test_filename
, p
-test_filename
);
282 file
= SMB_STRDUP(p
+1);
285 file
= test_filename
;
288 status
= notify_online(cli
, dir
, file
, &got_notify
);
289 d_printf("notify_online returned %s (%d)\n", nt_errstr(status
),
291 torture_close_connection(cli
);
292 return NT_STATUS_IS_OK(status
) && got_notify
;