]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Add binary representation of hash-size (#399)
authorAnders Björklund <anders.f.bjorklund@gmail.com>
Sat, 8 Jun 2019 19:17:14 +0000 (21:17 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Sat, 8 Jun 2019 19:17:14 +0000 (21:17 +0200)
* Add binary representation of hash-size

Fixed size efficient binary representation data,
instead of the variable size hexadecimal string.

This is suitable for machine use, while the other
is more suitable for human readability as string.

* Promote hex format as a global function

* Add unittest for the format_hex function

Make sure that output is NUL-terminated

configure.ac
src/ccache.h
src/util.c
unittest/framework.c
unittest/framework.h
unittest/test_util.c

index bb0f2be9ebebea9476843d7438577389f383acc6..70fb38cb85a09993536e63dffbbc0b7621fb2710 100644 (file)
@@ -82,12 +82,14 @@ AC_CHECK_TYPES(long long)
 
 AC_CHECK_HEADERS(ctype.h pwd.h stdlib.h string.h strings.h sys/time.h sys/mman.h)
 AC_CHECK_HEADERS(syslog.h)
+AC_CHECK_HEADERS(arpa/inet.h)
 AC_CHECK_HEADERS(termios.h)
 
 AC_CHECK_FUNCS(gethostname)
 AC_CHECK_FUNCS(getopt_long)
 AC_CHECK_FUNCS(getpwuid)
 AC_CHECK_FUNCS(gettimeofday)
+AC_CHECK_FUNCS(htonl)
 AC_CHECK_FUNCS(localtime_r)
 AC_CHECK_FUNCS(mkstemp)
 AC_CHECK_FUNCS(realpath)
index 4b3d65f23cadccd26abc48a724154c4b40a379cf..c0acb6da44365fad45218ebc79f8b3afa50bdfb8 100644 (file)
@@ -157,8 +157,11 @@ int create_parent_dirs(const char *path);
 const char *get_hostname(void);
 const char *tmp_string(void);
 char *format_hash_as_string(const unsigned char *hash, int size);
+typedef uint32_t binary[5]; // 20 bytes: 16 for hash + 4 for size
+void format_hash_as_binary(binary result, const unsigned char *hash, int size);
 int create_cachedirtag(const char *dir);
 char *format(const char *format, ...) ATTR_FORMAT(printf, 1, 2);
+char *format_hex(unsigned char *data, size_t size);
 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 5dcab39f7604a90c7a4795b5bc611feaa1afd714..23f56a966641bd94244de0c38f7fa9564f5e9ddf 100644 (file)
 #include <sys/time.h>
 #endif
 
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
 #ifdef _WIN32
 #include <windows.h>
 #include <sys/locking.h>
@@ -524,6 +528,21 @@ format_hash_as_string(const unsigned char *hash, int size)
        return ret;
 }
 
+// Return the hash result in binary.
+void format_hash_as_binary(binary result, const unsigned char *hash, int size)
+{
+       memcpy(result, hash, 16);
+#ifdef HAVE_HTONL
+       result[4] = htonl(size); // network byte order
+#else
+       uint32_t i = size;
+       unsigned char *bytes = (unsigned char *) result;
+       for (int j = 0; j < 4; j++) {
+               bytes[16 + j] = (i >> ((3 - j) * 8)) & 0xff; // (big endian)
+       }
+#endif
+}
+
 static char const CACHEDIR_TAG[] =
        "Signature: 8a477f597d28d172789f06886806bc55\n"
        "# This file is a cache directory tag created by ccache.\n"
@@ -580,6 +599,19 @@ format(const char *format, ...)
        return ptr;
 }
 
+// Construct a string representing data. Caller frees
+char *
+format_hex(unsigned char *data, size_t size)
+{
+       size_t i;
+       char *ret = x_malloc(2 * size + 1);
+       for (i = 0; i < size; i++) {
+               sprintf(&ret[i*2], "%02x", (unsigned) data[i]);
+       }
+       ret[2 * size] = '\0';
+       return ret;
+}
+
 // This is like strdup() but dies if the malloc fails.
 char *
 x_strdup(const char *s)
index 43170c8311ec2929a3949ef92725f9ff92925308..9e4a67df6f2d021229e66366f62b65408f25adbc 100644 (file)
@@ -209,6 +209,26 @@ cct_check_int_eq(const char *file, int line, const char *expression,
        }
 }
 
+bool cct_check_data_eq(const char *file, int line, const char *expression,
+                      void *expected, void *actual, size_t size)
+{
+       bool result;
+
+       if (expected && actual && memcmp(actual, expected, size) == 0) {
+               cct_check_passed(file, line, expression);
+               result = true;
+       } else {
+               char *exp_str = expected ? format_hex((unsigned char *) expected, size) : x_strdup("(null)");
+               char *act_str = actual ? format_hex((unsigned char *) actual, size) : x_strdup("(null)");
+               cct_check_failed(file, line, expression, exp_str, act_str);
+               free(exp_str);
+               free(act_str);
+               result = false;
+       }
+
+       return result;
+}
+
 bool
 cct_check_str_eq(const char *file, int line, const char *expression,
                  char *expected, char *actual,
index b23abfb33a4790f5e7f7302efd66d33754c17eb0..76aeb37b8d06ca68c78b77a66108a610ddf7f9e3 100644 (file)
 
 // ============================================================================
 
+#define CHECK_DATA_EQ(expected, actual, size) \
+       do { \
+               if (!cct_check_data_eq(__FILE__, __LINE__, #actual, (expected), \
+                                     (actual), size)) { \
+                       cct_test_end(); \
+                       cct_suite_end(); \
+                       return _test_counter; \
+               } \
+       } while (false)
+
+// ============================================================================
+
 #define CHECK_STR_EQ(expected, actual) \
        CHECK_POINTER_EQ_BASE(str, expected, actual, false, false)
 
@@ -139,6 +151,8 @@ bool cct_check_double_eq(const char *file, int line, const char *expression,
                          double expected, double actual);
 bool cct_check_int_eq(const char *file, int line, const char *expression,
                       int64_t expected, int64_t actual);
+bool cct_check_data_eq(const char *file, int line, const char *expression,
+                      void *expected, void *actual, size_t size);
 bool cct_check_str_eq(const char *file, int line, const char *expression,
                       char *expected, char *actual,
                      bool free1, bool free2);
index 8646a3d643f4d700c25f22728088f439284a38c5..b8e7384d7e552526dbb0824c7d5c2de371080b4a 100644 (file)
@@ -101,6 +101,34 @@ TEST(format_hash_as_string)
                           format_hash_as_string(hash, 12345));
 }
 
+TEST(format_hash_as_binary)
+{
+       unsigned char hash[16] = {
+               "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+       };
+
+       unsigned char data[20] = {
+               "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+               "\x00\x00\x00\x00"
+       };
+
+       binary buf;
+       CHECK_INT_EQ(sizeof(buf), 20);
+
+       format_hash_as_binary(buf, hash, 0);
+       CHECK_DATA_EQ(data, buf, 20);
+       hash[0] = 17;
+       hash[15] = 42;
+       format_hash_as_binary(buf, hash, 12345);
+       // data[0:16] = hash
+       data[0] = 0x11;
+       data[15] = 0x2a;
+       // 12345 = 0x3039 BE
+       data[18] = 0x30;
+       data[19] = 0x39;
+       CHECK_DATA_EQ(data, buf, 20);
+}
+
 TEST(subst_env_in_string)
 {
        char *errmsg;
@@ -207,4 +235,15 @@ TEST(format_command)
 
 }
 
+TEST(format_hex)
+{
+       unsigned char none[] = "";
+       unsigned char text[4] = "foo"; // incl. NUL
+       unsigned char data[4] = "\x00\x01\x02\x03";
+
+       CHECK_STR_EQ_FREE2("", format_hex(none, 0));
+       CHECK_STR_EQ_FREE2("666f6f00", format_hex(text, sizeof(text)));
+       CHECK_STR_EQ_FREE2("00010203", format_hex(data, sizeof(data)));
+}
+
 TEST_SUITE_END