2003-08-13 05:53:07 +04:00
/*
Unix SMB / CIFS implementation .
client file read / write routines
Copyright ( C ) Andrew Tridgell 1994 - 1998
Copyright ( C ) James Myers 2003
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 0213 9 , USA .
*/
# include "includes.h"
# define SETUP_REQUEST(cmd, wct, buflen) do { \
2004-08-04 17:23:35 +04:00
req = smbcli_request_setup ( tree , cmd , wct , buflen ) ; \
2003-08-13 05:53:07 +04:00
if ( ! req ) return NULL ; \
} while ( 0 )
/****************************************************************************
low level read operation ( async send )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-08-04 17:23:35 +04:00
struct smbcli_request * smb_raw_read_send ( struct smbcli_tree * tree , union smb_read * parms )
2003-08-13 05:53:07 +04:00
{
BOOL bigoffset = False ;
2004-08-21 05:54:46 +04:00
struct smbcli_request * req = NULL ;
2003-08-13 05:53:07 +04:00
switch ( parms - > generic . level ) {
case RAW_READ_READBRAW :
2004-03-08 10:11:13 +03:00
if ( tree - > session - > transport - > negotiate . capabilities & CAP_LARGE_FILES ) {
2003-08-13 05:53:07 +04:00
bigoffset = True ;
}
SETUP_REQUEST ( SMBreadbraw , bigoffset ? 10 : 8 , 0 ) ;
SSVAL ( req - > out . vwv , VWV ( 0 ) , parms - > readbraw . in . fnum ) ;
SIVAL ( req - > out . vwv , VWV ( 1 ) , parms - > readbraw . in . offset ) ;
SSVAL ( req - > out . vwv , VWV ( 3 ) , parms - > readbraw . in . maxcnt ) ;
SSVAL ( req - > out . vwv , VWV ( 4 ) , parms - > readbraw . in . mincnt ) ;
SIVAL ( req - > out . vwv , VWV ( 5 ) , parms - > readbraw . in . timeout ) ;
SSVAL ( req - > out . vwv , VWV ( 7 ) , 0 ) ; /* reserved */
if ( bigoffset ) {
SIVAL ( req - > out . vwv , VWV ( 8 ) , parms - > readbraw . in . offset > > 32 ) ;
}
break ;
case RAW_READ_LOCKREAD :
SETUP_REQUEST ( SMBlockread , 5 , 0 ) ;
SSVAL ( req - > out . vwv , VWV ( 0 ) , parms - > lockread . in . fnum ) ;
SSVAL ( req - > out . vwv , VWV ( 1 ) , parms - > lockread . in . count ) ;
SIVAL ( req - > out . vwv , VWV ( 2 ) , parms - > lockread . in . offset ) ;
SSVAL ( req - > out . vwv , VWV ( 4 ) , parms - > lockread . in . remaining ) ;
break ;
case RAW_READ_READ :
SETUP_REQUEST ( SMBread , 5 , 0 ) ;
SSVAL ( req - > out . vwv , VWV ( 0 ) , parms - > read . in . fnum ) ;
SSVAL ( req - > out . vwv , VWV ( 1 ) , parms - > read . in . count ) ;
SIVAL ( req - > out . vwv , VWV ( 2 ) , parms - > read . in . offset ) ;
SSVAL ( req - > out . vwv , VWV ( 4 ) , parms - > read . in . remaining ) ;
break ;
case RAW_READ_READX :
2004-03-08 10:11:13 +03:00
if ( tree - > session - > transport - > negotiate . capabilities & CAP_LARGE_FILES ) {
2003-08-13 05:53:07 +04:00
bigoffset = True ;
}
SETUP_REQUEST ( SMBreadX , bigoffset ? 12 : 10 , 0 ) ;
SSVAL ( req - > out . vwv , VWV ( 0 ) , 0xFF ) ;
SSVAL ( req - > out . vwv , VWV ( 1 ) , 0 ) ;
SSVAL ( req - > out . vwv , VWV ( 2 ) , parms - > readx . in . fnum ) ;
SIVAL ( req - > out . vwv , VWV ( 3 ) , parms - > readx . in . offset ) ;
2004-10-26 09:34:35 +04:00
SSVAL ( req - > out . vwv , VWV ( 5 ) , parms - > readx . in . maxcnt & 0xFFFF ) ;
2003-08-13 05:53:07 +04:00
SSVAL ( req - > out . vwv , VWV ( 6 ) , parms - > readx . in . mincnt ) ;
2004-10-26 09:34:35 +04:00
SIVAL ( req - > out . vwv , VWV ( 7 ) , parms - > readx . in . maxcnt > > 16 ) ;
2003-08-13 05:53:07 +04:00
SSVAL ( req - > out . vwv , VWV ( 9 ) , parms - > readx . in . remaining ) ;
if ( bigoffset ) {
SIVAL ( req - > out . vwv , VWV ( 10 ) , parms - > readx . in . offset > > 32 ) ;
}
break ;
}
2004-08-04 17:23:35 +04:00
if ( ! smbcli_request_send ( req ) ) {
smbcli_request_destroy ( req ) ;
2003-08-13 05:53:07 +04:00
return NULL ;
}
/* the transport layer needs to know that a readbraw is pending
and handle receives a little differently */
if ( parms - > generic . level = = RAW_READ_READBRAW ) {
tree - > session - > transport - > readbraw_pending = 1 ;
}
return req ;
}
/****************************************************************************
low level read operation ( async recv )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-08-04 17:23:35 +04:00
NTSTATUS smb_raw_read_recv ( struct smbcli_request * req , union smb_read * parms )
2003-08-13 05:53:07 +04:00
{
2004-08-04 17:23:35 +04:00
if ( ! smbcli_request_receive ( req ) | |
smbcli_request_is_error ( req ) ) {
2003-08-13 05:53:07 +04:00
goto failed ;
}
switch ( parms - > generic . level ) {
case RAW_READ_READBRAW :
parms - > readbraw . out . nread = req - > in . size - NBT_HDR_SIZE ;
if ( parms - > readbraw . out . nread >
MAX ( parms - > readx . in . mincnt , parms - > readx . in . maxcnt ) ) {
req - > status = NT_STATUS_BUFFER_TOO_SMALL ;
goto failed ;
}
memcpy ( parms - > readbraw . out . data , req - > in . buffer + NBT_HDR_SIZE , parms - > readbraw . out . nread ) ;
break ;
case RAW_READ_LOCKREAD :
2004-08-04 17:23:35 +04:00
SMBCLI_CHECK_WCT ( req , 5 ) ;
2003-08-13 05:53:07 +04:00
parms - > lockread . out . nread = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
if ( parms - > lockread . out . nread > parms - > lockread . in . count | |
2004-08-04 17:23:35 +04:00
! smbcli_raw_pull_data ( req , req - > in . data + 3 ,
2003-08-13 05:53:07 +04:00
parms - > lockread . out . nread , parms - > lockread . out . data ) ) {
req - > status = NT_STATUS_BUFFER_TOO_SMALL ;
}
break ;
case RAW_READ_READ :
/* there are 4 reserved words in the reply */
2004-08-04 17:23:35 +04:00
SMBCLI_CHECK_WCT ( req , 5 ) ;
2003-08-13 05:53:07 +04:00
parms - > read . out . nread = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
if ( parms - > read . out . nread > parms - > read . in . count | |
2004-08-04 17:23:35 +04:00
! smbcli_raw_pull_data ( req , req - > in . data + 3 ,
2003-08-13 05:53:07 +04:00
parms - > read . out . nread , parms - > read . out . data ) ) {
req - > status = NT_STATUS_BUFFER_TOO_SMALL ;
}
break ;
case RAW_READ_READX :
/* there are 5 reserved words in the reply */
2004-08-04 17:23:35 +04:00
SMBCLI_CHECK_WCT ( req , 12 ) ;
2003-08-13 05:53:07 +04:00
parms - > readx . out . remaining = SVAL ( req - > in . vwv , VWV ( 2 ) ) ;
parms - > readx . out . compaction_mode = SVAL ( req - > in . vwv , VWV ( 3 ) ) ;
parms - > readx . out . nread = SVAL ( req - > in . vwv , VWV ( 5 ) ) ;
if ( parms - > readx . out . nread > MAX ( parms - > readx . in . mincnt , parms - > readx . in . maxcnt ) | |
2004-08-04 17:23:35 +04:00
! smbcli_raw_pull_data ( req , req - > in . hdr + SVAL ( req - > in . vwv , VWV ( 6 ) ) ,
2003-08-13 05:53:07 +04:00
parms - > readx . out . nread ,
parms - > readx . out . data ) ) {
req - > status = NT_STATUS_BUFFER_TOO_SMALL ;
}
break ;
}
failed :
2004-08-04 17:23:35 +04:00
return smbcli_request_destroy ( req ) ;
2003-08-13 05:53:07 +04:00
}
/****************************************************************************
low level read operation ( sync interface )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-08-04 17:23:35 +04:00
NTSTATUS smb_raw_read ( struct smbcli_tree * tree , union smb_read * parms )
2003-08-13 05:53:07 +04:00
{
2004-08-04 17:23:35 +04:00
struct smbcli_request * req = smb_raw_read_send ( tree , parms ) ;
2003-08-13 05:53:07 +04:00
return smb_raw_read_recv ( req , parms ) ;
}
/****************************************************************************
raw write interface ( async send )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-08-04 17:23:35 +04:00
struct smbcli_request * smb_raw_write_send ( struct smbcli_tree * tree , union smb_write * parms )
2003-08-13 05:53:07 +04:00
{
BOOL bigoffset = False ;
2004-08-21 05:54:46 +04:00
struct smbcli_request * req = NULL ;
2003-08-13 05:53:07 +04:00
switch ( parms - > generic . level ) {
case RAW_WRITE_WRITEUNLOCK :
SETUP_REQUEST ( SMBwriteunlock , 5 , 3 + parms - > writeunlock . in . count ) ;
SSVAL ( req - > out . vwv , VWV ( 0 ) , parms - > writeunlock . in . fnum ) ;
SSVAL ( req - > out . vwv , VWV ( 1 ) , parms - > writeunlock . in . count ) ;
SIVAL ( req - > out . vwv , VWV ( 2 ) , parms - > writeunlock . in . offset ) ;
SSVAL ( req - > out . vwv , VWV ( 4 ) , parms - > writeunlock . in . remaining ) ;
SCVAL ( req - > out . data , 0 , SMB_DATA_BLOCK ) ;
SSVAL ( req - > out . data , 1 , parms - > writeunlock . in . count ) ;
if ( parms - > writeunlock . in . count > 0 ) {
memcpy ( req - > out . data + 3 , parms - > writeunlock . in . data ,
parms - > writeunlock . in . count ) ;
}
break ;
case RAW_WRITE_WRITE :
SETUP_REQUEST ( SMBwrite , 5 , 3 + parms - > write . in . count ) ;
SSVAL ( req - > out . vwv , VWV ( 0 ) , parms - > write . in . fnum ) ;
SSVAL ( req - > out . vwv , VWV ( 1 ) , parms - > write . in . count ) ;
SIVAL ( req - > out . vwv , VWV ( 2 ) , parms - > write . in . offset ) ;
SSVAL ( req - > out . vwv , VWV ( 4 ) , parms - > write . in . remaining ) ;
SCVAL ( req - > out . data , 0 , SMB_DATA_BLOCK ) ;
SSVAL ( req - > out . data , 1 , parms - > write . in . count ) ;
if ( parms - > write . in . count > 0 ) {
memcpy ( req - > out . data + 3 , parms - > write . in . data , parms - > write . in . count ) ;
}
break ;
case RAW_WRITE_WRITECLOSE :
SETUP_REQUEST ( SMBwriteclose , 6 , 1 + parms - > writeclose . in . count ) ;
SSVAL ( req - > out . vwv , VWV ( 0 ) , parms - > writeclose . in . fnum ) ;
SSVAL ( req - > out . vwv , VWV ( 1 ) , parms - > writeclose . in . count ) ;
SIVAL ( req - > out . vwv , VWV ( 2 ) , parms - > writeclose . in . offset ) ;
2004-04-11 00:18:22 +04:00
raw_push_dos_date3 ( tree - > session - > transport ,
req - > out . vwv , VWV ( 4 ) , parms - > writeclose . in . mtime ) ;
2003-08-13 05:53:07 +04:00
SCVAL ( req - > out . data , 0 , 0 ) ;
if ( parms - > writeclose . in . count > 0 ) {
memcpy ( req - > out . data + 1 , parms - > writeclose . in . data ,
parms - > writeclose . in . count ) ;
}
break ;
case RAW_WRITE_WRITEX :
2004-03-08 10:11:13 +03:00
if ( tree - > session - > transport - > negotiate . capabilities & CAP_LARGE_FILES ) {
2003-08-13 05:53:07 +04:00
bigoffset = True ;
}
SETUP_REQUEST ( SMBwriteX , bigoffset ? 14 : 12 , parms - > writex . in . count ) ;
SSVAL ( req - > out . vwv , VWV ( 0 ) , 0xFF ) ;
SSVAL ( req - > out . vwv , VWV ( 1 ) , 0 ) ;
SSVAL ( req - > out . vwv , VWV ( 2 ) , parms - > writex . in . fnum ) ;
SIVAL ( req - > out . vwv , VWV ( 3 ) , parms - > writex . in . offset ) ;
SIVAL ( req - > out . vwv , VWV ( 5 ) , 0 ) ; /* reserved */
SSVAL ( req - > out . vwv , VWV ( 7 ) , parms - > writex . in . wmode ) ;
SSVAL ( req - > out . vwv , VWV ( 8 ) , parms - > writex . in . remaining ) ;
2004-03-08 10:11:13 +03:00
SSVAL ( req - > out . vwv , VWV ( 9 ) , parms - > writex . in . count > > 16 ) ;
2003-08-13 05:53:07 +04:00
SSVAL ( req - > out . vwv , VWV ( 10 ) , parms - > writex . in . count ) ;
SSVAL ( req - > out . vwv , VWV ( 11 ) , PTR_DIFF ( req - > out . data , req - > out . hdr ) ) ;
if ( bigoffset ) {
SIVAL ( req - > out . vwv , VWV ( 12 ) , parms - > writex . in . offset > > 32 ) ;
}
if ( parms - > writex . in . count > 0 ) {
memcpy ( req - > out . data , parms - > writex . in . data , parms - > writex . in . count ) ;
}
break ;
case RAW_WRITE_SPLWRITE :
SETUP_REQUEST ( SMBsplwr , 1 , parms - > splwrite . in . count ) ;
SSVAL ( req - > out . vwv , VWV ( 0 ) , parms - > splwrite . in . fnum ) ;
if ( parms - > splwrite . in . count > 0 ) {
memcpy ( req - > out . data , parms - > splwrite . in . data , parms - > splwrite . in . count ) ;
}
break ;
}
2004-08-04 17:23:35 +04:00
if ( ! smbcli_request_send ( req ) ) {
smbcli_request_destroy ( req ) ;
2003-08-13 05:53:07 +04:00
return NULL ;
}
return req ;
}
/****************************************************************************
raw write interface ( async recv )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-08-04 17:23:35 +04:00
NTSTATUS smb_raw_write_recv ( struct smbcli_request * req , union smb_write * parms )
2003-08-13 05:53:07 +04:00
{
2004-08-04 17:23:35 +04:00
if ( ! smbcli_request_receive ( req ) | |
smbcli_request_is_error ( req ) ) {
2003-08-13 05:53:07 +04:00
goto failed ;
}
switch ( parms - > generic . level ) {
case RAW_WRITE_WRITEUNLOCK :
2004-08-04 17:23:35 +04:00
SMBCLI_CHECK_WCT ( req , 1 ) ;
2003-08-13 05:53:07 +04:00
parms - > writeunlock . out . nwritten = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
break ;
case RAW_WRITE_WRITE :
2004-08-04 17:23:35 +04:00
SMBCLI_CHECK_WCT ( req , 1 ) ;
2003-08-13 05:53:07 +04:00
parms - > write . out . nwritten = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
break ;
case RAW_WRITE_WRITECLOSE :
2004-08-04 17:23:35 +04:00
SMBCLI_CHECK_WCT ( req , 1 ) ;
2003-08-13 05:53:07 +04:00
parms - > writeclose . out . nwritten = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
break ;
case RAW_WRITE_WRITEX :
2004-08-04 17:23:35 +04:00
SMBCLI_CHECK_WCT ( req , 6 ) ;
2003-08-13 05:53:07 +04:00
parms - > writex . out . nwritten = SVAL ( req - > in . vwv , VWV ( 2 ) ) ;
parms - > writex . out . nwritten + = ( CVAL ( req - > in . vwv , VWV ( 4 ) ) < < 16 ) ;
parms - > writex . out . remaining = SVAL ( req - > in . vwv , VWV ( 3 ) ) ;
break ;
case RAW_WRITE_SPLWRITE :
break ;
}
failed :
2004-08-04 17:23:35 +04:00
return smbcli_request_destroy ( req ) ;
2003-08-13 05:53:07 +04:00
}
/****************************************************************************
raw write interface ( sync interface )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-08-04 17:23:35 +04:00
NTSTATUS smb_raw_write ( struct smbcli_tree * tree , union smb_write * parms )
2003-08-13 05:53:07 +04:00
{
2004-08-04 17:23:35 +04:00
struct smbcli_request * req = smb_raw_write_send ( tree , parms ) ;
2003-08-13 05:53:07 +04:00
return smb_raw_write_recv ( req , parms ) ;
}