aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichal Sojka <michal.sojka@cvut.cz>2023-04-17 19:34:09 +0200
committerMichal Sojka <michal.sojka@cvut.cz>2023-04-18 14:10:49 +0200
commitd30d2dc861ddb20f035a0ae549e57fc439217b62 (patch)
treedb5d2db866c40c9f61650e6c94b3b90b3acbb060
parentc56705c025a018950ea275432c8795afb3bd4d67 (diff)
Make "NAR info file is corrupt" messages more informative
Recently, I encountered the "NAR info file 'xxxx' is corrupt" error with my binary cache. The message is not helpful in determining, which kind of corruption happened. The file, fetched with curl, looked reasonably. This commit adds more information to the error message, which should allow debugging and hopefully fixing the problem.
-rw-r--r--src/libstore/nar-info.cc32
1 files changed, 22 insertions, 10 deletions
diff --git a/src/libstore/nar-info.cc b/src/libstore/nar-info.cc
index 274cd861c..d17253741 100644
--- a/src/libstore/nar-info.cc
+++ b/src/libstore/nar-info.cc
@@ -7,15 +7,18 @@ namespace nix {
NarInfo::NarInfo(const Store & store, const std::string & s, const std::string & whence)
: ValidPathInfo(StorePath(StorePath::dummy), Hash(Hash::dummy)) // FIXME: hack
{
- auto corrupt = [&]() {
- return Error("NAR info file '%1%' is corrupt", whence);
+ unsigned line = 1;
+
+ auto corrupt = [&](const char * reason) {
+ return Error("NAR info file '%1%' is corrupt: %2%", whence,
+ std::string(reason) + (line > 0 ? " at line " + std::to_string(line) : ""));
};
auto parseHashField = [&](const std::string & s) {
try {
return Hash::parseAnyPrefixed(s);
} catch (BadHash &) {
- throw corrupt();
+ throw corrupt("bad hash");
}
};
@@ -26,12 +29,12 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
while (pos < s.size()) {
size_t colon = s.find(':', pos);
- if (colon == std::string::npos) throw corrupt();
+ if (colon == std::string::npos) throw corrupt("expecting ':'");
std::string name(s, pos, colon - pos);
size_t eol = s.find('\n', colon + 2);
- if (eol == std::string::npos) throw corrupt();
+ if (eol == std::string::npos) throw corrupt("expecting '\\n'");
std::string value(s, colon + 2, eol - colon - 2);
@@ -47,7 +50,7 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
fileHash = parseHashField(value);
else if (name == "FileSize") {
auto n = string2Int<decltype(fileSize)>(value);
- if (!n) throw corrupt();
+ if (!n) throw corrupt("invalid FileSize");
fileSize = *n;
}
else if (name == "NarHash") {
@@ -56,12 +59,12 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
}
else if (name == "NarSize") {
auto n = string2Int<decltype(narSize)>(value);
- if (!n) throw corrupt();
+ if (!n) throw corrupt("invalid NarSize");
narSize = *n;
}
else if (name == "References") {
auto refs = tokenizeString<Strings>(value, " ");
- if (!references.empty()) throw corrupt();
+ if (!references.empty()) throw corrupt("extra References");
for (auto & r : refs)
references.insert(StorePath(r));
}
@@ -72,17 +75,26 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
else if (name == "Sig")
sigs.insert(value);
else if (name == "CA") {
- if (ca) throw corrupt();
+ if (ca) throw corrupt("extra CA");
// FIXME: allow blank ca or require skipping field?
ca = ContentAddress::parseOpt(value);
}
pos = eol + 1;
+ line += 1;
}
if (compression == "") compression = "bzip2";
- if (!havePath || !haveNarHash || url.empty() || narSize == 0) throw corrupt();
+ if (!havePath || !haveNarHash || url.empty() || narSize == 0) {
+ line = 0; // don't include line information in the error
+ throw corrupt(
+ !havePath ? "StorePath missing" :
+ !haveNarHash ? "NarHash missing" :
+ url.empty() ? "URL missing" :
+ narSize == 0 ? "NarSize missing or zero"
+ : "?");
+ }
}
std::string NarInfo::to_string(const Store & store) const