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++)
{
DnfPackage *pkg = pkglist->pdata[i];
int pkg_checksum_type;
const unsigned char *pkg_checksum_bytes = dnf_package_get_chksum (pkg, &pkg_checksum_type);
g_autofree char *pkg_checksum = hy_chksum_str (pkg_checksum_bytes, pkg_checksum_type);
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_autofree char* chksum_repr = NULL;
g_assert (rpmostree_get_repodata_chksum_repr (pkg, &chksum_repr, NULL));
g_ptr_array_add (pkg_checksums, g_steal_pointer (&chksum_repr));
}
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));
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 *
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

@ -431,7 +431,7 @@ get_lead_sig_header_as_bytes (RpmOstreeUnpacker *self,
bytes_remaining);
goto out;
}
ret = TRUE;
*out_metadata = g_bytes_new_take (g_steal_pointer (&buf), self->cpio_offset);
out:
@ -464,10 +464,13 @@ build_metadata_variant (RpmOstreeUnpacker *self,
g_auto(GVariantBuilder) metadata_builder;
g_variant_builder_init (&metadata_builder, (GVariantType*)"a{sv}");
/* NB: We store the full header of the RPM in the commit for two reasons:
* first, it holds the file security capabilities, and secondly, we'll need to
* provide it to librpm when it updates the rpmdb (see
* rpmostree_context_assemble_commit()). */
/* NB: We store the full header of the RPM in the commit for three reasons:
* 1. it holds the file security capabilities, which we need during checkout
* 2. we'll need to provide it to librpm when it updates the rpmdb (see
* 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;
@ -478,8 +481,6 @@ build_metadata_variant (RpmOstreeUnpacker *self,
g_variant_new_from_bytes ((GVariantType*)"ay",
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_bytes_get_size (metadata));
@ -506,7 +507,7 @@ build_metadata_variant (RpmOstreeUnpacker *self,
* compatible increments.
*/
g_variant_builder_add (&metadata_builder, "{sv}", "rpmostree.unpack_minor_version",
g_variant_new_uint32 (2));
g_variant_new_uint32 (3));
if (self->pkg)
{
@ -516,6 +517,16 @@ build_metadata_variant (RpmOstreeUnpacker *self,
g_variant_builder_add (&metadata_builder, "{sv}", "rpmostree.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);