static gboolean cockpit_ssh_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) { CockpitSshSource *cs = (CockpitSshSource *)source; CockpitSshTransport *self = cs->transport; GIOCondition cond = cs->pfd.revents; const gchar *msg; gint rc; g_return_val_if_fail ((cond & G_IO_NVAL) == 0, FALSE); g_assert (self->data != NULL); if (self->drain_buffer) { self->drain_buffer = 0; drain_buffer (self); } if (cond & (G_IO_HUP | G_IO_ERR)) { if (self->sent_close || self->sent_eof) { self->received_eof = TRUE; self->received_close = TRUE; } } /* * HACK: Yes this is anohter poll() call. The async support in * libssh is quite hacky right now. * * https://red.libssh.org/issues/155 */ rc = ssh_event_dopoll (self->event, 0); switch (rc) { case SSH_OK: case SSH_AGAIN: break; case SSH_ERROR: msg = ssh_get_error (self->data->session); /* * HACK: There doesn't seem to be a way to get at the original socket errno * here. So we have to screen scrape. * * https://red.libssh.org/issues/158 */ if (msg && (strstr (msg, "disconnected") || strstr (msg, "SSH_MSG_DISCONNECT") || strstr (msg, "Socket error: Success") || strstr (msg, "Socket error: Connection reset by peer"))) { g_debug ("%s: failed to process channel: %s", self->logname, msg); close_immediately (self, "terminated"); } else { g_message ("%s: failed to process channel: %s", self->logname, msg); close_immediately (self, "internal-error"); } return TRUE; default: g_critical ("%s: ssh_event_dopoll() returned %d", self->logname, rc); return FALSE; } if (cond & G_IO_ERR) { g_message ("%s: error reading from ssh", self->logname); close_immediately (self, "disconnected"); return TRUE; } if (self->drain_buffer) { self->drain_buffer = 0; drain_buffer (self); } if (cond & G_IO_OUT) { if (!dispatch_queue (self) && self->closing && !self->sent_eof) dispatch_eof (self); if (self->received_eof && self->sent_eof && !self->sent_close) dispatch_close (self); if (self->received_close && !self->sent_close) dispatch_close (self); } return TRUE; }
gboolean _ostree_static_delta_part_execute (OstreeRepo *repo, GVariant *objects, GVariant *part, gboolean stats_only, OstreeDeltaExecuteStats *stats, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; guint8 *checksums_data; g_autoptr(GVariant) mode_dict = NULL; g_autoptr(GVariant) xattr_dict = NULL; g_autoptr(GVariant) payload = NULL; g_autoptr(GVariant) ops = NULL; StaticDeltaExecutionState statedata = { 0, }; StaticDeltaExecutionState *state = &statedata; guint n_executed = 0; static_delta_execution_state_init (&statedata); state->repo = repo; state->async_error = error; state->stats_only = stats_only; if (!_ostree_static_delta_parse_checksum_array (objects, &checksums_data, &state->n_checksums, error)) goto out; /* Skip processing for empty delta part */ if (state->n_checksums == 0) { ret = TRUE; goto out; } state->checksums = checksums_data; g_variant_get (part, "(@a(uuu)@aa(ayay)@ay@ay)", &mode_dict, &xattr_dict, &payload, &ops); state->mode_dict = mode_dict; state->xattr_dict = xattr_dict; state->payload_data = g_variant_get_data (payload); state->payload_size = g_variant_get_size (payload); state->oplen = g_variant_n_children (ops); state->opdata = g_variant_get_data (ops); while (state->oplen > 0) { guint8 opcode; opcode = state->opdata[0]; state->oplen--; state->opdata++; switch (opcode) { case OSTREE_STATIC_DELTA_OP_OPEN_SPLICE_AND_CLOSE: if (!dispatch_open_splice_and_close (repo, state, cancellable, error)) goto out; break; case OSTREE_STATIC_DELTA_OP_OPEN: if (!dispatch_open (repo, state, cancellable, error)) goto out; break; case OSTREE_STATIC_DELTA_OP_WRITE: if (!dispatch_write (repo, state, cancellable, error)) goto out; break; case OSTREE_STATIC_DELTA_OP_SET_READ_SOURCE: if (!dispatch_set_read_source (repo, state, cancellable, error)) goto out; break; case OSTREE_STATIC_DELTA_OP_UNSET_READ_SOURCE: if (!dispatch_unset_read_source (repo, state, cancellable, error)) goto out; break; case OSTREE_STATIC_DELTA_OP_CLOSE: if (!dispatch_close (repo, state, cancellable, error)) goto out; break; case OSTREE_STATIC_DELTA_OP_BSPATCH: if (!dispatch_bspatch (repo, state, cancellable, error)) goto out; break; default: g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Unknown opcode %u at offset %u", opcode, n_executed); goto out; } n_executed++; if (stats) stats->n_ops_executed[delta_opcode_index(opcode)]++; } if (state->caught_error) goto out; ret = TRUE; out: g_clear_pointer (&state->content_checksum, g_checksum_free); 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; }
gboolean _ostree_static_delta_part_execute_raw (OstreeRepo *repo, GVariant *objects, GVariant *part, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; guint8 *checksums_data; gs_unref_variant GVariant *checksums = NULL; gs_unref_variant GVariant *mode_dict = NULL; gs_unref_variant GVariant *xattr_dict = NULL; gs_unref_variant GVariant *payload = NULL; gs_unref_variant GVariant *ops = NULL; StaticDeltaExecutionState statedata = { 0, }; StaticDeltaExecutionState *state = &statedata; guint n_executed = 0; state->repo = repo; state->async_error = error; if (!_ostree_static_delta_parse_checksum_array (objects, &checksums_data, &state->n_checksums, error)) goto out; state->checksums = checksums_data; g_assert (state->n_checksums > 0); g_variant_get (part, "(@a(uuu)@aa(ayay)@ay@ay)", &mode_dict, &xattr_dict, &payload, &ops); state->mode_dict = mode_dict; state->xattr_dict = xattr_dict; state->payload_data = g_variant_get_data (payload); state->payload_size = g_variant_get_size (payload); state->oplen = g_variant_n_children (ops); state->opdata = g_variant_get_data (ops); while (state->oplen > 0) { guint8 opcode; opcode = state->opdata[0]; state->oplen--; state->opdata++; switch (opcode) { case OSTREE_STATIC_DELTA_OP_OPEN_SPLICE_AND_CLOSE: if (!dispatch_open_splice_and_close (repo, state, cancellable, error)) goto out; break; case OSTREE_STATIC_DELTA_OP_OPEN: if (!dispatch_open (repo, state, cancellable, error)) goto out; break; case OSTREE_STATIC_DELTA_OP_WRITE: if (!dispatch_write (repo, state, cancellable, error)) goto out; break; case OSTREE_STATIC_DELTA_OP_SET_READ_SOURCE: if (!dispatch_set_read_source (repo, state, cancellable, error)) goto out; break; case OSTREE_STATIC_DELTA_OP_UNSET_READ_SOURCE: if (!dispatch_unset_read_source (repo, state, cancellable, error)) goto out; break; case OSTREE_STATIC_DELTA_OP_CLOSE: if (!dispatch_close (repo, state, cancellable, error)) goto out; break; case OSTREE_STATIC_DELTA_OP_BSPATCH: if (!dispatch_bspatch (repo, state, cancellable, error)) goto out; break; default: g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Unknown opcode %u at offset %u", opcode, n_executed); goto out; } n_executed++; } if (state->caught_error) goto out; ret = TRUE; out: return ret; }