From 83170da8f5069bd259919fb89f459e05fcaec633 Mon Sep 17 00:00:00 2001 From: Matthew Almond Date: Mon, 8 Mar 2021 12:57:53 -0800 Subject: [PATCH] Expose librepo's checksum functions via SWIG DNF has been carrying around yum's old checksum function. These functions duplicate code in librepo. They are slower because librepo can employ caching of digests. Lastly, these functions in Python do not know about changes in checksum logic like https://github.com/rpm-software-management/librepo/pull/222 The choices here are: 1. Replicate `lr_checksum_cow_fd()` and caching logic in Python 2. Just use librepo from dnf. This is 2. Note there is an open bug in librepo that forces no caching for `checksum_value()` (https://github.com/rpm-software-management/librepo/issues/233). For now we can keep the perf hit - this is no worse than the existing code and aim for more correctness. This change goes hand in hand with a change to `dnf` itself to make use of the new functions and eliminate the old ones. On errors, these functions raise libdnf.error.Error which can be easily mapped into MiscError in dnf --- bindings/swig/utils.i | 3 +++ libdnf/utils/utils.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++ libdnf/utils/utils.hpp | 16 ++++++++++++ 3 files changed, 76 insertions(+) diff --git a/bindings/swig/utils.i b/bindings/swig/utils.i index 60fabb02d6..df323e3755 100644 --- a/bindings/swig/utils.i +++ b/bindings/swig/utils.i @@ -44,4 +44,7 @@ namespace libdnf { namespace filesystem { void decompress(const char * inPath, const char * outPath, mode_t outMode, const char * compressType = nullptr); +bool checksum_check(const char * type, const char * inPath, const char * checksum_valid); +std::string checksum_value(const char * type, const char * inPath); + }} diff --git a/libdnf/utils/utils.cpp b/libdnf/utils/utils.cpp index 2bb1290d1b..3096c5a7a3 100644 --- a/libdnf/utils/utils.cpp +++ b/libdnf/utils/utils.cpp @@ -1,6 +1,7 @@ #include "utils.hpp" #include "libdnf/dnf-sack-private.hpp" #include "libdnf/sack/advisorymodule.hpp" +#include #include @@ -311,6 +312,62 @@ void decompress(const char * inPath, const char * outPath, mode_t outMode, const fclose(inFile); } +void checksum(const char * type, const char * inPath, const char * checksum_valid, bool * valid_out, gchar ** calculated_out) +{ + GError * errP{nullptr}; + gboolean valid; + LrChecksumType lr_type = lr_checksum_type(type); + + if (lr_type == LR_CHECKSUM_UNKNOWN) + throw libdnf::Error(tfm::format("Unknown checksum type %s", type)); + + auto inFd = open(inPath, O_RDONLY); + + if (inFd == -1) + throw libdnf::Error(tfm::format("Error opening %s: %s", inPath, strerror(errno))); + + auto ret = lr_checksum_fd_compare(lr_type, + inFd, + /** + * If checksum_valid references a string, pass it in, else use + * an empty string + */ + checksum_valid ? checksum_valid : "", + /** + * https://github.com/rpm-software-management/librepo/issues/233 + * We must pass FALSE here because librepo has a simple bug that + * doesn't set calculated if the checksum is cached + */ + checksum_valid ? TRUE : FALSE, + &valid, + calculated_out, + &errP); + + close(inFd); + if (!ret) + throw libdnf::Error(tfm::format("Error calculating checksum %s: (%d, %s)", inPath, errP->code, errP->message)); + if (valid_out) + *valid_out = valid == TRUE; /* gboolean -> bool */ +} + + +bool checksum_check(const char * type, const char * inPath, const char * checksum_valid) +{ + bool valid; + checksum(type, inPath, checksum_valid, &valid, NULL); + return valid; +} + +std::string checksum_value(const char * type, const char * inPath) +{ + gchar * calculated; + checksum(type, inPath, NULL, NULL, &calculated); + std::string out(calculated); + // if checksum raises an exception, this string may not be freed properly. + g_free(calculated); + return out; +} + } namespace numeric { diff --git a/libdnf/utils/utils.hpp b/libdnf/utils/utils.hpp index d032dd42bb..fcb84fa3e3 100644 --- a/libdnf/utils/utils.hpp +++ b/libdnf/utils/utils.hpp @@ -66,6 +66,22 @@ std::vector getDirContent(const std::string &dirPath); * @param compressType Type of compression (".bz2", ".gz", ...), nullptr - detect from inPath filename. Defaults to nullptr. */ void decompress(const char * inPath, const char * outPath, mode_t outMode, const char * compressType = nullptr); + +/** +* @brief checksum file and return if matching. +* +* @param type Checksum type ("sha", "sha1", "sha256" etc). Raises libdnf::Error if invalid. +* @param inPath Path to input file +* @param valid_checksum hexadecimal encoded checksum string. +*/ +bool checksum_check(const char * type, const char * inPath, const char * valid_checksum); +/** +* @brief checksum file and return checksum. +* +* @param type Checksum type ("sha", "sha1", "sha256" etc). Raises libdnf::Error if invalid. +* @param inPath Path to input file +*/ +std::string checksum_value(const char * type, const char * inPath); } namespace numeric {