Bug Summary

File:lib/rpmdb.c
Warning:line 425, column 5
Value stored to 'db' is never read

Annotated Source Code

1/** \ingroup rpmdb dbi
2 * \file lib/rpmdb.c
3 */
4
5#include "system.h"
6
7#include <sys/file.h>
8#include <utime.h>
9#include <errno(*__errno_location ()).h>
10
11#ifndef DYING /* XXX already in "system.h" */
12#include <fnmatch.h>
13#endif
14
15#include <regex.h>
16
17#include <rpm/rpmtypes.h>
18#include <rpm/rpmurl.h>
19#include <rpm/rpmpgp.h>
20#include <rpm/rpmpgp.h>
21#include <rpm/rpmmacro.h>
22#include <rpm/rpmsq.h>
23#include <rpm/rpmstring.h>
24#include <rpm/rpmfileutil.h>
25#include <rpm/rpmds.h> /* XXX isInstallPreReq macro only */
26#include <rpm/rpmlog.h>
27#include <rpm/rpmdb.h>
28#include <rpm/rpmts.h>
29#include <rpm/argv.h>
30
31#include "lib/rpmchroot.h"
32#include "lib/rpmdb_internal.h"
33#include "lib/fprint.h"
34#include "lib/header_internal.h" /* XXX for headerSetInstance() */
35#include "lib/backend/dbiset.h"
36#include "lib/misc.h"
37#include "debug.h"
38
39#undef HASHTYPE
40#undef HTKEYTYPE
41#undef HTDATATYPE
42#define HASHTYPE dbChk
43#define HTKEYTYPE unsigned int
44#define HTDATATYPE rpmRC
45#include "lib/rpmhash.H"
46#include "lib/rpmhash.C"
47#undef HASHTYPE
48#undef HTKEYTYPE
49#undef HTDATATYPE
50
51typedef rpmRC (*idxfunc)(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
52 dbiIndexItem rec);
53
54static rpmRC tag2index(dbiIndex dbi, rpmTagVal rpmtag,
55 unsigned int hdrNum, Header h,
56 idxfunc idxupdate);
57
58static rpmRC indexPut(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h);
59static rpmdb rpmdbUnlink(rpmdb db);
60
61static int buildIndexes(rpmdb db)
62{
63 int rc = 0;
64 Header h;
65 rpmdbMatchIterator mi;
66
67 rc += rpmdbOpenAll(db);
68
69 /* If the main db was just created, this is expected - dont whine */
70 if (!(dbiFlags(db->db_pkgs) & DBI_CREATED)) {
71 rpmlog(RPMLOG_WARNING,
72 _("Generating %d missing index(es), please wait...\n")dcgettext ("rpm", "Generating %d missing index(es), please wait...\n"
, 5)
,
73 db->db_buildindex);
74 }
75
76 /* Don't call us again */
77 db->db_buildindex = 0;
78
79 dbSetFSync(db, 0);
80
81 dbCtrl(db, RPMDB_CTRL_LOCK_RW);
82
83 mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, NULL((void*)0), 0);
84 while ((h = rpmdbNextIterator(mi))) {
85 unsigned int hdrNum = headerGetInstance(h);
86 /* Build all secondary indexes which were created on open */
87 for (int dbix = 0; dbix < db->db_ndbi; dbix++) {
88 dbiIndex dbi = db->db_indexes[dbix];
89 if (dbi && (dbiFlags(dbi) & DBI_CREATED)) {
90 rc += indexPut(dbi, db->db_tags[dbix], hdrNum, h);
91 }
92 }
93 }
94 rpmdbFreeIterator(mi);
95
96 dbCtrl(db, DB_CTRL_INDEXSYNC);
97 dbCtrl(db, DB_CTRL_UNLOCK_RW);
98
99 dbSetFSync(db, !db->cfg.db_no_fsync);
100 return rc;
101}
102
103static int uintCmp(unsigned int a, unsigned int b)
104{
105 return (a != b);
106}
107
108static unsigned int uintId(unsigned int a)
109{
110 return a;
111}
112
113/** \ingroup dbi
114 * Return (newly allocated) integer of the epoch.
115 * @param s version string optionally containing epoch number
116 * @retval version only the version part of s
117 * @return epoch integer within the [0; UINT32_MAX] interval,
118 * or -1 for no epoch
119 */
120static int64_t splitEpoch(const char *s, const char **version)
121{
122 int64_t e;
123 char *end;
124 int saveerrno = errno(*__errno_location ());
125
126 *version = s;
127 e = strtol(s, &end, 10);
128 if (*end == ':' && e >= 0 && e <= UINT32_MAX(4294967295U)) {
129 *version = end + 1;
130 } else {
131 e = -1;
132 }
133
134 errno(*__errno_location ()) = saveerrno;
135 return e;
136}
137
138static int pkgdbOpen(rpmdb db, int flags, dbiIndex *dbip)
139{
140 int rc = 0;
141 dbiIndex dbi = NULL((void*)0);
142
143 if (db == NULL((void*)0))
144 return -1;
145
146 /* Is this it already open ? */
147 if ((dbi = db->db_pkgs) != NULL((void*)0))
148 goto exit;
149
150 rc = dbiOpen(db, RPMDBI_PACKAGES, &dbi, flags);
151
152 if (rc == 0) {
153 int verifyonly = (flags & RPMDB_FLAG_VERIFYONLY);
154
155 db->db_pkgs = dbi;
156 /* Allocate header checking cache .. based on some random number */
157 if (!verifyonly && (db->db_checked == NULL((void*)0))) {
158 db->db_checked = dbChkCreate(567, uintId, uintCmp, NULL((void*)0), NULL((void*)0));
159 }
160 /* If primary got created, we can safely run without fsync */
161 if ((!verifyonly && (dbiFlags(dbi) & DBI_CREATED)) || db->cfg.db_no_fsync) {
162 rpmlog(RPMLOG_DEBUG, "disabling fsync on database\n");
163 db->cfg.db_no_fsync = 1;
164 dbSetFSync(db, 0);
165 }
166 } else {
167 rpmlog(RPMLOG_ERR, _("cannot open %s index using %s - %s (%d)\n")dcgettext ("rpm", "cannot open %s index using %s - %s (%d)\n"
, 5)
,
168 rpmTagGetName(RPMDBI_PACKAGES), db->db_descr,
169 (rc > 0 ? strerror(rc) : ""), rc);
170 }
171
172exit:
173 if (rc == 0 && dbip)
174 *dbip = dbi;
175
176 return rc;
177}
178
179static int indexOpen(rpmdb db, rpmDbiTagVal rpmtag, int flags, dbiIndex *dbip)
180{
181 int dbix, rc = 0;
182 dbiIndex dbi = NULL((void*)0);
183
184 if (db == NULL((void*)0))
185 return -1;
186
187 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
188 if (rpmtag == db->db_tags[dbix])
189 break;
190 }
191 if (dbix >= db->db_ndbi)
192 return -1;
193
194 /* Is this index already open ? */
195 if ((dbi = db->db_indexes[dbix]) != NULL((void*)0))
196 goto exit;
197
198 rc = dbiOpen(db, rpmtag, &dbi, flags);
199
200 if (rc == 0) {
201 int verifyonly = (flags & RPMDB_FLAG_VERIFYONLY);
202 int rebuild = (db->db_flags & RPMDB_FLAG_REBUILD);
203
204 db->db_indexes[dbix] = dbi;
205 if (!rebuild && !verifyonly && (dbiFlags(dbi) & DBI_CREATED)) {
206 rpmlog(RPMLOG_DEBUG, "index %s needs creating\n", dbiName(dbi));
207 db->db_buildindex++;
208 if (db->db_buildindex == 1) {
209 buildIndexes(db);
210 }
211 }
212 } else {
213 rpmlog(RPMLOG_ERR, _("cannot open %s index using %s - %s (%d)\n")dcgettext ("rpm", "cannot open %s index using %s - %s (%d)\n"
, 5)
,
214 rpmTagGetName(rpmtag), db->db_descr,
215 (rc > 0 ? strerror(rc) : ""), rc);
216 }
217
218exit:
219 if (rc == 0 && dbip)
220 *dbip = dbi;
221 return rc;
222}
223
224static rpmRC indexGet(dbiIndex dbi, const char *keyp, size_t keylen,
225 dbiIndexSet *set)
226{
227 rpmRC rc = RPMRC_FAIL; /* assume failure */
228 if (dbi != NULL((void*)0)) {
229 dbiCursor dbc = dbiCursorInit(dbi, DBC_READ);
230
231 if (keyp) {
232 if (keylen == 0)
233 keylen = strlen(keyp);
234 rc = idxdbGet(dbi, dbc, keyp, keylen, set, DBC_NORMAL_SEARCH);
235 } else {
236 do {
237 rc = idxdbGet(dbi, dbc, NULL((void*)0), 0, set, DBC_NORMAL_SEARCH);
238 } while (rc == RPMRC_OK);
239
240 /* If we got some results, not found is not an error */
241 if (rc == RPMRC_NOTFOUND && set != NULL((void*)0))
242 rc = RPMRC_OK;
243 }
244
245 dbiCursorFree(dbi, dbc);
246 }
247 return rc;
248}
249
250static rpmRC indexPrefixGet(dbiIndex dbi, const char *pfx, size_t plen,
251 dbiIndexSet *set)
252{
253 rpmRC rc = RPMRC_FAIL; /* assume failure */
254
255 if (dbi != NULL((void*)0) && pfx) {
256 dbiCursor dbc = dbiCursorInit(dbi, DBC_READ);
257
258 if (plen == 0)
259 plen = strlen(pfx);
260 rc = idxdbGet(dbi, dbc, pfx, plen, set, DBC_PREFIX_SEARCH);
261
262 dbiCursorFree(dbi, dbc);
263 }
264 return rc;
265}
266
267
268typedef struct miRE_s {
269 rpmTagVal tag; /*!< header tag */
270 rpmMireMode mode; /*!< pattern match mode */
271 char * pattern; /*!< pattern string */
272 int notmatch; /*!< like "grep -v" */
273 regex_t * preg; /*!< regex compiled pattern buffer */
274 int cflags; /*!< regcomp(3) flags */
275 int eflags; /*!< regexec(3) flags */
276 int fnflags; /*!< fnmatch(3) flags */
277} * miRE;
278
279struct rpmdbMatchIterator_s {
280 rpmdbMatchIterator mi_next;
281 rpmdb mi_db;
282 rpmDbiTagVal mi_rpmtag;
283 dbiIndexSet mi_set;
284 dbiCursor mi_dbc;
285 int mi_setx;
286 Header mi_h;
287 int mi_sorted;
288 int mi_cflags;
289 int mi_modified;
290 unsigned int mi_prevoffset; /* header instance (native endian) */
291 unsigned int mi_offset; /* header instance (native endian) */
292 unsigned int mi_filenum; /* tag element (native endian) */
293 int mi_nre;
294 miRE mi_re;
295 rpmts mi_ts;
296 rpmRC (*mi_hdrchk) (rpmts ts, const void * uh, size_t uc, char ** msg);
297
298};
299
300struct rpmdbIndexIterator_s {
301 rpmdbIndexIterator ii_next;
302 rpmdb ii_db;
303 dbiIndex ii_dbi;
304 rpmDbiTag ii_rpmtag;
305 dbiCursor ii_dbc;
306 dbiIndexSet ii_set;
307 unsigned int *ii_hdrNums;
308};
309
310static rpmdb rpmdbRock;
311static rpmdbMatchIterator rpmmiRock;
312static rpmdbIndexIterator rpmiiRock;
313
314void rpmAtExit(void)
315{
316 rpmdb db;
317 rpmdbMatchIterator mi;
318 rpmdbIndexIterator ii;
319
320 while ((mi = rpmmiRock) != NULL((void*)0))
321 rpmdbFreeIterator(mi);
322
323 while ((ii = rpmiiRock) != NULL((void*)0))
324 rpmdbIndexIteratorFree(ii);
325
326 while ((db = rpmdbRock) != NULL((void*)0))
327 (void) rpmdbClose(db);
328}
329
330rpmop rpmdbOp(rpmdb rpmdb, rpmdbOpX opx)
331{
332 rpmop op = NULL((void*)0);
333 switch (opx) {
334 case RPMDB_OP_DBGET:
335 op = &rpmdb->db_getops;
336 break;
337 case RPMDB_OP_DBPUT:
338 op = &rpmdb->db_putops;
339 break;
340 case RPMDB_OP_DBDEL:
341 op = &rpmdb->db_delops;
342 break;
343 default:
344 break;
345 }
346 return op;
347}
348
349const char *rpmdbHome(rpmdb db)
350{
351 const char *dbdir = NULL((void*)0);
352 if (db) {
353 dbdir = rpmChrootDone() ? db->db_home : db->db_fullpath;
354 }
355 return dbdir;
356}
357
358int rpmdbOpenAll(rpmdb db)
359{
360 int rc = 0;
361
362 if (db == NULL((void*)0)) return -2;
363
364 rc = pkgdbOpen(db, db->db_flags, NULL((void*)0));
365 for (int dbix = 0; dbix < db->db_ndbi; dbix++) {
366 rc += indexOpen(db, db->db_tags[dbix], db->db_flags, NULL((void*)0));
367 }
368 return rc;
369}
370
371static int dbiForeach(dbiIndex *dbis, int ndbi,
372 int (*func) (dbiIndex, unsigned int), int del)
373{
374 int xx, rc = 0;
375 for (int dbix = ndbi; --dbix >= 0; ) {
376 if (dbis[dbix] == NULL((void*)0))
377 continue;
378 xx = func(dbis[dbix], 0);
379 if (xx && rc == 0) rc = xx;
380 if (del)
381 dbis[dbix] = NULL((void*)0);
382 }
383 return rc;
384}
385
386int rpmdbClose(rpmdb db)
387{
388 rpmdb * prev, next;
389 int rc = 0;
390
391 if (db == NULL((void*)0))
392 goto exit;
393
394 prev = &rpmdbRock;
395 while ((next = *prev) != NULL((void*)0) && next != db)
396 prev = &next->db_next;
397 if (!next)
398 goto exit;
399
400 (void) rpmdbUnlink(db);
401
402 if (db->nrefs > 0)
403 goto exit;
404
405 /* Always re-enable fsync on close of rw-database */
406 if ((db->db_mode & O_ACCMODE0003) != O_RDONLY00)
407 dbSetFSync(db, 1);
408
409 if (db->db_pkgs)
410 rc = dbiClose(db->db_pkgs, 0);
411 rc += dbiForeach(db->db_indexes, db->db_ndbi, dbiClose, 1);
412
413 db->db_root = _free(db->db_root)rfree((db->db_root));
414 db->db_home = _free(db->db_home)rfree((db->db_home));
415 db->db_fullpath = _free(db->db_fullpath)rfree((db->db_fullpath));
416 db->db_checked = dbChkFree(db->db_checked);
417 db->db_indexes = _free(db->db_indexes)rfree((db->db_indexes));
418 db->db_descr = _free(db->db_descr)rfree((db->db_descr));
419
420 if (next) {
421 *prev = next->db_next;
422 next->db_next = NULL((void*)0);
423 }
424
425 db = _free(db)rfree((db));
Value stored to 'db' is never read
426
427 if (rpmdbRock == NULL((void*)0)) {
428 rpmsqActivate(0);
429 }
430exit:
431 return rc;
432}
433
434static rpmdb newRpmdb(const char * root, const char * home,
435 int mode, int perms, int flags)
436{
437 rpmdb db = NULL((void*)0);
438 char * db_home = rpmGetPath((home && *home) ? home : "%{_dbpath}", NULL((void*)0));
439
440 static rpmDbiTag const dbiTags[] = {
441 RPMDBI_NAME,
442 RPMDBI_BASENAMES,
443 RPMDBI_GROUP,
444 RPMDBI_REQUIRENAME,
445 RPMDBI_PROVIDENAME,
446 RPMDBI_CONFLICTNAME,
447 RPMDBI_OBSOLETENAME,
448 RPMDBI_TRIGGERNAME,
449 RPMDBI_DIRNAMES,
450 RPMDBI_INSTALLTID,
451 RPMDBI_SIGMD5,
452 RPMDBI_SHA1HEADER,
453 RPMDBI_FILETRIGGERNAME,
454 RPMDBI_TRANSFILETRIGGERNAME,
455 RPMDBI_RECOMMENDNAME,
456 RPMDBI_SUGGESTNAME,
457 RPMDBI_SUPPLEMENTNAME,
458 RPMDBI_ENHANCENAME,
459 };
460
461 if (!(db_home && db_home[0] != '%')) {
462 rpmlog(RPMLOG_ERR, _("no dbpath has been set\n")dcgettext ("rpm", "no dbpath has been set\n", 5));
463 free(db_home);
464 return NULL((void*)0);
465 }
466
467 db = xcalloc(sizeof(*db), 1)rcalloc((sizeof(*db)), (1));
468
469 if (!(perms & 0600)) perms = 0644; /* XXX sanity */
470
471 db->db_mode = (mode >= 0) ? mode : 0;
472 db->db_perms = (perms >= 0) ? perms : 0644;
473 db->db_flags = (flags >= 0) ? flags : 0;
474
475 db->db_home = db_home;
476 db->db_root = rpmGetPath((root && *root) ? root : "/", NULL((void*)0));
477 db->db_fullpath = rpmGenPath(db->db_root, db->db_home, NULL((void*)0));
478 /* XXX remove environment after chrooted operations, for now... */
479 db->db_remove_env = (!rstreq(db->db_root, "/") ? 1 : 0);
480 db->db_tags = dbiTags;
481 db->db_ndbi = sizeof(dbiTags) / sizeof(rpmDbiTag);
482 db->db_indexes = xcalloc(db->db_ndbi, sizeof(*db->db_indexes))rcalloc((db->db_ndbi), (sizeof(*db->db_indexes)));
483 db->db_descr = xstrdup("unknown db")rstrdup(("unknown db"));
484 db->nrefs = 0;
485 return rpmdbLink(db);
486}
487
488static int openDatabase(const char * prefix,
489 const char * dbpath, rpmdb *dbp,
490 int mode, int perms, int flags)
491{
492 rpmdb db;
493 int rc;
494 int justCheck = flags & RPMDB_FLAG_JUSTCHECK;
495
496 if (dbp)
497 *dbp = NULL((void*)0);
498 if ((mode & O_ACCMODE0003) == O_WRONLY01)
499 return 1;
500
501 db = newRpmdb(prefix, dbpath, mode, perms, flags);
502 if (db == NULL((void*)0))
503 return 1;
504
505 /* Try to ensure db home exists, error out if we can't even create */
506 rc = rpmioMkpath(rpmdbHome(db), 0755, getuid(), getgid());
507 if (rc == 0) {
508 if (rpmdbRock == NULL((void*)0)) {
509 rpmsqActivate(1);
510 }
511
512 /* Just the primary Packages database opened here */
513 rc = pkgdbOpen(db, db->db_flags, NULL((void*)0));
514 }
515
516 if (rc || justCheck || dbp == NULL((void*)0))
517 rpmdbClose(db);
518 else {
519 db->db_next = rpmdbRock;
520 rpmdbRock = db;
521 *dbp = db;
522 }
523
524 return rc;
525}
526
527static rpmdb rpmdbUnlink(rpmdb db)
528{
529 if (db)
530 db->nrefs--;
531 return NULL((void*)0);
532}
533
534rpmdb rpmdbLink(rpmdb db)
535{
536 if (db)
537 db->nrefs++;
538 return db;
539}
540
541int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, int perms)
542{
543 return openDatabase(prefix, NULL((void*)0), dbp, mode, perms, 0);
544}
545
546int rpmdbInit (const char * prefix, int perms)
547{
548 rpmdb db = NULL((void*)0);
549 int rc;
550
551 rc = openDatabase(prefix, NULL((void*)0), &db, (O_CREAT0100 | O_RDWR02), perms, 0);
552 if (db != NULL((void*)0)) {
553 int xx;
554 xx = rpmdbOpenAll(db);
555 if (xx && rc == 0) rc = xx;
556 xx = rpmdbClose(db);
557 if (xx && rc == 0) rc = xx;
558 db = NULL((void*)0);
559 }
560 return rc;
561}
562
563int rpmdbVerify(const char * prefix)
564{
565 rpmdb db = NULL((void*)0);
566 int rc = 0;
567
568 rc = openDatabase(prefix, NULL((void*)0), &db, O_RDONLY00, 0644, RPMDB_FLAG_VERIFYONLY);
569
570 if (db != NULL((void*)0)) {
571 int xx;
572 rc = rpmdbOpenAll(db);
573
574
575 if (db->db_pkgs)
576 rc += dbiVerify(db->db_pkgs, 0);
577 rc += dbiForeach(db->db_indexes, db->db_ndbi, dbiVerify, 0);
578
579 xx = rpmdbClose(db);
580 if (xx && rc == 0) rc = xx;
581 db = NULL((void*)0);
582 }
583 return rc;
584}
585
586Header rpmdbGetHeaderAt(rpmdb db, unsigned int offset)
587{
588 rpmdbMatchIterator mi = rpmdbInitIterator(db, RPMDBI_PACKAGES,
589 &offset, sizeof(offset));
590 Header h = headerLink(rpmdbNextIterator(mi));
591 rpmdbFreeIterator(mi);
592 return h;
593}
594
595/**
596 * Find file matches in database.
597 * @param db rpm database
598 * @param dbi index database handle (always RPMDBI_BASENAMES)
599 * @param filespec
600 * @param usestate take file state into account?
601 * @retval matches
602 * @return RPMRC_OK on match, RPMRC_NOMATCH or RPMRC_FAIL
603 */
604static rpmRC rpmdbFindByFile(rpmdb db, dbiIndex dbi, const char *filespec,
605 int usestate, dbiIndexSet * matches)
606{
607 char * dirName = NULL((void*)0);
608 const char * baseName;
609 fingerPrintCache fpc = NULL((void*)0);
610 fingerPrint * fp1 = NULL((void*)0);
611 dbiIndexSet allMatches = NULL((void*)0);
612 unsigned int i;
613 rpmRC rc = RPMRC_FAIL; /* assume error */
614
615 *matches = NULL((void*)0);
616 if (filespec == NULL((void*)0)) return rc; /* nothing alloced yet */
617
618 if ((baseName = strrchr(filespec, '/')) != NULL((void*)0)) {
619 size_t len = baseName - filespec + 1;
620 dirName = strncpy(xmalloc(len + 1)rmalloc((len + 1)), filespec, len);
621 dirName[len] = '\0';
622 baseName++;
623 } else {
624 dirName = xstrdup("")rstrdup((""));
625 baseName = filespec;
626 }
627 if (baseName == NULL((void*)0))
628 goto exit;
629
630 rc = indexGet(dbi, baseName, 0, &allMatches);
631
632 if (rc || allMatches == NULL((void*)0)) goto exit;
633
634 *matches = dbiIndexSetNew(0);
635 fpc = fpCacheCreate(allMatches->count, NULL((void*)0));
636 fpLookup(fpc, dirName, baseName, &fp1);
637
638 i = 0;
639 while (i < allMatches->count) {
640 struct rpmtd_s bn, dn, di, fs;
641 const char ** baseNames, ** dirNames;
642 uint32_t * dirIndexes;
643 unsigned int offset = dbiIndexRecordOffset(allMatches, i);
644 unsigned int prevoff;
645 Header h = rpmdbGetHeaderAt(db, offset);
646
647 if (h == NULL((void*)0)) {
648 i++;
649 continue;
650 }
651
652 headerGet(h, RPMTAG_BASENAMES, &bn, HEADERGET_MINMEM);
653 headerGet(h, RPMTAG_DIRNAMES, &dn, HEADERGET_MINMEM);
654 headerGet(h, RPMTAG_DIRINDEXES, &di, HEADERGET_MINMEM);
655 baseNames = bn.data;
656 dirNames = dn.data;
657 dirIndexes = di.data;
658 if (usestate)
659 headerGet(h, RPMTAG_FILESTATES, &fs, HEADERGET_MINMEM);
660
661 do {
662 unsigned int num = dbiIndexRecordFileNumber(allMatches, i);
663 int skip = 0;
664
665 if (usestate) {
666 rpmtdSetIndex(&fs, num);
667 if (!RPMFILE_IS_INSTALLED(rpmtdGetNumber(&fs))((rpmtdGetNumber(&fs)) == RPMFILE_STATE_NORMAL || (rpmtdGetNumber
(&fs)) == RPMFILE_STATE_NETSHARED)
) {
668 skip = 1;
669 }
670 }
671
672 if (!skip) {
673 const char *dirName = dirNames[dirIndexes[num]];
674 if (fpLookupEquals(fpc, fp1, dirName, baseNames[num])) {
675 struct dbiIndexItem_s rec = {
676 .hdrNum = dbiIndexRecordOffset(allMatches, i),
677 .tagNum = dbiIndexRecordFileNumber(allMatches, i),
678 };
679 dbiIndexSetAppend(*matches, &rec, 1, 0);
680 }
681 }
682
683 prevoff = offset;
684 i++;
685 if (i < allMatches->count)
686 offset = dbiIndexRecordOffset(allMatches, i);
687 } while (i < allMatches->count && offset == prevoff);
688
689 rpmtdFreeData(&bn);
690 rpmtdFreeData(&dn);
691 rpmtdFreeData(&di);
692 if (usestate)
693 rpmtdFreeData(&fs);
694 headerFree(h);
695 }
696
697 free(fp1);
698 fpCacheFree(fpc);
699
700 if ((*matches)->count == 0) {
701 *matches = dbiIndexSetFree(*matches);
702 rc = RPMRC_NOTFOUND;
703 } else {
704 rc = RPMRC_OK;
705 }
706
707exit:
708 dbiIndexSetFree(allMatches);
709 free(dirName);
710 return rc;
711}
712
713int rpmdbCountPackages(rpmdb db, const char * name)
714{
715 int count = -1;
716 dbiIndex dbi = NULL((void*)0);
717
718 if (name != NULL((void*)0) && indexOpen(db, RPMDBI_NAME, 0, &dbi) == 0) {
719 dbiIndexSet matches = NULL((void*)0);
720
721 rpmRC rc = indexGet(dbi, name, strlen(name), &matches);
722
723 if (rc == RPMRC_OK) {
724 count = dbiIndexSetCount(matches);
725 } else {
726 count = (rc == RPMRC_NOTFOUND) ? 0 : -1;
727 }
728 dbiIndexSetFree(matches);
729 }
730
731 return count;
732}
733
734/**
735 * Attempt partial matches on name[-version[-release]][.arch] strings.
736 * @param db rpmdb handle
737 * @param dbi index database
738 * @param name package name
739 * @param epoch package epoch (-1 for any epoch)
740 * @param version package version (can be a pattern)
741 * @param release package release (can be a pattern)
742 * @param arch package arch (can be a pattern)
743 * @retval matches set of header instances that match
744 * @return RPMRC_OK on match, RPMRC_NOMATCH or RPMRC_FAIL
745 */
746static rpmRC dbiFindMatches(rpmdb db, dbiIndex dbi,
747 const char * name,
748 int64_t epoch,
749 const char * version,
750 const char * release,
751 const char * arch,
752 dbiIndexSet * matches)
753{
754 unsigned int gotMatches = 0;
755 rpmRC rc;
756 unsigned int i;
757
758 rc = indexGet(dbi, name, strlen(name), matches);
759
760 /* No matches on the name, anything else wont match either */
761 if (rc != RPMRC_OK)
762 goto exit;
763
764 /* If we got matches on name and nothing else was specified, we're done */
765 if (epoch < 0 && version == NULL((void*)0) && release == NULL((void*)0) && arch == NULL((void*)0))
766 goto exit;
767
768 /* Make sure the version and release match. */
769 for (i = 0; i < dbiIndexSetCount(*matches); i++) {
770 unsigned int recoff = dbiIndexRecordOffset(*matches, i);
771 rpmdbMatchIterator mi;
772 Header h;
773
774 if (recoff == 0)
775 continue;
776
777 mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &recoff, sizeof(recoff));
778
779 /* Set iterator selectors for version/release if available. */
780 if (version &&
781 rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version))
782 {
783 rc = RPMRC_FAIL;
784 goto exit;
785 }
786 if (release &&
787 rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release))
788 {
789 rc = RPMRC_FAIL;
790 goto exit;
791 }
792 if (arch &&
793 rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_DEFAULT, arch))
794 {
795 rc = RPMRC_FAIL;
796 goto exit;
797 }
798
799 h = rpmdbNextIterator(mi);
800
801 if (epoch >= 0 && h) {
802 struct rpmtd_s td;
803 headerGet(h, RPMTAG_EPOCH, &td, HEADERGET_MINMEM);
804 if (epoch != rpmtdGetNumber(&td))
805 h = NULL((void*)0);
806 rpmtdFreeData(&td);
807 }
808 if (h)
809 (*matches)->recs[gotMatches++] = (*matches)->recs[i];
810 else
811 (*matches)->recs[i].hdrNum = 0;
812 rpmdbFreeIterator(mi);
813 }
814
815 if (gotMatches) {
816 (*matches)->count = gotMatches;
817 rc = RPMRC_OK;
818 } else
819 rc = RPMRC_NOTFOUND;
820
821exit:
822/* FIX: double indirection */
823 if (rc && matches && *matches)
824 *matches = dbiIndexSetFree(*matches);
825 return rc;
826}
827
828/**
829 * Lookup by name, name-version, and finally by name-version-release.
830 * Both version and release can be patterns.
831 * @todo Name must be an exact match, as name is a db key.
832 * @param db rpmdb handle
833 * @param dbi index database handle (always RPMDBI_NAME)
834 * @param arg name[-[epoch:]version[-release]] string
835 * @param arglen length of arg
836 * @param arch possible arch string (or NULL)
837 * @retval matches set of header instances that match
838 * @return RPMRC_OK on match, RPMRC_NOMATCH or RPMRC_FAIL
839 */
840static rpmRC dbiFindByLabelArch(rpmdb db, dbiIndex dbi,
841 const char * arg, size_t arglen, const char *arch,
842 dbiIndexSet * matches)
843{
844 char localarg[arglen+1];
845 int64_t epoch;
846 const char * version;
847 const char * release;
848 char * s;
849 char c;
850 int brackets;
851 rpmRC rc;
852
853 if (arglen == 0) return RPMRC_NOTFOUND;
854
855 strncpy(localarg, arg, arglen);
856 localarg[arglen] = '\0';
857
858 /* did they give us just a name? */
859 rc = dbiFindMatches(db, dbi, localarg, -1, NULL((void*)0), NULL((void*)0), arch, matches);
860 if (rc != RPMRC_NOTFOUND)
861 goto exit;
862
863 /* FIX: double indirection */
864 *matches = dbiIndexSetFree(*matches);
865
866 /* maybe a name-[epoch:]version ? */
867 s = localarg + arglen;
868
869 c = '\0';
870 brackets = 0;
871 for (s -= 1; s > localarg; s--) {
872 switch (*s) {
873 case '[':
874 brackets = 1;
875 break;
876 case ']':
877 if (c != '[') brackets = 0;
878 break;
879 }
880 if (!brackets && c && *s == '-')
881 break;
882 c = *s;
883 }
884
885 /* FIX: *matches may be NULL. */
886 if (s == localarg) {
887 rc = RPMRC_NOTFOUND;
888 goto exit;
889 }
890
891 *s = '\0';
892
893 epoch = splitEpoch(s + 1, &version);
894 rc = dbiFindMatches(db, dbi, localarg, epoch, version, NULL((void*)0), arch, matches);
895 if (rc != RPMRC_NOTFOUND) goto exit;
896
897 /* FIX: double indirection */
898 *matches = dbiIndexSetFree(*matches);
899
900 /* how about name-[epoch:]version-release? */
901
902 release = s + 1;
903
904 c = '\0';
905 brackets = 0;
906 for (; s > localarg; s--) {
907 switch (*s) {
908 case '[':
909 brackets = 1;
910 break;
911 case ']':
912 if (c != '[') brackets = 0;
913 break;
914 }
915 if (!brackets && c && *s == '-')
916 break;
917 c = *s;
918 }
919
920 if (s == localarg) {
921 rc = RPMRC_NOTFOUND;
922 goto exit;
923 }
924
925 *s = '\0';
926 /* FIX: *matches may be NULL. */
927 epoch = splitEpoch(s + 1, &version);
928 rc = dbiFindMatches(db, dbi, localarg, epoch, version, release, arch, matches);
929exit:
930 return rc;
931}
932
933static rpmRC dbiFindByLabel(rpmdb db, dbiIndex dbi, const char * label,
934 dbiIndexSet * matches)
935{
936 const char *arch = NULL((void*)0);
937 /* First, try with label as it is */
938 rpmRC rc = dbiFindByLabelArch(db, dbi, label, strlen(label), NULL((void*)0), matches);
939
940 /* If not found, retry with possible .arch specifier if there is one */
941 if (rc == RPMRC_NOTFOUND && (arch = strrchr(label, '.')))
942 rc = dbiFindByLabelArch(db, dbi, label, arch-label, arch+1, matches);
943
944 return rc;
945}
946
947/**
948 * Rewrite a header into packages (if necessary) and free the header.
949 * Note: this is called from a markReplacedFiles iteration, and *must*
950 * preserve the "join key" (i.e. offset) for the header.
951 * @param mi database iterator
952 * @param dbi index database handle
953 * @return 0 on success
954 */
955static int miFreeHeader(rpmdbMatchIterator mi, dbiIndex dbi)
956{
957 int rc = 0;
958
959 if (mi == NULL((void*)0) || mi->mi_h == NULL((void*)0))
960 return 0;
961
962 if (dbi && mi->mi_dbc && mi->mi_modified && mi->mi_prevoffset) {
963 rpmRC rpmrc = RPMRC_NOTFOUND;
964 unsigned int hdrLen = 0;
965 unsigned char *hdrBlob = headerExport(mi->mi_h, &hdrLen);
966
967 /* Check header digest/signature on blob export (if requested). */
968 if (mi->mi_hdrchk && mi->mi_ts) {
969 char * msg = NULL((void*)0);
970 int lvl;
971
972 rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, hdrBlob, hdrLen, &msg);
973 lvl = (rpmrc == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG);
974 rpmlog(lvl, "%s h#%8u %s",
975 (rpmrc == RPMRC_FAIL ? _("miFreeHeader: skipping")dcgettext ("rpm", "miFreeHeader: skipping", 5) : "write"),
976 mi->mi_prevoffset, (msg ? msg : "\n"));
977 msg = _free(msg)rfree((msg));
978 }
979
980 if (hdrBlob != NULL((void*)0) && rpmrc != RPMRC_FAIL) {
981 rpmsqBlock(SIG_BLOCK0);
982 dbCtrl(mi->mi_db, DB_CTRL_LOCK_RW);
983 rc = pkgdbPut(dbi, mi->mi_dbc, mi->mi_prevoffset,
984 hdrBlob, hdrLen);
985 dbCtrl(mi->mi_db, DB_CTRL_INDEXSYNC);
986 dbCtrl(mi->mi_db, DB_CTRL_UNLOCK_RW);
987 rpmsqBlock(SIG_UNBLOCK1);
988
989 if (rc) {
990 rpmlog(RPMLOG_ERR,
991 _("error(%d) storing record #%d into %s\n")dcgettext ("rpm", "error(%d) storing record #%d into %s\n", 5
)
,
992 rc, mi->mi_prevoffset, dbiName(dbi));
993 }
994 }
995 free(hdrBlob);
996 }
997
998 mi->mi_h = headerFree(mi->mi_h);
999
1000 return rc;
1001}
1002
1003rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi)
1004{
1005 rpmdbMatchIterator * prev, next;
1006 dbiIndex dbi = NULL((void*)0);
1007 int i;
1008
1009 if (mi == NULL((void*)0))
1010 return NULL((void*)0);
1011
1012 prev = &rpmmiRock;
1013 while ((next = *prev) != NULL((void*)0) && next != mi)
1014 prev = &next->mi_next;
1015 if (next) {
1016 *prev = next->mi_next;
1017 next->mi_next = NULL((void*)0);
1018 } else
1019 return NULL((void*)0);
1020
1021 pkgdbOpen(mi->mi_db, 0, &dbi);
1022
1023 miFreeHeader(mi, dbi);
1024
1025 mi->mi_dbc = dbiCursorFree(dbi, mi->mi_dbc);
1026
1027 if (mi->mi_re != NULL((void*)0))
1028 for (i = 0; i < mi->mi_nre; i++) {
1029 miRE mire = mi->mi_re + i;
1030 mire->pattern = _free(mire->pattern)rfree((mire->pattern));
1031 if (mire->preg != NULL((void*)0)) {
1032 regfree(mire->preg);
1033 mire->preg = _free(mire->preg)rfree((mire->preg));
1034 }
1035 }
1036 mi->mi_re = _free(mi->mi_re)rfree((mi->mi_re));
1037
1038 mi->mi_set = dbiIndexSetFree(mi->mi_set);
1039 rpmdbClose(mi->mi_db);
1040 mi->mi_ts = rpmtsFree(mi->mi_ts);
1041
1042 mi = _free(mi)rfree((mi));
1043
1044 (void) rpmsqPoll();
1045
1046 return NULL((void*)0);
1047}
1048
1049unsigned int rpmdbGetIteratorOffset(rpmdbMatchIterator mi)
1050{
1051 return (mi ? mi->mi_offset : 0);
1052}
1053
1054unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi)
1055{
1056 return (mi ? mi->mi_filenum : 0);
1057}
1058
1059int rpmdbGetIteratorCount(rpmdbMatchIterator mi)
1060{
1061 return (mi && mi->mi_set ? mi->mi_set->count : 0);
1062}
1063
1064int rpmdbGetIteratorIndex(rpmdbMatchIterator mi)
1065{
1066 return (mi ? mi->mi_setx : 0);
1067}
1068
1069void rpmdbSetIteratorIndex(rpmdbMatchIterator mi, unsigned int ix)
1070{
1071 if (mi)
1072 mi->mi_setx = ix;
1073}
1074
1075unsigned int rpmdbGetIteratorOffsetFor(rpmdbMatchIterator mi, unsigned int ix)
1076{
1077 if (mi && mi->mi_set && ix < mi->mi_set->count)
1078 return mi->mi_set->recs[ix].hdrNum;
1079 return 0;
1080}
1081
1082/**
1083 * Return pattern match.
1084 * @param mire match iterator regex
1085 * @param val value to match
1086 * @return 0 if pattern matches, >0 on nomatch, <0 on error
1087 */
1088static int miregexec(miRE mire, const char * val)
1089{
1090 int rc = 0;
1091
1092 switch (mire->mode) {
1093 case RPMMIRE_STRCMP:
1094 rc = (!rstreq(mire->pattern, val));
1095 break;
1096 case RPMMIRE_DEFAULT:
1097 case RPMMIRE_REGEX:
1098 rc = regexec(mire->preg, val, 0, NULL((void*)0), mire->eflags);
1099 if (rc && rc != REG_NOMATCH) {
1100 char msg[256];
1101 (void) regerror(rc, mire->preg, msg, sizeof(msg)-1);
1102 msg[sizeof(msg)-1] = '\0';
1103 rpmlog(RPMLOG_ERR, _("%s: regexec failed: %s\n")dcgettext ("rpm", "%s: regexec failed: %s\n", 5),
1104 mire->pattern, msg);
1105 rc = -1;
1106 }
1107 break;
1108 case RPMMIRE_GLOB:
1109 rc = fnmatch(mire->pattern, val, mire->fnflags);
1110 if (rc && rc != FNM_NOMATCH1)
1111 rc = -1;
1112 break;
1113 default:
1114 rc = -1;
1115 break;
1116 }
1117
1118 return rc;
1119}
1120
1121/**
1122 * Compare iterator selectors by rpm tag (qsort/bsearch).
1123 * @param a 1st iterator selector
1124 * @param b 2nd iterator selector
1125 * @return result of comparison
1126 */
1127static int mireCmp(const void * a, const void * b)
1128{
1129 const miRE mireA = (const miRE) a;
1130 const miRE mireB = (const miRE) b;
1131 return (mireA->tag - mireB->tag);
1132}
1133
1134/**
1135 * Copy pattern, escaping for appropriate mode.
1136 * @param tag rpm tag
1137 * @retval modep type of pattern match
1138 * @param pattern pattern to duplicate
1139 * @return duplicated pattern
1140 */
1141static char * mireDup(rpmTagVal tag, rpmMireMode *modep,
1142 const char * pattern)
1143{
1144 const char * s;
1145 char * pat;
1146 char * t;
1147 int brackets;
1148 size_t nb;
1149 int c;
1150
1151 switch (*modep) {
1152 default:
1153 case RPMMIRE_DEFAULT:
1154 if (tag == RPMTAG_DIRNAMES || tag == RPMTAG_BASENAMES) {
1155 *modep = RPMMIRE_GLOB;
1156 pat = xstrdup(pattern)rstrdup((pattern));
1157 break;
1158 }
1159
1160 nb = strlen(pattern) + sizeof("^$");
1161
1162 /* Find no. of bytes needed for pattern. */
1163 /* periods and plusses are escaped, splats become '.*' */
1164 c = '\0';
1165 brackets = 0;
1166 for (s = pattern; *s != '\0'; s++) {
1167 switch (*s) {
1168 case '.':
1169 case '+':
1170 case '*':
1171 if (!brackets) nb++;
1172 break;
1173 case '\\':
1174 s++;
1175 break;
1176 case '[':
1177 brackets = 1;
1178 break;
1179 case ']':
1180 if (c != '[') brackets = 0;
1181 break;
1182 }
1183 c = *s;
1184 }
1185
1186 pat = t = xmalloc(nb)rmalloc((nb));
1187
1188 if (pattern[0] != '^') *t++ = '^';
1189
1190 /* Copy pattern, escaping periods, prefixing splats with period. */
1191 c = '\0';
1192 brackets = 0;
1193 for (s = pattern; *s != '\0'; s++, t++) {
1194 switch (*s) {
1195 case '.':
1196 case '+':
1197 if (!brackets) *t++ = '\\';
1198 break;
1199 case '*':
1200 if (!brackets) *t++ = '.';
1201 break;
1202 case '\\':
1203 *t++ = *s++;
1204 break;
1205 case '[':
1206 brackets = 1;
1207 break;
1208 case ']':
1209 if (c != '[') brackets = 0;
1210 break;
1211 }
1212 c = *t = *s;
1213 }
1214
1215 if (s > pattern && s[-1] != '$') *t++ = '$';
1216 *t = '\0';
1217 *modep = RPMMIRE_REGEX;
1218 break;
1219 case RPMMIRE_STRCMP:
1220 case RPMMIRE_REGEX:
1221 case RPMMIRE_GLOB:
1222 pat = xstrdup(pattern)rstrdup((pattern));
1223 break;
1224 }
1225
1226 return pat;
1227}
1228
1229int rpmdbSetIteratorRE(rpmdbMatchIterator mi, rpmTagVal tag,
1230 rpmMireMode mode, const char * pattern)
1231{
1232 static rpmMireMode defmode = (rpmMireMode)-1;
1233 miRE mire = NULL((void*)0);
1234 char * allpat = NULL((void*)0);
1235 int notmatch = 0;
1236 regex_t * preg = NULL((void*)0);
1237 int cflags = 0;
1238 int eflags = 0;
1239 int fnflags = 0;
1240 int rc = 0;
1241
1242 if (defmode == (rpmMireMode)-1) {
1243 char *t = rpmExpand("%{?_query_selector_match}", NULL((void*)0));
1244
1245 if (*t == '\0' || rstreq(t, "default"))
1246 defmode = RPMMIRE_DEFAULT;
1247 else if (rstreq(t, "strcmp"))
1248 defmode = RPMMIRE_STRCMP;
1249 else if (rstreq(t, "regex"))
1250 defmode = RPMMIRE_REGEX;
1251 else if (rstreq(t, "glob"))
1252 defmode = RPMMIRE_GLOB;
1253 else
1254 defmode = RPMMIRE_DEFAULT;
1255 free(t);
1256 }
1257
1258 if (mi == NULL((void*)0) || pattern == NULL((void*)0))
1259 return rc;
1260
1261 /* Leading '!' inverts pattern match sense, like "grep -v". */
1262 if (*pattern == '!') {
1263 notmatch = 1;
1264 pattern++;
1265 }
1266
1267 allpat = mireDup(tag, &mode, pattern);
1268
1269 if (mode == RPMMIRE_DEFAULT)
1270 mode = defmode;
1271
1272 switch (mode) {
1273 case RPMMIRE_DEFAULT:
1274 case RPMMIRE_STRCMP:
1275 break;
1276 case RPMMIRE_REGEX:
1277 preg = xcalloc(1, sizeof(*preg))rcalloc((1), (sizeof(*preg)));
1278 cflags = (REG_EXTENDED1 | REG_NOSUB(((1 << 1) << 1) << 1));
1279 rc = regcomp(preg, allpat, cflags);
1280 if (rc) {
1281 char msg[256];
1282 (void) regerror(rc, preg, msg, sizeof(msg)-1);
1283 msg[sizeof(msg)-1] = '\0';
1284 rpmlog(RPMLOG_ERR, _("%s: regcomp failed: %s\n")dcgettext ("rpm", "%s: regcomp failed: %s\n", 5), allpat, msg);
1285 }
1286 break;
1287 case RPMMIRE_GLOB:
1288 fnflags = FNM_PATHNAME(1 << 0) | FNM_PERIOD(1 << 2);
1289 break;
1290 default:
1291 rc = -1;
1292 break;
1293 }
1294
1295 if (rc) {
1296 /* FIX: mire has kept values */
1297 allpat = _free(allpat)rfree((allpat));
1298 if (preg) {
1299 regfree(preg);
1300 preg = _free(preg)rfree((preg));
1301 }
1302 return rc;
1303 }
1304
1305 mi->mi_re = xrealloc(mi->mi_re, (mi->mi_nre + 1) * sizeof(*mi->mi_re))rrealloc((mi->mi_re), ((mi->mi_nre + 1) * sizeof(*mi->
mi_re)))
;
1306 mire = mi->mi_re + mi->mi_nre;
1307 mi->mi_nre++;
1308
1309 mire->tag = tag;
1310 mire->mode = mode;
1311 mire->pattern = allpat;
1312 mire->notmatch = notmatch;
1313 mire->preg = preg;
1314 mire->cflags = cflags;
1315 mire->eflags = eflags;
1316 mire->fnflags = fnflags;
1317
1318 if (mi->mi_nre > 1)
1319 qsort(mi->mi_re, mi->mi_nre, sizeof(*mi->mi_re), mireCmp);
1320
1321 return rc;
1322}
1323
1324/**
1325 * Return iterator selector match.
1326 * @param mi rpm database iterator
1327 * @return 1 if header should be skipped
1328 */
1329static int mireSkip (const rpmdbMatchIterator mi)
1330{
1331 miRE mire;
1332 uint32_t zero = 0;
1333 int ntags = 0;
1334 int nmatches = 0;
1335 int rc;
1336
1337 if (mi->mi_h == NULL((void*)0)) /* XXX can't happen */
1338 return 0;
1339
1340 /*
1341 * Apply tag tests, implicitly "||" for multiple patterns/values of a
1342 * single tag, implicitly "&&" between multiple tag patterns.
1343 */
1344 if ((mire = mi->mi_re) != NULL((void*)0))
1345 for (int i = 0; i < mi->mi_nre; i++, mire++) {
1346 int anymatch;
1347 struct rpmtd_s td;
1348
1349 if (!headerGet(mi->mi_h, mire->tag, &td, HEADERGET_MINMEM)) {
1350 if (mire->tag != RPMTAG_EPOCH) {
1351 ntags++;
1352 continue;
1353 }
1354 /* "is package already installed" checks rely on this behavior */
1355 td.count = 1;
1356 td.type = RPM_INT32_TYPE;
1357 td.data = &zero;
1358 }
1359
1360 anymatch = 0; /* no matches yet */
1361 while (1) {
1362 rpmtdInit(&td);
1363 while (rpmtdNext(&td) >= 0) {
1364 char *str = rpmtdFormat(&td, RPMTD_FORMAT_STRING, NULL((void*)0));
1365 if (str) {
1366 rc = miregexec(mire, str);
1367 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
1368 anymatch++;
1369 free(str);
1370 }
1371 }
1372 if ((i+1) < mi->mi_nre && mire[0].tag == mire[1].tag) {
1373 i++;
1374 mire++;
1375 continue;
1376 }
1377 break;
1378 }
1379 rpmtdFreeData(&td);
1380
1381 ntags++;
1382 if (anymatch)
1383 nmatches++;
1384 }
1385
1386 return (ntags == nmatches ? 0 : 1);
1387}
1388
1389int rpmdbSetIteratorRewrite(rpmdbMatchIterator mi, int rewrite)
1390{
1391 int rc;
1392 if (mi == NULL((void*)0))
1393 return 0;
1394 rc = (mi->mi_cflags & DBC_WRITE) ? 1 : 0;
1395 if (rewrite)
1396 mi->mi_cflags |= DBC_WRITE;
1397 else
1398 mi->mi_cflags &= ~DBC_WRITE;
1399 return rc;
1400}
1401
1402int rpmdbSetIteratorModified(rpmdbMatchIterator mi, int modified)
1403{
1404 int rc;
1405 if (mi == NULL((void*)0))
1406 return 0;
1407 rc = mi->mi_modified;
1408 mi->mi_modified = modified;
1409 return rc;
1410}
1411
1412int rpmdbSetHdrChk(rpmdbMatchIterator mi, rpmts ts,
1413 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg))
1414{
1415 int rc = 0;
1416 if (mi == NULL((void*)0))
1417 return 0;
1418 mi->mi_ts = rpmtsLink(ts);
1419 mi->mi_hdrchk = hdrchk;
1420 return rc;
1421}
1422
1423static rpmRC miVerifyHeader(rpmdbMatchIterator mi, const void *uh, size_t uhlen)
1424{
1425 rpmRC rpmrc = RPMRC_NOTFOUND;
1426
1427 if (!(mi->mi_hdrchk && mi->mi_ts))
1428 return rpmrc;
1429
1430 /* Don't bother re-checking a previously read header. */
1431 if (mi->mi_db->db_checked) {
1432 rpmRC *res;
1433 if (dbChkGetEntry(mi->mi_db->db_checked, mi->mi_offset,
1434 &res, NULL((void*)0), NULL((void*)0))) {
1435 rpmrc = res[0];
1436 }
1437 }
1438
1439 /* If blob is unchecked, check blob import consistency now. */
1440 if (rpmrc != RPMRC_OK) {
1441 char * msg = NULL((void*)0);
1442 int lvl;
1443
1444 rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, uh, uhlen, &msg);
1445 lvl = (rpmrc == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG);
1446 rpmlog(lvl, "%s h#%8u %s\n",
1447 (rpmrc == RPMRC_FAIL ? _("rpmdbNextIterator: skipping")dcgettext ("rpm", "rpmdbNextIterator: skipping", 5) : " read"),
1448 mi->mi_offset, (msg ? msg : ""));
1449 msg = _free(msg)rfree((msg));
1450
1451 /* Mark header checked. */
1452 if (mi->mi_db && mi->mi_db->db_checked) {
1453 dbChkAddEntry(mi->mi_db->db_checked, mi->mi_offset, rpmrc);
1454 }
1455 }
1456 return rpmrc;
1457}
1458
1459/* FIX: mi->mi_key.data may be NULL */
1460Header rpmdbNextIterator(rpmdbMatchIterator mi)
1461{
1462 dbiIndex dbi = NULL((void*)0);
1463 unsigned char * uh;
1464 unsigned int uhlen;
1465 int rc;
1466 headerImportFlags importFlags = HEADERIMPORT_FAST;
1467
1468 if (mi == NULL((void*)0))
1469 return NULL((void*)0);
1470
1471 if (pkgdbOpen(mi->mi_db, 0, &dbi))
1472 return NULL((void*)0);
1473
1474#if defined(_USE_COPY_LOAD)
1475 importFlags |= HEADERIMPORT_COPY;
1476#endif
1477 /*
1478 * Cursors are per-iterator, not per-dbi, so get a cursor for the
1479 * iterator on 1st call. If the iteration is to rewrite headers,
1480 * then the cursor needs to marked with DBC_WRITE as well.
1481 */
1482 if (mi->mi_dbc == NULL((void*)0))
1483 mi->mi_dbc = dbiCursorInit(dbi, mi->mi_cflags);
1484
1485top:
1486 uh = NULL((void*)0);
1487 uhlen = 0;
1488
1489 do {
1490 if (mi->mi_set) {
1491 if (!(mi->mi_setx < mi->mi_set->count))
1492 return NULL((void*)0);
1493 mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx);
1494 mi->mi_filenum = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx);
1495 } else {
1496 rc = pkgdbGet(dbi, mi->mi_dbc, 0, &uh, &uhlen);
1497 if (rc == 0)
1498 mi->mi_offset = pkgdbKey(dbi, mi->mi_dbc);
1499
1500 /* Terminate on error or end of keys */
1501 if (rc || (mi->mi_setx && mi->mi_offset == 0))
1502 return NULL((void*)0);
1503 }
1504 mi->mi_setx++;
1505 } while (mi->mi_offset == 0);
1506
1507 /* If next header is identical, return it now. */
1508 if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset)
1509 return mi->mi_h;
1510
1511 /* Retrieve next header blob for index iterator. */
1512 if (uh == NULL((void*)0)) {
1513 rc = pkgdbGet(dbi, mi->mi_dbc, mi->mi_offset, &uh, &uhlen);
1514 if (rc)
1515 return NULL((void*)0);
1516 }
1517
1518 /* Rewrite current header (if necessary) and unlink. */
1519 miFreeHeader(mi, dbi);
1520
1521 /* Is this the end of the iteration? */
1522 if (uh == NULL((void*)0))
1523 return NULL((void*)0);
1524
1525 /* Verify header if enabled, skip damaged and inconsistent headers */
1526 if (miVerifyHeader(mi, uh, uhlen) == RPMRC_FAIL) {
1527 goto top;
1528 }
1529
1530 /* Did the header blob load correctly? */
1531 mi->mi_h = headerImport(uh, uhlen, importFlags);
1532 if (mi->mi_h == NULL((void*)0) || !headerIsEntry(mi->mi_h, RPMTAG_NAME)) {
1533 rpmlog(RPMLOG_ERR,
1534 _("rpmdb: damaged header #%u retrieved -- skipping.\n")dcgettext ("rpm", "rpmdb: damaged header #%u retrieved -- skipping.\n"
, 5)
,
1535 mi->mi_offset);
1536 goto top;
1537 }
1538
1539 /*
1540 * Skip this header if iterator selector (if any) doesn't match.
1541 */
1542 if (mireSkip(mi)) {
1543 goto top;
1544 }
1545 headerSetInstance(mi->mi_h, mi->mi_offset);
1546
1547 mi->mi_prevoffset = mi->mi_offset;
1548 mi->mi_modified = 0;
1549
1550 return mi->mi_h;
1551}
1552
1553/** \ingroup rpmdb
1554 * sort the iterator by (recnum, filenum)
1555 * Return database iterator.
1556 * @param mi rpm database iterator
1557 */
1558void rpmdbSortIterator(rpmdbMatchIterator mi)
1559{
1560 if (mi && mi->mi_set) {
1561 dbiIndexSetSort(mi->mi_set);
1562 mi->mi_sorted = 1;
1563 }
1564}
1565
1566void rpmdbUniqIterator(rpmdbMatchIterator mi)
1567{
1568 if (mi && mi->mi_set) {
1569 dbiIndexSetUniq(mi->mi_set, mi->mi_sorted);
1570 }
1571}
1572
1573int rpmdbExtendIterator(rpmdbMatchIterator mi,
1574 const void * keyp, size_t keylen)
1575{
1576 dbiIndex dbi = NULL((void*)0);
1577 dbiIndexSet set = NULL((void*)0);
1578 int rc = 1; /* assume failure */
1579
1580 if (mi == NULL((void*)0) || keyp == NULL((void*)0))
1581 return rc;
1582
1583 rc = indexOpen(mi->mi_db, mi->mi_rpmtag, 0, &dbi);
1584
1585 if (rc == 0 && indexGet(dbi, keyp, keylen, &set) == RPMRC_OK) {
1586 if (mi->mi_set == NULL((void*)0)) {
1587 mi->mi_set = set;
1588 } else {
1589 dbiIndexSetAppendSet(mi->mi_set, set, 0);
1590 dbiIndexSetFree(set);
1591 }
1592 rc = 0;
1593 }
1594
1595 return rc;
1596}
1597
1598int rpmdbFilterIterator(rpmdbMatchIterator mi, packageHash hdrNums, int neg)
1599{
1600 if (mi == NULL((void*)0) || hdrNums == NULL((void*)0))
1601 return 1;
1602
1603 if (!mi->mi_set)
1604 return 0;
1605
1606 if (packageHashNumKeys(hdrNums) == 0) {
1607 if (!neg)
1608 mi->mi_set->count = 0;
1609 return 0;
1610 }
1611
1612 unsigned int from;
1613 unsigned int to = 0;
1614 unsigned int num = mi->mi_set->count;
1615 int cond;
1616
1617 assert(mi->mi_set->count > 0)({ if (mi->mi_set->count > 0) ; else __assert_fail (
"mi->mi_set->count > 0", "rpmdb.c", 1617, __PRETTY_FUNCTION__
); })
;
1618
1619 for (from = 0; from < num; from++) {
1620 cond = !packageHashHasEntry(hdrNums, mi->mi_set->recs[from].hdrNum);
1621 cond = neg ? !cond : cond;
1622 if (cond) {
1623 mi->mi_set->count--;
1624 continue;
1625 }
1626 if (from != to)
1627 mi->mi_set->recs[to] = mi->mi_set->recs[from]; /* structure assignment */
1628 to++;
1629 }
1630 return 0;
1631}
1632
1633int rpmdbPruneIterator(rpmdbMatchIterator mi, packageHash hdrNums)
1634{
1635 if (packageHashNumKeys(hdrNums) <= 0)
1636 return 1;
1637
1638 return rpmdbFilterIterator(mi, hdrNums, 1);
1639}
1640
1641
1642int rpmdbAppendIterator(rpmdbMatchIterator mi,
1643 const unsigned int * hdrNums, unsigned int nHdrNums)
1644{
1645 if (mi == NULL((void*)0) || hdrNums == NULL((void*)0) || nHdrNums == 0)
1646 return 1;
1647
1648 if (mi->mi_set == NULL((void*)0))
1649 mi->mi_set = dbiIndexSetNew(nHdrNums);
1650
1651 for (unsigned int i = 0; i < nHdrNums; i++) {
1652 struct dbiIndexItem_s rec = { .hdrNum = hdrNums[i], .tagNum = 0 };
1653 dbiIndexSetAppend(mi->mi_set, &rec, 1, 0);
1654 }
1655 return 0;
1656}
1657
1658rpmdbMatchIterator rpmdbNewIterator(rpmdb db, rpmDbiTagVal dbitag)
1659{
1660 rpmdbMatchIterator mi = NULL((void*)0);
1661
1662 if (dbitag == RPMDBI_PACKAGES) {
1663 if (pkgdbOpen(db, 0, NULL((void*)0)))
1664 return NULL((void*)0);
1665 } else {
1666 if (indexOpen(db, dbitag, 0, NULL((void*)0)))
1667 return NULL((void*)0);
1668 }
1669
1670 mi = xcalloc(1, sizeof(*mi))rcalloc((1), (sizeof(*mi)));
1671 mi->mi_set = NULL((void*)0);
1672 mi->mi_db = rpmdbLink(db);
1673 mi->mi_rpmtag = dbitag;
1674
1675 mi->mi_dbc = NULL((void*)0);
1676 mi->mi_setx = 0;
1677 mi->mi_h = NULL((void*)0);
1678 mi->mi_sorted = 0;
1679 mi->mi_cflags = 0;
1680 mi->mi_modified = 0;
1681 mi->mi_prevoffset = 0;
1682 mi->mi_offset = 0;
1683 mi->mi_filenum = 0;
1684 mi->mi_nre = 0;
1685 mi->mi_re = NULL((void*)0);
1686
1687 mi->mi_ts = NULL((void*)0);
1688 mi->mi_hdrchk = NULL((void*)0);
1689
1690 /* Chain cursors for teardown on abnormal exit. */
1691 mi->mi_next = rpmmiRock;
1692 rpmmiRock = mi;
1693
1694 return mi;
1695};
1696
1697static rpmdbMatchIterator pkgdbIterInit(rpmdb db,
1698 const unsigned int * keyp, size_t keylen)
1699{
1700 rpmdbMatchIterator mi = NULL((void*)0);
1701 rpmDbiTagVal dbtag = RPMDBI_PACKAGES;
1702 dbiIndex pkgs = NULL((void*)0);
1703
1704 /* Require a sane keylen if one is specified */
1705 if (keyp && keylen != sizeof(*keyp))
1706 return NULL((void*)0);
1707
1708 if (pkgdbOpen(db, 0, &pkgs) == 0) {
1709 mi = rpmdbNewIterator(db, dbtag);
1710 if (keyp)
1711 rpmdbAppendIterator(mi, keyp, 1);
1712 }
1713 return mi;
1714}
1715
1716static rpmdbMatchIterator indexIterInit(rpmdb db, rpmDbiTagVal rpmtag,
1717 const void * keyp, size_t keylen)
1718{
1719 rpmdbMatchIterator mi = NULL((void*)0);
1720 rpmDbiTagVal dbtag = rpmtag;
1721 dbiIndex dbi = NULL((void*)0);
1722 dbiIndexSet set = NULL((void*)0);
1723
1724 /* Fixup the physical index for our pseudo indexes */
1725 if (rpmtag == RPMDBI_LABEL) {
1726 dbtag = RPMDBI_NAME;
1727 } else if (rpmtag == RPMDBI_INSTFILENAMES) {
1728 dbtag = RPMDBI_BASENAMES;
1729 }
1730
1731 if (indexOpen(db, dbtag, 0, &dbi) == 0) {
1732 int rc = 0;
1733
1734 if (keyp) {
1735 if (rpmtag == RPMDBI_LABEL) {
1736 rc = dbiFindByLabel(db, dbi, keyp, &set);
1737 } else if (rpmtag == RPMDBI_BASENAMES) {
1738 rc = rpmdbFindByFile(db, dbi, keyp, 0, &set);
1739 } else if (rpmtag == RPMDBI_INSTFILENAMES) {
1740 rc = rpmdbFindByFile(db, dbi, keyp, 1, &set);
1741 } else {
1742 rc = indexGet(dbi, keyp, keylen, &set);
1743 }
1744 } else {
1745 /* get all entries from index */
1746 rc = indexGet(dbi, NULL((void*)0), 0, &set);
1747 }
1748
1749 if (rc) { /* error/not found */
1750 set = dbiIndexSetFree(set);
1751 } else {
1752 mi = rpmdbNewIterator(db, dbtag);
1753 mi->mi_set = set;
1754
1755 if (keyp) {
1756 rpmdbSortIterator(mi);
1757 }
1758 }
1759 }
1760
1761 return mi;
1762}
1763
1764rpmdbMatchIterator rpmdbInitIterator(rpmdb db, rpmDbiTagVal rpmtag,
1765 const void * keyp, size_t keylen)
1766{
1767 rpmdbMatchIterator mi = NULL((void*)0);
1768
1769 if (db != NULL((void*)0)) {
1770 (void) rpmsqPoll();
1771
1772 if (rpmtag == RPMDBI_PACKAGES)
1773 mi = pkgdbIterInit(db, keyp, keylen);
1774 else
1775 mi = indexIterInit(db, rpmtag, keyp, keylen);
1776 }
1777
1778 return mi;
1779}
1780
1781rpmdbMatchIterator rpmdbInitPrefixIterator(rpmdb db, rpmDbiTagVal rpmtag,
1782 const void * pfx, size_t plen)
1783{
1784 rpmdbMatchIterator mi = NULL((void*)0);
1785 dbiIndexSet set = NULL((void*)0);
1786 dbiIndex dbi = NULL((void*)0);
1787 rpmDbiTagVal dbtag = rpmtag;
1788
1789 if (!pfx)
1790 return NULL((void*)0);
1791
1792 if (db != NULL((void*)0) && rpmtag != RPMDBI_PACKAGES) {
1793 (void) rpmsqPoll();
1794
1795
1796 if (indexOpen(db, dbtag, 0, &dbi) == 0) {
1797 int rc = 0;
1798
1799 rc = indexPrefixGet(dbi, pfx, plen, &set);
1800
1801 if (rc) {
1802 set = dbiIndexSetFree(set);
1803 } else {
1804 mi = rpmdbNewIterator(db, dbtag);
1805 mi->mi_set = set;
1806 rpmdbSortIterator(mi);
1807 }
1808 }
1809
1810 }
1811
1812 return mi;
1813}
1814
1815/*
1816 * Convert current tag data to db key
1817 * @param tagdata Tag data container
1818 * @retval keylen Length of key
1819 * @return Pointer to key value or NULL to signal skip
1820 */
1821static const void * td2key(rpmtd tagdata, unsigned int *keylen)
1822{
1823 const void * data = NULL((void*)0);
1824 unsigned int size = 0;
1825 const char *str = NULL((void*)0);
1826
1827 switch (rpmtdType(tagdata)) {
1828 case RPM_CHAR_TYPE:
1829 case RPM_INT8_TYPE:
1830 size = sizeof(uint8_t);
1831 data = rpmtdGetChar(tagdata);
1832 break;
1833 case RPM_INT16_TYPE:
1834 size = sizeof(uint16_t);
1835 data = rpmtdGetUint16(tagdata);
1836 break;
1837 case RPM_INT32_TYPE:
1838 size = sizeof(uint32_t);
1839 data = rpmtdGetUint32(tagdata);
1840 break;
1841 case RPM_INT64_TYPE:
1842 size = sizeof(uint64_t);
1843 data = rpmtdGetUint64(tagdata);
1844 break;
1845 case RPM_BIN_TYPE:
1846 size = tagdata->count;
1847 data = tagdata->data;
1848 break;
1849 case RPM_STRING_TYPE:
1850 case RPM_I18NSTRING_TYPE:
1851 case RPM_STRING_ARRAY_TYPE:
1852 str = rpmtdGetString(tagdata);
1853 if (str) {
1854 size = strlen(str);
1855 data = str;
1856 }
1857 break;
1858 default:
1859 break;
1860 }
1861
1862 if (data && keylen)
1863 *keylen = size;
1864
1865 return data;
1866}
1867/*
1868 * rpmdbIndexIterator
1869 */
1870
1871rpmdbIndexIterator rpmdbIndexIteratorInit(rpmdb db, rpmDbiTag rpmtag)
1872{
1873 rpmdbIndexIterator ii;
1874 dbiIndex dbi = NULL((void*)0);
1875
1876 if (db == NULL((void*)0))
1877 return NULL((void*)0);
1878
1879 (void) rpmsqPoll();
1880
1881 if (indexOpen(db, rpmtag, 0, &dbi))
1882 return NULL((void*)0);
1883
1884 /* Chain cursors for teardown on abnormal exit. */
1885 ii = xcalloc(1, sizeof(*ii))rcalloc((1), (sizeof(*ii)));
1886 ii->ii_next = rpmiiRock;
1887 rpmiiRock = ii;
1888
1889 ii->ii_db = rpmdbLink(db);
1890 ii->ii_rpmtag = rpmtag;
1891 ii->ii_dbi = dbi;
1892 ii->ii_set = NULL((void*)0);
1893
1894 return ii;
1895}
1896
1897int rpmdbIndexIteratorNext(rpmdbIndexIterator ii, const void ** key, size_t * keylen)
1898{
1899 int rc;
1900 unsigned int iikeylen = 0; /* argh, size_t vs uint pointer... */
1901
1902 if (ii == NULL((void*)0))
1903 return -1;
1904
1905 if (ii->ii_dbc == NULL((void*)0))
1906 ii->ii_dbc = dbiCursorInit(ii->ii_dbi, DBC_READ);
1907
1908 /* free old data */
1909 ii->ii_set = dbiIndexSetFree(ii->ii_set);
1910
1911 rc = idxdbGet(ii->ii_dbi, ii->ii_dbc, NULL((void*)0), 0, &ii->ii_set, DBC_NORMAL_SEARCH);
1912
1913 *key = idxdbKey(ii->ii_dbi, ii->ii_dbc, &iikeylen);
1914 *keylen = iikeylen;
1915
1916 return (rc == RPMRC_OK) ? 0 : -1;
1917}
1918
1919int rpmdbIndexIteratorNextTd(rpmdbIndexIterator ii, rpmtd keytd)
1920{
1921 size_t keylen = 0;
1922 const void * keyp = NULL((void*)0);
1923
1924 int rc = rpmdbIndexIteratorNext(ii, &keyp, &keylen);
1925
1926 if (rc == 0) {
1927 rpmTagVal tag = ii->ii_rpmtag;
1928 rpmTagClass tagclass = rpmTagGetClass(tag);
1929
1930 /* Set the common values, overridden below as necessary */
1931 keytd->type = rpmTagGetTagType(tag);
1932 keytd->tag = tag;
1933 keytd->flags = RPMTD_ALLOCED;
1934 keytd->count = 1;
1935
1936 switch (tagclass) {
1937 case RPM_STRING_CLASS: {
1938 /*
1939 * XXX: We never return arrays here, so everything is a
1940 * "simple" string. However this can disagree with the
1941 * type of the index tag, eg requires are string arrays.
1942 */
1943 char *key = memcpy(xmalloc(keylen + 1)rmalloc((keylen + 1)), keyp, keylen);
1944 key[keylen] = '\0';
1945 keytd->data = key;
1946 keytd->type = RPM_STRING_TYPE;
1947 } break;
1948 case RPM_BINARY_CLASS:
1949 /* Binary types abuse count for data length */
1950 keytd->count = keylen;
1951 /* fallthrough */
1952 case RPM_NUMERIC_CLASS:
1953 keytd->data = memcpy(xmalloc(keylen)rmalloc((keylen)), keyp, keylen);
1954 break;
1955 default:
1956 rpmtdReset(keytd);
1957 rc = -1;
1958 break;
1959 }
1960 }
1961
1962 return rc;
1963}
1964
1965unsigned int rpmdbIndexIteratorNumPkgs(rpmdbIndexIterator ii)
1966{
1967 return (ii && ii->ii_set) ? dbiIndexSetCount(ii->ii_set) : 0;
1968}
1969
1970unsigned int rpmdbIndexIteratorPkgOffset(rpmdbIndexIterator ii, unsigned int nr)
1971{
1972 if (!ii || !ii->ii_set)
1973 return 0;
1974 if (dbiIndexSetCount(ii->ii_set) <= nr)
1975 return 0;
1976 return dbiIndexRecordOffset(ii->ii_set, nr);
1977}
1978
1979unsigned int *rpmdbIndexIteratorPkgOffsets(rpmdbIndexIterator ii)
1980{
1981 int i;
1982
1983 if (!ii || !ii->ii_set)
1984 return NULL((void*)0);
1985
1986 if (ii->ii_hdrNums)
1987 ii->ii_hdrNums = _free(ii->ii_hdrNums)rfree((ii->ii_hdrNums));
1988
1989 ii->ii_hdrNums = xmalloc(sizeof(*ii->ii_hdrNums) * ii->ii_set->count)rmalloc((sizeof(*ii->ii_hdrNums) * ii->ii_set->count
))
;
1990 for (i = 0; i < ii->ii_set->count; i++) {
1991 ii->ii_hdrNums[i] = ii->ii_set->recs[i].hdrNum;
1992 }
1993
1994 return ii->ii_hdrNums;
1995}
1996
1997unsigned int rpmdbIndexIteratorTagNum(rpmdbIndexIterator ii, unsigned int nr)
1998{
1999 if (!ii || !ii->ii_set)
2000 return 0;
2001 if (dbiIndexSetCount(ii->ii_set) <= nr)
2002 return 0;
2003 return dbiIndexRecordFileNumber(ii->ii_set, nr);
2004}
2005
2006rpmdbIndexIterator rpmdbIndexIteratorFree(rpmdbIndexIterator ii)
2007{
2008 rpmdbIndexIterator * prev, next;
2009
2010 if (ii == NULL((void*)0))
2011 return NULL((void*)0);
2012
2013 prev = &rpmiiRock;
2014 while ((next = *prev) != NULL((void*)0) && next != ii)
2015 prev = &next->ii_next;
2016 if (next) {
2017 *prev = next->ii_next;
2018 next->ii_next = NULL((void*)0);
2019 } else
2020 return NULL((void*)0);
2021
2022 ii->ii_dbc = dbiCursorFree(ii->ii_dbi, ii->ii_dbc);
2023 ii->ii_dbi = NULL((void*)0);
2024 rpmdbClose(ii->ii_db);
2025 ii->ii_set = dbiIndexSetFree(ii->ii_set);
2026
2027 if (ii->ii_hdrNums)
2028 ii->ii_hdrNums = _free(ii->ii_hdrNums)rfree((ii->ii_hdrNums));
2029
2030 ii = _free(ii)rfree((ii));
2031 return NULL((void*)0);
2032}
2033
2034static void logAddRemove(const char *dbiname, int removing, rpmtd tagdata)
2035{
2036 rpm_count_t c = rpmtdCount(tagdata);
2037 if (c == 1 && rpmtdType(tagdata) == RPM_STRING_TYPE) {
2038 rpmlog(RPMLOG_DEBUG, "%s \"%s\" %s %s index.\n",
2039 removing ? "removing" : "adding", rpmtdGetString(tagdata),
2040 removing ? "from" : "to", dbiname);
2041 } else if (c > 0) {
2042 rpmlog(RPMLOG_DEBUG, "%s %d entries %s %s index.\n",
2043 removing ? "removing" : "adding", c,
2044 removing ? "from" : "to", dbiname);
2045 }
2046}
2047
2048static rpmRC indexDel(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h)
2049{
2050 return tag2index(dbi, rpmtag, hdrNum, h, idxdbDel);
2051}
2052
2053int rpmdbRemove(rpmdb db, unsigned int hdrNum)
2054{
2055 dbiIndex dbi = NULL((void*)0);
2056 dbiCursor dbc = NULL((void*)0);
2057 Header h;
2058 int ret = 0;
2059
2060 if (db == NULL((void*)0))
2061 return 0;
2062
2063 h = rpmdbGetHeaderAt(db, hdrNum);
2064
2065 if (h == NULL((void*)0)) {
2066 rpmlog(RPMLOG_ERR, _("%s: cannot read header at 0x%x\n")dcgettext ("rpm", "%s: cannot read header at 0x%x\n", 5),
2067 "rpmdbRemove", hdrNum);
2068 return 1;
2069 } else {
2070 char *nevra = headerGetAsString(h, RPMTAG_NEVRA);
2071 rpmlog(RPMLOG_DEBUG, " --- h#%8u %s\n", hdrNum, nevra);
2072 free(nevra);
2073 }
2074
2075 if (pkgdbOpen(db, 0, &dbi))
2076 return 1;
2077
2078 rpmsqBlock(SIG_BLOCK0);
2079 dbCtrl(db, DB_CTRL_LOCK_RW);
2080
2081 /* Remove header from primary index */
2082 dbc = dbiCursorInit(dbi, DBC_WRITE);
2083 ret = pkgdbDel(dbi, dbc, hdrNum);
2084 dbiCursorFree(dbi, dbc);
2085
2086 /* Remove associated data from secondary indexes */
2087 if (ret == 0) {
2088 for (int dbix = 0; dbix < db->db_ndbi; dbix++) {
2089 rpmDbiTag rpmtag = db->db_tags[dbix];
2090
2091 if (indexOpen(db, rpmtag, 0, &dbi))
2092 continue;
2093
2094 ret += indexDel(dbi, rpmtag, hdrNum, h);
2095 }
2096 }
2097
2098 dbCtrl(db, DB_CTRL_INDEXSYNC);
2099 dbCtrl(db, DB_CTRL_UNLOCK_RW);
2100 rpmsqBlock(SIG_UNBLOCK1);
2101
2102 headerFree(h);
2103
2104 /* XXX return ret; */
2105 return 0;
2106}
2107
2108struct updateRichDepData {
2109 ARGV_t argv;
2110 int nargv;
2111 int neg;
2112 int level;
2113 int *nargv_level;
2114};
2115
2116static rpmRC updateRichDepCB(void *cbdata, rpmrichParseType type,
2117 const char *n, int nl, const char *e, int el, rpmsenseFlags sense,
2118 rpmrichOp op, char **emsg) {
2119 struct updateRichDepData *data = cbdata;
2120 if (type == RPMRICH_PARSE_ENTER) {
2121 data->level++;
2122 data->nargv_level = xrealloc(data->nargv_level, data->level * (sizeof(int)))rrealloc((data->nargv_level), (data->level * (sizeof(int
))))
;
2123 data->nargv_level[data->level - 1] = data->nargv;
2124 }
2125 if (type == RPMRICH_PARSE_LEAVE) {
2126 data->level--;
2127 }
2128 if (type == RPMRICH_PARSE_SIMPLE && nl && !(nl > 7 && !strncmp(n, "rpmlib(", 7))) {
2129 char *name = xmalloc(nl + 2)rmalloc((nl + 2));
2130 *name = data->neg ? '!' : ' ';
2131 strncpy(name + 1, n, nl);
2132 name[1 + nl] = 0;
2133 argvAdd(&data->argv, name);
2134 data->nargv++;
2135 _free(name)rfree((name));
2136 }
2137 if (type == RPMRICH_PARSE_OP && op == RPMRICHOP_IF) {
2138 /* save nargv in case of ELSE */
2139 data->nargv_level[data->level - 1] = data->nargv;
2140 data->neg ^= 1;
2141 }
2142 if (type == RPMRICH_PARSE_OP && op == RPMRICHOP_ELSE) {
2143 int i, nargv = data->nargv;
2144 /* copy and invert condition block */
2145 for (i = data->nargv_level[data->level - 1]; i < nargv; i++) {
2146 char *name = data->argv[i];
2147 *name ^= ' ' ^ '!';
2148 argvAdd(&data->argv, name);
2149 *name ^= ' ' ^ '!';
2150 data->nargv++;
2151 }
2152 data->neg ^= 1;
2153 }
2154 if (type == RPMRICH_PARSE_LEAVE && op == RPMRICHOP_IF) {
2155 data->neg ^= 1;
2156 }
2157 return RPMRC_OK;
2158}
2159
2160static rpmRC updateRichDep(dbiIndex dbi, dbiCursor dbc, const char *str,
2161 struct dbiIndexItem_s *rec,
2162 idxfunc idxupdate)
2163{
2164 int n, i, rc = 0;
2165 struct updateRichDepData data;
2166
2167 data.argv = argvNew();
2168 data.neg = 0;
2169 data.nargv = 0;
2170 data.level = 0;
2171 data.nargv_level = xcalloc(1, sizeof(int))rcalloc((1), (sizeof(int)));
2172 if (rpmrichParse(&str, NULL((void*)0), updateRichDepCB, &data) == RPMRC_OK) {
2173 n = argvCount(data.argv);
2174 if (n) {
2175 argvSort(data.argv, NULL((void*)0));
2176 for (i = 0; i < n; i++) {
2177 char *name = data.argv[i];
2178 if (i && !strcmp(data.argv[i - 1], name))
2179 continue; /* ignore dups */
2180 if (*name == ' ')
2181 name++;
2182 rc += idxupdate(dbi, dbc, name, strlen(name), rec);
2183 }
2184 }
2185 }
2186 _free(data.nargv_level)rfree((data.nargv_level));
2187 argvFree(data.argv);
2188 return rc;
2189}
2190
2191static rpmRC tag2index(dbiIndex dbi, rpmTagVal rpmtag,
2192 unsigned int hdrNum, Header h,
2193 idxfunc idxupdate)
2194{
2195 int i, rc = 0;
2196 struct rpmtd_s tagdata, reqflags, trig_index;
2197 dbiCursor dbc = NULL((void*)0);
2198
2199 switch (rpmtag) {
2200 case RPMTAG_REQUIRENAME:
2201 headerGet(h, RPMTAG_REQUIREFLAGS, &reqflags, HEADERGET_MINMEM);
2202 break;
2203 case RPMTAG_FILETRIGGERNAME:
2204 headerGet(h, RPMTAG_FILETRIGGERINDEX, &trig_index, HEADERGET_MINMEM);
2205 break;
2206 case RPMTAG_TRANSFILETRIGGERNAME:
2207 headerGet(h, RPMTAG_TRANSFILETRIGGERINDEX, &trig_index, HEADERGET_MINMEM);
2208 break;
2209 }
2210 headerGet(h, rpmtag, &tagdata, HEADERGET_MINMEM);
2211
2212 if (rpmtdCount(&tagdata) == 0) {
2213 if (rpmtag != RPMTAG_GROUP)
2214 goto exit;
2215
2216 /* XXX preserve legacy behavior */
2217 tagdata.type = RPM_STRING_TYPE;
2218 tagdata.data = (const char **) "Unknown";
2219 tagdata.count = 1;
2220 }
2221
2222 dbc = dbiCursorInit(dbi, DBC_WRITE);
2223
2224 logAddRemove(dbiName(dbi), 0, &tagdata);
2225 while ((i = rpmtdNext(&tagdata)) >= 0) {
2226 const void * key = NULL((void*)0);
2227 unsigned int keylen = 0;
2228 int j;
2229 struct dbiIndexItem_s rec;
2230
2231 switch (rpmtag) {
2232 /* Include trigger index in db index for triggers */
2233 case RPMTAG_FILETRIGGERNAME:
2234 case RPMTAG_TRANSFILETRIGGERNAME:
2235 rec.hdrNum = hdrNum;
2236 rec.tagNum = *rpmtdNextUint32(&trig_index);
2237 break;
2238
2239 /* Include the tagNum in the others indices (only files use though) */
2240 default:
2241 rec.hdrNum = hdrNum;
2242 rec.tagNum = i;
2243 break;
2244 }
2245
2246 switch (rpmtag) {
2247 case RPMTAG_REQUIRENAME: {
2248 /* Filter out install prerequisites. */
2249 rpm_flag_t *rflag = rpmtdNextUint32(&reqflags);
2250 if (rflag && isInstallPreReq(*rflag)((*rflag) & ((RPMSENSE_SCRIPT_PRE|RPMSENSE_SCRIPT_POST|RPMSENSE_RPMLIB
|RPMSENSE_KEYRING|RPMSENSE_PRETRANS|RPMSENSE_POSTTRANS) &
~RPMSENSE_PREREQ))
&&
2251 !isErasePreReq(*rflag)((*rflag) & ((RPMSENSE_SCRIPT_PREUN|RPMSENSE_SCRIPT_POSTUN
) & ~RPMSENSE_PREREQ))
)
2252 continue;
2253 break;
2254 }
2255 case RPMTAG_TRIGGERNAME:
2256 if (i > 0) { /* don't add duplicates */
2257 const char **tnames = tagdata.data;
2258 const char *str = rpmtdGetString(&tagdata);
2259 for (j = 0; j < i; j++) {
2260 if (rstreq(str, tnames[j]))
2261 break;
2262 }
2263 if (j < i)
2264 continue;
2265 }
2266 break;
2267 default:
2268 break;
2269 }
2270
2271 if ((key = td2key(&tagdata, &keylen)) == NULL((void*)0))
2272 continue;
2273
2274 rc += idxupdate(dbi, dbc, key, keylen, &rec);
2275
2276 if (*(char *)key == '(') {
2277 switch (rpmtag) {
2278 case RPMTAG_REQUIRENAME:
2279 case RPMTAG_CONFLICTNAME:
2280 case RPMTAG_SUGGESTNAME:
2281 case RPMTAG_SUPPLEMENTNAME:
2282 case RPMTAG_RECOMMENDNAME:
2283 case RPMTAG_ENHANCENAME:
2284 if (rpmtdType(&tagdata) == RPM_STRING_ARRAY_TYPE) {
2285 rc += updateRichDep(dbi, dbc, rpmtdGetString(&tagdata),
2286 &rec, idxupdate);
2287 }
2288 default:
2289 break;
2290 }
2291 }
2292 }
2293
2294 dbiCursorFree(dbi, dbc);
2295
2296exit:
2297 rpmtdFreeData(&tagdata);
2298 return (rc == 0) ? RPMRC_OK : RPMRC_FAIL;
2299}
2300
2301static rpmRC indexPut(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h)
2302{
2303 return tag2index(dbi, rpmtag, hdrNum, h, idxdbPut);
2304}
2305
2306int rpmdbAdd(rpmdb db, Header h)
2307{
2308 dbiIndex dbi = NULL((void*)0);
2309 dbiCursor dbc = NULL((void*)0);
2310 unsigned int hdrNum = 0;
2311 unsigned int hdrLen = 0;
2312 unsigned char *hdrBlob = NULL((void*)0);
2313 int ret = 0;
2314
2315 if (db == NULL((void*)0))
2316 return 0;
2317
2318 hdrBlob = headerExport(h, &hdrLen);
2319 if (hdrBlob == NULL((void*)0) || hdrLen == 0) {
2320 ret = -1;
2321 goto exit;
2322 }
2323
2324 ret = pkgdbOpen(db, 0, &dbi);
2325 if (ret)
2326 goto exit;
2327
2328 rpmsqBlock(SIG_BLOCK0);
2329 dbCtrl(db, DB_CTRL_LOCK_RW);
2330
2331 /* Add header to primary index */
2332 dbc = dbiCursorInit(dbi, DBC_WRITE);
2333 ret = pkgdbNew(dbi, dbc, &hdrNum);
2334 if (ret == 0)
2335 ret = pkgdbPut(dbi, dbc, hdrNum, hdrBlob, hdrLen);
2336 dbiCursorFree(dbi, dbc);
2337
2338 /* Add associated data to secondary indexes */
2339 if (ret == 0) {
2340 for (int dbix = 0; dbix < db->db_ndbi; dbix++) {
2341 rpmDbiTag rpmtag = db->db_tags[dbix];
2342
2343 if (indexOpen(db, rpmtag, 0, &dbi))
2344 continue;
2345
2346 ret += indexPut(dbi, rpmtag, hdrNum, h);
2347 }
2348 }
2349
2350 dbCtrl(db, DB_CTRL_INDEXSYNC);
2351 dbCtrl(db, DB_CTRL_UNLOCK_RW);
2352 rpmsqBlock(SIG_UNBLOCK1);
2353
2354 /* If everything ok, mark header as installed now */
2355 if (ret == 0) {
2356 headerSetInstance(h, hdrNum);
2357 /* Purge our verification cache on added public keys */
2358 if (db->db_checked && headerIsEntry(h, RPMTAG_PUBKEYS)) {
2359 dbChkEmpty(db->db_checked);
2360 }
2361 }
2362
2363exit:
2364 free(hdrBlob);
2365
2366 return ret;
2367}
2368
2369static int rpmdbRemoveFiles(char * pattern)
2370{
2371 int rc = 0;
2372 ARGV_t paths = NULL((void*)0), p;
2373
2374 if (rpmGlob(pattern, NULL((void*)0), &paths) == 0) {
2375 for (p = paths; *p; p++) {
2376 rc += unlink(*p);
2377 }
2378 argvFree(paths);
2379 }
2380 return rc;
2381}
2382
2383static int rpmdbRemoveDatabase(const char *dbpath)
2384{
2385 int rc = 0;
2386 char *pattern;
2387
2388 pattern = rpmGetPath(dbpath, "/*", NULL((void*)0));
2389 rc += rpmdbRemoveFiles(pattern);
2390 free(pattern);
2391 pattern = rpmGetPath(dbpath, "/.??*", NULL((void*)0));
2392 rc += rpmdbRemoveFiles(pattern);
2393 free(pattern);
2394
2395 rc += rmdir(dbpath);
2396 return rc;
2397}
2398
2399static int rpmdbMoveDatabase(const char * prefix, const char * srcdbpath,
2400 const char * dbpath, const char * tmppath)
2401{
2402 int rc = -1;
2403 int xx;
2404 char *src = rpmGetPath(prefix, "/", srcdbpath, NULL((void*)0));
2405 char *old = rpmGetPath(prefix, "/", tmppath, NULL((void*)0));
2406 char *dest = rpmGetPath(prefix, "/", dbpath, NULL((void*)0));
2407
2408 char * oldkeys = rpmGetPath(old, "/", "pubkeys", NULL((void*)0));
2409 char * destkeys = rpmGetPath(dest, "/", "pubkeys", NULL((void*)0));
2410
2411 xx = rename(dest, old);
2412 if (xx) {
2413 goto exit;
2414 }
2415 xx = rename(src, dest);
2416 if (xx) {
2417 rpmlog(RPMLOG_ERR, _("could not move new database in place\n")dcgettext ("rpm", "could not move new database in place\n", 5
)
);
2418 xx = rename(old, dest);
2419 if (xx) {
2420 rpmlog(RPMLOG_ERR, _("could also not restore old database from %s\n")dcgettext ("rpm", "could also not restore old database from %s\n"
, 5)
,
2421 old);
2422 rpmlog(RPMLOG_ERR, _("replace files in %s with files from %s "dcgettext ("rpm", "replace files in %s with files from %s " "to recover\n"
, 5)
2423 "to recover\n")dcgettext ("rpm", "replace files in %s with files from %s " "to recover\n"
, 5)
, dest, old);
2424 }
2425 goto exit;
2426 }
2427
2428 if (access(oldkeys, F_OK0 ) != -1) {
2429 xx = rename(oldkeys, destkeys);
2430 if (xx) {
2431 rpmlog(RPMLOG_ERR, _("Could not get public keys from %s\n")dcgettext ("rpm", "Could not get public keys from %s\n", 5), oldkeys);
2432 goto exit;
2433 }
2434 }
2435
2436 xx = rpmdbRemoveDatabase(old);
2437 if (xx) {
2438 rpmlog(RPMLOG_ERR, _("could not delete old database at %s\n")dcgettext ("rpm", "could not delete old database at %s\n", 5), old);
2439 }
2440
2441 rc = 0;
2442
2443 exit:
2444 _free(src)rfree((src));
2445 _free(old)rfree((old));
2446 _free(dest)rfree((dest));
2447 _free(oldkeys)rfree((oldkeys));
2448 _free(destkeys)rfree((destkeys));
2449 return rc;
2450}
2451
2452static int rpmdbSetPermissions(char * src, char * dest)
2453{
2454 struct dirent *dp;
2455 DIR *dfd;
2456
2457 struct stat st;
2458 int xx, rc = -1;
2459 char * filepath;
2460
2461 if (stat(dest, &st) < 0)
2462 goto exit;
2463 if (stat(src, &st) < 0)
2464 goto exit;
2465
2466 if ((dfd = opendir(dest)) == NULL((void*)0)) {
2467 goto exit;
2468 }
2469
2470 rc = 0;
2471 while ((dp = readdir(dfd)) != NULL((void*)0)) {
2472 if (!strcmp(dp->d_name, "..")) {
2473 continue;
2474 }
2475 filepath = rpmGetPath(dest, "/", dp->d_name, NULL((void*)0));
2476 xx = chown(filepath, st.st_uid, st.st_gid);
2477 rc += xx;
2478 if (!strcmp(dp->d_name, ".")) {
2479 xx = chmod(filepath, (st.st_mode & 07777));
2480 } else {
2481 xx = chmod(filepath, (st.st_mode & 07666));
2482 }
2483 rc += xx;
2484 _free(filepath)rfree((filepath));
2485 }
2486
2487 exit:
2488 return rc;
2489}
2490
2491int rpmdbRebuild(const char * prefix, rpmts ts,
2492 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg))
2493{
2494 rpmdb olddb;
2495 char * dbpath = NULL((void*)0);
2496 char * rootdbpath = NULL((void*)0);
2497 char * tmppath = NULL((void*)0);
2498 rpmdb newdb;
2499 char * newdbpath = NULL((void*)0);
2500 char * newrootdbpath = NULL((void*)0);
2501 int nocleanup = 1;
2502 int failed = 0;
2503 int rc = 0;
2504
2505 dbpath = rpmGetPath("%{?_dbpath}", NULL((void*)0));
2506 if (rstreq(dbpath, "")) {
2507 rpmlog(RPMLOG_ERR, _("no dbpath has been set")dcgettext ("rpm", "no dbpath has been set", 5));
2508 rc = 1;
2509 goto exit;
2510 }
2511 rootdbpath = rpmGetPath(prefix, dbpath, NULL((void*)0));
2512
2513 newdbpath = rpmGetPath("%{?_dbpath_rebuild}", NULL((void*)0));
2514 if (rstreq(newdbpath, "") || rstreq(newdbpath, dbpath)) {
2515 newdbpath = _free(newdbpath)rfree((newdbpath));
2516 rasprintf(&newdbpath, "%srebuilddb.%d", dbpath, (int) getpid());
2517 nocleanup = 0;
2518 }
2519 newrootdbpath = rpmGetPath(prefix, newdbpath, NULL((void*)0));
2520
2521 rpmlog(RPMLOG_DEBUG, "rebuilding database %s into %s\n",
2522 rootdbpath, newrootdbpath);
2523
2524 if (mkdir(newrootdbpath, 0755)) {
2525 rpmlog(RPMLOG_ERR, _("failed to create directory %s: %s\n")dcgettext ("rpm", "failed to create directory %s: %s\n", 5),
2526 newrootdbpath, strerror(errno(*__errno_location ())));
2527 rc = 1;
2528 goto exit;
2529 }
2530
2531 if (openDatabase(prefix, dbpath, &olddb,
2532 O_RDONLY00, 0644, RPMDB_FLAG_REBUILD)) {
2533 rc = 1;
2534 goto exit;
2535 }
2536 if (openDatabase(prefix, newdbpath, &newdb,
2537 (O_RDWR02 | O_CREAT0100), 0644, RPMDB_FLAG_REBUILD)) {
2538 rc = 1;
2539 goto exit;
2540 }
2541
2542 { Header h = NULL((void*)0);
2543 rpmdbMatchIterator mi;
2544
2545 mi = rpmdbInitIterator(olddb, RPMDBI_PACKAGES, NULL((void*)0), 0);
2546 if (ts && hdrchk)
2547 (void) rpmdbSetHdrChk(mi, ts, hdrchk);
2548
2549 while ((h = rpmdbNextIterator(mi)) != NULL((void*)0)) {
2550
2551 /* let's sanity check this record a bit, otherwise just skip it */
2552 if (!(headerIsEntry(h, RPMTAG_NAME) &&
2553 headerIsEntry(h, RPMTAG_VERSION) &&
2554 headerIsEntry(h, RPMTAG_RELEASE) &&
2555 headerIsEntry(h, RPMTAG_BUILDTIME)))
2556 {
2557 rpmlog(RPMLOG_ERR,
2558 _("header #%u in the database is bad -- skipping.\n")dcgettext ("rpm", "header #%u in the database is bad -- skipping.\n"
, 5)
,
2559 rpmdbGetIteratorOffset(mi));
2560 continue;
2561 }
2562
2563 /* Deleted entries are eliminated in legacy headers by copy. */
2564 if (headerIsEntry(h, RPMTAG_HEADERIMAGE)) {
2565 Header nh = headerReload(headerCopy(h), RPMTAG_HEADERIMAGE);
2566 rc = rpmdbAdd(newdb, h);
2567 headerFree(nh);
2568 } else {
2569 rc = rpmdbAdd(newdb, h);
2570 }
2571
2572 if (rc) {
2573 rpmlog(RPMLOG_ERR, _("cannot add record originally at %u\n")dcgettext ("rpm", "cannot add record originally at %u\n", 5),
2574 rpmdbGetIteratorOffset(mi));
2575 failed = 1;
2576 break;
2577 }
2578 }
2579
2580 rpmdbFreeIterator(mi);
2581
2582 }
2583
2584 rpmdbClose(olddb);
2585 rpmdbClose(newdb);
2586
2587 if (failed) {
2588 rpmlog(RPMLOG_WARNING,
2589 _("failed to rebuild database: original database "dcgettext ("rpm", "failed to rebuild database: original database "
"remains in place\n", 5)
2590 "remains in place\n")dcgettext ("rpm", "failed to rebuild database: original database "
"remains in place\n", 5)
);
2591
2592 rpmdbRemoveDatabase(newrootdbpath);
2593 rc = 1;
2594 goto exit;
2595 } else {
2596 rpmdbSetPermissions(dbpath, newdbpath);
2597 }
2598
2599 if (!nocleanup) {
2600 rasprintf(&tmppath, "%sold.%d", dbpath, (int) getpid());
2601 if (rpmdbMoveDatabase(prefix, newdbpath, dbpath, tmppath)) {
2602 rpmlog(RPMLOG_ERR, _("failed to replace old database with new "dcgettext ("rpm", "failed to replace old database with new " "database!\n"
, 5)
2603 "database!\n")dcgettext ("rpm", "failed to replace old database with new " "database!\n"
, 5)
);
2604 rpmlog(RPMLOG_ERR, _("replace files in %s with files from %s "dcgettext ("rpm", "replace files in %s with files from %s " "to recover\n"
, 5)
2605 "to recover\n")dcgettext ("rpm", "replace files in %s with files from %s " "to recover\n"
, 5)
, dbpath, newdbpath);
2606 rc = 1;
2607 goto exit;
2608 }
2609 }
2610 rc = 0;
2611
2612exit:
2613 free(newdbpath);
2614 free(dbpath);
2615 free(tmppath);
2616 free(newrootdbpath);
2617 free(rootdbpath);
2618
2619 return rc;
2620}
2621
2622int rpmdbCtrl(rpmdb db, rpmdbCtrlOp ctrl)
2623{
2624 dbCtrlOp dbctrl = 0;
2625 switch (ctrl) {
2626 case RPMDB_CTRL_LOCK_RO:
2627 dbctrl = DB_CTRL_LOCK_RO;
2628 break;
2629 case RPMDB_CTRL_UNLOCK_RO:
2630 dbctrl = DB_CTRL_UNLOCK_RO;
2631 break;
2632 case RPMDB_CTRL_LOCK_RW:
2633 dbctrl = DB_CTRL_LOCK_RW;
2634 break;
2635 case RPMDB_CTRL_UNLOCK_RW:
2636 dbctrl = DB_CTRL_UNLOCK_RW;
2637 break;
2638 case RPMDB_CTRL_INDEXSYNC:
2639 dbctrl = DB_CTRL_INDEXSYNC;
2640 break;
2641 }
2642 return dbctrl ? dbCtrl(db, dbctrl) : 1;
2643}
2644