mirror of
https://github.com/NixOS/nix.git
synced 2025-11-16 07:22:43 +01:00
Implement support for Git hashing with SHA-256
SHA-256 is Git's next hash algorithm. The world is still basically stuck on SHA-1 with git, but shouldn't be. We can at least do our part to get ready. On the C++ implementation side, only a little bit of generalization was needed, and that was fairly straight-forward. The tests (unit and system) were actually bigger, and care was taken to make sure they were all cover both algorithms equally.
This commit is contained in:
parent
7f4acb9f10
commit
d21e3f88ec
20 changed files with 350 additions and 181 deletions
|
|
@ -59,7 +59,7 @@ void parseBlob(
|
|||
{
|
||||
xpSettings.require(Xp::GitHashing);
|
||||
|
||||
unsigned long long size = std::stoi(getStringUntil(source, 0));
|
||||
const unsigned long long size = std::stoi(getStringUntil(source, 0));
|
||||
|
||||
auto doRegularFile = [&](bool executable) {
|
||||
sink.createRegularFile(sinkPath, [&](auto & crf) {
|
||||
|
|
@ -114,10 +114,11 @@ void parseTree(
|
|||
FileSystemObjectSink & sink,
|
||||
const CanonPath & sinkPath,
|
||||
Source & source,
|
||||
HashAlgorithm hashAlgo,
|
||||
std::function<SinkHook> hook,
|
||||
const ExperimentalFeatureSettings & xpSettings)
|
||||
{
|
||||
unsigned long long size = std::stoi(getStringUntil(source, 0));
|
||||
const unsigned long long size = std::stoi(getStringUntil(source, 0));
|
||||
unsigned long long left = size;
|
||||
|
||||
sink.createDirectory(sinkPath);
|
||||
|
|
@ -137,10 +138,15 @@ void parseTree(
|
|||
left -= name.size();
|
||||
left -= 1;
|
||||
|
||||
std::string hashs = getString(source, 20);
|
||||
left -= 20;
|
||||
const auto hashSize = regularHashSize(hashAlgo);
|
||||
std::string hashs = getString(source, hashSize);
|
||||
left -= hashSize;
|
||||
|
||||
Hash hash(HashAlgorithm::SHA1);
|
||||
if (!(hashAlgo == HashAlgorithm::SHA1 || hashAlgo == HashAlgorithm::SHA256)) {
|
||||
throw Error("Unsupported hash algorithm for git trees: %s", printHashAlgo(hashAlgo));
|
||||
}
|
||||
|
||||
Hash hash(hashAlgo);
|
||||
std::copy(hashs.begin(), hashs.end(), hash.hash);
|
||||
|
||||
hook(
|
||||
|
|
@ -171,6 +177,7 @@ void parse(
|
|||
const CanonPath & sinkPath,
|
||||
Source & source,
|
||||
BlobMode rootModeIfBlob,
|
||||
HashAlgorithm hashAlgo,
|
||||
std::function<SinkHook> hook,
|
||||
const ExperimentalFeatureSettings & xpSettings)
|
||||
{
|
||||
|
|
@ -183,7 +190,7 @@ void parse(
|
|||
parseBlob(sink, sinkPath, source, rootModeIfBlob, xpSettings);
|
||||
break;
|
||||
case ObjectType::Tree:
|
||||
parseTree(sink, sinkPath, source, hook, xpSettings);
|
||||
parseTree(sink, sinkPath, source, hashAlgo, hook, xpSettings);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
|
|
@ -210,9 +217,9 @@ std::optional<Mode> convertMode(SourceAccessor::Type type)
|
|||
}
|
||||
}
|
||||
|
||||
void restore(FileSystemObjectSink & sink, Source & source, std::function<RestoreHook> hook)
|
||||
void restore(FileSystemObjectSink & sink, Source & source, HashAlgorithm hashAlgo, std::function<RestoreHook> hook)
|
||||
{
|
||||
parse(sink, CanonPath::root, source, BlobMode::Regular, [&](CanonPath name, TreeEntry entry) {
|
||||
parse(sink, CanonPath::root, source, BlobMode::Regular, hashAlgo, [&](CanonPath name, TreeEntry entry) {
|
||||
auto [accessor, from] = hook(entry.hash);
|
||||
auto stat = accessor->lstat(from);
|
||||
auto gotOpt = convertMode(stat.type);
|
||||
|
|
|
|||
|
|
@ -20,23 +20,6 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
static size_t regularHashSize(HashAlgorithm type)
|
||||
{
|
||||
switch (type) {
|
||||
case HashAlgorithm::BLAKE3:
|
||||
return blake3HashSize;
|
||||
case HashAlgorithm::MD5:
|
||||
return md5HashSize;
|
||||
case HashAlgorithm::SHA1:
|
||||
return sha1HashSize;
|
||||
case HashAlgorithm::SHA256:
|
||||
return sha256HashSize;
|
||||
case HashAlgorithm::SHA512:
|
||||
return sha512HashSize;
|
||||
}
|
||||
unreachable();
|
||||
}
|
||||
|
||||
const StringSet hashAlgorithms = {"blake3", "md5", "sha1", "sha256", "sha512"};
|
||||
|
||||
const StringSet hashFormats = {"base64", "nix32", "base16", "sri"};
|
||||
|
|
|
|||
|
|
@ -94,10 +94,14 @@ void parseBlob(
|
|||
BlobMode blobMode,
|
||||
const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
|
||||
|
||||
/**
|
||||
* @param hashAlgo must be `HashAlgo::SHA1` or `HashAlgo::SHA256` for now.
|
||||
*/
|
||||
void parseTree(
|
||||
FileSystemObjectSink & sink,
|
||||
const CanonPath & sinkPath,
|
||||
Source & source,
|
||||
HashAlgorithm hashAlgo,
|
||||
std::function<SinkHook> hook,
|
||||
const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
|
||||
|
||||
|
|
@ -107,12 +111,15 @@ void parseTree(
|
|||
* @param rootModeIfBlob How to interpret a root blob, for which there is no
|
||||
* disambiguating dir entry to answer that questino. If the root it not
|
||||
* a blob, this is ignored.
|
||||
*
|
||||
* @param hashAlgo must be `HashAlgo::SHA1` or `HashAlgo::SHA256` for now.
|
||||
*/
|
||||
void parse(
|
||||
FileSystemObjectSink & sink,
|
||||
const CanonPath & sinkPath,
|
||||
Source & source,
|
||||
BlobMode rootModeIfBlob,
|
||||
HashAlgorithm hashAlgo,
|
||||
std::function<SinkHook> hook,
|
||||
const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
|
||||
|
||||
|
|
@ -131,8 +138,10 @@ using RestoreHook = SourcePath(Hash);
|
|||
|
||||
/**
|
||||
* Wrapper around `parse` and `RestoreSink`
|
||||
*
|
||||
* @param hashAlgo must be `HashAlgo::SHA1` or `HashAlgo::SHA256` for now.
|
||||
*/
|
||||
void restore(FileSystemObjectSink & sink, Source & source, std::function<RestoreHook> hook);
|
||||
void restore(FileSystemObjectSink & sink, Source & source, HashAlgorithm hashAlgo, std::function<RestoreHook> hook);
|
||||
|
||||
/**
|
||||
* Dumps a single file to a sink
|
||||
|
|
|
|||
|
|
@ -12,11 +12,26 @@ MakeError(BadHash, Error);
|
|||
|
||||
enum struct HashAlgorithm : char { MD5 = 42, SHA1, SHA256, SHA512, BLAKE3 };
|
||||
|
||||
const int blake3HashSize = 32;
|
||||
const int md5HashSize = 16;
|
||||
const int sha1HashSize = 20;
|
||||
const int sha256HashSize = 32;
|
||||
const int sha512HashSize = 64;
|
||||
/**
|
||||
* @return the size of a hash for the given algorithm
|
||||
*/
|
||||
constexpr inline size_t regularHashSize(HashAlgorithm type)
|
||||
{
|
||||
switch (type) {
|
||||
case HashAlgorithm::BLAKE3:
|
||||
return 32;
|
||||
case HashAlgorithm::MD5:
|
||||
return 16;
|
||||
case HashAlgorithm::SHA1:
|
||||
return 20;
|
||||
case HashAlgorithm::SHA256:
|
||||
return 32;
|
||||
case HashAlgorithm::SHA512:
|
||||
return 64;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
extern const StringSet hashAlgorithms;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue