Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:matthewdva:dnf
libdnf
0011-revert-use-of-rpmdb-cookie.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0011-revert-use-of-rpmdb-cookie.patch of Package libdnf
diff --git a/libdnf/utils/crypto/CMakeLists.txt b/libdnf/utils/crypto/CMakeLists.txt new file mode 100644 index 0000000..149d100 --- /dev/null +++ b/libdnf/utils/crypto/CMakeLists.txt @@ -0,0 +1,5 @@ +set(UTILS_SOURCES + ${UTILS_SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/sha1.cpp + PARENT_SCOPE +) diff --git a/libdnf/utils/crypto/sha1.cpp b/libdnf/utils/crypto/sha1.cpp new file mode 100644 index 0000000..e13c1a7 --- /dev/null +++ b/libdnf/utils/crypto/sha1.cpp @@ -0,0 +1,34 @@ +#include <cstring> + +#include <iomanip> +#include <sstream> + +#include "sha1.hpp" + + +SHA1Hash::SHA1Hash() +{ + SHA1_Init(&ctx); +} + + +void +SHA1Hash::update(const char * data) +{ + SHA1_Update(&ctx, (unsigned char *)data, strlen(data)); +} + + +std::string +SHA1Hash::hexdigest() +{ + unsigned char md[digestLength]; + SHA1_Final(md, &ctx); + + std::stringstream ss; + for(int i=0; i<digestLength; i++) { + ss << std::setfill('0') << std::setw(2) << std::hex << static_cast<int>(md[i]); + } + + return ss.str(); +} diff --git a/libdnf/utils/crypto/sha1.hpp b/libdnf/utils/crypto/sha1.hpp new file mode 100644 index 0000000..e452f99 --- /dev/null +++ b/libdnf/utils/crypto/sha1.hpp @@ -0,0 +1,24 @@ +#include <string> +#include <openssl/sha.h> + + +/* +USAGE: + +SHA1Hash h; +h.update("foo"); +h.update("bar"); +std::cout << h.hexdigest() << std::endl; +*/ + + +class SHA1Hash { +public: + SHA1Hash(); + void update(const char *data); + std::string hexdigest(); + static constexpr int digestLength = SHA_DIGEST_LENGTH; + +private: + SHA_CTX ctx; +}; diff --git a/libdnf/dnf-sack.cpp b/libdnf/dnf-sack.cpp index 06ae8cb..e9e0828 100644 --- a/libdnf/dnf-sack.cpp +++ b/libdnf/dnf-sack.cpp @@ -80,6 +80,7 @@ extern "C" { #include "module/ModulePackage.hpp" #include "repo/Repo-private.hpp" #include "repo/solvable/DependencyContainer.hpp" +#include "utils/crypto/sha1.hpp" #include "utils/File.hpp" #include "utils/utils.hpp" #include "log.hpp" @@ -2603,3 +2604,42 @@ std::pair<std::vector<std::vector<std::string>>, libdnf::ModulePackageContainer: setModuleExcludes(sack, hotfixRepos, *moduleContainer); return ret; } + +std::string dnf_sack_get_rpmdb_version(DnfSack *sack) { + // collect all sha1hdr checksums + // they are sufficiently unique IDs that represent installed RPMs + std::vector<std::string> checksums; + + // iterate all @System repo RPMs (rpmdb records) + libdnf::Query query{sack, libdnf::Query::ExcludeFlags::IGNORE_EXCLUDES}; + query.addFilter(HY_PKG_REPONAME, HY_EQ, HY_SYSTEM_REPO_NAME); + + auto pset = query.getResultPset(); + Id id = -1; + while(true) { + id = pset->next(id); + if (id == -1) { + break; + } + DnfPackage *pkg = dnf_package_new(sack, id); + // store pkgid (equals to sha1hdr) + checksums.push_back(libdnf::string::fromCstring(dnf_package_get_pkgid(pkg))); + g_object_unref(pkg); + } + + // sort checksums to compute the output checksum always the same + std::sort(checksums.begin(), checksums.end()); + + SHA1Hash h; + for (auto & checksum : checksums) { + h.update(checksum.c_str()); + } + + // build <count>:<hash> output + std::ostringstream result; + result << checksums.size(); + result << ":"; + result << h.hexdigest(); + + return result.str(); +} diff --git a/libdnf/dnf-sack-private.hpp b/libdnf/dnf-sack-private.hpp index 2db9632..5dd1c50 100644 --- a/libdnf/dnf-sack-private.hpp +++ b/libdnf/dnf-sack-private.hpp @@ -81,4 +81,18 @@ std::pair<std::vector<std::vector<std::string>>, libdnf::ModulePackageContainer: std::vector<libdnf::ModulePackage *> requiresModuleEnablement(DnfSack * sack, const libdnf::PackageSet * installSet); +/** + * @brief Return fingerprint of installed RPMs. + * The format is <count>:<hash>. + * <count> is a count of installed RPMs. + * <hash> is a sha1 hash of sorted sha1hdr hashes of installed RPMs. + * + * The count can be computed from the command line by running: + * rpm -qa --qf='%{name}\n' | grep -v '^gpg-pubkey$' | wc -l + * + * The hash can be computed from the command line by running: + * rpm -qa --qf='%{name} %{sha1header}\n' | grep -v '^gpg-pubkey ' \ + * | cut -d ' ' -f 2 | LC_ALL=C sort | tr -d '\n' | sha1sum + */ +std::string dnf_sack_get_rpmdb_version(DnfSack *sack); #endif // HY_SACK_INTERNAL_H diff --git a/libdnf/dnf-transaction.cpp b/libdnf/dnf-transaction.cpp index d93c5ec..da363d7 100644 --- a/libdnf/dnf-transaction.cpp +++ b/libdnf/dnf-transaction.cpp @@ -1138,8 +1138,9 @@ dnf_transaction_commit(DnfTransaction *transaction, HyGoal goal, DnfState *state libdnf::Swdb *swdb = priv->swdb; PluginHookContextTransactionData data{PLUGIN_HOOK_ID_CONTEXT_PRE_TRANSACTION, transaction, goal, state}; DnfSack * sack = hy_goal_get_sack(goal); - std::unique_ptr<char, decltype(free)*> rpmdb_cookie_uptr{nullptr, free}; - std::string rpmdb_cookie; + DnfSack * rpmdb_version_sack = NULL; + std::string rpmdb_begin; + std::string rpmdb_end; /* take lock */ ret = dnf_state_take_lock(state, DNF_LOCK_TYPE_RPMDB, DNF_LOCK_MODE_PROCESS, error); @@ -1443,13 +1444,17 @@ dnf_transaction_commit(DnfTransaction *transaction, HyGoal goal, DnfState *state } } - rpmdb_cookie_uptr.reset(rpmdbCookie(rpmtsGetRdb(priv->ts))); - rpmdb_cookie = libdnf::string::fromCstring(rpmdb_cookie_uptr.get()); - if (rpmdb_cookie.empty()) { - g_critical(_("The rpmdbCookie() function did not return cookie of rpm database.")); - } // FIXME get commandline - swdb->beginTransaction(_get_current_time(), rpmdb_cookie, "", priv->uid); + if (sack) { + rpmdb_begin = dnf_sack_get_rpmdb_version(sack); + } else { + // if sack is not available, create a custom instance + rpmdb_version_sack = dnf_sack_new(); + dnf_sack_load_system_repo(rpmdb_version_sack, nullptr, DNF_SACK_LOAD_FLAG_NONE, nullptr); + rpmdb_begin = dnf_sack_get_rpmdb_version(rpmdb_version_sack); + g_object_unref(rpmdb_version_sack); + } + swdb->beginTransaction(_get_current_time(), rpmdb_begin, "", priv->uid); /* run the transaction */ priv->state = dnf_state_get_child(state); @@ -1489,12 +1494,15 @@ dnf_transaction_commit(DnfTransaction *transaction, HyGoal goal, DnfState *state if (!ret) goto out; - rpmdb_cookie_uptr.reset(rpmdbCookie(rpmtsGetRdb(priv->ts))); - rpmdb_cookie = libdnf::string::fromCstring(rpmdb_cookie_uptr.get()); - if (rpmdb_cookie.empty()) { - g_critical(_("The rpmdbCookie() function did not return cookie of rpm database.")); - } - swdb->endTransaction(_get_current_time(), rpmdb_cookie, libdnf::TransactionState::DONE); + + // finalize swdb transaction + // always load a new sack with rpmdb state after the transaction + rpmdb_version_sack = dnf_sack_new(); + dnf_sack_load_system_repo(rpmdb_version_sack, nullptr, DNF_SACK_LOAD_FLAG_NONE, nullptr); + rpmdb_end = dnf_sack_get_rpmdb_version(rpmdb_version_sack); + g_object_unref(rpmdb_version_sack); + + swdb->endTransaction(_get_current_time(), rpmdb_end.c_str(), libdnf::TransactionState::DONE); swdb->closeTransaction(); data.hookId = PLUGIN_HOOK_ID_CONTEXT_TRANSACTION; diff --git a/libdnf/utils/CMakeLists.txt b/libdnf/utils/CMakeLists.txt index 4ec456e..71a1042 100644 --- a/libdnf/utils/CMakeLists.txt +++ b/libdnf/utils/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(bgettext) +add_subdirectory(crypto) add_subdirectory(iniparser) add_subdirectory(regex) add_subdirectory(sqlite3)
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor