mirror of
https://github.com/NixOS/nix
synced 2025-06-25 06:31:14 +02:00
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>
131 lines
3.3 KiB
C++
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;
|
|
}
|
|
|
|
}
|