1 #include "system.h"
2 
3 #include <sys/types.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include <stdint.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <errno.h>
11 
12 #include "lib/rpmdb_internal.h"
13 #include <rpm/rpmstring.h>
14 #include <rpm/rpmlog.h>
15 
16 #define BDB_HASH 0
17 #define BDB_BTREE 1
18 
19 struct dbiCursor_s;
20 
21 struct bdb_kv {
22     unsigned char *kv;
23     unsigned int len;
24 };
25 
26 struct bdb_db {
27     int fd;			/* file descriptor of database */
28     int type;			/* BDB_HASH / BDB_BTREE */
29     unsigned int pagesize;
30     unsigned int lastpage;
31     int swapped;		/* different endianess? */
32     /* btree */
33     unsigned int root;		/* root page of the b-tree */
34     /* hash */
35     unsigned int maxbucket;
36     unsigned int highmask;
37     unsigned int lowmask;
38     unsigned int spares[32];	/* spare pages for each splitpoint */
39 };
40 
41 struct bdb_cur {
42     struct bdb_db *db;
43 
44     struct bdb_kv key;		/* key and value from the db entry */
45     struct bdb_kv val;
46 
47     unsigned char *page;	/* the page we're looking at */
48 
49     unsigned char *ovpage;
50     struct bdb_kv keyov;	/* space to store oversized keys/values */
51     struct bdb_kv valov;
52 
53     int state;			/* 1: onpage, -1: error */
54     int idx;			/* entry index */
55     int numidx;			/* number of entries on the page */
56     int islookup;		/* we're doing a lookup operation */
57 
58     /* hash */
59     unsigned int bucket;	/* current bucket */
60 };
61 
62 
swap16(unsigned char * p)63 static void swap16(unsigned char *p)
64 {
65     int a = p[0];
66     p[0] = p[1];
67     p[1] = a;
68 }
69 
swap32(unsigned char * p)70 static void swap32(unsigned char *p)
71 {
72     int a = p[0];
73     p[0] = p[3];
74     p[3] = a;
75     a = p[1];
76     p[1] = p[2];
77     p[2] = a;
78 }
79 
swap32_2(unsigned char * p)80 static void swap32_2(unsigned char *p)
81 {
82     swap32(p);
83     swap32(p + 4);
84 }
85 
bdb_swapmetapage(struct bdb_db * db,unsigned char * page)86 static void bdb_swapmetapage(struct bdb_db *db, unsigned char *page)
87 {
88     int i, maxi = db->type == BDB_HASH ? 224 : 92;
89     for (i = 8; i < maxi; i += 4)
90         swap32((unsigned char *)(page + i));
91     swap32((unsigned char *)(page + 24));
92 }
93 
bdb_swappage(struct bdb_db * db,unsigned char * page)94 static void bdb_swappage(struct bdb_db *db, unsigned char *page)
95 {
96     unsigned int pagesize = db->pagesize;
97     int type, i, nent, off;
98     swap32(page + 8);		/* page number */
99     swap32_2(page + 12);	/* prev/next page */
100     swap16(page + 20);		/* nitems */
101     swap16(page + 22);		/* highfree */
102 
103     type = page[25];
104     if (type != 2 && type != 13 && type != 3 && type != 5)
105 	return;
106     nent = *(uint16_t *)(page + 20);
107     if (nent > (pagesize - 26) / 2)
108 	nent = (pagesize - 26) / 2;
109     for (i = 0; i < nent; i++) {
110 	int minoff = 26 + nent * 2;
111 	swap16(page + 26 + i * 2);		/* offset */
112 	off = *(uint16_t *)(page + 26 + i * 2);
113 	if (off < minoff || off >= pagesize)
114 	    continue;
115 	if (type == 2 || type == 13) {		/* hash */
116 	    if (page[off] == 3 && off + 12 <= pagesize)
117 	        swap32_2(page + off + 4);	/* page no/length */
118 	} else if (type == 3) {			/* btree internal */
119 	    if (off + 12 > pagesize)
120 	        continue;
121 	    swap16(page + off);			/* length */
122 	    swap32_2(page + off + 4);		/* page no/num recs */
123 	    if (page[off + 2] == 3 && off + 24 <= pagesize)
124 		swap32_2(page + off + 16);	/* with overflow page/length */
125 	} else if (type == 5) {			/* btree leaf */
126 	    if (off + 3 <= pagesize && page[off + 2] == 1)
127 		swap16(page + off);		/* length */
128 	    else if (off + 12 <= pagesize && page[off + 2] == 3)
129 		swap32_2(page + off + 4);	/* overflow page/length */
130 	}
131     }
132 }
133 
bdb_getpage(struct bdb_db * db,unsigned char * page,unsigned int pageno)134 static int bdb_getpage(struct bdb_db *db, unsigned char *page, unsigned int pageno)
135 {
136     if (!pageno || pageno > db->lastpage)
137 	return -1;
138     if (pread(db->fd, page, db->pagesize, (off_t)pageno * db->pagesize) != db->pagesize) {
139 	rpmlog(RPMLOG_ERR, "pread: %s\n", strerror(errno));
140 	return -1;
141     }
142     if (db->swapped)
143 	bdb_swappage(db, page);
144     if (pageno != *(uint32_t *)(page + 8))
145 	return -1;
146     return 0;
147 }
148 
bdb_close(struct bdb_db * db)149 static void bdb_close(struct bdb_db *db)
150 {
151     if (db->fd >= 0)
152 	close(db->fd);
153     free(db);
154 }
155 
bdb_open(const char * name)156 static struct bdb_db *bdb_open(const char *name)
157 {
158     uint32_t meta[512 / 4];
159     int i, fd;
160     struct bdb_db *db;
161 
162     fd = open(name, O_RDONLY);
163     if (fd == -1) {
164 	return NULL;
165     }
166     db = xcalloc(1, sizeof(*db));
167     db->fd = fd;
168     if (pread(fd, meta, 512, 0) != 512) {
169 	rpmlog(RPMLOG_ERR, "%s: pread: %s\n", name, strerror(errno));
170 	bdb_close(db);
171 	return NULL;
172     }
173     if (meta[3] == 0x00061561 || meta[3] == 0x61150600) {
174 	db->type = BDB_HASH;
175 	db->swapped = meta[3] == 0x61150600;
176     } else if (meta[3] == 0x00053162 || meta[3] == 0x62310500) {
177 	db->type = BDB_BTREE;
178 	db->swapped = meta[3] == 0x62310500;
179     } else {
180 	rpmlog(RPMLOG_ERR, "%s: not a berkeley db hash/btree database\n", name);
181 	bdb_close(db);
182 	return NULL;
183     }
184     if (db->swapped)
185         bdb_swapmetapage(db, (unsigned char *)meta);
186     db->pagesize = meta[5];
187     db->lastpage = meta[8];
188     if (db->type == BDB_HASH) {
189 	if (meta[4] < 8 || meta[4] > 10) {
190 	    rpmlog(RPMLOG_ERR, "%s: unsupported hash version %d\n", name, meta[4]);
191 	    bdb_close(db);
192 	    return NULL;
193 	}
194 	db->maxbucket = meta[18];
195 	db->highmask = meta[19];
196 	db->lowmask = meta[20];
197 	for (i = 0; i < 32; i++)
198 	    db->spares[i] = meta[24 + i];
199     }
200     if (db->type == BDB_BTREE) {
201 	if (meta[4] < 9 || meta[4] > 10) {
202 	    rpmlog(RPMLOG_ERR, "%s: unsupported btree version %d\n", name, meta[4]);
203 	    bdb_close(db);
204 	    return NULL;
205 	}
206 	db->root = meta[22];
207     }
208     return db;
209 }
210 
211 
212 /****** overflow handling ******/
213 
ovfl_get(struct bdb_cur * cur,struct bdb_kv * kv,struct bdb_kv * ov,uint32_t * pagenolen)214 static int ovfl_get(struct bdb_cur *cur, struct bdb_kv *kv, struct bdb_kv *ov, uint32_t *pagenolen)
215 {
216     unsigned int pageno = pagenolen[0];
217     unsigned int len = pagenolen[1];
218     unsigned int plen;
219     unsigned char *p;
220 
221     if (len == 0)
222 	return -1;
223     if (len > ov->len) {
224 	if (ov->kv)
225 	    ov->kv = xrealloc(ov->kv, len);
226 	else
227 	    ov->kv = xmalloc(len);
228 	ov->len = len;
229     }
230     if (!cur->ovpage)
231 	cur->ovpage = xmalloc(cur->db->pagesize);
232     p = ov->kv;
233     while (len > 0) {
234 	if (bdb_getpage(cur->db, cur->ovpage, pageno))
235 	    return -1;
236 	if (cur->ovpage[25] != 7)
237 	    return -1;
238 	plen = *(uint16_t *)(cur->ovpage + 22);
239 	if (plen + 26 > cur->db->pagesize || plen > len)
240 	    return -1;
241 	memcpy(p, cur->ovpage + 26, plen);
242 	p += plen;
243 	len -= plen;
244 	pageno = *(uint32_t *)(cur->ovpage + 16);
245     }
246     if (kv) {
247 	kv->kv = ov->kv;
248 	kv->len = pagenolen[1];
249     }
250     return 0;
251 }
252 
253 
254 /****** hash implementation ******/
255 
hash_bucket_to_page(struct bdb_db * db,unsigned int bucket)256 static int hash_bucket_to_page(struct bdb_db *db, unsigned int bucket)
257 {
258     unsigned int b;
259     int i = 0;
260     for (b = bucket; b; b >>= 1)
261 	i++;
262     return bucket + db->spares[i];
263 }
264 
hash_lookup(struct bdb_cur * cur,const unsigned char * key,unsigned int keyl)265 static int hash_lookup(struct bdb_cur *cur, const unsigned char *key, unsigned int keyl)
266 {
267     uint32_t bucket;
268     unsigned int pg, i;
269     cur->state = -1;
270     for (bucket = 0, i = 0; i < keyl; i++)
271 	bucket = (bucket * 16777619) ^ key[i];
272     bucket &= cur->db->highmask;
273     if (bucket > cur->db->maxbucket)
274 	bucket &= cur->db->lowmask;
275     cur->bucket = bucket;
276     pg = hash_bucket_to_page(cur->db, bucket);
277     if (bdb_getpage(cur->db, cur->page, pg))
278 	return -1;
279     if (cur->page[25] != 8 && cur->page[25] != 13)
280 	return -1;
281     cur->idx = (unsigned int)-2;
282     cur->numidx = *(uint16_t *)(cur->page + 20);
283     cur->state = 1;
284     return 0;
285 }
286 
hash_getkv(struct bdb_cur * cur,struct bdb_kv * kv,struct bdb_kv * ov,int off,int len)287 static int hash_getkv(struct bdb_cur *cur, struct bdb_kv *kv, struct bdb_kv *ov, int off, int len)
288 {
289     if (len <= 0 || off + len > cur->db->pagesize)
290 	return -1;
291     if (cur->page[off] == 1) {
292 	kv->kv = cur->page + off + 1;
293 	kv->len = len - 1;
294     } else if (cur->page[off] == 3) {
295 	uint32_t ovlpage[2];
296 	if (len != 12)
297 	    return -1;
298 	memcpy(ovlpage, cur->page + off + 4, 8);	/* off is unaligned */
299 	if (ovfl_get(cur, kv, ov, ovlpage))
300 	    return -1;
301     } else {
302 	return -1;
303     }
304     return 0;
305 }
306 
hash_next(struct bdb_cur * cur)307 static int hash_next(struct bdb_cur *cur)
308 {
309     int pagesize = cur->db->pagesize;
310     int koff, klen, voff, vlen;
311     if (!cur->state && hash_lookup(cur, 0, 0))
312 	return -1;
313     cur->idx += 2;
314     for (;;) {
315 	if (cur->idx + 1 >= cur->numidx) {
316 	    unsigned int pg;
317 	    cur->idx = cur->numidx = 0;
318 	    pg = *(uint32_t *)(cur->page + 16);
319 	    if (!pg) {
320 		if (cur->islookup || cur->bucket >= cur->db->maxbucket)
321 		    return 1;
322 		pg = hash_bucket_to_page(cur->db, ++cur->bucket);
323 	    }
324 	    if (bdb_getpage(cur->db, cur->page, pg))
325 		return -1;
326 	    if (cur->page[25] != 8 && cur->page[25] != 13)
327 		return -1;
328 	    cur->numidx = *(uint16_t *)(cur->page + 20);
329 	    continue;
330 	}
331 	koff = *(uint16_t *)(cur->page + 26 + 2 * cur->idx);
332 	voff = *(uint16_t *)(cur->page + 28 + 2 * cur->idx);
333 	if (koff >= pagesize || voff >= pagesize)
334 	    return -1;
335 	if (cur->idx == 0)
336 	    klen = pagesize - koff;
337 	else
338 	    klen = *(uint16_t *)(cur->page + 24 + 2 * cur->idx) - koff;
339 	vlen = koff - voff;
340 	if (hash_getkv(cur, &cur->key, &cur->keyov, koff, klen))
341 	    return -1;
342 	if (!cur->islookup && hash_getkv(cur, &cur->val, &cur->valov, voff, vlen))
343 	    return -1;
344 	return 0;
345     }
346 }
347 
hash_getval(struct bdb_cur * cur)348 static int hash_getval(struct bdb_cur *cur)
349 {
350     int koff, voff;
351     if (cur->state != 1 || cur->idx + 1 >= cur->numidx)
352 	return -1;
353     koff = *(uint16_t *)(cur->page + 26 + 2 * cur->idx);
354     voff = *(uint16_t *)(cur->page + 28 + 2 * cur->idx);
355     return hash_getkv(cur, &cur->val, &cur->valov, voff, koff - voff);
356 }
357 
358 
359 /****** btree implementation ******/
360 
btree_lookup(struct bdb_cur * cur,const unsigned char * key,unsigned int keylen)361 static int btree_lookup(struct bdb_cur *cur, const unsigned char *key, unsigned int keylen)
362 {
363     int pagesize = cur->db->pagesize;
364     int off, lastoff, idx, numidx;
365     unsigned int pg;
366     unsigned char *ekey;
367     unsigned int ekeylen;
368     int cmp;
369 
370     cur->state = -1;
371     pg = cur->db->root;
372     for (;;) {
373 	if (bdb_getpage(cur->db, cur->page, pg))
374 	    return -1;
375 	if (cur->page[25] == 5)
376 	    break;		/* found leaf page */
377 	if (cur->page[25] != 3)
378 	    return -1;
379 	numidx = *(uint16_t *)(cur->page + 20);
380 	if (!numidx)
381 	    return -1;
382 	for (lastoff = 0, idx = 0; idx < numidx; idx++, lastoff = off) {
383 	    off = *(uint16_t *)(cur->page + 26 + 2 * idx);
384 	    if ((off & 3) != 0 || off + 3 > pagesize)
385 		return -1;
386 	    ekeylen = *(uint16_t *)(cur->page + off);
387 	    if (off + 12 + ekeylen > pagesize)
388 		return -1;
389 	    if (!keylen) {
390 		lastoff = off;
391 		break;
392 	    }
393 	    if (idx == 0)
394 		continue;
395 	    ekey = cur->page + off + 12;
396 	    if ((cur->page[off + 2] & 0x7f) == 3) {
397 		if (ekeylen != 12)
398 		    return -1;
399 		if (ovfl_get(cur, 0, &cur->keyov, (uint32_t *)(ekey + 4)))
400 		    return -1;
401 		ekeylen = *(uint32_t *)(ekey + 8);
402 		ekey = cur->keyov.kv;
403 	    } else if ((cur->page[off + 2] & 0x7f) != 1) {
404 	      return -1;
405 	    }
406 	    cmp = memcmp(ekey, key, keylen < ekeylen ? keylen : ekeylen);
407 	    if (cmp > 0 || (cmp == 0 && ekeylen > keylen))
408 		break;
409 	}
410 	pg = *(uint32_t *)(cur->page + lastoff + 4);
411     }
412     cur->idx = (unsigned int)-2;
413     cur->numidx = *(uint16_t *)(cur->page + 20);
414     cur->state = 1;
415     return 0;
416 }
417 
btree_getkv(struct bdb_cur * cur,struct bdb_kv * kv,struct bdb_kv * ov,int off)418 static int btree_getkv(struct bdb_cur *cur, struct bdb_kv *kv, struct bdb_kv *ov, int off)
419 {
420     if ((off & 3) != 0)
421 	return -1;
422     if (cur->page[off + 2] == 1) {
423 	int len = *(uint16_t *)(cur->page + off);
424 	if (off + 3 + len > cur->db->pagesize)
425 	    return -1;
426 	kv->kv = cur->page + off + 3;
427 	kv->len = len;
428     } else if (cur->page[off + 2] == 3) {
429 	if (off + 12 > cur->db->pagesize)
430 	    return -1;
431 	if (ovfl_get(cur, kv, ov, (uint32_t *)(cur->page + off + 4)))
432 	    return -1;
433     } else {
434 	return -1;
435     }
436     return 0;
437 }
438 
btree_next(struct bdb_cur * cur)439 static int btree_next(struct bdb_cur *cur)
440 {
441     int pagesize = cur->db->pagesize;
442     int koff, voff;
443     if (!cur->state && btree_lookup(cur, 0, 0))
444 	return -1;
445     cur->idx += 2;
446     for (;;) {
447 	if (cur->idx + 1 >= cur->numidx) {
448 	    unsigned int pg;
449 	    cur->idx = cur->numidx = 0;
450 	    pg = *(uint32_t *)(cur->page + 16);
451 	    if (cur->islookup || !pg)
452 	      return 1;
453 	    if (bdb_getpage(cur->db, cur->page, pg))
454 		return -1;
455 	    if (cur->page[25] != 5)
456 		return -1;
457 	    cur->numidx = *(uint16_t *)(cur->page + 20);
458 	    continue;
459 	}
460 	koff = *(uint16_t *)(cur->page + 26 + 2 * cur->idx);
461 	voff = *(uint16_t *)(cur->page + 28 + 2 * cur->idx);
462 	if (koff + 3 > pagesize || voff + 3 > pagesize)
463 	    return -1;
464 	if ((cur->page[koff + 2] & 0x80) != 0 || (cur->page[voff + 2] & 0x80) != 0)
465 	    continue;	/* ignore deleted */
466 	if (btree_getkv(cur, &cur->key, &cur->keyov, koff))
467 	    return -1;
468 	if (!cur->islookup && btree_getkv(cur, &cur->val, &cur->valov, voff))
469 	    return -1;
470 	return 0;
471     }
472 }
473 
btree_getval(struct bdb_cur * cur)474 static int btree_getval(struct bdb_cur *cur)
475 {
476     int voff;
477     if (cur->state != 1 || cur->idx + 1 >= cur->numidx)
478 	return -1;
479     voff = *(uint16_t *)(cur->page + 28 + 2 * cur->idx);
480     return btree_getkv(cur, &cur->val, &cur->valov, voff);
481 }
482 
483 
484 /****** cursor functions ******/
485 
cur_open(struct bdb_db * db)486 static struct bdb_cur *cur_open(struct bdb_db *db)
487 {
488     struct bdb_cur *cur = xcalloc(1, sizeof(*cur));
489     cur->db = db;
490     cur->page = xmalloc(db->pagesize);
491     return cur;
492 }
493 
cur_close(struct bdb_cur * cur)494 static void cur_close(struct bdb_cur *cur)
495 {
496     if (cur->page)
497 	free(cur->page);
498     if (cur->ovpage)
499 	free(cur->ovpage);
500     if (cur->keyov.kv)
501 	free(cur->keyov.kv);
502     if (cur->valov.kv)
503 	free(cur->valov.kv);
504     free(cur);
505 }
506 
cur_next(struct bdb_cur * cur)507 static int cur_next(struct bdb_cur *cur)
508 {
509     if (cur->state < 0)
510 	return -1;
511     if (cur->db->type == BDB_HASH)
512 	return hash_next(cur);
513     if (cur->db->type == BDB_BTREE)
514 	return btree_next(cur);
515     return -1;
516 }
517 
cur_getval(struct bdb_cur * cur)518 static int cur_getval(struct bdb_cur *cur)
519 {
520     if (cur->state < 0)
521 	return -1;
522     if (cur->db->type == BDB_HASH)
523 	return hash_getval(cur);
524     if (cur->db->type == BDB_BTREE)
525 	return btree_getval(cur);
526     return -1;
527 }
528 
cur_lookup(struct bdb_cur * cur,const unsigned char * key,unsigned int keyl)529 static int cur_lookup(struct bdb_cur *cur, const unsigned char *key, unsigned int keyl)
530 {
531     int r = -1;
532     if (cur->db->type == BDB_HASH)
533 	r = hash_lookup(cur, key, keyl);
534     if (cur->db->type == BDB_BTREE)
535 	r = btree_lookup(cur, key, keyl);
536     if (r != 0)
537 	return r;
538     cur->islookup = 1;
539     while ((r = cur_next(cur)) == 0)
540 	if (keyl == cur->key.len && !memcmp(key, cur->key.kv, keyl))
541 	    break;
542     cur->islookup = 0;
543     if (r == 0)
544 	r = cur_getval(cur);
545     return r;
546 }
547 
cur_lookup_ge(struct bdb_cur * cur,const unsigned char * key,unsigned int keyl)548 static int cur_lookup_ge(struct bdb_cur *cur, const unsigned char *key, unsigned int keyl)
549 {
550     int r = -1;
551     if (cur->db->type == BDB_BTREE)
552 	r = btree_lookup(cur, key, keyl);
553     if (r != 0)
554 	return r;
555     cur->islookup = 1;
556     while ((r = cur_next(cur)) == 0) {
557 	unsigned int ekeyl = cur->key.len;
558 	int cmp = memcmp(cur->key.kv, key, keyl < ekeyl ? keyl : ekeyl);
559 	if (cmp > 0 || (cmp == 0 && ekeyl >= keyl))
560 	    break;
561     }
562     cur->islookup = 0;
563     if (r == 0)
564 	r = cur_getval(cur);
565     else if (r == 1)
566 	r = cur_next(cur);
567     return r;
568 }
569 
570 /****** glue code ******/
571 
getui32(unsigned char * x,int swapped)572 static unsigned int getui32(unsigned char *x, int swapped)
573 {
574     union _dbswap bs;
575     memcpy(bs.uc, x, 4);
576     if (swapped)
577       _DBSWAP(bs);
578     return bs.ui;
579 }
580 
setui32(unsigned char * x,uint32_t v,int swapped)581 static void setui32(unsigned char *x, uint32_t v, int swapped)
582 {
583     union _dbswap bs;
584     bs.ui = v;
585     if (swapped)
586       _DBSWAP(bs);
587     memcpy(x, bs.uc, 4);
588 }
589 
log_error(dbiIndex dbi)590 static void log_error(dbiIndex dbi)
591 {
592     rpmlog(RPMLOG_ERR, "bdb_ro error reading %s database\n", dbi->dbi_file);
593 }
594 
bdbro_Open(rpmdb rdb,rpmDbiTagVal rpmtag,dbiIndex * dbip,int flags)595 static int bdbro_Open(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
596 {
597     const char *dbhome = rpmdbHome(rdb);
598     dbiIndex dbi = NULL;
599     char *path;
600 
601     if (dbip)
602 	*dbip = NULL;
603     if ((rdb->db_mode & O_ACCMODE) != O_RDONLY)
604 	return EPERM;
605     if ((dbi = dbiNew(rdb, rpmtag)) == NULL)
606 	return 1;
607     path = rstrscat(NULL, dbhome, "/", dbi->dbi_file, NULL);
608     rpmlog(RPMLOG_DEBUG, "opening  db index       %s\n", path);
609     dbi->dbi_db = bdb_open(path);
610     if (!dbi->dbi_db) {
611 	int lvl = (dbi->dbi_type == DBI_PRIMARY) ? RPMLOG_ERR : RPMLOG_WARNING;
612 	rpmlog(lvl, "could not open %s: %s\n", path, strerror(errno));
613 	if (dbi->dbi_type == DBI_PRIMARY) {
614 	    free(path);
615 	    dbiFree(dbi);
616 	    return 1;
617 	}
618     }
619     free(path);
620     dbi->dbi_flags |= DBI_RDONLY;
621     if (dbip)
622 	*dbip = dbi;
623     else
624 	(void) dbiClose(dbi, 0);
625     return 0;
626 }
627 
bdbro_Close(dbiIndex dbi,unsigned int flags)628 static int bdbro_Close(dbiIndex dbi, unsigned int flags)
629 {
630     if (dbi->dbi_db)
631 	bdb_close(dbi->dbi_db);
632     dbiFree(dbi);
633     return 0;
634 }
635 
bdbro_Verify(dbiIndex dbi,unsigned int flags)636 static int bdbro_Verify(dbiIndex dbi, unsigned int flags)
637 {
638     return 0;
639 }
640 
bdbro_SetFSync(rpmdb rdb,int enable)641 static void bdbro_SetFSync(rpmdb rdb, int enable)
642 {
643 }
644 
bdbro_Ctrl(rpmdb rdb,dbCtrlOp ctrl)645 static int bdbro_Ctrl(rpmdb rdb, dbCtrlOp ctrl)
646 {
647     return 0;
648 }
649 
bdbro_CursorInit(dbiIndex dbi,unsigned int flags)650 static dbiCursor bdbro_CursorInit(dbiIndex dbi, unsigned int flags)
651 {
652     /* Secondary indexes may be missing */
653     return (dbi && dbi->dbi_db) ? (void *)cur_open(dbi->dbi_db) : NULL;
654 }
655 
bdbro_CursorFree(dbiIndex dbi,dbiCursor dbc)656 static dbiCursor bdbro_CursorFree(dbiIndex dbi, dbiCursor dbc)
657 {
658     if (dbc)
659 	cur_close((void *)dbc);
660     return NULL;
661 }
662 
appenddbt(dbiCursor dbc,unsigned char * val,unsigned int vallen,dbiIndexSet * setp)663 static void appenddbt(dbiCursor dbc, unsigned char *val, unsigned int vallen, dbiIndexSet *setp)
664 {
665     struct bdb_cur *cur = (void *)dbc;
666     dbiIndexSet set;
667     unsigned int i;
668 
669     set = dbiIndexSetNew(vallen / (2 * sizeof(uint32_t)));
670     set->count = vallen / (2 * sizeof(uint32_t));
671 
672     for (i = 0; i < set->count; i++, val += 8) {
673 	set->recs[i].hdrNum = getui32(val, cur->db->swapped);
674 	set->recs[i].tagNum = getui32(val + 4, cur->db->swapped);
675     }
676     if (*setp == NULL) {
677 	*setp = set;
678     } else {
679 	dbiIndexSetAppendSet(*setp, set, 0);
680 	dbiIndexSetFree(set);
681     }
682 }
683 
bdbro_idxdbPut(dbiIndex dbi,rpmTagVal rpmtag,unsigned int hdrNum,Header h)684 static rpmRC bdbro_idxdbPut(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h)
685 {
686     return RPMRC_FAIL;
687 }
688 
bdbro_idxdbDel(dbiIndex dbi,rpmTagVal rpmtag,unsigned int hdrNum,Header h)689 static rpmRC bdbro_idxdbDel(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h)
690 {
691     return RPMRC_FAIL;
692 }
693 
bdbro_idxdbGet(dbiIndex dbi,dbiCursor dbc,const char * keyp,size_t keylen,dbiIndexSet * set,int searchType)694 static rpmRC bdbro_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
695                           dbiIndexSet *set, int searchType)
696 {
697     struct bdb_cur *cur = (void *)dbc;
698     int r;
699 
700     if (!cur)
701 	return RPMRC_FAIL;
702     if (searchType == DBC_PREFIX_SEARCH) {
703 	rpmRC rc = RPMRC_NOTFOUND;
704 	if (!keyp)
705 	    return RPMRC_FAIL;
706 	r = cur_lookup_ge(cur, (const unsigned char *)keyp, keylen);
707 	for (; r == 0; r = cur_next(cur)) {
708 	    if (cur->key.len < keylen || memcmp(cur->key.kv, keyp, keylen) != 0)
709 		break;
710 	    if (set)
711 		appenddbt(dbc, cur->val.kv, cur->val.len, set);
712 	    rc = RPMRC_OK;
713 	}
714 	if (r == -1)
715 	    log_error(dbi);
716 	cur->key.kv = 0;
717 	return r == -1 ? RPMRC_FAIL : rc;
718     }
719     if (keyp) {
720 	if (keylen == 0) {
721 	    keyp = "";
722 	    keylen = 1;
723 	}
724 	r = cur_lookup(cur, (const unsigned char *)keyp, keylen);
725     } else {
726 	r = cur_next(cur);
727     }
728     if (r == 0) {
729 	if (set)
730 	    appenddbt(dbc, cur->val.kv, cur->val.len, set);
731 	return RPMRC_OK;
732     }
733     if (r == -1)
734 	log_error(dbi);
735     cur->key.kv = 0;
736     return r == 1 ? RPMRC_NOTFOUND : RPMRC_FAIL;
737 }
738 
bdbro_idxdbKey(dbiIndex dbi,dbiCursor dbc,unsigned int * keylen)739 static const void *bdbro_idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen)
740 {
741     struct bdb_cur *cur = (void *)dbc;
742     if (!cur || !cur->key.kv)
743 	return 0;
744     if (keylen)
745 	*keylen = cur->key.len;
746     return cur->key.kv;
747 }
748 
bdbro_pkgdbPut(dbiIndex dbi,dbiCursor dbc,unsigned int * hdrNum,unsigned char * hdrBlob,unsigned int hdrLen)749 static rpmRC bdbro_pkgdbPut(dbiIndex dbi, dbiCursor dbc,  unsigned int *hdrNum,
750 	unsigned char *hdrBlob, unsigned int hdrLen)
751 {
752     return RPMRC_FAIL;
753 }
754 
bdbro_pkgdbDel(dbiIndex dbi,dbiCursor dbc,unsigned int hdrNum)755 static rpmRC bdbro_pkgdbDel(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum)
756 {
757     return RPMRC_FAIL;
758 }
759 
bdbro_pkgdbGet(dbiIndex dbi,dbiCursor dbc,unsigned int hdrNum,unsigned char ** hdrBlob,unsigned int * hdrLen)760 static rpmRC bdbro_pkgdbGet(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum,
761 	unsigned char **hdrBlob, unsigned int *hdrLen)
762 {
763     struct bdb_cur *cur = (void *)dbc;
764     int r;
765     if (hdrNum) {
766 	unsigned char hdrkey[4];
767         setui32(hdrkey, hdrNum, cur->db->swapped);
768 	r = cur_lookup(cur, hdrkey, 4);
769     } else {
770 	r = cur_next(cur);
771     }
772     if (r == 0) {
773 	if (hdrBlob)
774 	    *hdrBlob = cur->val.kv;
775 	if (hdrLen)
776 	    *hdrLen = cur->val.len;
777 	return RPMRC_OK;
778     }
779     if (r == -1)
780 	log_error(dbi);
781     cur->key.kv = 0;
782     return r == 1 ? RPMRC_NOTFOUND : RPMRC_FAIL;
783 }
784 
bdbro_pkgdbKey(dbiIndex dbi,dbiCursor dbc)785 static unsigned int bdbro_pkgdbKey(dbiIndex dbi, dbiCursor dbc)
786 {
787     struct bdb_cur *cur = (void *)dbc;
788     if (!cur || !cur->key.kv || cur->key.len != 4)
789         return 0;
790     return getui32(cur->key.kv, cur->db->swapped);
791 }
792 
793 struct rpmdbOps_s bdbro_dbops = {
794     .name       = "bdb_ro",
795     .path       = "Packages",
796 
797     .open       = bdbro_Open,
798     .close      = bdbro_Close,
799     .verify     = bdbro_Verify,
800     .setFSync   = bdbro_SetFSync,
801     .ctrl       = bdbro_Ctrl,
802 
803     .cursorInit = bdbro_CursorInit,
804     .cursorFree = bdbro_CursorFree,
805 
806     .pkgdbPut   = bdbro_pkgdbPut,
807     .pkgdbDel   = bdbro_pkgdbDel,
808     .pkgdbGet   = bdbro_pkgdbGet,
809     .pkgdbKey   = bdbro_pkgdbKey,
810 
811     .idxdbGet   = bdbro_idxdbGet,
812     .idxdbPut   = bdbro_idxdbPut,
813     .idxdbDel   = bdbro_idxdbDel,
814     .idxdbKey   = bdbro_idxdbKey
815 };
816 
817