aboutsummaryrefslogtreecommitdiff
path: root/src/libutil
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/util.cc23
-rw-r--r--src/libutil/util.hh6
2 files changed, 25 insertions, 4 deletions
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 5a728617d..188453d16 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -53,7 +53,7 @@ Path absPath(Path path, Path dir)
}
-Path canonPath(const Path & path)
+Path canonPath(const Path & path, bool resolveSymlinks)
{
string s;
@@ -61,6 +61,11 @@ Path canonPath(const Path & path)
throw Error(format("not an absolute path: `%1%'") % path);
string::const_iterator i = path.begin(), end = path.end();
+ string temp;
+
+ /* Count the number of times we follow a symlink and stop at some
+ arbitrary (but high) limit to prevent infinite loops. */
+ unsigned int followCount = 0, maxFollow = 1024;
while (1) {
@@ -84,6 +89,20 @@ Path canonPath(const Path & path)
else {
s += '/';
while (i != end && *i != '/') s += *i++;
+
+ /* If s points to a symlink, resolve it and restart (since
+ the symlink target might contain new symlinks). */
+ if (resolveSymlinks && isLink(s)) {
+ followCount++;
+ if (followCount >= maxFollow)
+ throw Error(format("infinite symlink recursion in path `%1%'") % path);
+ temp = absPath(readLink(s), dirOf(s))
+ + string(i, end);
+ i = temp.begin(); /* restart */
+ end = temp.end();
+ s = "";
+ /* !!! potential for infinite loop */
+ }
}
}
@@ -264,7 +283,7 @@ void makePathReadOnly(const Path & path)
static Path tempName()
{
static int counter = 0;
- Path tmpRoot = canonPath(getEnv("TMPDIR", "/tmp"));
+ Path tmpRoot = canonPath(getEnv("TMPDIR", "/tmp"), true);
return (format("%1%/nix-%2%-%3%") % tmpRoot % getpid() % counter++).str();
}
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 9601e65b3..aac2acd17 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -64,8 +64,10 @@ string getEnv(const string & key, const string & def = "");
Path absPath(Path path, Path dir = "");
/* Canonicalise a path by removing all `.' or `..' components and
- double or trailing slashes. */
-Path canonPath(const Path & path);
+ double or trailing slashes. Optionally resolves all symlink
+ components such that each component of the resulting path is *not*
+ a symbolic link. */
+Path canonPath(const Path & path, bool resolveSymlinks = false);
/* Return the directory part of the given canonical path, i.e.,
everything before the final `/'. If the path is the root or an