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
the Free Software Foundation ; either version 2 of the License , or
( 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
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
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 ;
vfs_op_tuple * vfs_op_tuples ;
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 ;
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
}
2003-05-12 03:34:18 +04:00
NTSTATUS smb_register_vfs ( int version , const char * name , 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 ;
( ( void * * ) & vfs - > ops ) [ which ] = op ;
}
2003-04-16 18:45:11 +04:00
BOOL vfs_init_custom ( connection_struct * conn , const char * vfs_object )
{
vfs_op_tuple * ops ;
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 ;
2003-04-16 18:45:11 +04:00
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 ) ) ;
module_name = smb_xstrdup ( vfs_object ) ;
2005-05-06 17:26:54 +04:00
p = strchr_m ( module_name , ' : ' ) ;
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
}
2003-09-05 23:59:55 +04:00
trim_char ( module_name , ' ' , ' ' ) ;
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 ) ) | |
( NT_STATUS_IS_OK ( smb_probe_module ( " vfs " , module_name ) ) & &
( 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 ) ) ;
SAFE_FREE ( module_name ) ;
return False ;
}
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 ) ) ;
SAFE_FREE ( module_name ) ;
return False ;
}
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 ) {
DEBUG ( 0 , ( " talloc_zero() failed! \n " ) ) ;
SAFE_FREE ( module_name ) ;
return False ;
}
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
* will be overridded here .
*/
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
2003-05-12 03:34:18 +04:00
SAFE_FREE ( module_name ) ;
2002-03-27 06:00:39 +03:00
return True ;
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 ;
}
ext = TALLOC_ZERO ( handle - > conn - > mem_ctx ,
sizeof ( struct vfs_fsp_data ) + ext_size ) ;
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 ;
}
}
}
void * vfs_fetch_fsp_extension ( vfs_handle_struct * handle , files_struct * fsp )
{
struct vfs_fsp_data * head ;
for ( head = fsp - > vfs_extension ; head ; head = head - > next ) {
if ( head - > owner = = handle ) {
return EXT_DATA_AREA ( head ) ;
}
}
return NULL ;
}
# undef EXT_DATA_AREA
2001-06-30 02:32:24 +04:00
/*****************************************************************
Generic VFS init .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-10-18 04:27:20 +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
2001-07-04 11:15:53 +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 ;
BOOL ret ;
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-10-03 06:12:14 +04:00
/*******************************************************************
2001-07-04 11:15:53 +04:00
vfs mkdir wrapper
2000-10-03 06:12:14 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-05-12 03:34:18 +04:00
int vfs_MkDir ( connection_struct * conn , const char * name , mode_t mode )
2000-10-03 06:12:14 +04:00
{
int ret ;
SMB_STRUCT_STAT sbuf ;
2003-05-14 14:59:01 +04:00
if ( ! ( ret = SMB_VFS_MKDIR ( conn , name , mode ) ) ) {
2002-10-23 05:22:32 +04:00
inherit_access_acl ( conn , name , mode ) ;
2000-11-15 00:56:32 +03:00
/*
2000-10-03 06:12:14 +04:00
* 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 ) & &
2003-05-14 14:59:01 +04:00
! SMB_VFS_STAT ( conn , name , & sbuf ) & & ( mode & ~ sbuf . st_mode ) )
SMB_VFS_CHMOD ( conn , name , sbuf . st_mode | ( mode & ~ sbuf . st_mode ) ) ;
2000-10-03 06:12:14 +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
2002-01-05 00:11:35 +03: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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-03-19 05:32:39 +03: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 )
{
2005-07-08 08:51:27 +04:00
ssize_t ret = SMB_VFS_PREAD ( fsp , fsp - > fh - > fd , 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
2001-07-04 11:15:53 +04:00
ssize_t vfs_write_data ( 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
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
}
2004-01-06 04:22:14 +03:00
ssize_t vfs_pwrite_data ( files_struct * fsp , const char * buffer ,
size_t N , SMB_OFF_T offset )
{
size_t total = 0 ;
ssize_t ret ;
while ( total < N ) {
2005-07-08 08:51:27 +04:00
ret = SMB_VFS_PWRITE ( fsp , fsp - > fh - > fd , buffer + total ,
2004-01-06 04:22:14 +03:00
N - total , offset + total ) ;
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 ) ) ;
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 ) ;
2005-07-08 08:51:27 +04: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 ) ;
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 ) ) ;
2005-07-08 08:51:27 +04:00
pwrite_ret = SMB_VFS_PWRITE ( fsp , fsp - > fh - > fd , 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
2004-11-10 01:49:28 +03:00
ptr = SMB_VFS_READDIR ( conn , 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 ;
static pstring LastDir = " " ;
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 ) ;
2000-09-27 23:09:59 +04:00
if ( ! res )
pstrcpy ( LastDir , path ) ;
return ( res ) ;
}
/* number of list structures for a caching GetWd function. */
# define MAX_GETWDCACHE (50)
2002-07-15 14:35:28 +04:00
static struct {
2002-03-27 06:00:39 +03:00
SMB_DEV_T dev ; /* These *must* be compatible with the types returned in a stat() call. */
SMB_INO_T inode ; /* These *must* be compatible with the types returned in a stat() call. */
char * dos_path ; /* The pathname in DOS format. */
BOOL valid ;
2000-09-27 23:09:59 +04:00
} ino_list [ MAX_GETWDCACHE ] ;
extern BOOL use_getwd_cache ;
/****************************************************************************
Prompte a ptr ( to make it recently used )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void array_promote ( char * array , int elsize , int element )
{
char * p ;
if ( element = = 0 )
return ;
2004-12-07 21:25:53 +03:00
p = ( char * ) SMB_MALLOC ( elsize ) ;
2000-09-27 23:09:59 +04:00
if ( ! p ) {
DEBUG ( 5 , ( " array_promote: malloc fail \n " ) ) ;
return ;
}
memcpy ( p , array + element * elsize , elsize ) ;
memmove ( array + elsize , array , elsize * element ) ;
memcpy ( array , p , elsize ) ;
2001-09-17 15:25:41 +04:00
SAFE_FREE ( p ) ;
2000-09-27 23:09:59 +04:00
}
/*******************************************************************
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * vfs_GetWd ( connection_struct * conn , char * path )
{
2002-03-27 06:00:39 +03:00
pstring s ;
static BOOL getwd_cache_init = False ;
SMB_STRUCT_STAT st , st2 ;
int i ;
* s = 0 ;
if ( ! use_getwd_cache )
2003-05-14 14:59:01 +04:00
return ( SMB_VFS_GETWD ( conn , path ) ) ;
2002-03-27 06:00:39 +03:00
/* init the cache */
if ( ! getwd_cache_init ) {
getwd_cache_init = True ;
for ( i = 0 ; i < MAX_GETWDCACHE ; i + + ) {
string_set ( & ino_list [ i ] . dos_path , " " ) ;
ino_list [ i ] . valid = False ;
}
}
/* Get the inode of the current directory, if this doesn't work we're
in trouble : - ) */
2000-09-27 23:09:59 +04:00
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_STAT ( conn , " . " , & st ) = = - 1 ) {
2005-04-07 22:27:28 +04:00
/* Known to fail for root: the directory may be
* NFS - mounted and exported with root_squash ( so has no root access ) . */
DEBUG ( 1 , ( " vfs_GetWd: couldn't stat \" . \" path=%s error %s (NFS problem ?) \n " , path , strerror ( errno ) ) ) ;
2003-05-14 14:59:01 +04:00
return ( SMB_VFS_GETWD ( conn , path ) ) ;
2002-03-27 06:00:39 +03:00
}
2000-09-27 23:09:59 +04:00
2002-03-27 06:00:39 +03:00
for ( i = 0 ; i < MAX_GETWDCACHE ; i + + ) {
if ( ino_list [ i ] . valid ) {
/* If we have found an entry with a matching inode and dev number
then find the inode number for the directory in the cached string .
If this agrees with that returned by the stat for the current
directory then all is o . k . ( but make sure it is a directory all
the same . . . ) */
if ( st . st_ino = = ino_list [ i ] . inode & & st . st_dev = = ino_list [ i ] . dev ) {
2003-05-14 14:59:01 +04:00
if ( SMB_VFS_STAT ( conn , ino_list [ i ] . dos_path , & st2 ) = = 0 ) {
2002-03-27 06:00:39 +03:00
if ( st . st_ino = = st2 . st_ino & & st . st_dev = = st2 . st_dev & &
( st2 . st_mode & S_IFMT ) = = S_IFDIR ) {
pstrcpy ( path , ino_list [ i ] . dos_path ) ;
/* promote it for future use */
array_promote ( ( char * ) & ino_list [ 0 ] , sizeof ( ino_list [ 0 ] ) , i ) ;
return ( path ) ;
} else {
/* If the inode is different then something's changed,
scrub the entry and start from scratch . */
ino_list [ i ] . valid = False ;
}
}
}
}
}
2000-09-27 23:09:59 +04:00
2002-03-27 06:00:39 +03:00
/* 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
2003-05-14 14:59:01 +04:00
if ( ! SMB_VFS_GETWD ( conn , s ) ) {
DEBUG ( 0 , ( " vfs_GetWd: SMB_VFS_GETWD call failed, errno %s \n " , strerror ( errno ) ) ) ;
2002-03-27 06:00:39 +03:00
return ( NULL ) ;
}
2000-09-27 23:09:59 +04:00
2002-03-27 06:00:39 +03:00
pstrcpy ( path , s ) ;
2000-09-27 23:09:59 +04:00
2002-03-27 06:00:39 +03:00
DEBUG ( 5 , ( " vfs_GetWd %s, inode %.0f, dev %.0f \n " , s , ( double ) st . st_ino , ( double ) st . st_dev ) ) ;
2000-09-27 23:09:59 +04:00
2002-03-27 06:00:39 +03:00
/* add it to the cache */
i = MAX_GETWDCACHE - 1 ;
string_set ( & ino_list [ i ] . dos_path , s ) ;
ino_list [ i ] . dev = st . st_dev ;
ino_list [ i ] . inode = st . st_ino ;
ino_list [ i ] . valid = True ;
/* put it at the top of the list */
array_promote ( ( char * ) & ino_list [ 0 ] , sizeof ( ino_list [ 0 ] ) , i ) ;
return ( path ) ;
2000-09-27 23:09:59 +04:00
}
2004-05-28 05:54:01 +04:00
BOOL canonicalize_path ( connection_struct * conn , pstring path )
{
# ifdef REALPATH_TAKES_NULL
char * resolved_name = SMB_VFS_REALPATH ( conn , path , NULL ) ;
if ( ! resolved_name ) {
return False ;
}
pstrcpy ( path , resolved_name ) ;
SAFE_FREE ( resolved_name ) ;
return True ;
# else
# ifdef PATH_MAX
char resolved_name_buf [ PATH_MAX + 1 ] ;
# else
pstring resolved_name_buf ;
# endif
char * resolved_name = SMB_VFS_REALPATH ( conn , path , resolved_name_buf ) ;
if ( ! resolved_name ) {
return False ;
}
pstrcpy ( path , resolved_name ) ;
return True ;
# endif /* REALPATH_TAKES_NULL */
}
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-08-17 22:59:13 +04:00
BOOL reduce_name ( connection_struct * conn , const pstring fname )
2000-09-27 23:09:59 +04:00
{
2004-05-13 04:20:50 +04:00
# ifdef REALPATH_TAKES_NULL
BOOL free_resolved_name = True ;
2000-09-27 23:09:59 +04:00
# else
2004-05-13 04:20:50 +04:00
# ifdef PATH_MAX
char resolved_name_buf [ PATH_MAX + 1 ] ;
# else
pstring resolved_name_buf ;
# endif
BOOL free_resolved_name = False ;
# endif
char * resolved_name = NULL ;
size_t con_path_len = strlen ( conn - > connectpath ) ;
char * p = NULL ;
2004-06-11 21:54:23 +04:00
int saved_errno = errno ;
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 ) ) ;
2004-06-11 21:54:23 +04:00
errno = saved_errno ;
2004-05-13 04:20:50 +04:00
return False ;
case ENOENT :
{
pstring tmp_fname ;
fstring last_component ;
/* Last component didn't exist. Remove it and try and canonicalise the directory. */
pstrcpy ( tmp_fname , fname ) ;
p = strrchr_m ( tmp_fname , ' / ' ) ;
if ( p ) {
* p + + = ' \0 ' ;
fstrcpy ( last_component , p ) ;
2004-05-13 04:56:00 +04:00
} else {
fstrcpy ( last_component , tmp_fname ) ;
pstrcpy ( tmp_fname , " . " ) ;
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 ) ) ;
2004-06-11 21:54:23 +04:00
errno = saved_errno ;
2004-05-13 04:20:50 +04:00
return False ;
}
pstrcpy ( tmp_fname , resolved_name ) ;
pstrcat ( tmp_fname , " / " ) ;
pstrcat ( tmp_fname , last_component ) ;
# 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 ) ) ;
2004-06-11 21:54:23 +04:00
errno = saved_errno ;
2004-05-13 04:20:50 +04:00
return False ;
}
# else
# ifdef PATH_MAX
safe_strcpy ( resolved_name_buf , tmp_fname , PATH_MAX ) ;
# else
2005-04-21 05:46:18 +04:00
pstrcpy ( resolved_name_buf , tmp_fname ) ;
2004-05-13 04:20:50 +04:00
# endif
resolved_name = resolved_name_buf ;
# endif
break ;
}
default :
DEBUG ( 1 , ( " reduce_name: couldn't get realpath for %s \n " , fname ) ) ;
2004-11-18 00:05:47 +03:00
/* Don't restore the saved errno. We need to return the error that
realpath caused here as it was not one of the cases we handle . JRA . */
2004-05-13 04:20:50 +04:00
return False ;
}
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 " ) ) ;
if ( free_resolved_name )
SAFE_FREE ( resolved_name ) ;
2004-06-11 21:54:23 +04:00
errno = saved_errno ;
2004-05-13 04:20:50 +04:00
return False ;
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 ) ) ;
2004-05-13 04:20:50 +04:00
if ( free_resolved_name )
SAFE_FREE ( resolved_name ) ;
2004-06-11 21:54:23 +04:00
errno = EACCES ;
2004-05-13 04:20:50 +04:00
return False ;
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 */
# 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 ) ) ) {
if ( free_resolved_name )
SAFE_FREE ( resolved_name ) ;
DEBUG ( 3 , ( " reduce_name: denied: file path name %s is a symlink \n " , resolved_name ) ) ;
errno = EACCES ;
return False ;
}
}
# 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 ) ) ;
2004-05-13 04:20:50 +04:00
if ( free_resolved_name )
SAFE_FREE ( resolved_name ) ;
2004-06-11 21:54:23 +04:00
errno = saved_errno ;
2002-03-27 06:00:39 +03:00
return ( True ) ;
2000-09-27 23:09:59 +04:00
}