diff options
-rw-r--r-- | source4/include/structs.h | 3 | ||||
-rw-r--r-- | source4/libcli/composite/composite.c | 45 | ||||
-rw-r--r-- | source4/libcli/composite/composite.h | 16 | ||||
-rw-r--r-- | source4/libcli/composite/loadfile.c | 12 | ||||
-rw-r--r-- | source4/libcli/composite/savefile.c | 284 | ||||
-rw-r--r-- | source4/libcli/config.mk | 5 | ||||
-rw-r--r-- | source4/torture/raw/composite.c | 47 |
7 files changed, 392 insertions, 20 deletions
diff --git a/source4/include/structs.h b/source4/include/structs.h index c9297f9943..43dce0f0c0 100644 --- a/source4/include/structs.h +++ b/source4/include/structs.h @@ -135,5 +135,6 @@ struct lsa_RightSet; struct ldb_val; +struct smbcli_composite; struct smb_composite_loadfile; - +struct smb_composite_savefile; 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); +} diff --git a/source4/libcli/config.mk b/source4/libcli/config.mk index 4907ca9c72..40eecca0f9 100644 --- a/source4/libcli/config.mk +++ b/source4/libcli/config.mk @@ -19,7 +19,10 @@ REQUIRED_SUBSYSTEMS = RPC_NDR_LSA ADD_OBJ_FILES = libcli/util/clilsa.o [SUBSYSTEM::LIBCLI_COMPOSITE] -ADD_OBJ_FILES = libcli/composite/loadfile.o +ADD_OBJ_FILES = \ + libcli/composite/composite.o \ + libcli/composite/loadfile.o \ + libcli/composite/savefile.o [SUBSYSTEM::LIBCLI] REQUIRED_SUBSYSTEMS = LIBCLI_RAW LIBCLI_UTILS LIBCLI_AUTH LIBCLI_NMB LIBCLI_COMPOSITE diff --git a/source4/torture/raw/composite.c b/source4/torture/raw/composite.c index 97f820c9e5..563705740d 100644 --- a/source4/torture/raw/composite.c +++ b/source4/torture/raw/composite.c @@ -26,24 +26,57 @@ #define BASEDIR "\\composite" +/* + test a simple savefile/loadfile combination +*/ static BOOL test_loadfile(struct smbcli_state *cli, TALLOC_CTX *mem_ctx) { const char *fname = BASEDIR "\\test.txt"; - int fnum; NTSTATUS status; - struct smb_composite_loadfile io; - - fnum = create_complex_file(cli, mem_ctx, fname); - smbcli_close(cli->tree, fnum); + struct smb_composite_savefile io1; + struct smb_composite_loadfile io2; + char *data; + size_t len = random() % 100000; + + data = talloc_array(mem_ctx, uint8_t, len); + + generate_random_buffer(data, len); - io.in.fname = fname; + io1.in.fname = fname; + io1.in.data = data; + io1.in.size = len; - status = smb_composite_loadfile(cli->tree, mem_ctx, &io); + printf("testing savefile\n"); + + status = smb_composite_savefile(cli->tree, &io1); + if (!NT_STATUS_IS_OK(status)) { + printf("savefile failed: %s\n", nt_errstr(status)); + return False; + } + + io2.in.fname = fname; + + printf("testing loadfile\n"); + + status = smb_composite_loadfile(cli->tree, mem_ctx, &io2); if (!NT_STATUS_IS_OK(status)) { printf("Loadfile failed: %s\n", nt_errstr(status)); return False; } + if (io2.out.size != len) { + printf("wrong length in returned data - %d should be %d\n", + io2.out.size, len); + return False; + } + + if (memcmp(io2.out.data, data, len) != 0) { + printf("wrong data in loadfile!\n"); + return False; + } + + talloc_free(data); + return True; } |