SGPath: add support for custom PermissionChecker

Allow to add permission checks (read/write-access) for
eg. limiting access based on IORules.
This commit is contained in:
Thomas Geymayer 2013-12-12 21:03:24 +01:00
parent 890cc46825
commit 031c833e4d
3 changed files with 211 additions and 37 deletions

View File

@ -43,6 +43,30 @@ void test_dir()
cout << temp.path().modTime() << endl;
}
SGPath::Permissions validateNone(const SGPath&)
{
SGPath::Permissions p;
p.read = false;
p.write = false;
return p;
}
SGPath::Permissions validateRead(const SGPath&)
{
SGPath::Permissions p;
p.read = true;
p.write = false;
return p;
}
SGPath::Permissions validateWrite(const SGPath&)
{
SGPath::Permissions p;
p.read = false;
p.write = true;
return p;
}
int main(int argc, char* argv[])
{
SGPath pa;
@ -143,7 +167,26 @@ int main(int argc, char* argv[])
COMPARE(pf.dir(), "");
COMPARE(pf.lower_extension(), "gz");
COMPARE(pf.complete_lower_extension(), "txt.gz");
COMPARE(pf.canRead(), true);
COMPARE(pf.canWrite(), true);
SGPath pp(&validateNone);
COMPARE(pp.canRead(), false);
COMPARE(pp.canWrite(), false);
pp.append("./test-dir/file.txt");
COMPARE(pp.create_dir(0700), -3);
pp.setPermissonChecker(&validateRead);
COMPARE(pp.canRead(), true);
COMPARE(pp.canWrite(), false);
COMPARE(pp.create_dir(0700), -3);
pp.setPermissonChecker(&validateWrite);
COMPARE(pp.canRead(), false);
COMPARE(pp.canWrite(), true);
test_dir();
cout << "all tests passed OK" << endl;

View File

@ -75,27 +75,35 @@ SGPath::fix()
// default constructor
SGPath::SGPath()
SGPath::SGPath(PermissonChecker validator)
: path(""),
_permisson_checker(validator),
_cached(false),
_rwCached(false),
_cacheEnabled(true)
{
}
// create a path based on "path"
SGPath::SGPath( const std::string& p )
SGPath::SGPath( const std::string& p, PermissonChecker validator )
: path(p),
_permisson_checker(validator),
_cached(false),
_rwCached(false),
_cacheEnabled(true)
{
fix();
}
// create a path based on "path" and a "subpath"
SGPath::SGPath( const SGPath& p, const std::string& r )
SGPath::SGPath( const SGPath& p,
const std::string& r,
PermissonChecker validator )
: path(p.path),
_permisson_checker(validator),
_cached(false),
_rwCached(false),
_cacheEnabled(p._cacheEnabled)
{
append(r);
@ -104,8 +112,12 @@ SGPath::SGPath( const SGPath& p, const std::string& r )
SGPath::SGPath(const SGPath& p) :
path(p.path),
_permisson_checker(p._permisson_checker),
_cached(p._cached),
_rwCached(p._rwCached),
_cacheEnabled(p._cacheEnabled),
_canRead(p._canRead),
_canWrite(p._canWrite),
_exists(p._exists),
_isDir(p._isDir),
_isFile(p._isFile),
@ -116,8 +128,12 @@ SGPath::SGPath(const SGPath& p) :
SGPath& SGPath::operator=(const SGPath& p)
{
path = p.path;
_permisson_checker = p._permisson_checker,
_cached = p._cached;
_rwCached = p._rwCached;
_cacheEnabled = p._cacheEnabled;
_canRead = p._canRead;
_canWrite = p._canWrite;
_exists = p._exists;
_isDir = p._isDir;
_isFile = p._isFile;
@ -135,11 +151,26 @@ void SGPath::set( const string& p ) {
path = p;
fix();
_cached = false;
_rwCached = false;
}
//------------------------------------------------------------------------------
void SGPath::setPermissonChecker(PermissonChecker validator)
{
_permisson_checker = validator;
_rwCached = false;
}
//------------------------------------------------------------------------------
SGPath::PermissonChecker SGPath::getPermissonChecker() const
{
return _permisson_checker;
}
//------------------------------------------------------------------------------
void SGPath::set_cached(bool cached)
{
_cacheEnabled = cached;
_cacheEnabled = cached;
}
// append another piece to the existing path
@ -154,6 +185,7 @@ void SGPath::append( const string& p ) {
}
fix();
_cached = false;
_rwCached = false;
}
//------------------------------------------------------------------------------
@ -180,6 +212,7 @@ void SGPath::concat( const string& p ) {
}
fix();
_cached = false;
_rwCached = false;
}
@ -278,7 +311,7 @@ void SGPath::validate() const
if (_cached && _cacheEnabled) {
return;
}
#ifdef _WIN32
struct _stat buf ;
@ -310,12 +343,46 @@ void SGPath::validate() const
_cached = true;
}
void SGPath::checkAccess() const
{
if( _rwCached && _cacheEnabled )
return;
if( _permisson_checker )
{
Permissions p = _permisson_checker(*this);
_canRead = p.read;
_canWrite = p.write;
}
else
{
_canRead = true;
_canWrite = true;
}
_rwCached = true;
}
bool SGPath::exists() const
{
validate();
return _exists;
}
//------------------------------------------------------------------------------
bool SGPath::canRead() const
{
checkAccess();
return _canRead;
}
//------------------------------------------------------------------------------
bool SGPath::canWrite() const
{
checkAccess();
return _canWrite;
}
bool SGPath::isDir() const
{
validate();
@ -344,7 +411,7 @@ int SGPath::create_dir( mode_t mode ) {
bool absolute = !path.empty() && path[0] == sgDirPathSep;
unsigned int i = 1;
SGPath dir = absolute ? string( 1, sgDirPathSep ) : "";
SGPath dir(absolute ? string( 1, sgDirPathSep ) : "", _permisson_checker);
dir.concat( path_elements[0] );
#ifdef _WIN32
if ( dir.str().find(':') != string::npos && path_elements.size() >= 2 ) {
@ -360,16 +427,26 @@ int SGPath::create_dir( mode_t mode ) {
if ( r == 0 ) {
return 0; // Directory already exists
}
if ( sgMkDir( dir.c_str(), mode) ) {
SG_LOG( SG_IO, SG_ALERT, "Error creating directory: " + dir.str() );
for(;;)
{
if( !dir.canWrite() )
{
SG_LOG( SG_IO,
SG_ALERT, "Error creating directory: (" << dir.str() << ")" <<
" reason: access denied" );
return -3;
}
else if( sgMkDir(dir.c_str(), mode) )
{
SG_LOG( SG_IO,
SG_ALERT, "Error creating directory: (" << dir.str() << ")" );
return -2;
}
for(; i < path_elements.size(); i++) {
dir.append(path_elements[i]);
if ( sgMkDir( dir.c_str(), mode) ) {
SG_LOG( SG_IO, SG_ALERT, "Error creating directory: " + dir.str() );
return -2;
}
}
if( i >= path_elements.size() )
return 0;
dir.append(path_elements[i++]);
}
return 0;
@ -456,14 +533,27 @@ std::string SGPath::str_native() const
#endif
}
//------------------------------------------------------------------------------
bool SGPath::remove()
{
int err = ::unlink(c_str());
if (err) {
SG_LOG(SG_IO, SG_WARN, "file remove failed: (" << str() << ") " << strerror(errno));
}
_cached = false; // stat again if required
return (err == 0);
if( !canWrite() )
{
SG_LOG( SG_IO, SG_WARN, "file remove failed: (" << str() << ")"
" reason: access denied" );
return false;
}
int err = ::unlink(c_str());
if( err )
{
SG_LOG( SG_IO, SG_WARN, "file remove failed: (" << str() << ") "
" reason: " << strerror(errno) );
// TODO check if failed unlink can really change any of the cached values
}
_cached = false; // stat again if required
_rwCached = false;
return (err == 0);
}
time_t SGPath::modTime() const
@ -482,8 +572,17 @@ bool SGPath::operator!=(const SGPath& other) const
return (path != other.path);
}
//------------------------------------------------------------------------------
bool SGPath::rename(const SGPath& newName)
{
if( !newName.canWrite() )
{
SG_LOG( SG_IO, SG_WARN, "rename failed: from " << str() <<
" to " << newName.str() <<
" reason: access denied" );
return false;
}
#ifdef SG_WINDOWS
if (newName.exists()) {
SGPath r(newName);
@ -492,15 +591,19 @@ bool SGPath::rename(const SGPath& newName)
}
}
#endif
if (::rename(c_str(), newName.c_str()) != 0) {
SG_LOG(SG_IO, SG_WARN, "renamed failed: from " << str() << " to " << newName.str()
<< " reason: " << strerror(errno));
return false;
}
path = newName.path;
_cached = false;
return true;
if( ::rename(c_str(), newName.c_str()) != 0 )
{
SG_LOG( SG_IO, SG_WARN, "rename failed: from " << str() <<
" to " << newName.str() <<
" reason: " << strerror(errno) );
return false;
}
path = newName.path;
_cached = false;
_rwCached = false;
return true;
}
//------------------------------------------------------------------------------
@ -508,7 +611,7 @@ SGPath SGPath::fromEnv(const char* name, const SGPath& def)
{
const char* val = getenv(name);
if( val && val[0] )
return SGPath(val);
return SGPath(val, def._permisson_checker);
return def;
}

View File

@ -52,8 +52,15 @@ class SGPath {
public:
struct Permissions
{
bool read : 1;
bool write : 1;
};
typedef Permissions (*PermissonChecker)(const SGPath&);
/** Default constructor */
SGPath();
explicit SGPath(PermissonChecker validator = NULL);
/** Copy contructor */
SGPath(const SGPath& p);
@ -64,14 +71,16 @@ public:
* Construct a path based on the starting path provided.
* @param p initial path
*/
SGPath( const std::string& p );
SGPath( const std::string& p, PermissonChecker validator = NULL );
/**
* Construct a path based on the starting path provided and a relative subpath
* @param p initial path
* @param r relative subpath
*/
SGPath( const SGPath& p, const std::string& r );
SGPath( const SGPath& p,
const std::string& r,
PermissonChecker validator = NULL );
/** Destructor */
~SGPath();
@ -85,7 +94,10 @@ public:
bool operator==(const SGPath& other) const;
bool operator!=(const SGPath& other) const;
void setPermissonChecker(PermissonChecker validator);
PermissonChecker getPermissonChecker() const;
/**
* Set if file information (exists, type, mod-time) is cached or
* retrieved each time it is queried. Caching is enabled by default
@ -198,6 +210,17 @@ public:
*/
int create_dir(mode_t mode);
/**
* Check if reading file is allowed. Readabilty does not imply the existance
* of the file.
*
* @note By default all files will be marked as readable. No check is made
* if the operating system allows the given file to be read. Derived
* classes may actually implement custom read/write rights.
*/
bool canRead() const;
bool canWrite() const;
bool isFile() const;
bool isDir() const;
@ -258,11 +281,16 @@ private:
void fix();
void validate() const;
void checkAccess() const;
std::string path;
PermissonChecker _permisson_checker;
mutable bool _cached : 1;
mutable bool _rwCached : 1;
bool _cacheEnabled : 1; ///< cacheing can be disbled if required
mutable bool _canRead : 1;
mutable bool _canWrite : 1;
mutable bool _exists : 1;
mutable bool _isDir : 1;
mutable bool _isFile : 1;