diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c index 147d0f3c..49b3d43f 100644 --- a/src/libostree/ostree-core.c +++ b/src/libostree/ostree-core.c @@ -703,41 +703,6 @@ ostree_pack_object (GOutputStream *output, return ret; } -static gboolean -splice_and_checksum (GOutputStream *out, - GInputStream *in, - GChecksum *checksum, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - - if (checksum != NULL) - { - gsize bytes_read, bytes_written; - char buf[4096]; - do - { - if (!g_input_stream_read_all (in, buf, sizeof(buf), &bytes_read, cancellable, error)) - goto out; - if (checksum) - g_checksum_update (checksum, (guint8*)buf, bytes_read); - if (!g_output_stream_write_all (out, buf, bytes_read, &bytes_written, cancellable, error)) - goto out; - } - while (bytes_read > 0); - } - else - { - if (g_output_stream_splice (out, in, 0, cancellable, error) < 0) - goto out; - } - - ret = TRUE; - out: - return ret; -} - static gboolean unpack_meta (GFile *file, GFile *dest_file, @@ -749,9 +714,6 @@ unpack_meta (GFile *file, GChecksum *ret_checksum = NULL; GFileOutputStream *out = NULL; - if (out_checksum) - ret_checksum = g_checksum_new (G_CHECKSUM_SHA256); - in = g_file_read (file, NULL, error); if (!in) goto out; @@ -760,7 +722,8 @@ unpack_meta (GFile *file, if (!out) goto out; - if (!splice_and_checksum ((GOutputStream*)out, (GInputStream*)in, ret_checksum, NULL, error)) + if (!ot_gio_splice_and_checksum ((GOutputStream*)out, (GInputStream*)in, + out_checksum ? &ret_checksum : NULL, NULL, error)) goto out; if (!g_output_stream_close ((GOutputStream*)out, NULL, error)) @@ -768,8 +731,10 @@ unpack_meta (GFile *file, ret = TRUE; if (out_checksum) - *out_checksum = ret_checksum; - ret_checksum = NULL; + { + *out_checksum = ret_checksum; + ret_checksum = NULL; + } out: ot_clear_checksum (&ret_checksum); g_clear_object (&in); @@ -869,16 +834,13 @@ unpack_file (GFile *file, mode = GUINT32_FROM_BE (mode); content_len = GUINT64_FROM_BE (content_len); - if (out_checksum) - ret_checksum = g_checksum_new (G_CHECKSUM_SHA256); - if (S_ISREG (mode)) { out = g_file_replace (dest_file, NULL, FALSE, 0, NULL, error); if (!out) goto out; - if (!splice_and_checksum ((GOutputStream*)out, in, ret_checksum, NULL, error)) + if (!ot_gio_splice_and_checksum ((GOutputStream*)out, in, out_checksum ? &ret_checksum : NULL, NULL, error)) goto out; if (!g_output_stream_close ((GOutputStream*)out, NULL, error)) diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 729f9d4b..f58eec44 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -562,6 +562,76 @@ ostree_repo_is_archive (OstreeRepo *self) return priv->archive; } +static gboolean +stage_and_checksum (OstreeRepo *self, + OstreeObjectType objtype, + GInputStream *input, + GFile **out_tmpname, + GChecksum **out_checksum, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + const char *prefix = NULL; + OstreeRepoPrivate *priv = GET_PRIVATE (self); + GFile *tmp_f = NULL; + GOutputStream *stream = NULL; + GFile *ret_tmpname = NULL; + GChecksum *ret_checksum = NULL; + + switch (objtype) + { + case OSTREE_OBJECT_TYPE_FILE: + prefix = "file-tmp-"; + break; + case OSTREE_OBJECT_TYPE_META: + prefix = "meta-tmp-"; + break; + default: + g_assert_not_reached (); + break; + } + + if (!ot_gfile_create_tmp (priv->tmp_dir, prefix, NULL, 0666, + &tmp_f, &stream, cancellable, error)) + goto out; + + if (!ot_gio_splice_and_checksum (stream, input, &ret_checksum, cancellable, error)) + goto out; + + if (!g_output_stream_close ((GOutputStream*)stream, NULL, error)) + goto out; + + ret_tmpname = g_file_get_child (priv->tmp_dir, g_checksum_get_string (ret_checksum)); + if (rename (ot_gfile_get_path_cached (tmp_f), ot_gfile_get_path_cached (ret_tmpname)) < 0) + { + ot_util_set_error_from_errno (error, errno); + goto out; + } + /* Clear it here, since we know the file is now gone */ + g_clear_object (&tmp_f); + + ret = TRUE; + if (out_tmpname) + { + *out_tmpname = ret_tmpname; + ret_tmpname = NULL; + } + if (out_checksum) + { + *out_checksum = ret_checksum; + ret_checksum = NULL; + } + out: + if (tmp_f) + (void) g_file_delete (tmp_f, NULL, NULL); + g_clear_object (&tmp_f); + g_clear_object (&stream); + g_clear_object (&ret_tmpname); + ot_clear_checksum (&ret_checksum); + return ret; +} + static gboolean write_gvariant_to_tmp (OstreeRepo *self, OstreeSerializedVariantType type, @@ -570,58 +640,34 @@ write_gvariant_to_tmp (OstreeRepo *self, GChecksum **out_checksum, GError **error) { - OstreeRepoPrivate *priv = GET_PRIVATE (self); - GVariant *serialized = NULL; gboolean ret = FALSE; - gsize bytes_written; - GFile *tmp_f = NULL; - GOutputStream *stream = NULL; - GChecksum *checksum = NULL; + GVariant *serialized = NULL; + GInputStream *mem = NULL; + GChecksum *ret_checksum = NULL; GFile *ret_tmpname = NULL; serialized = ostree_wrap_metadata_variant (type, variant); - - if (!ot_gfile_create_tmp (priv->tmp_dir, "variant-tmp-", NULL, 0666, - &tmp_f, &stream, NULL, error)) + mem = g_memory_input_stream_new_from_data (g_variant_get_data (serialized), + g_variant_get_size (serialized), + NULL); + if (!stage_and_checksum (self, OSTREE_OBJECT_TYPE_META, + mem, &ret_tmpname, &ret_checksum, NULL, error)) goto out; - - checksum = g_checksum_new (G_CHECKSUM_SHA256); - - if (!g_output_stream_write_all ((GOutputStream*)stream, - g_variant_get_data (serialized), - g_variant_get_size (serialized), - &bytes_written, - NULL, - error)) - goto out; - - g_checksum_update (checksum, (guint8*)g_variant_get_data (serialized), g_variant_get_size (serialized)); - - if (!g_output_stream_close ((GOutputStream*)stream, - NULL, error)) - goto out; - - ret_tmpname = g_file_get_child (priv->tmp_dir, g_checksum_get_string (checksum)); - if (rename (ot_gfile_get_path_cached (tmp_f), ot_gfile_get_path_cached (ret_tmpname)) < 0) - { - ot_util_set_error_from_errno (error, errno); - goto out; - } - g_clear_object (&tmp_f); - + ret = TRUE; - *out_tmpname = ret_tmpname; - ret_tmpname = NULL; - *out_checksum = checksum; - checksum = NULL; + if (out_tmpname) + { + *out_tmpname = ret_tmpname; + ret_tmpname = NULL; + } + if (out_checksum) + { + *out_checksum = ret_checksum; + ret_checksum = NULL; + } out: - if (tmp_f) - (void) g_file_delete (tmp_f, NULL, NULL); - g_clear_object (&tmp_f); - g_clear_object (&stream); g_clear_object (&ret_tmpname); - ot_clear_checksum (&checksum); - ot_clear_gvariant (&serialized); + ot_clear_checksum (&ret_checksum); return ret; } diff --git a/src/libotutil/ot-gio-utils.c b/src/libotutil/ot-gio-utils.c index 0c4e0010..945bd414 100644 --- a/src/libotutil/ot-gio-utils.c +++ b/src/libotutil/ot-gio-utils.c @@ -138,6 +138,52 @@ ot_gfile_get_basename_cached (GFile *file) return name; } +gboolean +ot_gio_splice_and_checksum (GOutputStream *out, + GInputStream *in, + GChecksum **out_checksum, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + GChecksum *ret_checksum = NULL; + + if (out_checksum) + ret_checksum = g_checksum_new (G_CHECKSUM_SHA256); + + if (ret_checksum != NULL) + { + gsize bytes_read, bytes_written; + char buf[4096]; + do + { + if (!g_input_stream_read_all (in, buf, sizeof(buf), &bytes_read, cancellable, error)) + goto out; + if (ret_checksum) + g_checksum_update (ret_checksum, (guint8*)buf, bytes_read); + if (!g_output_stream_write_all (out, buf, bytes_read, &bytes_written, cancellable, error)) + goto out; + } + while (bytes_read > 0); + } + else + { + if (g_output_stream_splice (out, in, 0, cancellable, error) < 0) + goto out; + } + + ret = TRUE; + if (out_checksum) + { + *out_checksum = ret_checksum; + ret_checksum = NULL; + } + out: + ot_clear_checksum (&ret_checksum); + return ret; +} + + gboolean ot_gfile_create_tmp (GFile *dir, const char *prefix, diff --git a/src/libotutil/ot-gio-utils.h b/src/libotutil/ot-gio-utils.h index 26da9adf..ffdb0281 100644 --- a/src/libotutil/ot-gio-utils.h +++ b/src/libotutil/ot-gio-utils.h @@ -43,6 +43,13 @@ gboolean ot_gfile_load_contents_utf8 (GFile *file, GCancellable *cancellable, GError **error); +gboolean ot_gio_splice_and_checksum (GOutputStream *out, + GInputStream *in, + GChecksum **out_checksum, + GCancellable *cancellable, + GError **error); + + gboolean ot_gfile_create_tmp (GFile *dir, const char *prefix, const char *suffix,