mirror of
https://github.com/NixOS/nix
synced 2025-06-25 23:11:16 +02:00
nix shell: Handle output paths that are symlinks
This requires moving resolveSymlinks() into SourceAccessor. Also, it requires LocalStoreAccessor::maybeLstat() to work on parents of the store (to avoid an error like "/nix is not in the store"). Fixes #10375.
This commit is contained in:
parent
021488497d
commit
85b9f4ef4f
8 changed files with 97 additions and 72 deletions
|
@ -62,44 +62,6 @@ bool SourcePath::operator<(const SourcePath & x) const
|
|||
return std::tie(*accessor, path) < std::tie(*x.accessor, x.path);
|
||||
}
|
||||
|
||||
SourcePath SourcePath::resolveSymlinks(SymlinkResolution mode) const
|
||||
{
|
||||
auto res = SourcePath(accessor);
|
||||
|
||||
int linksAllowed = 1024;
|
||||
|
||||
std::list<std::string> todo;
|
||||
for (auto & c : path)
|
||||
todo.push_back(std::string(c));
|
||||
|
||||
bool resolve_last = mode == SymlinkResolution::Full;
|
||||
|
||||
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 (resolve_last || !todo.empty()) {
|
||||
if (auto st = res.maybeLstat(); st && st->type == InputAccessor::tSymlink) {
|
||||
if (!linksAllowed--)
|
||||
throw Error("infinite symlink recursion in path '%s'", path);
|
||||
auto target = res.readLink();
|
||||
res.path.pop();
|
||||
if (hasPrefix(target, "/"))
|
||||
res.path = CanonPath::root;
|
||||
todo.splice(todo.begin(), tokenizeString<std::list<std::string>>(target, "/"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & str, const SourcePath & path)
|
||||
{
|
||||
str << path.to_string();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue