Skip to content

Commit

Permalink
SourcePath::resolveSymlinks(): Fix handling of symlinks that start wi…
Browse files Browse the repository at this point in the history
…th '..'

Fixes #8437.
  • Loading branch information
edolstra committed Jun 5, 2023
1 parent 9c6ede8 commit 6731850
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 6 deletions.
8 changes: 2 additions & 6 deletions src/libfetchers/input-accessor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,8 @@ SourcePath SourcePath::resolveSymlinks() const
throw Error("infinite symlink recursion in path '%s'", path);
if (st->type != InputAccessor::tSymlink) break;
auto target = res.readLink();
if (hasPrefix(target, "/"))
res = CanonPath(target);
else {
res.path.pop();
res.path.extend(CanonPath(target));
}
res.path.pop();
res.path.apply(target);
} else
break;
}
Expand Down
24 changes: 24 additions & 0 deletions src/libutil/canon-path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,30 @@ void CanonPath::extend(const CanonPath & x)
path += x.abs();
}

void CanonPath::apply(std::string_view s)
{
if (hasPrefix(s, "/")) {
*this = CanonPath(s);
return;
}

while (!s.empty()) {
auto slash = s.find('/');
if (slash == s.npos) {
push(s);
return;
}
auto c = s.substr(0, slash);
if (c == ".")
;
else if (c == "..")
pop();
else
push(c);
s = s.substr(slash + 1);
}
}

CanonPath CanonPath::operator + (const CanonPath & x) const
{
auto res = *this;
Expand Down
8 changes: 8 additions & 0 deletions src/libutil/canon-path.hh
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,14 @@ public:
*/
void extend(const CanonPath & x);

/**
* "Apply" a string representation of a path to this one. If `s`
* is an absolute path, it replaces `this`. Otherwise, it is
* appended to this, where `..` components cause the previous
* component to be removed.
*/
void apply(std::string_view s);

/**
* Concatenate two paths.
*/
Expand Down
14 changes: 14 additions & 0 deletions src/libutil/tests/canon-path.cc
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,18 @@ namespace nix {
ASSERT_EQ(d.makeRelative(CanonPath("/foo/xyzzy/bla")), "../xyzzy/bla");
ASSERT_EQ(d.makeRelative(CanonPath("/xyzzy/bla")), "../../xyzzy/bla");
}

TEST(CanonPath, apply) {
{
CanonPath d("/common/pc/laptop/ssd");
d.pop();
d.apply("../ssd");
ASSERT_EQ(d, CanonPath("/common/pc/ssd"));
d.apply("foo/./bar/../xyzzy");
ASSERT_EQ(d, CanonPath("/common/pc/ssd/foo/xyzzy"));
d.apply("/foo/bar/../xyzzy");
ASSERT_EQ(d, CanonPath("/foo/xyzzy"));
}
}

}

0 comments on commit 6731850

Please sign in to comment.