1998-08-17 17:11:34 +04:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
file opening and share modes
Copyright ( C ) Andrew Tridgell 1992 - 1998
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
extern int DEBUGLEVEL ;
extern pstring sesssetup_user ;
1998-09-23 05:48:45 +04:00
extern uint16 global_oplock_port ;
1998-08-17 17:11:34 +04:00
/****************************************************************************
1998-09-02 00:11:54 +04:00
fd support routines - attempt to do a dos_open
1998-08-17 17:11:34 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-09-17 23:16:12 +04:00
static int fd_attempt_open ( char * fname , int flags , mode_t mode )
1998-08-17 17:11:34 +04:00
{
1998-09-02 00:11:54 +04:00
int fd = dos_open ( fname , flags , mode ) ;
1998-08-17 17:11:34 +04:00
/* Fix for files ending in '.' */
if ( ( fd = = - 1 ) & & ( errno = = ENOENT ) & &
( strchr ( fname , ' . ' ) = = NULL ) )
{
pstrcat ( fname , " . " ) ;
1998-09-02 00:11:54 +04:00
fd = dos_open ( fname , flags , mode ) ;
1998-08-17 17:11:34 +04:00
}
# if (defined(ENAMETOOLONG) && defined(HAVE_PATHCONF))
if ( ( fd = = - 1 ) & & ( errno = = ENAMETOOLONG ) )
{
int max_len ;
char * p = strrchr ( fname , ' / ' ) ;
if ( p = = fname ) /* name is "/xxx" */
{
max_len = pathconf ( " / " , _PC_NAME_MAX ) ;
p + + ;
}
else if ( ( p = = NULL ) | | ( p = = fname ) )
{
p = fname ;
max_len = pathconf ( " . " , _PC_NAME_MAX ) ;
}
else
{
* p = ' \0 ' ;
max_len = pathconf ( fname , _PC_NAME_MAX ) ;
* p = ' / ' ;
p + + ;
}
if ( strlen ( p ) > max_len )
{
char tmp = p [ max_len ] ;
p [ max_len ] = ' \0 ' ;
1998-09-02 00:11:54 +04:00
if ( ( fd = dos_open ( fname , flags , mode ) ) = = - 1 )
1998-08-17 17:11:34 +04:00
p [ max_len ] = tmp ;
}
}
# endif
return fd ;
}
/****************************************************************************
Cache a uid_t currently with this file open . This is an optimization only
used when multiple sessionsetup ' s have been done to one smbd .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void fd_add_to_uid_cache ( file_fd_struct * fd_ptr , uid_t u )
{
if ( fd_ptr - > uid_cache_count > = sizeof ( fd_ptr - > uid_users_cache ) / sizeof ( uid_t ) )
return ;
fd_ptr - > uid_users_cache [ fd_ptr - > uid_cache_count + + ] = u ;
}
/****************************************************************************
Remove a uid_t that currently has this file open . This is an optimization only
used when multiple sessionsetup ' s have been done to one smbd .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void fd_remove_from_uid_cache ( file_fd_struct * fd_ptr , uid_t u )
{
int i ;
for ( i = 0 ; i < fd_ptr - > uid_cache_count ; i + + )
if ( fd_ptr - > uid_users_cache [ i ] = = u ) {
if ( i < ( fd_ptr - > uid_cache_count - 1 ) )
memmove ( ( char * ) & fd_ptr - > uid_users_cache [ i ] , ( char * ) & fd_ptr - > uid_users_cache [ i + 1 ] ,
sizeof ( uid_t ) * ( fd_ptr - > uid_cache_count - 1 - i ) ) ;
fd_ptr - > uid_cache_count - - ;
}
return ;
}
/****************************************************************************
Check if a uid_t that currently has this file open is present . This is an
optimization only used when multiple sessionsetup ' s have been done to one smbd .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL fd_is_in_uid_cache ( file_fd_struct * fd_ptr , uid_t u )
{
int i ;
for ( i = 0 ; i < fd_ptr - > uid_cache_count ; i + + )
if ( fd_ptr - > uid_users_cache [ i ] = = u )
return True ;
return False ;
}
/****************************************************************************
fd support routines - attempt to re - open an already open fd as O_RDWR .
Save the already open fd ( we cannot close due to POSIX file locking braindamage .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-09-17 23:16:12 +04:00
static void fd_attempt_reopen ( char * fname , mode_t mode , file_fd_struct * fd_ptr )
1998-08-17 17:11:34 +04:00
{
1998-09-02 00:11:54 +04:00
int fd = dos_open ( fname , O_RDWR , mode ) ;
1998-08-17 17:11:34 +04:00
if ( fd = = - 1 )
return ;
if ( fd_ptr - > real_open_flags = = O_RDONLY )
fd_ptr - > fd_readonly = fd_ptr - > fd ;
if ( fd_ptr - > real_open_flags = = O_WRONLY )
fd_ptr - > fd_writeonly = fd_ptr - > fd ;
fd_ptr - > fd = fd ;
fd_ptr - > real_open_flags = O_RDWR ;
}
/****************************************************************************
fd support routines - attempt to close the file referenced by this fd .
Decrements the ref_count and returns it .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-09-08 23:21:04 +04:00
uint16 fd_attempt_close ( file_fd_struct * fd_ptr )
1998-08-17 17:11:34 +04:00
{
extern struct current_user current_user ;
1998-09-08 23:21:04 +04:00
uint16 ret_ref = fd_ptr - > ref_count ;
1998-08-17 17:11:34 +04:00
1998-09-05 00:53:58 +04:00
DEBUG ( 3 , ( " fd_attempt_close fd = %d, dev = %x, inode = %.0f, open_flags = %d, ref_count = %d. \n " ,
fd_ptr - > fd , ( unsigned int ) fd_ptr - > dev , ( double ) fd_ptr - > inode ,
1998-08-17 17:11:34 +04:00
fd_ptr - > real_open_flags ,
fd_ptr - > ref_count ) ) ;
1998-09-08 23:21:04 +04:00
SMB_ASSERT ( fd_ptr - > ref_count ! = 0 ) ;
fd_ptr - > ref_count - - ;
ret_ref = fd_ptr - > ref_count ;
if ( fd_ptr - > ref_count = = 0 ) {
if ( fd_ptr - > fd ! = - 1 )
close ( fd_ptr - > fd ) ;
if ( fd_ptr - > fd_readonly ! = - 1 )
close ( fd_ptr - > fd_readonly ) ;
if ( fd_ptr - > fd_writeonly ! = - 1 )
close ( fd_ptr - > fd_writeonly ) ;
/*
* Delete this fd_ptr .
*/
fd_ptr_free ( fd_ptr ) ;
} else {
fd_remove_from_uid_cache ( fd_ptr , ( uid_t ) current_user . uid ) ;
}
return ret_ref ;
1998-08-17 17:11:34 +04:00
}
/****************************************************************************
fd support routines - check that current user has permissions
to open this file . Used when uid not found in optimization cache .
This is really ugly code , as due to POSIX locking braindamage we must
fork and then attempt to open the file , and return success or failure
via an exit code .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL check_access_allowed_for_current_user ( char * fname , int accmode )
{
pid_t child_pid ;
if ( ( child_pid = fork ( ) ) < 0 ) {
DEBUG ( 0 , ( " check_access_allowed_for_current_user: fork failed. \n " ) ) ;
return False ;
}
if ( child_pid ) {
/*
* Parent .
*/
pid_t wpid ;
int status_code ;
if ( ( wpid = sys_waitpid ( child_pid , & status_code , 0 ) ) < 0 ) {
DEBUG ( 0 , ( " check_access_allowed_for_current_user: The process is no longer waiting! \n " ) ) ;
return ( False ) ;
}
if ( child_pid ! = wpid ) {
DEBUG ( 0 , ( " check_access_allowed_for_current_user: We were waiting for the wrong process ID \n " ) ) ;
return ( False ) ;
}
# if defined(WIFEXITED) && defined(WEXITSTATUS)
if ( WIFEXITED ( status_code ) = = 0 ) {
DEBUG ( 0 , ( " check_access_allowed_for_current_user: The process exited while we were waiting \n " ) ) ;
return ( False ) ;
}
if ( WEXITSTATUS ( status_code ) ! = 0 ) {
DEBUG ( 9 , ( " check_access_allowed_for_current_user: The status of the process exiting was %d. Returning access denied. \n " , status_code ) ) ;
return ( False ) ;
}
# else /* defined(WIFEXITED) && defined(WEXITSTATUS) */
if ( status_code ! = 0 ) {
DEBUG ( 9 , ( " check_access_allowed_for_current_user: The status of the process exiting was %d. Returning access denied. \n " , status_code ) ) ;
return ( False ) ;
}
# endif /* defined(WIFEXITED) && defined(WEXITSTATUS) */
/*
* Success - the child could open the file .
*/
DEBUG ( 9 , ( " check_access_allowed_for_current_user: The status of the process exiting was %d. Returning access allowed. \n " , status_code ) ) ;
return True ;
} else {
/*
* Child .
*/
int fd ;
DEBUG ( 9 , ( " check_access_allowed_for_current_user: Child - attempting to open %s with mode %d. \n " , fname , accmode ) ) ;
if ( ( fd = fd_attempt_open ( fname , accmode , 0 ) ) < 0 ) {
/* Access denied. */
_exit ( EACCES ) ;
}
close ( fd ) ;
DEBUG ( 9 , ( " check_access_allowed_for_current_user: Child - returning ok. \n " ) ) ;
_exit ( 0 ) ;
}
return False ;
}
/****************************************************************************
check a filename for the pipe string
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void check_for_pipe ( char * fname )
{
/* special case of pipe opens */
char s [ 10 ] ;
StrnCpy ( s , fname , 9 ) ;
strlower ( s ) ;
if ( strstr ( s , " pipe/ " ) ) {
DEBUG ( 3 , ( " Rejecting named pipe open for %s \n " , fname ) ) ;
unix_ERR_class = ERRSRV ;
unix_ERR_code = ERRaccess ;
}
}
/****************************************************************************
open a file
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void open_file ( files_struct * fsp , connection_struct * conn ,
1998-09-17 23:16:12 +04:00
char * fname1 , int flags , mode_t mode , SMB_STRUCT_STAT * sbuf )
1998-08-17 17:11:34 +04:00
{
extern struct current_user current_user ;
pstring fname ;
1998-09-02 00:11:54 +04:00
SMB_STRUCT_STAT statbuf ;
1998-08-17 17:11:34 +04:00
file_fd_struct * fd_ptr ;
1998-10-03 15:54:00 +04:00
int accmode = ( flags & O_ACCMODE ) ;
1998-08-17 17:11:34 +04:00
fsp - > open = False ;
fsp - > fd_ptr = 0 ;
fsp - > granted_oplock = False ;
errno = EPERM ;
pstrcpy ( fname , fname1 ) ;
/* check permissions */
/*
* This code was changed after seeing a client open request
* containing the open mode of ( DENY_WRITE / read - only ) with
* the ' create if not exist ' bit set . The previous code
* would fail to open the file read only on a read - only share
* as it was checking the flags parameter directly against O_RDONLY ,
* this was failing as the flags parameter was set to O_RDONLY | O_CREAT .
* JRA .
*/
if ( conn - > read_only & & ! conn - > printer ) {
/* It's a read-only share - fail if we wanted to write. */
if ( accmode ! = O_RDONLY ) {
DEBUG ( 3 , ( " Permission denied opening %s \n " , fname ) ) ;
check_for_pipe ( fname ) ;
return ;
} else if ( flags & O_CREAT ) {
/* We don't want to write - but we must make sure that O_CREAT
doesn ' t create the file if we have write access into the
directory .
*/
flags & = ~ O_CREAT ;
}
}
/* this handles a bug in Win95 - it doesn't say to create the file when it
should */
if ( conn - > printer ) {
flags | = O_CREAT ;
}
/*
if ( flags = = O_WRONLY )
DEBUG ( 3 , ( " Bug in client? Set O_WRONLY without O_CREAT \n " ) ) ;
*/
/*
* Ensure we have a valid struct stat so we can search the
* open fd table .
*/
if ( sbuf = = 0 ) {
1998-09-02 00:11:54 +04:00
if ( dos_stat ( fname , & statbuf ) < 0 ) {
1998-08-17 17:11:34 +04:00
if ( errno ! = ENOENT ) {
DEBUG ( 3 , ( " Error doing stat on file %s (%s) \n " ,
fname , strerror ( errno ) ) ) ;
check_for_pipe ( fname ) ;
return ;
}
sbuf = 0 ;
} else {
sbuf = & statbuf ;
}
}
/*
* Check to see if we have this file already
* open . If we do , just use the already open fd and increment the
* reference count ( fd_get_already_open increments the ref_count ) .
*/
if ( ( fd_ptr = fd_get_already_open ( sbuf ) ) ! = 0 ) {
/*
* File was already open .
*/
/*
* Check it wasn ' t open for exclusive use .
*/
if ( ( flags & O_CREAT ) & & ( flags & O_EXCL ) ) {
fd_ptr - > ref_count - - ;
errno = EEXIST ;
return ;
}
/*
* Ensure that the user attempting to open
* this file has permissions to do so , if
* the user who originally opened the file wasn ' t
* the same as the current user .
*/
if ( ! fd_is_in_uid_cache ( fd_ptr , ( uid_t ) current_user . uid ) ) {
if ( ! check_access_allowed_for_current_user ( fname , accmode ) ) {
/* Error - permission denied. */
DEBUG ( 3 , ( " Permission denied opening file %s (flags=%d, accmode = %d) \n " ,
fname , flags , accmode ) ) ;
/* Ensure the ref_count is decremented. */
fd_ptr - > ref_count - - ;
fd_remove_from_uid_cache ( fd_ptr , ( uid_t ) current_user . uid ) ;
errno = EACCES ;
return ;
}
}
fd_add_to_uid_cache ( fd_ptr , ( uid_t ) current_user . uid ) ;
/*
* If not opened O_RDWR try
* and do that here - a chmod may have been done
* between the last open and now .
*/
if ( fd_ptr - > real_open_flags ! = O_RDWR )
fd_attempt_reopen ( fname , mode , fd_ptr ) ;
/*
* Ensure that if we wanted write access
* it has been opened for write , and if we wanted read it
* was open for read .
*/
if ( ( ( accmode = = O_WRONLY ) & & ( fd_ptr - > real_open_flags = = O_RDONLY ) ) | |
( ( accmode = = O_RDONLY ) & & ( fd_ptr - > real_open_flags = = O_WRONLY ) ) | |
( ( accmode = = O_RDWR ) & & ( fd_ptr - > real_open_flags ! = O_RDWR ) ) ) {
DEBUG ( 3 , ( " Error opening (already open for flags=%d) file %s (%s) (flags=%d) \n " ,
fd_ptr - > real_open_flags , fname , strerror ( EACCES ) , flags ) ) ;
check_for_pipe ( fname ) ;
fd_remove_from_uid_cache ( fd_ptr , ( uid_t ) current_user . uid ) ;
fd_ptr - > ref_count - - ;
return ;
}
} else {
int open_flags ;
/* We need to allocate a new file_fd_struct (this increments the
ref_count ) . */
if ( ( fd_ptr = fd_get_new ( ) ) = = 0 )
return ;
/*
* Whatever the requested flags , attempt read / write access ,
* as we don ' t know what flags future file opens may require .
* If this fails , try again with the required flags .
* Even if we open read / write when only read access was
* requested the setting of the can_write flag in
* the file_struct will protect us from errant
* write requests . We never need to worry about O_APPEND
* as this is not set anywhere in Samba .
*/
fd_ptr - > real_open_flags = O_RDWR ;
/* Set the flags as needed without the read/write modes. */
open_flags = flags & ~ ( O_RDWR | O_WRONLY | O_RDONLY ) ;
fd_ptr - > fd = fd_attempt_open ( fname , open_flags | O_RDWR , mode ) ;
/*
* On some systems opening a file for R / W access on a read only
* filesystems sets errno to EROFS .
*/
# ifdef EROFS
if ( ( fd_ptr - > fd = = - 1 ) & & ( ( errno = = EACCES ) | | ( errno = = EROFS ) ) ) {
# else /* No EROFS */
if ( ( fd_ptr - > fd = = - 1 ) & & ( errno = = EACCES ) ) {
# endif /* EROFS */
if ( accmode ! = O_RDWR ) {
fd_ptr - > fd = fd_attempt_open ( fname , open_flags | accmode , mode ) ;
fd_ptr - > real_open_flags = accmode ;
}
}
}
if ( ( fd_ptr - > fd > = 0 ) & &
conn - > printer & & lp_minprintspace ( SNUM ( conn ) ) ) {
pstring dname ;
1998-09-18 03:06:57 +04:00
SMB_BIG_UINT dum1 , dum2 , dum3 ;
1998-08-17 17:11:34 +04:00
char * p ;
pstrcpy ( dname , fname ) ;
p = strrchr ( dname , ' / ' ) ;
if ( p ) * p = 0 ;
1998-09-18 03:06:57 +04:00
if ( sys_disk_free ( dname , & dum1 , & dum2 , & dum3 ) < ( SMB_BIG_UINT ) lp_minprintspace ( SNUM ( conn ) ) ) {
1998-09-05 07:14:40 +04:00
if ( fd_attempt_close ( fd_ptr ) = = 0 )
1998-09-02 00:11:54 +04:00
dos_unlink ( fname ) ;
1998-09-05 07:14:40 +04:00
fsp - > fd_ptr = 0 ;
1998-08-17 17:11:34 +04:00
errno = ENOSPC ;
return ;
}
}
if ( fd_ptr - > fd < 0 )
{
DEBUG ( 3 , ( " Error opening file %s (%s) (flags=%d) \n " ,
fname , strerror ( errno ) , flags ) ) ;
/* Ensure the ref_count is decremented. */
fd_attempt_close ( fd_ptr ) ;
check_for_pipe ( fname ) ;
return ;
}
if ( fd_ptr - > fd > = 0 )
{
if ( sbuf = = 0 ) {
/* Do the fstat */
1998-09-03 22:40:31 +04:00
if ( sys_fstat ( fd_ptr - > fd , & statbuf ) = = - 1 ) {
1998-08-17 17:11:34 +04:00
/* Error - backout !! */
DEBUG ( 3 , ( " Error doing fstat on fd %d, file %s (%s) \n " ,
fd_ptr - > fd , fname , strerror ( errno ) ) ) ;
/* Ensure the ref_count is decremented. */
fd_attempt_close ( fd_ptr ) ;
return ;
}
sbuf = & statbuf ;
}
/* Set the correct entries in fd_ptr. */
1998-09-01 00:20:54 +04:00
fd_ptr - > dev = sbuf - > st_dev ;
fd_ptr - > inode = sbuf - > st_ino ;
1998-08-17 17:11:34 +04:00
fsp - > fd_ptr = fd_ptr ;
conn - > num_files_open + + ;
fsp - > mode = sbuf - > st_mode ;
GetTimeOfDay ( & fsp - > open_time ) ;
fsp - > vuid = current_user . vuid ;
fsp - > size = 0 ;
fsp - > pos = - 1 ;
fsp - > open = True ;
fsp - > mmap_ptr = NULL ;
fsp - > mmap_size = 0 ;
fsp - > can_lock = True ;
fsp - > can_read = ( ( flags & O_WRONLY ) = = 0 ) ;
fsp - > can_write = ( ( flags & ( O_WRONLY | O_RDWR ) ) ! = 0 ) ;
fsp - > share_mode = 0 ;
fsp - > print_file = conn - > printer ;
fsp - > modified = False ;
fsp - > granted_oplock = False ;
fsp - > sent_oplock_break = False ;
fsp - > is_directory = False ;
fsp - > conn = conn ;
/*
* Note that the file name here is the * untranslated * name
* ie . it is still in the DOS codepage sent from the client .
* All use of this filename will pass though the sys_xxxx
* functions which will do the dos_to_unix translation before
* mapping into a UNIX filename . JRA .
*/
string_set ( & fsp - > fsp_name , fname ) ;
fsp - > wbmpx_ptr = NULL ;
/*
* If the printer is marked as postscript output a leading
* file identifier to ensure the file is treated as a raw
* postscript file .
* This has a similar effect as CtrlD = 0 in WIN . INI file .
* tim @ fsg . com 09 / 06 / 94
*/
if ( fsp - > print_file & & lp_postscript ( SNUM ( conn ) ) & & fsp - > can_write ) {
DEBUG ( 3 , ( " Writing postscript line \n " ) ) ;
write_file ( fsp , " %! \n " , 3 ) ;
}
DEBUG ( 2 , ( " %s opened file %s read=%s write=%s (numopen=%d) \n " ,
1998-08-25 06:29:17 +04:00
* sesssetup_user ? sesssetup_user : conn - > user , fsp - > fsp_name ,
1998-08-17 17:11:34 +04:00
BOOLSTR ( fsp - > can_read ) , BOOLSTR ( fsp - > can_write ) ,
conn - > num_files_open ) ) ;
}
1998-09-26 03:40:49 +04:00
}
1998-08-17 17:11:34 +04:00
1998-09-26 03:40:49 +04:00
/****************************************************************************
If it ' s a read - only file , and we were compiled with mmap enabled ,
try and mmap the file . This is split out from open_file ( ) above
as mmap ' ing the file can cause the kernel reference count to
be incremented , which can cause kernel oplocks to be refused .
Splitting this call off allows the kernel oplock to be granted , then
the file mmap ' ed .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void mmap_open_file ( files_struct * fsp )
{
1998-08-17 17:11:34 +04:00
# if WITH_MMAP
/* mmap it if read-only */
if ( ! fsp - > can_write ) {
1998-09-26 03:40:49 +04:00
fsp - > mmap_size = file_size ( fsp - > fsp_name ) ;
1998-09-18 07:00:20 +04:00
if ( fsp - > mmap_size < MAX_MMAP_SIZE ) {
fsp - > mmap_ptr = ( char * ) mmap ( NULL , fsp - > mmap_size ,
PROT_READ , MAP_SHARED , fsp - > fd_ptr - > fd , 0 ) ;
if ( fsp - > mmap_ptr = = ( char * ) - 1 | | ! fsp - > mmap_ptr ) {
DEBUG ( 3 , ( " Failed to mmap() %s - %s \n " ,
1998-09-26 03:40:49 +04:00
fsp - > fsp_name , strerror ( errno ) ) ) ;
1998-09-18 07:00:20 +04:00
fsp - > mmap_ptr = NULL ;
}
1998-08-17 17:11:34 +04:00
}
}
# endif
}
/****************************************************************************
C . Hoch 11 / 22 / 95
Helper for open_file_shared .
Truncate a file after checking locking ; close file if locked .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void truncate_unless_locked ( files_struct * fsp , connection_struct * conn , int token ,
BOOL * share_locked )
{
1998-09-18 06:27:24 +04:00
if ( fsp - > can_write ) {
SMB_OFF_T mask = ( ( SMB_OFF_T ) 0xC ) < < ( SMB_OFF_T_BITS - 4 ) ;
if ( is_locked ( fsp , conn , ~ mask , 0 , F_WRLCK ) ) {
/* If share modes are in force for this connection we
have the share entry locked . Unlock it before closing . */
if ( * share_locked & & lp_share_modes ( SNUM ( conn ) ) )
unlock_share_entry ( conn , fsp - > fd_ptr - > dev ,
fsp - > fd_ptr - > inode , token ) ;
close_file ( fsp , False ) ;
/* Share mode no longer locked. */
* share_locked = False ;
errno = EACCES ;
unix_ERR_class = ERRDOS ;
unix_ERR_code = ERRlock ;
} else {
sys_ftruncate ( fsp - > fd_ptr - > fd , 0 ) ;
}
}
1998-08-17 17:11:34 +04:00
}
1998-09-05 09:07:05 +04:00
enum { AFAIL , AREAD , AWRITE , AALL } ;
/*******************************************************************
reproduce the share mode access table
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int access_table ( int new_deny , int old_deny , int old_mode ,
int share_pid , char * fname )
{
if ( new_deny = = DENY_ALL | | old_deny = = DENY_ALL ) return ( AFAIL ) ;
if ( new_deny = = DENY_DOS | | old_deny = = DENY_DOS ) {
int pid = getpid ( ) ;
if ( old_deny = = new_deny & & share_pid = = pid )
return ( AALL ) ;
if ( old_mode = = 0 ) return ( AREAD ) ;
/* the new smbpub.zip spec says that if the file extension is
. com , . dll , . exe or . sym then allow the open . I will force
it to read - only as this seems sensible although the spec is
a little unclear on this . */
if ( ( fname = strrchr ( fname , ' . ' ) ) ) {
if ( strequal ( fname , " .com " ) | |
strequal ( fname , " .dll " ) | |
strequal ( fname , " .exe " ) | |
strequal ( fname , " .sym " ) )
return ( AREAD ) ;
}
return ( AFAIL ) ;
}
switch ( new_deny )
{
case DENY_WRITE :
if ( old_deny = = DENY_WRITE & & old_mode = = 0 ) return ( AREAD ) ;
if ( old_deny = = DENY_READ & & old_mode = = 0 ) return ( AWRITE ) ;
if ( old_deny = = DENY_NONE & & old_mode = = 0 ) return ( AALL ) ;
return ( AFAIL ) ;
case DENY_READ :
if ( old_deny = = DENY_WRITE & & old_mode = = 1 ) return ( AREAD ) ;
if ( old_deny = = DENY_READ & & old_mode = = 1 ) return ( AWRITE ) ;
if ( old_deny = = DENY_NONE & & old_mode = = 1 ) return ( AALL ) ;
return ( AFAIL ) ;
case DENY_NONE :
if ( old_deny = = DENY_WRITE ) return ( AREAD ) ;
if ( old_deny = = DENY_READ ) return ( AWRITE ) ;
if ( old_deny = = DENY_NONE ) return ( AALL ) ;
return ( AFAIL ) ;
}
return ( AFAIL ) ;
}
/****************************************************************************
check if we can open a file with a share mode
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int check_share_mode ( share_mode_entry * share , int deny_mode ,
char * fname ,
BOOL fcbopen , int * flags )
{
1998-10-23 04:58:28 +04:00
int old_open_mode = GET_OPEN_MODE ( share - > share_mode ) ;
int old_deny_mode = GET_DENY_MODE ( share - > share_mode ) ;
1998-09-05 09:07:05 +04:00
1998-10-23 07:34:50 +04:00
/*
* Setup the potential error to return .
*/
unix_ERR_class = ERRDOS ;
unix_ERR_code = ERRbadshare ;
/*
* Don ' t allow any open once the delete on close flag has been
* set .
*/
if ( GET_DELETE_ON_CLOSE_FLAG ( share - > share_mode ) )
{
DEBUG ( 5 , ( " check_share_mode: Failing open on file %s as delete on close flag is set. \n " ,
fname ) ) ;
unix_ERR_code = ERRnoaccess ;
return False ;
}
1998-09-05 09:07:05 +04:00
if ( old_deny_mode > 4 | | old_open_mode > 2 )
{
DEBUG ( 0 , ( " Invalid share mode found (%d,%d,%d) on file %s \n " ,
deny_mode , old_deny_mode , old_open_mode , fname ) ) ;
return False ;
}
{
int access_allowed = access_table ( deny_mode , old_deny_mode , old_open_mode ,
share - > pid , fname ) ;
if ( ( access_allowed = = AFAIL ) | |
( ! fcbopen & & ( access_allowed = = AREAD & & * flags = = O_RDWR ) ) | |
( access_allowed = = AREAD & & * flags = = O_WRONLY ) | |
( access_allowed = = AWRITE & & * flags = = O_RDONLY ) )
{
DEBUG ( 2 , ( " Share violation on file (%d,%d,%d,%d,%s,fcbopen = %d, flags = %d) = %d \n " ,
deny_mode , old_deny_mode , old_open_mode ,
share - > pid , fname , fcbopen , * flags , access_allowed ) ) ;
return False ;
}
if ( access_allowed = = AREAD )
* flags = O_RDONLY ;
if ( access_allowed = = AWRITE )
* flags = O_WRONLY ;
}
1998-10-23 07:34:50 +04:00
1998-09-05 09:07:05 +04:00
return True ;
}
1998-08-17 17:11:34 +04:00
/****************************************************************************
open a file with a share mode
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-10-22 20:55:03 +04:00
1998-08-17 17:11:34 +04:00
void open_file_shared ( files_struct * fsp , connection_struct * conn , char * fname , int share_mode , int ofun ,
1998-09-18 22:09:17 +04:00
mode_t mode , int oplock_request , int * Access , int * action )
1998-08-17 17:11:34 +04:00
{
int flags = 0 ;
int flags2 = 0 ;
1998-10-23 04:58:28 +04:00
int deny_mode = GET_DENY_MODE ( share_mode ) ;
BOOL allow_share_delete = GET_ALLOW_SHARE_DELETE ( share_mode ) ;
1998-09-02 00:11:54 +04:00
SMB_STRUCT_STAT sbuf ;
1998-08-17 17:11:34 +04:00
BOOL file_existed = file_exist ( fname , & sbuf ) ;
BOOL share_locked = False ;
BOOL fcbopen = False ;
int token ;
1998-09-01 00:20:54 +04:00
SMB_DEV_T dev = 0 ;
SMB_INO_T inode = 0 ;
1998-08-17 17:11:34 +04:00
int num_share_modes = 0 ;
fsp - > open = False ;
fsp - > fd_ptr = 0 ;
1998-10-22 20:55:03 +04:00
DEBUG ( 10 , ( " open_file_shared: fname = %s, share_mode = %x, ofun = %x, mode = %o, oplock request = %d \n " ,
fname , share_mode , ofun , mode , oplock_request ) ) ;
1998-08-17 17:11:34 +04:00
/* this is for OS/2 EAs - try and say we don't support them */
if ( strstr ( fname , " .+,;=[]. " ) )
{
unix_ERR_class = ERRDOS ;
/* OS/2 Workplace shell fix may be main code stream in a later release. */
# if 1 /* OS2_WPS_FIX - Recent versions of OS/2 need this. */
unix_ERR_code = ERRcannotopen ;
# else /* OS2_WPS_FIX */
unix_ERR_code = ERROR_EAS_NOT_SUPPORTED ;
# endif /* OS2_WPS_FIX */
1998-10-22 20:55:03 +04:00
DEBUG ( 5 , ( " open_file_shared: OS/2 EA's are not supported. \n " ) ) ;
1998-08-17 17:11:34 +04:00
return ;
}
1998-10-23 04:58:28 +04:00
if ( ( GET_FILE_OPEN_DISPOSITION ( ofun ) = = FILE_EXISTS_FAIL ) & & file_existed )
1998-08-17 17:11:34 +04:00
{
1998-10-22 20:55:03 +04:00
DEBUG ( 5 , ( " open_file_shared: create new requested for file %s and file already exists. \n " ,
fname ) ) ;
1998-08-17 17:11:34 +04:00
errno = EEXIST ;
return ;
}
1998-10-23 04:58:28 +04:00
if ( GET_FILE_CREATE_DISPOSITION ( ofun ) = = FILE_CREATE_IF_NOT_EXIST )
1998-08-17 17:11:34 +04:00
flags2 | = O_CREAT ;
1998-10-23 04:58:28 +04:00
if ( GET_FILE_OPEN_DISPOSITION ( ofun ) = = FILE_EXISTS_TRUNCATE )
1998-08-17 17:11:34 +04:00
flags2 | = O_TRUNC ;
/* note that we ignore the append flag as
append does not mean the same thing under dos and unix */
1998-10-23 04:58:28 +04:00
switch ( GET_OPEN_MODE ( share_mode ) )
1998-08-17 17:11:34 +04:00
{
1998-10-23 04:58:28 +04:00
case DOS_OPEN_WRONLY :
1998-08-17 17:11:34 +04:00
flags = O_WRONLY ;
break ;
1998-10-23 04:58:28 +04:00
case DOS_OPEN_FCB :
1998-08-17 17:11:34 +04:00
fcbopen = True ;
flags = O_RDWR ;
break ;
1998-10-23 04:58:28 +04:00
case DOS_OPEN_RDWR :
1998-08-17 17:11:34 +04:00
flags = O_RDWR ;
break ;
default :
flags = O_RDONLY ;
break ;
}
# if defined(O_SYNC)
1998-10-23 04:58:28 +04:00
if ( GET_FILE_SYNC_OPENMODE ( share_mode ) ) {
1998-08-17 17:11:34 +04:00
flags2 | = O_SYNC ;
}
# endif /* O_SYNC */
if ( flags ! = O_RDONLY & & file_existed & &
( ! CAN_WRITE ( conn ) | | IS_DOS_READONLY ( dos_mode ( conn , fname , & sbuf ) ) ) )
{
if ( ! fcbopen )
{
1998-10-22 20:55:03 +04:00
DEBUG ( 5 , ( " open_file_shared: read/write access requested for file %s on read only %s \n " ,
fname , ! CAN_WRITE ( conn ) ? " share " : " file " ) ) ;
1998-08-17 17:11:34 +04:00
errno = EACCES ;
return ;
}
flags = O_RDONLY ;
}
if ( deny_mode > DENY_NONE & & deny_mode ! = DENY_FCB )
{
DEBUG ( 2 , ( " Invalid deny mode %d on file %s \n " , deny_mode , fname ) ) ;
errno = EINVAL ;
return ;
}
1998-10-23 04:58:28 +04:00
if ( deny_mode = = DENY_FCB )
deny_mode = DENY_DOS ;
1998-08-17 17:11:34 +04:00
if ( lp_share_modes ( SNUM ( conn ) ) )
{
int i ;
share_mode_entry * old_shares = 0 ;
if ( file_existed )
{
1998-09-01 00:20:54 +04:00
dev = sbuf . st_dev ;
inode = sbuf . st_ino ;
1998-08-17 17:11:34 +04:00
lock_share_entry ( conn , dev , inode , & token ) ;
share_locked = True ;
num_share_modes = get_share_modes ( conn , token , dev , inode , & old_shares ) ;
}
/*
* Check if the share modes will give us access .
*/
if ( share_locked & & ( num_share_modes ! = 0 ) )
{
BOOL broke_oplock ;
do
{
broke_oplock = False ;
for ( i = 0 ; i < num_share_modes ; i + + )
{
share_mode_entry * share_entry = & old_shares [ i ] ;
/*
* By observation of NetBench , oplocks are broken * before * share
* modes are checked . This allows a file to be closed by the client
* if the share mode would deny access and the client has an oplock .
* Check if someone has an oplock on this file . If so we must break
* it before continuing .
*/
if ( share_entry - > op_type & ( EXCLUSIVE_OPLOCK | BATCH_OPLOCK ) )
{
1998-09-05 00:53:58 +04:00
DEBUG ( 5 , ( " open_file_shared: breaking oplock (%x) on file %s, \
dev = % x , inode = % .0f \ n " , share_entry->op_type, fname, (unsigned int)dev, (double)inode));
1998-08-17 17:11:34 +04:00
/* Oplock break.... */
unlock_share_entry ( conn , dev , inode , token ) ;
if ( request_oplock_break ( share_entry , dev , inode ) = = False )
{
free ( ( char * ) old_shares ) ;
1998-09-05 00:53:58 +04:00
DEBUG ( 0 , ( " open_file_shared: FAILED when breaking oplock (%x) on file %s, \
dev = % x , inode = % .0f \ n " , old_shares[i].op_type, fname, (unsigned int)dev, (double)inode));
1998-08-17 17:11:34 +04:00
errno = EACCES ;
unix_ERR_class = ERRDOS ;
unix_ERR_code = ERRbadshare ;
return ;
}
lock_share_entry ( conn , dev , inode , & token ) ;
broke_oplock = True ;
break ;
}
/* someone else has a share lock on it, check to see
if we can too */
if ( check_share_mode ( share_entry , deny_mode , fname , fcbopen , & flags ) = = False )
{
free ( ( char * ) old_shares ) ;
unlock_share_entry ( conn , dev , inode , token ) ;
errno = EACCES ;
return ;
}
} /* end for */
if ( broke_oplock )
{
free ( ( char * ) old_shares ) ;
num_share_modes = get_share_modes ( conn , token , dev , inode , & old_shares ) ;
}
} while ( broke_oplock ) ;
}
if ( old_shares ! = 0 )
free ( ( char * ) old_shares ) ;
}
DEBUG ( 4 , ( " calling open_file with flags=0x%X flags2=0x%X mode=0%o \n " ,
1998-09-17 23:16:12 +04:00
flags , flags2 , ( int ) mode ) ) ;
1998-08-17 17:11:34 +04:00
open_file ( fsp , conn , fname , flags | ( flags2 & ~ ( O_TRUNC ) ) , mode , file_existed ? & sbuf : 0 ) ;
if ( ! fsp - > open & & flags = = O_RDWR & & errno ! = ENOENT & & fcbopen )
{
flags = O_RDONLY ;
open_file ( fsp , conn , fname , flags , mode , file_existed ? & sbuf : 0 ) ;
}
if ( fsp - > open )
{
int open_mode = 0 ;
if ( ( share_locked = = False ) & & lp_share_modes ( SNUM ( conn ) ) )
{
/* We created the file - thus we must now lock the share entry before creating it. */
dev = fsp - > fd_ptr - > dev ;
inode = fsp - > fd_ptr - > inode ;
lock_share_entry ( conn , dev , inode , & token ) ;
share_locked = True ;
}
switch ( flags )
{
case O_RDONLY :
1998-10-23 04:58:28 +04:00
open_mode = DOS_OPEN_RDONLY ;
1998-08-17 17:11:34 +04:00
break ;
case O_RDWR :
1998-10-23 04:58:28 +04:00
open_mode = DOS_OPEN_RDWR ;
1998-08-17 17:11:34 +04:00
break ;
case O_WRONLY :
1998-10-23 04:58:28 +04:00
open_mode = DOS_OPEN_WRONLY ;
1998-08-17 17:11:34 +04:00
break ;
}
1998-10-23 04:58:28 +04:00
fsp - > share_mode = SET_DENY_MODE ( deny_mode ) |
SET_OPEN_MODE ( open_mode ) |
SET_ALLOW_SHARE_DELETE ( allow_share_delete ) ;
1998-08-17 17:11:34 +04:00
if ( Access )
( * Access ) = open_mode ;
if ( action )
{
if ( file_existed & & ! ( flags2 & O_TRUNC ) ) * action = FILE_WAS_OPENED ;
if ( ! file_existed ) * action = FILE_WAS_CREATED ;
if ( file_existed & & ( flags2 & O_TRUNC ) ) * action = FILE_WAS_OVERWRITTEN ;
}
/* We must create the share mode entry before truncate as
truncate can fail due to locking and have to close the
file ( which expects the share_mode_entry to be there ) .
*/
if ( lp_share_modes ( SNUM ( conn ) ) )
{
uint16 port = 0 ;
1998-09-23 05:48:45 +04:00
1998-08-17 17:11:34 +04:00
/* JRA. Currently this only services Exlcusive and batch
oplocks ( no other opens on this file ) . This needs to
be extended to level II oplocks ( multiple reader
oplocks ) . */
1998-09-18 22:09:17 +04:00
if ( ( oplock_request ) & & ( num_share_modes = = 0 ) & & lp_oplocks ( SNUM ( conn ) ) & &
1998-09-23 05:48:45 +04:00
! IS_VETO_OPLOCK_PATH ( conn , fname ) & & set_file_oplock ( fsp ) )
1998-08-17 17:11:34 +04:00
{
1998-09-23 05:48:45 +04:00
port = global_oplock_port ;
1998-08-17 17:11:34 +04:00
}
else
{
port = 0 ;
1998-09-18 22:09:17 +04:00
oplock_request = 0 ;
1998-08-17 17:11:34 +04:00
}
1998-09-23 05:48:45 +04:00
1998-09-18 22:09:17 +04:00
set_share_mode ( token , fsp , port , oplock_request ) ;
1998-08-17 17:11:34 +04:00
}
if ( ( flags2 & O_TRUNC ) & & file_existed )
truncate_unless_locked ( fsp , conn , token , & share_locked ) ;
1998-09-26 03:40:49 +04:00
/*
* Attempt to mmap a read only file .
* Moved until after a kernel oplock may
* be granted due to reference count issues . JRA .
*/
mmap_open_file ( fsp ) ;
1998-08-17 17:11:34 +04:00
}
if ( share_locked & & lp_share_modes ( SNUM ( conn ) ) )
unlock_share_entry ( conn , dev , inode , token ) ;
}
/****************************************************************************
Open a directory from an NT SMB call .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-10-23 04:58:28 +04:00
1998-08-17 17:11:34 +04:00
int open_directory ( files_struct * fsp , connection_struct * conn ,
1998-09-18 03:06:57 +04:00
char * fname , int smb_ofun , mode_t unixmode , int * action )
1998-08-17 17:11:34 +04:00
{
extern struct current_user current_user ;
1998-09-02 00:11:54 +04:00
SMB_STRUCT_STAT st ;
1998-08-17 17:11:34 +04:00
if ( smb_ofun & 0x10 ) {
/*
* Create the directory .
*/
1998-10-22 20:55:03 +04:00
if ( dos_mkdir ( fname , unix_mode ( conn , aDIR ) ) < 0 ) {
1998-08-17 17:11:34 +04:00
DEBUG ( 0 , ( " open_directory: unable to create %s. Error was %s \n " ,
fname , strerror ( errno ) ) ) ;
return - 1 ;
}
* action = FILE_WAS_CREATED ;
} else {
/*
* Check that it * was * a directory .
*/
1998-09-02 00:11:54 +04:00
if ( dos_stat ( fname , & st ) < 0 ) {
1998-08-17 17:11:34 +04:00
DEBUG ( 0 , ( " open_directory: unable to stat name = %s. Error was %s \n " ,
fname , strerror ( errno ) ) ) ;
return - 1 ;
}
if ( ! S_ISDIR ( st . st_mode ) ) {
DEBUG ( 0 , ( " open_directory: %s is not a directory ! \n " , fname ) ) ;
return - 1 ;
}
* action = FILE_WAS_OPENED ;
}
DEBUG ( 5 , ( " open_directory: opening directory %s \n " ,
fname ) ) ;
/*
* Setup the files_struct for it .
*/
fsp - > fd_ptr = NULL ;
conn - > num_files_open + + ;
fsp - > mode = 0 ;
GetTimeOfDay ( & fsp - > open_time ) ;
fsp - > vuid = current_user . vuid ;
fsp - > size = 0 ;
fsp - > pos = - 1 ;
fsp - > open = True ;
fsp - > mmap_ptr = NULL ;
fsp - > mmap_size = 0 ;
fsp - > can_lock = True ;
fsp - > can_read = False ;
fsp - > can_write = False ;
fsp - > share_mode = 0 ;
fsp - > print_file = False ;
fsp - > modified = False ;
fsp - > granted_oplock = False ;
fsp - > sent_oplock_break = False ;
fsp - > is_directory = True ;
fsp - > conn = conn ;
/*
* Note that the file name here is the * untranslated * name
* ie . it is still in the DOS codepage sent from the client .
* All use of this filename will pass though the sys_xxxx
* functions which will do the dos_to_unix translation before
* mapping into a UNIX filename . JRA .
*/
string_set ( & fsp - > fsp_name , fname ) ;
fsp - > wbmpx_ptr = NULL ;
return 0 ;
}
/*******************************************************************
check if the share mode on a file allows it to be deleted or unlinked
return True if sharing doesn ' t prevent the operation
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-10-23 04:58:28 +04:00
1998-08-17 17:11:34 +04:00
BOOL check_file_sharing ( connection_struct * conn , char * fname , BOOL rename_op )
{
int i ;
int ret = False ;
share_mode_entry * old_shares = 0 ;
int num_share_modes ;
1998-09-02 00:11:54 +04:00
SMB_STRUCT_STAT sbuf ;
1998-08-17 17:11:34 +04:00
int token ;
int pid = getpid ( ) ;
1998-09-01 00:20:54 +04:00
SMB_DEV_T dev ;
SMB_INO_T inode ;
1998-08-17 17:11:34 +04:00
if ( ! lp_share_modes ( SNUM ( conn ) ) )
return True ;
1998-09-02 00:11:54 +04:00
if ( dos_stat ( fname , & sbuf ) = = - 1 ) return ( True ) ;
1998-08-17 17:11:34 +04:00
1998-09-01 00:20:54 +04:00
dev = sbuf . st_dev ;
inode = sbuf . st_ino ;
1998-08-17 17:11:34 +04:00
lock_share_entry ( conn , dev , inode , & token ) ;
num_share_modes = get_share_modes ( conn , token , dev , inode , & old_shares ) ;
/*
* Check if the share modes will give us access .
*/
if ( num_share_modes ! = 0 )
{
BOOL broke_oplock ;
do
{
broke_oplock = False ;
for ( i = 0 ; i < num_share_modes ; i + + )
{
share_mode_entry * share_entry = & old_shares [ i ] ;
/*
* Break oplocks before checking share modes . See comment in
* open_file_shared for details .
* Check if someone has an oplock on this file . If so we must
* break it before continuing .
*/
if ( share_entry - > op_type & BATCH_OPLOCK )
{
/*
* It appears that the NT redirector may have a bug , in that
* it tries to do an SMBmv on a file that it has open with a
* batch oplock , and then fails to respond to the oplock break
* request . This only seems to occur when the client is doing an
* SMBmv to the smbd it is using - thus we try and detect this
* condition by checking if the file being moved is open and oplocked by
* this smbd process , and then not sending the oplock break in this
* special case . If the file was open with a deny mode that
* prevents the move the SMBmv will fail anyway with a share
* violation error . JRA .
*/
if ( rename_op & & ( share_entry - > pid = = pid ) )
{
1998-09-05 00:53:58 +04:00
DEBUG ( 0 , ( " check_file_sharing: NT redirector workaround - rename attempted on \
batch oplocked file % s , dev = % x , inode = % .0f \ n " , fname, (unsigned int)dev, (double)inode));
1998-08-17 17:11:34 +04:00
/*
* This next line is a test that allows the deny - mode
* processing to be skipped . This seems to be needed as
* NT insists on the rename succeeding ( in Office 9 x no less ! ) .
* This should be removed as soon as ( a ) MS fix the redirector
* bug or ( b ) NT SMB support in Samba makes NT not issue the
* call ( as is my fervent hope ) . JRA .
*/
continue ;
}
else
{
1998-09-05 00:53:58 +04:00
1998-08-17 17:11:34 +04:00
DEBUG ( 5 , ( " check_file_sharing: breaking oplock (%x) on file %s, \
1998-09-05 00:53:58 +04:00
dev = % x , inode = % .0f \ n " , share_entry->op_type, fname, (unsigned int)dev, (double)inode));
1998-08-17 17:11:34 +04:00
/* Oplock break.... */
unlock_share_entry ( conn , dev , inode , token ) ;
if ( request_oplock_break ( share_entry , dev , inode ) = = False )
{
free ( ( char * ) old_shares ) ;
1998-09-05 00:53:58 +04:00
1998-08-17 17:11:34 +04:00
DEBUG ( 0 , ( " check_file_sharing: FAILED when breaking oplock (%x) on file %s, \
1998-09-05 00:53:58 +04:00
dev = % x , inode = % .0f \ n " , old_shares[i].op_type, fname, (unsigned int)dev, (double)inode));
1998-08-17 17:11:34 +04:00
return False ;
}
lock_share_entry ( conn , dev , inode , & token ) ;
broke_oplock = True ;
break ;
}
}
1998-10-23 04:58:28 +04:00
/*
* If this is a delete request and ALLOW_SHARE_DELETE is set then allow
* this to proceed . This takes precedence over share modes .
*/
if ( ! rename_op & & GET_ALLOW_SHARE_DELETE ( share_entry - > share_mode ) )
continue ;
/*
* Someone else has a share lock on it , check to see
* if we can too .
*/
if ( ( GET_DENY_MODE ( share_entry - > share_mode ) ! = DENY_DOS ) | | ( share_entry - > pid ! = pid ) )
1998-08-17 17:11:34 +04:00
goto free_and_exit ;
} /* end for */
if ( broke_oplock )
{
free ( ( char * ) old_shares ) ;
num_share_modes = get_share_modes ( conn , token , dev , inode , & old_shares ) ;
}
} while ( broke_oplock ) ;
}
/* XXXX exactly what share mode combinations should be allowed for
deleting / renaming ? */
1998-10-23 04:58:28 +04:00
/*
* If we got here then either there were no share modes or
* all share modes were DENY_DOS and the pid = = getpid ( ) or
* delete access was requested and all share modes had the
* ALLOW_SHARE_DELETE bit set ( takes precedence over other
* share modes ) .
*/
1998-08-17 17:11:34 +04:00
ret = True ;
free_and_exit :
unlock_share_entry ( conn , dev , inode , token ) ;
if ( old_shares ! = NULL )
free ( ( char * ) old_shares ) ;
return ( ret ) ;
}