]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Add Digest class, replacing struct digest
authorJoel Rosdahl <joel@rosdahl.net>
Tue, 21 Apr 2020 17:58:55 +0000 (19:58 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Sun, 14 Jun 2020 09:29:43 +0000 (11:29 +0200)
20 files changed:
src/Context.cpp
src/Context.hpp
src/Digest.hpp [new file with mode: 0644]
src/InodeCache.cpp
src/InodeCache.hpp
src/Util.cpp
src/Util.hpp
src/ccache.cpp
src/hash.cpp
src/hash.hpp
src/hashutil.cpp
src/legacy_util.cpp
src/legacy_util.hpp
src/manifest.cpp
src/manifest.hpp
unittest/test_InodeCache.cpp
unittest/test_Util.cpp
unittest/test_hash.cpp
unittest/test_hashutil.cpp
unittest/test_legacy_util.cpp

index ec380237c08385e746e5a099f7942334705a5c3b..96044f112ec2ba0a4df69564e414eabc554b131b 100644 (file)
@@ -50,7 +50,7 @@ Context::~Context()
 }
 
 void
-Context::set_manifest_name(const struct digest& name)
+Context::set_manifest_name(const Digest& name)
 {
   m_manifest_name = name;
   set_path_and_stats_file(
@@ -58,7 +58,7 @@ Context::set_manifest_name(const struct digest& name)
 }
 
 void
-Context::set_result_name(const struct digest& name)
+Context::set_result_name(const Digest& name)
 {
   m_result_name = name;
   set_path_and_stats_file(name, ".result", m_result_path, m_result_stats_file);
@@ -78,13 +78,12 @@ Context::stats_file() const
 }
 
 void
-Context::set_path_and_stats_file(const struct digest& name,
+Context::set_path_and_stats_file(const Digest& name,
                                  string_view suffix,
                                  std::string& path_var,
                                  std::string& stats_file_var)
 {
-  char name_string[DIGEST_STRING_BUFFER_SIZE];
-  digest_as_string(&name, name_string);
+  std::string name_string = name.to_string();
   path_var = Util::get_path_in_cache(
     config.cache_dir(), config.cache_dir_levels(), name_string, suffix);
   stats_file_var =
index 608d639c789a490fcf1d8fb722bf4165880e0f68..2579f75c067832fbb9ebe361dc37710fec81237e 100644 (file)
@@ -57,9 +57,8 @@ public:
   // The original argument list.
   Args orig_args;
 
-  // Name (represented as a struct digest) of the file containing the cached
-  // result.
-  const struct digest& result_name() const;
+  // Name (represented as a hash) of the file containing the cached result.
+  const Digest& result_name() const;
 
   // Full path to the file containing the result
   // (cachedir/a/b/cdef[...]-size.result).
@@ -74,8 +73,7 @@ public:
   time_t time_of_compilation = 0;
 
   // Files included by the preprocessor and their hashes.
-  // Key: file path. Value: struct digest.
-  std::unordered_map<std::string, digest> included_files;
+  std::unordered_map<std::string, Digest> included_files;
 
   // Uses absolute path for some include files.
   bool has_absolute_include_headers = false;
@@ -89,9 +87,9 @@ public:
   // The name of the cpp stderr file.
   std::string cpp_stderr;
 
-  // Name (represented as a struct digest) of the file containing the manifest
-  // for the cached result.
-  const struct digest& manifest_name() const;
+  // Name (represented as a hash) of the file containing the manifest for the
+  // cached result.
+  const Digest& manifest_name() const;
 
   // The stats file to use for the manifest.
   const std::string& manifest_stats_file() const;
@@ -130,18 +128,18 @@ public:
   std::unique_ptr<MiniTrace> mini_trace;
 #endif
 
-  void set_manifest_name(const struct digest& name);
-  void set_result_name(const struct digest& name);
+  void set_manifest_name(const Digest& name);
+  void set_result_name(const Digest& name);
 
   // Register a temporary file to remove at program exit.
   void register_pending_tmp_file(const std::string& path);
 
 private:
-  nonstd::optional<struct digest> m_manifest_name;
+  nonstd::optional<Digest> m_manifest_name;
   std::string m_manifest_path;
   std::string m_manifest_stats_file;
 
-  nonstd::optional<struct digest> m_result_name;
+  nonstd::optional<Digest> m_result_name;
   std::string m_result_path;
   mutable std::string m_result_stats_file;
 
@@ -156,13 +154,13 @@ private:
   void unlink_pending_tmp_files();
   void unlink_pending_tmp_files_signal_safe(); // called from signal handler
 
-  void set_path_and_stats_file(const struct digest& name,
+  void set_path_and_stats_file(const Digest& name,
                                nonstd::string_view suffix,
                                std::string& path_var,
                                std::string& stats_file_var);
 };
 
-inline const struct digest&
+inline const Digest&
 Context::manifest_name() const
 {
   return *m_manifest_name;
@@ -182,7 +180,7 @@ Context::manifest_stats_file() const
   return m_manifest_stats_file;
 }
 
-inline const struct digest&
+inline const Digest&
 Context::result_name() const
 {
   return *m_result_name;
diff --git a/src/Digest.hpp b/src/Digest.hpp
new file mode 100644 (file)
index 0000000..627088c
--- /dev/null
@@ -0,0 +1,88 @@
+// Copyright (C) 2020 Joel Rosdahl and other contributors
+//
+// See doc/AUTHORS.adoc for a complete list of contributors.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#pragma once
+
+#include "system.hpp"
+
+#include "Util.hpp"
+
+#include "third_party/fmt/core.h"
+
+#include <string>
+
+// Digest represents the binary form of the final digest (AKA hash or checksum)
+// produced by the hash algorithm.
+class Digest
+{
+public:
+  Digest() = default;
+
+  // Access the raw byte buffer, which is `size()` bytes long.
+  const uint8_t* bytes() const;
+  uint8_t* bytes();
+
+  // Size of the digest in bytes.
+  constexpr static size_t size();
+
+  // Format the digest as hex string.
+  std::string to_string() const;
+
+  bool operator==(const Digest& other) const;
+  bool operator!=(const Digest& other) const;
+
+private:
+  constexpr static size_t k_digest_size = 20;
+  uint8_t m_bytes[k_digest_size];
+};
+
+inline const uint8_t*
+Digest::bytes() const
+{
+  return m_bytes;
+}
+
+inline uint8_t*
+Digest::bytes()
+{
+  return m_bytes;
+}
+
+inline constexpr size_t
+Digest::size()
+{
+  return k_digest_size;
+}
+
+inline std::string
+Digest::to_string() const
+{
+  return Util::format_hex(m_bytes, size());
+}
+
+inline bool
+Digest::operator==(const Digest& other) const
+{
+  return memcmp(bytes(), other.bytes(), size()) == 0;
+}
+
+inline bool
+Digest::operator!=(const Digest& other) const
+{
+  return !(*this == other);
+}
index 9a49e8795de1267419530798045c09195fe29f3c..004e2ccc362c210af4268ec4b0f012fd4830c231 100644 (file)
@@ -38,6 +38,7 @@
 #  include <sys/stat.h>
 #  include <sys/types.h>
 #  include <time.h>
+#  include <type_traits>
 #  include <unistd.h>
 
 namespace {
@@ -59,8 +60,10 @@ const uint32_t k_version = 1;
 const uint32_t k_num_buckets = 32 * 1024;
 const uint32_t k_num_entries = 4;
 
-static_assert(sizeof(digest::bytes) == 20,
+static_assert(Digest::size() == 20,
               "Increment version number if size of digest is changed.");
+static_assert(std::is_trivially_copyable<Digest>::value,
+              "Digest is expected to be trivially copyable.");
 
 static_assert(
   static_cast<int>(InodeCache::ContentType::binary) == 0,
@@ -99,8 +102,8 @@ struct InodeCache::Key
 
 struct InodeCache::Entry
 {
-  digest key_digest;  // Hashed key
-  digest file_digest; // Cached file hash
+  Digest key_digest;  // Hashed key
+  Digest file_digest; // Cached file hash
   int return_value;   // Cached return value
 };
 
@@ -168,7 +171,7 @@ InodeCache::mmap_file(const std::string& inode_cache_file)
 }
 
 bool
-InodeCache::hash_inode(const char* path, ContentType type, digest* digest)
+InodeCache::hash_inode(const char* path, ContentType type, Digest& digest)
 {
   Stat stat = Stat::stat(path);
   if (!stat) {
@@ -196,7 +199,7 @@ InodeCache::hash_inode(const char* path, ContentType type, digest* digest)
 
   struct hash* hash = hash_init();
   hash_buffer(hash, &key, sizeof(Key));
-  hash_result_as_bytes(hash, digest);
+  digest = hash_result(hash);
   hash_free(hash);
   return true;
 }
@@ -235,10 +238,10 @@ InodeCache::acquire_bucket(uint32_t index)
 }
 
 InodeCache::Bucket*
-InodeCache::acquire_bucket(const digest& key_digest)
+InodeCache::acquire_bucket(const Digest& key_digest)
 {
   uint32_t hash;
-  Util::big_endian_to_int(key_digest.bytes, hash);
+  Util::big_endian_to_int(key_digest.bytes(), hash);
   return acquire_bucket(hash % k_num_buckets);
 }
 
@@ -362,15 +365,15 @@ InodeCache::~InodeCache()
 bool
 InodeCache::get(const char* path,
                 ContentType type,
-                digest* file_digest,
+                Digest& file_digest,
                 int* return_value)
 {
   if (!initialize()) {
     return false;
   }
 
-  digest key_digest;
-  if (!hash_inode(path, type, &key_digest)) {
+  Digest key_digest;
+  if (!hash_inode(path, type, key_digest)) {
     return false;
   }
 
@@ -383,14 +386,14 @@ InodeCache::get(const char* path,
   bool found = false;
 
   for (uint32_t i = 0; i < k_num_entries; ++i) {
-    if (digests_equal(&bucket->entries[i].key_digest, &key_digest)) {
+    if (bucket->entries[i].key_digest == key_digest) {
       if (i > 0) {
         Entry tmp = bucket->entries[i];
         memmove(&bucket->entries[1], &bucket->entries[0], sizeof(Entry) * i);
         bucket->entries[0] = tmp;
       }
 
-      *file_digest = bucket->entries[0].file_digest;
+      file_digest = bucket->entries[0].file_digest;
       if (return_value) {
         *return_value = bucket->entries[0].return_value;
       }
@@ -420,15 +423,15 @@ InodeCache::get(const char* path,
 bool
 InodeCache::put(const char* path,
                 ContentType type,
-                const digest& file_digest,
+                const Digest& file_digest,
                 int return_value)
 {
   if (!initialize()) {
     return false;
   }
 
-  digest key_digest;
-  if (!hash_inode(path, type, &key_digest)) {
+  Digest key_digest;
+  if (!hash_inode(path, type, key_digest)) {
     return false;
   }
 
index b1633a8fd0b587b19ed12bf64487808c5ffb10cd..69b5ceccef13e1e01afe82c8eccffd8aa46a858c 100644 (file)
@@ -29,7 +29,7 @@
 
 class Config;
 class Context;
-struct digest;
+class Digest;
 
 class InodeCache
 {
@@ -54,7 +54,7 @@ public:
   // otherwise.
   bool get(const char* path,
            ContentType type,
-           digest* file_digest,
+           Digest& file_digest,
            int* return_value = nullptr);
 
   // Put hash digest and return value from a successful call to
@@ -63,7 +63,7 @@ public:
   // Returns true if values could be stored in the cache, false otherwise.
   bool put(const char* path,
            ContentType type,
-           const digest& file_digest,
+           const Digest& file_digest,
            int return_value = 0);
 
   // Unmaps the current cache and removes the mapped file from disk.
@@ -99,9 +99,9 @@ private:
   struct SharedRegion;
 
   bool mmap_file(const std::string& inode_cache_file);
-  bool hash_inode(const char* path, ContentType type, digest* digest);
+  bool hash_inode(const char* path, ContentType type, Digest& digest);
   Bucket* acquire_bucket(uint32_t index);
-  Bucket* acquire_bucket(const digest& key_digest);
+  Bucket* acquire_bucket(const Digest& key_digest);
   void release_bucket(Bucket* bucket);
   bool create_new_file(const std::string& filename);
   bool initialize();
index b1ed264812512d7e44172cc287eb38a5989dee4d..a4fa05416bf155f8eb2bee8999ca4cd4c506abb7 100644 (file)
@@ -267,6 +267,17 @@ for_each_level_1_subdir(const std::string& cache_dir,
   progress_receiver(1.0);
 }
 
+std::string
+format_hex(const uint8_t* data, size_t size)
+{
+  std::string result;
+  result.reserve(size);
+  for (size_t i = 0; i < size; i++) {
+    result += fmt::format("{:02x}", data[i]);
+  }
+  return result;
+}
+
 std::string
 get_actual_cwd()
 {
index 59d528ca270df40e492ecd3c517e362bdf013397..8661a7107f3432162d13533cfafcb447c35ee390 100644 (file)
@@ -135,6 +135,10 @@ void for_each_level_1_subdir(const std::string& cache_dir,
                              const SubdirVisitor& visitor,
                              const ProgressReceiver& progress_receiver);
 
+// Format a hexadecimal string representing `size` bytes of `data`. The returned
+// string will be `2 * size` long.
+std::string format_hex(const uint8_t* data, size_t size);
+
 // Return current working directory (CWD) as returned from getcwd(3) (i.e.,
 // normalized path without symlink parts). Returns the empty string on error.
 std::string get_actual_cwd();
index c0727f51de2d2054ccd39d2afac9768f34d00d4e..22c7c287f2c3a956d4b969cf1ecc74b595f67a83 100644 (file)
@@ -346,9 +346,7 @@ do_remember_include_file(Context& ctx,
       return false;
     }
     hash_delimiter(cpp_hash, using_pch_sum ? "pch_sum_hash" : "pch_hash");
-    char pch_digest[DIGEST_STRING_BUFFER_SIZE];
-    hash_result_as_string(fhash, pch_digest);
-    hash_string(cpp_hash, pch_digest);
+    hash_string(cpp_hash, hash_result(fhash).to_string());
   }
 
   if (ctx.config.direct_mode()) {
@@ -382,15 +380,12 @@ do_remember_include_file(Context& ctx,
       }
     }
 
-    digest d;
-    hash_result_as_bytes(fhash, &d);
+    Digest d = hash_result(fhash);
     ctx.included_files.emplace(path, d);
 
     if (depend_mode_hash) {
       hash_delimiter(depend_mode_hash, "include");
-      char digest[DIGEST_STRING_BUFFER_SIZE];
-      digest_as_string(&d, digest);
-      hash_string(depend_mode_hash, digest);
+      hash_string(depend_mode_hash, d.to_string());
     }
   }
 
@@ -685,7 +680,7 @@ use_relative_paths_in_depfile(const Context& ctx)
 
 // Extract the used includes from the dependency file. Note that we cannot
 // distinguish system headers from other includes here.
-static struct digest*
+static optional<Digest>
 result_name_from_depfile(Context& ctx, struct hash* hash)
 {
   std::string file_content;
@@ -695,7 +690,7 @@ result_name_from_depfile(Context& ctx, struct hash* hash)
     cc_log("Cannot open dependency file %s: %s",
            ctx.args_info.output_dep.c_str(),
            e.what());
-    return nullptr;
+    return nullopt;
   }
 
   for (string_view token : Util::split_into_views(file_content, " \t\r\n")) {
@@ -723,9 +718,7 @@ result_name_from_depfile(Context& ctx, struct hash* hash)
     print_included_files(ctx, stdout);
   }
 
-  auto d = static_cast<digest*>(x_malloc(sizeof(digest)));
-  hash_result_as_bytes(hash, d);
-  return d;
+  return hash_result(hash);
 }
 
 // Execute the compiler/preprocessor, with logic to retry without requesting
@@ -977,8 +970,7 @@ to_cache(Context& ctx,
   }
 
   if (ctx.config.depend_mode()) {
-    struct digest* result_name =
-      result_name_from_depfile(ctx, depend_mode_hash);
+    auto result_name = result_name_from_depfile(ctx, depend_mode_hash);
     if (!result_name) {
       failed(STATS_ERROR);
     }
@@ -1071,7 +1063,7 @@ to_cache(Context& ctx,
 
 // Find the result name by running the compiler in preprocessor mode and
 // hashing the result.
-static struct digest*
+static Digest
 get_result_name_from_cpp(Context& ctx, Args& args, struct hash* hash)
 {
   ctx.time_of_compilation = time(nullptr);
@@ -1156,9 +1148,7 @@ get_result_name_from_cpp(Context& ctx, Args& args, struct hash* hash)
     hash_string(hash, "false");
   }
 
-  auto name = static_cast<digest*>(x_malloc(sizeof(digest)));
-  hash_result_as_bytes(hash, name);
-  return name;
+  return hash_result(hash);
 }
 
 // Hash mtime or content of a file, or the output of a command, according to
@@ -1418,7 +1408,7 @@ hash_profile_data_file(const Context& ctx, struct hash* hash)
 // Update a hash sum with information specific to the direct and preprocessor
 // modes and calculate the result name. Returns the result name on success,
 // otherwise NULL. Caller frees.
-static struct digest*
+static optional<Digest>
 calculate_result_name(Context& ctx,
                       const Args& args,
                       Args& preprocessor_args,
@@ -1625,7 +1615,7 @@ calculate_result_name(Context& ctx,
     hash_string(hash, arch);
   }
 
-  struct digest* result_name = nullptr;
+  optional<Digest> result_name;
   if (direct_mode) {
     // Hash environment variables that affect the preprocessor output.
     const char* envvars[] = {"CPATH",
@@ -1665,12 +1655,10 @@ calculate_result_name(Context& ctx,
     if (result & HASH_SOURCE_CODE_FOUND_TIME) {
       cc_log("Disabling direct mode");
       ctx.config.set_direct_mode(false);
-      return nullptr;
+      return nullopt;
     }
 
-    struct digest manifest_name;
-    hash_result_as_bytes(hash, &manifest_name);
-    ctx.set_manifest_name(manifest_name);
+    ctx.set_manifest_name(hash_result(hash));
 
     cc_log("Looking for result name in %s", ctx.manifest_path().c_str());
     MTR_BEGIN("manifest", "manifest_get");
@@ -1693,8 +1681,7 @@ calculate_result_name(Context& ctx,
         cc_log("Got result name from preprocessor with -arch %s",
                ctx.args_info.arch_args[i].c_str());
         if (i != ctx.args_info.arch_args.size() - 1) {
-          free(result_name);
-          result_name = nullptr;
+          result_name = nullopt;
         }
         preprocessor_args.pop_back();
       }
@@ -2153,8 +2140,8 @@ do_cache_compilation(Context& ctx, const char* const* argv)
   args_to_hash.push_back(extra_args_to_hash);
 
   bool put_result_in_manifest = false;
-  struct digest* result_name = nullptr;
-  struct digest* result_name_from_manifest = nullptr;
+  optional<Digest> result_name;
+  optional<Digest> result_name_from_manifest;
   if (ctx.config.direct_mode()) {
     cc_log("Trying direct lookup");
     MTR_BEGIN("hash", "direct_hash");
@@ -2207,8 +2194,7 @@ do_cache_compilation(Context& ctx, const char* const* argv)
     }
     ctx.set_result_name(*result_name);
 
-    if (result_name_from_manifest
-        && !digests_equal(result_name_from_manifest, result_name)) {
+    if (result_name_from_manifest && result_name_from_manifest != result_name) {
       // The hash from manifest differs from the hash of the preprocessor
       // output. This could be because:
       //
@@ -2314,9 +2300,7 @@ handle_main_options(int argc, const char* const* argv)
       } else {
         hash_binary_file(ctx, hash, optarg);
       }
-      char digest[DIGEST_STRING_BUFFER_SIZE];
-      hash_result_as_string(hash, digest);
-      puts(digest);
+      puts(hash_result(hash).to_string().c_str());
       hash_free(hash);
       break;
     }
index fc5195ad3bb0148405ea42dc9458459fa32e0a3b..735a683c99caac2938d527b7e0b7217ccc729c87 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "hash.hpp"
 
-#include "legacy_util.hpp"
+#include "Util.hpp"
 #include "logging.hpp"
 
 #include <blake2.h>
@@ -33,18 +33,6 @@ struct hash
   FILE* debug_text;
 };
 
-void
-digest_as_string(const struct digest* d, char* buffer)
-{
-  format_hex(d->bytes, DIGEST_SIZE, buffer);
-}
-
-bool
-digests_equal(const struct digest* d1, const struct digest* d2)
-{
-  return memcmp(d1->bytes, d2->bytes, DIGEST_SIZE) == 0;
-}
-
 static void
 do_hash_buffer(struct hash* hash, const void* s, size_t len)
 {
@@ -68,7 +56,7 @@ struct hash*
 hash_init()
 {
   auto hash = static_cast<struct hash*>(malloc(sizeof(struct hash)));
-  blake2b_init(&hash->state, DIGEST_SIZE);
+  blake2b_init(&hash->state, Digest::size());
   hash->debug_binary = nullptr;
   hash->debug_text = nullptr;
   return hash;
@@ -111,21 +99,15 @@ hash_buffer(struct hash* hash, const void* s, size_t len)
   do_debug_text(hash, s, len);
 }
 
-void
-hash_result_as_bytes(struct hash* hash, struct digest* digest)
+Digest
+hash_result(struct hash* hash)
 {
   // make a copy before altering state
   struct hash* copy = hash_copy(hash);
-  blake2b_final(&copy->state, digest->bytes, DIGEST_SIZE);
+  Digest digest;
+  blake2b_final(&copy->state, digest.bytes(), digest.size());
   hash_free(copy);
-}
-
-void
-hash_result_as_string(struct hash* hash, char* buffer)
-{
-  struct digest d;
-  hash_result_as_bytes(hash, &d);
-  digest_as_string(&d, buffer);
+  return digest;
 }
 
 void
index 8b1636711642500bca6d5f8722ea750fa12ba5b6..557d648a38355be82a0f4ab4c0fdb1aef11423f7 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2018-2019 Joel Rosdahl and other contributors
+// Copyright (C) 2018-2020 Joel Rosdahl and other contributors
 //
 // See doc/AUTHORS.adoc for a complete list of contributors.
 //
 
 #include "system.hpp"
 
-#include "third_party/nonstd/string_view.hpp"
-
-#define DIGEST_SIZE 20
-#define DIGEST_STRING_BUFFER_SIZE (2 * DIGEST_SIZE + 1)
-
-// struct digest represents the binary form of the final digest (AKA hash or
-// checksum) produced by the hash algorithm.
-struct digest
-{
-  uint8_t bytes[DIGEST_SIZE];
-};
+#include "Digest.hpp"
 
-// Format the digest as a NUL-terminated hex string. The string buffer must
-// contain at least DIGEST_STRING_BUFFER_SIZE bytes.
-void digest_as_string(const struct digest* d, char* buffer);
-
-// Return true if d1 and d2 are equal, else false.
-bool digests_equal(const struct digest* d1, const struct digest* d2);
+#include "third_party/nonstd/string_view.hpp"
 
 // struct hash represents the hash algorithm's inner state.
 struct hash;
@@ -57,12 +42,8 @@ void hash_enable_debug(struct hash* hash,
                        FILE* debug_binary,
                        FILE* debug_text);
 
-// Retrieve the digest as bytes.
-void hash_result_as_bytes(struct hash* hash, struct digest* digest);
-
-// Retrieve the digest as a NUL-terminated hex string. The string buffer must
-// contain at least DIGEST_STRING_BUFFER_SIZE bytes.
-void hash_result_as_string(struct hash* hash, char* buffer);
+// Retrieve the digest.
+Digest hash_result(struct hash* hash);
 
 // Hash some data that is unlikely to occur in the input. The idea is twofold:
 //
index e18e93ed224c945da380bb49f4eb7ab8ff4e99b3..97f12f9395216955c2ff82f42a32f0cb38ed80e0 100644 (file)
@@ -322,9 +322,9 @@ hash_source_code_file(const Context& ctx,
   // files separately so that digests based on file contents can be reused. Then
   // add the digest into the outer hash instead.
   InodeCache::ContentType content_type = get_content_type(ctx.config, path);
-  struct digest digest;
+  Digest digest;
   int return_value;
-  if (!ctx.inode_cache.get(path, content_type, &digest, &return_value)) {
+  if (!ctx.inode_cache.get(path, content_type, digest, &return_value)) {
     struct hash* file_hash = hash_init();
     return_value = hash_source_code_file_nocache(
       ctx,
@@ -335,11 +335,11 @@ hash_source_code_file(const Context& ctx,
     if (return_value == HASH_SOURCE_CODE_ERROR) {
       return HASH_SOURCE_CODE_ERROR;
     }
-    hash_result_as_bytes(file_hash, &digest);
+    digest = hash_result(file_hash);
     hash_free(file_hash);
     ctx.inode_cache.put(path, content_type, digest, return_value);
   }
-  hash_buffer(hash, &digest.bytes, sizeof(digest::bytes));
+  hash_buffer(hash, digest.bytes(), Digest::size());
   return return_value;
 #endif
 }
@@ -358,17 +358,17 @@ hash_binary_file(const Context& ctx, struct hash* hash, const char* path)
   // Reusable file hashes must be independent of the outer context. Thus hash
   // files separately so that digests based on file contents can be reused. Then
   // add the digest into the outer hash instead.
-  struct digest digest;
-  if (!ctx.inode_cache.get(path, InodeCache::ContentType::binary, &digest)) {
+  Digest digest;
+  if (!ctx.inode_cache.get(path, InodeCache::ContentType::binary, digest)) {
     struct hash* file_hash = hash_init();
     if (!hash_file(hash, path)) {
       return false;
     }
-    hash_result_as_bytes(file_hash, &digest);
+    digest = hash_result(file_hash);
     hash_free(file_hash);
     ctx.inode_cache.put(path, InodeCache::ContentType::binary, digest);
   }
-  hash_buffer(hash, &digest.bytes, sizeof(digest::bytes));
+  hash_buffer(hash, digest.bytes(), Digest::size());
   return true;
 #else
   return hash_file(hash, path);
index 2db39c4f62f23d97e57da8a2b4bfba226d1b5958..938493ac440a76c48f0c33cb3722201b672b5bfa 100644 (file)
@@ -309,17 +309,6 @@ format(const char* format, ...)
   return ptr;
 }
 
-// Construct a hexadecimal string representing binary data. The buffer must
-// hold at least 2 * size + 1 bytes.
-void
-format_hex(const uint8_t* data, size_t size, char* buffer)
-{
-  for (size_t i = 0; i < size; i++) {
-    sprintf(&buffer[i * 2], "%02x", (unsigned)data[i]);
-  }
-  buffer[2 * size] = '\0';
-}
-
 // This is like strdup() but dies if the malloc fails.
 char*
 x_strdup(const char* s)
index 95de8367355cb0e0a6feef3c69bc7ea2e5654d62..734a7733c4f6d3aff2ad034da921e418756839b5 100644 (file)
@@ -32,7 +32,6 @@ bool move_file(const char* src, const char* dest);
 const char* get_hostname();
 const char* tmp_string();
 char* format(const char* format, ...) ATTR_FORMAT(printf, 1, 2);
-void format_hex(const uint8_t* data, size_t size, char* buffer);
 void reformat(char** ptr, const char* format, ...) ATTR_FORMAT(printf, 2, 3);
 char* x_strdup(const char* s);
 char* x_strndup(const char* s, size_t n);
index 7399bc2490abfb655936cd869bd46d737b1885bb..e4294cd63233f32d2eff015c278d7c67d08c13fb 100644 (file)
@@ -24,6 +24,7 @@
 #include "Checksum.hpp"
 #include "Config.hpp"
 #include "Context.hpp"
+#include "Digest.hpp"
 #include "File.hpp"
 #include "StdMakeUnique.hpp"
 #include "ccache.hpp"
@@ -57,7 +58,7 @@
 // <n_includes>    ::= uint32_t
 // <include_entry> ::= <path_index> <digest> <fsize> <mtime> <ctime>
 // <path_index>    ::= uint32_t
-// <digest>        ::= DIGEST_SIZE bytes
+// <digest>        ::= Digest::size() bytes
 // <fsize>         ::= uint64_t ; file size
 // <mtime>         ::= int64_t ; modification time
 // <ctime>         ::= int64_t ; status change time
@@ -66,7 +67,7 @@
 // <result>        ::= <n_indexes> <include_index>* <name>
 // <n_indexes>     ::= uint32_t
 // <include_index> ::= uint32_t
-// <name>          ::= DIGEST_SIZE bytes
+// <name>          ::= Digest::size() bytes
 // <epilogue>      ::= <checksum>
 // <checksum>      ::= uint64_t ; XXH64 of content bytes
 //
@@ -85,7 +86,7 @@
 // ----------------------------------------------------------------------------
 // <n_includes>    4 bytes
 // <path_index>    4 bytes
-// <digest>        DIGEST_SIZE bytes
+// <digest>        Digest::size() bytes
 // <fsize>         8 bytes
 // <mtime>         8 bytes
 // <ctime>         8 bytes
@@ -95,7 +96,7 @@
 // <n_indexes>     4 bytes
 // <include_index> 4 bytes
 // ...
-// <name>          DIGEST_SIZE bytes
+// <name>          Digest::size() bytes
 // ...
 // checksum        8 bytes
 //
 // 1: Introduced in ccache 3.0. (Files are always compressed with gzip.)
 // 2: Introduced in ccache 4.0.
 
+using nonstd::nullopt;
+using nonstd::optional;
+
 const uint8_t k_manifest_magic[4] = {'c', 'C', 'm', 'F'};
 const uint8_t k_manifest_version = 2;
 const uint32_t k_max_manifest_entries = 100;
@@ -118,7 +122,7 @@ struct FileInfo
   // Index to n_files.
   uint32_t index;
   // Digest of referenced file.
-  struct digest digest;
+  Digest digest;
   // Size of referenced file.
   uint64_t fsize;
   // mtime of referenced file.
@@ -130,7 +134,7 @@ struct FileInfo
 bool
 operator==(const FileInfo& lhs, const FileInfo& rhs)
 {
-  return lhs.index == rhs.index && digests_equal(&lhs.digest, &rhs.digest)
+  return lhs.index == rhs.index && lhs.digest == rhs.digest
          && lhs.fsize == rhs.fsize && lhs.mtime == rhs.mtime
          && lhs.ctime == rhs.ctime;
 }
@@ -159,7 +163,7 @@ struct ResultEntry
   std::vector<uint32_t> file_info_indexes;
 
   // Name of the result.
-  struct digest name;
+  Digest name;
 };
 
 struct ManifestData
@@ -175,8 +179,8 @@ struct ManifestData
 
   void
   add_result_entry(
-    const struct digest& result_digest,
-    const std::unordered_map<std::string, digest>& included_files,
+    const Digest& result_digest,
+    const std::unordered_map<std::string, Digest>& included_files,
     time_t time_of_compilation,
     bool save_timestamp)
   {
@@ -209,7 +213,7 @@ private:
   uint32_t
   get_file_info_index(
     const std::string& path,
-    const digest& digest,
+    const Digest& digest,
     const std::unordered_map<std::string, uint32_t>& mf_files,
     const std::unordered_map<FileInfo, uint32_t>& mf_file_infos,
     time_t time_of_compilation,
@@ -307,7 +311,7 @@ read_manifest(const std::string& path, FILE* dump_stream = nullptr)
     auto& entry = mf->file_infos.back();
 
     reader.read(entry.index);
-    reader.read(entry.digest.bytes, DIGEST_SIZE);
+    reader.read(entry.digest.bytes(), Digest::size());
     reader.read(entry.fsize);
     reader.read(entry.mtime);
     reader.read(entry.ctime);
@@ -325,7 +329,7 @@ read_manifest(const std::string& path, FILE* dump_stream = nullptr)
       reader.read(file_info_index);
       entry.file_info_indexes.push_back(file_info_index);
     }
-    reader.read(entry.name.bytes, DIGEST_SIZE);
+    reader.read(entry.name.bytes(), Digest::size());
   }
 
   reader.finalize();
@@ -343,12 +347,12 @@ write_manifest(const Config& config,
     payload_size += 2 + file.length();
   }
   payload_size += 4; // n_file_infos
-  payload_size += mf.file_infos.size() * (4 + DIGEST_SIZE + 8 + 8 + 8);
+  payload_size += mf.file_infos.size() * (4 + Digest::size() + 8 + 8 + 8);
   payload_size += 4; // n_results
   for (const auto& result : mf.results) {
     payload_size += 4; // n_file_info_indexes
     payload_size += result.file_info_indexes.size() * 4;
-    payload_size += DIGEST_SIZE;
+    payload_size += Digest::size();
   }
 
   AtomicFile atomic_manifest_file(path, AtomicFile::Mode::binary);
@@ -367,7 +371,7 @@ write_manifest(const Config& config,
   writer.write<uint32_t>(mf.file_infos.size());
   for (const auto& file_info : mf.file_infos) {
     writer.write<uint32_t>(file_info.index);
-    writer.write(file_info.digest.bytes, DIGEST_SIZE);
+    writer.write(file_info.digest.bytes(), Digest::size());
     writer.write(file_info.fsize);
     writer.write(file_info.mtime);
     writer.write(file_info.ctime);
@@ -379,7 +383,7 @@ write_manifest(const Config& config,
     for (uint32_t j = 0; j < result.file_info_indexes.size(); ++j) {
       writer.write(result.file_info_indexes[j]);
     }
-    writer.write(result.name.bytes, DIGEST_SIZE);
+    writer.write(result.name.bytes(), Digest::size());
   }
 
   writer.finalize();
@@ -392,7 +396,7 @@ verify_result(const Context& ctx,
               const ManifestData& mf,
               const ResultEntry& result,
               std::unordered_map<std::string, FileStats>& stated_files,
-              std::unordered_map<std::string, digest>& hashed_files)
+              std::unordered_map<std::string, Digest>& hashed_files)
 {
   for (uint32_t file_info_index : result.file_info_indexes) {
     const auto& fi = mf.file_infos[file_info_index];
@@ -458,13 +462,12 @@ verify_result(const Context& ctx,
         return false;
       }
 
-      digest actual;
-      hash_result_as_bytes(hash, &actual);
+      Digest actual = hash_result(hash);
       hash_free(hash);
       hashed_files_iter = hashed_files.emplace(path, actual).first;
     }
 
-    if (!digests_equal(&fi.digest, &hashed_files_iter->second)) {
+    if (fi.digest != hashed_files_iter->second) {
       return false;
     }
   }
@@ -474,7 +477,7 @@ verify_result(const Context& ctx,
 
 // Try to get the result name from a manifest file. Caller frees. Returns NULL
 // on failure.
-struct digest*
+optional<Digest>
 manifest_get(const Context& ctx, const std::string& path)
 {
   std::unique_ptr<ManifestData> mf;
@@ -485,28 +488,25 @@ manifest_get(const Context& ctx, const std::string& path)
       update_mtime(path.c_str());
     } else {
       cc_log("No such manifest file");
-      return nullptr;
+      return nullopt;
     }
   } catch (const Error& e) {
     cc_log("Error: %s", e.what());
-    return nullptr;
+    return nullopt;
   }
 
   std::unordered_map<std::string, FileStats> stated_files;
-  std::unordered_map<std::string, digest> hashed_files;
+  std::unordered_map<std::string, Digest> hashed_files;
 
   // Check newest result first since it's a bit more likely to match.
-  struct digest* name = nullptr;
   for (uint32_t i = mf->results.size(); i > 0; i--) {
     if (verify_result(
           ctx, *mf, mf->results[i - 1], stated_files, hashed_files)) {
-      name = static_cast<digest*>(x_malloc(sizeof(digest)));
-      *name = mf->results[i - 1].name;
-      break;
+      return mf->results[i - 1].name;
     }
   }
 
-  return name;
+  return nullopt;
 }
 
 // Put the result name into a manifest file given a set of included files.
@@ -514,8 +514,8 @@ manifest_get(const Context& ctx, const std::string& path)
 bool
 manifest_put(const Config& config,
              const std::string& path,
-             const struct digest& result_name,
-             const std::unordered_map<std::string, digest>& included_files,
+             const Digest& result_name,
+             const std::unordered_map<std::string, Digest>& included_files,
 
              time_t time_of_compilation,
              bool save_timestamp)
@@ -594,26 +594,22 @@ manifest_dump(const std::string& path, FILE* stream)
   }
   fmt::print(stream, "File infos ({}):\n", mf->file_infos.size());
   for (unsigned i = 0; i < mf->file_infos.size(); ++i) {
-    char digest[DIGEST_STRING_BUFFER_SIZE];
     fmt::print(stream, "  {}:\n", i);
     fmt::print(stream, "    Path index: {}\n", mf->file_infos[i].index);
-    digest_as_string(&mf->file_infos[i].digest, digest);
-    fmt::print(stream, "    Hash: {}\n", digest);
+    fmt::print(stream, "    Hash: {}\n", mf->file_infos[i].digest.to_string());
     fmt::print(stream, "    File size: {}\n", mf->file_infos[i].fsize);
     fmt::print(stream, "    Mtime: {}\n", mf->file_infos[i].mtime);
     fmt::print(stream, "    Ctime: {}\n", mf->file_infos[i].ctime);
   }
   fmt::print(stream, "Results ({}):\n", mf->results.size());
   for (unsigned i = 0; i < mf->results.size(); ++i) {
-    char name[DIGEST_STRING_BUFFER_SIZE];
     fmt::print(stream, "  {}:\n", i);
     fmt::print(stream, "    File info indexes:");
     for (uint32_t file_info_index : mf->results[i].file_info_indexes) {
       fmt::print(stream, " {}", file_info_index);
     }
     fmt::print(stream, "\n");
-    digest_as_string(&mf->results[i].name, name);
-    fmt::print(stream, "    Name: {}\n", name);
+    fmt::print(stream, "    Name: {}\n", mf->results[i].name.to_string());
   }
 
   return true;
index 6dff9140ef503a226b3d788a8296fdf8ceeead11..e95c704c9282115511b1522c63339a2fceddc79e 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2009-2019 Joel Rosdahl and other contributors
+// Copyright (C) 2009-2020 Joel Rosdahl and other contributors
 //
 // See doc/AUTHORS.adoc for a complete list of contributors.
 //
 
 #include "system.hpp"
 
+#include "third_party/nonstd/optional.hpp"
+
 #include <string>
 #include <unordered_map>
 
 class Config;
 class Context;
-struct digest;
+class Digest;
 
 extern const uint8_t k_manifest_magic[4];
 extern const uint8_t k_manifest_version;
 
-struct digest* manifest_get(const Context& ctx, const std::string& path);
+nonstd::optional<Digest> manifest_get(const Context& ctx,
+                                      const std::string& path);
 bool manifest_put(const Config& config,
                   const std::string& path,
-                  const struct digest& result_name,
-                  const std::unordered_map<std::string, digest>& included_files,
+                  const Digest& result_name,
+                  const std::unordered_map<std::string, Digest>& included_files,
                   time_t time_of_compilation,
                   bool save_timestamp);
 bool manifest_dump(const std::string& path, FILE* stream);
index 8323aa38ef3217f97050c52382b8b3074d63cd15..f2396116c762c12ecd59f75345e8221fdf8ab1c8 100644 (file)
@@ -31,22 +31,21 @@ using TestUtil::TestContext;
 
 namespace {
 
-struct digest
+Digest
 digest_from_string(const char* s)
 {
-  struct digest digest;
+  Digest digest;
   struct hash* hash = hash_init();
   hash_string(hash, s);
-  hash_result_as_bytes(hash, &digest);
+  digest = hash_result(hash);
   hash_free(hash);
   return digest;
 }
 
 bool
-digest_equals_string(const struct digest& digest, const char* s)
+digest_equals_string(const Digest& digest, const char* s)
 {
-  struct digest rhs = digest_from_string(s);
-  return digests_equal(&digest, &rhs);
+  return digest == digest_from_string(s);
 }
 
 bool
@@ -68,11 +67,11 @@ TEST_CASE("Test disabled")
   ctx.config.set_debug(true);
   ctx.config.set_inode_cache(false);
 
-  struct digest digest;
+  Digest digest;
   int return_value;
 
   CHECK(!ctx.inode_cache.get(
-    "a", InodeCache::ContentType::code, &digest, &return_value));
+    "a", InodeCache::ContentType::code, digest, &return_value));
   CHECK(!ctx.inode_cache.put(
     "a", InodeCache::ContentType::code, digest, return_value));
   CHECK(ctx.inode_cache.get_hits() == -1);
@@ -90,11 +89,11 @@ TEST_CASE("Test lookup nonexistent")
   ctx.inode_cache.drop();
   Util::write_file("a", "");
 
-  struct digest digest;
+  Digest digest;
   int return_value;
 
   CHECK(!ctx.inode_cache.get(
-    "a", InodeCache::ContentType::code, &digest, &return_value));
+    "a", InodeCache::ContentType::code, digest, &return_value));
   CHECK(ctx.inode_cache.get_hits() == 0);
   CHECK(ctx.inode_cache.get_misses() == 1);
   CHECK(ctx.inode_cache.get_errors() == 0);
@@ -112,11 +111,11 @@ TEST_CASE("Test put and lookup")
 
   CHECK(put(ctx, "a", "a text", 1));
 
-  struct digest digest;
+  Digest digest;
   int return_value;
 
   CHECK(ctx.inode_cache.get(
-    "a", InodeCache::ContentType::code, &digest, &return_value));
+    "a", InodeCache::ContentType::code, digest, &return_value));
   CHECK(digest_equals_string(digest, "a text"));
   CHECK(return_value == 1);
   CHECK(ctx.inode_cache.get_hits() == 1);
@@ -126,7 +125,7 @@ TEST_CASE("Test put and lookup")
   Util::write_file("a", "something else");
 
   CHECK(!ctx.inode_cache.get(
-    "a", InodeCache::ContentType::code, &digest, &return_value));
+    "a", InodeCache::ContentType::code, digest, &return_value));
   CHECK(ctx.inode_cache.get_hits() == 1);
   CHECK(ctx.inode_cache.get_misses() == 1);
   CHECK(ctx.inode_cache.get_errors() == 0);
@@ -134,7 +133,7 @@ TEST_CASE("Test put and lookup")
   CHECK(put(ctx, "a", "something else", 2));
 
   CHECK(ctx.inode_cache.get(
-    "a", InodeCache::ContentType::code, &digest, &return_value));
+    "a", InodeCache::ContentType::code, digest, &return_value));
   CHECK(digest_equals_string(digest, "something else"));
   CHECK(return_value == 2);
   CHECK(ctx.inode_cache.get_hits() == 2);
@@ -150,9 +149,9 @@ TEST_CASE("Drop file")
   ctx.config.set_debug(true);
   ctx.config.set_inode_cache(true);
 
-  struct digest digest;
+  Digest digest;
 
-  ctx.inode_cache.get("a", InodeCache::ContentType::binary, &digest);
+  ctx.inode_cache.get("a", InodeCache::ContentType::binary, digest);
   CHECK(Stat::stat(ctx.inode_cache.get_file()));
   CHECK(ctx.inode_cache.drop());
   CHECK(!Stat::stat(ctx.inode_cache.get_file()));
@@ -168,9 +167,9 @@ TEST_CASE("Test content type")
   ctx.inode_cache.drop();
   ctx.config.set_inode_cache(true);
   Util::write_file("a", "a text");
-  digest binary_digest = digest_from_string("binary");
-  digest code_digest = digest_from_string("code");
-  digest code_with_sloppy_time_macros_digest =
+  Digest binary_digest = digest_from_string("binary");
+  Digest code_digest = digest_from_string("code");
+  Digest code_with_sloppy_time_macros_digest =
     digest_from_string("sloppy_time_macros");
 
   CHECK(ctx.inode_cache.put(
@@ -183,25 +182,25 @@ TEST_CASE("Test content type")
                         code_with_sloppy_time_macros_digest,
                         3));
 
-  digest digest;
+  Digest digest;
   int return_value;
 
   CHECK(ctx.inode_cache.get(
-    "a", InodeCache::ContentType::binary, &digest, &return_value));
-  CHECK(digests_equal(&digest, &binary_digest));
+    "a", InodeCache::ContentType::binary, digest, &return_value));
+  CHECK(digest == binary_digest);
   CHECK(return_value == 1);
 
   CHECK(ctx.inode_cache.get(
-    "a", InodeCache::ContentType::code, &digest, &return_value));
-  CHECK(digests_equal(&digest, &code_digest));
+    "a", InodeCache::ContentType::code, digest, &return_value));
+  CHECK(digest == code_digest);
   CHECK(return_value == 2);
 
   CHECK(
     ctx.inode_cache.get("a",
                         InodeCache::ContentType::code_with_sloppy_time_macros,
-                        &digest,
+                        digest,
                         &return_value));
-  CHECK(digests_equal(&digest, &code_with_sloppy_time_macros_digest));
+  CHECK(digest == code_with_sloppy_time_macros_digest);
   CHECK(return_value == 3);
 }
 
index d74c044f9fe5d11cd04be5ce7090d310f699644a..d8cd6401bf6c613e971ac6b7120d2562b8d46281 100644 (file)
@@ -251,6 +251,17 @@ TEST_CASE("Util::for_each_level_1_subdir")
   CHECK(actual == expected);
 }
 
+TEST_CASE("format_hex")
+{
+  uint8_t none[] = "";
+  uint8_t text[4] = "foo"; // incl. NUL
+  uint8_t data[4] = {0, 1, 2, 3};
+
+  CHECK(Util::format_hex(none, 0) == "");
+  CHECK(Util::format_hex(text, sizeof(text)) == "666f6f00");
+  CHECK(Util::format_hex(data, sizeof(data)) == "00010203");
+}
+
 TEST_CASE("Util::get_extension")
 {
   CHECK(Util::get_extension("") == "");
index 4ef257435350d2cc72b2afe450ea005ee194cf3b..afe83a31d5b9096d1350a8b9e7bd880c8860a3bb 100644 (file)
 
 TEST_CASE("test_known_strings")
 {
-  char d[DIGEST_STRING_BUFFER_SIZE];
-
   {
     struct hash* h = hash_init();
     hash_string(h, "");
-    hash_result_as_string(h, d);
-    CHECK(strcmp(d, "3345524abf6bbe1809449224b5972c41790b6cf2") == 0);
+    CHECK(hash_result(h).to_string()
+          == "3345524abf6bbe1809449224b5972c41790b6cf2");
     hash_free(h);
   }
 
   {
     struct hash* h = hash_init();
     hash_string(h, "a");
-    hash_result_as_string(h, d);
-    CHECK(strcmp(d, "948caa2db61bc4cdb4faf7740cd491f195043914") == 0);
+    CHECK(hash_result(h).to_string()
+          == "948caa2db61bc4cdb4faf7740cd491f195043914");
     hash_free(h);
   }
 
   {
     struct hash* h = hash_init();
     hash_string(h, "message digest");
-    hash_result_as_string(h, d);
-    CHECK(strcmp(d, "6bfec6f65e52962be863d6ea1005fc5e4cc8478c") == 0);
+    CHECK(hash_result(h).to_string()
+          == "6bfec6f65e52962be863d6ea1005fc5e4cc8478c");
     hash_free(h);
   }
 
@@ -55,47 +53,44 @@ TEST_CASE("test_known_strings")
       "1234567890123456789012345678901234567890123456789012345678901234567890"
       "1"
       "234567890");
-    hash_result_as_string(h, d);
-    CHECK(strcmp(d, "c2be0e534a67d25947f0c7e78527b2f82abd260f") == 0);
+    CHECK(hash_result(h).to_string()
+          == "c2be0e534a67d25947f0c7e78527b2f82abd260f");
     hash_free(h);
   }
 }
 
 TEST_CASE("hash_result_should_not_alter_state")
 {
-  char d[DIGEST_STRING_BUFFER_SIZE];
   struct hash* h = hash_init();
   hash_string(h, "message");
-  hash_result_as_string(h, d);
+  hash_result(h);
   hash_string(h, " digest");
-  hash_result_as_string(h, d);
-  CHECK(strcmp(d, "6bfec6f65e52962be863d6ea1005fc5e4cc8478c") == 0);
+  CHECK(hash_result(h).to_string()
+        == "6bfec6f65e52962be863d6ea1005fc5e4cc8478c");
   hash_free(h);
 }
 
 TEST_CASE("hash_result_should_be_idempotent")
 {
-  char d[DIGEST_STRING_BUFFER_SIZE];
   struct hash* h = hash_init();
   hash_string(h, "");
-  hash_result_as_string(h, d);
-  CHECK(strcmp(d, "3345524abf6bbe1809449224b5972c41790b6cf2") == 0);
-  hash_result_as_string(h, d);
-  CHECK(strcmp(d, "3345524abf6bbe1809449224b5972c41790b6cf2") == 0);
-
+  hash_result(h);
+  CHECK(hash_result(h).to_string()
+        == "3345524abf6bbe1809449224b5972c41790b6cf2");
+  CHECK(hash_result(h).to_string()
+        == "3345524abf6bbe1809449224b5972c41790b6cf2");
   hash_free(h);
 }
 
-TEST_CASE("hash_result_as_bytes")
+TEST_CASE("hash_result digest bytes")
 {
   struct hash* h = hash_init();
   hash_string(h, "message digest");
-  struct digest d;
-  hash_result_as_bytes(h, &d);
-  uint8_t expected[sizeof(d.bytes)] = {
+  Digest d = hash_result(h);
+  uint8_t expected[Digest::size()] = {
     0x6b, 0xfe, 0xc6, 0xf6, 0x5e, 0x52, 0x96, 0x2b, 0xe8, 0x63,
     0xd6, 0xea, 0x10, 0x05, 0xfc, 0x5e, 0x4c, 0xc8, 0x47, 0x8c,
   };
-  CHECK(memcmp(d.bytes, expected, sizeof(d.bytes)) == 0);
+  CHECK(memcmp(d.bytes(), expected, sizeof(Digest::size())) == 0);
   hash_free(h);
 }
index e4333e75ded44f88bb290915090e679faf550e8d..84d585185f910d22f4c6b99b18d8e0ae5644d4d8 100644 (file)
@@ -26,17 +26,12 @@ using TestUtil::TestContext;
 
 TEST_CASE("hash_command_output_simple")
 {
-  char d1[DIGEST_STRING_BUFFER_SIZE];
-  char d2[DIGEST_STRING_BUFFER_SIZE];
-
   struct hash* h1 = hash_init();
   struct hash* h2 = hash_init();
 
   CHECK(hash_command_output(h1, "echo", "not used"));
   CHECK(hash_command_output(h2, "echo", "not used"));
-  hash_result_as_string(h1, d1);
-  hash_result_as_string(h2, d2);
-  CHECK(strcmp(d1, d2) == 0);
+  CHECK(hash_result(h1) == hash_result(h2));
 
   hash_free(h2);
   hash_free(h1);
@@ -44,19 +39,12 @@ TEST_CASE("hash_command_output_simple")
 
 TEST_CASE("hash_command_output_space_removal")
 {
-  Context ctx;
-
-  char d1[DIGEST_STRING_BUFFER_SIZE];
-  char d2[DIGEST_STRING_BUFFER_SIZE];
-
   struct hash* h1 = hash_init();
   struct hash* h2 = hash_init();
 
   CHECK(hash_command_output(h1, "echo", "not used"));
   CHECK(hash_command_output(h2, " echo ", "not used"));
-  hash_result_as_string(h1, d1);
-  hash_result_as_string(h2, d2);
-  CHECK(strcmp(d1, d2) == 0);
+  CHECK(hash_result(h1) == hash_result(h2));
 
   hash_free(h2);
   hash_free(h1);
@@ -64,19 +52,12 @@ TEST_CASE("hash_command_output_space_removal")
 
 TEST_CASE("hash_command_output_hash_inequality")
 {
-  Context ctx;
-
-  char d1[DIGEST_STRING_BUFFER_SIZE];
-  char d2[DIGEST_STRING_BUFFER_SIZE];
-
   struct hash* h1 = hash_init();
   struct hash* h2 = hash_init();
 
   CHECK(hash_command_output(h1, "echo foo", "not used"));
   CHECK(hash_command_output(h2, "echo bar", "not used"));
-  hash_result_as_string(h1, d1);
-  hash_result_as_string(h2, d2);
-  CHECK(!str_eq(d1, d2));
+  CHECK(hash_result(h1) != hash_result(h2));
 
   hash_free(h2);
   hash_free(h1);
@@ -84,19 +65,12 @@ TEST_CASE("hash_command_output_hash_inequality")
 
 TEST_CASE("hash_command_output_compiler_substitution")
 {
-  Context ctx;
-
-  char d1[DIGEST_STRING_BUFFER_SIZE];
-  char d2[DIGEST_STRING_BUFFER_SIZE];
-
   struct hash* h1 = hash_init();
   struct hash* h2 = hash_init();
 
   CHECK(hash_command_output(h1, "echo foo", "not used"));
   CHECK(hash_command_output(h2, "%compiler% foo", "echo"));
-  hash_result_as_string(h1, d1);
-  hash_result_as_string(h2, d2);
-  CHECK(strcmp(d1, d2) == 0);
+  CHECK(hash_result(h1) == hash_result(h2));
 
   hash_free(h2);
   hash_free(h1);
@@ -106,11 +80,6 @@ TEST_CASE("hash_command_output_stdout_versus_stderr")
 {
   TestContext test_context;
 
-  Context ctx;
-
-  char d1[DIGEST_STRING_BUFFER_SIZE];
-  char d2[DIGEST_STRING_BUFFER_SIZE];
-
   struct hash* h1 = hash_init();
   struct hash* h2 = hash_init();
 
@@ -124,9 +93,7 @@ TEST_CASE("hash_command_output_stdout_versus_stderr")
   CHECK(hash_command_output(h1, "echo foo", "not used"));
   CHECK(hash_command_output(h2, "stderr.bat", "not used"));
 #endif
-  hash_result_as_string(h1, d1);
-  hash_result_as_string(h2, d2);
-  CHECK(strcmp(d1, d2) == 0);
+  CHECK(hash_result(h1) == hash_result(h2));
 
   hash_free(h2);
   hash_free(h1);
@@ -134,11 +101,6 @@ TEST_CASE("hash_command_output_stdout_versus_stderr")
 
 TEST_CASE("hash_multicommand_output")
 {
-  Context ctx;
-
-  char d1[DIGEST_STRING_BUFFER_SIZE];
-  char d2[DIGEST_STRING_BUFFER_SIZE];
-
   struct hash* h1 = hash_init();
   struct hash* h2 = hash_init();
 
@@ -152,9 +114,7 @@ TEST_CASE("hash_multicommand_output")
   CHECK(hash_multicommand_output(h2, "echo foo; echo bar", "not used"));
   CHECK(hash_multicommand_output(h1, "foo.bat", "not used"));
 #endif
-  hash_result_as_string(h1, d1);
-  hash_result_as_string(h2, d2);
-  CHECK(strcmp(d1, d2) == 0);
+  CHECK(hash_result(h1) == hash_result(h2));
 
   hash_free(h2);
   hash_free(h1);
index e2dcfae015e1ee87c7160dd514ce19bc454d857e..46051fd90fbe8dacad6f2820622005d7ca440950 100644 (file)
@@ -134,20 +134,3 @@ TEST_CASE("format_command")
 
   CHECK_STR_EQ_FREE2("foo bar\n", format_command(argv));
 }
-
-TEST_CASE("format_hex")
-{
-  uint8_t none[] = "";
-  uint8_t text[4] = "foo"; // incl. NUL
-  uint8_t data[4] = {0, 1, 2, 3};
-  char result[2 * sizeof(data) + 1] = ".";
-
-  format_hex(none, 0, result);
-  CHECK(strcmp("", result) == 0);
-
-  format_hex(text, sizeof(text), result);
-  CHECK(strcmp("666f6f00", result) == 0);
-
-  format_hex(data, sizeof(data), result);
-  CHECK(strcmp("00010203", result) == 0);
-}