forked from lix-project/lix
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.
This commit is contained in:
parent
c56705c025
commit
d30d2dc861
|
@ -7,15 +7,18 @@ namespace nix {
|
||||||
NarInfo::NarInfo(const Store & store, const std::string & s, const std::string & whence)
|
NarInfo::NarInfo(const Store & store, const std::string & s, const std::string & whence)
|
||||||
: ValidPathInfo(StorePath(StorePath::dummy), Hash(Hash::dummy)) // FIXME: hack
|
: ValidPathInfo(StorePath(StorePath::dummy), Hash(Hash::dummy)) // FIXME: hack
|
||||||
{
|
{
|
||||||
auto corrupt = [&]() {
|
unsigned line = 1;
|
||||||
return Error("NAR info file '%1%' is corrupt", whence);
|
|
||||||
|
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) {
|
auto parseHashField = [&](const std::string & s) {
|
||||||
try {
|
try {
|
||||||
return Hash::parseAnyPrefixed(s);
|
return Hash::parseAnyPrefixed(s);
|
||||||
} catch (BadHash &) {
|
} 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()) {
|
while (pos < s.size()) {
|
||||||
|
|
||||||
size_t colon = s.find(':', pos);
|
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);
|
std::string name(s, pos, colon - pos);
|
||||||
|
|
||||||
size_t eol = s.find('\n', colon + 2);
|
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);
|
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);
|
fileHash = parseHashField(value);
|
||||||
else if (name == "FileSize") {
|
else if (name == "FileSize") {
|
||||||
auto n = string2Int<decltype(fileSize)>(value);
|
auto n = string2Int<decltype(fileSize)>(value);
|
||||||
if (!n) throw corrupt();
|
if (!n) throw corrupt("invalid FileSize");
|
||||||
fileSize = *n;
|
fileSize = *n;
|
||||||
}
|
}
|
||||||
else if (name == "NarHash") {
|
else if (name == "NarHash") {
|
||||||
|
@ -56,12 +59,12 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
|
||||||
}
|
}
|
||||||
else if (name == "NarSize") {
|
else if (name == "NarSize") {
|
||||||
auto n = string2Int<decltype(narSize)>(value);
|
auto n = string2Int<decltype(narSize)>(value);
|
||||||
if (!n) throw corrupt();
|
if (!n) throw corrupt("invalid NarSize");
|
||||||
narSize = *n;
|
narSize = *n;
|
||||||
}
|
}
|
||||||
else if (name == "References") {
|
else if (name == "References") {
|
||||||
auto refs = tokenizeString<Strings>(value, " ");
|
auto refs = tokenizeString<Strings>(value, " ");
|
||||||
if (!references.empty()) throw corrupt();
|
if (!references.empty()) throw corrupt("extra References");
|
||||||
for (auto & r : refs)
|
for (auto & r : refs)
|
||||||
references.insert(StorePath(r));
|
references.insert(StorePath(r));
|
||||||
}
|
}
|
||||||
|
@ -72,17 +75,26 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string &
|
||||||
else if (name == "Sig")
|
else if (name == "Sig")
|
||||||
sigs.insert(value);
|
sigs.insert(value);
|
||||||
else if (name == "CA") {
|
else if (name == "CA") {
|
||||||
if (ca) throw corrupt();
|
if (ca) throw corrupt("extra CA");
|
||||||
// FIXME: allow blank ca or require skipping field?
|
// FIXME: allow blank ca or require skipping field?
|
||||||
ca = ContentAddress::parseOpt(value);
|
ca = ContentAddress::parseOpt(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = eol + 1;
|
pos = eol + 1;
|
||||||
|
line += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compression == "") compression = "bzip2";
|
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
|
std::string NarInfo::to_string(const Store & store) const
|
||||||
|
|
Loading…
Reference in a new issue