1998-07-29 07:08:05 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-07-29 07:08:05 +04:00
functions to calculate the free disk space
Copyright ( C ) Andrew Tridgell 1998
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
1998-07-29 07:08:05 +04:00
( 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
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1998-07-29 07:08:05 +04:00
*/
# include "includes.h"
2009-01-08 14:03:45 +03:00
# include "smbd/globals.h"
1998-07-29 07:08:05 +04:00
/****************************************************************************
2005-10-20 00:02:12 +04:00
Normalise for DOS usage .
1998-07-29 07:08:05 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-10-20 00:02:12 +04:00
2008-10-14 03:59:36 +04:00
static void disk_norm ( bool small_query , uint64_t * bsize , uint64_t * dfree , uint64_t * dsize )
1998-07-29 07:08:05 +04:00
{
/* check if the disk is beyond the max disk size */
2008-10-14 03:59:36 +04:00
uint64_t maxdisksize = lp_maxdisksize ( ) ;
1998-07-29 07:08:05 +04:00
if ( maxdisksize ) {
/* convert to blocks - and don't overflow */
maxdisksize = ( ( maxdisksize * 1024 ) / ( * bsize ) ) * 1024 ;
if ( * dsize > maxdisksize ) * dsize = maxdisksize ;
if ( * dfree > maxdisksize ) * dfree = maxdisksize - 1 ;
/* the -1 should stop applications getting div by 0
errors */
}
1999-12-13 16:27:58 +03:00
2005-02-08 01:06:49 +03:00
if ( small_query ) {
while ( * dfree > WORDMAX | | * dsize > WORDMAX | | * bsize < 512 ) {
* dfree / = 2 ;
* dsize / = 2 ;
* bsize * = 2 ;
1999-12-13 16:27:58 +03:00
/*
* Force max to fit in 16 bit fields .
*/
if ( * bsize > ( WORDMAX * 512 ) ) {
* bsize = ( WORDMAX * 512 ) ;
if ( * dsize > WORDMAX )
* dsize = WORDMAX ;
if ( * dfree > WORDMAX )
* dfree = WORDMAX ;
break ;
}
1998-07-29 07:08:05 +04:00
}
}
}
/****************************************************************************
2005-10-20 00:02:12 +04:00
Return number of 1 K blocks available on a path and total number .
1998-07-29 07:08:05 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2008-10-14 03:59:36 +04:00
uint64_t sys_disk_free ( connection_struct * conn , const char * path , bool small_query ,
uint64_t * bsize , uint64_t * dfree , uint64_t * dsize )
1998-07-29 07:08:05 +04:00
{
2008-10-14 03:59:36 +04:00
uint64_t dfree_retval ;
uint64_t dfree_q = 0 ;
uint64_t bsize_q = 0 ;
uint64_t dsize_q = 0 ;
2005-10-20 00:02:12 +04:00
const char * dfree_command ;
1998-07-29 07:08:05 +04:00
( * dfree ) = ( * dsize ) = 0 ;
( * bsize ) = 512 ;
2000-01-06 04:41:27 +03:00
/*
* If external disk calculation specified , use it .
*/
2005-10-20 00:02:12 +04:00
dfree_command = lp_dfree_command ( SNUM ( conn ) ) ;
2000-01-06 04:41:27 +03:00
if ( dfree_command & & * dfree_command ) {
2003-05-12 05:20:17 +04:00
const char * p ;
2007-09-13 03:50:21 +04:00
char * * lines = NULL ;
char * syscmd = NULL ;
syscmd = talloc_asprintf ( talloc_tos ( ) ,
" %s %s " ,
dfree_command ,
path ) ;
if ( ! syscmd ) {
2008-10-14 03:59:36 +04:00
return ( uint64_t ) - 1 ;
2007-09-13 03:50:21 +04:00
}
2000-01-06 04:41:27 +03:00
2000-04-16 15:00:21 +04:00
DEBUG ( 3 , ( " disk_free: Running command %s \n " , syscmd ) ) ;
2000-02-15 22:36:47 +03:00
2001-07-04 11:15:53 +04:00
lines = file_lines_pload ( syscmd , NULL ) ;
2000-04-16 15:00:21 +04:00
if ( lines ) {
char * line = lines [ 0 ] ;
2000-01-06 04:41:27 +03:00
DEBUG ( 3 , ( " Read input from dfree, \" %s \" \n " , line ) ) ;
2003-05-12 05:20:17 +04:00
* dsize = STR_TO_SMB_BIG_UINT ( line , & p ) ;
while ( p & & * p & & isspace ( * p ) )
2000-01-06 04:41:27 +03:00
p + + ;
if ( p & & * p )
2003-05-12 05:20:17 +04:00
* dfree = STR_TO_SMB_BIG_UINT ( p , & p ) ;
while ( p & & * p & & isspace ( * p ) )
2000-01-06 04:41:27 +03:00
p + + ;
if ( p & & * p )
2003-05-12 05:20:17 +04:00
* bsize = STR_TO_SMB_BIG_UINT ( p , NULL ) ;
2000-01-06 04:41:27 +03:00
else
* bsize = 1024 ;
2008-10-12 19:34:43 +04:00
TALLOC_FREE ( lines ) ;
2000-01-06 04:41:27 +03:00
DEBUG ( 3 , ( " Parsed output of dfree, dsize=%u, dfree=%u, bsize=%u \n " ,
( unsigned int ) * dsize , ( unsigned int ) * dfree , ( unsigned int ) * bsize ) ) ;
if ( ! * dsize )
* dsize = 2048 ;
if ( ! * dfree )
* dfree = 1024 ;
} else {
2000-02-15 22:36:47 +03:00
DEBUG ( 0 , ( " disk_free: sys_popen() failed for command %s. Error was : %s \n " ,
2000-04-16 15:00:21 +04:00
syscmd , strerror ( errno ) ) ) ;
2005-03-16 04:41:21 +03:00
if ( sys_fsusage ( path , dfree , dsize ) ! = 0 ) {
DEBUG ( 0 , ( " disk_free: sys_fsusage() failed. Error was : %s \n " ,
strerror ( errno ) ) ) ;
2008-10-14 03:59:36 +04:00
return ( uint64_t ) - 1 ;
2005-03-16 04:41:21 +03:00
}
}
} else {
if ( sys_fsusage ( path , dfree , dsize ) ! = 0 ) {
DEBUG ( 0 , ( " disk_free: sys_fsusage() failed. Error was : %s \n " ,
strerror ( errno ) ) ) ;
2008-10-14 03:59:36 +04:00
return ( uint64_t ) - 1 ;
2000-01-06 04:41:27 +03:00
}
2005-03-16 04:41:21 +03:00
}
1998-07-29 07:08:05 +04:00
2001-11-04 02:34:24 +03:00
if ( disk_quotas ( path , & bsize_q , & dfree_q , & dsize_q ) ) {
1998-11-06 21:40:51 +03:00
( * bsize ) = bsize_q ;
( * dfree ) = MIN ( * dfree , dfree_q ) ;
( * dsize ) = MIN ( * dsize , dsize_q ) ;
}
/* FIXME : Any reason for this assumption ? */
1998-07-29 07:08:05 +04:00
if ( * bsize < 256 ) {
1998-11-09 06:45:49 +03:00
DEBUG ( 5 , ( " disk_free:Warning: bsize == %d < 256 . Changing to assumed correct bsize = 512 \n " , ( int ) * bsize ) ) ;
1998-07-29 07:08:05 +04:00
* bsize = 512 ;
}
if ( ( * dsize ) < 1 ) {
2009-01-08 14:03:45 +03:00
if ( ! dfree_broken ) {
1998-07-29 07:08:05 +04:00
DEBUG ( 0 , ( " WARNING: dfree is broken on this system \n " ) ) ;
2009-01-08 14:03:45 +03:00
dfree_broken = true ;
1998-07-29 07:08:05 +04:00
}
* dsize = 20 * 1024 * 1024 / ( * bsize ) ;
* dfree = MAX ( 1 , * dfree ) ;
}
1999-12-13 16:27:58 +03:00
disk_norm ( small_query , bsize , dfree , dsize ) ;
1998-07-29 07:08:05 +04:00
if ( ( * bsize ) < 1024 ) {
dfree_retval = ( * dfree ) / ( 1024 / ( * bsize ) ) ;
} else {
dfree_retval = ( ( * bsize ) / 1024 ) * ( * dfree ) ;
}
return ( dfree_retval ) ;
}
/****************************************************************************
2005-10-20 00:02:12 +04:00
Potentially returned cached dfree info .
1998-07-29 07:08:05 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-10-20 00:02:12 +04:00
2008-10-14 03:59:36 +04:00
uint64_t get_dfree_info ( connection_struct * conn ,
2005-10-20 00:02:12 +04:00
const char * path ,
2007-10-19 04:40:25 +04:00
bool small_query ,
2008-10-14 03:59:36 +04:00
uint64_t * bsize ,
uint64_t * dfree ,
uint64_t * dsize )
1998-07-29 07:08:05 +04:00
{
2005-10-20 00:02:12 +04:00
int dfree_cache_time = lp_dfree_cache_time ( SNUM ( conn ) ) ;
struct dfree_cached_info * dfc = conn - > dfree_info ;
2008-10-14 03:59:36 +04:00
uint64_t dfree_ret ;
2005-10-20 00:02:12 +04:00
if ( ! dfree_cache_time ) {
return SMB_VFS_DISK_FREE ( conn , path , small_query , bsize , dfree , dsize ) ;
}
if ( dfc & & ( conn - > lastused - dfc - > last_dfree_time < dfree_cache_time ) ) {
/* Return cached info. */
* bsize = dfc - > bsize ;
* dfree = dfc - > dfree ;
* dsize = dfc - > dsize ;
return dfc - > dfree_ret ;
}
dfree_ret = SMB_VFS_DISK_FREE ( conn , path , small_query , bsize , dfree , dsize ) ;
2008-10-14 03:59:36 +04:00
if ( dfree_ret = = ( uint64_t ) - 1 ) {
2005-10-20 00:02:12 +04:00
/* Don't cache bad data. */
return dfree_ret ;
}
/* No cached info or time to refresh. */
if ( ! dfc ) {
2008-04-28 12:31:49 +04:00
dfc = TALLOC_P ( conn , struct dfree_cached_info ) ;
2005-10-20 00:02:12 +04:00
if ( ! dfc ) {
return dfree_ret ;
}
conn - > dfree_info = dfc ;
}
dfc - > bsize = * bsize ;
dfc - > dfree = * dfree ;
dfc - > dsize = * dsize ;
dfc - > dfree_ret = dfree_ret ;
dfc - > last_dfree_time = conn - > lastused ;
return dfree_ret ;
1998-07-29 07:08:05 +04:00
}