Michael Schröder
160a8622a7
OBS-URL: https://build.opensuse.org/package/show/Base:System/rpm?expand=0&rev=525
880 lines
22 KiB
Diff
880 lines
22 KiB
Diff
--- ./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,814 @@
|
|
+#include "system.h"
|
|
+
|
|
+#include <sys/types.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
+#include <stdlib.h>
|
|
+#include <stdint.h>
|
|
+#include <unistd.h>
|
|
+#include <fcntl.h>
|
|
+#include <errno.h>
|
|
+
|
|
+#include "lib/rpmdb_internal.h"
|
|
+#include <rpm/rpmstring.h>
|
|
+#include <rpm/rpmlog.h>
|
|
+
|
|
+#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_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;
|