lib: Add a lighter weight internal checksum wrapper
authorColin Walters <walters@verbum.org>
Fri, 6 Oct 2017 20:38:08 +0000 (16:38 -0400)
committerAtomic Bot <atomic-devel@projectatomic.io>
Tue, 10 Oct 2017 21:25:40 +0000 (21:25 +0000)
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

src/libostree/ostree-core-private.h
src/libostree/ostree-core.c
src/libostree/ostree-repo-commit.c
src/libostree/ostree-repo-static-delta-processing.c
src/libostree/ostree-sysroot-deploy.c
src/libotutil/ot-checksum-instream.c
src/libotutil/ot-checksum-instream.h
src/libotutil/ot-checksum-utils.c
src/libotutil/ot-checksum-utils.h

index 0658a0cbbdf758b61c28f0dcbed304c9a9ed1ef3..70b12b68c7db66d124ee1ff71db3d270e12cd12b 100644 (file)
@@ -20,6 +20,7 @@
 #pragma once
 
 #include "ostree-core.h"
+#include "otutil.h"
 #include <sys/stat.h>
 
 G_BEGIN_DECLS
@@ -77,7 +78,7 @@ gboolean _ostree_write_variant_with_size (GOutputStream      *output,
                                           GVariant           *variant,
                                           guint64             alignment_offset,
                                           gsize              *out_bytes_written,
-                                          GChecksum          *checksum,
+                                          OtChecksum         *checksum,
                                           GCancellable       *cancellable,
                                           GError            **error);
 
index 7fa051f2ff224f8c15fe79521ecbcc72b2f311bf..2fafe99d70954e0e786dca1ef691ea245d0a6470 100644 (file)
@@ -358,7 +358,7 @@ write_padding (GOutputStream    *output,
                guint             alignment,
                gsize             offset,
                gsize            *out_bytes_written,
-               GChecksum        *checksum,
+               OtChecksum       *checksum,
                GCancellable     *cancellable,
                GError          **error)
 {
@@ -403,7 +403,7 @@ _ostree_write_variant_with_size (GOutputStream      *output,
                                  GVariant           *variant,
                                  guint64             alignment_offset,
                                  gsize              *out_bytes_written,
-                                 GChecksum          *checksum,
+                                 OtChecksum         *checksum,
                                  GCancellable       *cancellable,
                                  GError            **error)
 {
@@ -458,7 +458,7 @@ _ostree_write_variant_with_size (GOutputStream      *output,
 static gboolean
 write_file_header_update_checksum (GOutputStream         *out,
                                    GVariant              *header,
-                                   GChecksum             *checksum,
+                                   OtChecksum            *checksum,
                                    GCancellable          *cancellable,
                                    GError               **error)
 {
@@ -859,18 +859,19 @@ ostree_checksum_file_from_input (GFileInfo        *file_info,
                                  GError          **error)
 {
 
-  g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA256);
+  g_auto(OtChecksum) checksum = { 0, };
+  ot_checksum_init (&checksum);
 
   if (OSTREE_OBJECT_TYPE_IS_META (objtype))
     {
-      if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error))
+      if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error))
         return FALSE;
     }
   else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
     {
       g_autoptr(GVariant) dirmeta = ostree_create_directory_metadata (file_info, xattrs);
-      g_checksum_update (checksum, g_variant_get_data (dirmeta),
-                         g_variant_get_size (dirmeta));
+      ot_checksum_update (&checksum, g_variant_get_data (dirmeta),
+                          g_variant_get_size (dirmeta));
     }
   else
     {
@@ -878,18 +879,19 @@ ostree_checksum_file_from_input (GFileInfo        *file_info,
 
       file_header = _ostree_file_header_new (file_info, xattrs);
 
-      if (!write_file_header_update_checksum (NULL, file_header, checksum,
+      if (!write_file_header_update_checksum (NULL, file_header, &checksum,
                                               cancellable, error))
         return FALSE;
 
       if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
         {
-          if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error))
+          if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error))
             return FALSE;
         }
     }
 
-  *out_csum = ot_csum_from_gchecksum (checksum);
+  *out_csum = g_malloc (OSTREE_SHA256_DIGEST_LEN);
+  ot_checksum_get_digest (&checksum, *out_csum, OSTREE_SHA256_DIGEST_LEN);
   return TRUE;
 }
 
index 2bffbae39de5d495e50ad6f812fe3f8a65c08237..377adc754d5cfac2a65c1b26c9feed63cdc85640 100644 (file)
@@ -811,14 +811,19 @@ write_metadata_object (OstreeRepo         *self,
    * *original* sha256 to say what commit was being killed.
    */
   const gboolean is_tombstone = (objtype == OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT);
-  g_autofree char *actual_checksum = NULL;
+  char actual_checksum[OSTREE_SHA256_STRING_LEN+1];
   if (is_tombstone)
     {
-      actual_checksum = g_strdup (expected_checksum);
+      memcpy (actual_checksum, expected_checksum, sizeof (actual_checksum));
     }
   else
     {
-      actual_checksum = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, buf);
+      OtChecksum checksum = { 0, };
+      ot_checksum_init (&checksum);
+      gsize len;
+      const guint8*bufdata = g_bytes_get_data (buf, &len);
+      ot_checksum_update (&checksum, bufdata, len);
+      ot_checksum_get_hexdigest (&checksum, actual_checksum, sizeof (actual_checksum));
       gboolean have_obj;
       if (!_ostree_repo_has_loose_object (self, actual_checksum, objtype, &have_obj,
                                           cancellable, error))
index 844de2c6537322306eaf3909bee8c5fd2286d412..fca0f216105530afe8afd762e22bc53cfd461982 100644 (file)
@@ -58,7 +58,7 @@ typedef struct {
   GLnxTmpfile      tmpf;
   guint64          content_size;
   GOutputStream   *content_out;
-  GChecksum       *content_checksum;
+  OtChecksum       content_checksum;
   char             checksum[OSTREE_SHA256_STRING_LEN+1];
   char             *read_source_object;
   int               read_source_fd;
@@ -277,7 +277,7 @@ _ostree_static_delta_part_execute (OstreeRepo      *repo,
  out:
   glnx_tmpfile_clear (&state->tmpf);
   g_clear_object (&state->content_out);
-  g_clear_pointer (&state->content_checksum, g_checksum_free);
+  ot_checksum_clear (&state->content_checksum);
   return ret;
 }
 
@@ -385,8 +385,8 @@ content_out_write (OstreeRepo                 *repo,
 {
   gsize bytes_written;
 
-  if (state->content_checksum)
-    g_checksum_update (state->content_checksum, buf, len);
+  if (state->content_checksum.initialized)
+    ot_checksum_update (&state->content_checksum, buf, len);
 
   /* Ignore bytes_written since we discard partial content */
   if (!g_output_stream_write_all (state->content_out,
@@ -503,10 +503,10 @@ handle_untrusted_content_checksum (OstreeRepo                 *repo,
   g_autoptr(GFileInfo) finfo = _ostree_mode_uidgid_to_gfileinfo (state->mode, state->uid, state->gid);
   g_autoptr(GVariant) header = _ostree_file_header_new (finfo, state->xattrs);
 
-  state->content_checksum = g_checksum_new (G_CHECKSUM_SHA256);
+  ot_checksum_init (&state->content_checksum);
 
   gsize bytes_written;
-  if (!_ostree_write_variant_with_size (NULL, header, 0, &bytes_written, state->content_checksum,
+  if (!_ostree_write_variant_with_size (NULL, header, 0, &bytes_written, &state->content_checksum,
                                         cancellable, error))
     return FALSE;
 
@@ -827,9 +827,10 @@ dispatch_close (OstreeRepo                 *repo,
       if (!g_output_stream_flush (state->content_out, cancellable, error))
         return FALSE;
 
-      if (state->content_checksum)
+      if (state->content_checksum.initialized)
         {
-          const char *actual_checksum = g_checksum_get_string (state->content_checksum);
+          char actual_checksum[OSTREE_SHA256_STRING_LEN+1];
+          ot_checksum_get_hexdigest (&state->content_checksum, actual_checksum, sizeof (actual_checksum));
 
           if (strcmp (actual_checksum, state->checksum) != 0)
             return glnx_throw (error, "Corrupted object %s (actual checksum is %s)",
@@ -848,7 +849,7 @@ dispatch_close (OstreeRepo                 *repo,
     return FALSE;
 
   g_clear_pointer (&state->xattrs, g_variant_unref);
-  g_clear_pointer (&state->content_checksum, g_checksum_free);
+  ot_checksum_clear (&state->content_checksum);
 
   state->checksum_index++;
   state->output_target = NULL;
index 4f45303478d6de205e4d0a027cef7dd4319bd777..920c0eb47e701ecb02a1a77aca402d759a62bbc3 100644 (file)
@@ -989,13 +989,14 @@ get_kernel_from_tree_usrlib_modules (int                  deployment_dfd,
     }
 
   /* We found a module directory, compute the checksum */
-  g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA256);
+  g_auto(OtChecksum) checksum = { 0, };
+  ot_checksum_init (&checksum);
   glnx_fd_close int fd = -1;
   /* Checksum the kernel */
   if (!glnx_openat_rdonly (ret_layout->boot_dfd, "vmlinuz", TRUE, &fd, error))
     return FALSE;
   g_autoptr(GInputStream) in = g_unix_input_stream_new (fd, FALSE);
-  if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error))
+  if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error))
     return FALSE;
   g_clear_object (&in);
   (void) close (fd); fd = -1;
@@ -1022,11 +1023,13 @@ get_kernel_from_tree_usrlib_modules (int                  deployment_dfd,
       ret_layout->initramfs_srcpath = g_strdup (initramfs_path);
       ret_layout->initramfs_namever = g_strdup_printf ("initramfs-%s.img", kver);
       in = g_unix_input_stream_new (fd, FALSE);
-      if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error))
+      if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error))
         return FALSE;
     }
 
-  ret_layout->bootcsum = g_strdup (g_checksum_get_string (checksum));
+  char hexdigest[OSTREE_SHA256_STRING_LEN+1];
+  ot_checksum_get_hexdigest (&checksum, hexdigest, sizeof (hexdigest));
+  ret_layout->bootcsum = g_strdup (hexdigest);
 
   *out_layout = g_steal_pointer (&ret_layout);
   return TRUE;
index 368a337df5c76746c3ef3520b5c14e2a23945ac6..342b14b4f7362ae809da3f7e44cba6a85d81af52 100644 (file)
 #include "ot-checksum-instream.h"
 #include "ot-checksum-utils.h"
 
-#if defined(HAVE_OPENSSL)
-#include <openssl/evp.h>
-#elif defined(HAVE_GNUTLS)
-#include <gnutls/gnutls.h>
-#include <gnutls/crypto.h>
-#endif
-
 G_DEFINE_TYPE (OtChecksumInstream, ot_checksum_instream, G_TYPE_FILTER_INPUT_STREAM)
 
 struct _OtChecksumInstreamPrivate {
-#if defined(HAVE_OPENSSL)
-  EVP_MD_CTX *checksum;
-#elif defined(HAVE_GNUTLS)
-  gnutls_digest_algorithm_t checksum_type;
-  gnutls_hash_hd_t checksum;
-#else
-  GChecksumType checksum_type;
-  GChecksum *checksum;
-#endif
+  OtChecksum checksum;
 };
 
 static gssize   ot_checksum_instream_read         (GInputStream         *stream,
@@ -54,13 +39,7 @@ ot_checksum_instream_finalize (GObject *object)
 {
   OtChecksumInstream *self = (OtChecksumInstream*)object;
 
-#if defined(HAVE_OPENSSL)
-  EVP_MD_CTX_destroy (self->priv->checksum);
-#elif defined(HAVE_GNUTLS)
-  gnutls_hash_deinit (self->priv->checksum, NULL);
-#else
-  g_checksum_free (self->priv->checksum);
-#endif
+  ot_checksum_clear (&self->priv->checksum);
 
   G_OBJECT_CLASS (ot_checksum_instream_parent_class)->finalize (object);
 }
@@ -83,33 +62,6 @@ ot_checksum_instream_init (OtChecksumInstream *self)
   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, OT_TYPE_CHECKSUM_INSTREAM, OtChecksumInstreamPrivate);
 }
 
-#if defined(HAVE_OPENSSL)
-static const EVP_MD *
-gchecksum_type_to_openssl (GChecksumType checksum_type)
-{
-  switch (checksum_type)
-    {
-    case G_CHECKSUM_SHA256:
-      return EVP_sha256 ();
-    default:
-      /* If there's something else, fill in here */
-      g_assert_not_reached ();
-    }
-}
-#elif defined(HAVE_GNUTLS)
-static gnutls_digest_algorithm_t
-gchecksum_type_to_gnutls (GChecksumType checksum_type)
-{
-  switch (checksum_type)
-    {
-    case G_CHECKSUM_SHA256:
-      return GNUTLS_DIG_SHA256;
-    default:
-      g_assert_not_reached ();
-    }
-}
-#endif
-
 OtChecksumInstream *
 ot_checksum_instream_new (GInputStream    *base,
                           GChecksumType    checksum_type)
@@ -124,18 +76,7 @@ ot_checksum_instream_new (GInputStream    *base,
 
   /* For now */
   g_assert (checksum_type == G_CHECKSUM_SHA256);
-
-#if defined(HAVE_OPENSSL)
-  stream->priv->checksum = EVP_MD_CTX_create ();
-  g_assert (stream->priv->checksum);
-  g_assert (EVP_DigestInit_ex (stream->priv->checksum, gchecksum_type_to_openssl (checksum_type), NULL));
-#elif defined(HAVE_GNUTLS)
-  stream->priv->checksum_type = gchecksum_type_to_gnutls (checksum_type);
-  g_assert (!gnutls_hash_init (&stream->priv->checksum, stream->priv->checksum_type));
-#else
-  stream->priv->checksum = g_checksum_new (checksum_type);
-  stream->priv->checksum_type = checksum_type;
-#endif
+  ot_checksum_init (&stream->priv->checksum);
 
   return (OtChecksumInstream*) (stream);
 }
@@ -157,78 +98,15 @@ ot_checksum_instream_read (GInputStream  *stream,
                              cancellable,
                              error);
   if (res > 0)
-    {
-#if defined(HAVE_OPENSSL)
-      g_assert (EVP_DigestUpdate (self->priv->checksum, buffer, res));
-#elif defined(HAVE_GNUTLS)
-      g_assert (!gnutls_hash (self->priv->checksum, buffer, res));
-#else
-      g_checksum_update (self->priv->checksum, buffer, res);
-#endif
-    }
+    ot_checksum_update (&self->priv->checksum, buffer, res);
 
   return res;
 }
 
-void
-ot_checksum_instream_get_digest (OtChecksumInstream *stream,
-                                 guint8          *buffer,
-                                 gsize           *digest_len)
-{
-#if defined(HAVE_OPENSSL)
-  unsigned len;
-  EVP_DigestFinal_ex (stream->priv->checksum, buffer, &len);
-  if (digest_len)
-    *digest_len = len;
-#elif defined(HAVE_GNUTLS)
-  gnutls_hash_output (stream->priv->checksum, buffer);
-  if (digest_len)
-    *digest_len = gnutls_hash_get_len (stream->priv->checksum_type);
-#else
-  g_checksum_get_digest (stream->priv->checksum, buffer, digest_len);
-#endif
-}
-
-guint8*
-ot_checksum_instream_dup_digest (OtChecksumInstream *stream,
-                                 gsize              *ret_len)
-{
-#if defined(HAVE_OPENSSL)
-  guint len;
-  guchar *ret = g_malloc0 (EVP_MAX_MD_SIZE);
-  g_assert (EVP_DigestFinal_ex (stream->priv->checksum, ret, &len));
-#elif defined(HAVE_GNUTLS)
-  guint len = gnutls_hash_get_len (stream->priv->checksum_type);
-  guchar *ret = g_malloc0 (len);
-  gnutls_hash_output (stream->priv->checksum, ret);
-#else
-  gsize len = g_checksum_type_get_length (stream->priv->checksum_type);
-  guchar *ret = g_malloc (len);
-  g_checksum_get_digest (stream->priv->checksum, ret, &len);
-#endif
-  if (ret_len)
-    *ret_len = len;
-  return ret;
-}
-
 char *
 ot_checksum_instream_get_string (OtChecksumInstream *stream)
 {
-#if defined(HAVE_OPENSSL)
-  unsigned len;
-  guint8 csum[EVP_MAX_MD_SIZE];
-  g_assert (EVP_DigestFinal_ex (stream->priv->checksum, csum, &len));
-  char *buf = g_malloc (len * 2 + 1);
-  ot_bin2hex (buf, (guint8*)csum, len);
-  return buf;
-#elif defined(HAVE_GNUTLS)
-  gsize len;
-  guint8 *csum = ot_checksum_instream_dup_digest(stream, &len);
-  char *buf = g_malloc0 (len * 2 + 1);
-  ot_bin2hex (buf, csum, len);
-  g_free (csum);
-  return buf;
-#else
-  return g_strdup (g_checksum_get_string (stream->priv->checksum));
-#endif
+  char buf[_OSTREE_SHA256_STRING_LEN+1];
+  ot_checksum_get_hexdigest (&stream->priv->checksum, buf, sizeof(buf));
+  return g_strndup (buf, sizeof(buf));
 }
index 6525aa91f5aa6774c989f9735aff194c47b8dc18..410047a9e6e449ce4dcb476caa441904f1a623b7 100644 (file)
@@ -52,12 +52,6 @@ GType          ot_checksum_instream_get_type     (void) G_GNUC_CONST;
 
 OtChecksumInstream * ot_checksum_instream_new          (GInputStream   *stream, GChecksumType   checksum);
 
-void   ot_checksum_instream_get_digest (OtChecksumInstream *stream,
-                                        guint8          *buffer,
-                                        gsize           *digest_len);
-
-guint8* ot_checksum_instream_dup_digest (OtChecksumInstream *stream,
-                                         gsize              *ret_len);
 char * ot_checksum_instream_get_string (OtChecksumInstream *stream);
 
 G_END_DECLS
index bd787a3f86176f835c7dbb68a9332fb6c14d76e3..beba888b19d914a514f61b712e828328244b8d88 100644 (file)
 #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);
 }
index a0e72dbc0a1648f58ac70ec8206e415342ae7bb1..abf3c6db057799dd55872fbfe49096e258582dda 100644 (file)
@@ -21,7 +21,7 @@
 
 #pragma once
 
-#include <gio/gio.h>
+#include "libglnx.h"
 
 G_BEGIN_DECLS
 
@@ -29,11 +29,42 @@ void ot_bin2hex (char *out_buf, const guint8 *inbuf, gsize len);
 
 guchar *ot_csum_from_gchecksum (GChecksum *checksum);
 
+struct OtChecksum {
+  gboolean initialized;
+  guint uints[2];
+  gpointer data[2];
+};
+typedef struct OtChecksum OtChecksum;
+
+/* Same as OSTREE_SHA256_DIGEST_LEN, but this header can't depend on that */
+#define _OSTREE_SHA256_DIGEST_LEN (32)
+#if defined(OSTREE_SHA256_DIGEST_LEN) && _OSTREE_SHA256_DIGEST_LEN != OSTREE_SHA256_DIGEST_LEN
+#error Mismatched OSTREE_SHA256_DIGEST_LEN
+#endif
+/* See above */
+#define _OSTREE_SHA256_STRING_LEN (64)
+#if defined(OSTREE_SHA256_STRING_LEN) && _OSTREE_SHA256_STRING_LEN != OSTREE_SHA256_STRING_LEN
+#error Mismatched OSTREE_SHA256_STRING_LEN
+#endif
+
+void ot_checksum_init (OtChecksum *checksum);
+void ot_checksum_update (OtChecksum *checksum,
+                         const guint8   *buf,
+                         size_t          len);
+void ot_checksum_get_digest (OtChecksum *checksum,
+                             guint8      *buf,
+                             size_t       buflen);
+void ot_checksum_get_hexdigest (OtChecksum *checksum,
+                                char           *buf,
+                                size_t          buflen);
+void ot_checksum_clear (OtChecksum *checksum);
+G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OtChecksum, ot_checksum_clear)
+
 gboolean ot_gio_write_update_checksum (GOutputStream  *out,
                                        gconstpointer   data,
                                        gsize           len,
                                        gsize          *out_bytes_written,
-                                       GChecksum      *checksum,
+                                       OtChecksum     *checksum,
                                        GCancellable   *cancellable,
                                        GError        **error);
 
@@ -45,7 +76,7 @@ gboolean ot_gio_splice_get_checksum (GOutputStream  *out,
 
 gboolean ot_gio_splice_update_checksum (GOutputStream  *out,
                                         GInputStream   *in,
-                                        GChecksum      *checksum,
+                                        OtChecksum     *checksum,
                                         GCancellable   *cancellable,
                                         GError        **error);