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:
parent
fb6a3910c4
commit
9f572eb0e3
2 changed files with 108 additions and 147 deletions
|
@ -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,45 +37,38 @@ 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;
|
|
||||||
|
|
||||||
while (left > 0) {
|
|
||||||
auto n = std::min(left, buf.size());
|
|
||||||
readFull(fd.get(), buf.data(), n);
|
|
||||||
left -= n;
|
|
||||||
sink({buf.data(), n});
|
|
||||||
}
|
|
||||||
|
|
||||||
writePadding(size, sink);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static time_t dump(const Path & path, Sink & sink, PathFilter & filter)
|
|
||||||
{
|
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
|
||||||
auto st = lstat(path);
|
auto st = lstat(path);
|
||||||
time_t result = st.st_mtime;
|
|
||||||
|
|
||||||
sink << "(";
|
sink << "(";
|
||||||
|
|
||||||
if (S_ISREG(st.st_mode)) {
|
if (st.type == tRegular) {
|
||||||
sink << "type" << "regular";
|
sink << "type" << "regular";
|
||||||
if (st.st_mode & S_IXUSR)
|
if (st.isExecutable)
|
||||||
sink << "executable" << "";
|
sink << "executable" << "";
|
||||||
dumpContents(path, st.st_size, sink);
|
dumpContents(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (S_ISDIR(st.st_mode)) {
|
else if (st.type == tDirectory) {
|
||||||
sink << "type" << "directory";
|
sink << "type" << "directory";
|
||||||
|
|
||||||
/* If we're on a case-insensitive system like macOS, undo
|
/* If we're on a case-insensitive system like macOS, undo
|
||||||
|
@ -82,45 +76,95 @@ static time_t dump(const Path & path, Sink & sink, PathFilter & filter)
|
||||||
std::map<std::string, std::string> unhacked;
|
std::map<std::string, std::string> unhacked;
|
||||||
for (auto & i : readDirectory(path))
|
for (auto & i : readDirectory(path))
|
||||||
if (archiveSettings.useCaseHack) {
|
if (archiveSettings.useCaseHack) {
|
||||||
std::string name(i.name);
|
std::string name(i.first);
|
||||||
size_t pos = i.name.find(caseHackSuffix);
|
size_t pos = i.first.find(caseHackSuffix);
|
||||||
if (pos != std::string::npos) {
|
if (pos != std::string::npos) {
|
||||||
debug("removing case hack suffix from '%1%'", path + "/" + i.name);
|
debug("removing case hack suffix from '%s'", path + i.first);
|
||||||
name.erase(pos);
|
name.erase(pos);
|
||||||
}
|
}
|
||||||
if (!unhacked.emplace(name, i.name).second)
|
if (!unhacked.emplace(name, i.first).second)
|
||||||
throw Error("file name collision in between '%1%' and '%2%'",
|
throw Error("file name collision in between '%s' and '%s'",
|
||||||
(path + "/" + unhacked[name]),
|
(path + unhacked[name]),
|
||||||
(path + "/" + i.name));
|
(path + i.first));
|
||||||
} else
|
} else
|
||||||
unhacked.emplace(i.name, i.name);
|
unhacked.emplace(i.first, i.first);
|
||||||
|
|
||||||
for (auto & i : unhacked)
|
for (auto & i : unhacked)
|
||||||
if (filter(path + "/" + i.first)) {
|
if (filter((path + i.first).abs())) {
|
||||||
sink << "entry" << "(" << "name" << i.first << "node";
|
sink << "entry" << "(" << "name" << i.first << "node";
|
||||||
auto tmp_mtime = dump(path + "/" + i.second, sink, filter);
|
dump(path + i.second);
|
||||||
if (tmp_mtime > result) {
|
|
||||||
result = tmp_mtime;
|
|
||||||
}
|
|
||||||
sink << ")";
|
sink << ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (S_ISLNK(st.st_mode))
|
else if (st.type == tSymlink)
|
||||||
sink << "type" << "symlink" << "target" << readLink(path);
|
sink << "type" << "symlink" << "target" << readLink(path);
|
||||||
|
|
||||||
else throw Error("file '%1%' has an unsupported type", path);
|
else throw Error("file '%s' has an unsupported type", path);
|
||||||
|
|
||||||
sink << ")";
|
sink << ")";
|
||||||
|
};
|
||||||
|
|
||||||
return result;
|
sink << narVersionMagic1;
|
||||||
|
dump(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct FSSourceAccessor : SourceAccessor
|
||||||
|
{
|
||||||
|
time_t mtime = 0; // most recent mtime seen
|
||||||
|
|
||||||
|
std::string readFile(const CanonPath & path) override
|
||||||
|
{
|
||||||
|
return nix::readFile(path.abs());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pathExists(const CanonPath & path) override
|
||||||
|
{
|
||||||
|
return nix::pathExists(path.abs());
|
||||||
|
}
|
||||||
|
|
||||||
|
Stat lstat(const CanonPath & path) override
|
||||||
|
{
|
||||||
|
auto st = nix::lstat(path.abs());
|
||||||
|
mtime = std::max(mtime, st.st_mtime);
|
||||||
|
return Stat {
|
||||||
|
.type =
|
||||||
|
S_ISREG(st.st_mode) ? tRegular :
|
||||||
|
S_ISDIR(st.st_mode) ? tDirectory :
|
||||||
|
S_ISLNK(st.st_mode) ? tSymlink :
|
||||||
|
tMisc,
|
||||||
|
.isExecutable = S_ISREG(st.st_mode) && st.st_mode & S_IXUSR
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
DirEntries readDirectory(const CanonPath & path) override
|
||||||
|
{
|
||||||
|
DirEntries res;
|
||||||
|
for (auto & entry : nix::readDirectory(path.abs())) {
|
||||||
|
std::optional<Type> type;
|
||||||
|
switch (entry.type) {
|
||||||
|
case DT_REG: type = Type::tRegular; break;
|
||||||
|
case DT_LNK: type = Type::tSymlink; break;
|
||||||
|
case DT_DIR: type = Type::tDirectory; break;
|
||||||
|
}
|
||||||
|
res.emplace(entry.name, type);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string readLink(const CanonPath & path) override
|
||||||
|
{
|
||||||
|
return nix::readLink(path.abs());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue