/src/samba/source4/libcli/smb_composite/loadfile.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | |
4 | | Copyright (C) Andrew Tridgell 2005 |
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 | | a composite API for loading a whole file into memory |
21 | | */ |
22 | | |
23 | | #include "includes.h" |
24 | | #include "libcli/raw/libcliraw.h" |
25 | | #include "libcli/composite/composite.h" |
26 | | #include "libcli/smb_composite/smb_composite.h" |
27 | | |
28 | | /* the stages of this call */ |
29 | | enum loadfile_stage {LOADFILE_OPEN, LOADFILE_READ, LOADFILE_CLOSE}; |
30 | | |
31 | | |
32 | | static void loadfile_handler(struct smbcli_request *req); |
33 | | |
34 | | struct loadfile_state { |
35 | | enum loadfile_stage stage; |
36 | | struct smb_composite_loadfile *io; |
37 | | struct smbcli_request *req; |
38 | | union smb_open *io_open; |
39 | | union smb_read *io_read; |
40 | | }; |
41 | | |
42 | | /* |
43 | | setup for the close |
44 | | */ |
45 | | static NTSTATUS setup_close(struct composite_context *c, |
46 | | struct smbcli_tree *tree, uint16_t fnum) |
47 | 0 | { |
48 | 0 | struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state); |
49 | 0 | union smb_close *io_close; |
50 | | |
51 | | /* nothing to read, setup the close */ |
52 | 0 | io_close = talloc(c, union smb_close); |
53 | 0 | NT_STATUS_HAVE_NO_MEMORY(io_close); |
54 | | |
55 | 0 | io_close->close.level = RAW_CLOSE_CLOSE; |
56 | 0 | io_close->close.in.file.fnum = fnum; |
57 | 0 | io_close->close.in.write_time = 0; |
58 | |
|
59 | 0 | state->req = smb_raw_close_send(tree, io_close); |
60 | 0 | NT_STATUS_HAVE_NO_MEMORY(state->req); |
61 | | |
62 | | /* call the handler again when the close is done */ |
63 | 0 | state->req->async.fn = loadfile_handler; |
64 | 0 | state->req->async.private_data = c; |
65 | 0 | state->stage = LOADFILE_CLOSE; |
66 | |
|
67 | 0 | return NT_STATUS_OK; |
68 | 0 | } |
69 | | |
70 | | /* |
71 | | called when the open is done - pull the results and setup for the |
72 | | first readx, or close if the file is zero size |
73 | | */ |
74 | | static NTSTATUS loadfile_open(struct composite_context *c, |
75 | | struct smb_composite_loadfile *io) |
76 | 0 | { |
77 | 0 | struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state); |
78 | 0 | struct smbcli_tree *tree = state->req->tree; |
79 | 0 | NTSTATUS status; |
80 | |
|
81 | 0 | status = smb_raw_open_recv(state->req, c, state->io_open); |
82 | 0 | NT_STATUS_NOT_OK_RETURN(status); |
83 | | |
84 | | /* don't allow stupidly large loads */ |
85 | 0 | if (state->io_open->ntcreatex.out.size > 100*1000*1000) { |
86 | 0 | return NT_STATUS_INSUFFICIENT_RESOURCES; |
87 | 0 | } |
88 | | |
89 | | /* allocate space for the file data */ |
90 | 0 | io->out.size = state->io_open->ntcreatex.out.size; |
91 | 0 | io->out.data = talloc_array(c, uint8_t, io->out.size); |
92 | 0 | NT_STATUS_HAVE_NO_MEMORY(io->out.data); |
93 | | |
94 | 0 | if (io->out.size == 0) { |
95 | 0 | return setup_close(c, tree, state->io_open->ntcreatex.out.file.fnum); |
96 | 0 | } |
97 | | |
98 | | /* setup for the read */ |
99 | 0 | state->io_read = talloc(c, union smb_read); |
100 | 0 | NT_STATUS_HAVE_NO_MEMORY(state->io_read); |
101 | | |
102 | 0 | state->io_read->readx.level = RAW_READ_READX; |
103 | 0 | state->io_read->readx.in.file.fnum = state->io_open->ntcreatex.out.file.fnum; |
104 | 0 | state->io_read->readx.in.offset = 0; |
105 | 0 | state->io_read->readx.in.mincnt = MIN(32768, io->out.size); |
106 | 0 | state->io_read->readx.in.maxcnt = state->io_read->readx.in.mincnt; |
107 | 0 | state->io_read->readx.in.remaining = 0; |
108 | 0 | state->io_read->readx.in.read_for_execute = false; |
109 | 0 | state->io_read->readx.out.data = io->out.data; |
110 | |
|
111 | 0 | state->req = smb_raw_read_send(tree, state->io_read); |
112 | 0 | NT_STATUS_HAVE_NO_MEMORY(state->req); |
113 | | |
114 | | /* call the handler again when the first read is done */ |
115 | 0 | state->req->async.fn = loadfile_handler; |
116 | 0 | state->req->async.private_data = c; |
117 | 0 | state->stage = LOADFILE_READ; |
118 | |
|
119 | 0 | talloc_free(state->io_open); |
120 | |
|
121 | 0 | return NT_STATUS_OK; |
122 | 0 | } |
123 | | |
124 | | |
125 | | /* |
126 | | called when a read is done - pull the results and setup for the |
127 | | next read, or close if the file is all done |
128 | | */ |
129 | | static NTSTATUS loadfile_read(struct composite_context *c, |
130 | | struct smb_composite_loadfile *io) |
131 | 0 | { |
132 | 0 | struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state); |
133 | 0 | struct smbcli_tree *tree = state->req->tree; |
134 | 0 | NTSTATUS status; |
135 | |
|
136 | 0 | status = smb_raw_read_recv(state->req, state->io_read); |
137 | 0 | NT_STATUS_NOT_OK_RETURN(status); |
138 | | |
139 | | /* we might be done */ |
140 | 0 | if (state->io_read->readx.in.offset + |
141 | 0 | state->io_read->readx.out.nread == io->out.size) { |
142 | 0 | return setup_close(c, tree, state->io_read->readx.in.file.fnum); |
143 | 0 | } |
144 | | |
145 | | /* setup for the next read */ |
146 | 0 | state->io_read->readx.in.offset += state->io_read->readx.out.nread; |
147 | 0 | state->io_read->readx.in.mincnt = MIN(32768, io->out.size - state->io_read->readx.in.offset); |
148 | 0 | state->io_read->readx.out.data = io->out.data + state->io_read->readx.in.offset; |
149 | |
|
150 | 0 | state->req = smb_raw_read_send(tree, state->io_read); |
151 | 0 | NT_STATUS_HAVE_NO_MEMORY(state->req); |
152 | | |
153 | | /* call the handler again when the read is done */ |
154 | 0 | state->req->async.fn = loadfile_handler; |
155 | 0 | state->req->async.private_data = c; |
156 | |
|
157 | 0 | return NT_STATUS_OK; |
158 | 0 | } |
159 | | |
160 | | /* |
161 | | called when the close is done, check the status and cleanup |
162 | | */ |
163 | | static NTSTATUS loadfile_close(struct composite_context *c, |
164 | | struct smb_composite_loadfile *io) |
165 | 0 | { |
166 | 0 | struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state); |
167 | 0 | NTSTATUS status; |
168 | |
|
169 | 0 | status = smbcli_request_simple_recv(state->req); |
170 | 0 | NT_STATUS_NOT_OK_RETURN(status); |
171 | | |
172 | 0 | c->state = COMPOSITE_STATE_DONE; |
173 | |
|
174 | 0 | return NT_STATUS_OK; |
175 | 0 | } |
176 | | |
177 | | |
178 | | /* |
179 | | handler for completion of a sub-request in loadfile |
180 | | */ |
181 | | static void loadfile_handler(struct smbcli_request *req) |
182 | 0 | { |
183 | 0 | struct composite_context *c = (struct composite_context *)req->async.private_data; |
184 | 0 | struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state); |
185 | | |
186 | | /* when this handler is called, the stage indicates what |
187 | | call has just finished */ |
188 | 0 | switch (state->stage) { |
189 | 0 | case LOADFILE_OPEN: |
190 | 0 | c->status = loadfile_open(c, state->io); |
191 | 0 | break; |
192 | | |
193 | 0 | case LOADFILE_READ: |
194 | 0 | c->status = loadfile_read(c, state->io); |
195 | 0 | break; |
196 | | |
197 | 0 | case LOADFILE_CLOSE: |
198 | 0 | c->status = loadfile_close(c, state->io); |
199 | 0 | break; |
200 | 0 | } |
201 | | |
202 | 0 | if (!NT_STATUS_IS_OK(c->status)) { |
203 | 0 | c->state = COMPOSITE_STATE_ERROR; |
204 | 0 | } |
205 | |
|
206 | 0 | if (c->state >= COMPOSITE_STATE_DONE && |
207 | 0 | c->async.fn) { |
208 | 0 | c->async.fn(c); |
209 | 0 | } |
210 | 0 | } |
211 | | |
212 | | /* |
213 | | composite loadfile call - does an openx followed by a number of readx calls, |
214 | | followed by a close |
215 | | */ |
216 | | struct composite_context *smb_composite_loadfile_send(struct smbcli_tree *tree, |
217 | | struct smb_composite_loadfile *io) |
218 | 0 | { |
219 | 0 | struct composite_context *c; |
220 | 0 | struct loadfile_state *state; |
221 | |
|
222 | 0 | c = talloc_zero(tree, struct composite_context); |
223 | 0 | if (c == NULL) goto failed; |
224 | | |
225 | 0 | state = talloc(c, struct loadfile_state); |
226 | 0 | if (state == NULL) goto failed; |
227 | | |
228 | 0 | state->io = io; |
229 | |
|
230 | 0 | c->private_data = state; |
231 | 0 | c->state = COMPOSITE_STATE_IN_PROGRESS; |
232 | 0 | c->event_ctx = tree->session->transport->ev; |
233 | | |
234 | | /* setup for the open */ |
235 | 0 | state->io_open = talloc_zero(c, union smb_open); |
236 | 0 | if (state->io_open == NULL) goto failed; |
237 | | |
238 | 0 | state->io_open->ntcreatex.level = RAW_OPEN_NTCREATEX; |
239 | 0 | state->io_open->ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED; |
240 | 0 | state->io_open->ntcreatex.in.access_mask = SEC_FILE_READ_DATA; |
241 | 0 | state->io_open->ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; |
242 | 0 | state->io_open->ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; |
243 | 0 | state->io_open->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; |
244 | 0 | state->io_open->ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; |
245 | 0 | state->io_open->ntcreatex.in.fname = io->in.fname; |
246 | | |
247 | | /* send the open on its way */ |
248 | 0 | state->req = smb_raw_open_send(tree, state->io_open); |
249 | 0 | if (state->req == NULL) goto failed; |
250 | | |
251 | | /* setup the callback handler */ |
252 | 0 | state->req->async.fn = loadfile_handler; |
253 | 0 | state->req->async.private_data = c; |
254 | 0 | state->stage = LOADFILE_OPEN; |
255 | |
|
256 | 0 | return c; |
257 | | |
258 | 0 | failed: |
259 | 0 | talloc_free(c); |
260 | 0 | return NULL; |
261 | 0 | } |
262 | | |
263 | | |
264 | | /* |
265 | | composite loadfile call - recv side |
266 | | */ |
267 | | NTSTATUS smb_composite_loadfile_recv(struct composite_context *c, TALLOC_CTX *mem_ctx) |
268 | 0 | { |
269 | 0 | NTSTATUS status; |
270 | |
|
271 | 0 | status = composite_wait(c); |
272 | |
|
273 | 0 | if (NT_STATUS_IS_OK(status)) { |
274 | 0 | struct loadfile_state *state = talloc_get_type(c->private_data, struct loadfile_state); |
275 | 0 | talloc_steal(mem_ctx, state->io->out.data); |
276 | 0 | } |
277 | |
|
278 | 0 | talloc_free(c); |
279 | 0 | return status; |
280 | 0 | } |
281 | | |
282 | | |
283 | | /* |
284 | | composite loadfile call - sync interface |
285 | | */ |
286 | | NTSTATUS smb_composite_loadfile(struct smbcli_tree *tree, |
287 | | TALLOC_CTX *mem_ctx, |
288 | | struct smb_composite_loadfile *io) |
289 | 0 | { |
290 | 0 | struct composite_context *c = smb_composite_loadfile_send(tree, io); |
291 | 0 | return smb_composite_loadfile_recv(c, mem_ctx); |
292 | 0 | } |
293 | | |