You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
6.4 KiB
170 lines
6.4 KiB
8 months ago
|
From 983aeea57d75494fd4ea2ff2903f966136278c15 Mon Sep 17 00:00:00 2001
|
||
|
From: =?UTF-8?q?Ale=C5=A1=20Mat=C4=9Bj?= <amatej@redhat.com>
|
||
|
Date: Wed, 9 Feb 2022 13:17:00 +0100
|
||
|
Subject: [PATCH 28/34] Add private API for filling, reading and verifying new
|
||
|
dnf solv userdata
|
||
|
|
||
|
---
|
||
|
libdnf/hy-iutil-private.hpp | 24 +++++++++
|
||
|
libdnf/hy-iutil.cpp | 102 ++++++++++++++++++++++++++++++++++++
|
||
|
2 files changed, 126 insertions(+)
|
||
|
|
||
|
diff --git a/libdnf/hy-iutil-private.hpp b/libdnf/hy-iutil-private.hpp
|
||
|
index e07b1b51..d498c032 100644
|
||
|
--- a/libdnf/hy-iutil-private.hpp
|
||
|
+++ b/libdnf/hy-iutil-private.hpp
|
||
|
@@ -24,6 +24,30 @@
|
||
|
#include "hy-iutil.h"
|
||
|
#include "hy-types.h"
|
||
|
#include "sack/packageset.hpp"
|
||
|
+#include <array>
|
||
|
+#include <utility>
|
||
|
+
|
||
|
+// Use 8 bytes for libsolv version (API: solv_toolversion)
|
||
|
+// to be future proof even though it currently is "1.2"
|
||
|
+static constexpr const size_t solv_userdata_solv_toolversion_size{8};
|
||
|
+static constexpr const std::array<char, 4> solv_userdata_magic{'\0', 'd', 'n', 'f'};
|
||
|
+static constexpr const std::array<char, 4> solv_userdata_dnf_version{'\0', '1', '.', '0'};
|
||
|
+
|
||
|
+static constexpr const int solv_userdata_size = solv_userdata_solv_toolversion_size + \
|
||
|
+ solv_userdata_magic.size() + \
|
||
|
+ solv_userdata_dnf_version.size() + \
|
||
|
+ CHKSUM_BYTES;
|
||
|
+
|
||
|
+struct SolvUserdata {
|
||
|
+ char dnf_magic[solv_userdata_magic.size()];
|
||
|
+ char dnf_version[solv_userdata_dnf_version.size()];
|
||
|
+ char libsolv_version[solv_userdata_solv_toolversion_size];
|
||
|
+ unsigned char checksum[CHKSUM_BYTES];
|
||
|
+}__attribute__((packed)); ;
|
||
|
+
|
||
|
+int solv_userdata_fill(SolvUserdata *solv_userdata, const unsigned char *checksum, GError** error);
|
||
|
+std::unique_ptr<SolvUserdata> solv_userdata_read(FILE *fp);
|
||
|
+int solv_userdata_verify(const SolvUserdata *solv_userdata, const unsigned char *checksum);
|
||
|
|
||
|
/* crypto utils */
|
||
|
int checksum_cmp(const unsigned char *cs1, const unsigned char *cs2);
|
||
|
diff --git a/libdnf/hy-iutil.cpp b/libdnf/hy-iutil.cpp
|
||
|
index 2af13197..f81ca52f 100644
|
||
|
--- a/libdnf/hy-iutil.cpp
|
||
|
+++ b/libdnf/hy-iutil.cpp
|
||
|
@@ -43,6 +43,7 @@ extern "C" {
|
||
|
#include <solv/evr.h>
|
||
|
#include <solv/solver.h>
|
||
|
#include <solv/solverdebug.h>
|
||
|
+#include <solv/repo_solv.h>
|
||
|
#include <solv/util.h>
|
||
|
#include <solv/pool_parserpmrichdep.h>
|
||
|
}
|
||
|
@@ -182,6 +183,107 @@ int checksum_write(const unsigned char *cs, FILE *fp)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+static std::array<char, solv_userdata_solv_toolversion_size>
|
||
|
+get_padded_solv_toolversion()
|
||
|
+{
|
||
|
+ std::array<char, solv_userdata_solv_toolversion_size> padded_solv_toolversion{};
|
||
|
+ std::string solv_ver_str{solv_toolversion};
|
||
|
+ std::copy(solv_ver_str.rbegin(), solv_ver_str.rend(), padded_solv_toolversion.rbegin());
|
||
|
+
|
||
|
+ return padded_solv_toolversion;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+solv_userdata_fill(SolvUserdata *solv_userdata, const unsigned char *checksum, GError** error)
|
||
|
+{
|
||
|
+ if (strlen(solv_toolversion) > solv_userdata_solv_toolversion_size) {
|
||
|
+ g_set_error(error, DNF_ERROR, DNF_ERROR_INTERNAL_ERROR,
|
||
|
+ _("Libsolv's solv_toolversion is: %zu long but we expect max of: %zu"),
|
||
|
+ strlen(solv_toolversion), solv_userdata_solv_toolversion_size);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ // copy dnf solv file magic
|
||
|
+ memcpy(solv_userdata->dnf_magic, solv_userdata_magic.data(), solv_userdata_magic.size());
|
||
|
+
|
||
|
+ // copy dnf solv file version
|
||
|
+ memcpy(solv_userdata->dnf_version, solv_userdata_dnf_version.data(), solv_userdata_dnf_version.size());
|
||
|
+
|
||
|
+ // copy libsolv solv file version
|
||
|
+ memcpy(solv_userdata->libsolv_version, get_padded_solv_toolversion().data(), solv_userdata_solv_toolversion_size);
|
||
|
+
|
||
|
+ // copy checksum
|
||
|
+ memcpy(solv_userdata->checksum, checksum, CHKSUM_BYTES);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+std::unique_ptr<SolvUserdata>
|
||
|
+solv_userdata_read(FILE *fp)
|
||
|
+{
|
||
|
+ unsigned char *dnf_solvfile_userdata_read = NULL;
|
||
|
+ int dnf_solvfile_userdata_len_read;
|
||
|
+ if (!fp) {
|
||
|
+ return nullptr;
|
||
|
+ }
|
||
|
+
|
||
|
+ int ret_code = solv_read_userdata(fp, &dnf_solvfile_userdata_read, &dnf_solvfile_userdata_len_read);
|
||
|
+ // The userdata layout has to match our struct exactly so we can just cast the memory
|
||
|
+ // allocated by libsolv
|
||
|
+ std::unique_ptr<SolvUserdata> uniq_userdata(reinterpret_cast<SolvUserdata *>(dnf_solvfile_userdata_read));
|
||
|
+ if(ret_code) {
|
||
|
+ g_warning("Failed to read solv userdata: solv_read_userdata returned: %i", ret_code);
|
||
|
+ return nullptr;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (dnf_solvfile_userdata_len_read != solv_userdata_size) {
|
||
|
+ g_warning("Solv userdata length mismatch, read: %i vs expected: %i",
|
||
|
+ dnf_solvfile_userdata_len_read, solv_userdata_size);
|
||
|
+ return nullptr;
|
||
|
+ }
|
||
|
+
|
||
|
+ return uniq_userdata;
|
||
|
+}
|
||
|
+
|
||
|
+gboolean
|
||
|
+solv_userdata_verify(const SolvUserdata *solv_userdata, const unsigned char *checksum)
|
||
|
+{
|
||
|
+ // check dnf solvfile magic bytes
|
||
|
+ if (memcmp(solv_userdata->dnf_magic, solv_userdata_magic.data(), solv_userdata_magic.size()) != 0) {
|
||
|
+ // This is not dnf header do not read after it
|
||
|
+ g_warning("magic bytes don't match, read: %s vs. dnf solvfile magic: %s",
|
||
|
+ solv_userdata->dnf_magic, solv_userdata_magic.data());
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
+ // check dnf solvfile version
|
||
|
+ if (memcmp(solv_userdata->dnf_version, solv_userdata_dnf_version.data(), solv_userdata_dnf_version.size()) != 0) {
|
||
|
+ // Mismatching dnf solvfile version -> we need to regenerate
|
||
|
+ g_warning("dnf solvfile version doesn't match, read: %s vs. dnf solvfile version: %s",
|
||
|
+ solv_userdata->dnf_version, solv_userdata_dnf_version.data());
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
+ // check libsolv solvfile version
|
||
|
+ if (memcmp(solv_userdata->libsolv_version, get_padded_solv_toolversion().data(), solv_userdata_solv_toolversion_size) != 0) {
|
||
|
+ // Mismatching libsolv solvfile version -> we need to regenerate
|
||
|
+ g_warning("libsolv solvfile version doesn't match, read: %s vs. libsolv version: %s",
|
||
|
+ solv_userdata->libsolv_version, solv_toolversion);
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
+ // check solvfile checksum
|
||
|
+ if (checksum_cmp(solv_userdata->checksum, checksum)) {
|
||
|
+ // Mismatching solvfile checksum -> we need to regenerate
|
||
|
+ g_debug("solvfile checksum doesn't match, read: %s vs. repomd checksum: %s",
|
||
|
+ solv_userdata->checksum, checksum);
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
int
|
||
|
checksum_type2length(int type)
|
||
|
{
|
||
|
--
|
||
|
2.31.1
|
||
|
|