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