1996-05-04 11:50:46 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1996-05-04 11:50:46 +04:00
Main SMB reply routines
1998-01-22 16:27:43 +03:00
Copyright ( C ) Andrew Tridgell 1992 - 1998
2001-09-16 10:35:35 +04:00
Copyright ( C ) Andrew Bartlett 2001
1996-05-04 11:50:46 +04:00
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 .
*/
/*
This file handles most of the reply_ calls that the server
makes to handle specific protocols
*/
# include "includes.h"
/* look in server.c for some explanation of these variables */
extern int Protocol ;
1997-02-28 23:39:36 +03:00
extern int max_send ;
extern int max_recv ;
1996-05-04 11:50:46 +04:00
extern char magic_char ;
extern BOOL case_sensitive ;
1997-01-13 22:41:08 +03:00
extern BOOL case_preserve ;
1997-02-12 01:53:29 +03:00
extern BOOL short_case_preserve ;
1997-09-30 06:38:19 +04:00
extern int global_oplock_break ;
1999-12-13 16:27:58 +03:00
unsigned int smb_echo_count = 0 ;
1996-05-04 11:50:46 +04:00
2001-09-26 17:55:59 +04:00
extern BOOL global_encrypted_passwords_negotiated ;
2001-09-16 10:35:35 +04:00
2003-08-13 07:28:06 +04:00
/****************************************************************************
Ensure we check the path in the same way as W2K .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS check_path_syntax ( const char * name )
{
while ( * name = = ' \\ ' )
name + + ;
if ( strequal ( name , " . " ) )
return NT_STATUS_OBJECT_NAME_INVALID ;
else if ( strequal ( name , " .. " ) )
return NT_STATUS_OBJECT_PATH_SYNTAX_BAD ;
return NT_STATUS_OK ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
2003-06-13 21:49:03 +04:00
Reply to a special message .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
1996-05-04 11:50:46 +04:00
int reply_special ( char * inbuf , char * outbuf )
{
1997-09-18 11:05:43 +04:00
int outsize = 4 ;
int msg_type = CVAL ( inbuf , 0 ) ;
int msg_flags = CVAL ( inbuf , 1 ) ;
pstring name1 , name2 ;
1997-10-28 09:07:07 +03:00
char name_type = 0 ;
1997-09-18 11:05:43 +04:00
2002-08-17 19:27:10 +04:00
static BOOL already_got_session = False ;
1997-09-18 11:05:43 +04:00
* name1 = * name2 = 0 ;
1999-12-13 16:27:58 +03:00
memset ( outbuf , ' \0 ' , smb_size ) ;
1998-08-04 05:01:26 +04:00
1997-09-18 11:05:43 +04:00
smb_setlen ( outbuf , 0 ) ;
switch ( msg_type ) {
1997-10-28 09:07:07 +03:00
case 0x81 : /* session request */
2002-08-17 19:27:10 +04:00
if ( already_got_session ) {
exit_server ( " multiple session request not permitted " ) ;
}
2002-01-11 22:10:25 +03:00
SCVAL ( outbuf , 0 , 0x82 ) ;
SCVAL ( outbuf , 3 , 0 ) ;
1997-10-28 09:07:07 +03:00
if ( name_len ( inbuf + 4 ) > 50 | |
name_len ( inbuf + 4 + name_len ( inbuf + 4 ) ) > 50 ) {
DEBUG ( 0 , ( " Invalid name length in session request \n " ) ) ;
return ( 0 ) ;
}
name_extract ( inbuf , 4 , name1 ) ;
2003-07-27 07:29:40 +04:00
name_type = name_extract ( inbuf , 4 + name_len ( inbuf + 4 ) , name2 ) ;
1997-09-18 11:05:43 +04:00
DEBUG ( 2 , ( " netbios connect: name1=%s name2=%s \n " ,
name1 , name2 ) ) ;
1997-09-26 22:55:29 +04:00
2003-03-18 12:52:55 +03:00
set_local_machine_name ( name1 , True ) ;
set_remote_machine_name ( name2 , True ) ;
1997-09-26 22:55:29 +04:00
2003-07-27 07:29:40 +04:00
DEBUG ( 2 , ( " netbios connect: local=%s remote=%s, name type = %x \n " ,
get_local_machine_name ( ) , get_remote_machine_name ( ) ,
name_type ) ) ;
2001-06-24 00:01:23 +04:00
1997-10-28 09:07:07 +03:00
if ( name_type = = ' R ' ) {
/* We are being asked for a pathworks session ---
no thanks ! */
2002-01-11 22:10:25 +03:00
SCVAL ( outbuf , 0 , 0x83 ) ;
1997-10-28 09:07:07 +03:00
break ;
}
1997-09-26 22:55:29 +04:00
2001-01-24 01:13:41 +03:00
/* only add the client's machine name to the list
of possibly valid usernames if we are operating
in share mode security */
if ( lp_security ( ) = = SEC_SHARE ) {
2002-08-17 19:27:10 +04:00
add_session_user ( get_remote_machine_name ( ) ) ;
2001-01-24 01:13:41 +03:00
}
1997-09-26 22:55:29 +04:00
1997-10-28 09:07:07 +03:00
reload_services ( True ) ;
reopen_logs ( ) ;
1997-09-26 22:55:29 +04:00
2002-09-25 19:19:00 +04:00
claim_connection ( NULL , " " , 0 , True , FLAG_MSG_GENERAL | FLAG_MSG_SMBD ) ;
1998-03-15 06:06:50 +03:00
2002-08-17 19:27:10 +04:00
already_got_session = True ;
1997-10-28 09:07:07 +03:00
break ;
1997-09-18 11:05:43 +04:00
case 0x89 : /* session keepalive request
( some old clients produce this ? ) */
2002-01-11 22:10:25 +03:00
SCVAL ( outbuf , 0 , SMBkeepalive ) ;
SCVAL ( outbuf , 3 , 0 ) ;
1997-09-18 11:05:43 +04:00
break ;
case 0x82 : /* positive session response */
case 0x83 : /* negative session response */
case 0x84 : /* retarget session response */
DEBUG ( 0 , ( " Unexpected session response \n " ) ) ;
break ;
2001-10-21 03:34:40 +04:00
case SMBkeepalive : /* session keepalive */
1997-09-18 11:05:43 +04:00
default :
return ( 0 ) ;
1996-05-04 11:50:46 +04:00
}
1997-09-18 11:05:43 +04:00
1998-08-14 21:38:29 +04:00
DEBUG ( 5 , ( " init msg_type=0x%x msg_flags=0x%x \n " ,
msg_type , msg_flags ) ) ;
1997-09-18 11:05:43 +04:00
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
1999-12-13 16:27:58 +03:00
Reply to a tcon .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
1998-08-14 21:38:29 +04:00
int reply_tcon ( connection_struct * conn ,
char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-08-17 19:27:10 +04:00
const char * service ;
pstring service_buf ;
1998-08-14 21:38:29 +04:00
pstring password ;
pstring dev ;
int outsize = 0 ;
uint16 vuid = SVAL ( inbuf , smb_uid ) ;
int pwlen = 0 ;
2001-09-24 03:07:53 +04:00
NTSTATUS nt_status ;
2001-03-13 09:55:47 +03:00
char * p ;
2001-10-31 13:46:25 +03:00
DATA_BLOB password_blob ;
2000-10-06 07:21:49 +04:00
START_PROFILE ( SMBtcon ) ;
1998-08-14 21:38:29 +04:00
2002-08-17 19:27:10 +04:00
* service_buf = * password = * dev = 0 ;
1998-08-14 21:38:29 +04:00
2001-03-13 09:55:47 +03:00
p = smb_buf ( inbuf ) + 1 ;
2003-03-18 14:22:52 +03:00
p + = srvstr_pull_buf ( inbuf , service_buf , p , sizeof ( service_buf ) , STR_TERMINATE ) + 1 ;
2002-07-15 14:35:28 +04:00
pwlen = srvstr_pull_buf ( inbuf , password , p , sizeof ( password ) , STR_TERMINATE ) + 1 ;
2001-10-31 13:46:25 +03:00
p + = pwlen ;
2002-07-15 14:35:28 +04:00
p + = srvstr_pull_buf ( inbuf , dev , p , sizeof ( dev ) , STR_TERMINATE ) + 1 ;
1998-08-14 21:38:29 +04:00
2002-08-17 19:27:10 +04:00
p = strrchr_m ( service_buf , ' \\ ' ) ;
2001-03-13 09:55:47 +03:00
if ( p ) {
2002-08-17 19:27:10 +04:00
service = p + 1 ;
} else {
service = service_buf ;
2001-03-13 09:55:47 +03:00
}
2001-10-31 13:46:25 +03:00
password_blob = data_blob ( password , pwlen + 1 ) ;
conn = make_connection ( service , password_blob , dev , vuid , & nt_status ) ;
2001-10-31 15:28:40 +03:00
2001-11-01 08:02:41 +03:00
data_blob_clear_free ( & password_blob ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
if ( ! conn ) {
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBtcon ) ;
2001-09-24 03:07:53 +04:00
return ERROR_NT ( nt_status ) ;
1998-08-14 21:38:29 +04:00
}
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
outsize = set_message ( outbuf , 2 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , max_recv ) ;
SSVAL ( outbuf , smb_vwv1 , conn - > cnum ) ;
SSVAL ( outbuf , smb_tid , conn - > cnum ) ;
1996-05-04 11:50:46 +04:00
2001-09-15 16:55:59 +04:00
DEBUG ( 3 , ( " tcon service=%s cnum=%d \n " ,
service , conn - > cnum ) ) ;
1996-05-04 11:50:46 +04:00
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBtcon ) ;
1998-08-14 21:38:29 +04:00
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
1999-12-13 16:27:58 +03:00
Reply to a tcon and X .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-22 04:57:59 +04:00
1998-08-14 21:38:29 +04:00
int reply_tcon_and_X ( connection_struct * conn , char * inbuf , char * outbuf , int length , int bufsize )
1996-05-04 11:50:46 +04:00
{
2000-04-22 12:28:22 +04:00
fstring service ;
2001-10-31 13:46:25 +03:00
DATA_BLOB password ;
2003-03-28 01:27:53 +03:00
/* what the cleint thinks the device is */
fstring client_devicetype ;
/* what the server tells the client the share represents */
const char * server_devicetype ;
2001-09-24 03:07:53 +04:00
NTSTATUS nt_status ;
1998-08-14 21:38:29 +04:00
uint16 vuid = SVAL ( inbuf , smb_uid ) ;
int passlen = SVAL ( inbuf , smb_vwv3 ) ;
2001-03-10 14:38:27 +03:00
pstring path ;
char * p , * q ;
2001-10-31 13:46:25 +03:00
extern BOOL global_encrypted_passwords_negotiated ;
2003-03-28 01:27:53 +03:00
2001-10-31 13:46:25 +03:00
START_PROFILE ( SMBtconX ) ;
2003-03-28 01:27:53 +03:00
* service = * client_devicetype = 0 ;
1998-06-10 23:45:13 +04:00
1998-08-14 21:38:29 +04:00
/* we might have to close an old one */
if ( ( SVAL ( inbuf , smb_vwv2 ) & 0x1 ) & & conn ) {
close_cnum ( conn , vuid ) ;
}
1998-06-10 23:45:13 +04:00
1998-08-14 21:38:29 +04:00
if ( passlen > MAX_PASS_LEN ) {
2001-10-15 11:50:21 +04:00
return ERROR_DOS ( ERRDOS , ERRbuftoosmall ) ;
1998-08-14 21:38:29 +04:00
}
1999-12-13 16:27:58 +03:00
2001-10-31 13:46:25 +03:00
if ( global_encrypted_passwords_negotiated ) {
password = data_blob ( smb_buf ( inbuf ) , passlen ) ;
} else {
password = data_blob ( smb_buf ( inbuf ) , passlen + 1 ) ;
/* Ensure correct termination */
password . data [ passlen ] = 0 ;
}
2001-03-10 14:38:27 +03:00
p = smb_buf ( inbuf ) + passlen ;
2002-07-15 14:35:28 +04:00
p + = srvstr_pull_buf ( inbuf , path , p , sizeof ( path ) , STR_TERMINATE ) ;
1996-05-04 11:50:46 +04:00
2001-08-22 17:08:01 +04:00
/*
* the service name can be either : \ \ server \ share
* or share directly like on the DELL PowerVault 705
*/
if ( * path = = ' \\ ' ) {
q = strchr_m ( path + 2 , ' \\ ' ) ;
if ( ! q ) {
END_PROFILE ( SMBtconX ) ;
2001-08-27 12:19:43 +04:00
return ( ERROR_DOS ( ERRDOS , ERRnosuchshare ) ) ;
2001-08-22 17:08:01 +04:00
}
fstrcpy ( service , q + 1 ) ;
2000-10-06 07:21:49 +04:00
}
2001-08-22 17:08:01 +04:00
else
fstrcpy ( service , path ) ;
2003-03-28 01:27:53 +03:00
p + = srvstr_pull ( inbuf , client_devicetype , p , sizeof ( client_devicetype ) , 6 , STR_ASCII ) ;
1999-12-13 16:27:58 +03:00
2003-03-28 01:27:53 +03:00
DEBUG ( 4 , ( " Client requested device type [%s] for share [%s] \n " , client_devicetype , service ) ) ;
1998-12-01 01:42:13 +03:00
2003-03-28 01:27:53 +03:00
conn = make_connection ( service , password , client_devicetype , vuid , & nt_status ) ;
1998-08-14 21:38:29 +04:00
2001-10-31 15:28:40 +03:00
data_blob_clear_free ( & password ) ;
2001-11-01 08:02:41 +03:00
2000-10-06 07:21:49 +04:00
if ( ! conn ) {
END_PROFILE ( SMBtconX ) ;
2001-09-24 03:07:53 +04:00
return ERROR_NT ( nt_status ) ;
2000-10-06 07:21:49 +04:00
}
1997-08-31 18:14:22 +04:00
2003-03-28 01:27:53 +03:00
if ( IS_IPC ( conn ) )
server_devicetype = " IPC " ;
else if ( IS_PRINT ( conn ) )
2003-04-12 03:28:15 +04:00
server_devicetype = " LPT1: " ;
2003-03-28 01:27:53 +03:00
else
server_devicetype = " A: " ;
1998-08-14 21:38:29 +04:00
if ( Protocol < PROTOCOL_NT1 ) {
2001-03-13 03:55:19 +03:00
set_message ( outbuf , 2 , 0 , True ) ;
p = smb_buf ( outbuf ) ;
2003-03-28 01:27:53 +03:00
p + = srvstr_push ( outbuf , p , server_devicetype , - 1 ,
2001-07-04 11:15:53 +04:00
STR_TERMINATE | STR_ASCII ) ;
2001-03-13 03:55:19 +03:00
set_message_end ( outbuf , p ) ;
1998-08-14 21:38:29 +04:00
} else {
2001-03-13 06:45:09 +03:00
/* NT sets the fstype of IPC$ to the null string */
2003-04-23 15:11:02 +04:00
const char * fstype = IS_IPC ( conn ) ? " " : lp_fstype ( SNUM ( conn ) ) ;
2003-03-25 07:14:54 +03:00
2001-03-10 14:38:27 +03:00
set_message ( outbuf , 3 , 0 , True ) ;
1997-08-31 18:14:22 +04:00
1998-08-14 21:38:29 +04:00
p = smb_buf ( outbuf ) ;
2003-03-28 01:27:53 +03:00
p + = srvstr_push ( outbuf , p , server_devicetype , - 1 ,
2001-07-04 11:15:53 +04:00
STR_TERMINATE | STR_ASCII ) ;
2003-04-23 15:11:02 +04:00
p + = srvstr_push ( outbuf , p , fstype , - 1 ,
2001-07-04 11:15:53 +04:00
STR_TERMINATE ) ;
1998-08-14 21:38:29 +04:00
2001-03-10 14:38:27 +03:00
set_message_end ( outbuf , p ) ;
1998-08-14 21:38:29 +04:00
1998-09-20 19:48:10 +04:00
/* what does setting this bit do? It is set by NT4 and
may affect the ability to autorun mounted cdroms */
2002-04-10 05:04:13 +04:00
SSVAL ( outbuf , smb_vwv2 , SMB_SUPPORT_SEARCH_BITS |
( lp_csc_policy ( SNUM ( conn ) ) < < 2 ) ) ;
2000-03-09 01:14:30 +03:00
init_dfsroot ( conn , inbuf , outbuf ) ;
1998-08-14 21:38:29 +04:00
}
2000-03-09 01:14:30 +03:00
1996-05-04 11:50:46 +04:00
2001-09-15 16:55:59 +04:00
DEBUG ( 3 , ( " tconX service=%s \n " ,
service ) ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
/* set the incoming and outgoing tid to the just created one */
SSVAL ( inbuf , smb_tid , conn - > cnum ) ;
SSVAL ( outbuf , smb_tid , conn - > cnum ) ;
1996-05-04 11:50:46 +04:00
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBtconX ) ;
1998-08-14 21:38:29 +04:00
return chain_reply ( inbuf , outbuf , length , bufsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to an unknown type .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1996-05-04 11:50:46 +04:00
int reply_unknown ( char * inbuf , char * outbuf )
{
1998-08-14 21:38:29 +04:00
int type ;
type = CVAL ( inbuf , smb_com ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
DEBUG ( 0 , ( " unknown command type (%s): type=%d (0x%X) \n " ,
smb_fn_name ( type ) , type , type ) ) ;
1996-05-04 11:50:46 +04:00
2001-08-27 12:19:43 +04:00
return ( ERROR_DOS ( ERRSRV , ERRunknownsmb ) ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to an ioctl .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_ioctl ( connection_struct * conn ,
char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
1999-12-13 16:27:58 +03:00
uint16 device = SVAL ( inbuf , smb_vwv1 ) ;
uint16 function = SVAL ( inbuf , smb_vwv2 ) ;
uint32 ioctl_code = ( device < < 16 ) + function ;
int replysize , outsize ;
char * p ;
2000-10-06 07:21:49 +04:00
START_PROFILE ( SMBioctl ) ;
1999-12-13 16:27:58 +03:00
DEBUG ( 4 , ( " Received IOCTL (code 0x%x) \n " , ioctl_code ) ) ;
2002-09-25 19:19:00 +04:00
switch ( ioctl_code ) {
1999-12-13 16:27:58 +03:00
case IOCTL_QUERY_JOB_INFO :
replysize = 32 ;
break ;
default :
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBioctl ) ;
2001-08-27 12:19:43 +04:00
return ( ERROR_DOS ( ERRSRV , ERRnosupport ) ) ;
1999-12-13 16:27:58 +03:00
}
outsize = set_message ( outbuf , 8 , replysize + 1 , True ) ;
SSVAL ( outbuf , smb_vwv1 , replysize ) ; /* Total data bytes returned */
SSVAL ( outbuf , smb_vwv5 , replysize ) ; /* Data bytes this buffer */
SSVAL ( outbuf , smb_vwv6 , 52 ) ; /* Offset to data */
p = smb_buf ( outbuf ) + 1 ; /* Allow for alignment */
2002-09-25 19:19:00 +04:00
switch ( ioctl_code ) {
case IOCTL_QUERY_JOB_INFO :
{
2003-09-09 00:27:28 +04:00
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
if ( ! fsp ) {
END_PROFILE ( SMBioctl ) ;
return ( UNIXERROR ( ERRDOS , ERRbadfid ) ) ;
}
2002-12-05 07:00:16 +03:00
SSVAL ( p , 0 , fsp - > rap_print_jobid ) ; /* Job number */
2002-11-13 02:20:50 +03:00
srvstr_push ( outbuf , p + 2 , global_myname ( ) , 15 , STR_TERMINATE | STR_ASCII ) ;
2002-09-25 19:19:00 +04:00
srvstr_push ( outbuf , p + 18 , lp_servicename ( SNUM ( conn ) ) , 13 , STR_TERMINATE | STR_ASCII ) ;
break ;
}
1999-12-13 16:27:58 +03:00
}
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBioctl ) ;
1999-12-13 16:27:58 +03:00
return outsize ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a chkpth .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_chkpth ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-09-25 19:19:00 +04:00
int outsize = 0 ;
int mode ;
pstring name ;
BOOL ok = False ;
BOOL bad_path = False ;
SMB_STRUCT_STAT sbuf ;
2003-08-13 07:28:06 +04:00
NTSTATUS status ;
2002-09-25 19:19:00 +04:00
START_PROFILE ( SMBchkpth ) ;
2001-03-13 06:45:09 +03:00
2002-09-25 19:19:00 +04:00
srvstr_pull_buf ( inbuf , name , smb_buf ( inbuf ) + 1 , sizeof ( name ) , STR_TERMINATE ) ;
2000-03-09 01:14:30 +03:00
2003-08-13 07:28:06 +04:00
status = check_path_syntax ( name ) ;
if ( ! NT_STATUS_IS_OK ( status ) )
return ERROR_NT ( status ) ;
2002-09-25 19:19:00 +04:00
RESOLVE_DFSPATH ( name , conn , inbuf , outbuf ) ;
2000-03-09 01:14:30 +03:00
2002-09-25 19:19:00 +04:00
unix_convert ( name , conn , 0 , & bad_path , & sbuf ) ;
1996-05-04 11:50:46 +04:00
2002-09-25 19:19:00 +04:00
mode = SVAL ( inbuf , smb_vwv0 ) ;
1999-12-13 16:27:58 +03:00
2002-09-25 19:19:00 +04:00
if ( check_name ( name , conn ) ) {
2003-05-14 14:59:01 +04:00
if ( VALID_STAT ( sbuf ) | | SMB_VFS_STAT ( conn , name , & sbuf ) = = 0 )
2003-03-27 01:15:21 +03:00
if ( ! ( ok = S_ISDIR ( sbuf . st_mode ) ) )
errno = ENOTDIR ;
2002-09-25 19:19:00 +04:00
}
1996-05-04 11:50:46 +04:00
2002-09-25 19:19:00 +04:00
if ( ! ok ) {
/* We special case this - as when a Windows machine
is parsing a path is steps through the components
one at a time - if a component fails it expects
ERRbadpath , not ERRbadfile .
*/
2003-08-13 06:31:22 +04:00
if ( errno = = ENOENT ) {
/*
* Windows returns different error codes if
* the parent directory is valid but not the
* last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
* for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
* if the path is invalid .
*/
if ( bad_path ) {
return ERROR_NT ( NT_STATUS_OBJECT_PATH_NOT_FOUND ) ;
} else {
return ERROR_NT ( NT_STATUS_OBJECT_NAME_NOT_FOUND ) ;
}
} else if ( errno = = ENOTDIR )
return ERROR_NT ( NT_STATUS_NOT_A_DIRECTORY ) ;
1997-10-04 00:36:06 +04:00
2002-09-25 19:19:00 +04:00
return ( UNIXERROR ( ERRDOS , ERRbadpath ) ) ;
}
1998-08-01 02:39:15 +04:00
2002-09-25 19:19:00 +04:00
outsize = set_message ( outbuf , 0 , 0 , True ) ;
1998-08-01 02:39:15 +04:00
2002-09-25 19:19:00 +04:00
DEBUG ( 3 , ( " chkpth %s mode=%d \n " , name , mode ) ) ;
1998-08-01 02:39:15 +04:00
2002-09-25 19:19:00 +04:00
END_PROFILE ( SMBchkpth ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a getatr .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_getatr ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
pstring fname ;
int outsize = 0 ;
SMB_STRUCT_STAT sbuf ;
BOOL ok = False ;
int mode = 0 ;
SMB_OFF_T size = 0 ;
time_t mtime = 0 ;
BOOL bad_path = False ;
char * p ;
START_PROFILE ( SMBgetatr ) ;
p = smb_buf ( inbuf ) + 1 ;
p + = srvstr_pull_buf ( inbuf , fname , p , sizeof ( fname ) , STR_TERMINATE ) ;
RESOLVE_DFSPATH ( fname , conn , inbuf , outbuf ) ;
/* dos smetimes asks for a stat of "" - it returns a "hidden directory"
under WfWg - weird ! */
if ( ! ( * fname ) ) {
mode = aHIDDEN | aDIR ;
if ( ! CAN_WRITE ( conn ) )
mode | = aRONLY ;
size = 0 ;
mtime = 0 ;
ok = True ;
} else {
unix_convert ( fname , conn , 0 , & bad_path , & sbuf ) ;
if ( check_name ( fname , conn ) ) {
2003-05-14 14:59:01 +04:00
if ( VALID_STAT ( sbuf ) | | SMB_VFS_STAT ( conn , fname , & sbuf ) = = 0 ) {
2002-12-04 02:57:45 +03:00
mode = dos_mode ( conn , fname , & sbuf ) ;
size = sbuf . st_size ;
mtime = sbuf . st_mtime ;
if ( mode & aDIR )
size = 0 ;
ok = True ;
} else {
DEBUG ( 3 , ( " stat of %s failed (%s) \n " , fname , strerror ( errno ) ) ) ;
}
}
}
if ( ! ok ) {
END_PROFILE ( SMBgetatr ) ;
2003-08-16 06:34:03 +04:00
return set_bad_path_error ( errno , bad_path , outbuf , ERRDOS , ERRbadfile ) ;
2002-12-04 02:57:45 +03:00
}
1997-08-21 00:32:23 +04:00
2002-12-04 02:57:45 +03:00
outsize = set_message ( outbuf , 10 , 0 , True ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
SSVAL ( outbuf , smb_vwv0 , mode ) ;
if ( lp_dos_filetime_resolution ( SNUM ( conn ) ) )
put_dos_date3 ( outbuf , smb_vwv1 , mtime & ~ 1 ) ;
else
put_dos_date3 ( outbuf , smb_vwv1 , mtime ) ;
SIVAL ( outbuf , smb_vwv3 , ( uint32 ) size ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
if ( Protocol > = PROTOCOL_NT1 )
SSVAL ( outbuf , smb_flg2 , SVAL ( outbuf , smb_flg2 ) | FLAGS2_IS_LONG_NAME ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
DEBUG ( 3 , ( " getatr name=%s mode=%d size=%d \n " , fname , mode , ( uint32 ) size ) ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
END_PROFILE ( SMBgetatr ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a setatr .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_setatr ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
pstring fname ;
int outsize = 0 ;
BOOL ok = False ;
int mode ;
time_t mtime ;
SMB_STRUCT_STAT sbuf ;
BOOL bad_path = False ;
char * p ;
START_PROFILE ( SMBsetatr ) ;
p = smb_buf ( inbuf ) + 1 ;
p + = srvstr_pull_buf ( inbuf , fname , p , sizeof ( fname ) , STR_TERMINATE ) ;
unix_convert ( fname , conn , 0 , & bad_path , & sbuf ) ;
mode = SVAL ( inbuf , smb_vwv0 ) ;
mtime = make_unix_date3 ( inbuf + smb_vwv1 ) ;
2003-08-15 03:15:02 +04:00
if ( mode ! = FILE_ATTRIBUTE_NORMAL ) {
if ( VALID_STAT_OF_DIR ( sbuf ) )
mode | = aDIR ;
else
mode & = ~ aDIR ;
if ( check_name ( fname , conn ) )
ok = ( file_chmod ( conn , fname , mode , NULL ) = = 0 ) ;
} else {
ok = True ;
}
2002-12-04 02:57:45 +03:00
if ( ok )
ok = set_filetime ( conn , fname , mtime ) ;
if ( ! ok ) {
END_PROFILE ( SMBsetatr ) ;
2003-08-16 06:34:03 +04:00
return set_bad_path_error ( errno , bad_path , outbuf , ERRDOS , ERRnoaccess ) ;
2002-12-04 02:57:45 +03:00
}
1997-08-21 00:32:23 +04:00
2002-12-04 02:57:45 +03:00
outsize = set_message ( outbuf , 0 , 0 , True ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
DEBUG ( 3 , ( " setatr name=%s mode=%d \n " , fname , mode ) ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
END_PROFILE ( SMBsetatr ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a dskattr .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_dskattr ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-07-15 14:35:28 +04:00
int outsize = 0 ;
SMB_BIG_UINT dfree , dsize , bsize ;
START_PROFILE ( SMBdskattr ) ;
2003-05-14 14:59:01 +04:00
SMB_VFS_DISK_FREE ( conn , " . " , True , & bsize , & dfree , & dsize ) ;
1996-05-04 11:50:46 +04:00
2002-07-15 14:35:28 +04:00
outsize = set_message ( outbuf , 5 , 0 , True ) ;
if ( Protocol < = PROTOCOL_LANMAN2 ) {
double total_space , free_space ;
/* we need to scale this to a number that DOS6 can handle. We
use floating point so we can handle large drives on systems
that don ' t have 64 bit integers
1998-08-01 02:39:15 +04:00
2002-07-15 14:35:28 +04:00
we end up displaying a maximum of 2 G to DOS systems
*/
total_space = dsize * ( double ) bsize ;
free_space = dfree * ( double ) bsize ;
1998-08-01 02:39:15 +04:00
2002-07-15 14:35:28 +04:00
dsize = ( total_space + 63 * 512 ) / ( 64 * 512 ) ;
dfree = ( free_space + 63 * 512 ) / ( 64 * 512 ) ;
if ( dsize > 0xFFFF ) dsize = 0xFFFF ;
if ( dfree > 0xFFFF ) dfree = 0xFFFF ;
SSVAL ( outbuf , smb_vwv0 , dsize ) ;
SSVAL ( outbuf , smb_vwv1 , 64 ) ; /* this must be 64 for dos systems */
SSVAL ( outbuf , smb_vwv2 , 512 ) ; /* and this must be 512 */
SSVAL ( outbuf , smb_vwv3 , dfree ) ;
} else {
SSVAL ( outbuf , smb_vwv0 , dsize ) ;
SSVAL ( outbuf , smb_vwv1 , bsize / 512 ) ;
SSVAL ( outbuf , smb_vwv2 , 512 ) ;
SSVAL ( outbuf , smb_vwv3 , dfree ) ;
}
DEBUG ( 3 , ( " dskattr dfree=%d \n " , ( unsigned int ) dfree ) ) ;
END_PROFILE ( SMBdskattr ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a search .
Can be called from SMBsearch , SMBffirst or SMBfunique .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_search ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
pstring mask ;
pstring directory ;
pstring fname ;
SMB_OFF_T size ;
int mode ;
time_t date ;
int dirtype ;
int outsize = 0 ;
int numentries = 0 ;
BOOL finished = False ;
int maxentries ;
int i ;
char * p ;
BOOL ok = False ;
int status_len ;
pstring path ;
char status [ 21 ] ;
int dptr_num = - 1 ;
BOOL check_descend = False ;
BOOL expect_close = False ;
BOOL can_open = True ;
BOOL bad_path = False ;
START_PROFILE ( SMBsearch ) ;
* mask = * directory = * fname = 0 ;
/* If we were called as SMBffirst then we must expect close. */
if ( CVAL ( inbuf , smb_com ) = = SMBffirst )
expect_close = True ;
outsize = set_message ( outbuf , 1 , 3 , True ) ;
maxentries = SVAL ( inbuf , smb_vwv0 ) ;
dirtype = SVAL ( inbuf , smb_vwv1 ) ;
p = smb_buf ( inbuf ) + 1 ;
p + = srvstr_pull_buf ( inbuf , path , p , sizeof ( path ) , STR_TERMINATE ) ;
p + + ;
status_len = SVAL ( p , 0 ) ;
p + = 2 ;
/* dirtype &= ~aDIR; */
if ( status_len = = 0 ) {
SMB_STRUCT_STAT sbuf ;
pstring dir2 ;
pstrcpy ( directory , path ) ;
pstrcpy ( dir2 , path ) ;
unix_convert ( directory , conn , 0 , & bad_path , & sbuf ) ;
unix_format ( dir2 ) ;
if ( ! check_name ( directory , conn ) )
can_open = False ;
p = strrchr_m ( dir2 , ' / ' ) ;
if ( p = = NULL ) {
pstrcpy ( mask , dir2 ) ;
* dir2 = 0 ;
} else {
* p = 0 ;
pstrcpy ( mask , p + 1 ) ;
}
p = strrchr_m ( directory , ' / ' ) ;
if ( ! p )
* directory = 0 ;
else
* p = 0 ;
if ( strlen ( directory ) = = 0 )
2002-12-13 22:07:37 +03:00
pstrcpy ( directory , " . " ) ;
2002-12-04 02:57:45 +03:00
memset ( ( char * ) status , ' \0 ' , 21 ) ;
SCVAL ( status , 0 , ( dirtype & 0x1F ) ) ;
} else {
int status_dirtype ;
memcpy ( status , p , 21 ) ;
status_dirtype = CVAL ( status , 0 ) & 0x1F ;
if ( status_dirtype ! = ( dirtype & 0x1F ) )
dirtype = status_dirtype ;
conn - > dirptr = dptr_fetch ( status + 12 , & dptr_num ) ;
if ( ! conn - > dirptr )
goto SearchEmpty ;
string_set ( & conn - > dirpath , dptr_path ( dptr_num ) ) ;
2003-01-14 11:53:59 +03:00
pstrcpy ( mask , dptr_wcard ( dptr_num ) ) ;
2002-12-04 02:57:45 +03:00
}
if ( can_open ) {
p = smb_buf ( outbuf ) + 3 ;
ok = True ;
1999-12-13 16:27:58 +03:00
2002-12-04 02:57:45 +03:00
if ( status_len = = 0 ) {
dptr_num = dptr_create ( conn , directory , True , expect_close , SVAL ( inbuf , smb_pid ) ) ;
if ( dptr_num < 0 ) {
if ( dptr_num = = - 2 ) {
END_PROFILE ( SMBsearch ) ;
2003-08-16 06:34:03 +04:00
return set_bad_path_error ( errno , bad_path , outbuf , ERRDOS , ERRnofids ) ;
2002-12-04 02:57:45 +03:00
}
END_PROFILE ( SMBsearch ) ;
return ERROR_DOS ( ERRDOS , ERRnofids ) ;
}
dptr_set_wcard ( dptr_num , strdup ( mask ) ) ;
2002-12-05 01:48:13 +03:00
dptr_set_attr ( dptr_num , dirtype ) ;
} else {
dirtype = dptr_attr ( dptr_num ) ;
2002-12-04 02:57:45 +03:00
}
DEBUG ( 4 , ( " dptr_num is %d \n " , dptr_num ) ) ;
if ( ok ) {
if ( ( dirtype & 0x1F ) = = aVOLID ) {
memcpy ( p , status , 21 ) ;
make_dir_struct ( p , " ??????????? " , volume_label ( SNUM ( conn ) ) , 0 , aVOLID , 0 ) ;
dptr_fill ( p + 12 , dptr_num ) ;
if ( dptr_zero ( p + 12 ) & & ( status_len = = 0 ) )
numentries = 1 ;
else
numentries = 0 ;
p + = DIR_STRUCT_SIZE ;
} else {
DEBUG ( 8 , ( " dirpath=<%s> dontdescend=<%s> \n " ,
conn - > dirpath , lp_dontdescend ( SNUM ( conn ) ) ) ) ;
if ( in_list ( conn - > dirpath , lp_dontdescend ( SNUM ( conn ) ) , True ) )
check_descend = True ;
for ( i = numentries ; ( i < maxentries ) & & ! finished ; i + + ) {
finished = ! get_dir_entry ( conn , mask , dirtype , fname , & size , & mode , & date , check_descend ) ;
if ( ! finished ) {
memcpy ( p , status , 21 ) ;
make_dir_struct ( p , mask , fname , size , mode , date ) ;
dptr_fill ( p + 12 , dptr_num ) ;
numentries + + ;
}
p + = DIR_STRUCT_SIZE ;
}
}
} /* if (ok ) */
}
1996-05-04 11:50:46 +04:00
1999-12-13 16:27:58 +03:00
SearchEmpty :
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
/* If we were called as SMBffirst with smb_search_id == NULL
and no entries were found then return error and close dirptr
( X / Open spec ) */
if ( ok & & expect_close & & numentries = = 0 & & status_len = = 0 ) {
2003-08-19 05:02:41 +04:00
if ( Protocol < PROTOCOL_NT1 ) {
SCVAL ( outbuf , smb_rcls , ERRDOS ) ;
SSVAL ( outbuf , smb_err , ERRnofiles ) ;
}
2002-12-04 02:57:45 +03:00
/* Also close the dptr - we know it's gone */
dptr_close ( & dptr_num ) ;
2003-08-19 05:02:41 +04:00
} else if ( numentries = = 0 | | ! ok ) {
if ( Protocol < PROTOCOL_NT1 ) {
SCVAL ( outbuf , smb_rcls , ERRDOS ) ;
SSVAL ( outbuf , smb_err , ERRnofiles ) ;
}
dptr_close ( & dptr_num ) ;
2002-12-04 02:57:45 +03:00
}
/* If we were called as SMBfunique, then we can close the dirptr now ! */
if ( dptr_num > = 0 & & CVAL ( inbuf , smb_com ) = = SMBfunique )
dptr_close ( & dptr_num ) ;
SSVAL ( outbuf , smb_vwv0 , numentries ) ;
SSVAL ( outbuf , smb_vwv1 , 3 + numentries * DIR_STRUCT_SIZE ) ;
SCVAL ( smb_buf ( outbuf ) , 0 , 5 ) ;
SSVAL ( smb_buf ( outbuf ) , 1 , numentries * DIR_STRUCT_SIZE ) ;
if ( Protocol > = PROTOCOL_NT1 )
SSVAL ( outbuf , smb_flg2 , SVAL ( outbuf , smb_flg2 ) | FLAGS2_IS_LONG_NAME ) ;
outsize + = DIR_STRUCT_SIZE * numentries ;
smb_setlen ( outbuf , outsize - 4 ) ;
if ( ( ! * directory ) & & dptr_path ( dptr_num ) )
slprintf ( directory , sizeof ( directory ) - 1 , " (%s) " , dptr_path ( dptr_num ) ) ;
DEBUG ( 4 , ( " %s mask=%s path=%s dtype=%d nument=%d of %d \n " ,
smb_fn_name ( CVAL ( inbuf , smb_com ) ) ,
mask , directory , dirtype , numentries , maxentries ) ) ;
END_PROFILE ( SMBsearch ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a fclose ( stop directory search ) .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_fclose ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
int outsize = 0 ;
int status_len ;
pstring path ;
char status [ 21 ] ;
int dptr_num = - 2 ;
char * p ;
2001-03-10 14:57:38 +03:00
2002-12-04 02:57:45 +03:00
START_PROFILE ( SMBfclose ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
outsize = set_message ( outbuf , 1 , 0 , True ) ;
p = smb_buf ( inbuf ) + 1 ;
p + = srvstr_pull_buf ( inbuf , path , p , sizeof ( path ) , STR_TERMINATE ) ;
p + + ;
status_len = SVAL ( p , 0 ) ;
p + = 2 ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
if ( status_len = = 0 ) {
END_PROFILE ( SMBfclose ) ;
return ERROR_DOS ( ERRSRV , ERRsrverror ) ;
}
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
memcpy ( status , p , 21 ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
if ( dptr_fetch ( status + 12 , & dptr_num ) ) {
/* Close the dptr - we know it's gone */
dptr_close ( & dptr_num ) ;
}
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
SSVAL ( outbuf , smb_vwv0 , 0 ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
DEBUG ( 3 , ( " search close \n " ) ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
END_PROFILE ( SMBfclose ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to an open .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-10-23 04:58:28 +04:00
1998-08-14 21:38:29 +04:00
int reply_open ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
pstring fname ;
int outsize = 0 ;
int fmode = 0 ;
int share_mode ;
SMB_OFF_T size = 0 ;
time_t mtime = 0 ;
mode_t unixmode ;
int rmode = 0 ;
SMB_STRUCT_STAT sbuf ;
BOOL bad_path = False ;
files_struct * fsp ;
int oplock_request = CORE_OPLOCK_REQUEST ( inbuf ) ;
START_PROFILE ( SMBopen ) ;
1997-08-21 00:32:23 +04:00
2002-12-04 02:57:45 +03:00
share_mode = SVAL ( inbuf , smb_vwv0 ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
srvstr_pull_buf ( inbuf , fname , smb_buf ( inbuf ) + 1 , sizeof ( fname ) , STR_TERMINATE ) ;
2000-03-09 01:14:30 +03:00
2002-12-04 02:57:45 +03:00
RESOLVE_DFSPATH ( fname , conn , inbuf , outbuf ) ;
2000-03-09 01:14:30 +03:00
2002-12-04 02:57:45 +03:00
unix_convert ( fname , conn , 0 , & bad_path , & sbuf ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
unixmode = unix_mode ( conn , aARCH , fname ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
fsp = open_file_shared ( conn , fname , & sbuf , share_mode , ( FILE_FAIL_IF_NOT_EXIST | FILE_EXISTS_OPEN ) ,
unixmode , oplock_request , & rmode , NULL ) ;
if ( ! fsp ) {
END_PROFILE ( SMBopen ) ;
2003-08-16 06:34:03 +04:00
return set_bad_path_error ( errno , bad_path , outbuf , ERRDOS , ERRnoaccess ) ;
2002-12-04 02:57:45 +03:00
}
size = sbuf . st_size ;
fmode = dos_mode ( conn , fname , & sbuf ) ;
mtime = sbuf . st_mtime ;
if ( fmode & aDIR ) {
DEBUG ( 3 , ( " attempt to open a directory %s \n " , fname ) ) ;
close_file ( fsp , False ) ;
END_PROFILE ( SMBopen ) ;
return ERROR_DOS ( ERRDOS , ERRnoaccess ) ;
}
outsize = set_message ( outbuf , 7 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , fsp - > fnum ) ;
SSVAL ( outbuf , smb_vwv1 , fmode ) ;
if ( lp_dos_filetime_resolution ( SNUM ( conn ) ) )
put_dos_date3 ( outbuf , smb_vwv2 , mtime & ~ 1 ) ;
else
put_dos_date3 ( outbuf , smb_vwv2 , mtime ) ;
SIVAL ( outbuf , smb_vwv4 , ( uint32 ) size ) ;
SSVAL ( outbuf , smb_vwv6 , rmode ) ;
if ( oplock_request & & lp_fake_oplocks ( SNUM ( conn ) ) )
SCVAL ( outbuf , smb_flg , CVAL ( outbuf , smb_flg ) | CORE_OPLOCK_GRANTED ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
if ( EXCLUSIVE_OPLOCK_TYPE ( fsp - > oplock_type ) )
SCVAL ( outbuf , smb_flg , CVAL ( outbuf , smb_flg ) | CORE_OPLOCK_GRANTED ) ;
END_PROFILE ( SMBopen ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to an open and X .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_open_and_X ( connection_struct * conn , char * inbuf , char * outbuf , int length , int bufsize )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
pstring fname ;
int smb_mode = SVAL ( inbuf , smb_vwv3 ) ;
int smb_attr = SVAL ( inbuf , smb_vwv5 ) ;
/* Breakout the oplock request bits so we can set the
reply bits separately . */
BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST ( inbuf ) ;
BOOL core_oplock_request = CORE_OPLOCK_REQUEST ( inbuf ) ;
BOOL oplock_request = ex_oplock_request | core_oplock_request ;
1996-05-04 11:50:46 +04:00
#if 0
2002-12-04 02:57:45 +03:00
int open_flags = SVAL ( inbuf , smb_vwv2 ) ;
int smb_sattr = SVAL ( inbuf , smb_vwv4 ) ;
uint32 smb_time = make_unix_date3 ( inbuf + smb_vwv6 ) ;
1996-05-04 11:50:46 +04:00
# endif
2002-12-04 02:57:45 +03:00
int smb_ofun = SVAL ( inbuf , smb_vwv8 ) ;
mode_t unixmode ;
SMB_OFF_T size = 0 ;
int fmode = 0 , mtime = 0 , rmode = 0 ;
SMB_STRUCT_STAT sbuf ;
int smb_action = 0 ;
BOOL bad_path = False ;
files_struct * fsp ;
START_PROFILE ( SMBopenX ) ;
/* If it's an IPC, pass off the pipe handler. */
if ( IS_IPC ( conn ) ) {
if ( lp_nt_pipe_support ( ) ) {
END_PROFILE ( SMBopenX ) ;
return reply_open_pipe_and_X ( conn , inbuf , outbuf , length , bufsize ) ;
} else {
END_PROFILE ( SMBopenX ) ;
return ERROR_DOS ( ERRSRV , ERRaccess ) ;
}
}
1996-08-15 19:11:34 +04:00
2002-12-04 02:57:45 +03:00
/* XXXX we need to handle passed times, sattr and flags */
srvstr_pull_buf ( inbuf , fname , smb_buf ( inbuf ) , sizeof ( fname ) , STR_TERMINATE ) ;
2000-03-09 01:14:30 +03:00
2002-12-04 02:57:45 +03:00
RESOLVE_DFSPATH ( fname , conn , inbuf , outbuf ) ;
2000-03-09 01:14:30 +03:00
2002-12-04 02:57:45 +03:00
unix_convert ( fname , conn , 0 , & bad_path , & sbuf ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
unixmode = unix_mode ( conn , smb_attr | aARCH , fname ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
fsp = open_file_shared ( conn , fname , & sbuf , smb_mode , smb_ofun , unixmode ,
oplock_request , & rmode , & smb_action ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
if ( ! fsp ) {
END_PROFILE ( SMBopenX ) ;
2003-08-16 06:34:03 +04:00
return set_bad_path_error ( errno , bad_path , outbuf , ERRDOS , ERRnoaccess ) ;
2002-12-04 02:57:45 +03:00
}
size = sbuf . st_size ;
fmode = dos_mode ( conn , fname , & sbuf ) ;
mtime = sbuf . st_mtime ;
if ( fmode & aDIR ) {
close_file ( fsp , False ) ;
END_PROFILE ( SMBopenX ) ;
return ERROR_DOS ( ERRDOS , ERRnoaccess ) ;
}
/* If the caller set the extended oplock request bit
and we granted one ( by whatever means ) - set the
correct bit for extended oplock reply .
*/
if ( ex_oplock_request & & lp_fake_oplocks ( SNUM ( conn ) ) )
smb_action | = EXTENDED_OPLOCK_GRANTED ;
if ( ex_oplock_request & & EXCLUSIVE_OPLOCK_TYPE ( fsp - > oplock_type ) )
smb_action | = EXTENDED_OPLOCK_GRANTED ;
/* If the caller set the core oplock request bit
and we granted one ( by whatever means ) - set the
correct bit for core oplock reply .
*/
if ( core_oplock_request & & lp_fake_oplocks ( SNUM ( conn ) ) )
SCVAL ( outbuf , smb_flg , CVAL ( outbuf , smb_flg ) | CORE_OPLOCK_GRANTED ) ;
if ( core_oplock_request & & EXCLUSIVE_OPLOCK_TYPE ( fsp - > oplock_type ) )
SCVAL ( outbuf , smb_flg , CVAL ( outbuf , smb_flg ) | CORE_OPLOCK_GRANTED ) ;
set_message ( outbuf , 15 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv2 , fsp - > fnum ) ;
SSVAL ( outbuf , smb_vwv3 , fmode ) ;
if ( lp_dos_filetime_resolution ( SNUM ( conn ) ) )
put_dos_date3 ( outbuf , smb_vwv4 , mtime & ~ 1 ) ;
else
put_dos_date3 ( outbuf , smb_vwv4 , mtime ) ;
SIVAL ( outbuf , smb_vwv6 , ( uint32 ) size ) ;
SSVAL ( outbuf , smb_vwv8 , rmode ) ;
SSVAL ( outbuf , smb_vwv11 , smb_action ) ;
END_PROFILE ( SMBopenX ) ;
return chain_reply ( inbuf , outbuf , length , bufsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a SMBulogoffX .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_ulogoffX ( connection_struct * conn , char * inbuf , char * outbuf , int length , int bufsize )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
uint16 vuid = SVAL ( inbuf , smb_uid ) ;
user_struct * vuser = get_valid_user_struct ( vuid ) ;
START_PROFILE ( SMBulogoffX ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
if ( vuser = = 0 )
DEBUG ( 3 , ( " ulogoff, vuser id %d does not map to user. \n " , vuid ) ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
/* in user level security we are supposed to close any files
open by this user */
if ( ( vuser ! = 0 ) & & ( lp_security ( ) ! = SEC_SHARE ) )
file_close_user ( vuid ) ;
1996-10-05 14:41:13 +04:00
2002-12-04 02:57:45 +03:00
invalidate_vuid ( vuid ) ;
1996-10-26 00:30:22 +04:00
2002-12-04 02:57:45 +03:00
set_message ( outbuf , 2 , 0 , True ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
DEBUG ( 3 , ( " ulogoffX vuid=%d \n " , vuid ) ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
END_PROFILE ( SMBulogoffX ) ;
return chain_reply ( inbuf , outbuf , length , bufsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a mknew or a create .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_mknew ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
pstring fname ;
int com ;
int outsize = 0 ;
int createmode ;
mode_t unixmode ;
int ofun = 0 ;
BOOL bad_path = False ;
files_struct * fsp ;
int oplock_request = CORE_OPLOCK_REQUEST ( inbuf ) ;
SMB_STRUCT_STAT sbuf ;
START_PROFILE ( SMBcreate ) ;
1997-05-28 00:28:45 +04:00
2002-12-04 02:57:45 +03:00
com = SVAL ( inbuf , smb_com ) ;
createmode = SVAL ( inbuf , smb_vwv0 ) ;
srvstr_pull_buf ( inbuf , fname , smb_buf ( inbuf ) + 1 , sizeof ( fname ) , STR_TERMINATE ) ;
RESOLVE_DFSPATH ( fname , conn , inbuf , outbuf ) ;
unix_convert ( fname , conn , 0 , & bad_path , & sbuf ) ;
if ( createmode & aVOLID )
DEBUG ( 0 , ( " Attempt to create file (%s) with volid set - please report this \n " , fname ) ) ;
unixmode = unix_mode ( conn , createmode , fname ) ;
if ( com = = SMBmknew ) {
/* We should fail if file exists. */
ofun = FILE_CREATE_IF_NOT_EXIST ;
} else {
/* SMBcreate - Create if file doesn't exist, truncate if it does. */
ofun = FILE_CREATE_IF_NOT_EXIST | FILE_EXISTS_TRUNCATE ;
}
/* Open file in dos compatibility share mode. */
fsp = open_file_shared ( conn , fname , & sbuf , SET_DENY_MODE ( DENY_FCB ) | SET_OPEN_MODE ( DOS_OPEN_FCB ) ,
ofun , unixmode , oplock_request , NULL , NULL ) ;
if ( ! fsp ) {
END_PROFILE ( SMBcreate ) ;
2003-08-16 06:34:03 +04:00
return set_bad_path_error ( errno , bad_path , outbuf , ERRDOS , ERRnoaccess ) ;
2002-12-04 02:57:45 +03:00
}
1997-08-21 00:32:23 +04:00
2002-12-04 02:57:45 +03:00
outsize = set_message ( outbuf , 1 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , fsp - > fnum ) ;
1996-10-05 14:41:13 +04:00
2002-12-04 02:57:45 +03:00
if ( oplock_request & & lp_fake_oplocks ( SNUM ( conn ) ) )
SCVAL ( outbuf , smb_flg , CVAL ( outbuf , smb_flg ) | CORE_OPLOCK_GRANTED ) ;
1997-09-26 23:26:56 +04:00
2002-12-04 02:57:45 +03:00
if ( EXCLUSIVE_OPLOCK_TYPE ( fsp - > oplock_type ) )
SCVAL ( outbuf , smb_flg , CVAL ( outbuf , smb_flg ) | CORE_OPLOCK_GRANTED ) ;
1997-09-26 23:26:56 +04:00
2002-12-04 02:57:45 +03:00
DEBUG ( 2 , ( " new file %s \n " , fname ) ) ;
DEBUG ( 3 , ( " mknew %s fd=%d dmode=%d umode=%o \n " , fname , fsp - > fd , createmode , ( int ) unixmode ) ) ;
1998-08-01 02:39:15 +04:00
2002-12-04 02:57:45 +03:00
END_PROFILE ( SMBcreate ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a create temporary file .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_ctemp ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
pstring fname ;
int outsize = 0 ;
int createmode ;
mode_t unixmode ;
BOOL bad_path = False ;
files_struct * fsp ;
int oplock_request = CORE_OPLOCK_REQUEST ( inbuf ) ;
int tmpfd ;
SMB_STRUCT_STAT sbuf ;
char * p , * s ;
START_PROFILE ( SMBctemp ) ;
createmode = SVAL ( inbuf , smb_vwv0 ) ;
srvstr_pull_buf ( inbuf , fname , smb_buf ( inbuf ) + 1 , sizeof ( fname ) , STR_TERMINATE ) ;
pstrcat ( fname , " \\ TMXXXXXX " ) ;
RESOLVE_DFSPATH ( fname , conn , inbuf , outbuf ) ;
unix_convert ( fname , conn , 0 , & bad_path , & sbuf ) ;
unixmode = unix_mode ( conn , createmode , fname ) ;
tmpfd = smb_mkstemp ( fname ) ;
if ( tmpfd = = - 1 ) {
END_PROFILE ( SMBctemp ) ;
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
}
2003-05-14 14:59:01 +04:00
SMB_VFS_STAT ( conn , fname , & sbuf ) ;
2002-12-04 02:57:45 +03:00
/* Open file in dos compatibility share mode. */
/* We should fail if file does not exist. */
fsp = open_file_shared ( conn , fname , & sbuf ,
SET_DENY_MODE ( DENY_FCB ) | SET_OPEN_MODE ( DOS_OPEN_FCB ) ,
FILE_EXISTS_OPEN | FILE_FAIL_IF_NOT_EXIST ,
unixmode , oplock_request , NULL , NULL ) ;
/* close fd from smb_mkstemp() */
close ( tmpfd ) ;
if ( ! fsp ) {
END_PROFILE ( SMBctemp ) ;
2003-08-16 06:34:03 +04:00
return set_bad_path_error ( errno , bad_path , outbuf , ERRDOS , ERRnoaccess ) ;
2002-12-04 02:57:45 +03:00
}
outsize = set_message ( outbuf , 1 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , fsp - > fnum ) ;
/* the returned filename is relative to the directory */
s = strrchr_m ( fname , ' / ' ) ;
if ( ! s )
s = fname ;
else
s + + ;
p = smb_buf ( outbuf ) ;
SSVALS ( p , 0 , - 1 ) ; /* what is this? not in spec */
SSVAL ( p , 2 , strlen ( s ) ) ;
p + = 4 ;
p + = srvstr_push ( outbuf , p , s , - 1 , STR_ASCII ) ;
outsize = set_message_end ( outbuf , p ) ;
if ( oplock_request & & lp_fake_oplocks ( SNUM ( conn ) ) )
SCVAL ( outbuf , smb_flg , CVAL ( outbuf , smb_flg ) | CORE_OPLOCK_GRANTED ) ;
if ( EXCLUSIVE_OPLOCK_TYPE ( fsp - > oplock_type ) )
SCVAL ( outbuf , smb_flg , CVAL ( outbuf , smb_flg ) | CORE_OPLOCK_GRANTED ) ;
DEBUG ( 2 , ( " created temp file %s \n " , fname ) ) ;
DEBUG ( 3 , ( " ctemp %s fd=%d dmode=%d umode=%o \n " ,
fname , fsp - > fd , createmode , ( int ) unixmode ) ) ;
END_PROFILE ( SMBctemp ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
2002-03-23 05:57:44 +03:00
/*******************************************************************
Check if a user is allowed to rename a file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS can_rename ( char * fname , connection_struct * conn , SMB_STRUCT_STAT * pst )
{
int smb_action ;
int access_mode ;
files_struct * fsp ;
if ( ! CAN_WRITE ( conn ) )
return NT_STATUS_MEDIA_WRITE_PROTECTED ;
if ( S_ISDIR ( pst - > st_mode ) )
return NT_STATUS_OK ;
/* We need a better way to return NT status codes from open... */
unix_ERR_class = 0 ;
unix_ERR_code = 0 ;
fsp = open_file_shared1 ( conn , fname , pst , DELETE_ACCESS , SET_DENY_MODE ( DENY_ALL ) ,
( FILE_FAIL_IF_NOT_EXIST | FILE_EXISTS_OPEN ) , 0 , 0 , & access_mode , & smb_action ) ;
if ( ! fsp ) {
NTSTATUS ret = NT_STATUS_ACCESS_DENIED ;
if ( unix_ERR_class = = ERRDOS & & unix_ERR_code = = ERRbadshare )
ret = NT_STATUS_SHARING_VIOLATION ;
unix_ERR_class = 0 ;
unix_ERR_code = 0 ;
return ret ;
}
close_file ( fsp , False ) ;
return NT_STATUS_OK ;
}
1996-05-04 11:50:46 +04:00
/*******************************************************************
2001-11-17 06:19:17 +03:00
Check if a user is allowed to delete a file .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-11-17 06:19:17 +03:00
2001-09-21 18:27:43 +04:00
static NTSTATUS can_delete ( char * fname , connection_struct * conn , int dirtype )
1996-05-04 11:50:46 +04:00
{
2001-09-21 18:27:43 +04:00
SMB_STRUCT_STAT sbuf ;
int fmode ;
2002-03-23 05:57:44 +03:00
int smb_action ;
int access_mode ;
files_struct * fsp ;
1996-05-04 11:50:46 +04:00
2003-08-13 04:31:23 +04:00
DEBUG ( 10 , ( " can_delete: %s, dirtype = %d \n " ,
fname , dirtype ) ) ;
2001-11-17 06:19:17 +03:00
if ( ! CAN_WRITE ( conn ) )
return NT_STATUS_MEDIA_WRITE_PROTECTED ;
1996-05-04 11:50:46 +04:00
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_LSTAT ( conn , fname , & sbuf ) ! = 0 )
2001-11-17 06:19:17 +03:00
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
2001-09-21 18:27:43 +04:00
fmode = dos_mode ( conn , fname , & sbuf ) ;
2003-08-13 04:31:23 +04:00
/* Can't delete a directory. */
2001-11-17 06:19:17 +03:00
if ( fmode & aDIR )
return NT_STATUS_FILE_IS_A_DIRECTORY ;
2003-08-16 06:34:03 +04:00
#if 0 /* JRATEST */
2003-08-13 04:31:23 +04:00
else if ( dirtype & aDIR ) /* Asked for a directory and it isn't. */
return NT_STATUS_OBJECT_NAME_INVALID ;
2003-08-16 06:34:03 +04:00
# endif /* JRATEST */
2003-08-13 04:31:23 +04:00
2001-09-21 18:27:43 +04:00
if ( ! lp_delete_readonly ( SNUM ( conn ) ) ) {
2001-11-17 06:19:17 +03:00
if ( fmode & aRONLY )
return NT_STATUS_CANNOT_DELETE ;
2001-09-21 18:27:43 +04:00
}
if ( ( fmode & ~ dirtype ) & ( aHIDDEN | aSYSTEM ) )
2003-08-12 08:28:22 +04:00
return NT_STATUS_NO_SUCH_FILE ;
2001-09-21 18:27:43 +04:00
2002-03-23 05:57:44 +03:00
/* We need a better way to return NT status codes from open... */
unix_ERR_class = 0 ;
unix_ERR_code = 0 ;
fsp = open_file_shared1 ( conn , fname , & sbuf , DELETE_ACCESS , SET_DENY_MODE ( DENY_ALL ) ,
( FILE_FAIL_IF_NOT_EXIST | FILE_EXISTS_OPEN ) , 0 , 0 , & access_mode , & smb_action ) ;
2001-09-21 18:27:43 +04:00
2002-03-23 05:57:44 +03:00
if ( ! fsp ) {
NTSTATUS ret = NT_STATUS_ACCESS_DENIED ;
2002-11-06 01:49:07 +03:00
if ( ! NT_STATUS_IS_OK ( unix_ERR_ntstatus ) )
ret = unix_ERR_ntstatus ;
else if ( unix_ERR_class = = ERRDOS & & unix_ERR_code = = ERRbadshare )
2002-03-23 05:57:44 +03:00
ret = NT_STATUS_SHARING_VIOLATION ;
unix_ERR_class = 0 ;
unix_ERR_code = 0 ;
2002-11-06 01:49:07 +03:00
unix_ERR_ntstatus = NT_STATUS_OK ;
2002-03-23 05:57:44 +03:00
return ret ;
}
close_file ( fsp , False ) ;
2001-09-21 18:27:43 +04:00
return NT_STATUS_OK ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2000-11-15 00:56:32 +03:00
The guts of the unlink command , split out so it may be called by the NT SMB
code .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2001-09-04 11:13:01 +04:00
NTSTATUS unlink_internals ( connection_struct * conn , int dirtype , char * name )
1996-05-04 11:50:46 +04:00
{
2001-08-27 12:19:43 +04:00
pstring directory ;
pstring mask ;
char * p ;
int count = 0 ;
2001-09-04 11:13:01 +04:00
NTSTATUS error = NT_STATUS_OK ;
2001-08-27 12:19:43 +04:00
BOOL has_wild ;
BOOL bad_path = False ;
BOOL rc = True ;
SMB_STRUCT_STAT sbuf ;
* directory = * mask = 0 ;
2003-07-29 23:16:59 +04:00
/* We must check for wildcards in the name given
* directly by the client - before any unmangling .
* This prevents an unmangling of a UNIX name containing
* a DOS wildcard like ' * ' or ' ? ' from unmangling into
* a wildcard delete which was not intended .
* FIX for # 226. JRA .
*/
has_wild = ms_has_wild ( name ) ;
2001-08-27 12:19:43 +04:00
rc = unix_convert ( name , conn , 0 , & bad_path , & sbuf ) ;
p = strrchr_m ( name , ' / ' ) ;
if ( ! p ) {
2002-03-19 05:32:39 +03:00
pstrcpy ( directory , " . " ) ;
2001-08-27 12:19:43 +04:00
pstrcpy ( mask , name ) ;
} else {
* p = 0 ;
pstrcpy ( directory , name ) ;
pstrcpy ( mask , p + 1 ) ;
}
/*
* We should only check the mangled cache
* here if unix_convert failed . This means
* that the path in ' mask ' doesn ' t exist
* on the file system and so we need to look
* for a possible mangle . This patch from
* Tine Smukavec < valentin . smukavec @ hermes . si > .
*/
2002-04-11 06:20:56 +04:00
if ( ! rc & & mangle_is_mangled ( mask ) )
mangle_check_cache ( mask ) ;
2001-08-27 12:19:43 +04:00
if ( ! has_wild ) {
pstrcat ( directory , " / " ) ;
pstrcat ( directory , mask ) ;
2001-09-21 18:27:43 +04:00
error = can_delete ( directory , conn , dirtype ) ;
2003-07-29 23:16:59 +04:00
if ( ! NT_STATUS_IS_OK ( error ) )
return error ;
2001-09-21 18:27:43 +04:00
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_UNLINK ( conn , directory ) = = 0 ) {
2001-08-27 12:19:43 +04:00
count + + ;
}
} else {
void * dirptr = NULL ;
2003-03-18 01:56:13 +03:00
const char * dname ;
2001-08-27 12:19:43 +04:00
if ( check_name ( directory , conn ) )
dirptr = OpenDir ( conn , directory , True ) ;
/* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
the pattern matches against the long name , otherwise the short name
We don ' t implement this yet XXXX
*/
if ( dirptr ) {
2003-08-13 04:31:23 +04:00
error = NT_STATUS_NO_SUCH_FILE ;
2001-08-27 12:19:43 +04:00
if ( strequal ( mask , " ????????.??? " ) )
pstrcpy ( mask , " * " ) ;
1996-05-04 11:50:46 +04:00
2001-08-27 12:19:43 +04:00
while ( ( dname = ReadDirName ( dirptr ) ) ) {
pstring fname ;
pstrcpy ( fname , dname ) ;
2003-07-29 23:16:59 +04:00
if ( ! mask_match ( fname , mask , case_sensitive ) )
continue ;
2001-08-27 12:19:43 +04:00
slprintf ( fname , sizeof ( fname ) - 1 , " %s/%s " , directory , dname ) ;
2001-09-21 18:27:43 +04:00
error = can_delete ( fname , conn , dirtype ) ;
2003-07-29 23:16:59 +04:00
if ( ! NT_STATUS_IS_OK ( error ) )
continue ;
if ( SMB_VFS_UNLINK ( conn , fname ) = = 0 )
count + + ;
2001-08-27 12:19:43 +04:00
DEBUG ( 3 , ( " unlink_internals: succesful unlink [%s] \n " , fname ) ) ;
}
CloseDir ( dirptr ) ;
}
}
2001-09-04 11:13:01 +04:00
if ( count = = 0 & & NT_STATUS_IS_OK ( error ) ) {
error = map_nt_error_from_unix ( errno ) ;
2001-08-27 12:19:43 +04:00
}
2001-09-04 11:13:01 +04:00
return error ;
2000-11-15 00:56:32 +03:00
}
/****************************************************************************
Reply to a unlink
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-08-27 12:19:43 +04:00
int reply_unlink ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size ,
int dum_buffsize )
2000-11-15 00:56:32 +03:00
{
2001-08-27 12:19:43 +04:00
int outsize = 0 ;
pstring name ;
int dirtype ;
2001-09-04 11:13:01 +04:00
NTSTATUS status ;
2001-08-27 12:19:43 +04:00
START_PROFILE ( SMBunlink ) ;
dirtype = SVAL ( inbuf , smb_vwv0 ) ;
2002-07-15 14:35:28 +04:00
srvstr_pull_buf ( inbuf , name , smb_buf ( inbuf ) + 1 , sizeof ( name ) , STR_TERMINATE ) ;
2001-08-27 12:19:43 +04:00
2003-08-13 07:28:06 +04:00
status = check_path_syntax ( name ) ;
if ( ! NT_STATUS_IS_OK ( status ) )
return ERROR_NT ( status ) ;
2001-08-27 12:19:43 +04:00
RESOLVE_DFSPATH ( name , conn , inbuf , outbuf ) ;
DEBUG ( 3 , ( " reply_unlink : %s \n " , name ) ) ;
2001-09-04 11:13:01 +04:00
status = unlink_internals ( conn , dirtype , name ) ;
2003-07-29 23:16:59 +04:00
if ( ! NT_STATUS_IS_OK ( status ) )
return ERROR_NT ( status ) ;
2001-09-04 11:13:01 +04:00
/*
* Win2k needs a changenotify request response before it will
* update after a rename . .
*/
process_pending_change_notify_queue ( ( time_t ) 0 ) ;
outsize = set_message ( outbuf , 0 , 0 , True ) ;
1996-05-04 11:50:46 +04:00
2001-08-27 12:19:43 +04:00
END_PROFILE ( SMBunlink ) ;
return outsize ;
1996-05-04 11:50:46 +04:00
}
2001-09-04 23:10:30 +04:00
/****************************************************************************
Fail for readbraw .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void fail_readraw ( void )
{
pstring errstr ;
2001-11-05 03:02:38 +03:00
slprintf ( errstr , sizeof ( errstr ) - 1 , " FAIL ! reply_readbraw: socket write fail (%s) " ,
2001-09-04 23:10:30 +04:00
strerror ( errno ) ) ;
exit_server ( errstr ) ;
}
1996-05-04 11:50:46 +04:00
2002-09-25 19:19:00 +04:00
/****************************************************************************
Use sendfile in readbraw .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void send_file_readbraw ( connection_struct * conn , files_struct * fsp , SMB_OFF_T startpos , size_t nread ,
ssize_t mincount , char * outbuf )
{
ssize_t ret = 0 ;
# if defined(WITH_SENDFILE)
/*
* We can only use sendfile on a non - chained packet and on a file
* that is exclusively oplocked . reply_readbraw has already checked the length .
*/
if ( ( nread > 0 ) & & ( lp_write_cache_size ( SNUM ( conn ) ) = = 0 ) & &
EXCLUSIVE_OPLOCK_TYPE ( fsp - > oplock_type ) & & lp_use_sendfile ( SNUM ( conn ) ) ) {
DATA_BLOB header ;
_smb_setlen ( outbuf , nread ) ;
header . data = outbuf ;
header . length = 4 ;
header . free = NULL ;
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_SENDFILE ( smbd_server_fd ( ) , fsp , fsp - > fd , & header , startpos , nread ) = = - 1 ) {
2002-09-25 19:19:00 +04:00
/*
* Special hack for broken Linux with no 64 bit clean sendfile . If we
* return ENOSYS then pretend we just got a normal read .
*/
if ( errno = = ENOSYS )
goto normal_read ;
DEBUG ( 0 , ( " send_file_readbraw: sendfile failed for file %s (%s). Terminating \n " ,
fsp - > fsp_name , strerror ( errno ) ) ) ;
exit_server ( " send_file_readbraw sendfile failed " ) ;
}
}
normal_read :
# endif
if ( nread > 0 ) {
ret = read_file ( fsp , outbuf + 4 , startpos , nread ) ;
if ( ret < mincount )
ret = 0 ;
}
_smb_setlen ( outbuf , ret ) ;
if ( write_data ( smbd_server_fd ( ) , outbuf , 4 + ret ) ! = 4 + ret )
fail_readraw ( ) ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
2001-09-04 23:10:30 +04:00
Reply to a readbraw ( core + protocol ) .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
1998-08-14 21:38:29 +04:00
int reply_readbraw ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2003-04-10 02:31:37 +04:00
extern struct current_user current_user ;
2001-11-14 05:35:56 +03:00
ssize_t maxcount , mincount ;
2001-09-04 23:10:30 +04:00
size_t nread = 0 ;
SMB_OFF_T startpos ;
char * header = outbuf ;
files_struct * fsp ;
START_PROFILE ( SMBreadbraw ) ;
1996-05-04 11:50:46 +04:00
2003-07-18 04:53:34 +04:00
if ( srv_is_signing_active ( ) ) {
2003-07-17 04:53:37 +04:00
exit_server ( " reply_readbraw: SMB signing is active - raw reads/writes are disallowed. " ) ;
}
2001-09-04 23:10:30 +04:00
/*
* Special check if an oplock break has been issued
* and the readraw request croses on the wire , we must
* return a zero length response here .
*/
1997-10-02 03:32:22 +04:00
2001-09-04 23:10:30 +04:00
if ( global_oplock_break ) {
_smb_setlen ( header , 0 ) ;
if ( write_data ( smbd_server_fd ( ) , header , 4 ) ! = 4 )
fail_readraw ( ) ;
DEBUG ( 5 , ( " readbraw - oplock break finished \n " ) ) ;
END_PROFILE ( SMBreadbraw ) ;
return - 1 ;
}
1997-10-02 03:32:22 +04:00
2001-09-04 23:10:30 +04:00
fsp = file_fsp ( inbuf , smb_vwv0 ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
if ( ! FNUM_OK ( fsp , conn ) | | ! fsp - > can_read ) {
/*
* fsp could be NULL here so use the value from the packet . JRA .
*/
DEBUG ( 3 , ( " fnum %d not open in readbraw - cache prime? \n " , ( int ) SVAL ( inbuf , smb_vwv0 ) ) ) ;
_smb_setlen ( header , 0 ) ;
if ( write_data ( smbd_server_fd ( ) , header , 4 ) ! = 4 )
fail_readraw ( ) ;
END_PROFILE ( SMBreadbraw ) ;
return ( - 1 ) ;
}
1999-12-13 16:27:58 +03:00
2001-09-04 23:10:30 +04:00
CHECK_FSP ( fsp , conn ) ;
1999-12-13 16:27:58 +03:00
2001-09-04 23:10:30 +04:00
flush_write_cache ( fsp , READRAW_FLUSH ) ;
1999-12-13 16:27:58 +03:00
2002-12-03 11:02:41 +03:00
startpos = IVAL_TO_SMB_OFF_T ( inbuf , smb_vwv1 ) ;
2001-09-04 23:10:30 +04:00
if ( CVAL ( inbuf , smb_wct ) = = 10 ) {
/*
* This is a large offset ( 64 bit ) read .
*/
1999-12-13 16:27:58 +03:00
# ifdef LARGE_SMB_OFF_T
2001-09-04 23:10:30 +04:00
startpos | = ( ( ( SMB_OFF_T ) IVAL ( inbuf , smb_vwv8 ) ) < < 32 ) ;
1999-12-13 16:27:58 +03:00
# else /* !LARGE_SMB_OFF_T */
2001-09-04 23:10:30 +04:00
/*
* Ensure we haven ' t been sent a > 32 bit offset .
*/
1999-12-13 16:27:58 +03:00
2001-09-04 23:10:30 +04:00
if ( IVAL ( inbuf , smb_vwv8 ) ! = 0 ) {
DEBUG ( 0 , ( " readbraw - large offset (%x << 32) used and we don't support \
1999-12-13 16:27:58 +03:00
64 bit offsets . \ n " , (unsigned int)IVAL(inbuf,smb_vwv8) ));
2001-09-04 23:10:30 +04:00
_smb_setlen ( header , 0 ) ;
if ( write_data ( smbd_server_fd ( ) , header , 4 ) ! = 4 )
fail_readraw ( ) ;
END_PROFILE ( SMBreadbraw ) ;
return ( - 1 ) ;
}
1999-12-13 16:27:58 +03:00
# endif /* LARGE_SMB_OFF_T */
2001-09-04 23:10:30 +04:00
if ( startpos < 0 ) {
DEBUG ( 0 , ( " readbraw - negative 64 bit readraw offset (%.0f) ! \n " , ( double ) startpos ) ) ;
_smb_setlen ( header , 0 ) ;
if ( write_data ( smbd_server_fd ( ) , header , 4 ) ! = 4 )
fail_readraw ( ) ;
END_PROFILE ( SMBreadbraw ) ;
return ( - 1 ) ;
}
}
maxcount = ( SVAL ( inbuf , smb_vwv3 ) & 0xFFFF ) ;
mincount = ( SVAL ( inbuf , smb_vwv4 ) & 0xFFFF ) ;
/* ensure we don't overrun the packet size */
maxcount = MIN ( 65535 , maxcount ) ;
maxcount = MAX ( mincount , maxcount ) ;
if ( ! is_locked ( fsp , conn , ( SMB_BIG_UINT ) maxcount , ( SMB_BIG_UINT ) startpos , READ_LOCK , False ) ) {
SMB_OFF_T size = fsp - > size ;
SMB_OFF_T sizeneeded = startpos + maxcount ;
if ( size < sizeneeded ) {
SMB_STRUCT_STAT st ;
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_FSTAT ( fsp , fsp - > fd , & st ) = = 0 )
2001-09-04 23:10:30 +04:00
size = st . st_size ;
if ( ! fsp - > can_write )
fsp - > size = size ;
}
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
if ( startpos > = size )
nread = 0 ;
else
nread = MIN ( maxcount , ( size - startpos ) ) ;
}
1998-07-31 01:18:57 +04:00
2001-09-04 23:10:30 +04:00
if ( nread < mincount )
nread = 0 ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
DEBUG ( 3 , ( " readbraw fnum=%d start=%.0f max=%d min=%d nread=%d \n " , fsp - > fnum , ( double ) startpos ,
( int ) maxcount , ( int ) mincount , ( int ) nread ) ) ;
1996-05-04 11:50:46 +04:00
2002-09-25 19:19:00 +04:00
send_file_readbraw ( conn , fsp , startpos , nread , mincount , outbuf ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
DEBUG ( 5 , ( " readbraw finished \n " ) ) ;
END_PROFILE ( SMBreadbraw ) ;
return - 1 ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a lockread ( core + protocol ) .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-20 23:28:37 +04:00
int reply_lockread ( connection_struct * conn , char * inbuf , char * outbuf , int length , int dum_buffsiz )
1996-05-04 11:50:46 +04:00
{
2001-08-27 12:19:43 +04:00
ssize_t nread = - 1 ;
char * data ;
int outsize = 0 ;
SMB_OFF_T startpos ;
size_t numtoread ;
NTSTATUS status ;
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
START_PROFILE ( SMBlockread ) ;
1996-05-04 11:50:46 +04:00
2001-08-27 12:19:43 +04:00
CHECK_FSP ( fsp , conn ) ;
CHECK_READ ( fsp ) ;
1996-05-04 11:50:46 +04:00
2001-08-27 12:19:43 +04:00
release_level_2_oplocks_on_change ( fsp ) ;
2000-11-16 03:59:18 +03:00
2001-08-27 12:19:43 +04:00
numtoread = SVAL ( inbuf , smb_vwv1 ) ;
2002-12-03 11:02:41 +03:00
startpos = IVAL_TO_SMB_OFF_T ( inbuf , smb_vwv2 ) ;
1996-05-04 11:50:46 +04:00
2001-08-27 12:19:43 +04:00
outsize = set_message ( outbuf , 5 , 3 , True ) ;
numtoread = MIN ( BUFFER_SIZE - outsize , numtoread ) ;
data = smb_buf ( outbuf ) + 3 ;
/*
* NB . Discovered by Menny Hamburger at Mainsoft . This is a core +
* protocol request that predates the read / write lock concept .
* Thus instead of asking for a read lock here we need to ask
* for a write lock . JRA .
*/
2002-03-13 23:28:19 +03:00
status = do_lock_spin ( fsp , conn , SVAL ( inbuf , smb_pid ) ,
2001-08-27 12:19:43 +04:00
( SMB_BIG_UINT ) numtoread , ( SMB_BIG_UINT ) startpos , WRITE_LOCK ) ;
1999-12-13 16:27:58 +03:00
2001-08-27 21:52:23 +04:00
if ( NT_STATUS_V ( status ) ) {
2002-09-25 19:19:00 +04:00
if ( lp_blocking_locks ( SNUM ( conn ) ) & & ERROR_WAS_LOCK_DENIED ( status ) ) {
2001-08-27 12:19:43 +04:00
/*
* A blocking lock was requested . Package up
* this smb into a queued request and push it
* onto the blocking lock queue .
*/
2003-02-27 04:04:34 +03:00
if ( push_blocking_lock_request ( inbuf , length , - 1 , 0 , SVAL ( inbuf , smb_pid ) , ( SMB_BIG_UINT ) startpos ,
( SMB_BIG_UINT ) numtoread ) ) {
2001-08-27 12:19:43 +04:00
END_PROFILE ( SMBlockread ) ;
2002-09-25 19:19:00 +04:00
return - 1 ;
}
2001-08-27 12:19:43 +04:00
}
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBlockread ) ;
2001-08-27 12:19:43 +04:00
return ERROR_NT ( status ) ;
}
1998-08-01 02:39:15 +04:00
2001-08-27 12:19:43 +04:00
nread = read_file ( fsp , data , startpos , numtoread ) ;
1998-08-01 02:39:15 +04:00
2001-08-27 12:19:43 +04:00
if ( nread < 0 ) {
END_PROFILE ( SMBlockread ) ;
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
}
outsize + = nread ;
SSVAL ( outbuf , smb_vwv0 , nread ) ;
SSVAL ( outbuf , smb_vwv5 , nread + 3 ) ;
SSVAL ( smb_buf ( outbuf ) , 1 , nread ) ;
DEBUG ( 3 , ( " lockread fnum=%d num=%d nread=%d \n " ,
fsp - > fnum , ( int ) numtoread , ( int ) nread ) ) ;
1998-08-01 02:39:15 +04:00
2001-08-27 12:19:43 +04:00
END_PROFILE ( SMBlockread ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a read .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
int reply_read ( connection_struct * conn , char * inbuf , char * outbuf , int size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-09-25 19:19:00 +04:00
size_t numtoread ;
ssize_t nread = 0 ;
char * data ;
SMB_OFF_T startpos ;
int outsize = 0 ;
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
START_PROFILE ( SMBread ) ;
1996-05-04 11:50:46 +04:00
2002-09-25 19:19:00 +04:00
CHECK_FSP ( fsp , conn ) ;
CHECK_READ ( fsp ) ;
2001-08-27 12:19:43 +04:00
2002-09-25 19:19:00 +04:00
numtoread = SVAL ( inbuf , smb_vwv1 ) ;
2002-12-03 11:02:41 +03:00
startpos = IVAL_TO_SMB_OFF_T ( inbuf , smb_vwv2 ) ;
2001-08-27 12:19:43 +04:00
2002-09-25 19:19:00 +04:00
outsize = set_message ( outbuf , 5 , 3 , True ) ;
numtoread = MIN ( BUFFER_SIZE - outsize , numtoread ) ;
data = smb_buf ( outbuf ) + 3 ;
1996-05-04 11:50:46 +04:00
2002-09-25 19:19:00 +04:00
if ( is_locked ( fsp , conn , ( SMB_BIG_UINT ) numtoread , ( SMB_BIG_UINT ) startpos , READ_LOCK , False ) ) {
END_PROFILE ( SMBread ) ;
return ERROR_DOS ( ERRDOS , ERRlock ) ;
}
1996-05-04 11:50:46 +04:00
2002-09-25 19:19:00 +04:00
if ( numtoread > 0 )
nread = read_file ( fsp , data , startpos , numtoread ) ;
2001-08-27 12:19:43 +04:00
2002-09-25 19:19:00 +04:00
if ( nread < 0 ) {
END_PROFILE ( SMBread ) ;
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
}
1996-05-04 11:50:46 +04:00
2002-09-25 19:19:00 +04:00
outsize + = nread ;
SSVAL ( outbuf , smb_vwv0 , nread ) ;
SSVAL ( outbuf , smb_vwv5 , nread + 3 ) ;
SCVAL ( smb_buf ( outbuf ) , 0 , 1 ) ;
SSVAL ( smb_buf ( outbuf ) , 1 , nread ) ;
1996-05-04 11:50:46 +04:00
2002-09-25 19:19:00 +04:00
DEBUG ( 3 , ( " read fnum=%d num=%d nread=%d \n " ,
fsp - > fnum , ( int ) numtoread , ( int ) nread ) ) ;
1998-08-01 02:39:15 +04:00
2002-09-25 19:19:00 +04:00
END_PROFILE ( SMBread ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
2002-09-25 19:19:00 +04:00
/****************************************************************************
Reply to a read and X - possibly using sendfile .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int send_file_readX ( connection_struct * conn , char * inbuf , char * outbuf , int length ,
files_struct * fsp , SMB_OFF_T startpos , size_t smb_maxcnt )
{
ssize_t nread = - 1 ;
char * data = smb_buf ( outbuf ) ;
# if defined(WITH_SENDFILE)
/*
* We can only use sendfile on a non - chained packet and on a file
* that is exclusively oplocked .
*/
if ( ( CVAL ( inbuf , smb_vwv0 ) = = 0xFF ) & & EXCLUSIVE_OPLOCK_TYPE ( fsp - > oplock_type ) & &
lp_use_sendfile ( SNUM ( conn ) ) & & ( lp_write_cache_size ( SNUM ( conn ) ) = = 0 ) ) {
SMB_STRUCT_STAT sbuf ;
DATA_BLOB header ;
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_FSTAT ( fsp , fsp - > fd , & sbuf ) = = - 1 )
2002-09-25 19:19:00 +04:00
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
if ( startpos > sbuf . st_size )
goto normal_read ;
if ( smb_maxcnt > ( sbuf . st_size - startpos ) )
smb_maxcnt = ( sbuf . st_size - startpos ) ;
if ( smb_maxcnt = = 0 )
goto normal_read ;
/*
* Set up the packet header before send . We
* assume here the sendfile will work ( get the
* correct amount of data ) .
*/
SSVAL ( outbuf , smb_vwv5 , smb_maxcnt ) ;
SSVAL ( outbuf , smb_vwv6 , smb_offset ( data , outbuf ) ) ;
SSVAL ( smb_buf ( outbuf ) , - 2 , smb_maxcnt ) ;
SCVAL ( outbuf , smb_vwv0 , 0xFF ) ;
set_message ( outbuf , 12 , smb_maxcnt , False ) ;
header . data = outbuf ;
header . length = data - outbuf ;
header . free = NULL ;
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_SENDFILE ( smbd_server_fd ( ) , fsp , fsp - > fd , & header , startpos , smb_maxcnt ) = = - 1 ) {
2002-09-25 19:19:00 +04:00
/*
* Special hack for broken Linux with no 64 bit clean sendfile . If we
* return ENOSYS then pretend we just got a normal read .
*/
if ( errno = = ENOSYS )
goto normal_read ;
DEBUG ( 0 , ( " send_file_readX: sendfile failed for file %s (%s). Terminating \n " ,
fsp - > fsp_name , strerror ( errno ) ) ) ;
exit_server ( " send_file_readX sendfile failed " ) ;
}
DEBUG ( 3 , ( " send_file_readX: sendfile fnum=%d max=%d nread=%d \n " ,
fsp - > fnum , ( int ) smb_maxcnt , ( int ) nread ) ) ;
return - 1 ;
}
normal_read :
# endif
nread = read_file ( fsp , data , startpos , smb_maxcnt ) ;
if ( nread < 0 ) {
END_PROFILE ( SMBreadX ) ;
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
}
SSVAL ( outbuf , smb_vwv5 , nread ) ;
SSVAL ( outbuf , smb_vwv6 , smb_offset ( data , outbuf ) ) ;
SSVAL ( smb_buf ( outbuf ) , - 2 , nread ) ;
DEBUG ( 3 , ( " send_file_readX fnum=%d max=%d nread=%d \n " ,
fsp - > fnum , ( int ) smb_maxcnt , ( int ) nread ) ) ;
return nread ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a read and X .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_read_and_X ( connection_struct * conn , char * inbuf , char * outbuf , int length , int bufsize )
1996-05-04 11:50:46 +04:00
{
2002-09-25 19:19:00 +04:00
files_struct * fsp = file_fsp ( inbuf , smb_vwv2 ) ;
2002-12-03 11:02:41 +03:00
SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T ( inbuf , smb_vwv3 ) ;
2002-09-25 19:19:00 +04:00
ssize_t nread = - 1 ;
size_t smb_maxcnt = SVAL ( inbuf , smb_vwv5 ) ;
#if 0
size_t smb_mincnt = SVAL ( inbuf , smb_vwv6 ) ;
# endif
1996-05-04 11:50:46 +04:00
2002-09-25 19:19:00 +04:00
START_PROFILE ( SMBreadX ) ;
1998-03-12 02:20:26 +03:00
2002-09-25 19:19:00 +04:00
/* If it's an IPC, pass off the pipe handler. */
if ( IS_IPC ( conn ) ) {
END_PROFILE ( SMBreadX ) ;
return reply_pipe_read_and_X ( inbuf , outbuf , length , bufsize ) ;
}
CHECK_FSP ( fsp , conn ) ;
CHECK_READ ( fsp ) ;
1996-05-04 11:50:46 +04:00
2002-09-25 19:19:00 +04:00
set_message ( outbuf , 12 , 0 , True ) ;
1996-05-04 11:50:46 +04:00
2002-09-25 19:19:00 +04:00
if ( CVAL ( inbuf , smb_wct ) = = 12 ) {
1999-12-13 16:27:58 +03:00
# ifdef LARGE_SMB_OFF_T
2002-09-25 19:19:00 +04:00
/*
* This is a large offset ( 64 bit ) read .
*/
startpos | = ( ( ( SMB_OFF_T ) IVAL ( inbuf , smb_vwv10 ) ) < < 32 ) ;
1999-12-13 16:27:58 +03:00
# else /* !LARGE_SMB_OFF_T */
2002-09-25 19:19:00 +04:00
/*
* Ensure we haven ' t been sent a > 32 bit offset .
*/
1999-12-13 16:27:58 +03:00
2002-09-25 19:19:00 +04:00
if ( IVAL ( inbuf , smb_vwv10 ) ! = 0 ) {
DEBUG ( 0 , ( " reply_read_and_X - large offset (%x << 32) used and we don't support \
1999-12-13 16:27:58 +03:00
64 bit offsets . \ n " , (unsigned int)IVAL(inbuf,smb_vwv10) ));
2002-09-25 19:19:00 +04:00
END_PROFILE ( SMBreadX ) ;
return ERROR_DOS ( ERRDOS , ERRbadaccess ) ;
}
1999-12-13 16:27:58 +03:00
1998-09-11 23:14:27 +04:00
# endif /* LARGE_SMB_OFF_T */
1998-09-11 05:24:30 +04:00
2002-09-25 19:19:00 +04:00
}
1999-12-13 16:27:58 +03:00
2002-09-25 19:19:00 +04:00
if ( is_locked ( fsp , conn , ( SMB_BIG_UINT ) smb_maxcnt , ( SMB_BIG_UINT ) startpos , READ_LOCK , False ) ) {
END_PROFILE ( SMBreadX ) ;
return ERROR_DOS ( ERRDOS , ERRlock ) ;
}
2001-08-27 12:19:43 +04:00
2002-09-25 19:19:00 +04:00
nread = send_file_readX ( conn , inbuf , outbuf , length , fsp , startpos , smb_maxcnt ) ;
if ( nread ! = - 1 )
nread = chain_reply ( inbuf , outbuf , length , bufsize ) ;
1996-05-04 11:50:46 +04:00
2002-09-25 19:19:00 +04:00
END_PROFILE ( SMBreadX ) ;
return nread ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a writebraw ( core + or LANMAN1 .0 protocol ) .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
int reply_writebraw ( connection_struct * conn , char * inbuf , char * outbuf , int size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2001-09-04 23:10:30 +04:00
ssize_t nwritten = 0 ;
ssize_t total_written = 0 ;
size_t numtowrite = 0 ;
size_t tcount ;
SMB_OFF_T startpos ;
char * data = NULL ;
BOOL write_through ;
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
int outsize = 0 ;
START_PROFILE ( SMBwritebraw ) ;
1996-05-04 11:50:46 +04:00
2003-07-18 04:53:34 +04:00
if ( srv_is_signing_active ( ) ) {
2003-07-17 04:53:37 +04:00
exit_server ( " reply_readbraw: SMB signing is active - raw reads/writes are disallowed. " ) ;
}
2001-09-04 23:10:30 +04:00
CHECK_FSP ( fsp , conn ) ;
CHECK_WRITE ( fsp ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
tcount = IVAL ( inbuf , smb_vwv1 ) ;
2002-12-03 11:02:41 +03:00
startpos = IVAL_TO_SMB_OFF_T ( inbuf , smb_vwv3 ) ;
2001-09-04 23:10:30 +04:00
write_through = BITSETW ( inbuf + smb_vwv7 , 0 ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
/* We have to deal with slightly different formats depending
on whether we are using the core + or lanman1 .0 protocol */
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
if ( Protocol < = PROTOCOL_COREPLUS ) {
numtowrite = SVAL ( smb_buf ( inbuf ) , - 2 ) ;
data = smb_buf ( inbuf ) ;
} else {
numtowrite = SVAL ( inbuf , smb_vwv10 ) ;
data = smb_base ( inbuf ) + SVAL ( inbuf , smb_vwv11 ) ;
}
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
/* force the error type */
2002-01-11 22:10:25 +03:00
SCVAL ( inbuf , smb_com , SMBwritec ) ;
SCVAL ( outbuf , smb_com , SMBwritec ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
if ( is_locked ( fsp , conn , ( SMB_BIG_UINT ) tcount , ( SMB_BIG_UINT ) startpos , WRITE_LOCK , False ) ) {
END_PROFILE ( SMBwritebraw ) ;
return ( ERROR_DOS ( ERRDOS , ERRlock ) ) ;
}
if ( numtowrite > 0 )
nwritten = write_file ( fsp , data , startpos , numtowrite ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
DEBUG ( 3 , ( " writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d \n " ,
fsp - > fnum , ( double ) startpos , ( int ) numtowrite , ( int ) nwritten , ( int ) write_through ) ) ;
1996-05-04 11:50:46 +04:00
2002-12-31 13:25:11 +03:00
if ( nwritten < ( ssize_t ) numtowrite ) {
2001-09-04 23:10:30 +04:00
END_PROFILE ( SMBwritebraw ) ;
return ( UNIXERROR ( ERRHRD , ERRdiskfull ) ) ;
}
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
total_written = nwritten ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
/* Return a message to the redirector to tell it to send more bytes */
2002-01-11 22:10:25 +03:00
SCVAL ( outbuf , smb_com , SMBwritebraw ) ;
2001-09-04 23:10:30 +04:00
SSVALS ( outbuf , smb_vwv0 , - 1 ) ;
outsize = set_message ( outbuf , Protocol > PROTOCOL_COREPLUS ? 1 : 0 , 0 , True ) ;
if ( ! send_smb ( smbd_server_fd ( ) , outbuf ) )
2001-11-05 03:02:38 +03:00
exit_server ( " reply_writebraw: send_smb failed. " ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
/* Now read the raw data into the buffer and write it */
if ( read_smb_length ( smbd_server_fd ( ) , inbuf , SMB_SECONDARY_WAIT ) = = - 1 ) {
exit_server ( " secondary writebraw failed " ) ;
}
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
/* Even though this is not an smb message, smb_len returns the generic length of an smb message */
numtowrite = smb_len ( inbuf ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
/* Set up outbuf to return the correct return */
outsize = set_message ( outbuf , 1 , 0 , True ) ;
2002-01-11 22:10:25 +03:00
SCVAL ( outbuf , smb_com , SMBwritec ) ;
2001-09-04 23:10:30 +04:00
SSVAL ( outbuf , smb_vwv0 , total_written ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
if ( numtowrite ! = 0 ) {
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
if ( numtowrite > BUFFER_SIZE ) {
DEBUG ( 0 , ( " reply_writebraw: Oversize secondary write raw requested (%u). Terminating \n " ,
( unsigned int ) numtowrite ) ) ;
exit_server ( " secondary writebraw failed " ) ;
}
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
if ( tcount > nwritten + numtowrite ) {
DEBUG ( 3 , ( " Client overestimated the write %d %d %d \n " ,
( int ) tcount , ( int ) nwritten , ( int ) numtowrite ) ) ;
}
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
if ( read_data ( smbd_server_fd ( ) , inbuf + 4 , numtowrite ) ! = numtowrite ) {
DEBUG ( 0 , ( " reply_writebraw: Oversize secondary write raw read failed (%s). Terminating \n " ,
strerror ( errno ) ) ) ;
exit_server ( " secondary writebraw failed " ) ;
}
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
nwritten = write_file ( fsp , inbuf + 4 , startpos + nwritten , numtowrite ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
if ( nwritten < ( ssize_t ) numtowrite ) {
2002-01-11 22:10:25 +03:00
SCVAL ( outbuf , smb_rcls , ERRHRD ) ;
2001-09-04 23:10:30 +04:00
SSVAL ( outbuf , smb_err , ERRdiskfull ) ;
}
if ( nwritten > 0 )
total_written + = nwritten ;
}
if ( ( lp_syncalways ( SNUM ( conn ) ) | | write_through ) & & lp_strict_sync ( SNUM ( conn ) ) )
sync_file ( conn , fsp ) ;
DEBUG ( 3 , ( " writebraw2 fnum=%d start=%.0f num=%d wrote=%d \n " ,
fsp - > fnum , ( double ) startpos , ( int ) numtowrite , ( int ) total_written ) ) ;
/* we won't return a status if write through is not selected - this follows what WfWg does */
END_PROFILE ( SMBwritebraw ) ;
if ( ! write_through & & total_written = = tcount ) {
2002-04-11 06:20:56 +04:00
# if RABBIT_PELLET_FIX
2001-09-04 23:10:30 +04:00
/*
* Fix for " rabbit pellet " mode , trigger an early TCP ack by
* sending a SMBkeepalive . Thanks to DaveCB at Sun for this . JRA .
*/
if ( ! send_keepalive ( smbd_server_fd ( ) ) )
exit_server ( " reply_writebraw: send of keepalive failed " ) ;
2002-04-11 06:20:56 +04:00
# endif
2001-09-04 23:10:30 +04:00
return ( - 1 ) ;
}
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a writeunlock ( core + ) .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2001-08-27 12:19:43 +04:00
int reply_writeunlock ( connection_struct * conn , char * inbuf , char * outbuf ,
int size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2001-08-27 12:19:43 +04:00
ssize_t nwritten = - 1 ;
size_t numtowrite ;
SMB_OFF_T startpos ;
char * data ;
NTSTATUS status ;
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
int outsize = 0 ;
START_PROFILE ( SMBwriteunlock ) ;
CHECK_FSP ( fsp , conn ) ;
CHECK_WRITE ( fsp ) ;
1996-05-04 11:50:46 +04:00
2001-08-27 12:19:43 +04:00
numtowrite = SVAL ( inbuf , smb_vwv1 ) ;
2002-12-03 11:02:41 +03:00
startpos = IVAL_TO_SMB_OFF_T ( inbuf , smb_vwv2 ) ;
2001-08-27 12:19:43 +04:00
data = smb_buf ( inbuf ) + 3 ;
1996-05-04 11:50:46 +04:00
2001-08-27 12:19:43 +04:00
if ( is_locked ( fsp , conn , ( SMB_BIG_UINT ) numtowrite , ( SMB_BIG_UINT ) startpos ,
WRITE_LOCK , False ) ) {
END_PROFILE ( SMBwriteunlock ) ;
return ERROR_DOS ( ERRDOS , ERRlock ) ;
}
2001-08-07 05:19:32 +04:00
2001-08-27 12:19:43 +04:00
/* The special X/Open SMB protocol handling of
zero length writes is * NOT * done for
this call */
if ( numtowrite = = 0 )
nwritten = 0 ;
else
nwritten = write_file ( fsp , data , startpos , numtowrite ) ;
if ( lp_syncalways ( SNUM ( conn ) ) )
sync_file ( conn , fsp ) ;
if ( ( ( nwritten = = 0 ) & & ( numtowrite ! = 0 ) ) | | ( nwritten < 0 ) ) {
END_PROFILE ( SMBwriteunlock ) ;
2003-01-09 02:49:21 +03:00
return ( UNIXERROR ( ERRHRD , ERRdiskfull ) ) ;
2001-08-07 05:19:32 +04:00
}
2001-08-27 12:19:43 +04:00
status = do_unlock ( fsp , conn , SVAL ( inbuf , smb_pid ) , ( SMB_BIG_UINT ) numtowrite ,
( SMB_BIG_UINT ) startpos ) ;
2001-08-27 21:52:23 +04:00
if ( NT_STATUS_V ( status ) ) {
2001-08-27 12:19:43 +04:00
END_PROFILE ( SMBwriteunlock ) ;
return ERROR_NT ( status ) ;
}
outsize = set_message ( outbuf , 1 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , nwritten ) ;
DEBUG ( 3 , ( " writeunlock fnum=%d num=%d wrote=%d \n " ,
fsp - > fnum , ( int ) numtowrite , ( int ) nwritten ) ) ;
END_PROFILE ( SMBwriteunlock ) ;
return outsize ;
2001-08-07 05:19:32 +04:00
}
/****************************************************************************
Reply to a write .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
int reply_write ( connection_struct * conn , char * inbuf , char * outbuf , int size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2001-11-25 05:23:22 +03:00
size_t numtowrite ;
ssize_t nwritten = - 1 ;
SMB_OFF_T startpos ;
char * data ;
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
int outsize = 0 ;
START_PROFILE ( SMBwrite ) ;
1996-05-04 11:50:46 +04:00
2001-11-25 05:23:22 +03:00
/* If it's an IPC, pass off the pipe handler. */
if ( IS_IPC ( conn ) ) {
END_PROFILE ( SMBwrite ) ;
return reply_pipe_write ( inbuf , outbuf , size , dum_buffsize ) ;
}
1999-11-16 01:11:10 +03:00
2001-11-25 05:23:22 +03:00
CHECK_FSP ( fsp , conn ) ;
CHECK_WRITE ( fsp ) ;
1996-05-04 11:50:46 +04:00
2001-11-25 05:23:22 +03:00
numtowrite = SVAL ( inbuf , smb_vwv1 ) ;
2002-12-03 11:02:41 +03:00
startpos = IVAL_TO_SMB_OFF_T ( inbuf , smb_vwv2 ) ;
2001-11-25 05:23:22 +03:00
data = smb_buf ( inbuf ) + 3 ;
1996-05-04 11:50:46 +04:00
2001-11-25 05:23:22 +03:00
if ( is_locked ( fsp , conn , ( SMB_BIG_UINT ) numtowrite , ( SMB_BIG_UINT ) startpos , WRITE_LOCK , False ) ) {
END_PROFILE ( SMBwrite ) ;
return ERROR_DOS ( ERRDOS , ERRlock ) ;
}
1996-05-04 11:50:46 +04:00
2001-11-25 05:23:22 +03:00
/*
* X / Open SMB protocol says that if smb_vwv1 is
* zero then the file size should be extended or
* truncated to the size given in smb_vwv [ 2 - 3 ] .
*/
if ( numtowrite = = 0 ) {
/*
* This is actually an allocate call , and set EOF . JRA .
*/
nwritten = vfs_allocate_file_space ( fsp , ( SMB_OFF_T ) startpos ) ;
if ( nwritten < 0 ) {
END_PROFILE ( SMBwrite ) ;
return ERROR_NT ( NT_STATUS_DISK_FULL ) ;
}
nwritten = vfs_set_filelen ( fsp , ( SMB_OFF_T ) startpos ) ;
if ( nwritten < 0 ) {
END_PROFILE ( SMBwrite ) ;
return ERROR_NT ( NT_STATUS_DISK_FULL ) ;
}
} else
nwritten = write_file ( fsp , data , startpos , numtowrite ) ;
1996-05-04 11:50:46 +04:00
2001-11-25 05:23:22 +03:00
if ( lp_syncalways ( SNUM ( conn ) ) )
sync_file ( conn , fsp ) ;
1996-05-04 11:50:46 +04:00
2001-11-25 05:23:22 +03:00
if ( ( ( nwritten = = 0 ) & & ( numtowrite ! = 0 ) ) | | ( nwritten < 0 ) ) {
END_PROFILE ( SMBwrite ) ;
2003-01-09 02:49:21 +03:00
return ( UNIXERROR ( ERRHRD , ERRdiskfull ) ) ;
2001-11-25 05:23:22 +03:00
}
1996-05-04 11:50:46 +04:00
2001-11-25 05:23:22 +03:00
outsize = set_message ( outbuf , 1 , 0 , True ) ;
1996-05-04 11:50:46 +04:00
2001-11-25 05:23:22 +03:00
SSVAL ( outbuf , smb_vwv0 , nwritten ) ;
1996-05-04 11:50:46 +04:00
2001-11-25 05:23:22 +03:00
if ( nwritten < ( ssize_t ) numtowrite ) {
2002-01-11 22:10:25 +03:00
SCVAL ( outbuf , smb_rcls , ERRHRD ) ;
2001-11-25 05:23:22 +03:00
SSVAL ( outbuf , smb_err , ERRdiskfull ) ;
}
1996-05-04 11:50:46 +04:00
2001-11-25 05:23:22 +03:00
DEBUG ( 3 , ( " write fnum=%d num=%d wrote=%d \n " , fsp - > fnum , ( int ) numtowrite , ( int ) nwritten ) ) ;
1998-08-01 02:39:15 +04:00
2001-11-25 05:23:22 +03:00
END_PROFILE ( SMBwrite ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a write and X .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_write_and_X ( connection_struct * conn , char * inbuf , char * outbuf , int length , int bufsize )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
files_struct * fsp = file_fsp ( inbuf , smb_vwv2 ) ;
SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T ( inbuf , smb_vwv3 ) ;
size_t numtowrite = SVAL ( inbuf , smb_vwv10 ) ;
BOOL write_through = BITSETW ( inbuf + smb_vwv7 , 0 ) ;
ssize_t nwritten = - 1 ;
unsigned int smb_doff = SVAL ( inbuf , smb_vwv11 ) ;
unsigned int smblen = smb_len ( inbuf ) ;
char * data ;
BOOL large_writeX = ( ( CVAL ( inbuf , smb_wct ) = = 14 ) & & ( smblen > 0xFFFF ) ) ;
START_PROFILE ( SMBwriteX ) ;
/* If it's an IPC, pass off the pipe handler. */
if ( IS_IPC ( conn ) ) {
END_PROFILE ( SMBwriteX ) ;
return reply_pipe_write_and_X ( inbuf , outbuf , length , bufsize ) ;
}
CHECK_FSP ( fsp , conn ) ;
CHECK_WRITE ( fsp ) ;
/* Deal with possible LARGE_WRITEX */
if ( large_writeX )
numtowrite | = ( ( ( ( size_t ) SVAL ( inbuf , smb_vwv9 ) ) & 1 ) < < 16 ) ;
if ( smb_doff > smblen | | ( smb_doff + numtowrite > smblen ) ) {
END_PROFILE ( SMBwriteX ) ;
return ERROR_DOS ( ERRDOS , ERRbadmem ) ;
}
data = smb_base ( inbuf ) + smb_doff ;
if ( CVAL ( inbuf , smb_wct ) = = 14 ) {
1999-12-13 16:27:58 +03:00
# ifdef LARGE_SMB_OFF_T
2002-12-04 02:57:45 +03:00
/*
* This is a large offset ( 64 bit ) write .
*/
startpos | = ( ( ( SMB_OFF_T ) IVAL ( inbuf , smb_vwv12 ) ) < < 32 ) ;
1999-12-13 16:27:58 +03:00
# else /* !LARGE_SMB_OFF_T */
2002-12-04 02:57:45 +03:00
/*
* Ensure we haven ' t been sent a > 32 bit offset .
*/
1999-12-13 16:27:58 +03:00
2002-12-04 02:57:45 +03:00
if ( IVAL ( inbuf , smb_vwv12 ) ! = 0 ) {
DEBUG ( 0 , ( " reply_write_and_X - large offset (%x << 32) used and we don't support \
1999-12-13 16:27:58 +03:00
64 bit offsets . \ n " , (unsigned int)IVAL(inbuf,smb_vwv12) ));
2002-12-04 02:57:45 +03:00
END_PROFILE ( SMBwriteX ) ;
return ERROR_DOS ( ERRDOS , ERRbadaccess ) ;
}
1999-12-13 16:27:58 +03:00
1998-09-11 23:14:27 +04:00
# endif /* LARGE_SMB_OFF_T */
2002-12-04 02:57:45 +03:00
}
if ( is_locked ( fsp , conn , ( SMB_BIG_UINT ) numtowrite , ( SMB_BIG_UINT ) startpos , WRITE_LOCK , False ) ) {
END_PROFILE ( SMBwriteX ) ;
return ERROR_DOS ( ERRDOS , ERRlock ) ;
}
/* X/Open SMB protocol says that, unlike SMBwrite
if the length is zero then NO truncation is
done , just a write of zero . To truncate a file ,
use SMBwrite . */
if ( numtowrite = = 0 )
nwritten = 0 ;
else
nwritten = write_file ( fsp , data , startpos , numtowrite ) ;
if ( ( ( nwritten = = 0 ) & & ( numtowrite ! = 0 ) ) | | ( nwritten < 0 ) ) {
END_PROFILE ( SMBwriteX ) ;
2003-01-09 02:49:21 +03:00
return ( UNIXERROR ( ERRHRD , ERRdiskfull ) ) ;
2002-12-04 02:57:45 +03:00
}
set_message ( outbuf , 6 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv2 , nwritten ) ;
if ( large_writeX )
SSVAL ( outbuf , smb_vwv4 , ( nwritten > > 16 ) & 1 ) ;
if ( nwritten < ( ssize_t ) numtowrite ) {
SCVAL ( outbuf , smb_rcls , ERRHRD ) ;
SSVAL ( outbuf , smb_err , ERRdiskfull ) ;
}
DEBUG ( 3 , ( " writeX fnum=%d num=%d wrote=%d \n " ,
fsp - > fnum , ( int ) numtowrite , ( int ) nwritten ) ) ;
if ( lp_syncalways ( SNUM ( conn ) ) | | write_through )
sync_file ( conn , fsp ) ;
END_PROFILE ( SMBwriteX ) ;
return chain_reply ( inbuf , outbuf , length , bufsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a lseek .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
int reply_lseek ( connection_struct * conn , char * inbuf , char * outbuf , int size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
SMB_OFF_T startpos ;
SMB_OFF_T res = - 1 ;
int mode , umode ;
int outsize = 0 ;
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
START_PROFILE ( SMBlseek ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
CHECK_FSP ( fsp , conn ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
flush_write_cache ( fsp , SEEK_FLUSH ) ;
1999-12-13 16:27:58 +03:00
2002-12-04 02:57:45 +03:00
mode = SVAL ( inbuf , smb_vwv1 ) & 3 ;
/* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
startpos = ( SMB_OFF_T ) IVALS ( inbuf , smb_vwv2 ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
switch ( mode ) {
case 0 :
umode = SEEK_SET ;
2003-08-15 01:16:06 +04:00
res = startpos ;
2002-12-04 02:57:45 +03:00
break ;
case 1 :
umode = SEEK_CUR ;
2003-08-15 01:16:06 +04:00
res = fsp - > pos + startpos ;
2002-12-04 02:57:45 +03:00
break ;
case 2 :
umode = SEEK_END ;
break ;
default :
umode = SEEK_SET ;
2003-08-15 01:16:06 +04:00
res = startpos ;
2002-12-04 02:57:45 +03:00
break ;
}
1998-07-31 01:18:57 +04:00
2003-08-15 01:16:06 +04:00
if ( umode = = SEEK_END ) {
if ( ( res = SMB_VFS_LSEEK ( fsp , fsp - > fd , startpos , umode ) ) = = - 1 ) {
if ( errno = = EINVAL ) {
SMB_OFF_T current_pos = startpos ;
2002-12-04 02:57:45 +03:00
SMB_STRUCT_STAT sbuf ;
1999-12-13 16:27:58 +03:00
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_FSTAT ( fsp , fsp - > fd , & sbuf ) = = - 1 ) {
2002-12-04 02:57:45 +03:00
END_PROFILE ( SMBlseek ) ;
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
}
1999-12-13 16:27:58 +03:00
2002-12-04 02:57:45 +03:00
current_pos + = sbuf . st_size ;
2003-08-15 01:16:06 +04:00
if ( current_pos < 0 )
res = SMB_VFS_LSEEK ( fsp , fsp - > fd , 0 , SEEK_SET ) ;
2002-12-04 02:57:45 +03:00
}
}
1999-12-13 16:27:58 +03:00
2002-12-04 02:57:45 +03:00
if ( res = = - 1 ) {
END_PROFILE ( SMBlseek ) ;
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
}
}
1998-10-19 02:06:35 +04:00
2002-12-04 02:57:45 +03:00
fsp - > pos = res ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
outsize = set_message ( outbuf , 2 , 0 , True ) ;
SIVAL ( outbuf , smb_vwv0 , res ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
DEBUG ( 3 , ( " lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d \n " ,
fsp - > fnum , ( double ) startpos , ( double ) res , mode ) ) ;
1998-08-01 02:39:15 +04:00
2002-12-04 02:57:45 +03:00
END_PROFILE ( SMBlseek ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a flush .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
int reply_flush ( connection_struct * conn , char * inbuf , char * outbuf , int size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2001-08-24 08:56:33 +04:00
int outsize = set_message ( outbuf , 0 , 0 , True ) ;
2003-08-19 05:26:43 +04:00
uint16 fnum = SVAL ( inbuf , smb_vwv0 ) ;
2001-08-24 08:56:33 +04:00
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
START_PROFILE ( SMBflush ) ;
1996-05-04 11:50:46 +04:00
2003-08-19 05:26:43 +04:00
if ( fnum ! = 0xFFFF )
CHECK_FSP ( fsp , conn ) ;
2001-08-24 08:56:33 +04:00
if ( ! fsp ) {
file_sync_all ( conn ) ;
} else {
2000-05-10 05:31:46 +04:00
sync_file ( conn , fsp ) ;
2001-08-24 08:56:33 +04:00
}
DEBUG ( 3 , ( " flush \n " ) ) ;
END_PROFILE ( SMBflush ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a exit .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_exit ( connection_struct * conn ,
char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2000-10-06 07:21:49 +04:00
int outsize ;
START_PROFILE ( SMBexit ) ;
2003-08-19 05:53:45 +04:00
file_close_pid ( SVAL ( inbuf , smb_pid ) ) ;
2000-10-06 07:21:49 +04:00
outsize = set_message ( outbuf , 0 , 0 , True ) ;
1998-08-14 21:38:29 +04:00
DEBUG ( 3 , ( " exit \n " ) ) ;
1998-08-01 02:39:15 +04:00
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBexit ) ;
1998-08-14 21:38:29 +04:00
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
1998-07-18 02:21:24 +04:00
Reply to a close - has to deal with closing a directory opened by NT SMB ' s .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1999-12-13 16:27:58 +03:00
int reply_close ( connection_struct * conn , char * inbuf , char * outbuf , int size ,
int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2003-04-10 02:31:37 +04:00
extern struct current_user current_user ;
1998-08-14 21:38:29 +04:00
int outsize = 0 ;
time_t mtime ;
int32 eclass = 0 , err = 0 ;
files_struct * fsp = NULL ;
2000-10-06 07:21:49 +04:00
START_PROFILE ( SMBclose ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
outsize = set_message ( outbuf , 0 , 0 , True ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
/* If it's an IPC, pass off to the pipe handler. */
2000-10-06 07:21:49 +04:00
if ( IS_IPC ( conn ) ) {
END_PROFILE ( SMBclose ) ;
1998-08-14 21:38:29 +04:00
return reply_pipe_close ( conn , inbuf , outbuf ) ;
2000-10-06 07:21:49 +04:00
}
1997-10-30 04:05:13 +03:00
1998-08-17 07:52:05 +04:00
fsp = file_fsp ( inbuf , smb_vwv0 ) ;
1997-10-30 04:05:13 +03:00
1998-08-14 21:38:29 +04:00
/*
1998-08-15 11:27:34 +04:00
* We can only use CHECK_FSP if we know it ' s not a directory .
1998-08-14 21:38:29 +04:00
*/
1998-07-18 02:21:24 +04:00
2003-04-10 02:31:37 +04:00
if ( ! fsp | | ( fsp - > conn ! = conn ) | | ( fsp - > vuid ! = current_user . vuid ) ) {
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBclose ) ;
2001-08-27 12:19:43 +04:00
return ERROR_DOS ( ERRDOS , ERRbadfid ) ;
1998-08-14 21:38:29 +04:00
}
1996-05-04 11:50:46 +04:00
2002-03-20 03:46:53 +03:00
if ( fsp - > is_directory ) {
1998-08-14 21:38:29 +04:00
/*
2002-03-20 03:46:53 +03:00
* Special case - close NT SMB directory handle .
1998-08-14 21:38:29 +04:00
*/
1999-12-13 16:27:58 +03:00
DEBUG ( 3 , ( " close %s fnum=%d \n " , fsp - > is_directory ? " directory " : " stat file open " , fsp - > fnum ) ) ;
close_file ( fsp , True ) ;
1998-08-14 21:38:29 +04:00
} else {
/*
* Close ordinary file .
*/
1999-12-13 16:27:58 +03:00
int close_err ;
2001-12-17 00:04:19 +03:00
pstring file_name ;
1998-11-18 02:44:52 +03:00
2001-12-17 00:04:19 +03:00
/* Save the name for time set in close. */
pstrcpy ( file_name , fsp - > fsp_name ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
DEBUG ( 3 , ( " close fd=%d fnum=%d (numopen=%d) \n " ,
2000-04-10 17:05:23 +04:00
fsp - > fd , fsp - > fnum ,
1998-08-14 21:38:29 +04:00
conn - > num_files_open ) ) ;
1999-12-13 16:27:58 +03:00
/*
* close_file ( ) returns the unix errno if an error
* was detected on close - normally this is due to
* a disk full error . If not then it was probably an I / O error .
*/
if ( ( close_err = close_file ( fsp , True ) ) ! = 0 ) {
errno = close_err ;
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBclose ) ;
1999-12-13 16:27:58 +03:00
return ( UNIXERROR ( ERRHRD , ERRgeneral ) ) ;
}
2001-12-17 00:04:19 +03:00
/*
* Now take care of any time sent in the close .
*/
mtime = make_unix_date3 ( inbuf + smb_vwv1 ) ;
/* try and set the date */
set_filetime ( conn , file_name , mtime ) ;
1998-08-14 21:38:29 +04:00
}
1996-06-04 10:42:03 +04:00
1998-08-14 21:38:29 +04:00
/* We have a cached error */
2000-10-06 07:21:49 +04:00
if ( eclass | | err ) {
END_PROFILE ( SMBclose ) ;
2001-08-27 12:19:43 +04:00
return ERROR_DOS ( eclass , err ) ;
2000-10-06 07:21:49 +04:00
}
1996-05-04 11:50:46 +04:00
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBclose ) ;
1998-08-14 21:38:29 +04:00
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a writeclose ( Core + protocol ) .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
1998-08-14 21:38:29 +04:00
int reply_writeclose ( connection_struct * conn ,
1999-12-13 16:27:58 +03:00
char * inbuf , char * outbuf , int size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
1998-09-11 05:24:30 +04:00
size_t numtowrite ;
ssize_t nwritten = - 1 ;
1998-08-14 21:38:29 +04:00
int outsize = 0 ;
1999-12-13 16:27:58 +03:00
int close_err = 0 ;
1998-09-11 05:24:30 +04:00
SMB_OFF_T startpos ;
1998-08-14 21:38:29 +04:00
char * data ;
time_t mtime ;
1998-08-17 07:52:05 +04:00
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
2000-10-06 07:21:49 +04:00
START_PROFILE ( SMBwriteclose ) ;
1998-08-14 21:38:29 +04:00
1998-08-15 11:27:34 +04:00
CHECK_FSP ( fsp , conn ) ;
CHECK_WRITE ( fsp ) ;
1998-08-14 21:38:29 +04:00
numtowrite = SVAL ( inbuf , smb_vwv1 ) ;
2002-12-03 11:02:41 +03:00
startpos = IVAL_TO_SMB_OFF_T ( inbuf , smb_vwv2 ) ;
1998-08-14 21:38:29 +04:00
mtime = make_unix_date3 ( inbuf + smb_vwv4 ) ;
data = smb_buf ( inbuf ) + 1 ;
2001-06-30 05:59:48 +04:00
if ( is_locked ( fsp , conn , ( SMB_BIG_UINT ) numtowrite , ( SMB_BIG_UINT ) startpos , WRITE_LOCK , False ) ) {
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBwriteclose ) ;
2001-08-27 12:19:43 +04:00
return ERROR_DOS ( ERRDOS , ERRlock ) ;
2000-10-06 07:21:49 +04:00
}
1999-12-13 16:27:58 +03:00
nwritten = write_file ( fsp , data , startpos , numtowrite ) ;
1996-05-04 11:50:46 +04:00
1998-08-15 11:27:34 +04:00
set_filetime ( conn , fsp - > fsp_name , mtime ) ;
1996-05-04 11:50:46 +04:00
1999-12-13 16:27:58 +03:00
close_err = close_file ( fsp , True ) ;
1996-06-04 10:42:03 +04:00
1998-08-14 21:38:29 +04:00
DEBUG ( 3 , ( " writeclose fnum=%d num=%d wrote=%d (numopen=%d) \n " ,
1999-12-13 16:27:58 +03:00
fsp - > fnum , ( int ) numtowrite , ( int ) nwritten ,
1998-08-14 21:38:29 +04:00
conn - > num_files_open ) ) ;
1996-05-04 11:50:46 +04:00
2003-01-09 02:49:21 +03:00
if ( ( ( nwritten = = 0 ) & & ( numtowrite ! = 0 ) ) | | ( nwritten < 0 ) ) {
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBwriteclose ) ;
2003-01-09 02:49:21 +03:00
return ( UNIXERROR ( ERRHRD , ERRdiskfull ) ) ;
2000-10-06 07:21:49 +04:00
}
1999-12-13 16:27:58 +03:00
if ( close_err ! = 0 ) {
errno = close_err ;
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBwriteclose ) ;
1999-12-13 16:27:58 +03:00
return ( UNIXERROR ( ERRHRD , ERRgeneral ) ) ;
}
1998-08-14 21:38:29 +04:00
outsize = set_message ( outbuf , 1 , 0 , True ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
SSVAL ( outbuf , smb_vwv0 , nwritten ) ;
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBwriteclose ) ;
1998-08-14 21:38:29 +04:00
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a lock .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_lock ( connection_struct * conn ,
1998-08-20 23:28:37 +04:00
char * inbuf , char * outbuf , int length , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
1998-08-14 21:38:29 +04:00
int outsize = set_message ( outbuf , 0 , 0 , True ) ;
2000-04-11 23:44:54 +04:00
SMB_BIG_UINT count , offset ;
2001-08-27 12:19:43 +04:00
NTSTATUS status ;
1998-08-17 07:52:05 +04:00
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
2000-10-06 07:21:49 +04:00
START_PROFILE ( SMBlock ) ;
1996-05-04 11:50:46 +04:00
1998-08-15 11:27:34 +04:00
CHECK_FSP ( fsp , conn ) ;
1996-05-04 11:50:46 +04:00
2000-11-16 03:59:18 +03:00
release_level_2_oplocks_on_change ( fsp ) ;
2000-04-11 23:44:54 +04:00
count = ( SMB_BIG_UINT ) IVAL ( inbuf , smb_vwv1 ) ;
offset = ( SMB_BIG_UINT ) IVAL ( inbuf , smb_vwv3 ) ;
1996-05-04 11:50:46 +04:00
1998-09-11 05:24:30 +04:00
DEBUG ( 3 , ( " lock fd=%d fnum=%d offset=%.0f count=%.0f \n " ,
2000-04-10 17:05:23 +04:00
fsp - > fd , fsp - > fnum , ( double ) offset , ( double ) count ) ) ;
1996-05-04 11:50:46 +04:00
2002-03-13 23:28:19 +03:00
status = do_lock_spin ( fsp , conn , SVAL ( inbuf , smb_pid ) , count , offset , WRITE_LOCK ) ;
2001-08-27 21:52:23 +04:00
if ( NT_STATUS_V ( status ) ) {
2002-09-25 19:19:00 +04:00
if ( lp_blocking_locks ( SNUM ( conn ) ) & & ERROR_WAS_LOCK_DENIED ( status ) ) {
2001-08-27 12:19:43 +04:00
/*
* A blocking lock was requested . Package up
* this smb into a queued request and push it
* onto the blocking lock queue .
*/
2003-02-27 04:04:34 +03:00
if ( push_blocking_lock_request ( inbuf , length , - 1 , 0 , SVAL ( inbuf , smb_pid ) , offset , count ) ) {
2001-08-27 12:19:43 +04:00
END_PROFILE ( SMBlock ) ;
return - 1 ;
}
}
END_PROFILE ( SMBlock ) ;
return ERROR_NT ( status ) ;
2000-10-06 07:21:49 +04:00
}
1998-08-01 02:39:15 +04:00
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBlock ) ;
1998-08-14 21:38:29 +04:00
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a unlock .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
2001-08-27 12:19:43 +04:00
int reply_unlock ( connection_struct * conn , char * inbuf , char * outbuf , int size ,
int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2001-08-27 12:19:43 +04:00
int outsize = set_message ( outbuf , 0 , 0 , True ) ;
SMB_BIG_UINT count , offset ;
NTSTATUS status ;
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
START_PROFILE ( SMBunlock ) ;
1996-05-04 11:50:46 +04:00
2001-08-27 12:19:43 +04:00
CHECK_FSP ( fsp , conn ) ;
count = ( SMB_BIG_UINT ) IVAL ( inbuf , smb_vwv1 ) ;
offset = ( SMB_BIG_UINT ) IVAL ( inbuf , smb_vwv3 ) ;
status = do_unlock ( fsp , conn , SVAL ( inbuf , smb_pid ) , count , offset ) ;
2001-08-27 21:52:23 +04:00
if ( NT_STATUS_V ( status ) ) {
2001-08-27 12:19:43 +04:00
END_PROFILE ( SMBunlock ) ;
return ERROR_NT ( status ) ;
}
1996-05-04 11:50:46 +04:00
2001-08-27 12:19:43 +04:00
DEBUG ( 3 , ( " unlock fd=%d fnum=%d offset=%.0f count=%.0f \n " ,
fsp - > fd , fsp - > fnum , ( double ) offset , ( double ) count ) ) ;
END_PROFILE ( SMBunlock ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a tdis .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_tdis ( connection_struct * conn ,
char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
1998-08-14 21:38:29 +04:00
int outsize = set_message ( outbuf , 0 , 0 , True ) ;
uint16 vuid ;
2000-10-06 07:21:49 +04:00
START_PROFILE ( SMBtdis ) ;
1996-10-26 00:30:22 +04:00
1998-08-14 21:38:29 +04:00
vuid = SVAL ( inbuf , smb_uid ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
if ( ! conn ) {
DEBUG ( 4 , ( " Invalid connection in tdis \n " ) ) ;
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBtdis ) ;
2001-08-27 12:19:43 +04:00
return ERROR_DOS ( ERRSRV , ERRinvnid ) ;
1998-08-14 21:38:29 +04:00
}
1996-07-03 05:58:27 +04:00
1998-08-14 21:38:29 +04:00
conn - > used = False ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
close_cnum ( conn , vuid ) ;
1996-05-04 11:50:46 +04:00
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBtdis ) ;
1998-08-14 21:38:29 +04:00
return outsize ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a echo .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_echo ( connection_struct * conn ,
char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
1998-08-14 21:38:29 +04:00
int smb_reverb = SVAL ( inbuf , smb_vwv0 ) ;
int seq_num ;
2000-04-27 20:53:31 +04:00
unsigned int data_len = smb_buflen ( inbuf ) ;
1998-08-14 21:38:29 +04:00
int outsize = set_message ( outbuf , 1 , data_len , True ) ;
2000-10-06 07:21:49 +04:00
START_PROFILE ( SMBecho ) ;
2000-04-27 20:53:31 +04:00
data_len = MIN ( data_len , ( sizeof ( inbuf ) - ( smb_buf ( inbuf ) - inbuf ) ) ) ;
1998-08-14 21:38:29 +04:00
/* copy any incoming data back out */
if ( data_len > 0 )
memcpy ( smb_buf ( outbuf ) , smb_buf ( inbuf ) , data_len ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
if ( smb_reverb > 100 ) {
DEBUG ( 0 , ( " large reverb (%d)?? Setting to 100 \n " , smb_reverb ) ) ;
smb_reverb = 100 ;
}
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
for ( seq_num = 1 ; seq_num < = smb_reverb ; seq_num + + ) {
SSVAL ( outbuf , smb_vwv0 , seq_num ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
smb_setlen ( outbuf , outsize - 4 ) ;
1996-05-04 11:50:46 +04:00
2001-06-09 05:38:54 +04:00
if ( ! send_smb ( smbd_server_fd ( ) , outbuf ) )
2001-11-05 03:02:38 +03:00
exit_server ( " reply_echo: send_smb failed. " ) ;
1998-08-14 21:38:29 +04:00
}
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
DEBUG ( 3 , ( " echo %d times \n " , smb_reverb ) ) ;
1996-05-04 11:50:46 +04:00
1999-12-13 16:27:58 +03:00
smb_echo_count + + ;
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBecho ) ;
1998-08-14 21:38:29 +04:00
return - 1 ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a printopen .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_printopen ( connection_struct * conn ,
char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
1998-08-14 21:38:29 +04:00
int outsize = 0 ;
files_struct * fsp ;
2000-10-06 07:21:49 +04:00
START_PROFILE ( SMBsplopen ) ;
1998-08-14 21:38:29 +04:00
2000-10-06 07:21:49 +04:00
if ( ! CAN_PRINT ( conn ) ) {
END_PROFILE ( SMBsplopen ) ;
2001-08-27 12:19:43 +04:00
return ERROR_DOS ( ERRDOS , ERRnoaccess ) ;
2000-10-06 07:21:49 +04:00
}
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
/* Open for exclusive use, write only. */
2002-01-25 23:16:14 +03:00
fsp = print_fsp_open ( conn , NULL ) ;
1996-05-04 11:50:46 +04:00
2000-04-22 04:33:16 +04:00
if ( ! fsp ) {
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBsplopen ) ;
1998-08-14 21:38:29 +04:00
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
}
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
outsize = set_message ( outbuf , 1 , 0 , True ) ;
1998-08-15 11:27:34 +04:00
SSVAL ( outbuf , smb_vwv0 , fsp - > fnum ) ;
1996-05-04 11:50:46 +04:00
2000-04-10 17:05:23 +04:00
DEBUG ( 3 , ( " openprint fd=%d fnum=%d \n " ,
fsp - > fd , fsp - > fnum ) ) ;
1998-08-01 02:39:15 +04:00
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBsplopen ) ;
1998-08-14 21:38:29 +04:00
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a printclose .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-12-04 02:57:45 +03:00
1998-08-14 21:38:29 +04:00
int reply_printclose ( connection_struct * conn ,
char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
1998-08-14 21:38:29 +04:00
int outsize = set_message ( outbuf , 0 , 0 , True ) ;
1998-08-17 07:52:05 +04:00
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
1999-12-13 16:27:58 +03:00
int close_err = 0 ;
2000-10-06 07:21:49 +04:00
START_PROFILE ( SMBsplclose ) ;
1996-05-04 11:50:46 +04:00
1998-08-15 11:27:34 +04:00
CHECK_FSP ( fsp , conn ) ;
1996-05-04 11:50:46 +04:00
2000-10-06 07:21:49 +04:00
if ( ! CAN_PRINT ( conn ) ) {
END_PROFILE ( SMBsplclose ) ;
2003-08-19 05:26:43 +04:00
return ERROR_NT ( NT_STATUS_UNSUCCESSFUL ) ;
2000-10-06 07:21:49 +04:00
}
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
DEBUG ( 3 , ( " printclose fd=%d fnum=%d \n " ,
2000-04-10 17:05:23 +04:00
fsp - > fd , fsp - > fnum ) ) ;
1996-05-04 11:50:46 +04:00
1999-12-13 16:27:58 +03:00
close_err = close_file ( fsp , True ) ;
if ( close_err ! = 0 ) {
errno = close_err ;
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBsplclose ) ;
1999-12-13 16:27:58 +03:00
return ( UNIXERROR ( ERRHRD , ERRgeneral ) ) ;
}
1998-04-16 23:23:10 +04:00
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBsplclose ) ;
1998-08-14 21:38:29 +04:00
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a printqueue .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_printqueue ( connection_struct * conn ,
char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
1998-08-14 21:38:29 +04:00
int outsize = set_message ( outbuf , 2 , 3 , True ) ;
int max_count = SVAL ( inbuf , smb_vwv0 ) ;
int start_index = SVAL ( inbuf , smb_vwv1 ) ;
2000-10-06 07:21:49 +04:00
START_PROFILE ( SMBsplretq ) ;
1998-08-14 21:38:29 +04:00
/* we used to allow the client to get the cnum wrong, but that
is really quite gross and only worked when there was only
one printer - I think we should now only accept it if they
get it right ( tridge ) */
2000-10-06 07:21:49 +04:00
if ( ! CAN_PRINT ( conn ) ) {
END_PROFILE ( SMBsplretq ) ;
2001-08-27 12:19:43 +04:00
return ERROR_DOS ( ERRDOS , ERRnoaccess ) ;
2000-10-06 07:21:49 +04:00
}
1998-08-14 21:38:29 +04:00
SSVAL ( outbuf , smb_vwv0 , 0 ) ;
SSVAL ( outbuf , smb_vwv1 , 0 ) ;
2002-01-11 22:10:25 +03:00
SCVAL ( smb_buf ( outbuf ) , 0 , 1 ) ;
1998-08-14 21:38:29 +04:00
SSVAL ( smb_buf ( outbuf ) , 1 , 0 ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
DEBUG ( 3 , ( " printqueue start_index=%d max_count=%d \n " ,
start_index , max_count ) ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
{
print_queue_struct * queue = NULL ;
2001-12-29 12:52:24 +03:00
print_status_struct status ;
1998-08-14 21:38:29 +04:00
char * p = smb_buf ( outbuf ) + 3 ;
2001-12-29 12:52:24 +03:00
int count = print_queue_status ( SNUM ( conn ) , & queue , & status ) ;
1998-08-14 21:38:29 +04:00
int num_to_get = ABS ( max_count ) ;
int first = ( max_count > 0 ? start_index : start_index + max_count + 1 ) ;
int i ;
if ( first > = count )
num_to_get = 0 ;
else
num_to_get = MIN ( num_to_get , count - first ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
for ( i = first ; i < first + num_to_get ; i + + ) {
put_dos_date2 ( p , 0 , queue [ i ] . time ) ;
2002-01-11 22:10:25 +03:00
SCVAL ( p , 4 , ( queue [ i ] . status = = LPQ_PRINTING ? 2 : 3 ) ) ;
2000-04-16 10:22:31 +04:00
SSVAL ( p , 5 , queue [ i ] . job ) ;
1998-08-14 21:38:29 +04:00
SIVAL ( p , 7 , queue [ i ] . size ) ;
2002-01-11 22:10:25 +03:00
SCVAL ( p , 11 , 0 ) ;
2002-03-15 11:14:10 +03:00
srvstr_push ( outbuf , p + 12 , queue [ i ] . fs_user , 16 , STR_ASCII ) ;
1998-08-14 21:38:29 +04:00
p + = 28 ;
}
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
if ( count > 0 ) {
outsize = set_message ( outbuf , 2 , 28 * count + 3 , False ) ;
SSVAL ( outbuf , smb_vwv0 , count ) ;
SSVAL ( outbuf , smb_vwv1 , ( max_count > 0 ? first + count : first - 1 ) ) ;
2002-01-11 22:10:25 +03:00
SCVAL ( smb_buf ( outbuf ) , 0 , 1 ) ;
1998-08-14 21:38:29 +04:00
SSVAL ( smb_buf ( outbuf ) , 1 , 28 * count ) ;
}
1996-05-04 11:50:46 +04:00
2001-09-17 15:25:41 +04:00
SAFE_FREE ( queue ) ;
1996-05-04 11:50:46 +04:00
1998-08-14 21:38:29 +04:00
DEBUG ( 3 , ( " %d entries returned in queue \n " , count ) ) ;
}
1996-05-04 11:50:46 +04:00
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBsplretq ) ;
1998-08-14 21:38:29 +04:00
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a printwrite .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_printwrite ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
int numtowrite ;
int outsize = set_message ( outbuf , 0 , 0 , True ) ;
char * data ;
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
START_PROFILE ( SMBsplwr ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
if ( ! CAN_PRINT ( conn ) ) {
END_PROFILE ( SMBsplwr ) ;
return ERROR_DOS ( ERRDOS , ERRnoaccess ) ;
}
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
CHECK_FSP ( fsp , conn ) ;
CHECK_WRITE ( fsp ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
numtowrite = SVAL ( smb_buf ( inbuf ) , 1 ) ;
data = smb_buf ( inbuf ) + 3 ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
if ( write_file ( fsp , data , - 1 , numtowrite ) ! = numtowrite ) {
END_PROFILE ( SMBsplwr ) ;
2003-01-09 02:49:21 +03:00
return ( UNIXERROR ( ERRHRD , ERRdiskfull ) ) ;
2002-12-04 02:57:45 +03:00
}
2000-10-06 07:21:49 +04:00
2002-12-04 02:57:45 +03:00
DEBUG ( 3 , ( " printwrite fnum=%d num=%d \n " , fsp - > fnum , numtowrite ) ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
END_PROFILE ( SMBsplwr ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2000-07-25 17:15:16 +04:00
The guts of the mkdir command , split out so it may be called by the NT SMB
code .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
2001-09-04 11:13:01 +04:00
NTSTATUS mkdir_internal ( connection_struct * conn , pstring directory )
1996-05-04 11:50:46 +04:00
{
2001-09-04 11:13:01 +04:00
BOOL bad_path = False ;
SMB_STRUCT_STAT sbuf ;
int ret = - 1 ;
unix_convert ( directory , conn , 0 , & bad_path , & sbuf ) ;
2003-07-18 11:07:29 +04:00
if ( ms_has_wild ( directory ) ) {
return NT_STATUS_OBJECT_NAME_INVALID ;
}
2001-09-04 11:13:01 +04:00
if ( check_name ( directory , conn ) )
2003-05-12 03:34:18 +04:00
ret = vfs_MkDir ( conn , directory , unix_mode ( conn , aDIR , directory ) ) ;
2001-09-04 11:13:01 +04:00
if ( ret = = - 1 ) {
2003-08-16 06:34:03 +04:00
NTSTATUS nterr = NT_STATUS_OK ;
if ( errno = = ENOENT ) {
unix_ERR_class = ERRDOS ;
if ( bad_path ) {
unix_ERR_code = ERRbadpath ;
nterr = NT_STATUS_OBJECT_PATH_NOT_FOUND ;
} else {
unix_ERR_code = ERRbadfile ;
nterr = NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
}
2002-04-02 23:34:36 +04:00
if ( ! NT_STATUS_IS_OK ( nterr ) )
return nterr ;
2001-09-04 11:13:01 +04:00
return map_nt_error_from_unix ( errno ) ;
}
return NT_STATUS_OK ;
2000-07-25 17:15:16 +04:00
}
1998-08-01 02:39:15 +04:00
2000-07-25 17:15:16 +04:00
/****************************************************************************
2001-08-31 02:20:02 +04:00
Reply to a mkdir .
2000-07-25 17:15:16 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-08-31 02:20:02 +04:00
2000-07-25 17:15:16 +04:00
int reply_mkdir ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
{
2001-08-31 02:20:02 +04:00
pstring directory ;
int outsize ;
2001-09-04 11:13:01 +04:00
NTSTATUS status ;
2001-08-31 02:20:02 +04:00
START_PROFILE ( SMBmkdir ) ;
2000-07-25 17:15:16 +04:00
2002-07-15 14:35:28 +04:00
srvstr_pull_buf ( inbuf , directory , smb_buf ( inbuf ) + 1 , sizeof ( directory ) , STR_TERMINATE ) ;
2000-07-25 17:15:16 +04:00
2002-08-17 19:27:10 +04:00
RESOLVE_DFSPATH ( directory , conn , inbuf , outbuf ) ;
2001-09-04 11:13:01 +04:00
status = mkdir_internal ( conn , directory ) ;
2001-11-17 06:19:17 +03:00
if ( ! NT_STATUS_IS_OK ( status ) )
return ERROR_NT ( status ) ;
2001-09-04 11:13:01 +04:00
outsize = set_message ( outbuf , 0 , 0 , True ) ;
1998-08-01 02:39:15 +04:00
2001-08-31 02:20:02 +04:00
DEBUG ( 3 , ( " mkdir %s ret=%d \n " , directory , outsize ) ) ;
1998-08-01 02:39:15 +04:00
2001-08-31 02:20:02 +04:00
END_PROFILE ( SMBmkdir ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
1997-09-17 05:29:53 +04:00
/****************************************************************************
2001-08-31 02:20:02 +04:00
Static function used by reply_rmdir to delete an entire directory
tree recursively . Return False on ok , True on fail .
1997-09-17 05:29:53 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2000-02-03 08:17:25 +03:00
static BOOL recursive_rmdir ( connection_struct * conn , char * directory )
1997-09-17 05:29:53 +04:00
{
2003-03-18 01:56:13 +03:00
const char * dname = NULL ;
2001-08-31 02:20:02 +04:00
BOOL ret = False ;
void * dirptr = OpenDir ( conn , directory , False ) ;
1997-09-17 05:29:53 +04:00
2001-08-31 02:20:02 +04:00
if ( dirptr = = NULL )
return True ;
1997-09-17 05:29:53 +04:00
2001-08-31 02:20:02 +04:00
while ( ( dname = ReadDirName ( dirptr ) ) ) {
pstring fullname ;
SMB_STRUCT_STAT st ;
1997-09-17 05:29:53 +04:00
2001-08-31 02:20:02 +04:00
if ( ( strcmp ( dname , " . " ) = = 0 ) | | ( strcmp ( dname , " .. " ) = = 0 ) )
continue ;
1997-09-17 05:29:53 +04:00
2001-08-31 02:20:02 +04:00
/* Construct the full name. */
if ( strlen ( directory ) + strlen ( dname ) + 1 > = sizeof ( fullname ) ) {
errno = ENOMEM ;
ret = True ;
break ;
}
1997-09-17 05:29:53 +04:00
2001-08-31 02:20:02 +04:00
pstrcpy ( fullname , directory ) ;
pstrcat ( fullname , " / " ) ;
pstrcat ( fullname , dname ) ;
1997-09-17 05:29:53 +04:00
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_LSTAT ( conn , fullname , & st ) ! = 0 ) {
2001-08-31 02:20:02 +04:00
ret = True ;
break ;
}
if ( st . st_mode & S_IFDIR ) {
if ( recursive_rmdir ( conn , fullname ) ! = 0 ) {
ret = True ;
break ;
}
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_RMDIR ( conn , fullname ) ! = 0 ) {
2001-08-31 02:20:02 +04:00
ret = True ;
break ;
}
2003-05-14 14:59:01 +04:00
} else if ( SMB_VFS_UNLINK ( conn , fullname ) ! = 0 ) {
2001-08-31 02:20:02 +04:00
ret = True ;
break ;
}
}
CloseDir ( dirptr ) ;
return ret ;
1997-09-17 05:29:53 +04:00
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
1999-12-13 16:27:58 +03:00
The internals of the rmdir code - called elsewhere .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL rmdir_internals ( connection_struct * conn , char * directory )
{
2001-08-31 02:20:02 +04:00
BOOL ok ;
2003-05-14 14:59:01 +04:00
ok = ( SMB_VFS_RMDIR ( conn , directory ) = = 0 ) ;
2001-08-31 02:20:02 +04:00
if ( ! ok & & ( ( errno = = ENOTEMPTY ) | | ( errno = = EEXIST ) ) & & lp_veto_files ( SNUM ( conn ) ) ) {
/*
* Check to see if the only thing in this directory are
* vetoed files / directories . If so then delete them and
* retry . If we fail to delete any of them ( and we * don ' t *
* do a recursive delete ) then fail the rmdir .
*/
BOOL all_veto_files = True ;
2003-03-18 01:56:13 +03:00
const char * dname ;
2001-08-31 02:20:02 +04:00
void * dirptr = OpenDir ( conn , directory , False ) ;
1999-12-13 16:27:58 +03:00
2001-08-31 02:20:02 +04:00
if ( dirptr ! = NULL ) {
int dirpos = TellDir ( dirptr ) ;
while ( ( dname = ReadDirName ( dirptr ) ) ) {
if ( ( strcmp ( dname , " . " ) = = 0 ) | | ( strcmp ( dname , " .. " ) = = 0 ) )
continue ;
if ( ! IS_VETO_PATH ( conn , dname ) ) {
all_veto_files = False ;
break ;
}
}
1999-12-13 16:27:58 +03:00
2001-08-31 02:20:02 +04:00
if ( all_veto_files ) {
SeekDir ( dirptr , dirpos ) ;
while ( ( dname = ReadDirName ( dirptr ) ) ) {
pstring fullname ;
SMB_STRUCT_STAT st ;
1999-12-13 16:27:58 +03:00
2001-08-31 02:20:02 +04:00
if ( ( strcmp ( dname , " . " ) = = 0 ) | | ( strcmp ( dname , " .. " ) = = 0 ) )
continue ;
1999-12-13 16:27:58 +03:00
2001-08-31 02:20:02 +04:00
/* Construct the full name. */
if ( strlen ( directory ) + strlen ( dname ) + 1 > = sizeof ( fullname ) ) {
errno = ENOMEM ;
break ;
}
pstrcpy ( fullname , directory ) ;
pstrcat ( fullname , " / " ) ;
pstrcat ( fullname , dname ) ;
1999-12-13 16:27:58 +03:00
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_LSTAT ( conn , fullname , & st ) ! = 0 )
2001-08-31 02:20:02 +04:00
break ;
if ( st . st_mode & S_IFDIR ) {
if ( lp_recursive_veto_delete ( SNUM ( conn ) ) ) {
if ( recursive_rmdir ( conn , fullname ) ! = 0 )
break ;
}
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_RMDIR ( conn , fullname ) ! = 0 )
2001-08-31 02:20:02 +04:00
break ;
2003-05-14 14:59:01 +04:00
} else if ( SMB_VFS_UNLINK ( conn , fullname ) ! = 0 )
2001-08-31 02:20:02 +04:00
break ;
}
CloseDir ( dirptr ) ;
/* Retry the rmdir */
2003-05-14 14:59:01 +04:00
ok = ( SMB_VFS_RMDIR ( conn , directory ) = = 0 ) ;
2001-08-31 02:20:02 +04:00
} else {
CloseDir ( dirptr ) ;
}
} else {
errno = ENOTEMPTY ;
}
}
if ( ! ok )
DEBUG ( 3 , ( " rmdir_internals: couldn't remove directory %s : %s \n " , directory , strerror ( errno ) ) ) ;
1999-12-13 16:27:58 +03:00
2001-08-31 02:20:02 +04:00
return ok ;
1999-12-13 16:27:58 +03:00
}
/****************************************************************************
Reply to a rmdir .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
1998-08-14 21:38:29 +04:00
int reply_rmdir ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
pstring directory ;
int outsize = 0 ;
BOOL ok = False ;
BOOL bad_path = False ;
SMB_STRUCT_STAT sbuf ;
START_PROFILE ( SMBrmdir ) ;
srvstr_pull_buf ( inbuf , directory , smb_buf ( inbuf ) + 1 , sizeof ( directory ) , STR_TERMINATE ) ;
RESOLVE_DFSPATH ( directory , conn , inbuf , outbuf )
unix_convert ( directory , conn , NULL , & bad_path , & sbuf ) ;
if ( check_name ( directory , conn ) ) {
dptr_closepath ( directory , SVAL ( inbuf , smb_pid ) ) ;
ok = rmdir_internals ( conn , directory ) ;
}
if ( ! ok ) {
END_PROFILE ( SMBrmdir ) ;
2003-08-16 06:34:03 +04:00
return set_bad_path_error ( errno , bad_path , outbuf , ERRDOS , ERRbadpath ) ;
2002-12-04 02:57:45 +03:00
}
1997-08-21 00:32:23 +04:00
2002-12-04 02:57:45 +03:00
outsize = set_message ( outbuf , 0 , 0 , True ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
DEBUG ( 3 , ( " rmdir %s \n " , directory ) ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
END_PROFILE ( SMBrmdir ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/*******************************************************************
2002-09-25 19:19:00 +04:00
Resolve wildcards in a filename rename .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
2003-04-12 03:48:24 +04:00
static BOOL resolve_wildcards ( const char * name1 , char * name2 )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
fstring root1 , root2 ;
fstring ext1 , ext2 ;
2003-04-12 03:48:24 +04:00
char * p , * p2 , * pname1 , * pname2 ;
int available_space ;
2002-12-04 02:57:45 +03:00
2003-04-12 03:48:24 +04:00
pname1 = strrchr_m ( name1 , ' / ' ) ;
pname2 = strrchr_m ( name2 , ' / ' ) ;
2002-12-04 02:57:45 +03:00
2003-04-12 03:48:24 +04:00
if ( ! pname1 | | ! pname2 )
2002-12-04 02:57:45 +03:00
return ( False ) ;
2003-04-12 03:48:24 +04:00
fstrcpy ( root1 , pname1 ) ;
fstrcpy ( root2 , pname2 ) ;
2002-12-04 02:57:45 +03:00
p = strrchr_m ( root1 , ' . ' ) ;
if ( p ) {
* p = 0 ;
fstrcpy ( ext1 , p + 1 ) ;
} else {
fstrcpy ( ext1 , " " ) ;
}
p = strrchr_m ( root2 , ' . ' ) ;
if ( p ) {
* p = 0 ;
fstrcpy ( ext2 , p + 1 ) ;
} else {
fstrcpy ( ext2 , " " ) ;
}
p = root1 ;
p2 = root2 ;
while ( * p2 ) {
if ( * p2 = = ' ? ' ) {
* p2 = * p ;
p2 + + ;
} else {
p2 + + ;
}
if ( * p )
p + + ;
}
p = ext1 ;
p2 = ext2 ;
while ( * p2 ) {
if ( * p2 = = ' ? ' ) {
* p2 = * p ;
p2 + + ;
} else {
p2 + + ;
}
if ( * p )
p + + ;
}
2003-04-12 03:48:24 +04:00
available_space = sizeof ( pstring ) - PTR_DIFF ( pname2 , name2 ) ;
2002-12-04 02:57:45 +03:00
if ( ext2 [ 0 ] ) {
2003-04-14 03:45:35 +04:00
snprintf ( pname2 , available_space - 1 , " %s.%s " , root2 , ext2 ) ;
} else {
2003-04-23 17:27:35 +04:00
pstrcpy_base ( pname2 , root2 , name2 ) ;
2002-12-04 02:57:45 +03:00
}
return ( True ) ;
1996-05-04 11:50:46 +04:00
}
2003-08-16 06:34:03 +04:00
/****************************************************************************
Ensure open files have their names updates .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void rename_open_files ( connection_struct * conn , SMB_DEV_T dev , SMB_INO_T inode , char * newname )
{
files_struct * fsp ;
BOOL did_rename = False ;
for ( fsp = file_find_di_first ( dev , inode ) ; fsp ; fsp = file_find_di_next ( fsp ) ) {
DEBUG ( 10 , ( " rename_open_files: renaming file fnum %d (dev = %x, inode = %.0f) from %s -> %s \n " ,
fsp - > fnum , ( unsigned int ) fsp - > dev , ( double ) fsp - > inode ,
fsp - > fsp_name , newname ) ) ;
string_set ( & fsp - > fsp_name , newname ) ;
did_rename = True ;
}
if ( ! did_rename )
DEBUG ( 10 , ( " rename_open_files: no open files on dev %x, inode %.0f for %s \n " ,
( unsigned int ) dev , ( double ) inode , newname ) ) ;
}
/****************************************************************************
Rename an open file - given an fsp .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS rename_internals_fsp ( connection_struct * conn , files_struct * fsp , char * newname , BOOL replace_if_exists )
{
SMB_STRUCT_STAT sbuf ;
BOOL bad_path = False ;
pstring newname_last_component ;
NTSTATUS error = NT_STATUS_OK ;
BOOL dest_exists ;
ZERO_STRUCT ( sbuf ) ;
unix_convert ( newname , conn , newname_last_component , & bad_path , & sbuf ) ;
/* Ensure newname contains a '/' */
if ( strrchr_m ( newname , ' / ' ) = = 0 ) {
pstring tmpstr ;
pstrcpy ( tmpstr , " ./ " ) ;
pstrcat ( tmpstr , newname ) ;
pstrcpy ( newname , tmpstr ) ;
}
/*
* Check for special case with case preserving and not
* case sensitive . If the old last component differs from the original
* last component only by case , then we should allow
* the rename ( user is trying to change the case of the
* filename ) .
*/
if ( ( case_sensitive = = False ) & & ( case_preserve = = True ) & &
strequal ( newname , fsp - > fsp_name ) ) {
char * p ;
pstring newname_modified_last_component ;
/*
* Get the last component of the modified name .
* Note that we guarantee that newname contains a ' / '
* character above .
*/
p = strrchr_m ( newname , ' / ' ) ;
pstrcpy ( newname_modified_last_component , p + 1 ) ;
if ( strcsequal ( newname_modified_last_component ,
newname_last_component ) = = False ) {
/*
* Replace the modified last component with
* the original .
*/
pstrcpy ( p + 1 , newname_last_component ) ;
}
}
/*
* If the src and dest names are identical - including case ,
* don ' t do the rename , just return success .
*/
if ( strcsequal ( fsp - > fsp_name , newname ) ) {
DEBUG ( 3 , ( " rename_internals_fsp: identical names in rename %s - returning success \n " ,
newname ) ) ;
return NT_STATUS_OK ;
}
dest_exists = vfs_object_exist ( conn , newname , NULL ) ;
if ( ! replace_if_exists & & dest_exists ) {
DEBUG ( 3 , ( " rename_internals_fsp: dest exists doing rename %s -> %s \n " ,
fsp - > fsp_name , newname ) ) ;
return NT_STATUS_OBJECT_NAME_COLLISION ;
}
error = can_rename ( newname , conn , & sbuf ) ;
if ( dest_exists & & ! NT_STATUS_IS_OK ( error ) ) {
DEBUG ( 3 , ( " rename_internals: Error %s rename %s -> %s \n " ,
nt_errstr ( error ) , fsp - > fsp_name , newname ) ) ;
if ( NT_STATUS_EQUAL ( error , NT_STATUS_SHARING_VIOLATION ) )
error = NT_STATUS_ACCESS_DENIED ;
return error ;
}
if ( SMB_VFS_RENAME ( conn , fsp - > fsp_name , newname ) = = 0 ) {
DEBUG ( 3 , ( " rename_internals_fsp: succeeded doing rename on %s -> %s \n " ,
fsp - > fsp_name , newname ) ) ;
rename_open_files ( conn , fsp - > dev , fsp - > inode , newname ) ;
return NT_STATUS_OK ;
}
if ( errno = = ENOTDIR | | errno = = EISDIR )
error = NT_STATUS_OBJECT_NAME_COLLISION ;
else
error = map_nt_error_from_unix ( errno ) ;
DEBUG ( 3 , ( " rename_internals_fsp: Error %s rename %s -> %s \n " ,
nt_errstr ( error ) , fsp - > fsp_name , newname ) ) ;
return error ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
1998-07-11 04:28:34 +04:00
The guts of the rename command , split out so it may be called by the NT SMB
code .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-01-05 00:11:35 +03:00
NTSTATUS rename_internals ( connection_struct * conn , char * name , char * newname , BOOL replace_if_exists )
1996-05-04 11:50:46 +04:00
{
1998-08-14 21:38:29 +04:00
pstring directory ;
pstring mask ;
pstring newname_last_component ;
char * p ;
BOOL has_wild ;
BOOL bad_path1 = False ;
BOOL bad_path2 = False ;
int count = 0 ;
2001-09-04 11:13:01 +04:00
NTSTATUS error = NT_STATUS_OK ;
1999-12-13 16:27:58 +03:00
BOOL rc = True ;
2000-10-19 06:58:24 +04:00
SMB_STRUCT_STAT sbuf1 , sbuf2 ;
1998-08-14 21:38:29 +04:00
* directory = * mask = 0 ;
2003-08-16 06:34:03 +04:00
ZERO_STRUCT ( sbuf1 ) ;
ZERO_STRUCT ( sbuf2 ) ;
2000-10-19 06:58:24 +04:00
rc = unix_convert ( name , conn , 0 , & bad_path1 , & sbuf1 ) ;
unix_convert ( newname , conn , newname_last_component , & bad_path2 , & sbuf2 ) ;
1998-08-14 21:38:29 +04:00
/*
* Split the old name into directory and last component
1999-12-13 16:27:58 +03:00
* strings . Note that unix_convert may have stripped off a
1998-08-14 21:38:29 +04:00
* leading . / from both name and newname if the rename is
* at the root of the share . We need to make sure either both
* name and newname contain a / character or neither of them do
* as this is checked in resolve_wildcards ( ) .
*/
2001-07-04 11:36:09 +04:00
p = strrchr_m ( name , ' / ' ) ;
1998-08-14 21:38:29 +04:00
if ( ! p ) {
pstrcpy ( directory , " . " ) ;
pstrcpy ( mask , name ) ;
} else {
* p = 0 ;
pstrcpy ( directory , name ) ;
pstrcpy ( mask , p + 1 ) ;
* p = ' / ' ; /* Replace needed for exceptional test below. */
}
1997-01-13 22:41:08 +03:00
1999-12-13 16:27:58 +03:00
/*
* We should only check the mangled cache
* here if unix_convert failed . This means
* that the path in ' mask ' doesn ' t exist
* on the file system and so we need to look
* for a possible mangle . This patch from
* Tine Smukavec < valentin . smukavec @ hermes . si > .
*/
2002-04-11 06:20:56 +04:00
if ( ! rc & & mangle_is_mangled ( mask ) )
mangle_check_cache ( mask ) ;
1997-02-18 20:20:14 +03:00
2000-04-30 15:04:28 +04:00
has_wild = ms_has_wild ( mask ) ;
1997-01-13 22:41:08 +03:00
1998-08-14 21:38:29 +04:00
if ( ! has_wild ) {
/*
* No wildcards - just process the one file .
*/
2002-04-11 06:20:56 +04:00
BOOL is_short_name = mangle_is_8_3 ( name , True ) ;
1997-01-13 22:41:08 +03:00
1998-08-14 21:38:29 +04:00
/* Add a terminating '/' to the directory name. */
pstrcat ( directory , " / " ) ;
pstrcat ( directory , mask ) ;
/* Ensure newname contains a '/' also */
2001-07-04 11:36:09 +04:00
if ( strrchr_m ( newname , ' / ' ) = = 0 ) {
1998-08-14 21:38:29 +04:00
pstring tmpstr ;
pstrcpy ( tmpstr , " ./ " ) ;
pstrcat ( tmpstr , newname ) ;
pstrcpy ( newname , tmpstr ) ;
}
2002-01-05 00:11:35 +03:00
DEBUG ( 3 , ( " rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, \
directory = % s , newname = % s , newname_last_component = % s , is_8_3 = % d \ n " ,
1998-08-14 21:38:29 +04:00
case_sensitive , case_preserve , short_case_preserve , directory ,
newname , newname_last_component , is_short_name ) ) ;
/*
* Check for special case with case preserving and not
* case sensitive , if directory and newname are identical ,
* and the old last component differs from the original
* last component only by case , then we should allow
* the rename ( user is trying to change the case of the
* filename ) .
*/
if ( ( case_sensitive = = False ) & &
( ( ( case_preserve = = True ) & &
( is_short_name = = False ) ) | |
( ( short_case_preserve = = True ) & &
( is_short_name = = True ) ) ) & &
strcsequal ( directory , newname ) ) {
pstring newname_modified_last_component ;
/*
* Get the last component of the modified name .
* Note that we guarantee that newname contains a ' / '
* character above .
*/
2001-07-04 11:36:09 +04:00
p = strrchr_m ( newname , ' / ' ) ;
1998-08-14 21:38:29 +04:00
pstrcpy ( newname_modified_last_component , p + 1 ) ;
if ( strcsequal ( newname_modified_last_component ,
newname_last_component ) = = False ) {
/*
* Replace the modified last component with
* the original .
*/
pstrcpy ( p + 1 , newname_last_component ) ;
}
}
2002-01-05 00:11:35 +03:00
resolve_wildcards ( directory , newname ) ;
/*
* The source object must exist .
*/
2000-11-15 00:56:32 +03:00
2002-03-23 05:57:44 +03:00
if ( ! vfs_object_exist ( conn , directory , & sbuf1 ) ) {
2002-01-05 00:11:35 +03:00
DEBUG ( 3 , ( " rename_internals: source doesn't exist doing rename %s -> %s \n " ,
directory , newname ) ) ;
if ( errno = = ENOTDIR | | errno = = EISDIR | | errno = = ENOENT ) {
/*
* Must return different errors depending on whether the parent
* directory existed or not .
*/
p = strrchr_m ( directory , ' / ' ) ;
if ( ! p )
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
* p = ' \0 ' ;
if ( vfs_object_exist ( conn , directory , NULL ) )
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
return NT_STATUS_OBJECT_PATH_NOT_FOUND ;
}
error = map_nt_error_from_unix ( errno ) ;
DEBUG ( 3 , ( " rename_internals: Error %s rename %s -> %s \n " ,
2002-03-17 07:36:35 +03:00
nt_errstr ( error ) , directory , newname ) ) ;
2002-01-05 00:11:35 +03:00
return error ;
1998-08-14 21:38:29 +04:00
}
1997-01-13 22:41:08 +03:00
2002-03-23 05:57:44 +03:00
error = can_rename ( directory , conn , & sbuf1 ) ;
2002-01-05 00:11:35 +03:00
if ( ! NT_STATUS_IS_OK ( error ) ) {
DEBUG ( 3 , ( " rename_internals: Error %s rename %s -> %s \n " ,
2002-03-17 07:36:35 +03:00
nt_errstr ( error ) , directory , newname ) ) ;
2002-01-05 01:30:00 +03:00
return error ;
2002-01-05 00:11:35 +03:00
}
/*
* If the src and dest names are identical - including case ,
* don ' t do the rename , just return success .
*/
if ( strcsequal ( directory , newname ) ) {
2003-08-16 06:34:03 +04:00
rename_open_files ( conn , sbuf1 . st_dev , sbuf1 . st_ino , newname ) ;
2002-01-05 00:11:35 +03:00
DEBUG ( 3 , ( " rename_internals: identical names in rename %s - returning success \n " , directory ) ) ;
return NT_STATUS_OK ;
1998-08-14 21:38:29 +04:00
}
2002-01-05 00:11:35 +03:00
if ( ! replace_if_exists & & vfs_object_exist ( conn , newname , NULL ) ) {
DEBUG ( 3 , ( " rename_internals: dest exists doing rename %s -> %s \n " ,
directory , newname ) ) ;
return NT_STATUS_OBJECT_NAME_COLLISION ;
}
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_RENAME ( conn , directory , newname ) = = 0 ) {
2002-01-05 00:11:35 +03:00
DEBUG ( 3 , ( " rename_internals: succeeded doing rename on %s -> %s \n " ,
directory , newname ) ) ;
2003-08-16 06:34:03 +04:00
rename_open_files ( conn , sbuf1 . st_dev , sbuf1 . st_ino , newname ) ;
2002-01-05 00:11:35 +03:00
return NT_STATUS_OK ;
}
if ( errno = = ENOTDIR | | errno = = EISDIR )
error = NT_STATUS_OBJECT_NAME_COLLISION ;
else
error = map_nt_error_from_unix ( errno ) ;
DEBUG ( 3 , ( " rename_internals: Error %s rename %s -> %s \n " ,
2002-03-17 07:36:35 +03:00
nt_errstr ( error ) , directory , newname ) ) ;
2002-01-05 00:11:35 +03:00
return error ;
1998-08-14 21:38:29 +04:00
} else {
/*
* Wildcards - process each file that matches .
*/
void * dirptr = NULL ;
2003-03-18 01:56:13 +03:00
const char * dname ;
1998-08-14 21:38:29 +04:00
pstring destname ;
if ( check_name ( directory , conn ) )
dirptr = OpenDir ( conn , directory , True ) ;
if ( dirptr ) {
2001-09-04 11:13:01 +04:00
error = NT_STATUS_OBJECT_NAME_NOT_FOUND ;
1998-08-14 21:38:29 +04:00
if ( strequal ( mask , " ????????.??? " ) )
pstrcpy ( mask , " * " ) ;
while ( ( dname = ReadDirName ( dirptr ) ) ) {
pstring fname ;
2000-03-29 11:44:23 +04:00
1998-08-14 21:38:29 +04:00
pstrcpy ( fname , dname ) ;
2000-04-30 15:04:28 +04:00
if ( ! mask_match ( fname , mask , case_sensitive ) )
1998-08-14 21:38:29 +04:00
continue ;
2001-09-04 11:13:01 +04:00
error = NT_STATUS_ACCESS_DENIED ;
1998-08-14 21:38:29 +04:00
slprintf ( fname , sizeof ( fname ) - 1 , " %s/%s " , directory , dname ) ;
2002-03-23 05:57:44 +03:00
if ( ! vfs_object_exist ( conn , fname , & sbuf1 ) ) {
error = NT_STATUS_OBJECT_NAME_NOT_FOUND ;
DEBUG ( 6 , ( " rename %s failed. Error %s \n " , fname , nt_errstr ( error ) ) ) ;
continue ;
}
error = can_rename ( fname , conn , & sbuf1 ) ;
2002-01-05 00:11:35 +03:00
if ( ! NT_STATUS_IS_OK ( error ) ) {
1998-08-14 21:38:29 +04:00
DEBUG ( 6 , ( " rename %s refused \n " , fname ) ) ;
continue ;
}
pstrcpy ( destname , newname ) ;
if ( ! resolve_wildcards ( fname , destname ) ) {
2000-02-04 02:08:24 +03:00
DEBUG ( 6 , ( " resolve_wildcards %s %s failed \n " ,
fname , destname ) ) ;
1998-08-14 21:38:29 +04:00
continue ;
}
2000-02-04 02:08:24 +03:00
if ( ! replace_if_exists & &
vfs_file_exist ( conn , destname , NULL ) ) {
2000-02-03 08:17:25 +03:00
DEBUG ( 6 , ( " file_exist %s \n " , destname ) ) ;
2001-09-04 11:13:01 +04:00
error = NT_STATUS_OBJECT_NAME_COLLISION ;
1998-08-14 21:38:29 +04:00
continue ;
}
2003-08-16 06:34:03 +04:00
if ( ! SMB_VFS_RENAME ( conn , fname , destname ) ) {
rename_open_files ( conn , sbuf1 . st_dev , sbuf1 . st_ino , newname ) ;
1998-08-14 21:38:29 +04:00
count + + ;
2003-08-16 06:34:03 +04:00
}
1998-08-14 21:38:29 +04:00
DEBUG ( 3 , ( " rename_internals: doing rename on %s -> %s \n " , fname , destname ) ) ;
}
CloseDir ( dirptr ) ;
}
}
2001-09-04 11:13:01 +04:00
if ( count = = 0 & & NT_STATUS_IS_OK ( error ) ) {
error = map_nt_error_from_unix ( errno ) ;
1998-08-14 21:38:29 +04:00
}
2001-09-04 11:13:01 +04:00
return error ;
1998-07-11 04:28:34 +04:00
}
/****************************************************************************
Reply to a mv .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-09-04 11:13:01 +04:00
int reply_mv ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size ,
int dum_buffsize )
1998-07-11 04:28:34 +04:00
{
2001-09-04 11:13:01 +04:00
int outsize = 0 ;
pstring name ;
pstring newname ;
char * p ;
NTSTATUS status ;
2000-03-09 01:14:30 +03:00
2001-09-04 11:13:01 +04:00
START_PROFILE ( SMBmv ) ;
1998-07-11 04:28:34 +04:00
2001-09-04 11:13:01 +04:00
p = smb_buf ( inbuf ) + 1 ;
2002-07-15 14:35:28 +04:00
p + = srvstr_pull_buf ( inbuf , name , p , sizeof ( name ) , STR_TERMINATE ) ;
2001-09-04 11:13:01 +04:00
p + + ;
2002-07-15 14:35:28 +04:00
p + = srvstr_pull_buf ( inbuf , newname , p , sizeof ( newname ) , STR_TERMINATE ) ;
2001-09-04 11:13:01 +04:00
RESOLVE_DFSPATH ( name , conn , inbuf , outbuf ) ;
RESOLVE_DFSPATH ( newname , conn , inbuf , outbuf ) ;
DEBUG ( 3 , ( " reply_mv : %s -> %s \n " , name , newname ) ) ;
status = rename_internals ( conn , name , newname , False ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return ERROR_NT ( status ) ;
}
2000-09-20 23:00:21 +04:00
/*
2001-09-04 11:13:01 +04:00
* Win2k needs a changenotify request response before it will
* update after a rename . .
*/
process_pending_change_notify_queue ( ( time_t ) 0 ) ;
outsize = set_message ( outbuf , 0 , 0 , True ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 11:13:01 +04:00
END_PROFILE ( SMBmv ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/*******************************************************************
2001-09-04 23:10:30 +04:00
Copy a file as part of a reply_copy .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-10-23 04:58:28 +04:00
1998-08-14 21:38:29 +04:00
static BOOL copy_file ( char * src , char * dest1 , connection_struct * conn , int ofun ,
1999-12-13 16:27:58 +03:00
int count , BOOL target_is_directory , int * err_ret )
1996-05-04 11:50:46 +04:00
{
2001-09-04 23:10:30 +04:00
int Access , action ;
SMB_STRUCT_STAT src_sbuf , sbuf2 ;
SMB_OFF_T ret = - 1 ;
files_struct * fsp1 , * fsp2 ;
pstring dest ;
* err_ret = 0 ;
pstrcpy ( dest , dest1 ) ;
if ( target_is_directory ) {
char * p = strrchr_m ( src , ' / ' ) ;
if ( p )
p + + ;
else
p = src ;
pstrcat ( dest , " / " ) ;
pstrcat ( dest , p ) ;
}
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
if ( ! vfs_file_exist ( conn , src , & src_sbuf ) )
return ( False ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
fsp1 = open_file_shared ( conn , src , & src_sbuf , SET_DENY_MODE ( DENY_NONE ) | SET_OPEN_MODE ( DOS_OPEN_RDONLY ) ,
( FILE_FAIL_IF_NOT_EXIST | FILE_EXISTS_OPEN ) , 0 , 0 , & Access , & action ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
if ( ! fsp1 )
return ( False ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
if ( ! target_is_directory & & count )
ofun = FILE_EXISTS_OPEN ;
1996-05-04 11:50:46 +04:00
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_STAT ( conn , dest , & sbuf2 ) = = - 1 )
2001-09-04 23:10:30 +04:00
ZERO_STRUCTP ( & sbuf2 ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
fsp2 = open_file_shared ( conn , dest , & sbuf2 , SET_DENY_MODE ( DENY_NONE ) | SET_OPEN_MODE ( DOS_OPEN_WRONLY ) ,
ofun , src_sbuf . st_mode , 0 , & Access , & action ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
if ( ! fsp2 ) {
close_file ( fsp1 , False ) ;
return ( False ) ;
}
if ( ( ofun & 3 ) = = 1 ) {
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_LSEEK ( fsp2 , fsp2 - > fd , 0 , SEEK_END ) = = - 1 ) {
2001-09-04 23:10:30 +04:00
DEBUG ( 0 , ( " copy_file: error - vfs lseek returned error %s \n " , strerror ( errno ) ) ) ;
/*
* Stop the copy from occurring .
*/
ret = - 1 ;
src_sbuf . st_size = 0 ;
}
}
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
if ( src_sbuf . st_size )
ret = vfs_transfer_file ( fsp1 , fsp2 , src_sbuf . st_size ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
close_file ( fsp1 , False ) ;
2002-01-03 23:49:06 +03:00
/* Ensure the modtime is set correctly on the destination file. */
fsp2 - > pending_modtime = src_sbuf . st_mtime ;
2001-09-04 23:10:30 +04:00
/*
* As we are opening fsp1 read - only we only expect
* an error on close on fsp2 if we are out of space .
* Thus we don ' t look at the error return from the
* close of fsp1 .
*/
* err_ret = close_file ( fsp2 , False ) ;
1996-05-04 11:50:46 +04:00
2001-09-04 23:10:30 +04:00
return ( ret = = ( SMB_OFF_T ) src_sbuf . st_size ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a file copy .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
int reply_copy ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
int outsize = 0 ;
pstring name ;
pstring directory ;
pstring mask , newname ;
char * p ;
int count = 0 ;
int error = ERRnoaccess ;
int err = 0 ;
BOOL has_wild ;
BOOL exists = False ;
int tid2 = SVAL ( inbuf , smb_vwv0 ) ;
int ofun = SVAL ( inbuf , smb_vwv1 ) ;
int flags = SVAL ( inbuf , smb_vwv2 ) ;
BOOL target_is_directory = False ;
BOOL bad_path1 = False ;
BOOL bad_path2 = False ;
BOOL rc = True ;
SMB_STRUCT_STAT sbuf1 , sbuf2 ;
START_PROFILE ( SMBcopy ) ;
* directory = * mask = 0 ;
p = smb_buf ( inbuf ) ;
p + = srvstr_pull_buf ( inbuf , name , p , sizeof ( name ) , STR_TERMINATE ) ;
p + = srvstr_pull_buf ( inbuf , newname , p , sizeof ( newname ) , STR_TERMINATE ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
DEBUG ( 3 , ( " reply_copy : %s -> %s \n " , name , newname ) ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
if ( tid2 ! = conn - > cnum ) {
/* can't currently handle inter share copies XXXX */
DEBUG ( 3 , ( " Rejecting inter-share copy \n " ) ) ;
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBcopy ) ;
2002-12-04 02:57:45 +03:00
return ERROR_DOS ( ERRSRV , ERRinvdevice ) ;
1999-12-13 16:27:58 +03:00
}
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
RESOLVE_DFSPATH ( name , conn , inbuf , outbuf ) ;
RESOLVE_DFSPATH ( newname , conn , inbuf , outbuf ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
rc = unix_convert ( name , conn , 0 , & bad_path1 , & sbuf1 ) ;
unix_convert ( newname , conn , 0 , & bad_path2 , & sbuf2 ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
target_is_directory = VALID_STAT_OF_DIR ( sbuf2 ) ;
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
if ( ( flags & 1 ) & & target_is_directory ) {
END_PROFILE ( SMBcopy ) ;
return ERROR_DOS ( ERRDOS , ERRbadfile ) ;
}
1996-05-04 11:50:46 +04:00
2002-12-04 02:57:45 +03:00
if ( ( flags & 2 ) & & ! target_is_directory ) {
END_PROFILE ( SMBcopy ) ;
return ERROR_DOS ( ERRDOS , ERRbadpath ) ;
}
if ( ( flags & ( 1 < < 5 ) ) & & VALID_STAT_OF_DIR ( sbuf1 ) ) {
/* wants a tree copy! XXXX */
DEBUG ( 3 , ( " Rejecting tree copy \n " ) ) ;
END_PROFILE ( SMBcopy ) ;
return ERROR_DOS ( ERRSRV , ERRerror ) ;
}
p = strrchr_m ( name , ' / ' ) ;
if ( ! p ) {
pstrcpy ( directory , " ./ " ) ;
pstrcpy ( mask , name ) ;
} else {
* p = 0 ;
pstrcpy ( directory , name ) ;
pstrcpy ( mask , p + 1 ) ;
}
/*
* We should only check the mangled cache
* here if unix_convert failed . This means
* that the path in ' mask ' doesn ' t exist
* on the file system and so we need to look
* for a possible mangle . This patch from
* Tine Smukavec < valentin . smukavec @ hermes . si > .
*/
if ( ! rc & & mangle_is_mangled ( mask ) )
mangle_check_cache ( mask ) ;
has_wild = ms_has_wild ( mask ) ;
if ( ! has_wild ) {
pstrcat ( directory , " / " ) ;
pstrcat ( directory , mask ) ;
if ( resolve_wildcards ( directory , newname ) & &
copy_file ( directory , newname , conn , ofun , count , target_is_directory , & err ) )
count + + ;
if ( ! count & & err ) {
errno = err ;
END_PROFILE ( SMBcopy ) ;
return ( UNIXERROR ( ERRHRD , ERRgeneral ) ) ;
}
if ( ! count ) {
exists = vfs_file_exist ( conn , directory , NULL ) ;
}
} else {
void * dirptr = NULL ;
2003-03-18 01:56:13 +03:00
const char * dname ;
2002-12-04 02:57:45 +03:00
pstring destname ;
if ( check_name ( directory , conn ) )
dirptr = OpenDir ( conn , directory , True ) ;
if ( dirptr ) {
error = ERRbadfile ;
if ( strequal ( mask , " ????????.??? " ) )
pstrcpy ( mask , " * " ) ;
while ( ( dname = ReadDirName ( dirptr ) ) ) {
pstring fname ;
pstrcpy ( fname , dname ) ;
if ( ! mask_match ( fname , mask , case_sensitive ) )
continue ;
error = ERRnoaccess ;
slprintf ( fname , sizeof ( fname ) - 1 , " %s/%s " , directory , dname ) ;
pstrcpy ( destname , newname ) ;
if ( resolve_wildcards ( fname , destname ) & &
copy_file ( fname , destname , conn , ofun ,
count , target_is_directory , & err ) )
count + + ;
DEBUG ( 3 , ( " reply_copy : doing copy on %s -> %s \n " , fname , destname ) ) ;
}
CloseDir ( dirptr ) ;
}
}
if ( count = = 0 ) {
if ( err ) {
/* Error on close... */
errno = err ;
END_PROFILE ( SMBcopy ) ;
return ( UNIXERROR ( ERRHRD , ERRgeneral ) ) ;
}
if ( exists ) {
END_PROFILE ( SMBcopy ) ;
return ERROR_DOS ( ERRDOS , error ) ;
} else {
if ( ( errno = = ENOENT ) & & ( bad_path1 | | bad_path2 ) ) {
unix_ERR_class = ERRDOS ;
unix_ERR_code = ERRbadpath ;
}
END_PROFILE ( SMBcopy ) ;
return ( UNIXERROR ( ERRDOS , error ) ) ;
}
}
outsize = set_message ( outbuf , 1 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , count ) ;
END_PROFILE ( SMBcopy ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a setdir .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
1998-08-14 21:38:29 +04:00
int reply_setdir ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-12-04 02:57:45 +03:00
int snum ;
int outsize = 0 ;
BOOL ok = False ;
pstring newdir ;
START_PROFILE ( pathworks_setdir ) ;
snum = SNUM ( conn ) ;
if ( ! CAN_SETDIR ( snum ) ) {
END_PROFILE ( pathworks_setdir ) ;
return ERROR_DOS ( ERRDOS , ERRnoaccess ) ;
}
srvstr_pull_buf ( inbuf , newdir , smb_buf ( inbuf ) + 1 , sizeof ( newdir ) , STR_TERMINATE ) ;
if ( strlen ( newdir ) = = 0 ) {
ok = True ;
} else {
ok = vfs_directory_exist ( conn , newdir , NULL ) ;
if ( ok )
string_set ( & conn - > connectpath , newdir ) ;
}
if ( ! ok ) {
END_PROFILE ( pathworks_setdir ) ;
return ERROR_DOS ( ERRDOS , ERRbadpath ) ;
}
outsize = set_message ( outbuf , 0 , 0 , True ) ;
SCVAL ( outbuf , smb_reh , CVAL ( inbuf , smb_reh ) ) ;
DEBUG ( 3 , ( " setdir %s \n " , newdir ) ) ;
END_PROFILE ( pathworks_setdir ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
2001-07-02 06:42:41 +04:00
/****************************************************************************
Get a lock pid , dealing with large count requests .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint16 get_lock_pid ( char * data , int data_offset , BOOL large_file_format )
{
if ( ! large_file_format )
return SVAL ( data , SMB_LPID_OFFSET ( data_offset ) ) ;
else
2001-11-09 23:34:12 +03:00
return SVAL ( data , SMB_LARGE_LPID_OFFSET ( data_offset ) ) ;
2001-07-02 06:42:41 +04:00
}
1999-12-13 16:27:58 +03:00
/****************************************************************************
Get a lock count , dealing with large count requests .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-11 23:44:54 +04:00
SMB_BIG_UINT get_lock_count ( char * data , int data_offset , BOOL large_file_format )
1999-12-13 16:27:58 +03:00
{
2002-12-04 02:57:45 +03:00
SMB_BIG_UINT count = 0 ;
1999-12-13 16:27:58 +03:00
2002-12-04 02:57:45 +03:00
if ( ! large_file_format ) {
count = ( SMB_BIG_UINT ) IVAL ( data , SMB_LKLEN_OFFSET ( data_offset ) ) ;
} else {
1999-12-13 16:27:58 +03:00
2000-04-11 23:44:54 +04:00
# if defined(HAVE_LONGLONG)
2002-12-04 02:57:45 +03:00
count = ( ( ( SMB_BIG_UINT ) IVAL ( data , SMB_LARGE_LKLEN_OFFSET_HIGH ( data_offset ) ) ) < < 32 ) |
( ( SMB_BIG_UINT ) IVAL ( data , SMB_LARGE_LKLEN_OFFSET_LOW ( data_offset ) ) ) ;
2000-04-11 23:44:54 +04:00
# else /* HAVE_LONGLONG */
1999-12-13 16:27:58 +03:00
2002-12-04 02:57:45 +03:00
/*
* NT4 . x seems to be broken in that it sends large file ( 64 bit )
* lockingX calls even if the CAP_LARGE_FILES was * not *
* negotiated . For boxes without large unsigned ints truncate the
* lock count by dropping the top 32 bits .
*/
if ( IVAL ( data , SMB_LARGE_LKLEN_OFFSET_HIGH ( data_offset ) ) ! = 0 ) {
DEBUG ( 3 , ( " get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count. \n " ,
( unsigned int ) IVAL ( data , SMB_LARGE_LKLEN_OFFSET_HIGH ( data_offset ) ) ,
( unsigned int ) IVAL ( data , SMB_LARGE_LKLEN_OFFSET_LOW ( data_offset ) ) ) ) ;
SIVAL ( data , SMB_LARGE_LKLEN_OFFSET_HIGH ( data_offset ) , 0 ) ;
}
count = ( SMB_BIG_UINT ) IVAL ( data , SMB_LARGE_LKLEN_OFFSET_LOW ( data_offset ) ) ;
2000-04-11 23:44:54 +04:00
# endif /* HAVE_LONGLONG */
2002-12-04 02:57:45 +03:00
}
2000-04-11 23:44:54 +04:00
2002-12-04 02:57:45 +03:00
return count ;
1999-12-13 16:27:58 +03:00
}
2001-09-08 00:01:19 +04:00
# if !defined(HAVE_LONGLONG)
2001-09-07 02:43:21 +04:00
/****************************************************************************
Pathetically try and map a 64 bit lock offset into 31 bits . I hate Windows : - ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
2001-09-07 02:43:21 +04:00
static uint32 map_lock_offset ( uint32 high , uint32 low )
{
unsigned int i ;
uint32 mask = 0 ;
uint32 highcopy = high ;
/*
* Try and find out how many significant bits there are in high .
*/
for ( i = 0 ; highcopy ; i + + )
highcopy > > = 1 ;
/*
* We use 31 bits not 32 here as POSIX
* lock offsets may not be negative .
*/
mask = ( ~ 0 ) < < ( 31 - i ) ;
if ( low & mask )
return 0 ; /* Fail. */
high < < = ( 31 - i ) ;
return ( high | low ) ;
}
2001-09-08 00:01:19 +04:00
# endif /* !defined(HAVE_LONGLONG) */
2001-09-07 02:43:21 +04:00
1999-12-13 16:27:58 +03:00
/****************************************************************************
Get a lock offset , dealing with large offset requests .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-04-11 23:44:54 +04:00
SMB_BIG_UINT get_lock_offset ( char * data , int data_offset , BOOL large_file_format , BOOL * err )
1999-12-13 16:27:58 +03:00
{
2002-12-04 02:57:45 +03:00
SMB_BIG_UINT offset = 0 ;
1999-12-13 16:27:58 +03:00
2002-12-04 02:57:45 +03:00
* err = False ;
1999-12-13 16:27:58 +03:00
2002-12-04 02:57:45 +03:00
if ( ! large_file_format ) {
offset = ( SMB_BIG_UINT ) IVAL ( data , SMB_LKOFF_OFFSET ( data_offset ) ) ;
} else {
1999-12-13 16:27:58 +03:00
2000-04-11 23:44:54 +04:00
# if defined(HAVE_LONGLONG)
2002-12-04 02:57:45 +03:00
offset = ( ( ( SMB_BIG_UINT ) IVAL ( data , SMB_LARGE_LKOFF_OFFSET_HIGH ( data_offset ) ) ) < < 32 ) |
( ( SMB_BIG_UINT ) IVAL ( data , SMB_LARGE_LKOFF_OFFSET_LOW ( data_offset ) ) ) ;
2000-04-11 23:44:54 +04:00
# else /* HAVE_LONGLONG */
1999-12-13 16:27:58 +03:00
2002-12-04 02:57:45 +03:00
/*
* NT4 . x seems to be broken in that it sends large file ( 64 bit )
* lockingX calls even if the CAP_LARGE_FILES was * not *
* negotiated . For boxes without large unsigned ints mangle the
* lock offset by mapping the top 32 bits onto the lower 32.
*/
1999-12-13 16:27:58 +03:00
2002-12-04 02:57:45 +03:00
if ( IVAL ( data , SMB_LARGE_LKOFF_OFFSET_HIGH ( data_offset ) ) ! = 0 ) {
uint32 low = IVAL ( data , SMB_LARGE_LKOFF_OFFSET_LOW ( data_offset ) ) ;
uint32 high = IVAL ( data , SMB_LARGE_LKOFF_OFFSET_HIGH ( data_offset ) ) ;
uint32 new_low = 0 ;
if ( ( new_low = map_lock_offset ( high , low ) ) = = 0 ) {
* err = True ;
return ( SMB_BIG_UINT ) - 1 ;
}
DEBUG ( 3 , ( " get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x. \n " ,
( unsigned int ) high , ( unsigned int ) low , ( unsigned int ) new_low ) ) ;
SIVAL ( data , SMB_LARGE_LKOFF_OFFSET_HIGH ( data_offset ) , 0 ) ;
SIVAL ( data , SMB_LARGE_LKOFF_OFFSET_LOW ( data_offset ) , new_low ) ;
}
offset = ( SMB_BIG_UINT ) IVAL ( data , SMB_LARGE_LKOFF_OFFSET_LOW ( data_offset ) ) ;
2000-04-13 01:46:22 +04:00
# endif /* HAVE_LONGLONG */
2002-12-04 02:57:45 +03:00
}
2000-04-11 23:44:54 +04:00
2002-12-04 02:57:45 +03:00
return offset ;
1999-12-13 16:27:58 +03:00
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
2002-09-25 19:19:00 +04:00
Reply to a lockingX request .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
1998-08-14 21:38:29 +04:00
int reply_lockingX ( connection_struct * conn , char * inbuf , char * outbuf , int length , int bufsize )
1996-05-04 11:50:46 +04:00
{
2001-08-27 12:19:43 +04:00
files_struct * fsp = file_fsp ( inbuf , smb_vwv2 ) ;
unsigned char locktype = CVAL ( inbuf , smb_vwv3 ) ;
unsigned char oplocklevel = CVAL ( inbuf , smb_vwv3 + 1 ) ;
uint16 num_ulocks = SVAL ( inbuf , smb_vwv6 ) ;
uint16 num_locks = SVAL ( inbuf , smb_vwv7 ) ;
SMB_BIG_UINT count = 0 , offset = 0 ;
uint16 lock_pid ;
int32 lock_timeout = IVAL ( inbuf , smb_vwv4 ) ;
int i ;
char * data ;
BOOL large_file_format = ( locktype & LOCKING_ANDX_LARGE_FILES ) ? True : False ;
BOOL err ;
NTSTATUS status ;
1999-12-13 16:27:58 +03:00
2001-08-27 12:19:43 +04:00
START_PROFILE ( SMBlockingX ) ;
CHECK_FSP ( fsp , conn ) ;
data = smb_buf ( inbuf ) ;
2002-03-11 04:34:14 +03:00
if ( locktype & ( LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_CHANGE_LOCKTYPE ) ) {
/* we don't support these - and CANCEL_LOCK makes w2k
and XP reboot so I don ' t really want to be
compatible ! ( tridge ) */
return ERROR_NT ( NT_STATUS_NOT_SUPPORTED ) ;
}
2001-08-27 12:19:43 +04:00
/* Check if this is an oplock break on a file
we have granted an oplock on .
*/
if ( ( locktype & LOCKING_ANDX_OPLOCK_RELEASE ) ) {
/* Client can insist on breaking to none. */
BOOL break_to_none = ( oplocklevel = = 0 ) ;
DEBUG ( 5 , ( " reply_lockingX: oplock break reply (%u) from client for fnum = %d \n " ,
( unsigned int ) oplocklevel , fsp - > fnum ) ) ;
1999-12-13 16:27:58 +03:00
2001-08-27 12:19:43 +04:00
/*
* Make sure we have granted an exclusive or batch oplock on this file .
*/
if ( ! EXCLUSIVE_OPLOCK_TYPE ( fsp - > oplock_type ) ) {
DEBUG ( 0 , ( " reply_lockingX: Error : oplock break from client for fnum = %d and \
1999-12-13 16:27:58 +03:00
no oplock granted on this file ( % s ) . \ n " , fsp->fnum, fsp->fsp_name)) ;
1998-09-05 00:53:58 +04:00
2001-08-27 12:19:43 +04:00
/* if this is a pure oplock break request then don't send a reply */
if ( num_locks = = 0 & & num_ulocks = = 0 ) {
END_PROFILE ( SMBlockingX ) ;
return - 1 ;
} else {
END_PROFILE ( SMBlockingX ) ;
return ERROR_DOS ( ERRDOS , ERRlock ) ;
}
}
1998-09-11 05:24:30 +04:00
2001-08-27 12:19:43 +04:00
if ( remove_oplock ( fsp , break_to_none ) = = False ) {
DEBUG ( 0 , ( " reply_lockingX: error in removing oplock on file %s \n " ,
fsp - > fsp_name ) ) ;
}
/* if this is a pure oplock break request then don't send a reply */
if ( num_locks = = 0 & & num_ulocks = = 0 ) {
/* Sanity check - ensure a pure oplock break is not a
chained request . */
if ( CVAL ( inbuf , smb_vwv0 ) ! = 0xff )
DEBUG ( 0 , ( " reply_lockingX: Error : pure oplock break is a chained %d request ! \n " ,
( unsigned int ) CVAL ( inbuf , smb_vwv0 ) ) ) ;
END_PROFILE ( SMBlockingX ) ;
return - 1 ;
}
}
1999-12-13 16:27:58 +03:00
2001-08-27 12:19:43 +04:00
/*
* We do this check * after * we have checked this is not a oplock break
* response message . JRA .
*/
release_level_2_oplocks_on_change ( fsp ) ;
/* Data now points at the beginning of the list
of smb_unlkrng structs */
for ( i = 0 ; i < ( int ) num_ulocks ; i + + ) {
lock_pid = get_lock_pid ( data , i , large_file_format ) ;
count = get_lock_count ( data , i , large_file_format ) ;
offset = get_lock_offset ( data , i , large_file_format , & err ) ;
/*
* There is no error code marked " stupid client bug " . . . . : - ) .
*/
if ( err ) {
END_PROFILE ( SMBlockingX ) ;
return ERROR_DOS ( ERRDOS , ERRnoaccess ) ;
}
1998-09-11 05:24:30 +04:00
2001-08-27 12:19:43 +04:00
DEBUG ( 10 , ( " reply_lockingX: unlock start=%.0f, len=%.0f for pid %u, file %s \n " ,
( double ) offset , ( double ) count , ( unsigned int ) lock_pid , fsp - > fsp_name ) ) ;
status = do_unlock ( fsp , conn , lock_pid , count , offset ) ;
2001-08-27 21:52:23 +04:00
if ( NT_STATUS_V ( status ) ) {
2001-08-27 12:19:43 +04:00
END_PROFILE ( SMBlockingX ) ;
return ERROR_NT ( status ) ;
}
2000-10-06 07:21:49 +04:00
}
1996-05-04 11:50:46 +04:00
2001-08-27 12:19:43 +04:00
/* Setup the timeout in seconds. */
2002-03-13 23:28:19 +03:00
2003-06-06 14:42:16 +04:00
lock_timeout = ( ( lock_timeout = = - 1 ) ? - 1 : ( lock_timeout + 499 ) / 500 ) ;
2001-08-27 12:19:43 +04:00
/* Now do any requested locks */
data + = ( ( large_file_format ? 20 : 10 ) * num_ulocks ) ;
/* Data now points at the beginning of the list
of smb_lkrng structs */
for ( i = 0 ; i < ( int ) num_locks ; i + + ) {
lock_pid = get_lock_pid ( data , i , large_file_format ) ;
count = get_lock_count ( data , i , large_file_format ) ;
offset = get_lock_offset ( data , i , large_file_format , & err ) ;
/*
* There is no error code marked " stupid client bug " . . . . : - ) .
*/
if ( err ) {
END_PROFILE ( SMBlockingX ) ;
return ERROR_DOS ( ERRDOS , ERRnoaccess ) ;
}
2002-03-13 23:28:19 +03:00
DEBUG ( 10 , ( " reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s timeout = %d \n " ,
( double ) offset , ( double ) count , ( unsigned int ) lock_pid ,
2002-03-14 01:55:47 +03:00
fsp - > fsp_name , ( int ) lock_timeout ) ) ;
2001-08-27 12:19:43 +04:00
2002-03-13 23:28:19 +03:00
status = do_lock_spin ( fsp , conn , lock_pid , count , offset ,
2001-08-27 12:19:43 +04:00
( ( locktype & 1 ) ? READ_LOCK : WRITE_LOCK ) ) ;
2001-08-27 21:52:23 +04:00
if ( NT_STATUS_V ( status ) ) {
2002-09-25 19:19:00 +04:00
if ( ( lock_timeout ! = 0 ) & & lp_blocking_locks ( SNUM ( conn ) ) & & ERROR_WAS_LOCK_DENIED ( status ) ) {
2001-08-27 12:19:43 +04:00
/*
* A blocking lock was requested . Package up
* this smb into a queued request and push it
* onto the blocking lock queue .
*/
2003-02-27 04:04:34 +03:00
if ( push_blocking_lock_request ( inbuf , length , lock_timeout , i , lock_pid , offset , count ) ) {
2001-08-27 12:19:43 +04:00
END_PROFILE ( SMBlockingX ) ;
return - 1 ;
}
}
break ;
}
}
/* If any of the above locks failed, then we must unlock
all of the previous locks ( X / Open spec ) . */
if ( i ! = num_locks & & num_locks ! = 0 ) {
/*
* Ensure we don ' t do a remove on the lock that just failed ,
* as under POSIX rules , if we have a lock already there , we
* will delete it ( and we shouldn ' t ) . . . . .
*/
for ( i - - ; i > = 0 ; i - - ) {
lock_pid = get_lock_pid ( data , i , large_file_format ) ;
count = get_lock_count ( data , i , large_file_format ) ;
offset = get_lock_offset ( data , i , large_file_format , & err ) ;
/*
* There is no error code marked " stupid client bug " . . . . : - ) .
*/
if ( err ) {
END_PROFILE ( SMBlockingX ) ;
return ERROR_DOS ( ERRDOS , ERRnoaccess ) ;
}
do_unlock ( fsp , conn , lock_pid , count , offset ) ;
}
END_PROFILE ( SMBlockingX ) ;
return ERROR_NT ( status ) ;
}
1998-09-11 05:24:30 +04:00
2001-08-27 12:19:43 +04:00
set_message ( outbuf , 2 , 0 , True ) ;
DEBUG ( 3 , ( " lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d \n " ,
fsp - > fnum , ( unsigned int ) locktype , num_locks , num_ulocks ) ) ;
2000-10-06 07:21:49 +04:00
END_PROFILE ( SMBlockingX ) ;
2001-08-27 12:19:43 +04:00
return chain_reply ( inbuf , outbuf , length , bufsize ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2001-10-19 04:56:03 +04:00
Reply to a SMBreadbmpx ( read block multiplex ) request .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-19 04:56:03 +04:00
1998-08-14 21:38:29 +04:00
int reply_readbmpx ( connection_struct * conn , char * inbuf , char * outbuf , int length , int bufsize )
1996-05-04 11:50:46 +04:00
{
2001-10-19 04:56:03 +04:00
ssize_t nread = - 1 ;
ssize_t total_read ;
char * data ;
SMB_OFF_T startpos ;
int outsize ;
size_t maxcount ;
int max_per_packet ;
size_t tcount ;
int pad ;
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
START_PROFILE ( SMBreadBmpx ) ;
1996-05-04 11:50:46 +04:00
2001-10-19 04:56:03 +04:00
/* this function doesn't seem to work - disable by default */
if ( ! lp_readbmpx ( ) ) {
END_PROFILE ( SMBreadBmpx ) ;
return ERROR_DOS ( ERRSRV , ERRuseSTD ) ;
}
1996-05-04 11:50:46 +04:00
2001-10-19 04:56:03 +04:00
outsize = set_message ( outbuf , 8 , 0 , True ) ;
1996-05-04 11:50:46 +04:00
2001-10-19 04:56:03 +04:00
CHECK_FSP ( fsp , conn ) ;
CHECK_READ ( fsp ) ;
1996-05-04 11:50:46 +04:00
2002-12-03 11:02:41 +03:00
startpos = IVAL_TO_SMB_OFF_T ( inbuf , smb_vwv1 ) ;
2001-10-19 04:56:03 +04:00
maxcount = SVAL ( inbuf , smb_vwv3 ) ;
1996-05-04 11:50:46 +04:00
2001-10-19 04:56:03 +04:00
data = smb_buf ( outbuf ) ;
pad = ( ( long ) data ) % 4 ;
if ( pad )
pad = 4 - pad ;
data + = pad ;
1996-05-04 11:50:46 +04:00
2001-10-19 04:56:03 +04:00
max_per_packet = bufsize - ( outsize + pad ) ;
tcount = maxcount ;
total_read = 0 ;
1996-05-04 11:50:46 +04:00
2001-10-19 04:56:03 +04:00
if ( is_locked ( fsp , conn , ( SMB_BIG_UINT ) maxcount , ( SMB_BIG_UINT ) startpos , READ_LOCK , False ) ) {
END_PROFILE ( SMBreadBmpx ) ;
return ERROR_DOS ( ERRDOS , ERRlock ) ;
}
2000-10-06 07:21:49 +04:00
2001-10-19 04:56:03 +04:00
do {
size_t N = MIN ( max_per_packet , tcount - total_read ) ;
1996-05-04 11:50:46 +04:00
2001-10-19 04:56:03 +04:00
nread = read_file ( fsp , data , startpos , N ) ;
1996-05-04 11:50:46 +04:00
2001-10-19 04:56:03 +04:00
if ( nread < = 0 )
nread = 0 ;
1996-05-04 11:50:46 +04:00
2001-10-19 04:56:03 +04:00
if ( nread < ( ssize_t ) N )
tcount = total_read + nread ;
1996-05-04 11:50:46 +04:00
2001-10-19 04:56:03 +04:00
set_message ( outbuf , 8 , nread , False ) ;
SIVAL ( outbuf , smb_vwv0 , startpos ) ;
SSVAL ( outbuf , smb_vwv2 , tcount ) ;
SSVAL ( outbuf , smb_vwv6 , nread ) ;
SSVAL ( outbuf , smb_vwv7 , smb_offset ( data , outbuf ) ) ;
1996-05-04 11:50:46 +04:00
2001-10-19 04:56:03 +04:00
if ( ! send_smb ( smbd_server_fd ( ) , outbuf ) )
2001-11-05 03:02:38 +03:00
exit_server ( " reply_readbmpx: send_smb failed. " ) ;
1996-05-04 11:50:46 +04:00
2001-10-19 04:56:03 +04:00
total_read + = nread ;
startpos + = nread ;
} while ( total_read < ( ssize_t ) tcount ) ;
1996-05-04 11:50:46 +04:00
2001-10-19 04:56:03 +04:00
END_PROFILE ( SMBreadBmpx ) ;
return ( - 1 ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2001-10-19 04:56:03 +04:00
Reply to a SMBsetattrE .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
int reply_setattrE ( connection_struct * conn , char * inbuf , char * outbuf , int size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-03-20 03:46:53 +03:00
struct utimbuf unix_times ;
int outsize = 0 ;
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
START_PROFILE ( SMBsetattrE ) ;
1996-05-04 11:50:46 +04:00
2002-03-20 03:46:53 +03:00
outsize = set_message ( outbuf , 0 , 0 , True ) ;
1996-05-04 11:50:46 +04:00
2002-03-20 03:46:53 +03:00
if ( ! fsp | | ( fsp - > conn ! = conn ) ) {
END_PROFILE ( SMBgetattrE ) ;
return ERROR_DOS ( ERRDOS , ERRbadfid ) ;
}
1996-05-04 11:50:46 +04:00
2002-03-20 03:46:53 +03:00
/*
* Convert the DOS times into unix times . Ignore create
* time as UNIX can ' t set this .
*/
unix_times . actime = make_unix_date2 ( inbuf + smb_vwv3 ) ;
unix_times . modtime = make_unix_date2 ( inbuf + smb_vwv5 ) ;
1996-05-04 11:50:46 +04:00
2002-03-20 03:46:53 +03:00
/*
* Patch from Ray Frush < frush @ engr . colostate . edu >
* Sometimes times are sent as zero - ignore them .
*/
1997-09-23 23:19:06 +04:00
2002-03-20 03:46:53 +03:00
if ( ( unix_times . actime = = 0 ) & & ( unix_times . modtime = = 0 ) ) {
/* Ignore request */
if ( DEBUGLVL ( 3 ) ) {
dbgtext ( " reply_setattrE fnum=%d " , fsp - > fnum ) ;
dbgtext ( " ignoring zero request - not setting timestamps of 0 \n " ) ;
}
END_PROFILE ( SMBsetattrE ) ;
return ( outsize ) ;
} else if ( ( unix_times . actime ! = 0 ) & & ( unix_times . modtime = = 0 ) ) {
/* set modify time = to access time if modify time was 0 */
unix_times . modtime = unix_times . actime ;
}
1997-09-23 23:19:06 +04:00
2002-03-20 03:46:53 +03:00
/* Set the date on this file */
if ( file_utime ( conn , fsp - > fsp_name , & unix_times ) ) {
END_PROFILE ( SMBsetattrE ) ;
return ERROR_DOS ( ERRDOS , ERRnoaccess ) ;
}
1996-05-04 11:50:46 +04:00
2002-03-20 03:46:53 +03:00
DEBUG ( 3 , ( " reply_setattrE fnum=%d actime=%d modtime=%d \n " ,
fsp - > fnum , ( int ) unix_times . actime , ( int ) unix_times . modtime ) ) ;
1996-05-04 11:50:46 +04:00
2002-03-20 03:46:53 +03:00
END_PROFILE ( SMBsetattrE ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}
2001-10-19 04:56:03 +04:00
/* Back from the dead for OS/2..... JRA. */
/****************************************************************************
Reply to a SMBwritebmpx ( write block multiplex primary ) request .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_writebmpx ( connection_struct * conn , char * inbuf , char * outbuf , int size , int dum_buffsize )
{
size_t numtowrite ;
ssize_t nwritten = - 1 ;
int outsize = 0 ;
SMB_OFF_T startpos ;
size_t tcount ;
BOOL write_through ;
int smb_doff ;
char * data ;
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
START_PROFILE ( SMBwriteBmpx ) ;
CHECK_FSP ( fsp , conn ) ;
CHECK_WRITE ( fsp ) ;
CHECK_ERROR ( fsp ) ;
tcount = SVAL ( inbuf , smb_vwv1 ) ;
2002-12-03 11:02:41 +03:00
startpos = IVAL_TO_SMB_OFF_T ( inbuf , smb_vwv3 ) ;
2001-10-19 04:56:03 +04:00
write_through = BITSETW ( inbuf + smb_vwv7 , 0 ) ;
numtowrite = SVAL ( inbuf , smb_vwv10 ) ;
smb_doff = SVAL ( inbuf , smb_vwv11 ) ;
data = smb_base ( inbuf ) + smb_doff ;
/* If this fails we need to send an SMBwriteC response,
not an SMBwritebmpx - set this up now so we don ' t forget */
2002-01-11 22:10:25 +03:00
SCVAL ( outbuf , smb_com , SMBwritec ) ;
2001-10-19 04:56:03 +04:00
if ( is_locked ( fsp , conn , ( SMB_BIG_UINT ) tcount , ( SMB_BIG_UINT ) startpos , WRITE_LOCK , False ) ) {
END_PROFILE ( SMBwriteBmpx ) ;
return ( ERROR_DOS ( ERRDOS , ERRlock ) ) ;
}
nwritten = write_file ( fsp , data , startpos , numtowrite ) ;
if ( lp_syncalways ( SNUM ( conn ) ) | | write_through )
sync_file ( conn , fsp ) ;
if ( nwritten < ( ssize_t ) numtowrite ) {
END_PROFILE ( SMBwriteBmpx ) ;
return ( UNIXERROR ( ERRHRD , ERRdiskfull ) ) ;
}
/* If the maximum to be written to this file
is greater than what we just wrote then set
up a secondary struct to be attached to this
fd , we will use this to cache error messages etc . */
if ( ( ssize_t ) tcount > nwritten ) {
write_bmpx_struct * wbms ;
if ( fsp - > wbmpx_ptr ! = NULL )
wbms = fsp - > wbmpx_ptr ; /* Use an existing struct */
else
wbms = ( write_bmpx_struct * ) malloc ( sizeof ( write_bmpx_struct ) ) ;
if ( ! wbms ) {
DEBUG ( 0 , ( " Out of memory in reply_readmpx \n " ) ) ;
END_PROFILE ( SMBwriteBmpx ) ;
return ( ERROR_DOS ( ERRSRV , ERRnoresource ) ) ;
}
wbms - > wr_mode = write_through ;
wbms - > wr_discard = False ; /* No errors yet */
wbms - > wr_total_written = nwritten ;
wbms - > wr_errclass = 0 ;
wbms - > wr_error = 0 ;
fsp - > wbmpx_ptr = wbms ;
}
/* We are returning successfully, set the message type back to
SMBwritebmpx */
2002-01-11 22:10:25 +03:00
SCVAL ( outbuf , smb_com , SMBwriteBmpx ) ;
2001-10-19 04:56:03 +04:00
outsize = set_message ( outbuf , 1 , 0 , True ) ;
SSVALS ( outbuf , smb_vwv0 , - 1 ) ; /* We don't support smb_remaining */
DEBUG ( 3 , ( " writebmpx fnum=%d num=%d wrote=%d \n " ,
fsp - > fnum , ( int ) numtowrite , ( int ) nwritten ) ) ;
if ( write_through & & tcount = = nwritten ) {
/* We need to send both a primary and a secondary response */
smb_setlen ( outbuf , outsize - 4 ) ;
if ( ! send_smb ( smbd_server_fd ( ) , outbuf ) )
2001-11-05 03:02:38 +03:00
exit_server ( " reply_writebmpx: send_smb failed. " ) ;
2001-10-19 04:56:03 +04:00
/* Now the secondary */
outsize = set_message ( outbuf , 1 , 0 , True ) ;
2002-01-11 22:10:25 +03:00
SCVAL ( outbuf , smb_com , SMBwritec ) ;
2001-10-19 04:56:03 +04:00
SSVAL ( outbuf , smb_vwv0 , nwritten ) ;
}
END_PROFILE ( SMBwriteBmpx ) ;
return ( outsize ) ;
}
/****************************************************************************
Reply to a SMBwritebs ( write block multiplex secondary ) request .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int reply_writebs ( connection_struct * conn , char * inbuf , char * outbuf , int dum_size , int dum_buffsize )
{
size_t numtowrite ;
ssize_t nwritten = - 1 ;
int outsize = 0 ;
SMB_OFF_T startpos ;
size_t tcount ;
BOOL write_through ;
int smb_doff ;
char * data ;
write_bmpx_struct * wbms ;
BOOL send_response = False ;
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
START_PROFILE ( SMBwriteBs ) ;
CHECK_FSP ( fsp , conn ) ;
CHECK_WRITE ( fsp ) ;
tcount = SVAL ( inbuf , smb_vwv1 ) ;
2002-12-03 11:02:41 +03:00
startpos = IVAL_TO_SMB_OFF_T ( inbuf , smb_vwv2 ) ;
2001-10-19 04:56:03 +04:00
numtowrite = SVAL ( inbuf , smb_vwv6 ) ;
smb_doff = SVAL ( inbuf , smb_vwv7 ) ;
data = smb_base ( inbuf ) + smb_doff ;
/* We need to send an SMBwriteC response, not an SMBwritebs */
2002-01-11 22:10:25 +03:00
SCVAL ( outbuf , smb_com , SMBwritec ) ;
2001-10-19 04:56:03 +04:00
/* This fd should have an auxiliary struct attached,
check that it does */
wbms = fsp - > wbmpx_ptr ;
if ( ! wbms ) {
END_PROFILE ( SMBwriteBs ) ;
return ( - 1 ) ;
}
/* If write through is set we can return errors, else we must cache them */
write_through = wbms - > wr_mode ;
/* Check for an earlier error */
if ( wbms - > wr_discard ) {
END_PROFILE ( SMBwriteBs ) ;
return - 1 ; /* Just discard the packet */
}
nwritten = write_file ( fsp , data , startpos , numtowrite ) ;
if ( lp_syncalways ( SNUM ( conn ) ) | | write_through )
sync_file ( conn , fsp ) ;
if ( nwritten < ( ssize_t ) numtowrite ) {
if ( write_through ) {
/* We are returning an error - we can delete the aux struct */
if ( wbms )
free ( ( char * ) wbms ) ;
fsp - > wbmpx_ptr = NULL ;
END_PROFILE ( SMBwriteBs ) ;
return ( ERROR_DOS ( ERRHRD , ERRdiskfull ) ) ;
}
END_PROFILE ( SMBwriteBs ) ;
return ( CACHE_ERROR ( wbms , ERRHRD , ERRdiskfull ) ) ;
}
/* Increment the total written, if this matches tcount
we can discard the auxiliary struct ( hurrah ! ) and return a writeC */
wbms - > wr_total_written + = nwritten ;
if ( wbms - > wr_total_written > = tcount ) {
if ( write_through ) {
outsize = set_message ( outbuf , 1 , 0 , True ) ;
SSVAL ( outbuf , smb_vwv0 , wbms - > wr_total_written ) ;
send_response = True ;
}
free ( ( char * ) wbms ) ;
fsp - > wbmpx_ptr = NULL ;
}
if ( send_response ) {
END_PROFILE ( SMBwriteBs ) ;
return ( outsize ) ;
}
END_PROFILE ( SMBwriteBs ) ;
return ( - 1 ) ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
2001-10-19 04:56:03 +04:00
Reply to a SMBgetattrE .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
int reply_getattrE ( connection_struct * conn , char * inbuf , char * outbuf , int size , int dum_buffsize )
1996-05-04 11:50:46 +04:00
{
2002-03-20 03:46:53 +03:00
SMB_STRUCT_STAT sbuf ;
int outsize = 0 ;
int mode ;
files_struct * fsp = file_fsp ( inbuf , smb_vwv0 ) ;
START_PROFILE ( SMBgetattrE ) ;
1996-05-04 11:50:46 +04:00
2002-03-20 03:46:53 +03:00
outsize = set_message ( outbuf , 11 , 0 , True ) ;
1996-05-04 11:50:46 +04:00
2002-03-20 03:46:53 +03:00
if ( ! fsp | | ( fsp - > conn ! = conn ) ) {
END_PROFILE ( SMBgetattrE ) ;
return ERROR_DOS ( ERRDOS , ERRbadfid ) ;
}
1996-05-04 11:50:46 +04:00
2002-03-20 03:46:53 +03:00
/* Do an fstat on this file */
if ( fsp_stat ( fsp , & sbuf ) ) {
END_PROFILE ( SMBgetattrE ) ;
return ( UNIXERROR ( ERRDOS , ERRnoaccess ) ) ;
}
1996-05-04 11:50:46 +04:00
2002-03-20 03:46:53 +03:00
mode = dos_mode ( conn , fsp - > fsp_name , & sbuf ) ;
1996-05-04 11:50:46 +04:00
2002-03-20 03:46:53 +03:00
/*
* Convert the times into dos times . Set create
* date to be last modify date as UNIX doesn ' t save
* this .
*/
put_dos_date2 ( outbuf , smb_vwv0 , get_create_time ( & sbuf , lp_fake_dir_create_times ( SNUM ( conn ) ) ) ) ;
put_dos_date2 ( outbuf , smb_vwv2 , sbuf . st_atime ) ;
put_dos_date2 ( outbuf , smb_vwv4 , sbuf . st_mtime ) ;
if ( mode & aDIR ) {
SIVAL ( outbuf , smb_vwv6 , 0 ) ;
SIVAL ( outbuf , smb_vwv8 , 0 ) ;
} else {
2003-06-06 09:32:36 +04:00
uint32 allocation_size = get_allocation_size ( fsp , & sbuf ) ;
2002-03-20 03:46:53 +03:00
SIVAL ( outbuf , smb_vwv6 , ( uint32 ) sbuf . st_size ) ;
2003-06-06 09:32:36 +04:00
SIVAL ( outbuf , smb_vwv8 , allocation_size ) ;
2002-03-20 03:46:53 +03:00
}
SSVAL ( outbuf , smb_vwv10 , mode ) ;
1996-05-04 11:50:46 +04:00
2002-03-20 03:46:53 +03:00
DEBUG ( 3 , ( " reply_getattrE fnum=%d \n " , fsp - > fnum ) ) ;
1996-05-04 11:50:46 +04:00
2002-03-20 03:46:53 +03:00
END_PROFILE ( SMBgetattrE ) ;
return ( outsize ) ;
1996-05-04 11:50:46 +04:00
}