summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--lib/util.cc1
1 files changed, 1 insertions, 0 deletions
diff --git a/lib/util.cc b/lib/util.cc
index 74039c6..069590b 100644
--- a/lib/util.cc
+++ b/lib/util.cc
@@ -1,98 +1,99 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <cassert>
#include <konforka/util.h>
namespace konforka {
/*
* XXX: this code is borrowed from sitecing as is, although it should be optimized.
*/
string normalize_path(const string& p,int o) {
const char *s = p.c_str();
if( s[0]=='.' && s[1]=='/' )
s += 2; // skip leading './'
if(o&strip_leading_slash)
for(;(*s)=='/';s++);
string rv;
string::size_type notslash = 0;
for(;*s;s++) {
if(s[0]=='/') {
if(s[1]=='/')
continue; // skip duplicate slash
if(s[1]=='.' && s[2]=='/') {
// '/./' sequence encountered
s += 2;
continue;
}
}
if(
(o&restrict_dotdot) && (
( rv.empty() && s[0]=='.' && s[1]=='.' && s[2]=='/' ) // '^../'
||
( s[0]=='/' && s[1]=='.' && s[2]=='.' && (s[3]=='/' || s[3]==0) ) // '/../' or '/..$'
)
)
throw restricted_sequence_error(CODEPOINT,"restricted updir (..) sequence encountered");
rv += *s;
if( (*s) !='/' )
notslash = rv.length();
}
if(!(o&strip_trailing_slash))
notslash++;
if(notslash<rv.length())
rv.erase(notslash); // XXX: does this operation have enough sense to be performed?
return rv;
}
string dir_name(const string& p) {
string::size_type sl = p.find_last_of('/');
if(sl==string::npos)
return ""; // no slashes -- no dir.
string::size_type nosl = p.find_last_not_of('/',sl);
if(nosl==string::npos)
return ""; // only slashes -- no dir.
return p.substr(0,nosl+1);
}
string combine_path(const string& orig,const string& rel,int o) {
string r = normalize_path(rel,0);
if(r.empty()) {
// XXX: this behaviour is questionable.
return normalize_path( (o&origin_is_file)?dir_name(orig):orig, strip_leading_slash|restrict_dotdot|strip_trailing_slash);
}
string rv;
if(r[0]=='/') {
r.erase(0,1);
}else{
rv = normalize_path( (o&origin_is_file)?dir_name(orig):orig, restrict_dotdot|strip_trailing_slash);
}
string::size_type lsl = rv.rfind('/');
// iterate through slashes in relative path
for(string::size_type sl=r.find('/');sl!=string::npos;sl=r.find('/')) {
assert(sl!=0); // sure we don't start with '/' at this point
if(sl==1 && r[0]=='.') { // './'
r.erase(0,2);
}else if(sl==2 && r[0]=='.' && r[1]=='.') { // '../'
if(lsl==string::npos) {
if(rv.empty() && (o&fail_beyond_root))
throw beyond_root_error(CODEPOINT,"went beyond root while combining path");
rv.clear();
}else{
rv.erase(lsl);
lsl = rv.rfind('/');
}
r.erase(0,3);
}else{ // 'something/'
lsl = rv.length();
rv += '/';
rv += r.substr(0,sl);
r.erase(0,sl+1);
}
}
if(r.empty())
return rv+'/';
if(r.length()==2 && r[0]=='.' && r[1]=='.') {
if(lsl==string::npos) {
if(rv.empty() && (o&fail_beyond_root))
throw beyond_root_error(CODEPOINT,"went beyond root while combining path");