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

Merge pull request #12531 from obsidiansystems/store-accessor-root

`Store::getFSAccessor`: Do not include the store dir
This commit is contained in:
Eelco Dolstra 2025-04-10 09:55:03 +02:00 committed by GitHub
commit 26cb166bca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 164 additions and 59 deletions

View file

@ -246,6 +246,30 @@ EvalState::EvalState(
} }
, repair(NoRepair) , repair(NoRepair)
, emptyBindings(0) , emptyBindings(0)
, storeFS(
makeMountedSourceAccessor(
{
{CanonPath::root, makeEmptySourceAccessor()},
/* In the pure eval case, we can simply require
valid paths. However, in the *impure* eval
case this gets in the way of the union
mechanism, because an invalid access in the
upper layer will *not* be caught by the union
source accessor, but instead abort the entire
lookup.
This happens when the store dir in the
ambient file system has a path (e.g. because
another Nix store there), but the relocated
store does not.
TODO make the various source accessors doing
access control all throw the same type of
exception, and make union source accessor
catch it, so we don't need to do this hack.
*/
{CanonPath(store->storeDir), store->getFSAccessor(settings.pureEval)},
}))
, rootFS( , rootFS(
({ ({
/* In pure eval mode, we provide a filesystem that only /* In pure eval mode, we provide a filesystem that only
@ -261,11 +285,6 @@ EvalState::EvalState(
auto realStoreDir = dirOf(store->toRealPath(StorePath::dummy)); auto realStoreDir = dirOf(store->toRealPath(StorePath::dummy));
if (settings.pureEval || store->storeDir != realStoreDir) { if (settings.pureEval || store->storeDir != realStoreDir) {
auto storeFS = makeMountedSourceAccessor(
{
{CanonPath::root, makeEmptySourceAccessor()},
{CanonPath(store->storeDir), makeFSSourceAccessor(realStoreDir)}
});
accessor = settings.pureEval accessor = settings.pureEval
? storeFS ? storeFS
: makeUnionSourceAccessor({accessor, storeFS}); : makeUnionSourceAccessor({accessor, storeFS});

View file

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

View file

@ -5,11 +5,7 @@ namespace nix {
ref<SourceAccessor> makeStorePathAccessor(ref<Store> store, const StorePath & storePath) ref<SourceAccessor> makeStorePathAccessor(ref<Store> store, const StorePath & storePath)
{ {
// FIXME: should use `store->getFSAccessor()` return projectSubdirSourceAccessor(store->getFSAccessor(), storePath.to_string());
auto root = std::filesystem::path{store->toRealPath(storePath)};
auto accessor = makeFSSourceAccessor(root);
accessor->setPathDisplay(root.string());
return accessor;
} }
} }

View file

@ -524,7 +524,7 @@ bool Worker::pathContentsGood(const StorePath & path)
res = false; res = false;
else { else {
auto current = hashPath( auto current = hashPath(
{store.getFSAccessor(), CanonPath(store.printStorePath(path))}, {store.getFSAccessor(), CanonPath(path.to_string())},
FileIngestionMethod::NixArchive, info->narHash.algo).first; FileIngestionMethod::NixArchive, info->narHash.algo).first;
Hash nullHash(HashAlgorithm::SHA256); Hash nullHash(HashAlgorithm::SHA256);
res = info->narHash == nullHash || info->narHash == current; res = info->narHash == nullHash || info->narHash == current;

View file

@ -83,7 +83,9 @@ struct DummyStore : public virtual DummyStoreConfig, public virtual Store
{ callback(nullptr); } { callback(nullptr); }
virtual ref<SourceAccessor> getFSAccessor(bool requireValidPath) override virtual ref<SourceAccessor> getFSAccessor(bool requireValidPath) override
{ unsupported("getFSAccessor"); } {
return makeEmptySourceAccessor();
}
}; };
static RegisterStoreImplementation<DummyStore, DummyStoreConfig> regDummyStore; static RegisterStoreImplementation<DummyStore, DummyStoreConfig> regDummyStore;

View file

@ -33,30 +33,35 @@ struct LocalStoreAccessor : PosixSourceAccessor
bool requireValidPath; bool requireValidPath;
LocalStoreAccessor(ref<LocalFSStore> store, bool requireValidPath) LocalStoreAccessor(ref<LocalFSStore> store, bool requireValidPath)
: store(store) : PosixSourceAccessor(std::filesystem::path{store->realStoreDir.get()})
, store(store)
, requireValidPath(requireValidPath) , requireValidPath(requireValidPath)
{ }
CanonPath toRealPath(const CanonPath & path)
{ {
auto [storePath, rest] = store->toStorePath(path.abs()); }
void requireStoreObject(const CanonPath & path)
{
auto [storePath, rest] = store->toStorePath(store->storeDir + path.abs());
if (requireValidPath && !store->isValidPath(storePath)) if (requireValidPath && !store->isValidPath(storePath))
throw InvalidPath("path '%1%' is not a valid store path", store->printStorePath(storePath)); throw InvalidPath("path '%1%' is not a valid store path", store->printStorePath(storePath));
return CanonPath(store->getRealStoreDir()) / storePath.to_string() / CanonPath(rest);
} }
std::optional<Stat> maybeLstat(const CanonPath & path) override std::optional<Stat> maybeLstat(const CanonPath & path) override
{ {
/* Handle the case where `path` is (a parent of) the store. */ /* Also allow `path` to point to the entire store, which is
if (isDirOrInDir(store->storeDir, path.abs())) needed for resolving symlinks. */
if (path.isRoot())
return Stat{ .type = tDirectory }; return Stat{ .type = tDirectory };
return PosixSourceAccessor::maybeLstat(toRealPath(path)); requireStoreObject(path);
return PosixSourceAccessor::maybeLstat(path);
} }
DirEntries readDirectory(const CanonPath & path) override DirEntries readDirectory(const CanonPath & path) override
{ {
return PosixSourceAccessor::readDirectory(toRealPath(path)); requireStoreObject(path);
return PosixSourceAccessor::readDirectory(path);
} }
void readFile( void readFile(
@ -64,12 +69,14 @@ struct LocalStoreAccessor : PosixSourceAccessor
Sink & sink, Sink & sink,
std::function<void(uint64_t)> sizeCallback) override std::function<void(uint64_t)> sizeCallback) override
{ {
return PosixSourceAccessor::readFile(toRealPath(path), sink, sizeCallback); requireStoreObject(path);
return PosixSourceAccessor::readFile(path, sink, sizeCallback);
} }
std::string readLink(const CanonPath & path) override std::string readLink(const CanonPath & path) override
{ {
return PosixSourceAccessor::readLink(toRealPath(path)); requireStoreObject(path);
return PosixSourceAccessor::readLink(path);
} }
}; };

View file

@ -1102,7 +1102,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
auto & specified = *info.ca; auto & specified = *info.ca;
auto actualHash = ({ auto actualHash = ({
auto accessor = getFSAccessor(false); auto accessor = getFSAccessor(false);
CanonPath path { printStorePath(info.path) }; CanonPath path { info.path.to_string() };
Hash h { HashAlgorithm::SHA256 }; // throwaway def to appease C++ Hash h { HashAlgorithm::SHA256 }; // throwaway def to appease C++
auto fim = specified.method.getFileIngestionMethod(); auto fim = specified.method.getFileIngestionMethod();
switch (fim) { switch (fim) {

View file

@ -51,7 +51,7 @@ ref<SourceAccessor> RemoteFSAccessor::addToCache(std::string_view hashPart, std:
std::pair<ref<SourceAccessor>, CanonPath> RemoteFSAccessor::fetch(const CanonPath & path) std::pair<ref<SourceAccessor>, CanonPath> RemoteFSAccessor::fetch(const CanonPath & path)
{ {
auto [storePath, restPath_] = store->toStorePath(path.abs()); auto [storePath, restPath_] = store->toStorePath(store->storeDir + path.abs());
auto restPath = CanonPath(restPath_); auto restPath = CanonPath(restPath_);
if (requireValidPath && !store->isValidPath(storePath)) if (requireValidPath && !store->isValidPath(storePath))

View file

@ -1233,7 +1233,7 @@ static Derivation readDerivationCommon(Store & store, const StorePath & drvPath,
auto accessor = store.getFSAccessor(requireValidPath); auto accessor = store.getFSAccessor(requireValidPath);
try { try {
return parseDerivation(store, return parseDerivation(store,
accessor->readFile(CanonPath(store.printStorePath(drvPath))), accessor->readFile(CanonPath(drvPath.to_string())),
Derivation::nameFromPath(drvPath)); Derivation::nameFromPath(drvPath));
} catch (FormatError & e) { } catch (FormatError & e) {
throw Error("error parsing derivation '%s': %s", store.printStorePath(drvPath), e.msg()); throw Error("error parsing derivation '%s': %s", store.printStorePath(drvPath), e.msg());

View file

@ -222,4 +222,10 @@ ref<SourceAccessor> makeMountedSourceAccessor(std::map<CanonPath, ref<SourceAcce
*/ */
ref<SourceAccessor> makeUnionSourceAccessor(std::vector<ref<SourceAccessor>> && accessors); ref<SourceAccessor> makeUnionSourceAccessor(std::vector<ref<SourceAccessor>> && accessors);
/**
* Creates a new source accessor which is confined to the subdirectory
* of the given source accessor.
*/
ref<SourceAccessor> projectSubdirSourceAccessor(ref<SourceAccessor>, CanonPath subdirectory);
} }

View file

@ -142,6 +142,7 @@ sources = [config_priv_h] + files(
'signature/signer.cc', 'signature/signer.cc',
'source-accessor.cc', 'source-accessor.cc',
'source-path.cc', 'source-path.cc',
'subdir-source-accessor.cc',
'strings.cc', 'strings.cc',
'suggestions.cc', 'suggestions.cc',
'tarfile.cc', 'tarfile.cc',

View file

@ -114,9 +114,11 @@ CanonPath SourceAccessor::resolveSymlinks(
if (!linksAllowed--) if (!linksAllowed--)
throw Error("infinite symlink recursion in path '%s'", showPath(path)); throw Error("infinite symlink recursion in path '%s'", showPath(path));
auto target = readLink(res); auto target = readLink(res);
res.pop(); if (isAbsolute(target)) {
if (isAbsolute(target))
res = CanonPath::root; res = CanonPath::root;
} else {
res.pop();
}
todo.splice(todo.begin(), tokenizeString<std::list<std::string>>(target, "/")); todo.splice(todo.begin(), tokenizeString<std::list<std::string>>(target, "/"));
} }
} }

View file

@ -0,0 +1,59 @@
#include "nix/util/source-accessor.hh"
namespace nix {
struct SubdirSourceAccessor : SourceAccessor
{
ref<SourceAccessor> parent;
CanonPath subdirectory;
SubdirSourceAccessor(ref<SourceAccessor> && parent, CanonPath && subdirectory)
: parent(std::move(parent))
, subdirectory(std::move(subdirectory))
{
displayPrefix.clear();
}
std::string readFile(const CanonPath & path) override
{
return parent->readFile(subdirectory / path);
}
void readFile(const CanonPath & path, Sink & sink, std::function<void(uint64_t)> sizeCallback) override
{
return parent->readFile(subdirectory / path, sink, sizeCallback);
}
bool pathExists(const CanonPath & path) override
{
return parent->pathExists(subdirectory / path);
}
std::optional<Stat> maybeLstat(const CanonPath & path) override
{
return parent->maybeLstat(subdirectory / path);
}
DirEntries readDirectory(const CanonPath & path) override
{
return parent->readDirectory(subdirectory / path);
}
std::string readLink(const CanonPath & path) override
{
return parent->readLink(subdirectory / path);
}
std::string showPath(const CanonPath & path) override
{
return displayPrefix + parent->showPath(subdirectory / path) + displaySuffix;
}
};
ref<SourceAccessor> projectSubdirSourceAccessor(ref<SourceAccessor> parent, CanonPath subdirectory)
{
return make_ref<SubdirSourceAccessor>(std::move(parent), std::move(subdirectory));
}
}

View file

@ -563,7 +563,7 @@ static void registerValidity(bool reregister, bool hashGiven, bool canonicalise)
#endif #endif
if (!hashGiven) { if (!hashGiven) {
HashResult hash = hashPath( HashResult hash = hashPath(
{store->getFSAccessor(false), CanonPath { store->printStorePath(info->path) }}, {store->getFSAccessor(false), CanonPath { info->path.to_string() }},
FileSerialisationMethod::NixArchive, HashAlgorithm::SHA256); FileSerialisationMethod::NixArchive, HashAlgorithm::SHA256);
info->narHash = hash.first; info->narHash = hash.first;
info->narSize = hash.second; info->narSize = hash.second;

View file

@ -6,21 +6,21 @@ using namespace nix;
struct MixCat : virtual Args struct MixCat : virtual Args
{ {
std::string path; void cat(ref<SourceAccessor> accessor, CanonPath path)
void cat(ref<SourceAccessor> accessor)
{ {
auto st = accessor->lstat(CanonPath(path)); auto st = accessor->lstat(path);
if (st.type != SourceAccessor::Type::tRegular) if (st.type != SourceAccessor::Type::tRegular)
throw Error("path '%1%' is not a regular file", path); throw Error("path '%1%' is not a regular file", path.abs());
logger->stop(); logger->stop();
writeFull(getStandardOutput(), accessor->readFile(CanonPath(path))); writeFull(getStandardOutput(), accessor->readFile(path));
} }
}; };
struct CmdCatStore : StoreCommand, MixCat struct CmdCatStore : StoreCommand, MixCat
{ {
std::string path;
CmdCatStore() CmdCatStore()
{ {
expectArgs({ expectArgs({
@ -44,7 +44,8 @@ struct CmdCatStore : StoreCommand, MixCat
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
cat(store->getFSAccessor()); auto [storePath, rest] = store->toStorePath(path);
cat(store->getFSAccessor(), CanonPath{storePath.to_string()} / CanonPath{rest});
} }
}; };
@ -52,6 +53,8 @@ struct CmdCatNar : StoreCommand, MixCat
{ {
Path narPath; Path narPath;
std::string path;
CmdCatNar() CmdCatNar()
{ {
expectArgs({ expectArgs({
@ -76,7 +79,7 @@ struct CmdCatNar : StoreCommand, MixCat
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
cat(makeNarAccessor(readFile(narPath))); cat(makeNarAccessor(readFile(narPath)), CanonPath{path});
} }
}; };

View file

@ -65,11 +65,11 @@ struct CmdShell : InstallablesCommand, MixEnvironment
void run(ref<Store> store, Installables && installables) override void run(ref<Store> store, Installables && installables) override
{ {
auto state = getEvalState();
auto outPaths = auto outPaths =
Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables); Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables);
auto accessor = store->getFSAccessor();
std::unordered_set<StorePath> done; std::unordered_set<StorePath> done;
std::queue<StorePath> todo; std::queue<StorePath> todo;
for (auto & path : outPaths) for (auto & path : outPaths)
@ -85,13 +85,16 @@ struct CmdShell : InstallablesCommand, MixEnvironment
if (!done.insert(path).second) if (!done.insert(path).second)
continue; continue;
if (true) auto binDir = state->storeFS->resolveSymlinks(CanonPath(store->printStorePath(path)) / "bin");
pathAdditions.push_back(store->printStorePath(path) + "/bin"); if (!store->isInStore(binDir.abs()))
throw Error("path '%s' is not in the Nix store", binDir);
auto propPath = accessor->resolveSymlinks( pathAdditions.push_back(binDir.abs());
auto propPath = state->storeFS->resolveSymlinks(
CanonPath(store->printStorePath(path)) / "nix-support" / "propagated-user-env-packages"); CanonPath(store->printStorePath(path)) / "nix-support" / "propagated-user-env-packages");
if (auto st = accessor->maybeLstat(propPath); st && st->type == SourceAccessor::tRegular) { if (auto st = state->storeFS->maybeLstat(propPath); st && st->type == SourceAccessor::tRegular) {
for (auto & p : tokenizeString<Paths>(accessor->readFile(propPath))) for (auto & p : tokenizeString<Paths>(state->storeFS->readFile(propPath)))
todo.push(store->parseStorePath(p)); 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 // 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. // 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); execProgramInStore(store, UseLookupPath::Use, *command.begin(), args);
} }

View file

@ -8,8 +8,6 @@ using namespace nix;
struct MixLs : virtual Args, MixJSON struct MixLs : virtual Args, MixJSON
{ {
std::string path;
bool recursive = false; bool recursive = false;
bool verbose = false; bool verbose = false;
bool showDirectory = false; bool showDirectory = false;
@ -38,7 +36,7 @@ struct MixLs : virtual Args, MixJSON
}); });
} }
void listText(ref<SourceAccessor> accessor) void listText(ref<SourceAccessor> accessor, CanonPath path)
{ {
std::function<void(const SourceAccessor::Stat &, const CanonPath &, std::string_view, bool)> doPath; std::function<void(const SourceAccessor::Stat &, const CanonPath &, std::string_view, bool)> doPath;
@ -77,26 +75,27 @@ struct MixLs : virtual Args, MixJSON
showFile(curPath, relPath); showFile(curPath, relPath);
}; };
auto path2 = CanonPath(path); auto st = accessor->lstat(path);
auto st = accessor->lstat(path2); doPath(st, path,
doPath(st, path2, st.type == SourceAccessor::Type::tDirectory ? "." : path.baseName().value_or(""),
st.type == SourceAccessor::Type::tDirectory ? "." : path2.baseName().value_or(""),
showDirectory); showDirectory);
} }
void list(ref<SourceAccessor> accessor) void list(ref<SourceAccessor> accessor, CanonPath path)
{ {
if (json) { if (json) {
if (showDirectory) if (showDirectory)
throw UsageError("'--directory' is useless with '--json'"); throw UsageError("'--directory' is useless with '--json'");
logger->cout("%s", listNar(accessor, CanonPath(path), recursive)); logger->cout("%s", listNar(accessor, path, recursive));
} else } else
listText(accessor); listText(accessor, std::move(path));
} }
}; };
struct CmdLsStore : StoreCommand, MixLs struct CmdLsStore : StoreCommand, MixLs
{ {
std::string path;
CmdLsStore() CmdLsStore()
{ {
expectArgs({ expectArgs({
@ -120,7 +119,8 @@ struct CmdLsStore : StoreCommand, MixLs
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
list(store->getFSAccessor()); auto [storePath, rest] = store->toStorePath(path);
list(store->getFSAccessor(), CanonPath{storePath.to_string()} / CanonPath{rest});
} }
}; };
@ -128,6 +128,8 @@ struct CmdLsNar : Command, MixLs
{ {
Path narPath; Path narPath;
std::string path;
CmdLsNar() CmdLsNar()
{ {
expectArgs({ expectArgs({
@ -152,7 +154,7 @@ struct CmdLsNar : Command, MixLs
void run() override void run() override
{ {
list(makeNarAccessor(readFile(narPath))); list(makeNarAccessor(readFile(narPath)), CanonPath{path});
} }
}; };

View file

@ -172,7 +172,7 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
struct BailOut { }; struct BailOut { };
printNode = [&](Node & node, const std::string & firstPad, const std::string & tailPad) { printNode = [&](Node & node, const std::string & firstPad, const std::string & tailPad) {
CanonPath pathS(store->printStorePath(node.path)); CanonPath pathS(node.path.to_string());
assert(node.dist != inf); assert(node.dist != inf);
if (precise) { if (precise) {