diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/buildtool/build_engine/expression/expression.cpp | 2 | ||||
-rw-r--r-- | src/buildtool/build_engine/target_map/utils.cpp | 4 | ||||
-rw-r--r-- | src/buildtool/common/artifact_digest.hpp | 3 | ||||
-rw-r--r-- | src/buildtool/crypto/hash_function.cpp | 97 | ||||
-rw-r--r-- | src/buildtool/crypto/hash_function.hpp | 68 | ||||
-rw-r--r-- | src/buildtool/storage/compactifier.cpp | 3 |
6 files changed, 111 insertions, 66 deletions
diff --git a/src/buildtool/build_engine/expression/expression.cpp b/src/buildtool/build_engine/expression/expression.cpp index d84c3b0a..9f901708 100644 --- a/src/buildtool/build_engine/expression/expression.cpp +++ b/src/buildtool/build_engine/expression/expression.cpp @@ -254,7 +254,7 @@ auto Expression::ComputeHash() const noexcept -> std::string { hash = hash_function.ComputeHash(prefix + ToString()).Bytes(); } else { - auto hasher = hash_function.Hasher(); + auto hasher = hash_function.MakeHasher(); if (IsList()) { auto list = Value<Expression::list_t>(); hasher.Update("["); diff --git a/src/buildtool/build_engine/target_map/utils.cpp b/src/buildtool/build_engine/target_map/utils.cpp index cb7ad42d..742a5e2f 100644 --- a/src/buildtool/build_engine/target_map/utils.cpp +++ b/src/buildtool/build_engine/target_map/utils.cpp @@ -187,7 +187,7 @@ auto BuildMaps::Target::Utils::getTainted( namespace { auto hash_vector(HashFunction hash_function, std::vector<std::string> const& vec) -> std::string { - auto hasher = hash_function.Hasher(); + auto hasher = hash_function.MakeHasher(); for (auto const& s : vec) { hasher.Update(hash_function.ComputeHash(s).Bytes()); } @@ -208,7 +208,7 @@ auto BuildMaps::Target::Utils::createAction( // The type of HashFunction is irrelevant here. It is used for // identification and quick comparison of descriptions. SHA256 is used. HashFunction hash_function{HashFunction::JustHash::Compatible}; - auto hasher = hash_function.Hasher(); + auto hasher = hash_function.MakeHasher(); hasher.Update(hash_vector(hash_function, output_files)); hasher.Update(hash_vector(hash_function, output_dirs)); diff --git a/src/buildtool/common/artifact_digest.hpp b/src/buildtool/common/artifact_digest.hpp index 686a6fa5..1a620793 100644 --- a/src/buildtool/common/artifact_digest.hpp +++ b/src/buildtool/common/artifact_digest.hpp @@ -97,7 +97,8 @@ class ArtifactDigest { std::filesystem::path const& path) noexcept -> std::optional<ArtifactDigest> { static constexpr bool kIsTree = IsTreeObject(kType); - auto hash = hash_function.ComputeHashFile(path, kIsTree); + auto const hash = kIsTree ? hash_function.HashTreeFile(path) + : hash_function.HashBlobFile(path); if (hash) { return ArtifactDigest{ hash->first.HexString(), hash->second, kIsTree}; diff --git a/src/buildtool/crypto/hash_function.cpp b/src/buildtool/crypto/hash_function.cpp index d1ca0c2b..a759a0ce 100644 --- a/src/buildtool/crypto/hash_function.cpp +++ b/src/buildtool/crypto/hash_function.cpp @@ -15,41 +15,94 @@ #include "src/buildtool/crypto/hash_function.hpp" #include <cstddef> +#include <exception> #include <fstream> +#include <limits> #include "src/buildtool/logging/log_level.hpp" #include "src/buildtool/logging/logger.hpp" -[[nodiscard]] auto HashFunction::ComputeHashFile( - const std::filesystem::path& file_path, - bool as_tree) const noexcept +namespace { +[[nodiscard]] auto CreateGitTreeTag(std::size_t size) noexcept -> std::string { + return std::string("tree ") + std::to_string(size) + '\0'; +} +[[nodiscard]] auto CreateGitBlobTag(std::size_t size) noexcept -> std::string { + return std::string("blob ") + std::to_string(size) + '\0'; +} +} // namespace + +auto HashFunction::ComputeBlobHash(std::string const& data) const noexcept + -> Hasher::HashDigest { + return HashTaggedLine(data, CreateGitBlobTag); +} + +auto HashFunction::ComputeTreeHash(std::string const& data) const noexcept + -> Hasher::HashDigest { + return HashTaggedLine(data, CreateGitTreeTag); +} + +auto HashFunction::ComputeHash(std::string const& data) const noexcept + -> Hasher::HashDigest { + return HashTaggedLine(data, std::nullopt); +} + +auto HashFunction::HashTaggedLine(std::string const& data, + std::optional<TagCreator> tag_creator) + const noexcept -> Hasher::HashDigest { + auto hasher = MakeHasher(); + if (type_ == JustHash::Native and tag_creator.has_value()) { + hasher.Update(std::invoke(*tag_creator, data.size())); + } + hasher.Update(data); + return std::move(hasher).Finalize(); +} + +auto HashFunction::HashBlobFile( + std::filesystem::path const& path) const noexcept -> std::optional<std::pair<Hasher::HashDigest, std::uintmax_t>> { + return HashTaggedFile(path, CreateGitBlobTag); +} + +auto HashFunction::HashTreeFile( + std::filesystem::path const& path) const noexcept + -> std::optional<std::pair<Hasher::HashDigest, std::uintmax_t>> { + return HashTaggedFile(path, CreateGitTreeTag); +} + +auto HashFunction::HashTaggedFile(std::filesystem::path const& path, + TagCreator const& tag_creator) const noexcept + -> std::optional<std::pair<Hasher::HashDigest, std::uintmax_t>> { + auto const size = std::filesystem::file_size(path); + static constexpr std::size_t kChunkSize{4048}; + static_assert(kChunkSize < std::numeric_limits<std::streamsize>::max(), + "An overflow will occur while reading"); + + auto hasher = MakeHasher(); + if (type_ == JustHash::Native) { + hasher.Update(std::invoke(tag_creator, size)); + } + try { - auto hasher = Hasher(); - auto size = std::filesystem::file_size(file_path); - if (type_ == JustHash::Native) { - hasher.Update( - (as_tree ? std::string{"tree "} : std::string{"blob "}) + - std::to_string(size) + '\0'); + auto chunk = std::string(kChunkSize, '\0'); + std::ifstream file_reader(path.string(), std::ios::binary); + if (not file_reader.is_open()) { + return std::nullopt; } - std::string chunk{}; - chunk.resize(kChunkSize); - std::ifstream file_reader(file_path.string(), std::ios::binary); - if (file_reader.is_open()) { - auto chunk_size = gsl::narrow<std::streamsize>(chunk.size()); - do { - file_reader.read(chunk.data(), chunk_size); - auto count = file_reader.gcount(); - hasher.Update(chunk.substr(0, gsl::narrow<std::size_t>(count))); - } while (file_reader.good()); - file_reader.close(); - return std::make_pair(std::move(hasher).Finalize(), size); + + while (file_reader.good()) { + file_reader.read(chunk.data(), + static_cast<std::streamsize>(kChunkSize)); + + auto const count = static_cast<std::size_t>(file_reader.gcount()); + hasher.Update(chunk.substr(0, count)); } + file_reader.close(); + return std::make_pair(std::move(hasher).Finalize(), size); } catch (std::exception const& e) { Logger::Log(LogLevel::Debug, "Error while trying to hash {}: {}", - file_path.string(), + path.string(), e.what()); } return std::nullopt; diff --git a/src/buildtool/crypto/hash_function.hpp b/src/buildtool/crypto/hash_function.hpp index 8d932016..c73458eb 100644 --- a/src/buildtool/crypto/hash_function.hpp +++ b/src/buildtool/crypto/hash_function.hpp @@ -45,44 +45,35 @@ class HashFunction { return type_; } - /// \brief Compute a plain hash. - [[nodiscard]] auto ComputeHash(std::string const& data) const noexcept - -> Hasher::HashDigest { - return ComputeTaggedHash(data); - } - - /// \brief Compute a blob hash. + /// \brief Compute the blob hash of a string. [[nodiscard]] auto ComputeBlobHash(std::string const& data) const noexcept - -> Hasher::HashDigest { - static auto const kBlobTagCreator = - [](std::string const& data) -> std::string { - return {"blob " + std::to_string(data.size()) + '\0'}; - }; - return ComputeTaggedHash(data, kBlobTagCreator); - } + -> Hasher::HashDigest; + + /// \brief Compute the tree hash of a string. + [[nodiscard]] auto ComputeTreeHash(std::string const& data) const noexcept + -> Hasher::HashDigest; + + /// \brief Compute the plain hash of a string. + [[nodiscard]] auto ComputeHash(std::string const& data) const noexcept + -> Hasher::HashDigest; /// \brief Compute the blob hash of a file or std::nullopt on IO error. - [[nodiscard]] auto ComputeHashFile(const std::filesystem::path& file_path, - bool as_tree) const noexcept + [[nodiscard]] auto HashBlobFile( + std::filesystem::path const& path) const noexcept -> std::optional<std::pair<Hasher::HashDigest, std::uintmax_t>>; - /// \brief Compute a tree hash. - [[nodiscard]] auto ComputeTreeHash(std::string const& data) const noexcept - -> Hasher::HashDigest { - static auto const kTreeTagCreator = - [](std::string const& data) -> std::string { - return {"tree " + std::to_string(data.size()) + '\0'}; - }; - return ComputeTaggedHash(data, kTreeTagCreator); - } + /// \brief Compute the tree hash of a file or std::nullopt on IO error. + [[nodiscard]] auto HashTreeFile( + std::filesystem::path const& path) const noexcept + -> std::optional<std::pair<Hasher::HashDigest, std::uintmax_t>>; /// \brief Obtain incremental hasher for computing plain hashes. - [[nodiscard]] auto Hasher() const noexcept -> ::Hasher { + [[nodiscard]] auto MakeHasher() const noexcept -> Hasher { switch (type_) { case JustHash::Native: - return ::Hasher{Hasher::HashType::SHA1}; + return Hasher{Hasher::HashType::SHA1}; case JustHash::Compatible: - return ::Hasher{Hasher::HashType::SHA256}; + return Hasher{Hasher::HashType::SHA256}; } Ensures(false); // unreachable } @@ -90,17 +81,16 @@ class HashFunction { private: JustHash const type_; - [[nodiscard]] auto ComputeTaggedHash( - std::string const& data, - std::function<std::string(std::string const&)> const& tag_creator = {}) - const noexcept -> Hasher::HashDigest { - auto hasher = Hasher(); - if (tag_creator and type_ == JustHash::Native) { - hasher.Update(tag_creator(data)); - } - hasher.Update(data); - return std::move(hasher).Finalize(); - } + using TagCreator = std::function<std::string(std::size_t)>; + + [[nodiscard]] auto HashTaggedLine(std::string const& data, + std::optional<TagCreator> tag_creator) + const noexcept -> Hasher::HashDigest; + + [[nodiscard]] auto HashTaggedFile( + std::filesystem::path const& path, + TagCreator const& tag_creator) const noexcept + -> std::optional<std::pair<Hasher::HashDigest, std::uintmax_t>>; }; #endif // INCLUDED_SRC_BUILDTOOL_CRYPTO_HASH_FUNCTION_HPP diff --git a/src/buildtool/storage/compactifier.cpp b/src/buildtool/storage/compactifier.cpp index 264312f5..e6f9a344 100644 --- a/src/buildtool/storage/compactifier.cpp +++ b/src/buildtool/storage/compactifier.cpp @@ -156,7 +156,8 @@ template <ObjectType kType> } // Calculate reference hash size: - auto const kHashSize = task.cas.GetHashFunction().Hasher().GetHashLength(); + auto const kHashSize = + task.cas.GetHashFunction().MakeHasher().GetHashLength(); auto const kFileNameSize = kHashSize - FileStorageData::kDirectoryNameLength; |