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; 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[]) int main(int argc, char* argv[])
{ {
SGPath pa; SGPath pa;
@ -143,7 +167,26 @@ int main(int argc, char* argv[])
COMPARE(pf.dir(), ""); COMPARE(pf.dir(), "");
COMPARE(pf.lower_extension(), "gz"); COMPARE(pf.lower_extension(), "gz");
COMPARE(pf.complete_lower_extension(), "txt.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(); test_dir();
cout << "all tests passed OK" << endl; cout << "all tests passed OK" << endl;

View File

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

View File

@ -52,8 +52,15 @@ class SGPath {
public: public:
struct Permissions
{
bool read : 1;
bool write : 1;
};
typedef Permissions (*PermissonChecker)(const SGPath&);
/** Default constructor */ /** Default constructor */
SGPath(); explicit SGPath(PermissonChecker validator = NULL);
/** Copy contructor */ /** Copy contructor */
SGPath(const SGPath& p); SGPath(const SGPath& p);
@ -64,14 +71,16 @@ public:
* Construct a path based on the starting path provided. * Construct a path based on the starting path provided.
* @param p initial path * @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 * Construct a path based on the starting path provided and a relative subpath
* @param p initial path * @param p initial path
* @param r relative subpath * @param r relative subpath
*/ */
SGPath( const SGPath& p, const std::string& r ); SGPath( const SGPath& p,
const std::string& r,
PermissonChecker validator = NULL );
/** Destructor */ /** Destructor */
~SGPath(); ~SGPath();
@ -85,7 +94,10 @@ public:
bool operator==(const SGPath& other) const; bool operator==(const SGPath& other) const;
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 * Set if file information (exists, type, mod-time) is cached or
* retrieved each time it is queried. Caching is enabled by default * retrieved each time it is queried. Caching is enabled by default
@ -198,6 +210,17 @@ public:
*/ */
int create_dir(mode_t mode); 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 isFile() const;
bool isDir() const; bool isDir() const;
@ -258,11 +281,16 @@ private:
void fix(); void fix();
void validate() const; void validate() const;
void checkAccess() const;
std::string path; std::string path;
PermissonChecker _permisson_checker;
mutable bool _cached : 1; mutable bool _cached : 1;
mutable bool _rwCached : 1;
bool _cacheEnabled : 1; ///< cacheing can be disbled if required bool _cacheEnabled : 1; ///< cacheing can be disbled if required
mutable bool _canRead : 1;
mutable bool _canWrite : 1;
mutable bool _exists : 1; mutable bool _exists : 1;
mutable bool _isDir : 1; mutable bool _isDir : 1;
mutable bool _isFile : 1; mutable bool _isFile : 1;