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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 a composite API for saving a whole file from memory
25 #include "libcli/raw/libcliraw.h"
26 #include "libcli/composite/composite.h"
27 #include "libcli/smb_composite/smb_composite.h"
28 #include "librpc/gen_ndr/ndr_security.h"
30 /* the stages of this call */
31 enum savefile_stage {SAVEFILE_OPEN, SAVEFILE_WRITE, SAVEFILE_CLOSE};
33 static void savefile_handler(struct smbcli_request *req);
35 struct savefile_state {
36 enum savefile_stage stage;
38 struct smb_composite_savefile *io;
39 union smb_open *io_open;
40 union smb_write *io_write;
41 struct smbcli_request *req;
48 static NTSTATUS setup_close(struct composite_context *c,
49 struct smbcli_tree *tree, uint16_t fnum)
51 struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
52 union smb_close *io_close;
54 /* nothing to write, setup the close */
55 io_close = talloc(c, union smb_close);
56 NT_STATUS_HAVE_NO_MEMORY(io_close);
58 io_close->close.level = RAW_CLOSE_CLOSE;
59 io_close->close.in.fnum = fnum;
60 io_close->close.in.write_time = 0;
62 state->req = smb_raw_close_send(tree, io_close);
63 NT_STATUS_HAVE_NO_MEMORY(state->req);
65 /* call the handler again when the close is done */
66 state->stage = SAVEFILE_CLOSE;
67 state->req->async.fn = savefile_handler;
68 state->req->async.private = c;
74 called when the open is done - pull the results and setup for the
75 first writex, or close if the file is zero size
77 static NTSTATUS savefile_open(struct composite_context *c,
78 struct smb_composite_savefile *io)
80 struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
81 union smb_write *io_write;
82 struct smbcli_tree *tree = state->req->tree;
84 uint32_t max_xmit = tree->session->transport->negotiate.max_xmit;
86 status = smb_raw_open_recv(state->req, c, state->io_open);
87 NT_STATUS_NOT_OK_RETURN(status);
89 if (io->in.size == 0) {
90 return setup_close(c, tree, state->io_open->ntcreatex.out.fnum);
93 /* setup for the first write */
94 io_write = talloc(c, union smb_write);
95 NT_STATUS_HAVE_NO_MEMORY(io_write);
97 io_write->writex.level = RAW_WRITE_WRITEX;
98 io_write->writex.in.fnum = state->io_open->ntcreatex.out.fnum;
99 io_write->writex.in.offset = 0;
100 io_write->writex.in.wmode = 0;
101 io_write->writex.in.remaining = 0;
102 io_write->writex.in.count = MIN(max_xmit - 100, io->in.size);
103 io_write->writex.in.data = io->in.data;
104 state->io_write = io_write;
106 state->req = smb_raw_write_send(tree, io_write);
107 NT_STATUS_HAVE_NO_MEMORY(state->req);
109 /* call the handler again when the first write is done */
110 state->stage = SAVEFILE_WRITE;
111 state->req->async.fn = savefile_handler;
112 state->req->async.private = c;
113 talloc_free(state->io_open);
120 called when a write is done - pull the results and setup for the
121 next write, or close if the file is all done
123 static NTSTATUS savefile_write(struct composite_context *c,
124 struct smb_composite_savefile *io)
126 struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
127 struct smbcli_tree *tree = state->req->tree;
129 uint32_t max_xmit = tree->session->transport->negotiate.max_xmit;
131 status = smb_raw_write_recv(state->req, state->io_write);
132 NT_STATUS_NOT_OK_RETURN(status);
134 state->total_written += state->io_write->writex.out.nwritten;
136 /* we might be done */
137 if (state->io_write->writex.out.nwritten != state->io_write->writex.in.count ||
138 state->total_written == io->in.size) {
139 return setup_close(c, tree, state->io_write->writex.in.fnum);
142 /* setup for the next write */
143 state->io_write->writex.in.offset = state->total_written;
144 state->io_write->writex.in.count = MIN(max_xmit - 100,
145 io->in.size - state->total_written);
146 state->io_write->writex.in.data = io->in.data + state->total_written;
148 state->req = smb_raw_write_send(tree, state->io_write);
149 NT_STATUS_HAVE_NO_MEMORY(state->req);
151 /* call the handler again when the write is done */
152 state->req->async.fn = savefile_handler;
153 state->req->async.private = c;
159 called when the close is done, check the status and cleanup
161 static NTSTATUS savefile_close(struct composite_context *c,
162 struct smb_composite_savefile *io)
164 struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
167 status = smbcli_request_simple_recv(state->req);
168 NT_STATUS_NOT_OK_RETURN(status);
170 if (state->total_written != io->in.size) {
171 return NT_STATUS_DISK_FULL;
174 c->state = COMPOSITE_STATE_DONE;
181 handler for completion of a sub-request in savefile
183 static void savefile_handler(struct smbcli_request *req)
185 struct composite_context *c = req->async.private;
186 struct savefile_state *state = talloc_get_type(c->private_data, struct savefile_state);
188 /* when this handler is called, the stage indicates what
189 call has just finished */
190 switch (state->stage) {
192 c->status = savefile_open(c, state->io);
196 c->status = savefile_write(c, state->io);
200 c->status = savefile_close(c, state->io);
204 if (!NT_STATUS_IS_OK(c->status)) {
205 c->state = COMPOSITE_STATE_ERROR;
208 if (c->state >= COMPOSITE_STATE_DONE &&
215 composite savefile call - does an openx followed by a number of writex calls,
218 struct composite_context *smb_composite_savefile_send(struct smbcli_tree *tree,
219 struct smb_composite_savefile *io)
221 struct composite_context *c;
222 struct savefile_state *state;
223 union smb_open *io_open;
225 c = talloc_zero(tree, struct composite_context);
226 if (c == NULL) goto failed;
228 c->state = COMPOSITE_STATE_IN_PROGRESS;
229 c->event_ctx = tree->session->transport->socket->event.ctx;
231 state = talloc(c, struct savefile_state);
232 if (state == NULL) goto failed;
234 state->stage = SAVEFILE_OPEN;
235 state->total_written = 0;
238 /* setup for the open */
239 io_open = talloc_zero(c, union smb_open);
240 if (io_open == NULL) goto failed;
242 io_open->ntcreatex.level = RAW_OPEN_NTCREATEX;
243 io_open->ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
244 io_open->ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
245 io_open->ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
246 io_open->ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
247 io_open->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
248 io_open->ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
249 io_open->ntcreatex.in.fname = io->in.fname;
250 state->io_open = io_open;
252 /* send the open on its way */
253 state->req = smb_raw_open_send(tree, io_open);
254 if (state->req == NULL) goto failed;
256 /* setup the callback handler */
257 state->req->async.fn = savefile_handler;
258 state->req->async.private = c;
259 c->private_data = state;
270 composite savefile call - recv side
272 NTSTATUS smb_composite_savefile_recv(struct composite_context *c)
275 status = composite_wait(c);
282 composite savefile call - sync interface
284 NTSTATUS smb_composite_savefile(struct smbcli_tree *tree,
285 struct smb_composite_savefile *io)
287 struct composite_context *c = smb_composite_savefile_send(tree, io);
288 return smb_composite_savefile_recv(c);