2011-06-28 16:59:18 +04:00
/*
2006-11-09 23:29:31 +03:00
* Unix SMB / CIFS implementation .
* Provide a connection to GPFS specific features
* Copyright ( C ) Volker Lendecke 2005
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
2007-07-09 23:25:36 +04:00
* the Free Software Foundation ; either version 3 of the License , or
2006-11-09 23:29:31 +03:00
* ( at your option ) any later version .
2011-06-28 16:59:18 +04:00
*
2006-11-09 23:29:31 +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 .
2011-06-28 16:59:18 +04:00
*
2006-11-09 23:29:31 +03:00
* You should have received a copy of the GNU General Public License
2007-07-10 09:23:25 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2006-11-09 23:29:31 +03:00
*/
# include "includes.h"
2011-05-16 16:25:01 +04:00
# include "system/filesys.h"
2011-03-23 00:34:22 +03:00
# include "smbd/smbd.h"
2006-11-09 23:29:31 +03:00
2011-10-25 03:52:50 +04:00
# include <fcntl.h>
2010-10-28 17:50:37 +04:00
# include "libcli/security/security.h"
2012-03-03 01:26:19 +04:00
# include "gpfs_fcntl.h"
2006-11-09 23:29:31 +03:00
# include "gpfs_gpl.h"
2008-01-16 12:18:57 +03:00
# include "vfs_gpfs.h"
2006-11-09 23:29:31 +03:00
static int ( * gpfs_set_share_fn ) ( int fd , unsigned int allow , unsigned int deny ) ;
static int ( * gpfs_set_lease_fn ) ( int fd , unsigned int leaseType ) ;
static int ( * gpfs_getacl_fn ) ( char * pathname , int flags , void * acl ) ;
static int ( * gpfs_putacl_fn ) ( char * pathname , int flags , void * acl ) ;
2008-12-10 14:32:24 +03:00
static int ( * gpfs_get_realfilename_path_fn ) ( char * pathname , char * filenamep ,
int * buflen ) ;
2009-05-27 14:03:12 +04:00
static int ( * gpfs_set_winattrs_path_fn ) ( char * pathname , int flags , struct gpfs_winattr * attrs ) ;
static int ( * gpfs_get_winattrs_path_fn ) ( char * pathname , struct gpfs_winattr * attrs ) ;
2009-05-29 02:20:10 +04:00
static int ( * gpfs_get_winattrs_fn ) ( int fd , struct gpfs_winattr * attrs ) ;
2012-03-09 01:57:12 +04:00
static int ( * gpfs_prealloc_fn ) ( int fd , gpfs_off64_t startOffset , gpfs_off64_t bytesToPrealloc ) ;
2010-10-08 15:43:17 +04:00
static int ( * gpfs_ftruncate_fn ) ( int fd , gpfs_off64_t length ) ;
2011-02-21 20:25:36 +03:00
static int ( * gpfs_lib_init_fn ) ( int flags ) ;
2014-01-07 22:55:46 +04:00
static int ( * gpfs_set_times_path_fn ) ( char * pathname , int flags ,
gpfs_timestruc_t times [ 4 ] ) ;
2012-03-03 01:26:19 +04:00
static int ( * gpfs_quotactl_fn ) ( char * pathname , int cmd , int id , void * bufferP ) ;
static int ( * gpfs_fcntl_fn ) ( gpfs_file_t fileDesc , void * fcntlArgP ) ;
static int ( * gpfs_getfilesetid_fn ) ( char * pathname , char * name , int * idP ) ;
2006-11-09 23:29:31 +03:00
2007-10-19 04:40:25 +04:00
bool set_gpfs_sharemode ( files_struct * fsp , uint32 access_mask ,
2006-11-09 23:29:31 +03:00
uint32 share_access )
{
unsigned int allow = GPFS_SHARE_NONE ;
unsigned int deny = GPFS_DENY_NONE ;
int result ;
if ( gpfs_set_share_fn = = NULL ) {
return False ;
}
if ( ( fsp = = NULL ) | | ( fsp - > fh = = NULL ) | | ( fsp - > fh - > fd < 0 ) ) {
/* No real file, don't disturb */
return True ;
}
allow | = ( access_mask & ( FILE_WRITE_DATA | FILE_APPEND_DATA |
DELETE_ACCESS ) ) ? GPFS_SHARE_WRITE : 0 ;
allow | = ( access_mask & ( FILE_READ_DATA | FILE_EXECUTE ) ) ?
GPFS_SHARE_READ : 0 ;
2007-01-13 00:56:25 +03:00
if ( allow = = GPFS_SHARE_NONE ) {
DEBUG ( 10 , ( " special case am=no_access:%x \n " , access_mask ) ) ;
}
else {
2007-01-24 18:29:58 +03:00
deny | = ( share_access & FILE_SHARE_WRITE ) ?
2007-01-13 00:56:25 +03:00
0 : GPFS_DENY_WRITE ;
deny | = ( share_access & ( FILE_SHARE_READ ) ) ?
0 : GPFS_DENY_READ ;
}
2006-11-09 23:29:31 +03:00
DEBUG ( 10 , ( " am=%x, allow=%d, sa=%x, deny=%d \n " ,
access_mask , allow , share_access , deny ) ) ;
result = gpfs_set_share_fn ( fsp - > fh - > fd , allow , deny ) ;
if ( result ! = 0 ) {
if ( errno = = ENOSYS ) {
DEBUG ( 5 , ( " VFS module vfs_gpfs loaded, but no gpfs "
" support has been compiled into Samba. Allowing access \n " ) ) ;
return True ;
} else {
DEBUG ( 10 , ( " gpfs_set_share failed: %s \n " ,
strerror ( errno ) ) ) ;
}
}
return ( result = = 0 ) ;
}
int set_gpfs_lease ( int fd , int leasetype )
{
int gpfs_type = GPFS_LEASE_NONE ;
if ( gpfs_set_lease_fn = = NULL ) {
errno = EINVAL ;
return - 1 ;
}
if ( leasetype = = F_RDLCK ) {
gpfs_type = GPFS_LEASE_READ ;
}
if ( leasetype = = F_WRLCK ) {
gpfs_type = GPFS_LEASE_WRITE ;
}
2008-10-01 14:26:55 +04:00
2008-01-16 12:18:57 +03:00
/* we unconditionally set CAP_LEASE, rather than looking for
- 1 / EACCES as there is a bug in some versions of
libgpfs_gpl . so which results in a leaked fd on / dev / ss0
each time we try this with the wrong capabilities set
*/
linux_set_lease_capability ( ) ;
2006-11-09 23:29:31 +03:00
return gpfs_set_lease_fn ( fd , gpfs_type ) ;
}
int smbd_gpfs_getacl ( char * pathname , int flags , void * acl )
{
if ( gpfs_getacl_fn = = NULL ) {
errno = ENOSYS ;
return - 1 ;
}
return gpfs_getacl_fn ( pathname , flags , acl ) ;
}
int smbd_gpfs_putacl ( char * pathname , int flags , void * acl )
{
if ( gpfs_putacl_fn = = NULL ) {
errno = ENOSYS ;
return - 1 ;
}
return gpfs_putacl_fn ( pathname , flags , acl ) ;
}
2010-10-08 15:43:17 +04:00
int smbd_gpfs_ftruncate ( int fd , gpfs_off64_t length )
{
2011-12-22 18:54:41 +04:00
if ( gpfs_ftruncate_fn = = NULL ) {
2010-10-08 15:43:17 +04:00
errno = ENOSYS ;
return - 1 ;
}
return gpfs_ftruncate_fn ( fd , length ) ;
}
2008-12-10 14:32:24 +03:00
int smbd_gpfs_get_realfilename_path ( char * pathname , char * filenamep ,
int * buflen )
{
2011-12-22 18:54:41 +04:00
if ( gpfs_get_realfilename_path_fn = = NULL ) {
2008-12-10 14:32:24 +03:00
errno = ENOSYS ;
return - 1 ;
}
return gpfs_get_realfilename_path_fn ( pathname , filenamep , buflen ) ;
}
2009-05-27 14:03:12 +04:00
int get_gpfs_winattrs ( char * pathname , struct gpfs_winattr * attrs )
{
2011-12-22 17:36:55 +04:00
if ( gpfs_get_winattrs_path_fn = = NULL ) {
2009-05-27 14:03:12 +04:00
errno = ENOSYS ;
return - 1 ;
}
2009-09-28 01:34:04 +04:00
DEBUG ( 10 , ( " gpfs_get_winattrs_path:open call %s \n " , pathname ) ) ;
2009-05-27 14:03:12 +04:00
return gpfs_get_winattrs_path_fn ( pathname , attrs ) ;
}
2009-05-29 02:20:10 +04:00
int smbd_fget_gpfs_winattrs ( int fd , struct gpfs_winattr * attrs )
{
2011-12-22 17:36:55 +04:00
if ( gpfs_get_winattrs_fn = = NULL ) {
2009-05-29 02:20:10 +04:00
errno = ENOSYS ;
return - 1 ;
}
2014-06-13 14:05:05 +04:00
DEBUG ( 10 , ( " gpfs_get_winattrs:open call %d \n " , fd ) ) ;
2009-05-29 02:20:10 +04:00
return gpfs_get_winattrs_fn ( fd , attrs ) ;
}
2012-03-09 01:57:12 +04:00
int smbd_gpfs_prealloc ( int fd , gpfs_off64_t start , gpfs_off64_t bytes )
{
if ( gpfs_prealloc_fn = = NULL ) {
errno = ENOSYS ;
return - 1 ;
}
return gpfs_prealloc_fn ( fd , start , bytes ) ;
}
2009-05-27 14:03:12 +04:00
int set_gpfs_winattrs ( char * pathname , int flags , struct gpfs_winattr * attrs )
{
2011-12-22 17:36:55 +04:00
if ( gpfs_set_winattrs_path_fn = = NULL ) {
2009-05-27 14:03:12 +04:00
errno = ENOSYS ;
return - 1 ;
}
2009-09-28 01:34:04 +04:00
DEBUG ( 10 , ( " gpfs_set_winattrs_path:open call %s \n " , pathname ) ) ;
2009-05-27 14:03:12 +04:00
return gpfs_set_winattrs_path_fn ( pathname , flags , attrs ) ;
}
2012-03-03 01:26:19 +04:00
int get_gpfs_quota ( const char * pathname , int type , int id ,
struct gpfs_quotaInfo * qi )
{
int ret ;
if ( ! gpfs_quotactl_fn ) {
errno = ENOSYS ;
return - 1 ;
}
ZERO_STRUCTP ( qi ) ;
ret = gpfs_quotactl_fn ( discard_const_p ( char , pathname ) ,
GPFS_QCMD ( Q_GETQUOTA , type ) , id , qi ) ;
if ( ret ) {
if ( errno = = GPFS_E_NO_QUOTA_INST ) {
DEBUG ( 10 , ( " Quotas disabled on GPFS filesystem. \n " ) ) ;
} else {
DEBUG ( 0 , ( " Get quota failed, type %d, id, %d, "
" errno %d. \n " , type , id , errno ) ) ;
}
return ret ;
}
DEBUG ( 10 , ( " quota type %d, id %d, blk u:%lld h:%lld s:%lld gt:%u \n " ,
type , id , qi - > blockUsage , qi - > blockHardLimit ,
qi - > blockSoftLimit , qi - > blockGraceTime ) ) ;
return ret ;
}
int get_gpfs_fset_id ( const char * pathname , int * fset_id )
{
int err , fd , errno_fcntl ;
struct {
gpfsFcntlHeader_t hdr ;
gpfsGetFilesetName_t fsn ;
} arg ;
if ( ! gpfs_fcntl_fn | | ! gpfs_getfilesetid_fn ) {
errno = ENOSYS ;
return - 1 ;
}
arg . hdr . totalLength = sizeof ( arg ) ;
arg . hdr . fcntlVersion = GPFS_FCNTL_CURRENT_VERSION ;
arg . hdr . fcntlReserved = 0 ;
arg . fsn . structLen = sizeof ( arg . fsn ) ;
arg . fsn . structType = GPFS_FCNTL_GET_FILESETNAME ;
fd = open ( pathname , O_RDONLY ) ;
2012-08-16 23:47:52 +04:00
if ( fd = = - 1 ) {
DEBUG ( 1 , ( " Could not open %s: %s \n " ,
pathname , strerror ( errno ) ) ) ;
2012-03-03 01:26:19 +04:00
return fd ;
2012-08-16 23:47:52 +04:00
}
2012-03-03 01:26:19 +04:00
err = gpfs_fcntl_fn ( fd , & arg ) ;
errno_fcntl = errno ;
close ( fd ) ;
if ( err ) {
errno = errno_fcntl ;
2012-08-16 23:47:52 +04:00
DEBUG ( 1 , ( " GPFS_FCNTL_GET_FILESETNAME for %s failed: %s \n " ,
pathname , strerror ( errno ) ) ) ;
2012-03-03 01:26:19 +04:00
return err ;
}
2012-08-16 23:47:52 +04:00
err = gpfs_getfilesetid_fn ( discard_const_p ( char , pathname ) ,
arg . fsn . buffer , fset_id ) ;
if ( err ) {
DEBUG ( 1 , ( " gpfs_getfilesetid for %s failed: %s \n " ,
pathname , strerror ( errno ) ) ) ;
}
return err ;
2012-03-03 01:26:19 +04:00
}
2011-02-21 20:25:36 +03:00
void smbd_gpfs_lib_init ( )
{
if ( gpfs_lib_init_fn ) {
int rc = gpfs_lib_init_fn ( 0 ) ;
DEBUG ( 10 , ( " gpfs_lib_init() finished with rc %d "
" and errno %d \n " , rc , errno ) ) ;
} else {
DEBUG ( 10 , ( " libgpfs lacks gpfs_lib_init \n " ) ) ;
}
}
2014-01-07 22:55:46 +04:00
static void timespec_to_gpfs_time ( struct timespec ts , gpfs_timestruc_t * gt ,
int idx , int * flags )
{
if ( ! null_timespec ( ts ) ) {
* flags | = 1 < < idx ;
gt [ idx ] . tv_sec = ts . tv_sec ;
gt [ idx ] . tv_nsec = ts . tv_nsec ;
DEBUG ( 10 , ( " Setting GPFS time %d, flags 0x%x \n " , idx , * flags ) ) ;
}
}
int smbd_gpfs_set_times_path ( char * path , struct smb_file_time * ft )
{
gpfs_timestruc_t gpfs_times [ 4 ] ;
int flags = 0 ;
int rc ;
if ( ! gpfs_set_times_path_fn ) {
errno = ENOSYS ;
return - 1 ;
}
ZERO_ARRAY ( gpfs_times ) ;
timespec_to_gpfs_time ( ft - > atime , gpfs_times , 0 , & flags ) ;
timespec_to_gpfs_time ( ft - > mtime , gpfs_times , 1 , & flags ) ;
/* No good mapping from LastChangeTime to ctime, not storing */
timespec_to_gpfs_time ( ft - > create_time , gpfs_times , 3 , & flags ) ;
if ( ! flags ) {
DEBUG ( 10 , ( " nothing to do, return to avoid EINVAL \n " ) ) ;
return 0 ;
}
rc = gpfs_set_times_path_fn ( path , flags , gpfs_times ) ;
if ( rc ! = 0 ) {
DEBUG ( 1 , ( " gpfs_set_times() returned with error %s \n " ,
strerror ( errno ) ) ) ;
}
return rc ;
}
2008-11-12 16:32:45 +03:00
static bool init_gpfs_function_lib ( void * plibhandle_pointer ,
const char * libname ,
void * pfn_pointer , const char * fn_name )
2006-11-09 23:29:31 +03:00
{
2008-11-12 16:32:45 +03:00
bool did_open_here = false ;
void * * libhandle_pointer = ( void * * ) plibhandle_pointer ;
void * * fn_pointer = ( void * * ) pfn_pointer ;
2008-12-10 14:32:24 +03:00
DEBUG ( 10 , ( " trying to load name %s from %s \n " ,
fn_name , libname ) ) ;
2008-11-12 16:32:45 +03:00
if ( * libhandle_pointer = = NULL ) {
2008-12-11 01:14:46 +03:00
* libhandle_pointer = dlopen ( libname , RTLD_LAZY ) ;
2008-11-12 16:32:45 +03:00
did_open_here = true ;
}
if ( * libhandle_pointer = = NULL ) {
DEBUG ( 10 , ( " Could not open lib %s \n " , libname ) ) ;
return false ;
}
2008-12-11 01:14:46 +03:00
* fn_pointer = dlsym ( * libhandle_pointer , fn_name ) ;
2008-11-12 16:32:45 +03:00
if ( * fn_pointer = = NULL ) {
DEBUG ( 10 , ( " Did not find symbol %s in lib %s \n " ,
fn_name , libname ) ) ;
if ( did_open_here ) {
2008-12-11 01:14:46 +03:00
dlclose ( * libhandle_pointer ) ;
2008-11-12 16:32:45 +03:00
* libhandle_pointer = NULL ;
}
return false ;
2006-11-09 23:29:31 +03:00
}
2008-11-12 16:32:45 +03:00
return true ;
}
2006-11-09 23:29:31 +03:00
2008-11-12 16:32:45 +03:00
static bool init_gpfs_function ( void * fn_pointer , const char * fn_name )
{
static void * libgpfs_handle = NULL ;
static void * libgpfs_gpl_handle = NULL ;
2006-11-09 23:29:31 +03:00
2008-11-12 16:32:45 +03:00
if ( init_gpfs_function_lib ( & libgpfs_handle , " libgpfs.so " ,
fn_pointer , fn_name ) ) {
return true ;
2006-11-09 23:29:31 +03:00
}
2008-11-12 16:32:45 +03:00
if ( init_gpfs_function_lib ( & libgpfs_gpl_handle , " libgpfs_gpl.so " ,
fn_pointer , fn_name ) ) {
return true ;
2006-11-09 23:29:31 +03:00
}
2008-11-12 16:32:45 +03:00
return false ;
}
2006-11-09 23:29:31 +03:00
2008-11-12 16:32:45 +03:00
void init_gpfs ( void )
{
init_gpfs_function ( & gpfs_set_share_fn , " gpfs_set_share " ) ;
init_gpfs_function ( & gpfs_set_lease_fn , " gpfs_set_lease " ) ;
init_gpfs_function ( & gpfs_getacl_fn , " gpfs_getacl " ) ;
init_gpfs_function ( & gpfs_putacl_fn , " gpfs_putacl " ) ;
2008-12-10 14:32:24 +03:00
init_gpfs_function ( & gpfs_get_realfilename_path_fn ,
" gpfs_get_realfilename_path " ) ;
2009-05-27 14:03:12 +04:00
init_gpfs_function ( & gpfs_get_winattrs_path_fn , " gpfs_get_winattrs_path " ) ;
init_gpfs_function ( & gpfs_set_winattrs_path_fn , " gpfs_set_winattrs_path " ) ;
2009-05-29 02:20:10 +04:00
init_gpfs_function ( & gpfs_get_winattrs_fn , " gpfs_get_winattrs " ) ;
2012-03-09 01:57:12 +04:00
init_gpfs_function ( & gpfs_prealloc_fn , " gpfs_prealloc " ) ;
2010-10-08 15:43:17 +04:00
init_gpfs_function ( & gpfs_ftruncate_fn , " gpfs_ftruncate " ) ;
2011-02-21 20:25:36 +03:00
init_gpfs_function ( & gpfs_lib_init_fn , " gpfs_lib_init " ) ;
2014-01-07 22:55:46 +04:00
init_gpfs_function ( & gpfs_set_times_path_fn , " gpfs_set_times_path " ) ;
2012-03-03 01:26:19 +04:00
init_gpfs_function ( & gpfs_quotactl_fn , " gpfs_quotactl " ) ;
init_gpfs_function ( & gpfs_fcntl_fn , " gpfs_fcntl " ) ;
init_gpfs_function ( & gpfs_getfilesetid_fn , " gpfs_getfilesetid " ) ;
2006-11-09 23:29:31 +03:00
2007-05-29 23:54:26 +04:00
return ;
2006-11-09 23:29:31 +03:00
}