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 */ 30enum savefile_stage {SAVEFILE_OPEN, SAVEFILE_WRITE, SAVEFILE_CLOSE}; 31 32static void savefile_handler(struct smbcli_request *req); 33 34struct 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*/ 47static 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.in.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_data = 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*/ 76static 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.out.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.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; 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_data = 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*/ 122static 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.in.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_data = c; 153 154 return NT_STATUS_OK; 155} 156 157/* 158 called when the close is done, check the status and cleanup 159*/ 160static 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*/ 182static void savefile_handler(struct smbcli_request *req) 183{ 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); 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*/ 217struct 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_data = c; 258 c->private_data = state; 259 260 return c; 261 262failed: 263 talloc_free(c); 264 return NULL; 265} 266 267 268/* 269 composite savefile call - recv side 270*/ 271NTSTATUS 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*/ 283NTSTATUS 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} 289