1998-08-19 05:49:57 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-08-19 05:49:57 +04:00
Blocking Locking functions
2003-02-27 04:04:34 +03:00
Copyright ( C ) Jeremy Allison 1998 - 2003
1998-08-19 05:49:57 +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 .
*/
# include "includes.h"
2001-10-02 08:29:50 +04:00
1998-08-19 05:49:57 +04:00
/****************************************************************************
This is the structure to queue to implement blocking locks .
notify . It consists of the requesting SMB and the expiry time .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-08-21 04:43:21 +04:00
typedef struct _blocking_lock_record {
struct _blocking_lock_record * next ;
struct _blocking_lock_record * prev ;
2003-07-24 10:56:56 +04:00
int com_type ;
files_struct * fsp ;
time_t expire_time ;
int lock_num ;
SMB_BIG_UINT offset ;
SMB_BIG_UINT count ;
uint16 lock_pid ;
2006-04-10 19:33:04 +04:00
enum brl_flavour lock_flav ;
enum brl_type lock_type ;
2003-07-24 10:56:56 +04:00
char * inbuf ;
int length ;
1998-08-19 05:49:57 +04:00
} blocking_lock_record ;
2004-08-21 04:43:21 +04:00
static blocking_lock_record * blocking_lock_queue ;
1998-08-19 05:49:57 +04:00
/****************************************************************************
Destructor for the above structure .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void free_blocking_lock_record ( blocking_lock_record * blr )
{
2004-08-21 04:43:21 +04:00
DLIST_REMOVE ( blocking_lock_queue , blr ) ;
2003-07-24 10:56:56 +04:00
SAFE_FREE ( blr - > inbuf ) ;
SAFE_FREE ( blr ) ;
1998-08-19 05:49:57 +04:00
}
/****************************************************************************
1998-08-20 23:28:37 +04:00
Determine if this is a secondary element of a chained SMB .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL in_chained_smb ( void )
{
2003-07-24 10:56:56 +04:00
return ( chain_size ! = 0 ) ;
1998-08-20 23:28:37 +04:00
}
2005-09-30 21:13:37 +04:00
static void received_unlock_msg ( int msg_type , struct process_id src ,
void * buf , size_t len ) ;
2003-02-27 04:04:34 +03:00
1998-08-20 23:28:37 +04:00
/****************************************************************************
Function to push a blocking lock request onto the lock queue .
1998-08-19 05:49:57 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-04-10 19:33:04 +04:00
BOOL push_blocking_lock_request ( char * inbuf , int length ,
files_struct * fsp ,
int lock_timeout ,
int lock_num ,
uint16 lock_pid ,
enum brl_type lock_type ,
enum brl_flavour lock_flav ,
SMB_BIG_UINT offset , SMB_BIG_UINT count )
1998-08-19 05:49:57 +04:00
{
2003-07-24 10:56:56 +04:00
static BOOL set_lock_msg ;
2004-08-21 04:43:21 +04:00
blocking_lock_record * blr , * tmp ;
2003-10-09 05:46:01 +04:00
BOOL my_lock_ctx = False ;
2006-04-10 19:33:04 +04:00
struct byte_range_lock * br_lck = NULL ;
2003-07-24 10:56:56 +04:00
NTSTATUS status ;
if ( in_chained_smb ( ) ) {
DEBUG ( 0 , ( " push_blocking_lock_request: cannot queue a chained request (currently). \n " ) ) ;
return False ;
}
/*
* Now queue an entry on the blocking lock queue . We setup
* the expiration time here .
*/
2003-02-27 04:04:34 +03:00
2004-12-07 21:25:53 +03:00
if ( ( blr = SMB_MALLOC_P ( blocking_lock_record ) ) = = NULL ) {
2003-07-24 10:56:56 +04:00
DEBUG ( 0 , ( " push_blocking_lock_request: Malloc fail ! \n " ) ) ;
return False ;
}
2006-04-10 19:33:04 +04:00
blr - > next = NULL ;
blr - > prev = NULL ;
2004-12-07 21:25:53 +03:00
if ( ( blr - > inbuf = ( char * ) SMB_MALLOC ( length ) ) = = NULL ) {
2003-07-24 10:56:56 +04:00
DEBUG ( 0 , ( " push_blocking_lock_request: Malloc fail (2)! \n " ) ) ;
SAFE_FREE ( blr ) ;
return False ;
}
1998-08-19 05:49:57 +04:00
2003-07-24 10:56:56 +04:00
blr - > com_type = CVAL ( inbuf , smb_com ) ;
2006-04-10 19:33:04 +04:00
blr - > fsp = fsp ;
2003-07-24 10:56:56 +04:00
blr - > expire_time = ( lock_timeout = = - 1 ) ? ( time_t ) - 1 : time ( NULL ) + ( time_t ) lock_timeout ;
blr - > lock_num = lock_num ;
blr - > lock_pid = lock_pid ;
2006-04-10 19:33:04 +04:00
blr - > lock_flav = lock_flav ;
blr - > lock_type = lock_type ;
2003-07-24 10:56:56 +04:00
blr - > offset = offset ;
blr - > count = count ;
memcpy ( blr - > inbuf , inbuf , length ) ;
blr - > length = length ;
2006-04-14 02:22:54 +04:00
br_lck = brl_get_locks ( blr - > fsp ) ;
2006-04-10 19:33:04 +04:00
if ( ! br_lck ) {
free_blocking_lock_record ( blr ) ;
return False ;
}
2003-07-24 10:56:56 +04:00
/* Add a pending lock record for this. */
2006-04-10 19:33:04 +04:00
status = brl_lock ( br_lck ,
lock_pid ,
procid_self ( ) ,
offset ,
count ,
PENDING_LOCK ,
blr - > lock_flav ,
& my_lock_ctx ) ;
2006-04-14 02:22:54 +04:00
byte_range_lock_destructor ( br_lck ) ;
2003-07-24 10:56:56 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " push_blocking_lock_request: failed to add PENDING_LOCK record. \n " ) ) ;
free_blocking_lock_record ( blr ) ;
return False ;
}
2004-08-21 04:43:21 +04:00
DLIST_ADD_END ( blocking_lock_queue , blr , tmp ) ;
2003-07-24 10:56:56 +04:00
/* Ensure we'll receive messages when this is unlocked. */
if ( ! set_lock_msg ) {
message_register ( MSG_SMB_UNLOCK , received_unlock_msg ) ;
set_lock_msg = True ;
}
1998-08-21 05:30:29 +04:00
2003-07-24 10:56:56 +04:00
DEBUG ( 3 , ( " push_blocking_lock_request: lock request length=%d blocked with expiry time %d (+%d) \
2000-05-05 01:57:28 +04:00
for fnum = % d , name = % s \ n " , length, (int)blr->expire_time, lock_timeout,
2003-07-24 10:56:56 +04:00
blr - > fsp - > fnum , blr - > fsp - > fsp_name ) ) ;
1998-08-19 05:49:57 +04:00
2003-07-24 10:56:56 +04:00
/* Push the MID of this packet on the signing queue. */
2003-10-22 01:19:00 +04:00
srv_defer_sign_response ( SVAL ( inbuf , smb_mid ) ) ;
2003-07-24 10:56:56 +04:00
return True ;
1998-08-19 05:49:57 +04:00
}
/****************************************************************************
1998-08-20 23:28:37 +04:00
Return a smd with a given size .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void send_blocking_reply ( char * outbuf , int outsize )
{
2001-06-09 05:38:54 +04:00
if ( outsize > 4 )
smb_setlen ( outbuf , outsize - 4 ) ;
1998-08-20 23:28:37 +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 ( " send_blocking_reply: send_smb failed. " ) ;
1998-08-20 23:28:37 +04:00
}
/****************************************************************************
Return a lockingX success SMB .
1998-08-19 05:49:57 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-20 23:28:37 +04:00
static void reply_lockingX_success ( blocking_lock_record * blr )
1998-08-19 05:49:57 +04:00
{
2005-06-28 02:53:56 +04:00
char * outbuf = get_OutBuffer ( ) ;
2003-07-24 10:56:56 +04:00
int bufsize = BUFFER_SIZE ;
char * inbuf = blr - > inbuf ;
int outsize = 0 ;
1998-08-19 05:49:57 +04:00
2003-07-24 10:56:56 +04:00
construct_reply_common ( inbuf , outbuf ) ;
set_message ( outbuf , 2 , 0 , True ) ;
1998-08-19 05:49:57 +04:00
2003-07-24 10:56:56 +04:00
/*
* As this message is a lockingX call we must handle
* any following chained message correctly .
* This is normally handled in construct_reply ( ) ,
* but as that calls switch_message , we can ' t use
* that here and must set up the chain info manually .
*/
1998-08-19 05:49:57 +04:00
2003-07-24 10:56:56 +04:00
outsize = chain_reply ( inbuf , outbuf , blr - > length , bufsize ) ;
1998-08-19 05:49:57 +04:00
2003-07-24 10:56:56 +04:00
outsize + = chain_size ;
1998-08-19 05:49:57 +04:00
2003-07-24 10:56:56 +04:00
send_blocking_reply ( outbuf , outsize ) ;
1998-08-20 23:28:37 +04:00
}
/****************************************************************************
Return a generic lock fail error blocking call .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-08-27 12:19:43 +04:00
static void generic_blocking_lock_error ( blocking_lock_record * blr , NTSTATUS status )
1998-08-20 23:28:37 +04:00
{
2005-06-28 02:53:56 +04:00
char * outbuf = get_OutBuffer ( ) ;
2001-06-09 05:38:54 +04:00
char * inbuf = blr - > inbuf ;
construct_reply_common ( inbuf , outbuf ) ;
1998-08-20 23:28:37 +04:00
2002-03-11 02:18:44 +03:00
/* whenever a timeout is given w2k maps LOCK_NOT_GRANTED to
FILE_LOCK_CONFLICT ! ( tridge ) */
if ( NT_STATUS_EQUAL ( status , NT_STATUS_LOCK_NOT_GRANTED ) ) {
status = NT_STATUS_FILE_LOCK_CONFLICT ;
}
2001-08-27 12:19:43 +04:00
ERROR_NT ( status ) ;
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 ( " generic_blocking_lock_error: send_smb failed. " ) ;
1998-08-19 05:49:57 +04:00
}
/****************************************************************************
1998-08-20 23:28:37 +04:00
Return a lock fail error for a lockingX call . Undo all the locks we have
obtained first .
1998-08-19 05:49:57 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-08-27 12:19:43 +04:00
static void reply_lockingX_error ( blocking_lock_record * blr , NTSTATUS status )
1998-08-19 05:49:57 +04:00
{
2001-08-27 12:19:43 +04:00
char * inbuf = blr - > inbuf ;
files_struct * fsp = blr - > fsp ;
uint16 num_ulocks = SVAL ( inbuf , smb_vwv6 ) ;
SMB_BIG_UINT count = ( SMB_BIG_UINT ) 0 , offset = ( SMB_BIG_UINT ) 0 ;
uint16 lock_pid ;
unsigned char locktype = CVAL ( inbuf , smb_vwv3 ) ;
BOOL large_file_format = ( locktype & LOCKING_ANDX_LARGE_FILES ) ;
char * data ;
int i ;
data = smb_buf ( inbuf ) + ( ( large_file_format ? 20 : 10 ) * num_ulocks ) ;
/*
* Data now points at the beginning of the list
* of smb_lkrng structs .
*/
/*
* 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 = blr - > lock_num - 1 ; i > = 0 ; i - - ) {
BOOL err ;
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 ) ;
/*
* We know err cannot be set as if it was the lock
* request would never have been queued . JRA .
*/
2006-04-10 19:33:04 +04:00
do_unlock ( fsp ,
lock_pid ,
count ,
offset ,
WINDOWS_LOCK ) ;
2001-08-27 12:19:43 +04:00
}
generic_blocking_lock_error ( blr , status ) ;
1998-08-20 23:28:37 +04:00
}
/****************************************************************************
Return a lock fail error .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-08-27 12:19:43 +04:00
static void blocking_lock_reply_error ( blocking_lock_record * blr , NTSTATUS status )
1998-08-20 23:28:37 +04:00
{
2001-08-27 12:19:43 +04:00
switch ( blr - > com_type ) {
2006-04-10 19:33:04 +04:00
#if 0
/* We no longer push blocking lock requests for anything but lockingX and trans2. */
2001-08-27 12:19:43 +04:00
case SMBlock :
case SMBlockread :
generic_blocking_lock_error ( blr , status ) ;
break ;
2006-04-10 19:33:04 +04:00
# endif
2001-08-27 12:19:43 +04:00
case SMBlockingX :
reply_lockingX_error ( blr , status ) ;
break ;
2006-04-10 19:33:04 +04:00
case SMBtrans2 :
case SMBtranss2 :
{
char * outbuf = get_OutBuffer ( ) ;
char * inbuf = blr - > inbuf ;
construct_reply_common ( inbuf , outbuf ) ;
/* construct_reply_common has done us the favor to pre-fill the
* command field with SMBtranss2 which is wrong : - )
*/
SCVAL ( outbuf , smb_com , SMBtrans2 ) ;
ERROR_NT ( status ) ;
if ( ! send_smb ( smbd_server_fd ( ) , outbuf ) ) {
exit_server ( " blocking_lock_reply_error: send_smb failed. " ) ;
}
break ;
}
2001-08-27 12:19:43 +04:00
default :
DEBUG ( 0 , ( " blocking_lock_reply_error: PANIC - unknown type on blocking lock queue - exiting.! \n " ) ) ;
exit_server ( " PANIC - unknown type on blocking lock queue " ) ;
}
1998-08-20 23:28:37 +04:00
}
2006-04-10 19:33:04 +04:00
#if 0
/* We no longer push blocking lock requests for anything but lockingX and trans2. */
1998-08-20 23:28:37 +04:00
/****************************************************************************
Attempt to finish off getting all pending blocking locks for a lockread call .
Returns True if we want to be removed from the list .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL process_lockread ( blocking_lock_record * blr )
{
2005-06-28 02:53:56 +04:00
char * outbuf = get_OutBuffer ( ) ;
2001-08-27 12:19:43 +04:00
char * inbuf = blr - > inbuf ;
ssize_t nread = - 1 ;
char * data , * p ;
int outsize = 0 ;
2002-12-03 11:02:41 +03:00
SMB_BIG_UINT startpos ;
2001-08-27 12:19:43 +04:00
size_t numtoread ;
NTSTATUS status ;
files_struct * fsp = blr - > fsp ;
2003-10-09 05:46:01 +04:00
BOOL my_lock_ctx = False ;
2001-08-27 12:19:43 +04:00
numtoread = SVAL ( inbuf , smb_vwv1 ) ;
2002-12-03 11:02:41 +03:00
startpos = ( SMB_BIG_UINT ) IVAL ( inbuf , smb_vwv2 ) ;
2001-08-27 12:19:43 +04:00
numtoread = MIN ( BUFFER_SIZE - outsize , numtoread ) ;
data = smb_buf ( outbuf ) + 3 ;
1998-08-20 23:28:37 +04:00
2006-04-10 19:33:04 +04:00
status = do_lock_spin ( fsp ,
SVAL ( inbuf , smb_pid ) ,
( SMB_BIG_UINT ) numtoread ,
startpos ,
READ_LOCK ,
WINDOWS_LOCK ,
& my_lock_ctx ) ;
2001-08-27 21:52:23 +04:00
if ( NT_STATUS_V ( status ) ) {
2002-08-17 19:27:10 +04:00
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_LOCK_NOT_GRANTED ) & &
! NT_STATUS_EQUAL ( status , NT_STATUS_FILE_LOCK_CONFLICT ) ) {
2001-08-27 12:19:43 +04:00
/*
2002-08-17 19:27:10 +04:00
* We have other than a " can't get lock "
2001-08-27 12:19:43 +04:00
* error . Send an error .
* Return True so we get dequeued .
*/
generic_blocking_lock_error ( blr , status ) ;
return True ;
}
/*
* Still waiting for lock . . . .
*/
DEBUG ( 10 , ( " process_lockread: failed to get lock for file = %s. Still waiting.... \n " ,
fsp - > fsp_name ) ) ;
return False ;
}
nread = read_file ( fsp , data , startpos , numtoread ) ;
if ( nread < 0 ) {
generic_blocking_lock_error ( blr , NT_STATUS_ACCESS_DENIED ) ;
return True ;
}
construct_reply_common ( inbuf , outbuf ) ;
outsize = set_message ( outbuf , 5 , 0 , True ) ;
outsize + = nread ;
SSVAL ( outbuf , smb_vwv0 , nread ) ;
SSVAL ( outbuf , smb_vwv5 , nread + 3 ) ;
p = smb_buf ( outbuf ) ;
* p + + = 1 ;
SSVAL ( p , 0 , nread ) ; p + = 2 ;
set_message_end ( outbuf , p + nread ) ;
2005-09-30 21:13:37 +04:00
DEBUG ( 3 , ( " process_lockread file = %s, fnum=%d num=%lu nread=%ld \n " ,
fsp - > fsp_name , fsp - > fnum , ( unsigned long ) numtoread , ( long ) nread ) ) ;
2001-08-27 12:19:43 +04:00
send_blocking_reply ( outbuf , outsize ) ;
return True ;
1998-08-19 05:49:57 +04:00
}
/****************************************************************************
1998-08-20 23:28:37 +04:00
Attempt to finish off getting all pending blocking locks for a lock call .
1998-08-19 05:49:57 +04:00
Returns True if we want to be removed from the list .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-20 23:28:37 +04:00
static BOOL process_lock ( blocking_lock_record * blr )
{
2005-06-28 02:53:56 +04:00
char * outbuf = get_OutBuffer ( ) ;
2001-08-27 12:19:43 +04:00
char * inbuf = blr - > inbuf ;
int outsize ;
2002-12-03 11:02:41 +03:00
SMB_BIG_UINT count = ( SMB_BIG_UINT ) 0 , offset = ( SMB_BIG_UINT ) 0 ;
2001-08-27 12:19:43 +04:00
NTSTATUS status ;
files_struct * fsp = blr - > fsp ;
2003-10-09 05:46:01 +04:00
BOOL my_lock_ctx = False ;
2001-08-27 12:19:43 +04:00
2002-12-03 11:02:41 +03:00
count = IVAL_TO_SMB_OFF_T ( inbuf , smb_vwv1 ) ;
offset = IVAL_TO_SMB_OFF_T ( inbuf , smb_vwv3 ) ;
2001-08-27 12:19:43 +04:00
errno = 0 ;
2006-04-10 19:33:04 +04:00
status = do_lock_spin ( fsp ,
SVAL ( inbuf , smb_pid ) ,
count ,
offset ,
WRITE_LOCK ,
WINDOWS_LOCK ,
& my_lock_ctx ) ;
2001-08-27 21:52:23 +04:00
if ( NT_STATUS_IS_ERR ( status ) ) {
2002-08-17 19:27:10 +04:00
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_LOCK_NOT_GRANTED ) & &
! NT_STATUS_EQUAL ( status , NT_STATUS_FILE_LOCK_CONFLICT ) ) {
2001-08-27 12:19:43 +04:00
/*
2002-08-17 19:27:10 +04:00
* We have other than a " can't get lock "
2001-08-27 12:19:43 +04:00
* error . Send an error .
* Return True so we get dequeued .
*/
blocking_lock_reply_error ( blr , status ) ;
return True ;
}
/*
* Still can ' t get the lock - keep waiting .
*/
DEBUG ( 10 , ( " process_lock: failed to get lock for file = %s. Still waiting.... \n " ,
fsp - > fsp_name ) ) ;
return False ;
}
/*
* Success - we got the lock .
*/
DEBUG ( 3 , ( " process_lock : file=%s fnum=%d offset=%.0f count=%.0f \n " ,
fsp - > fsp_name , fsp - > fnum , ( double ) offset , ( double ) count ) ) ;
construct_reply_common ( inbuf , outbuf ) ;
outsize = set_message ( outbuf , 0 , 0 , True ) ;
send_blocking_reply ( outbuf , outsize ) ;
return True ;
1998-08-20 23:28:37 +04:00
}
2006-04-10 19:33:04 +04:00
# endif
1998-08-20 23:28:37 +04:00
/****************************************************************************
Attempt to finish off getting all pending blocking locks for a lockingX call .
Returns True if we want to be removed from the list .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL process_lockingX ( blocking_lock_record * blr )
1998-08-19 05:49:57 +04:00
{
2001-08-27 12:19:43 +04:00
char * inbuf = blr - > inbuf ;
unsigned char locktype = CVAL ( inbuf , smb_vwv3 ) ;
files_struct * fsp = blr - > fsp ;
uint16 num_ulocks = SVAL ( inbuf , smb_vwv6 ) ;
uint16 num_locks = SVAL ( inbuf , smb_vwv7 ) ;
SMB_BIG_UINT count = ( SMB_BIG_UINT ) 0 , offset = ( SMB_BIG_UINT ) 0 ;
uint16 lock_pid ;
BOOL large_file_format = ( locktype & LOCKING_ANDX_LARGE_FILES ) ;
char * data ;
2003-10-09 05:46:01 +04:00
BOOL my_lock_ctx = False ;
2001-08-27 21:52:23 +04:00
NTSTATUS status = NT_STATUS_OK ;
2001-08-27 12:19:43 +04:00
data = smb_buf ( inbuf ) + ( ( large_file_format ? 20 : 10 ) * num_ulocks ) ;
/*
* Data now points at the beginning of the list
* of smb_lkrng structs .
*/
for ( ; blr - > lock_num < num_locks ; blr - > lock_num + + ) {
BOOL err ;
lock_pid = get_lock_pid ( data , blr - > lock_num , large_file_format ) ;
count = get_lock_count ( data , blr - > lock_num , large_file_format ) ;
offset = get_lock_offset ( data , blr - > lock_num , large_file_format , & err ) ;
/*
* We know err cannot be set as if it was the lock
* request would never have been queued . JRA .
*/
errno = 0 ;
2006-04-10 19:33:04 +04:00
status = do_lock_spin ( fsp ,
lock_pid ,
count ,
offset ,
( ( locktype & 1 ) ? READ_LOCK : WRITE_LOCK ) ,
WINDOWS_LOCK ,
& my_lock_ctx ) ;
if ( NT_STATUS_IS_ERR ( status ) ) {
break ;
}
2001-08-27 12:19:43 +04:00
}
if ( blr - > lock_num = = num_locks ) {
/*
* Success - we got all the locks .
*/
DEBUG ( 3 , ( " process_lockingX file = %s, fnum=%d type=%d num_locks=%d \n " ,
fsp - > fsp_name , fsp - > fnum , ( unsigned int ) locktype , num_locks ) ) ;
reply_lockingX_success ( blr ) ;
return True ;
2002-08-17 19:27:10 +04:00
} else if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_LOCK_NOT_GRANTED ) & &
! NT_STATUS_EQUAL ( status , NT_STATUS_FILE_LOCK_CONFLICT ) ) {
/*
* We have other than a " can't get lock "
* error . Free any locks we had and return an error .
* Return True so we get dequeued .
*/
2001-08-27 12:19:43 +04:00
blocking_lock_reply_error ( blr , status ) ;
return True ;
}
/*
* Still can ' t get all the locks - keep waiting .
*/
DEBUG ( 10 , ( " process_lockingX: only got %d locks of %d needed for file %s, fnum = %d. \
Waiting . . . . \ n " ,
blr - > lock_num , num_locks , fsp - > fsp_name , fsp - > fnum ) ) ;
return False ;
1998-08-19 05:49:57 +04:00
}
2006-04-10 19:33:04 +04:00
/****************************************************************************
Attempt to get the posix lock request from a SMBtrans2 call .
Returns True if we want to be removed from the list .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL process_trans2 ( blocking_lock_record * blr )
{
extern int max_send ;
char * inbuf = blr - > inbuf ;
char * outbuf ;
BOOL my_lock_ctx = False ;
char params [ 2 ] ;
NTSTATUS status ;
status = do_lock ( blr - > fsp ,
blr - > lock_pid ,
blr - > count ,
blr - > offset ,
blr - > lock_type ,
blr - > lock_flav ,
& my_lock_ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
if ( ERROR_WAS_LOCK_DENIED ( status ) ) {
/* Still can't get the lock, just keep waiting. */
return False ;
}
/*
* We have other than a " can't get lock "
* error . Send an error and return True so we get dequeued .
*/
blocking_lock_reply_error ( blr , status ) ;
return True ;
}
/* We finally got the lock, return success. */
outbuf = get_OutBuffer ( ) ;
construct_reply_common ( inbuf , outbuf ) ;
SCVAL ( outbuf , smb_com , SMBtrans2 ) ;
SSVAL ( params , 0 , 0 ) ;
send_trans2_replies ( outbuf , max_send , params , 2 , NULL , 0 ) ;
return True ;
}
1998-08-20 23:28:37 +04:00
/****************************************************************************
Process a blocking lock SMB .
Returns True if we want to be removed from the list .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL blocking_lock_record_process ( blocking_lock_record * blr )
{
2003-07-24 10:56:56 +04:00
switch ( blr - > com_type ) {
2006-04-10 19:33:04 +04:00
#if 0
/* We no longer push blocking lock requests for anything but lockingX and trans2. */
2003-07-24 10:56:56 +04:00
case SMBlock :
return process_lock ( blr ) ;
case SMBlockread :
return process_lockread ( blr ) ;
2006-04-10 19:33:04 +04:00
# endif
2003-07-24 10:56:56 +04:00
case SMBlockingX :
return process_lockingX ( blr ) ;
2006-04-10 19:33:04 +04:00
case SMBtrans2 :
case SMBtranss2 :
return process_trans2 ( blr ) ;
2003-07-24 10:56:56 +04:00
default :
DEBUG ( 0 , ( " blocking_lock_record_process: PANIC - unknown type on blocking lock queue - exiting.! \n " ) ) ;
exit_server ( " PANIC - unknown type on blocking lock queue " ) ;
}
return False ; /* Keep compiler happy. */
1998-08-20 23:28:37 +04:00
}
1998-08-19 05:49:57 +04:00
/****************************************************************************
Delete entries by fnum from the blocking lock pending queue .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void remove_pending_lock_requests_by_fid ( files_struct * fsp )
{
2004-08-21 04:43:21 +04:00
blocking_lock_record * blr , * next = NULL ;
1998-08-19 05:49:57 +04:00
2004-08-21 04:43:21 +04:00
for ( blr = blocking_lock_queue ; blr ; blr = next ) {
next = blr - > next ;
2003-07-24 10:56:56 +04:00
if ( blr - > fsp - > fnum = = fsp - > fnum ) {
2006-04-14 02:22:54 +04:00
struct byte_range_lock * br_lck = brl_get_locks ( fsp ) ;
1998-08-21 05:30:29 +04:00
2006-04-10 19:33:04 +04:00
if ( br_lck ) {
DEBUG ( 10 , ( " remove_pending_lock_requests_by_fid - removing request type %d for \
1998-08-21 05:30:29 +04:00
file % s fnum = % d \ n " , blr->com_type, fsp->fsp_name, fsp->fnum ));
1998-08-19 05:49:57 +04:00
2006-04-10 19:33:04 +04:00
brl_remove_pending_lock ( br_lck ,
blr - > lock_pid ,
procid_self ( ) ,
blr - > offset ,
blr - > count ,
blr - > lock_flav ) ;
2006-04-14 02:22:54 +04:00
byte_range_lock_destructor ( br_lck ) ;
2006-04-10 19:33:04 +04:00
}
2003-02-27 04:04:34 +03:00
2004-08-21 04:43:21 +04:00
free_blocking_lock_record ( blr ) ;
2003-07-24 10:56:56 +04:00
}
}
1998-08-19 05:49:57 +04:00
}
/****************************************************************************
Delete entries by mid from the blocking lock pending queue . Always send reply .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void remove_pending_lock_requests_by_mid ( int mid )
{
2004-08-21 04:43:21 +04:00
blocking_lock_record * blr , * next = NULL ;
1998-08-19 05:49:57 +04:00
2004-08-21 04:43:21 +04:00
for ( blr = blocking_lock_queue ; blr ; blr = next ) {
next = blr - > next ;
2003-07-24 10:56:56 +04:00
if ( SVAL ( blr - > inbuf , smb_mid ) = = mid ) {
files_struct * fsp = blr - > fsp ;
2006-04-14 02:22:54 +04:00
struct byte_range_lock * br_lck = brl_get_locks ( fsp ) ;
1998-08-21 05:30:29 +04:00
2006-04-10 19:33:04 +04:00
if ( br_lck ) {
DEBUG ( 10 , ( " remove_pending_lock_requests_by_mid - removing request type %d for \
1998-08-21 05:30:29 +04:00
file % s fnum = % d \ n " , blr->com_type, fsp->fsp_name, fsp->fnum ));
2006-04-10 19:33:04 +04:00
brl_remove_pending_lock ( br_lck ,
blr - > lock_pid ,
procid_self ( ) ,
blr - > offset ,
blr - > count ,
blr - > lock_flav ) ;
2006-04-14 02:22:54 +04:00
byte_range_lock_destructor ( br_lck ) ;
2006-04-10 19:33:04 +04:00
}
2003-10-10 06:02:05 +04:00
blocking_lock_reply_error ( blr , NT_STATUS_FILE_LOCK_CONFLICT ) ;
2004-08-21 04:43:21 +04:00
free_blocking_lock_record ( blr ) ;
2003-07-24 10:56:56 +04:00
}
}
1998-08-19 05:49:57 +04:00
}
2003-02-27 04:04:34 +03:00
/****************************************************************************
Set a flag as an unlock request affects one of our pending locks .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-09-30 21:13:37 +04:00
static void received_unlock_msg ( int msg_type , struct process_id src ,
void * buf , size_t len )
2003-02-27 04:04:34 +03:00
{
DEBUG ( 10 , ( " received_unlock_msg \n " ) ) ;
process_blocking_lock_queue ( time ( NULL ) ) ;
}
1999-12-13 16:27:58 +03:00
/****************************************************************************
2002-09-25 19:19:00 +04:00
Return the number of seconds to the next blocking locks timeout , or default_timeout
1999-12-13 16:27:58 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-02-27 04:04:34 +03:00
2002-09-25 19:19:00 +04:00
unsigned blocking_locks_timeout ( unsigned default_timeout )
1999-12-13 16:27:58 +03:00
{
2002-09-25 19:19:00 +04:00
unsigned timeout = default_timeout ;
time_t t ;
2004-08-21 04:43:21 +04:00
blocking_lock_record * blr = blocking_lock_queue ;
2002-09-25 19:19:00 +04:00
/* note that we avoid the time() syscall if there are no blocking locks */
2003-02-27 04:04:34 +03:00
if ( ! blr )
2002-09-25 19:19:00 +04:00
return timeout ;
t = time ( NULL ) ;
2004-08-21 04:43:21 +04:00
for ( ; blr ; blr = blr - > next ) {
2003-02-27 04:04:34 +03:00
if ( ( blr - > expire_time ! = ( time_t ) - 1 ) & &
( timeout > ( blr - > expire_time - t ) ) ) {
2002-09-25 19:19:00 +04:00
timeout = blr - > expire_time - t ;
}
}
2003-02-27 04:04:34 +03:00
if ( timeout < 1 )
2002-09-25 19:19:00 +04:00
timeout = 1 ;
return timeout ;
1999-12-13 16:27:58 +03:00
}
1998-08-19 05:49:57 +04:00
/****************************************************************************
Process the blocking lock queue . Note that this is only called as root .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_blocking_lock_queue ( time_t t )
{
2004-08-21 04:43:21 +04:00
blocking_lock_record * blr , * next = NULL ;
2003-07-24 10:56:56 +04:00
/*
* Go through the queue and see if we can get any of the locks .
*/
2004-08-21 04:43:21 +04:00
for ( blr = blocking_lock_queue ; blr ; blr = next ) {
2003-07-24 10:56:56 +04:00
connection_struct * conn = NULL ;
uint16 vuid ;
files_struct * fsp = NULL ;
2004-08-21 04:43:21 +04:00
next = blr - > next ;
2003-07-24 10:56:56 +04:00
/*
* Ensure we don ' t have any old chain_fsp values
* sitting around . . . .
*/
chain_size = 0 ;
file_chain_reset ( ) ;
fsp = blr - > fsp ;
conn = conn_find ( SVAL ( blr - > inbuf , smb_tid ) ) ;
vuid = ( lp_security ( ) = = SEC_SHARE ) ? UID_FIELD_INVALID :
SVAL ( blr - > inbuf , smb_uid ) ;
DEBUG ( 5 , ( " process_blocking_lock_queue: examining pending lock fnum = %d for file %s \n " ,
fsp - > fnum , fsp - > fsp_name ) ) ;
if ( ( blr - > expire_time ! = - 1 ) & & ( blr - > expire_time < = t ) ) {
2006-04-14 02:22:54 +04:00
struct byte_range_lock * br_lck = brl_get_locks ( fsp ) ;
2006-04-10 19:33:04 +04:00
2003-07-24 10:56:56 +04:00
/*
* Lock expired - throw away all previously
* obtained locks and return lock error .
*/
2006-04-10 19:33:04 +04:00
if ( br_lck ) {
DEBUG ( 5 , ( " process_blocking_lock_queue: pending lock fnum = %d for file %s timed out. \n " ,
fsp - > fnum , fsp - > fsp_name ) ) ;
brl_remove_pending_lock ( br_lck ,
blr - > lock_pid ,
procid_self ( ) ,
blr - > offset ,
blr - > count ,
blr - > lock_flav ) ;
2006-04-14 02:22:54 +04:00
byte_range_lock_destructor ( br_lck ) ;
2006-04-10 19:33:04 +04:00
}
2003-07-24 10:56:56 +04:00
blocking_lock_reply_error ( blr , NT_STATUS_FILE_LOCK_CONFLICT ) ;
2004-08-21 04:43:21 +04:00
free_blocking_lock_record ( blr ) ;
2003-07-24 10:56:56 +04:00
continue ;
}
if ( ! change_to_user ( conn , vuid ) ) {
2006-04-14 02:22:54 +04:00
struct byte_range_lock * br_lck = brl_get_locks ( fsp ) ;
2006-04-10 19:33:04 +04:00
2003-07-24 10:56:56 +04:00
/*
* Remove the entry and return an error to the client .
*/
2006-04-10 19:33:04 +04:00
if ( br_lck ) {
brl_remove_pending_lock ( br_lck ,
blr - > lock_pid ,
procid_self ( ) ,
blr - > offset ,
blr - > count ,
blr - > lock_flav ) ;
2006-04-14 02:22:54 +04:00
byte_range_lock_destructor ( br_lck ) ;
2006-04-10 19:33:04 +04:00
}
2003-07-24 10:56:56 +04:00
2006-04-10 19:33:04 +04:00
DEBUG ( 0 , ( " process_blocking_lock_queue: Unable to become user vuid=%d. \n " ,
vuid ) ) ;
blocking_lock_reply_error ( blr , NT_STATUS_ACCESS_DENIED ) ;
2004-08-21 04:43:21 +04:00
free_blocking_lock_record ( blr ) ;
2003-07-24 10:56:56 +04:00
continue ;
}
2004-06-15 22:36:45 +04:00
if ( ! set_current_service ( conn , SVAL ( blr - > inbuf , smb_flg ) , True ) ) {
2006-04-14 02:22:54 +04:00
struct byte_range_lock * br_lck = brl_get_locks ( fsp ) ;
2006-04-10 19:33:04 +04:00
2003-07-24 10:56:56 +04:00
/*
* Remove the entry and return an error to the client .
*/
2006-04-10 19:33:04 +04:00
if ( br_lck ) {
brl_remove_pending_lock ( br_lck ,
blr - > lock_pid ,
procid_self ( ) ,
blr - > offset ,
blr - > count ,
blr - > lock_flav ) ;
2006-04-14 02:22:54 +04:00
byte_range_lock_destructor ( br_lck ) ;
2006-04-10 19:33:04 +04:00
}
2003-07-24 10:56:56 +04:00
2006-04-10 19:33:04 +04:00
DEBUG ( 0 , ( " process_blocking_lock_queue: Unable to become service Error was %s. \n " , strerror ( errno ) ) ) ;
blocking_lock_reply_error ( blr , NT_STATUS_ACCESS_DENIED ) ;
2004-08-21 04:43:21 +04:00
free_blocking_lock_record ( blr ) ;
2003-07-24 10:56:56 +04:00
change_to_root_user ( ) ;
continue ;
}
/*
* Go through the remaining locks and try and obtain them .
* The call returns True if all locks were obtained successfully
* and False if we still need to wait .
*/
if ( blocking_lock_record_process ( blr ) ) {
2006-04-14 02:22:54 +04:00
struct byte_range_lock * br_lck = brl_get_locks ( fsp ) ;
2006-04-10 19:33:04 +04:00
if ( br_lck ) {
brl_remove_pending_lock ( br_lck ,
blr - > lock_pid ,
procid_self ( ) ,
blr - > offset ,
blr - > count ,
blr - > lock_flav ) ;
2006-04-14 02:22:54 +04:00
byte_range_lock_destructor ( br_lck ) ;
2006-04-10 19:33:04 +04:00
}
2003-07-24 10:56:56 +04:00
2004-08-21 04:43:21 +04:00
free_blocking_lock_record ( blr ) ;
2003-07-24 10:56:56 +04:00
}
change_to_root_user ( ) ;
}
1998-08-19 05:49:57 +04:00
}