1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-09 03:56:01 +01:00

Merge pull request #14080 from NixOS/storeFS-prep

Some `storeFS` and similar cleanup
This commit is contained in:
John Ericson 2025-09-25 10:50:25 -04:00 committed by GitHub
commit 46095284f1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 80 additions and 35 deletions

View file

@ -17,6 +17,7 @@
#include "nix/expr/print.hh" #include "nix/expr/print.hh"
#include "nix/fetchers/filtering-source-accessor.hh" #include "nix/fetchers/filtering-source-accessor.hh"
#include "nix/util/memory-source-accessor.hh" #include "nix/util/memory-source-accessor.hh"
#include "nix/util/mounted-source-accessor.hh"
#include "nix/expr/gc-small-vector.hh" #include "nix/expr/gc-small-vector.hh"
#include "nix/util/url.hh" #include "nix/util/url.hh"
#include "nix/fetchers/fetch-to-store.hh" #include "nix/fetchers/fetch-to-store.hh"
@ -225,22 +226,25 @@ EvalState::EvalState(
*/ */
{CanonPath(store->storeDir), store->getFSAccessor(settings.pureEval)}, {CanonPath(store->storeDir), store->getFSAccessor(settings.pureEval)},
})) }))
, rootFS(({ , rootFS([&] {
/* In pure eval mode, we provide a filesystem that only auto accessor = [&]() -> decltype(rootFS) {
contains the Nix store. /* In pure eval mode, we provide a filesystem that only
contains the Nix store. */
if (settings.pureEval)
return storeFS;
If we have a chroot store and pure eval is not enabled, /* If we have a chroot store and pure eval is not enabled,
use a union accessor to make the chroot store available use a union accessor to make the chroot store available
at its logical location while still having the at its logical location while still having the underlying
underlying directory available. This is necessary for directory available. This is necessary for instance if
instance if we're evaluating a file from the physical we're evaluating a file from the physical /nix/store
/nix/store while using a chroot store. */ while using a chroot store. */
auto accessor = getFSSourceAccessor(); auto realStoreDir = dirOf(store->toRealPath(StorePath::dummy));
if (store->storeDir != realStoreDir)
return makeUnionSourceAccessor({getFSSourceAccessor(), storeFS});
auto realStoreDir = dirOf(store->toRealPath(StorePath::dummy)); return getFSSourceAccessor();
if (settings.pureEval || store->storeDir != realStoreDir) { }();
accessor = settings.pureEval ? storeFS : makeUnionSourceAccessor({accessor, storeFS});
}
/* Apply access control if needed. */ /* Apply access control if needed. */
if (settings.restrictEval || settings.pureEval) if (settings.restrictEval || settings.pureEval)
@ -251,8 +255,8 @@ EvalState::EvalState(
throw RestrictedPathError("access to absolute path '%1%' is forbidden %2%", path, modeInformation); throw RestrictedPathError("access to absolute path '%1%' is forbidden %2%", path, modeInformation);
}); });
accessor; return accessor;
})) }())
, corepkgsFS(make_ref<MemorySourceAccessor>()) , corepkgsFS(make_ref<MemorySourceAccessor>())
, internalFS(make_ref<MemorySourceAccessor>()) , internalFS(make_ref<MemorySourceAccessor>())
, derivationInternal{corepkgsFS->addFile( , derivationInternal{corepkgsFS->addFile(
@ -334,7 +338,7 @@ EvalState::EvalState(
EvalState::~EvalState() {} EvalState::~EvalState() {}
void EvalState::allowPath(const Path & path) void EvalState::allowPathLegacy(const Path & path)
{ {
if (auto rootFS2 = rootFS.dynamic_pointer_cast<AllowListSourceAccessor>()) if (auto rootFS2 = rootFS.dynamic_pointer_cast<AllowListSourceAccessor>())
rootFS2->allowPrefix(CanonPath(path)); rootFS2->allowPrefix(CanonPath(path));
@ -3177,7 +3181,7 @@ std::optional<SourcePath> EvalState::resolveLookupPathPath(const LookupPath::Pat
/* Allow access to paths in the search path. */ /* Allow access to paths in the search path. */
if (initAccessControl) { if (initAccessControl) {
allowPath(path.path.abs()); allowPathLegacy(path.path.abs());
if (store->isInStore(path.path.abs())) { if (store->isInStore(path.path.abs())) {
try { try {
allowClosure(store->toStorePath(path.path.abs()).first); allowClosure(store->toStorePath(path.path.abs()).first);

View file

@ -49,6 +49,7 @@ class StorePath;
struct SingleDerivedPath; struct SingleDerivedPath;
enum RepairFlag : bool; enum RepairFlag : bool;
struct MemorySourceAccessor; struct MemorySourceAccessor;
struct MountedSourceAccessor;
namespace eval_cache { namespace eval_cache {
class EvalCache; class EvalCache;
@ -320,7 +321,7 @@ public:
/** /**
* The accessor corresponding to `store`. * The accessor corresponding to `store`.
*/ */
const ref<SourceAccessor> storeFS; const ref<MountedSourceAccessor> storeFS;
/** /**
* The accessor for the root filesystem. * The accessor for the root filesystem.
@ -489,8 +490,11 @@ public:
/** /**
* Allow access to a path. * Allow access to a path.
*
* Only for restrict eval: pure eval just whitelist store paths,
* never arbitrary paths.
*/ */
void allowPath(const Path & path); void allowPathLegacy(const Path & path);
/** /**
* Allow access to a store path. Note that this gets remapped to * Allow access to a store path. Note that this gets remapped to

View file

@ -15,6 +15,7 @@
#include "nix/fetchers/fetch-settings.hh" #include "nix/fetchers/fetch-settings.hh"
#include "nix/util/json-utils.hh" #include "nix/util/json-utils.hh"
#include "nix/util/archive.hh" #include "nix/util/archive.hh"
#include "nix/util/mounted-source-accessor.hh"
#include <regex> #include <regex>
#include <string.h> #include <string.h>

View file

@ -47,6 +47,7 @@ headers = files(
'logging.hh', 'logging.hh',
'lru-cache.hh', 'lru-cache.hh',
'memory-source-accessor.hh', 'memory-source-accessor.hh',
'mounted-source-accessor.hh',
'muxable-pipe.hh', 'muxable-pipe.hh',
'os-string.hh', 'os-string.hh',
'pool.hh', 'pool.hh',

View file

@ -0,0 +1,20 @@
#pragma once
#include "source-accessor.hh"
namespace nix {
struct MountedSourceAccessor : SourceAccessor
{
virtual void mount(CanonPath mountPoint, ref<SourceAccessor> accessor) = 0;
/**
* Return the accessor mounted on `mountPoint`, or `nullptr` if
* there is no such mount point.
*/
virtual std::shared_ptr<SourceAccessor> getMount(CanonPath mountPoint) = 0;
};
ref<MountedSourceAccessor> makeMountedSourceAccessor(std::map<CanonPath, ref<SourceAccessor>> mounts);
} // namespace nix

View file

@ -214,8 +214,6 @@ ref<SourceAccessor> getFSSourceAccessor();
*/ */
ref<SourceAccessor> makeFSSourceAccessor(std::filesystem::path root); ref<SourceAccessor> makeFSSourceAccessor(std::filesystem::path root);
ref<SourceAccessor> makeMountedSourceAccessor(std::map<CanonPath, ref<SourceAccessor>> mounts);
/** /**
* Construct an accessor that presents a "union" view of a vector of * Construct an accessor that presents a "union" view of a vector of
* underlying accessors. Earlier accessors take precedence over later. * underlying accessors. Earlier accessors take precedence over later.

View file

@ -1,18 +1,22 @@
#include "nix/util/source-accessor.hh" #include "nix/util/mounted-source-accessor.hh"
#include <boost/unordered/concurrent_flat_map.hpp>
namespace nix { namespace nix {
struct MountedSourceAccessor : SourceAccessor struct MountedSourceAccessorImpl : MountedSourceAccessor
{ {
std::map<CanonPath, ref<SourceAccessor>> mounts; boost::concurrent_flat_map<CanonPath, ref<SourceAccessor>> mounts;
MountedSourceAccessor(std::map<CanonPath, ref<SourceAccessor>> _mounts) MountedSourceAccessorImpl(std::map<CanonPath, ref<SourceAccessor>> _mounts)
: mounts(std::move(_mounts))
{ {
displayPrefix.clear(); displayPrefix.clear();
// Currently we require a root filesystem. This could be relaxed. // Currently we require a root filesystem. This could be relaxed.
assert(mounts.contains(CanonPath::root)); assert(_mounts.contains(CanonPath::root));
for (auto & [path, accessor] : _mounts)
mount(path, accessor);
// FIXME: return dummy parent directories automatically? // FIXME: return dummy parent directories automatically?
} }
@ -52,10 +56,9 @@ struct MountedSourceAccessor : SourceAccessor
// Find the nearest parent of `path` that is a mount point. // Find the nearest parent of `path` that is a mount point.
std::vector<std::string> subpath; std::vector<std::string> subpath;
while (true) { while (true) {
auto i = mounts.find(path); if (auto mount = getMount(path)) {
if (i != mounts.end()) {
std::reverse(subpath.begin(), subpath.end()); std::reverse(subpath.begin(), subpath.end());
return {i->second, CanonPath(subpath)}; return {ref(mount), CanonPath(subpath)};
} }
assert(!path.isRoot()); assert(!path.isRoot());
@ -69,11 +72,24 @@ struct MountedSourceAccessor : SourceAccessor
auto [accessor, subpath] = resolve(path); auto [accessor, subpath] = resolve(path);
return accessor->getPhysicalPath(subpath); return accessor->getPhysicalPath(subpath);
} }
void mount(CanonPath mountPoint, ref<SourceAccessor> accessor) override
{
mounts.emplace(std::move(mountPoint), std::move(accessor));
}
std::shared_ptr<SourceAccessor> getMount(CanonPath mountPoint) override
{
if (auto res = getConcurrent(mounts, mountPoint))
return *res;
else
return nullptr;
}
}; };
ref<SourceAccessor> makeMountedSourceAccessor(std::map<CanonPath, ref<SourceAccessor>> mounts) ref<MountedSourceAccessor> makeMountedSourceAccessor(std::map<CanonPath, ref<SourceAccessor>> mounts)
{ {
return make_ref<MountedSourceAccessor>(std::move(mounts)); return make_ref<MountedSourceAccessorImpl>(std::move(mounts));
} }
} // namespace nix } // namespace nix

View file

@ -7,6 +7,7 @@
#include "nix/util/strings.hh" #include "nix/util/strings.hh"
#include "nix/util/executable-path.hh" #include "nix/util/executable-path.hh"
#include "nix/util/environment-variables.hh" #include "nix/util/environment-variables.hh"
#include "nix/util/mounted-source-accessor.hh"
using namespace nix; using namespace nix;

View file

@ -177,8 +177,8 @@ struct ProfileManifest
else if (std::filesystem::exists(profile / "manifest.nix")) { else if (std::filesystem::exists(profile / "manifest.nix")) {
// FIXME: needed because of pure mode; ugly. // FIXME: needed because of pure mode; ugly.
state.allowPath(state.store->followLinksToStore(profile.string())); state.allowPath(state.store->followLinksToStorePath(profile.string()));
state.allowPath(state.store->followLinksToStore((profile / "manifest.nix").string())); state.allowPath(state.store->followLinksToStorePath((profile / "manifest.nix").string()));
auto packageInfos = queryInstalled(state, state.store->followLinksToStore(profile.string())); auto packageInfos = queryInstalled(state, state.store->followLinksToStore(profile.string()));