gboolean _ostree_static_delta_part_open (GInputStream *part_in, GBytes *inline_part_bytes, OstreeStaticDeltaOpenFlags flags, const char *expected_checksum, GVariant **out_part, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; const gboolean trusted = (flags & OSTREE_STATIC_DELTA_OPEN_FLAGS_VARIANT_TRUSTED) > 0; const gboolean skip_checksum = (flags & OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM) > 0; gsize bytes_read; guint8 comptype; g_autoptr(GChecksum) checksum = NULL; g_autoptr(GInputStream) checksum_in = NULL; g_autoptr(GVariant) ret_part = NULL; GInputStream *source_in; /* We either take a fd or a GBytes reference */ g_return_val_if_fail (G_IS_FILE_DESCRIPTOR_BASED (part_in) || inline_part_bytes != NULL, FALSE); g_return_val_if_fail (skip_checksum || expected_checksum != NULL, FALSE); if (!skip_checksum) { checksum = g_checksum_new (G_CHECKSUM_SHA256); checksum_in = (GInputStream*)ostree_checksum_input_stream_new (part_in, checksum); source_in = checksum_in; } else { source_in = part_in; } { guint8 buf[1]; /* First byte is compression type */ if (!g_input_stream_read_all (source_in, buf, sizeof(buf), &bytes_read, cancellable, error)) { g_prefix_error (error, "Reading initial compression flag byte: "); goto out; } comptype = buf[0]; } switch (comptype) { case 0: if (!inline_part_bytes) { int part_fd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*)part_in); /* No compression, no checksums - a fast path */ if (!ot_util_variant_map_fd (part_fd, 1, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0), trusted, &ret_part, error)) goto out; } else { g_autoptr(GBytes) content_bytes = g_bytes_new_from_bytes (inline_part_bytes, 1, g_bytes_get_size (inline_part_bytes) - 1); ret_part = g_variant_new_from_bytes (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0), content_bytes, trusted); g_variant_ref_sink (ret_part); } if (!skip_checksum) g_checksum_update (checksum, g_variant_get_data (ret_part), g_variant_get_size (ret_part)); break; case 'x': { g_autofree char *tmppath = g_strdup ("/var/tmp/ostree-delta-XXXXXX"); g_autoptr(GConverter) decomp = (GConverter*) _ostree_lzma_decompressor_new (); g_autoptr(GInputStream) convin = g_converter_input_stream_new (source_in, decomp); g_autoptr(GOutputStream) unpacked_out = NULL; glnx_fd_close int unpacked_fd = -1; gssize n_bytes_written; unpacked_fd = g_mkstemp_full (tmppath, O_RDWR | O_CLOEXEC, 0640); if (unpacked_fd < 0) { glnx_set_error_from_errno (error); goto out; } /* Now make it autocleanup on process exit - in the future, we * should consider caching unpacked deltas as well. */ if (unlink (tmppath) < 0) { glnx_set_error_from_errno (error); goto out; } unpacked_out = g_unix_output_stream_new (unpacked_fd, FALSE); n_bytes_written = g_output_stream_splice (unpacked_out, convin, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, cancellable, error); if (n_bytes_written < 0) goto out; if (!ot_util_variant_map_fd (unpacked_fd, 0, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0), trusted, &ret_part, error)) goto out; } break; default: g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid compression type '%u'", comptype); goto out; } if (checksum) { const char *actual_checksum = g_checksum_get_string (checksum); g_assert (expected_checksum != NULL); if (strcmp (actual_checksum, expected_checksum) != 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Checksum mismatch in static delta part; expected=%s actual=%s", expected_checksum, actual_checksum); goto out; } } ret = TRUE; *out_part = g_steal_pointer (&ret_part); out: return ret; }
gboolean _ostree_static_delta_part_open (GInputStream *part_in, GBytes *inline_part_bytes, OstreeStaticDeltaOpenFlags flags, const char *expected_checksum, GVariant **out_part, GCancellable *cancellable, GError **error) { const gboolean trusted = (flags & OSTREE_STATIC_DELTA_OPEN_FLAGS_VARIANT_TRUSTED) > 0; const gboolean skip_checksum = (flags & OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM) > 0; gsize bytes_read; guint8 comptype; g_autoptr(GChecksum) checksum = NULL; g_autoptr(GInputStream) checksum_in = NULL; GInputStream *source_in; /* We either take a fd or a GBytes reference */ g_return_val_if_fail (G_IS_FILE_DESCRIPTOR_BASED (part_in) || inline_part_bytes != NULL, FALSE); g_return_val_if_fail (skip_checksum || expected_checksum != NULL, FALSE); if (!skip_checksum) { checksum = g_checksum_new (G_CHECKSUM_SHA256); checksum_in = (GInputStream*)ostree_checksum_input_stream_new (part_in, checksum); source_in = checksum_in; } else { source_in = part_in; } { guint8 buf[1]; /* First byte is compression type */ if (!g_input_stream_read_all (source_in, buf, sizeof(buf), &bytes_read, cancellable, error)) return glnx_prefix_error (error, "Reading initial compression flag byte"); comptype = buf[0]; } g_autoptr(GVariant) ret_part = NULL; switch (comptype) { case 0: if (!inline_part_bytes) { int part_fd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*)part_in); /* No compression, no checksums - a fast path */ if (!ot_util_variant_map_fd (part_fd, 1, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0), trusted, &ret_part, error)) return FALSE; } else { g_autoptr(GBytes) content_bytes = g_bytes_new_from_bytes (inline_part_bytes, 1, g_bytes_get_size (inline_part_bytes) - 1); ret_part = g_variant_new_from_bytes (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0), content_bytes, trusted); g_variant_ref_sink (ret_part); } if (!skip_checksum) g_checksum_update (checksum, g_variant_get_data (ret_part), g_variant_get_size (ret_part)); break; case 'x': { g_autoptr(GConverter) decomp = (GConverter*) _ostree_lzma_decompressor_new (); g_autoptr(GInputStream) convin = g_converter_input_stream_new (source_in, decomp); g_autoptr(GBytes) buf = ot_map_anonymous_tmpfile_from_content (convin, cancellable, error); if (!buf) return FALSE; ret_part = g_variant_new_from_bytes (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0), buf, FALSE); } break; default: return glnx_throw (error, "Invalid compression type '%u'", comptype); } if (checksum) { const char *actual_checksum = g_checksum_get_string (checksum); g_assert (expected_checksum != NULL); if (strcmp (actual_checksum, expected_checksum) != 0) return glnx_throw (error, "Checksum mismatch in static delta part; expected=%s actual=%s", expected_checksum, actual_checksum); } *out_part = g_steal_pointer (&ret_part); return TRUE; }