2010-05-21 18:05:50 -04:00
/*
* libretroshare / src / util : rsdiscspace . cc
*
* Universal Networking Header for RetroShare .
*
* Copyright 2010 - 2010 by Cyril Soler .
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Library General Public
* License Version 2 as published by the Free Software Foundation .
*
* This library 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
* Library General Public License for more details .
*
* You should have received a copy of the GNU Library General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307
* USA .
*
* Please report all bugs and problems to " csoler@users.sourceforge.net " .
*
*/
# include <iostream>
2012-12-27 05:23:38 -05:00
# include <stdexcept>
2013-10-21 07:00:49 -04:00
# include <time.h>
2014-01-07 17:51:22 -05:00
# include "rsserver/p3face.h"
2010-08-06 05:40:23 -04:00
# include "retroshare/rsfiles.h"
# include "retroshare/rsiface.h"
2014-01-17 21:32:55 -05:00
# include "rsserver/rsaccounts.h"
2010-05-21 18:05:50 -04:00
# include "rsdiscspace.h"
# include <util/rsthreads.h>
2016-08-22 21:19:33 -04:00
# ifdef __ANDROID__
# include <android / api-level.h>
# endif
# ifdef WIN32
# include <wtypes.h>
# elif defined(__ANDROID__) && (__ANDROID_API__ < 21)
# include <sys / vfs.h>
# define statvfs64 statfs
# warning statvfs64 is not supported with android platform < 21 falling back to statfs that is untested (may misbehave)
2013-10-21 07:00:49 -04:00
# else
2016-08-22 21:19:33 -04:00
# include <sys / statvfs.h>
2010-05-21 19:59:35 -04:00
# endif
2010-05-21 18:05:50 -04:00
# define DELAY_BETWEEN_CHECKS 2
/*
* # define DEBUG_RSDISCSPACE
*/
2013-07-26 19:12:09 -04:00
time_t RsDiscSpace : : _last_check [ RS_DIRECTORY_COUNT ] = { 0 , 0 , 0 , 0 } ;
2010-05-21 18:05:50 -04:00
uint32_t RsDiscSpace : : _size_limit_mb = 100 ;
2013-07-26 19:12:09 -04:00
uint32_t RsDiscSpace : : _current_size [ RS_DIRECTORY_COUNT ] = { 10000 , 10000 , 10000 , 10000 } ;
bool RsDiscSpace : : _last_res [ RS_DIRECTORY_COUNT ] = { true , true , true , true } ;
2011-07-04 18:59:39 -04:00
RsMutex RsDiscSpace : : _mtx ( " RsDiscSpace " ) ;
2011-09-23 17:08:11 -04:00
std : : string RsDiscSpace : : _partials_path = " " ;
std : : string RsDiscSpace : : _download_path = " " ;
2010-05-21 18:05:50 -04:00
2010-05-25 04:18:10 -04:00
bool RsDiscSpace : : crossSystemDiskStats ( const char * file , uint64_t & free_blocks , uint64_t & block_size )
2010-05-21 19:59:35 -04:00
{
# if defined(WIN32) || defined(MINGW) || defined(__CYGWIN__)
DWORD dwFreeClusters ;
DWORD dwBytesPerSector ;
DWORD dwSectorPerCluster ;
DWORD dwTotalClusters ;
# ifdef WIN_CROSS_UBUNTU
wchar_t szDrive [ 4 ] ;
szDrive [ 0 ] = file [ 0 ] ;
szDrive [ 1 ] = file [ 1 ] ;
szDrive [ 2 ] = file [ 2 ] ;
# else
2010-05-23 19:53:17 -04:00
char szDrive [ 4 ] = " " ;
2010-05-21 19:59:35 -04:00
2010-05-23 19:53:17 -04:00
char * pszFullPath = _fullpath ( NULL , file , 0 ) ;
if ( pszFullPath = = 0 ) {
2010-06-26 20:18:33 -04:00
std : : cerr < < " Size estimate failed for drive (_fullpath) " < < std : : endl ;
2010-05-23 19:53:17 -04:00
return false ;
}
_splitpath ( pszFullPath , szDrive , NULL , NULL , NULL ) ;
free ( pszFullPath ) ;
2010-05-21 19:59:35 -04:00
# endif
szDrive [ 3 ] = 0 ;
2010-06-26 20:18:33 -04:00
if ( ! GetDiskFreeSpaceA ( szDrive , & dwSectorPerCluster , & dwBytesPerSector , & dwFreeClusters , & dwTotalClusters ) )
2010-05-21 19:59:35 -04:00
{
std : : cerr < < " Size estimate failed for drive " < < szDrive < < std : : endl ;
return false ;
}
free_blocks = dwFreeClusters ;
block_size = dwSectorPerCluster * dwBytesPerSector ;
# else
2010-05-27 18:34:45 -04:00
# ifdef __APPLE__
struct statvfs buf ;
if ( 0 ! = statvfs ( file , & buf ) )
2010-05-21 19:59:35 -04:00
{
std : : cerr < < " Size estimate failed for file " < < file < < std : : endl ;
return false ;
}
2010-05-27 18:34:45 -04:00
2010-05-23 17:27:41 -04:00
free_blocks = buf . f_bavail ;
block_size = buf . f_frsize ;
# else
2010-05-27 18:34:45 -04:00
struct statvfs64 buf ;
if ( 0 ! = statvfs64 ( file , & buf ) )
{
std : : cerr < < " Size estimate failed for file " < < file < < std : : endl ;
return false ;
}
2010-05-21 19:59:35 -04:00
free_blocks = buf . f_bavail ;
block_size = buf . f_bsize ;
2010-05-23 17:27:41 -04:00
# endif
2010-05-21 19:59:35 -04:00
# endif
return true ;
}
2011-09-23 17:08:11 -04:00
void RsDiscSpace : : setDownloadPath ( const std : : string & path )
{
RsStackMutex m ( _mtx ) ; // Locked
_download_path = path ;
}
void RsDiscSpace : : setPartialsPath ( const std : : string & path )
{
RsStackMutex m ( _mtx ) ; // Locked
_partials_path = path ;
}
2010-05-21 18:05:50 -04:00
bool RsDiscSpace : : checkForDiscSpace ( RsDiscSpace : : DiscLocation loc )
{
RsStackMutex m ( _mtx ) ; // Locked
2014-03-17 16:56:06 -04:00
if ( ( _partials_path = = " " & & loc = = RS_PARTIALS_DIRECTORY ) | | ( _download_path = = " " & & loc = = RS_DOWNLOAD_DIRECTORY ) )
2012-12-27 05:23:38 -05:00
throw std : : runtime_error ( " Download path and partial path not properly set in RsDiscSpace. Please call RsDiscSpace::setPartialsPath() and RsDiscSpace::setDownloadPath() " ) ;
2010-05-21 18:05:50 -04:00
time_t now = time ( NULL ) ;
if ( _last_check [ loc ] + DELAY_BETWEEN_CHECKS < now )
{
2010-05-25 04:18:10 -04:00
uint64_t free_blocks , block_size ;
2010-05-21 19:59:35 -04:00
int rs = false ;
2010-05-21 18:05:50 -04:00
# ifdef DEBUG_RSDISCSPACE
std : : cerr < < " Size determination: " < < std : : endl ;
# endif
switch ( loc )
{
2011-09-23 17:08:11 -04:00
case RS_DOWNLOAD_DIRECTORY : rs = crossSystemDiskStats ( _download_path . c_str ( ) , free_blocks , block_size ) ;
2010-05-21 18:05:50 -04:00
# ifdef DEBUG_RSDISCSPACE
2011-09-23 17:08:11 -04:00
std : : cerr < < " path = " < < _download_path < < std : : endl ;
2010-05-21 18:05:50 -04:00
# endif
break ;
2011-09-23 17:08:11 -04:00
case RS_PARTIALS_DIRECTORY : rs = crossSystemDiskStats ( _partials_path . c_str ( ) , free_blocks , block_size ) ;
2010-05-21 18:05:50 -04:00
# ifdef DEBUG_RSDISCSPACE
2011-09-23 17:08:11 -04:00
std : : cerr < < " path = " < < _partials_path < < std : : endl ;
2010-05-21 18:05:50 -04:00
# endif
break ;
2014-08-25 17:07:07 -04:00
case RS_CONFIG_DIRECTORY : rs = crossSystemDiskStats ( rsAccounts - > PathAccountDirectory ( ) . c_str ( ) , free_blocks , block_size ) ;
2010-05-21 18:05:50 -04:00
# ifdef DEBUG_RSDISCSPACE
std : : cerr < < " path = " < < RsInit : : RsConfigDirectory ( ) < < std : : endl ;
2013-07-25 16:05:31 -04:00
# endif
break ;
2014-08-25 17:07:07 -04:00
case RS_PGP_DIRECTORY : rs = crossSystemDiskStats ( rsAccounts - > PathPGPDirectory ( ) . c_str ( ) , free_blocks , block_size ) ;
2013-07-25 16:05:31 -04:00
# ifdef DEBUG_RSDISCSPACE
std : : cerr < < " path = " < < RsInit : : RsPGPDirectory ( ) < < std : : endl ;
2010-05-21 18:05:50 -04:00
# endif
break ;
}
2010-05-21 19:59:35 -04:00
if ( ! rs )
2010-05-21 18:05:50 -04:00
{
std : : cerr < < " Determination of free disc space failed ! Be careful ! " < < std : : endl ;
return true ;
}
_last_check [ loc ] = now ;
// Now compute the size in megabytes
//
2010-05-25 04:18:10 -04:00
_current_size [ loc ] = uint32_t ( block_size * free_blocks / ( uint64_t ) ( 1024 * 1024 ) ) ; // on purpose integer division
2010-05-21 18:05:50 -04:00
# ifdef DEBUG_RSDISCSPACE
2010-05-21 19:59:35 -04:00
std : : cerr < < " blocks available = " < < free_blocks < < std : : endl ;
std : : cerr < < " blocks size = " < < block_size < < std : : endl ;
2010-05-21 18:05:50 -04:00
std : : cerr < < " free MBs = " < < _current_size [ loc ] < < std : : endl ;
# endif
}
bool res = _current_size [ loc ] > _size_limit_mb ;
if ( _last_res [ loc ] & & ! res )
2014-01-07 17:51:22 -05:00
RsServer : : notify ( ) - > notifyDiskFull ( loc , _size_limit_mb ) ;
2010-05-21 18:05:50 -04:00
_last_res [ loc ] = res ;
return res ;
}
void RsDiscSpace : : setFreeSpaceLimit ( uint32_t size_in_mb )
{
RsStackMutex m ( _mtx ) ; // Locked
_size_limit_mb = size_in_mb ;
}
uint32_t RsDiscSpace : : freeSpaceLimit ( )
{
RsStackMutex m ( _mtx ) ; // Locked
return _size_limit_mb ;
}