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/raw/raw_proto.h"
26 #include "libcli/composite/composite.h"
27 #include "libcli/smb_composite/smb_composite.h"
29 /* the stages of this call */
30 enum savefile_stage
{SAVEFILE_OPEN
, SAVEFILE_WRITE
, SAVEFILE_CLOSE
};
32 static void savefile_handler(struct smbcli_request
*req
);
34 struct savefile_state
{
35 enum savefile_stage stage
;
37 struct smb_composite_savefile
*io
;
38 union smb_open
*io_open
;
39 union smb_write
*io_write
;
40 struct smbcli_request
*req
;
47 static NTSTATUS
setup_close(struct composite_context
*c
,
48 struct smbcli_tree
*tree
, uint16_t fnum
)
50 struct savefile_state
*state
= talloc_get_type(c
->private_data
, struct savefile_state
);
51 union smb_close
*io_close
;
53 /* nothing to write, setup the close */
54 io_close
= talloc(c
, union smb_close
);
55 NT_STATUS_HAVE_NO_MEMORY(io_close
);
57 io_close
->close
.level
= RAW_CLOSE_CLOSE
;
58 io_close
->close
.in
.file
.fnum
= fnum
;
59 io_close
->close
.in
.write_time
= 0;
61 state
->req
= smb_raw_close_send(tree
, io_close
);
62 NT_STATUS_HAVE_NO_MEMORY(state
->req
);
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_data
= c
;
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
76 static NTSTATUS
savefile_open(struct composite_context
*c
,
77 struct smb_composite_savefile
*io
)
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
;
83 uint32_t max_xmit
= tree
->session
->transport
->negotiate
.max_xmit
;
85 status
= smb_raw_open_recv(state
->req
, c
, state
->io_open
);
86 NT_STATUS_NOT_OK_RETURN(status
);
88 if (io
->in
.size
== 0) {
89 return setup_close(c
, tree
, state
->io_open
->ntcreatex
.out
.file
.fnum
);
92 /* setup for the first write */
93 io_write
= talloc(c
, union smb_write
);
94 NT_STATUS_HAVE_NO_MEMORY(io_write
);
96 io_write
->writex
.level
= RAW_WRITE_WRITEX
;
97 io_write
->writex
.in
.file
.fnum
= state
->io_open
->ntcreatex
.out
.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
;
105 state
->req
= smb_raw_write_send(tree
, io_write
);
106 NT_STATUS_HAVE_NO_MEMORY(state
->req
);
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_data
= c
;
112 talloc_free(state
->io_open
);
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
122 static NTSTATUS
savefile_write(struct composite_context
*c
,
123 struct smb_composite_savefile
*io
)
125 struct savefile_state
*state
= talloc_get_type(c
->private_data
, struct savefile_state
);
126 struct smbcli_tree
*tree
= state
->req
->tree
;
128 uint32_t max_xmit
= tree
->session
->transport
->negotiate
.max_xmit
;
130 status
= smb_raw_write_recv(state
->req
, state
->io_write
);
131 NT_STATUS_NOT_OK_RETURN(status
);
133 state
->total_written
+= state
->io_write
->writex
.out
.nwritten
;
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
.in
.file
.fnum
);
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
;
147 state
->req
= smb_raw_write_send(tree
, state
->io_write
);
148 NT_STATUS_HAVE_NO_MEMORY(state
->req
);
150 /* call the handler again when the write is done */
151 state
->req
->async
.fn
= savefile_handler
;
152 state
->req
->async
.private_data
= c
;
158 called when the close is done, check the status and cleanup
160 static NTSTATUS
savefile_close(struct composite_context
*c
,
161 struct smb_composite_savefile
*io
)
163 struct savefile_state
*state
= talloc_get_type(c
->private_data
, struct savefile_state
);
166 status
= smbcli_request_simple_recv(state
->req
);
167 NT_STATUS_NOT_OK_RETURN(status
);
169 if (state
->total_written
!= io
->in
.size
) {
170 return NT_STATUS_DISK_FULL
;
173 c
->state
= COMPOSITE_STATE_DONE
;
180 handler for completion of a sub-request in savefile
182 static void savefile_handler(struct smbcli_request
*req
)
184 struct composite_context
*c
= (struct composite_context
*)req
->async
.private_data
;
185 struct savefile_state
*state
= talloc_get_type(c
->private_data
, struct savefile_state
);
187 /* when this handler is called, the stage indicates what
188 call has just finished */
189 switch (state
->stage
) {
191 c
->status
= savefile_open(c
, state
->io
);
195 c
->status
= savefile_write(c
, state
->io
);
199 c
->status
= savefile_close(c
, state
->io
);
203 if (!NT_STATUS_IS_OK(c
->status
)) {
204 c
->state
= COMPOSITE_STATE_ERROR
;
207 if (c
->state
>= COMPOSITE_STATE_DONE
&&
214 composite savefile call - does an openx followed by a number of writex calls,
217 struct composite_context
*smb_composite_savefile_send(struct smbcli_tree
*tree
,
218 struct smb_composite_savefile
*io
)
220 struct composite_context
*c
;
221 struct savefile_state
*state
;
222 union smb_open
*io_open
;
224 c
= talloc_zero(tree
, struct composite_context
);
225 if (c
== NULL
) goto failed
;
227 c
->state
= COMPOSITE_STATE_IN_PROGRESS
;
228 c
->event_ctx
= tree
->session
->transport
->ev
;
230 state
= talloc(c
, struct savefile_state
);
231 if (state
== NULL
) goto failed
;
233 state
->stage
= SAVEFILE_OPEN
;
234 state
->total_written
= 0;
237 /* setup for the open */
238 io_open
= talloc_zero(c
, union smb_open
);
239 if (io_open
== NULL
) goto failed
;
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
;
251 /* send the open on its way */
252 state
->req
= smb_raw_open_send(tree
, io_open
);
253 if (state
->req
== NULL
) goto failed
;
255 /* setup the callback handler */
256 state
->req
->async
.fn
= savefile_handler
;
257 state
->req
->async
.private_data
= c
;
258 c
->private_data
= state
;
269 composite savefile call - recv side
271 NTSTATUS
smb_composite_savefile_recv(struct composite_context
*c
)
274 status
= composite_wait(c
);
281 composite savefile call - sync interface
283 NTSTATUS
smb_composite_savefile(struct smbcli_tree
*tree
,
284 struct smb_composite_savefile
*io
)
286 struct composite_context
*c
= smb_composite_savefile_send(tree
, io
);
287 return smb_composite_savefile_recv(c
);