diff options
author | Colin Walters <walters@verbum.org> | 2017-12-08 13:55:39 -0500 |
---|---|---|
committer | Atomic Bot <atomic-devel@projectatomic.io> | 2017-12-12 14:17:20 +0000 |
commit | f81e3c6f03f6636f1e4e4d1f13a79983820a9d29 (patch) | |
tree | 453c85d0e8312e381df78939710cfc6a0aeeeeed | |
parent | 6d8aaf629c904d6b0e1c2a06641829590eeebf45 (diff) | |
download | ostree-f81e3c6f03f6636f1e4e4d1f13a79983820a9d29.tar.gz |
lib/commit: Use more direct path for regfile commits
In the non-`CONSUME` path for regfiles (which happens currently for
`bare-user`), we go to a lot of contortions to make an "object stream",
only to immediately parse it again.
Fixing this will also enable the `G_IS_FILE_DESCRIPTOR_BASED()` fast path in
commit, since the input stream will actually reference the file descriptor and
not be an `_OstreeChainInputStream`.
There's a slight concern here in that we're no longer checksumming *literally*
the object stream passed in for the stream case, but I mention in the comment,
the data should be the same, and if it's not somehow we're not adding risk,
since the checksum is still covering the data we actually care about.
Prep for further changes to break up the `write_content_object()` path into
separate paths for archive, as well as regfile vs symlink in non-archive.
Closes: #1371
Approved by: jlebon
-rw-r--r-- | src/libostree/ostree-repo-commit.c | 63 | ||||
-rw-r--r-- | src/libotutil/ot-checksum-instream.c | 12 | ||||
-rw-r--r-- | src/libotutil/ot-checksum-instream.h | 2 |
3 files changed, 52 insertions, 25 deletions
diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index ca384fb8..50ffeac5 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -597,7 +597,8 @@ static gboolean write_content_object (OstreeRepo *self, const char *expected_checksum, GInputStream *input, - guint64 file_object_length, + GFileInfo *file_info, + GVariant *xattrs, guchar **out_csum, GCancellable *cancellable, GError **error) @@ -610,18 +611,30 @@ write_content_object (OstreeRepo *self, OstreeRepoMode repo_mode = ostree_repo_get_mode (self); + GInputStream *file_input; /* Unowned alias */ + g_autoptr(GInputStream) file_input_owned = NULL; /* We need a temporary for bare-user symlinks */ glnx_unref_object OtChecksumInstream *checksum_input = NULL; if (out_csum) - checksum_input = ot_checksum_instream_new (input, G_CHECKSUM_SHA256); - - g_autoptr(GInputStream) file_input = NULL; - g_autoptr(GVariant) xattrs = NULL; - g_autoptr(GFileInfo) file_info = NULL; - if (!ostree_content_stream_parse (FALSE, checksum_input ? (GInputStream*)checksum_input : input, - file_object_length, FALSE, - &file_input, &file_info, &xattrs, - cancellable, error)) - return FALSE; + { + /* Previously we checksummed the input verbatim; now + * ostree_repo_write_content() parses without checksumming, then we + * re-synthesize a header here. The data should be identical; if somehow + * it's not that's not a serious problem because we're still computing a + * checksum over the data we actually use. + */ + g_autoptr(GBytes) header = _ostree_file_header_new (file_info, xattrs); + size_t len; + const guint8 *buf = g_bytes_get_data (header, &len); + /* Give a null input if there's no content */ + g_autoptr(GInputStream) null_input = NULL; + if (!input) + null_input = input = g_memory_input_stream_new_from_data ("", 0, NULL); + checksum_input = ot_checksum_instream_new_with_start (input, G_CHECKSUM_SHA256, + buf, len); + file_input = (GInputStream*)checksum_input; + } + else + file_input = input; gboolean phys_object_is_symlink = FALSE; const GFileType object_file_type = g_file_info_get_file_type (file_info); @@ -645,10 +658,8 @@ write_content_object (OstreeRepo *self, const char *target_str = g_file_info_get_symlink_target (file_info); g_autoptr(GBytes) target = g_bytes_new (target_str, strlen (target_str) + 1); - if (file_input != NULL) - g_object_unref (file_input); /* Include the terminating zero so we can e.g. mmap this file */ - file_input = g_memory_input_stream_new_from_bytes (target); + file_input = file_input_owned = g_memory_input_stream_new_from_bytes (target); size = g_bytes_get_size (target); } else if (!phys_object_is_symlink) @@ -851,7 +862,7 @@ write_content_object (OstreeRepo *self, /* Update statistics */ g_mutex_lock (&self->txn_lock); self->txn.stats.content_objects_written++; - self->txn.stats.content_bytes_written += file_object_length; + self->txn.stats.content_bytes_written += g_file_info_get_size (file_info); self->txn.stats.content_objects_total++; g_mutex_unlock (&self->txn_lock); @@ -2246,8 +2257,17 @@ ostree_repo_write_content (OstreeRepo *self, } } + /* Parse the stream */ + g_autoptr(GInputStream) file_input = NULL; + g_autoptr(GVariant) xattrs = NULL; + g_autoptr(GFileInfo) file_info = NULL; + if (!ostree_content_stream_parse (FALSE, object_input, length, FALSE, + &file_input, &file_info, &xattrs, + cancellable, error)) + return FALSE; + return write_content_object (self, expected_checksum, - object_input, length, out_csum, + file_input, file_info, xattrs, out_csum, cancellable, error); } @@ -3152,16 +3172,9 @@ write_content_to_mtree_internal (OstreeRepo *self, } } - g_autoptr(GInputStream) file_object_input = NULL; - guint64 file_obj_length; - if (!ostree_raw_file_to_content_stream (file_input, - modified_info, xattrs, - &file_object_input, &file_obj_length, - cancellable, error)) - return FALSE; g_autofree guchar *child_file_csum = NULL; - if (!ostree_repo_write_content (self, NULL, file_object_input, file_obj_length, - &child_file_csum, cancellable, error)) + if (!write_content_object (self, NULL, file_input, modified_info, xattrs, + &child_file_csum, cancellable, error)) return FALSE; char tmp_checksum[OSTREE_SHA256_STRING_LEN+1]; diff --git a/src/libotutil/ot-checksum-instream.c b/src/libotutil/ot-checksum-instream.c index 342b14b4..a536d7bb 100644 --- a/src/libotutil/ot-checksum-instream.c +++ b/src/libotutil/ot-checksum-instream.c @@ -66,6 +66,16 @@ OtChecksumInstream * ot_checksum_instream_new (GInputStream *base, GChecksumType checksum_type) { + return ot_checksum_instream_new_with_start (base, checksum_type, NULL, 0); +} + +/* Initialize a checksum stream with starting state from data */ +OtChecksumInstream * +ot_checksum_instream_new_with_start (GInputStream *base, + GChecksumType checksum_type, + const guint8 *buf, + size_t len) +{ OtChecksumInstream *stream; g_return_val_if_fail (G_IS_INPUT_STREAM (base), NULL); @@ -77,6 +87,8 @@ ot_checksum_instream_new (GInputStream *base, /* For now */ g_assert (checksum_type == G_CHECKSUM_SHA256); ot_checksum_init (&stream->priv->checksum); + if (buf) + ot_checksum_update (&stream->priv->checksum, buf, len); return (OtChecksumInstream*) (stream); } diff --git a/src/libotutil/ot-checksum-instream.h b/src/libotutil/ot-checksum-instream.h index 410047a9..c13c0898 100644 --- a/src/libotutil/ot-checksum-instream.h +++ b/src/libotutil/ot-checksum-instream.h @@ -51,6 +51,8 @@ struct _OtChecksumInstreamClass GType ot_checksum_instream_get_type (void) G_GNUC_CONST; OtChecksumInstream * ot_checksum_instream_new (GInputStream *stream, GChecksumType checksum); +OtChecksumInstream * ot_checksum_instream_new_with_start (GInputStream *stream, GChecksumType checksum, + const guint8 *buf, size_t len); char * ot_checksum_instream_get_string (OtChecksumInstream *stream); |