diff --git a/.files b/.files
index 18e4953..4a6190f 100644
Binary files a/.files and b/.files differ
diff --git a/.rev b/.rev
index db6c251..0ac8f63 100644
--- a/.rev
+++ b/.rev
@@ -2146,4 +2146,12 @@ Note that this will require adding `Preinstall: libzstd1` to the `openSUSE:Facto
- update to rpm-4.15.1
755878
+
+ c0d13fdbad36ccbed7219fbb541a46d5
+ 4.15.1
+
+ dimstar_suse
+ Use libgcrypt as crypto library, switch to ndb database
+ 769573
+
diff --git a/bdb_ro.diff b/bdb_ro.diff
new file mode 100644
index 0000000..8c449b8
--- /dev/null
+++ b/bdb_ro.diff
@@ -0,0 +1,884 @@
+--- ./configure.ac.orig 2020-01-17 12:07:10.366060891 +0000
++++ ./configure.ac 2020-01-17 12:07:57.129945219 +0000
+@@ -588,6 +588,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)],
+--- ./lib/Makefile.am.orig 2019-06-26 14:17:31.404985707 +0000
++++ ./lib/Makefile.am 2020-01-17 12:07:57.129945219 +0000
+@@ -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 \
+--- ./lib/backend/bdb_ro.c.orig 2020-01-17 12:07:57.129945219 +0000
++++ ./lib/backend/bdb_ro.c 2020-01-17 12:11:21.125440629 +0000
+@@ -0,0 +1,819 @@
++#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, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec)
++{
++ return RPMRC_FAIL;
++}
++
++static rpmRC bdbro_idxdbDel(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen, dbiIndexItem rec)
++{
++ 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_pkgdbNew(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,
++ .pkgdbNew = bdbro_pkgdbNew,
++ .pkgdbKey = bdbro_pkgdbKey,
++
++ .idxdbGet = bdbro_idxdbGet,
++ .idxdbPut = bdbro_idxdbPut,
++ .idxdbDel = bdbro_idxdbDel,
++ .idxdbKey = bdbro_idxdbKey
++};
++
+--- ./lib/backend/dbi.c.orig 2020-01-17 12:07:10.382060851 +0000
++++ ./lib/backend/dbi.c 2020-01-17 12:07:57.129945219 +0000
+@@ -22,6 +22,9 @@ const struct rpmdbOps_s *backends[] = {
+ #if defined(WITH_BDB)
+ &db3_dbops,
+ #endif
++#if defined(WITH_BDB_RO)
++ &bdbro_dbops,
++#endif
+ &dummydb_dbops,
+ NULL
+ };
+--- ./lib/backend/dbi.h.orig 2020-01-17 12:07:10.382060851 +0000
++++ ./lib/backend/dbi.h 2020-01-17 12:07:57.129945219 +0000
+@@ -273,6 +273,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;
diff --git a/beecrypt-4.1.2-build.diff b/beecrypt-4.1.2-build.diff
deleted file mode 100644
index 1834564..0000000
--- a/beecrypt-4.1.2-build.diff
+++ /dev/null
@@ -1,41 +0,0 @@
----
- acinclude.m4 | 4 ++--
- configure.ac | 2 +-
- 2 files changed, 3 insertions(+), 3 deletions(-)
-
-Index: beecrypt-4.1.2/configure.ac
-===================================================================
---- beecrypt-4.1.2.orig/configure.ac
-+++ beecrypt-4.1.2/configure.ac
-@@ -1,8 +1,8 @@
- # Process this file with autoconf to produce a configure script.
-
- AC_INIT([beecrypt],[4.1.2],[bob.deblier@telenet.be])
--AM_INIT_AUTOMAKE
- AC_CANONICAL_TARGET
-+AM_INIT_AUTOMAKE
- AC_CONFIG_SRCDIR(beecrypt.h)
- AC_CONFIG_HEADERS([config.h])
-
-Index: beecrypt-4.1.2/acinclude.m4
-===================================================================
---- beecrypt-4.1.2.orig/acinclude.m4
-+++ beecrypt-4.1.2/acinclude.m4
-@@ -459,7 +459,7 @@ AC_DEFUN([BEECRYPT_GNU_CC],[
- CFLAGS="$CFLAGS -Wall -pedantic"
- else
- # Generic optimizations, including cpu tuning
-- BEECRYPT_CFLAGS_REM([-g])
-+ #BEECRYPT_CFLAGS_REM([-g])
- CFLAGS="$CFLAGS -DNDEBUG -fomit-frame-pointer"
- if test "$bc_cv_c_aggressive_opt" = yes; then
- case $bc_target_cpu in
-@@ -571,7 +571,7 @@ AC_DEFUN([BEECRYPT_GNU_CXX],[
- CXXFLAGS="$CXXFLAGS -Wall -pedantic"
- else
- # Generic optimizations, including cpu tuning
-- BEECRYPT_CXXFLAGS_REM([-g])
-+ #BEECRYPT_CXXFLAGS_REM([-g])
- CXXFLAGS="$CXXFLAGS -DNDEBUG"
- if test "$bc_cv_c_aggressive_opt" = yes; then
- case $bc_target_cpu in
diff --git a/beecrypt-4.1.2.diff b/beecrypt-4.1.2.diff
deleted file mode 100644
index bd99c65..0000000
--- a/beecrypt-4.1.2.diff
+++ /dev/null
@@ -1,52 +0,0 @@
-Index: beecrypt-4.1.2/Makefile.am
-===================================================================
---- beecrypt-4.1.2/Makefile.am.orig
-+++ beecrypt-4.1.2/Makefile.am
-@@ -49,7 +49,7 @@ libaltdir=$(prefix)/lib@LIBALT@
-
- libalt_LTLIBRARIES = libbeecrypt.la
-
--libbeecrypt_la_SOURCES = aes.c base64.c beecrypt.c blockmode.c blockpad.c blowfish.c dhaes.c dldp.c dlkp.c dlpk.c dlsvdp-dh.c dsa.c elgamal.c endianness.c entropy.c fips186.c hmac.c hmacmd5.c hmacsha1.c hmacsha256.c md5.c hmacsha384.c hmacsha512.c memchunk.c mp.c mpbarrett.c mpnumber.c mpprime.c mtprng.c pkcs1.c pkcs12.c rsa.c rsakp.c rsapk.c sha1.c sha256.c sha384.c sha512.c sha_k.c timestamp.c cppglue.cxx
-+libbeecrypt_la_SOURCES = aes.c base64.c beecrypt.c blockmode.c blockpad.c blowfish.c dhaes.c dldp.c dlkp.c dlpk.c dlsvdp-dh.c dsa.c elgamal.c endianness.c entropy.c fips186.c hmac.c hmacmd5.c hmacsha1.c hmacsha256.c md5.c hmacsha384.c hmacsha512.c memchunk.c mp.c mpbarrett.c mpnumber.c mpprime.c mtprng.c pkcs1.c pkcs12.c rsa.c rsakp.c rsapk.c sha1.c sha256.c sha384.c sha512.c sha_k.c timestamp.c
- libbeecrypt_la_DEPENDENCIES = $(BEECRYPT_OBJECTS)
- libbeecrypt_la_LIBADD = aesopt.lo blowfishopt.lo mpopt.lo sha1opt.lo
- libbeecrypt_la_LDFLAGS = -no-undefined -version-info $(LIBBEECRYPT_LT_CURRENT):$(LIBBEECRYPT_LT_REVISION):$(LIBBEECRYPT_LT_AGE)
-@@ -62,5 +62,11 @@ EXTRA_DIST = BENCHMARKS BUGS CONTRIBUTOR
-
- DISTCLEANFILES = mpopt.s aesopt.s blowfishopt.s sha1opt.s
-
-+BUILT_SOURCES = listobjs
-+
-+.PHONY: listobjs
-+listobjs:
-+ @echo $(libbeecrypt_la_OBJECTS) $(libbeecrypt_la_LIBADD) > $@
-+
- bench:
- (cd tests && $(MAKE) $(AM_MAKEFLAGS) bench)
-Index: beecrypt-4.1.2/base64.c
-===================================================================
---- beecrypt-4.1.2/base64.c.orig
-+++ beecrypt-4.1.2/base64.c
-@@ -253,7 +253,6 @@ char* b64encode(const void* data, size_t
- unsigned c;
-
- if (s == NULL) return NULL;
-- if (*s == '\0') return calloc(1, sizeof(*t));
-
- if (ns == 0) ns = strlen((const char*) s);
- nt = ((ns + 2) / 3) * 4;
-Index: beecrypt-4.1.2/c++/io/DataOutputStream.cxx
-===================================================================
---- beecrypt-4.1.2/c++/io/DataOutputStream.cxx.orig
-+++ beecrypt-4.1.2/c++/io/DataOutputStream.cxx
-@@ -126,8 +126,8 @@ void DataOutputStream::writeLong(javalon
- void DataOutputStream::writeChar(javaint v) throw (IOException)
- {
- _lock.lock();
-- out.write((v >> 8) && 0xff);
-- out.write((v ) && 0xff);
-+ out.write((v >> 8) & 0xff);
-+ out.write((v ) & 0xff);
- written += 2;
- _lock.unlock();
- }
diff --git a/beecrypt-4.1.2.tar.bz2 b/beecrypt-4.1.2.tar.bz2
deleted file mode 120000
index a99ac82..0000000
--- a/beecrypt-4.1.2.tar.bz2
+++ /dev/null
@@ -1 +0,0 @@
-/ipfs/bafybeigdwofduvmi6r5kgnoosciqozkpn6ap6iby6v2oemfygw4ykuqgdi
\ No newline at end of file
diff --git a/db_conversion.diff b/db_conversion.diff
new file mode 100644
index 0000000..f7b01b0
--- /dev/null
+++ b/db_conversion.diff
@@ -0,0 +1,170 @@
+--- ./lib/backend/bdb_ro.c.orig 2020-01-17 15:48:50.622349363 +0000
++++ ./lib/backend/bdb_ro.c 2020-01-17 15:49:20.514287856 +0000
+@@ -795,6 +795,7 @@ static unsigned int bdbro_pkgdbKey(dbiIn
+ struct rpmdbOps_s bdbro_dbops = {
+ .name = "bdb_ro",
+ .path = "Packages",
++ .readonly = 1,
+
+ .open = bdbro_Open,
+ .close = bdbro_Close,
+--- ./lib/backend/dbi.c.orig 2020-01-17 15:48:50.622349363 +0000
++++ ./lib/backend/dbi.c 2020-01-17 15:49:20.514287856 +0000
+@@ -105,11 +105,20 @@ dbDetectBackend(rpmdb rdb)
+ }
+
+ rdb->db_descr = rdb->db_ops->name;
++ rdb->db_ops_config = ops_config;
+
+ if (db_backend)
+ free(db_backend);
+ }
+
++int dbiNeedConversion(rpmdb rdb)
++{
++ if (!rdb->db_ops)
++ dbDetectBackend(rdb);
++ return rdb->db_ops->readonly && rdb->db_ops_config
++ && rdb->db_ops_config->path && !rdb->db_ops_config->readonly;
++}
++
+ const char * dbiName(dbiIndex dbi)
+ {
+ return dbi->dbi_file;
+--- ./lib/backend/dbi.h.orig 2020-01-17 15:48:50.622349363 +0000
++++ ./lib/backend/dbi.h 2020-01-17 15:49:49.886227415 +0000
+@@ -10,6 +10,7 @@ enum rpmdbFlags {
+ RPMDB_FLAG_JUSTCHECK = (1 << 0),
+ RPMDB_FLAG_REBUILD = (1 << 1),
+ RPMDB_FLAG_VERIFYONLY = (1 << 2),
++ RPMDB_FLAG_CONVERT = (1 << 3),
+ };
+
+ typedef enum dbCtrlOp_e {
+@@ -62,6 +63,7 @@ struct rpmdb_s {
+ int db_buildindex; /*!< Index rebuild indicator */
+
+ const struct rpmdbOps_s * db_ops; /*!< backend ops */
++ const struct rpmdbOps_s * db_ops_config; /*!< configured backend ops */
+
+ /* dbenv and related parameters */
+ void * db_dbenv; /*!< Backend private handle */
+@@ -201,6 +203,14 @@ RPM_GNUC_INTERNAL
+ const char * dbiName(dbiIndex dbi);
+
+ /** \ingroup dbi
++ * Check if the database needs to be converted to a different format
++ * @param db rpm database
++ * @return boolean
++ */
++RPM_GNUC_INTERNAL
++int dbiNeedConversion(rpmdb rdb);
++
++/** \ingroup dbi
+ * Open a database cursor.
+ * @param dbi index database handle
+ * @param flags DBC_WRITE if writing, or 0 (DBC_READ) for reading
+@@ -246,6 +256,7 @@ const void * idxdbKey(dbiIndex dbi, dbiC
+ struct rpmdbOps_s {
+ const char *name; /* backend name */
+ const char *path; /* main database name */
++ int readonly; /* cannot modify database */
+
+ int (*open)(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags);
+ int (*close)(dbiIndex dbi, unsigned int flags);
+--- ./lib/rpmdb.c.orig 2020-01-17 15:48:50.622349363 +0000
++++ ./lib/rpmdb.c 2020-01-17 15:53:52.241669094 +0000
+@@ -513,8 +513,16 @@ static int openDatabase(const char * pre
+ rpmsqActivate(1);
+ }
+
++ /* Convert the database if needed */
++ if (!db->db_pkgs && !justCheck && (mode & O_ACCMODE) == O_RDWR && dbiNeedConversion(db)) {
++ rpmlog(RPMLOG_WARNING, _("Converting database from %s to %s format\n"), db->db_ops->name, db->db_ops_config->name);
++ rc = rpmdbRebuild(prefix, NULL, NULL, RPMDB_FLAG_CONVERT);
++ db->db_ops = NULL; /* force re-detection of backend */
++ }
++
+ /* Just the primary Packages database opened here */
+- rc = pkgdbOpen(db, db->db_flags, NULL);
++ if (!rc)
++ rc = pkgdbOpen(db, db->db_flags, NULL);
+ if (!db->db_descr)
+ db->db_descr = "unknown db";
+ }
+@@ -2316,6 +2324,15 @@ int rpmdbAdd(rpmdb db, Header h)
+ if (db == NULL)
+ return 0;
+
++ if ((db->db_flags & RPMDB_FLAG_CONVERT) != 0) {
++ /* keep old instance numbers when converting */
++ hdrNum = headerGetInstance(h);
++ if (hdrNum == 0) {
++ ret = -1;
++ goto exit;
++ }
++ }
++
+ hdrBlob = headerExport(h, &hdrLen);
+ if (hdrBlob == NULL || hdrLen == 0) {
+ ret = -1;
+@@ -2331,7 +2348,8 @@ int rpmdbAdd(rpmdb db, Header h)
+
+ /* Add header to primary index */
+ dbc = dbiCursorInit(dbi, DBC_WRITE);
+- ret = pkgdbNew(dbi, dbc, &hdrNum);
++ if ((db->db_flags & RPMDB_FLAG_CONVERT) == 0)
++ ret = pkgdbNew(dbi, dbc, &hdrNum);
+ if (ret == 0)
+ ret = pkgdbPut(dbi, dbc, hdrNum, hdrBlob, hdrLen);
+ dbiCursorFree(dbi, dbc);
+@@ -2491,7 +2509,8 @@ static int rpmdbSetPermissions(char * sr
+ }
+
+ 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 newdbflags)
+ {
+ rpmdb olddb;
+ char * dbpath = NULL;
+@@ -2536,7 +2555,7 @@ int rpmdbRebuild(const char * prefix, rp
+ goto exit;
+ }
+ if (openDatabase(prefix, newdbpath, &newdb,
+- (O_RDWR | O_CREAT), 0644, RPMDB_FLAG_REBUILD)) {
++ (O_RDWR | O_CREAT), 0644, RPMDB_FLAG_REBUILD | newdbflags)) {
+ rc = 1;
+ goto exit;
+ }
+--- ./lib/rpmdb_internal.h.orig 2020-01-17 15:51:16.134030103 +0000
++++ ./lib/rpmdb_internal.h 2020-01-17 15:50:27.050144956 +0000
+@@ -63,11 +63,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 newdbflags extra flags for the new database
+ * @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 newdbflags);
+
+ /** \ingroup rpmdb
+ * Verify database components.
+--- ./lib/rpmts.c.orig 2020-01-17 15:51:37.813979967 +0000
++++ ./lib/rpmts.c 2020-01-17 15:51:48.925954269 +0000
+@@ -143,9 +143,9 @@ int rpmtsRebuildDB(rpmts ts)
+ txn = rpmtxnBegin(ts, RPMTXN_WRITE);
+ if (txn) {
+ if (!(ts->vsflags & RPMVSF_NOHDRCHK))
+- rc = rpmdbRebuild(ts->rootDir, ts, headerCheck);
++ rc = rpmdbRebuild(ts->rootDir, ts, headerCheck, 0);
+ else
+- rc = rpmdbRebuild(ts->rootDir, NULL, NULL);
++ rc = rpmdbRebuild(ts->rootDir, NULL, NULL, 0);
+ rpmtxnEnd(txn);
+ }
+ return rc;
diff --git a/db_ops_name.diff b/db_ops_name.diff
new file mode 100644
index 0000000..d3f32f4
--- /dev/null
+++ b/db_ops_name.diff
@@ -0,0 +1,248 @@
+--- ./lib/backend/db3.c.orig 2020-01-17 11:50:39.048477444 +0000
++++ ./lib/backend/db3.c 2020-01-17 11:58:15.351365745 +0000
+@@ -421,10 +421,6 @@ static int db_init(rpmdb rdb, const char
+ if (rdb->db_dbenv != NULL) {
+ rdb->db_opens++;
+ return 0;
+- } else {
+- /* On first call, set backend description to something... */
+- free(rdb->db_descr);
+- rasprintf(&rdb->db_descr, "db%u", DB_VERSION_MAJOR);
+ }
+
+ /*
+@@ -1426,6 +1422,9 @@ static rpmRC db3_pkgdbNew(dbiIndex dbi,
+ }
+
+ struct rpmdbOps_s db3_dbops = {
++ .name = "bdb",
++ .path = "Packages",
++
+ .open = db3_dbiOpen,
+ .close = db3_dbiClose,
+ .verify = db3_dbiVerify,
+--- ./lib/backend/dbi.c.orig 2020-01-17 11:54:38.207894769 +0000
++++ ./lib/backend/dbi.c 2020-01-17 11:56:45.555584517 +0000
+@@ -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,59 +51,58 @@ dbDetectBackend(rpmdb rdb)
+ const char *dbhome = rpmdbHome(rdb);
+ char *db_backend = rpmExpand("%{?_db_backend}", NULL);
+ char *path = NULL;
++ const struct rpmdbOps_s **ops, *ops_config;
+
+-#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");
++ rdb->db_ops = NULL;
++
++ ops_config = NULL;
++ for (ops = backends; *ops; ops++) {
++ if (rstreq(db_backend, (*ops)->name)) {
++ ops_config = *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);
++ /* if we have a configured backend, check it first */
++ if (ops_config && ops_config->path) {
++ path = rstrscat(NULL, dbhome, "/", ops_config->path, NULL);
++ if (access(path, F_OK) == 0)
++ rdb->db_ops = ops_config;
++ free(path);
+ }
+- 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 it did not match, check all available backends */
++ if (rdb->db_ops == NULL) {
++ for (ops = backends; *ops; ops++) {
++ if ((*ops)->path == NULL || *ops == ops_config)
++ continue;
+
+-#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);
++ path = rstrscat(NULL, dbhome, "/", (*ops)->path, NULL);
++ if (access(path, F_OK) == 0) {
++ rpmlog(RPMLOG_DEBUG,
++ _("Found %s %s database while attempting %s backend: "
++ "using %s backend.\n"),
++ (*ops)->name, (*ops)->path, db_backend, (*ops)->name);
++ rdb->db_ops = *ops;
++ }
++ free(path);
++ if (rdb->db_ops != NULL)
++ break;
++ }
+ }
+- free(path);
+-#endif
+
++ /* if we did not find a match, use the configured backend */
++ if (rdb->db_ops == NULL && ops_config)
++ rdb->db_ops = ops_config;
++
++ /* if everything failed fall back to dummydb */
+ if (rdb->db_ops == NULL) {
+ rdb->db_ops = &dummydb_dbops;
+- rpmlog(RPMLOG_DEBUG, "using dummy database, installs not possible\n");
++ rpmlog(RPMLOG_WARNING, "using dummy database, installs not possible\n");
+ }
+
++ rdb->db_descr = rdb->db_ops->name;
++
+ if (db_backend)
+ free(db_backend);
+ }
+--- ./lib/backend/dbi.h.orig 2020-01-17 11:52:17.960236465 +0000
++++ ./lib/backend/dbi.h 2020-01-17 11:57:36.907459407 +0000
+@@ -51,7 +51,7 @@ struct rpmdb_s {
+ int db_flags;
+ int db_mode; /*!< open mode */
+ int db_perms; /*!< open permissions */
+- char * db_descr; /*!< db backend description (for error msgs) */
++ const char * db_descr; /*!< db backend description (for error msgs) */
+ struct dbChk_s * db_checked;/*!< headerCheck()'ed package instances */
+ rpmdb db_next;
+ int db_opens;
+@@ -61,7 +61,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 */
+@@ -244,6 +244,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);
+--- ./lib/backend/dummydb.c.orig 2020-01-17 11:50:49.472452046 +0000
++++ ./lib/backend/dummydb.c 2020-01-17 11:52:08.048260613 +0000
+@@ -93,6 +93,9 @@ static const void * dummydb_idxdbKey(dbi
+
+
+ struct rpmdbOps_s dummydb_dbops = {
++ .name = "dummy",
++ .path = NULL,
++
+ .open = dummydb_Open,
+ .close = dummydb_Close,
+ .verify = dummydb_Verify,
+--- ./lib/backend/lmdb.c.orig 2020-01-17 11:50:45.808460969 +0000
++++ ./lib/backend/lmdb.c 2020-01-17 11:58:30.247329459 +0000
+@@ -137,10 +137,6 @@ static int db_init(rpmdb rdb, const char
+ if (rdb->db_dbenv != NULL) {
+ rdb->db_opens++;
+ return 0;
+- } else {
+- /* On first call, set backend description to something... */
+- free(rdb->db_descr);
+- rdb->db_descr = xstrdup("lmdb");
+ }
+
+ MDB_dbi maxdbs = 32;
+@@ -916,6 +912,9 @@ exit:
+ }
+
+ struct rpmdbOps_s lmdb_dbops = {
++ .name = "lmdb",
++ .path = "data.mdb",
++
+ .open = lmdb_dbiOpen,
+ .close = lmdb_dbiClose,
+ .verify = lmdb_dbiVerify,
+--- ./lib/backend/ndb/glue.c.orig 2020-01-17 11:51:09.708402746 +0000
++++ ./lib/backend/ndb/glue.c 2020-01-17 11:51:56.272289298 +0000
+@@ -482,6 +482,9 @@ static const void * ndb_idxdbKey(dbiInde
+
+
+ struct rpmdbOps_s ndb_dbops = {
++ .name = "ndb",
++ .path = "Packages.db",
++
+ .open = ndb_Open,
+ .close = ndb_Close,
+ .verify = ndb_Verify,
+--- ./lib/rpmdb.c.orig 2020-01-17 11:59:15.279219743 +0000
++++ ./lib/rpmdb.c 2020-01-17 12:00:36.495021876 +0000
+@@ -417,7 +417,6 @@ int rpmdbClose(rpmdb db)
+ db->db_fullpath = _free(db->db_fullpath);
+ db->db_checked = dbChkFree(db->db_checked);
+ db->db_indexes = _free(db->db_indexes);
+- db->db_descr = _free(db->db_descr);
+
+ if (next) {
+ *prev = next->db_next;
+@@ -482,7 +481,6 @@ static rpmdb newRpmdb(const char * root,
+ db->db_tags = dbiTags;
+ db->db_ndbi = sizeof(dbiTags) / sizeof(rpmDbiTag);
+ db->db_indexes = xcalloc(db->db_ndbi, sizeof(*db->db_indexes));
+- db->db_descr = xstrdup("unknown db");
+ db->nrefs = 0;
+ return rpmdbLink(db);
+ }
+@@ -517,6 +515,8 @@ static int openDatabase(const char * pre
+
+ /* Just the primary Packages database opened here */
+ rc = pkgdbOpen(db, db->db_flags, NULL);
++ if (!db->db_descr)
++ db->db_descr = "unknown db";
+ }
+
+ if (rc || justCheck || dbp == NULL)
diff --git a/disable_bdb.diff b/disable_bdb.diff
new file mode 100644
index 0000000..d44632e
--- /dev/null
+++ b/disable_bdb.diff
@@ -0,0 +1,15 @@
+--- configure.ac.orig 2020-01-17 12:25:06.451387587 +0000
++++ configure.ac 2020-01-17 12:25:17.707357939 +0000
+@@ -537,11 +537,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([
diff --git a/ndb_backport.diff b/ndb_backport.diff
new file mode 100644
index 0000000..24d6744
--- /dev/null
+++ b/ndb_backport.diff
@@ -0,0 +1,733 @@
+--- ./lib/backend/ndb/glue.c.orig 2020-01-23 12:47:46.527816289 +0000
++++ ./lib/backend/ndb/glue.c 2020-02-03 12:57:34.817304473 +0000
+@@ -52,8 +52,8 @@ static void closeEnv(rpmdb rdb)
+ if (ndbenv->data)
+ free(ndbenv->data);
+ free(ndbenv);
++ rdb->db_dbenv = 0;
+ }
+- rdb->db_dbenv = 0;
+ }
+
+ static struct ndbEnv_s *openEnv(rpmdb rdb)
+@@ -80,6 +80,31 @@ static int ndb_Close(dbiIndex dbi, unsig
+ 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,12 +155,13 @@ static int ndb_Open(rpmdb rdb, rpmDbiTag
+ }
+ 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 */
+ 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;
+@@ -144,6 +170,7 @@ static int ndb_Open(rpmdb rdb, rpmDbiTag
+ } 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, rpmDbiTag
+ }
+ 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;
+@@ -179,7 +208,13 @@ static int ndb_Open(rpmdb rdb, rpmDbiTag
+
+ 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)
+@@ -396,15 +431,15 @@ static rpmRC ndb_idxdbIter(dbiIndex dbi,
+ }
+ 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);
+--- ./lib/backend/ndb/rpmpkg.c.orig 2019-11-13 09:19:29.306710577 +0000
++++ ./lib/backend/ndb/rpmpkg.c 2020-01-23 12:48:59.739630414 +0000
+@@ -7,7 +7,6 @@
+ #include
+ #include
+ #include
+-#include
+ #include
+ #include
+ #include
+@@ -19,10 +18,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);
+
+@@ -49,23 +44,19 @@ typedef struct rpmpkgdb_s {
+ unsigned int nextpkgidx;
+
+ struct pkgslot_s *slots;
+- unsigned int aslots; /* allocated slots */
+ unsigned int nslots; /* used slots */
+
+ unsigned int *slothash;
+ 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)
+ {
+@@ -144,10 +135,6 @@ static int rpmpkgReadHeader(rpmpkgdb pkg
+ 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;
+@@ -200,6 +187,7 @@ static inline unsigned int hashpkgidx(un
+ return h;
+ }
+
++/* (re-)create a hash mapping pkgidx numbers to slots */
+ static int rpmpkgHashSlots(rpmpkgdb pkgdb)
+ {
+ unsigned int nslots, num;
+@@ -208,14 +196,14 @@ static int rpmpkgHashSlots(rpmpkgdb pkgd
+ 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 {
+@@ -228,8 +216,6 @@ static int rpmpkgHashSlots(rpmpkgdb pkgd
+ ;
+ hash[h] = i + 1;
+ }
+- pkgdb->slothash = hash;
+- pkgdb->nslothash = num;
+ return RPMRC_OK;
+ }
+
+@@ -247,10 +233,6 @@ static int rpmpkgReadSlots(rpmpkgdb pkgd
+ free(pkgdb->slots);
+ pkgdb->slots = 0;
+ }
+- if (pkgdb->slothash) {
+- free(pkgdb->slothash);
+- pkgdb->slothash = 0;
+- }
+ pkgdb->nslots = 0;
+ pkgdb->freeslot = 0;
+
+@@ -262,8 +244,7 @@ static int rpmpkgReadSlots(rpmpkgdb pkgd
+ 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);
+@@ -299,7 +280,7 @@ static int rpmpkgReadSlots(rpmpkgdb pkgd
+ }
+ }
+ pkgdb->nslots = i;
+- pkgdb->slotorder = SLOTORDER_UNORDERED; /* XXX: always order? */
++ pkgdb->ordered = 0;
+ pkgdb->fileblks = fileblks;
+ pkgdb->freeslot = freeslot;
+ if (rpmpkgHashSlots(pkgdb)) {
+@@ -317,15 +298,13 @@ static int orderslots_blkoff_cmp(const v
+ 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);
+ }
+
+@@ -340,6 +319,8 @@ static inline pkgslot *rpmpkgFindSlot(rp
+ return 0;
+ }
+
++/* Find an empty space for blkcnt blocks. If dontprepend is true, ignore
++ the space between the slot area and the first blob */
+ static int rpmpkgFindEmptyOffset(rpmpkgdb pkgdb, unsigned int pkgidx, unsigned int blkcnt, unsigned *blkoffp, pkgslot **oldslotp, int dontprepend)
+ {
+ unsigned int i, nslots = pkgdb->nslots;
+@@ -348,8 +329,8 @@ static int rpmpkgFindEmptyOffset(rpmpkgd
+ 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;
+@@ -382,14 +363,15 @@ static int rpmpkgFindEmptyOffset(rpmpkgd
+ return RPMRC_OK;
+ }
+
++/* verify the blobs to the left and right of a free area */
+ static int rpmpkgNeighbourCheck(rpmpkgdb pkgdb, unsigned int blkoff, unsigned int blkcnt, unsigned int *newblkcnt)
+ {
+ unsigned int i, nslots = pkgdb->nslots;
+ 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++) {
+@@ -413,7 +395,7 @@ static int rpmpkgNeighbourCheck(rpmpkgdb
+ if (right && rpmpkgVerifyblob(pkgdb, right->pkgidx, right->blkoff, right->blkcnt) != RPMRC_OK)
+ return RPMRC_FAIL;
+ *newblkcnt = right ? right->blkoff - blkoff : blkcnt;
+- /* bounds are intect. free area. */
++ /* bounds are intact. ok to zero area. */
+ return RPMRC_OK;
+ }
+
+@@ -433,6 +415,7 @@ static int rpmpkgWriteslot(rpmpkgdb pkgd
+ return RPMRC_FAIL;
+ }
+ pkgdb->generation++;
++ /* rpmpkgFsync() is done by rpmpkgWriteHeader() */
+ if (rpmpkgWriteHeader(pkgdb)) {
+ return RPMRC_FAIL;
+ }
+@@ -527,7 +510,7 @@ static int rpmpkgValidateZero(rpmpkgdb p
+
+ /*** 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)
+@@ -536,10 +519,10 @@ static int rpmpkgValidateZero(rpmpkgdb p
+ #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;
+@@ -555,7 +538,7 @@ static int rpmpkgReadBlob(rpmpkgdb pkgdb
+ 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 */
+@@ -600,8 +583,8 @@ static int rpmpkgReadBlob(rpmpkgdb pkgdb
+ }
+ if (bloblp)
+ *bloblp = bloblen;
+- if (tstampp)
+- *tstampp = tstamp;
++ if (generationp)
++ *generationp = generation;
+ return RPMRC_OK;
+ }
+
+@@ -684,14 +667,14 @@ static int rpmpkgMoveBlob(rpmpkgdb pkgdb
+ 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;
+ }
+@@ -703,15 +686,15 @@ static int rpmpkgMoveBlob(rpmpkgdb pkgdb
+ 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 */
+@@ -729,7 +712,7 @@ static int rpmpkgAddSlotPage(rpmpkgdb pk
+ if (rpmpkgMoveBlob(pkgdb, slot, newblkoff)) {
+ return RPMRC_FAIL;
+ }
+- rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF);
++ rpmpkgOrderSlots(pkgdb);
+ }
+
+ /* make sure our new page is empty */
+@@ -958,6 +941,7 @@ static int rpmpkgPutInternal(rpmpkgdb pk
+ pkgslot *oldslot;
+
+ /* we always read all slots when writing, just in case */
++ /* this also will set pkgdb->freeslot */
+ if (rpmpkgReadSlots(pkgdb)) {
+ return RPMRC_FAIL;
+ }
+@@ -981,14 +965,15 @@ static int rpmpkgPutInternal(rpmpkgdb pk
+ 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;
+ }
++ /* update nextpkgidx if needed */
++ if (pkgidx >= pkgdb->nextpkgidx) {
++ pkgdb->nextpkgidx = pkgidx + 1;
++ }
+ /* write slot */
+ slotno = oldslot ? oldslot->slotno : pkgdb->freeslot;
+- if (!slotno) {
+- return RPMRC_FAIL;
+- }
+ if (rpmpkgWriteslot(pkgdb, slotno, pkgidx, blkoff, blkcnt)) {
+ free(pkgdb->slots);
+ pkgdb->slots = 0;
+@@ -1006,7 +991,7 @@ static int rpmpkgPutInternal(rpmpkgdb pk
+ /* 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;
+@@ -1023,7 +1008,7 @@ static int rpmpkgDelInternal(rpmpkgdb pk
+ if (rpmpkgReadSlots(pkgdb)) {
+ return RPMRC_FAIL;
+ }
+- rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF);
++ rpmpkgOrderSlots(pkgdb);
+ slot = rpmpkgFindSlot(pkgdb, pkgidx);
+ if (!slot) {
+ return RPMRC_OK;
+@@ -1049,9 +1034,10 @@ static int rpmpkgDelInternal(rpmpkgdb pk
+ }
+ slot->blkoff = 0;
+ slot->blkcnt = 0;
++ /* try to move the last two slots, the bigger one first */
+ slot = pkgdb->slots + pkgdb->nslots - 2;
+ if (slot->blkcnt < slot[1].blkcnt)
+- slot++; /* bigger slot first */
++ slot++; /* bigger slot first */
+ for (i = 0; i < 2; i++, slot++) {
+ if (slot == pkgdb->slots + pkgdb->nslots)
+ slot -= 2;
+@@ -1065,7 +1051,7 @@ static int rpmpkgDelInternal(rpmpkgdb pk
+ blkoff += slot->blkcnt;
+ blkcnt -= slot->blkcnt;
+ }
+- rpmpkgOrderSlots(pkgdb, SLOTORDER_BLKOFF);
++ rpmpkgOrderSlots(pkgdb);
+ } else {
+ slot->blkoff = 0;
+ slot->blkcnt = 0;
+@@ -1104,7 +1090,7 @@ static int rpmpkgListInternal(rpmpkgdb p
+ *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++) {
+@@ -1115,6 +1101,22 @@ static int rpmpkgListInternal(rpmpkgdb p
+ 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;
+@@ -1127,10 +1129,6 @@ int rpmpkgGet(rpmpkgdb pkgdb, unsigned i
+ 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 +1141,7 @@ int rpmpkgPut(rpmpkgdb pkgdb, unsigned i
+ }
+ 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;
+ }
+@@ -1184,6 +1173,16 @@ int rpmpkgList(rpmpkgdb pkgdb, unsigned
+ 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))
+@@ -1233,64 +1232,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
+--- ./lib/backend/ndb/rpmpkg.h.orig 2019-06-26 14:17:31.406985703 +0000
++++ ./lib/backend/ndb/rpmpkg.h 2020-01-23 12:48:20.919728972 +0000
+@@ -12,6 +12,7 @@ int rpmpkgGet(rpmpkgdb pkgdb, unsigned i
+ 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);
+--- ./lib/backend/ndb/rpmxdb.c.orig 2019-11-13 09:19:29.307710583 +0000
++++ ./lib/backend/ndb/rpmxdb.c 2020-01-23 12:48:20.919728972 +0000
+@@ -224,11 +224,33 @@ static int usedslots_cmp(const void *a,
+ 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)
+- 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);
++ if (rpmxdbReadHeaderRaw(xdb, &generation, &slotnpages, &pagesize, &usergeneration))
+ 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;
+@@ -922,6 +930,43 @@ int rpmxdbDelBlob(rpmxdb xdb, unsigned i
+ rpmxdbUnlock(xdb, 1);
+ 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)
+ {
+--- ./lib/backend/ndb/rpmxdb.h.orig 2019-11-13 09:19:29.307710583 +0000
++++ ./lib/backend/ndb/rpmxdb.h 2020-01-23 12:48:20.919728972 +0000
+@@ -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);
diff --git a/python-rpm.spec b/python-rpm.spec
index ab6775b..109159d 100644
--- a/python-rpm.spec
+++ b/python-rpm.spec
@@ -1,7 +1,7 @@
#
# spec file for package python-rpm
#
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LINUX GmbH, Nuernberg, Germany.
# Copyright (c) 2017 Neal Gompa .
#
# All modifications and additions to the file contributed by third parties
@@ -34,6 +34,7 @@ BuildRequires: libacl-devel
BuildRequires: libbz2-devel
BuildRequires: libcap-devel
BuildRequires: libelf-devel
+BuildRequires: libgcrypt-devel
BuildRequires: libselinux-devel
BuildRequires: libsemanage-devel
BuildRequires: libtool
diff --git a/rpm.changes b/rpm.changes
index 16acd2d..8643932 100644
--- a/rpm.changes
+++ b/rpm.changes
@@ -1,4 +1,25 @@
-------------------------------------------------------------------
+Fri Jan 17 11:27:17 CET 2020 - mls@suse.de
+
+- Use libgcrypt as crypto library instead of beecrypt
+ * dropped patch: beecrypt-4.1.2-build.diff
+ * dropped patch: beecrypt-4.1.2.diff
+- Rewrite rpmqpack to use rpm's database interface
+ modified patch: rpmqpack.diff
+- Backport database detection code from upstream
+ new patch: db_ops_name.diff
+- Backport read-only BerkeleyDB code
+ new patch: bdb_ro.diff
+- Enable ndb backend
+- Backport bdb disabling fix
+ new patch: disable_bdb.diff
+- Backport ndb improvements
+ new patch: ndb_backport.diff
+- Backport automatic db conversion
+ new patch: db_conversion.diff
+- Disable the BerkeleyDB backend and switch over to 'ndb'
+
+-------------------------------------------------------------------
Fri Dec 6 15:30:48 CET 2019 - mls@suse.de
- disable pythondist requires generator for now
diff --git a/rpm.spec b/rpm.spec
index dc561b4..da1f9e8 100644
--- a/rpm.spec
+++ b/rpm.spec
@@ -1,7 +1,7 @@
#
# spec file for package rpm
#
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -20,6 +20,7 @@
%{?!_fillupdir:%define _fillupdir /var/adm/fillup-templates}
%global librpmsover 9
+%global without_bdb 1
Name: rpm
BuildRequires: binutils
@@ -35,6 +36,7 @@ BuildRequires: libbz2-devel
BuildRequires: libcap-devel
BuildRequires: libdw-devel
BuildRequires: libelf-devel
+BuildRequires: libgcrypt-devel
BuildRequires: libselinux-devel
BuildRequires: libsemanage-devel
BuildRequires: libtool
@@ -66,14 +68,11 @@ Source1: RPM-HOWTO.tar.bz2
Source5: rpmsort
Source8: rpmconfigcheck
Source9: sysconfig.services-rpm
-Source10: beecrypt-4.1.2.tar.bz2
Source11: db-4.8.30.tar.bz2
Source12: baselibs.conf
Source13: rpmconfigcheck.service
-Patch1: beecrypt-4.1.2.diff
Patch2: db.diff
Patch3: rpm-4.12.0.1-fix-bashisms.patch
-Patch4: beecrypt-4.1.2-build.diff
Patch5: usr-lib-sysimage-rpm.patch
# quilt patches start here
Patch11: debugedit.diff
@@ -127,6 +126,11 @@ Patch102: emptymanifest.diff
Patch103: find-lang-qt-qm.patch
Patch109: pythondistdeps.diff
Patch117: findsupplements.diff
+Patch118: db_ops_name.diff
+Patch119: bdb_ro.diff
+Patch120: disable_bdb.diff
+Patch121: ndb_backport.diff
+Patch122: db_conversion.diff
Patch6464: auto-config-update-aarch64-ppc64le.diff
BuildRoot: %{_tmppath}/%{name}-%{version}-build
#
@@ -212,19 +216,17 @@ and requires some packages that are usually required.
%prep
%setup -q -n rpm-%{version}
rm -rf sqlite
-rm -rf beecrypt
-tar xjf %{SOURCE10}
+%if 0%{?!without_bdb:1}
tar xjf %{SOURCE11}
ln -s db-4.8.30 db
cd db
%patch2 -p1
cd ..
-ln -s beecrypt-4.1.2 beecrypt
chmod -R u+w db/*
rm -f rpmdb/db.h
-%patch -P 1
+cp config.guess config.sub db/dist/
+%endif
%patch3 -p1
-%patch -P 4
%patch5 -p1
%patch -P 11 -P 12 -P 13 -P 15 -P 16 -P 18
%patch -P 20 -P 21 -P 24 -P 25 -P 26 -P 27 -P 29
@@ -237,13 +239,12 @@ rm -f rpmdb/db.h
%patch -P 93 -P 94 -P 99
%patch -P 100 -P 102 -P 103
%patch -P 109 -P 117
+%patch -P 118 -P 119 -P 120 -P 121 -P 122
%ifarch aarch64 ppc64le riscv64
%patch6464
%endif
-cp config.guess config.sub db/dist/
-cp config.guess config.sub beecrypt/
tar -xjvf %{SOURCE1}
rm -f m4/libtool.m4
rm -f m4/lt*.m4
@@ -261,13 +262,6 @@ BUILDTARGET="--build=%{_target_cpu}-suse-linux-gnueabi"
BUILDTARGET="--build=%{_target_cpu}-suse-linux"
%endif
-#cp -p /usr/share/gettext/config.rpath .
-cp autogen.sh beecrypt
-pushd beecrypt
-./autogen.sh --disable-dependency-tracking --with-pic --without-python $BUILDTARGET
-make %{?_smp_mflags}
-popd
-
autoreconf -fi
./configure --disable-dependency-tracking --prefix=%{_prefix} --mandir=%{_mandir} --infodir=%{_infodir} \
--libdir=%{_libdir} --sysconfdir=/etc --localstatedir=/var --sharedstatedir=/var/lib \
@@ -276,11 +270,16 @@ autoreconf -fi
--with-rundir=/run \
--without-archive \
--with-selinux \
---with-internal-beecrypt \
+--with-crypto=libgcrypt \
--with-acl \
--with-cap \
+--enable-shared \
+--enable-ndb \
+--enable-bdb-ro \
--enable-zstd \
---enable-shared %{?with_python: --enable-python} $BUILDTARGET
+%{?without_bdb: --enable-bdb=no} \
+%{?with_python: --enable-python} \
+$BUILDTARGET
rm po/de.gmo
make %{?_smp_mflags}
@@ -292,7 +291,9 @@ ln -s ../share/locale %{buildroot}/usr/lib/locale
%make_install
mkdir -p %{buildroot}/bin
ln -s /usr/bin/rpm %{buildroot}/bin/rpm
+%if 0%{?!without_bdb:1}
install -m 644 db3/db.h %{buildroot}/usr/include/rpm
+%endif
# remove .la file and the static variant of libpopt
# have to remove the dependency from other .la files as well
for f in %{buildroot}/%{_libdir}/*.la; do
@@ -362,17 +363,24 @@ sh %{buildroot}/usr/lib/rpm/find-lang.sh %{buildroot} rpm
# so we need to enforce the platform here.
echo -n "%{_target_cpu}-suse-linux-gnueabi" > %{buildroot}/etc/rpm/platform
%endif
+%if 0%{?without_bdb:1}
+# make ndb the default database backend
+echo "setting the default database backend to 'ndb'"
+sed -i -e '/_db_backend/s/bdb/ndb/' %{buildroot}/usr/lib/rpm/macros
+%endif
%post
%{fillup_only -an services}
# var/lib/rpm migration: set forwards compatible symlink for /usr/lib/sysimage/rpm so scriptlets in same transaction will still work
-if test ! -L var/lib/rpm -a -f var/lib/rpm/Packages -a ! -f usr/lib/sysimage/rpm/Packages ; then
- rmdir usr/lib/sysimage/rpm
- ln -s ../../../var/lib/rpm usr/lib/sysimage/rpm
+if test ! -L var/lib/rpm -a ! -f usr/lib/sysimage/rpm/Packages -a ! -f usr/lib/sysimage/rpm/Packages.db ; then
+ if test -f var/lib/rpm/Packages -o -f var/lib/rpm/Packages.db ; then
+ rmdir usr/lib/sysimage/rpm
+ ln -s ../../../var/lib/rpm usr/lib/sysimage/rpm
+ fi
fi
-test -f usr/lib/sysimage/rpm/Packages || rpmdb --initdb
+test -f usr/lib/sysimage/rpm/Packages -o -f usr/lib/sysimage/rpm/Packages.db || rpmdb --initdb
test -e var/lib/rpm || ln -s ../../usr/lib/sysimage/rpm var/lib/rpm
%posttrans
@@ -381,7 +389,7 @@ if test ! -L var/lib/rpm ; then
# delete no longer maintained databases
rm -f var/lib/rpm/Filemd5s var/lib/rpm/Filedigests var/lib/rpm/Requireversion var/lib/rpm/Provideversion
- if test -f var/lib/rpm/Packages ; then
+ if test -f var/lib/rpm/Packages -o -f var/lib/rpm/Packages.db ; then
echo "migrating rpmdb from /var/lib/rpm to /usr/lib/sysimage/rpm..."
# remove forwards compatible symlink
diff --git a/rpmqpack.diff b/rpmqpack.diff
index d336845..726d695 100644
--- a/rpmqpack.diff
+++ b/rpmqpack.diff
@@ -50,9 +50,9 @@
+
+.SH AUTHOR
+Michael Schroeder
---- ./rpmqpack.c.orig 2017-12-01 15:04:13.398003904 +0000
-+++ ./rpmqpack.c 2017-12-01 15:04:13.398003904 +0000
-@@ -0,0 +1,59 @@
+--- ./rpmqpack.c.orig 2019-12-06 10:14:03.989178873 +0000
++++ ./rpmqpack.c 2019-12-06 10:32:16.430275015 +0000
+@@ -0,0 +1,60 @@
+#include
+#include
+#include
@@ -60,55 +60,56 @@
+#include
+#include
+
-+#include
-+
-+DBT key;
-+DBT data;
++#include
++#include
++#include
+
+int
+main(int argc, char **argv)
+{
-+ DB *db = 0;
-+ DBC *dbc = 0;
+ int ret = 0;
++ rpmts ts;
+
-+ if (db_create(&db, 0, 0))
++ rpmDefineMacro(NULL, "_dbpath /var/lib/rpm", 0);
++ ts = rpmtsCreate();
++ if (!ts)
+ {
-+ perror("db_create");
++ fprintf(stderr, "rpmtsCreate failed\n");
+ exit(1);
+ }
-+ if (db->open(db, 0, "/var/lib/rpm/Name", 0, DB_UNKNOWN, DB_RDONLY, 0664))
++ if (rpmtsOpenDB(ts, O_RDONLY))
+ {
-+ perror("db->open");
++ perror("rpmtsOpenDB");
+ exit(1);
+ }
-+ if (argc == 1)
++ if (argc <= 1)
+ {
-+ if (db->cursor(db, NULL, &dbc, 0))
++ rpmdbIndexIterator ii;
++ ii = rpmdbIndexIteratorInit(rpmtsGetRdb(ts), RPMDBI_NAME);
++ if (ii)
+ {
-+ perror("db->cursor");
-+ exit(1);
++ const void *key = 0;
++ size_t keylen = 0;
++ while ((rpmdbIndexIteratorNext(ii, &key, &keylen)) == 0)
++ printf("%*.*s\n", (int)keylen, (int)keylen, (char *)key);
+ }
-+ while (dbc->c_get(dbc, &key, &data, DB_NEXT) == 0)
-+ printf("%*.*s\n", (int)key.size, (int)key.size, (char *)key.data);
-+ dbc->c_close(dbc);
++ rpmdbIndexIteratorFree(ii);
+ }
+ else
+ {
+ argc--;
+ while (argc--)
+ {
++ rpmdbMatchIterator mi;
+ argv++;
-+ key.data = (void *)*argv;
-+ key.size = strlen(*argv);
-+ data.data = NULL;
-+ data.size = 0;
-+ if (db->get(db, 0, &key, &data, 0) == 0)
++ mi = rpmdbInitIterator(rpmtsGetRdb(ts), RPMDBI_NAME, (void *)*argv, strlen(*argv));
++ if (mi && rpmdbGetIteratorCount(mi))
+ printf("%s\n", *argv);
-+ else
++ else
+ ret = 1;
-+ }
++ rpmdbFreeIterator(mi);
++ }
+ }
-+ db->close(db, 0);
++ rpmtsFree(ts);
+ return ret;
+}