mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-28 08:36:15 +02:00
Improve symlink handling
This commit is contained in:
parent
2a53574675
commit
df2aa29690
7 changed files with 51 additions and 22 deletions
|
@ -680,7 +680,7 @@ SourcePath resolveExprPath(const SourcePath & path)
|
||||||
{
|
{
|
||||||
/* If `path' is a symlink, follow it. This is so that relative
|
/* If `path' is a symlink, follow it. This is so that relative
|
||||||
path references work. */
|
path references work. */
|
||||||
SourcePath path2 { path.accessor, path.path.resolveSymlinks() };
|
auto path2 = path.resolveSymlinks();
|
||||||
|
|
||||||
/* If `path' refers to a directory, append `/default.nix'. */
|
/* If `path' refers to a directory, append `/default.nix'. */
|
||||||
if (path2.lstat().type == InputAccessor::tDirectory)
|
if (path2.lstat().type == InputAccessor::tDirectory)
|
||||||
|
|
|
@ -1376,7 +1376,8 @@ static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args,
|
||||||
/* Resolve symlinks in ‘path’, unless ‘path’ itself is a symlink
|
/* Resolve symlinks in ‘path’, unless ‘path’ itself is a symlink
|
||||||
directly in the store. The latter condition is necessary so
|
directly in the store. The latter condition is necessary so
|
||||||
e.g. nix-push does the right thing. */
|
e.g. nix-push does the right thing. */
|
||||||
if (!state.store->isStorePath(path.abs())) path = path.resolveSymlinks();
|
if (!state.store->isStorePath(path.abs()))
|
||||||
|
path = CanonPath(canonPath(path.abs(), true));
|
||||||
if (!state.store->isInStore(path.abs()))
|
if (!state.store->isInStore(path.abs()))
|
||||||
throw EvalError({
|
throw EvalError({
|
||||||
.msg = hintfmt("path '%1%' is not in the Nix store", path),
|
.msg = hintfmt("path '%1%' is not in the Nix store", path),
|
||||||
|
|
|
@ -87,6 +87,14 @@ void InputAccessor::dumpPath(
|
||||||
dump(path);
|
dump(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<InputAccessor::Stat> InputAccessor::maybeLstat(const CanonPath & path)
|
||||||
|
{
|
||||||
|
// FIXME: merge these into one operation.
|
||||||
|
if (!pathExists(path))
|
||||||
|
return {};
|
||||||
|
return lstat(path);
|
||||||
|
}
|
||||||
|
|
||||||
std::string InputAccessor::showPath(const CanonPath & path)
|
std::string InputAccessor::showPath(const CanonPath & path)
|
||||||
{
|
{
|
||||||
return "/virtual/" + std::to_string(number) + path.abs();
|
return "/virtual/" + std::to_string(number) + path.abs();
|
||||||
|
@ -157,14 +165,7 @@ struct FSInputAccessorImpl : FSInputAccessor
|
||||||
|
|
||||||
CanonPath makeAbsPath(const CanonPath & path)
|
CanonPath makeAbsPath(const CanonPath & path)
|
||||||
{
|
{
|
||||||
// FIXME: resolve symlinks in 'path' and check that any
|
return root + path;
|
||||||
// intermediate path is allowed.
|
|
||||||
auto p = root + path;
|
|
||||||
try {
|
|
||||||
return p.resolveSymlinks();
|
|
||||||
} catch (Error &) {
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkAllowed(const CanonPath & absPath) override
|
void checkAllowed(const CanonPath & absPath) override
|
||||||
|
@ -239,7 +240,10 @@ struct MemoryInputAccessorImpl : MemoryInputAccessor
|
||||||
|
|
||||||
Stat lstat(const CanonPath & path) override
|
Stat lstat(const CanonPath & path) override
|
||||||
{
|
{
|
||||||
throw UnimplementedError("MemoryInputAccessor::lstat");
|
auto i = files.find(path);
|
||||||
|
if (i != files.end())
|
||||||
|
return Stat { .type = tRegular, .isExecutable = false };
|
||||||
|
throw Error("file '%s' does not exist", path);
|
||||||
}
|
}
|
||||||
|
|
||||||
DirEntries readDirectory(const CanonPath & path) override
|
DirEntries readDirectory(const CanonPath & path) override
|
||||||
|
@ -275,4 +279,28 @@ SourcePath SourcePath::parent() const
|
||||||
return {accessor, std::move(*p)};
|
return {accessor, std::move(*p)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourcePath SourcePath::resolveSymlinks() const
|
||||||
|
{
|
||||||
|
CanonPath res("/");
|
||||||
|
|
||||||
|
for (auto & component : path) {
|
||||||
|
res.push(component);
|
||||||
|
while (true) {
|
||||||
|
if (auto st = accessor.maybeLstat(res)) {
|
||||||
|
if (st->type != InputAccessor::tSymlink) break;
|
||||||
|
auto target = accessor.readLink(res);
|
||||||
|
if (hasPrefix(target, "/"))
|
||||||
|
res = CanonPath(target);
|
||||||
|
else {
|
||||||
|
res.pop();
|
||||||
|
res.extend(CanonPath(target));
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {accessor, res};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ struct InputAccessor
|
||||||
|
|
||||||
virtual Stat lstat(const CanonPath & path) = 0;
|
virtual Stat lstat(const CanonPath & path) = 0;
|
||||||
|
|
||||||
|
std::optional<Stat> maybeLstat(const CanonPath & path);
|
||||||
|
|
||||||
typedef std::optional<Type> DirEntry;
|
typedef std::optional<Type> DirEntry;
|
||||||
|
|
||||||
typedef std::map<std::string, DirEntry> DirEntries;
|
typedef std::map<std::string, DirEntry> DirEntries;
|
||||||
|
@ -101,6 +103,9 @@ struct SourcePath
|
||||||
InputAccessor::Stat lstat() const
|
InputAccessor::Stat lstat() const
|
||||||
{ return accessor.lstat(path); }
|
{ return accessor.lstat(path); }
|
||||||
|
|
||||||
|
std::optional<InputAccessor::Stat> maybeLstat() const
|
||||||
|
{ return accessor.maybeLstat(path); }
|
||||||
|
|
||||||
InputAccessor::DirEntries readDirectory() const
|
InputAccessor::DirEntries readDirectory() const
|
||||||
{ return accessor.readDirectory(path); }
|
{ return accessor.readDirectory(path); }
|
||||||
|
|
||||||
|
@ -132,6 +137,8 @@ struct SourcePath
|
||||||
{
|
{
|
||||||
return std::tie(accessor, path) < std::tie(x.accessor, x.path);
|
return std::tie(accessor, path) < std::tie(x.accessor, x.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourcePath resolveSymlinks() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream & operator << (std::ostream & str, const SourcePath & path);
|
std::ostream & operator << (std::ostream & str, const SourcePath & path);
|
||||||
|
|
|
@ -26,11 +26,6 @@ void CanonPath::pop()
|
||||||
path.resize(std::max((size_t) 1, slash));
|
path.resize(std::max((size_t) 1, slash));
|
||||||
}
|
}
|
||||||
|
|
||||||
CanonPath CanonPath::resolveSymlinks() const
|
|
||||||
{
|
|
||||||
return CanonPath(unchecked_t(), canonPath(abs(), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CanonPath::isWithin(const CanonPath & parent) const
|
bool CanonPath::isWithin(const CanonPath & parent) const
|
||||||
{
|
{
|
||||||
return !(
|
return !(
|
||||||
|
|
|
@ -91,8 +91,8 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Iterator begin() { return Iterator(rel()); }
|
Iterator begin() const { return Iterator(rel()); }
|
||||||
Iterator end() { return Iterator(rel().substr(path.size() - 1)); }
|
Iterator end() const { return Iterator(rel().substr(path.size() - 1)); }
|
||||||
|
|
||||||
std::optional<CanonPath> parent() const;
|
std::optional<CanonPath> parent() const;
|
||||||
|
|
||||||
|
@ -136,8 +136,6 @@ public:
|
||||||
return i == path.end() && j != x.path.end();
|
return i == path.end() && j != x.path.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
CanonPath resolveSymlinks() const;
|
|
||||||
|
|
||||||
/* Return true if `this` is equal to `parent` or a child of
|
/* Return true if `this` is equal to `parent` or a child of
|
||||||
`parent`. */
|
`parent`. */
|
||||||
bool isWithin(const CanonPath & parent) const;
|
bool isWithin(const CanonPath & parent) const;
|
||||||
|
|
|
@ -119,7 +119,7 @@ static void getAllExprs(EvalState & state,
|
||||||
|
|
||||||
InputAccessor::Stat st;
|
InputAccessor::Stat st;
|
||||||
try {
|
try {
|
||||||
st = path2.accessor.lstat(path2.path.resolveSymlinks());
|
st = path2.resolveSymlinks().lstat();
|
||||||
} catch (Error &) {
|
} catch (Error &) {
|
||||||
continue; // ignore dangling symlinks in ~/.nix-defexpr
|
continue; // ignore dangling symlinks in ~/.nix-defexpr
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ static void getAllExprs(EvalState & state,
|
||||||
|
|
||||||
static void loadSourceExpr(EvalState & state, const SourcePath & path, Value & v)
|
static void loadSourceExpr(EvalState & state, const SourcePath & path, Value & v)
|
||||||
{
|
{
|
||||||
auto st = path.accessor.lstat(path.path.resolveSymlinks());
|
auto st = path.resolveSymlinks().lstat();
|
||||||
|
|
||||||
if (isNixExpr(path, st))
|
if (isNixExpr(path, st))
|
||||||
state.evalFile(path, v);
|
state.evalFile(path, v);
|
||||||
|
|
Loading…
Reference in a new issue