diff options
-rw-r--r-- | third_party/nix/src/libstore/store-api.cc | 5 | ||||
-rw-r--r-- | third_party/nix/src/libutil/hash.cc | 4 | ||||
-rw-r--r-- | third_party/nix/src/libutil/hash.hh | 6 | ||||
-rw-r--r-- | third_party/nix/src/nix/hash.cc | 4 | ||||
-rw-r--r-- | third_party/nix/src/tests/CMakeLists.txt | 10 | ||||
-rw-r--r-- | third_party/nix/src/tests/references_test.cc | 74 |
6 files changed, 98 insertions, 5 deletions
diff --git a/third_party/nix/src/libstore/store-api.cc b/third_party/nix/src/libstore/store-api.cc index a6863cc04b52..ae403b0be65f 100644 --- a/third_party/nix/src/libstore/store-api.cc +++ b/third_party/nix/src/libstore/store-api.cc @@ -323,9 +323,8 @@ Path Store::makeStorePath(const std::string& type, const Hash& hash, checkStoreName(name); - return storeDir + "/" + - compressHash(hashString(htSHA256, s), 20).to_string(Base32, false) + - "-" + name; + return absl::StrCat(storeDir, "/", hashString(htSHA256, s).ToStorePathHash(), + "-", name); } Path Store::makeOutputPath(const std::string& id, const Hash& hash, diff --git a/third_party/nix/src/libutil/hash.cc b/third_party/nix/src/libutil/hash.cc index 426096e73af8..9d14ad9dfe14 100644 --- a/third_party/nix/src/libutil/hash.cc +++ b/third_party/nix/src/libutil/hash.cc @@ -158,6 +158,10 @@ bool Hash::IsValidBase32(absl::string_view s) { return true; } +std::string Hash::ToStorePathHash() const { + return compressHash(*this, kStorePathHashSize).to_string(Base32, false); +} + static std::string printHash32(const Hash& hash) { assert(hash.hashSize); size_t len = hash.base32Len(); diff --git a/third_party/nix/src/libutil/hash.hh b/third_party/nix/src/libutil/hash.hh index 4d52702aee75..6fbeec5b47fb 100644 --- a/third_party/nix/src/libutil/hash.hh +++ b/third_party/nix/src/libutil/hash.hh @@ -8,6 +8,9 @@ namespace nix { +// Size of the hashes rendered in store paths, in bytes +constexpr unsigned int kStorePathHashSize = 20; + MakeError(BadHash, Error); // TODO(grfn): Replace this with the hash type enum from the daemon proto so we @@ -90,6 +93,9 @@ struct Hash { /* Returns whether the passed string contains entirely valid base32 characters. */ static bool IsValidBase32(absl::string_view s); + + // Convert this Hash to the format expected in store paths + [[nodiscard]] std::string ToStorePathHash() const; }; /* Print a hash in base-16 if it's MD5, or base-32 otherwise. */ diff --git a/third_party/nix/src/nix/hash.cc b/third_party/nix/src/nix/hash.cc index 24529c67ce8c..08ada7ccfb3a 100644 --- a/third_party/nix/src/nix/hash.cc +++ b/third_party/nix/src/nix/hash.cc @@ -36,8 +36,8 @@ struct CmdHash final : Command { void run() override { for (const auto& path : paths) { Hash h = mode == mFile ? hashFile(ht, path) : hashPath(ht, path).first; - if (truncate && h.hashSize > 20) { - h = compressHash(h, 20); + if (truncate && h.hashSize > nix::kStorePathHashSize) { + h = compressHash(h, nix::kStorePathHashSize); } std::cout << format("%1%\n") % h.to_string(base, base == SRI); } diff --git a/third_party/nix/src/tests/CMakeLists.txt b/third_party/nix/src/tests/CMakeLists.txt index 929acc5ea671..cda8f5da8483 100644 --- a/third_party/nix/src/tests/CMakeLists.txt +++ b/third_party/nix/src/tests/CMakeLists.txt @@ -30,6 +30,16 @@ target_link_libraries(hash_test gtest_discover_tests(hash_test) +add_executable(references_test references_test.cc) +target_link_libraries(references_test + nixstore + rapidcheck + rapidcheck_gtest + GTest::gtest_main +) + +gtest_discover_tests(references_test) + add_executable(store_test store_tests.cc) target_link_libraries(store_test nixstore diff --git a/third_party/nix/src/tests/references_test.cc b/third_party/nix/src/tests/references_test.cc new file mode 100644 index 000000000000..8dcb3ed37a8b --- /dev/null +++ b/third_party/nix/src/tests/references_test.cc @@ -0,0 +1,74 @@ +#include "libstore/references.hh" + +#include <cstdio> +#include <fstream> +#include <ostream> +#include <unordered_set> + +#include <absl/strings/str_format.h> +#include <gtest/gtest.h> +#include <rapidcheck.h> +#include <rapidcheck/gtest.h> + +#include "libutil/hash.hh" + +class ReferencesTest : public ::testing::Test {}; + +namespace nix { + +TEST(ReferencesTest, ScanForOneReferenceNotFound) { + char path[] = "store_XXXXXXX"; + auto f = mkstemp(path); + + auto hash = hashString(htSHA256, "foo"); + auto ref = absl::StrFormat("/nix/store/%s-foo", hash.ToStorePathHash()); + + HashResult hr; + auto result = scanForReferences(path, {ref}, hr); + + ASSERT_EQ(result.find(ref), result.end()); + + EXPECT_EQ(close(f), 0); +} + +TEST(ReferencesTest, ScanForOneReferenceFound) { + char path[] = "store_XXXXXXX"; + auto f = mkstemp(path); + + auto hash = hashString(htSHA256, "foo"); + auto ref = absl::StrFormat("/nix/store/%s-foo", hash.ToStorePathHash()); + + EXPECT_GT(write(f, ref.c_str(), sizeof(char) * ref.size()), 0); + + HashResult hr; + auto result = scanForReferences(path, {ref}, hr); + + ASSERT_NE(result.find(ref), result.end()); + + ASSERT_EQ(close(f), 0); +} + +RC_GTEST_PROP(ReferencesTest, ScanForReferences, + (std::unordered_set<std::string> strs)) { + char path[] = "store_XXXXXXX"; + auto f = mkstemp(path); + + PathSet refs; + for (const auto& s : strs) { + auto hash = hashString(htSHA256, s); + auto ref = absl::StrFormat("/nix/store/%s-foo", hash.ToStorePathHash()); + refs.insert(ref); + RC_ASSERT(write(f, ref.c_str(), sizeof(char) * ref.size()) > 0); + } + + HashResult hr; + auto result = scanForReferences(path, refs, hr); + + for (const auto& ref : refs) { + RC_ASSERT(result.find(ref) != result.end()); + } + + RC_ASSERT(close(f) == 0); +} + +} // namespace nix |