1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-25 10:41:16 +02:00

nix shell: Resolve symlinks in storeFS

`storeFS` is the `MountedSourceAccessor` that wraps `store->getFSAccessor()`.
This commit is contained in:
Eelco Dolstra 2025-03-26 21:07:17 +01:00 committed by John Ericson
parent eb643d034f
commit 9d3595646d
4 changed files with 42 additions and 33 deletions

View file

@ -246,22 +246,8 @@ EvalState::EvalState(
}
, repair(NoRepair)
, emptyBindings(0)
, rootFS(
({
/* In pure eval mode, we provide a filesystem that only
contains the Nix store.
If we have a chroot store and pure eval is not enabled,
use a union accessor to make the chroot store available
at its logical location while still having the
underlying directory available. This is necessary for
instance if we're evaluating a file from the physical
/nix/store while using a chroot store. */
auto accessor = getFSSourceAccessor();
auto realStoreDir = dirOf(store->toRealPath(StorePath::dummy));
if (settings.pureEval || store->storeDir != realStoreDir) {
auto storeFS = makeMountedSourceAccessor(
, storeFS(
makeMountedSourceAccessor(
{
{CanonPath::root, makeEmptySourceAccessor()},
/* In the pure eval case, we can simply require
@ -283,7 +269,22 @@ EvalState::EvalState(
catch it, so we don't need to do this hack.
*/
{CanonPath(store->storeDir), store->getFSAccessor(settings.pureEval)},
});
}))
, rootFS(
({
/* In pure eval mode, we provide a filesystem that only
contains the Nix store.
If we have a chroot store and pure eval is not enabled,
use a union accessor to make the chroot store available
at its logical location while still having the
underlying directory available. This is necessary for
instance if we're evaluating a file from the physical
/nix/store while using a chroot store. */
auto accessor = getFSSourceAccessor();
auto realStoreDir = dirOf(store->toRealPath(StorePath::dummy));
if (settings.pureEval || store->storeDir != realStoreDir) {
accessor = settings.pureEval
? storeFS
: makeUnionSourceAccessor({accessor, storeFS});

View file

@ -265,6 +265,11 @@ public:
/** `"unknown"` */
Value vStringUnknown;
/**
* The accessor corresponding to `store`.
*/
const ref<SourceAccessor> storeFS;
/**
* The accessor for the root filesystem.
*/

View file

@ -65,11 +65,11 @@ struct CmdShell : InstallablesCommand, MixEnvironment
void run(ref<Store> store, Installables && installables) override
{
auto state = getEvalState();
auto outPaths =
Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables);
auto accessor = store->getFSAccessor();
std::unordered_set<StorePath> done;
std::queue<StorePath> todo;
for (auto & path : outPaths)
@ -85,13 +85,16 @@ struct CmdShell : InstallablesCommand, MixEnvironment
if (!done.insert(path).second)
continue;
if (true)
pathAdditions.push_back(store->printStorePath(path) + "/bin");
auto binDir = state->storeFS->resolveSymlinks(CanonPath(store->printStorePath(path)) / "bin");
if (!store->isInStore(binDir.abs()))
throw Error("path '%s' is not in the Nix store", binDir);
auto propPath =
accessor->resolveSymlinks(CanonPath(path.to_string()) / "nix-support" / "propagated-user-env-packages");
if (auto st = accessor->maybeLstat(propPath); st && st->type == SourceAccessor::tRegular) {
for (auto & p : tokenizeString<Paths>(accessor->readFile(propPath)))
pathAdditions.push_back(binDir.abs());
auto propPath = state->storeFS->resolveSymlinks(
CanonPath(store->printStorePath(path)) / "nix-support" / "propagated-user-env-packages");
if (auto st = state->storeFS->maybeLstat(propPath); st && st->type == SourceAccessor::tRegular) {
for (auto & p : tokenizeString<Paths>(state->storeFS->readFile(propPath)))
todo.push(store->parseStorePath(p));
}
}
@ -108,7 +111,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment
// Release our references to eval caches to ensure they are persisted to disk, because
// we are about to exec out of this process without running C++ destructors.
getEvalState()->evalCaches.clear();
state->evalCaches.clear();
execProgramInStore(store, UseLookupPath::Use, *command.begin(), args);
}

View file

@ -21,7 +21,7 @@ nix shell -f shell-hello.nix 'hello^*' -c hello2 | grep 'Hello2'
nix shell -f shell-hello.nix hello-symlink -c hello | grep 'Hello World'
# Test that symlinks outside of the store don't work.
expect 1 nix shell -f shell-hello.nix forbidden-symlink -c hello 2>&1 | grepQuiet "points outside source tree"
expect 1 nix shell -f shell-hello.nix forbidden-symlink -c hello 2>&1 | grepQuiet "is not in the Nix store"
# Test that we're not setting any more environment variables than necessary.
# For instance, we might set an environment variable temporarily to affect some