2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2005
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/>.
20 a composite API for saving a whole file from memory
24 #include "libcli/raw/libcliraw.h"
25 #include "libcli/composite/composite.h"
26 #include "libcli/smb_composite/smb_composite.h"
28 /* the stages of this call */
29 enum savefile_stage {SAVEFILE_OPEN, SAVEFILE_WRITE, SAVEFILE_CLOSE};
31 static void savefile_handler(struct smbcli_request *req);
33 struct savefile_state {
34 enum savefile_stage stage;
36 struct smb_composite_savefile *io;
37 union smb_open *io_open;
38 union smb_write *io_write;
39 struct smbcli_request *req;
46 static NTSTATUS setup_close(struct composite_context *c,
47 struct smbcli_tree *tree, uint16_t fnum)
49 struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
50 union smb_close *io_close;
52 /* nothing to write, setup the close */
53 io_close = talloc(c, union smb_close);
54 NT_STATUS_HAVE_NO_MEMORY(io_close);
56 io_close->close.level = RAW_CLOSE_CLOSE;
57 io_close->close.in.file.fnum = fnum;
58 io_close->close.in.write_time = 0;
60 state->req = smb_raw_close_send(tree, io_close);
61 NT_STATUS_HAVE_NO_MEMORY(state->req);
63 /* call the handler again when the close is done */
64 state->stage = SAVEFILE_CLOSE;
65 state->req->async.fn = savefile_handler;
66 state->req->async.private = c;
72 called when the open is done - pull the results and setup for the
73 first writex, or close if the file is zero size
75 static NTSTATUS savefile_open(struct composite_context *c,
76 struct smb_composite_savefile *io)
78 struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
79 union smb_write *io_write;
80 struct smbcli_tree *tree = state->req->tree;
82 uint32_t max_xmit = tree->session->transport->negotiate.max_xmit;
84 status = smb_raw_open_recv(state->req, c, state->io_open);
85 NT_STATUS_NOT_OK_RETURN(status);
87 if (io->in.size == 0) {
88 return setup_close(c, tree, state->io_open->ntcreatex.out.file.fnum);
91 /* setup for the first write */
92 io_write = talloc(c, union smb_write);
93 NT_STATUS_HAVE_NO_MEMORY(io_write);
95 io_write->writex.level = RAW_WRITE_WRITEX;
96 io_write->writex.in.file.fnum = state->io_open->ntcreatex.out.file.fnum;
97 io_write->writex.in.offset = 0;
98 io_write->writex.in.wmode = 0;
99 io_write->writex.in.remaining = 0;
100 io_write->writex.in.count = MIN(max_xmit - 100, io->in.size);
101 io_write->writex.in.data = io->in.data;
102 state->io_write = io_write;
104 state->req = smb_raw_write_send(tree, io_write);
105 NT_STATUS_HAVE_NO_MEMORY(state->req);
107 /* call the handler again when the first write is done */
108 state->stage = SAVEFILE_WRITE;
109 state->req->async.fn = savefile_handler;
110 state->req->async.private = c;
111 talloc_free(state->io_open);
118 called when a write is done - pull the results and setup for the
119 next write, or close if the file is all done
121 static NTSTATUS savefile_write(struct composite_context *c,
122 struct smb_composite_savefile *io)
124 struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
125 struct smbcli_tree *tree = state->req->tree;
127 uint32_t max_xmit = tree->session->transport->negotiate.max_xmit;
129 status = smb_raw_write_recv(state->req, state->io_write);
130 NT_STATUS_NOT_OK_RETURN(status);
132 state->total_written += state->io_write->writex.out.nwritten;
134 /* we might be done */
135 if (state->io_write->writex.out.nwritten != state->io_write->writex.in.count ||
136 state->total_written == io->in.size) {
137 return setup_close(c, tree, state->io_write->writex.in.file.fnum);
140 /* setup for the next write */
141 state->io_write->writex.in.offset = state->total_written;
142 state->io_write->writex.in.count = MIN(max_xmit - 100,
143 io->in.size - state->total_written);
144 state->io_write->writex.in.data = io->in.data + state->total_written;
146 state->req = smb_raw_write_send(tree, state->io_write);
147 NT_STATUS_HAVE_NO_MEMORY(state->req);
149 /* call the handler again when the write is done */
150 state->req->async.fn = savefile_handler;
151 state->req->async.private = c;
157 called when the close is done, check the status and cleanup
159 static NTSTATUS savefile_close(struct composite_context *c,
160 struct smb_composite_savefile *io)
162 struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
165 status = smbcli_request_simple_recv(state->req);
166 NT_STATUS_NOT_OK_RETURN(status);
168 if (state->total_written != io->in.size) {
169 return NT_STATUS_DISK_FULL;
172 c->state = COMPOSITE_STATE_DONE;
179 handler for completion of a sub-request in savefile
181 static void savefile_handler(struct smbcli_request *req)
183 struct composite_context *c = req->async.private;
184 struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
186 /* when this handler is called, the stage indicates what
187 call has just finished */
188 switch (state->stage) {
190 c->status = savefile_open(c, state->io);
194 c->status = savefile_write(c, state->io);
198 c->status = savefile_close(c, state->io);
202 if (!NT_STATUS_IS_OK(c->status)) {
203 c->state = COMPOSITE_STATE_ERROR;
206 if (c->state >= COMPOSITE_STATE_DONE &&
213 composite savefile call - does an openx followed by a number of writex calls,
216 struct composite_context *smb_composite_savefile_send(struct smbcli_tree *tree,
217 struct smb_composite_savefile *io)
219 struct composite_context *c;
220 struct savefile_state *state;
221 union smb_open *io_open;
223 c = talloc_zero(tree, struct composite_context);
224 if (c == NULL) goto failed;
226 c->state = COMPOSITE_STATE_IN_PROGRESS;
227 c->event_ctx = tree->session->transport->socket->event.ctx;
229 state = talloc(c, struct savefile_state);
230 if (state == NULL) goto failed;
232 state->stage = SAVEFILE_OPEN;
233 state->total_written = 0;
236 /* setup for the open */
237 io_open = talloc_zero(c, union smb_open);
238 if (io_open == NULL) goto failed;
240 io_open->ntcreatex.level = RAW_OPEN_NTCREATEX;
241 io_open->ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
242 io_open->ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
243 io_open->ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
244 io_open->ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
245 io_open->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
246 io_open->ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
247 io_open->ntcreatex.in.fname = io->in.fname;
248 state->io_open = io_open;
250 /* send the open on its way */
251 state->req = smb_raw_open_send(tree, io_open);
252 if (state->req == NULL) goto failed;
254 /* setup the callback handler */
255 state->req->async.fn = savefile_handler;
256 state->req->async.private = c;
257 c->private_data = state;
268 composite savefile call - recv side
270 NTSTATUS smb_composite_savefile_recv(struct composite_context *c)
273 status = composite_wait(c);
280 composite savefile call - sync interface
282 NTSTATUS smb_composite_savefile(struct smbcli_tree *tree,
283 struct smb_composite_savefile *io)
285 struct composite_context *c = smb_composite_savefile_send(tree, io);
286 return smb_composite_savefile_recv(c);