unpacker: embed RPM checksum in metadata

In addition to the header checksum, we also want a checksum of the RPM
file itself. This will allow us to know right away whether an RPM with
the same NEVRA in the repos is actually the same one we already
imported.

Closes: #769
Approved by: cgwalters
This commit is contained in:
Jonathan Lebon 2017-05-08 17:10:49 -04:00 committed by Atomic Bot
parent fa10f36fb6
commit eff00053ef
4 changed files with 54 additions and 14 deletions

View File

@ -1360,12 +1360,9 @@ rpmostree_dnf_add_checksum_goal (GChecksum *checksum,
for (i = 0; i < pkglist->len; i++) for (i = 0; i < pkglist->len; i++)
{ {
DnfPackage *pkg = pkglist->pdata[i]; DnfPackage *pkg = pkglist->pdata[i];
int pkg_checksum_type; g_autofree char* chksum_repr = NULL;
const unsigned char *pkg_checksum_bytes = dnf_package_get_chksum (pkg, &pkg_checksum_type); g_assert (rpmostree_get_repodata_chksum_repr (pkg, &chksum_repr, NULL));
g_autofree char *pkg_checksum = hy_chksum_str (pkg_checksum_bytes, pkg_checksum_type); g_ptr_array_add (pkg_checksums, g_steal_pointer (&chksum_repr));
char *pkg_checksum_with_type = g_strconcat (hy_chksum_name (pkg_checksum_type), ":", pkg_checksum, NULL);
g_ptr_array_add (pkg_checksums, pkg_checksum_with_type);
} }
g_ptr_array_sort (pkg_checksums, rpmostree_ptrarray_sort_compare_strings); g_ptr_array_sort (pkg_checksums, rpmostree_ptrarray_sort_compare_strings);

View File

@ -1057,3 +1057,30 @@ rpmostree_fcap_to_xattr_variant (const char *fcap)
vfsbytes, FALSE)); vfsbytes, FALSE));
return g_variant_ref_sink (g_variant_builder_end (&builder)); return g_variant_ref_sink (g_variant_builder_end (&builder));
} }
/* Returns the checksum of the RPM we retrieved from the repodata XML. The
* actual checksum type used depends on how the repodata was created. Thus, the
* output is a string representation of the form "TYPE:HASH" where TYPE is the
* name of the checksum employed. In most cases, it will be "sha256" (the
* current default for `createrepo_c`). */
gboolean
rpmostree_get_repodata_chksum_repr (DnfPackage *pkg,
char **out_chksum_repr,
GError **error)
{
int chksum_type;
g_autofree char *chksum = NULL;
const unsigned char *chksum_raw = NULL;
chksum_raw = dnf_package_get_chksum (pkg, &chksum_type);
if (chksum_raw)
chksum = hy_chksum_str (chksum_raw, chksum_type);
if (chksum == NULL)
return glnx_throw (error, "Couldn't get chksum for pkg %s",
dnf_package_get_nevra(pkg));
*out_chksum_repr =
g_strconcat (hy_chksum_name (chksum_type), ":", chksum, NULL);
return TRUE;
}

View File

@ -166,3 +166,8 @@ typedef enum {
char * char *
rpmostree_pkg_custom_nevra_strdup (Header h, RpmOstreePkgNevraFlags flags); rpmostree_pkg_custom_nevra_strdup (Header h, RpmOstreePkgNevraFlags flags);
gboolean
rpmostree_get_repodata_chksum_repr (DnfPackage *pkg,
char **out_chksum_repr,
GError **error);

View File

@ -464,10 +464,13 @@ build_metadata_variant (RpmOstreeUnpacker *self,
g_auto(GVariantBuilder) metadata_builder; g_auto(GVariantBuilder) metadata_builder;
g_variant_builder_init (&metadata_builder, (GVariantType*)"a{sv}"); g_variant_builder_init (&metadata_builder, (GVariantType*)"a{sv}");
/* NB: We store the full header of the RPM in the commit for two reasons: /* NB: We store the full header of the RPM in the commit for three reasons:
* first, it holds the file security capabilities, and secondly, we'll need to * 1. it holds the file security capabilities, which we need during checkout
* provide it to librpm when it updates the rpmdb (see * 2. we'll need to provide it to librpm when it updates the rpmdb (see
* rpmostree_context_assemble_commit()). */ * rpmostree_context_assemble_commit())
* 3. it's needed in the local pkgs paths to fool the libdnf stack (see
* rpmostree_context_prepare_install())
*/
{ {
g_autoptr(GBytes) metadata = NULL; g_autoptr(GBytes) metadata = NULL;
@ -478,8 +481,6 @@ build_metadata_variant (RpmOstreeUnpacker *self,
g_variant_new_from_bytes ((GVariantType*)"ay", g_variant_new_from_bytes ((GVariantType*)"ay",
metadata, TRUE)); metadata, TRUE));
/* NB: the header also includes checksums for every entry in the (cut-off)
* archive, so there's no need to also bring that in */
g_checksum_update (pkg_checksum, g_bytes_get_data (metadata, NULL), g_checksum_update (pkg_checksum, g_bytes_get_data (metadata, NULL),
g_bytes_get_size (metadata)); g_bytes_get_size (metadata));
@ -506,7 +507,7 @@ build_metadata_variant (RpmOstreeUnpacker *self,
* compatible increments. * compatible increments.
*/ */
g_variant_builder_add (&metadata_builder, "{sv}", "rpmostree.unpack_minor_version", g_variant_builder_add (&metadata_builder, "{sv}", "rpmostree.unpack_minor_version",
g_variant_new_uint32 (2)); g_variant_new_uint32 (3));
if (self->pkg) if (self->pkg)
{ {
@ -516,6 +517,16 @@ build_metadata_variant (RpmOstreeUnpacker *self,
g_variant_builder_add (&metadata_builder, "{sv}", "rpmostree.repo", g_variant_builder_add (&metadata_builder, "{sv}", "rpmostree.repo",
repo_metadata_to_variant (repo)); repo_metadata_to_variant (repo));
} }
/* include a checksum of the RPM as a whole; the actual algo used depends
* on how the repodata was created, so just keep a repr */
g_autofree char* chksum_repr = NULL;
if (!rpmostree_get_repodata_chksum_repr (self->pkg, &chksum_repr, error))
return FALSE;
g_variant_builder_add (&metadata_builder, "{sv}",
"rpmostree.repodata_checksum",
g_variant_new_string (chksum_repr));
} }
*out_variant = g_variant_builder_end (&metadata_builder); *out_variant = g_variant_builder_end (&metadata_builder);