diff options
-rw-r--r-- | src/test.cc | 9 | ||||
-rw-r--r-- | src/util.cc | 38 |
2 files changed, 42 insertions, 5 deletions
diff --git a/src/test.cc b/src/test.cc index b30a5b0e9..c2a1cd3bf 100644 --- a/src/test.cc +++ b/src/test.cc @@ -71,6 +71,15 @@ void runTests() abort(); } catch (BadRefError err) { }; + /* Path canonicalisation. */ + cout << canonPath("/./../././//") << endl; + cout << canonPath("/foo/bar") << endl; + cout << canonPath("///foo/////bar//") << endl; + cout << canonPath("/././/foo/////bar//.") << endl; + cout << canonPath("/foo////bar//..///x/") << endl; + cout << canonPath("/foo////bar//..//..//x/y/../z/") << endl; + cout << canonPath("/foo/bar/../../../..///") << endl; + /* Dumping. */ #if 0 diff --git a/src/util.cc b/src/util.cc index 8ccd3c152..00a3063d6 100644 --- a/src/util.cc +++ b/src/util.cc @@ -40,11 +40,39 @@ string absPath(string path, string dir) string canonPath(const string & path) { - char resolved[PATH_MAX]; - if (!realpath(path.c_str(), resolved)) - throw SysError(format("cannot canonicalise path `%1%'") % path); - /* !!! check that this removes trailing slashes */ - return resolved; + string s; + + if (path[0] != '/') + throw Error(format("not an absolute path: `%1%'") % path); + + string::const_iterator i = path.begin(), end = path.end(); + + while (1) { + + /* Skip slashes. */ + while (i != end && *i == '/') i++; + if (i == end) break; + + /* Ignore `.'. */ + if (*i == '.' && (i + 1 == end || i[1] == '/')) + i++; + + /* If `..', delete the last component. */ + else if (*i == '.' && i + 1 < end && i[1] == '.' && + (i + 2 == end || i[2] == '/')) + { + if (!s.empty()) s.erase(s.rfind('/')); + i += 2; + } + + /* Normal component; copy it. */ + else { + s += '/'; + while (i != end && *i != '/') s += *i++; + } + } + + return s.empty() ? "/" : s; } |