#include #include "nix/util/source-accessor.hh" namespace nix { static std::atomic 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 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 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 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>(target, "/")); } } } } return res; } }