1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-27 08:31:16 +02:00

Unify the two implementations of dumpPath()

This commit is contained in:
Eelco Dolstra 2023-10-19 15:07:56 +02:00
parent fb6a3910c4
commit 9f572eb0e3
2 changed files with 108 additions and 147 deletions

View file

@ -14,6 +14,7 @@
#include "archive.hh" #include "archive.hh"
#include "util.hh" #include "util.hh"
#include "config.hh" #include "config.hh"
#include "source-accessor.hh"
namespace nix { namespace nix {
@ -36,91 +37,134 @@ static GlobalConfig::Register rArchiveSettings(&archiveSettings);
PathFilter defaultPathFilter = [](const Path &) { return true; }; PathFilter defaultPathFilter = [](const Path &) { return true; };
static void dumpContents(const Path & path, off_t size, void SourceAccessor::dumpPath(
Sink & sink) const CanonPath & path,
Sink & sink,
PathFilter & filter)
{ {
sink << "contents" << size; auto dumpContents = [&](const CanonPath & path)
{
/* It would be nice if this was streaming, but we need the
size before the contents. */
auto s = readFile(path);
sink << "contents" << s.size();
sink(s);
writePadding(s.size(), sink);
};
AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC); std::function<void(const CanonPath & path)> dump;
if (!fd) throw SysError("opening file '%1%'", path);
std::vector<char> buf(65536); dump = [&](const CanonPath & path) {
size_t left = size; checkInterrupt();
while (left > 0) { auto st = lstat(path);
auto n = std::min(left, buf.size());
readFull(fd.get(), buf.data(), n);
left -= n;
sink({buf.data(), n});
}
writePadding(size, sink); sink << "(";
if (st.type == tRegular) {
sink << "type" << "regular";
if (st.isExecutable)
sink << "executable" << "";
dumpContents(path);
}
else if (st.type == tDirectory) {
sink << "type" << "directory";
/* If we're on a case-insensitive system like macOS, undo
the case hack applied by restorePath(). */
std::map<std::string, std::string> unhacked;
for (auto & i : readDirectory(path))
if (archiveSettings.useCaseHack) {
std::string name(i.first);
size_t pos = i.first.find(caseHackSuffix);
if (pos != std::string::npos) {
debug("removing case hack suffix from '%s'", path + i.first);
name.erase(pos);
}
if (!unhacked.emplace(name, i.first).second)
throw Error("file name collision in between '%s' and '%s'",
(path + unhacked[name]),
(path + i.first));
} else
unhacked.emplace(i.first, i.first);
for (auto & i : unhacked)
if (filter((path + i.first).abs())) {
sink << "entry" << "(" << "name" << i.first << "node";
dump(path + i.second);
sink << ")";
}
}
else if (st.type == tSymlink)
sink << "type" << "symlink" << "target" << readLink(path);
else throw Error("file '%s' has an unsupported type", path);
sink << ")";
};
sink << narVersionMagic1;
dump(path);
} }
static time_t dump(const Path & path, Sink & sink, PathFilter & filter) struct FSSourceAccessor : SourceAccessor
{ {
checkInterrupt(); time_t mtime = 0; // most recent mtime seen
auto st = lstat(path); std::string readFile(const CanonPath & path) override
time_t result = st.st_mtime; {
return nix::readFile(path.abs());
sink << "(";
if (S_ISREG(st.st_mode)) {
sink << "type" << "regular";
if (st.st_mode & S_IXUSR)
sink << "executable" << "";
dumpContents(path, st.st_size, sink);
} }
else if (S_ISDIR(st.st_mode)) { bool pathExists(const CanonPath & path) override
sink << "type" << "directory"; {
return nix::pathExists(path.abs());
}
/* If we're on a case-insensitive system like macOS, undo Stat lstat(const CanonPath & path) override
the case hack applied by restorePath(). */ {
std::map<std::string, std::string> unhacked; auto st = nix::lstat(path.abs());
for (auto & i : readDirectory(path)) mtime = std::max(mtime, st.st_mtime);
if (archiveSettings.useCaseHack) { return Stat {
std::string name(i.name); .type =
size_t pos = i.name.find(caseHackSuffix); S_ISREG(st.st_mode) ? tRegular :
if (pos != std::string::npos) { S_ISDIR(st.st_mode) ? tDirectory :
debug("removing case hack suffix from '%1%'", path + "/" + i.name); S_ISLNK(st.st_mode) ? tSymlink :
name.erase(pos); tMisc,
} .isExecutable = S_ISREG(st.st_mode) && st.st_mode & S_IXUSR
if (!unhacked.emplace(name, i.name).second) };
throw Error("file name collision in between '%1%' and '%2%'", }
(path + "/" + unhacked[name]),
(path + "/" + i.name));
} else
unhacked.emplace(i.name, i.name);
for (auto & i : unhacked) DirEntries readDirectory(const CanonPath & path) override
if (filter(path + "/" + i.first)) { {
sink << "entry" << "(" << "name" << i.first << "node"; DirEntries res;
auto tmp_mtime = dump(path + "/" + i.second, sink, filter); for (auto & entry : nix::readDirectory(path.abs())) {
if (tmp_mtime > result) { std::optional<Type> type;
result = tmp_mtime; switch (entry.type) {
} case DT_REG: type = Type::tRegular; break;
sink << ")"; case DT_LNK: type = Type::tSymlink; break;
case DT_DIR: type = Type::tDirectory; break;
} }
res.emplace(entry.name, type);
}
return res;
} }
else if (S_ISLNK(st.st_mode)) std::string readLink(const CanonPath & path) override
sink << "type" << "symlink" << "target" << readLink(path); {
return nix::readLink(path.abs());
else throw Error("file '%1%' has an unsupported type", path); }
};
sink << ")";
return result;
}
time_t dumpPathAndGetMtime(const Path & path, Sink & sink, PathFilter & filter) time_t dumpPathAndGetMtime(const Path & path, Sink & sink, PathFilter & filter)
{ {
sink << narVersionMagic1; FSSourceAccessor accessor;
return dump(path, sink, filter); accessor.dumpPath(CanonPath::fromCwd(path), sink, filter);
return accessor.mtime;
} }
void dumpPath(const Path & path, Sink & sink, PathFilter & filter) void dumpPath(const Path & path, Sink & sink, PathFilter & filter)
@ -141,17 +185,6 @@ static SerialisationError badArchive(const std::string & s)
} }
#if 0
static void skipGeneric(Source & source)
{
if (readString(source) == "(") {
while (readString(source) != ")")
skipGeneric(source);
}
}
#endif
static void parseContents(ParseSink & sink, Source & source, const Path & path) static void parseContents(ParseSink & sink, Source & source, const Path & path)
{ {
uint64_t size = readLongLong(source); uint64_t size = readLongLong(source);

View file

@ -10,78 +10,6 @@ SourceAccessor::SourceAccessor()
{ {
} }
// FIXME: merge with archive.cc.
void SourceAccessor::dumpPath(
const CanonPath & path,
Sink & sink,
PathFilter & filter)
{
auto dumpContents = [&](const CanonPath & path)
{
// FIXME: pipe
auto s = readFile(path);
sink << "contents" << s.size();
sink(s);
writePadding(s.size(), sink);
};
std::function<void(const CanonPath & path)> dump;
dump = [&](const CanonPath & path) {
checkInterrupt();
auto st = lstat(path);
sink << "(";
if (st.type == tRegular) {
sink << "type" << "regular";
if (st.isExecutable)
sink << "executable" << "";
dumpContents(path);
}
else if (st.type == tDirectory) {
sink << "type" << "directory";
/* If we're on a case-insensitive system like macOS, undo
the case hack applied by restorePath(). */
std::map<std::string, std::string> unhacked;
for (auto & i : readDirectory(path))
if (/* archiveSettings.useCaseHack */ false) { // FIXME
std::string name(i.first);
size_t pos = i.first.find(caseHackSuffix);
if (pos != std::string::npos) {
debug("removing case hack suffix from '%s'", path + i.first);
name.erase(pos);
}
if (!unhacked.emplace(name, i.first).second)
throw Error("file name collision in between '%s' and '%s'",
(path + unhacked[name]),
(path + i.first));
} else
unhacked.emplace(i.first, i.first);
for (auto & i : unhacked)
if (filter((path + i.first).abs())) {
sink << "entry" << "(" << "name" << i.first << "node";
dump(path + i.second);
sink << ")";
}
}
else if (st.type == tSymlink)
sink << "type" << "symlink" << "target" << readLink(path);
else throw Error("file '%s' has an unsupported type", path);
sink << ")";
};
sink << narVersionMagic1;
dump(path);
}
Hash SourceAccessor::hashPath( Hash SourceAccessor::hashPath(
const CanonPath & path, const CanonPath & path,
PathFilter & filter, PathFilter & filter,