Fix SourcePath::resolveSymlinks()
This fixes handling of symlinks that start with '..', and symlink targets that contain symlinks themselves.
This commit is contained in:
parent
9c6ede85fc
commit
f5c6b29940
2 changed files with 24 additions and 12 deletions
|
@ -75,22 +75,28 @@ SourcePath SourcePath::resolveSymlinks() const
|
|||
|
||||
int linksAllowed = 1024;
|
||||
|
||||
for (auto & component : path) {
|
||||
res.path.push(component);
|
||||
while (true) {
|
||||
if (auto st = res.maybeLstat()) {
|
||||
std::list<std::string> todo;
|
||||
for (auto & c : path)
|
||||
todo.push_back(std::string(c));
|
||||
|
||||
while (!todo.empty()) {
|
||||
auto c = *todo.begin();
|
||||
todo.pop_front();
|
||||
if (c == "" || c == ".")
|
||||
;
|
||||
else if (c == "..")
|
||||
res.path.pop();
|
||||
else {
|
||||
res.path.push(c);
|
||||
if (auto st = res.maybeLstat(); st && st->type == InputAccessor::tSymlink) {
|
||||
if (!linksAllowed--)
|
||||
throw Error("infinite symlink recursion in path '%s'", path);
|
||||
if (st->type != InputAccessor::tSymlink) break;
|
||||
auto target = res.readLink();
|
||||
res.path.pop();
|
||||
if (hasPrefix(target, "/"))
|
||||
res = CanonPath(target);
|
||||
else {
|
||||
res.path.pop();
|
||||
res.path.extend(CanonPath(target));
|
||||
}
|
||||
} else
|
||||
break;
|
||||
res.path = CanonPath::root;
|
||||
todo.splice(todo.begin(), tokenizeString<std::list<std::string>>(target, "/"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,3 +35,9 @@ nix-instantiate --eval -E 'assert 1 + 2 == 3; true'
|
|||
# Check that symlink cycles don't cause a hang.
|
||||
ln -sfn cycle.nix $TEST_ROOT/cycle.nix
|
||||
(! nix eval --file $TEST_ROOT/cycle.nix)
|
||||
|
||||
# Check that relative symlinks are resolved correctly.
|
||||
mkdir -p $TEST_ROOT/xyzzy $TEST_ROOT/foo
|
||||
ln -sfn ../xyzzy $TEST_ROOT/foo/bar
|
||||
printf 123 > $TEST_ROOT/xyzzy/default.nix
|
||||
[[ $(nix eval --impure --expr "import $TEST_ROOT/foo/bar") = 123 ]]
|
||||
|
|
Loading…
Reference in a new issue