2000-11-15 00:56:32 +03:00
/*
2000-02-03 08:10:09 +03:00
Unix SMB / Netbios implementation .
Version 1.9 .
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 ,
vfswrap_chown ,
vfswrap_chdir ,
vfswrap_getwd ,
vfswrap_utime ,
vfswrap_ftruncate ,
vfswrap_lock ,
vfswrap_fget_nt_acl ,
vfswrap_get_nt_acl ,
vfswrap_fset_nt_acl ,
vfswrap_set_nt_acl
2000-02-03 08:10:09 +03:00
} ;
/****************************************************************************
initialise default vfs hooks
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int vfs_init_default ( connection_struct * conn )
{
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
BOOL vfs_init_custom ( connection_struct * conn )
{
2000-11-07 00:44:33 +03:00
int vfs_version = - 1 ;
struct vfs_ops * ops , * ( * init_fptr ) ( int * ) ;
2000-02-03 08:10:09 +03:00
DEBUG ( 3 , ( " Initialising custom vfs hooks from %s \n " ,
lp_vfsobj ( SNUM ( conn ) ) ) ) ;
/* Open object file */
2000-10-06 07:21:49 +04:00
if ( ( conn - > dl_handle = dlopen ( lp_vfsobj ( SNUM ( conn ) ) , RTLD_NOW | RTLD_GLOBAL ) ) = = NULL ) {
DEBUG ( 0 , ( " Error opening %s: %s \n " , lp_vfsobj ( SNUM ( conn ) ) , dlerror ( ) ) ) ;
return False ;
2000-02-03 08:10:09 +03:00
}
/* Get handle on vfs_init() symbol */
2000-11-07 00:44:33 +03:00
init_fptr = ( struct vfs_ops * ( * ) ( int * ) ) dlsym ( conn - > dl_handle , " vfs_init " ) ;
2000-02-03 08:10:09 +03:00
2000-11-07 00:44:33 +03:00
if ( init_fptr = = NULL ) {
2000-11-15 00:56:32 +03:00
DEBUG ( 0 , ( " No vfs_init() symbol found in %s \n " ,
2000-02-03 08:10:09 +03:00
lp_vfsobj ( SNUM ( conn ) ) ) ) ;
2000-11-07 00:44:33 +03:00
return False ;
2000-02-03 08:10:09 +03:00
}
/* Initialise vfs_ops structure */
2000-11-07 00:44:33 +03:00
if ( ( ops = init_fptr ( & vfs_version ) ) = = NULL ) {
2000-02-03 08:10:09 +03:00
DEBUG ( 0 , ( " vfs_init function from %s failed \n " , lp_vfsobj ( SNUM ( conn ) ) ) ) ;
2000-11-07 00:44:33 +03:00
return False ;
2000-02-03 08:10:09 +03: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 " ,
vfs_version , SMB_VFS_INTERFACE_VERSION ) ) ;
return False ;
}
2000-02-03 08:10:09 +03:00
/* Fill in unused operations with default (disk based) ones.
There ' s probably a neater way to do this then a whole bunch of
2000-11-15 00:56:32 +03:00
if statements . */
2000-02-03 08:10:09 +03:00
2000-10-06 07:21:49 +04:00
memcpy ( & conn - > vfs_ops , ops , sizeof ( struct vfs_ops ) ) ;
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
if ( conn - > vfs_ops . connect = = NULL ) {
conn - > vfs_ops . connect = default_vfs_ops . connect ;
}
if ( conn - > vfs_ops . disconnect = = NULL ) {
conn - > vfs_ops . disconnect = default_vfs_ops . disconnect ;
}
if ( conn - > vfs_ops . disk_free = = NULL ) {
conn - > vfs_ops . disk_free = default_vfs_ops . disk_free ;
}
if ( conn - > vfs_ops . opendir = = NULL ) {
conn - > vfs_ops . opendir = default_vfs_ops . opendir ;
}
if ( conn - > vfs_ops . readdir = = NULL ) {
conn - > vfs_ops . readdir = default_vfs_ops . readdir ;
}
if ( conn - > vfs_ops . mkdir = = NULL ) {
conn - > vfs_ops . mkdir = default_vfs_ops . mkdir ;
}
if ( conn - > vfs_ops . rmdir = = NULL ) {
conn - > vfs_ops . rmdir = default_vfs_ops . rmdir ;
}
if ( conn - > vfs_ops . closedir = = NULL ) {
conn - > vfs_ops . closedir = default_vfs_ops . closedir ;
}
if ( conn - > vfs_ops . open = = NULL ) {
conn - > vfs_ops . open = default_vfs_ops . open ;
}
if ( conn - > vfs_ops . close = = NULL ) {
conn - > vfs_ops . close = default_vfs_ops . close ;
}
if ( conn - > vfs_ops . read = = NULL ) {
conn - > vfs_ops . read = default_vfs_ops . read ;
}
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
if ( conn - > vfs_ops . write = = NULL ) {
conn - > vfs_ops . write = default_vfs_ops . write ;
}
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
if ( conn - > vfs_ops . lseek = = NULL ) {
conn - > vfs_ops . lseek = default_vfs_ops . lseek ;
}
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
if ( conn - > vfs_ops . rename = = NULL ) {
conn - > vfs_ops . rename = default_vfs_ops . rename ;
}
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
if ( conn - > vfs_ops . fsync = = NULL ) {
conn - > vfs_ops . fsync = default_vfs_ops . fsync ;
}
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
if ( conn - > vfs_ops . stat = = NULL ) {
conn - > vfs_ops . stat = default_vfs_ops . stat ;
}
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
if ( conn - > vfs_ops . fstat = = NULL ) {
conn - > vfs_ops . fstat = default_vfs_ops . fstat ;
}
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
if ( conn - > vfs_ops . lstat = = NULL ) {
conn - > vfs_ops . lstat = default_vfs_ops . lstat ;
}
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
if ( conn - > vfs_ops . unlink = = NULL ) {
conn - > vfs_ops . unlink = default_vfs_ops . unlink ;
}
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
if ( conn - > vfs_ops . chmod = = NULL ) {
conn - > vfs_ops . chmod = default_vfs_ops . chmod ;
}
2000-11-15 00:56:32 +03:00
2000-09-27 23:09:59 +04:00
if ( conn - > vfs_ops . chown = = NULL ) {
conn - > vfs_ops . chown = default_vfs_ops . chown ;
}
2000-11-15 00:56:32 +03:00
2000-10-05 23:04:41 +04:00
if ( conn - > vfs_ops . chdir = = NULL ) {
conn - > vfs_ops . chdir = default_vfs_ops . chdir ;
}
if ( conn - > vfs_ops . getwd = = NULL ) {
conn - > vfs_ops . getwd = default_vfs_ops . getwd ;
}
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
if ( conn - > vfs_ops . utime = = NULL ) {
conn - > vfs_ops . utime = default_vfs_ops . utime ;
}
2000-11-15 00:56:32 +03:00
2000-04-22 04:33:16 +04:00
if ( conn - > vfs_ops . ftruncate = = NULL ) {
2000-05-02 07:20:47 +04:00
conn - > vfs_ops . ftruncate = default_vfs_ops . ftruncate ;
}
2000-11-15 00:56:32 +03:00
2000-05-02 07:20:47 +04:00
if ( conn - > vfs_ops . lock = = NULL ) {
conn - > vfs_ops . lock = default_vfs_ops . lock ;
2000-04-22 04:33:16 +04:00
}
2000-10-05 23:04:41 +04:00
if ( conn - > vfs_ops . fget_nt_acl = = NULL ) {
conn - > vfs_ops . fget_nt_acl = default_vfs_ops . fget_nt_acl ;
}
if ( conn - > vfs_ops . get_nt_acl = = NULL ) {
conn - > vfs_ops . get_nt_acl = default_vfs_ops . get_nt_acl ;
}
if ( conn - > vfs_ops . fset_nt_acl = = NULL ) {
conn - > vfs_ops . fset_nt_acl = default_vfs_ops . fset_nt_acl ;
}
if ( conn - > vfs_ops . set_nt_acl = = NULL ) {
conn - > vfs_ops . set_nt_acl = default_vfs_ops . set_nt_acl ;
}
2000-11-15 00:56:32 +03:00
2000-02-03 08:10:09 +03:00
return True ;
}
# endif
2000-09-27 23:09:59 +04:00
/*******************************************************************
Check if directory exists .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-02-03 08:10:09 +03:00
2000-09-27 23:09:59 +04:00
BOOL vfs_directory_exist ( connection_struct * conn , char * dname , SMB_STRUCT_STAT * st )
{
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
return ret ;
}
2000-10-03 06:12:14 +04:00
/*******************************************************************
vfs mkdir wrapper that calls dos_to_unix .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int vfs_mkdir ( connection_struct * conn , char * fname , mode_t mode )
{
int ret ;
pstring name ;
SMB_STRUCT_STAT sbuf ;
pstrcpy ( name , dos_to_unix ( fname , False ) ) ; /* paranoia copy */
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
/*******************************************************************
vfs getwd wrapper that calls dos_to_unix .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * vfs_getwd ( connection_struct * conn , char * unix_path )
{
char * wd ;
2000-10-06 07:21:49 +04:00
wd = conn - > vfs_ops . getwd ( conn , unix_path ) ;
2000-09-27 23:09:59 +04:00
if ( wd )
unix_to_dos ( wd , True ) ;
return wd ;
}
/*******************************************************************
Check if a vfs file exists .
2000-02-03 08:10:09 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-09-27 23:09:59 +04:00
2000-02-03 08:10:09 +03:00
BOOL vfs_file_exist ( connection_struct * conn , char * fname , SMB_STRUCT_STAT * sbuf )
{
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
2000-02-03 08:10:09 +03:00
ssize_t vfs_write_data ( files_struct * fsp , char * buffer , size_t N )
{
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 ;
}
/****************************************************************************
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
{
static pstring buf ;
memcpy ( buf , dname , NAMLEN ( ptr ) + 1 ) ;
unix_to_dos ( buf , True ) ;
dname = buf ;
}
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 ) ;
p = strrchr ( base_name , ' / ' ) ;
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
}