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:
parent
890cc46825
commit
031c833e4d
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user