static gboolean meta_monitor_manager_handle_get_crtc_gamma (MetaDBusDisplayConfig *skeleton, GDBusMethodInvocation *invocation, guint serial, guint crtc_id) { MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton); MetaMonitorManagerClass *klass; MetaCRTC *crtc; gsize size; unsigned short *red; unsigned short *green; unsigned short *blue; GBytes *red_bytes, *green_bytes, *blue_bytes; GVariant *red_v, *green_v, *blue_v; if (serial != manager->serial) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED, "The requested configuration is based on stale information"); return TRUE; } if (crtc_id >= manager->n_crtcs) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid crtc id"); return TRUE; } crtc = &manager->crtcs[crtc_id]; klass = META_MONITOR_MANAGER_GET_CLASS (manager); if (klass->get_crtc_gamma) klass->get_crtc_gamma (manager, crtc, &size, &red, &green, &blue); else { size = 0; red = green = blue = NULL; } red_bytes = g_bytes_new_take (red, size * sizeof (unsigned short)); green_bytes = g_bytes_new_take (green, size * sizeof (unsigned short)); blue_bytes = g_bytes_new_take (blue, size * sizeof (unsigned short)); red_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), red_bytes, TRUE); green_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), green_bytes, TRUE); blue_v = g_variant_new_from_bytes (G_VARIANT_TYPE ("aq"), blue_bytes, TRUE); meta_dbus_display_config_complete_get_crtc_gamma (skeleton, invocation, red_v, green_v, blue_v); g_bytes_unref (red_bytes); g_bytes_unref (green_bytes); g_bytes_unref (blue_bytes); return TRUE; }
gboolean _ostree_static_delta_part_execute (OstreeRepo *repo, GVariant *header, GBytes *part_bytes, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; gsize partlen; const guint8*partdata; gs_unref_bytes GBytes *part_payload_bytes = NULL; gs_unref_bytes GBytes *payload_data = NULL; gs_unref_variant GVariant *payload = NULL; guint8 comptype; partdata = g_bytes_get_data (part_bytes, &partlen); if (partlen < 1) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Corrupted 0 length delta part"); goto out; } /* First byte is compression type */ comptype = partdata[0]; /* Then the rest may be compressed or uncompressed */ part_payload_bytes = g_bytes_new_from_bytes (part_bytes, 1, partlen - 1); switch (comptype) { case 0: /* No compression */ payload_data = g_bytes_ref (part_payload_bytes); break; case 'x': { gs_unref_object GConverter *decomp = (GConverter*) _ostree_lzma_decompressor_new (); if (!decompress_all (decomp, part_payload_bytes, &payload_data, cancellable, error)) goto out; } break; default: g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid compression type '%u'", comptype); goto out; } payload = g_variant_new_from_bytes (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0), payload_data, FALSE); if (!_ostree_static_delta_part_execute_raw (repo, header, payload, cancellable, error)) goto out; ret = TRUE; out: return ret; }
GVariant * ot_variant_new_from_bytes (const GVariantType *type, GBytes *bytes, gboolean trusted) { #if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_36 return g_variant_new_from_bytes (type, bytes, trusted); #else gsize size; gconstpointer data = g_bytes_get_data (bytes, &size); g_bytes_ref (bytes); return g_variant_new_from_data (type, data, size, trusted, (GDestroyNotify)g_bytes_unref, bytes); #endif }
static gboolean commit_checksum_from_any_summary (OstreeRepo *repo, const gchar *remote_name, const gchar *ref, const gchar *summary_url, GCancellable *cancellable, gchar **out_checksum, EosExtensions **out_extensions, GError **error) { g_autoptr(GBytes) contents = NULL; g_autoptr(GBytes) signature = NULL; g_autoptr(OstreeGpgVerifyResult) gpg_result = NULL; g_autoptr(GVariant) summary = NULL; g_autofree gchar *checksum = NULL; g_autoptr(EosExtensions) extensions = NULL; if (!must_download_file_and_signature (summary_url, &contents, &signature, error)) return FALSE; gpg_result = ostree_repo_verify_summary (repo, remote_name, contents, signature, cancellable, error); if (!ostree_gpg_verify_result_require_valid_signature (gpg_result, error)) return FALSE; summary = g_variant_ref_sink (g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, contents, FALSE)); checksum = get_commit_checksum_from_summary (summary, ref, error); if (checksum == NULL) return FALSE; extensions = eos_extensions_new_empty (); extensions->summary = g_steal_pointer (&contents); extensions->summary_sig = g_steal_pointer (&signature); *out_checksum = g_steal_pointer (&checksum); *out_extensions = g_steal_pointer (&extensions); return TRUE; }
static GVariant * gdk_pixbuf_serialize (GIcon *icon) { GError *error = NULL; GVariant *result; GBytes *bytes; bytes = gdk_pixbuf_make_bytes (GDK_PIXBUF (icon), &error); if (!bytes) { g_critical ("Unable to serialise GdkPixbuf to png (via g_icon_serialize()): %s", error->message); g_error_free (error); return NULL; } result = g_variant_new_from_bytes (G_VARIANT_TYPE_BYTESTRING, bytes, TRUE); g_bytes_unref (bytes); return g_variant_new ("(sv)", "bytes", result); }
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; }
static gboolean meta_monitor_manager_handle_get_resources (MetaDBusDisplayConfig *skeleton, GDBusMethodInvocation *invocation) { MetaMonitorManager *manager = META_MONITOR_MANAGER (skeleton); MetaMonitorManagerClass *manager_class = META_MONITOR_MANAGER_GET_CLASS (skeleton); GVariantBuilder crtc_builder, output_builder, mode_builder; unsigned int i, j; g_variant_builder_init (&crtc_builder, G_VARIANT_TYPE ("a(uxiiiiiuaua{sv})")); g_variant_builder_init (&output_builder, G_VARIANT_TYPE ("a(uxiausauaua{sv})")); g_variant_builder_init (&mode_builder, G_VARIANT_TYPE ("a(uxuud)")); for (i = 0; i < manager->n_crtcs; i++) { MetaCRTC *crtc = &manager->crtcs[i]; GVariantBuilder transforms; g_variant_builder_init (&transforms, G_VARIANT_TYPE ("au")); for (j = 0; j <= WL_OUTPUT_TRANSFORM_FLIPPED_270; j++) if (crtc->all_transforms & (1 << j)) g_variant_builder_add (&transforms, "u", j); g_variant_builder_add (&crtc_builder, "(uxiiiiiuaua{sv})", i, /* ID */ (gint64)crtc->crtc_id, (int)crtc->rect.x, (int)crtc->rect.y, (int)crtc->rect.width, (int)crtc->rect.height, (int)(crtc->current_mode ? crtc->current_mode - manager->modes : -1), (guint32)crtc->transform, &transforms, NULL /* properties */); } for (i = 0; i < manager->n_outputs; i++) { MetaOutput *output = &manager->outputs[i]; GVariantBuilder crtcs, modes, clones, properties; GBytes *edid; char *edid_file; g_variant_builder_init (&crtcs, G_VARIANT_TYPE ("au")); for (j = 0; j < output->n_possible_crtcs; j++) g_variant_builder_add (&crtcs, "u", (unsigned)(output->possible_crtcs[j] - manager->crtcs)); g_variant_builder_init (&modes, G_VARIANT_TYPE ("au")); for (j = 0; j < output->n_modes; j++) g_variant_builder_add (&modes, "u", (unsigned)(output->modes[j] - manager->modes)); g_variant_builder_init (&clones, G_VARIANT_TYPE ("au")); for (j = 0; j < output->n_possible_clones; j++) g_variant_builder_add (&clones, "u", (unsigned)(output->possible_clones[j] - manager->outputs)); g_variant_builder_init (&properties, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add (&properties, "{sv}", "vendor", g_variant_new_string (output->vendor)); g_variant_builder_add (&properties, "{sv}", "product", g_variant_new_string (output->product)); g_variant_builder_add (&properties, "{sv}", "serial", g_variant_new_string (output->serial)); g_variant_builder_add (&properties, "{sv}", "width-mm", g_variant_new_int32 (output->width_mm)); g_variant_builder_add (&properties, "{sv}", "height-mm", g_variant_new_int32 (output->height_mm)); g_variant_builder_add (&properties, "{sv}", "display-name", g_variant_new_take_string (make_display_name (manager, output))); g_variant_builder_add (&properties, "{sv}", "backlight", g_variant_new_int32 (output->backlight)); g_variant_builder_add (&properties, "{sv}", "primary", g_variant_new_boolean (output->is_primary)); g_variant_builder_add (&properties, "{sv}", "presentation", g_variant_new_boolean (output->is_presentation)); edid_file = manager_class->get_edid_file (manager, output); if (edid_file) { g_variant_builder_add (&properties, "{sv}", "edid-file", g_variant_new_take_string (edid_file)); } else { edid = manager_class->read_edid (manager, output); if (edid) { g_variant_builder_add (&properties, "{sv}", "edid", g_variant_new_from_bytes (G_VARIANT_TYPE ("ay"), edid, TRUE)); g_bytes_unref (edid); } } g_variant_builder_add (&output_builder, "(uxiausauaua{sv})", i, /* ID */ (gint64)output->output_id, (int)(output->crtc ? output->crtc - manager->crtcs : -1), &crtcs, output->name, &modes, &clones, &properties); } for (i = 0; i < manager->n_modes; i++) { MetaMonitorMode *mode = &manager->modes[i]; g_variant_builder_add (&mode_builder, "(uxuud)", i, /* ID */ (gint64)mode->mode_id, (guint32)mode->width, (guint32)mode->height, (double)mode->refresh_rate); } meta_dbus_display_config_complete_get_resources (skeleton, invocation, manager->serial, g_variant_builder_end (&crtc_builder), g_variant_builder_end (&output_builder), g_variant_builder_end (&mode_builder), manager->max_screen_width, manager->max_screen_height); return TRUE; }
static gboolean rewrite_delta (OstreeRepo *src_repo, const char *src_commit, OstreeRepo *dst_repo, const char *dst_commit, GVariant *dst_commitv, const char *from, GError **error) { g_autoptr(GFile) src_delta_file = NULL; g_autoptr(GFile) dst_delta_file = NULL; g_autofree char *src_detached_key = _ostree_get_relative_static_delta_path (from, src_commit, "commitmeta"); g_autofree char *dst_detached_key = _ostree_get_relative_static_delta_path (from, dst_commit, "commitmeta"); g_autofree char *src_delta_dir = _ostree_get_relative_static_delta_path (from, src_commit, NULL); g_autofree char *dst_delta_dir = _ostree_get_relative_static_delta_path (from, dst_commit, NULL); g_autofree char *src_superblock_path = _ostree_get_relative_static_delta_path (from, src_commit, "superblock"); g_autofree char *dst_superblock_path = _ostree_get_relative_static_delta_path (from, dst_commit, "superblock"); GMappedFile *mfile = NULL; g_auto(GVariantBuilder) superblock_builder = FLATPAK_VARIANT_BUILDER_INITIALIZER; g_autoptr(GVariant) src_superblock = NULL; g_autoptr(GVariant) dst_superblock = NULL; g_autoptr(GBytes) bytes = NULL; g_autoptr(GVariant) dst_detached = NULL; g_autoptr(GVariant) src_metadata = NULL; g_autoptr(GVariant) src_recurse = NULL; g_autoptr(GVariant) src_parts = NULL; g_auto(GVariantDict) dst_metadata_dict = FLATPAK_VARIANT_DICT_INITIALIZER; int i; src_delta_file = g_file_resolve_relative_path (ostree_repo_get_path (src_repo), src_superblock_path); mfile = g_mapped_file_new (flatpak_file_get_path_cached (src_delta_file), FALSE, NULL); if (mfile == NULL) return TRUE; /* No superblock, not an error */ bytes = g_mapped_file_get_bytes (mfile); g_mapped_file_unref (mfile); src_superblock = g_variant_ref_sink (g_variant_new_from_bytes (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT), bytes, FALSE)); src_metadata = g_variant_get_child_value (src_superblock, 0); src_recurse = g_variant_get_child_value (src_superblock, 5); src_parts = g_variant_get_child_value (src_superblock, 6); if (g_variant_n_children (src_recurse) != 0) return flatpak_fail (error, "Recursive deltas not supported, ignoring"); g_variant_builder_init (&superblock_builder, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT)); g_variant_dict_init (&dst_metadata_dict, src_metadata); g_variant_dict_remove (&dst_metadata_dict, src_detached_key); if (ostree_repo_read_commit_detached_metadata (dst_repo, dst_commit, &dst_detached, NULL, NULL) && dst_detached != NULL) g_variant_dict_insert_value (&dst_metadata_dict, dst_detached_key, dst_detached); g_variant_builder_add_value (&superblock_builder, g_variant_dict_end (&dst_metadata_dict)); g_variant_builder_add_value (&superblock_builder, g_variant_get_child_value (src_superblock, 1)); /* timestamp */ g_variant_builder_add_value (&superblock_builder, from ? ostree_checksum_to_bytes_v (from) : new_bytearray ((guchar *) "", 0)); g_variant_builder_add_value (&superblock_builder, ostree_checksum_to_bytes_v (dst_commit)); g_variant_builder_add_value (&superblock_builder, dst_commitv); g_variant_builder_add_value (&superblock_builder, src_recurse); g_variant_builder_add_value (&superblock_builder, src_parts); g_variant_builder_add_value (&superblock_builder, g_variant_get_child_value (src_superblock, 7)); /* fallback */ dst_superblock = g_variant_ref_sink (g_variant_builder_end (&superblock_builder)); if (!glnx_shutil_mkdir_p_at (ostree_repo_get_dfd (dst_repo), dst_delta_dir, 0755, NULL, error)) return FALSE; for (i = 0; i < g_variant_n_children (src_parts); i++) { g_autofree char *src_part_path = g_strdup_printf ("%s/%d", src_delta_dir, i); g_autofree char *dst_part_path = g_strdup_printf ("%s/%d", dst_delta_dir, i); if (!glnx_file_copy_at (ostree_repo_get_dfd (src_repo), src_part_path, NULL, ostree_repo_get_dfd (dst_repo), dst_part_path, GLNX_FILE_COPY_OVERWRITE | GLNX_FILE_COPY_NOXATTRS, NULL, error)) return FALSE; } dst_delta_file = g_file_resolve_relative_path (ostree_repo_get_path (dst_repo), dst_superblock_path); if (!flatpak_variant_save (dst_delta_file, dst_superblock, NULL, error)) return FALSE; return TRUE; }
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; }
void ot_dump_summary_bytes (GBytes *summary_bytes, OstreeDumpFlags flags) { g_autoptr(GVariant) summary = NULL; g_autoptr(GVariant) refs = NULL; g_autoptr(GVariant) exts = NULL; GVariantIter iter; GVariant *value; char *key; g_return_if_fail (summary_bytes != NULL); summary = g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, summary_bytes, FALSE); if (flags & OSTREE_DUMP_RAW) { ot_dump_variant (summary); return; } refs = g_variant_get_child_value (summary, 0); exts = g_variant_get_child_value (summary, 1); g_variant_iter_init (&iter, refs); while ((value = g_variant_iter_next_value (&iter)) != NULL) { const char *ref_name = NULL; g_variant_get_child (value, 0, "&s", &ref_name); if (ref_name != NULL) { g_autoptr(GVariant) csum_v = NULL; g_autoptr(GVariantIter) metadata = NULL; guint64 commit_size; g_variant_get_child (value, 1, "(t@aya{sv})", &commit_size, &csum_v, &metadata); dump_summary_ref (ref_name, commit_size, csum_v, metadata); g_print ("\n"); } g_variant_unref (value); } g_variant_iter_init (&iter, exts); while (g_variant_iter_loop (&iter, "{sv}", &key, &value)) { g_autofree gchar *value_str = NULL; const gchar *pretty_key = NULL; if (g_strcmp0 (key, OSTREE_SUMMARY_STATIC_DELTAS) == 0) { pretty_key = "Static Deltas"; value_str = g_variant_print (value, FALSE); } else if (g_strcmp0 (key, OSTREE_SUMMARY_LAST_MODIFIED) == 0) { pretty_key = "Last-Modified"; value_str = uint64_secs_to_iso8601 (GUINT64_FROM_BE (g_variant_get_uint64 (value))); } else if (g_strcmp0 (key, OSTREE_SUMMARY_EXPIRES) == 0) { pretty_key = "Expires"; value_str = uint64_secs_to_iso8601 (GUINT64_FROM_BE (g_variant_get_uint64 (value))); } else { value_str = g_variant_print (value, FALSE); } /* Print out. */ if (pretty_key != NULL) g_print ("%s (%s): %s\n", pretty_key, key, value_str); else g_print ("%s: %s\n", key, value_str); } }
gboolean install_bundle (XdgAppDir *dir, GOptionContext *context, int argc, char **argv, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; g_autoptr(GFile) deploy_base = NULL; g_autoptr(GFile) file = NULL; g_autoptr(GFile) gpg_tmp_file = NULL; const char *filename; g_autofree char *ref = NULL; g_autofree char *origin = NULL; gboolean created_deploy_base = FALSE; gboolean added_remote = FALSE; g_autofree char *to_checksum = NULL; g_auto(GStrv) parts = NULL; g_autoptr(GBytes) gpg_data = NULL; g_autofree char *remote = NULL; OstreeRepo *repo; g_autoptr(OstreeGpgVerifyResult) gpg_result = NULL; g_autoptr(GError) my_error = NULL; g_auto(GLnxLockFile) lock = GLNX_LOCK_FILE_INIT; if (argc < 2) return usage_error (context, "bundle filename must be specified", error); filename = argv[1]; repo = xdg_app_dir_get_repo (dir); if (!xdg_app_supports_bundles (repo)) return xdg_app_fail (error, "Your version of ostree is too old to support single-file bundles"); if (!xdg_app_dir_lock (dir, &lock, cancellable, error)) goto out; file = g_file_new_for_commandline_arg (filename); { g_autoptr(GVariant) delta = NULL; g_autoptr(GVariant) metadata = NULL; g_autoptr(GBytes) bytes = NULL; g_autoptr(GVariant) to_csum_v = NULL; g_autoptr(GVariant) gpg_value = NULL; GMappedFile *mfile = g_mapped_file_new (gs_file_get_path_cached (file), FALSE, error); if (mfile == NULL) return FALSE; bytes = g_mapped_file_get_bytes (mfile); g_mapped_file_unref (mfile); delta = g_variant_new_from_bytes (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT), bytes, FALSE); g_variant_ref_sink (delta); to_csum_v = g_variant_get_child_value (delta, 3); if (!ostree_validate_structureof_csum_v (to_csum_v, error)) return FALSE; to_checksum = ostree_checksum_from_bytes_v (to_csum_v); metadata = g_variant_get_child_value (delta, 0); if (!g_variant_lookup (metadata, "ref", "s", &ref)) return xdg_app_fail (error, "Invalid bundle, no ref in metadata"); if (!g_variant_lookup (metadata, "origin", "s", &origin)) origin = NULL; gpg_value = g_variant_lookup_value (metadata, "gpg-keys", G_VARIANT_TYPE("ay")); if (gpg_value) { gsize n_elements; const char *data = g_variant_get_fixed_array (gpg_value, &n_elements, 1); gpg_data = g_bytes_new (data, n_elements); } } parts = xdg_app_decompose_ref (ref, error); if (parts == NULL) return FALSE; deploy_base = xdg_app_dir_get_deploy_dir (dir, ref); if (g_file_query_exists (deploy_base, cancellable)) return xdg_app_fail (error, "%s branch %s already installed", parts[1], parts[3]); if (opt_gpg_file != NULL) { /* Override gpg_data from file */ gpg_data = read_gpg_data (cancellable, error); if (gpg_data == NULL) return FALSE; } /* Add a remote for later updates */ if (origin != NULL) { g_auto(GStrv) remotes = ostree_repo_remote_list (repo, NULL); int version = 0; do { g_autofree char *name = NULL; if (version == 0) name = g_strdup_printf ("%s-origin", parts[1]); else name = g_strdup_printf ("%s-%d-origin", parts[1], version); version++; if (remotes == NULL || !g_strv_contains ((const char * const *) remotes, name)) remote = g_steal_pointer (&name); } while (remote == NULL); } if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) return FALSE; ostree_repo_transaction_set_ref (repo, remote, ref, to_checksum); if (!ostree_repo_static_delta_execute_offline (repo, file, FALSE, cancellable, error)) return FALSE; if (gpg_data) { g_autoptr(GFileIOStream) stream; GOutputStream *o; gpg_tmp_file = g_file_new_tmp (".xdg-app-XXXXXX", &stream, error); if (gpg_tmp_file == NULL) return FALSE; o = g_io_stream_get_output_stream (G_IO_STREAM (stream)); if (!g_output_stream_write_all (o, g_bytes_get_data (gpg_data, NULL), g_bytes_get_size (gpg_data), NULL, cancellable, error)) return FALSE; } gpg_result = ostree_repo_verify_commit_ext (repo, to_checksum, NULL, gpg_tmp_file, cancellable, &my_error); if (gpg_tmp_file) g_file_delete (gpg_tmp_file, cancellable, NULL); if (gpg_result == NULL) { /* NOT_FOUND means no gpg signature, we ignore this *if* there * is no gpg key specified in the bundle or by the user */ if (g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) && gpg_data == NULL) g_clear_error (&my_error); else { g_propagate_error (error, g_steal_pointer (&my_error)); return FALSE; } } else { /* If there is no valid gpg signature we fail, unless there is no gpg key specified (on the command line or in the file) because then we trust the source bundle. */ if (ostree_gpg_verify_result_count_valid (gpg_result) == 0 && gpg_data != NULL) return xdg_app_fail (error, "GPG signatures found, but none are in trusted keyring"); } if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error)) return FALSE; if (!g_file_make_directory_with_parents (deploy_base, cancellable, error)) return FALSE; /* From here we need to goto out on error, to clean up */ created_deploy_base = TRUE; if (remote) { g_autoptr(GVariantBuilder) optbuilder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); g_autofree char *basename = g_file_get_basename (file); g_variant_builder_add (optbuilder, "{s@v}", "xa.title", g_variant_new_variant (g_variant_new_string (basename))); g_variant_builder_add (optbuilder, "{s@v}", "xa.noenumerate", g_variant_new_variant (g_variant_new_boolean (TRUE))); g_variant_builder_add (optbuilder, "{s@v}", "xa.prio", g_variant_new_variant (g_variant_new_string ("0"))); if (!ostree_repo_remote_add (repo, remote, origin, g_variant_builder_end (optbuilder), cancellable, error)) goto out; added_remote = TRUE; if (gpg_data) { g_autoptr(GInputStream) gpg_data_as_stream = g_memory_input_stream_new_from_bytes (gpg_data); if (!ostree_repo_remote_gpg_import (repo, remote, gpg_data_as_stream, NULL, NULL, cancellable, error)) goto out; } if (!xdg_app_dir_set_origin (dir, ref, remote, cancellable, error)) goto out; } if (!xdg_app_dir_deploy (dir, ref, to_checksum, cancellable, error)) goto out; if (!xdg_app_dir_make_current_ref (dir, ref, cancellable, error)) goto out; if (strcmp (parts[0], "app") == 0) { if (!xdg_app_dir_update_exports (dir, parts[1], cancellable, error)) goto out; } glnx_release_lock_file (&lock); xdg_app_dir_cleanup_removed (dir, cancellable, NULL); if (!xdg_app_dir_mark_changed (dir, error)) goto out; ret = TRUE; out: if (created_deploy_base && !ret) gs_shutil_rm_rf (deploy_base, cancellable, NULL); if (added_remote && !ret) ostree_repo_remote_delete (repo, remote, NULL, NULL); return ret; }
/** * ostree_repo_remote_list_refs: * @self: Repo * @remote_name: Name of the remote. * @out_all_refs: (out) (element-type utf8 utf8): Mapping from ref to checksum * @cancellable: Cancellable * @error: Error * */ gboolean ostree_repo_remote_list_refs (OstreeRepo *self, const char *remote_name, GHashTable **out_all_refs, GCancellable *cancellable, GError **error) { g_autoptr(GBytes) summary_bytes = NULL; g_autoptr(GHashTable) ret_all_refs = NULL; if (!ostree_repo_remote_fetch_summary (self, remote_name, &summary_bytes, NULL, cancellable, error)) return FALSE; if (summary_bytes == NULL) { return glnx_throw (error, "Remote refs not available; server has no summary file"); } else { g_autoptr(GVariant) summary = NULL; g_autoptr(GVariant) ref_map = NULL; GVariantIter iter; GVariant *child; ret_all_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); summary = g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, summary_bytes, FALSE); ref_map = g_variant_get_child_value (summary, 0); g_variant_iter_init (&iter, ref_map); while ((child = g_variant_iter_next_value (&iter)) != NULL) { const char *ref_name = NULL; g_autoptr(GVariant) csum_v = NULL; char tmp_checksum[OSTREE_SHA256_STRING_LEN+1]; g_variant_get_child (child, 0, "&s", &ref_name); if (ref_name != NULL) { g_variant_get_child (child, 1, "(t@aya{sv})", NULL, &csum_v, NULL); const guchar *csum_bytes = ostree_checksum_bytes_peek_validate (csum_v, error); if (csum_bytes == NULL) return FALSE; ostree_checksum_inplace_from_bytes (csum_bytes, tmp_checksum); g_hash_table_insert (ret_all_refs, g_strdup (ref_name), g_strdup (tmp_checksum)); } g_variant_unref (child); } } ot_transfer_out_value (out_all_refs, &ret_all_refs); return TRUE; }