From 9aabff85daa82cdc4359b54260fb167e39d6ce12 Mon Sep 17 00:00:00 2001 From: panxiaohe Date: Mon, 11 Jan 2021 18:44:49 +0800 Subject: [PATCH] Deprecate Berkeley DB --- ...a-salvagedb-option-to-the-rpmdb-tool.patch | 164 ++++ ...c-call-at-the-end-of-a-database-rebu.patch | 33 + ...-and-path-of-main-database-file-to-d.patch | 98 ++ ...-for-reading-BDB-without-the-library.patch | 924 ++++++++++++++++++ ...initialize-the-entire-database-at-on.patch | 107 ++ ...precate-Berkeley-DB-database-backend.patch | 30 + ...-building-with-no-BerkeleyDB-support.patch | 33 + ...ge-dirent.h-compatibility-mess-from-.patch | 143 +++ backport-Handle-XZ-in-uncompress-macro.patch | 27 + ...ment-a-key-only-rpmdb-index-iterator.patch | 191 ++++ ...ding-the-keyring-once-the-rpmdb-is-o.patch | 41 + ...-database-queries-on-read-only-media.patch | 28 + ...imental-status-from-the-ndb-database.patch | 26 + ...ilure-when-trying-to-open-a-database.patch | 30 + ...b_ops-in-the-backends-too-where-poss.patch | 30 + ...end-struct-data-for-backend-configur.patch | 118 +++ backport-ndb-add-a-rpmpkgSalvage-method.patch | 219 +++++ ...t-ndb-add-a-rpmxdbDelAllBlobs-method.patch | 143 +++ backport-ndb-add-a-verify-method.patch | 93 ++ ...e-mapped-pointer-when-keeping-a-slot.patch | 45 + ...he-index-databases-read-write-all-th.patch | 106 ++ ...xdb-s-header-read-write-all-the-time.patch | 190 ++++ ...rop-unused-number-of-allocated-slots.patch | 38 + ...b-fix-ftruncate-return-value-warning.patch | 28 + ...dex-regeneration-if-the-index-is-out.patch | 80 ++ ...db-make-ordered-slots-flag-a-boolean.patch | 154 +++ ...ke-rpmxdbWriteHeader-a-void-function.patch | 39 + ...ger-free-the-pkgid-hash-all-the-time.patch | 70 ++ ...he-dbenv-in-the-rpmdb-if-the-last-re.patch | 6 +- ...b-remove-unused-lzo-compression-code.patch | 121 +++ ...header-when-closing-the-xdb-database.patch | 30 + ...ration-instead-of-the-current-time-i.patch | 99 ++ rpm.spec | 98 +- 33 files changed, 3549 insertions(+), 33 deletions(-) create mode 100644 backport-Add-a-salvagedb-option-to-the-rpmdb-tool.patch create mode 100644 backport-Add-an-index-sync-call-at-the-end-of-a-database-rebu.patch create mode 100644 backport-Add-backend-name-and-path-of-main-database-file-to-d.patch create mode 100644 backport-Add-support-for-reading-BDB-without-the-library.patch create mode 100644 backport-Always-open-and-initialize-the-entire-database-at-on.patch create mode 100644 backport-Deprecate-Berkeley-DB-database-backend.patch create mode 100644 backport-Fix-building-with-no-BerkeleyDB-support.patch create mode 100644 backport-Flush-1998-vintage-dirent.h-compatibility-mess-from-.patch create mode 100644 backport-Handle-XZ-in-uncompress-macro.patch create mode 100644 backport-Implement-a-key-only-rpmdb-index-iterator.patch create mode 100644 backport-Only-attempt-loading-the-keyring-once-the-rpmdb-is-o.patch create mode 100644 backport-Permit-ndb-database-queries-on-read-only-media.patch create mode 100644 backport-Remove-the-experimental-status-from-the-ndb-database.patch create mode 100644 backport-Stop-on-first-failure-when-trying-to-open-a-database.patch create mode 100644 backport-Use-paths-from-db_ops-in-the-backends-too-where-poss.patch create mode 100644 backport-Use-the-new-backend-struct-data-for-backend-configur.patch create mode 100644 backport-ndb-add-a-rpmpkgSalvage-method.patch create mode 100644 backport-ndb-add-a-rpmxdbDelAllBlobs-method.patch create mode 100644 backport-ndb-add-a-verify-method.patch create mode 100644 backport-ndb-also-copy-the-mapped-pointer-when-keeping-a-slot.patch create mode 100644 backport-ndb-do-not-map-the-index-databases-read-write-all-th.patch create mode 100644 backport-ndb-do-not-map-xdb-s-header-read-write-all-the-time.patch create mode 100644 backport-ndb-drop-unused-number-of-allocated-slots.patch create mode 100644 backport-ndb-fix-ftruncate-return-value-warning.patch create mode 100644 backport-ndb-implement-index-regeneration-if-the-index-is-out.patch create mode 100644 backport-ndb-make-ordered-slots-flag-a-boolean.patch create mode 100644 backport-ndb-make-rpmxdbWriteHeader-a-void-function.patch create mode 100644 backport-ndb-no-longer-free-the-pkgid-hash-all-the-time.patch create mode 100644 backport-ndb-remove-unused-lzo-compression-code.patch create mode 100644 backport-ndb-unmap-xdb-s-header-when-closing-the-xdb-database.patch create mode 100644 backport-ndb-use-the-generation-instead-of-the-current-time-i.patch diff --git a/backport-Add-a-salvagedb-option-to-the-rpmdb-tool.patch b/backport-Add-a-salvagedb-option-to-the-rpmdb-tool.patch new file mode 100644 index 0000000..7d62a80 --- /dev/null +++ b/backport-Add-a-salvagedb-option-to-the-rpmdb-tool.patch @@ -0,0 +1,164 @@ +From 243041f5fb68b68102243d713a1c5a3dc52698a2 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Mon, 3 Feb 2020 14:20:19 +0100 +Subject: [PATCH] Add a --salvagedb option to the rpmdb tool + +URL:https://github.com/rpm-software-management/rpm/commit/243041f5fb68b68102243d713a1c5a3dc52698a2 +--- + lib/backend/dbi.h | 1 + + lib/backend/ndb/glue.c | 7 +++++-- + lib/rpmdb.c | 7 +++++-- + lib/rpmdb_internal.h | 8 +++++++- + lib/rpmts.c | 8 ++++++-- + rpmdb.c | 6 ++++++ + 6 files changed, 30 insertions(+), 7 deletions(-) + +diff --git a/lib/backend/dbi.h b/lib/backend/dbi.h +index c4bf387..f70eb33 100644 +--- a/lib/backend/dbi.h ++++ b/lib/backend/dbi.h +@@ -10,6 +10,7 @@ enum rpmdbFlags { + RPMDB_FLAG_JUSTCHECK = (1 << 0), + RPMDB_FLAG_REBUILD = (1 << 1), + RPMDB_FLAG_VERIFYONLY = (1 << 2), ++ RPMDB_FLAG_SALVAGE = (1 << 3), + }; + + typedef enum dbCtrlOp_e { +diff --git a/lib/backend/ndb/glue.c b/lib/backend/ndb/glue.c +index d19da7c..ae30ceb 100644 +--- a/lib/backend/ndb/glue.c ++++ b/lib/backend/ndb/glue.c +@@ -128,8 +128,11 @@ static int ndb_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags) + rpmpkgdb pkgdb = 0; + char *path = rstrscat(NULL, dbhome, "/", rdb->db_ops->path, NULL); + rpmlog(RPMLOG_DEBUG, "opening db index %s mode=0x%x\n", path, rdb->db_mode); +- rc = rpmpkgOpen(&pkgdb, path, oflags, 0666); +- if (rc && errno == ENOENT) { ++ if ((rdb->db_flags & RPMDB_FLAG_SALVAGE) == 0) ++ rc = rpmpkgOpen(&pkgdb, path, oflags, 0666); ++ else ++ rc = rpmpkgSalvage(&pkgdb, path); ++ if (rc && errno == ENOENT && (rdb->db_flags & RPMDB_FLAG_SALVAGE) == 0) { + oflags = O_RDWR|O_CREAT; + dbi->dbi_flags |= DBI_CREATED; + rc = rpmpkgOpen(&pkgdb, path, oflags, 0666); +diff --git a/lib/rpmdb.c b/lib/rpmdb.c +index 91543eb..a072813 100644 +--- a/lib/rpmdb.c ++++ b/lib/rpmdb.c +@@ -2479,7 +2479,8 @@ static int rpmdbSetPermissions(char * src, char * dest) + } + + int rpmdbRebuild(const char * prefix, rpmts ts, +- rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg)) ++ rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg), ++ int rebuildflags) + { + rpmdb olddb; + char * dbpath = NULL; +@@ -2519,7 +2520,9 @@ int rpmdbRebuild(const char * prefix, rpmts ts, + } + + if (openDatabase(prefix, dbpath, &olddb, +- O_RDONLY, 0644, RPMDB_FLAG_REBUILD)) { ++ O_RDONLY, 0644, RPMDB_FLAG_REBUILD | ++ (rebuildflags & RPMDB_REBUILD_FLAG_SALVAGE ? ++ RPMDB_FLAG_SALVAGE : 0))) { + rc = 1; + goto exit; + } +diff --git a/lib/rpmdb_internal.h b/lib/rpmdb_internal.h +index 5ad844c..d7446e5 100644 +--- a/lib/rpmdb_internal.h ++++ b/lib/rpmdb_internal.h +@@ -23,6 +23,10 @@ extern "C" { + #undef HTKEYTYPE + #undef HTDATATYPE + ++enum rpmdbRebuildFlags_e { ++ RPMDB_REBUILD_FLAG_SALVAGE = (1 << 0), ++}; ++ + /** \ingroup rpmdb + * Reference a database instance. + * @param db rpm database +@@ -63,11 +67,13 @@ int rpmdbClose (rpmdb db); + * @param prefix path to top of install tree + * @param ts transaction set (or NULL) + * @param (*hdrchk) headerCheck() vector (or NULL) ++ * @param rebuildflags flags + * @return 0 on success + */ + RPM_GNUC_INTERNAL + int rpmdbRebuild(const char * prefix, rpmts ts, +- rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg)); ++ rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg), ++ int rebuildflags); + + /** \ingroup rpmdb + * Verify database components. +diff --git a/lib/rpmts.c b/lib/rpmts.c +index d0fdfbe..eb98da7 100644 +--- a/lib/rpmts.c ++++ b/lib/rpmts.c +@@ -135,17 +135,21 @@ int rpmtsRebuildDB(rpmts ts) + { + int rc = -1; + rpmtxn txn = NULL; ++ int rebuildflags = 0; + + /* Cannot do this on a populated transaction set */ + if (rpmtsNElements(ts) > 0) + return -1; + ++ if (rpmExpandNumeric("%{?_rebuilddb_salvage}")) ++ rebuildflags |= RPMDB_REBUILD_FLAG_SALVAGE; ++ + txn = rpmtxnBegin(ts, RPMTXN_WRITE); + if (txn) { + if (!(ts->vsflags & RPMVSF_NOHDRCHK)) +- rc = rpmdbRebuild(ts->rootDir, ts, headerCheck); ++ rc = rpmdbRebuild(ts->rootDir, ts, headerCheck, rebuildflags); + else +- rc = rpmdbRebuild(ts->rootDir, NULL, NULL); ++ rc = rpmdbRebuild(ts->rootDir, NULL, NULL, rebuildflags); + rpmtxnEnd(txn); + } + return rc; +diff --git a/rpmdb.c b/rpmdb.c +index 25c088d..b72f0a5 100644 +--- a/rpmdb.c ++++ b/rpmdb.c +@@ -12,6 +12,7 @@ enum modes { + MODE_VERIFYDB = (1 << 2), + MODE_EXPORTDB = (1 << 3), + MODE_IMPORTDB = (1 << 4), ++ MODE_SALVAGEDB = (1 << 5), + }; + + static int mode = 0; +@@ -24,6 +25,8 @@ static struct poptOption dbOptsTable[] = { + NULL}, + { "verifydb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR|POPT_ARGFLAG_DOC_HIDDEN), + &mode, MODE_VERIFYDB, N_("verify database files"), NULL}, ++ { "salvagedb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR|POPT_ARGFLAG_DOC_HIDDEN), ++ &mode, MODE_SALVAGEDB, N_("salvage database"), NULL}, + { "exportdb", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_EXPORTDB, + N_("export database to stdout header list"), + NULL}, +@@ -108,8 +111,11 @@ int main(int argc, char *argv[]) + ec = rpmtsInitDB(ts, 0644); + break; + case MODE_REBUILDDB: ++ case MODE_SALVAGEDB: + { rpmVSFlags vsflags = rpmExpandNumeric("%{_vsflags_rebuilddb}"); + rpmVSFlags ovsflags = rpmtsSetVSFlags(ts, vsflags); ++ if (mode == MODE_SALVAGEDB) ++ rpmDefineMacro(NULL, "_rebuilddb_salvage 1", 0); + ec = rpmtsRebuildDB(ts); + rpmtsSetVSFlags(ts, ovsflags); + } break; +-- +1.8.3.1 + diff --git a/backport-Add-an-index-sync-call-at-the-end-of-a-database-rebu.patch b/backport-Add-an-index-sync-call-at-the-end-of-a-database-rebu.patch new file mode 100644 index 0000000..90bd342 --- /dev/null +++ b/backport-Add-an-index-sync-call-at-the-end-of-a-database-rebu.patch @@ -0,0 +1,33 @@ +From de3f36acc91bf13e694bb479e8dbe0502a4cc4e1 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Tue, 14 Apr 2020 11:09:29 +0200 +Subject: [PATCH] Add an index sync call at the end of a database rebuild + +This is normally unneeded because an index sync is already done +after each package is added to the database. But rebuilding an +empty database lead to no index sync being done and a mismatch +between the generation count. This in turn will trigger a +index regeneration. + +Found by using ndb when running the test suite. + +URL:https://github.com/rpm-software-management/rpm/commit/de3f36acc91bf13e694bb479e8dbe0502a4cc4e1 +--- + lib/rpmdb.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/lib/rpmdb.c b/lib/rpmdb.c +index 57a3c3d..4c10156 100644 +--- a/lib/rpmdb.c ++++ b/lib/rpmdb.c +@@ -2578,6 +2578,7 @@ int rpmdbRebuild(const char * prefix, rpmts ts, + } + + rpmdbClose(olddb); ++ dbCtrl(newdb, DB_CTRL_INDEXSYNC); + rpmdbClose(newdb); + + if (failed) { +-- +1.8.3.1 + diff --git a/backport-Add-backend-name-and-path-of-main-database-file-to-d.patch b/backport-Add-backend-name-and-path-of-main-database-file-to-d.patch new file mode 100644 index 0000000..59b0737 --- /dev/null +++ b/backport-Add-backend-name-and-path-of-main-database-file-to-d.patch @@ -0,0 +1,98 @@ +From bc00f99cb0c6bc367bd198b3b0fdc7cd445737c5 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Mon, 21 Oct 2019 13:37:22 +0300 +Subject: [PATCH] Add backend name and path of main database file to db_ops + struct + +URL:https://github.com/rpm-software-management/rpm/commit/bc00f99cb0c6bc367bd198b3b0fdc7cd445737c5 +Conflict:delete the contents of lib/backend/sqlite.c, because we have no sqlite database. +--- + lib/backend/db3.c | 3 +++ + lib/backend/dbi.h | 5 ++++- + lib/backend/dummydb.c | 3 +++ + lib/backend/lmdb.c | 3 +++ + lib/backend/ndb/glue.c | 3 +++ + 5 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/lib/backend/db3.c b/lib/backend/db3.c +index ff1fc26..ab2f11f 100644 +--- a/lib/backend/db3.c ++++ b/lib/backend/db3.c +@@ -1365,6 +1365,9 @@ static unsigned int db3_pkgdbKey(dbiIndex dbi, dbiCursor dbc) + } + + struct rpmdbOps_s db3_dbops = { ++ .name = "bdb", ++ .path = "Packages", ++ + .open = db3_dbiOpen, + .close = db3_dbiClose, + .verify = db3_dbiVerify, +diff --git a/lib/backend/dbi.h b/lib/backend/dbi.h +index e9e42d8..a618ea2 100644 +--- a/lib/backend/dbi.h ++++ b/lib/backend/dbi.h +@@ -59,7 +59,7 @@ struct rpmdb_s { + dbiIndex * db_indexes; /*!< Tag indices. */ + int db_buildindex; /*!< Index rebuild indicator */ + +- struct rpmdbOps_s * db_ops; /*!< backend ops */ ++ const struct rpmdbOps_s * db_ops; /*!< backend ops */ + + /* dbenv and related parameters */ + void * db_dbenv; /*!< Backend private handle */ +@@ -245,6 +245,9 @@ RPM_GNUC_INTERNAL + const void * idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen); + + struct rpmdbOps_s { ++ const char *name; /* backend name */ ++ const char *path; /* main database name */ ++ + int (*open)(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags); + int (*close)(dbiIndex dbi, unsigned int flags); + int (*verify)(dbiIndex dbi, unsigned int flags); +diff --git a/lib/backend/dummydb.c b/lib/backend/dummydb.c +index 6137675..631b635 100644 +--- a/lib/backend/dummydb.c ++++ b/lib/backend/dummydb.c +@@ -88,6 +88,9 @@ static const void * dummydb_idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int * + + + struct rpmdbOps_s dummydb_dbops = { ++ .name = "dummy", ++ .path = NULL, ++ + .open = dummydb_Open, + .close = dummydb_Close, + .verify = dummydb_Verify, +diff --git a/lib/backend/lmdb.c b/lib/backend/lmdb.c +index f63fcb7..801f50e 100644 +--- a/lib/backend/lmdb.c ++++ b/lib/backend/lmdb.c +@@ -922,6 +922,9 @@ static unsigned int lmdb_pkgdbKey(dbiIndex dbi, dbiCursor dbc) + } + + struct rpmdbOps_s lmdb_dbops = { ++ .name = "lmdb", ++ .path = "data.mdb", ++ + .open = lmdb_dbiOpen, + .close = lmdb_dbiClose, + .verify = lmdb_dbiVerify, +diff --git a/lib/backend/ndb/glue.c b/lib/backend/ndb/glue.c +index b088a0b..d679ed1 100644 +--- a/lib/backend/ndb/glue.c ++++ b/lib/backend/ndb/glue.c +@@ -496,6 +496,9 @@ static const void * ndb_idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keyl + + + struct rpmdbOps_s ndb_dbops = { ++ .name = "ndb", ++ .path = "Packages.db", ++ + .open = ndb_Open, + .close = ndb_Close, + .verify = ndb_Verify, +-- +1.8.3.1 + diff --git a/backport-Add-support-for-reading-BDB-without-the-library.patch b/backport-Add-support-for-reading-BDB-without-the-library.patch new file mode 100644 index 0000000..62a9203 --- /dev/null +++ b/backport-Add-support-for-reading-BDB-without-the-library.patch @@ -0,0 +1,924 @@ +From 7cc9eb84a3b2baa0109be599572d78870e0dd3fe Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Thu, 19 Dec 2019 14:08:50 +0100 +Subject: [PATCH] Add support for reading BDB without the library + +This commit implements a read-only backend that allows accessing +of BerkeleyDB databases without using the BerkeleyDB library. +The code supports btree version 9-10 and hash version 8-10. + +There are two use cases for this: + +1) Conversion of an existing BerkeleyDB to a different + backend. + +2) Allowing package scriptlets to do database queries while + in a transaction that replaced rpm with a version that + no longer links against BerkeleyDB. + +If both BerkeleyDB and the read-only backend are enabled, rpm will +default to BerkeleyDB. + +URL:https://github.com/rpm-software-management/rpm/commit/7cc9eb84a3b2baa0109be599572d78870e0dd3fe +Conflict:delete the contents of ci/Dockerfile +--- + configure.ac | 14 + + lib/Makefile.am | 4 + + lib/backend/bdb_ro.c | 813 +++++++++++++++++++++++++++++++++++++++++++++++++++ + lib/backend/dbi.c | 3 + + lib/backend/dbi.h | 5 + + 5 files changed, 839 insertions(+) + create mode 100644 lib/backend/bdb_ro.c + +diff --git a/configure.ac b/configure.ac +index 2801b13..0257dde 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -595,6 +595,20 @@ AS_IF([test "$enable_ndb" = yes],[ + AM_CONDITIONAL([NDB], [test "$enable_ndb" = yes]) + + #================= ++# Process --enable-bdb-ro ++AC_ARG_ENABLE([bdb-ro], [AS_HELP_STRING([--enable-bdb-ro (EXPERIMENTAL)],[enable the read-only Berkeley DB code])], ++[case "$enable_bdb_ro" in ++yes|no) ;; ++*) AC_MSG_ERROR([invalid argument to --enable-bdb-ro]) ++ ;; ++esac], ++[enable_bdb_ro=no]) ++AS_IF([test "$enable_bdb_ro" = yes],[ ++ AC_DEFINE(WITH_BDB_RO, 1, [Build with read-only Berkeley DB]) ++]) ++AM_CONDITIONAL([BDB_RO], [test "$enable_bdb_ro" = yes]) ++ ++#================= + # Check for LMDB support + AC_ARG_ENABLE([lmdb], + [AS_HELP_STRING([--enable-lmdb=@<:@yes/no/auto@:>@ (EXPERIMENTAL)], +diff --git a/lib/Makefile.am b/lib/Makefile.am +index 349b5ca..2006d70 100644 +--- a/lib/Makefile.am ++++ b/lib/Makefile.am +@@ -68,6 +68,10 @@ librpm_la_LIBADD += @WITH_DB_LIB@ + endif + endif + ++if BDB_RO ++librpm_la_SOURCES += backend/bdb_ro.c ++endif ++ + if NDB + librpm_la_SOURCES += \ + backend/ndb/glue.c \ +diff --git a/lib/backend/bdb_ro.c b/lib/backend/bdb_ro.c +new file mode 100644 +index 0000000..74569cb +--- /dev/null ++++ b/lib/backend/bdb_ro.c +@@ -0,0 +1,813 @@ ++#include "system.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "lib/rpmdb_internal.h" ++#include ++#include ++ ++#define BDB_HASH 0 ++#define BDB_BTREE 1 ++ ++struct dbiCursor_s; ++ ++struct bdb_kv { ++ unsigned char *kv; ++ unsigned int len; ++}; ++ ++struct bdb_db { ++ int fd; /* file descriptor of database */ ++ int type; /* BDB_HASH / BDB_BTREE */ ++ unsigned int pagesize; ++ unsigned int lastpage; ++ int swapped; /* different endianess? */ ++ /* btree */ ++ unsigned int root; /* root page of the b-tree */ ++ /* hash */ ++ unsigned int maxbucket; ++ unsigned int highmask; ++ unsigned int lowmask; ++ unsigned int spares[32]; /* spare pages for each splitpoint */ ++}; ++ ++struct bdb_cur { ++ struct bdb_db *db; ++ ++ struct bdb_kv key; /* key and value from the db entry */ ++ struct bdb_kv val; ++ ++ unsigned char *page; /* the page we're looking at */ ++ ++ unsigned char *ovpage; ++ struct bdb_kv keyov; /* space to store oversized keys/values */ ++ struct bdb_kv valov; ++ ++ int state; /* 1: onpage, -1: error */ ++ int idx; /* entry index */ ++ int numidx; /* number of entries on the page */ ++ int islookup; /* we're doing a lookup operation */ ++ ++ /* hash */ ++ unsigned int bucket; /* current bucket */ ++}; ++ ++ ++static void swap16(unsigned char *p) ++{ ++ int a = p[0]; ++ p[0] = p[1]; ++ p[1] = a; ++} ++ ++static void swap32(unsigned char *p) ++{ ++ int a = p[0]; ++ p[0] = p[3]; ++ p[3] = a; ++ a = p[1]; ++ p[1] = p[2]; ++ p[2] = a; ++} ++ ++static void swap32_2(unsigned char *p) ++{ ++ swap32(p); ++ swap32(p + 4); ++} ++ ++static void bdb_swapmetapage(struct bdb_db *db, unsigned char *page) ++{ ++ int i, maxi = db->type == BDB_HASH ? 224 : 92; ++ for (i = 8; i < maxi; i += 4) ++ swap32((unsigned char *)(page + i)); ++ swap32((unsigned char *)(page + 24)); ++} ++ ++static void bdb_swappage(struct bdb_db *db, unsigned char *page) ++{ ++ unsigned int pagesize = db->pagesize; ++ int type, i, nent, off; ++ swap32(page + 8); /* page number */ ++ swap32_2(page + 12); /* prev/next page */ ++ swap16(page + 20); /* nitems */ ++ swap16(page + 22); /* highfree */ ++ ++ type = page[25]; ++ if (type != 2 && type != 13 && type != 3 && type != 5) ++ return; ++ nent = *(uint16_t *)(page + 20); ++ if (nent > (pagesize - 26) / 2) ++ nent = (pagesize - 26) / 2; ++ for (i = 0; i < nent; i++) { ++ int minoff = 26 + nent * 2; ++ swap16(page + 26 + i * 2); /* offset */ ++ off = *(uint16_t *)(page + 26 + i * 2); ++ if (off < minoff || off >= pagesize) ++ continue; ++ if (type == 2 || type == 13) { /* hash */ ++ if (page[off] == 3 && off + 12 <= pagesize) ++ swap32_2(page + off + 4); /* page no/length */ ++ } else if (type == 3) { /* btree internal */ ++ if (off + 12 > pagesize) ++ continue; ++ swap16(page + off); /* length */ ++ swap32_2(page + off + 4); /* page no/num recs */ ++ if (page[off + 2] == 3 && off + 24 <= pagesize) ++ swap32_2(page + off + 16); /* with overflow page/length */ ++ } else if (type == 5) { /* btree leaf */ ++ if (off + 3 <= pagesize && page[off + 2] == 1) ++ swap16(page + off); /* length */ ++ else if (off + 12 <= pagesize && page[off + 2] == 3) ++ swap32_2(page + off + 4); /* overflow page/length */ ++ } ++ } ++} ++ ++static int bdb_getpage(struct bdb_db *db, unsigned char *page, unsigned int pageno) ++{ ++ if (!pageno || pageno > db->lastpage) ++ return -1; ++ if (pread(db->fd, page, db->pagesize, (off_t)pageno * db->pagesize) != db->pagesize) { ++ rpmlog(RPMLOG_ERR, "pread: %s\n", strerror(errno)); ++ return -1; ++ } ++ if (db->swapped) ++ bdb_swappage(db, page); ++ if (pageno != *(uint32_t *)(page + 8)) ++ return -1; ++ return 0; ++} ++ ++static void bdb_close(struct bdb_db *db) ++{ ++ if (db->fd >= 0) ++ close(db->fd); ++ free(db); ++} ++ ++static struct bdb_db *bdb_open(const char *name) ++{ ++ uint32_t meta[512 / 4]; ++ int i, fd; ++ struct bdb_db *db; ++ ++ fd = open(name, O_RDONLY); ++ if (!fd) { ++ rpmlog(RPMLOG_ERR, "%s: %s\n", name, strerror(errno)); ++ return NULL; ++ } ++ db = xcalloc(1, sizeof(*db)); ++ db->fd = fd; ++ if (pread(fd, meta, 512, 0) != 512) { ++ rpmlog(RPMLOG_ERR, "%s: pread: %s\n", name, strerror(errno)); ++ bdb_close(db); ++ return NULL; ++ } ++ if (meta[3] == 0x00061561 || meta[3] == 0x61150600) { ++ db->type = BDB_HASH; ++ db->swapped = meta[3] == 0x61150600; ++ } else if (meta[3] == 0x00053162 || meta[3] == 0x62310500) { ++ db->type = BDB_BTREE; ++ db->swapped = meta[3] == 0x62310500; ++ } else { ++ rpmlog(RPMLOG_ERR, "%s: not a berkeley db hash/btree database\n", name); ++ bdb_close(db); ++ return NULL; ++ } ++ if (db->swapped) ++ bdb_swapmetapage(db, (unsigned char *)meta); ++ db->pagesize = meta[5]; ++ db->lastpage = meta[8]; ++ if (db->type == BDB_HASH) { ++ if (meta[4] < 8 || meta[4] > 10) { ++ rpmlog(RPMLOG_ERR, "%s: unsupported hash version %d\n", name, meta[4]); ++ bdb_close(db); ++ return NULL; ++ } ++ db->maxbucket = meta[18]; ++ db->highmask = meta[19]; ++ db->lowmask = meta[20]; ++ for (i = 0; i < 32; i++) ++ db->spares[i] = meta[24 + i]; ++ } ++ if (db->type == BDB_BTREE) { ++ if (meta[4] < 9 || meta[4] > 10) { ++ rpmlog(RPMLOG_ERR, "%s: unsupported btree version %d\n", name, meta[4]); ++ bdb_close(db); ++ return NULL; ++ } ++ db->root = meta[22]; ++ } ++ return db; ++} ++ ++ ++/****** overflow handling ******/ ++ ++static int ovfl_get(struct bdb_cur *cur, struct bdb_kv *kv, struct bdb_kv *ov, uint32_t *pagenolen) ++{ ++ unsigned int pageno = pagenolen[0]; ++ unsigned int len = pagenolen[1]; ++ unsigned int plen; ++ unsigned char *p; ++ ++ if (len == 0) ++ return -1; ++ if (len > ov->len) { ++ if (ov->kv) ++ ov->kv = xrealloc(ov->kv, len); ++ else ++ ov->kv = xmalloc(len); ++ ov->len = len; ++ } ++ if (!cur->ovpage) ++ cur->ovpage = xmalloc(cur->db->pagesize); ++ p = ov->kv; ++ while (len > 0) { ++ if (bdb_getpage(cur->db, cur->ovpage, pageno)) ++ return -1; ++ if (cur->ovpage[25] != 7) ++ return -1; ++ plen = *(uint16_t *)(cur->ovpage + 22); ++ if (plen + 26 > cur->db->pagesize || plen > len) ++ return -1; ++ memcpy(p, cur->ovpage + 26, plen); ++ p += plen; ++ len -= plen; ++ pageno = *(uint32_t *)(cur->ovpage + 16); ++ } ++ if (kv) { ++ kv->kv = ov->kv; ++ kv->len = pagenolen[1]; ++ } ++ return 0; ++} ++ ++ ++/****** hash implementation ******/ ++ ++static int hash_bucket_to_page(struct bdb_db *db, unsigned int bucket) ++{ ++ unsigned int b; ++ int i = 0; ++ for (b = bucket; b; b >>= 1) ++ i++; ++ return bucket + db->spares[i]; ++} ++ ++static int hash_lookup(struct bdb_cur *cur, const unsigned char *key, unsigned int keyl) ++{ ++ uint32_t bucket; ++ unsigned int pg, i; ++ cur->state = -1; ++ for (bucket = 0, i = 0; i < keyl; i++) ++ bucket = (bucket * 16777619) ^ key[i]; ++ bucket &= cur->db->highmask; ++ if (bucket > cur->db->maxbucket) ++ bucket &= cur->db->lowmask; ++ cur->bucket = bucket; ++ pg = hash_bucket_to_page(cur->db, bucket); ++ if (bdb_getpage(cur->db, cur->page, pg)) ++ return -1; ++ if (cur->page[25] != 8 && cur->page[25] != 13) ++ return -1; ++ cur->idx = (unsigned int)-2; ++ cur->numidx = *(uint16_t *)(cur->page + 20); ++ cur->state = 1; ++ return 0; ++} ++ ++static int hash_getkv(struct bdb_cur *cur, struct bdb_kv *kv, struct bdb_kv *ov, int off, int len) ++{ ++ if (len <= 0 || off + len > cur->db->pagesize) ++ return -1; ++ if (cur->page[off] == 1) { ++ kv->kv = cur->page + off + 1; ++ kv->len = len - 1; ++ } else if (cur->page[off] == 3) { ++ uint32_t ovlpage[2]; ++ if (len != 12) ++ return -1; ++ memcpy(ovlpage, cur->page + off + 4, 8); /* off is unaligned */ ++ if (ovfl_get(cur, kv, ov, ovlpage)) ++ return -1; ++ } else { ++ return -1; ++ } ++ return 0; ++} ++ ++static int hash_next(struct bdb_cur *cur) ++{ ++ int pagesize = cur->db->pagesize; ++ int koff, klen, voff, vlen; ++ if (!cur->state && hash_lookup(cur, 0, 0)) ++ return -1; ++ cur->idx += 2; ++ for (;;) { ++ if (cur->idx + 1 >= cur->numidx) { ++ unsigned int pg; ++ cur->idx = cur->numidx = 0; ++ pg = *(uint32_t *)(cur->page + 16); ++ if (!pg) { ++ if (cur->islookup || cur->bucket >= cur->db->maxbucket) ++ return 1; ++ pg = hash_bucket_to_page(cur->db, ++cur->bucket); ++ } ++ if (bdb_getpage(cur->db, cur->page, pg)) ++ return -1; ++ if (cur->page[25] != 8 && cur->page[25] != 13) ++ return -1; ++ cur->numidx = *(uint16_t *)(cur->page + 20); ++ continue; ++ } ++ koff = *(uint16_t *)(cur->page + 26 + 2 * cur->idx); ++ voff = *(uint16_t *)(cur->page + 28 + 2 * cur->idx); ++ if (koff >= pagesize || voff >= pagesize) ++ return -1; ++ if (cur->idx == 0) ++ klen = pagesize - koff; ++ else ++ klen = *(uint16_t *)(cur->page + 24 + 2 * cur->idx) - koff; ++ vlen = koff - voff; ++ if (hash_getkv(cur, &cur->key, &cur->keyov, koff, klen)) ++ return -1; ++ if (!cur->islookup && hash_getkv(cur, &cur->val, &cur->valov, voff, vlen)) ++ return -1; ++ return 0; ++ } ++} ++ ++static int hash_getval(struct bdb_cur *cur) ++{ ++ int koff, voff; ++ if (cur->state != 1 || cur->idx + 1 >= cur->numidx) ++ return -1; ++ koff = *(uint16_t *)(cur->page + 26 + 2 * cur->idx); ++ voff = *(uint16_t *)(cur->page + 28 + 2 * cur->idx); ++ return hash_getkv(cur, &cur->val, &cur->valov, voff, koff - voff); ++} ++ ++ ++/****** btree implementation ******/ ++ ++static int btree_lookup(struct bdb_cur *cur, const unsigned char *key, unsigned int keylen) ++{ ++ int pagesize = cur->db->pagesize; ++ int off, lastoff, idx, numidx; ++ unsigned int pg; ++ unsigned char *ekey; ++ unsigned int ekeylen; ++ int cmp; ++ ++ cur->state = -1; ++ pg = cur->db->root; ++ for (;;) { ++ if (bdb_getpage(cur->db, cur->page, pg)) ++ return -1; ++ if (cur->page[25] == 5) ++ break; /* found leaf page */ ++ if (cur->page[25] != 3) ++ return -1; ++ numidx = *(uint16_t *)(cur->page + 20); ++ if (!numidx) ++ return -1; ++ for (lastoff = 0, idx = 0; idx < numidx; idx++, lastoff = off) { ++ off = *(uint16_t *)(cur->page + 26 + 2 * idx); ++ if ((off & 3) != 0 || off + 3 > pagesize) ++ return -1; ++ ekeylen = *(uint16_t *)(cur->page + off); ++ if (off + 12 + ekeylen > pagesize) ++ return -1; ++ if (!keylen) { ++ lastoff = off; ++ break; ++ } ++ if (idx == 0) ++ continue; ++ ekey = cur->page + off + 12; ++ if ((cur->page[off + 2] & 0x7f) == 3) { ++ if (ekeylen != 12) ++ return -1; ++ if (ovfl_get(cur, 0, &cur->keyov, (uint32_t *)(ekey + 4))) ++ return -1; ++ ekeylen = *(uint32_t *)(ekey + 8); ++ ekey = cur->keyov.kv; ++ } else if ((cur->page[off + 2] & 0x7f) != 1) { ++ return -1; ++ } ++ cmp = memcmp(ekey, key, keylen < ekeylen ? keylen : ekeylen); ++ if (cmp > 0 || (cmp == 0 && ekeylen > keylen)) ++ break; ++ } ++ pg = *(uint32_t *)(cur->page + lastoff + 4); ++ } ++ cur->idx = (unsigned int)-2; ++ cur->numidx = *(uint16_t *)(cur->page + 20); ++ cur->state = 1; ++ return 0; ++} ++ ++static int btree_getkv(struct bdb_cur *cur, struct bdb_kv *kv, struct bdb_kv *ov, int off) ++{ ++ if ((off & 3) != 0) ++ return -1; ++ if (cur->page[off + 2] == 1) { ++ int len = *(uint16_t *)(cur->page + off); ++ if (off + 3 + len > cur->db->pagesize) ++ return -1; ++ kv->kv = cur->page + off + 3; ++ kv->len = len; ++ } else if (cur->page[off + 2] == 3) { ++ if (off + 12 > cur->db->pagesize) ++ return -1; ++ if (ovfl_get(cur, kv, ov, (uint32_t *)(cur->page + off + 4))) ++ return -1; ++ } else { ++ return -1; ++ } ++ return 0; ++} ++ ++static int btree_next(struct bdb_cur *cur) ++{ ++ int pagesize = cur->db->pagesize; ++ int koff, voff; ++ if (!cur->state && btree_lookup(cur, 0, 0)) ++ return -1; ++ cur->idx += 2; ++ for (;;) { ++ if (cur->idx + 1 >= cur->numidx) { ++ unsigned int pg; ++ cur->idx = cur->numidx = 0; ++ pg = *(uint32_t *)(cur->page + 16); ++ if (cur->islookup || !pg) ++ return 1; ++ if (bdb_getpage(cur->db, cur->page, pg)) ++ return -1; ++ if (cur->page[25] != 5) ++ return -1; ++ cur->numidx = *(uint16_t *)(cur->page + 20); ++ continue; ++ } ++ koff = *(uint16_t *)(cur->page + 26 + 2 * cur->idx); ++ voff = *(uint16_t *)(cur->page + 28 + 2 * cur->idx); ++ if (koff + 3 > pagesize || voff + 3 > pagesize) ++ return -1; ++ if ((cur->page[koff + 2] & 0x80) != 0 || (cur->page[voff + 2] & 0x80) != 0) ++ continue; /* ignore deleted */ ++ if (btree_getkv(cur, &cur->key, &cur->keyov, koff)) ++ return -1; ++ if (!cur->islookup && btree_getkv(cur, &cur->val, &cur->valov, voff)) ++ return -1; ++ return 0; ++ } ++} ++ ++static int btree_getval(struct bdb_cur *cur) ++{ ++ int voff; ++ if (cur->state != 1 || cur->idx + 1 >= cur->numidx) ++ return -1; ++ voff = *(uint16_t *)(cur->page + 28 + 2 * cur->idx); ++ return btree_getkv(cur, &cur->val, &cur->valov, voff); ++} ++ ++ ++/****** cursor functions ******/ ++ ++static struct bdb_cur *cur_open(struct bdb_db *db) ++{ ++ struct bdb_cur *cur = xcalloc(1, sizeof(*cur)); ++ cur->db = db; ++ cur->page = xmalloc(db->pagesize); ++ return cur; ++} ++ ++static void cur_close(struct bdb_cur *cur) ++{ ++ if (cur->page) ++ free(cur->page); ++ if (cur->ovpage) ++ free(cur->ovpage); ++ if (cur->keyov.kv) ++ free(cur->keyov.kv); ++ if (cur->valov.kv) ++ free(cur->valov.kv); ++ free(cur); ++} ++ ++static int cur_next(struct bdb_cur *cur) ++{ ++ if (cur->state < 0) ++ return -1; ++ if (cur->db->type == BDB_HASH) ++ return hash_next(cur); ++ if (cur->db->type == BDB_BTREE) ++ return btree_next(cur); ++ return -1; ++} ++ ++static int cur_getval(struct bdb_cur *cur) ++{ ++ if (cur->state < 0) ++ return -1; ++ if (cur->db->type == BDB_HASH) ++ return hash_getval(cur); ++ if (cur->db->type == BDB_BTREE) ++ return btree_getval(cur); ++ return -1; ++} ++ ++static int cur_lookup(struct bdb_cur *cur, const unsigned char *key, unsigned int keyl) ++{ ++ int r = -1; ++ if (cur->db->type == BDB_HASH) ++ r = hash_lookup(cur, key, keyl); ++ if (cur->db->type == BDB_BTREE) ++ r = btree_lookup(cur, key, keyl); ++ if (r != 0) ++ return r; ++ cur->islookup = 1; ++ while ((r = cur_next(cur)) == 0) ++ if (keyl == cur->key.len && !memcmp(key, cur->key.kv, keyl)) ++ break; ++ cur->islookup = 0; ++ if (r == 0) ++ r = cur_getval(cur); ++ return r; ++} ++ ++static int cur_lookup_ge(struct bdb_cur *cur, const unsigned char *key, unsigned int keyl) ++{ ++ int r = -1; ++ if (cur->db->type == BDB_BTREE) ++ r = btree_lookup(cur, key, keyl); ++ if (r != 0) ++ return r; ++ cur->islookup = 1; ++ while ((r = cur_next(cur)) == 0) { ++ unsigned int ekeyl = cur->key.len; ++ int cmp = memcmp(cur->key.kv, key, keyl < ekeyl ? keyl : ekeyl); ++ if (cmp > 0 || (cmp == 0 && ekeyl >= keyl)) ++ break; ++ } ++ cur->islookup = 0; ++ if (r == 0) ++ r = cur_getval(cur); ++ else if (r == 1) ++ r = cur_next(cur); ++ return r; ++} ++ ++/****** glue code ******/ ++ ++static unsigned int getui32(unsigned char *x, int swapped) ++{ ++ union _dbswap bs; ++ memcpy(bs.uc, x, 4); ++ if (swapped) ++ _DBSWAP(bs); ++ return bs.ui; ++} ++ ++static void setui32(unsigned char *x, uint32_t v, int swapped) ++{ ++ union _dbswap bs; ++ bs.ui = v; ++ if (swapped) ++ _DBSWAP(bs); ++ memcpy(x, bs.uc, 4); ++} ++ ++static void log_error(dbiIndex dbi) ++{ ++ rpmlog(RPMLOG_ERR, "bdb_ro error reading %s database\n", dbi->dbi_file); ++} ++ ++static int bdbro_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags) ++{ ++ const char *dbhome = rpmdbHome(rdb); ++ dbiIndex dbi = NULL; ++ char *path; ++ ++ if (dbip) ++ *dbip = NULL; ++ if ((rdb->db_mode & O_ACCMODE) != O_RDONLY) ++ return EPERM; ++ if ((dbi = dbiNew(rdb, rpmtag)) == NULL) ++ return 1; ++ path = rstrscat(NULL, dbhome, "/", dbi->dbi_file, NULL); ++ rpmlog(RPMLOG_DEBUG, "opening db index %s\n", path); ++ dbi->dbi_db = bdb_open(path); ++ if (!dbi->dbi_db) { ++ rpmlog(RPMLOG_ERR, "could not open %s: %s\n", path, strerror(errno)); ++ free(path); ++ dbiFree(dbi); ++ return 1; ++ } ++ free(path); ++ dbi->dbi_flags |= DBI_RDONLY; ++ if (dbip) ++ *dbip = dbi; ++ else ++ (void) dbiClose(dbi, 0); ++ return 0; ++} ++ ++static int bdbro_Close(dbiIndex dbi, unsigned int flags) ++{ ++ if (dbi->dbi_db) ++ bdb_close(dbi->dbi_db); ++ dbiFree(dbi); ++ return 0; ++} ++ ++static int bdbro_Verify(dbiIndex dbi, unsigned int flags) ++{ ++ return 0; ++} ++ ++static void bdbro_SetFSync(rpmdb rdb, int enable) ++{ ++} ++ ++static int bdbro_Ctrl(rpmdb rdb, dbCtrlOp ctrl) ++{ ++ return 0; ++} ++ ++static dbiCursor bdbro_CursorInit(dbiIndex dbi, unsigned int flags) ++{ ++ return dbi ? (void *)cur_open(dbi->dbi_db) : NULL; ++} ++ ++static dbiCursor bdbro_CursorFree(dbiIndex dbi, dbiCursor dbc) ++{ ++ if (dbc) ++ cur_close((void *)dbc); ++ return NULL; ++} ++ ++static void appenddbt(dbiCursor dbc, unsigned char *val, unsigned int vallen, dbiIndexSet *setp) ++{ ++ struct bdb_cur *cur = (void *)dbc; ++ dbiIndexSet set; ++ unsigned int i; ++ ++ set = dbiIndexSetNew(vallen / (2 * sizeof(uint32_t))); ++ set->count = vallen / (2 * sizeof(uint32_t)); ++ ++ for (i = 0; i < set->count; i++, val += 8) { ++ set->recs[i].hdrNum = getui32(val, cur->db->swapped); ++ set->recs[i].tagNum = getui32(val + 4, cur->db->swapped); ++ } ++ if (*setp == NULL) { ++ *setp = set; ++ } else { ++ dbiIndexSetAppendSet(*setp, set, 0); ++ dbiIndexSetFree(set); ++ } ++} ++ ++static rpmRC bdbro_idxdbPut(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h) ++{ ++ return RPMRC_FAIL; ++} ++ ++static rpmRC bdbro_idxdbDel(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h) ++{ ++ return RPMRC_FAIL; ++} ++ ++static rpmRC bdbro_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, ++ dbiIndexSet *set, int searchType) ++{ ++ struct bdb_cur *cur = (void *)dbc; ++ int r; ++ ++ if (!cur) ++ return RPMRC_FAIL; ++ if (searchType == DBC_PREFIX_SEARCH) { ++ rpmRC rc = RPMRC_NOTFOUND; ++ if (!keyp) ++ return RPMRC_FAIL; ++ r = cur_lookup_ge(cur, (const unsigned char *)keyp, keylen); ++ for (; r == 0; r = cur_next(cur)) { ++ if (cur->key.len < keylen || memcmp(cur->key.kv, keyp, keylen) != 0) ++ break; ++ if (set) ++ appenddbt(dbc, cur->val.kv, cur->val.len, set); ++ rc = RPMRC_OK; ++ } ++ if (r == -1) ++ log_error(dbi); ++ cur->key.kv = 0; ++ return r == -1 ? RPMRC_FAIL : rc; ++ } ++ if (keyp) { ++ if (keylen == 0) { ++ keyp = ""; ++ keylen = 1; ++ } ++ r = cur_lookup(cur, (const unsigned char *)keyp, keylen); ++ } else { ++ r = cur_next(cur); ++ } ++ if (r == 0) { ++ if (set) ++ appenddbt(dbc, cur->val.kv, cur->val.len, set); ++ return RPMRC_OK; ++ } ++ if (r == -1) ++ log_error(dbi); ++ cur->key.kv = 0; ++ return r == 1 ? RPMRC_NOTFOUND : RPMRC_FAIL; ++} ++ ++static const void *bdbro_idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen) ++{ ++ struct bdb_cur *cur = (void *)dbc; ++ if (!cur || !cur->key.kv) ++ return 0; ++ if (keylen) ++ *keylen = cur->key.len; ++ return cur->key.kv; ++} ++ ++static rpmRC bdbro_pkgdbPut(dbiIndex dbi, dbiCursor dbc, unsigned int *hdrNum, ++ unsigned char *hdrBlob, unsigned int hdrLen) ++{ ++ return RPMRC_FAIL; ++} ++ ++static rpmRC bdbro_pkgdbDel(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum) ++{ ++ return RPMRC_FAIL; ++} ++ ++static rpmRC bdbro_pkgdbGet(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum, ++ unsigned char **hdrBlob, unsigned int *hdrLen) ++{ ++ struct bdb_cur *cur = (void *)dbc; ++ int r; ++ if (hdrNum) { ++ unsigned char hdrkey[4]; ++ setui32(hdrkey, hdrNum, cur->db->swapped); ++ r = cur_lookup(cur, hdrkey, 4); ++ } else { ++ r = cur_next(cur); ++ } ++ if (r == 0) { ++ if (hdrBlob) ++ *hdrBlob = cur->val.kv; ++ if (hdrLen) ++ *hdrLen = cur->val.len; ++ return RPMRC_OK; ++ } ++ if (r == -1) ++ log_error(dbi); ++ cur->key.kv = 0; ++ return r == 1 ? RPMRC_NOTFOUND : RPMRC_FAIL; ++} ++ ++static unsigned int bdbro_pkgdbKey(dbiIndex dbi, dbiCursor dbc) ++{ ++ struct bdb_cur *cur = (void *)dbc; ++ if (!cur || !cur->key.kv || cur->key.len != 4) ++ return 0; ++ return getui32(cur->key.kv, cur->db->swapped); ++} ++ ++struct rpmdbOps_s bdbro_dbops = { ++ .name = "bdb_ro", ++ .path = "Packages", ++ ++ .open = bdbro_Open, ++ .close = bdbro_Close, ++ .verify = bdbro_Verify, ++ .setFSync = bdbro_SetFSync, ++ .ctrl = bdbro_Ctrl, ++ ++ .cursorInit = bdbro_CursorInit, ++ .cursorFree = bdbro_CursorFree, ++ ++ .pkgdbPut = bdbro_pkgdbPut, ++ .pkgdbDel = bdbro_pkgdbDel, ++ .pkgdbGet = bdbro_pkgdbGet, ++ .pkgdbKey = bdbro_pkgdbKey, ++ ++ .idxdbGet = bdbro_idxdbGet, ++ .idxdbPut = bdbro_idxdbPut, ++ .idxdbDel = bdbro_idxdbDel, ++ .idxdbKey = bdbro_idxdbKey ++}; ++ +diff --git a/lib/backend/dbi.c b/lib/backend/dbi.c +index 9b6c0a9..7841440 100644 +--- a/lib/backend/dbi.c ++++ b/lib/backend/dbi.c +@@ -25,6 +25,9 @@ const struct rpmdbOps_s *backends[] = { + #if defined(WITH_BDB) + &db3_dbops, + #endif ++#if defined(WITH_BDB_RO) ++ &bdbro_dbops, ++#endif + &dummydb_dbops, + NULL + }; +diff --git a/lib/backend/dbi.h b/lib/backend/dbi.h +index b2b9717..c4bf387 100644 +--- a/lib/backend/dbi.h ++++ b/lib/backend/dbi.h +@@ -274,6 +274,11 @@ RPM_GNUC_INTERNAL + extern struct rpmdbOps_s db3_dbops; + #endif + ++#if defined(WITH_BDB_RO) ++RPM_GNUC_INTERNAL ++extern struct rpmdbOps_s bdbro_dbops; ++#endif ++ + #ifdef ENABLE_NDB + RPM_GNUC_INTERNAL + extern struct rpmdbOps_s ndb_dbops; +-- +1.8.3.1 + diff --git a/backport-Always-open-and-initialize-the-entire-database-at-on.patch b/backport-Always-open-and-initialize-the-entire-database-at-on.patch new file mode 100644 index 0000000..50be0db --- /dev/null +++ b/backport-Always-open-and-initialize-the-entire-database-at-on.patch @@ -0,0 +1,107 @@ +From 8cd161b5bb9b639f5b729063272115436caab545 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Thu, 12 Mar 2020 11:42:15 +0200 +Subject: [PATCH] Always open (and initialize) the entire database at once + +In some scenarios we previously only created some of the indexes only +lazy db init through query. Partially initialized databases don't make +sense and are only asking for trouble, in particular this was causing +issues with sqlite backend which is stricter about readonly-mode. + +Except for the special case of reading a potentially damaged database +for rebuilding, always open all the indexes from openDatabase(). + +URL:https://github.com/rpm-software-management/rpm/commit/8cd161b5bb9b639f5b729063272115436caab545 +Conflict:context adaptation about openDatabase +--- + lib/rpmdb.c | 37 ++++++++++++++++++------------------- + 1 file changed, 18 insertions(+), 19 deletions(-) + +diff --git a/lib/rpmdb.c b/lib/rpmdb.c +index c5d8f49..073800b 100644 +--- a/lib/rpmdb.c ++++ b/lib/rpmdb.c +@@ -357,17 +357,22 @@ const char *rpmdbHome(rpmdb db) + return dbdir; + } + +-int rpmdbOpenAll(rpmdb db) ++static int doOpen(rpmdb db, int justPkgs) + { +- int rc = 0; ++ int rc = pkgdbOpen(db, db->db_flags, NULL); ++ if (!justPkgs) { ++ for (int dbix = 0; dbix < db->db_ndbi; dbix++) { ++ rc += indexOpen(db, db->db_tags[dbix], db->db_flags, NULL); ++ } ++ } ++ return rc; ++} + ++int rpmdbOpenAll(rpmdb db) ++{ + if (db == NULL) return -2; + +- rc = pkgdbOpen(db, db->db_flags, NULL); +- for (int dbix = 0; dbix < db->db_ndbi; dbix++) { +- rc += indexOpen(db, db->db_tags[dbix], db->db_flags, NULL); +- } +- return rc; ++ return doOpen(db, 0); + } + + static int dbiForeach(dbiIndex *dbis, int ndbi, +@@ -510,13 +515,16 @@ static int openDatabase(const char * prefix, + /* Try to ensure db home exists, error out if we can't even create */ + rc = rpmioMkpath(rpmdbHome(db), 0755, getuid(), getgid()); + if (rc == 0) { ++ /* Open just bare minimum when rebuilding a potentially damaged db */ ++ int justPkgs = (db->db_flags & RPMDB_FLAG_REBUILD) && ++ ((db->db_mode & O_ACCMODE) == O_RDONLY); + /* Enable signal queue on the first db open */ + if (db->db_next == NULL) { + rpmsqActivate(1); + } + +- /* Just the primary Packages database opened here */ +- rc = pkgdbOpen(db, db->db_flags, NULL); ++ rc = doOpen(db, justPkgs); ++ + } + + if (rc || justCheck || dbp == NULL) +@@ -554,10 +562,7 @@ int rpmdbInit (const char * prefix, int perms) + + rc = openDatabase(prefix, NULL, &db, (O_CREAT | O_RDWR), perms, 0); + if (db != NULL) { +- int xx; +- xx = rpmdbOpenAll(db); +- if (xx && rc == 0) rc = xx; +- xx = rpmdbClose(db); ++ int xx = rpmdbClose(db); + if (xx && rc == 0) rc = xx; + db = NULL; + } +@@ -573,8 +578,6 @@ int rpmdbVerify(const char * prefix) + + if (db != NULL) { + int xx; +- rc = rpmdbOpenAll(db); +- + + if (db->db_pkgs) + rc += dbiVerify(db->db_pkgs, 0); +@@ -2551,10 +2554,6 @@ int rpmdbRebuild(const char * prefix, rpmts ts, + rc = 1; + goto exit; + } +- if (rpmdbOpenAll(newdb)) { +- rc = 1; +- goto exit; +- } + + { Header h = NULL; + rpmdbMatchIterator mi; +-- +1.8.3.1 + diff --git a/backport-Deprecate-Berkeley-DB-database-backend.patch b/backport-Deprecate-Berkeley-DB-database-backend.patch new file mode 100644 index 0000000..08fc60b --- /dev/null +++ b/backport-Deprecate-Berkeley-DB-database-backend.patch @@ -0,0 +1,30 @@ +From fc0169eb03c893d63dc44f2ada954d42e0e759ed Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Mon, 23 Mar 2020 11:22:31 +0200 +Subject: [PATCH] Deprecate Berkeley DB database backend + +Berkeley DB 5.x is dead upstream ever since the license change some +seven years ago. Mark as deprecated for later removal now that we're +starting to have viable alternatives. + +URL:https://github.com/rpm-software-management/rpm/commit/fc0169eb03c893d63dc44f2ada954d42e0e759ed +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index d5ce5ef..bdfe2c6 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -533,7 +533,7 @@ AM_CONDITIONAL(HAVE_LIBDW_STRTAB,[test "$HAVE_LIBDW_STRTAB" = yes]) + #================= + # Check for BDB support + AC_ARG_ENABLE([bdb], +- [AS_HELP_STRING([--enable-bdb=@<:@yes/no/auto@:>@], ++ [AS_HELP_STRING([--enable-bdb=@<:@yes/no/auto@:>@ (DEPRECATED)], + [build with Berkeley DB rpm database format support (default=yes)])], + [enable_bdb="$enableval"], + [enable_bdb=yes]) +-- +1.8.3.1 + diff --git a/backport-Fix-building-with-no-BerkeleyDB-support.patch b/backport-Fix-building-with-no-BerkeleyDB-support.patch new file mode 100644 index 0000000..3535f40 --- /dev/null +++ b/backport-Fix-building-with-no-BerkeleyDB-support.patch @@ -0,0 +1,33 @@ +From 4c7323f69b4fddf928245e9db2d1c9ca9b277ef2 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Wed, 18 Dec 2019 17:42:31 +0100 +Subject: [PATCH] Fix building with no BerkeleyDB support + +The configure script used to define BDB even if BerkeleyDB has +been disabled. + +URL:https://github.com/rpm-software-management/rpm/commit/4c7323f69b4fddf928245e9db2d1c9ca9b277ef2 +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index de6034c..7a90b2f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -544,11 +544,11 @@ AC_ARG_ENABLE([bdb], + [enable_bdb="$enableval"], + [enable_bdb=yes]) + ++have_bdb="no" + AS_IF([test "x$enable_bdb" != "xno"], [ + if [ test -x db/dist/configure ]; then + have_bdb="internal" + else +- have_bdb="no" + AC_CHECK_HEADERS([db.h],[ + AC_PREPROC_IFELSE([ + AC_LANG_SOURCE([ +-- +1.8.3.1 + diff --git a/backport-Flush-1998-vintage-dirent.h-compatibility-mess-from-.patch b/backport-Flush-1998-vintage-dirent.h-compatibility-mess-from-.patch new file mode 100644 index 0000000..12950e1 --- /dev/null +++ b/backport-Flush-1998-vintage-dirent.h-compatibility-mess-from-.patch @@ -0,0 +1,143 @@ +From 7630389dcd3494c13b74b119cca37f97d2d8445a Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Mon, 30 Mar 2020 11:29:19 +0300 +Subject: [PATCH] Flush 1998 vintage dirent.h compatibility mess from system.h + +dirent.h and struct dirent are actually standard on this millenium, the +only thing that isn't is d_type member for which we have and retain +a specific test in configure.ac. Include where needed, +relatively few places do which makes it even a bigger insult to have +this included from system.h. + +URL:https://github.com/rpm-software-management/rpm/commit/7630389dcd3494c13b74b119cca37f97d2d8445a +--- + lib/backend/ndb/rpmpkg.c | 1 + + lib/backend/ndb/rpmxdb.c | 1 + + lib/rpmdb.c | 1 + + misc/fts.c | 1 + + rpmio/rpmglob.c | 5 ++--- + rpmio/rpmio.c | 1 + + system.h | 17 ----------------- + 7 files changed, 7 insertions(+), 20 deletions(-) + +diff --git a/lib/backend/ndb/rpmpkg.c b/lib/backend/ndb/rpmpkg.c +index b9cd67c..64d0493 100644 +--- a/lib/backend/ndb/rpmpkg.c ++++ b/lib/backend/ndb/rpmpkg.c +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + #include "rpmpkg.h" + +diff --git a/lib/backend/ndb/rpmxdb.c b/lib/backend/ndb/rpmxdb.c +index dbd4942..5136fbc 100644 +--- a/lib/backend/ndb/rpmxdb.c ++++ b/lib/backend/ndb/rpmxdb.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + + #include "rpmxdb.h" + +diff --git a/lib/rpmdb.c b/lib/rpmdb.c +index 3035e63..57a3c3d 100644 +--- a/lib/rpmdb.c ++++ b/lib/rpmdb.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + + #ifndef DYING /* XXX already in "system.h" */ + #include +diff --git a/misc/fts.c b/misc/fts.c +index 5c6f53d..b43f261 100644 +--- a/misc/fts.c ++++ b/misc/fts.c +@@ -68,6 +68,7 @@ static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; + #include "system.h" + #include + #include ++#include + #include + #include "misc/rpmfts.h" + # define __set_errno(val) (*__errno_location ()) = (val) +diff --git a/rpmio/rpmglob.c b/rpmio/rpmglob.c +index 3c497cb..93f7fa5 100644 +--- a/rpmio/rpmglob.c ++++ b/rpmio/rpmglob.c +@@ -26,6 +26,7 @@ + + #include + #include ++#include + #include + #include + #include /* S_ISDIR */ +@@ -75,8 +76,6 @@ typedef struct { + int (*gl_stat)(const char *, struct stat *); + } glob_t; + +-#define NAMLEN(_d) NLENGTH(_d) +- + #include + #ifndef __set_errno + #define __set_errno(val) errno = (val) +@@ -746,7 +745,7 @@ glob_in_dir(const char *pattern, const char *directory, int flags, + if (fnmatch(pattern, name, fnm_flags) == 0) { + struct globlink *new = (struct globlink *) + alloca(sizeof(struct globlink)); +- len = NAMLEN(d); ++ len = strlen(d->d_name); + new->name = (char *) xmalloc(len + 1); + *((char *) mempcpy(new->name, name, len)) + = '\0'; +diff --git a/rpmio/rpmio.c b/rpmio/rpmio.c +index 82c3302..aa1357c 100644 +--- a/rpmio/rpmio.c ++++ b/rpmio/rpmio.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #if defined(__linux__) + #include + #endif +diff --git a/system.h b/system.h +index 8854d70..f0122cb 100644 +--- a/system.h ++++ b/system.h +@@ -49,23 +49,6 @@ char * stpncpy(char * dest, const char * src, size_t n); + #include + #endif + +-#ifdef HAVE_DIRENT_H +-# include +-# define NLENGTH(direct) (strlen((direct)->d_name)) +-#else /* not HAVE_DIRENT_H */ +-# define dirent direct +-# define NLENGTH(direct) ((direct)->d_namlen) +-# ifdef HAVE_SYS_NDIR_H +-# include +-# endif /* HAVE_SYS_NDIR_H */ +-# ifdef HAVE_SYS_DIR_H +-# include +-# endif /* HAVE_SYS_DIR_H */ +-# ifdef HAVE_NDIR_H +-# include +-# endif /* HAVE_NDIR_H */ +-#endif /* HAVE_DIRENT_H */ +- + #if HAVE_LIMITS_H + #include + #endif +-- +1.8.3.1 + diff --git a/backport-Handle-XZ-in-uncompress-macro.patch b/backport-Handle-XZ-in-uncompress-macro.patch new file mode 100644 index 0000000..2e95ce9 --- /dev/null +++ b/backport-Handle-XZ-in-uncompress-macro.patch @@ -0,0 +1,27 @@ +From 3d63df622037796279514a4da3ddc6807a102c1d Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Fri, 27 Mar 2009 14:11:43 +0200 +Subject: [PATCH] Handle XZ in %uncompress macro - should've been in commit + 8078d0ba24662308b10d9eb0f0da978584b7e757 + +--- + rpmio/macro.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/rpmio/macro.c b/rpmio/macro.c +index c55b9e2..32eb6ec 100644 +--- a/rpmio/macro.c ++++ b/rpmio/macro.c +@@ -981,6 +981,9 @@ doFoo(MacroBuf mb, int negate, const char * f, size_t fn, + case COMPRESSED_LZMA: + sprintf(be, "%%__lzma -dc %s", b); + break; ++ case COMPRESSED_XZ: ++ sprintf(be, "%%__xz -dc %s", b); ++ break; + } + b = be; + } else if (STREQ("getenv", f, fn)) { +-- +1.8.3.1 + diff --git a/backport-Implement-a-key-only-rpmdb-index-iterator.patch b/backport-Implement-a-key-only-rpmdb-index-iterator.patch new file mode 100644 index 0000000..70030ee --- /dev/null +++ b/backport-Implement-a-key-only-rpmdb-index-iterator.patch @@ -0,0 +1,191 @@ +From 4eb7900d54609738d0d562ba7ac5f0d0f2ebf7e0 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Thu, 5 Dec 2019 14:22:08 +0200 +Subject: [PATCH] Implement a key-only rpmdb index iterator + +The regular index iterator grabs the associated data too, which we +don't always need. The data associated with indexes is relatively +lightweight, but as with everything, it adds up if in the millions scale. + +Update all backends to allow for NULL set in the index retrieve to +signal key-only retrieval. Ndb actually had an earlier, abandoned +implementation of the same idea under slightly different API, lets +reuse the code-block. + +URL:https://github.com/rpm-software-management/rpm/commit/4eb7900d54609738d0d562ba7ac5f0d0f2ebf7e0 +Conflict: delete the contents of lib/backend/sqlite.c, because we have no sqlite database. +--- + lib/backend/db3.c | 18 ++++++++++-------- + lib/backend/lmdb.c | 18 ++++++++++-------- + lib/backend/ndb/glue.c | 6 +++--- + lib/rpmdb.c | 11 ++++++++++- + lib/rpmdb.h | 8 ++++++++ + 5 files changed, 41 insertions(+), 20 deletions(-) + +diff --git a/lib/backend/db3.c b/lib/backend/db3.c +index ff0fe43..3e6d198 100644 +--- a/lib/backend/db3.c ++++ b/lib/backend/db3.c +@@ -1008,7 +1008,7 @@ static rpmRC db3_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t + dbiIndexSet *set, int searchType) + { + rpmRC rc = RPMRC_FAIL; /* assume failure */ +- if (dbi != NULL && dbc != NULL && set != NULL) { ++ if (dbi != NULL && dbc != NULL) { + int cflags = DB_NEXT; + int dbrc; + DBT data, key; +@@ -1033,12 +1033,14 @@ static rpmRC db3_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t + if (searchType == DBC_PREFIX_SEARCH && + (key.size < keylen || memcmp(key.data, keyp, keylen) != 0)) + break; +- dbt2set(dbi, &data, &newset); +- if (*set == NULL) { +- *set = newset; +- } else { +- dbiIndexSetAppendSet(*set, newset, 0); +- dbiIndexSetFree(newset); ++ if (set) { ++ dbt2set(dbi, &data, &newset); ++ if (*set == NULL) { ++ *set = newset; ++ } else { ++ dbiIndexSetAppendSet(*set, newset, 0); ++ dbiIndexSetFree(newset); ++ } + } + if (searchType != DBC_PREFIX_SEARCH) + break; +@@ -1048,7 +1050,7 @@ static rpmRC db3_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t + } + + /* fixup result status for prefix search */ +- if (searchType == DBC_PREFIX_SEARCH) { ++ if (searchType == DBC_PREFIX_SEARCH && set) { + if (dbrc == DB_NOTFOUND && *set != NULL && (*set)->count > 0) + dbrc = 0; + else if (dbrc == 0 && (*set == NULL || (*set)->count == 0)) +diff --git a/lib/backend/lmdb.c b/lib/backend/lmdb.c +index badd317..f5b94ce 100644 +--- a/lib/backend/lmdb.c ++++ b/lib/backend/lmdb.c +@@ -574,7 +574,7 @@ static rpmRC lmdb_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t + dbiIndexSet *set, int searchType) + { + rpmRC rc = RPMRC_FAIL; /* assume failure */ +- if (dbi != NULL && dbc != NULL && set != NULL) { ++ if (dbi != NULL && dbc != NULL) { + int cflags = MDB_NEXT; + int dbrc; + MDB_val key = { 0, NULL }; +@@ -598,12 +598,14 @@ static rpmRC lmdb_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t + if (searchType == DBC_PREFIX_SEARCH && + (key.mv_size < keylen || memcmp(key.mv_data, keyp, keylen) != 0)) + break; +- dbt2set(dbi, &data, &newset); +- if (*set == NULL) { +- *set = newset; +- } else { +- dbiIndexSetAppendSet(*set, newset, 0); +- dbiIndexSetFree(newset); ++ if (set) { ++ dbt2set(dbi, &data, &newset); ++ if (*set == NULL) { ++ *set = newset; ++ } else { ++ dbiIndexSetAppendSet(*set, newset, 0); ++ dbiIndexSetFree(newset); ++ } + } + if (searchType != DBC_PREFIX_SEARCH) + break; +@@ -613,7 +615,7 @@ static rpmRC lmdb_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t + } + + /* fixup result status for prefix search */ +- if (searchType == DBC_PREFIX_SEARCH) { ++ if (searchType == DBC_PREFIX_SEARCH && set) { + if (dbrc == MDB_NOTFOUND && *set != NULL && (*set)->count > 0) + dbrc = 0; + else if (dbrc == 0 && (*set == NULL || (*set)->count == 0)) +diff --git a/lib/backend/ndb/glue.c b/lib/backend/ndb/glue.c +index 03aaaa8..07ddb0a 100644 +--- a/lib/backend/ndb/glue.c ++++ b/lib/backend/ndb/glue.c +@@ -400,15 +400,15 @@ static rpmRC ndb_idxdbIter(dbiIndex dbi, dbiCursor dbc, dbiIndexSet *set) + } + k = dbc->listdata + dbc->list[dbc->ilist]; + kl = dbc->list[dbc->ilist + 1]; +-#if 0 +- if (searchType == DBC_KEY_SEARCH) { ++ ++ if (set == NULL) { + dbc->ilist += 2; + dbc->key = k; + dbc->keylen = kl; + rc = RPMRC_OK; + break; + } +-#endif ++ + pkglist = 0; + pkglistn = 0; + rc = rpmidxGet(dbc->dbi->dbi_db, k, kl, &pkglist, &pkglistn); +diff --git a/lib/rpmdb.c b/lib/rpmdb.c +index 9cd50e7..6317dd0 100644 +--- a/lib/rpmdb.c ++++ b/lib/rpmdb.c +@@ -298,6 +298,7 @@ struct rpmdbIndexIterator_s { + dbiCursor ii_dbc; + dbiIndexSet ii_set; + unsigned int *ii_hdrNums; ++ int ii_skipdata; + }; + + static rpmdb rpmdbRock; +@@ -1885,6 +1886,13 @@ rpmdbIndexIterator rpmdbIndexIteratorInit(rpmdb db, rpmDbiTag rpmtag) + return ii; + } + ++rpmdbIndexIterator rpmdbIndexKeyIteratorInit(rpmdb db, rpmDbiTag rpmtag) ++{ ++ rpmdbIndexIterator ki = rpmdbIndexIteratorInit(db, rpmtag); ++ ki->ii_skipdata = 1; ++ return ki; ++} ++ + int rpmdbIndexIteratorNext(rpmdbIndexIterator ii, const void ** key, size_t * keylen) + { + int rc; +@@ -1899,7 +1907,8 @@ int rpmdbIndexIteratorNext(rpmdbIndexIterator ii, const void ** key, size_t * ke + /* free old data */ + ii->ii_set = dbiIndexSetFree(ii->ii_set); + +- rc = idxdbGet(ii->ii_dbi, ii->ii_dbc, NULL, 0, &ii->ii_set, DBC_NORMAL_SEARCH); ++ rc = idxdbGet(ii->ii_dbi, ii->ii_dbc, NULL, 0, ++ ii->ii_skipdata ? NULL : &ii->ii_set, DBC_NORMAL_SEARCH); + + *key = idxdbKey(ii->ii_dbi, ii->ii_dbc, &iikeylen); + *keylen = iikeylen; +diff --git a/lib/rpmdb.h b/lib/rpmdb.h +index 75a722e..8e3ab5a 100644 +--- a/lib/rpmdb.h ++++ b/lib/rpmdb.h +@@ -154,6 +154,14 @@ Header rpmdbNextIterator(rpmdbMatchIterator mi); + rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi); + + /** \ingroup rpmdb ++ * Get an iterator for index keys ++ * @param db rpm database ++ * @param rpmtag the index to iterate over ++ * @return the index iterator ++ */ ++rpmdbIndexIterator rpmdbIndexKeyIteratorInit(rpmdb db, rpmDbiTag rpmtag); ++ ++/** \ingroup rpmdb + * Get an iterator for an index + * @param db rpm database + * @param rpmtag the index to iterate over +-- +1.8.3.1 + diff --git a/backport-Only-attempt-loading-the-keyring-once-the-rpmdb-is-o.patch b/backport-Only-attempt-loading-the-keyring-once-the-rpmdb-is-o.patch new file mode 100644 index 0000000..db9da9d --- /dev/null +++ b/backport-Only-attempt-loading-the-keyring-once-the-rpmdb-is-o.patch @@ -0,0 +1,41 @@ +From 3cb955b77f07c70ba01d765aa6377908847608f5 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Mon, 23 Nov 2020 13:46:14 +0200 +Subject: [PATCH] Only attempt loading the keyring once the rpmdb is open + +When we do lazy rpmdb open in rpmtsInitIterator(), we also do a lazy +keyring open. Except that since the keyring typically lives in the rpmdb, +we PROBABLY should try open the database first. One of those "WTF I've +been smoking" moments, lol. + +Prevents an ugly if mostly harmless double error anything we can't open +the database for one reason or another. + +URL:https://github.com/rpm-software-management/rpm/commit/3cb955b77f07c70ba01d765aa6377908847608f5 +--- + lib/rpmts.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/lib/rpmts.c b/lib/rpmts.c +index 9fa9cb0..8c8ae42 100644 +--- a/lib/rpmts.c ++++ b/lib/rpmts.c +@@ -177,12 +177,12 @@ rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmDbiTagVal rpmtag, + if (ts == NULL) + return NULL; + +- if (ts && ts->keyring == NULL) +- loadKeyring(ts); +- + if (ts->rdb == NULL && rpmtsOpenDB(ts, ts->dbmode)) + return NULL; + ++ if (ts->keyring == NULL) ++ loadKeyring(ts); ++ + /* Parse out "N(EVR)" tokens from a label key if present */ + if (rpmtag == RPMDBI_LABEL && keyp != NULL && strchr(keyp, '(')) { + const char *se, *s = keyp; +-- +1.8.3.1 + diff --git a/backport-Permit-ndb-database-queries-on-read-only-media.patch b/backport-Permit-ndb-database-queries-on-read-only-media.patch new file mode 100644 index 0000000..f54a755 --- /dev/null +++ b/backport-Permit-ndb-database-queries-on-read-only-media.patch @@ -0,0 +1,28 @@ +From 2d63d5ee78963a8f90dcdf93c461f89d326a5a18 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Mon, 3 Feb 2020 11:37:30 +0100 +Subject: [PATCH] Permit ndb database queries on read-only media + +See also commit a429c99e13fbe9926243f29b78df8d64222c4469 for db3. + +URL:https://github.com/rpm-software-management/rpm/commit/2d63d5ee78963a8f90dcdf93c461f89d326a5a18 +--- + lib/backend/ndb/glue.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/backend/ndb/glue.c b/lib/backend/ndb/glue.c +index 90c10f8..d19da7c 100644 +--- a/lib/backend/ndb/glue.c ++++ b/lib/backend/ndb/glue.c +@@ -161,7 +161,7 @@ static int ndb_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags) + /* Open indexes readwrite if possible */ + ioflags = O_RDWR; + rc = rpmxdbOpen(&ndbenv->xdb, rdb->db_pkgs->dbi_db, path, ioflags, 0666); +- if (rc && errno == EACCES) { ++ if (rc && (errno == EACCES || errno == EROFS)) { + /* If it is not asked for rw explicitly, try to open ro */ + if (!(oflags & O_RDWR)) { + ioflags = O_RDONLY; +-- +1.8.3.1 + diff --git a/backport-Remove-the-experimental-status-from-the-ndb-database.patch b/backport-Remove-the-experimental-status-from-the-ndb-database.patch new file mode 100644 index 0000000..f037eea --- /dev/null +++ b/backport-Remove-the-experimental-status-from-the-ndb-database.patch @@ -0,0 +1,26 @@ +From 7949d290b80aaebf7213e0b70a614d0d00585577 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Fri, 10 Jan 2020 15:56:59 +0100 +Subject: [PATCH] Remove the experimental status from the ndb database + +URL:https://github.com/rpm-software-management/rpm/commit/7949d290b80aaebf7213e0b70a614d0d00585577 +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index 7a90b2f..2801b13 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -581,7 +581,7 @@ fi + + #================= + # Process --enable-ndb +-AC_ARG_ENABLE([ndb], [AS_HELP_STRING([--enable-ndb (EXPERIMENTAL)],[enable the new rpm database format])], ++AC_ARG_ENABLE([ndb], [AS_HELP_STRING([--enable-ndb],[enable the new rpm database format])], + [case "$enable_ndb" in + yes|no) ;; + *) AC_MSG_ERROR([invalid argument to --enable-ndb]) +-- +1.8.3.1 + diff --git a/backport-Stop-on-first-failure-when-trying-to-open-a-database.patch b/backport-Stop-on-first-failure-when-trying-to-open-a-database.patch new file mode 100644 index 0000000..c763868 --- /dev/null +++ b/backport-Stop-on-first-failure-when-trying-to-open-a-database.patch @@ -0,0 +1,30 @@ +From fd054a40b2ba005571455d749de0423975e77651 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Wed, 18 Nov 2020 13:56:14 +0200 +Subject: [PATCH] Stop on first failure when trying to open a database + (RhBug:1898301) + +If an index open fails there's no point trying to go on, things are +not going to work and at least BDB will segfault in some cases... + +URL:https://github.com/rpm-software-management/rpm/commit/fd054a40b2ba005571455d749de0423975e77651 +--- + lib/rpmdb.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/rpmdb.c b/lib/rpmdb.c +index 874f079..41da9da 100644 +--- a/lib/rpmdb.c ++++ b/lib/rpmdb.c +@@ -355,7 +355,7 @@ static int doOpen(rpmdb db, int justPkgs) + { + int rc = pkgdbOpen(db, db->db_flags, NULL); + if (!justPkgs) { +- for (int dbix = 0; dbix < db->db_ndbi; dbix++) { ++ for (int dbix = 0; rc == 0 && dbix < db->db_ndbi; dbix++) { + rc += indexOpen(db, db->db_tags[dbix], db->db_flags, NULL); + } + } +-- +1.8.3.1 + diff --git a/backport-Use-paths-from-db_ops-in-the-backends-too-where-poss.patch b/backport-Use-paths-from-db_ops-in-the-backends-too-where-poss.patch new file mode 100644 index 0000000..793c2c9 --- /dev/null +++ b/backport-Use-paths-from-db_ops-in-the-backends-too-where-poss.patch @@ -0,0 +1,30 @@ +From 108adfc4d10b2158d38d599430275b149ad236c5 Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Mon, 21 Oct 2019 14:50:22 +0300 +Subject: [PATCH] Use paths from db_ops in the backends too where possible + +ndb and sqlite have control of their own paths, BDB and LMDB do things +differently and dummydb doesn't have a path at all. + +URL:https://github.com/rpm-software-management/rpm/commit/108adfc4d10b2158d38d599430275b149ad236c5 +Conflict: delete the contents of lib/backend/sqlite.c, because we have no sqlite database. +--- + lib/backend/ndb/glue.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/lib/backend/ndb/glue.c b/lib/backend/ndb/glue.c +index d679ed1..03aaaa8 100644 +--- a/lib/backend/ndb/glue.c ++++ b/lib/backend/ndb/glue.c +@@ -101,7 +101,7 @@ static int ndb_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags) + + if (dbi->dbi_type == DBI_PRIMARY) { + rpmpkgdb pkgdb = 0; +- char *path = rstrscat(NULL, dbhome, "/Packages.db", NULL); ++ char *path = rstrscat(NULL, dbhome, "/", rdb->db_ops->path, NULL); + rpmlog(RPMLOG_DEBUG, "opening db index %s mode=0x%x\n", path, rdb->db_mode); + rc = rpmpkgOpen(&pkgdb, path, oflags, 0666); + if (rc && errno == ENOENT) { +-- +1.8.3.1 + diff --git a/backport-Use-the-new-backend-struct-data-for-backend-configur.patch b/backport-Use-the-new-backend-struct-data-for-backend-configur.patch new file mode 100644 index 0000000..3133ed1 --- /dev/null +++ b/backport-Use-the-new-backend-struct-data-for-backend-configur.patch @@ -0,0 +1,118 @@ +From bc236cc369b8af9995dd50ba5263d354f47421ce Mon Sep 17 00:00:00 2001 +From: Panu Matilainen +Date: Mon, 21 Oct 2019 14:39:50 +0300 +Subject: [PATCH] Use the new backend struct data for backend configuration and + detection + +Refactor the hand-written separate tests into an array walk now that we can. +No functional changes, except that there's no more special fallback for BDB. + +URL:https://github.com/rpm-software-management/rpm/commit/bc236cc369b8af9995dd50ba5263d354f47421ce +Conflict:delete the contents of sqlite, because we have no sqlite database. +--- + lib/backend/dbi.c | 77 +++++++++++++++++++++++++------------------------------ + 1 file changed, 35 insertions(+), 42 deletions(-) + +diff --git a/lib/backend/dbi.c b/lib/backend/dbi.c +index 5e00310..a4a40a8 100644 +--- a/lib/backend/dbi.c ++++ b/lib/backend/dbi.c +@@ -12,6 +12,19 @@ + #include "lib/rpmdb_internal.h" + #include "debug.h" + ++const struct rpmdbOps_s *backends[] = { ++#if defined(WITH_LMDB) ++ &lmdb_dbops, ++#endif ++#ifdef ENABLE_NDB ++ &ndb_dbops, ++#endif ++#if defined(WITH_BDB) ++ &db3_dbops, ++#endif ++ &dummydb_dbops, ++ NULL ++}; + + dbiIndex dbiFree(dbiIndex dbi) + { +@@ -38,53 +51,33 @@ dbDetectBackend(rpmdb rdb) + const char *dbhome = rpmdbHome(rdb); + char *db_backend = rpmExpand("%{?_db_backend}", NULL); + char *path = NULL; ++ const struct rpmdbOps_s **ops; + +-#if defined(WITH_LMDB) +- if (!strcmp(db_backend, "lmdb")) { +- rdb->db_ops = &lmdb_dbops; +- } else +-#endif +-#ifdef ENABLE_NDB +- if (!strcmp(db_backend, "ndb")) { +- rdb->db_ops = &ndb_dbops; +- } else +-#endif +-#if defined(WITH_BDB) +- { +- rdb->db_ops = &db3_dbops; +- if (*db_backend == '\0') { +- free(db_backend); +- db_backend = xstrdup("bdb"); ++ for (ops = backends; ops && *ops; ops++) { ++ if (rstreq(db_backend, (*ops)->name)) { ++ rdb->db_ops = *ops; ++ break; + } + } +-#endif + +-#if defined(WITH_LMDB) +- path = rstrscat(NULL, dbhome, "/data.mdb", NULL); +- if (access(path, F_OK) == 0 && rdb->db_ops != &lmdb_dbops) { +- rdb->db_ops = &lmdb_dbops; +- rpmlog(RPMLOG_WARNING, _("Found LMDB data.mdb database while attempting %s backend: using lmdb backend.\n"), db_backend); +- } +- free(path); +-#endif +- +-#ifdef ENABLE_NDB +- path = rstrscat(NULL, dbhome, "/Packages.db", NULL); +- if (access(path, F_OK) == 0 && rdb->db_ops != &ndb_dbops) { +- rdb->db_ops = &ndb_dbops; +- rpmlog(RPMLOG_WARNING, _("Found NDB Packages.db database while attempting %s backend: using ndb backend.\n"), db_backend); +- } +- free(path); +-#endif +- +-#if defined(WITH_BDB) +- path = rstrscat(NULL, dbhome, "/Packages", NULL); +- if (access(path, F_OK) == 0 && rdb->db_ops != &db3_dbops) { +- rdb->db_ops = &db3_dbops; +- rpmlog(RPMLOG_WARNING, _("Found BDB Packages database while attempting %s backend: using bdb backend.\n"), db_backend); ++ for (ops = backends; ops && *ops; ops++) { ++ int stop = 0; ++ if ((*ops)->path == NULL) ++ continue; ++ ++ path = rstrscat(NULL, dbhome, "/", (*ops)->path, NULL); ++ if (access(path, F_OK) == 0 && rdb->db_ops != *ops) { ++ rpmlog(RPMLOG_WARNING, ++ _("Found %s %s database while attempting %s backend: " ++ "using %s backend.\n"), ++ (*ops)->name, (*ops)->path, db_backend, (*ops)->name); ++ rdb->db_ops = *ops; ++ stop = 1; ++ } ++ free(path); ++ if (stop) ++ break; + } +- free(path); +-#endif + + if (rdb->db_ops == NULL) { + rdb->db_ops = &dummydb_dbops; +-- +1.8.3.1 + diff --git a/backport-ndb-add-a-rpmpkgSalvage-method.patch b/backport-ndb-add-a-rpmpkgSalvage-method.patch new file mode 100644 index 0000000..3b7eb5d --- /dev/null +++ b/backport-ndb-add-a-rpmpkgSalvage-method.patch @@ -0,0 +1,219 @@ +From 6489957449fec63ddf330330e9435b4ee0c388b0 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Mon, 3 Feb 2020 14:18:23 +0100 +Subject: [PATCH] ndb: add a rpmpkgSalvage() method + +This can be used to recover as much data as possibly from a +terminally broken database. It works by scanning the database +file for entries that are not corrupt. + +URL:https://github.com/rpm-software-management/rpm/commit/6489957449fec63ddf330330e9435b4ee0c388b0 +--- + lib/backend/ndb/rpmpkg.c | 157 +++++++++++++++++++++++++++++++++++++++++++++-- + lib/backend/ndb/rpmpkg.h | 1 + + 2 files changed, 153 insertions(+), 5 deletions(-) + +diff --git a/lib/backend/ndb/rpmpkg.c b/lib/backend/ndb/rpmpkg.c +index 922ae11..b9cd67c 100644 +--- a/lib/backend/ndb/rpmpkg.c ++++ b/lib/backend/ndb/rpmpkg.c +@@ -30,8 +30,6 @@ typedef struct pkgslot_s { + + typedef struct rpmpkgdb_s { + int fd; /* our file descriptor */ +- int flags; +- int mode; + + int rdonly; + +@@ -885,8 +883,6 @@ int rpmpkgOpen(rpmpkgdb *pkgdbp, const char *filename, int flags, int mode) + return RPMRC_FAIL; + } + } +- pkgdb->flags = flags; +- pkgdb->mode = mode; + pkgdb->dofsync = 1; + *pkgdbp = pkgdb; + return RPMRC_OK; +@@ -908,6 +904,157 @@ void rpmpkgClose(rpmpkgdb pkgdb) + free(pkgdb); + } + ++ ++static unsigned int salvage_latest_blob(unsigned int *salvaged, unsigned int cnt) ++{ ++ unsigned int i, max = 0, maxi = 0; ++ for (i = 0; i < cnt - 1; i++) { ++ if (salvaged[i * 4 + 7] - salvaged[i * 4 + 3] > max) { ++ max = salvaged[i * 4 + 7] - salvaged[i * 4 + 3]; ++ maxi = i; ++ } ++ } ++ if ((unsigned int)(salvaged[3] - salvaged[i * 4 + 3]) > max) ++ maxi = cnt - 1; ++ return maxi; ++} ++ ++static int salvage_cmp(const void *av, const void *bv) ++{ ++ const unsigned int *a = av, *b = bv; ++ if (a[0] != b[0]) ++ return a[0] > b[0] ? 1 : -1; ++ if (a[3] != b[3]) ++ return a[3] > b[3] ? 1 : -1; ++ if (a[1] != b[1]) ++ return a[1] > b[1] ? 1 : -1; ++ return 0; ++} ++ ++#define SALVAGE_PAGESIZE 4096 ++#define SALVAGE_BLKCHUNK (SALVAGE_PAGESIZE / BLK_SIZE) ++ ++int rpmpkgSalvage(rpmpkgdb *pkgdbp, const char *filename) ++{ ++ struct stat stb; ++ rpmpkgdb pkgdb; ++ unsigned int blk, iblk, blkskip; ++ unsigned int blkoff, blkcnt, pkgidx, generation, bloblen; ++ unsigned int nfound, nslots, i, j; ++ unsigned char page[SALVAGE_PAGESIZE]; ++ unsigned int *salvaged; ++ ++ *pkgdbp = 0; ++ pkgdb = xcalloc(1, sizeof(*pkgdb)); ++ pkgdb->filename = xstrdup(filename); ++ pkgdb->rdonly = 1; ++ if ((pkgdb->fd = open(filename, O_RDONLY)) == -1) { ++ rpmpkgClose(pkgdb); ++ return RPMRC_FAIL; ++ } ++ if (rpmpkgGetLock(pkgdb, LOCK_SH)) { ++ rpmpkgClose(pkgdb); ++ return RPMRC_FAIL; ++ } ++ pkgdb->locked_shared++; ++ if (fstat(pkgdb->fd, &stb)) { ++ rpmpkgClose(pkgdb); ++ return RPMRC_FAIL; ++ } ++ if (stb.st_size < BLK_SIZE) { ++ rpmpkgClose(pkgdb); ++ return RPMRC_FAIL; ++ } ++ pkgdb->fileblks = stb.st_size / BLK_SIZE; ++ blkskip = 1; ++ nfound = 0; ++ salvaged = xmalloc(64 * (4 * sizeof(unsigned int))); ++ for (blk = 0; blk < pkgdb->fileblks; blk += SALVAGE_BLKCHUNK) { ++ unsigned int size; ++ unsigned char *bp = page; ++ if (pkgdb->fileblks - blk > SALVAGE_BLKCHUNK) ++ size = SALVAGE_PAGESIZE; ++ else ++ size = (pkgdb->fileblks - blk) * BLK_SIZE; ++ if (pread(pkgdb->fd, page, size, (off_t)blk * BLK_SIZE) != size) ++ continue; ++ if (size != SALVAGE_PAGESIZE) ++ memset(page + size, 0, SALVAGE_PAGESIZE - size); ++ if (blkskip) { ++ memset(page, 0, blkskip * BLK_SIZE); ++ blkskip = 0; ++ } ++ for (iblk = 0; iblk < SALVAGE_BLKCHUNK; iblk++, bp += BLK_SIZE) { ++ if (le2h(bp) != BLOBHEAD_MAGIC) ++ continue; ++ pkgidx = le2h(bp + 4); ++ if (!pkgidx) ++ continue; ++ generation = le2h(bp + 8); ++ bloblen = le2h(bp + 12); ++ blkoff = blk + iblk; ++ blkcnt = (BLOBHEAD_SIZE + bloblen + BLOBTAIL_SIZE + BLK_SIZE - 1) / BLK_SIZE; ++ if (blkoff + blkcnt > pkgdb->fileblks) ++ continue; ++ if (rpmpkgVerifyblob(pkgdb, pkgidx, blkoff, blkcnt)) ++ continue; ++ /* found a valid blob, add to salvaged list */ ++ if (nfound && (nfound & 63) == 0) ++ salvaged = xrealloc(salvaged, (nfound + 64) * (4 * sizeof(unsigned int))); ++ salvaged[nfound * 4 + 0] = pkgidx; ++ salvaged[nfound * 4 + 1] = blkoff; ++ salvaged[nfound * 4 + 2] = blkcnt; ++ salvaged[nfound * 4 + 3] = generation; ++ nfound++; ++ /* advance to after the blob! */ ++ blkoff += blkcnt; ++ if (blkoff >= blk + SALVAGE_BLKCHUNK) { ++ blkskip = blkoff % SALVAGE_BLKCHUNK; ++ blk = blkoff - blkskip - SALVAGE_BLKCHUNK; ++ break; ++ } else { ++ iblk = blkoff - blk - 1; ++ bp = page + iblk * BLK_SIZE; ++ } ++ } ++ } ++ /* now strip duplicate entries */ ++ nslots = 0; ++ if (nfound > 1) { ++ qsort(salvaged, nfound, sizeof(unsigned int) * 4, salvage_cmp); ++ for (i = 0; i < nfound; i++) { ++ pkgidx = salvaged[i * 4]; ++ for (j = i + 1; j < nfound; j++) ++ if (salvaged[j * 4] != pkgidx) ++ break; ++ if (j != i + 1) ++ i += salvage_latest_blob(salvaged + i * 4, j - i); ++ if (i != nslots) ++ memcpy(salvaged + nslots * 4, salvaged + i * 4, sizeof(unsigned int) * 4); ++ nslots++; ++ i = j - 1; ++ } ++ } ++ pkgdb->slots = xcalloc(nslots + 1, sizeof(*pkgdb->slots)); ++ for (i = 0; i < nslots; i++) { ++ pkgdb->slots[i].pkgidx = salvaged[i * 4 + 0]; ++ pkgdb->slots[i].blkoff = salvaged[i * 4 + 1]; ++ pkgdb->slots[i].blkcnt = salvaged[i * 4 + 2]; ++ pkgdb->slots[i].slotno = 0; ++ } ++ free(salvaged); ++ pkgdb->header_ok = 1; ++ pkgdb->nslots = nslots; ++ pkgdb->ordered = 0; ++ rpmpkgOrderSlots(pkgdb); ++ if (rpmpkgHashSlots(pkgdb)) { ++ rpmpkgClose(pkgdb); ++ return RPMRC_FAIL; ++ } ++ *pkgdbp = pkgdb; ++ return RPMRC_OK; ++} ++ + void rpmpkgSetFsync(rpmpkgdb pkgdb, int dofsync) + { + pkgdb->dofsync = dofsync; +@@ -1184,7 +1331,7 @@ int rpmpkgVerify(rpmpkgdb pkgdb) + + int rpmpkgNextPkgIdx(rpmpkgdb pkgdb, unsigned int *pkgidxp) + { +- if (rpmpkgLockReadHeader(pkgdb, 1)) ++ if (rpmpkgLockReadHeader(pkgdb, 1) || !pkgdb->nextpkgidx) + return RPMRC_FAIL; + *pkgidxp = pkgdb->nextpkgidx++; + if (rpmpkgWriteHeader(pkgdb)) { +diff --git a/lib/backend/ndb/rpmpkg.h b/lib/backend/ndb/rpmpkg.h +index 72d05c4..6466818 100644 +--- a/lib/backend/ndb/rpmpkg.h ++++ b/lib/backend/ndb/rpmpkg.h +@@ -2,6 +2,7 @@ struct rpmpkgdb_s; + typedef struct rpmpkgdb_s *rpmpkgdb; + + int rpmpkgOpen(rpmpkgdb *pkgdbp, const char *filename, int flags, int mode); ++int rpmpkgSalvage(rpmpkgdb *pkgdbp, const char *filename); + void rpmpkgClose(rpmpkgdb pkgdbp); + void rpmpkgSetFsync(rpmpkgdb pkgdbp, int dofsync); + +-- +1.8.3.1 + diff --git a/backport-ndb-add-a-rpmxdbDelAllBlobs-method.patch b/backport-ndb-add-a-rpmxdbDelAllBlobs-method.patch new file mode 100644 index 0000000..a454ea7 --- /dev/null +++ b/backport-ndb-add-a-rpmxdbDelAllBlobs-method.patch @@ -0,0 +1,143 @@ +From 49d43a334572199088ecc24ce6fc0e86c8699d2e Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Fri, 10 Jan 2020 15:49:16 +0100 +Subject: [PATCH] ndb: add a rpmxdbDelAllBlobs method + +This will delete all blobs (i.e. index databases) from the +ndb master index database. We do this kind of low-level on purpose, +so that it even works if the index database is corrupt. + +This will be used in the next commit which implements automatic +index regeneration if the index is out of sync. + +URL:https://github.com/rpm-software-management/rpm/commit/49d43a334572199088ecc24ce6fc0e86c8699d2e +--- + lib/backend/ndb/rpmxdb.c | 81 +++++++++++++++++++++++++++++++++++++----------- + lib/backend/ndb/rpmxdb.h | 1 + + 2 files changed, 64 insertions(+), 18 deletions(-) + +diff --git a/lib/backend/ndb/rpmxdb.c b/lib/backend/ndb/rpmxdb.c +index 2f94491..3baafa6 100644 +--- a/lib/backend/ndb/rpmxdb.c ++++ b/lib/backend/ndb/rpmxdb.c +@@ -224,11 +224,33 @@ static int usedslots_cmp(const void *a, const void *b) + return sa->startpage > sb->startpage ? 1 : -1; + } + ++static int rpmxdbReadHeaderRaw(rpmxdb xdb, unsigned int *generationp, unsigned int *slotnpagesp, unsigned int *pagesizep, unsigned int *usergenerationp) ++{ ++ unsigned int header[XDB_HEADER_SIZE / sizeof(unsigned int)]; ++ unsigned int version; ++ if (pread(xdb->fd, header, sizeof(header), 0) != sizeof(header)) ++ return RPMRC_FAIL; ++ if (le2ha((unsigned char *)header + XDB_OFFSET_MAGIC) != XDB_MAGIC) ++ return RPMRC_FAIL; ++ version = le2ha((unsigned char *)header + XDB_OFFSET_VERSION); ++ if (version != XDB_VERSION) { ++ rpmlog(RPMLOG_ERR, _("rpmxdb: Version mismatch. Expected version: %u. " ++ "Found version: %u\n"), XDB_VERSION, version); ++ return RPMRC_FAIL; ++ } ++ *generationp = le2ha((unsigned char *)header + XDB_OFFSET_GENERATION); ++ *slotnpagesp = le2ha((unsigned char *)header + XDB_OFFSET_SLOTNPAGES); ++ *pagesizep = le2ha((unsigned char *)header + XDB_OFFSET_PAGESIZE); ++ *usergenerationp = le2ha((unsigned char *)header + XDB_OFFSET_USERGENERATION); ++ if (!*slotnpagesp || !*pagesizep) ++ return RPMRC_FAIL; ++ return RPMRC_OK; ++} ++ + static int rpmxdbReadHeader(rpmxdb xdb) + { + struct xdb_slot *slot; +- unsigned int header[XDB_HEADER_SIZE / sizeof(unsigned int)]; +- unsigned int slotnpages, pagesize, generation, usergeneration, version; ++ unsigned int slotnpages, pagesize, generation, usergeneration; + unsigned int page, *lastfreep; + unsigned char *pageptr; + struct xdb_slot *slots, **usedslots, *lastslot; +@@ -246,23 +268,9 @@ static int rpmxdbReadHeader(rpmxdb xdb) + if (fstat(xdb->fd, &stb)) { + return RPMRC_FAIL; + } +- if (pread(xdb->fd, header, sizeof(header), 0) != sizeof(header)) { +- return RPMRC_FAIL; +- } +- if (le2ha((unsigned char *)header + XDB_OFFSET_MAGIC) != XDB_MAGIC) ++ if (rpmxdbReadHeaderRaw(xdb, &generation, &slotnpages, &pagesize, &usergeneration)) + return RPMRC_FAIL; +- version = le2ha((unsigned char *)header + XDB_OFFSET_VERSION); +- if (version != XDB_VERSION) { +- rpmlog(RPMLOG_ERR, _("rpmxdb: Version mismatch. Expected version: %u. " +- "Found version: %u\n"), XDB_VERSION, version); +- return RPMRC_FAIL; +- } +- +- generation = le2ha((unsigned char *)header + XDB_OFFSET_GENERATION); +- slotnpages = le2ha((unsigned char *)header + XDB_OFFSET_SLOTNPAGES); +- pagesize = le2ha((unsigned char *)header + XDB_OFFSET_PAGESIZE); +- usergeneration = le2ha((unsigned char *)header + XDB_OFFSET_USERGENERATION); +- if (!slotnpages || !pagesize || stb.st_size % pagesize != 0) ++ if (stb.st_size % pagesize != 0) + return RPMRC_FAIL; + xdb->pagesize = pagesize; + xdb->mapflags = xdb->rdonly ? PROT_READ : PROT_READ | PROT_WRITE; +@@ -923,6 +931,43 @@ int rpmxdbDelBlob(rpmxdb xdb, unsigned int id) + return RPMRC_OK; + } + ++int rpmxdbDelAllBlobs(rpmxdb xdb) ++{ ++ unsigned int slotnpages, pagesize, generation, usergeneration; ++ if (rpmxdbLockOnly(xdb, 1)) ++ return RPMRC_FAIL; ++ /* unmap all blobs */ ++ if (xdb->slots) { ++ int i; ++ struct xdb_slot *slot; ++ for (i = 1, slot = xdb->slots + i; i < xdb->nslots; i++, slot++) { ++ if (slot->startpage && slot->mapped) { ++ unmapslot(xdb, slot); ++ slot->mapcallback(xdb, slot->mapcallbackdata, 0, 0); ++ } ++ } ++ free(xdb->slots); ++ xdb->slots = 0; ++ } ++ if (xdb->mapped) ++ unmapheader(xdb); ++ if (rpmxdbReadHeaderRaw(xdb, &generation, &slotnpages, &pagesize, &usergeneration)) { ++ rpmxdbUnlock(xdb, 1); ++ return RPMRC_FAIL; ++ } ++ xdb->generation = generation + 1; ++ xdb->slotnpages = 1; ++ xdb->pagesize = pagesize; ++ xdb->usergeneration = usergeneration; ++ if (rpmxdbWriteEmptySlotpage(xdb, 0)) { ++ rpmxdbUnlock(xdb, 1); ++ return RPMRC_FAIL; ++ } ++ ftruncate(xdb->fd, xdb->pagesize); ++ rpmxdbUnlock(xdb, 1); ++ return RPMRC_OK; ++} ++ + int rpmxdbResizeBlob(rpmxdb xdb, unsigned int id, size_t newsize) + { + struct xdb_slot *slot; +diff --git a/lib/backend/ndb/rpmxdb.h b/lib/backend/ndb/rpmxdb.h +index 88a3e61..ddf02c1 100644 +--- a/lib/backend/ndb/rpmxdb.h ++++ b/lib/backend/ndb/rpmxdb.h +@@ -14,6 +14,7 @@ int rpmxdbUnlock(rpmxdb xdb, int excl); + + int rpmxdbLookupBlob(rpmxdb xdb, unsigned int *idp, unsigned int blobtag, unsigned int subtag, int flags); + int rpmxdbDelBlob(rpmxdb xdb, unsigned int id) ; ++int rpmxdbDelAllBlobs(rpmxdb xdb); + + int rpmxdbMapBlob(rpmxdb xdb, unsigned int id, int flags, void (*mapcallback)(rpmxdb xdb, void *data, void *newaddr, size_t newsize), void *mapcallbackdata); + int rpmxdbUnmapBlob(rpmxdb xdb, unsigned int id); +-- +1.8.3.1 + diff --git a/backport-ndb-add-a-verify-method.patch b/backport-ndb-add-a-verify-method.patch new file mode 100644 index 0000000..8c420de --- /dev/null +++ b/backport-ndb-add-a-verify-method.patch @@ -0,0 +1,93 @@ +From 3feb7993a800525395dca5a173ade5f8e4fbd8d5 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Fri, 10 Jan 2020 11:55:32 +0100 +Subject: [PATCH] ndb: add a verify method + +This adds a verify method for ndb's Packages.db database. The +Index.db database is currently not verified. + +URL:https://github.com/rpm-software-management/rpm/commit/3feb7993a800525395dca5a173ade5f8e4fbd8d5 +--- + lib/backend/ndb/glue.c | 8 +++++++- + lib/backend/ndb/rpmpkg.c | 26 ++++++++++++++++++++++++++ + lib/backend/ndb/rpmpkg.h | 1 + + 3 files changed, 34 insertions(+), 1 deletion(-) + +diff --git a/lib/backend/ndb/glue.c b/lib/backend/ndb/glue.c +index 07ddb0a..376e360 100644 +--- a/lib/backend/ndb/glue.c ++++ b/lib/backend/ndb/glue.c +@@ -179,7 +179,13 @@ static int ndb_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags) + + static int ndb_Verify(dbiIndex dbi, unsigned int flags) + { +- return 0; ++ int rc; ++ if (dbi->dbi_type == DBI_PRIMARY) { ++ rc = rpmpkgVerify(dbi->dbi_db); ++ } else { ++ rc = 0; /* cannot verify the index databases */ ++ } ++ return rc; + } + + static void ndb_SetFSync(rpmdb rdb, int enable) +diff --git a/lib/backend/ndb/rpmpkg.c b/lib/backend/ndb/rpmpkg.c +index b95f29f..2213872 100644 +--- a/lib/backend/ndb/rpmpkg.c ++++ b/lib/backend/ndb/rpmpkg.c +@@ -1101,6 +1101,22 @@ static int rpmpkgListInternal(rpmpkgdb pkgdb, unsigned int **pkgidxlistp, unsign + return RPMRC_OK; + } + ++static int rpmpkgVerifyInternal(rpmpkgdb pkgdb) ++{ ++ unsigned int i, nslots; ++ pkgslot *slot; ++ ++ if (rpmpkgReadSlots(pkgdb)) ++ return RPMRC_FAIL; ++ rpmpkgOrderSlots(pkgdb); ++ nslots = pkgdb->nslots; ++ for (i = 0, slot = pkgdb->slots; i < nslots; i++, slot++) { ++ if (rpmpkgVerifyblob(pkgdb, slot->pkgidx, slot->blkoff, slot->blkcnt)) ++ return RPMRC_FAIL; ++ } ++ return RPMRC_OK; ++} ++ + int rpmpkgGet(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned char **blobp, unsigned int *bloblp) + { + int rc; +@@ -1157,6 +1173,16 @@ int rpmpkgList(rpmpkgdb pkgdb, unsigned int **pkgidxlistp, unsigned int *npkgidx + return rc; + } + ++int rpmpkgVerify(rpmpkgdb pkgdb) ++{ ++ int rc; ++ if (rpmpkgLockReadHeader(pkgdb, 0)) ++ return RPMRC_FAIL; ++ rc = rpmpkgVerifyInternal(pkgdb); ++ rpmpkgUnlock(pkgdb, 0); ++ return rc; ++} ++ + int rpmpkgNextPkgIdx(rpmpkgdb pkgdb, unsigned int *pkgidxp) + { + if (rpmpkgLockReadHeader(pkgdb, 1)) +diff --git a/lib/backend/ndb/rpmpkg.h b/lib/backend/ndb/rpmpkg.h +index 7e5d0c6..72d05c4 100644 +--- a/lib/backend/ndb/rpmpkg.h ++++ b/lib/backend/ndb/rpmpkg.h +@@ -12,6 +12,7 @@ int rpmpkgGet(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned char **blobp, unsign + int rpmpkgPut(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned char *blob, unsigned int blobl); + int rpmpkgDel(rpmpkgdb pkgdb, unsigned int pkgidx); + int rpmpkgList(rpmpkgdb pkgdb, unsigned int **pkgidxlistp, unsigned int *npkgidxlistp); ++int rpmpkgVerify(rpmpkgdb pkgdb); + + int rpmpkgNextPkgIdx(rpmpkgdb pkgdb, unsigned int *pkgidxp); + int rpmpkgGeneration(rpmpkgdb pkgdb, unsigned int *generationp); +-- +1.8.3.1 + diff --git a/backport-ndb-also-copy-the-mapped-pointer-when-keeping-a-slot.patch b/backport-ndb-also-copy-the-mapped-pointer-when-keeping-a-slot.patch new file mode 100644 index 0000000..a0a3af6 --- /dev/null +++ b/backport-ndb-also-copy-the-mapped-pointer-when-keeping-a-slot.patch @@ -0,0 +1,45 @@ +From 85b51e2dcf2a0a6393d2fbc51b78d5398e5ffeed Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Tue, 14 Apr 2020 10:44:11 +0200 +Subject: [PATCH] ndb: also copy the mapped pointer when keeping a slot + +We forgot to copy the mapped pointer if a slot was kept when +re-syncing after a generation mismatch. This led to the mapped +pointer being zero even if the map callback was set. +Also add an extra test for the map callback before setting the +protection flag to PROT_READ. + +Found by testing the code with different mapping protection flags. +See the next commits. + +URL:https://github.com/rpm-software-management/rpm/commit/85b51e2dcf2a0a6393d2fbc51b78d5398e5ffeed +--- + lib/backend/ndb/rpmxdb.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/lib/backend/ndb/rpmxdb.c b/lib/backend/ndb/rpmxdb.c +index 5136fbc..354a098 100644 +--- a/lib/backend/ndb/rpmxdb.c ++++ b/lib/backend/ndb/rpmxdb.c +@@ -369,6 +369,8 @@ static int rpmxdbReadHeader(rpmxdb xdb) + nslot->mapcallback(xdb, nslot->mapcallbackdata, 0, 0); + } + } ++ } else { ++ nslot->mapped = slot->mapped; + } + } + } +@@ -624,7 +626,8 @@ static int moveblobto(rpmxdb xdb, struct xdb_slot *oldslot, struct xdb_slot *aft + didmap = 0; + oldpagecnt = oldslot->pagecnt; + if (!oldslot->mapped && oldpagecnt) { +- oldslot->mapflags = PROT_READ; ++ if (!oldslot->mapcallback) ++ oldslot->mapflags = PROT_READ; + if (mapslot(xdb, oldslot)) + return RPMRC_FAIL; + didmap = 1; +-- +1.8.3.1 + diff --git a/backport-ndb-do-not-map-the-index-databases-read-write-all-th.patch b/backport-ndb-do-not-map-the-index-databases-read-write-all-th.patch new file mode 100644 index 0000000..a796308 --- /dev/null +++ b/backport-ndb-do-not-map-the-index-databases-read-write-all-th.patch @@ -0,0 +1,106 @@ +From 3cfd298e9d03a7867118326fc60cc86fd7ea9b73 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Tue, 14 Apr 2020 10:58:34 +0200 +Subject: [PATCH] ndb: do not map the index databases read-write all the time + +Pass the flags to rpmidxOpenXdb and use read only mode if the +user specified O_RDONLY. We already did that for rpmidxOpen in +the past but we always used read-write mode when using the Xdb. + +We still open the Xdb itself in read-write mode so that we can +regenerate missing index databases. + +URL:https://github.com/rpm-software-management/rpm/commit/3cfd298e9d03a7867118326fc60cc86fd7ea9b73 +--- + lib/backend/ndb/glue.c | 11 ++++------- + lib/backend/ndb/rpmidx.c | 8 ++++++-- + lib/backend/ndb/rpmidx.h | 2 +- + 3 files changed, 11 insertions(+), 10 deletions(-) + +diff --git a/lib/backend/ndb/glue.c b/lib/backend/ndb/glue.c +index f69a46e..2bdfecc 100644 +--- a/lib/backend/ndb/glue.c ++++ b/lib/backend/ndb/glue.c +@@ -147,9 +147,6 @@ static int ndb_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags) + free(path); + dbi->dbi_db = ndbenv->pkgdb = pkgdb; + rpmpkgSetFsync(pkgdb, ndbenv->dofsync); +- +- if ((oflags & (O_RDWR | O_RDONLY)) == O_RDONLY) +- dbi->dbi_flags |= DBI_RDONLY; + } else { + unsigned int id; + rpmidxdb idxdb = 0; +@@ -188,20 +185,20 @@ static int ndb_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags) + ndb_CheckIndexSync(ndbenv->pkgdb, ndbenv->xdb); + } + if (rpmxdbLookupBlob(ndbenv->xdb, &id, rpmtag, 0, 0) == RPMRC_NOTFOUND) { ++ oflags = O_RDWR|O_CREAT; + dbi->dbi_flags |= DBI_CREATED; + } + rpmlog(RPMLOG_DEBUG, "opening db index %s tag=%d\n", dbiName(dbi), rpmtag); +- if (rpmidxOpenXdb(&idxdb, rdb->db_pkgs->dbi_db, ndbenv->xdb, rpmtag)) { ++ if (rpmidxOpenXdb(&idxdb, rdb->db_pkgs->dbi_db, ndbenv->xdb, rpmtag, oflags)) { + perror("rpmidxOpenXdb"); + ndb_Close(dbi, 0); + return 1; + } + dbi->dbi_db = idxdb; +- +- if (rpmxdbIsRdonly(ndbenv->xdb)) +- dbi->dbi_flags |= DBI_RDONLY; + } + ++ if ((oflags & (O_RDWR | O_RDONLY)) == O_RDONLY) ++ dbi->dbi_flags |= DBI_RDONLY; + + if (dbip != NULL) + *dbip = dbi; +diff --git a/lib/backend/ndb/rpmidx.c b/lib/backend/ndb/rpmidx.c +index 0ec8c8d..90b22d5 100644 +--- a/lib/backend/ndb/rpmidx.c ++++ b/lib/backend/ndb/rpmidx.c +@@ -885,13 +885,17 @@ int rpmidxOpen(rpmidxdb *idxdbp, rpmpkgdb pkgdb, const char *filename, int flags + return RPMRC_FAIL; + } + +-int rpmidxOpenXdb(rpmidxdb *idxdbp, rpmpkgdb pkgdb, rpmxdb xdb, unsigned int xdbtag) ++int rpmidxOpenXdb(rpmidxdb *idxdbp, rpmpkgdb pkgdb, rpmxdb xdb, unsigned int xdbtag, int flags) + { + rpmidxdb idxdb; + unsigned int id; + *idxdbp = 0; + int rc; + ++ if (rpmxdbIsRdonly(xdb) && (flags & (O_RDONLY|O_RDWR)) != O_RDONLY) { ++ errno = EACCES; ++ return RPMRC_FAIL; ++ } + if (rpmxdbLock(xdb, 0)) + return RPMRC_FAIL; + rc = rpmxdbLookupBlob(xdb, &id, xdbtag, IDXDB_XDB_SUBTAG, 0); +@@ -907,7 +911,7 @@ int rpmidxOpenXdb(rpmidxdb *idxdbp, rpmpkgdb pkgdb, rpmxdb xdb, unsigned int xdb + idxdb->xdbid = id; + idxdb->pkgdb = pkgdb; + idxdb->pagesize = rpmxdbPagesize(xdb); +- idxdb->rdonly = rpmxdbIsRdonly(xdb) ? 1 : 0; ++ idxdb->rdonly = (flags & (O_RDONLY|O_RDWR)) == O_RDONLY ? 1 : 0; + if (!id) { + if (rpmidxInit(idxdb)) { + free(idxdb); +diff --git a/lib/backend/ndb/rpmidx.h b/lib/backend/ndb/rpmidx.h +index e89bd82..9b01fb9 100644 +--- a/lib/backend/ndb/rpmidx.h ++++ b/lib/backend/ndb/rpmidx.h +@@ -5,7 +5,7 @@ struct rpmidxdb_s; + typedef struct rpmidxdb_s *rpmidxdb; + + int rpmidxOpen(rpmidxdb *idxdbp, rpmpkgdb pkgdb, const char *filename, int flags, int mode); +-int rpmidxOpenXdb(rpmidxdb *idxdbp, rpmpkgdb pkgdb, rpmxdb xdb, unsigned int xdbtag); ++int rpmidxOpenXdb(rpmidxdb *idxdbp, rpmpkgdb pkgdb, rpmxdb xdb, unsigned int xdbtag, int flags); + int rpmidxDelXdb(rpmpkgdb pkgdb, rpmxdb xdb, unsigned int xdbtag); + void rpmidxClose(rpmidxdb idxdbp); + +-- +1.8.3.1 + diff --git a/backport-ndb-do-not-map-xdb-s-header-read-write-all-the-time.patch b/backport-ndb-do-not-map-xdb-s-header-read-write-all-the-time.patch new file mode 100644 index 0000000..e1e1a65 --- /dev/null +++ b/backport-ndb-do-not-map-xdb-s-header-read-write-all-the-time.patch @@ -0,0 +1,190 @@ +From aea8c86ec8a73d34f26c77ad40179df92970260f Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Tue, 14 Apr 2020 11:07:31 +0200 +Subject: [PATCH] ndb: do not map xdb's header read-write all the time + +Instead just map it read-write if one of the functions request +exclusive access. We keep track of the number of exclusive +locks and fall back to read-only mapping if the count reaches +zero again. + +URL:https://github.com/rpm-software-management/rpm/commit/aea8c86ec8a73d34f26c77ad40179df92970260f +--- + lib/backend/ndb/rpmxdb.c | 55 +++++++++++++++++++++++++++++++++++------------- + 1 file changed, 40 insertions(+), 15 deletions(-) + +diff --git a/lib/backend/ndb/rpmxdb.c b/lib/backend/ndb/rpmxdb.c +index 354a098..ec408f8 100644 +--- a/lib/backend/ndb/rpmxdb.c ++++ b/lib/backend/ndb/rpmxdb.c +@@ -37,7 +37,7 @@ typedef struct rpmxdb_s { + unsigned int usergeneration; + + unsigned char *mapped; +- int mapflags; ++ int mappedrw; + unsigned int mappedlen; + + struct xdb_slot { +@@ -58,6 +58,7 @@ typedef struct rpmxdb_s { + unsigned int usedblobpages; + unsigned int systempagesize; + int dofsync; ++ unsigned int locked_excl; + } *rpmxdb; + + +@@ -126,17 +127,19 @@ static void unmapmem(void *addr, size_t size) + #define ROUNDTOSYSTEMPAGE(xdb, size) (((size) + (xdb->systempagesize - 1)) & ~(xdb->systempagesize - 1)) + + /* xdb header mapping functions */ +-static int mapheader(rpmxdb xdb, unsigned int slotnpages) ++static int mapheader(rpmxdb xdb, unsigned int slotnpages, int rw) + { + unsigned char *mapped; + size_t mappedlen = slotnpages * xdb->pagesize; ++ int mapflags = rw ? PROT_READ | PROT_WRITE : PROT_READ; + + mappedlen = ROUNDTOSYSTEMPAGE(xdb, mappedlen); +- mapped = mapmem(xdb->mapped, xdb->mappedlen, mappedlen, xdb->mapflags, xdb->fd, 0); ++ mapped = mapmem(xdb->mapped, xdb->mappedlen, mappedlen, mapflags, xdb->fd, 0); + if ((void *)mapped == MAP_FAILED) + return RPMRC_FAIL; + xdb->mapped = mapped; + xdb->mappedlen = mappedlen; ++ xdb->mappedrw = rw; + return RPMRC_OK; + } + +@@ -248,7 +251,7 @@ static int rpmxdbReadHeaderRaw(rpmxdb xdb, unsigned int *generationp, unsigned i + return RPMRC_OK; + } + +-static int rpmxdbReadHeader(rpmxdb xdb) ++static int rpmxdbReadHeader(rpmxdb xdb, int rw) + { + struct xdb_slot *slot; + unsigned int slotnpages, pagesize, generation, usergeneration; +@@ -262,6 +265,11 @@ static int rpmxdbReadHeader(rpmxdb xdb) + + if (xdb->mapped) { + if (le2ha(xdb->mapped + XDB_OFFSET_GENERATION) == xdb->generation) { ++ if (rw && !xdb->mappedrw) { ++ unmapheader(xdb); ++ if (mapheader(xdb, xdb->slotnpages, rw)) ++ return RPMRC_FAIL; ++ } + return RPMRC_OK; + } + unmapheader(xdb); +@@ -274,9 +282,8 @@ static int rpmxdbReadHeader(rpmxdb xdb) + if (stb.st_size % pagesize != 0) + return RPMRC_FAIL; + xdb->pagesize = pagesize; +- xdb->mapflags = xdb->rdonly ? PROT_READ : PROT_READ | PROT_WRITE; + +- if (mapheader(xdb, slotnpages)) ++ if (mapheader(xdb, slotnpages, rw)) + return RPMRC_FAIL; + + /* read in all slots */ +@@ -476,19 +483,25 @@ static int rpmxdbInitInternal(rpmxdb xdb) + /* we use the master pdb for locking */ + static int rpmxdbLockOnly(rpmxdb xdb, int excl) + { ++ int rc; + if (excl && xdb->rdonly) + return RPMRC_FAIL; +- return rpmpkgLock(xdb->pkgdb, excl); ++ rc = rpmpkgLock(xdb->pkgdb, excl); ++ if (!rc && excl) ++ xdb->locked_excl++; ++ return rc; + } + +-/* this is the same as rpmxdbLockReadHeader. It does the ++/* This is similar to rpmxdbLockReadHeader. It does the + * ReadHeader to sync the mappings if xdb moved some blobs. ++ * Note that we just ask for rad-only access in the ++ * rpmxdbReadHeader call. + */ + int rpmxdbLock(rpmxdb xdb, int excl) + { + if (rpmxdbLockOnly(xdb, excl)) + return RPMRC_FAIL; +- if (rpmxdbReadHeader(xdb)) { ++ if (rpmxdbReadHeader(xdb, 0)) { + rpmxdbUnlock(xdb, excl); + return RPMRC_FAIL; + } +@@ -497,14 +510,25 @@ int rpmxdbLock(rpmxdb xdb, int excl) + + int rpmxdbUnlock(rpmxdb xdb, int excl) + { ++ if (excl && xdb->locked_excl) { ++ xdb->locked_excl--; ++ if (!xdb->locked_excl && xdb->mapped && xdb->mappedrw) { ++ unmapheader(xdb); ++ mapheader(xdb, xdb->slotnpages, 0); ++ } ++ } + return rpmpkgUnlock(xdb->pkgdb, excl); + } + ++/* Like rpmxdbLock, but map the header rw if excl is set. ++ * This is what the functions in this module use, whereas ++ * rpmidx uses rpmxdbLock. ++ */ + static int rpmxdbLockReadHeader(rpmxdb xdb, int excl) + { + if (rpmxdbLockOnly(xdb, excl)) + return RPMRC_FAIL; +- if (rpmxdbReadHeader(xdb)) { ++ if (rpmxdbReadHeader(xdb, excl)) { + rpmxdbUnlock(xdb, excl); + return RPMRC_FAIL; + } +@@ -776,7 +800,7 @@ static int addslotpage(rpmxdb xdb) + return RPMRC_FAIL; + + /* remap the header */ +- if (mapheader(xdb, xdb->slotnpages + 1)) ++ if (mapheader(xdb, xdb->slotnpages + 1, xdb->mappedrw)) + return RPMRC_FAIL; + + /* update the header */ +@@ -856,7 +880,8 @@ int rpmxdbLookupBlob(rpmxdb xdb, unsigned int *idp, unsigned int blobtag, unsign + { + struct xdb_slot *slot; + unsigned int i, nslots; +- if (rpmxdbLockReadHeader(xdb, flags ? 1 : 0)) ++ int excl = flags ? 1 : 0; ++ if (rpmxdbLockReadHeader(xdb, excl)) + return RPMRC_FAIL; + nslots = xdb->nslots; + slot = 0; +@@ -869,18 +894,18 @@ int rpmxdbLookupBlob(rpmxdb xdb, unsigned int *idp, unsigned int blobtag, unsign + i = 0; + if (i && (flags & O_TRUNC) != 0) { + if (rpmxdbResizeBlob(xdb, i, 0)) { +- rpmxdbUnlock(xdb, flags ? 1 : 0); ++ rpmxdbUnlock(xdb, excl); + return RPMRC_FAIL; + } + } + if (!i && (flags & O_CREAT) != 0) { + if (createblob(xdb, &i, blobtag, subtag)) { +- rpmxdbUnlock(xdb, flags ? 1 : 0); ++ rpmxdbUnlock(xdb, excl); + return RPMRC_FAIL; + } + } + *idp = i; +- rpmxdbUnlock(xdb, flags ? 1 : 0); ++ rpmxdbUnlock(xdb, excl); + return i ? RPMRC_OK : RPMRC_NOTFOUND; + } + +-- +1.8.3.1 + diff --git a/backport-ndb-drop-unused-number-of-allocated-slots.patch b/backport-ndb-drop-unused-number-of-allocated-slots.patch new file mode 100644 index 0000000..8dfdc3b --- /dev/null +++ b/backport-ndb-drop-unused-number-of-allocated-slots.patch @@ -0,0 +1,38 @@ +From 8e39098fa991b097ec0c746f0b4e3d8ab19a69ee Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Fri, 10 Jan 2020 11:45:52 +0100 +Subject: [PATCH] ndb: drop unused number of allocated slots + +This is not used as we re-read all slots everytime a package +is added or deleted. + +URL:https://github.com/rpm-software-management/rpm/commit/8e39098fa991b097ec0c746f0b4e3d8ab19a69ee +--- + lib/backend/ndb/rpmpkg.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/lib/backend/ndb/rpmpkg.c b/lib/backend/ndb/rpmpkg.c +index eb65049..b613fa5 100644 +--- a/lib/backend/ndb/rpmpkg.c ++++ b/lib/backend/ndb/rpmpkg.c +@@ -45,7 +45,6 @@ typedef struct rpmpkgdb_s { + unsigned int nextpkgidx; + + struct pkgslot_s *slots; +- unsigned int aslots; /* allocated slots */ + unsigned int nslots; /* used slots */ + + unsigned int *slothash; +@@ -256,8 +255,7 @@ static int rpmpkgReadSlots(rpmpkgdb pkgdb) + fileblks = stb.st_size / BLK_SIZE; + + /* read (and somewhat verify) all slots */ +- pkgdb->aslots = slotnpages * (PAGE_SIZE / SLOT_SIZE); +- pkgdb->slots = xcalloc(pkgdb->aslots, sizeof(*pkgdb->slots)); ++ pkgdb->slots = xcalloc(slotnpages * (PAGE_SIZE / SLOT_SIZE), sizeof(*pkgdb->slots)); + i = 0; + slot = pkgdb->slots; + minblkoff = slotnpages * (PAGE_SIZE / BLK_SIZE); +-- +1.8.3.1 + diff --git a/backport-ndb-fix-ftruncate-return-value-warning.patch b/backport-ndb-fix-ftruncate-return-value-warning.patch new file mode 100644 index 0000000..8f2e2ec --- /dev/null +++ b/backport-ndb-fix-ftruncate-return-value-warning.patch @@ -0,0 +1,28 @@ +From bc13afbbfdfa33b10bb87e9503b3b06a0d65bfd2 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Tue, 14 Jan 2020 17:05:27 +0100 +Subject: [PATCH] ndb: fix ftruncate return value warning + +URL:https://github.com/rpm-software-management/rpm/commit/bc13afbbfdfa33b10bb87e9503b3b06a0d65bfd2 +--- + lib/backend/ndb/rpmxdb.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/lib/backend/ndb/rpmxdb.c b/lib/backend/ndb/rpmxdb.c +index 3baafa6..dbd4942 100644 +--- a/lib/backend/ndb/rpmxdb.c ++++ b/lib/backend/ndb/rpmxdb.c +@@ -963,7 +963,9 @@ int rpmxdbDelAllBlobs(rpmxdb xdb) + rpmxdbUnlock(xdb, 1); + return RPMRC_FAIL; + } +- ftruncate(xdb->fd, xdb->pagesize); ++ if (ftruncate(xdb->fd, xdb->pagesize)) { ++ /* ftruncate failed, but that is not a problem */ ++ } + rpmxdbUnlock(xdb, 1); + return RPMRC_OK; + } +-- +1.8.3.1 + diff --git a/backport-ndb-implement-index-regeneration-if-the-index-is-out.patch b/backport-ndb-implement-index-regeneration-if-the-index-is-out.patch new file mode 100644 index 0000000..f9e1b29 --- /dev/null +++ b/backport-ndb-implement-index-regeneration-if-the-index-is-out.patch @@ -0,0 +1,80 @@ +From 40269d4b3f960e6cb73db1cea0bcc5973f9ce72c Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Fri, 10 Jan 2020 15:51:38 +0100 +Subject: [PATCH] ndb: implement index regeneration if the index is out of sync + +We compare the user generation stored in the index database with +the generation count from the package database. In case there +is a mismatch, we delete all the index databases and rely on the +already existing missing index creation code to rebuild the +database. + +URL:https://github.com/rpm-software-management/rpm/commit/40269d4b3f960e6cb73db1cea0bcc5973f9ce72c +--- + lib/backend/ndb/glue.c | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + +diff --git a/lib/backend/ndb/glue.c b/lib/backend/ndb/glue.c +index 841c2fe..90c10f8 100644 +--- a/lib/backend/ndb/glue.c ++++ b/lib/backend/ndb/glue.c +@@ -80,6 +80,31 @@ static int ndb_Close(dbiIndex dbi, unsigned int flags) + return 0; + } + ++static void ndb_CheckIndexSync(rpmpkgdb pkgdb, rpmxdb xdb) ++{ ++ unsigned int generation, xdb_generation; ++ if (!pkgdb || !xdb) ++ return; ++ if (rpmpkgLock(pkgdb, 0)) ++ return; ++ if (rpmpkgGeneration(pkgdb, &generation)) { ++ rpmpkgUnlock(pkgdb, 0); ++ return; ++ } ++ if (!rpmxdbGetUserGeneration(xdb, &xdb_generation) && generation == xdb_generation) { ++ rpmpkgUnlock(pkgdb, 0); ++ return; ++ } ++ rpmpkgUnlock(pkgdb, 0); ++ /* index corrupt or with different generation */ ++ if (rpmxdbIsRdonly(xdb)) { ++ rpmlog(RPMLOG_WARNING, _("Detected outdated index databases\n")); ++ } else { ++ rpmlog(RPMLOG_WARNING, _("Rebuilding outdated index databases\n")); ++ rpmxdbDelAllBlobs(xdb); ++ } ++} ++ + static int ndb_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags) + { + const char *dbhome = rpmdbHome(rdb); +@@ -130,6 +155,7 @@ static int ndb_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags) + } + if (!ndbenv->xdb) { + char *path = rstrscat(NULL, dbhome, "/Index.db", NULL); ++ int created = 0; + rpmlog(RPMLOG_DEBUG, "opening db index %s mode=0x%x\n", path, rdb->db_mode); + + /* Open indexes readwrite if possible */ +@@ -144,6 +170,7 @@ static int ndb_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags) + } else if (rc && errno == ENOENT) { + ioflags = O_CREAT|O_RDWR; + rc = rpmxdbOpen(&ndbenv->xdb, rdb->db_pkgs->dbi_db, path, ioflags, 0666); ++ created = 1; + } + if (rc) { + perror("rpmxdbOpen"); +@@ -153,6 +180,8 @@ static int ndb_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags) + } + free(path); + rpmxdbSetFsync(ndbenv->xdb, ndbenv->dofsync); ++ if (!created) ++ ndb_CheckIndexSync(ndbenv->pkgdb, ndbenv->xdb); + } + if (rpmxdbLookupBlob(ndbenv->xdb, &id, rpmtag, 0, 0) == RPMRC_NOTFOUND) { + dbi->dbi_flags |= DBI_CREATED; +-- +1.8.3.1 + diff --git a/backport-ndb-make-ordered-slots-flag-a-boolean.patch b/backport-ndb-make-ordered-slots-flag-a-boolean.patch new file mode 100644 index 0000000..78fd0d1 --- /dev/null +++ b/backport-ndb-make-ordered-slots-flag-a-boolean.patch @@ -0,0 +1,154 @@ +From cbe9bcf954b2043dcefabbda6722ee3e149d8a8b Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Fri, 10 Jan 2020 11:44:01 +0100 +Subject: [PATCH] ndb: make "ordered slots" flag a boolean + +We never needed to order by pkgid or slot number, so simplify +the code. + +https://github.com/rpm-software-management/rpm/commit/cbe9bcf954b2043dcefabbda6722ee3e149d8a8b +--- + lib/backend/ndb/rpmpkg.c | 43 +++++++++++++++++++------------------------ + 1 file changed, 19 insertions(+), 24 deletions(-) + +diff --git a/lib/backend/ndb/rpmpkg.c b/lib/backend/ndb/rpmpkg.c +index b8e33bf..eb65049 100644 +--- a/lib/backend/ndb/rpmpkg.c ++++ b/lib/backend/ndb/rpmpkg.c +@@ -52,16 +52,13 @@ typedef struct rpmpkgdb_s { + unsigned int nslothash; + + unsigned int freeslot; /* first free slot */ +- int slotorder; ++ int ordered; /* slots are ordered by the blk offsets */ + + char *filename; + unsigned int fileblks; /* file size in blks */ + int dofsync; + } * rpmpkgdb; + +-#define SLOTORDER_UNORDERED 0 +-#define SLOTORDER_BLKOFF 1 +- + + static inline unsigned int le2h(unsigned char *p) + { +@@ -296,7 +293,7 @@ static int rpmpkgReadSlots(rpmpkgdb pkgdb) + } + } + pkgdb->nslots = i; +- pkgdb->slotorder = SLOTORDER_UNORDERED; /* XXX: always order? */ ++ pkgdb->ordered = 0; + pkgdb->fileblks = fileblks; + pkgdb->freeslot = freeslot; + if (rpmpkgHashSlots(pkgdb)) { +@@ -314,15 +311,13 @@ static int orderslots_blkoff_cmp(const void *a, const void *b) + return blkoffa > blkoffb ? 1 : blkoffa < blkoffb ? -1 : 0; + } + +-static void rpmpkgOrderSlots(rpmpkgdb pkgdb, int slotorder) ++static void rpmpkgOrderSlots(rpmpkgdb pkgdb) + { +- if (pkgdb->slotorder == slotorder) ++ if (pkgdb->ordered) + return; +- if (slotorder == SLOTORDER_BLKOFF) { +- if (pkgdb->nslots > 1) +- qsort(pkgdb->slots, pkgdb->nslots, sizeof(*pkgdb->slots), orderslots_blkoff_cmp); +- } +- pkgdb->slotorder = slotorder; ++ if (pkgdb->nslots > 1) ++ qsort(pkgdb->slots, pkgdb->nslots, sizeof(*pkgdb->slots), orderslots_blkoff_cmp); ++ pkgdb->ordered = 1; + rpmpkgHashSlots(pkgdb); + } + +@@ -347,8 +342,8 @@ static int rpmpkgFindEmptyOffset(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned i + unsigned int lastblkend = pkgdb->slotnpages * (PAGE_SIZE / BLK_SIZE); + pkgslot *slot, *oldslot = 0; + +- if (pkgdb->slotorder != SLOTORDER_BLKOFF) +- rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF); ++ if (!pkgdb->ordered) ++ rpmpkgOrderSlots(pkgdb); + + if (dontprepend && nslots) { + lastblkend = pkgdb->slots[0].blkoff; +@@ -388,8 +383,8 @@ static int rpmpkgNeighbourCheck(rpmpkgdb pkgdb, unsigned int blkoff, unsigned in + unsigned int lastblkend = pkgdb->slotnpages * (PAGE_SIZE / BLK_SIZE); + pkgslot *slot, *left = 0, *right = 0; + +- if (pkgdb->slotorder != SLOTORDER_BLKOFF) +- rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF); ++ if (!pkgdb->ordered) ++ rpmpkgOrderSlots(pkgdb); + if (blkoff < lastblkend) + return RPMRC_FAIL; + for (i = 0, slot = pkgdb->slots; i < nslots; i++, slot++) { +@@ -704,15 +699,15 @@ static int rpmpkgMoveBlob(rpmpkgdb pkgdb, pkgslot *slot, unsigned int newblkoff) + return RPMRC_FAIL; + } + slot->blkoff = newblkoff; +- pkgdb->slotorder = SLOTORDER_UNORDERED; ++ pkgdb->ordered = 0; + return RPMRC_OK; + } + + static int rpmpkgAddSlotPage(rpmpkgdb pkgdb) + { + unsigned int cutoff; +- if (pkgdb->slotorder != SLOTORDER_BLKOFF) +- rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF); ++ if (!pkgdb->ordered) ++ rpmpkgOrderSlots(pkgdb); + cutoff = (pkgdb->slotnpages + 1) * (PAGE_SIZE / BLK_SIZE); + + /* now move every blob before cutoff */ +@@ -730,7 +725,7 @@ static int rpmpkgAddSlotPage(rpmpkgdb pkgdb) + if (rpmpkgMoveBlob(pkgdb, slot, newblkoff)) { + return RPMRC_FAIL; + } +- rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF); ++ rpmpkgOrderSlots(pkgdb); + } + + /* make sure our new page is empty */ +@@ -1008,7 +1003,7 @@ static int rpmpkgPutInternal(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned char + /* just update the slot, no need to free the slot data */ + oldslot->blkoff = blkoff; + oldslot->blkcnt = blkcnt; +- pkgdb->slotorder = SLOTORDER_UNORDERED; ++ pkgdb->ordered = 0; + } else { + free(pkgdb->slots); + pkgdb->slots = 0; +@@ -1025,7 +1020,7 @@ static int rpmpkgDelInternal(rpmpkgdb pkgdb, unsigned int pkgidx) + if (rpmpkgReadSlots(pkgdb)) { + return RPMRC_FAIL; + } +- rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF); ++ rpmpkgOrderSlots(pkgdb); + slot = rpmpkgFindSlot(pkgdb, pkgidx); + if (!slot) { + return RPMRC_OK; +@@ -1068,7 +1063,7 @@ static int rpmpkgDelInternal(rpmpkgdb pkgdb, unsigned int pkgidx) + blkoff += slot->blkcnt; + blkcnt -= slot->blkcnt; + } +- rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF); ++ rpmpkgOrderSlots(pkgdb); + } else { + slot->blkoff = 0; + slot->blkcnt = 0; +@@ -1107,7 +1102,7 @@ static int rpmpkgListInternal(rpmpkgdb pkgdb, unsigned int **pkgidxlistp, unsign + *npkgidxlistp = pkgdb->nslots; + return RPMRC_OK; + } +- rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF); ++ rpmpkgOrderSlots(pkgdb); + nslots = pkgdb->nslots; + pkgidxlist = xcalloc(nslots + 1, sizeof(unsigned int)); + for (i = 0, slot = pkgdb->slots; i < nslots; i++, slot++) { +-- +1.8.3.1 + diff --git a/backport-ndb-make-rpmxdbWriteHeader-a-void-function.patch b/backport-ndb-make-rpmxdbWriteHeader-a-void-function.patch new file mode 100644 index 0000000..6c1b72a --- /dev/null +++ b/backport-ndb-make-rpmxdbWriteHeader-a-void-function.patch @@ -0,0 +1,39 @@ +From 6511823c97c6f40b8d99961767537f4f3bebc16e Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Tue, 14 Apr 2020 11:27:46 +0200 +Subject: [PATCH] ndb: make rpmxdbWriteHeader a void function + +It's a static function and nobody tests the return code. It just +writes into mapped memory like rpmxdbUpdateSlot, which is also void. + +URL:https://github.com/rpm-software-management/rpm/commit/6511823c97c6f40b8d99961767537f4f3bebc16e +--- + lib/backend/ndb/rpmxdb.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/lib/backend/ndb/rpmxdb.c b/lib/backend/ndb/rpmxdb.c +index ab22746..be85fdc 100644 +--- a/lib/backend/ndb/rpmxdb.c ++++ b/lib/backend/ndb/rpmxdb.c +@@ -392,17 +392,14 @@ static int rpmxdbReadHeader(rpmxdb xdb, int rw) + return RPMRC_OK; + } + +-static int rpmxdbWriteHeader(rpmxdb xdb) ++static void rpmxdbWriteHeader(rpmxdb xdb) + { +- if (!xdb->mapped) +- return RPMRC_FAIL; + h2lea(XDB_MAGIC, xdb->mapped + XDB_OFFSET_MAGIC); + h2lea(XDB_VERSION, xdb->mapped + XDB_OFFSET_VERSION); + h2lea(xdb->generation, xdb->mapped + XDB_OFFSET_GENERATION); + h2lea(xdb->slotnpages, xdb->mapped + XDB_OFFSET_SLOTNPAGES); + h2lea(xdb->pagesize, xdb->mapped + XDB_OFFSET_PAGESIZE); + h2lea(xdb->usergeneration, xdb->mapped + XDB_OFFSET_USERGENERATION); +- return RPMRC_OK; + } + + static void rpmxdbUpdateSlot(rpmxdb xdb, struct xdb_slot *slot) +-- +1.8.3.1 + diff --git a/backport-ndb-no-longer-free-the-pkgid-hash-all-the-time.patch b/backport-ndb-no-longer-free-the-pkgid-hash-all-the-time.patch new file mode 100644 index 0000000..2ba691e --- /dev/null +++ b/backport-ndb-no-longer-free-the-pkgid-hash-all-the-time.patch @@ -0,0 +1,70 @@ +From d435beb937ca38a3d3f1c6acb1b3ca06dcb3544d Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Fri, 10 Jan 2020 11:51:07 +0100 +Subject: [PATCH] ndb: no longer free the pkgid hash all the time + +Reuse the hash if the size matches. This was actually the original +intention, but for some reason the code was disabled by always +freeing the hash. + +URL:https://github.com/rpm-software-management/rpm/commit/d435beb937ca38a3d3f1c6acb1b3ca06dcb3544d +--- + lib/backend/ndb/rpmpkg.c | 16 +++------------- + 1 file changed, 3 insertions(+), 13 deletions(-) + +diff --git a/lib/backend/ndb/rpmpkg.c b/lib/backend/ndb/rpmpkg.c +index b613fa5..b95f29f 100644 +--- a/lib/backend/ndb/rpmpkg.c ++++ b/lib/backend/ndb/rpmpkg.c +@@ -136,10 +136,6 @@ static int rpmpkgReadHeader(rpmpkgdb pkgdb) + if (pkgdb->slots && (pkgdb->generation != generation || pkgdb->slotnpages != slotnpages)) { + free(pkgdb->slots); + pkgdb->slots = 0; +- if (pkgdb->slothash) { +- free(pkgdb->slothash); +- pkgdb->slothash = 0; +- } + } + pkgdb->generation = generation; + pkgdb->slotnpages = slotnpages; +@@ -201,14 +197,14 @@ static int rpmpkgHashSlots(rpmpkgdb pkgdb) + int i; + pkgslot *slot; + +- pkgdb->nslothash = 0; +- num = pkgdb->nslots; ++ num = pkgdb->nslots + 32; + while (num & (num - 1)) + num = num & (num - 1); + num *= 4; + hash = pkgdb->slothash; + if (!hash || pkgdb->nslothash != num) { +- free(pkgdb->slothash); ++ if (hash) ++ free(hash); + hash = pkgdb->slothash = xcalloc(num, sizeof(unsigned int)); + pkgdb->nslothash = num; + } else { +@@ -221,8 +217,6 @@ static int rpmpkgHashSlots(rpmpkgdb pkgdb) + ; + hash[h] = i + 1; + } +- pkgdb->slothash = hash; +- pkgdb->nslothash = num; + return RPMRC_OK; + } + +@@ -240,10 +234,6 @@ static int rpmpkgReadSlots(rpmpkgdb pkgdb) + free(pkgdb->slots); + pkgdb->slots = 0; + } +- if (pkgdb->slothash) { +- free(pkgdb->slothash); +- pkgdb->slothash = 0; +- } + pkgdb->nslots = 0; + pkgdb->freeslot = 0; + +-- +1.8.3.1 + diff --git a/backport-ndb-only-clear-the-dbenv-in-the-rpmdb-if-the-last-re.patch b/backport-ndb-only-clear-the-dbenv-in-the-rpmdb-if-the-last-re.patch index 09a8b0f..e896a48 100644 --- a/backport-ndb-only-clear-the-dbenv-in-the-rpmdb-if-the-last-re.patch +++ b/backport-ndb-only-clear-the-dbenv-in-the-rpmdb-if-the-last-re.patch @@ -5,12 +5,14 @@ Subject: [PATCH] ndb: only clear the dbenv in the rpmdb if the last reference is gone Otherwise we will segfault if just one index is closed. + +URL:https://github.com/rpm-software-management/rpm/commit/52c3ee60a1ce0e7e527dc396dd1e1a0e29b7b0ed --- lib/backend/ndb/glue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/backend/ndb/glue.c b/lib/backend/ndb/glue.c -index 376e360e3..841c2fe42 100644 +index 376e360..841c2fe 100644 --- a/lib/backend/ndb/glue.c +++ b/lib/backend/ndb/glue.c @@ -52,8 +52,8 @@ static void closeEnv(rpmdb rdb) @@ -24,5 +26,5 @@ index 376e360e3..841c2fe42 100644 static struct ndbEnv_s *openEnv(rpmdb rdb) -- -2.27.0 +1.8.3.1 diff --git a/backport-ndb-remove-unused-lzo-compression-code.patch b/backport-ndb-remove-unused-lzo-compression-code.patch new file mode 100644 index 0000000..d8d4bce --- /dev/null +++ b/backport-ndb-remove-unused-lzo-compression-code.patch @@ -0,0 +1,121 @@ +From dc0a504d3e893e40df60bd8a4a45852dcfca307a Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Fri, 10 Jan 2020 11:26:49 +0100 +Subject: [PATCH] ndb: remove unused lzo compression code + +URL:https://github.com/rpm-software-management/rpm/commit/dc0a504d3e893e40df60bd8a4a45852dcfca307a +--- + lib/backend/ndb/rpmpkg.c | 78 ------------------------------------------------ + 1 file changed, 78 deletions(-) + +diff --git a/lib/backend/ndb/rpmpkg.c b/lib/backend/ndb/rpmpkg.c +index 0809af1..94ecde1 100644 +--- a/lib/backend/ndb/rpmpkg.c ++++ b/lib/backend/ndb/rpmpkg.c +@@ -19,10 +19,6 @@ + #define RPMRC_NOTFOUND 1 + #define RPMRC_OK 0 + +-#ifdef RPMPKG_LZO +-static int rpmpkgLZOCompress(unsigned char **blobp, unsigned int *bloblp); +-static int rpmpkgLZODecompress(unsigned char **blobp, unsigned int *bloblp); +-#endif + + static int rpmpkgVerifyblob(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned int blkoff, unsigned int blkcnt); + +@@ -1127,10 +1123,6 @@ int rpmpkgGet(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned char **blobp, unsign + return RPMRC_FAIL; + rc = rpmpkgGetInternal(pkgdb, pkgidx, blobp, bloblp); + rpmpkgUnlock(pkgdb, 0); +-#ifdef RPMPKG_LZO +- if (!rc) +- rc = rpmpkgLZODecompress(blobp, bloblp); +-#endif + return rc; + } + +@@ -1143,16 +1135,7 @@ int rpmpkgPut(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned char *blob, unsigned + } + if (rpmpkgLockReadHeader(pkgdb, 1)) + return RPMRC_FAIL; +-#ifdef RPMPKG_LZO +- if (rpmpkgLZOCompress(&blob, &blobl)) { +- rpmpkgUnlock(pkgdb, 1); +- return RPMRC_FAIL; +- } +-#endif + rc = rpmpkgPutInternal(pkgdb, pkgidx, blob, blobl); +-#ifdef RPMPKG_LZO +- free(blob); +-#endif + rpmpkgUnlock(pkgdb, 1); + return rc; + } +@@ -1233,64 +1216,3 @@ int rpmpkgStats(rpmpkgdb pkgdb) + return RPMRC_OK; + } + +-#ifdef RPMPKG_LZO +- +-#include "lzo/lzoconf.h" +-#include "lzo/lzo1x.h" +- +-#define BLOBLZO_MAGIC ('L' | 'Z' << 8 | 'O' << 16 | 'B' << 24) +- +-static int rpmpkgLZOCompress(unsigned char **blobp, unsigned int *bloblp) +-{ +- unsigned char *blob = *blobp; +- unsigned int blobl = *bloblp; +- unsigned char *lzoblob, *workmem; +- unsigned int lzoblobl; +- lzo_uint blobl2; +- +- if (lzo_init() != LZO_E_OK) { +- return RPMRC_FAIL; +- } +- workmem = xmalloc(LZO1X_1_MEM_COMPRESS); +- lzoblobl = 4 + 4 + blobl + blobl / 16 + 64 + 3; +- lzoblob = xmalloc(lzoblobl); +- h2le(BLOBLZO_MAGIC, lzoblob); +- h2le(blobl, lzoblob + 4); +- if (lzo1x_1_compress(blob, blobl, lzoblob + 8, &blobl2, workmem) != LZO_E_OK) { +- free(workmem); +- free(lzoblob); +- return RPMRC_FAIL; +- } +- free(workmem); +- *blobp = lzoblob; +- *bloblp = 8 + blobl2; +- return RPMRC_OK; +-} +- +-static int rpmpkgLZODecompress(unsigned char **blobp, unsigned int *bloblp) +-{ +- unsigned char *lzoblob = *blobp; +- unsigned int lzoblobl = *bloblp; +- unsigned char *blob; +- unsigned int blobl; +- lzo_uint blobl2; +- +- if (!lzoblob || lzoblobl < 8) +- return RPMRC_FAIL; +- if (le2h(lzoblob) != BLOBLZO_MAGIC) +- return RPMRC_FAIL; +- if (lzo_init() != LZO_E_OK) +- return RPMRC_FAIL; +- blobl = le2h(lzoblob + 4); +- blob = xmalloc(blobl ? blobl : 1); +- if (lzo1x_decompress(lzoblob + 8, lzoblobl - 8, blob, &blobl2, 0) != LZO_E_OK || blobl2 != blobl) { +- free(blob); +- return RPMRC_FAIL; +- } +- free(lzoblob); +- *blobp = blob; +- *bloblp = blobl; +- return RPMRC_OK; +-} +- +-#endif +-- +1.8.3.1 + diff --git a/backport-ndb-unmap-xdb-s-header-when-closing-the-xdb-database.patch b/backport-ndb-unmap-xdb-s-header-when-closing-the-xdb-database.patch new file mode 100644 index 0000000..0f177e1 --- /dev/null +++ b/backport-ndb-unmap-xdb-s-header-when-closing-the-xdb-database.patch @@ -0,0 +1,30 @@ +From 1187cf005a2821d5f239bec1a0ecddfef190a125 Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Tue, 14 Apr 2020 11:22:39 +0200 +Subject: [PATCH] ndb: unmap xdb's header when closing the xdb database + +Somehow I was under the impression that mapped regions are unmapped when +the corresponding file descriptor is closed, but that's not the case +for POSIX systems. + +URL:https://github.com/rpm-software-management/rpm/commit/1187cf005a2821d5f239bec1a0ecddfef190a125 +--- + lib/backend/ndb/rpmxdb.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/lib/backend/ndb/rpmxdb.c b/lib/backend/ndb/rpmxdb.c +index ec408f8..ab22746 100644 +--- a/lib/backend/ndb/rpmxdb.c ++++ b/lib/backend/ndb/rpmxdb.c +@@ -621,6 +621,8 @@ void rpmxdbClose(rpmxdb xdb) + } + if (xdb->slots) + free(xdb->slots); ++ if (xdb->mapped) ++ unmapheader(xdb); + if (xdb->fd >= 0) + close(xdb->fd); + if (xdb->filename) +-- +1.8.3.1 + diff --git a/backport-ndb-use-the-generation-instead-of-the-current-time-i.patch b/backport-ndb-use-the-generation-instead-of-the-current-time-i.patch new file mode 100644 index 0000000..b0c9f04 --- /dev/null +++ b/backport-ndb-use-the-generation-instead-of-the-current-time-i.patch @@ -0,0 +1,99 @@ +From f674af7efbeeb44d6c0f0da8c611e6cd7257ee4f Mon Sep 17 00:00:00 2001 +From: Michael Schroeder +Date: Fri, 10 Jan 2020 12:00:49 +0100 +Subject: [PATCH] ndb: use the generation instead of the current time in blobs + +This seems to saner as the somewhat unreliable current time. +This element is not used in normal database operation, it is +for repair tools that need to decide which blob to take if two +blobs have the same pkgid. + +URL:https://github.com/rpm-software-management/rpm/commit/f674af7efbeeb44d6c0f0da8c611e6cd7257ee4f +--- + lib/backend/ndb/rpmpkg.c | 21 ++++++++++----------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +diff --git a/lib/backend/ndb/rpmpkg.c b/lib/backend/ndb/rpmpkg.c +index 2213872..922ae11 100644 +--- a/lib/backend/ndb/rpmpkg.c ++++ b/lib/backend/ndb/rpmpkg.c +@@ -7,7 +7,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -511,7 +510,7 @@ static int rpmpkgValidateZero(rpmpkgdb pkgdb, unsigned int blkoff, unsigned int + + /*** Blob primitives ***/ + +-/* head: magic + pkgidx + timestamp + bloblen */ ++/* head: magic + pkgidx + generation + bloblen */ + /* tail: adler32 + bloblen + magic */ + + #define BLOBHEAD_MAGIC ('B' | 'l' << 8 | 'b' << 16 | 'S' << 24) +@@ -520,10 +519,10 @@ static int rpmpkgValidateZero(rpmpkgdb pkgdb, unsigned int blkoff, unsigned int + #define BLOBHEAD_SIZE (4 + 4 + 4 + 4) + #define BLOBTAIL_SIZE (4 + 4 + 4) + +-static int rpmpkgReadBlob(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned int blkoff, unsigned int blkcnt, unsigned char *blob, unsigned int *bloblp, unsigned int *tstampp) ++static int rpmpkgReadBlob(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned int blkoff, unsigned int blkcnt, unsigned char *blob, unsigned int *bloblp, unsigned int *generationp) + { + unsigned char buf[BLOBHEAD_SIZE > BLOBTAIL_SIZE ? BLOBHEAD_SIZE : BLOBTAIL_SIZE]; +- unsigned int bloblen, toread, tstamp; ++ unsigned int bloblen, toread, generation; + off_t fileoff; + unsigned int adl; + int verifyadler = bloblp ? 0 : 1; +@@ -539,7 +538,7 @@ static int rpmpkgReadBlob(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned int blko + return RPMRC_FAIL; /* bad blob */ + if (le2h(buf + 4) != pkgidx) + return RPMRC_FAIL; /* bad blob */ +- tstamp = le2h(buf + 8); ++ generation = le2h(buf + 8); + bloblen = le2h(buf + 12); + if (blkcnt != (BLOBHEAD_SIZE + bloblen + BLOBTAIL_SIZE + BLK_SIZE - 1) / BLK_SIZE) + return RPMRC_FAIL; /* bad blob */ +@@ -584,8 +583,8 @@ static int rpmpkgReadBlob(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned int blko + } + if (bloblp) + *bloblp = bloblen; +- if (tstampp) +- *tstampp = tstamp; ++ if (generationp) ++ *generationp = generation; + return RPMRC_OK; + } + +@@ -668,14 +667,14 @@ static int rpmpkgMoveBlob(rpmpkgdb pkgdb, pkgslot *slot, unsigned int newblkoff) + unsigned int blkoff = slot->blkoff; + unsigned int blkcnt = slot->blkcnt; + unsigned char *blob; +- unsigned int tstamp, blobl; ++ unsigned int generation, blobl; + + blob = xmalloc((size_t)blkcnt * BLK_SIZE); +- if (rpmpkgReadBlob(pkgdb, pkgidx, blkoff, blkcnt, blob, &blobl, &tstamp)) { ++ if (rpmpkgReadBlob(pkgdb, pkgidx, blkoff, blkcnt, blob, &blobl, &generation)) { + free(blob); + return RPMRC_FAIL; + } +- if (rpmpkgWriteBlob(pkgdb, pkgidx, newblkoff, blkcnt, blob, blobl, tstamp)) { ++ if (rpmpkgWriteBlob(pkgdb, pkgidx, newblkoff, blkcnt, blob, blobl, generation)) { + free(blob); + return RPMRC_FAIL; + } +@@ -966,7 +965,7 @@ static int rpmpkgPutInternal(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned char + return RPMRC_FAIL; + } + /* write new blob */ +- if (rpmpkgWriteBlob(pkgdb, pkgidx, blkoff, blkcnt, blob, blobl, (unsigned int)time(0))) { ++ if (rpmpkgWriteBlob(pkgdb, pkgidx, blkoff, blkcnt, blob, blobl, pkgdb->generation)) { + return RPMRC_FAIL; + } + /* write slot */ +-- +1.8.3.1 + diff --git a/rpm.spec b/rpm.spec index 86da59f..64776f2 100644 --- a/rpm.spec +++ b/rpm.spec @@ -1,6 +1,6 @@ Name: rpm Version: 4.15.1 -Release: 19 +Release: 20 Summary: RPM Package Manager License: GPLv2+ URL: http://www.rpm.org/ @@ -28,31 +28,62 @@ Patch17: backport-Fix-resource-leaks-on-zstd-open-error-paths.patch Patch18: backport-rpmio-initialise-libgcrypt.patch Patch19: backport-fix-zstd-magic.patch Patch20: backport-Don-t-require-signature-header-to-be-in-single-conti.patch -Patch21: backport-ndb-only-clear-the-dbenv-in-the-rpmdb-if-the-last-re.patch -Patch22: backport-Fix-regression-on-v3-package-handling-on-database-re.patch -Patch23: backport-Fix-a-minor-memory-leak-on-suppressed-inhibition-loc.patch -Patch24: backport-Fix-POPT_ARG_STRING-memleaks-in-librpmbuild.patch -Patch25: backport-Fix-build-regression-in-commit-307872f71b357a3839fd0.patch -Patch26: backport-Fix-isUnorderedReq-for-multiple-qualifiers.patch -Patch27: backport-If-fork-fails-in-getOutputFrom-close-opened-unused-p.patch -Patch28: backport-Fix-pointer-dereference-before-testing-for-NULL-in-r.patch -Patch29: backport-Don-t-look-into-source-package-provides-in-depsolvin.patch -Patch30: backport-rpmfiArchiveRead-use-signed-return-value-to-handle-1.patch -Patch31: backport-Fix-bump-up-the-limit-of-signature-header-to-64MB.patch -Patch32: backport-Remove-compare-of-global-array-tagsByName-to-NULL.patch -Patch33: backport-Always-close-libelf-handle-1313.patch -Patch34: backport-Add-missing-terminator-to-copyTagsFromMainDebug-arra.patch -Patch35: backport-Fix-possible-read-beyond-buffer-in-rstrnlenhash.patch -Patch36: backport-Make-fdSeek-return-0-on-success-1-on-error.patch -Patch37: backport-Fix-logic-error-in-grabArgs.patch -Patch38: backport-Use-libelf-for-determining-file-colors.patch +Patch21: backport-Fix-regression-on-v3-package-handling-on-database-re.patch +Patch22: backport-Fix-a-minor-memory-leak-on-suppressed-inhibition-loc.patch +Patch23: backport-Fix-POPT_ARG_STRING-memleaks-in-librpmbuild.patch +Patch24: backport-Fix-build-regression-in-commit-307872f71b357a3839fd0.patch +Patch25: backport-Fix-isUnorderedReq-for-multiple-qualifiers.patch +Patch26: backport-If-fork-fails-in-getOutputFrom-close-opened-unused-p.patch +Patch27: backport-Fix-pointer-dereference-before-testing-for-NULL-in-r.patch +Patch28: backport-Don-t-look-into-source-package-provides-in-depsolvin.patch +Patch29: backport-rpmfiArchiveRead-use-signed-return-value-to-handle-1.patch +Patch30: backport-Fix-bump-up-the-limit-of-signature-header-to-64MB.patch +Patch31: backport-Remove-compare-of-global-array-tagsByName-to-NULL.patch +Patch32: backport-Always-close-libelf-handle-1313.patch +Patch33: backport-Add-missing-terminator-to-copyTagsFromMainDebug-arra.patch +Patch34: backport-Fix-possible-read-beyond-buffer-in-rstrnlenhash.patch +Patch35: backport-Make-fdSeek-return-0-on-success-1-on-error.patch +Patch36: backport-Fix-logic-error-in-grabArgs.patch +Patch37: backport-Use-libelf-for-determining-file-colors.patch -BuildRequires: gcc autoconf automake libtool make gawk popt-devel openssl-devel readline-devel libdb-devel +Patch38: backport-Add-backend-name-and-path-of-main-database-file-to-d.patch +Patch39: backport-Use-paths-from-db_ops-in-the-backends-too-where-poss.patch +Patch40: backport-Use-the-new-backend-struct-data-for-backend-configur.patch +Patch41: backport-Add-support-for-reading-BDB-without-the-library.patch +Patch42: backport-Fix-building-with-no-BerkeleyDB-support.patch +Patch43: backport-Implement-a-key-only-rpmdb-index-iterator.patch +Patch44: backport-ndb-remove-unused-lzo-compression-code.patch +Patch45: backport-ndb-make-ordered-slots-flag-a-boolean.patch +Patch46: backport-ndb-drop-unused-number-of-allocated-slots.patch +Patch47: backport-ndb-no-longer-free-the-pkgid-hash-all-the-time.patch +Patch48: backport-ndb-add-a-verify-method.patch +Patch49: backport-ndb-use-the-generation-instead-of-the-current-time-i.patch +Patch50: backport-ndb-only-clear-the-dbenv-in-the-rpmdb-if-the-last-re.patch +Patch51: backport-ndb-add-a-rpmxdbDelAllBlobs-method.patch +Patch52: backport-ndb-implement-index-regeneration-if-the-index-is-out.patch +Patch53: backport-Remove-the-experimental-status-from-the-ndb-database.patch +Patch54: backport-ndb-fix-ftruncate-return-value-warning.patch +Patch55: backport-Permit-ndb-database-queries-on-read-only-media.patch +Patch56: backport-ndb-add-a-rpmpkgSalvage-method.patch +Patch57: backport-Add-a-salvagedb-option-to-the-rpmdb-tool.patch +Patch58: backport-Flush-1998-vintage-dirent.h-compatibility-mess-from-.patch +Patch59: backport-ndb-also-copy-the-mapped-pointer-when-keeping-a-slot.patch +Patch60: backport-ndb-do-not-map-the-index-databases-read-write-all-th.patch +Patch61: backport-ndb-do-not-map-xdb-s-header-read-write-all-the-time.patch +Patch62: backport-ndb-unmap-xdb-s-header-when-closing-the-xdb-database.patch +Patch63: backport-ndb-make-rpmxdbWriteHeader-a-void-function.patch +Patch64: backport-Add-an-index-sync-call-at-the-end-of-a-database-rebu.patch +Patch65: backport-Deprecate-Berkeley-DB-database-backend.patch +Patch66: backport-Always-open-and-initialize-the-entire-database-at-on.patch +Patch67: backport-Stop-on-first-failure-when-trying-to-open-a-database.patch +Patch68: backport-Only-attempt-loading-the-keyring-once-the-rpmdb-is-o.patch + +BuildRequires: gcc autoconf automake libtool make gawk popt-devel openssl-devel readline-devel BuildRequires: zlib-devel libzstd-devel xz-devel bzip2-devel libarchive-devel ima-evm-utils-devel BuildRequires: dbus-devel fakechroot elfutils-devel elfutils-libelf-devel ima-evm-utils BuildRequires: lua-devel libcap-devel libacl-devel libselinux-devel file-devel gettext-devel ncurses-devel BuildRequires: system-rpm-config gdb dwz -Requires: coreutils popt curl zstd libcap gnupg2 crontabs logrotate libdb-utils %{name}-libs +Requires: coreutils popt curl zstd libcap gnupg2 crontabs logrotate %{name}-libs Obsoletes: %{name}-build-libs %{name}-sign-libs %{name}-sign %{name}-cron Provides: %{name}-build-libs %{name}-sign-libs %{name}-sign %{name}-cron Obsoletes: %{name}-plugin-selinux %{name}-plugin-syslog %{name}-plugin-systemd-inhibit %{name}-plugin-ima %{name}-plugin-prioreset @@ -130,6 +161,7 @@ Obsoletes: apidocs %autosetup -n %{name}-%{version} -p1 sed -ie 's:^python test:python2 test:g' tests/rpmtests tests/local.at +sed -i -e "/_db_backend/ s/ bdb/ ndb/g" macros.in %build CPPFLAGS="$CPPFLAGS -DLUA_COMPAT_APIINTCASTS" @@ -157,6 +189,9 @@ done; --with-selinux \ --with-cap \ --with-acl \ + --enable-ndb \ + --enable-bdb-ro \ + --enable-bdb=no \ --with-imaevm \ --enable-zstd \ --enable-python \ @@ -190,14 +225,8 @@ mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/rpm mkdir -p $RPM_BUILD_ROOT%{_rpmconfigdir}/macros.d mkdir -p $RPM_BUILD_ROOT/var/lib/rpm -for dbi in \ - Basenames Conflictname Dirnames Group Installtid Name Obsoletename \ - Packages Providename Requirename Triggername Sha1header Sigmd5 \ - __db.001 __db.002 __db.003 __db.004 __db.005 __db.006 __db.007 \ - __db.008 __db.009 -do - touch $RPM_BUILD_ROOT/var/lib/rpm/$dbi -done +./rpmdb --define "_db_backend ndb" --dbpath=${PWD}/ndb --initdb +cp -va ndb/. $RPM_BUILD_ROOT/var/lib/rpm/ #./rpmdb --dbpath=$RPM_BUILD_ROOT/var/lib/rpm --initdb @@ -234,7 +263,8 @@ make check || (cat tests/rpmtests.log; exit 0) %config(noreplace) %{_sysconfdir}/logrotate.d/rpm %dir %{_sysconfdir}/rpm %dir /var/lib/rpm -%attr(0644, root, root) %verify(not md5 size mtime) %ghost %config(missingok,noreplace) /var/lib/rpm/* +%attr(0644, root, root) %ghost %config(missingok,noreplace) /var/lib/rpm/* +%attr(0644, root, root) %ghost /var/lib/rpm/.*.lock %lang(fr) %{_mandir}/fr/man[18]/*.[18]* %lang(ko) %{_mandir}/ko/man[18]/*.[18]* %lang(ja) %{_mandir}/ja/man[18]/*.[18]* @@ -314,7 +344,13 @@ make check || (cat tests/rpmtests.log; exit 0) %{_mandir}/man1/gendiff.1* %changelog -* Fri Jan 11 2021 Liquor - 4.15.1-19 +* Tue Jan 12 2021 panxiaohe - 4.15.1-20 +- Type:enhancement +- ID:NA +- SUG:NA +- DESC:use ndb instead of Berkeley DB, and deprecate Berkeley DB. + +* Mon Jan 11 2021 Liquor - 4.15.1-19 - Type:enhancement - ID:NA - SUG:NA