2005-01-12 11:43:18 +00:00
/*
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
2007-07-10 02:07:03 +00:00
the Free Software Foundation ; either version 3 of the License , or
2005-01-12 11:43:18 +00:00
( 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
2007-07-10 02:07:03 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-01-12 11:43:18 +00:00
*/
/*
a composite API for saving a whole file from memory
*/
# include "includes.h"
# include "libcli/raw/libcliraw.h"
# include "libcli/composite/composite.h"
2005-09-26 11:47:55 +00:00
# include "libcli/smb_composite/smb_composite.h"
2005-01-12 11:43:18 +00:00
/* 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 {
2005-01-22 02:51:39 +00:00
enum savefile_stage stage ;
2005-01-12 11:43:18 +00:00
off_t total_written ;
2005-01-16 21:58:28 +00:00
struct smb_composite_savefile * io ;
union smb_open * io_open ;
union smb_write * io_write ;
2005-01-16 22:22:13 +00:00
struct smbcli_request * req ;
2005-01-12 11:43:18 +00:00
} ;
/*
setup for the close
*/
2005-01-31 08:30:44 +00:00
static NTSTATUS setup_close ( struct composite_context * c ,
2005-01-12 11:43:18 +00:00
struct smbcli_tree * tree , uint16_t fnum )
{
2005-09-26 11:47:55 +00:00
struct savefile_state * state = talloc_get_type ( c - > private_data , struct savefile_state ) ;
2005-01-12 11:43:18 +00:00
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 ;
2006-03-12 22:48:25 +00:00
io_close - > close . in . file . fnum = fnum ;
2005-01-12 11:43:18 +00:00
io_close - > close . in . write_time = 0 ;
2005-01-16 22:22:13 +00:00
state - > req = smb_raw_close_send ( tree , io_close ) ;
NT_STATUS_HAVE_NO_MEMORY ( state - > req ) ;
2005-01-12 11:43:18 +00:00
/* call the handler again when the close is done */
2005-01-22 02:51:39 +00:00
state - > stage = SAVEFILE_CLOSE ;
2005-01-16 22:22:13 +00:00
state - > req - > async . fn = savefile_handler ;
state - > req - > async . private = c ;
2005-01-12 11:43:18 +00:00
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
*/
2005-01-31 08:30:44 +00:00
static NTSTATUS savefile_open ( struct composite_context * c ,
2005-01-12 11:43:18 +00:00
struct smb_composite_savefile * io )
{
2005-09-26 11:47:55 +00:00
struct savefile_state * state = talloc_get_type ( c - > private_data , struct savefile_state ) ;
2005-01-16 21:58:28 +00:00
union smb_write * io_write ;
2005-01-16 22:22:13 +00:00
struct smbcli_tree * tree = state - > req - > tree ;
2005-01-12 11:43:18 +00:00
NTSTATUS status ;
uint32_t max_xmit = tree - > session - > transport - > negotiate . max_xmit ;
2005-01-16 22:22:13 +00:00
status = smb_raw_open_recv ( state - > req , c , state - > io_open ) ;
2005-01-12 11:43:18 +00:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
if ( io - > in . size = = 0 ) {
2006-03-12 22:48:25 +00:00
return setup_close ( c , tree , state - > io_open - > ntcreatex . out . file . fnum ) ;
2005-01-12 11:43:18 +00:00
}
/* 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 ;
2006-03-12 22:48:25 +00:00
io_write - > writex . in . file . fnum = state - > io_open - > ntcreatex . out . file . fnum ;
2005-01-12 11:43:18 +00:00
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 ;
2005-01-16 21:58:28 +00:00
state - > io_write = io_write ;
2005-01-12 11:43:18 +00:00
2005-01-16 22:22:13 +00:00
state - > req = smb_raw_write_send ( tree , io_write ) ;
NT_STATUS_HAVE_NO_MEMORY ( state - > req ) ;
2005-01-12 11:43:18 +00:00
/* call the handler again when the first write is done */
2005-01-22 02:51:39 +00:00
state - > stage = SAVEFILE_WRITE ;
2005-01-16 22:22:13 +00:00
state - > req - > async . fn = savefile_handler ;
state - > req - > async . private = c ;
2005-01-16 21:58:28 +00:00
talloc_free ( state - > io_open ) ;
2005-01-12 11:43:18 +00:00
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
*/
2005-01-31 08:30:44 +00:00
static NTSTATUS savefile_write ( struct composite_context * c ,
2005-01-12 11:43:18 +00:00
struct smb_composite_savefile * io )
{
2005-09-26 11:47:55 +00:00
struct savefile_state * state = talloc_get_type ( c - > private_data , struct savefile_state ) ;
2005-01-16 22:22:13 +00:00
struct smbcli_tree * tree = state - > req - > tree ;
2005-01-12 11:43:18 +00:00
NTSTATUS status ;
uint32_t max_xmit = tree - > session - > transport - > negotiate . max_xmit ;
2005-01-16 22:22:13 +00:00
status = smb_raw_write_recv ( state - > req , state - > io_write ) ;
2005-01-12 11:43:18 +00:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2005-01-16 21:58:28 +00:00
state - > total_written + = state - > io_write - > writex . out . nwritten ;
2005-01-12 11:43:18 +00:00
/* we might be done */
2005-01-16 21:58:28 +00:00
if ( state - > io_write - > writex . out . nwritten ! = state - > io_write - > writex . in . count | |
2005-01-12 11:43:18 +00:00
state - > total_written = = io - > in . size ) {
2006-03-12 22:48:25 +00:00
return setup_close ( c , tree , state - > io_write - > writex . in . file . fnum ) ;
2005-01-12 11:43:18 +00:00
}
/* setup for the next write */
2005-01-16 21:58:28 +00:00
state - > io_write - > writex . in . offset = state - > total_written ;
state - > io_write - > writex . in . count = MIN ( max_xmit - 100 ,
io - > in . size - state - > total_written ) ;
state - > io_write - > writex . in . data = io - > in . data + state - > total_written ;
2005-01-12 11:43:18 +00:00
2005-01-16 22:22:13 +00:00
state - > req = smb_raw_write_send ( tree , state - > io_write ) ;
NT_STATUS_HAVE_NO_MEMORY ( state - > req ) ;
2005-01-12 11:43:18 +00:00
/* call the handler again when the write is done */
2005-01-16 22:22:13 +00:00
state - > req - > async . fn = savefile_handler ;
state - > req - > async . private = c ;
2005-01-12 11:43:18 +00:00
return NT_STATUS_OK ;
}
/*
called when the close is done , check the status and cleanup
*/
2005-01-31 08:30:44 +00:00
static NTSTATUS savefile_close ( struct composite_context * c ,
2005-01-12 11:43:18 +00:00
struct smb_composite_savefile * io )
{
2005-09-26 11:47:55 +00:00
struct savefile_state * state = talloc_get_type ( c - > private_data , struct savefile_state ) ;
2005-01-16 21:58:28 +00:00
NTSTATUS status ;
2005-01-12 11:43:18 +00:00
2005-01-16 22:22:13 +00:00
status = smbcli_request_simple_recv ( state - > req ) ;
2005-01-12 11:43:18 +00:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
if ( state - > total_written ! = io - > in . size ) {
return NT_STATUS_DISK_FULL ;
}
2005-09-26 11:47:55 +00:00
c - > state = COMPOSITE_STATE_DONE ;
2005-01-12 11:43:18 +00:00
return NT_STATUS_OK ;
}
/*
handler for completion of a sub - request in savefile
*/
static void savefile_handler ( struct smbcli_request * req )
{
2007-09-07 13:31:15 +00:00
struct composite_context * c = ( struct composite_context * ) req - > async . private ;
2005-09-26 11:47:55 +00:00
struct savefile_state * state = talloc_get_type ( c - > private_data , struct savefile_state ) ;
2005-01-12 11:43:18 +00:00
/* when this handler is called, the stage indicates what
call has just finished */
2005-01-22 02:51:39 +00:00
switch ( state - > stage ) {
2005-01-12 11:43:18 +00:00
case SAVEFILE_OPEN :
2005-01-23 08:16:16 +00:00
c - > status = savefile_open ( c , state - > io ) ;
2005-01-12 11:43:18 +00:00
break ;
case SAVEFILE_WRITE :
2005-01-23 08:16:16 +00:00
c - > status = savefile_write ( c , state - > io ) ;
2005-01-12 11:43:18 +00:00
break ;
case SAVEFILE_CLOSE :
2005-01-23 08:16:16 +00:00
c - > status = savefile_close ( c , state - > io ) ;
2005-01-12 11:43:18 +00:00
break ;
}
2005-01-23 08:16:16 +00:00
if ( ! NT_STATUS_IS_OK ( c - > status ) ) {
2005-09-26 11:47:55 +00:00
c - > state = COMPOSITE_STATE_ERROR ;
2005-01-23 08:16:16 +00:00
}
2005-09-26 11:47:55 +00:00
if ( c - > state > = COMPOSITE_STATE_DONE & &
2005-01-23 08:16:16 +00:00
c - > async . fn ) {
c - > async . fn ( c ) ;
2005-01-12 11:43:18 +00:00
}
}
/*
composite savefile call - does an openx followed by a number of writex calls ,
followed by a close
*/
2005-01-31 08:30:44 +00:00
struct composite_context * smb_composite_savefile_send ( struct smbcli_tree * tree ,
2005-09-26 11:47:55 +00:00
struct smb_composite_savefile * io )
2005-01-12 11:43:18 +00:00
{
2005-01-31 08:30:44 +00:00
struct composite_context * c ;
2005-01-12 11:43:18 +00:00
struct savefile_state * state ;
2005-01-16 21:58:28 +00:00
union smb_open * io_open ;
2005-01-12 11:43:18 +00:00
2005-01-31 08:30:44 +00:00
c = talloc_zero ( tree , struct composite_context ) ;
2005-01-12 11:43:18 +00:00
if ( c = = NULL ) goto failed ;
2005-09-26 11:47:55 +00:00
c - > state = COMPOSITE_STATE_IN_PROGRESS ;
2005-01-15 10:29:43 +00:00
c - > event_ctx = tree - > session - > transport - > socket - > event . ctx ;
2005-01-12 11:43:18 +00:00
state = talloc ( c , struct savefile_state ) ;
if ( state = = NULL ) goto failed ;
2005-01-22 02:51:39 +00:00
state - > stage = SAVEFILE_OPEN ;
2005-01-12 11:43:18 +00:00
state - > total_written = 0 ;
2005-01-16 21:58:28 +00:00
state - > io = io ;
2005-01-12 11:43:18 +00:00
/* 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 ;
2005-01-16 21:58:28 +00:00
state - > io_open = io_open ;
2005-01-12 11:43:18 +00:00
/* send the open on its way */
2005-01-16 22:22:13 +00:00
state - > req = smb_raw_open_send ( tree , io_open ) ;
if ( state - > req = = NULL ) goto failed ;
2005-01-12 11:43:18 +00:00
/* setup the callback handler */
2005-01-16 22:22:13 +00:00
state - > req - > async . fn = savefile_handler ;
state - > req - > async . private = c ;
2005-09-26 11:47:55 +00:00
c - > private_data = state ;
2005-01-12 11:43:18 +00:00
return c ;
failed :
talloc_free ( c ) ;
return NULL ;
}
/*
composite savefile call - recv side
*/
2005-01-31 08:30:44 +00:00
NTSTATUS smb_composite_savefile_recv ( struct composite_context * c )
2005-01-12 11:43:18 +00:00
{
NTSTATUS status ;
2005-01-31 08:30:44 +00:00
status = composite_wait ( c ) ;
2005-01-12 11:43:18 +00:00
talloc_free ( c ) ;
return status ;
}
/*
composite savefile call - sync interface
*/
NTSTATUS smb_composite_savefile ( struct smbcli_tree * tree ,
struct smb_composite_savefile * io )
{
2005-01-31 08:30:44 +00:00
struct composite_context * c = smb_composite_savefile_send ( tree , io ) ;
2005-01-12 11:43:18 +00:00
return smb_composite_savefile_recv ( c ) ;
}