2008-12-08 16:42:45 -08:00
/*
2008-12-08 16:57:58 -08:00
* Unix SMB / CIFS implementation .
*
2008-12-31 21:24:25 -08:00
* This file began with some code from source3 / smbd / open . c and has been
* modified it work with ifs_createfile .
2008-12-08 16:57:58 -08:00
*
* ifs_createfile is a CIFS - specific syscall for opening / files and
* directories . It adds support for :
* - Full in - kernel access checks using a windows access_mask
* - Cluster - coherent share mode locks
* - Cluster - coherent oplocks
* - Streams
* - Setting security descriptors at create time
* - Setting dos_attributes at create time
*
* Copyright ( C ) Andrew Tridgell 1992 - 1998
* Copyright ( C ) Jeremy Allison 2001 - 2004
* Copyright ( C ) Volker Lendecke 2005
* Copyright ( C ) Tim Prouty , 2008
*
* 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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
2008-12-08 16:42:45 -08:00
2009-02-27 14:47:47 -08:00
# include "includes.h"
2008-12-08 16:57:58 -08:00
# include "onefs.h"
2009-02-27 14:47:47 -08:00
# include "onefs_config.h"
# include "oplock_onefs.h"
2009-01-27 16:13:35 -08:00
# include "smbd/globals.h"
2008-12-08 16:42:45 -08:00
extern const struct generic_mapping file_generic_mapping ;
2009-01-27 16:13:35 -08:00
struct onefs_fsp_data {
uint64_t oplock_callback_id ;
2008-12-08 16:42:45 -08:00
} ;
2008-12-08 16:57:58 -08:00
static NTSTATUS onefs_create_file_unixpath ( connection_struct * conn ,
struct smb_request * req ,
const char * fname ,
uint32_t access_mask ,
uint32_t share_access ,
uint32_t create_disposition ,
uint32_t create_options ,
uint32_t file_attributes ,
uint32_t oplock_request ,
uint64_t allocation_size ,
struct security_descriptor * sd ,
struct ea_list * ea_list ,
files_struct * * result ,
int * pinfo ,
2009-01-27 16:13:35 -08:00
struct onefs_fsp_data * fsp_data ,
2008-12-08 16:57:58 -08:00
SMB_STRUCT_STAT * psbuf ) ;
2008-12-08 16:42:45 -08:00
/****************************************************************************
Open a file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-12-08 16:57:58 -08:00
static NTSTATUS onefs_open_file ( files_struct * fsp ,
connection_struct * conn ,
struct smb_request * req ,
const char * parent_dir ,
const char * name ,
const char * path ,
SMB_STRUCT_STAT * psbuf ,
int flags ,
mode_t unx_mode ,
uint32 access_mask ,
uint32 open_access_mask ,
int oplock_request ,
uint64 id ,
uint32 share_access ,
uint32 create_options ,
uint32_t new_dos_attributes ,
struct security_descriptor * sd ,
int * granted_oplock )
2008-12-08 16:42:45 -08:00
{
NTSTATUS status = NT_STATUS_OK ;
int accmode = ( flags & O_ACCMODE ) ;
int local_flags = flags ;
bool file_existed = VALID_STAT ( * psbuf ) ;
2008-12-08 16:57:58 -08:00
const char * wild ;
2008-12-12 14:32:48 -08:00
char * base = NULL ;
char * stream = NULL ;
int base_fd = - 1 ;
2008-12-08 16:42:45 -08:00
fsp - > fh - > fd = - 1 ;
errno = EPERM ;
/* 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 ( ! CAN_WRITE ( conn ) ) {
/* It's a read-only share - fail if we wanted to write. */
if ( accmode ! = O_RDONLY ) {
DEBUG ( 3 , ( " Permission denied opening %s \n " , path ) ) ;
return NT_STATUS_ACCESS_DENIED ;
} 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 ;
local_flags & = ~ O_CREAT ;
}
}
/*
* This little piece of insanity is inspired by the
* fact that an NT client can open a file for O_RDONLY ,
* but set the create disposition to FILE_EXISTS_TRUNCATE .
* If the client * can * write to the file , then it expects to
* truncate the file , even though it is opening for readonly .
* Quicken uses this stupid trick in backup file creation . . .
* Thanks * greatly * to " David W. Chapman Jr. " < dwcjr @ inethouston . net >
* for helping track this one down . It didn ' t bite us in 2.0 . x
* as we always opened files read - write in that release . JRA .
*/
if ( ( accmode = = O_RDONLY ) & & ( ( flags & O_TRUNC ) = = O_TRUNC ) ) {
2008-12-08 16:57:58 -08:00
DEBUG ( 10 , ( " onefs_open_file: truncate requested on read-only "
" open for file %s \n " , path ) ) ;
2008-12-08 16:42:45 -08:00
local_flags = ( flags & ~ O_ACCMODE ) | O_RDWR ;
}
2008-12-08 16:57:58 -08:00
# if defined(O_NONBLOCK) && defined(S_ISFIFO)
/*
* We would block on opening a FIFO with no one else on the
* other end . Do what we used to do and add O_NONBLOCK to the
* open flags . JRA .
*/
if ( file_existed & & S_ISFIFO ( psbuf - > st_mode ) ) {
local_flags | = O_NONBLOCK ;
}
# endif
2008-12-08 16:42:45 -08:00
2008-12-08 16:57:58 -08:00
/* Don't create files with Microsoft wildcard characters. */
if ( fsp - > base_fsp ) {
2008-12-08 16:42:45 -08:00
/*
2008-12-08 16:57:58 -08:00
* wildcard characters are allowed in stream names
* only test the basefilename
2008-12-08 16:42:45 -08:00
*/
2008-12-08 16:57:58 -08:00
wild = fsp - > base_fsp - > fsp_name ;
} else {
wild = path ;
}
if ( ( local_flags & O_CREAT ) & & ! file_existed & &
ms_has_wild ( wild ) ) {
2008-12-08 16:42:45 -08:00
/*
2008-12-08 16:57:58 -08:00
* XXX : may need to remvoe this return . . .
*
* We dont think this check needs to exist . All it does is
* block creating files with Microsoft wildcards , which is
* fine if the creation originated from NFS or locally and
* then was copied via Samba .
2008-12-08 16:42:45 -08:00
*/
2008-12-08 16:57:58 -08:00
DEBUG ( 1 , ( " onefs_open_file: creating file with wildcard: %s \n " ,
path ) ) ;
return NT_STATUS_OBJECT_NAME_INVALID ;
}
2008-12-08 16:42:45 -08:00
2008-12-08 16:57:58 -08:00
/* Actually do the open */
2008-12-08 16:42:45 -08:00
2008-12-08 16:57:58 -08:00
# ifdef O_NOFOLLOW
/*
* Never follow symlinks on a POSIX client . The
* client should be doing this .
*/
2008-12-08 16:42:45 -08:00
2008-12-08 16:57:58 -08:00
if ( fsp - > posix_open | | ! lp_symlinks ( SNUM ( conn ) ) ) {
flags | = O_NOFOLLOW ;
}
# endif
2008-12-12 14:32:48 -08:00
/* Stream handling */
if ( is_ntfs_stream_name ( path ) ) {
status = onefs_split_ntfs_stream_name ( talloc_tos ( ) , path ,
& base , & stream ) ;
}
/* It's a stream, so pass in the base_fd */
2009-02-27 16:25:31 -08:00
if ( ( conn - > fs_capabilities & FILE_NAMED_STREAMS ) & & stream ! = NULL ) {
2008-12-12 14:32:48 -08:00
SMB_ASSERT ( fsp - > base_fsp ) ;
2009-01-27 16:13:35 -08:00
/*
* We have never seen an oplock taken on a stream , and our
* current implementation doesn ' t support it . If a request is
* seen , log a loud error message and ignore the requested
* oplock .
*/
if ( ( oplock_request & ~ SAMBA_PRIVATE_OPLOCK_MASK ) ! =
NO_OPLOCK ) {
DEBUG ( 0 , ( " Oplock(%d) being requested on a stream! "
2009-03-25 12:53:06 -07:00
" Ignoring oplock request: base=%s, stream=%s \n " ,
2009-01-27 16:13:35 -08:00
oplock_request & ~ SAMBA_PRIVATE_OPLOCK_MASK ,
base , stream ) ) ;
/* Recover by requesting NO_OPLOCK instead. */
oplock_request & = SAMBA_PRIVATE_OPLOCK_MASK ;
}
2009-03-25 12:53:06 -07:00
DEBUG ( 10 , ( " Opening a stream: base=%s(%d), stream=%s \n " ,
2008-12-12 14:32:48 -08:00
base , fsp - > base_fsp - > fh - > fd , stream ) ) ;
base_fd = fsp - > base_fsp - > fh - > fd ;
}
2008-12-08 16:57:58 -08:00
fsp - > fh - > fd = onefs_sys_create_file ( conn ,
2008-12-12 14:32:48 -08:00
base_fd ,
stream ! = NULL ? stream :
( base ! = NULL ? base : path ) ,
2008-12-08 16:57:58 -08:00
access_mask ,
open_access_mask ,
share_access ,
create_options ,
flags ,
unx_mode ,
oplock_request ,
id ,
sd ,
new_dos_attributes ,
granted_oplock ) ;
if ( fsp - > fh - > fd = = - 1 ) {
if ( errno = = EMFILE ) {
static time_t last_warned = 0L ;
if ( time ( ( time_t * ) NULL ) > last_warned ) {
DEBUG ( 0 , ( " Too many open files, unable "
" to open more! smbd's max "
" open files = %d, also check "
" sysctl kern.maxfiles and "
" sysctl kern.maxfilesperproc \n " ,
lp_max_open_files ( ) ) ) ;
last_warned = time ( ( time_t * ) NULL ) ;
2008-12-08 16:42:45 -08:00
}
2008-12-08 16:57:58 -08:00
}
2008-12-08 16:42:45 -08:00
2008-12-08 16:57:58 -08:00
status = map_nt_error_from_unix ( errno ) ;
DEBUG ( 3 , ( " Error opening file %s (%s) (local_flags=%d) "
2009-01-27 16:13:35 -08:00
" (flags=%d) \n " ,
path , strerror ( errno ) , local_flags , flags ) ) ;
2008-12-08 16:57:58 -08:00
return status ;
}
if ( ( local_flags & O_CREAT ) & & ! file_existed ) {
2008-12-08 16:42:45 -08:00
2008-12-08 16:57:58 -08:00
/* Inherit the ACL if required */
if ( lp_inherit_perms ( SNUM ( conn ) ) ) {
inherit_access_posix_acl ( conn , parent_dir , path ,
unx_mode ) ;
2008-12-08 16:42:45 -08:00
}
2008-12-08 16:57:58 -08:00
/* Change the owner if required. */
if ( lp_inherit_owner ( SNUM ( conn ) ) ) {
change_file_owner_to_parent ( conn , parent_dir ,
fsp ) ;
2008-12-08 16:42:45 -08:00
}
2008-12-08 16:57:58 -08:00
notify_fname ( conn , NOTIFY_ACTION_ADDED ,
FILE_NOTIFY_CHANGE_FILE_NAME , path ) ;
2008-12-08 16:42:45 -08:00
}
if ( ! file_existed ) {
int ret ;
if ( fsp - > fh - > fd = = - 1 ) {
ret = SMB_VFS_STAT ( conn , path , psbuf ) ;
} else {
ret = SMB_VFS_FSTAT ( fsp , psbuf ) ;
/* If we have an fd, this stat should succeed. */
if ( ret = = - 1 ) {
DEBUG ( 0 , ( " Error doing fstat on open file %s "
" (%s) \n " , path , strerror ( errno ) ) ) ;
}
}
/* For a non-io open, this stat failing means file not found. JRA */
if ( ret = = - 1 ) {
status = map_nt_error_from_unix ( errno ) ;
fd_close ( fsp ) ;
return status ;
}
}
/*
* POSIX allows read - only opens of directories . We don ' t
* want to do this ( we use a different code path for this )
* so catch a directory open and return an EISDIR . JRA .
*/
if ( S_ISDIR ( psbuf - > st_mode ) ) {
fd_close ( fsp ) ;
errno = EISDIR ;
return NT_STATUS_FILE_IS_A_DIRECTORY ;
}
fsp - > mode = psbuf - > st_mode ;
fsp - > file_id = vfs_file_id_from_sbuf ( conn , psbuf ) ;
fsp - > vuid = req ? req - > vuid : UID_FIELD_INVALID ;
fsp - > file_pid = req ? req - > smbpid : 0 ;
fsp - > can_lock = True ;
fsp - > can_read = ( access_mask & ( FILE_READ_DATA ) ) ? True : False ;
if ( ! CAN_WRITE ( conn ) ) {
fsp - > can_write = False ;
} else {
fsp - > can_write = ( access_mask & ( FILE_WRITE_DATA | FILE_APPEND_DATA ) ) ?
True : False ;
}
fsp - > print_file = False ;
fsp - > modified = False ;
fsp - > sent_oplock_break = NO_BREAK_SENT ;
fsp - > is_directory = False ;
if ( conn - > aio_write_behind_list & &
is_in_path ( path , conn - > aio_write_behind_list , conn - > case_sensitive ) ) {
fsp - > aio_write_behind = True ;
}
string_set ( & fsp - > fsp_name , path ) ;
fsp - > wcp = NULL ; /* Write cache pointer. */
DEBUG ( 2 , ( " %s opened file %s read=%s write=%s (numopen=%d) \n " ,
conn - > server_info - > unix_name ,
fsp - > fsp_name ,
BOOLSTR ( fsp - > can_read ) , BOOLSTR ( fsp - > can_write ) ,
conn - > num_files_open ) ) ;
errno = 0 ;
return NT_STATUS_OK ;
}
/****************************************************************************
Handle the 1 second delay in returning a SHARING_VIOLATION error .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void defer_open ( struct share_mode_lock * lck ,
struct timeval request_time ,
struct timeval timeout ,
struct smb_request * req ,
struct deferred_open_record * state )
{
int i ;
/* Paranoia check */
for ( i = 0 ; i < lck - > num_share_modes ; i + + ) {
struct share_mode_entry * e = & lck - > share_modes [ i ] ;
if ( ! is_deferred_open_entry ( e ) ) {
continue ;
}
if ( procid_is_me ( & e - > pid ) & & ( e - > op_mid = = req - > mid ) ) {
DEBUG ( 0 , ( " Trying to defer an already deferred "
" request: mid=%d, exiting \n " , req - > mid ) ) ;
exit_server ( " attempt to defer a deferred request " ) ;
}
}
/* End paranoia check */
DEBUG ( 10 , ( " defer_open_sharing_error: time [%u.%06u] adding deferred "
" open entry for mid %u \n " ,
( unsigned int ) request_time . tv_sec ,
( unsigned int ) request_time . tv_usec ,
( unsigned int ) req - > mid ) ) ;
if ( ! push_deferred_smb_message ( req , request_time , timeout ,
( char * ) state , sizeof ( * state ) ) ) {
exit_server ( " push_deferred_smb_message failed " ) ;
}
add_deferred_open ( lck , req - > mid , request_time , state - > id ) ;
}
static void schedule_defer_open ( struct share_mode_lock * lck ,
struct timeval request_time ,
struct smb_request * req )
{
struct deferred_open_record state ;
/* This is a relative time, added to the absolute
request_time value to get the absolute timeout time .
Note that if this is the second or greater time we enter
this codepath for this particular request mid then
request_time is left as the absolute time of the * first *
time this request mid was processed . This is what allows
the request to eventually time out . */
struct timeval timeout ;
/* Normally the smbd we asked should respond within
* OPLOCK_BREAK_TIMEOUT seconds regardless of whether
* the client did , give twice the timeout as a safety
* measure here in case the other smbd is stuck
* somewhere else . */
2009-01-27 16:13:35 -08:00
/*
* On OneFS , the kernel will always send an oplock_revoked message
* before this timeout is hit .
*/
timeout = timeval_set ( OPLOCK_BREAK_TIMEOUT * 10 , 0 ) ;
2008-12-08 16:42:45 -08:00
/* Nothing actually uses state.delayed_for_oplocks
but it ' s handy to differentiate in debug messages
between a 30 second delay due to oplock break , and
a 1 second delay for share mode conflicts . */
state . delayed_for_oplocks = True ;
2009-01-27 16:13:35 -08:00
state . failed = false ;
2008-12-08 16:42:45 -08:00
state . id = lck - > id ;
if ( ! request_timed_out ( request_time , timeout ) ) {
defer_open ( lck , request_time , timeout , req , & state ) ;
}
}
/****************************************************************************
2008-12-08 16:57:58 -08:00
Open a file with a share mode . Passed in an already created files_struct .
2008-12-08 16:42:45 -08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-12-08 16:57:58 -08:00
NTSTATUS onefs_open_file_ntcreate ( connection_struct * conn ,
struct smb_request * req ,
const char * fname ,
uint32 access_mask ,
uint32 share_access ,
uint32 create_disposition ,
uint32 create_options ,
uint32 new_dos_attributes ,
int oplock_request ,
struct security_descriptor * sd ,
files_struct * fsp ,
int * pinfo ,
2009-01-27 16:13:35 -08:00
struct onefs_fsp_data * fsp_data ,
2008-12-08 16:57:58 -08:00
SMB_STRUCT_STAT * psbuf )
2008-12-08 16:42:45 -08:00
{
int flags = 0 ;
int flags2 = 0 ;
bool file_existed = VALID_STAT ( * psbuf ) ;
bool def_acl = False ;
bool posix_open = False ;
bool new_file_created = False ;
2008-12-12 14:32:48 -08:00
bool clear_ads = False ;
2008-12-08 16:42:45 -08:00
struct file_id id ;
mode_t new_unx_mode = ( mode_t ) 0 ;
mode_t unx_mode = ( mode_t ) 0 ;
int info ;
uint32 existing_dos_attributes = 0 ;
struct pending_message_list * pml = NULL ;
struct timeval request_time = timeval_zero ( ) ;
struct share_mode_lock * lck = NULL ;
uint32 open_access_mask = access_mask ;
NTSTATUS status ;
int ret_flock ;
char * parent_dir ;
const char * newname ;
2008-12-08 16:57:58 -08:00
int granted_oplock ;
2009-01-27 16:13:35 -08:00
uint64_t oplock_callback_id = 0 ;
2008-12-08 16:57:58 -08:00
uint32 createfile_attributes = 0 ;
2008-12-08 16:42:45 -08:00
ZERO_STRUCT ( id ) ;
if ( conn - > printer ) {
/*
* Printers are handled completely differently .
* Most of the passed parameters are ignored .
*/
if ( pinfo ) {
* pinfo = FILE_WAS_CREATED ;
}
2008-12-08 16:57:58 -08:00
DEBUG ( 10 , ( " onefs_open_file_ntcreate: printer open fname=%s \n " ,
fname ) ) ;
2008-12-08 16:42:45 -08:00
2008-12-31 21:24:25 -08:00
return print_fsp_open ( req , conn , fname , req - > vuid , fsp , psbuf ) ;
2008-12-08 16:42:45 -08:00
}
2008-12-24 13:51:47 +01:00
if ( ! parent_dirname ( talloc_tos ( ) , fname , & parent_dir , & newname ) ) {
2008-12-08 16:42:45 -08:00
return NT_STATUS_NO_MEMORY ;
}
if ( new_dos_attributes & FILE_FLAG_POSIX_SEMANTICS ) {
posix_open = True ;
unx_mode = ( mode_t ) ( new_dos_attributes & ~ FILE_FLAG_POSIX_SEMANTICS ) ;
new_dos_attributes = 0 ;
} else {
/* We add aARCH to this as this mode is only used if the file is
* created new . */
unx_mode = unix_mode ( conn , new_dos_attributes | aARCH , fname ,
parent_dir ) ;
}
2008-12-08 16:57:58 -08:00
DEBUG ( 10 , ( " onefs_open_file_ntcreate: fname=%s, dos_attrs=0x%x "
" access_mask=0x%x share_access=0x%x "
" create_disposition = 0x%x create_options=0x%x "
" unix mode=0%o oplock_request=0x%x \n " ,
fname , new_dos_attributes , access_mask , share_access ,
create_disposition , create_options , unx_mode ,
oplock_request ) ) ;
2008-12-08 16:42:45 -08:00
2009-01-27 16:13:35 -08:00
/*
* Any non - stat - only open has the potential to contend oplocks , which
* means to avoid blocking in the kernel ( which is unacceptable ) , the
* open must be deferred . In order to defer opens , req must not be
* NULL . The known cases of calling with a NULL req :
*
* 1. Open the base file of a stream : Always done stat - only
*
* 2. Open the stream : Oplocks are disallowed on streams , so an
* oplock will never be contended .
*
* 3. open_file_fchmod ( ) , which is called from 3 places :
* A . try_chown : Posix acls only . Never called on onefs .
* B . set_ea_dos_attributes : Can ' t be called from onefs , because
* SMB_VFS_SETXATTR return ENOSYS .
* C . file_set_dos_mode : This would only happen if the " dos
* filemode " smb.conf parameter is set to yes. We ship with
* it off , but if a customer were to turn it on it would be
* bad .
*/
if ( req = = NULL & & ! is_stat_open ( access_mask ) & & ! is_ntfs_stream_name ( fname ) ) {
smb_panic ( " NULL req on a non-stat-open! " ) ;
}
2008-12-08 16:42:45 -08:00
if ( ( req = = NULL ) & & ( ( oplock_request & INTERNAL_OPEN_ONLY ) = = 0 ) ) {
DEBUG ( 0 , ( " No smb request but not an internal only open! \n " ) ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
/*
* Only non - internal opens can be deferred at all
*/
if ( ( req ! = NULL )
& & ( ( pml = get_open_deferred_message ( req - > mid ) ) ! = NULL ) ) {
struct deferred_open_record * state =
( struct deferred_open_record * ) pml - > private_data . data ;
/* Remember the absolute time of the original
request with this mid . We ' ll use it later to
see if this has timed out . */
request_time = pml - > request_time ;
/* Remove the deferred open entry under lock. */
lck = get_share_mode_lock ( talloc_tos ( ) , state - > id , NULL , NULL ,
NULL ) ;
if ( lck = = NULL ) {
DEBUG ( 0 , ( " could not get share mode lock \n " ) ) ;
} else {
del_deferred_open_entry ( lck , req - > mid ) ;
TALLOC_FREE ( lck ) ;
}
/* Ensure we don't reprocess this message. */
remove_deferred_open_smb_message ( req - > mid ) ;
2008-12-08 16:57:58 -08:00
/*
* When receiving a semlock_async_failure message , the
* deferred open will be marked as " failed " . Returning
* INTERNAL_ERROR .
*/
if ( state - > failed ) {
DEBUG ( 0 , ( " onefs_open_file_ntcreate: "
" semlock_async_failure detected! \n " ) ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
2008-12-08 16:42:45 -08:00
}
status = check_name ( conn , fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( ! posix_open ) {
new_dos_attributes & = SAMBA_ATTRIBUTES_MASK ;
if ( file_existed ) {
existing_dos_attributes = dos_mode ( conn , fname , psbuf ) ;
}
}
2008-12-08 16:57:58 -08:00
/* Setup dos_attributes to be set by ifs_createfile */
if ( lp_store_dos_attributes ( SNUM ( conn ) ) ) {
createfile_attributes = ( new_dos_attributes | aARCH ) &
~ ( FILE_ATTRIBUTE_NONINDEXED | FILE_ATTRIBUTE_COMPRESSED ) ;
}
/* Ignore oplock requests if oplocks are disabled. */
2008-12-08 16:42:45 -08:00
if ( ! lp_oplocks ( SNUM ( conn ) ) | | global_client_failed_oplock_break | |
IS_VETO_OPLOCK_PATH ( conn , fname ) ) {
/* Mask off everything except the private Samba bits. */
oplock_request & = SAMBA_PRIVATE_OPLOCK_MASK ;
}
/* this is for OS/2 long file names - say we don't support them */
if ( ! lp_posix_pathnames ( ) & & strstr ( fname , " .+,;=[]. " ) ) {
/* OS/2 Workplace shell fix may be main code stream in a later
* release . */
2008-12-08 16:57:58 -08:00
DEBUG ( 5 , ( " onefs_open_file_ntcreate: OS/2 long filenames are "
" not supported. \n " ) ) ;
2008-12-08 16:42:45 -08:00
if ( use_nt_status ( ) ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
return NT_STATUS_DOS ( ERRDOS , ERRcannotopen ) ;
}
switch ( create_disposition ) {
/*
* Currently we ' re using FILE_SUPERSEDE as the same as
* FILE_OVERWRITE_IF but they really are
* different . FILE_SUPERSEDE deletes an existing file
* ( requiring delete access ) then recreates it .
*/
case FILE_SUPERSEDE :
2008-12-08 16:57:58 -08:00
/**
* @ todo : Clear all file attributes ?
* http : //www.osronline.com/article.cfm?article=302
* create if not exist , trunc if exist
*
* If file exists replace / overwrite . If file doesn ' t
* exist create .
*/
2008-12-08 16:42:45 -08:00
flags2 | = ( O_CREAT | O_TRUNC ) ;
2008-12-12 14:32:48 -08:00
clear_ads = true ;
2008-12-08 16:42:45 -08:00
break ;
case FILE_OVERWRITE_IF :
/* If file exists replace/overwrite. If file doesn't
* exist create . */
flags2 | = ( O_CREAT | O_TRUNC ) ;
2008-12-12 14:32:48 -08:00
clear_ads = true ;
2008-12-08 16:42:45 -08:00
break ;
case FILE_OPEN :
/* If file exists open. If file doesn't exist error. */
if ( ! file_existed ) {
2008-12-08 16:57:58 -08:00
DEBUG ( 5 , ( " onefs_open_file_ntcreate: FILE_OPEN "
2008-12-08 16:42:45 -08:00
" requested for file %s and file "
" doesn't exist. \n " , fname ) ) ;
errno = ENOENT ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
break ;
case FILE_OVERWRITE :
/* If file exists overwrite. If file doesn't exist
* error . */
if ( ! file_existed ) {
2008-12-08 16:57:58 -08:00
DEBUG ( 5 , ( " onefs_open_file_ntcreate: "
" FILE_OVERWRITE requested for file "
" %s and file doesn't exist. \n " ,
fname ) ) ;
2008-12-08 16:42:45 -08:00
errno = ENOENT ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
flags2 | = O_TRUNC ;
2008-12-12 14:32:48 -08:00
clear_ads = true ;
2008-12-08 16:42:45 -08:00
break ;
case FILE_CREATE :
/* If file exists error. If file doesn't exist
* create . */
if ( file_existed ) {
2008-12-08 16:57:58 -08:00
DEBUG ( 5 , ( " onefs_open_file_ntcreate: "
" FILE_CREATE requested for file %s "
" and file already exists. \n " ,
fname ) ) ;
2008-12-08 16:42:45 -08:00
if ( S_ISDIR ( psbuf - > st_mode ) ) {
errno = EISDIR ;
} else {
errno = EEXIST ;
}
return map_nt_error_from_unix ( errno ) ;
}
flags2 | = ( O_CREAT | O_EXCL ) ;
break ;
case FILE_OPEN_IF :
/* If file exists open. If file doesn't exist
* create . */
flags2 | = O_CREAT ;
break ;
default :
return NT_STATUS_INVALID_PARAMETER ;
}
2008-12-08 16:57:58 -08:00
/* Match attributes on file exists and overwrite. */
if ( ! posix_open & & file_existed & &
( ( create_disposition = = FILE_OVERWRITE ) | |
( create_disposition = = FILE_OVERWRITE_IF ) ) ) {
2008-12-08 16:42:45 -08:00
if ( ! open_match_attributes ( conn , fname ,
existing_dos_attributes ,
new_dos_attributes , psbuf - > st_mode ,
unx_mode , & new_unx_mode ) ) {
2008-12-08 16:57:58 -08:00
DEBUG ( 5 , ( " onefs_open_file_ntcreate: attributes "
" missmatch for file %s (%x %x) (0%o, 0%o) \n " ,
fname , existing_dos_attributes ,
new_dos_attributes ,
( unsigned int ) psbuf - > st_mode ,
( unsigned int ) unx_mode ) ) ;
2008-12-08 16:42:45 -08:00
errno = EACCES ;
return NT_STATUS_ACCESS_DENIED ;
}
}
2008-12-08 16:57:58 -08:00
/*
* OneFS understands MAXIMUM_ALLOWED_ACCESS , so only hack the
* access_mask , but leave the MAA for the actual open in
* open_access_mask .
*/
open_access_mask = access_mask ;
if ( open_access_mask & MAXIMUM_ALLOWED_ACCESS ) {
access_mask | = FILE_GENERIC_ALL ;
2008-12-08 16:42:45 -08:00
}
2008-12-08 16:57:58 -08:00
/* Convert GENERIC bits to specific bits. */
se_map_generic ( & access_mask , & file_generic_mapping ) ;
se_map_generic ( & open_access_mask , & file_generic_mapping ) ;
2008-12-08 16:42:45 -08:00
if ( ( flags2 & O_TRUNC ) | | ( oplock_request & FORCE_OPLOCK_BREAK_TO_NONE ) ) {
2008-12-08 16:57:58 -08:00
/* This will cause oplock breaks. */
open_access_mask | = FILE_WRITE_DATA ;
2008-12-08 16:42:45 -08:00
}
2009-02-11 09:52:02 -08:00
if ( lp_parm_bool ( SNUM ( fsp - > conn ) , PARM_ONEFS_TYPE ,
2009-02-12 14:07:30 -08:00
PARM_IGNORE_SACLS , PARM_IGNORE_SACLS_DEFAULT ) ) {
2009-02-11 09:52:02 -08:00
access_mask & = ~ SYSTEM_SECURITY_ACCESS ;
}
2008-12-08 16:57:58 -08:00
DEBUG ( 10 , ( " onefs_open_file_ntcreate: fname=%s, after mapping "
" open_access_mask=%#x, access_mask=0x%x \n " ,
fname , open_access_mask , access_mask ) ) ;
2008-12-08 16:42:45 -08:00
/*
* Note that we ignore the append flag as append does not
* mean the same thing under DOS and Unix .
*/
if ( ( access_mask & ( FILE_WRITE_DATA | FILE_APPEND_DATA ) ) | |
2008-12-08 16:57:58 -08:00
( oplock_request & FORCE_OPLOCK_BREAK_TO_NONE ) ) {
/*
* DENY_DOS opens are always underlying read - write on the
* file handle , no matter what the requested access mask
* says . Stock samba just sets the flags , but since
* ifs_createfile uses the access_mask , it must be updated as
* well . This allows BASE - DENY * to pass .
*/
if ( create_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS ) {
DEBUG ( 10 , ( " onefs_open_file_ntcreate: deny_dos: "
" Adding O_RDWR to flags "
" (0x%x) and some READ bits to "
" open_access_mask (0x%x) \n " ,
flags , open_access_mask ) ) ;
flags = O_RDWR ;
open_access_mask | = ( FILE_READ_ATTRIBUTES |
FILE_READ_DATA | FILE_READ_EA | FILE_EXECUTE ) ;
} else if ( access_mask & ( FILE_READ_ATTRIBUTES |
FILE_READ_DATA |
FILE_READ_EA |
FILE_EXECUTE ) ) {
2008-12-08 16:42:45 -08:00
flags = O_RDWR ;
} else {
flags = O_WRONLY ;
}
} else {
flags = O_RDONLY ;
}
2008-12-08 16:57:58 -08:00
/* Currently we only look at FILE_WRITE_THROUGH for create options. */
2008-12-08 16:42:45 -08:00
# if defined(O_SYNC)
2008-12-08 16:57:58 -08:00
if ( ( create_options & FILE_WRITE_THROUGH ) & &
lp_strict_sync ( SNUM ( conn ) ) ) {
2008-12-08 16:42:45 -08:00
flags2 | = O_SYNC ;
}
# endif /* O_SYNC */
if ( posix_open & & ( access_mask & FILE_APPEND_DATA ) ) {
flags2 | = O_APPEND ;
}
if ( ! posix_open & & ! CAN_WRITE ( conn ) ) {
/*
* We should really return a permission denied error if either
* O_CREAT or O_TRUNC are set , but for compatibility with
* older versions of Samba we just AND them out .
*/
flags2 & = ~ ( O_CREAT | O_TRUNC ) ;
2008-12-30 17:17:24 -08:00
/* Deny DELETE_ACCESS explicitly if the share is read only. */
if ( access_mask & DELETE_ACCESS ) {
2008-12-08 16:57:58 -08:00
return map_nt_error_from_unix ( EACCES ) ;
}
}
2008-12-08 16:42:45 -08:00
2008-12-08 16:57:58 -08:00
/* Ensure we can't write on a read-only share or file. */
2008-12-08 16:42:45 -08:00
if ( flags ! = O_RDONLY & & file_existed & &
( ! CAN_WRITE ( conn ) | | IS_DOS_READONLY ( existing_dos_attributes ) ) ) {
2008-12-08 16:57:58 -08:00
DEBUG ( 5 , ( " onefs_open_file_ntcreate: write access requested "
" for file %s on read only %s \n " ,
fname , ! CAN_WRITE ( conn ) ? " share " : " file " ) ) ;
2008-12-08 16:42:45 -08:00
errno = EACCES ;
return NT_STATUS_ACCESS_DENIED ;
}
2008-12-08 16:57:58 -08:00
DEBUG ( 10 , ( " fsp = %p \n " , fsp ) ) ;
2008-12-08 16:42:45 -08:00
fsp - > file_id = vfs_file_id_from_sbuf ( conn , psbuf ) ;
fsp - > share_access = share_access ;
fsp - > fh - > private_options = create_options ;
fsp - > access_mask = open_access_mask ; /* We change this to the
* requested access_mask after
* the open is done . */
fsp - > posix_open = posix_open ;
/* Ensure no SAMBA_PRIVATE bits can be set. */
fsp - > oplock_type = ( oplock_request & ~ SAMBA_PRIVATE_OPLOCK_MASK ) ;
if ( timeval_is_zero ( & request_time ) ) {
request_time = fsp - > open_time ;
}
if ( file_existed ) {
struct timespec old_write_time = get_mtimespec ( psbuf ) ;
id = vfs_file_id_from_sbuf ( conn , psbuf ) ;
lck = get_share_mode_lock ( talloc_tos ( ) , id ,
conn - > connectpath ,
fname , & old_write_time ) ;
if ( lck = = NULL ) {
DEBUG ( 0 , ( " Could not get share mode lock \n " ) ) ;
return NT_STATUS_SHARING_VIOLATION ;
}
2008-12-08 16:57:58 -08:00
if ( lck - > delete_on_close ) {
/* DELETE_PENDING is not deferred for a second */
2008-12-08 16:42:45 -08:00
TALLOC_FREE ( lck ) ;
2008-12-08 16:57:58 -08:00
return NT_STATUS_DELETE_PENDING ;
2008-12-08 16:42:45 -08:00
}
2008-12-08 16:57:58 -08:00
}
2008-12-08 16:42:45 -08:00
2008-12-08 16:57:58 -08:00
SMB_ASSERT ( ! file_existed | | ( lck ! = NULL ) ) ;
2008-12-08 16:42:45 -08:00
2008-12-08 16:57:58 -08:00
/*
* Ensure we pay attention to default ACLs on directories . May be
* neccessary depending on ACL policies .
*/
if ( ( flags2 & O_CREAT ) & & lp_inherit_acls ( SNUM ( conn ) ) & &
( def_acl = directory_has_default_acl ( conn , parent_dir ) ) ) {
unx_mode = 0777 ;
}
2008-12-08 16:42:45 -08:00
2008-12-08 16:57:58 -08:00
DEBUG ( 4 , ( " calling onefs_open_file with flags=0x%X flags2=0x%X "
" mode=0%o, access_mask = 0x%x, open_access_mask = 0x%x \n " ,
( unsigned int ) flags , ( unsigned int ) flags2 ,
( unsigned int ) unx_mode , ( unsigned int ) access_mask ,
( unsigned int ) open_access_mask ) ) ;
2009-01-27 16:13:35 -08:00
/*
* Since the open is guaranteed to be stat only if req = = NULL , a
* callback record is only needed if req ! = NULL .
*/
if ( req ) {
SMB_ASSERT ( fsp_data ) ;
oplock_callback_id = onefs_oplock_wait_record ( req - > mid ) ;
if ( oplock_callback_id = = 0 ) {
return NT_STATUS_NO_MEMORY ;
}
} else {
/*
* It is also already asserted it ' s either a stream or a
* stat - only open at this point .
*/
SMB_ASSERT ( fsp - > oplock_type = = NO_OPLOCK ) ;
2008-12-08 16:57:58 -08:00
}
/* Do the open. */
status = onefs_open_file ( fsp ,
conn ,
req ,
parent_dir ,
newname ,
fname ,
psbuf ,
flags | flags2 ,
unx_mode ,
access_mask ,
open_access_mask ,
fsp - > oplock_type ,
2009-01-27 16:13:35 -08:00
oplock_callback_id ,
2008-12-08 16:57:58 -08:00
share_access ,
create_options ,
createfile_attributes ,
sd ,
& granted_oplock ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
/* OneFS Oplock Handling */
if ( errno = = EINPROGRESS ) {
if ( lck = = NULL ) {
struct deferred_open_record state ;
struct timespec old_write_time ;
old_write_time = get_mtimespec ( psbuf ) ;
DEBUG ( 3 , ( " Someone created file %s with an "
" oplock after we looked: Retrying \n " ,
fname ) ) ;
/*
* We hit the race that when we did the stat
* on the file it did not exist , and someone
* has created it in between the stat and the
* open_file ( ) call . Just retry immediately .
*/
id = vfs_file_id_from_sbuf ( conn , psbuf ) ;
if ( ! ( lck = get_share_mode_lock ( talloc_tos ( ) ,
id , conn - > connectpath , fname ,
& old_write_time ) ) ) {
/*
* Emergency exit
*/
DEBUG ( 0 , ( " onefs_open_file_ntcreate: "
" Could not get share mode "
" lock for %s \n " , fname ) ) ;
status = NT_STATUS_SHARING_VIOLATION ;
goto cleanup_destroy ;
}
state . delayed_for_oplocks = False ;
state . id = id ;
if ( req ! = NULL ) {
defer_open ( lck , request_time ,
timeval_zero ( ) , req , & state ) ;
}
goto cleanup_destroy ;
}
/* Waiting for an oplock */
2009-01-27 16:13:35 -08:00
DEBUG ( 5 , ( " Async createfile because a client has an "
" oplock on %s \n " , fname ) ) ;
2008-12-08 16:57:58 -08:00
SMB_ASSERT ( req ) ;
schedule_defer_open ( lck , request_time , req ) ;
goto cleanup ;
2008-12-08 16:42:45 -08:00
}
2008-12-08 16:57:58 -08:00
/* Check for a sharing violation */
if ( ( errno = = EAGAIN ) | | ( errno = = EWOULDBLOCK ) ) {
2008-12-08 16:42:45 -08:00
uint32 can_access_mask ;
bool can_access = True ;
/* Check if this can be done with the deny_dos and fcb
* calls . */
2008-12-08 16:57:58 -08:00
/* Try to find dup fsp if possible. */
2008-12-08 16:42:45 -08:00
if ( create_options &
( NTCREATEX_OPTIONS_PRIVATE_DENY_DOS |
NTCREATEX_OPTIONS_PRIVATE_DENY_FCB ) ) {
2008-12-08 16:57:58 -08:00
2008-12-08 16:42:45 -08:00
if ( req = = NULL ) {
DEBUG ( 0 , ( " DOS open without an SMB "
" request! \n " ) ) ;
2008-12-08 16:57:58 -08:00
status = NT_STATUS_INTERNAL_ERROR ;
goto cleanup_destroy ;
2008-12-08 16:42:45 -08:00
}
/* Use the client requested access mask here,
* not the one we open with . */
status = fcb_or_dos_open ( req ,
conn ,
fsp ,
fname ,
id ,
req - > smbpid ,
req - > vuid ,
access_mask ,
share_access ,
create_options ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( lck ) ;
if ( pinfo ) {
* pinfo = FILE_WAS_OPENED ;
}
2008-12-08 16:57:58 -08:00
status = NT_STATUS_OK ;
goto cleanup ;
2008-12-08 16:42:45 -08:00
}
}
/*
* This next line is a subtlety we need for
* MS - Access . If a file open will fail due to share
* permissions and also for security ( access ) reasons ,
* we need to return the access failed error , not the
* share error . We can ' t open the file due to kernel
* oplock deadlock ( it ' s possible we failed above on
* the open_mode_check ( ) ) so use a userspace check .
*/
if ( flags & O_RDWR ) {
can_access_mask = FILE_READ_DATA | FILE_WRITE_DATA ;
} else if ( flags & O_WRONLY ) {
can_access_mask = FILE_WRITE_DATA ;
} else {
can_access_mask = FILE_READ_DATA ;
}
if ( ( ( can_access_mask & FILE_WRITE_DATA ) & & ! CAN_WRITE ( conn ) ) | |
! can_access_file_data ( conn , fname , psbuf , can_access_mask ) ) {
can_access = False ;
}
/*
* If we ' re returning a share violation , ensure we
* cope with the braindead 1 second delay .
*/
if ( ! ( oplock_request & INTERNAL_OPEN_ONLY ) & &
lp_defer_sharing_violations ( ) ) {
struct timeval timeout ;
struct deferred_open_record state ;
int timeout_usecs ;
/* this is a hack to speed up torture tests
in ' make test ' */
timeout_usecs = lp_parm_int ( SNUM ( conn ) ,
2008-12-08 16:57:58 -08:00
" smbd " , " sharedelay " ,
SHARING_VIOLATION_USEC_WAIT ) ;
/* This is a relative time, added to the
absolute request_time value to get the
absolute timeout time . Note that if this
is the second or greater time we enter this
codepath for this particular request mid
then request_time is left as the absolute
time of the * first * time this request mid
was processed . This is what allows the
request to eventually time out . */
2008-12-08 16:42:45 -08:00
timeout = timeval_set ( 0 , timeout_usecs ) ;
2008-12-08 16:57:58 -08:00
/* Nothing actually uses
state . delayed_for_oplocks but it ' s handy to
differentiate in debug messages between a
30 second delay due to oplock break , and a
1 second delay for share mode conflicts . */
2008-12-08 16:42:45 -08:00
state . delayed_for_oplocks = False ;
state . id = id ;
2008-12-08 16:57:58 -08:00
state . failed = false ;
2008-12-08 16:42:45 -08:00
if ( ( req ! = NULL )
& & ! request_timed_out ( request_time ,
timeout ) ) {
defer_open ( lck , request_time , timeout ,
req , & state ) ;
}
}
if ( can_access ) {
/*
* We have detected a sharing violation here
* so return the correct error code
*/
status = NT_STATUS_SHARING_VIOLATION ;
} else {
status = NT_STATUS_ACCESS_DENIED ;
}
2008-12-08 16:57:58 -08:00
goto cleanup_destroy ;
2008-12-08 16:42:45 -08:00
}
/*
2008-12-08 16:57:58 -08:00
* Normal error , for example EACCES
2008-12-08 16:42:45 -08:00
*/
2008-12-08 16:57:58 -08:00
cleanup_destroy :
2009-01-27 16:13:35 -08:00
if ( oplock_callback_id ! = 0 ) {
destroy_onefs_callback_record ( oplock_callback_id ) ;
}
2008-12-08 16:57:58 -08:00
cleanup :
TALLOC_FREE ( lck ) ;
return status ;
2008-12-08 16:42:45 -08:00
}
2008-12-08 16:57:58 -08:00
fsp - > oplock_type = granted_oplock ;
2008-12-08 16:42:45 -08:00
2009-01-27 16:13:35 -08:00
if ( oplock_callback_id ! = 0 ) {
onefs_set_oplock_callback ( oplock_callback_id , fsp ) ;
fsp_data - > oplock_callback_id = oplock_callback_id ;
} else {
SMB_ASSERT ( fsp - > oplock_type = = NO_OPLOCK ) ;
}
2008-12-08 16:42:45 -08:00
if ( ! file_existed ) {
struct timespec old_write_time = get_mtimespec ( psbuf ) ;
/*
* Deal with the race condition where two smbd ' s detect the
* file doesn ' t exist and do the create at the same time . One
* of them will win and set a share mode , the other ( ie . this
* one ) should check if the requested share mode for this
* create is allowed .
*/
/*
* Now the file exists and fsp is successfully opened ,
* fsp - > dev and fsp - > inode are valid and should replace the
* dev = 0 , inode = 0 from a non existent file . Spotted by
* Nadav Danieli < nadavd @ exanet . com > . JRA .
*/
id = fsp - > file_id ;
lck = get_share_mode_lock ( talloc_tos ( ) , id ,
conn - > connectpath ,
fname , & old_write_time ) ;
if ( lck = = NULL ) {
2008-12-08 16:57:58 -08:00
DEBUG ( 0 , ( " onefs_open_file_ntcreate: Could not get "
" share mode lock for %s \n " , fname ) ) ;
2008-12-08 16:42:45 -08:00
fd_close ( fsp ) ;
return NT_STATUS_SHARING_VIOLATION ;
}
2008-12-08 16:57:58 -08:00
if ( lck - > delete_on_close ) {
status = NT_STATUS_DELETE_PENDING ;
2008-12-08 16:42:45 -08:00
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
struct deferred_open_record state ;
fd_close ( fsp ) ;
state . delayed_for_oplocks = False ;
state . id = id ;
/* Do it all over again immediately. In the second
* round we will find that the file existed and handle
* the DELETE_PENDING and FCB cases correctly . No need
* to duplicate the code here . Essentially this is a
* " goto top of this function " , but don ' t tell
* anybody . . . */
if ( req ! = NULL ) {
defer_open ( lck , request_time , timeval_zero ( ) ,
req , & state ) ;
}
TALLOC_FREE ( lck ) ;
return status ;
}
/*
* We exit this block with the share entry * locked * . . . . .
*/
}
SMB_ASSERT ( lck ! = NULL ) ;
2008-12-12 14:32:48 -08:00
/* Delete streams if create_disposition requires it */
2009-02-18 18:26:39 -08:00
if ( file_existed & & clear_ads & & ! is_ntfs_stream_name ( fname ) ) {
2008-12-12 14:32:48 -08:00
status = delete_all_streams ( conn , fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( lck ) ;
fd_close ( fsp ) ;
return status ;
}
}
2008-12-08 16:42:45 -08:00
/* note that we ignore failure for the following. It is
basically a hack for NFS , and NFS will never set one of
these only read them . Nobody but Samba can ever set a deny
mode and we have already checked our more authoritative
locking database for permission to set this deny mode . If
the kernel refuses the operations then the kernel is wrong .
note that GPFS supports it as well - jmcd */
if ( fsp - > fh - > fd ! = - 1 ) {
ret_flock = SMB_VFS_KERNEL_FLOCK ( fsp , share_access ) ;
if ( ret_flock = = - 1 ) {
TALLOC_FREE ( lck ) ;
fd_close ( fsp ) ;
return NT_STATUS_SHARING_VIOLATION ;
}
}
/*
* At this point onwards , we can guarentee that the share entry
* is locked , whether we created the file or not , and that the
* deny mode is compatible with all current opens .
*/
/* Record the options we were opened with. */
fsp - > share_access = share_access ;
fsp - > fh - > private_options = create_options ;
/*
* According to Samba4 , SEC_FILE_READ_ATTRIBUTE is always granted ,
*/
fsp - > access_mask = access_mask | FILE_READ_ATTRIBUTES ;
if ( file_existed ) {
/* stat opens on existing files don't get oplocks. */
if ( is_stat_open ( open_access_mask ) ) {
fsp - > oplock_type = NO_OPLOCK ;
}
if ( ! ( flags2 & O_TRUNC ) ) {
info = FILE_WAS_OPENED ;
} else {
info = FILE_WAS_OVERWRITTEN ;
}
} else {
info = FILE_WAS_CREATED ;
}
if ( pinfo ) {
* pinfo = info ;
}
/*
* Setup the oplock info in both the shared memory and
* file structs .
*/
if ( ( fsp - > oplock_type ! = NO_OPLOCK ) & &
( fsp - > oplock_type ! = FAKE_LEVEL_II_OPLOCK ) ) {
if ( ! set_file_oplock ( fsp , fsp - > oplock_type ) ) {
/* Could not get the kernel oplock */
fsp - > oplock_type = NO_OPLOCK ;
}
}
2009-01-27 16:13:35 -08:00
if ( fsp - > oplock_type = = LEVEL_II_OPLOCK & &
( ! lp_level2_oplocks ( SNUM ( conn ) ) | |
! ( global_client_caps & CAP_LEVEL_II_OPLOCKS ) ) ) {
DEBUG ( 5 , ( " Downgrading level2 oplock on open "
" because level2 oplocks = off \n " ) ) ;
release_file_oplock ( fsp ) ;
}
2008-12-08 16:57:58 -08:00
if ( info = = FILE_WAS_OVERWRITTEN | | info = = FILE_WAS_CREATED | |
info = = FILE_WAS_SUPERSEDED ) {
2008-12-08 16:42:45 -08:00
new_file_created = True ;
}
set_share_mode ( lck , fsp , conn - > server_info - > utok . uid , 0 ,
2008-12-06 16:08:35 -08:00
fsp - > oplock_type ) ;
2008-12-08 16:42:45 -08:00
/* Handle strange delete on close create semantics. */
if ( create_options & FILE_DELETE_ON_CLOSE ) {
status = can_set_delete_on_close ( fsp , True , new_dos_attributes ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
/* Remember to delete the mode we just added. */
del_share_mode ( lck , fsp ) ;
TALLOC_FREE ( lck ) ;
fd_close ( fsp ) ;
return status ;
}
/* Note that here we set the *inital* delete on close flag,
not the regular one . The magic gets handled in close . */
fsp - > initial_delete_on_close = True ;
}
/*
* Take care of inherited ACLs on created files - if default ACL not
* selected .
2008-12-08 16:57:58 -08:00
* May be necessary depending on acl policies .
2008-12-08 16:42:45 -08:00
*/
2008-12-08 16:57:58 -08:00
if ( ! posix_open & & ! file_existed & & ! def_acl & & ! ( VALID_STAT ( * psbuf )
& & ( psbuf - > st_flags & SF_HASNTFSACL ) ) ) {
2008-12-08 16:42:45 -08:00
int saved_errno = errno ; /* We might get ENOSYS in the next
* call . . */
if ( SMB_VFS_FCHMOD_ACL ( fsp , unx_mode ) = = - 1 & &
errno = = ENOSYS ) {
errno = saved_errno ; /* Ignore ENOSYS */
}
} else if ( new_unx_mode ) {
int ret = - 1 ;
/* Attributes need changing. File already existed. */
{
int saved_errno = errno ; /* We might get ENOSYS in the
* next call . . */
ret = SMB_VFS_FCHMOD_ACL ( fsp , new_unx_mode ) ;
if ( ret = = - 1 & & errno = = ENOSYS ) {
errno = saved_errno ; /* Ignore ENOSYS */
} else {
2008-12-08 16:57:58 -08:00
DEBUG ( 5 , ( " onefs_open_file_ntcreate: reset "
2008-12-08 16:42:45 -08:00
" attributes of file %s to 0%o \n " ,
fname , ( unsigned int ) new_unx_mode ) ) ;
ret = 0 ; /* Don't do the fchmod below. */
}
}
if ( ( ret = = - 1 ) & &
( SMB_VFS_FCHMOD ( fsp , new_unx_mode ) = = - 1 ) )
2008-12-08 16:57:58 -08:00
DEBUG ( 5 , ( " onefs_open_file_ntcreate: failed to reset "
2008-12-08 16:42:45 -08:00
" attributes of file %s to 0%o \n " ,
fname , ( unsigned int ) new_unx_mode ) ) ;
}
/* If this is a successful open, we must remove any deferred open
* records . */
if ( req ! = NULL ) {
del_deferred_open_entry ( lck , req - > mid ) ;
}
TALLOC_FREE ( lck ) ;
return NT_STATUS_OK ;
}
2008-12-08 16:57:58 -08:00
2008-12-08 16:42:45 -08:00
/****************************************************************************
Open a directory from an NT SMB call .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-12-08 16:57:58 -08:00
static NTSTATUS onefs_open_directory ( connection_struct * conn ,
struct smb_request * req ,
const char * fname ,
uint32 access_mask ,
uint32 share_access ,
uint32 create_disposition ,
uint32 create_options ,
uint32 file_attributes ,
struct security_descriptor * sd ,
files_struct * * result ,
int * pinfo ,
SMB_STRUCT_STAT * psbuf )
2008-12-08 16:42:45 -08:00
{
files_struct * fsp = NULL ;
struct share_mode_lock * lck = NULL ;
NTSTATUS status ;
struct timespec mtimespec ;
int info = 0 ;
2008-12-08 16:57:58 -08:00
char * parent_dir ;
const char * dirname ;
bool posix_open = false ;
uint32 create_flags = 0 ;
uint32 mode = lp_dir_mask ( SNUM ( conn ) ) ;
DEBUG ( 5 , ( " onefs_open_directory: opening directory %s, "
" access_mask = 0x%x, "
" share_access = 0x%x create_options = 0x%x, "
" create_disposition = 0x%x, file_attributes = 0x%x \n " ,
fname , ( unsigned int ) access_mask , ( unsigned int ) share_access ,
( unsigned int ) create_options , ( unsigned int ) create_disposition ,
( unsigned int ) file_attributes ) ) ;
2008-12-08 16:42:45 -08:00
if ( ! ( file_attributes & FILE_FLAG_POSIX_SEMANTICS ) & &
2008-12-08 16:57:58 -08:00
( conn - > fs_capabilities & FILE_NAMED_STREAMS ) & &
is_ntfs_stream_name ( fname ) ) {
DEBUG ( 2 , ( " onefs_open_directory: %s is a stream name! \n " , fname ) ) ;
2008-12-08 16:42:45 -08:00
return NT_STATUS_NOT_A_DIRECTORY ;
}
2008-12-08 16:57:58 -08:00
switch ( create_disposition ) {
2008-12-08 16:42:45 -08:00
case FILE_OPEN :
2008-12-08 16:57:58 -08:00
/* If directory exists open. If directory doesn't
* exist error . */
create_flags = 0 ;
2008-12-08 16:42:45 -08:00
info = FILE_WAS_OPENED ;
break ;
case FILE_CREATE :
/* If directory exists error. If directory doesn't
* exist create . */
2008-12-08 16:57:58 -08:00
create_flags = O_CREAT | O_EXCL ;
2008-12-08 16:42:45 -08:00
info = FILE_WAS_CREATED ;
break ;
case FILE_OPEN_IF :
2008-12-08 16:57:58 -08:00
/* If directory exists open. If directory doesn't
* exist create . */
2008-12-08 16:42:45 -08:00
2008-12-08 16:57:58 -08:00
/* Note: in order to return whether the directory was
* opened or created , we first try to open and then try
* to create . */
create_flags = 0 ;
info = FILE_WAS_OPENED ;
2008-12-08 16:42:45 -08:00
break ;
case FILE_SUPERSEDE :
case FILE_OVERWRITE :
case FILE_OVERWRITE_IF :
default :
2008-12-08 16:57:58 -08:00
DEBUG ( 5 , ( " onefs_open_directory: invalid "
" create_disposition 0x%x for directory %s \n " ,
( unsigned int ) create_disposition , fname ) ) ;
2008-12-08 16:42:45 -08:00
return NT_STATUS_INVALID_PARAMETER ;
}
2008-12-08 16:57:58 -08:00
/*
* Check for write access to the share . Done in mkdir_internal ( ) in
* mainline samba .
*/
if ( ! CAN_WRITE ( conn ) & & ( create_flags & O_CREAT ) ) {
return NT_STATUS_ACCESS_DENIED ;
2008-12-08 16:42:45 -08:00
}
2008-12-08 16:57:58 -08:00
/* Get parent dirname */
2008-12-24 13:51:47 +01:00
if ( ! parent_dirname ( talloc_tos ( ) , fname , & parent_dir , & dirname ) ) {
2008-12-08 16:57:58 -08:00
return NT_STATUS_NO_MEMORY ;
2008-12-08 16:42:45 -08:00
}
2008-12-08 16:57:58 -08:00
if ( file_attributes & FILE_FLAG_POSIX_SEMANTICS ) {
posix_open = true ;
mode = ( mode_t ) ( file_attributes & ~ FILE_FLAG_POSIX_SEMANTICS ) ;
file_attributes = 0 ;
} else {
mode = unix_mode ( conn , aDIR , fname , parent_dir ) ;
}
/*
* The NONINDEXED and COMPRESSED bits seem to always be cleared on
* directories , no matter if you specify that they should be set .
*/
file_attributes & =
~ ( FILE_ATTRIBUTE_NONINDEXED | FILE_ATTRIBUTE_COMPRESSED ) ;
2008-12-08 16:42:45 -08:00
status = file_new ( req , conn , & fsp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/*
2008-12-08 16:57:58 -08:00
* Actual open with retry magic to handle FILE_OPEN_IF which is
* unique because the kernel won ' t tell us if the file was opened or
* created .
2008-12-08 16:42:45 -08:00
*/
2008-12-08 16:57:58 -08:00
retry_open :
fsp - > fh - > fd = onefs_sys_create_file ( conn ,
- 1 ,
fname ,
access_mask ,
access_mask ,
share_access ,
create_options ,
create_flags | O_DIRECTORY ,
mode ,
0 ,
0 ,
sd ,
file_attributes ,
NULL ) ;
if ( fsp - > fh - > fd = = - 1 ) {
DEBUG ( 3 , ( " Error opening %s. Errno=%d (%s). \n " , fname , errno ,
strerror ( errno ) ) ) ;
SMB_ASSERT ( errno ! = EINPROGRESS ) ;
if ( create_disposition = = FILE_OPEN_IF ) {
if ( errno = = ENOENT ) {
/* Try again, creating it this time. */
create_flags = O_CREAT | O_EXCL ;
info = FILE_WAS_CREATED ;
goto retry_open ;
} else if ( errno = = EEXIST ) {
/* Uggh. Try again again. */
create_flags = 0 ;
info = FILE_WAS_OPENED ;
goto retry_open ;
}
}
/* Error cases below: */
file_free ( req , fsp ) ;
if ( ( errno = = ENOENT ) & & ( create_disposition = = FILE_OPEN ) ) {
DEBUG ( 5 , ( " onefs_open_directory: FILE_OPEN requested "
" for directory %s and it doesn't "
" exist. \n " , fname ) ) ;
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
} else if ( ( errno = = EEXIST ) & &
( create_disposition = = FILE_CREATE ) ) {
DEBUG ( 5 , ( " onefs_open_directory: FILE_CREATE "
" requested for directory %s and it "
" already exists. \n " , fname ) ) ;
return NT_STATUS_OBJECT_NAME_COLLISION ;
} else if ( ( errno = = EAGAIN ) | | ( errno = = EWOULDBLOCK ) ) {
/* Catch sharing violations. */
return NT_STATUS_SHARING_VIOLATION ;
}
return map_nt_error_from_unix ( errno ) ;
}
if ( info = = FILE_WAS_CREATED ) {
/* Pulled from mkdir_internal() */
if ( SMB_VFS_LSTAT ( conn , fname , psbuf ) = = - 1 ) {
DEBUG ( 2 , ( " Could not stat directory '%s' just "
" created: %s \n " , fname , strerror ( errno ) ) ) ;
return map_nt_error_from_unix ( errno ) ;
}
if ( ! S_ISDIR ( psbuf - > st_mode ) ) {
DEBUG ( 0 , ( " Directory just '%s' created is not a "
" directory \n " , fname ) ) ;
return NT_STATUS_ACCESS_DENIED ;
}
if ( ! posix_open ) {
/*
* Check if high bits should have been set , then ( if
* bits are missing ) : add them . Consider bits
* automagically set by UNIX , i . e . SGID bit from
* parent dir .
*/
if ( mode & ~ ( S_IRWXU | S_IRWXG | S_IRWXO ) & &
( mode & ~ psbuf - > st_mode ) ) {
SMB_VFS_CHMOD ( conn , fname , ( psbuf - > st_mode |
( mode & ~ psbuf - > st_mode ) ) ) ;
}
}
/* Change the owner if required. */
if ( lp_inherit_owner ( SNUM ( conn ) ) ) {
change_dir_owner_to_parent ( conn , parent_dir , fname ,
psbuf ) ;
}
notify_fname ( conn , NOTIFY_ACTION_ADDED ,
FILE_NOTIFY_CHANGE_DIR_NAME , fname ) ;
}
/* Stat the fd for Samba bookkeeping. */
if ( SMB_VFS_FSTAT ( fsp , psbuf ) ! = 0 ) {
fd_close ( fsp ) ;
file_free ( req , fsp ) ;
return map_nt_error_from_unix ( errno ) ;
}
2008-12-08 16:42:45 -08:00
2008-12-08 16:57:58 -08:00
/* Setup the files_struct for it. */
2008-12-08 16:42:45 -08:00
fsp - > mode = psbuf - > st_mode ;
fsp - > file_id = vfs_file_id_from_sbuf ( conn , psbuf ) ;
fsp - > vuid = req ? req - > vuid : UID_FIELD_INVALID ;
fsp - > file_pid = req ? req - > smbpid : 0 ;
fsp - > can_lock = False ;
fsp - > can_read = False ;
fsp - > can_write = False ;
fsp - > share_access = share_access ;
fsp - > fh - > private_options = create_options ;
/*
* According to Samba4 , SEC_FILE_READ_ATTRIBUTE is always granted ,
*/
fsp - > access_mask = access_mask | FILE_READ_ATTRIBUTES ;
fsp - > print_file = False ;
fsp - > modified = False ;
fsp - > oplock_type = NO_OPLOCK ;
fsp - > sent_oplock_break = NO_BREAK_SENT ;
fsp - > is_directory = True ;
2008-12-08 16:57:58 -08:00
fsp - > posix_open = posix_open ;
2008-12-08 16:42:45 -08:00
string_set ( & fsp - > fsp_name , fname ) ;
mtimespec = get_mtimespec ( psbuf ) ;
2008-12-08 16:57:58 -08:00
/*
* Still set the samba share mode lock for correct delete - on - close
* semantics and to make smbstatus more useful .
*/
2008-12-08 16:42:45 -08:00
lck = get_share_mode_lock ( talloc_tos ( ) , fsp - > file_id ,
conn - > connectpath ,
fname , & mtimespec ) ;
if ( lck = = NULL ) {
2008-12-08 16:57:58 -08:00
DEBUG ( 0 , ( " onefs_open_directory: Could not get share mode "
" lock for %s \n " , fname ) ) ;
fd_close ( fsp ) ;
2008-12-08 16:42:45 -08:00
file_free ( req , fsp ) ;
return NT_STATUS_SHARING_VIOLATION ;
}
2008-12-08 16:57:58 -08:00
if ( lck - > delete_on_close ) {
2008-12-08 16:42:45 -08:00
TALLOC_FREE ( lck ) ;
2008-12-08 16:57:58 -08:00
fd_close ( fsp ) ;
2008-12-08 16:42:45 -08:00
file_free ( req , fsp ) ;
2008-12-08 16:57:58 -08:00
return NT_STATUS_DELETE_PENDING ;
2008-12-08 16:42:45 -08:00
}
2008-12-06 16:08:35 -08:00
set_share_mode ( lck , fsp , conn - > server_info - > utok . uid , 0 , NO_OPLOCK ) ;
2008-12-08 16:42:45 -08:00
2008-12-08 16:57:58 -08:00
/*
* For directories the delete on close bit at open time seems
* always to be honored on close . . . See test 19 in Samba4 BASE - DELETE .
*/
2008-12-08 16:42:45 -08:00
if ( create_options & FILE_DELETE_ON_CLOSE ) {
status = can_set_delete_on_close ( fsp , True , 0 ) ;
2008-12-08 16:57:58 -08:00
if ( ! NT_STATUS_IS_OK ( status ) & &
! NT_STATUS_EQUAL ( status , NT_STATUS_DIRECTORY_NOT_EMPTY ) ) {
2008-12-08 16:42:45 -08:00
TALLOC_FREE ( lck ) ;
2008-12-08 16:57:58 -08:00
fd_close ( fsp ) ;
2008-12-08 16:42:45 -08:00
file_free ( req , fsp ) ;
return status ;
}
if ( NT_STATUS_IS_OK ( status ) ) {
/* Note that here we set the *inital* delete on close flag,
not the regular one . The magic gets handled in close . */
fsp - > initial_delete_on_close = True ;
}
}
TALLOC_FREE ( lck ) ;
if ( pinfo ) {
* pinfo = info ;
}
* result = fsp ;
return NT_STATUS_OK ;
}
/*
2008-12-08 16:57:58 -08:00
* Wrapper around onefs_open_file_ntcreate and onefs_open_directory .
2008-12-08 16:42:45 -08:00
*/
2008-12-08 16:57:58 -08:00
static NTSTATUS onefs_create_file_unixpath ( connection_struct * conn ,
struct smb_request * req ,
const char * fname ,
uint32_t access_mask ,
uint32_t share_access ,
uint32_t create_disposition ,
uint32_t create_options ,
uint32_t file_attributes ,
uint32_t oplock_request ,
uint64_t allocation_size ,
struct security_descriptor * sd ,
struct ea_list * ea_list ,
files_struct * * result ,
int * pinfo ,
2009-01-27 16:13:35 -08:00
struct onefs_fsp_data * fsp_data ,
2008-12-08 16:57:58 -08:00
SMB_STRUCT_STAT * psbuf )
2008-12-08 16:42:45 -08:00
{
SMB_STRUCT_STAT sbuf ;
int info = FILE_WAS_OPENED ;
files_struct * base_fsp = NULL ;
files_struct * fsp = NULL ;
NTSTATUS status ;
2008-12-08 16:57:58 -08:00
DEBUG ( 10 , ( " onefs_create_file_unixpath: access_mask = 0x%x "
2008-12-08 16:42:45 -08:00
" file_attributes = 0x%x, share_access = 0x%x, "
" create_disposition = 0x%x create_options = 0x%x "
" oplock_request = 0x%x ea_list = 0x%p, sd = 0x%p, "
" fname = %s \n " ,
( unsigned int ) access_mask ,
( unsigned int ) file_attributes ,
( unsigned int ) share_access ,
( unsigned int ) create_disposition ,
( unsigned int ) create_options ,
( unsigned int ) oplock_request ,
ea_list , sd , fname ) ) ;
if ( create_options & FILE_OPEN_BY_FILE_ID ) {
status = NT_STATUS_NOT_SUPPORTED ;
goto fail ;
}
if ( create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
if ( req = = NULL ) {
2009-01-27 16:13:35 -08:00
SMB_ASSERT ( ( oplock_request & ~ SAMBA_PRIVATE_OPLOCK_MASK ) = =
NO_OPLOCK ) ;
2008-12-08 16:42:45 -08:00
oplock_request | = INTERNAL_OPEN_ONLY ;
}
if ( psbuf ! = NULL ) {
sbuf = * psbuf ;
}
else {
if ( SMB_VFS_STAT ( conn , fname , & sbuf ) = = - 1 ) {
SET_STAT_INVALID ( sbuf ) ;
}
}
if ( ( conn - > fs_capabilities & FILE_NAMED_STREAMS )
& & ( access_mask & DELETE_ACCESS )
& & ! is_ntfs_stream_name ( fname ) ) {
/*
* We can ' t open a file with DELETE access if any of the
* streams is open without FILE_SHARE_DELETE
*/
status = open_streams_for_delete ( conn , fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
}
if ( ( conn - > fs_capabilities & FILE_NAMED_STREAMS )
2008-12-12 14:32:48 -08:00
& & is_ntfs_stream_name ( fname ) ) {
2008-12-08 16:42:45 -08:00
char * base ;
uint32 base_create_disposition ;
if ( create_options & FILE_DIRECTORY_FILE ) {
status = NT_STATUS_NOT_A_DIRECTORY ;
goto fail ;
}
2008-12-12 14:32:48 -08:00
status = onefs_split_ntfs_stream_name ( talloc_tos ( ) , fname ,
& base , NULL ) ;
2008-12-08 16:42:45 -08:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-12-08 16:57:58 -08:00
DEBUG ( 10 , ( " onefs_create_file_unixpath: "
" split_ntfs_stream_name failed: %s \n " ,
nt_errstr ( status ) ) ) ;
2008-12-08 16:42:45 -08:00
goto fail ;
}
SMB_ASSERT ( ! is_ntfs_stream_name ( base ) ) ; /* paranoia.. */
switch ( create_disposition ) {
case FILE_OPEN :
base_create_disposition = FILE_OPEN ;
break ;
default :
base_create_disposition = FILE_OPEN_IF ;
break ;
}
2008-12-08 16:57:58 -08:00
status = onefs_create_file_unixpath (
conn , /* conn */
NULL , /* req */
base , /* fname */
2009-01-27 16:13:35 -08:00
SYNCHRONIZE_ACCESS , /* access_mask */
2008-12-08 16:57:58 -08:00
( FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE ) , /* share_access */
base_create_disposition , /* create_disposition*/
0 , /* create_options */
2008-12-12 14:32:48 -08:00
file_attributes , /* file_attributes */
2008-12-08 16:57:58 -08:00
NO_OPLOCK , /* oplock_request */
0 , /* allocation_size */
NULL , /* sd */
NULL , /* ea_list */
& base_fsp , /* result */
NULL , /* pinfo */
2009-01-27 16:13:35 -08:00
NULL , /* fsp_data */
2008-12-08 16:57:58 -08:00
NULL ) ; /* psbuf */
2008-12-08 16:42:45 -08:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-12-08 16:57:58 -08:00
DEBUG ( 10 , ( " onefs_create_file_unixpath for base %s "
" failed: %s \n " , base , nt_errstr ( status ) ) ) ;
2008-12-08 16:42:45 -08:00
goto fail ;
}
}
2008-12-08 16:57:58 -08:00
/* Covert generic bits in the security descriptor. */
if ( sd ! = NULL ) {
security_acl_map_generic ( sd - > dacl , & file_generic_mapping ) ;
security_acl_map_generic ( sd - > sacl , & file_generic_mapping ) ;
}
2008-12-08 16:42:45 -08:00
/*
* If it ' s a request for a directory open , deal with it separately .
*/
if ( create_options & FILE_DIRECTORY_FILE ) {
if ( create_options & FILE_NON_DIRECTORY_FILE ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
/* Can't open a temp directory. IFS kit test. */
if ( ! ( file_attributes & FILE_FLAG_POSIX_SEMANTICS ) & &
( file_attributes & FILE_ATTRIBUTE_TEMPORARY ) ) {
status = NT_STATUS_INVALID_PARAMETER ;
goto fail ;
}
/*
* We will get a create directory here if the Win32
* app specified a security descriptor in the
* CreateDirectory ( ) call .
*/
2008-12-08 16:57:58 -08:00
status = onefs_open_directory (
conn , /* conn */
req , /* req */
fname , /* fname */
access_mask , /* access_mask */
share_access , /* share_access */
create_disposition , /* create_disposition*/
create_options , /* create_options */
file_attributes , /* file_attributes */
sd , /* sd */
& fsp , /* result */
& info , /* pinfo */
& sbuf ) ; /* psbuf */
2008-12-08 16:42:45 -08:00
} else {
/*
* Ordinary file case .
*/
status = file_new ( req , conn , & fsp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
/*
* We ' re opening the stream element of a base_fsp
* we already opened . Set up the base_fsp pointer .
*/
if ( base_fsp ) {
fsp - > base_fsp = base_fsp ;
}
2008-12-08 16:57:58 -08:00
status = onefs_open_file_ntcreate (
conn , /* conn */
req , /* req */
fname , /* fname */
access_mask , /* access_mask */
share_access , /* share_access */
create_disposition , /* create_disposition*/
create_options , /* create_options */
file_attributes , /* file_attributes */
oplock_request , /* oplock_request */
sd , /* sd */
fsp , /* result */
& info , /* pinfo */
2009-01-27 16:13:35 -08:00
fsp_data , /* fsp_data */
2008-12-08 16:57:58 -08:00
& sbuf ) ; /* psbuf */
2008-12-08 16:42:45 -08:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
file_free ( req , fsp ) ;
fsp = NULL ;
}
if ( NT_STATUS_EQUAL ( status , NT_STATUS_FILE_IS_A_DIRECTORY ) ) {
/* A stream open never opens a directory */
if ( base_fsp ) {
status = NT_STATUS_FILE_IS_A_DIRECTORY ;
goto fail ;
}
/*
* Fail the open if it was explicitly a non - directory
* file .
*/
if ( create_options & FILE_NON_DIRECTORY_FILE ) {
status = NT_STATUS_FILE_IS_A_DIRECTORY ;
goto fail ;
}
2008-12-08 16:57:58 -08:00
create_options | = FILE_DIRECTORY_FILE ;
status = onefs_open_directory (
conn , /* conn */
req , /* req */
fname , /* fname */
access_mask , /* access_mask */
share_access , /* share_access */
create_disposition , /* create_disposition*/
create_options , /* create_options */
file_attributes , /* file_attributes */
sd , /* sd */
& fsp , /* result */
& info , /* pinfo */
& sbuf ) ; /* psbuf */
2008-12-08 16:42:45 -08:00
}
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
fsp - > base_fsp = base_fsp ;
2008-12-08 16:57:58 -08:00
SMB_ASSERT ( fsp ) ;
2008-12-08 16:42:45 -08:00
if ( ( ea_list ! = NULL ) & & ( info = = FILE_WAS_CREATED ) ) {
status = set_ea ( conn , fsp , fname , ea_list ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
}
if ( ! fsp - > is_directory & & S_ISDIR ( sbuf . st_mode ) ) {
status = NT_STATUS_ACCESS_DENIED ;
goto fail ;
}
/* Save the requested allocation size. */
if ( ( info = = FILE_WAS_CREATED ) | | ( info = = FILE_WAS_OVERWRITTEN ) ) {
if ( allocation_size
& & ( allocation_size > sbuf . st_size ) ) {
fsp - > initial_allocation_size = smb_roundup (
fsp - > conn , allocation_size ) ;
if ( fsp - > is_directory ) {
/* Can't set allocation size on a directory. */
status = NT_STATUS_ACCESS_DENIED ;
goto fail ;
}
if ( vfs_allocate_file_space (
fsp , fsp - > initial_allocation_size ) = = - 1 ) {
status = NT_STATUS_DISK_FULL ;
goto fail ;
}
} else {
fsp - > initial_allocation_size = smb_roundup (
fsp - > conn , ( uint64_t ) sbuf . st_size ) ;
}
}
2008-12-08 16:57:58 -08:00
DEBUG ( 10 , ( " onefs_create_file_unixpath: info=%d \n " , info ) ) ;
2008-12-08 16:42:45 -08:00
* result = fsp ;
if ( pinfo ! = NULL ) {
* pinfo = info ;
}
if ( psbuf ! = NULL ) {
if ( ( fsp - > fh = = NULL ) | | ( fsp - > fh - > fd = = - 1 ) ) {
* psbuf = sbuf ;
}
else {
SMB_VFS_FSTAT ( fsp , psbuf ) ;
}
}
return NT_STATUS_OK ;
fail :
2008-12-08 16:57:58 -08:00
DEBUG ( 10 , ( " onefs_create_file_unixpath: %s \n " , nt_errstr ( status ) ) ) ;
2008-12-08 16:42:45 -08:00
if ( fsp ! = NULL ) {
if ( base_fsp & & fsp - > base_fsp = = base_fsp ) {
/*
* The close_file below will close
* fsp - > base_fsp .
*/
base_fsp = NULL ;
}
close_file ( req , fsp , ERROR_CLOSE ) ;
fsp = NULL ;
}
if ( base_fsp ! = NULL ) {
close_file ( req , base_fsp , ERROR_CLOSE ) ;
base_fsp = NULL ;
}
return status ;
}
2008-12-08 16:57:58 -08:00
2009-01-27 16:13:35 -08:00
static void destroy_onefs_fsp_data ( void * p_data )
{
struct onefs_fsp_data * fsp_data = ( struct onefs_fsp_data * ) p_data ;
destroy_onefs_callback_record ( fsp_data - > oplock_callback_id ) ;
}
2008-12-08 16:57:58 -08:00
/**
* SMB_VFS_CREATE_FILE interface to onefs .
*/
NTSTATUS onefs_create_file ( vfs_handle_struct * handle ,
struct smb_request * req ,
uint16_t root_dir_fid ,
const char * fname ,
uint32_t create_file_flags ,
uint32_t access_mask ,
uint32_t share_access ,
uint32_t create_disposition ,
uint32_t create_options ,
uint32_t file_attributes ,
uint32_t oplock_request ,
uint64_t allocation_size ,
struct security_descriptor * sd ,
struct ea_list * ea_list ,
files_struct * * result ,
int * pinfo ,
SMB_STRUCT_STAT * psbuf )
2008-12-08 16:42:45 -08:00
{
2008-12-08 16:57:58 -08:00
connection_struct * conn = handle - > conn ;
2008-12-08 16:42:45 -08:00
struct case_semantics_state * case_state = NULL ;
2009-01-27 16:13:35 -08:00
struct onefs_fsp_data fsp_data = { } ;
2008-12-08 16:42:45 -08:00
SMB_STRUCT_STAT sbuf ;
int info = FILE_WAS_OPENED ;
files_struct * fsp = NULL ;
NTSTATUS status ;
2008-12-08 16:57:58 -08:00
DEBUG ( 10 , ( " onefs_create_file: access_mask = 0x%x "
2008-12-08 16:42:45 -08:00
" file_attributes = 0x%x, share_access = 0x%x, "
" create_disposition = 0x%x create_options = 0x%x "
" oplock_request = 0x%x "
" root_dir_fid = 0x%x, ea_list = 0x%p, sd = 0x%p, "
" create_file_flags = 0x%x, fname = %s \n " ,
( unsigned int ) access_mask ,
( unsigned int ) file_attributes ,
( unsigned int ) share_access ,
( unsigned int ) create_disposition ,
( unsigned int ) create_options ,
( unsigned int ) oplock_request ,
( unsigned int ) root_dir_fid ,
ea_list , sd , create_file_flags , fname ) ) ;
2008-12-08 16:57:58 -08:00
/* Get the file name if root_dir_fid was specified. */
2008-12-08 16:42:45 -08:00
if ( root_dir_fid ! = 0 ) {
char * new_fname ;
status = get_relative_fid_filename ( conn , req , root_dir_fid ,
fname , & new_fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
fname = new_fname ;
}
2008-12-08 16:57:58 -08:00
/* Resolve the file name if this was a DFS pathname. */
2008-12-08 16:42:45 -08:00
if ( ( req ! = NULL ) & & ( req - > flags2 & FLAGS2_DFS_PATHNAMES ) ) {
char * resolved_fname ;
status = resolve_dfspath ( talloc_tos ( ) , conn , true , fname ,
& resolved_fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
/*
* For PATH_NOT_COVERED we had
* reply_botherror ( req , NT_STATUS_PATH_NOT_COVERED ,
* ERRSRV , ERRbadpath ) ;
* Need to fix in callers
*/
goto fail ;
}
fname = resolved_fname ;
}
2008-12-08 16:57:58 -08:00
/* Check if POSIX semantics are wanted. */
2008-12-08 16:42:45 -08:00
if ( file_attributes & FILE_FLAG_POSIX_SEMANTICS ) {
case_state = set_posix_case_semantics ( talloc_tos ( ) , conn ) ;
}
2008-12-08 16:57:58 -08:00
/* Convert dos path to unix path if it hasn't already been done. */
2008-12-08 16:42:45 -08:00
if ( create_file_flags & CFF_DOS_PATH ) {
char * converted_fname ;
SET_STAT_INVALID ( sbuf ) ;
status = unix_convert ( talloc_tos ( ) , conn , fname , False ,
& converted_fname , NULL , & sbuf ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
fname = converted_fname ;
} else {
if ( psbuf ! = NULL ) {
sbuf = * psbuf ;
} else {
if ( SMB_VFS_STAT ( conn , fname , & sbuf ) = = - 1 ) {
SET_STAT_INVALID ( sbuf ) ;
}
}
}
TALLOC_FREE ( case_state ) ;
/* All file access must go through check_name() */
status = check_name ( conn , fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2008-12-08 16:57:58 -08:00
status = onefs_create_file_unixpath (
conn , /* conn */
req , /* req */
fname , /* fname */
access_mask , /* access_mask */
share_access , /* share_access */
create_disposition , /* create_disposition*/
create_options , /* create_options */
file_attributes , /* file_attributes */
oplock_request , /* oplock_request */
allocation_size , /* allocation_size */
sd , /* sd */
ea_list , /* ea_list */
& fsp , /* result */
& info , /* pinfo */
2009-01-27 16:13:35 -08:00
& fsp_data , /* fsp_data */
2008-12-08 16:57:58 -08:00
& sbuf ) ; /* psbuf */
2008-12-08 16:42:45 -08:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto fail ;
}
2008-12-08 16:57:58 -08:00
DEBUG ( 10 , ( " onefs_create_file: info=%d \n " , info ) ) ;
2008-12-08 16:42:45 -08:00
2009-01-27 16:13:35 -08:00
/*
* Setup private onefs_fsp_data . Currently the private data struct is
* only used to store the oplock_callback_id so that when the file is
* closed , the onefs_callback_record can be properly cleaned up in the
* oplock_onefs sub - system .
*/
if ( fsp ) {
struct onefs_fsp_data * fsp_data_tmp = NULL ;
fsp_data_tmp = ( struct onefs_fsp_data * )
VFS_ADD_FSP_EXTENSION ( handle , fsp , struct onefs_fsp_data ,
& destroy_onefs_fsp_data ) ;
if ( fsp_data_tmp = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
goto fail ;
}
* fsp_data_tmp = fsp_data ;
}
2008-12-08 16:42:45 -08:00
* result = fsp ;
if ( pinfo ! = NULL ) {
* pinfo = info ;
}
if ( psbuf ! = NULL ) {
* psbuf = sbuf ;
}
return NT_STATUS_OK ;
fail :
2008-12-08 16:57:58 -08:00
DEBUG ( 10 , ( " onefs_create_file: %s \n " , nt_errstr ( status ) ) ) ;
2008-12-08 16:42:45 -08:00
if ( fsp ! = NULL ) {
close_file ( req , fsp , ERROR_CLOSE ) ;
fsp = NULL ;
}
return status ;
}