2000-11-15 00:56:32 +03:00
/*
2000-02-03 08:10:09 +03:00
Unix SMB / Netbios implementation .
2001-07-04 11:15:53 +04:00
Version 3.0
2000-02-03 08:10:09 +03:00
VFS initialisation and support functions
Copyright ( C ) Tim Potter 1999
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 .
*/
# include "includes.h"
extern int DEBUGLEVEL ;
/* Some structures to help us initialise the vfs operations table */
struct vfs_syminfo {
2000-10-06 22:13:52 +04:00
char * name ;
void * fptr ;
2000-02-03 08:10:09 +03:00
} ;
/* Default vfs hooks. WARNING: The order of these initialisers is
very important . They must be in the same order as defined in
vfs . h . Change at your own peril . */
struct vfs_ops default_vfs_ops = {
2000-11-15 00:56:32 +03:00
/* Disk operations */
2000-10-06 22:13:52 +04:00
vfswrap_dummy_connect ,
vfswrap_dummy_disconnect ,
vfswrap_disk_free ,
/* Directory operations */
vfswrap_opendir ,
vfswrap_readdir ,
vfswrap_mkdir ,
vfswrap_rmdir ,
vfswrap_closedir ,
/* File operations */
vfswrap_open ,
vfswrap_close ,
vfswrap_read ,
vfswrap_write ,
vfswrap_lseek ,
vfswrap_rename ,
vfswrap_fsync ,
vfswrap_stat ,
vfswrap_fstat ,
vfswrap_lstat ,
vfswrap_unlink ,
vfswrap_chmod ,
2001-04-14 04:19:12 +04:00
vfswrap_fchmod ,
2000-10-06 22:13:52 +04:00
vfswrap_chown ,
2001-04-14 04:19:12 +04:00
vfswrap_fchown ,
2000-10-06 22:13:52 +04:00
vfswrap_chdir ,
vfswrap_getwd ,
vfswrap_utime ,
vfswrap_ftruncate ,
vfswrap_lock ,
2001-06-30 02:32:24 +04:00
vfswrap_symlink ,
vfswrap_readlink ,
2000-10-06 22:13:52 +04:00
vfswrap_fget_nt_acl ,
vfswrap_get_nt_acl ,
vfswrap_fset_nt_acl ,
2001-01-23 04:52:30 +03:00
vfswrap_set_nt_acl ,
2001-03-26 09:43:04 +04:00
# if defined(HAVE_NO_ACLS)
NULL ,
NULL
# else
2001-01-23 04:52:30 +03:00
vfswrap_chmod_acl ,
vfswrap_fchmod_acl
2001-03-26 09:43:04 +04:00
# endif
2000-02-03 08:10:09 +03:00
} ;
/****************************************************************************
initialise default vfs hooks
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-06-30 02:32:24 +04:00
static BOOL vfs_init_default ( connection_struct * conn )
2000-02-03 08:10:09 +03:00
{
DEBUG ( 3 , ( " Initialising default vfs hooks \n " ) ) ;
2000-10-06 07:21:49 +04:00
memcpy ( & conn - > vfs_ops , & default_vfs_ops , sizeof ( struct vfs_ops ) ) ;
2000-02-03 08:10:09 +03:00
return True ;
}
/****************************************************************************
initialise custom vfs hooks
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-07-10 10:41:04 +04:00
2000-02-03 08:10:09 +03:00
# ifdef HAVE_LIBDL
2001-06-30 02:32:24 +04:00
static BOOL vfs_init_custom ( connection_struct * conn )
2000-02-03 08:10:09 +03:00
{
2000-11-07 00:44:33 +03:00
int vfs_version = - 1 ;
2001-07-04 11:15:53 +04:00
struct vfs_ops * ops , * ( * init_fptr ) ( int * , struct vfs_ops * ) ;
2000-02-03 08:10:09 +03:00
2001-07-04 11:15:53 +04:00
DEBUG ( 3 , ( " Initialising custom vfs hooks from %s \n " ,
lp_vfsobj ( SNUM ( conn ) ) ) ) ;
2000-02-03 08:10:09 +03:00
2001-07-04 11:15:53 +04:00
/* Open object file */
if ( ( conn - > dl_handle = sys_dlopen ( lp_vfsobj ( SNUM ( conn ) ) ,
RTLD_NOW | RTLD_GLOBAL ) ) = = NULL ) {
2001-07-06 22:45:59 +04:00
DEBUG ( 0 , ( " Error opening %s: %s \n " , lp_vfsobj ( SNUM ( conn ) ) , sys_dlerror ( ) ) ) ;
2000-10-06 07:21:49 +04:00
return False ;
2001-07-04 11:15:53 +04:00
}
2000-02-03 08:10:09 +03:00
2001-07-04 11:15:53 +04:00
/* Get handle on vfs_init() symbol */
init_fptr = ( struct vfs_ops * ( * ) ( int * , struct vfs_ops * ) ) sys_dlsym ( conn - > dl_handle , " vfs_init " ) ;
2000-02-03 08:10:09 +03:00
2001-07-04 11:15:53 +04:00
if ( init_fptr = = NULL ) {
2000-11-15 00:56:32 +03:00
DEBUG ( 0 , ( " No vfs_init() symbol found in %s \n " ,
2001-07-04 11:15:53 +04:00
lp_vfsobj ( SNUM ( conn ) ) ) ) ;
2000-11-07 00:44:33 +03:00
return False ;
2001-07-04 11:15:53 +04:00
}
2000-02-03 08:10:09 +03:00
2001-07-04 11:15:53 +04:00
/* Initialise vfs_ops structure */
conn - > vfs_ops = default_vfs_ops ;
2000-02-03 08:10:09 +03:00
2001-07-04 11:15:53 +04:00
if ( ( ops = init_fptr ( & vfs_version , & conn - > vfs_ops ) ) = = NULL ) {
DEBUG ( 0 , ( " vfs_init function from %s failed \n " , lp_vfsobj ( SNUM ( conn ) ) ) ) ;
2000-11-07 00:44:33 +03:00
return False ;
2001-07-04 11:15:53 +04:00
}
2000-11-07 00:44:33 +03:00
if ( vfs_version ! = SMB_VFS_INTERFACE_VERSION ) {
DEBUG ( 0 , ( " vfs_init returned wrong interface version info (was %d, should be %d) \n " ,
2001-07-04 11:15:53 +04:00
vfs_version , SMB_VFS_INTERFACE_VERSION ) ) ;
2000-11-07 00:44:33 +03:00
return False ;
}
2001-07-04 11:15:53 +04:00
if ( ops ! = & conn - > vfs_ops ) {
memcpy ( & conn - > vfs_ops , ops , sizeof ( struct vfs_ops ) ) ;
}
2000-11-07 00:44:33 +03:00
2001-07-04 11:15:53 +04:00
return True ;
2000-02-03 08:10:09 +03:00
}
# endif
2001-06-30 02:32:24 +04:00
/*****************************************************************
Generic VFS init .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL vfs_init ( connection_struct * conn )
{
if ( * lp_vfsobj ( SNUM ( conn ) ) ) {
# ifdef HAVE_LIBDL
/* Loadable object file */
if ( ! vfs_init_custom ( conn ) ) {
DEBUG ( 0 , ( " vfs_init: vfs_init_custom failed \n " ) ) ;
return False ;
}
return True ;
# else
DEBUG ( 0 , ( " vfs_init: No libdl present - cannot use VFS objects \n " ) ) ;
return False ;
# endif
}
/* Normal share - initialise with disk access functions */
return vfs_init_default ( conn ) ;
}
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
2000-11-15 00:56:32 +03:00
if ( 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 ;
}
/*******************************************************************
vfs getwd wrapper
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * vfs_getwd ( connection_struct * conn , char * path )
{
return conn - > vfs_ops . getwd ( conn , path ) ;
2000-02-03 08:10:09 +03:00
}
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-07-04 11:15:53 +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 ;
2000-10-06 07:21:49 +04:00
if ( ! ( ret = conn - > vfs_ops . mkdir ( 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 ) & &
! vfs_stat ( conn , name , & sbuf ) & & ( mode & ~ sbuf . st_mode ) )
vfs_chmod ( conn , name , sbuf . st_mode | ( mode & ~ sbuf . st_mode ) ) ;
}
return ret ;
}
2000-09-27 23:09:59 +04:00
/*******************************************************************
Check if a vfs file exists .
2000-02-03 08:10:09 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-09-27 23:09:59 +04:00
2001-07-04 11:15:53 +04:00
BOOL vfs_file_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
if ( vfs_stat ( conn , fname , sbuf ) ! = 0 )
2000-09-27 23:09:59 +04:00
return ( False ) ;
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 )
{
ssize_t ret = fsp - > conn - > vfs_ops . read ( fsp , fsp - > fd , buf + total ,
byte_count - 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
{
size_t total = 0 ;
ssize_t ret ;
while ( total < N )
{
2000-10-06 07:21:49 +04:00
ret = fsp - > conn - > vfs_ops . write ( fsp , fsp - > fd , buffer + total , N - total ) ;
2000-02-03 08:10:09 +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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int vfs_allocate_file_space ( files_struct * fsp , SMB_OFF_T len )
{
int ret ;
SMB_STRUCT_STAT st ;
struct vfs_ops * vfs_ops = & fsp - > conn - > vfs_ops ;
if ( ! lp_strict_allocate ( SNUM ( fsp - > conn ) ) )
return vfs_set_filelen ( fsp , len ) ;
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 ) ) ;
ret = vfs_fstat ( fsp , fsp - > fd , & st ) ;
if ( ret = = - 1 )
return ret ;
if ( len = = st . st_size )
return 0 ;
if ( len < st . st_size ) {
/* Shrink - use ftruncate. */
DEBUG ( 10 , ( " vfs_allocate_file_space: file %s, shrink. Current size %.0f \n " ,
fsp - > fsp_name , ( double ) st . st_size ) ) ;
if ( ( ret = vfs_ops - > ftruncate ( fsp , fsp - > fd , len ) ) ! = - 1 ) {
set_filelen_write_cache ( fsp , len ) ;
}
return ret ;
}
/* Grow - we need to write out the space.... */
{
static unsigned char zero_space [ 65536 ] ;
SMB_OFF_T start_pos = st . st_size ;
SMB_OFF_T len_to_write = len - st . st_size ;
SMB_OFF_T retlen ;
DEBUG ( 10 , ( " vfs_allocate_file_space: file %s, grow. Current size %.0f \n " ,
fsp - > fsp_name , ( double ) st . st_size ) ) ;
if ( ( retlen = vfs_ops - > lseek ( fsp , fsp - > fd , start_pos , SEEK_SET ) ) ! = start_pos )
return - 1 ;
while ( len_to_write > 0 ) {
SMB_OFF_T current_len_to_write = MIN ( sizeof ( zero_space ) , len_to_write ) ;
2001-08-25 00:32:01 +04:00
retlen = vfs_ops - > write ( fsp , fsp - > fd , ( const char * ) zero_space , current_len_to_write ) ;
2001-08-06 23:21:23 +04:00
if ( retlen < = 0 ) {
2001-08-02 02:13:50 +04:00
/* Write fail - return to original size. */
int save_errno = errno ;
fsp - > conn - > vfs_ops . ftruncate ( fsp , fsp - > fd , st . st_size ) ;
errno = save_errno ;
2001-08-04 04:24:54 +04:00
DEBUG ( 10 , ( " vfs_allocate_file_space: file %s, grow. write fail %s \n " ,
fsp - > fsp_name , strerror ( errno ) ) ) ;
2001-08-02 02:13:50 +04:00
return - 1 ;
}
DEBUG ( 10 , ( " vfs_allocate_file_space: file %s, grow. wrote %.0f \n " ,
2001-08-07 04:36:10 +04:00
fsp - > fsp_name , ( double ) retlen ) ) ;
2001-08-02 02:13:50 +04:00
2001-08-06 23:21:23 +04:00
len_to_write - = retlen ;
2001-08-02 02:13:50 +04:00
}
set_filelen_write_cache ( fsp , len ) ;
}
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-08-02 02:13:50 +04:00
if ( ( ret = fsp - > conn - > vfs_ops . ftruncate ( fsp , fsp - > fd , len ) ) ! = - 1 )
2000-11-16 03:59:18 +03:00
set_filelen_write_cache ( fsp , len ) ;
return ret ;
}
2000-02-03 08:10:09 +03:00
/****************************************************************************
2000-09-27 23:09:59 +04:00
Transfer some data between two file_struct ' s .
2000-02-03 08:10:09 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-09-27 23:09:59 +04:00
2000-11-15 00:56:32 +03:00
SMB_OFF_T vfs_transfer_file ( int in_fd , files_struct * in_fsp ,
2000-02-03 08:10:09 +03:00
int out_fd , files_struct * out_fsp ,
SMB_OFF_T n , char * header , int headlen , int align )
{
2000-11-15 00:56:32 +03:00
static char * buf = NULL ;
2000-02-03 08:10:09 +03:00
static int size = 0 ;
char * buf1 , * abuf ;
SMB_OFF_T total = 0 ;
DEBUG ( 4 , ( " vfs_transfer_file n=%.0f (head=%d) called \n " , ( double ) n , headlen ) ) ;
/* Check we have at least somewhere to read from */
SMB_ASSERT ( ( in_fd ! = - 1 ) | | ( in_fsp ! = NULL ) ) ;
if ( size = = 0 ) {
size = lp_readsize ( ) ;
size = MAX ( size , 1024 ) ;
}
while ( ! buf & & size > 0 ) {
buf = ( char * ) Realloc ( buf , size + 8 ) ;
if ( ! buf ) size / = 2 ;
}
if ( ! buf ) {
DEBUG ( 0 , ( " Can't allocate transfer buffer! \n " ) ) ;
exit ( 1 ) ;
}
abuf = buf + ( align % 8 ) ;
if ( header )
n + = headlen ;
while ( n > 0 )
{
int s = ( int ) MIN ( n , ( SMB_OFF_T ) size ) ;
int ret , ret2 = 0 ;
ret = 0 ;
if ( header & & ( headlen > = MIN ( s , 1024 ) ) ) {
buf1 = header ;
s = headlen ;
ret = headlen ;
headlen = 0 ;
header = NULL ;
} else {
buf1 = abuf ;
}
if ( header & & headlen > 0 )
{
ret = MIN ( headlen , size ) ;
memcpy ( buf1 , header , ret ) ;
headlen - = ret ;
header + = ret ;
if ( headlen < = 0 ) header = NULL ;
}
if ( s > ret ) {
2000-11-15 00:56:32 +03:00
ret + = in_fsp ?
2000-10-06 07:21:49 +04:00
in_fsp - > conn - > vfs_ops . read ( in_fsp , in_fsp - > fd , buf1 + ret , s - ret ) : read ( in_fd , buf1 + ret , s - ret ) ;
2000-02-03 08:10:09 +03:00
}
2000-10-06 07:21:49 +04:00
if ( ret > 0 ) {
if ( out_fsp )
ret2 = out_fsp - > conn - > vfs_ops . write ( out_fsp , out_fsp - > fd , buf1 , ret ) ;
else
ret2 = ( out_fd ! = - 1 ) ? write_data ( out_fd , buf1 , ret ) : ret ;
2000-02-03 08:10:09 +03:00
}
if ( ret2 > 0 ) total + = ret2 ;
/* if we can't write then dump excess data */
if ( ret2 ! = ret )
vfs_transfer_file ( in_fd , in_fsp , - 1 , NULL , n - ( ret + headlen ) , NULL , 0 , 0 ) ;
if ( ret < = 0 | | ret2 ! = ret )
return ( total ) ;
n - = ret ;
}
return ( total ) ;
}
/*******************************************************************
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 )
{
struct dirent * ptr ;
char * dname ;
2000-09-27 23:09:59 +04:00
if ( ! p )
return ( NULL ) ;
2000-11-15 00:56:32 +03:00
2000-10-06 07:21:49 +04:00
ptr = ( struct dirent * ) conn - > vfs_ops . 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
# ifdef HAVE_BROKEN_READDIR
/* using /usr/ucb/cc is BAD */
dname = dname - 2 ;
# endif
return ( dname ) ;
}
2000-02-04 08:18:06 +03:00
/* VFS options not quite working yet */
#if 0
2000-02-03 08:10:09 +03:00
/***************************************************************************
handle the interpretation of the vfs option parameter
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL handle_vfs_option ( char * pszParmValue , char * * ptr )
{
struct vfs_options * new_option , * * options = ( struct vfs_options * * ) ptr ;
int i ;
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
/* Create new vfs option */
new_option = ( struct vfs_options * ) malloc ( sizeof ( * new_option ) ) ;
if ( new_option = = NULL ) {
return False ;
}
ZERO_STRUCTP ( new_option ) ;
/* Get name and value */
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
new_option - > name = strtok ( pszParmValue , " = " ) ;
if ( new_option - > name = = NULL ) {
return False ;
}
while ( isspace ( * new_option - > name ) ) {
new_option - > name + + ;
}
for ( i = strlen ( new_option - > name ) ; i > 0 ; i - - ) {
if ( ! isspace ( new_option - > name [ i - 1 ] ) ) break ;
}
new_option - > name [ i ] = ' \0 ' ;
new_option - > name = strdup ( new_option - > name ) ;
new_option - > value = strtok ( NULL , " = " ) ;
if ( new_option - > value ! = NULL ) {
while ( isspace ( * new_option - > value ) ) {
new_option - > value + + ;
}
for ( i = strlen ( new_option - > value ) ; i > 0 ; i - - ) {
if ( ! isspace ( new_option - > value [ i - 1 ] ) ) break ;
}
new_option - > value [ i ] = ' \0 ' ;
new_option - > value = strdup ( new_option - > value ) ;
}
/* Add to list */
DLIST_ADD ( * options , new_option ) ;
return True ;
}
2000-02-04 08:18:06 +03:00
# endif
2000-09-27 23:09:59 +04:00
/*******************************************************************
A wrapper for vfs_chdir ( ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int vfs_ChDir ( connection_struct * conn , char * path )
{
int res ;
static pstring LastDir = " " ;
if ( strcsequal ( path , " . " ) )
return ( 0 ) ;
if ( * path = = ' / ' & & strcsequal ( LastDir , path ) )
return ( 0 ) ;
DEBUG ( 3 , ( " vfs_ChDir to %s \n " , path ) ) ;
res = vfs_chdir ( conn , path ) ;
if ( ! res )
pstrcpy ( LastDir , path ) ;
return ( res ) ;
}
/* number of list structures for a caching GetWd function. */
# define MAX_GETWDCACHE (50)
struct
{
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 ;
} 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 ;
p = ( char * ) malloc ( elsize ) ;
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 ) ;
free ( p ) ;
}
/*******************************************************************
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 )
{
pstring s ;
static BOOL getwd_cache_init = False ;
SMB_STRUCT_STAT st , st2 ;
int i ;
* s = 0 ;
if ( ! use_getwd_cache )
return ( vfs_getwd ( conn , path ) ) ;
/* 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 : - ) */
if ( vfs_stat ( conn , " . " , & st ) = = - 1 )
{
DEBUG ( 0 , ( " Very strange, couldn't stat \" . \" path=%s \n " , path ) ) ;
return ( vfs_getwd ( conn , path ) ) ;
}
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 )
{
if ( vfs_stat ( conn , ino_list [ i ] . dos_path , & st2 ) = = 0 )
{
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 ;
}
}
}
}
/* 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 . */
if ( ! vfs_getwd ( conn , s ) )
{
DEBUG ( 0 , ( " vfs_GetWd: vfs_getwd call failed, errno %s \n " , strerror ( errno ) ) ) ;
return ( NULL ) ;
}
pstrcpy ( path , s ) ;
DEBUG ( 5 , ( " vfs_GetWd %s, inode %.0f, dev %.0f \n " , s , ( double ) st . st_ino , ( double ) st . st_dev ) ) ;
/* 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-11-15 00:56:32 +03:00
Reduce a file name , removing . . elements and checking that
2000-09-27 23:09:59 +04:00
it is below dir in the heirachy . This uses vfs_GetWd ( ) and so must be run
on the system that has the referenced file system .
Widelinks are allowed if widelinks is true .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL reduce_name ( connection_struct * conn , char * s , char * dir , BOOL widelinks )
{
# ifndef REDUCE_PATHS
return True ;
# else
pstring dir2 ;
pstring wd ;
pstring base_name ;
pstring newname ;
char * p = NULL ;
BOOL relative = ( * s ! = ' / ' ) ;
* dir2 = * wd = * base_name = * newname = 0 ;
if ( widelinks )
{
unix_clean_name ( s ) ;
/* can't have a leading .. */
if ( strncmp ( s , " .. " , 2 ) = = 0 & & ( s [ 2 ] = = 0 | | s [ 2 ] = = ' / ' ) )
{
DEBUG ( 3 , ( " Illegal file name? (%s) \n " , s ) ) ;
return ( False ) ;
}
if ( strlen ( s ) = = 0 )
pstrcpy ( s , " ./ " ) ;
return ( True ) ;
}
2000-11-15 00:56:32 +03:00
2000-09-27 23:09:59 +04:00
DEBUG ( 3 , ( " reduce_name [%s] [%s] \n " , s , dir ) ) ;
/* remove any double slashes */
all_string_sub ( s , " // " , " / " , 0 ) ;
pstrcpy ( base_name , s ) ;
2001-07-04 11:36:09 +04:00
p = strrchr_m ( base_name , ' / ' ) ;
2000-09-27 23:09:59 +04:00
if ( ! p )
return ( True ) ;
if ( ! vfs_GetWd ( conn , wd ) )
{
DEBUG ( 0 , ( " couldn't vfs_GetWd for %s %s \n " , s , dir ) ) ;
return ( False ) ;
}
if ( vfs_ChDir ( conn , dir ) ! = 0 )
{
DEBUG ( 0 , ( " couldn't vfs_ChDir to %s \n " , dir ) ) ;
return ( False ) ;
}
if ( ! vfs_GetWd ( conn , dir2 ) )
{
DEBUG ( 0 , ( " couldn't vfs_GetWd for %s \n " , dir ) ) ;
vfs_ChDir ( conn , wd ) ;
return ( False ) ;
}
if ( p & & ( p ! = base_name ) )
{
* p = 0 ;
if ( strcmp ( p + 1 , " . " ) = = 0 )
p [ 1 ] = 0 ;
if ( strcmp ( p + 1 , " .. " ) = = 0 )
* p = ' / ' ;
}
if ( vfs_ChDir ( conn , base_name ) ! = 0 )
{
vfs_ChDir ( conn , wd ) ;
DEBUG ( 3 , ( " couldn't vfs_ChDir for %s %s basename=%s \n " , s , dir , base_name ) ) ;
return ( False ) ;
}
if ( ! vfs_GetWd ( conn , newname ) )
{
vfs_ChDir ( conn , wd ) ;
DEBUG ( 2 , ( " couldn't get vfs_GetWd for %s %s \n " , s , dir2 ) ) ;
return ( False ) ;
}
if ( p & & ( p ! = base_name ) )
{
pstrcat ( newname , " / " ) ;
pstrcat ( newname , p + 1 ) ;
}
{
2000-11-15 00:56:32 +03:00
size_t l = strlen ( dir2 ) ;
2000-09-27 23:09:59 +04:00
if ( dir2 [ l - 1 ] = = ' / ' )
l - - ;
if ( strncmp ( newname , dir2 , l ) ! = 0 )
{
vfs_ChDir ( conn , wd ) ;
DEBUG ( 2 , ( " Bad access attempt? s=%s dir=%s newname=%s l=%d \n " , s , dir2 , newname , ( int ) l ) ) ;
return ( False ) ;
}
if ( relative )
{
if ( newname [ l ] = = ' / ' )
pstrcpy ( s , newname + l + 1 ) ;
else
pstrcpy ( s , newname + l ) ;
}
else
pstrcpy ( s , newname ) ;
}
vfs_ChDir ( conn , wd ) ;
if ( strlen ( s ) = = 0 )
pstrcpy ( s , " ./ " ) ;
DEBUG ( 3 , ( " reduced to %s \n " , s ) ) ;
return ( True ) ;
# endif
}