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