static gboolean do_content_open_generic (OstreeRepo *repo, StaticDeltaExecutionState *state, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; g_autoptr(GVariant) modev = NULL; guint64 mode_offset; guint64 xattr_offset; guint32 uid, gid, mode; if (!read_varuint64 (state, &mode_offset, error)) goto out; if (!read_varuint64 (state, &xattr_offset, error)) goto out; state->barecommitstate.fd = -1; modev = g_variant_get_child_value (state->mode_dict, mode_offset); g_variant_get (modev, "(uuu)", &uid, &gid, &mode); state->uid = GUINT32_FROM_BE (uid); state->gid = GUINT32_FROM_BE (gid); state->mode = GUINT32_FROM_BE (mode); state->xattrs = g_variant_get_child_value (state->xattr_dict, xattr_offset); ret = TRUE; out: return ret; }
static gboolean dispatch_bspatch (OstreeRepo *repo, StaticDeltaExecutionState *state, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; guint64 offset, length; g_autoptr(GInputStream) in_stream = NULL; g_autoptr(GMappedFile) input_mfile = NULL; g_autofree guchar *buf = NULL; struct bspatch_stream stream; struct bzpatch_opaque_s opaque; gsize bytes_written; if (!read_varuint64 (state, &offset, error)) goto out; if (!read_varuint64 (state, &length, error)) goto out; if (!state->have_obj) { input_mfile = g_mapped_file_new_from_fd (state->read_source_fd, FALSE, error); if (!input_mfile) goto out; buf = g_malloc0 (state->content_size); opaque.state = state; opaque.offset = offset; opaque.length = length; stream.read = bspatch_read; stream.opaque = &opaque; if (bspatch ((const guint8*)g_mapped_file_get_contents (input_mfile), g_mapped_file_get_length (input_mfile), buf, state->content_size, &stream) < 0) goto out; if (!g_output_stream_write_all (state->content_out, buf, state->content_size, &bytes_written, cancellable, error)) goto out; g_assert (bytes_written == state->content_size); } ret = TRUE; out: return ret; }
static gboolean dispatch_set_read_source (OstreeRepo *repo, StaticDeltaExecutionState *state, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; guint64 source_offset; if (state->read_source_fd) { (void) close (state->read_source_fd); state->read_source_fd = -1; } if (!read_varuint64 (state, &source_offset, error)) goto out; if (!validate_ofs (state, source_offset, 32, error)) goto out; g_free (state->read_source_object); state->read_source_object = ostree_checksum_from_bytes (state->payload_data + source_offset); if (!_ostree_repo_read_bare_fd (repo, state->read_source_object, &state->read_source_fd, cancellable, error)) goto out; ret = TRUE; out: if (!ret) g_prefix_error (error, "opcode set-read-source: "); return ret; }
static size_t squash_brieflz_get_uncompressed_size (SquashCodec* codec, size_t compressed_size, const uint8_t compressed[SQUASH_ARRAY_PARAM(compressed_size)]) { uint64_t v; return read_varuint64 (compressed, compressed_size, &v) == 0 ? 0 : v; }
static gboolean dispatch_open (OstreeRepo *repo, StaticDeltaExecutionState *state, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; g_assert (state->output_target == NULL); /* FIXME - lift this restriction */ if (!state->stats_only) { g_assert (repo->mode == OSTREE_REPO_MODE_BARE || repo->mode == OSTREE_REPO_MODE_BARE_USER || repo->mode == OSTREE_REPO_MODE_BARE_USER_ONLY); } if (!open_output_target (state, cancellable, error)) goto out; if (!do_content_open_generic (repo, state, cancellable, error)) goto out; if (!read_varuint64 (state, &state->content_size, error)) goto out; if (state->stats_only) { ret = TRUE; goto out; } if (!_ostree_repo_open_content_bare (repo, state->checksum, state->content_size, &state->barecommitstate, &state->content_out, &state->have_obj, cancellable, error)) goto out; if (!handle_untrusted_content_checksum (repo, state, cancellable, error)) goto out; ret = TRUE; out: if (!ret) g_prefix_error (error, "opcode open: "); return ret; }
static SquashStatus squash_brieflz_decompress_buffer (SquashCodec* codec, size_t* decompressed_size, uint8_t decompressed[SQUASH_ARRAY_PARAM(*decompressed_size)], size_t compressed_size, const uint8_t compressed[SQUASH_ARRAY_PARAM(compressed_size)], SquashOptions* options) { const uint8_t *src = compressed; uint64_t original_size; size_t size; size = read_varuint64 (src, compressed_size, &original_size); if (SQUASH_UNLIKELY(size == 0)) { return squash_error (SQUASH_FAILED); } src += size; compressed_size -= size; if (SQUASH_UNLIKELY(original_size > *decompressed_size)) { return squash_error (SQUASH_BUFFER_FULL); } #if ULONG_MAX < SIZE_MAX if (SQUASH_UNLIKELY(ULONG_MAX < compressed_size) || SQUASH_UNLIKELY(ULONG_MAX < original_size)) return squash_error (SQUASH_RANGE); #endif size = blz_depack_safe (src, (unsigned long) compressed_size, decompressed, (unsigned long) original_size); if (SQUASH_UNLIKELY(size != original_size)) { return squash_error (SQUASH_FAILED); } #if SIZE_MAX < ULONG_MAX if (SQUASH_UNLIKELY(SIZE_MAX < size)) return squash_error (SQUASH_RANGE); #endif *decompressed_size = size; return SQUASH_OK; }
static gboolean dispatch_write (OstreeRepo *repo, StaticDeltaExecutionState *state, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; guint64 content_size; guint64 content_offset; if (!read_varuint64 (state, &content_size, error)) goto out; if (!read_varuint64 (state, &content_offset, error)) goto out; if (state->stats_only) { ret = TRUE; goto out; } if (!state->have_obj) { if (state->read_source_fd != -1) { if (lseek (state->read_source_fd, content_offset, SEEK_SET) == -1) { glnx_set_error_from_errno (error); goto out; } while (content_size > 0) { char buf[4096]; gssize bytes_read; do bytes_read = read (state->read_source_fd, buf, MIN(sizeof(buf), content_size)); while (G_UNLIKELY (bytes_read == -1 && errno == EINTR)); if (bytes_read == -1) { glnx_set_error_from_errno (error); goto out; } if (G_UNLIKELY (bytes_read == 0)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unexpected EOF reading object %s", state->read_source_object); goto out; } if (!content_out_write (repo, state, (guint8*)buf, bytes_read, cancellable, error)) goto out; content_size -= bytes_read; } } else { if (!validate_ofs (state, content_offset, content_size, error)) goto out; if (!content_out_write (repo, state, state->payload_data + content_offset, content_size, cancellable, error)) goto out; } } ret = TRUE; out: if (!ret) g_prefix_error (error, "opcode open-splice-and-close: "); return ret; }
static gboolean dispatch_open_splice_and_close (OstreeRepo *repo, StaticDeltaExecutionState *state, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; if (!open_output_target (state, cancellable, error)) goto out; if (OSTREE_OBJECT_TYPE_IS_META (state->output_objtype)) { g_autoptr(GVariant) metadata = NULL; guint64 offset; guint64 length; if (!read_varuint64 (state, &length, error)) goto out; if (!read_varuint64 (state, &offset, error)) goto out; if (!validate_ofs (state, offset, length, error)) goto out; if (state->stats_only) { ret = TRUE; goto out; } metadata = g_variant_new_from_data (ostree_metadata_variant_type (state->output_objtype), state->payload_data + offset, length, TRUE, NULL, NULL); { g_autofree guchar *actual_csum = NULL; if (!ostree_repo_write_metadata (state->repo, state->output_objtype, state->checksum, metadata, &actual_csum, cancellable, error)) goto out; } } else { guint64 content_offset; guint64 objlen; g_autoptr(GInputStream) object_input = NULL; g_autoptr(GInputStream) memin = NULL; if (!do_content_open_generic (repo, state, cancellable, error)) goto out; if (!read_varuint64 (state, &state->content_size, error)) goto out; if (!read_varuint64 (state, &content_offset, error)) goto out; if (!validate_ofs (state, content_offset, state->content_size, error)) goto out; if (state->stats_only) { ret = TRUE; goto out; } /* Fast path for regular files to bare repositories */ if (S_ISREG (state->mode) && (repo->mode == OSTREE_REPO_MODE_BARE || repo->mode == OSTREE_REPO_MODE_BARE_USER)) { if (!_ostree_repo_open_content_bare (repo, state->checksum, state->content_size, &state->barecommitstate, &state->content_out, &state->have_obj, cancellable, error)) goto out; if (!state->have_obj) { if (!handle_untrusted_content_checksum (repo, state, cancellable, error)) goto out; if (!content_out_write (repo, state, state->payload_data + content_offset, state->content_size, cancellable, error)) goto out; } } else { /* Slower path, for symlinks and unpacking deltas into archive-z2 */ g_autoptr(GFileInfo) finfo = NULL; finfo = _ostree_header_gfile_info_new (state->mode, state->uid, state->gid); if (S_ISLNK (state->mode)) { g_autofree char *nulterminated_target = g_strndup ((char*)state->payload_data + content_offset, state->content_size); g_file_info_set_symlink_target (finfo, nulterminated_target); } else { g_assert (S_ISREG (state->mode)); g_file_info_set_size (finfo, state->content_size); memin = g_memory_input_stream_new_from_data (state->payload_data + content_offset, state->content_size, NULL); } if (!ostree_raw_file_to_content_stream (memin, finfo, state->xattrs, &object_input, &objlen, cancellable, error)) goto out; { g_autofree guchar *actual_csum = NULL; if (!ostree_repo_write_content (state->repo, state->checksum, object_input, objlen, &actual_csum, cancellable, error)) goto out; } } } if (!dispatch_close (repo, state, cancellable, error)) goto out; ret = TRUE; out: if (state->stats_only) (void) dispatch_close (repo, state, cancellable, NULL); if (!ret) g_prefix_error (error, "opcode open-splice-and-close: "); return ret; }