2000-04-25 18:04:06 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2000-04-25 18:04:06 +04:00
client file read / write routines
Copyright ( C ) Andrew Tridgell 1994 - 1998
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 .
*/
# define NO_SYSLOG
# include "includes.h"
/****************************************************************************
2001-08-25 00:20:08 +04:00
Issue a single SMBread and don ' t wait for a reply .
2000-04-25 18:04:06 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-29 04:22:22 +04:00
static BOOL cli_issue_read ( struct cli_state * cli , int fnum , off_t offset ,
2000-04-25 18:04:06 +04:00
size_t size , int i )
{
2002-12-19 23:26:44 +03:00
BOOL bigoffset = False ;
2000-04-25 18:04:06 +04:00
memset ( cli - > outbuf , ' \0 ' , smb_size ) ;
memset ( cli - > inbuf , ' \0 ' , smb_size ) ;
2002-12-19 23:26:44 +03:00
if ( ( SMB_BIG_UINT ) offset > > 32 )
bigoffset = True ;
set_message ( cli - > outbuf , bigoffset ? 12 : 10 , 0 , True ) ;
2000-04-25 18:04:06 +04:00
2002-01-11 22:10:25 +03:00
SCVAL ( cli - > outbuf , smb_com , SMBreadX ) ;
2000-04-25 18:04:06 +04:00
SSVAL ( cli - > outbuf , smb_tid , cli - > cnum ) ;
cli_setup_packet ( cli ) ;
2002-01-11 22:10:25 +03:00
SCVAL ( cli - > outbuf , smb_vwv0 , 0xFF ) ;
2000-04-25 18:04:06 +04:00
SSVAL ( cli - > outbuf , smb_vwv2 , fnum ) ;
SIVAL ( cli - > outbuf , smb_vwv3 , offset ) ;
SSVAL ( cli - > outbuf , smb_vwv5 , size ) ;
SSVAL ( cli - > outbuf , smb_vwv6 , size ) ;
SSVAL ( cli - > outbuf , smb_mid , cli - > mid + i ) ;
2002-12-19 23:26:44 +03:00
if ( bigoffset )
SIVAL ( cli - > outbuf , smb_vwv10 , ( offset > > 32 ) & 0xffffffff ) ;
2001-06-29 04:22:22 +04:00
return cli_send_smb ( cli ) ;
2000-04-25 18:04:06 +04:00
}
2001-06-22 05:09:40 +04:00
/****************************************************************************
2001-06-29 04:22:22 +04:00
Read size bytes at offset offset using SMBreadX .
2001-06-22 05:09:40 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-29 04:22:22 +04:00
ssize_t cli_read ( struct cli_state * cli , int fnum , char * buf , off_t offset , size_t size )
2001-06-22 05:09:40 +04:00
{
char * p ;
int size2 ;
2001-06-29 04:22:22 +04:00
int readsize ;
ssize_t total = 0 ;
2001-06-22 05:09:40 +04:00
if ( size = = 0 )
return 0 ;
2001-06-29 04:22:22 +04:00
/*
* Set readsize to the maximum size we can handle in one readX ,
* rounded down to a multiple of 1024.
*/
2001-06-22 05:09:40 +04:00
2001-06-29 04:22:22 +04:00
readsize = ( cli - > max_xmit - ( smb_size + 32 ) ) & ~ 1023 ;
2001-06-22 05:09:40 +04:00
2001-06-29 04:22:22 +04:00
while ( total < size ) {
2001-07-01 17:18:35 +04:00
readsize = MIN ( readsize , size - total ) ;
2001-06-22 05:09:40 +04:00
2001-06-29 04:22:22 +04:00
/* Issue a read and receive a reply */
2001-06-22 05:09:40 +04:00
2001-06-29 04:22:22 +04:00
if ( ! cli_issue_read ( cli , fnum , offset , readsize , 0 ) )
return - 1 ;
2001-06-22 04:42:53 +04:00
2001-06-29 04:22:22 +04:00
if ( ! cli_receive_smb ( cli ) )
return - 1 ;
2000-04-25 18:04:06 +04:00
2001-08-10 10:00:33 +04:00
/* Check for error. Make sure to check for DOS and NT
errors . */
2000-04-25 18:04:06 +04:00
2001-08-10 10:00:33 +04:00
if ( cli_is_error ( cli ) ) {
2002-11-27 22:11:46 +03:00
BOOL recoverable_error = False ;
2001-08-27 21:52:23 +04:00
NTSTATUS status = NT_STATUS_OK ;
2001-08-10 10:00:33 +04:00
uint8 eclass = 0 ;
2001-08-27 21:52:23 +04:00
uint32 ecode = 0 ;
2001-08-10 10:00:33 +04:00
if ( cli_is_nt_error ( cli ) )
status = cli_nt_error ( cli ) ;
else
2001-08-27 21:52:23 +04:00
cli_dos_error ( cli , & eclass , & ecode ) ;
2001-08-10 10:00:33 +04:00
2002-11-27 22:11:46 +03:00
/*
* ERRDOS ERRmoredata or STATUS_MORE_ENRTIES is a
* recoverable error , plus we have valid data in the
* packet so don ' t error out here .
*/
2001-08-27 21:52:23 +04:00
if ( ( eclass = = ERRDOS & & ecode = = ERRmoredata ) | |
NT_STATUS_V ( status ) = = NT_STATUS_V ( STATUS_MORE_ENTRIES ) )
2002-11-27 22:11:46 +03:00
recoverable_error = True ;
if ( ! recoverable_error )
2001-08-10 10:00:33 +04:00
return - 1 ;
2000-04-25 18:04:06 +04:00
}
size2 = SVAL ( cli - > inbuf , smb_vwv5 ) ;
2001-06-29 04:22:22 +04:00
if ( size2 > readsize ) {
DEBUG ( 5 , ( " server returned more than we wanted! \n " ) ) ;
2000-04-25 18:04:06 +04:00
return - 1 ;
2001-06-29 04:22:22 +04:00
} else if ( size2 < 0 ) {
DEBUG ( 5 , ( " read return < 0! \n " ) ) ;
2000-04-25 18:04:06 +04:00
return - 1 ;
}
2001-06-29 04:22:22 +04:00
/* Copy data into buffer */
2000-04-25 18:04:06 +04:00
p = smb_base ( cli - > inbuf ) + SVAL ( cli - > inbuf , smb_vwv6 ) ;
2001-06-29 04:22:22 +04:00
memcpy ( buf + total , p , size2 ) ;
2000-04-25 18:04:06 +04:00
2001-06-29 04:22:22 +04:00
total + = size2 ;
offset + = size2 ;
2000-04-25 18:04:06 +04:00
2001-06-29 04:22:22 +04:00
/*
* If the server returned less than we asked for we ' re at EOF .
*/
2000-04-25 18:04:06 +04:00
2001-06-29 04:22:22 +04:00
if ( size2 < readsize )
break ;
2000-04-25 18:04:06 +04:00
}
2001-06-29 04:22:22 +04:00
2000-04-25 18:04:06 +04:00
return total ;
}
2002-09-25 19:19:00 +04:00
#if 0 /* relies on client_receive_smb(), now a static in libsmb/clientgen.c */
2002-07-15 14:35:28 +04:00
/* This call is INCOMPATIBLE with SMB signing. If you remove the #if 0
you must fix ensure you don ' t attempt to sign the packets - data
* will * be currupted */
/****************************************************************************
Issue a single SMBreadraw and don ' t wait for a reply .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL cli_issue_readraw ( struct cli_state * cli , int fnum , off_t offset ,
size_t size , int i )
{
if ( ! cli - > sign_info . use_smb_signing ) {
DEBUG ( 0 , ( " Cannot use readraw and SMB Signing \n " ) ) ;
return False ;
}
memset ( cli - > outbuf , ' \0 ' , smb_size ) ;
memset ( cli - > inbuf , ' \0 ' , smb_size ) ;
set_message ( cli - > outbuf , 10 , 0 , True ) ;
SCVAL ( cli - > outbuf , smb_com , SMBreadbraw ) ;
SSVAL ( cli - > outbuf , smb_tid , cli - > cnum ) ;
cli_setup_packet ( cli ) ;
SSVAL ( cli - > outbuf , smb_vwv0 , fnum ) ;
SIVAL ( cli - > outbuf , smb_vwv1 , offset ) ;
SSVAL ( cli - > outbuf , smb_vwv2 , size ) ;
SSVAL ( cli - > outbuf , smb_vwv3 , size ) ;
SSVAL ( cli - > outbuf , smb_mid , cli - > mid + i ) ;
return cli_send_smb ( cli ) ;
}
2001-08-25 00:20:08 +04:00
/****************************************************************************
Tester for the readraw call .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t cli_readraw ( struct cli_state * cli , int fnum , char * buf , off_t offset , size_t size )
{
char * p ;
int size2 ;
size_t readsize ;
ssize_t total = 0 ;
if ( size = = 0 )
return 0 ;
/*
* Set readsize to the maximum size we can handle in one readraw .
*/
readsize = 0xFFFF ;
while ( total < size ) {
readsize = MIN ( readsize , size - total ) ;
/* Issue a read and receive a reply */
if ( ! cli_issue_readraw ( cli , fnum , offset , readsize , 0 ) )
return - 1 ;
if ( ! client_receive_smb ( cli - > fd , cli - > inbuf , cli - > timeout ) )
return - 1 ;
size2 = smb_len ( cli - > inbuf ) ;
if ( size2 > readsize ) {
DEBUG ( 5 , ( " server returned more than we wanted! \n " ) ) ;
return - 1 ;
} else if ( size2 < 0 ) {
DEBUG ( 5 , ( " read return < 0! \n " ) ) ;
return - 1 ;
}
/* Copy data into buffer */
if ( size2 ) {
p = cli - > inbuf + 4 ;
memcpy ( buf + total , p , size2 ) ;
}
total + = size2 ;
offset + = size2 ;
/*
* If the server returned less than we asked for we ' re at EOF .
*/
if ( size2 < readsize )
break ;
}
return total ;
}
2002-07-15 14:35:28 +04:00
# endif
2000-04-25 18:04:06 +04:00
/****************************************************************************
issue a single SMBwrite and don ' t wait for a reply
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-29 04:22:22 +04:00
2003-01-03 11:28:12 +03:00
static BOOL cli_issue_write ( struct cli_state * cli , int fnum , off_t offset ,
uint16 mode , const char * buf ,
2000-04-25 18:04:06 +04:00
size_t size , int i )
{
char * p ;
2002-12-30 09:12:13 +03:00
BOOL bigoffset = False ;
2000-04-25 18:04:06 +04:00
2002-03-20 04:43:06 +03:00
if ( size > cli - > bufsize ) {
cli - > outbuf = realloc ( cli - > outbuf , size + 1024 ) ;
cli - > inbuf = realloc ( cli - > inbuf , size + 1024 ) ;
if ( cli - > outbuf = = NULL | | cli - > inbuf = = NULL )
return False ;
cli - > bufsize = size + 1024 ;
}
2000-04-25 18:04:06 +04:00
memset ( cli - > outbuf , ' \0 ' , smb_size ) ;
memset ( cli - > inbuf , ' \0 ' , smb_size ) ;
2002-12-30 09:12:13 +03:00
if ( ( SMB_BIG_UINT ) offset > > 32 )
bigoffset = True ;
if ( bigoffset )
2001-06-21 13:10:42 +04:00
set_message ( cli - > outbuf , 14 , 0 , True ) ;
2001-06-05 12:17:16 +04:00
else
2001-06-21 13:10:42 +04:00
set_message ( cli - > outbuf , 12 , 0 , True ) ;
2000-04-25 18:04:06 +04:00
2002-01-11 22:10:25 +03:00
SCVAL ( cli - > outbuf , smb_com , SMBwriteX ) ;
2000-04-25 18:04:06 +04:00
SSVAL ( cli - > outbuf , smb_tid , cli - > cnum ) ;
cli_setup_packet ( cli ) ;
2002-01-11 22:10:25 +03:00
SCVAL ( cli - > outbuf , smb_vwv0 , 0xFF ) ;
2000-04-25 18:04:06 +04:00
SSVAL ( cli - > outbuf , smb_vwv2 , fnum ) ;
SIVAL ( cli - > outbuf , smb_vwv3 , offset ) ;
2002-12-30 09:12:13 +03:00
SIVAL ( cli - > outbuf , smb_vwv5 , 0 ) ;
2000-04-25 18:04:06 +04:00
SSVAL ( cli - > outbuf , smb_vwv7 , mode ) ;
2003-01-15 21:57:41 +03:00
SSVAL ( cli - > outbuf , smb_vwv8 , ( mode & 0x0008 ) ? size : 0 ) ;
2002-12-30 09:12:13 +03:00
/*
2003-01-15 21:57:41 +03:00
* According to CIFS - TR - 1 p00 , this following field should only
* be set if CAP_LARGE_WRITEX is set . We should check this
* locally . However , this check might already have been
* done by our callers .
2002-12-30 09:12:13 +03:00
*/
2001-06-05 12:17:16 +04:00
SSVAL ( cli - > outbuf , smb_vwv9 , ( ( size > > 16 ) & 1 ) ) ;
2000-04-25 18:04:06 +04:00
SSVAL ( cli - > outbuf , smb_vwv10 , size ) ;
SSVAL ( cli - > outbuf , smb_vwv11 ,
smb_buf ( cli - > outbuf ) - smb_base ( cli - > outbuf ) ) ;
2002-12-30 09:12:13 +03:00
if ( bigoffset )
SIVAL ( cli - > outbuf , smb_vwv12 , ( offset > > 32 ) & 0xffffffff ) ;
2000-04-25 18:04:06 +04:00
p = smb_base ( cli - > outbuf ) + SVAL ( cli - > outbuf , smb_vwv11 ) ;
memcpy ( p , buf , size ) ;
2001-06-21 13:10:42 +04:00
cli_setup_bcc ( cli , p + size ) ;
2000-04-25 18:04:06 +04:00
SSVAL ( cli - > outbuf , smb_mid , cli - > mid + i ) ;
show_msg ( cli - > outbuf ) ;
2001-06-29 04:22:22 +04:00
return cli_send_smb ( cli ) ;
2000-04-25 18:04:06 +04:00
}
/****************************************************************************
write to a file
write_mode : 0x0001 disallow write cacheing
0x0002 return bytes remaining
0x0004 use raw named pipe protocol
0x0008 start of message mode named pipe protocol
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-29 04:22:22 +04:00
2000-04-25 18:04:06 +04:00
ssize_t cli_write ( struct cli_state * cli ,
int fnum , uint16 write_mode ,
2003-01-03 11:28:12 +03:00
const char * buf , off_t offset , size_t size )
2000-04-25 18:04:06 +04:00
{
int bwritten = 0 ;
int issued = 0 ;
int received = 0 ;
2004-09-17 04:49:41 +04:00
int mpx = 1 ;
2003-08-08 21:08:35 +04:00
int block = cli - > max_xmit - ( smb_size + 32 ) ;
2000-04-25 18:04:06 +04:00
int blocks = ( size + ( block - 1 ) ) / block ;
2004-09-17 04:53:17 +04:00
if ( cli - > max_mux > 1 ) {
2004-09-17 04:49:41 +04:00
mpx = cli - > max_mux - 1 ;
2004-09-17 04:53:17 +04:00
} else {
mpx = 1 ;
2004-09-17 04:49:41 +04:00
}
2000-04-25 18:04:06 +04:00
while ( received < blocks ) {
2001-06-29 04:22:22 +04:00
while ( ( issued - received < mpx ) & & ( issued < blocks ) ) {
2000-04-25 18:04:06 +04:00
int bsent = issued * block ;
int size1 = MIN ( block , size - bsent ) ;
2001-06-29 04:22:22 +04:00
if ( ! cli_issue_write ( cli , fnum , offset + bsent ,
2000-04-25 18:04:06 +04:00
write_mode ,
buf + bsent ,
2001-06-29 04:22:22 +04:00
size1 , issued ) )
return - 1 ;
2000-04-25 18:04:06 +04:00
issued + + ;
}
if ( ! cli_receive_smb ( cli ) )
return bwritten ;
received + + ;
2001-09-05 15:32:59 +04:00
if ( cli_is_error ( cli ) )
2000-04-25 18:04:06 +04:00
break ;
bwritten + = SVAL ( cli - > inbuf , smb_vwv2 ) ;
2002-03-20 04:43:06 +03:00
bwritten + = ( ( ( int ) ( SVAL ( cli - > inbuf , smb_vwv4 ) ) ) > > 16 ) ;
2000-04-25 18:04:06 +04:00
}
while ( received < issued & & cli_receive_smb ( cli ) )
received + + ;
return bwritten ;
}
/****************************************************************************
write to a file using a SMBwrite and not bypassing 0 byte writes
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-29 04:22:22 +04:00
2000-04-25 18:04:06 +04:00
ssize_t cli_smbwrite ( struct cli_state * cli ,
int fnum , char * buf , off_t offset , size_t size1 )
{
char * p ;
ssize_t total = 0 ;
do {
size_t size = MIN ( size1 , cli - > max_xmit - 48 ) ;
memset ( cli - > outbuf , ' \0 ' , smb_size ) ;
memset ( cli - > inbuf , ' \0 ' , smb_size ) ;
2001-06-21 13:10:42 +04:00
set_message ( cli - > outbuf , 5 , 0 , True ) ;
2000-04-25 18:04:06 +04:00
2002-01-11 22:10:25 +03:00
SCVAL ( cli - > outbuf , smb_com , SMBwrite ) ;
2000-04-25 18:04:06 +04:00
SSVAL ( cli - > outbuf , smb_tid , cli - > cnum ) ;
cli_setup_packet ( cli ) ;
SSVAL ( cli - > outbuf , smb_vwv0 , fnum ) ;
SSVAL ( cli - > outbuf , smb_vwv1 , size ) ;
SIVAL ( cli - > outbuf , smb_vwv2 , offset ) ;
SSVAL ( cli - > outbuf , smb_vwv4 , 0 ) ;
p = smb_buf ( cli - > outbuf ) ;
* p + + = 1 ;
2001-06-21 13:10:42 +04:00
SSVAL ( p , 0 , size ) ; p + = 2 ;
memcpy ( p , buf , size ) ; p + = size ;
cli_setup_bcc ( cli , p ) ;
2000-04-25 18:04:06 +04:00
2001-06-29 04:22:22 +04:00
if ( ! cli_send_smb ( cli ) )
return - 1 ;
if ( ! cli_receive_smb ( cli ) )
2000-04-25 18:04:06 +04:00
return - 1 ;
2001-09-05 15:32:59 +04:00
if ( cli_is_error ( cli ) )
2000-04-25 18:04:06 +04:00
return - 1 ;
size = SVAL ( cli - > inbuf , smb_vwv0 ) ;
2001-06-29 04:22:22 +04:00
if ( size = = 0 )
break ;
2000-04-25 18:04:06 +04:00
size1 - = size ;
total + = size ;
2002-03-20 04:47:31 +03:00
offset + = size ;
2000-04-25 18:04:06 +04:00
} while ( size1 ) ;
return total ;
}