2000-11-15 00:56:32 +03:00
/*
2002-03-19 05:32:39 +03:00
Unix SMB / Netbios implementation .
Version 1.9 .
2000-02-03 08:10:09 +03:00
VFS initialisation and support functions
Copyright ( C ) Tim Potter 1999
2002-08-17 19:27:10 +04:00
Copyright ( C ) Alexander Bokovoy 2002
2006-07-11 22:01:26 +04:00
Copyright ( C ) James Peach 2006
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2000-02-03 08:10:09 +03:00
( at your option ) any later version .
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
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 .
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2002-08-17 19:27:10 +04:00
This work was sponsored by Optifacio Software Services , Inc .
2000-02-03 08:10:09 +03:00
*/
# include "includes.h"
2002-09-25 19:19:00 +04:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_VFS
2006-04-26 19:41:25 +04:00
static_decl_vfs ;
2003-04-16 18:45:11 +04:00
struct vfs_init_function_entry {
2003-05-12 03:34:18 +04:00
char * name ;
2007-12-27 22:00:13 +03:00
const vfs_op_tuple * vfs_op_tuples ;
2003-05-12 03:34:18 +04:00
struct vfs_init_function_entry * prev , * next ;
2003-04-16 18:45:11 +04:00
} ;
static struct vfs_init_function_entry * backends = NULL ;
2002-09-25 19:19:00 +04:00
2003-04-16 18:45:11 +04:00
/****************************************************************************
maintain the list of available backends
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct vfs_init_function_entry * vfs_find_backend_entry ( const char * name )
{
2003-05-12 03:34:18 +04:00
struct vfs_init_function_entry * entry = backends ;
2007-10-28 13:58:26 +03:00
DEBUG ( 10 , ( " vfs_find_backend_entry called for %s \n " , name ) ) ;
2003-05-12 03:34:18 +04:00
while ( entry ) {
2003-05-16 10:20:57 +04:00
if ( strcmp ( entry - > name , name ) = = 0 ) return entry ;
2003-05-12 03:34:18 +04:00
entry = entry - > next ;
}
2003-04-16 18:45:11 +04:00
2003-05-12 03:34:18 +04:00
return NULL ;
2003-04-16 18:45:11 +04:00
}
2007-12-27 22:00:13 +03:00
NTSTATUS smb_register_vfs ( int version , const char * name , const vfs_op_tuple * vfs_op_tuples )
2003-04-16 18:45:11 +04:00
{
2003-05-12 03:34:18 +04:00
struct vfs_init_function_entry * entry = backends ;
if ( ( version ! = SMB_VFS_INTERFACE_VERSION ) ) {
DEBUG ( 0 , ( " Failed to register vfs module. \n "
" The module was compiled against SMB_VFS_INTERFACE_VERSION %d, \n "
" current SMB_VFS_INTERFACE_VERSION is %d. \n "
" Please recompile against the current Samba Version! \n " ,
version , SMB_VFS_INTERFACE_VERSION ) ) ;
return NT_STATUS_OBJECT_TYPE_MISMATCH ;
}
if ( ! name | | ! name [ 0 ] | | ! vfs_op_tuples ) {
DEBUG ( 0 , ( " smb_register_vfs() called with NULL pointer or empty name! \n " ) ) ;
return NT_STATUS_INVALID_PARAMETER ;
}
if ( vfs_find_backend_entry ( name ) ) {
DEBUG ( 0 , ( " VFS module %s already loaded! \n " , name ) ) ;
return NT_STATUS_OBJECT_NAME_COLLISION ;
}
2004-12-07 21:25:53 +03:00
entry = SMB_XMALLOC_P ( struct vfs_init_function_entry ) ;
2003-05-12 03:34:18 +04:00
entry - > name = smb_xstrdup ( name ) ;
entry - > vfs_op_tuples = vfs_op_tuples ;
DLIST_ADD ( backends , entry ) ;
DEBUG ( 5 , ( " Successfully added vfs backend '%s' \n " , name ) ) ;
return NT_STATUS_OK ;
2003-04-16 18:45:11 +04:00
}
2000-02-03 08:10:09 +03:00
/****************************************************************************
initialise default vfs hooks
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-30 02:32:24 +04:00
2002-08-17 19:27:10 +04:00
static void vfs_init_default ( connection_struct * conn )
2000-02-03 08:10:09 +03:00
{
2002-03-27 06:00:39 +03:00
DEBUG ( 3 , ( " Initialising default vfs hooks \n " ) ) ;
2006-07-11 22:01:26 +04:00
vfs_init_custom ( conn , DEFAULT_VFS_MODULE_NAME ) ;
2003-04-16 18:45:11 +04:00
}
/****************************************************************************
initialise custom vfs hooks
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-07-11 22:01:26 +04:00
static inline void vfs_set_operation ( struct vfs_ops * vfs , vfs_op_type which ,
struct vfs_handle_struct * handle , void * op )
{
( ( struct vfs_handle_struct * * ) & vfs - > handles ) [ which ] = handle ;
2006-10-06 21:28:52 +04:00
( ( void * * ) ( void * ) & vfs - > ops ) [ which ] = op ;
2006-07-11 22:01:26 +04:00
}
2007-10-19 04:40:25 +04:00
bool vfs_init_custom ( connection_struct * conn , const char * vfs_object )
2003-04-16 18:45:11 +04:00
{
2007-12-27 22:00:13 +03:00
const vfs_op_tuple * ops ;
2007-10-28 13:58:26 +03:00
char * module_path = NULL ;
2003-05-12 03:34:18 +04:00
char * module_name = NULL ;
char * module_param = NULL , * p ;
2003-04-16 18:45:11 +04:00
int i ;
2003-05-12 03:34:18 +04:00
vfs_handle_struct * handle ;
2007-12-27 22:00:13 +03:00
const struct vfs_init_function_entry * entry ;
2003-05-12 03:34:18 +04:00
if ( ! conn | | ! vfs_object | | ! vfs_object [ 0 ] ) {
DEBUG ( 0 , ( " vfs_init_custon() called with NULL pointer or emtpy vfs_object! \n " ) ) ;
return False ;
}
2003-04-16 18:45:11 +04:00
2005-05-06 17:26:54 +04:00
if ( ! backends ) {
static_init_vfs ;
}
2003-04-16 18:45:11 +04:00
2003-05-12 03:34:18 +04:00
DEBUG ( 3 , ( " Initialising custom vfs hooks from [%s] \n " , vfs_object ) ) ;
2007-10-28 13:58:26 +03:00
module_path = smb_xstrdup ( vfs_object ) ;
2003-05-12 03:34:18 +04:00
2007-10-28 13:58:26 +03:00
p = strchr_m ( module_path , ' : ' ) ;
2003-05-12 03:34:18 +04:00
if ( p ) {
* p = 0 ;
module_param = p + 1 ;
2003-09-05 23:59:55 +04:00
trim_char ( module_param , ' ' , ' ' ) ;
2003-05-12 03:34:18 +04:00
}
2007-10-28 13:58:26 +03:00
trim_char ( module_path , ' ' , ' ' ) ;
module_name = smb_xstrdup ( module_path ) ;
if ( ( module_name [ 0 ] = = ' / ' ) & &
( strcmp ( module_path , DEFAULT_VFS_MODULE_NAME ) ! = 0 ) ) {
/*
* Extract the module name from the path . Just use the base
* name of the last path component .
*/
SAFE_FREE ( module_name ) ;
module_name = smb_xstrdup ( strrchr_m ( module_path , ' / ' ) + 1 ) ;
p = strchr_m ( module_name , ' . ' ) ;
if ( p ! = NULL ) {
* p = ' \0 ' ;
}
}
2003-05-12 03:34:18 +04:00
2003-04-16 18:45:11 +04:00
/* First, try to load the module with the new module system */
2003-05-12 03:34:18 +04:00
if ( ( entry = vfs_find_backend_entry ( module_name ) ) | |
2007-10-28 13:58:26 +03:00
( NT_STATUS_IS_OK ( smb_probe_module ( " vfs " , module_path ) ) & &
2003-05-12 03:34:18 +04:00
( entry = vfs_find_backend_entry ( module_name ) ) ) ) {
2003-04-16 18:45:11 +04:00
2003-05-12 03:34:18 +04:00
DEBUGADD ( 5 , ( " Successfully loaded vfs module [%s] with the new modules system \n " , vfs_object ) ) ;
2003-04-16 18:45:11 +04:00
2003-05-12 03:34:18 +04:00
if ( ( ops = entry - > vfs_op_tuples ) = = NULL ) {
DEBUG ( 0 , ( " entry->vfs_op_tuples==NULL for [%s] failed \n " , vfs_object ) ) ;
2007-10-28 13:58:26 +03:00
goto fail ;
2003-05-12 03:34:18 +04:00
}
2003-04-16 18:45:11 +04:00
} else {
2003-05-12 03:34:18 +04:00
DEBUG ( 0 , ( " Can't find a vfs module [%s] \n " , vfs_object ) ) ;
2007-10-28 13:58:26 +03:00
goto fail ;
2003-05-12 03:34:18 +04:00
}
2004-12-07 21:25:53 +03:00
handle = TALLOC_ZERO_P ( conn - > mem_ctx , vfs_handle_struct ) ;
2003-05-12 03:34:18 +04:00
if ( ! handle ) {
2007-04-28 03:18:41 +04:00
DEBUG ( 0 , ( " TALLOC_ZERO() failed! \n " ) ) ;
2007-10-28 13:58:26 +03:00
goto fail ;
2003-05-12 03:34:18 +04:00
}
memcpy ( & handle - > vfs_next , & conn - > vfs , sizeof ( struct vfs_ops ) ) ;
handle - > conn = conn ;
if ( module_param ) {
handle - > param = talloc_strdup ( conn - > mem_ctx , module_param ) ;
2003-04-16 18:45:11 +04:00
}
2003-05-12 03:34:18 +04:00
DLIST_ADD ( conn - > vfs_handles , handle ) ;
2003-04-16 18:45:11 +04:00
2002-08-17 19:27:10 +04:00
for ( i = 0 ; ops [ i ] . op ! = NULL ; i + + ) {
2005-06-28 02:53:56 +04:00
DEBUG ( 5 , ( " Checking operation #%d (type %d, layer %d) \n " , i , ops [ i ] . type , ops [ i ] . layer ) ) ;
if ( ops [ i ] . layer = = SMB_VFS_LAYER_OPAQUE ) {
2006-07-11 22:01:26 +04:00
/* If this operation was already made opaque by different module, it
2007-04-08 23:41:47 +04:00
* will be overridden here .
2006-07-11 22:01:26 +04:00
*/
DEBUGADD ( 5 , ( " Making operation type %d opaque [module %s] \n " , ops [ i ] . type , vfs_object ) ) ;
vfs_set_operation ( & conn - > vfs_opaque , ops [ i ] . type , handle , ops [ i ] . op ) ;
2005-06-28 02:53:56 +04:00
}
/* Change current VFS disposition*/
DEBUGADD ( 5 , ( " Accepting operation type %d from module %s \n " , ops [ i ] . type , vfs_object ) ) ;
2006-07-11 22:01:26 +04:00
vfs_set_operation ( & conn - > vfs , ops [ i ] . type , handle , ops [ i ] . op ) ;
2001-07-04 11:15:53 +04:00
}
2000-11-07 00:44:33 +03:00
2007-10-28 13:58:26 +03:00
SAFE_FREE ( module_path ) ;
2003-05-12 03:34:18 +04:00
SAFE_FREE ( module_name ) ;
2002-03-27 06:00:39 +03:00
return True ;
2007-10-28 13:58:26 +03:00
fail :
SAFE_FREE ( module_path ) ;
SAFE_FREE ( module_name ) ;
return False ;
2000-02-03 08:10:09 +03:00
}
2006-07-11 22:01:26 +04:00
/*****************************************************************
Allow VFS modules to extend files_struct with VFS - specific state .
This will be ok for small numbers of extensions , but might need to
be refactored if it becomes more widely used .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
void * vfs_add_fsp_extension_notype ( vfs_handle_struct * handle , files_struct * fsp , size_t ext_size )
{
struct vfs_fsp_data * ext ;
void * ext_data ;
/* Prevent VFS modules adding multiple extensions. */
if ( ( ext_data = vfs_fetch_fsp_extension ( handle , fsp ) ) ) {
return ext_data ;
}
2006-08-01 01:40:25 +04:00
ext = ( struct vfs_fsp_data * ) TALLOC_ZERO (
handle - > conn - > mem_ctx , sizeof ( struct vfs_fsp_data ) + ext_size ) ;
2006-07-11 22:01:26 +04:00
if ( ext = = NULL ) {
return NULL ;
}
ext - > owner = handle ;
ext - > next = fsp - > vfs_extension ;
fsp - > vfs_extension = ext ;
return EXT_DATA_AREA ( ext ) ;
}
void vfs_remove_fsp_extension ( vfs_handle_struct * handle , files_struct * fsp )
{
struct vfs_fsp_data * curr ;
struct vfs_fsp_data * prev ;
for ( curr = fsp - > vfs_extension , prev = NULL ;
curr ;
prev = curr , curr = curr - > next ) {
if ( curr - > owner = = handle ) {
if ( prev ) {
prev - > next = curr - > next ;
} else {
fsp - > vfs_extension = curr - > next ;
}
TALLOC_FREE ( curr ) ;
return ;
}
}
}
2007-10-16 01:01:12 +04:00
void * vfs_memctx_fsp_extension ( vfs_handle_struct * handle , files_struct * fsp )
2006-07-11 22:01:26 +04:00
{
struct vfs_fsp_data * head ;
for ( head = fsp - > vfs_extension ; head ; head = head - > next ) {
if ( head - > owner = = handle ) {
2007-10-16 01:01:12 +04:00
return head ;
2006-07-11 22:01:26 +04:00
}
}
return NULL ;
}
2007-10-16 01:01:12 +04:00
void * vfs_fetch_fsp_extension ( vfs_handle_struct * handle , files_struct * fsp )
{
struct vfs_fsp_data * head ;
2007-12-20 22:59:44 +03:00
head = ( struct vfs_fsp_data * ) vfs_memctx_fsp_extension ( handle , fsp ) ;
2007-10-16 01:01:12 +04:00
if ( head ! = NULL ) {
return EXT_DATA_AREA ( head ) ;
}
return NULL ;
}
2006-07-11 22:01:26 +04:00
# undef EXT_DATA_AREA
2001-06-30 02:32:24 +04:00
/*****************************************************************
Generic VFS init .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool smbd_vfs_init ( connection_struct * conn )
2001-06-30 02:32:24 +04:00
{
2003-04-16 18:45:11 +04:00
const char * * vfs_objects ;
unsigned int i = 0 ;
int j = 0 ;
2002-08-17 19:27:10 +04:00
/* Normal share - initialise with disk access functions */
vfs_init_default ( conn ) ;
2003-05-12 03:34:18 +04:00
vfs_objects = lp_vfs_objects ( SNUM ( conn ) ) ;
2002-08-17 19:27:10 +04:00
2003-04-21 23:43:25 +04:00
/* Override VFS functions if 'vfs object' was not specified*/
if ( ! vfs_objects | | ! vfs_objects [ 0 ] )
2003-04-16 18:45:11 +04:00
return True ;
2003-05-12 03:34:18 +04:00
for ( i = 0 ; vfs_objects [ i ] ; ) {
i + + ;
2003-04-16 18:45:11 +04:00
}
for ( j = i - 1 ; j > = 0 ; j - - ) {
2003-05-12 03:34:18 +04:00
if ( ! vfs_init_custom ( conn , vfs_objects [ j ] ) ) {
DEBUG ( 0 , ( " smbd_vfs_init: vfs_init_custom failed for %s \n " , vfs_objects [ j ] ) ) ;
2003-04-16 18:45:11 +04:00
return False ;
2001-06-30 02:32:24 +04:00
}
}
2002-08-17 19:27:10 +04:00
return True ;
}
2000-09-27 23:09:59 +04:00
/*******************************************************************
Check if directory exists .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-02-03 08:10:09 +03:00
2007-10-19 04:40:25 +04:00
bool vfs_directory_exist ( connection_struct * conn , const char * dname , SMB_STRUCT_STAT * st )
2000-09-27 23:09:59 +04:00
{
SMB_STRUCT_STAT st2 ;
2007-10-19 04:40:25 +04:00
bool ret ;
2000-09-27 23:09:59 +04:00
if ( ! st )
st = & st2 ;
2000-02-03 08:10:09 +03:00
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_STAT ( conn , dname , st ) ! = 0 )
2000-09-27 23:09:59 +04:00
return ( False ) ;
ret = S_ISDIR ( st - > st_mode ) ;
if ( ! ret )
errno = ENOTDIR ;
2000-02-03 08:10:09 +03:00
2001-07-04 11:15:53 +04:00
return ret ;
}
2000-09-27 23:09:59 +04:00
/*******************************************************************
2002-01-05 00:11:35 +03:00
Check if an object exists in the vfs .
2000-02-03 08:10:09 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-09-27 23:09:59 +04:00
2007-10-19 04:40:25 +04:00
bool vfs_object_exist ( connection_struct * conn , const char * fname , SMB_STRUCT_STAT * sbuf )
2000-02-03 08:10:09 +03:00
{
2000-09-27 23:09:59 +04:00
SMB_STRUCT_STAT st ;
2000-02-03 08:10:09 +03:00
2000-09-27 23:09:59 +04:00
if ( ! sbuf )
sbuf = & st ;
2000-10-19 06:58:24 +04:00
ZERO_STRUCTP ( sbuf ) ;
2000-11-15 00:56:32 +03:00
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_STAT ( conn , fname , sbuf ) = = - 1 )
2000-09-27 23:09:59 +04:00
return ( False ) ;
2002-01-05 00:11:35 +03:00
return True ;
}
/*******************************************************************
Check if a file exists in the vfs .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool vfs_file_exist ( connection_struct * conn , const char * fname , SMB_STRUCT_STAT * sbuf )
2002-01-05 00:11:35 +03:00
{
SMB_STRUCT_STAT st ;
if ( ! sbuf )
sbuf = & st ;
2000-09-27 23:09:59 +04:00
2002-01-05 00:11:35 +03:00
ZERO_STRUCTP ( sbuf ) ;
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_STAT ( conn , fname , sbuf ) = = - 1 )
2002-01-05 00:11:35 +03:00
return False ;
2000-09-27 23:09:59 +04:00
return ( S_ISREG ( sbuf - > st_mode ) ) ;
2000-02-03 08:10:09 +03:00
}
2000-11-15 00:56:32 +03:00
/****************************************************************************
Read data from fsp on the vfs . ( note : EINTR re - read differs from vfs_write_data )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t vfs_read_data ( files_struct * fsp , char * buf , size_t byte_count )
{
size_t total = 0 ;
while ( total < byte_count )
{
2005-07-08 08:51:27 +04:00
ssize_t ret = SMB_VFS_READ ( fsp , fsp - > fh - > fd , buf + total ,
2002-03-27 06:00:39 +03:00
byte_count - total ) ;
2000-11-15 00:56:32 +03:00
if ( ret = = 0 ) return total ;
if ( ret = = - 1 ) {
if ( errno = = EINTR )
continue ;
else
return - 1 ;
}
total + = ret ;
}
return ( ssize_t ) total ;
}
2004-01-06 04:22:14 +03:00
ssize_t vfs_pread_data ( files_struct * fsp , char * buf ,
size_t byte_count , SMB_OFF_T offset )
{
size_t total = 0 ;
while ( total < byte_count )
{
2008-01-07 02:14:19 +03:00
ssize_t ret = SMB_VFS_PREAD ( fsp , buf + total ,
2004-01-06 04:22:14 +03:00
byte_count - total , offset + total ) ;
if ( ret = = 0 ) return total ;
if ( ret = = - 1 ) {
if ( errno = = EINTR )
continue ;
else
return - 1 ;
}
total + = ret ;
}
return ( ssize_t ) total ;
}
2000-02-03 08:10:09 +03:00
/****************************************************************************
2000-09-27 23:09:59 +04:00
Write data to a fd on the vfs .
2000-02-03 08:10:09 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-09-27 23:09:59 +04:00
2007-10-31 02:22:24 +03:00
ssize_t vfs_write_data ( struct smb_request * req ,
files_struct * fsp ,
const char * buffer ,
size_t N )
2000-02-03 08:10:09 +03:00
{
2001-11-12 04:00:54 +03:00
size_t total = 0 ;
ssize_t ret ;
2000-02-03 08:10:09 +03:00
2007-10-31 02:22:24 +03:00
if ( req & & req - > unread_bytes ) {
SMB_ASSERT ( req - > unread_bytes = = N ) ;
2007-11-01 00:01:35 +03:00
/* VFS_RECVFILE must drain the socket
* before returning . */
req - > unread_bytes = 0 ;
return SMB_VFS_RECVFILE ( smbd_server_fd ( ) ,
2007-10-31 02:22:24 +03:00
fsp ,
fsp - > fh - > fd ,
( SMB_OFF_T ) - 1 ,
N ) ;
}
2001-11-12 04:00:54 +03:00
while ( total < N ) {
2005-07-08 08:51:27 +04:00
ret = SMB_VFS_WRITE ( fsp , fsp - > fh - > fd , buffer + total , N - total ) ;
2000-02-03 08:10:09 +03:00
2001-11-12 04:00:54 +03:00
if ( ret = = - 1 )
return - 1 ;
if ( ret = = 0 )
return total ;
2000-02-03 08:10:09 +03:00
2001-11-12 04:00:54 +03:00
total + = ret ;
}
return ( ssize_t ) total ;
2000-02-03 08:10:09 +03:00
}
2007-10-31 02:22:24 +03:00
ssize_t vfs_pwrite_data ( struct smb_request * req ,
files_struct * fsp ,
const char * buffer ,
size_t N ,
SMB_OFF_T offset )
2004-01-06 04:22:14 +03:00
{
size_t total = 0 ;
ssize_t ret ;
2007-10-31 02:22:24 +03:00
if ( req & & req - > unread_bytes ) {
SMB_ASSERT ( req - > unread_bytes = = N ) ;
2007-11-01 00:01:35 +03:00
/* VFS_RECVFILE must drain the socket
* before returning . */
req - > unread_bytes = 0 ;
return SMB_VFS_RECVFILE ( smbd_server_fd ( ) ,
2007-10-31 02:22:24 +03:00
fsp ,
fsp - > fh - > fd ,
offset ,
N ) ;
}
2004-01-06 04:22:14 +03:00
while ( total < N ) {
2008-01-07 11:23:04 +03:00
ret = SMB_VFS_PWRITE ( fsp , buffer + total , N - total ,
offset + total ) ;
2004-01-06 04:22:14 +03:00
if ( ret = = - 1 )
return - 1 ;
if ( ret = = 0 )
return total ;
total + = ret ;
}
return ( ssize_t ) total ;
}
2001-08-02 02:13:50 +04:00
/****************************************************************************
An allocate file space call using the vfs interface .
Allocates space for a file from a filedescriptor .
Returns 0 on success , - 1 on failure .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-12-04 06:12:09 +03:00
int vfs_allocate_file_space ( files_struct * fsp , SMB_BIG_UINT len )
2001-08-02 02:13:50 +04:00
{
int ret ;
SMB_STRUCT_STAT st ;
2001-11-12 04:00:54 +03:00
connection_struct * conn = fsp - > conn ;
2002-12-04 06:12:09 +03:00
SMB_BIG_UINT space_avail ;
2001-11-12 04:00:54 +03:00
SMB_BIG_UINT bsize , dfree , dsize ;
2001-08-02 02:13:50 +04:00
release_level_2_oplocks_on_change ( fsp ) ;
/*
* Actually try and commit the space on disk . . . .
*/
DEBUG ( 10 , ( " vfs_allocate_file_space: file %s, len %.0f \n " , fsp - > fsp_name , ( double ) len ) ) ;
2002-12-04 06:12:09 +03:00
if ( ( ( SMB_OFF_T ) len ) < 0 ) {
DEBUG ( 0 , ( " vfs_allocate_file_space: %s negative len requested. \n " , fsp - > fsp_name ) ) ;
2007-01-31 01:20:55 +03:00
errno = EINVAL ;
2002-12-04 06:12:09 +03:00
return - 1 ;
}
2005-07-08 08:51:27 +04:00
ret = SMB_VFS_FSTAT ( fsp , fsp - > fh - > fd , & st ) ;
2001-08-02 02:13:50 +04:00
if ( ret = = - 1 )
return ret ;
2002-12-04 06:12:09 +03:00
if ( len = = ( SMB_BIG_UINT ) st . st_size )
2001-08-02 02:13:50 +04:00
return 0 ;
2002-12-04 06:12:09 +03:00
if ( len < ( SMB_BIG_UINT ) st . st_size ) {
2001-08-02 02:13:50 +04:00
/* Shrink - use ftruncate. */
DEBUG ( 10 , ( " vfs_allocate_file_space: file %s, shrink. Current size %.0f \n " ,
fsp - > fsp_name , ( double ) st . st_size ) ) ;
2002-01-20 03:04:15 +03:00
flush_write_cache ( fsp , SIZECHANGE_FLUSH ) ;
2005-07-08 08:51:27 +04:00
if ( ( ret = SMB_VFS_FTRUNCATE ( fsp , fsp - > fh - > fd , ( SMB_OFF_T ) len ) ) ! = - 1 ) {
2001-08-02 02:13:50 +04:00
set_filelen_write_cache ( fsp , len ) ;
}
return ret ;
}
2001-11-12 04:00:54 +03:00
/* Grow - we need to test if we have enough space. */
2001-08-02 02:13:50 +04:00
2001-11-12 05:03:44 +03:00
if ( ! lp_strict_allocate ( SNUM ( fsp - > conn ) ) )
return 0 ;
2001-11-12 04:00:54 +03:00
len - = st . st_size ;
len / = 1024 ; /* Len is now number of 1k blocks needed. */
2005-11-01 01:30:05 +03:00
space_avail = get_dfree_info ( conn , fsp - > fsp_name , False , & bsize , & dfree , & dsize ) ;
2005-03-16 05:11:44 +03:00
if ( space_avail = = ( SMB_BIG_UINT ) - 1 ) {
return - 1 ;
}
2001-08-02 02:13:50 +04:00
2002-12-04 06:12:09 +03:00
DEBUG ( 10 , ( " vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f \n " ,
fsp - > fsp_name , ( double ) st . st_size , ( double ) len , ( double ) space_avail ) ) ;
2001-08-02 02:13:50 +04:00
2001-11-12 04:00:54 +03:00
if ( len > space_avail ) {
errno = ENOSPC ;
return - 1 ;
2001-08-02 02:13:50 +04:00
}
2001-11-12 04:00:54 +03:00
2001-08-02 02:13:50 +04:00
return 0 ;
}
2000-11-16 03:59:18 +03:00
/****************************************************************************
A vfs set_filelen call .
set the length of a file from a filedescriptor .
Returns 0 on success , - 1 on failure .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int vfs_set_filelen ( files_struct * fsp , SMB_OFF_T len )
{
int ret ;
release_level_2_oplocks_on_change ( fsp ) ;
2001-11-08 02:47:20 +03:00
DEBUG ( 10 , ( " vfs_set_filelen: ftruncate %s to len %.0f \n " , fsp - > fsp_name , ( double ) len ) ) ;
2002-01-20 03:04:15 +03:00
flush_write_cache ( fsp , SIZECHANGE_FLUSH ) ;
2007-02-03 19:53:52 +03:00
if ( ( ret = SMB_VFS_FTRUNCATE ( fsp , fsp - > fh - > fd , len ) ) ! = - 1 ) {
2000-11-16 03:59:18 +03:00
set_filelen_write_cache ( fsp , len ) ;
2007-02-03 19:53:52 +03:00
notify_fname ( fsp - > conn , NOTIFY_ACTION_MODIFIED ,
FILE_NOTIFY_CHANGE_SIZE
| FILE_NOTIFY_CHANGE_ATTRIBUTES ,
fsp - > fsp_name ) ;
}
2000-11-16 03:59:18 +03:00
return ret ;
}
2005-05-17 05:04:51 +04:00
/****************************************************************************
A vfs fill sparse call .
Writes zeros from the end of file to len , if len is greater than EOF .
Used only by strict_sync .
Returns 0 on success , - 1 on failure .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static char * sparse_buf ;
# define SPARSE_BUF_WRITE_SIZE (32*1024)
int vfs_fill_sparse ( files_struct * fsp , SMB_OFF_T len )
{
int ret ;
SMB_STRUCT_STAT st ;
SMB_OFF_T offset ;
size_t total ;
size_t num_to_write ;
ssize_t pwrite_ret ;
release_level_2_oplocks_on_change ( fsp ) ;
2005-07-08 08:51:27 +04:00
ret = SMB_VFS_FSTAT ( fsp , fsp - > fh - > fd , & st ) ;
2005-05-17 05:04:51 +04:00
if ( ret = = - 1 ) {
return ret ;
}
if ( len < = st . st_size ) {
return 0 ;
}
DEBUG ( 10 , ( " vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes) \n " ,
fsp - > fsp_name , ( double ) st . st_size , ( double ) len , ( double ) ( len - st . st_size ) ) ) ;
flush_write_cache ( fsp , SIZECHANGE_FLUSH ) ;
if ( ! sparse_buf ) {
sparse_buf = SMB_CALLOC_ARRAY ( char , SPARSE_BUF_WRITE_SIZE ) ;
if ( ! sparse_buf ) {
errno = ENOMEM ;
return - 1 ;
}
}
offset = st . st_size ;
num_to_write = len - st . st_size ;
total = 0 ;
while ( total < num_to_write ) {
size_t curr_write_size = MIN ( SPARSE_BUF_WRITE_SIZE , ( num_to_write - total ) ) ;
2008-01-07 11:23:04 +03:00
pwrite_ret = SMB_VFS_PWRITE ( fsp , sparse_buf , curr_write_size , offset + total ) ;
2005-05-17 05:04:51 +04:00
if ( pwrite_ret = = - 1 ) {
DEBUG ( 10 , ( " vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s \n " ,
fsp - > fsp_name , strerror ( errno ) ) ) ;
return - 1 ;
}
if ( pwrite_ret = = 0 ) {
return 0 ;
}
total + = pwrite_ret ;
}
set_filelen_write_cache ( fsp , len ) ;
return 0 ;
}
2000-02-03 08:10:09 +03:00
/****************************************************************************
2001-09-04 23:10:30 +04:00
Transfer some data ( n bytes ) between two file_struct ' s .
2000-02-03 08:10:09 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-09-27 23:09:59 +04:00
2001-09-04 23:10:30 +04:00
static files_struct * in_fsp ;
static files_struct * out_fsp ;
2000-02-03 08:10:09 +03:00
2001-09-04 23:10:30 +04:00
static ssize_t read_fn ( int fd , void * buf , size_t len )
{
2003-05-14 14:59:01 +04:00
return SMB_VFS_READ ( in_fsp , fd , buf , len ) ;
2001-09-04 23:10:30 +04:00
}
2000-02-03 08:10:09 +03:00
2001-09-04 23:10:30 +04:00
static ssize_t write_fn ( int fd , const void * buf , size_t len )
{
2003-05-14 14:59:01 +04:00
return SMB_VFS_WRITE ( out_fsp , fd , buf , len ) ;
2001-09-04 23:10:30 +04:00
}
2000-02-03 08:10:09 +03:00
2001-09-04 23:10:30 +04:00
SMB_OFF_T vfs_transfer_file ( files_struct * in , files_struct * out , SMB_OFF_T n )
{
in_fsp = in ;
out_fsp = out ;
2000-02-03 08:10:09 +03:00
2005-07-08 08:51:27 +04:00
return transfer_file_internal ( in_fsp - > fh - > fd , out_fsp - > fh - > fd , n , read_fn , write_fn ) ;
2000-02-03 08:10:09 +03:00
}
/*******************************************************************
2000-09-27 23:09:59 +04:00
A vfs_readdir wrapper which just returns the file name .
2000-02-03 08:10:09 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-09-27 23:09:59 +04:00
2000-02-03 08:10:09 +03:00
char * vfs_readdirname ( connection_struct * conn , void * p )
{
2004-11-10 01:49:28 +03:00
SMB_STRUCT_DIRENT * ptr = NULL ;
2000-02-03 08:10:09 +03:00
char * dname ;
2000-09-27 23:09:59 +04:00
if ( ! p )
return ( NULL ) ;
2000-11-15 00:56:32 +03:00
2006-08-01 01:40:25 +04:00
ptr = SMB_VFS_READDIR ( conn , ( DIR * ) p ) ;
2000-09-27 23:09:59 +04:00
if ( ! ptr )
return ( NULL ) ;
2000-02-03 08:10:09 +03:00
dname = ptr - > d_name ;
# ifdef NEXT2
2000-09-27 23:09:59 +04:00
if ( telldir ( p ) < 0 )
return ( NULL ) ;
2000-02-03 08:10:09 +03:00
# endif
2006-03-27 23:50:45 +04:00
# ifdef HAVE_BROKEN_READDIR_NAME
2000-02-03 08:10:09 +03:00
/* using /usr/ucb/cc is BAD */
dname = dname - 2 ;
# endif
return ( dname ) ;
}
2000-09-27 23:09:59 +04:00
/*******************************************************************
A wrapper for vfs_chdir ( ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-03-03 23:12:37 +03:00
int vfs_ChDir ( connection_struct * conn , const char * path )
2000-09-27 23:09:59 +04:00
{
int res ;
2007-09-13 01:48:20 +04:00
static char * LastDir = NULL ;
if ( ! LastDir ) {
LastDir = SMB_STRDUP ( " " ) ;
}
2000-09-27 23:09:59 +04:00
if ( strcsequal ( path , " . " ) )
return ( 0 ) ;
if ( * path = = ' / ' & & strcsequal ( LastDir , path ) )
return ( 0 ) ;
2003-05-12 03:34:18 +04:00
DEBUG ( 4 , ( " vfs_ChDir to %s \n " , path ) ) ;
2000-09-27 23:09:59 +04:00
2003-05-14 14:59:01 +04:00
res = SMB_VFS_CHDIR ( conn , path ) ;
2007-09-13 01:48:20 +04:00
if ( ! res ) {
SAFE_FREE ( LastDir ) ;
LastDir = SMB_STRDUP ( path ) ;
}
2000-09-27 23:09:59 +04:00
return ( res ) ;
}
/*******************************************************************
Return the absolute current directory path - given a UNIX pathname .
Note that this path is returned in DOS format , not UNIX
format . Note this can be called with conn = = NULL .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-12-18 11:41:03 +03:00
struct getwd_cache_key {
SMB_DEV_T dev ;
SMB_INO_T ino ;
} ;
2007-09-13 01:48:20 +04:00
char * vfs_GetWd ( TALLOC_CTX * ctx , connection_struct * conn )
2000-09-27 23:09:59 +04:00
{
2007-09-13 01:48:20 +04:00
char s [ PATH_MAX + 1 ] ;
2002-03-27 06:00:39 +03:00
SMB_STRUCT_STAT st , st2 ;
2007-12-18 11:41:03 +03:00
char * result ;
DATA_BLOB cache_value ;
struct getwd_cache_key key ;
2002-03-27 06:00:39 +03:00
* s = 0 ;
2007-12-18 11:41:03 +03:00
if ( ! lp_getwd_cache ( ) ) {
goto nocache ;
2002-03-27 06:00:39 +03:00
}
2007-12-18 11:41:03 +03:00
SET_STAT_INVALID ( st ) ;
2000-09-27 23:09:59 +04:00
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_STAT ( conn , " . " , & st ) = = - 1 ) {
2007-12-18 11:41:03 +03:00
/*
* Known to fail for root : the directory may be NFS - mounted
* and exported with root_squash ( so has no root access ) .
*/
2007-09-13 01:48:20 +04:00
DEBUG ( 1 , ( " vfs_GetWd: couldn't stat \" . \" error %s "
2007-12-18 11:41:03 +03:00
" (NFS problem ?) \n " , strerror ( errno ) ) ) ;
2007-09-13 01:48:20 +04:00
goto nocache ;
2002-03-27 06:00:39 +03:00
}
2000-09-27 23:09:59 +04:00
2007-12-18 11:41:03 +03:00
ZERO_STRUCT ( key ) ; /* unlikely, but possible padding */
key . dev = st . st_dev ;
key . ino = st . st_ino ;
2000-09-27 23:09:59 +04:00
2007-12-18 11:41:03 +03:00
if ( ! memcache_lookup ( smbd_memcache ( ) , GETWD_CACHE ,
data_blob_const ( & key , sizeof ( key ) ) ,
& cache_value ) ) {
goto nocache ;
2002-03-27 06:00:39 +03:00
}
2000-09-27 23:09:59 +04:00
2007-12-18 11:41:03 +03:00
SMB_ASSERT ( ( cache_value . length > 0 )
& & ( cache_value . data [ cache_value . length - 1 ] = = ' \0 ' ) ) ;
2000-09-27 23:09:59 +04:00
2007-12-18 11:41:03 +03:00
if ( ( SMB_VFS_STAT ( conn , ( char * ) cache_value . data , & st2 ) = = 0 )
& & ( st . st_dev = = st2 . st_dev ) & & ( st . st_ino = = st2 . st_ino )
& & ( S_ISDIR ( st . st_mode ) ) ) {
/*
* Ok , we ' re done
*/
result = talloc_strdup ( ctx , ( char * ) cache_value . data ) ;
if ( result = = NULL ) {
errno = ENOMEM ;
}
return result ;
2002-03-27 06:00:39 +03:00
}
2000-09-27 23:09:59 +04:00
2007-12-18 11:41:03 +03:00
nocache :
/*
* We don ' t have the information to hand so rely on traditional
* methods . The very slow getcwd , which spawns a process on some
* systems , or the not quite so bad getwd .
*/
2000-09-27 23:09:59 +04:00
2007-12-18 11:41:03 +03:00
if ( ! SMB_VFS_GETWD ( conn , s ) ) {
DEBUG ( 0 , ( " vfs_GetWd: SMB_VFS_GETWD call failed: %s \n " ,
strerror ( errno ) ) ) ;
return NULL ;
}
2000-09-27 23:09:59 +04:00
2007-12-18 11:41:03 +03:00
if ( lp_getwd_cache ( ) & & VALID_STAT ( st ) ) {
ZERO_STRUCT ( key ) ; /* unlikely, but possible padding */
key . dev = st . st_dev ;
key . ino = st . st_ino ;
2002-03-27 06:00:39 +03:00
2007-12-18 11:41:03 +03:00
memcache_add ( smbd_memcache ( ) , GETWD_CACHE ,
data_blob_const ( & key , sizeof ( key ) ) ,
data_blob_const ( s , strlen ( s ) + 1 ) ) ;
}
2002-03-27 06:00:39 +03:00
2007-12-18 11:41:03 +03:00
result = talloc_strdup ( ctx , s ) ;
if ( result = = NULL ) {
2007-09-13 01:48:20 +04:00
errno = ENOMEM ;
}
2007-12-18 11:41:03 +03:00
return result ;
2000-09-27 23:09:59 +04:00
}
/*******************************************************************
2000-11-15 00:56:32 +03:00
Reduce a file name , removing . . elements and checking that
2004-05-13 04:20:50 +04:00
it is below dir in the heirachy . This uses realpath .
2000-09-27 23:09:59 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-07-09 13:43:41 +04:00
NTSTATUS check_reduced_name ( connection_struct * conn , const char * fname )
2000-09-27 23:09:59 +04:00
{
2004-05-13 04:20:50 +04:00
# ifdef REALPATH_TAKES_NULL
2007-10-19 04:40:25 +04:00
bool free_resolved_name = True ;
2000-09-27 23:09:59 +04:00
# else
2004-05-13 04:20:50 +04:00
char resolved_name_buf [ PATH_MAX + 1 ] ;
2007-10-19 04:40:25 +04:00
bool free_resolved_name = False ;
2004-05-13 04:20:50 +04:00
# endif
char * resolved_name = NULL ;
size_t con_path_len = strlen ( conn - > connectpath ) ;
char * p = NULL ;
2002-03-27 06:00:39 +03:00
2004-05-13 04:20:50 +04:00
DEBUG ( 3 , ( " reduce_name [%s] [%s] \n " , fname , conn - > connectpath ) ) ;
2002-03-27 06:00:39 +03:00
2004-05-13 04:20:50 +04:00
# ifdef REALPATH_TAKES_NULL
resolved_name = SMB_VFS_REALPATH ( conn , fname , NULL ) ;
# else
resolved_name = SMB_VFS_REALPATH ( conn , fname , resolved_name_buf ) ;
# endif
2002-03-27 06:00:39 +03:00
2004-05-13 04:20:50 +04:00
if ( ! resolved_name ) {
switch ( errno ) {
case ENOTDIR :
DEBUG ( 3 , ( " reduce_name: Component not a directory in getting realpath for %s \n " , fname ) ) ;
2007-01-17 05:09:37 +03:00
return map_nt_error_from_unix ( errno ) ;
2004-05-13 04:20:50 +04:00
case ENOENT :
{
2007-09-13 01:48:20 +04:00
TALLOC_CTX * tmp_ctx = talloc_stackframe ( ) ;
char * tmp_fname = NULL ;
char * last_component = NULL ;
2004-05-13 04:20:50 +04:00
/* Last component didn't exist. Remove it and try and canonicalise the directory. */
2007-09-13 01:48:20 +04:00
tmp_fname = talloc_strdup ( tmp_ctx , fname ) ;
if ( ! tmp_fname ) {
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
2004-05-13 04:20:50 +04:00
p = strrchr_m ( tmp_fname , ' / ' ) ;
if ( p ) {
* p + + = ' \0 ' ;
2007-09-13 01:48:20 +04:00
last_component = p ;
2004-05-13 04:56:00 +04:00
} else {
2007-09-13 01:48:20 +04:00
last_component = tmp_fname ;
tmp_fname = talloc_strdup ( tmp_ctx ,
" . " ) ;
if ( ! tmp_fname ) {
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
2004-05-13 04:20:50 +04:00
}
2004-05-13 04:56:00 +04:00
2004-05-13 04:20:50 +04:00
# ifdef REALPATH_TAKES_NULL
resolved_name = SMB_VFS_REALPATH ( conn , tmp_fname , NULL ) ;
# else
resolved_name = SMB_VFS_REALPATH ( conn , tmp_fname , resolved_name_buf ) ;
# endif
if ( ! resolved_name ) {
DEBUG ( 3 , ( " reduce_name: couldn't get realpath for %s \n " , fname ) ) ;
2007-09-13 01:48:20 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2007-01-17 05:09:37 +03:00
return map_nt_error_from_unix ( errno ) ;
2004-05-13 04:20:50 +04:00
}
2007-09-13 01:48:20 +04:00
tmp_fname = talloc_asprintf ( tmp_ctx ,
" %s/%s " ,
resolved_name ,
last_component ) ;
if ( ! tmp_fname ) {
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_NO_MEMORY ;
}
2004-05-13 04:20:50 +04:00
# ifdef REALPATH_TAKES_NULL
SAFE_FREE ( resolved_name ) ;
2004-12-07 21:25:53 +03:00
resolved_name = SMB_STRDUP ( tmp_fname ) ;
2004-05-13 04:20:50 +04:00
if ( ! resolved_name ) {
DEBUG ( 0 , ( " reduce_name: malloc fail for %s \n " , tmp_fname ) ) ;
2007-01-17 05:09:37 +03:00
return NT_STATUS_NO_MEMORY ;
2004-05-13 04:20:50 +04:00
}
# else
safe_strcpy ( resolved_name_buf , tmp_fname , PATH_MAX ) ;
resolved_name = resolved_name_buf ;
# endif
2007-09-13 01:48:20 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2004-05-13 04:20:50 +04:00
break ;
}
default :
DEBUG ( 1 , ( " reduce_name: couldn't get realpath for %s \n " , fname ) ) ;
2007-01-17 05:09:37 +03:00
return map_nt_error_from_unix ( errno ) ;
2004-05-13 04:20:50 +04:00
}
2002-03-27 06:00:39 +03:00
}
2004-05-13 04:20:50 +04:00
DEBUG ( 10 , ( " reduce_name realpath [%s] -> [%s] \n " , fname , resolved_name ) ) ;
2002-03-27 06:00:39 +03:00
2004-05-13 04:20:50 +04:00
if ( * resolved_name ! = ' / ' ) {
DEBUG ( 0 , ( " reduce_name: realpath doesn't return absolute paths ! \n " ) ) ;
2007-01-17 05:09:37 +03:00
if ( free_resolved_name ) {
2004-05-13 04:20:50 +04:00
SAFE_FREE ( resolved_name ) ;
2007-01-17 05:09:37 +03:00
}
return NT_STATUS_OBJECT_NAME_INVALID ;
2002-03-27 06:00:39 +03:00
}
2004-09-01 02:52:05 +04:00
/* Check for widelinks allowed. */
if ( ! lp_widelinks ( SNUM ( conn ) ) & & ( strncmp ( conn - > connectpath , resolved_name , con_path_len ) ! = 0 ) ) {
2004-05-28 05:54:01 +04:00
DEBUG ( 2 , ( " reduce_name: Bad access attempt: %s is a symlink outside the share path " , fname ) ) ;
2007-01-17 05:09:37 +03:00
if ( free_resolved_name ) {
2004-05-13 04:20:50 +04:00
SAFE_FREE ( resolved_name ) ;
2007-01-17 05:09:37 +03:00
}
return NT_STATUS_ACCESS_DENIED ;
2002-03-27 06:00:39 +03:00
}
2004-09-01 02:52:05 +04:00
/* Check if we are allowing users to follow symlinks */
/* Patch from David Clerc <David.Clerc@cui.unige.ch>
University of Geneva */
2007-09-13 01:48:20 +04:00
2004-09-01 02:52:05 +04:00
# ifdef S_ISLNK
if ( ! lp_symlinks ( SNUM ( conn ) ) ) {
SMB_STRUCT_STAT statbuf ;
if ( ( SMB_VFS_LSTAT ( conn , fname , & statbuf ) ! = - 1 ) & &
( S_ISLNK ( statbuf . st_mode ) ) ) {
2007-01-17 05:09:37 +03:00
if ( free_resolved_name ) {
2004-09-01 02:52:05 +04:00
SAFE_FREE ( resolved_name ) ;
2007-01-17 05:09:37 +03:00
}
2004-09-01 02:52:05 +04:00
DEBUG ( 3 , ( " reduce_name: denied: file path name %s is a symlink \n " , resolved_name ) ) ;
2007-01-17 05:09:37 +03:00
return NT_STATUS_ACCESS_DENIED ;
2004-09-01 02:52:05 +04:00
}
}
# endif
2000-09-27 23:09:59 +04:00
2005-03-11 21:50:09 +03:00
DEBUG ( 3 , ( " reduce_name: %s reduced to %s \n " , fname , resolved_name ) ) ;
2007-01-17 05:09:37 +03:00
if ( free_resolved_name ) {
2004-05-13 04:20:50 +04:00
SAFE_FREE ( resolved_name ) ;
2007-01-17 05:09:37 +03:00
}
return NT_STATUS_OK ;
2000-09-27 23:09:59 +04:00
}