about summary refs log tree commit diff
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 5a728617dbd4..188453d16abd 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 9601e65b3c63..aac2acd1730b 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