0001-01-01 02:30:17 +02:30
/*
Unix SMB / Netbios implementation .
Version 1.9 .
0001-01-01 02:30:17 +02:30
VFS initialisation and support functions
Copyright ( C ) Tim Potter 1999
0001-01-01 02:30:17 +02:30
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 .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
0001-01-01 02:30:17 +02:30
# ifdef HAVE_LIBDL
0001-01-01 02:30:17 +02:30
# include <dlfcn.h>
0001-01-01 02:30:17 +02:30
# endif
0001-01-01 02:30:17 +02:30
extern int DEBUGLEVEL ;
/* Some structures to help us initialise the vfs operations table */
struct vfs_syminfo {
char * name ;
void * fptr ;
} ;
/* Default vfs hooks. WARNING: The order of these initialisers is
0001-01-01 02:30:17 +02:30
very important . They must be in the same order as defined in
vfs . h . Change at your own peril . */
0001-01-01 02:30:17 +02:30
struct vfs_ops default_vfs_ops = {
/* Disk operations */
0001-01-01 02:30:17 +02:30
vfswrap_dummy_connect ,
vfswrap_dummy_disconnect ,
0001-01-01 02:30:17 +02:30
vfswrap_disk_free ,
/* Directory operations */
vfswrap_opendir ,
vfswrap_readdir ,
vfswrap_mkdir ,
vfswrap_rmdir ,
0001-01-01 02:30:17 +02:30
vfswrap_closedir ,
0001-01-01 02:30:17 +02:30
/* File operations */
vfswrap_open ,
vfswrap_close ,
vfswrap_read ,
vfswrap_write ,
vfswrap_lseek ,
vfswrap_rename ,
vfswrap_sync_file ,
vfswrap_stat ,
vfswrap_fstat ,
vfswrap_lstat ,
vfswrap_fcntl_lock ,
vfswrap_unlink ,
vfswrap_chmod ,
vfswrap_utime
} ;
/****************************************************************************
initialise default vfs hooks
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int vfs_init_default ( connection_struct * conn )
{
DEBUG ( 3 , ( " Initialising default vfs hooks \n " ) ) ;
0001-01-01 02:30:17 +02:30
memcpy ( & conn - > vfs_ops , & default_vfs_ops , sizeof ( conn - > vfs_ops ) ) ;
return True ;
0001-01-01 02:30:17 +02:30
}
/****************************************************************************
initialise custom vfs hooks
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
# ifdef HAVE_LIBDL
0001-01-01 02:30:17 +02:30
BOOL vfs_init_custom ( connection_struct * conn )
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
void * handle ;
0001-01-01 02:30:17 +02:30
struct vfs_ops * ops , * ( * fptr ) ( struct vfs_options * options ) ;
0001-01-01 02:30:17 +02:30
DEBUG ( 3 , ( " Initialising custom vfs hooks from %s \n " ,
lp_vfsobj ( SNUM ( conn ) ) ) ) ;
/* Open object file */
handle = dlopen ( lp_vfsobj ( SNUM ( conn ) ) , RTLD_NOW ) ;
if ( ! handle ) {
DEBUG ( 0 , ( " Error opening %s: %s \n " , lp_vfsobj ( SNUM ( conn ) ) ,
dlerror ( ) ) ) ;
0001-01-01 02:30:17 +02:30
return False ;
}
/* Get handle on vfs_init() symbol */
fptr = dlsym ( handle , " vfs_init " ) ;
if ( fptr = = NULL ) {
DEBUG ( 0 , ( " No vfs_init() symbol found in %s \n " ,
lp_vfsobj ( SNUM ( conn ) ) ) ) ;
return False ;
}
dlclose ( handle ) ;
0001-01-01 02:30:17 +02:30
/* Initialise vfs_ops structure */
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( ( ops = fptr ( lp_vfsoptions ( SNUM ( conn ) ) ) ) = = NULL ) {
0001-01-01 02:30:17 +02:30
return False ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
/* Fill in unused operations with default (disk based) ones.
There ' s probably a neater way to do this then a whole bunch of
if statements . */
0001-01-01 02:30:17 +02:30
memcpy ( & conn - > vfs_ops , ops , sizeof ( conn - > vfs_ops ) ) ;
if ( conn - > vfs_ops . connect = = NULL ) {
conn - > vfs_ops . connect = default_vfs_ops . connect ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( conn - > vfs_ops . disconnect = = NULL ) {
conn - > vfs_ops . disconnect = default_vfs_ops . disconnect ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( conn - > vfs_ops . disk_free = = NULL ) {
conn - > vfs_ops . disk_free = default_vfs_ops . disk_free ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
if ( conn - > vfs_ops . opendir = = NULL ) {
conn - > vfs_ops . opendir = default_vfs_ops . opendir ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( conn - > vfs_ops . readdir = = NULL ) {
conn - > vfs_ops . readdir = default_vfs_ops . readdir ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
if ( conn - > vfs_ops . mkdir = = NULL ) {
conn - > vfs_ops . mkdir = default_vfs_ops . mkdir ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
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 ;
}
if ( conn - > vfs_ops . write = = NULL ) {
conn - > vfs_ops . write = default_vfs_ops . write ;
}
if ( conn - > vfs_ops . lseek = = NULL ) {
conn - > vfs_ops . lseek = default_vfs_ops . lseek ;
}
if ( conn - > vfs_ops . rename = = NULL ) {
conn - > vfs_ops . rename = default_vfs_ops . rename ;
}
if ( conn - > vfs_ops . sync = = NULL ) {
conn - > vfs_ops . sync = default_vfs_ops . sync ;
}
if ( conn - > vfs_ops . stat = = NULL ) {
conn - > vfs_ops . stat = default_vfs_ops . stat ;
}
if ( conn - > vfs_ops . fstat = = NULL ) {
conn - > vfs_ops . fstat = default_vfs_ops . fstat ;
}
if ( conn - > vfs_ops . lstat = = NULL ) {
conn - > vfs_ops . lstat = default_vfs_ops . lstat ;
}
if ( conn - > vfs_ops . lock = = NULL ) {
conn - > vfs_ops . lock = default_vfs_ops . lock ;
}
if ( conn - > vfs_ops . unlink = = NULL ) {
conn - > vfs_ops . unlink = default_vfs_ops . unlink ;
}
if ( conn - > vfs_ops . chmod = = NULL ) {
conn - > vfs_ops . chmod = default_vfs_ops . chmod ;
}
if ( conn - > vfs_ops . utime = = NULL ) {
conn - > vfs_ops . utime = default_vfs_ops . utime ;
}
return True ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
# endif
0001-01-01 02:30:17 +02:30
/*******************************************************************
check if a vfs file exists
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL vfs_file_exist ( connection_struct * conn , char * fname , SMB_STRUCT_STAT * sbuf )
{
SMB_STRUCT_STAT st ;
if ( ! sbuf ) sbuf = & st ;
if ( conn - > vfs_ops . stat ( fname , sbuf ) ! = 0 )
return ( False ) ;
return ( S_ISREG ( sbuf - > st_mode ) ) ;
}
/****************************************************************************
write data to a fd on the vfs
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t vfs_write_data ( files_struct * fsp , char * buffer , size_t N )
{
size_t total = 0 ;
ssize_t ret ;
int fd = fsp - > fd_ptr - > fd ;
while ( total < N )
{
ret = fsp - > conn - > vfs_ops . write ( fd , buffer + total , N - total ) ;
if ( ret = = - 1 ) return - 1 ;
if ( ret = = 0 ) return total ;
total + = ret ;
}
return ( ssize_t ) total ;
}
/****************************************************************************
transfer some data between two file_struct ' s
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
SMB_OFF_T vfs_transfer_file ( int in_fd , files_struct * in_fsp ,
int out_fd , files_struct * out_fsp ,
SMB_OFF_T n , char * header , int headlen , int align )
{
static char * buf = NULL ;
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 ) {
ret + = in_fsp ?
in_fsp - > conn - > vfs_ops . read ( in_fsp - > fd_ptr - > fd , buf1 + ret , s - ret ) : read ( in_fd , buf1 + ret , s - ret ) ;
}
if ( ret > 0 )
{
if ( out_fsp ) {
ret2 = out_fsp - > conn - > vfs_ops . write ( out_fsp - > fd_ptr - > fd , buf1 , ret ) ;
} else {
ret2 = ( out_fd ! = - 1 ) ? write_data ( out_fd , buf1 , ret ) : ret ;
}
}
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 ) ;
}
/*******************************************************************
a vfs_readdir wrapper which just returns the file name
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * vfs_readdirname ( connection_struct * conn , void * p )
{
struct dirent * ptr ;
char * dname ;
if ( ! p ) return ( NULL ) ;
ptr = ( struct dirent * ) conn - > vfs_ops . readdir ( p ) ;
if ( ! ptr ) return ( NULL ) ;
dname = ptr - > d_name ;
# ifdef NEXT2
if ( telldir ( p ) < 0 ) return ( NULL ) ;
# 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 ;
}
unix_to_dos ( dname , True ) ;
return ( dname ) ;
}