diff --git a/src/libostree/ostree-cmdprivate.c b/src/libostree/ostree-cmdprivate.c index 99834937..74c32a3c 100644 --- a/src/libostree/ostree-cmdprivate.c +++ b/src/libostree/ostree-cmdprivate.c @@ -23,6 +23,7 @@ #include "ostree-cmdprivate.h" #include "ostree-repo-private.h" #include "ostree-core-private.h" +#include "ostree-repo-static-delta-private.h" #include "ostree-sysroot.h" #include "ostree-bootloader-grub2.h" @@ -44,7 +45,8 @@ const OstreeCmdPrivateVTable * ostree_cmd__private__ (void) { static OstreeCmdPrivateVTable table = { - impl_ostree_generate_grub2_config + impl_ostree_generate_grub2_config, + _ostree_repo_static_delta_dump }; return &table; diff --git a/src/libostree/ostree-cmdprivate.h b/src/libostree/ostree-cmdprivate.h index 317a7592..7746406b 100644 --- a/src/libostree/ostree-cmdprivate.h +++ b/src/libostree/ostree-cmdprivate.h @@ -26,6 +26,7 @@ G_BEGIN_DECLS typedef struct { gboolean (* ostree_generate_grub2_config) (OstreeSysroot *sysroot, int bootversion, int target_fd, GCancellable *cancellable, GError **error); + gboolean (* ostree_static_delta_dump) (OstreeRepo *repo, const char *delta_id, GCancellable *cancellable, GError **error); } OstreeCmdPrivateVTable; const OstreeCmdPrivateVTable * diff --git a/src/libostree/ostree-repo-static-delta-core.c b/src/libostree/ostree-repo-static-delta-core.c index b2ffddc5..bc1b460c 100644 --- a/src/libostree/ostree-repo-static-delta-core.c +++ b/src/libostree/ostree-repo-static-delta-core.c @@ -22,6 +22,7 @@ #include "ostree-core-private.h" #include "ostree-repo-private.h" +#include "ostree-cmdprivate.h" #include "ostree-repo-static-delta-private.h" #include "otutil.h" @@ -404,3 +405,95 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self, out: return ret; } + +gboolean +_ostree_repo_static_delta_dump (OstreeRepo *self, + const char *delta_id, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + g_autofree char *from = NULL; + g_autofree char *to = NULL; + g_autofree char *superblock_path = NULL; + glnx_fd_close int superblock_fd = -1; + g_autoptr(GVariant) delta_superblock = NULL; + guint64 total_size = 0, total_usize = 0; + guint64 total_fallback_size = 0, total_fallback_usize = 0; + guint i; + + _ostree_parse_delta_name (delta_id, &from, &to); + superblock_path = _ostree_get_relative_static_delta_superblock_path (from, to); + + if (!ot_util_variant_map_at (self->repo_dir_fd, superblock_path, + (GVariantType*)OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT, + TRUE, &delta_superblock, error)) + goto out; + + g_print ("Delta: %s\n", delta_id); + { guint64 ts; + g_variant_get_child (delta_superblock, 1, "t", &ts); + g_print ("Timestamp: %" G_GUINT64_FORMAT "\n", GUINT64_FROM_BE (ts)); + } + { g_autoptr(GVariant) recurse = NULL; + g_variant_get_child (delta_superblock, 5, "@ay", &recurse); + g_print ("Number of parents: %u\n", (guint)(g_variant_get_size (recurse) / (OSTREE_SHA256_DIGEST_LEN * 2))); + } + { g_autoptr(GVariant) fallback = NULL; + guint n_fallback; + + g_variant_get_child (delta_superblock, 7, "@a" OSTREE_STATIC_DELTA_FALLBACK_FORMAT, &fallback); + n_fallback = g_variant_n_children (fallback); + + g_print ("Number of fallback entries: %u\n", n_fallback); + + for (i = 0; i < n_fallback; i++) + { + guint64 size, usize; + g_variant_get_child (fallback, i, "(y@aytt)", NULL, NULL, &size, &usize); + total_fallback_size += size; + total_fallback_usize += usize; + } + { g_autofree char *sizestr = g_format_size (total_fallback_size); + g_autofree char *usizestr = g_format_size (total_fallback_usize); + g_print ("Total Fallback Size: %" G_GUINT64_FORMAT " (%s)\n", total_fallback_size, sizestr); + g_print ("Total Fallback Uncompressed Size: %" G_GUINT64_FORMAT " (%s)\n", total_fallback_usize, usizestr); + } + } + { g_autoptr(GVariant) meta_entries = NULL; + guint n_parts; + + g_variant_get_child (delta_superblock, 6, "@a" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT, &meta_entries); + n_parts = g_variant_n_children (meta_entries); + g_print ("Number of parts: %u\n", n_parts); + + for (i = 0; i < n_parts; i++) + { + guint32 version; + guint64 size, usize; + g_autoptr(GVariant) objects = NULL; + g_variant_get_child (meta_entries, i, "(u@aytt@ay)", &version, NULL, &size, &usize, &objects); + total_size += size; + total_usize += usize; + g_print ("Part%u: nobjects=%u size=%" G_GUINT64_FORMAT " usize=%" G_GUINT64_FORMAT "\n", + i, (guint)(g_variant_get_size (objects) / OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN), size, usize); + } + } + + { g_autofree char *sizestr = g_format_size (total_size); + g_autofree char *usizestr = g_format_size (total_usize); + g_print ("Total Part Size: %" G_GUINT64_FORMAT " (%s)\n", total_size, sizestr); + g_print ("Total Part Uncompressed Size: %" G_GUINT64_FORMAT " (%s)\n", total_usize, usizestr); + } + { guint64 overall_size = total_size + total_fallback_size; + guint64 overall_usize = total_usize + total_fallback_usize; + g_autofree char *sizestr = g_format_size (overall_size); + g_autofree char *usizestr = g_format_size (overall_usize); + g_print ("Total Size: %" G_GUINT64_FORMAT " (%s)\n", overall_size, sizestr); + g_print ("Total Uncompressed Size: %" G_GUINT64_FORMAT " (%s)\n", overall_usize, usizestr); + } + + ret = TRUE; + out: + return ret; +} diff --git a/src/libostree/ostree-repo-static-delta-private.h b/src/libostree/ostree-repo-static-delta-private.h index de32ec65..b0e82ade 100644 --- a/src/libostree/ostree-repo-static-delta-private.h +++ b/src/libostree/ostree-repo-static-delta-private.h @@ -103,6 +103,11 @@ G_BEGIN_DECLS */ #define OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT "(a{sv}tayay" OSTREE_COMMIT_GVARIANT_STRING "aya" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT "a" OSTREE_STATIC_DELTA_FALLBACK_FORMAT ")" +gboolean _ostree_static_delta_dump (OstreeRepo *repo, + const char *delta_id, + GCancellable *cancellable, + GError **error); + gboolean _ostree_static_delta_part_validate (OstreeRepo *repo, GInputStream *in, guint part_offset, @@ -177,4 +182,10 @@ _ostree_delta_compute_similar_objects (OstreeRepo *repo, GCancellable *cancellable, GError **error); +gboolean +_ostree_repo_static_delta_dump (OstreeRepo *repo, + const char *delta_id, + GCancellable *cancellable, + GError **error); + G_END_DECLS diff --git a/src/libotutil/ot-variant-utils.c b/src/libotutil/ot-variant-utils.c index 1210a785..ed650268 100644 --- a/src/libotutil/ot-variant-utils.c +++ b/src/libotutil/ot-variant-utils.c @@ -154,6 +154,28 @@ ot_util_variant_map (GFile *src, return ret; } +gboolean +ot_util_variant_map_at (int dfd, + const char *path, + const GVariantType *type, + gboolean trusted, + GVariant **out_variant, + GError **error) +{ + glnx_fd_close int fd = -1; + g_autoptr(GVariant) ret_variant = NULL; + + fd = openat (dfd, path, O_RDONLY | O_CLOEXEC); + if (fd < 0) + { + glnx_set_error_from_errno (error); + g_prefix_error (error, "Opening %s: ", path); + return FALSE; + } + + return ot_util_variant_map_fd (fd, 0, type, trusted, out_variant, error); +} + typedef struct { gpointer addr; gsize len; diff --git a/src/libotutil/ot-variant-utils.h b/src/libotutil/ot-variant-utils.h index 34b6eb5d..1a7abe0e 100644 --- a/src/libotutil/ot-variant-utils.h +++ b/src/libotutil/ot-variant-utils.h @@ -48,6 +48,13 @@ gboolean ot_util_variant_map (GFile *src, GVariant **out_variant, GError **error); +gboolean ot_util_variant_map_at (int dfd, + const char *path, + const GVariantType *type, + gboolean trusted, + GVariant **out_variant, + GError **error); + gboolean ot_util_variant_map_fd (int fd, goffset offset, const GVariantType *type, diff --git a/src/ostree/ot-builtin-static-delta.c b/src/ostree/ot-builtin-static-delta.c index 903e5fd6..c3c99ba0 100644 --- a/src/ostree/ot-builtin-static-delta.c +++ b/src/ostree/ot-builtin-static-delta.c @@ -23,6 +23,7 @@ #include "ot-main.h" #include "ot-builtins.h" #include "ostree.h" +#include "ostree-cmdprivate.h" #include "ot-main.h" #include "otutil.h" @@ -38,6 +39,7 @@ static gboolean opt_disable_bsdiff; #define BUILTINPROTO(name) static gboolean ot_static_delta_builtin_ ## name (int argc, char **argv, GCancellable *cancellable, GError **error) BUILTINPROTO(list); +BUILTINPROTO(show); BUILTINPROTO(generate); BUILTINPROTO(apply_offline); @@ -45,6 +47,7 @@ BUILTINPROTO(apply_offline); static OstreeCommand static_delta_subcommands[] = { { "list", ot_static_delta_builtin_list }, + { "show", ot_static_delta_builtin_show }, { "generate", ot_static_delta_builtin_generate }, { "apply-offline", ot_static_delta_builtin_apply_offline }, { NULL, NULL } @@ -129,6 +132,38 @@ ot_static_delta_builtin_list (int argc, char **argv, GCancellable *cancellable, return ret; } +static gboolean +ot_static_delta_builtin_show (int argc, char **argv, GCancellable *cancellable, GError **error) +{ + gboolean ret = FALSE; + GOptionContext *context; + glnx_unref_object OstreeRepo *repo = NULL; + const char *delta_id = NULL; + + context = g_option_context_new ("SHOW - Dump information on a delta"); + + if (!ostree_option_context_parse (context, list_options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) + goto out; + + if (argc < 3) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "DELTA must be specified"); + goto out; + } + + delta_id = argv[2]; + + if (!ostree_cmd__private__ ()->ostree_static_delta_dump (repo, delta_id, cancellable, error)) + goto out; + + ret = TRUE; + out: + if (context) + g_option_context_free (context); + return ret; +} + static gboolean ot_static_delta_builtin_generate (int argc, char **argv, GCancellable *cancellable, GError **error) {