2016-01-05 22:12:00 +03:00
/*
* Fake Disk - Free and Quota VFS module . Implements passthrough operation
* of all VFS calls , except for " disk free " and " get quota " which
* are handled by reading a text file named " .dfq " in the current directory .
*
* This module is intended for testing purposes .
*
* Copyright ( C ) Uri Simchoni , 2016
*
* 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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "smbd/smbd.h"
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_VFS
2017-06-01 21:45:25 +03:00
static int dfq_get_quota ( struct vfs_handle_struct * handle ,
const struct smb_filename * smb_fname ,
enum SMB_QUOTA_TYPE qtype ,
unid_t id ,
SMB_DISK_QUOTA * qt ) ;
2016-01-05 22:12:00 +03:00
static uint64_t dfq_load_param ( int snum , const char * path , const char * section ,
const char * param , uint64_t def_val )
{
uint64_t ret ;
char * option =
talloc_asprintf ( talloc_tos ( ) , " %s/%s/%s " , section , param , path ) ;
if ( option = = NULL ) {
return def_val ;
}
ret = ( uint64_t ) lp_parm_ulonglong ( snum , " fake_dfq " , option ,
( unsigned long long ) def_val ) ;
TALLOC_FREE ( option ) ;
return ret ;
}
2017-05-23 20:40:47 +03:00
static uint64_t dfq_disk_free ( vfs_handle_struct * handle ,
const struct smb_filename * smb_fname ,
uint64_t * bsize ,
uint64_t * dfree ,
uint64_t * dsize )
2016-01-05 22:12:00 +03:00
{
uint64_t free_1k ;
int snum = SNUM ( handle - > conn ) ;
uint64_t dfq_bsize = 0 ;
2017-06-30 21:32:59 +03:00
struct smb_filename * rpath_fname = NULL ;
2016-01-05 22:12:00 +03:00
/* look up the params based on real path to be resilient
* to refactoring of path < - > realpath
*/
2017-06-30 21:32:59 +03:00
rpath_fname = SMB_VFS_NEXT_REALPATH ( handle , talloc_tos ( ) , smb_fname ) ;
if ( rpath_fname ! = NULL ) {
dfq_bsize = dfq_load_param ( snum , rpath_fname - > base_name ,
" df " , " block size " , 0 ) ;
2016-01-05 22:12:00 +03:00
}
if ( dfq_bsize = = 0 ) {
2017-06-30 21:32:59 +03:00
TALLOC_FREE ( rpath_fname ) ;
2017-05-23 20:40:47 +03:00
return SMB_VFS_NEXT_DISK_FREE ( handle , smb_fname , bsize , dfree ,
2016-01-05 22:12:00 +03:00
dsize ) ;
}
* bsize = dfq_bsize ;
2017-06-30 21:32:59 +03:00
* dfree = dfq_load_param ( snum , rpath_fname - > base_name ,
" df " , " disk free " , 0 ) ;
* dsize = dfq_load_param ( snum , rpath_fname - > base_name ,
" df " , " disk size " , 0 ) ;
2016-01-05 22:12:00 +03:00
if ( ( * bsize ) < 1024 ) {
free_1k = ( * dfree ) / ( 1024 / ( * bsize ) ) ;
} else {
free_1k = ( ( * bsize ) / 1024 ) * ( * dfree ) ;
}
2017-06-30 21:32:59 +03:00
TALLOC_FREE ( rpath_fname ) ;
2016-01-05 22:12:00 +03:00
return free_1k ;
}
2017-06-01 21:45:25 +03:00
static int dfq_get_quota ( struct vfs_handle_struct * handle ,
const struct smb_filename * smb_fname ,
enum SMB_QUOTA_TYPE qtype ,
unid_t id ,
SMB_DISK_QUOTA * qt )
2016-01-05 22:12:00 +03:00
{
int rc = 0 ;
int save_errno ;
char * section = NULL ;
int snum = SNUM ( handle - > conn ) ;
uint64_t bsize = 0 ;
2017-06-30 21:32:59 +03:00
struct smb_filename * rpath_fname = NULL ;
2016-01-05 22:12:00 +03:00
2017-06-30 21:32:59 +03:00
rpath_fname = SMB_VFS_NEXT_REALPATH ( handle , talloc_tos ( ) , smb_fname ) ;
if ( rpath_fname = = NULL ) {
2016-01-05 22:12:00 +03:00
goto dflt ;
}
switch ( qtype ) {
case SMB_USER_QUOTA_TYPE :
section = talloc_asprintf ( talloc_tos ( ) , " u%llu " ,
( unsigned long long ) id . uid ) ;
break ;
case SMB_GROUP_QUOTA_TYPE :
section = talloc_asprintf ( talloc_tos ( ) , " g%llu " ,
( unsigned long long ) id . gid ) ;
break ;
2016-05-26 21:59:38 +03:00
case SMB_USER_FS_QUOTA_TYPE :
section = talloc_strdup ( talloc_tos ( ) , " udflt " ) ;
break ;
case SMB_GROUP_FS_QUOTA_TYPE :
section = talloc_strdup ( talloc_tos ( ) , " gdflt " ) ;
break ;
2016-01-05 22:12:00 +03:00
default :
break ;
}
if ( section = = NULL ) {
goto dflt ;
}
2017-06-30 21:32:59 +03:00
bsize = dfq_load_param ( snum , rpath_fname - > base_name ,
section , " block size " , 4096 ) ;
2016-01-05 22:12:00 +03:00
if ( bsize = = 0 ) {
goto dflt ;
}
2017-06-30 21:32:59 +03:00
if ( dfq_load_param ( snum , rpath_fname - > base_name ,
section , " err " , 0 ) ! = 0 ) {
2016-01-05 22:12:00 +03:00
errno = ENOTSUP ;
rc = - 1 ;
goto out ;
}
2017-06-30 21:32:59 +03:00
if ( dfq_load_param ( snum , rpath_fname - > base_name ,
section , " nosys " , 0 ) ! = 0 ) {
2016-05-26 21:59:38 +03:00
errno = ENOSYS ;
rc = - 1 ;
goto out ;
}
2016-01-05 22:12:00 +03:00
ZERO_STRUCTP ( qt ) ;
qt - > bsize = bsize ;
2017-06-30 21:32:59 +03:00
qt - > hardlimit = dfq_load_param ( snum , rpath_fname - > base_name ,
section , " hard limit " , 0 ) ;
qt - > softlimit = dfq_load_param ( snum , rpath_fname - > base_name ,
section , " soft limit " , 0 ) ;
qt - > curblocks = dfq_load_param ( snum , rpath_fname - > base_name ,
section , " cur blocks " , 0 ) ;
2016-01-05 22:12:00 +03:00
qt - > ihardlimit =
2017-06-30 21:32:59 +03:00
dfq_load_param ( snum , rpath_fname - > base_name ,
section , " inode hard limit " , 0 ) ;
2016-01-05 22:12:00 +03:00
qt - > isoftlimit =
2017-06-30 21:32:59 +03:00
dfq_load_param ( snum , rpath_fname - > base_name ,
section , " inode soft limit " , 0 ) ;
qt - > curinodes = dfq_load_param ( snum , rpath_fname - > base_name ,
section , " cur inodes " , 0 ) ;
qt - > qflags = dfq_load_param ( snum , rpath_fname - > base_name ,
section , " qflags " , QUOTAS_DENY_DISK ) ;
2016-01-05 22:12:00 +03:00
goto out ;
dflt :
2017-06-01 21:45:25 +03:00
rc = SMB_VFS_NEXT_GET_QUOTA ( handle , smb_fname , qtype , id , qt ) ;
2016-01-05 22:12:00 +03:00
out :
save_errno = errno ;
TALLOC_FREE ( section ) ;
2017-06-30 21:32:59 +03:00
TALLOC_FREE ( rpath_fname ) ;
2016-01-05 22:12:00 +03:00
errno = save_errno ;
return rc ;
}
2019-08-13 23:37:22 +03:00
static void dfq_fake_stat ( struct vfs_handle_struct * handle ,
struct smb_filename * smb_fname ,
SMB_STRUCT_STAT * sbuf )
{
int snum = SNUM ( handle - > conn ) ;
char * full_path = NULL ;
char * to_free = NULL ;
char path [ PATH_MAX + 1 ] ;
int len ;
gid_t gid ;
2019-08-09 01:22:31 +03:00
len = full_path_tos ( handle - > conn - > cwd_fsp - > fsp_name - > base_name ,
2019-08-13 23:37:22 +03:00
smb_fname - > base_name ,
path , sizeof ( path ) ,
& full_path , & to_free ) ;
if ( len = = - 1 ) {
DBG_ERR ( " Could not allocate memory in full_path_tos. \n " ) ;
return ;
}
gid = dfq_load_param ( snum , full_path , " stat " , " sgid " , 0 ) ;
if ( gid ! = 0 ) {
sbuf - > st_ex_gid = gid ;
sbuf - > st_ex_mode | = S_ISGID ;
}
TALLOC_FREE ( to_free ) ;
}
static int dfq_stat ( vfs_handle_struct * handle ,
struct smb_filename * smb_fname )
{
int ret ;
ret = SMB_VFS_NEXT_STAT ( handle , smb_fname ) ;
if ( ret = = - 1 ) {
return ret ;
}
dfq_fake_stat ( handle , smb_fname , & smb_fname - > st ) ;
return 0 ;
}
static int dfq_fstat ( vfs_handle_struct * handle ,
files_struct * fsp ,
SMB_STRUCT_STAT * sbuf )
{
int ret ;
ret = SMB_VFS_NEXT_FSTAT ( handle , fsp , sbuf ) ;
if ( ret = = - 1 ) {
return ret ;
}
dfq_fake_stat ( handle , fsp - > fsp_name , sbuf ) ;
return 0 ;
}
static int dfq_lstat ( vfs_handle_struct * handle ,
struct smb_filename * smb_fname )
{
int ret ;
ret = SMB_VFS_NEXT_LSTAT ( handle , smb_fname ) ;
if ( ret = = - 1 ) {
return ret ;
}
dfq_fake_stat ( handle , smb_fname , & smb_fname - > st ) ;
return 0 ;
}
2016-01-05 22:12:00 +03:00
struct vfs_fn_pointers vfs_fake_dfq_fns = {
/* Disk operations */
. disk_free_fn = dfq_disk_free ,
. get_quota_fn = dfq_get_quota ,
2019-08-13 23:37:22 +03:00
. stat_fn = dfq_stat ,
. fstat_fn = dfq_fstat ,
. lstat_fn = dfq_lstat ,
2016-01-05 22:12:00 +03:00
} ;
static_decl_vfs ;
2017-04-20 22:24:43 +03:00
NTSTATUS vfs_fake_dfq_init ( TALLOC_CTX * ctx )
2016-01-05 22:12:00 +03:00
{
return smb_register_vfs ( SMB_VFS_INTERFACE_VERSION , " fake_dfq " ,
& vfs_fake_dfq_fns ) ;
}