1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-16 15:32:43 +01:00
nix/src/libstore/local-fs-store.cc
John Ericson a97d6d89d8 Create a second Store::getFSAccessor for a single store object
This is sometimes easier / more performant to implement, and
independently it is also a more convenient interface for many callers.

The existing store-wide `getFSAccessor` is only used for

 - `nix why-depends`
 - the evaluator

I hope we can get rid of it for those, too, and then we have the option
of getting rid of the store-wide method.

Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>
2025-09-24 15:49:14 -04:00

145 lines
4.4 KiB
C++

#include "nix/util/archive.hh"
#include "nix/util/posix-source-accessor.hh"
#include "nix/store/store-api.hh"
#include "nix/store/local-fs-store.hh"
#include "nix/store/globals.hh"
#include "nix/util/compression.hh"
#include "nix/store/derivations.hh"
namespace nix {
Path LocalFSStoreConfig::getDefaultStateDir()
{
return settings.nixStateDir;
}
Path LocalFSStoreConfig::getDefaultLogDir()
{
return settings.nixLogDir;
}
LocalFSStoreConfig::LocalFSStoreConfig(PathView rootDir, const Params & params)
: StoreConfig(params)
// Default `?root` from `rootDir` if non set
// FIXME don't duplicate description once we don't have root setting
, rootDir{
this,
!rootDir.empty() && params.count("root") == 0 ? (std::optional<Path>{rootDir}) : std::nullopt,
"root",
"Directory prefixed to all other paths."}
{
}
LocalFSStore::LocalFSStore(const Config & config)
: Store{static_cast<const Store::Config &>(*this)}
, config{config}
{
}
struct LocalStoreAccessor : PosixSourceAccessor
{
ref<LocalFSStore> store;
bool requireValidPath;
LocalStoreAccessor(ref<LocalFSStore> store, bool requireValidPath)
: PosixSourceAccessor(std::filesystem::path{store->config.realStoreDir.get()})
, store(store)
, requireValidPath(requireValidPath)
{
}
void requireStoreObject(const CanonPath & path)
{
auto [storePath, rest] = store->toStorePath(store->storeDir + path.abs());
if (requireValidPath && !store->isValidPath(storePath))
throw InvalidPath("path '%1%' is not a valid store path", store->printStorePath(storePath));
}
std::optional<Stat> maybeLstat(const CanonPath & path) override
{
/* Also allow `path` to point to the entire store, which is
needed for resolving symlinks. */
if (path.isRoot())
return Stat{.type = tDirectory};
requireStoreObject(path);
return PosixSourceAccessor::maybeLstat(path);
}
DirEntries readDirectory(const CanonPath & path) override
{
requireStoreObject(path);
return PosixSourceAccessor::readDirectory(path);
}
void readFile(const CanonPath & path, Sink & sink, std::function<void(uint64_t)> sizeCallback) override
{
requireStoreObject(path);
return PosixSourceAccessor::readFile(path, sink, sizeCallback);
}
std::string readLink(const CanonPath & path) override
{
requireStoreObject(path);
return PosixSourceAccessor::readLink(path);
}
};
ref<SourceAccessor> LocalFSStore::getFSAccessor(bool requireValidPath)
{
return make_ref<LocalStoreAccessor>(
ref<LocalFSStore>(std::dynamic_pointer_cast<LocalFSStore>(shared_from_this())), requireValidPath);
}
std::shared_ptr<SourceAccessor> LocalFSStore::getFSAccessor(const StorePath & path, bool requireValidPath)
{
auto absPath = std::filesystem::path{config.realStoreDir.get()} / path.to_string();
if (requireValidPath) {
/* Only return non-null if the store object is a fully-valid
member of the store. */
if (!isValidPath(path))
return nullptr;
} else {
/* Return non-null as long as the some file system data exists,
even if the store object is not fully registered. */
if (!pathExists(absPath))
return nullptr;
}
return std::make_shared<PosixSourceAccessor>(std::move(absPath));
}
void LocalFSStore::narFromPath(const StorePath & path, Sink & sink)
{
if (!isValidPath(path))
throw Error("path '%s' is not valid", printStorePath(path));
dumpPath(getRealStoreDir() + std::string(printStorePath(path), storeDir.size()), sink);
}
const std::string LocalFSStore::drvsLogDir = "drvs";
std::optional<std::string> LocalFSStore::getBuildLogExact(const StorePath & path)
{
auto baseName = path.to_string();
for (int j = 0; j < 2; j++) {
Path logPath =
j == 0 ? fmt("%s/%s/%s/%s", config.logDir.get(), drvsLogDir, baseName.substr(0, 2), baseName.substr(2))
: fmt("%s/%s/%s", config.logDir.get(), drvsLogDir, baseName);
Path logBz2Path = logPath + ".bz2";
if (pathExists(logPath))
return readFile(logPath);
else if (pathExists(logBz2Path)) {
try {
return decompress("bzip2", readFile(logBz2Path));
} catch (Error &) {
}
}
}
return std::nullopt;
}
} // namespace nix