1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-25 06:31:14 +02:00
nix/src/libutil/source-accessor.cc
Farid Zakaria 6aed9d877c cherry-pick https://gerrit.lix.systems/c/lix/+/2100
Cherry-pick https://gerrit.lix.systems/c/lix/+/2100

This change fixes a potential concurrency failure when accessing random
which is not thread safe.

Co-authored-by: Lily Ballard <lily@ballards.net>
2025-05-21 08:49:09 -07:00

131 lines
3.3 KiB
C++

#include <atomic>
#include "nix/util/source-accessor.hh"
namespace nix {
static std::atomic<size_t> nextNumber{0};
bool SourceAccessor::Stat::isNotNARSerialisable()
{
return this->type != tRegular && this->type != tSymlink && this->type != tDirectory;
}
std::string SourceAccessor::Stat::typeString() {
switch (this->type) {
case tRegular: return "regular";
case tSymlink: return "symlink";
case tDirectory: return "directory";
case tChar: return "character device";
case tBlock: return "block device";
case tSocket: return "socket";
case tFifo: return "fifo";
case tUnknown:
default: return "unknown";
}
return "unknown";
}
SourceAccessor::SourceAccessor()
: number(++nextNumber)
, displayPrefix{"«unknown»"}
{
}
bool SourceAccessor::pathExists(const CanonPath & path)
{
return maybeLstat(path).has_value();
}
std::string SourceAccessor::readFile(const CanonPath & path)
{
StringSink sink;
std::optional<uint64_t> size;
readFile(path, sink, [&](uint64_t _size)
{
size = _size;
});
assert(size && *size == sink.s.size());
return std::move(sink.s);
}
void SourceAccessor::readFile(
const CanonPath & path,
Sink & sink,
std::function<void(uint64_t)> sizeCallback)
{
auto s = readFile(path);
sizeCallback(s.size());
sink(s);
}
Hash SourceAccessor::hashPath(
const CanonPath & path,
PathFilter & filter,
HashAlgorithm ha)
{
HashSink sink(ha);
dumpPath(path, sink, filter);
return sink.finish().first;
}
SourceAccessor::Stat SourceAccessor::lstat(const CanonPath & path)
{
if (auto st = maybeLstat(path))
return *st;
else
throw FileNotFound("path '%s' does not exist", showPath(path));
}
void SourceAccessor::setPathDisplay(std::string displayPrefix, std::string displaySuffix)
{
this->displayPrefix = std::move(displayPrefix);
this->displaySuffix = std::move(displaySuffix);
}
std::string SourceAccessor::showPath(const CanonPath & path)
{
return displayPrefix + path.abs() + displaySuffix;
}
CanonPath SourceAccessor::resolveSymlinks(
const CanonPath & path,
SymlinkResolution mode)
{
auto res = CanonPath::root;
int linksAllowed = 1024;
std::list<std::string> todo;
for (auto & c : path)
todo.push_back(std::string(c));
while (!todo.empty()) {
auto c = *todo.begin();
todo.pop_front();
if (c == "" || c == ".")
;
else if (c == "..") {
if (!res.isRoot())
res.pop();
} else {
res.push(c);
if (mode == SymlinkResolution::Full || !todo.empty()) {
if (auto st = maybeLstat(res); st && st->type == SourceAccessor::tSymlink) {
if (!linksAllowed--)
throw Error("infinite symlink recursion in path '%s'", showPath(path));
auto target = readLink(res);
if (isAbsolute(target)) {
res = CanonPath::root;
} else {
res.pop();
}
todo.splice(todo.begin(), tokenizeString<std::list<std::string>>(target, "/"));
}
}
}
}
return res;
}
}