diff options
author | Colin Walters <walters@verbum.org> | 2017-10-06 16:38:08 -0400 |
---|---|---|
committer | Atomic Bot <atomic-devel@projectatomic.io> | 2017-10-10 21:25:40 +0000 |
commit | 1c9975cbd12b05927e1969e5675479aea437188b (patch) | |
tree | df0cf969cd9f8119b31a6508804900f63a554953 /src/libotutil/ot-checksum-utils.c | |
parent | bba7eb80699cb789f31914bc98fc338c46237b37 (diff) | |
download | ostree-1c9975cbd12b05927e1969e5675479aea437188b.tar.gz |
lib: Add a lighter weight internal checksum wrapper
The faster (OpenSSL/GnuTLS) code lived in a `GInputStream` wrapper, and that
adds a lot of weight (GObject + vtable calls). Move it into a simple
autoptr-struct wrapper, and use it in the metadata path, so we're
now using the faster checksums there too.
This also drops a malloc there as the new API does hexdigest in place to a
buffer.
Prep for more work in the commit path to avoid `GInputStream` for local file
commits, and ["adopting" files](https://github.com/ostreedev/ostree/pull/1255).
Closes: #1256
Approved by: jlebon
Diffstat (limited to 'src/libotutil/ot-checksum-utils.c')
-rw-r--r-- | src/libotutil/ot-checksum-utils.c | 147 |
1 files changed, 136 insertions, 11 deletions
diff --git a/src/libotutil/ot-checksum-utils.c b/src/libotutil/ot-checksum-utils.c index bd787a3f..beba888b 100644 --- a/src/libotutil/ot-checksum-utils.c +++ b/src/libotutil/ot-checksum-utils.c @@ -22,10 +22,15 @@ #include "config.h" #include "otutil.h" +#if defined(HAVE_OPENSSL) +#include <openssl/evp.h> +#elif defined(HAVE_GNUTLS) +#include <gnutls/gnutls.h> +#include <gnutls/crypto.h> +#endif #include <string.h> - void ot_bin2hex (char *out_buf, const guint8 *inbuf, gsize len) { @@ -41,6 +46,119 @@ ot_bin2hex (char *out_buf, const guint8 *inbuf, gsize len) out_buf[j] = '\0'; } +/* I like to think of this as AbstractChecksumProxyFactoryBean. In homage to + * https://news.ycombinator.com/item?id=4549544 + * aka http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.html + */ +typedef struct { + gboolean initialized; +#if defined(HAVE_OPENSSL) + EVP_MD_CTX *checksum; +#elif defined(HAVE_GNUTLS) + gnutls_hash_hd_t checksum; +#else + GChecksum *checksum; +#endif + guint digest_len; +} OtRealChecksum; + +G_STATIC_ASSERT (sizeof (OtChecksum) >= sizeof (OtRealChecksum)); + +void +ot_checksum_init (OtChecksum *checksum) +{ + OtRealChecksum *real = (OtRealChecksum*)checksum; + g_return_if_fail (!real->initialized); +#if defined(HAVE_OPENSSL) + real->checksum = EVP_MD_CTX_create (); + g_assert (real->checksum); + g_assert (EVP_DigestInit_ex (real->checksum, EVP_sha256 (), NULL)); + real->digest_len = EVP_MAX_MD_SIZE; +#elif defined(HAVE_GNUTLS) + g_assert (!gnutls_hash_init (&real->checksum, GNUTLS_DIG_SHA256)); + real->digest_len = gnutls_hash_get_len (GNUTLS_DIG_SHA256); +#else + real->checksum = g_checksum_new (G_CHECKSUM_SHA256); + real->digest_len = g_checksum_type_get_length (G_CHECKSUM_SHA256); +#endif + real->initialized = TRUE; +} + +void +ot_checksum_update (OtChecksum *checksum, + const guint8 *buf, + size_t len) +{ + OtRealChecksum *real = (OtRealChecksum*)checksum; + g_return_if_fail (real->initialized); +#if defined(HAVE_OPENSSL) + g_assert (EVP_DigestUpdate (real->checksum, buf, len)); +#elif defined(HAVE_GNUTLS) + g_assert (!gnutls_hash (real->checksum, buf, len)); +#else + g_checksum_update (real->checksum, buf, len); +#endif +} + +static void +ot_checksum_get_digest_internal (OtRealChecksum *real, + guint8 *buf, + size_t buflen) +{ + g_return_if_fail (real->initialized); + g_assert_cmpint (buflen, ==, _OSTREE_SHA256_DIGEST_LEN); +#if defined(HAVE_OPENSSL) + guint digest_len = buflen; + g_assert (EVP_DigestFinal_ex (real->checksum, digest_buf, &digest_len)); + g_assert_cmpint (digest_len, ==, buflen); +#elif defined(HAVE_GNUTLS) + gnutls_hash_output (real->checksum, buf); +#else + gsize digest_len = buflen; + g_checksum_get_digest (real->checksum, buf, &digest_len); + g_assert_cmpint (digest_len, ==, buflen); +#endif +} + +void +ot_checksum_get_digest (OtChecksum *checksum, + guint8 *buf, + size_t buflen) +{ + OtRealChecksum *real = (OtRealChecksum*)checksum; + ot_checksum_get_digest_internal (real, buf, buflen); + real->initialized = FALSE; +} + +void +ot_checksum_get_hexdigest (OtChecksum *checksum, + char *buf, + size_t buflen) +{ + OtRealChecksum *real = (OtRealChecksum*)checksum; + const guint digest_len = real->digest_len; + guint8 digest_buf[digest_len]; + ot_checksum_get_digest (checksum, digest_buf, digest_len); + ot_bin2hex (buf, (guint8*)digest_buf, digest_len); + real->initialized = FALSE; +} + +void +ot_checksum_clear (OtChecksum *checksum) +{ + OtRealChecksum *real = (OtRealChecksum*)checksum; + if (!real->initialized) + return; +#if defined(HAVE_OPENSSL) + EVP_MD_CTX_destroy (real->checksum); +#elif defined(HAVE_GNUTLS) + gnutls_hash_deinit (real->checksum, NULL); +#else + g_checksum_free (real->checksum); +#endif + real->initialized = FALSE; +} + guchar * ot_csum_from_gchecksum (GChecksum *checksum) { @@ -57,7 +175,7 @@ ot_gio_write_update_checksum (GOutputStream *out, gconstpointer data, gsize len, gsize *out_bytes_written, - GChecksum *checksum, + OtChecksum *checksum, GCancellable *cancellable, GError **error) { @@ -73,14 +191,14 @@ ot_gio_write_update_checksum (GOutputStream *out, } if (checksum) - g_checksum_update (checksum, data, len); + ot_checksum_update (checksum, data, len); return TRUE; } gboolean ot_gio_splice_update_checksum (GOutputStream *out, GInputStream *in, - GChecksum *checksum, + OtChecksum *checksum, GCancellable *cancellable, GError **error) { @@ -92,7 +210,7 @@ ot_gio_splice_update_checksum (GOutputStream *out, char buf[4096]; do { - if (!g_input_stream_read_all (in, buf, sizeof(buf), &bytes_read, cancellable, error)) + if (!g_input_stream_read_all (in, buf, sizeof (buf), &bytes_read, cancellable, error)) return FALSE; if (!ot_gio_write_update_checksum (out, buf, bytes_read, &bytes_written, checksum, cancellable, error)) @@ -119,12 +237,16 @@ ot_gio_splice_get_checksum (GOutputStream *out, GCancellable *cancellable, GError **error) { - g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA256); + g_auto(OtChecksum) checksum = { 0, }; + ot_checksum_init (&checksum); - if (!ot_gio_splice_update_checksum (out, in, checksum, cancellable, error)) + if (!ot_gio_splice_update_checksum (out, in, &checksum, cancellable, error)) return FALSE; - g_autofree guchar *ret_csum = ot_csum_from_gchecksum (checksum); + guint8 digest[_OSTREE_SHA256_DIGEST_LEN]; + ot_checksum_get_digest (&checksum, digest, sizeof (digest)); + g_autofree guchar *ret_csum = g_malloc (sizeof (digest)); + memcpy (ret_csum, digest, sizeof (digest)); ot_transfer_out_value (out_csum, &ret_csum); return TRUE; } @@ -151,9 +273,12 @@ ot_checksum_file_at (int dfd, if (!ot_openat_read_stream (dfd, path, TRUE, &in, cancellable, error)) return FALSE; - g_autoptr(GChecksum) checksum = g_checksum_new (checksum_type); - if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) + g_auto(OtChecksum) checksum = { 0, }; + ot_checksum_init (&checksum); + if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error)) return FALSE; - return g_strdup (g_checksum_get_string (checksum)); + char hexdigest[_OSTREE_SHA256_STRING_LEN+1]; + ot_checksum_get_hexdigest (&checksum, hexdigest, sizeof (hexdigest)); + return g_strdup (hexdigest); } |