Skip to content

Commit

Permalink
Add a storeFS accessor for paths resulting from IFD
Browse files Browse the repository at this point in the history
Hopefully fixes NixOS#11503.
  • Loading branch information
edolstra committed Feb 18, 2025
1 parent dcdafc6 commit 806492e
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 35 deletions.
18 changes: 7 additions & 11 deletions src/libexpr/eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,12 @@ EvalState::EvalState(
throw RestrictedPathError("access to absolute path '%1%' is forbidden %2%", path, modeInformation);
}))
: getFSSourceAccessor())
, storeFS(
makeMountedSourceAccessor(
{
{CanonPath::root, makeEmptySourceAccessor()},
{CanonPath(store->storeDir), makeFSSourceAccessor(dirOf(store->toRealPath(StorePath::dummy)))}
}))
, corepkgsFS(make_ref<MemorySourceAccessor>())
, internalFS(make_ref<MemorySourceAccessor>())
, derivationInternal{corepkgsFS->addFile(
Expand Down Expand Up @@ -422,16 +428,6 @@ void EvalState::checkURI(const std::string & uri)
}


Path EvalState::toRealPath(const Path & path, const NixStringContext & context)
{
// FIXME: check whether 'path' is in 'context'.
return
!context.empty() && store->isInStore(path)
? store->toRealPath(path)
: path;
}


Value * EvalState::addConstant(const std::string & name, Value & v, Constant info)
{
Value * v2 = allocValue();
Expand Down Expand Up @@ -2432,7 +2428,7 @@ SourcePath EvalState::coerceToPath(const PosIdx pos, Value & v, NixStringContext
auto path = coerceToString(pos, v, context, errorCtx, false, false, true).toOwned();
if (path == "" || path[0] != '/')
error<EvalError>("string '%1%' doesn't represent an absolute path", path).withTrace(pos, errorCtx).debugThrow();
return rootPath(CanonPath(path));
return stringWithContextToPath(path, context);
}


Expand Down
28 changes: 17 additions & 11 deletions src/libexpr/eval.hh
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,11 @@ public:
*/
const ref<SourceAccessor> rootFS;

/**
* The accessor for the store.
*/
const ref<SourceAccessor> storeFS;

/**
* The in-memory filesystem for <nix/...> paths.
*/
Expand Down Expand Up @@ -389,6 +394,18 @@ public:
*/
SourcePath rootPath(PathView path);

/**
* Convert `s` to a path. If `context` is not empty, the resulting
* path will use the `storeFS` accessor; otherwise it will use
* `rootFS`. When using a chroot store, this allows us to
* distinguish between store paths resulting from
* import-from-derivation and sources stored in the actual
* /nix/store.
*/
SourcePath stringWithContextToPath(
std::string_view s,
const NixStringContext & context);

/**
* Allow access to a path.
*/
Expand All @@ -412,17 +429,6 @@ public:

void checkURI(const std::string & uri);

/**
* When using a diverted store and 'path' is in the Nix store, map
* 'path' to the diverted location (e.g. /nix/store/foo is mapped
* to /home/alice/my-nix/nix/store/foo). However, this is only
* done if the context is not empty, since otherwise we're
* probably trying to read from the actual /nix/store. This is
* intended to distinguish between import-from-derivation and
* sources stored in the actual /nix/store.
*/
Path toRealPath(const Path & path, const NixStringContext & context);

/**
* Parse a Nix expression from the specified file.
*/
Expand Down
12 changes: 12 additions & 0 deletions src/libexpr/paths.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "eval.hh"
#include "store-api.hh"

namespace nix {

Expand All @@ -12,4 +13,15 @@ SourcePath EvalState::rootPath(PathView path)
return {rootFS, CanonPath(absPath(path))};
}

SourcePath EvalState::stringWithContextToPath(
std::string_view s,
const NixStringContext & context)
{
auto path = CanonPath(s);
return
!context.empty()
? SourcePath{storeFS, std::move(path)}
: rootPath(std::move(path));
}

}
17 changes: 4 additions & 13 deletions src/libexpr/primops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,9 @@ static SourcePath realisePath(EvalState & state, const PosIdx pos, Value & v, st
auto path = state.coerceToPath(noPos, v, context, "while realising the context of a path");

try {
if (!context.empty() && path.accessor == state.rootFS) {
if (!context.empty() && path.accessor == state.storeFS) {
auto rewrites = state.realiseContext(context);
auto realPath = state.toRealPath(rewriteStrings(path.path.abs(), rewrites), context);
path = {path.accessor, CanonPath(realPath)};
path = {path.accessor, CanonPath(rewriteStrings(path.path.abs(), rewrites))};
}
return resolveSymlinks ? path.resolveSymlinks(*resolveSymlinks) : path;
} catch (Error & e) {
Expand Down Expand Up @@ -2481,19 +2480,11 @@ static void addPath(
try {
StorePathSet refs;

if (path.accessor == state.rootFS && state.store->isInStore(path.path.abs())) {
if (path.accessor == state.storeFS && state.store->isInStore(path.path.abs())) {
// FIXME: handle CA derivation outputs (where path needs to
// be rewritten to the actual output).
auto rewrites = state.realiseContext(context);
path = {state.rootFS, CanonPath(state.toRealPath(rewriteStrings(path.path.abs(), rewrites), context))};

try {
auto [storePath, subPath] = state.store->toStorePath(path.path.abs());
// FIXME: we should scanForReferences on the path before adding it
refs = state.store->queryPathInfo(storePath)->references;
path = {state.rootFS, CanonPath(state.store->toRealPath(storePath) + subPath)};
} catch (Error &) { // FIXME: should be InvalidPathError
}
path = {path.accessor, CanonPath(rewriteStrings(path.path.abs(), rewrites))};
}

std::unique_ptr<PathFilter> filter;
Expand Down

0 comments on commit 806492e

Please sign in to comment.