From 287515fd3db1932f06d56da3bb388a7efc1120eb Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 12 Jan 2005 11:43:18 +0000 Subject: r4710: added a smb_composite_savefile() function, and expanded the test suite a little (This used to be commit ef4dbc443dbdebc4160209ed3f23cbb97109c414) --- source4/libcli/composite/composite.c | 45 ++++++ source4/libcli/composite/composite.h | 16 +- source4/libcli/composite/loadfile.c | 12 +- source4/libcli/composite/savefile.c | 284 +++++++++++++++++++++++++++++++++++ 4 files changed, 346 insertions(+), 11 deletions(-) create mode 100644 source4/libcli/composite/composite.c create mode 100644 source4/libcli/composite/savefile.c (limited to 'source4/libcli/composite') diff --git a/source4/libcli/composite/composite.c b/source4/libcli/composite/composite.c new file mode 100644 index 0000000000..f7e23cd4bc --- /dev/null +++ b/source4/libcli/composite/composite.c @@ -0,0 +1,45 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Andrew Tridgell 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + composite API helper functions +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/composite/composite.h" + + +/* + block until a composite function has completed, then return the status +*/ +NTSTATUS smb_composite_wait(struct smbcli_composite *c) +{ + if (c == NULL) return NT_STATUS_NO_MEMORY; + + while (c->state < SMBCLI_REQUEST_DONE) { + if (event_loop_once(c->req->transport->event.ctx) != 0) { + return NT_STATUS_UNSUCCESSFUL; + } + } + + return c->status; +} + + diff --git a/source4/libcli/composite/composite.h b/source4/libcli/composite/composite.h index 895c88a4f6..7b9477a942 100644 --- a/source4/libcli/composite/composite.h +++ b/source4/libcli/composite/composite.h @@ -45,6 +45,9 @@ struct smbcli_composite { /* the parameters of the whole composite function */ void *composite_parms; + /* a private pointer for use by the composite code */ + void *private; + /* status code when finished */ NTSTATUS status; @@ -53,7 +56,6 @@ struct smbcli_composite { void (*fn)(struct smbcli_composite *); void *private; } async; - }; @@ -70,3 +72,15 @@ struct smb_composite_loadfile { uint32_t size; } out; }; + +/* + a composite open/write(s)/close request that saves a whole file from + memory. Used as a demo of the composite system. +*/ +struct smb_composite_savefile { + struct { + const char *fname; + uint8_t *data; + uint32_t size; + } in; +}; diff --git a/source4/libcli/composite/loadfile.c b/source4/libcli/composite/loadfile.c index 1bf1fd5403..61260aa963 100644 --- a/source4/libcli/composite/loadfile.c +++ b/source4/libcli/composite/loadfile.c @@ -257,22 +257,14 @@ NTSTATUS smb_composite_loadfile_recv(struct smbcli_composite *c, TALLOC_CTX *mem { NTSTATUS status; - if (!c) return NT_STATUS_NO_MEMORY; + status = smb_composite_wait(c); - while (c->state < SMBCLI_REQUEST_DONE) { - if (event_loop_once(c->req->transport->event.ctx) != 0) { - return NT_STATUS_UNSUCCESSFUL; - } - } - - if (NT_STATUS_IS_OK(c->status)) { + if (NT_STATUS_IS_OK(status)) { struct smb_composite_loadfile *io = c->composite_parms; talloc_steal(mem_ctx, io->out.data); } - status = c->status; talloc_free(c); - return status; } diff --git a/source4/libcli/composite/savefile.c b/source4/libcli/composite/savefile.c new file mode 100644 index 0000000000..dc9ee2f9ec --- /dev/null +++ b/source4/libcli/composite/savefile.c @@ -0,0 +1,284 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Andrew Tridgell 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +/* + a composite API for saving a whole file from memory +*/ + +#include "includes.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/composite/composite.h" +#include "librpc/gen_ndr/ndr_security.h" + +/* the stages of this call */ +enum savefile_stage {SAVEFILE_OPEN, SAVEFILE_WRITE, SAVEFILE_CLOSE}; + + +static void savefile_handler(struct smbcli_request *req); + +struct savefile_state { + off_t total_written; +}; + + +/* + setup for the close +*/ +static NTSTATUS setup_close(struct smbcli_composite *c, + struct smbcli_tree *tree, uint16_t fnum) +{ + union smb_close *io_close; + + /* nothing to write, setup the close */ + io_close = talloc(c, union smb_close); + NT_STATUS_HAVE_NO_MEMORY(io_close); + + io_close->close.level = RAW_CLOSE_CLOSE; + io_close->close.in.fnum = fnum; + io_close->close.in.write_time = 0; + + c->req = smb_raw_close_send(tree, io_close); + NT_STATUS_HAVE_NO_MEMORY(c->req); + + /* call the handler again when the close is done */ + c->stage = SAVEFILE_CLOSE; + c->req->async.fn = savefile_handler; + c->req->async.private = c; + c->req_parms = io_close; + + return NT_STATUS_OK; +} + +/* + called when the open is done - pull the results and setup for the + first writex, or close if the file is zero size +*/ +static NTSTATUS savefile_open(struct smbcli_composite *c, + struct smb_composite_savefile *io) +{ + union smb_open *io_open = c->req_parms; + struct smbcli_tree *tree = c->req->tree; + union smb_write *io_write; + NTSTATUS status; + uint32_t max_xmit = tree->session->transport->negotiate.max_xmit; + + status = smb_raw_open_recv(c->req, c, io_open); + NT_STATUS_NOT_OK_RETURN(status); + + if (io->in.size == 0) { + return setup_close(c, tree, io_open->ntcreatex.out.fnum); + } + + /* setup for the first write */ + io_write = talloc(c, union smb_write); + NT_STATUS_HAVE_NO_MEMORY(io_write); + + io_write->writex.level = RAW_WRITE_WRITEX; + io_write->writex.in.fnum = io_open->ntcreatex.out.fnum; + io_write->writex.in.offset = 0; + io_write->writex.in.wmode = 0; + io_write->writex.in.remaining = 0; + io_write->writex.in.count = MIN(max_xmit - 100, io->in.size); + io_write->writex.in.data = io->in.data; + + c->req = smb_raw_write_send(tree, io_write); + NT_STATUS_HAVE_NO_MEMORY(c->req); + + /* call the handler again when the first write is done */ + c->stage = SAVEFILE_WRITE; + c->req->async.fn = savefile_handler; + c->req->async.private = c; + c->req_parms = io_write; + talloc_free(io_open); + + return NT_STATUS_OK; +} + + +/* + called when a write is done - pull the results and setup for the + next write, or close if the file is all done +*/ +static NTSTATUS savefile_write(struct smbcli_composite *c, + struct smb_composite_savefile *io) +{ + union smb_write *io_write = c->req_parms; + struct smbcli_tree *tree = c->req->tree; + struct savefile_state *state = c->private; + NTSTATUS status; + uint32_t max_xmit = tree->session->transport->negotiate.max_xmit; + + status = smb_raw_write_recv(c->req, io_write); + NT_STATUS_NOT_OK_RETURN(status); + + state->total_written += io_write->writex.out.nwritten; + + /* we might be done */ + if (io_write->writex.out.nwritten != io_write->writex.in.count || + state->total_written == io->in.size) { + return setup_close(c, tree, io_write->writex.in.fnum); + } + + /* setup for the next write */ + io_write->writex.in.offset = state->total_written; + io_write->writex.in.count = MIN(max_xmit - 100, io->in.size - state->total_written); + io_write->writex.in.data = io->in.data + state->total_written; + + c->req = smb_raw_write_send(tree, io_write); + NT_STATUS_HAVE_NO_MEMORY(c->req); + + /* call the handler again when the write is done */ + c->req->async.fn = savefile_handler; + c->req->async.private = c; + + return NT_STATUS_OK; +} + +/* + called when the close is done, check the status and cleanup +*/ +static NTSTATUS savefile_close(struct smbcli_composite *c, + struct smb_composite_savefile *io) +{ + NTSTATUS status; + struct savefile_state *state = c->private; + + status = smbcli_request_simple_recv(c->req); + NT_STATUS_NOT_OK_RETURN(status); + + if (state->total_written != io->in.size) { + return NT_STATUS_DISK_FULL; + } + + c->state = SMBCLI_REQUEST_DONE; + if (c->async.fn) { + c->async.fn(c); + } + + return NT_STATUS_OK; +} + + +/* + handler for completion of a sub-request in savefile +*/ +static void savefile_handler(struct smbcli_request *req) +{ + struct smbcli_composite *c = req->async.private; + struct smb_composite_savefile *io = c->composite_parms; + + /* when this handler is called, the stage indicates what + call has just finished */ + switch (c->stage) { + case SAVEFILE_OPEN: + c->status = savefile_open(c, io); + break; + + case SAVEFILE_WRITE: + c->status = savefile_write(c, io); + break; + + case SAVEFILE_CLOSE: + c->status = savefile_close(c, io); + break; + } + + if (!NT_STATUS_IS_OK(c->status)) { + c->state = SMBCLI_REQUEST_ERROR; + if (c->async.fn) { + c->async.fn(c); + } + } +} + +/* + composite savefile call - does an openx followed by a number of writex calls, + followed by a close +*/ +struct smbcli_composite *smb_composite_savefile_send(struct smbcli_tree *tree, + struct smb_composite_savefile *io) +{ + struct smbcli_composite *c; + union smb_open *io_open; + struct savefile_state *state; + + c = talloc_zero(tree, struct smbcli_composite); + if (c == NULL) goto failed; + + c->state = SMBCLI_REQUEST_SEND; + c->stage = SAVEFILE_OPEN; + c->composite_parms = io; + + state = talloc(c, struct savefile_state); + if (state == NULL) goto failed; + + state->total_written = 0; + + /* setup for the open */ + io_open = talloc_zero(c, union smb_open); + if (io_open == NULL) goto failed; + + io_open->ntcreatex.level = RAW_OPEN_NTCREATEX; + io_open->ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED; + io_open->ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA; + io_open->ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL; + io_open->ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE; + io_open->ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF; + io_open->ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io_open->ntcreatex.in.fname = io->in.fname; + + /* send the open on its way */ + c->req = smb_raw_open_send(tree, io_open); + if (c->req == NULL) goto failed; + + /* setup the callback handler */ + c->req->async.fn = savefile_handler; + c->req->async.private = c; + c->req_parms = io_open; + c->private = state; + + return c; + +failed: + talloc_free(c); + return NULL; +} + + +/* + composite savefile call - recv side +*/ +NTSTATUS smb_composite_savefile_recv(struct smbcli_composite *c) +{ + NTSTATUS status; + status = smb_composite_wait(c); + talloc_free(c); + return status; +} + + +/* + composite savefile call - sync interface +*/ +NTSTATUS smb_composite_savefile(struct smbcli_tree *tree, + struct smb_composite_savefile *io) +{ + struct smbcli_composite *c = smb_composite_savefile_send(tree, io); + return smb_composite_savefile_recv(c); +} -- cgit