From cab3f4977a412681a77767ec7307ee642b61332d Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 8 Jul 2003 19:58:41 +0000 Subject: [PATCH] * A path canonicaliser that doesn't depend on the existence of paths (i.e., it doesn't use realpath(3), which is broken in any case). Therefore it doesn't resolve symlinks. --- src/test.cc | 9 +++++++++ src/util.cc | 38 +++++++++++++++++++++++++++++++++----- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/test.cc b/src/test.cc index b30a5b0e90..c2a1cd3bfd 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 8ccd3c1524..00a3063d6d 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; }