Bug Summary

File:lib/rpmdb.c
Warning:line 1294, column 2
Value stored to 'allpat' 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));
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 dbiIndexSetAppendOne(*matches, dbiIndexRecordOffset(allMatches, i),
676 dbiIndexRecordFileNumber(allMatches, i), 0);
677 }
678 }
679
680 prevoff = offset;
681 i++;
682 if (i < allMatches->count)
683 offset = dbiIndexRecordOffset(allMatches, i);
684 } while (i < allMatches->count && offset == prevoff);
685
686 rpmtdFreeData(&bn);
687 rpmtdFreeData(&dn);
688 rpmtdFreeData(&di);
689 if (usestate)
690 rpmtdFreeData(&fs);
691 headerFree(h);
692 }
693
694 free(fp1);
695 fpCacheFree(fpc);
696
697 if ((*matches)->count == 0) {
698 *matches = dbiIndexSetFree(*matches);
699 rc = RPMRC_NOTFOUND;
700 } else {
701 rc = RPMRC_OK;
702 }
703
704exit:
705 dbiIndexSetFree(allMatches);
706 free(dirName);
707 return rc;
708}
709
710int rpmdbCountPackages(rpmdb db, const char * name)
711{
712 int count = -1;
713 dbiIndex dbi = NULL((void*)0);
714
715 if (name != NULL((void*)0) && indexOpen(db, RPMDBI_NAME, 0, &dbi) == 0) {
716 dbiIndexSet matches = NULL((void*)0);
717
718 rpmRC rc = indexGet(dbi, name, strlen(name), &matches);
719
720 if (rc == RPMRC_OK) {
721 count = dbiIndexSetCount(matches);
722 } else {
723 count = (rc == RPMRC_NOTFOUND) ? 0 : -1;
724 }
725 dbiIndexSetFree(matches);
726 }
727
728 return count;
729}
730
731/**
732 * Attempt partial matches on name[-version[-release]][.arch] strings.
733 * @param db rpmdb handle
734 * @param dbi index database
735 * @param name package name
736 * @param epoch package epoch (-1 for any epoch)
737 * @param version package version (can be a pattern)
738 * @param release package release (can be a pattern)
739 * @param arch package arch (can be a pattern)
740 * @retval matches set of header instances that match
741 * @return RPMRC_OK on match, RPMRC_NOMATCH or RPMRC_FAIL
742 */
743static rpmRC dbiFindMatches(rpmdb db, dbiIndex dbi,
744 const char * name,
745 int64_t epoch,
746 const char * version,
747 const char * release,
748 const char * arch,
749 dbiIndexSet * matches)
750{
751 unsigned int gotMatches = 0;
752 rpmRC rc;
753 unsigned int i;
754
755 rc = indexGet(dbi, name, strlen(name), matches);
756
757 /* No matches on the name, anything else wont match either */
758 if (rc != RPMRC_OK)
759 goto exit;
760
761 /* If we got matches on name and nothing else was specified, we're done */
762 if (epoch < 0 && version == NULL((void*)0) && release == NULL((void*)0) && arch == NULL((void*)0))
763 goto exit;
764
765 /* Make sure the version and release match. */
766 for (i = 0; i < dbiIndexSetCount(*matches); i++) {
767 unsigned int recoff = dbiIndexRecordOffset(*matches, i);
768 rpmdbMatchIterator mi;
769 Header h;
770
771 if (recoff == 0)
772 continue;
773
774 mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &recoff, sizeof(recoff));
775
776 /* Set iterator selectors for version/release if available. */
777 if (version &&
778 rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version))
779 {
780 rc = RPMRC_FAIL;
781 goto exit;
782 }
783 if (release &&
784 rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release))
785 {
786 rc = RPMRC_FAIL;
787 goto exit;
788 }
789 if (arch &&
790 rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_DEFAULT, arch))
791 {
792 rc = RPMRC_FAIL;
793 goto exit;
794 }
795
796 h = rpmdbNextIterator(mi);
797
798 if (epoch >= 0 && h) {
799 struct rpmtd_s td;
800 headerGet(h, RPMTAG_EPOCH, &td, HEADERGET_MINMEM);
801 if (epoch != rpmtdGetNumber(&td))
802 h = NULL((void*)0);
803 rpmtdFreeData(&td);
804 }
805 if (h)
806 (*matches)->recs[gotMatches++] = (*matches)->recs[i];
807 else
808 (*matches)->recs[i].hdrNum = 0;
809 rpmdbFreeIterator(mi);
810 }
811
812 if (gotMatches) {
813 (*matches)->count = gotMatches;
814 rc = RPMRC_OK;
815 } else
816 rc = RPMRC_NOTFOUND;
817
818exit:
819/* FIX: double indirection */
820 if (rc && matches && *matches)
821 *matches = dbiIndexSetFree(*matches);
822 return rc;
823}
824
825/**
826 * Lookup by name, name-version, and finally by name-version-release.
827 * Both version and release can be patterns.
828 * @todo Name must be an exact match, as name is a db key.
829 * @param db rpmdb handle
830 * @param dbi index database handle (always RPMDBI_NAME)
831 * @param arg name[-[epoch:]version[-release]] string
832 * @param arglen length of arg
833 * @param arch possible arch string (or NULL)
834 * @retval matches set of header instances that match
835 * @return RPMRC_OK on match, RPMRC_NOMATCH or RPMRC_FAIL
836 */
837static rpmRC dbiFindByLabelArch(rpmdb db, dbiIndex dbi,
838 const char * arg, size_t arglen, const char *arch,
839 dbiIndexSet * matches)
840{
841 char localarg[arglen+1];
842 int64_t epoch;
843 const char * version;
844 const char * release;
845 char * s;
846 char c;
847 int brackets;
848 rpmRC rc;
849
850 if (arglen == 0) return RPMRC_NOTFOUND;
851
852 strncpy(localarg, arg, arglen);
853 localarg[arglen] = '\0';
854
855 /* did they give us just a name? */
856 rc = dbiFindMatches(db, dbi, localarg, -1, NULL((void*)0), NULL((void*)0), arch, matches);
857 if (rc != RPMRC_NOTFOUND)
858 goto exit;
859
860 /* FIX: double indirection */
861 *matches = dbiIndexSetFree(*matches);
862
863 /* maybe a name-[epoch:]version ? */
864 s = localarg + arglen;
865
866 c = '\0';
867 brackets = 0;
868 for (s -= 1; s > localarg; s--) {
869 switch (*s) {
870 case '[':
871 brackets = 1;
872 break;
873 case ']':
874 if (c != '[') brackets = 0;
875 break;
876 }
877 if (!brackets && c && *s == '-')
878 break;
879 c = *s;
880 }
881
882 /* FIX: *matches may be NULL. */
883 if (s == localarg) {
884 rc = RPMRC_NOTFOUND;
885 goto exit;
886 }
887
888 *s = '\0';
889
890 epoch = splitEpoch(s + 1, &version);
891 rc = dbiFindMatches(db, dbi, localarg, epoch, version, NULL((void*)0), arch, matches);
892 if (rc != RPMRC_NOTFOUND) goto exit;
893
894 /* FIX: double indirection */
895 *matches = dbiIndexSetFree(*matches);
896
897 /* how about name-[epoch:]version-release? */
898
899 release = s + 1;
900
901 c = '\0';
902 brackets = 0;
903 for (; s > localarg; s--) {
904 switch (*s) {
905 case '[':
906 brackets = 1;
907 break;
908 case ']':
909 if (c != '[') brackets = 0;
910 break;
911 }
912 if (!brackets && c && *s == '-')
913 break;
914 c = *s;
915 }
916
917 if (s == localarg) {
918 rc = RPMRC_NOTFOUND;
919 goto exit;
920 }
921
922 *s = '\0';
923 /* FIX: *matches may be NULL. */
924 epoch = splitEpoch(s + 1, &version);
925 rc = dbiFindMatches(db, dbi, localarg, epoch, version, release, arch, matches);
926exit:
927 return rc;
928}
929
930static rpmRC dbiFindByLabel(rpmdb db, dbiIndex dbi, const char * label,
931 dbiIndexSet * matches)
932{
933 const char *arch = NULL((void*)0);
934 /* First, try with label as it is */
935 rpmRC rc = dbiFindByLabelArch(db, dbi, label, strlen(label), NULL((void*)0), matches);
936
937 /* If not found, retry with possible .arch specifier if there is one */
938 if (rc == RPMRC_NOTFOUND && (arch = strrchr(label, '.')))
939 rc = dbiFindByLabelArch(db, dbi, label, arch-label, arch+1, matches);
940
941 return rc;
942}
943
944/**
945 * Rewrite a header into packages (if necessary) and free the header.
946 * Note: this is called from a markReplacedFiles iteration, and *must*
947 * preserve the "join key" (i.e. offset) for the header.
948 * @param mi database iterator
949 * @param dbi index database handle
950 * @return 0 on success
951 */
952static int miFreeHeader(rpmdbMatchIterator mi, dbiIndex dbi)
953{
954 int rc = 0;
955
956 if (mi == NULL((void*)0) || mi->mi_h == NULL((void*)0))
957 return 0;
958
959 if (dbi && mi->mi_dbc && mi->mi_modified && mi->mi_prevoffset) {
960 rpmRC rpmrc = RPMRC_NOTFOUND;
961 unsigned int hdrLen = 0;
962 unsigned char *hdrBlob = headerExport(mi->mi_h, &hdrLen);
963
964 /* Check header digest/signature on blob export (if requested). */
965 if (mi->mi_hdrchk && mi->mi_ts) {
966 char * msg = NULL((void*)0);
967 int lvl;
968
969 rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, hdrBlob, hdrLen, &msg);
970 lvl = (rpmrc == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG);
971 rpmlog(lvl, "%s h#%8u %s",
972 (rpmrc == RPMRC_FAIL ? _("miFreeHeader: skipping")dcgettext ("rpm", "miFreeHeader: skipping", 5) : "write"),
973 mi->mi_prevoffset, (msg ? msg : "\n"));
974 msg = _free(msg)rfree((msg));
975 }
976
977 if (hdrBlob != NULL((void*)0) && rpmrc != RPMRC_FAIL) {
978 rpmsqBlock(SIG_BLOCK0);
979 dbCtrl(mi->mi_db, DB_CTRL_LOCK_RW);
980 rc = pkgdbPut(dbi, mi->mi_dbc, mi->mi_prevoffset,
981 hdrBlob, hdrLen);
982 dbCtrl(mi->mi_db, DB_CTRL_INDEXSYNC);
983 dbCtrl(mi->mi_db, DB_CTRL_UNLOCK_RW);
984 rpmsqBlock(SIG_UNBLOCK1);
985
986 if (rc) {
987 rpmlog(RPMLOG_ERR,
988 _("error(%d) storing record #%d into %s\n")dcgettext ("rpm", "error(%d) storing record #%d into %s\n", 5
)
,
989 rc, mi->mi_prevoffset, dbiName(dbi));
990 }
991 }
992 free(hdrBlob);
993 }
994
995 mi->mi_h = headerFree(mi->mi_h);
996
997 return rc;
998}
999
1000rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi)
1001{
1002 rpmdbMatchIterator * prev, next;
1003 dbiIndex dbi = NULL((void*)0);
1004 int i;
1005
1006 if (mi == NULL((void*)0))
1007 return NULL((void*)0);
1008
1009 prev = &rpmmiRock;
1010 while ((next = *prev) != NULL((void*)0) && next != mi)
1011 prev = &next->mi_next;
1012 if (next) {
1013 *prev = next->mi_next;
1014 next->mi_next = NULL((void*)0);
1015 } else
1016 return NULL((void*)0);
1017
1018 pkgdbOpen(mi->mi_db, 0, &dbi);
1019
1020 miFreeHeader(mi, dbi);
1021
1022 mi->mi_dbc = dbiCursorFree(dbi, mi->mi_dbc);
1023
1024 if (mi->mi_re != NULL((void*)0))
1025 for (i = 0; i < mi->mi_nre; i++) {
1026 miRE mire = mi->mi_re + i;
1027 mire->pattern = _free(mire->pattern)rfree((mire->pattern));
1028 if (mire->preg != NULL((void*)0)) {
1029 regfree(mire->preg);
1030 mire->preg = _free(mire->preg)rfree((mire->preg));
1031 }
1032 }
1033 mi->mi_re = _free(mi->mi_re)rfree((mi->mi_re));
1034
1035 mi->mi_set = dbiIndexSetFree(mi->mi_set);
1036 rpmdbClose(mi->mi_db);
1037 mi->mi_ts = rpmtsFree(mi->mi_ts);
1038
1039 mi = _free(mi)rfree((mi));
1040
1041 (void) rpmsqPoll();
1042
1043 return NULL((void*)0);
1044}
1045
1046unsigned int rpmdbGetIteratorOffset(rpmdbMatchIterator mi)
1047{
1048 return (mi ? mi->mi_offset : 0);
1049}
1050
1051unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi)
1052{
1053 return (mi ? mi->mi_filenum : 0);
1054}
1055
1056int rpmdbGetIteratorCount(rpmdbMatchIterator mi)
1057{
1058 return (mi && mi->mi_set ? mi->mi_set->count : 0);
1059}
1060
1061int rpmdbGetIteratorIndex(rpmdbMatchIterator mi)
1062{
1063 return (mi ? mi->mi_setx : 0);
1064}
1065
1066void rpmdbSetIteratorIndex(rpmdbMatchIterator mi, unsigned int ix)
1067{
1068 if (mi)
1069 mi->mi_setx = ix;
1070}
1071
1072unsigned int rpmdbGetIteratorOffsetFor(rpmdbMatchIterator mi, unsigned int ix)
1073{
1074 if (mi && mi->mi_set && ix < mi->mi_set->count)
1075 return mi->mi_set->recs[ix].hdrNum;
1076 return 0;
1077}
1078
1079/**
1080 * Return pattern match.
1081 * @param mire match iterator regex
1082 * @param val value to match
1083 * @return 0 if pattern matches, >0 on nomatch, <0 on error
1084 */
1085static int miregexec(miRE mire, const char * val)
1086{
1087 int rc = 0;
1088
1089 switch (mire->mode) {
1090 case RPMMIRE_STRCMP:
1091 rc = (!rstreq(mire->pattern, val));
1092 break;
1093 case RPMMIRE_DEFAULT:
1094 case RPMMIRE_REGEX:
1095 rc = regexec(mire->preg, val, 0, NULL((void*)0), mire->eflags);
1096 if (rc && rc != REG_NOMATCH) {
1097 char msg[256];
1098 (void) regerror(rc, mire->preg, msg, sizeof(msg)-1);
1099 msg[sizeof(msg)-1] = '\0';
1100 rpmlog(RPMLOG_ERR, _("%s: regexec failed: %s\n")dcgettext ("rpm", "%s: regexec failed: %s\n", 5),
1101 mire->pattern, msg);
1102 rc = -1;
1103 }
1104 break;
1105 case RPMMIRE_GLOB:
1106 rc = fnmatch(mire->pattern, val, mire->fnflags);
1107 if (rc && rc != FNM_NOMATCH1)
1108 rc = -1;
1109 break;
1110 default:
1111 rc = -1;
1112 break;
1113 }
1114
1115 return rc;
1116}
1117
1118/**
1119 * Compare iterator selectors by rpm tag (qsort/bsearch).
1120 * @param a 1st iterator selector
1121 * @param b 2nd iterator selector
1122 * @return result of comparison
1123 */
1124static int mireCmp(const void * a, const void * b)
1125{
1126 const miRE mireA = (const miRE) a;
1127 const miRE mireB = (const miRE) b;
1128 return (mireA->tag - mireB->tag);
1129}
1130
1131/**
1132 * Copy pattern, escaping for appropriate mode.
1133 * @param tag rpm tag
1134 * @retval modep type of pattern match
1135 * @param pattern pattern to duplicate
1136 * @return duplicated pattern
1137 */
1138static char * mireDup(rpmTagVal tag, rpmMireMode *modep,
1139 const char * pattern)
1140{
1141 const char * s;
1142 char * pat;
1143 char * t;
1144 int brackets;
1145 size_t nb;
1146 int c;
1147
1148 switch (*modep) {
1149 default:
1150 case RPMMIRE_DEFAULT:
1151 if (tag == RPMTAG_DIRNAMES || tag == RPMTAG_BASENAMES) {
1152 *modep = RPMMIRE_GLOB;
1153 pat = xstrdup(pattern)rstrdup((pattern));
1154 break;
1155 }
1156
1157 nb = strlen(pattern) + sizeof("^$");
1158
1159 /* Find no. of bytes needed for pattern. */
1160 /* periods and plusses are escaped, splats become '.*' */
1161 c = '\0';
1162 brackets = 0;
1163 for (s = pattern; *s != '\0'; s++) {
1164 switch (*s) {
1165 case '.':
1166 case '+':
1167 case '*':
1168 if (!brackets) nb++;
1169 break;
1170 case '\\':
1171 s++;
1172 break;
1173 case '[':
1174 brackets = 1;
1175 break;
1176 case ']':
1177 if (c != '[') brackets = 0;
1178 break;
1179 }
1180 c = *s;
1181 }
1182
1183 pat = t = xmalloc(nb)rmalloc((nb));
1184
1185 if (pattern[0] != '^') *t++ = '^';
1186
1187 /* Copy pattern, escaping periods, prefixing splats with period. */
1188 c = '\0';
1189 brackets = 0;
1190 for (s = pattern; *s != '\0'; s++, t++) {
1191 switch (*s) {
1192 case '.':
1193 case '+':
1194 if (!brackets) *t++ = '\\';
1195 break;
1196 case '*':
1197 if (!brackets) *t++ = '.';
1198 break;
1199 case '\\':
1200 *t++ = *s++;
1201 break;
1202 case '[':
1203 brackets = 1;
1204 break;
1205 case ']':
1206 if (c != '[') brackets = 0;
1207 break;
1208 }
1209 c = *t = *s;
1210 }
1211
1212 if (s > pattern && s[-1] != '$') *t++ = '$';
1213 *t = '\0';
1214 *modep = RPMMIRE_REGEX;
1215 break;
1216 case RPMMIRE_STRCMP:
1217 case RPMMIRE_REGEX:
1218 case RPMMIRE_GLOB:
1219 pat = xstrdup(pattern)rstrdup((pattern));
1220 break;
1221 }
1222
1223 return pat;
1224}
1225
1226int rpmdbSetIteratorRE(rpmdbMatchIterator mi, rpmTagVal tag,
1227 rpmMireMode mode, const char * pattern)
1228{
1229 static rpmMireMode defmode = (rpmMireMode)-1;
1230 miRE mire = NULL((void*)0);
1231 char * allpat = NULL((void*)0);
1232 int notmatch = 0;
1233 regex_t * preg = NULL((void*)0);
1234 int cflags = 0;
1235 int eflags = 0;
1236 int fnflags = 0;
1237 int rc = 0;
1238
1239 if (defmode == (rpmMireMode)-1) {
1240 char *t = rpmExpand("%{?_query_selector_match}", NULL((void*)0));
1241
1242 if (*t == '\0' || rstreq(t, "default"))
1243 defmode = RPMMIRE_DEFAULT;
1244 else if (rstreq(t, "strcmp"))
1245 defmode = RPMMIRE_STRCMP;
1246 else if (rstreq(t, "regex"))
1247 defmode = RPMMIRE_REGEX;
1248 else if (rstreq(t, "glob"))
1249 defmode = RPMMIRE_GLOB;
1250 else
1251 defmode = RPMMIRE_DEFAULT;
1252 free(t);
1253 }
1254
1255 if (mi == NULL((void*)0) || pattern == NULL((void*)0))
1256 return rc;
1257
1258 /* Leading '!' inverts pattern match sense, like "grep -v". */
1259 if (*pattern == '!') {
1260 notmatch = 1;
1261 pattern++;
1262 }
1263
1264 allpat = mireDup(tag, &mode, pattern);
1265
1266 if (mode == RPMMIRE_DEFAULT)
1267 mode = defmode;
1268
1269 switch (mode) {
1270 case RPMMIRE_DEFAULT:
1271 case RPMMIRE_STRCMP:
1272 break;
1273 case RPMMIRE_REGEX:
1274 preg = xcalloc(1, sizeof(*preg))rcalloc((1), (sizeof(*preg)));
1275 cflags = (REG_EXTENDED1 | REG_NOSUB(((1 << 1) << 1) << 1));
1276 rc = regcomp(preg, allpat, cflags);
1277 if (rc) {
1278 char msg[256];
1279 (void) regerror(rc, preg, msg, sizeof(msg)-1);
1280 msg[sizeof(msg)-1] = '\0';
1281 rpmlog(RPMLOG_ERR, _("%s: regcomp failed: %s\n")dcgettext ("rpm", "%s: regcomp failed: %s\n", 5), allpat, msg);
1282 }
1283 break;
1284 case RPMMIRE_GLOB:
1285 fnflags = FNM_PATHNAME(1 << 0) | FNM_PERIOD(1 << 2);
1286 break;
1287 default:
1288 rc = -1;
1289 break;
1290 }
1291
1292 if (rc) {
1293 /* FIX: mire has kept values */
1294 allpat = _free(allpat)rfree((allpat));
Value stored to 'allpat' is never read
1295 if (preg) {
1296 regfree(preg);
1297 preg = _free(preg)rfree((preg));
1298 }
1299 return rc;
1300 }
1301
1302 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)))
;
1303 mire = mi->mi_re + mi->mi_nre;
1304 mi->mi_nre++;
1305
1306 mire->tag = tag;
1307 mire->mode = mode;
1308 mire->pattern = allpat;
1309 mire->notmatch = notmatch;
1310 mire->preg = preg;
1311 mire->cflags = cflags;
1312 mire->eflags = eflags;
1313 mire->fnflags = fnflags;
1314
1315 if (mi->mi_nre > 1)
1316 qsort(mi->mi_re, mi->mi_nre, sizeof(*mi->mi_re), mireCmp);
1317
1318 return rc;
1319}
1320
1321/**
1322 * Return iterator selector match.
1323 * @param mi rpm database iterator
1324 * @return 1 if header should be skipped
1325 */
1326static int mireSkip (const rpmdbMatchIterator mi)
1327{
1328 miRE mire;
1329 uint32_t zero = 0;
1330 int ntags = 0;
1331 int nmatches = 0;
1332 int rc;
1333
1334 if (mi->mi_h == NULL((void*)0)) /* XXX can't happen */
1335 return 0;
1336
1337 /*
1338 * Apply tag tests, implicitly "||" for multiple patterns/values of a
1339 * single tag, implicitly "&&" between multiple tag patterns.
1340 */
1341 if ((mire = mi->mi_re) != NULL((void*)0))
1342 for (int i = 0; i < mi->mi_nre; i++, mire++) {
1343 int anymatch;
1344 struct rpmtd_s td;
1345
1346 if (!headerGet(mi->mi_h, mire->tag, &td, HEADERGET_MINMEM)) {
1347 if (mire->tag != RPMTAG_EPOCH) {
1348 ntags++;
1349 continue;
1350 }
1351 /* "is package already installed" checks rely on this behavior */
1352 td.count = 1;
1353 td.type = RPM_INT32_TYPE;
1354 td.data = &zero;
1355 }
1356
1357 anymatch = 0; /* no matches yet */
1358 while (1) {
1359 rpmtdInit(&td);
1360 while (rpmtdNext(&td) >= 0) {
1361 char *str = rpmtdFormat(&td, RPMTD_FORMAT_STRING, NULL((void*)0));
1362 if (str) {
1363 rc = miregexec(mire, str);
1364 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
1365 anymatch++;
1366 free(str);
1367 }
1368 }
1369 if ((i+1) < mi->mi_nre && mire[0].tag == mire[1].tag) {
1370 i++;
1371 mire++;
1372 continue;
1373 }
1374 break;
1375 }
1376 rpmtdFreeData(&td);
1377
1378 ntags++;
1379 if (anymatch)
1380 nmatches++;
1381 }
1382
1383 return (ntags == nmatches ? 0 : 1);
1384}
1385
1386int rpmdbSetIteratorRewrite(rpmdbMatchIterator mi, int rewrite)
1387{
1388 int rc;
1389 if (mi == NULL((void*)0))
1390 return 0;
1391 rc = (mi->mi_cflags & DBC_WRITE) ? 1 : 0;
1392 if (rewrite)
1393 mi->mi_cflags |= DBC_WRITE;
1394 else
1395 mi->mi_cflags &= ~DBC_WRITE;
1396 return rc;
1397}
1398
1399int rpmdbSetIteratorModified(rpmdbMatchIterator mi, int modified)
1400{
1401 int rc;
1402 if (mi == NULL((void*)0))
1403 return 0;
1404 rc = mi->mi_modified;
1405 mi->mi_modified = modified;
1406 return rc;
1407}
1408
1409int rpmdbSetHdrChk(rpmdbMatchIterator mi, rpmts ts,
1410 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg))
1411{
1412 int rc = 0;
1413 if (mi == NULL((void*)0))
1414 return 0;
1415 mi->mi_ts = rpmtsLink(ts);
1416 mi->mi_hdrchk = hdrchk;
1417 return rc;
1418}
1419
1420static rpmRC miVerifyHeader(rpmdbMatchIterator mi, const void *uh, size_t uhlen)
1421{
1422 rpmRC rpmrc = RPMRC_NOTFOUND;
1423
1424 if (!(mi->mi_hdrchk && mi->mi_ts))
1425 return rpmrc;
1426
1427 /* Don't bother re-checking a previously read header. */
1428 if (mi->mi_db->db_checked) {
1429 rpmRC *res;
1430 if (dbChkGetEntry(mi->mi_db->db_checked, mi->mi_offset,
1431 &res, NULL((void*)0), NULL((void*)0))) {
1432 rpmrc = res[0];
1433 }
1434 }
1435
1436 /* If blob is unchecked, check blob import consistency now. */
1437 if (rpmrc != RPMRC_OK) {
1438 char * msg = NULL((void*)0);
1439 int lvl;
1440
1441 rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, uh, uhlen, &msg);
1442 lvl = (rpmrc == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG);
1443 rpmlog(lvl, "%s h#%8u %s\n",
1444 (rpmrc == RPMRC_FAIL ? _("rpmdbNextIterator: skipping")dcgettext ("rpm", "rpmdbNextIterator: skipping", 5) : " read"),
1445 mi->mi_offset, (msg ? msg : ""));
1446 msg = _free(msg)rfree((msg));
1447
1448 /* Mark header checked. */
1449 if (mi->mi_db && mi->mi_db->db_checked) {
1450 dbChkAddEntry(mi->mi_db->db_checked, mi->mi_offset, rpmrc);
1451 }
1452 }
1453 return rpmrc;
1454}
1455
1456/* FIX: mi->mi_key.data may be NULL */
1457Header rpmdbNextIterator(rpmdbMatchIterator mi)
1458{
1459 dbiIndex dbi = NULL((void*)0);
1460 unsigned char * uh;
1461 unsigned int uhlen;
1462 int rc;
1463 headerImportFlags importFlags = HEADERIMPORT_FAST;
1464
1465 if (mi == NULL((void*)0))
1466 return NULL((void*)0);
1467
1468 if (pkgdbOpen(mi->mi_db, 0, &dbi))
1469 return NULL((void*)0);
1470
1471#if defined(_USE_COPY_LOAD)
1472 importFlags |= HEADERIMPORT_COPY;
1473#endif
1474 /*
1475 * Cursors are per-iterator, not per-dbi, so get a cursor for the
1476 * iterator on 1st call. If the iteration is to rewrite headers,
1477 * then the cursor needs to marked with DBC_WRITE as well.
1478 */
1479 if (mi->mi_dbc == NULL((void*)0))
1480 mi->mi_dbc = dbiCursorInit(dbi, mi->mi_cflags);
1481
1482top:
1483 uh = NULL((void*)0);
1484 uhlen = 0;
1485
1486 do {
1487 if (mi->mi_set) {
1488 if (!(mi->mi_setx < mi->mi_set->count))
1489 return NULL((void*)0);
1490 mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx);
1491 mi->mi_filenum = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx);
1492 } else {
1493 rc = pkgdbGet(dbi, mi->mi_dbc, 0, &uh, &uhlen);
1494 if (rc == 0)
1495 mi->mi_offset = pkgdbKey(dbi, mi->mi_dbc);
1496
1497 /* Terminate on error or end of keys */
1498 if (rc || (mi->mi_setx && mi->mi_offset == 0))
1499 return NULL((void*)0);
1500 }
1501 mi->mi_setx++;
1502 } while (mi->mi_offset == 0);
1503
1504 /* If next header is identical, return it now. */
1505 if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset)
1506 return mi->mi_h;
1507
1508 /* Retrieve next header blob for index iterator. */
1509 if (uh == NULL((void*)0)) {
1510 rc = pkgdbGet(dbi, mi->mi_dbc, mi->mi_offset, &uh, &uhlen);
1511 if (rc)
1512 return NULL((void*)0);
1513 }
1514
1515 /* Rewrite current header (if necessary) and unlink. */
1516 miFreeHeader(mi, dbi);
1517
1518 /* Is this the end of the iteration? */
1519 if (uh == NULL((void*)0))
1520 return NULL((void*)0);
1521
1522 /* Verify header if enabled, skip damaged and inconsistent headers */
1523 if (miVerifyHeader(mi, uh, uhlen) == RPMRC_FAIL) {
1524 goto top;
1525 }
1526
1527 /* Did the header blob load correctly? */
1528 mi->mi_h = headerImport(uh, uhlen, importFlags);
1529 if (mi->mi_h == NULL((void*)0) || !headerIsEntry(mi->mi_h, RPMTAG_NAME)) {
1530 rpmlog(RPMLOG_ERR,
1531 _("rpmdb: damaged header #%u retrieved -- skipping.\n")dcgettext ("rpm", "rpmdb: damaged header #%u retrieved -- skipping.\n"
, 5)
,
1532 mi->mi_offset);
1533 goto top;
1534 }
1535
1536 /*
1537 * Skip this header if iterator selector (if any) doesn't match.
1538 */
1539 if (mireSkip(mi)) {
1540 goto top;
1541 }
1542 headerSetInstance(mi->mi_h, mi->mi_offset);
1543
1544 mi->mi_prevoffset = mi->mi_offset;
1545 mi->mi_modified = 0;
1546
1547 return mi->mi_h;
1548}
1549
1550/** \ingroup rpmdb
1551 * sort the iterator by (recnum, filenum)
1552 * Return database iterator.
1553 * @param mi rpm database iterator
1554 */
1555void rpmdbSortIterator(rpmdbMatchIterator mi)
1556{
1557 if (mi && mi->mi_set) {
1558 dbiIndexSetSort(mi->mi_set);
1559 mi->mi_sorted = 1;
1560 }
1561}
1562
1563void rpmdbUniqIterator(rpmdbMatchIterator mi)
1564{
1565 if (mi && mi->mi_set) {
1566 dbiIndexSetUniq(mi->mi_set, mi->mi_sorted);
1567 }
1568}
1569
1570int rpmdbExtendIterator(rpmdbMatchIterator mi,
1571 const void * keyp, size_t keylen)
1572{
1573 dbiIndex dbi = NULL((void*)0);
1574 dbiIndexSet set = NULL((void*)0);
1575 int rc = 1; /* assume failure */
1576
1577 if (mi == NULL((void*)0) || keyp == NULL((void*)0))
1578 return rc;
1579
1580 rc = indexOpen(mi->mi_db, mi->mi_rpmtag, 0, &dbi);
1581
1582 if (rc == 0 && indexGet(dbi, keyp, keylen, &set) == RPMRC_OK) {
1583 if (mi->mi_set == NULL((void*)0)) {
1584 mi->mi_set = set;
1585 } else {
1586 dbiIndexSetAppendSet(mi->mi_set, set, 0);
1587 dbiIndexSetFree(set);
1588 }
1589 rc = 0;
1590 }
1591
1592 return rc;
1593}
1594
1595int rpmdbFilterIterator(rpmdbMatchIterator mi, packageHash hdrNums, int neg)
1596{
1597 if (mi == NULL((void*)0) || hdrNums == NULL((void*)0))
1598 return 1;
1599
1600 if (!mi->mi_set)
1601 return 0;
1602
1603 if (packageHashNumKeys(hdrNums) == 0) {
1604 if (!neg)
1605 mi->mi_set->count = 0;
1606 return 0;
1607 }
1608
1609 unsigned int from;
1610 unsigned int to = 0;
1611 unsigned int num = mi->mi_set->count;
1612 int cond;
1613
1614 assert(mi->mi_set->count > 0)((void) sizeof ((mi->mi_set->count > 0) == 0), __extension__
({ if (mi->mi_set->count > 0) ; else __assert_fail (
"mi->mi_set->count > 0", "rpmdb.c", 1614, __extension__
__PRETTY_FUNCTION__); }))
;
1615
1616 for (from = 0; from < num; from++) {
1617 cond = !packageHashHasEntry(hdrNums, mi->mi_set->recs[from].hdrNum);
1618 cond = neg ? !cond : cond;
1619 if (cond) {
1620 mi->mi_set->count--;
1621 continue;
1622 }
1623 if (from != to)
1624 mi->mi_set->recs[to] = mi->mi_set->recs[from]; /* structure assignment */
1625 to++;
1626 }
1627 return 0;
1628}
1629
1630int rpmdbPruneIterator(rpmdbMatchIterator mi, packageHash hdrNums)
1631{
1632 if (packageHashNumKeys(hdrNums) <= 0)
1633 return 1;
1634
1635 return rpmdbFilterIterator(mi, hdrNums, 1);
1636}
1637
1638
1639int rpmdbAppendIterator(rpmdbMatchIterator mi,
1640 const unsigned int * hdrNums, unsigned int nHdrNums)
1641{
1642 if (mi == NULL((void*)0) || hdrNums == NULL((void*)0) || nHdrNums == 0)
1643 return 1;
1644
1645 if (mi->mi_set == NULL((void*)0))
1646 mi->mi_set = dbiIndexSetNew(nHdrNums);
1647
1648 for (unsigned int i = 0; i < nHdrNums; i++)
1649 dbiIndexSetAppendOne(mi->mi_set, hdrNums[i], 0, 0);
1650 return 0;
1651}
1652
1653rpmdbMatchIterator rpmdbNewIterator(rpmdb db, rpmDbiTagVal dbitag)
1654{
1655 rpmdbMatchIterator mi = NULL((void*)0);
1656
1657 if (dbitag == RPMDBI_PACKAGES) {
1658 if (pkgdbOpen(db, 0, NULL((void*)0)))
1659 return NULL((void*)0);
1660 } else {
1661 if (indexOpen(db, dbitag, 0, NULL((void*)0)))
1662 return NULL((void*)0);
1663 }
1664
1665 mi = xcalloc(1, sizeof(*mi))rcalloc((1), (sizeof(*mi)));
1666 mi->mi_set = NULL((void*)0);
1667 mi->mi_db = rpmdbLink(db);
1668 mi->mi_rpmtag = dbitag;
1669
1670 mi->mi_dbc = NULL((void*)0);
1671 mi->mi_setx = 0;
1672 mi->mi_h = NULL((void*)0);
1673 mi->mi_sorted = 0;
1674 mi->mi_cflags = 0;
1675 mi->mi_modified = 0;
1676 mi->mi_prevoffset = 0;
1677 mi->mi_offset = 0;
1678 mi->mi_filenum = 0;
1679 mi->mi_nre = 0;
1680 mi->mi_re = NULL((void*)0);
1681
1682 mi->mi_ts = NULL((void*)0);
1683 mi->mi_hdrchk = NULL((void*)0);
1684
1685 /* Chain cursors for teardown on abnormal exit. */
1686 mi->mi_next = rpmmiRock;
1687 rpmmiRock = mi;
1688
1689 return mi;
1690};
1691
1692static rpmdbMatchIterator pkgdbIterInit(rpmdb db,
1693 const unsigned int * keyp, size_t keylen)
1694{
1695 rpmdbMatchIterator mi = NULL((void*)0);
1696 rpmDbiTagVal dbtag = RPMDBI_PACKAGES;
1697 dbiIndex pkgs = NULL((void*)0);
1698
1699 /* Require a sane keylen if one is specified */
1700 if (keyp && keylen != sizeof(*keyp))
1701 return NULL((void*)0);
1702
1703 if (pkgdbOpen(db, 0, &pkgs) == 0) {
1704 mi = rpmdbNewIterator(db, dbtag);
1705 if (keyp)
1706 rpmdbAppendIterator(mi, keyp, 1);
1707 }
1708 return mi;
1709}
1710
1711static rpmdbMatchIterator indexIterInit(rpmdb db, rpmDbiTagVal rpmtag,
1712 const void * keyp, size_t keylen)
1713{
1714 rpmdbMatchIterator mi = NULL((void*)0);
1715 rpmDbiTagVal dbtag = rpmtag;
1716 dbiIndex dbi = NULL((void*)0);
1717 dbiIndexSet set = NULL((void*)0);
1718
1719 /* Fixup the physical index for our pseudo indexes */
1720 if (rpmtag == RPMDBI_LABEL) {
1721 dbtag = RPMDBI_NAME;
1722 } else if (rpmtag == RPMDBI_INSTFILENAMES) {
1723 dbtag = RPMDBI_BASENAMES;
1724 }
1725
1726 if (indexOpen(db, dbtag, 0, &dbi) == 0) {
1727 int rc = 0;
1728
1729 if (keyp) {
1730 if (rpmtag == RPMDBI_LABEL) {
1731 rc = dbiFindByLabel(db, dbi, keyp, &set);
1732 } else if (rpmtag == RPMDBI_BASENAMES) {
1733 rc = rpmdbFindByFile(db, dbi, keyp, 0, &set);
1734 } else if (rpmtag == RPMDBI_INSTFILENAMES) {
1735 rc = rpmdbFindByFile(db, dbi, keyp, 1, &set);
1736 } else {
1737 rc = indexGet(dbi, keyp, keylen, &set);
1738 }
1739 } else {
1740 /* get all entries from index */
1741 rc = indexGet(dbi, NULL((void*)0), 0, &set);
1742 }
1743
1744 if (rc) { /* error/not found */
1745 set = dbiIndexSetFree(set);
1746 } else {
1747 mi = rpmdbNewIterator(db, dbtag);
1748 mi->mi_set = set;
1749
1750 if (keyp) {
1751 rpmdbSortIterator(mi);
1752 }
1753 }
1754 }
1755
1756 return mi;
1757}
1758
1759rpmdbMatchIterator rpmdbInitIterator(rpmdb db, rpmDbiTagVal rpmtag,
1760 const void * keyp, size_t keylen)
1761{
1762 rpmdbMatchIterator mi = NULL((void*)0);
1763
1764 if (db != NULL((void*)0)) {
1765 (void) rpmsqPoll();
1766
1767 if (rpmtag == RPMDBI_PACKAGES)
1768 mi = pkgdbIterInit(db, keyp, keylen);
1769 else
1770 mi = indexIterInit(db, rpmtag, keyp, keylen);
1771 }
1772
1773 return mi;
1774}
1775
1776rpmdbMatchIterator rpmdbInitPrefixIterator(rpmdb db, rpmDbiTagVal rpmtag,
1777 const void * pfx, size_t plen)
1778{
1779 rpmdbMatchIterator mi = NULL((void*)0);
1780 dbiIndexSet set = NULL((void*)0);
1781 dbiIndex dbi = NULL((void*)0);
1782 rpmDbiTagVal dbtag = rpmtag;
1783
1784 if (!pfx)
1785 return NULL((void*)0);
1786
1787 if (db != NULL((void*)0) && rpmtag != RPMDBI_PACKAGES) {
1788 (void) rpmsqPoll();
1789
1790
1791 if (indexOpen(db, dbtag, 0, &dbi) == 0) {
1792 int rc = 0;
1793
1794 rc = indexPrefixGet(dbi, pfx, plen, &set);
1795
1796 if (rc) {
1797 set = dbiIndexSetFree(set);
1798 } else {
1799 mi = rpmdbNewIterator(db, dbtag);
1800 mi->mi_set = set;
1801 rpmdbSortIterator(mi);
1802 }
1803 }
1804
1805 }
1806
1807 return mi;
1808}
1809
1810/*
1811 * Convert current tag data to db key
1812 * @param tagdata Tag data container
1813 * @retval keylen Length of key
1814 * @return Pointer to key value or NULL to signal skip
1815 */
1816static const void * td2key(rpmtd tagdata, unsigned int *keylen)
1817{
1818 const void * data = NULL((void*)0);
1819 unsigned int size = 0;
1820 const char *str = NULL((void*)0);
1821
1822 switch (rpmtdType(tagdata)) {
1823 case RPM_CHAR_TYPE:
1824 case RPM_INT8_TYPE:
1825 size = sizeof(uint8_t);
1826 data = rpmtdGetChar(tagdata);
1827 break;
1828 case RPM_INT16_TYPE:
1829 size = sizeof(uint16_t);
1830 data = rpmtdGetUint16(tagdata);
1831 break;
1832 case RPM_INT32_TYPE:
1833 size = sizeof(uint32_t);
1834 data = rpmtdGetUint32(tagdata);
1835 break;
1836 case RPM_INT64_TYPE:
1837 size = sizeof(uint64_t);
1838 data = rpmtdGetUint64(tagdata);
1839 break;
1840 case RPM_BIN_TYPE:
1841 size = tagdata->count;
1842 data = tagdata->data;
1843 break;
1844 case RPM_STRING_TYPE:
1845 case RPM_I18NSTRING_TYPE:
1846 case RPM_STRING_ARRAY_TYPE:
1847 str = rpmtdGetString(tagdata);
1848 if (str) {
1849 size = strlen(str);
1850 data = str;
1851 }
1852 break;
1853 default:
1854 break;
1855 }
1856
1857 if (data && keylen)
1858 *keylen = size;
1859
1860 return data;
1861}
1862/*
1863 * rpmdbIndexIterator
1864 */
1865
1866rpmdbIndexIterator rpmdbIndexIteratorInit(rpmdb db, rpmDbiTag rpmtag)
1867{
1868 rpmdbIndexIterator ii;
1869 dbiIndex dbi = NULL((void*)0);
1870
1871 if (db == NULL((void*)0))
1872 return NULL((void*)0);
1873
1874 (void) rpmsqPoll();
1875
1876 if (indexOpen(db, rpmtag, 0, &dbi))
1877 return NULL((void*)0);
1878
1879 /* Chain cursors for teardown on abnormal exit. */
1880 ii = xcalloc(1, sizeof(*ii))rcalloc((1), (sizeof(*ii)));
1881 ii->ii_next = rpmiiRock;
1882 rpmiiRock = ii;
1883
1884 ii->ii_db = rpmdbLink(db);
1885 ii->ii_rpmtag = rpmtag;
1886 ii->ii_dbi = dbi;
1887 ii->ii_set = NULL((void*)0);
1888
1889 return ii;
1890}
1891
1892int rpmdbIndexIteratorNext(rpmdbIndexIterator ii, const void ** key, size_t * keylen)
1893{
1894 int rc;
1895 unsigned int iikeylen = 0; /* argh, size_t vs uint pointer... */
1896
1897 if (ii == NULL((void*)0))
1898 return -1;
1899
1900 if (ii->ii_dbc == NULL((void*)0))
1901 ii->ii_dbc = dbiCursorInit(ii->ii_dbi, DBC_READ);
1902
1903 /* free old data */
1904 ii->ii_set = dbiIndexSetFree(ii->ii_set);
1905
1906 rc = idxdbGet(ii->ii_dbi, ii->ii_dbc, NULL((void*)0), 0, &ii->ii_set, DBC_NORMAL_SEARCH);
1907
1908 *key = idxdbKey(ii->ii_dbi, ii->ii_dbc, &iikeylen);
1909 *keylen = iikeylen;
1910
1911 return (rc == RPMRC_OK) ? 0 : -1;
1912}
1913
1914int rpmdbIndexIteratorNextTd(rpmdbIndexIterator ii, rpmtd keytd)
1915{
1916 size_t keylen = 0;
1917 const void * keyp = NULL((void*)0);
1918
1919 int rc = rpmdbIndexIteratorNext(ii, &keyp, &keylen);
1920
1921 if (rc == 0) {
1922 rpmTagVal tag = ii->ii_rpmtag;
1923 rpmTagClass tagclass = rpmTagGetClass(tag);
1924
1925 /* Set the common values, overridden below as necessary */
1926 keytd->type = rpmTagGetTagType(tag);
1927 keytd->tag = tag;
1928 keytd->flags = RPMTD_ALLOCED;
1929 keytd->count = 1;
1930
1931 switch (tagclass) {
1932 case RPM_STRING_CLASS: {
1933 /*
1934 * XXX: We never return arrays here, so everything is a
1935 * "simple" string. However this can disagree with the
1936 * type of the index tag, eg requires are string arrays.
1937 */
1938 char *key = memcpy(xmalloc(keylen + 1)rmalloc((keylen + 1)), keyp, keylen);
1939 key[keylen] = '\0';
1940 keytd->data = key;
1941 keytd->type = RPM_STRING_TYPE;
1942 } break;
1943 case RPM_BINARY_CLASS:
1944 /* Binary types abuse count for data length */
1945 keytd->count = keylen;
1946 /* fallthrough */
1947 case RPM_NUMERIC_CLASS:
1948 keytd->data = memcpy(xmalloc(keylen)rmalloc((keylen)), keyp, keylen);
1949 break;
1950 default:
1951 rpmtdReset(keytd);
1952 rc = -1;
1953 break;
1954 }
1955 }
1956
1957 return rc;
1958}
1959
1960unsigned int rpmdbIndexIteratorNumPkgs(rpmdbIndexIterator ii)
1961{
1962 return (ii && ii->ii_set) ? dbiIndexSetCount(ii->ii_set) : 0;
1963}
1964
1965unsigned int rpmdbIndexIteratorPkgOffset(rpmdbIndexIterator ii, unsigned int nr)
1966{
1967 if (!ii || !ii->ii_set)
1968 return 0;
1969 if (dbiIndexSetCount(ii->ii_set) <= nr)
1970 return 0;
1971 return dbiIndexRecordOffset(ii->ii_set, nr);
1972}
1973
1974unsigned int *rpmdbIndexIteratorPkgOffsets(rpmdbIndexIterator ii)
1975{
1976 int i;
1977
1978 if (!ii || !ii->ii_set)
1979 return NULL((void*)0);
1980
1981 if (ii->ii_hdrNums)
1982 ii->ii_hdrNums = _free(ii->ii_hdrNums)rfree((ii->ii_hdrNums));
1983
1984 ii->ii_hdrNums = xmalloc(sizeof(*ii->ii_hdrNums) * ii->ii_set->count)rmalloc((sizeof(*ii->ii_hdrNums) * ii->ii_set->count
))
;
1985 for (i = 0; i < ii->ii_set->count; i++) {
1986 ii->ii_hdrNums[i] = ii->ii_set->recs[i].hdrNum;
1987 }
1988
1989 return ii->ii_hdrNums;
1990}
1991
1992unsigned int rpmdbIndexIteratorTagNum(rpmdbIndexIterator ii, unsigned int nr)
1993{
1994 if (!ii || !ii->ii_set)
1995 return 0;
1996 if (dbiIndexSetCount(ii->ii_set) <= nr)
1997 return 0;
1998 return dbiIndexRecordFileNumber(ii->ii_set, nr);
1999}
2000
2001rpmdbIndexIterator rpmdbIndexIteratorFree(rpmdbIndexIterator ii)
2002{
2003 rpmdbIndexIterator * prev, next;
2004
2005 if (ii == NULL((void*)0))
2006 return NULL((void*)0);
2007
2008 prev = &rpmiiRock;
2009 while ((next = *prev) != NULL((void*)0) && next != ii)
2010 prev = &next->ii_next;
2011 if (next) {
2012 *prev = next->ii_next;
2013 next->ii_next = NULL((void*)0);
2014 } else
2015 return NULL((void*)0);
2016
2017 ii->ii_dbc = dbiCursorFree(ii->ii_dbi, ii->ii_dbc);
2018 ii->ii_dbi = NULL((void*)0);
2019 rpmdbClose(ii->ii_db);
2020 ii->ii_set = dbiIndexSetFree(ii->ii_set);
2021
2022 if (ii->ii_hdrNums)
2023 ii->ii_hdrNums = _free(ii->ii_hdrNums)rfree((ii->ii_hdrNums));
2024
2025 ii = _free(ii)rfree((ii));
2026 return NULL((void*)0);
2027}
2028
2029static void logAddRemove(const char *dbiname, int removing, rpmtd tagdata)
2030{
2031 rpm_count_t c = rpmtdCount(tagdata);
2032 if (c == 1 && rpmtdType(tagdata) == RPM_STRING_TYPE) {
2033 rpmlog(RPMLOG_DEBUG, "%s \"%s\" %s %s index.\n",
2034 removing ? "removing" : "adding", rpmtdGetString(tagdata),
2035 removing ? "from" : "to", dbiname);
2036 } else if (c > 0) {
2037 rpmlog(RPMLOG_DEBUG, "%s %d entries %s %s index.\n",
2038 removing ? "removing" : "adding", c,
2039 removing ? "from" : "to", dbiname);
2040 }
2041}
2042
2043static rpmRC indexDel(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h)
2044{
2045 return tag2index(dbi, rpmtag, hdrNum, h, idxdbDel);
2046}
2047
2048int rpmdbRemove(rpmdb db, unsigned int hdrNum)
2049{
2050 dbiIndex dbi = NULL((void*)0);
2051 dbiCursor dbc = NULL((void*)0);
2052 Header h;
2053 int ret = 0;
2054
2055 if (db == NULL((void*)0))
2056 return 0;
2057
2058 h = rpmdbGetHeaderAt(db, hdrNum);
2059
2060 if (h == NULL((void*)0)) {
2061 rpmlog(RPMLOG_ERR, _("%s: cannot read header at 0x%x\n")dcgettext ("rpm", "%s: cannot read header at 0x%x\n", 5),
2062 "rpmdbRemove", hdrNum);
2063 return 1;
2064 } else {
2065 char *nevra = headerGetAsString(h, RPMTAG_NEVRA);
2066 rpmlog(RPMLOG_DEBUG, " --- h#%8u %s\n", hdrNum, nevra);
2067 free(nevra);
2068 }
2069
2070 if (pkgdbOpen(db, 0, &dbi))
2071 return 1;
2072
2073 rpmsqBlock(SIG_BLOCK0);
2074 dbCtrl(db, DB_CTRL_LOCK_RW);
2075
2076 /* Remove header from primary index */
2077 dbc = dbiCursorInit(dbi, DBC_WRITE);
2078 ret = pkgdbDel(dbi, dbc, hdrNum);
2079 dbiCursorFree(dbi, dbc);
2080
2081 /* Remove associated data from secondary indexes */
2082 if (ret == 0) {
2083 for (int dbix = 0; dbix < db->db_ndbi; dbix++) {
2084 rpmDbiTag rpmtag = db->db_tags[dbix];
2085
2086 if (indexOpen(db, rpmtag, 0, &dbi))
2087 continue;
2088
2089 ret += indexDel(dbi, rpmtag, hdrNum, h);
2090 }
2091 }
2092
2093 dbCtrl(db, DB_CTRL_INDEXSYNC);
2094 dbCtrl(db, DB_CTRL_UNLOCK_RW);
2095 rpmsqBlock(SIG_UNBLOCK1);
2096
2097 headerFree(h);
2098
2099 /* XXX return ret; */
2100 return 0;
2101}
2102
2103struct updateRichDepData {
2104 ARGV_t argv;
2105 int nargv;
2106 int neg;
2107 int level;
2108 int *nargv_level;
2109};
2110
2111static rpmRC updateRichDepCB(void *cbdata, rpmrichParseType type,
2112 const char *n, int nl, const char *e, int el, rpmsenseFlags sense,
2113 rpmrichOp op, char **emsg) {
2114 struct updateRichDepData *data = cbdata;
2115 if (type == RPMRICH_PARSE_ENTER) {
2116 data->level++;
2117 data->nargv_level = xrealloc(data->nargv_level, data->level * (sizeof(int)))rrealloc((data->nargv_level), (data->level * (sizeof(int
))))
;
2118 data->nargv_level[data->level - 1] = data->nargv;
2119 }
2120 if (type == RPMRICH_PARSE_LEAVE) {
2121 data->level--;
2122 }
2123 if (type == RPMRICH_PARSE_SIMPLE && nl && !(nl > 7 && !strncmp(n, "rpmlib(", 7))) {
2124 char *name = xmalloc(nl + 2)rmalloc((nl + 2));
2125 *name = data->neg ? '!' : ' ';
2126 strncpy(name + 1, n, nl);
2127 name[1 + nl] = 0;
2128 argvAdd(&data->argv, name);
2129 data->nargv++;
2130 _free(name)rfree((name));
2131 }
2132 if (type == RPMRICH_PARSE_OP && op == RPMRICHOP_IF) {
2133 /* save nargv in case of ELSE */
2134 data->nargv_level[data->level - 1] = data->nargv;
2135 data->neg ^= 1;
2136 }
2137 if (type == RPMRICH_PARSE_OP && op == RPMRICHOP_ELSE) {
2138 int i, nargv = data->nargv;
2139 /* copy and invert condition block */
2140 for (i = data->nargv_level[data->level - 1]; i < nargv; i++) {
2141 char *name = data->argv[i];
2142 *name ^= ' ' ^ '!';
2143 argvAdd(&data->argv, name);
2144 *name ^= ' ' ^ '!';
2145 data->nargv++;
2146 }
2147 data->neg ^= 1;
2148 }
2149 if (type == RPMRICH_PARSE_LEAVE && op == RPMRICHOP_IF) {
2150 data->neg ^= 1;
2151 }
2152 return RPMRC_OK;
2153}
2154
2155static rpmRC updateRichDep(dbiIndex dbi, dbiCursor dbc, const char *str,
2156 struct dbiIndexItem_s *rec,
2157 idxfunc idxupdate)
2158{
2159 int n, i, rc = 0;
2160 struct updateRichDepData data;
2161
2162 data.argv = argvNew();
2163 data.neg = 0;
2164 data.nargv = 0;
2165 data.level = 0;
2166 data.nargv_level = xcalloc(1, sizeof(int))rcalloc((1), (sizeof(int)));
2167 if (rpmrichParse(&str, NULL((void*)0), updateRichDepCB, &data) == RPMRC_OK) {
2168 n = argvCount(data.argv);
2169 if (n) {
2170 argvSort(data.argv, NULL((void*)0));
2171 for (i = 0; i < n; i++) {
2172 char *name = data.argv[i];
2173 if (i && !strcmp(data.argv[i - 1], name))
2174 continue; /* ignore dups */
2175 if (*name == ' ')
2176 name++;
2177 rc += idxupdate(dbi, dbc, name, strlen(name), rec);
2178 }
2179 }
2180 }
2181 _free(data.nargv_level)rfree((data.nargv_level));
2182 argvFree(data.argv);
2183 return rc;
2184}
2185
2186static rpmRC tag2index(dbiIndex dbi, rpmTagVal rpmtag,
2187 unsigned int hdrNum, Header h,
2188 idxfunc idxupdate)
2189{
2190 int i, rc = 0;
2191 struct rpmtd_s tagdata, reqflags, trig_index;
2192 dbiCursor dbc = NULL((void*)0);
2193
2194 switch (rpmtag) {
2195 case RPMTAG_REQUIRENAME:
2196 headerGet(h, RPMTAG_REQUIREFLAGS, &reqflags, HEADERGET_MINMEM);
2197 break;
2198 case RPMTAG_FILETRIGGERNAME:
2199 headerGet(h, RPMTAG_FILETRIGGERINDEX, &trig_index, HEADERGET_MINMEM);
2200 break;
2201 case RPMTAG_TRANSFILETRIGGERNAME:
2202 headerGet(h, RPMTAG_TRANSFILETRIGGERINDEX, &trig_index, HEADERGET_MINMEM);
2203 break;
2204 }
2205 headerGet(h, rpmtag, &tagdata, HEADERGET_MINMEM);
2206
2207 if (rpmtdCount(&tagdata) == 0) {
2208 if (rpmtag != RPMTAG_GROUP)
2209 goto exit;
2210
2211 /* XXX preserve legacy behavior */
2212 tagdata.type = RPM_STRING_TYPE;
2213 tagdata.data = (const char **) "Unknown";
2214 tagdata.count = 1;
2215 }
2216
2217 dbc = dbiCursorInit(dbi, DBC_WRITE);
2218
2219 logAddRemove(dbiName(dbi), 0, &tagdata);
2220 while ((i = rpmtdNext(&tagdata)) >= 0) {
2221 const void * key = NULL((void*)0);
2222 unsigned int keylen = 0;
2223 int j;
2224 struct dbiIndexItem_s rec;
2225
2226 switch (rpmtag) {
2227 /* Include trigger index in db index for triggers */
2228 case RPMTAG_FILETRIGGERNAME:
2229 case RPMTAG_TRANSFILETRIGGERNAME:
2230 rec.hdrNum = hdrNum;
2231 rec.tagNum = *rpmtdNextUint32(&trig_index);
2232 break;
2233
2234 /* Include the tagNum in the others indices (only files use though) */
2235 default:
2236 rec.hdrNum = hdrNum;
2237 rec.tagNum = i;
2238 break;
2239 }
2240
2241 switch (rpmtag) {
2242 case RPMTAG_REQUIRENAME: {
2243 /* Filter out install prerequisites. */
2244 rpm_flag_t *rflag = rpmtdNextUint32(&reqflags);
2245 if (rflag && isInstallPreReq(*rflag)((*rflag) & ((RPMSENSE_SCRIPT_PRE|RPMSENSE_SCRIPT_POST|RPMSENSE_RPMLIB
|RPMSENSE_KEYRING|RPMSENSE_PRETRANS|RPMSENSE_POSTTRANS) &
~RPMSENSE_PREREQ))
&&
2246 !isErasePreReq(*rflag)((*rflag) & ((RPMSENSE_SCRIPT_PREUN|RPMSENSE_SCRIPT_POSTUN
) & ~RPMSENSE_PREREQ))
)
2247 continue;
2248 break;
2249 }
2250 case RPMTAG_TRIGGERNAME:
2251 if (i > 0) { /* don't add duplicates */
2252 const char **tnames = tagdata.data;
2253 const char *str = rpmtdGetString(&tagdata);
2254 for (j = 0; j < i; j++) {
2255 if (rstreq(str, tnames[j]))
2256 break;
2257 }
2258 if (j < i)
2259 continue;
2260 }
2261 break;
2262 default:
2263 break;
2264 }
2265
2266 if ((key = td2key(&tagdata, &keylen)) == NULL((void*)0))
2267 continue;
2268
2269 rc += idxupdate(dbi, dbc, key, keylen, &rec);
2270
2271 if (*(char *)key == '(') {
2272 switch (rpmtag) {
2273 case RPMTAG_REQUIRENAME:
2274 case RPMTAG_CONFLICTNAME:
2275 case RPMTAG_SUGGESTNAME:
2276 case RPMTAG_SUPPLEMENTNAME:
2277 case RPMTAG_RECOMMENDNAME:
2278 case RPMTAG_ENHANCENAME:
2279 if (rpmtdType(&tagdata) == RPM_STRING_ARRAY_TYPE) {
2280 rc += updateRichDep(dbi, dbc, rpmtdGetString(&tagdata),
2281 &rec, idxupdate);
2282 }
2283 default:
2284 break;
2285 }
2286 }
2287 }
2288
2289 dbiCursorFree(dbi, dbc);
2290
2291exit:
2292 rpmtdFreeData(&tagdata);
2293 return (rc == 0) ? RPMRC_OK : RPMRC_FAIL;
2294}
2295
2296static rpmRC indexPut(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h)
2297{
2298 return tag2index(dbi, rpmtag, hdrNum, h, idxdbPut);
2299}
2300
2301int rpmdbAdd(rpmdb db, Header h)
2302{
2303 dbiIndex dbi = NULL((void*)0);
2304 dbiCursor dbc = NULL((void*)0);
2305 unsigned int hdrNum = 0;
2306 unsigned int hdrLen = 0;
2307 unsigned char *hdrBlob = NULL((void*)0);
2308 int ret = 0;
2309
2310 if (db == NULL((void*)0))
2311 return 0;
2312
2313 hdrBlob = headerExport(h, &hdrLen);
2314 if (hdrBlob == NULL((void*)0) || hdrLen == 0) {
2315 ret = -1;
2316 goto exit;
2317 }
2318
2319 ret = pkgdbOpen(db, 0, &dbi);
2320 if (ret)
2321 goto exit;
2322
2323 rpmsqBlock(SIG_BLOCK0);
2324 dbCtrl(db, DB_CTRL_LOCK_RW);
2325
2326 /* Add header to primary index */
2327 dbc = dbiCursorInit(dbi, DBC_WRITE);
2328 ret = pkgdbNew(dbi, dbc, &hdrNum);
2329 if (ret == 0)
2330 ret = pkgdbPut(dbi, dbc, hdrNum, hdrBlob, hdrLen);
2331 dbiCursorFree(dbi, dbc);
2332
2333 /* Add associated data to secondary indexes */
2334 if (ret == 0) {
2335 for (int dbix = 0; dbix < db->db_ndbi; dbix++) {
2336 rpmDbiTag rpmtag = db->db_tags[dbix];
2337
2338 if (indexOpen(db, rpmtag, 0, &dbi))
2339 continue;
2340
2341 ret += indexPut(dbi, rpmtag, hdrNum, h);
2342 }
2343 }
2344
2345 dbCtrl(db, DB_CTRL_INDEXSYNC);
2346 dbCtrl(db, DB_CTRL_UNLOCK_RW);
2347 rpmsqBlock(SIG_UNBLOCK1);
2348
2349 /* If everything ok, mark header as installed now */
2350 if (ret == 0) {
2351 headerSetInstance(h, hdrNum);
2352 /* Purge our verification cache on added public keys */
2353 if (db->db_checked && headerIsEntry(h, RPMTAG_PUBKEYS)) {
2354 dbChkEmpty(db->db_checked);
2355 }
2356 }
2357
2358exit:
2359 free(hdrBlob);
2360
2361 return ret;
2362}
2363
2364static int rpmdbRemoveFiles(char * pattern)
2365{
2366 int rc = 0;
2367 ARGV_t paths = NULL((void*)0), p;
2368
2369 if (rpmGlob(pattern, NULL((void*)0), &paths) == 0) {
2370 for (p = paths; *p; p++) {
2371 rc += unlink(*p);
2372 }
2373 argvFree(paths);
2374 }
2375 return rc;
2376}
2377
2378static int rpmdbRemoveDatabase(const char *dbpath)
2379{
2380 int rc = 0;
2381 char *pattern;
2382
2383 pattern = rpmGetPath(dbpath, "/*", NULL((void*)0));
2384 rc += rpmdbRemoveFiles(pattern);
2385 free(pattern);
2386 pattern = rpmGetPath(dbpath, "/.??*", NULL((void*)0));
2387 rc += rpmdbRemoveFiles(pattern);
2388 free(pattern);
2389
2390 rc += rmdir(dbpath);
2391 return rc;
2392}
2393
2394static int rpmdbMoveDatabase(const char * prefix, const char * srcdbpath,
2395 const char * dbpath, const char * tmppath)
2396{
2397 int rc = -1;
2398 int xx;
2399 char *src = rpmGetPath(prefix, "/", srcdbpath, NULL((void*)0));
2400 char *old = rpmGetPath(prefix, "/", tmppath, NULL((void*)0));
2401 char *dest = rpmGetPath(prefix, "/", dbpath, NULL((void*)0));
2402
2403 char * oldkeys = rpmGetPath(old, "/", "pubkeys", NULL((void*)0));
2404 char * destkeys = rpmGetPath(dest, "/", "pubkeys", NULL((void*)0));
2405
2406 xx = rename(dest, old);
2407 if (xx) {
2408 goto exit;
2409 }
2410 xx = rename(src, dest);
2411 if (xx) {
2412 rpmlog(RPMLOG_ERR, _("could not move new database in place\n")dcgettext ("rpm", "could not move new database in place\n", 5
)
);
2413 xx = rename(old, dest);
2414 if (xx) {
2415 rpmlog(RPMLOG_ERR, _("could also not restore old database from %s\n")dcgettext ("rpm", "could also not restore old database from %s\n"
, 5)
,
2416 old);
2417 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)
2418 "to recover\n")dcgettext ("rpm", "replace files in %s with files from %s " "to recover\n"
, 5)
, dest, old);
2419 }
2420 goto exit;
2421 }
2422
2423 if (access(oldkeys, F_OK0 ) != -1) {
2424 xx = rename(oldkeys, destkeys);
2425 if (xx) {
2426 rpmlog(RPMLOG_ERR, _("Could not get public keys from %s\n")dcgettext ("rpm", "Could not get public keys from %s\n", 5), oldkeys);
2427 goto exit;
2428 }
2429 }
2430
2431 xx = rpmdbRemoveDatabase(old);
2432 if (xx) {
2433 rpmlog(RPMLOG_ERR, _("could not delete old database at %s\n")dcgettext ("rpm", "could not delete old database at %s\n", 5), old);
2434 }
2435
2436 rc = 0;
2437
2438 exit:
2439 _free(src)rfree((src));
2440 _free(old)rfree((old));
2441 _free(dest)rfree((dest));
2442 _free(oldkeys)rfree((oldkeys));
2443 _free(destkeys)rfree((destkeys));
2444 return rc;
2445}
2446
2447static int rpmdbSetPermissions(char * src, char * dest)
2448{
2449 struct dirent *dp;
2450 DIR *dfd;
2451
2452 struct stat st;
2453 int xx, rc = -1;
2454 char * filepath;
2455
2456 if (stat(dest, &st) < 0)
2457 goto exit;
2458 if (stat(src, &st) < 0)
2459 goto exit;
2460
2461 if ((dfd = opendir(dest)) == NULL((void*)0)) {
2462 goto exit;
2463 }
2464
2465 rc = 0;
2466 while ((dp = readdir(dfd)) != NULL((void*)0)) {
2467 if (!strcmp(dp->d_name, "..")) {
2468 continue;
2469 }
2470 filepath = rpmGetPath(dest, "/", dp->d_name, NULL((void*)0));
2471 xx = chown(filepath, st.st_uid, st.st_gid);
2472 rc += xx;
2473 if (!strcmp(dp->d_name, ".")) {
2474 xx = chmod(filepath, (st.st_mode & 07777));
2475 } else {
2476 xx = chmod(filepath, (st.st_mode & 07666));
2477 }
2478 rc += xx;
2479 _free(filepath)rfree((filepath));
2480 }
2481
2482 exit:
2483 return rc;
2484}
2485
2486int rpmdbRebuild(const char * prefix, rpmts ts,
2487 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg))
2488{
2489 rpmdb olddb;
2490 char * dbpath = NULL((void*)0);
2491 char * rootdbpath = NULL((void*)0);
2492 char * tmppath = NULL((void*)0);
2493 rpmdb newdb;
2494 char * newdbpath = NULL((void*)0);
2495 char * newrootdbpath = NULL((void*)0);
2496 int nocleanup = 1;
2497 int failed = 0;
2498 int rc = 0;
2499
2500 dbpath = rpmGetPath("%{?_dbpath}", NULL((void*)0));
2501 if (rstreq(dbpath, "")) {
2502 rpmlog(RPMLOG_ERR, _("no dbpath has been set")dcgettext ("rpm", "no dbpath has been set", 5));
2503 rc = 1;
2504 goto exit;
2505 }
2506 rootdbpath = rpmGetPath(prefix, dbpath, NULL((void*)0));
2507
2508 newdbpath = rpmGetPath("%{?_dbpath_rebuild}", NULL((void*)0));
2509 if (rstreq(newdbpath, "") || rstreq(newdbpath, dbpath)) {
2510 newdbpath = _free(newdbpath)rfree((newdbpath));
2511 rasprintf(&newdbpath, "%srebuilddb.%d", dbpath, (int) getpid());
2512 nocleanup = 0;
2513 }
2514 newrootdbpath = rpmGetPath(prefix, newdbpath, NULL((void*)0));
2515
2516 rpmlog(RPMLOG_DEBUG, "rebuilding database %s into %s\n",
2517 rootdbpath, newrootdbpath);
2518
2519 if (mkdir(newrootdbpath, 0755)) {
2520 rpmlog(RPMLOG_ERR, _("failed to create directory %s: %s\n")dcgettext ("rpm", "failed to create directory %s: %s\n", 5),
2521 newrootdbpath, strerror(errno(*__errno_location ())));
2522 rc = 1;
2523 goto exit;
2524 }
2525
2526 if (openDatabase(prefix, dbpath, &olddb,
2527 O_RDONLY00, 0644, RPMDB_FLAG_REBUILD)) {
2528 rc = 1;
2529 goto exit;
2530 }
2531 if (openDatabase(prefix, newdbpath, &newdb,
2532 (O_RDWR02 | O_CREAT0100), 0644, RPMDB_FLAG_REBUILD)) {
2533 rc = 1;
2534 goto exit;
2535 }
2536
2537 { Header h = NULL((void*)0);
2538 rpmdbMatchIterator mi;
2539
2540 mi = rpmdbInitIterator(olddb, RPMDBI_PACKAGES, NULL((void*)0), 0);
2541 if (ts && hdrchk)
2542 (void) rpmdbSetHdrChk(mi, ts, hdrchk);
2543
2544 while ((h = rpmdbNextIterator(mi)) != NULL((void*)0)) {
2545
2546 /* let's sanity check this record a bit, otherwise just skip it */
2547 if (!(headerIsEntry(h, RPMTAG_NAME) &&
2548 headerIsEntry(h, RPMTAG_VERSION) &&
2549 headerIsEntry(h, RPMTAG_RELEASE) &&
2550 headerIsEntry(h, RPMTAG_BUILDTIME)))
2551 {
2552 rpmlog(RPMLOG_ERR,
2553 _("header #%u in the database is bad -- skipping.\n")dcgettext ("rpm", "header #%u in the database is bad -- skipping.\n"
, 5)
,
2554 rpmdbGetIteratorOffset(mi));
2555 continue;
2556 }
2557
2558 /* Deleted entries are eliminated in legacy headers by copy. */
2559 if (headerIsEntry(h, RPMTAG_HEADERIMAGE)) {
2560 Header nh = headerReload(headerCopy(h), RPMTAG_HEADERIMAGE);
2561 rc = rpmdbAdd(newdb, h);
2562 headerFree(nh);
2563 } else {
2564 rc = rpmdbAdd(newdb, h);
2565 }
2566
2567 if (rc) {
2568 rpmlog(RPMLOG_ERR, _("cannot add record originally at %u\n")dcgettext ("rpm", "cannot add record originally at %u\n", 5),
2569 rpmdbGetIteratorOffset(mi));
2570 failed = 1;
2571 break;
2572 }
2573 }
2574
2575 rpmdbFreeIterator(mi);
2576
2577 }
2578
2579 rpmdbClose(olddb);
2580 rpmdbClose(newdb);
2581
2582 if (failed) {
2583 rpmlog(RPMLOG_WARNING,
2584 _("failed to rebuild database: original database "dcgettext ("rpm", "failed to rebuild database: original database "
"remains in place\n", 5)
2585 "remains in place\n")dcgettext ("rpm", "failed to rebuild database: original database "
"remains in place\n", 5)
);
2586
2587 rpmdbRemoveDatabase(newrootdbpath);
2588 rc = 1;
2589 goto exit;
2590 } else {
2591 rpmdbSetPermissions(dbpath, newdbpath);
2592 }
2593
2594 if (!nocleanup) {
2595 rasprintf(&tmppath, "%sold.%d", dbpath, (int) getpid());
2596 if (rpmdbMoveDatabase(prefix, newdbpath, dbpath, tmppath)) {
2597 rpmlog(RPMLOG_ERR, _("failed to replace old database with new "dcgettext ("rpm", "failed to replace old database with new " "database!\n"
, 5)
2598 "database!\n")dcgettext ("rpm", "failed to replace old database with new " "database!\n"
, 5)
);
2599 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)
2600 "to recover\n")dcgettext ("rpm", "replace files in %s with files from %s " "to recover\n"
, 5)
, dbpath, newdbpath);
2601 rc = 1;
2602 goto exit;
2603 }
2604 }
2605 rc = 0;
2606
2607exit:
2608 free(newdbpath);
2609 free(dbpath);
2610 free(tmppath);
2611 free(newrootdbpath);
2612 free(rootdbpath);
2613
2614 return rc;
2615}
2616
2617int rpmdbCtrl(rpmdb db, rpmdbCtrlOp ctrl)
2618{
2619 dbCtrlOp dbctrl = 0;
2620 switch (ctrl) {
2621 case RPMDB_CTRL_LOCK_RO:
2622 dbctrl = DB_CTRL_LOCK_RO;
2623 break;
2624 case RPMDB_CTRL_UNLOCK_RO:
2625 dbctrl = DB_CTRL_UNLOCK_RO;
2626 break;
2627 case RPMDB_CTRL_LOCK_RW:
2628 dbctrl = DB_CTRL_LOCK_RW;
2629 break;
2630 case RPMDB_CTRL_UNLOCK_RW:
2631 dbctrl = DB_CTRL_UNLOCK_RW;
2632 break;
2633 case RPMDB_CTRL_INDEXSYNC:
2634 dbctrl = DB_CTRL_INDEXSYNC;
2635 break;
2636 }
2637 return dbctrl ? dbCtrl(db, dbctrl) : 1;
2638}
2639