12 #include <sys/signal.h>
15 #include <rpmurl.h> /* XXX for assert.h */
16 #include <rpmmacro.h> /* XXX for rpmGetPath/rpmGenPath */
20 /*@access dbiIndexSet@*/
21 /*@access dbiIndexItem@*/
22 /*@access Header@*/ /* XXX compared with NULL */
23 /*@access rpmdbMatchIterator@*/
28 extern int _noDirTokens;
29 static int _rebuildinprogress = 0;
31 int _filterDbDups = 0; /* Filter duplicate entries ? (bug in pre rpm-3.0.4) */
34 #define _DBI_PERMS 0644
37 static int dbiTagsMax = 0;
38 /*@only@*/ static int *dbiTags = NULL;
41 * Return dbi index used for rpm tag.
42 * @param rpmtag rpm header tag
43 * @return dbi index, -1 on error
45 static int dbiTagToDbix(int rpmtag)
49 if (!(dbiTagsMax > 0 && dbiTags))
51 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
52 if (rpmtag == dbiTags[dbix])
59 * Initialize database (index, tag) tuple from configuration.
61 static void dbiTagsInit(void)
63 static const char * _dbiTagStr_default =
64 "Packages:Name:Basenames:Group:Requirename:Providename:Conflictname:Triggername";
69 dbiTagStr = rpmExpand("%{_dbi_tags}", NULL);
70 if (!(dbiTagStr && *dbiTagStr && *dbiTagStr != '%')) {
72 dbiTagStr = xstrdup(_dbiTagStr_default);
75 if (dbiTagsMax || dbiTags) {
81 /* Always allocate package index */
83 dbiTags = xcalloc(1, dbiTagsMax * sizeof(*dbiTags));
85 for (o = dbiTagStr; o && *o; o = oe) {
86 while (*o && isspace(*o))
90 for (oe = o; oe && *oe; oe++) {
93 if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/'))
101 fprintf(stderr, _("dbiTagsInit: unrecognized tag name: \"%s\" ignored\n"), o);
104 if (dbiTagToDbix(rpmtag) >= 0)
107 dbiTags = xrealloc(dbiTags, (dbiTagsMax + 1) * sizeof(*dbiTags));
108 dbiTags[dbiTagsMax++] = rpmtag;
115 extern struct _dbiVec db1vec;
116 #define DB1vec &db1vec
122 extern struct _dbiVec db2vec;
123 #define DB2vec &db2vec
129 extern struct _dbiVec db3vec;
130 #define DB3vec &db3vec
135 static struct _dbiVec *mydbvecs[] = {
136 DB1vec, DB1vec, DB2vec, DB3vec, NULL
139 INLINE int dbiSync(dbiIndex dbi, unsigned int flags) {
140 if (_debug < 0 || dbi->dbi_debug)
141 fprintf(stderr, " Sync %s\n", tagName(dbi->dbi_rpmtag));
142 return (*dbi->dbi_vec->sync) (dbi, flags);
145 INLINE int dbiByteSwapped(dbiIndex dbi) {
146 return (*dbi->dbi_vec->byteswapped) (dbi);
149 INLINE int XdbiCopen(dbiIndex dbi, /*@out@*/ DBC ** dbcp, unsigned int flags,
150 const char * f, unsigned int l)
152 if (_debug < 0 || dbi->dbi_debug)
153 fprintf(stderr, "+++ RMW %s (%s:%u)\n", tagName(dbi->dbi_rpmtag), f, l);
154 return (*dbi->dbi_vec->copen) (dbi, dbcp, flags);
157 INLINE int XdbiCclose(dbiIndex dbi, /*@only@*/ DBC * dbcursor, unsigned int flags,
158 const char * f, unsigned int l)
160 if (_debug < 0 || dbi->dbi_debug)
161 fprintf(stderr, "--- RMW %s (%s:%u)\n", tagName(dbi->dbi_rpmtag), f, l);
162 return (*dbi->dbi_vec->cclose) (dbi, dbcursor, flags);
165 INLINE int dbiDel(dbiIndex dbi, DBC * dbcursor, const void * keyp, size_t keylen, unsigned int flags)
170 /* XXX make sure that keylen is correct for "" lookup */
171 NULkey = (keyp && *((char *)keyp) == '\0' && keylen == 0);
172 if (NULkey) keylen++;
173 rc = (*dbi->dbi_vec->cdel) (dbi, dbcursor, keyp, keylen, flags);
174 if (NULkey) keylen--;
176 if (_debug < 0 || dbi->dbi_debug)
177 fprintf(stderr, " Del %s key (%p,%ld) %s rc %d\n", tagName(dbi->dbi_rpmtag), keyp, (long)keylen, (dbi->dbi_rpmtag != RPMDBI_PACKAGES ? (char *)keyp : ""), rc);
182 INLINE int dbiGet(dbiIndex dbi, DBC * dbcursor, void ** keypp, size_t * keylenp,
183 void ** datapp, size_t * datalenp, unsigned int flags)
188 /* XXX make sure that keylen is correct for "" lookup */
189 NULkey = (keypp && *keypp && *((char *)(*keypp)) == '\0' && keylenp && *keylenp == 0);
190 if (NULkey) (*keylenp)++;
191 rc = (*dbi->dbi_vec->cget) (dbi, dbcursor, keypp, keylenp, datapp, datalenp, flags);
192 if (NULkey) (*keylenp)--;
194 if (_debug < 0 || dbi->dbi_debug) {
196 int dataval = 0xdeadbeef;
197 if (dbi->dbi_rpmtag == RPMDBI_PACKAGES && keypp && *keypp && keylenp && *keylenp >= sizeof(keyval)) {
199 memcpy(&keyint, *keypp, sizeof(keyint));
200 sprintf(keyval, "%d", keyint);
201 } else keyval[0] = '\0';
202 if (rc == 0 && datapp && *datapp && datalenp && *datalenp >= sizeof(dataval))
203 memcpy(&dataval, *datapp, sizeof(dataval));
204 fprintf(stderr, " Get %s key (%p,%ld) data (%p,%ld) \"%s\" %x rc %d\n",
205 tagName(dbi->dbi_rpmtag), *keypp, (long)*keylenp, *datapp, (long)*datalenp,
206 (dbi->dbi_rpmtag != RPMDBI_PACKAGES ? (char *)*keypp : keyval), dataval, rc);
211 INLINE int dbiPut(dbiIndex dbi, DBC * dbcursor, const void * keyp, size_t keylen,
212 const void * datap, size_t datalen, unsigned int flags)
217 /* XXX make sure that keylen is correct for "" lookup */
218 NULkey = (keyp && *((char *)keyp) == '\0' && keylen == 0);
219 if (NULkey) keylen++;
220 rc = (*dbi->dbi_vec->cput) (dbi, dbcursor, keyp, keylen, datap, datalen, flags);
221 if (NULkey) keylen--;
223 if (_debug < 0 || dbi->dbi_debug) {
224 int dataval = 0xdeadbeef;
225 if (datap) memcpy(&dataval, datap, sizeof(dataval));
226 fprintf(stderr, " Put %s key (%p,%ld) data (%p,%ld) \"%s\" %x rc %d\n", tagName(dbi->dbi_rpmtag), keyp, (long)keylen, datap, (long)datalen, (dbi->dbi_rpmtag != RPMDBI_PACKAGES ? (char *)keyp : ""), dataval, rc);
232 INLINE int dbiClose(dbiIndex dbi, unsigned int flags) {
233 if (_debug < 0 || dbi->dbi_debug)
234 fprintf(stderr, " %s Close\n", tagName(dbi->dbi_rpmtag));
235 return (*dbi->dbi_vec->close) (dbi, flags);
238 dbiIndex dbiOpen(rpmdb rpmdb, int rpmtag, /*@unused@*/ unsigned int flags)
242 int _dbapi, _dbapi_rebuild, _dbapi_wanted;
245 dbix = dbiTagToDbix(rpmtag);
246 if (dbix < 0 || dbix >= dbiTagsMax)
249 /* Is this index already open ? */
250 if ((dbi = rpmdb->_dbi[dbix]) != NULL)
253 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
254 if (_dbapi_rebuild < 1 || _dbapi_rebuild > 3)
256 _dbapi_wanted = (_rebuildinprogress ? -1 : rpmdb->db_api);
258 switch (_dbapi_wanted) {
260 _dbapi = _dbapi_wanted;
261 if (_dbapi < 0 || _dbapi >= 4 || mydbvecs[_dbapi] == NULL) {
262 static int _printed = 0;
264 fprintf(stderr, _("\n\
265 --> This version of rpm was not compiled with support for \"%%_dbapi %d\".\n\
266 Please verify the setting of the macro %%_dbapi using \"rpm --showrc\"\n\
267 and configure \"%%_dbapi 3\" (e.g. create and/or edit /etc/rpm/macros).\n\
274 rc = (*mydbvecs[_dbapi]->open) (rpmdb, rpmtag, &dbi);
276 static int _printed[32];
277 if (!_printed[dbix & 0x1f]++)
278 rpmError(RPMERR_DBOPEN,
279 _("cannot open %s index using db%d - %s (%d)"),
280 tagName(rpmtag), _dbapi,
281 (rc > 0 ? strerror(rc) : ""), rc);
287 while (_dbapi-- > 1) {
288 if (mydbvecs[_dbapi] == NULL)
292 rc = (*mydbvecs[_dbapi]->open) (rpmdb, rpmtag, &dbi);
297 static int _printed[32];
298 if (!_printed[dbix & 0x1f]++)
299 rpmError(RPMERR_DBOPEN, _("cannot open %s index"),
304 if (rpmdb->db_api == -1 && _dbapi > 0)
305 rpmdb->db_api = _dbapi;
309 /* Require conversion. */
310 if (rc && _dbapi_wanted >= 0 && _dbapi != _dbapi_wanted && _dbapi_wanted == _dbapi_rebuild) {
311 static int _printed = 0;
312 rc = (_rebuildinprogress ? 0 : 1);
313 if (rc && !_printed++)
314 fprintf(stderr, _("\n\
315 --> The rpm database cannot be opened in db%d format.\n\
316 If you have just upgraded the rpm package you need to convert\n\
317 your database to db%d format by running \"rpm --rebuilddb\" as root.\n\
319 "), _dbapi_wanted, (_dbapi_rebuild > 0 ? _dbapi_rebuild : 3));
323 /* Suggest possible configuration */
324 if (_dbapi_wanted >= 0 && _dbapi != _dbapi_wanted) {
325 static int _printed = 0;
327 fprintf(stderr, _("\n\
328 --> The configured %%_dbapi was db%d, but the rpm database is db%d format.\n\
329 Please verify the setting of the macro %%_dbapi using \"rpm --showrc\"\n\
330 and configure \"%%_dbapi %d\" (e.g. create and/or edit /etc/rpm/macros).\n\
332 "), _dbapi_wanted, _dbapi, _dbapi);
337 /* Suggest possible configuration */
338 if (_dbapi_wanted < 0 && _dbapi != _dbapi_rebuild) {
339 static int _printed = 0;
340 rc = (_rebuildinprogress ? 0 : 1);
341 if (rc && !_printed++)
342 fprintf(stderr, _("\n\
343 --> The rpm database is in db%d format, not the suggested db%d format.\n\
344 Please verify the setting of the macros %%_dbapi and %%_dbapi_rebuild\n\
345 using \"rpm --showrc\", and either run \"rpm --rebuilddb\" as root\n\
346 to convert your database from db%d to db%d format, or configure\n\
347 \"%%_dbapi_rebuild %d\" (e.g. create and/or edit /etc/rpm/macros).\n\
349 "), _dbapi, (_dbapi_rebuild > 0 ? _dbapi_rebuild : 3),
350 _dbapi, (_dbapi_rebuild > 0 ? _dbapi_rebuild : 3), _dbapi);
355 if (rc == 0 && dbi) {
356 rpmdb->_dbi[dbix] = dbi;
366 * Create and initialize item for index database set.
367 * @param hdrNum header instance in db
368 * @param tagNum tag index in header
371 static INLINE dbiIndexItem dbiIndexNewItem(unsigned int hdrNum, unsigned int tagNum) {
372 dbiIndexItem rec = xcalloc(1, sizeof(*rec));
373 rec->hdrNum = hdrNum;
374 rec->tagNum = tagNum;
383 #define _DBSWAP(_a) \
384 { unsigned char _b, *_c = (_a).uc; \
385 _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
386 _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
390 * Return items that match criteria.
391 * @param dbi index database handle
392 * @param keyp search key
393 * @param keylen search key length (0 will use strlen(key))
394 * @param setp address of items retrieved from index database
395 * @return -1 error, 0 success, 1 not found
397 static int dbiSearch(dbiIndex dbi, DBC * dbcursor, const char * keyp, size_t keylen,
404 if (setp) *setp = NULL;
405 if (keylen == 0) keylen = strlen(keyp);
407 rc = dbiGet(dbi, dbcursor, (void **)&keyp, &keylen, &datap, &datalen, 0);
410 rpmError(RPMERR_DBGETINDEX, _("error(%d) getting \"%s\" records from %s index"),
411 rc, keyp, tagName(dbi->dbi_rpmtag));
413 if (rc == 0 && setp) {
414 int _dbbyteswapped = dbiByteSwapped(dbi);
415 const char * sdbir = datap;
419 set = xmalloc(sizeof(*set));
421 /* Convert to database internal format */
422 switch (dbi->dbi_jlen) {
424 case 2*sizeof(int_32):
425 set->count = datalen / (2*sizeof(int_32));
426 set->recs = xmalloc(set->count * sizeof(*(set->recs)));
427 for (i = 0; i < set->count; i++) {
428 union _dbswap hdrNum, tagNum;
430 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
431 sdbir += sizeof(hdrNum.ui);
432 memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
433 sdbir += sizeof(tagNum.ui);
434 if (_dbbyteswapped) {
438 set->recs[i].hdrNum = hdrNum.ui;
439 set->recs[i].tagNum = tagNum.ui;
440 set->recs[i].fpNum = 0;
441 set->recs[i].dbNum = 0;
444 case 1*sizeof(int_32):
445 set->count = datalen / (1*sizeof(int_32));
446 set->recs = xmalloc(set->count * sizeof(*(set->recs)));
447 for (i = 0; i < set->count; i++) {
448 union _dbswap hdrNum;
450 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
451 sdbir += sizeof(hdrNum.ui);
452 if (_dbbyteswapped) {
455 set->recs[i].hdrNum = hdrNum.ui;
456 set->recs[i].tagNum = 0;
457 set->recs[i].fpNum = 0;
458 set->recs[i].dbNum = 0;
468 * Change/delete items that match criteria.
469 * @param dbi index database handle
470 * @param keyp update key
471 * @param set items to update in index database
472 * @return 0 success, 1 not found
475 static int dbiUpdateIndex(dbiIndex dbi, DBC * dbcursor, const char * keyp, dbiIndexSet set)
477 size_t keylen = strlen(keyp);
485 int _dbbyteswapped = dbiByteSwapped(dbi);
487 /* Convert to database internal format */
489 switch (dbi->dbi_jlen) {
491 case 2*sizeof(int_32):
492 datalen = set->count * (2 * sizeof(int_32));
493 datap = tdbir = alloca(datalen);
494 for (i = 0; i < set->count; i++) {
495 union _dbswap hdrNum, tagNum;
497 hdrNum.ui = set->recs[i].hdrNum;
498 tagNum.ui = set->recs[i].tagNum;
499 if (_dbbyteswapped) {
503 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
504 tdbir += sizeof(hdrNum.ui);
505 memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
506 tdbir += sizeof(tagNum.ui);
509 case 1*sizeof(int_32):
510 datalen = set->count * (1 * sizeof(int_32));
511 datap = tdbir = alloca(datalen);
512 for (i = 0; i < set->count; i++) {
513 union _dbswap hdrNum;
515 hdrNum.ui = set->recs[i].hdrNum;
516 if (_dbbyteswapped) {
519 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
520 tdbir += sizeof(hdrNum.ui);
525 rc = dbiPut(dbi, dbcursor, keyp, keylen, datap, datalen, 0);
528 rpmError(RPMERR_DBPUTINDEX, _("error(%d) storing record %s into %s"),
529 rc, keyp, tagName(dbi->dbi_rpmtag));
534 rc = dbiDel(dbi, dbcursor, keyp, keylen, 0);
537 rpmError(RPMERR_DBPUTINDEX, _("error(%d) removing record %s from %s"),
538 rc, keyp, tagName(dbi->dbi_rpmtag));
547 /* XXX assumes hdrNum is first int in dbiIndexItem */
548 static int hdrNumCmp(const void * one, const void * two) {
549 const int * a = one, * b = two;
554 * Append element(s) to set of index database items.
555 * @param set set of index database items
556 * @param recs array of items to append to set
557 * @param nrecs number of items
558 * @param recsize size of an array item
559 * @param sortset should resulting set be sorted?
560 * @return 0 success, 1 failure (bad args)
562 static INLINE int dbiAppendSet(dbiIndexSet set, const void * recs,
563 int nrecs, size_t recsize, int sortset)
565 const char * rptr = recs;
566 size_t rlen = (recsize < sizeof(*(set->recs)))
567 ? recsize : sizeof(*(set->recs));
569 if (set == NULL || recs == NULL || nrecs <= 0 || recsize <= 0)
572 set->recs = (set->count == 0)
573 ? xmalloc(nrecs * sizeof(*(set->recs)))
574 : xrealloc(set->recs, (set->count + nrecs) * sizeof(*(set->recs)));
576 memset(set->recs + set->count, 0, nrecs * sizeof(*(set->recs)));
578 while (nrecs-- > 0) {
579 memcpy(set->recs + set->count, rptr, rlen);
584 if (set->count > 1 && sortset)
585 qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
591 * Remove element(s) from set of index database items.
592 * @param set set of index database items
593 * @param recs array of items to remove from set
594 * @param nrecs number of items
595 * @param recsize size of an array item
596 * @param sorted array is already sorted?
597 * @return 0 success, 1 failure (no items found)
599 static INLINE int dbiPruneSet(dbiIndexSet set, void * recs, int nrecs,
600 size_t recsize, int sorted)
604 int num = set->count;
607 if (nrecs > 1 && !sorted)
608 qsort(recs, nrecs, recsize, hdrNumCmp);
610 for (from = 0; from < num; from++) {
611 if (bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) {
616 set->recs[to] = set->recs[from]; /* structure assignment */
621 return (numCopied == num);
624 /* XXX transaction.c */
625 unsigned int dbiIndexSetCount(dbiIndexSet set) {
629 /* XXX transaction.c */
630 unsigned int dbiIndexRecordOffset(dbiIndexSet set, int recno) {
631 return set->recs[recno].hdrNum;
634 /* XXX transaction.c */
635 unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, int recno) {
636 return set->recs[recno].tagNum;
639 /* XXX transaction.c */
640 void dbiFreeIndexSet(dbiIndexSet set) {
642 if (set->recs) free(set->recs);
648 * Disable all signals, returning previous signal mask.
650 static void blockSignals(rpmdb rpmdb, /*@out@*/ sigset_t * oldMask)
654 /* XXX HACK (disabled) permit ^C aborts for now ... */
655 if (!(rpmdb && rpmdb->db_api == 4)) {
656 sigfillset(&newMask); /* block all signals */
657 sigprocmask(SIG_BLOCK, &newMask, oldMask);
662 * Restore signal mask.
664 static void unblockSignals(rpmdb rpmdb, sigset_t * oldMask)
666 /* XXX HACK (disabled) permit ^C aborts for now ... */
667 if (!(rpmdb && rpmdb->db_api == 4)) {
668 sigprocmask(SIG_SETMASK, oldMask, NULL);
673 #define _DB_HOME "%{_dbpath}"
676 #define _DB_PERMS 0644
679 #define _DB_REMOVE_ENV 0
680 #define _DB_FILTER_DUPS 0
681 #define _DB_ERRPFX "rpmdb"
683 static struct rpmdb_s dbTemplate = {
684 _DB_ROOT, _DB_HOME, _DB_FLAGS, _DB_MODE, _DB_PERMS,
685 _DB_MAJOR, _DB_REMOVE_ENV, _DB_FILTER_DUPS, _DB_ERRPFX
688 int rpmdbOpenAll (rpmdb rpmdb)
692 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
693 if (rpmdb->_dbi[dbix] != NULL)
695 (void) dbiOpen(rpmdb, dbiTags[dbix], rpmdb->db_flags);
700 /* XXX query.c, rpminstall.c, verify.c */
701 int rpmdbClose (rpmdb rpmdb)
705 for (dbix = rpmdb->db_ndbi; --dbix >= 0; ) {
706 if (rpmdb->_dbi[dbix] == NULL)
708 dbiClose(rpmdb->_dbi[dbix], 0);
709 rpmdb->_dbi[dbix] = NULL;
711 if (rpmdb->db_errpfx) {
712 xfree(rpmdb->db_errpfx);
713 rpmdb->db_errpfx = NULL;
715 if (rpmdb->db_root) {
716 xfree(rpmdb->db_root);
717 rpmdb->db_root = NULL;
719 if (rpmdb->db_home) {
720 xfree(rpmdb->db_home);
721 rpmdb->db_home = NULL;
731 int rpmdbSync(rpmdb rpmdb)
735 for (dbix = 0; dbix < rpmdb->db_ndbi; dbix++) {
737 if (rpmdb->_dbi[dbix] == NULL)
739 xx = dbiSync(rpmdb->_dbi[dbix], 0);
744 static /*@only@*/ rpmdb newRpmdb(const char * root, const char * home,
745 int mode, int perms, int flags)
747 rpmdb rpmdb = xcalloc(sizeof(*rpmdb), 1);
748 static int _initialized = 0;
751 _filterDbDups = rpmExpandNumeric("%{_filterdbdups}");
755 *rpmdb = dbTemplate; /* structure assignment */
757 if (!(perms & 0600)) perms = 0644; /* XXX sanity */
760 rpmdb->db_root = (*root ? root : _DB_ROOT);
762 rpmdb->db_home = (*home ? home : _DB_HOME);
763 if (mode >= 0) rpmdb->db_mode = mode;
764 if (perms >= 0) rpmdb->db_perms = perms;
765 if (flags >= 0) rpmdb->db_flags = flags;
768 rpmdb->db_root = rpmGetPath(rpmdb->db_root, NULL);
769 if (rpmdb->db_home) {
770 rpmdb->db_home = rpmGetPath(rpmdb->db_home, NULL);
771 if (!(rpmdb->db_home && rpmdb->db_home[0] != '%')) {
772 rpmError(RPMERR_DBOPEN, _("no dbpath has been set"));
776 if (rpmdb->db_errpfx)
777 rpmdb->db_errpfx = xstrdup(rpmdb->db_errpfx);
778 rpmdb->db_remove_env = 0;
779 rpmdb->db_filter_dups = _filterDbDups;
780 rpmdb->db_ndbi = dbiTagsMax;
781 rpmdb->_dbi = xcalloc(rpmdb->db_ndbi, sizeof(*rpmdb->_dbi));
790 static int openDatabase(const char * prefix, const char * dbpath, int _dbapi,
791 /*@out@*/ rpmdb *dbp, int mode, int perms, int flags)
795 static int _initialized = 0;
796 int justCheck = flags & RPMDB_FLAG_JUSTCHECK;
797 int minimal = flags & RPMDB_FLAG_MINIMAL;
799 if (!_initialized || dbiTagsMax == 0) {
804 /* Insure that _dbapi has one of -1, 1, 2, or 3 */
805 if (_dbapi < -1 || _dbapi > 3)
815 rpmdb = newRpmdb(prefix, dbpath, mode, perms, flags);
816 rpmdb->db_api = _dbapi;
821 for (dbix = 0; rc == 0 && dbix < dbiTagsMax; dbix++) {
825 /* Filter out temporary databases */
826 switch ((rpmtag = dbiTags[dbix])) {
827 case RPMDBI_AVAILABLE:
832 /*@notreached@*/ break;
837 dbi = dbiOpen(rpmdb, rpmtag, 0);
840 case RPMDBI_PACKAGES:
841 if (dbi == NULL) rc |= 1;
843 if (rpmdb->db_api == 3)
848 if (dbi == NULL) rc |= 1;
852 case RPMTAG_BASENAMES:
853 { void * keyp = NULL;
857 /* We used to store the fileindexes as complete paths, rather then
858 plain basenames. Let's see which version we are... */
860 * XXX FIXME: db->fileindex can be NULL under pathological (e.g. mixed
861 * XXX db1/db2 linkage) conditions.
866 xx = dbiCopen(dbi, &dbcursor, 0);
867 xx = dbiGet(dbi, dbcursor, &keyp, NULL, NULL, NULL, 0);
869 const char * akey = keyp;
870 if (strchr(akey, '/')) {
871 rpmError(RPMERR_OLDDB, _("old format database is present; "
872 "use --rebuilddb to generate a new format database"));
876 xx = dbiCclose(dbi, dbcursor, 0);
886 if (rc || justCheck || dbp == NULL)
894 /* XXX python/rpmmodule.c */
895 int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, int perms)
897 int _dbapi = rpmExpandNumeric("%{_dbapi}");
898 return openDatabase(prefix, NULL, _dbapi, dbp, mode, perms, 0);
901 int rpmdbInit (const char * prefix, int perms)
904 int _dbapi = rpmExpandNumeric("%{_dbapi}");
907 rc = openDatabase(prefix, NULL, _dbapi, &rpmdb, (O_CREAT | O_RDWR), perms, RPMDB_FLAG_JUSTCHECK);
916 static Header rpmdbGetRecord(rpmdb rpmdb, unsigned int offset)
919 DBC * dbcursor = NULL;
922 void * keyp = &offset;
923 size_t keylen = sizeof(offset);
927 dbi = dbiOpen(rpmdb, RPMDBI_PACKAGES, 0);
930 xx = dbiCopen(dbi, &dbcursor, 0);
931 rc = dbiGet(dbi, dbcursor, &keyp, &keylen, &uh, &uhlen, 0);
932 xx = dbiCclose(dbi, dbcursor, 0);
936 return headerLoad(uh);
940 static int rpmdbFindByFile(rpmdb rpmdb, const char * filespec,
941 /*@out@*/ dbiIndexSet * matches)
943 const char * dirName;
944 const char * baseName;
945 fingerPrintCache fpc;
949 dbiIndexSet allMatches = NULL;
950 dbiIndexItem rec = NULL;
956 if ((baseName = strrchr(filespec, '/')) != NULL) {
960 len = baseName - filespec + 1;
961 t = strncpy(alloca(len + 1), filespec, len);
970 fpc = fpCacheCreate(20);
971 fp1 = fpLookup(fpc, dirName, baseName, 1);
973 dbi = dbiOpen(rpmdb, RPMTAG_BASENAMES, 0);
975 xx = dbiCopen(dbi, &dbcursor, 0);
976 rc = dbiSearch(dbi, dbcursor, baseName, 0, &allMatches);
977 xx = dbiCclose(dbi, dbcursor, 0);
980 dbiFreeIndexSet(allMatches);
986 *matches = xcalloc(1, sizeof(**matches));
987 rec = dbiIndexNewItem(0, 0);
989 while (i < allMatches->count) {
990 const char ** baseNames, ** dirNames;
992 unsigned int offset = dbiIndexRecordOffset(allMatches, i);
993 unsigned int prevoff;
997 h = rpmdbGetRecord(rpmdb, offset);
999 { rpmdbMatchIterator mi;
1000 mi = rpmdbInitIterator(rpmdb, RPMDBI_PACKAGES, &offset, sizeof(offset));
1001 h = rpmdbNextIterator(mi);
1004 rpmdbFreeIterator(mi);
1013 headerGetEntryMinMemory(h, RPMTAG_BASENAMES, NULL,
1014 (void **) &baseNames, NULL);
1015 headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
1016 (void **) &dirIndexes, NULL);
1017 headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
1018 (void **) &dirNames, NULL);
1022 int num = dbiIndexRecordFileNumber(allMatches, i);
1024 fp2 = fpLookup(fpc, dirNames[dirIndexes[num]], baseNames[num], 1);
1025 if (FP_EQUAL(fp1, fp2)) {
1026 rec->hdrNum = dbiIndexRecordOffset(allMatches, i);
1027 rec->tagNum = dbiIndexRecordFileNumber(allMatches, i);
1028 dbiAppendSet(*matches, rec, 1, sizeof(*rec), 0);
1033 offset = dbiIndexRecordOffset(allMatches, i);
1034 } while (i < allMatches->count &&
1035 (i == 0 || offset == prevoff));
1047 dbiFreeIndexSet(allMatches);
1053 if ((*matches)->count == 0) {
1054 dbiFreeIndexSet(*matches);
1062 /* XXX python/upgrade.c, install.c, uninstall.c */
1063 int rpmdbCountPackages(rpmdb rpmdb, const char * name)
1066 dbiIndexSet matches = NULL;
1070 dbi = dbiOpen(rpmdb, RPMTAG_NAME, 0);
1072 DBC * dbcursor = NULL;
1073 xx = dbiCopen(dbi, &dbcursor, 0);
1074 rc = dbiSearch(dbi, dbcursor, name, 0, &matches);
1075 xx = dbiCclose(dbi, dbcursor, 0);
1079 if (rc == 0) /* success */
1080 rc = dbiIndexSetCount(matches);
1081 else if (rc > 0) /* error */
1082 rpmError(RPMERR_DBCORRUPT, _("error(%d) counting packages"), rc);
1083 else /* not found */
1087 dbiFreeIndexSet(matches);
1092 /* XXX transaction.c */
1093 /* 0 found matches */
1096 static int dbiFindMatches(dbiIndex dbi, DBC * dbcursor,
1097 const char * name, const char * version, const char * release,
1098 /*@out@*/ dbiIndexSet * matches)
1104 rc = dbiSearch(dbi, dbcursor, name, 0, matches);
1107 rc = ((rc == -1) ? 2 : 1);
1111 if (!version && !release) {
1118 /* make sure the version and releases match */
1119 for (i = 0; i < dbiIndexSetCount(*matches); i++) {
1120 unsigned int recoff = dbiIndexRecordOffset(*matches, i);
1121 int goodRelease, goodVersion;
1122 const char * pkgVersion;
1123 const char * pkgRelease;
1130 h = rpmdbGetRecord(dbi->dbi_rpmdb, recoff);
1132 { rpmdbMatchIterator mi;
1133 mi = rpmdbInitIterator(dbi->dbi_rpmdb, RPMDBI_PACKAGES, &recoff, sizeof(recoff));
1134 h = rpmdbNextIterator(mi);
1137 rpmdbFreeIterator(mi);
1141 rpmError(RPMERR_DBCORRUPT, _("%s: cannot read header at 0x%x"),
1142 "findMatches", recoff);
1147 headerNVR(h, NULL, &pkgVersion, &pkgRelease);
1149 goodRelease = goodVersion = 1;
1151 if (release && strcmp(release, pkgRelease)) goodRelease = 0;
1152 if (version && strcmp(version, pkgVersion)) goodVersion = 0;
1154 if (goodRelease && goodVersion) {
1155 /* structure assignment */
1156 (*matches)->recs[gotMatches++] = (*matches)->recs[i];
1158 (*matches)->recs[i].hdrNum = 0;
1164 (*matches)->count = gotMatches;
1171 if (rc && matches && *matches) {
1172 dbiFreeIndexSet(*matches);
1178 /* 0 found matches */
1181 static int dbiFindByLabel(dbiIndex dbi, DBC * dbcursor, const char * arg, dbiIndexSet * matches)
1183 char * localarg, * chptr;
1187 if (!strlen(arg)) return 1;
1189 /* did they give us just a name? */
1190 rc = dbiFindMatches(dbi, dbcursor, arg, NULL, NULL, matches);
1191 if (rc != 1) return rc;
1193 dbiFreeIndexSet(*matches);
1197 /* maybe a name and a release */
1198 localarg = alloca(strlen(arg) + 1);
1199 strcpy(localarg, arg);
1201 chptr = (localarg + strlen(localarg)) - 1;
1202 while (chptr > localarg && *chptr != '-') chptr--;
1203 if (chptr == localarg) return 1;
1206 rc = dbiFindMatches(dbi, dbcursor, localarg, chptr + 1, NULL, matches);
1207 if (rc != 1) return rc;
1208 if (*matches) dbiFreeIndexSet(*matches);
1210 /* how about name-version-release? */
1212 release = chptr + 1;
1213 while (chptr > localarg && *chptr != '-') chptr--;
1214 if (chptr == localarg) return 1;
1217 return dbiFindMatches(dbi, dbcursor, localarg, chptr + 1, release, matches);
1221 * Rewrite a header in the database.
1222 * Note: this is called from a markReplacedFiles iteration, and *must*
1223 * preserve the "join key" (i.e. offset) for the header.
1224 * @param dbi index database handle (always RPMDBI_PACKAGES)
1225 * @param offset join key
1226 * @param h rpm header
1227 * @return 0 on success
1229 static int dbiUpdateRecord(dbiIndex dbi, DBC * dbcursor, int offset, Header h)
1231 sigset_t signalMask;
1240 uhlen = headerSizeof(h, HEADER_MAGIC_NO);
1241 uh = headerUnload(h);
1242 blockSignals(dbi->dbi_rpmdb, &signalMask);
1243 rc = dbiPut(dbi, dbcursor, &offset, sizeof(offset), uh, uhlen, 0);
1244 xx = dbiSync(dbi, 0);
1245 unblockSignals(dbi->dbi_rpmdb, &signalMask);
1251 struct _rpmdbMatchIterator {
1252 const void * mi_keyp;
1262 unsigned int mi_prevoffset;
1263 unsigned int mi_offset;
1264 unsigned int mi_filenum;
1265 unsigned int mi_fpnum;
1266 unsigned int mi_dbnum;
1267 const char * mi_version;
1268 const char * mi_release;
1271 void rpmdbFreeIterator(rpmdbMatchIterator mi)
1273 dbiIndex dbi = NULL;
1279 dbi = dbiOpen(mi->mi_rpmdb, RPMDBI_PACKAGES, 0);
1281 if (mi->mi_modified && mi->mi_prevoffset) {
1282 DBC * dbcursor = NULL;
1283 xx = dbiCopen(dbi, &dbcursor, 0);
1284 dbiUpdateRecord(dbi, dbcursor, mi->mi_prevoffset, mi->mi_h);
1285 xx = dbiCclose(dbi, dbcursor, 0);
1288 headerFree(mi->mi_h);
1292 xx = dbiCclose(dbi, dbi->dbi_rmw, 0);
1293 dbi->dbi_rmw = NULL;
1296 if (mi->mi_release) {
1297 xfree(mi->mi_release);
1298 mi->mi_release = NULL;
1300 if (mi->mi_version) {
1301 xfree(mi->mi_version);
1302 mi->mi_version = NULL;
1305 int xx = dbiCclose(dbi, mi->mi_dbc, 1);
1309 dbiFreeIndexSet(mi->mi_set);
1319 rpmdb rpmdbGetIteratorRpmDB(rpmdbMatchIterator mi) {
1322 return mi->mi_rpmdb;
1325 unsigned int rpmdbGetIteratorOffset(rpmdbMatchIterator mi) {
1328 return mi->mi_offset;
1331 unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi) {
1334 return mi->mi_filenum;
1337 int rpmdbGetIteratorCount(rpmdbMatchIterator mi) {
1338 if (!(mi && mi->mi_set))
1339 return 0; /* XXX W2DO? */
1340 return mi->mi_set->count;
1343 void rpmdbSetIteratorRelease(rpmdbMatchIterator mi, const char * release) {
1346 if (mi->mi_release) {
1347 xfree(mi->mi_release);
1348 mi->mi_release = NULL;
1350 mi->mi_release = (release ? xstrdup(release) : NULL);
1353 void rpmdbSetIteratorVersion(rpmdbMatchIterator mi, const char * version) {
1356 if (mi->mi_version) {
1357 xfree(mi->mi_version);
1358 mi->mi_version = NULL;
1360 mi->mi_version = (version ? xstrdup(version) : NULL);
1363 int rpmdbSetIteratorModified(rpmdbMatchIterator mi, int modified) {
1367 rc = mi->mi_modified;
1368 mi->mi_modified = modified;
1372 Header XrpmdbNextIterator(rpmdbMatchIterator mi, const char * f, unsigned l)
1385 dbi = dbiOpen(mi->mi_rpmdb, RPMDBI_PACKAGES, 0);
1388 /* XXX cursors need to be per-iterator, not per-dbi. Get a cursor now. */
1389 if (mi->mi_dbc == NULL) {
1390 xx = XdbiCopen(dbi, &mi->mi_dbc, 1, f, l);
1394 /* XXX skip over instances with 0 join key */
1397 if (!(mi->mi_setx < mi->mi_set->count))
1399 mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx);
1400 mi->mi_filenum = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx);
1401 keyp = &mi->mi_offset;
1402 keylen = sizeof(mi->mi_offset);
1404 keyp = (void *)mi->mi_keyp; /* XXX FIXME const */
1405 keylen = mi->mi_keylen;
1407 rc = dbiGet(dbi, mi->mi_dbc, &keyp, &keylen, &uh, &uhlen, 0);
1410 * If we got the next key, save the header instance number.
1411 * For db1 Packages (db1->dbi_lastoffset != 0), always copy.
1412 * For db3 Packages, instance 0 (i.e. mi->mi_setx == 0) is the
1413 * largest header instance in the database, and should be
1416 if (rc == 0 && keyp && (dbi->dbi_lastoffset || mi->mi_setx))
1417 memcpy(&mi->mi_offset, keyp, sizeof(mi->mi_offset));
1419 /* Terminate on error or end of keys */
1420 if (rc || (mi->mi_setx && mi->mi_offset == 0))
1424 } while (mi->mi_offset == 0);
1426 if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset)
1429 /* Retrieve next header */
1431 rc = dbiGet(dbi, mi->mi_dbc, &keyp, &keylen, &uh, &uhlen, 0);
1436 /* Free current header */
1438 if (mi->mi_modified && mi->mi_prevoffset)
1439 dbiUpdateRecord(dbi, mi->mi_dbc, mi->mi_prevoffset, mi->mi_h);
1440 headerFree(mi->mi_h);
1444 mi->mi_h = headerLoad(uh);
1446 if (mi->mi_release) {
1447 const char *release;
1448 headerNVR(mi->mi_h, NULL, NULL, &release);
1449 if (strcmp(mi->mi_release, release))
1453 if (mi->mi_version) {
1454 const char *version;
1455 headerNVR(mi->mi_h, NULL, &version, NULL);
1456 if (strcmp(mi->mi_version, version))
1460 mi->mi_prevoffset = mi->mi_offset;
1461 mi->mi_modified = 0;
1465 static void rpmdbSortIterator(rpmdbMatchIterator mi) {
1466 if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) {
1467 qsort(mi->mi_set->recs, mi->mi_set->count, sizeof(*mi->mi_set->recs),
1473 static int rpmdbGrowIterator(rpmdbMatchIterator mi,
1474 const void * keyp, size_t keylen, int fpNum)
1476 dbiIndex dbi = NULL;
1477 DBC * dbcursor = NULL;
1478 dbiIndexSet set = NULL;
1485 dbi = dbiOpen(mi->mi_rpmdb, mi->mi_rpmtag, 0);
1490 keylen = strlen(keyp);
1492 xx = dbiCopen(dbi, &dbcursor, 0);
1493 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
1494 xx = dbiCclose(dbi, dbcursor, 0);
1497 if (rc == 0) { /* success */
1499 for (i = 0; i < set->count; i++)
1500 set->recs[i].fpNum = fpNum;
1502 if (mi->mi_set == NULL) {
1506 mi->mi_set->recs = xrealloc(mi->mi_set->recs,
1507 (mi->mi_set->count + set->count) * sizeof(*(mi->mi_set->recs)));
1508 memcpy(mi->mi_set->recs + mi->mi_set->count, set->recs,
1509 set->count * sizeof(*(mi->mi_set->recs)));
1510 mi->mi_set->count += set->count;
1515 dbiFreeIndexSet(set);
1519 int rpmdbPruneIterator(rpmdbMatchIterator mi, int * hdrNums,
1520 int nHdrNums, int sorted)
1522 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
1526 dbiPruneSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), sorted);
1530 int rpmdbAppendIterator(rpmdbMatchIterator mi, int * hdrNums, int nHdrNums)
1532 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
1535 if (mi->mi_set == NULL)
1536 mi->mi_set = xcalloc(1, sizeof(*mi->mi_set));
1537 dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0);
1541 rpmdbMatchIterator rpmdbInitIterator(rpmdb rpmdb, int rpmtag,
1542 const void * keyp, size_t keylen)
1544 rpmdbMatchIterator mi = NULL;
1545 dbiIndexSet set = NULL;
1549 /* XXX HACK to remove rpmdbFindByLabel/findMatches from the API */
1552 rpmtag = RPMTAG_NAME;
1557 dbi = dbiOpen(rpmdb, rpmtag, 0);
1562 assert(dbi->dbi_rmw == NULL); /* db3: avoid "lost" cursors */
1565 fprintf(stderr, "*** RMW %s %p\n", tagName(rpmtag), dbi->dbi_rmw);
1567 assert(dbi->dbi_lastoffset == 0); /* db0: avoid "lost" cursors */
1569 dbi->dbi_lastoffset = 0; /* db0: rewind to beginning */
1571 if (rpmtag != RPMDBI_PACKAGES && keyp) {
1572 DBC * dbcursor = NULL;
1577 /* XXX HACK to get rpmdbFindByLabel out of the API */
1578 xx = dbiCopen(dbi, &dbcursor, 0);
1579 rc = dbiFindByLabel(dbi, dbcursor, keyp, &set);
1580 xx = dbiCclose(dbi, dbcursor, 0);
1582 } else if (rpmtag == RPMTAG_BASENAMES) {
1583 rc = rpmdbFindByFile(rpmdb, keyp, &set);
1585 xx = dbiCopen(dbi, &dbcursor, 0);
1586 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
1587 xx = dbiCclose(dbi, dbcursor, 0);
1590 if (rc) { /* error/not found */
1592 dbiFreeIndexSet(set);
1600 if (rpmtag != RPMDBI_PACKAGES && keylen == 0)
1601 keylen = strlen(keyp);
1602 k = xmalloc(keylen + 1);
1603 memcpy(k, keyp, keylen);
1604 k[keylen] = '\0'; /* XXX for strings */
1608 mi = xcalloc(sizeof(*mi), 1);
1610 mi->mi_keylen = keylen;
1612 mi->mi_rpmdb = rpmdb;
1613 mi->mi_rpmtag = rpmtag;
1620 mi->mi_modified = 0;
1621 mi->mi_prevoffset = 0;
1626 mi->mi_version = NULL;
1627 mi->mi_release = NULL;
1631 static INLINE int removeIndexEntry(dbiIndex dbi, DBC * dbcursor, const char * keyp,
1634 dbiIndexSet set = NULL;
1637 rc = dbiSearch(dbi, dbcursor, keyp, 0, &set);
1639 if (rc < 0) /* not found */
1641 else if (rc > 0) /* error */
1642 rc = 1; /* error message already generated from dbindex.c */
1643 else { /* success */
1644 if (!dbiPruneSet(set, rec, 1, sizeof(*rec), 1) &&
1645 dbiUpdateIndex(dbi, dbcursor, keyp, set))
1650 dbiFreeIndexSet(set);
1657 /* XXX install.c uninstall.c */
1658 int rpmdbRemove(rpmdb rpmdb, unsigned int hdrNum)
1661 sigset_t signalMask;
1664 h = rpmdbGetRecord(rpmdb, hdrNum);
1666 { rpmdbMatchIterator mi;
1667 mi = rpmdbInitIterator(rpmdb, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum));
1668 h = rpmdbNextIterator(mi);
1671 rpmdbFreeIterator(mi);
1675 rpmError(RPMERR_DBCORRUPT, _("%s: cannot read header at 0x%x"),
1676 "rpmdbRemove", hdrNum);
1680 { const char *n, *v, *r;
1681 headerNVR(h, &n, &v, &r);
1682 rpmMessage(RPMMESS_DEBUG, " --- %10d %s-%s-%s\n", hdrNum, n, v, r);
1685 blockSignals(rpmdb, &signalMask);
1688 dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
1690 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
1692 DBC * dbcursor = NULL;
1694 const char ** rpmvals = NULL;
1702 rpmtag = dbiTags[dbix];
1705 /* Filter out temporary databases */
1706 case RPMDBI_AVAILABLE:
1708 case RPMDBI_REMOVED:
1709 case RPMDBI_DEPENDS:
1711 /*@notreached@*/ break;
1712 case RPMDBI_PACKAGES:
1713 dbi = dbiOpen(rpmdb, rpmtag, 0);
1714 xx = dbiCopen(dbi, &dbcursor, 0);
1715 xx = dbiDel(dbi, dbcursor, &hdrNum, sizeof(hdrNum), 0);
1716 xx = dbiCclose(dbi, dbcursor, 0);
1718 /* XXX HACK sync is on the bt with multiple db access */
1719 if (!dbi->dbi_no_dbsync)
1720 xx = dbiSync(dbi, 0);
1722 /*@notreached@*/ break;
1725 if (!headerGetEntry(h, rpmtag, &rpmtype,
1726 (void **) &rpmvals, &rpmcnt)) {
1728 rpmMessage(RPMMESS_DEBUG, _("removing 0 %s entries.\n"),
1734 dbi = dbiOpen(rpmdb, rpmtag, 0);
1735 xx = dbiCopen(dbi, &dbcursor, 0);
1737 if (rpmtype == RPM_STRING_TYPE) {
1739 rpmMessage(RPMMESS_DEBUG, _("removing \"%s\" from %s index.\n"),
1740 (const char *)rpmvals, tagName(dbi->dbi_rpmtag));
1742 /* XXX force uniform headerGetEntry return */
1743 av[0] = (const char *) rpmvals;
1748 rpmMessage(RPMMESS_DEBUG, _("removing %d entries from %s index.\n"),
1749 rpmcnt, tagName(dbi->dbi_rpmtag));
1753 for (i = 0; i < rpmcnt; i++) {
1755 rpmMessage(RPMMESS_DEBUG, ("%6d %s\n"), i, rpmvals[i]);
1758 * This is almost right, but, if there are duplicate tag
1759 * values, there will be duplicate attempts to remove
1760 * the header instance. It's easier to just ignore errors
1761 * than to do things correctly.
1763 xx = removeIndexEntry(dbi, dbcursor, rpmvals[i], rec);
1766 xx = dbiCclose(dbi, dbcursor, 0);
1769 /* XXX HACK sync is on the bt with multiple db access */
1770 if (!dbi->dbi_no_dbsync)
1771 xx = dbiSync(dbi, 0);
1774 case RPM_STRING_ARRAY_TYPE:
1775 case RPM_I18NSTRING_TYPE:
1790 unblockSignals(rpmdb, &signalMask);
1797 static INLINE int addIndexEntry(dbiIndex dbi, DBC * dbcursor, const char *index, dbiIndexItem rec)
1799 dbiIndexSet set = NULL;
1802 rc = dbiSearch(dbi, dbcursor, index, 0, &set);
1807 if (rc < 0) { /* not found */
1809 set = xcalloc(1, sizeof(*set));
1811 dbiAppendSet(set, rec, 1, sizeof(*rec), 0);
1812 if (dbiUpdateIndex(dbi, dbcursor, index, set))
1817 dbiFreeIndexSet(set);
1825 int rpmdbAdd(rpmdb rpmdb, Header h)
1827 sigset_t signalMask;
1828 const char ** baseNames;
1833 unsigned int hdrNum;
1838 * If old style filename tags is requested, the basenames need to be
1839 * retrieved early, and the header needs to be converted before
1840 * being written to the package header database.
1843 headerGetEntry(h, RPMTAG_BASENAMES, &type, (void **) &baseNames, &count);
1848 blockSignals(rpmdb, &signalMask);
1851 unsigned int firstkey = 0;
1852 DBC * dbcursor = NULL;
1853 void * keyp = &firstkey;
1854 size_t keylen = sizeof(firstkey);
1855 void * datap = NULL;
1858 dbi = dbiOpen(rpmdb, RPMDBI_PACKAGES, 0);
1860 /* XXX db0: hack to pass sizeof header to fadAlloc */
1862 datalen = headerSizeof(h, HEADER_MAGIC_NO);
1864 xx = dbiCopen(dbi, &dbcursor, 0);
1866 /* Retrieve join key for next header instance. */
1868 rc = dbiGet(dbi, dbcursor, &keyp, &keylen, &datap, &datalen, 0);
1871 if (rc == 0 && datap)
1872 memcpy(&hdrNum, datap, sizeof(hdrNum));
1874 if (rc == 0 && datap) {
1875 memcpy(datap, &hdrNum, sizeof(hdrNum));
1878 datalen = sizeof(hdrNum);
1881 rc = dbiPut(dbi, dbcursor, keyp, keylen, datap, datalen, 0);
1882 xx = dbiSync(dbi, 0);
1884 xx = dbiCclose(dbi, dbcursor, 0);
1890 rpmError(RPMERR_DBCORRUPT, _("error(%d) allocating new package instance"), rc);
1894 /* Now update the indexes */
1896 { dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
1898 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
1899 DBC * dbcursor = NULL;
1901 const char **rpmvals = NULL;
1908 rpmtag = dbiTags[dbix];
1911 /* Filter out temporary databases */
1912 case RPMDBI_AVAILABLE:
1914 case RPMDBI_REMOVED:
1915 case RPMDBI_DEPENDS:
1917 /*@notreached@*/ break;
1918 case RPMDBI_PACKAGES:
1919 dbi = dbiOpen(rpmdb, rpmtag, 0);
1920 xx = dbiCopen(dbi, &dbcursor, 0);
1921 xx = dbiUpdateRecord(dbi, dbcursor, hdrNum, h);
1922 xx = dbiCclose(dbi, dbcursor, 0);
1924 if (!dbi->dbi_no_dbsync)
1925 xx = dbiSync(dbi, 0);
1926 { const char *n, *v, *r;
1927 headerNVR(h, &n, &v, &r);
1928 rpmMessage(RPMMESS_DEBUG, " +++ %10d %s-%s-%s\n", hdrNum, n, v, r);
1931 /*@notreached@*/ break;
1932 /* XXX preserve legacy behavior */
1933 case RPMTAG_BASENAMES:
1935 rpmvals = baseNames;
1939 headerGetEntry(h, rpmtag, &rpmtype,
1940 (void **) &rpmvals, &rpmcnt);
1945 if (rpmtag != RPMTAG_GROUP) {
1947 rpmMessage(RPMMESS_DEBUG, _("adding 0 %s entries.\n"),
1953 /* XXX preserve legacy behavior */
1954 rpmtype = RPM_STRING_TYPE;
1955 rpmvals = (const char **) "Unknown";
1959 dbi = dbiOpen(rpmdb, rpmtag, 0);
1961 xx = dbiCopen(dbi, &dbcursor, 0);
1962 if (rpmtype == RPM_STRING_TYPE) {
1963 rpmMessage(RPMMESS_DEBUG, _("adding \"%s\" to %s index.\n"),
1964 (const char *)rpmvals, tagName(dbi->dbi_rpmtag));
1966 /* XXX force uniform headerGetEntry return */
1967 av[0] = (const char *) rpmvals;
1972 rpmMessage(RPMMESS_DEBUG, _("adding %d entries to %s index.\n"),
1973 rpmcnt, tagName(dbi->dbi_rpmtag));
1977 for (i = 0; i < rpmcnt; i++) {
1979 rpmMessage(RPMMESS_DEBUG, ("%6d %s\n"), i, rpmvals[i]);
1983 * Include the tagNum in all indices. rpm-3.0.4 and earlier
1984 * included the tagNum only for files.
1986 switch (dbi->dbi_rpmtag) {
1987 case RPMTAG_TRIGGERNAME:
1988 if (i) { /* don't add duplicates */
1989 for (j = 0; j < i; j++) {
1990 if (!strcmp(rpmvals[i], rpmvals[j]))
2002 rc += addIndexEntry(dbi, dbcursor, rpmvals[i], rec);
2004 xx = dbiCclose(dbi, dbcursor, 0);
2007 /* XXX HACK sync is on the bt with multiple db access */
2008 if (!dbi->dbi_no_dbsync)
2009 xx = dbiSync(dbi, 0);
2012 case RPM_STRING_ARRAY_TYPE:
2013 case RPM_I18NSTRING_TYPE:
2029 unblockSignals(rpmdb, &signalMask);
2034 /* XXX transaction.c */
2035 int rpmdbFindFpList(rpmdb rpmdb, fingerPrint * fpList, dbiIndexSet * matchList,
2038 rpmdbMatchIterator mi;
2039 fingerPrintCache fpc;
2043 mi = rpmdbInitIterator(rpmdb, RPMTAG_BASENAMES, NULL, 0);
2045 /* Gather all matches from the database */
2046 for (i = 0; i < numItems; i++) {
2047 rpmdbGrowIterator(mi, fpList[i].baseName, 0, i);
2048 matchList[i] = xcalloc(1, sizeof(*(matchList[i])));
2051 if ((i = rpmdbGetIteratorCount(mi)) == 0) {
2052 rpmdbFreeIterator(mi);
2055 fpc = fpCacheCreate(i);
2057 rpmdbSortIterator(mi);
2058 /* iterator is now sorted by (recnum, filenum) */
2060 /* For each set of files matched in a package ... */
2061 while ((h = rpmdbNextIterator(mi)) != NULL) {
2062 const char ** dirNames;
2063 const char ** baseNames;
2064 const char ** fullBaseNames;
2065 int_32 * dirIndexes;
2066 int_32 * fullDirIndexes;
2073 start = mi->mi_setx - 1;
2074 im = mi->mi_set->recs + start;
2076 /* Find the end of the set of matched files in this package. */
2077 for (end = start + 1; end < mi->mi_set->count; end++) {
2078 if (im->hdrNum != mi->mi_set->recs[end].hdrNum)
2083 /* Compute fingerprints for this header's matches */
2084 headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
2085 (void **) &dirNames, NULL);
2086 headerGetEntryMinMemory(h, RPMTAG_BASENAMES, NULL,
2087 (void **) &fullBaseNames, NULL);
2088 headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
2089 (void **) &fullDirIndexes, NULL);
2091 baseNames = xcalloc(num, sizeof(*baseNames));
2092 dirIndexes = xcalloc(num, sizeof(*dirIndexes));
2093 for (i = 0; i < num; i++) {
2094 baseNames[i] = fullBaseNames[im[i].tagNum];
2095 dirIndexes[i] = fullDirIndexes[im[i].tagNum];
2098 fps = xcalloc(num, sizeof(*fps));
2099 fpLookupList(fpc, dirNames, baseNames, dirIndexes, num, fps);
2101 /* Add db (recnum,filenum) to list for fingerprint matches. */
2102 for (i = 0; i < num; i++, im++) {
2103 if (FP_EQUAL(fps[i], fpList[im->fpNum]))
2104 dbiAppendSet(matchList[im->fpNum], im, 1, sizeof(*im), 0);
2109 free(fullBaseNames);
2116 rpmdbFreeIterator(mi);
2124 static int rpmdbRemoveDatabase(const char * rootdir,
2125 const char * dbpath, int _dbapi)
2132 if (dbpath[i - 1] != '/') {
2133 filename = alloca(i);
2134 strcpy(filename, dbpath);
2136 filename[i + 1] = '\0';
2140 filename = alloca(strlen(rootdir) + strlen(dbpath) + 40);
2144 for (i = 0; i < dbiTagsMax; i++) {
2145 const char * base = tagName(dbiTags[i]);
2146 sprintf(filename, "%s/%s/%s", rootdir, dbpath, base);
2147 (void)rpmCleanPath(filename);
2148 xx = unlink(filename);
2150 for (i = 0; i < 16; i++) {
2151 sprintf(filename, "%s/%s/__db.%03d", rootdir, dbpath, i);
2152 (void)rpmCleanPath(filename);
2153 xx = unlink(filename);
2159 for (i = 0; i < dbiTagsMax; i++) {
2160 const char * base = db1basename(dbiTags[i]);
2161 sprintf(filename, "%s/%s/%s", rootdir, dbpath, base);
2162 (void)rpmCleanPath(filename);
2163 xx = unlink(filename);
2169 sprintf(filename, "%s/%s", rootdir, dbpath);
2170 (void)rpmCleanPath(filename);
2171 xx = rmdir(filename);
2176 static int rpmdbMoveDatabase(const char * rootdir,
2177 const char * olddbpath, int _olddbapi,
2178 const char * newdbpath, int _newdbapi)
2181 char * ofilename, * nfilename;
2185 i = strlen(olddbpath);
2186 if (olddbpath[i - 1] != '/') {
2187 ofilename = alloca(i + 2);
2188 strcpy(ofilename, olddbpath);
2190 ofilename[i + 1] = '\0';
2191 olddbpath = ofilename;
2194 i = strlen(newdbpath);
2195 if (newdbpath[i - 1] != '/') {
2196 nfilename = alloca(i + 2);
2197 strcpy(nfilename, newdbpath);
2199 nfilename[i + 1] = '\0';
2200 newdbpath = nfilename;
2203 ofilename = alloca(strlen(rootdir) + strlen(olddbpath) + 40);
2204 nfilename = alloca(strlen(rootdir) + strlen(newdbpath) + 40);
2206 switch (_olddbapi) {
2208 for (i = 0; i < dbiTagsMax; i++) {
2212 /* Filter out temporary databases */
2213 switch ((rpmtag = dbiTags[i])) {
2214 case RPMDBI_AVAILABLE:
2216 case RPMDBI_REMOVED:
2217 case RPMDBI_DEPENDS:
2219 /*@notreached@*/ break;
2224 base = tagName(rpmtag);
2225 sprintf(ofilename, "%s/%s/%s", rootdir, olddbpath, base);
2226 (void)rpmCleanPath(ofilename);
2227 if (!rpmfileexists(ofilename))
2229 sprintf(nfilename, "%s/%s/%s", rootdir, newdbpath, base);
2230 (void)rpmCleanPath(nfilename);
2231 if ((xx = Rename(ofilename, nfilename)) != 0)
2234 for (i = 0; i < 16; i++) {
2235 sprintf(ofilename, "%s/%s/__db.%03d", rootdir, olddbpath, i);
2236 (void)rpmCleanPath(ofilename);
2237 if (!rpmfileexists(ofilename))
2239 sprintf(nfilename, "%s/%s/__db.%03d", rootdir, newdbpath, i);
2240 (void)rpmCleanPath(nfilename);
2241 if ((xx = Rename(ofilename, nfilename)) != 0)
2248 for (i = 0; i < dbiTagsMax; i++) {
2252 /* Filter out temporary databases */
2253 switch ((rpmtag = dbiTags[i])) {
2254 case RPMDBI_AVAILABLE:
2256 case RPMDBI_REMOVED:
2257 case RPMDBI_DEPENDS:
2259 /*@notreached@*/ break;
2264 base = db1basename(rpmtag);
2265 sprintf(ofilename, "%s/%s/%s", rootdir, olddbpath, base);
2266 (void)rpmCleanPath(ofilename);
2267 if (!rpmfileexists(ofilename))
2269 sprintf(nfilename, "%s/%s/%s", rootdir, newdbpath, base);
2270 (void)rpmCleanPath(nfilename);
2271 if ((xx = Rename(ofilename, nfilename)) != 0)
2277 if (rc || _olddbapi == _newdbapi)
2280 rc = rpmdbRemoveDatabase(rootdir, newdbpath, _newdbapi);
2284 int rpmdbRebuild(const char * rootdir)
2287 const char * dbpath = NULL;
2288 const char * rootdbpath = NULL;
2290 const char * newdbpath = NULL;
2291 const char * newrootdbpath = NULL;
2300 _dbapi = rpmExpandNumeric("%{_dbapi}");
2301 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
2303 tfn = rpmGetPath("%{_dbpath}", NULL);
2304 if (!(tfn && tfn[0] != '%')) {
2305 rpmMessage(RPMMESS_DEBUG, _("no dbpath has been set"));
2309 dbpath = rootdbpath = rpmGetPath(rootdir, tfn, NULL);
2310 if (!(rootdir[0] == '/' && rootdir[1] == '\0'))
2311 dbpath += strlen(rootdir);
2314 tfn = rpmGetPath("%{_dbpath_rebuild}", NULL);
2315 if (!(tfn && tfn[0] != '%' && strcmp(tfn, dbpath))) {
2318 sprintf(pidbuf, "rebuilddb.%d", (int) getpid());
2319 t = xmalloc(strlen(dbpath) + strlen(pidbuf) + 1);
2320 (void)stpcpy(stpcpy(t, dbpath), pidbuf);
2321 if (tfn) xfree(tfn);
2325 newdbpath = newrootdbpath = rpmGetPath(rootdir, tfn, NULL);
2326 if (!(rootdir[0] == '/' && rootdir[1] == '\0'))
2327 newdbpath += strlen(rootdir);
2330 rpmMessage(RPMMESS_DEBUG, _("rebuilding database %s into %s\n"),
2331 rootdbpath, newrootdbpath);
2333 if (!access(newrootdbpath, F_OK)) {
2334 rpmError(RPMERR_MKDIR, _("temporary database %s already exists"),
2340 rpmMessage(RPMMESS_DEBUG, _("creating directory %s\n"), newrootdbpath);
2341 if (Mkdir(newrootdbpath, 0755)) {
2342 rpmError(RPMERR_MKDIR, _("error creating directory %s: %s"),
2343 newrootdbpath, strerror(errno));
2349 rpmMessage(RPMMESS_DEBUG, _("opening old database with dbapi %d\n"),
2351 _rebuildinprogress = 1;
2352 if (openDatabase(rootdir, dbpath, _dbapi, &olddb, O_RDONLY, 0644,
2353 RPMDB_FLAG_MINIMAL)) {
2357 _dbapi = olddb->db_api;
2358 _rebuildinprogress = 0;
2360 rpmMessage(RPMMESS_DEBUG, _("opening new database with dbapi %d\n"),
2362 if (openDatabase(rootdir, newdbpath, _dbapi_rebuild, &newdb, O_RDWR | O_CREAT, 0644, 0)) {
2366 _dbapi_rebuild = newdb->db_api;
2369 rpmdbMatchIterator mi;
2370 #define _RECNUM rpmdbGetIteratorOffset(mi)
2372 /* RPMDBI_PACKAGES */
2373 mi = rpmdbInitIterator(olddb, RPMDBI_PACKAGES, NULL, 0);
2374 while ((h = rpmdbNextIterator(mi)) != NULL) {
2376 /* let's sanity check this record a bit, otherwise just skip it */
2377 if (!(headerIsEntry(h, RPMTAG_NAME) &&
2378 headerIsEntry(h, RPMTAG_VERSION) &&
2379 headerIsEntry(h, RPMTAG_RELEASE) &&
2380 headerIsEntry(h, RPMTAG_BUILDTIME)))
2382 rpmError(RPMERR_INTERNAL,
2383 _("record number %d in database is bad -- skipping."),
2388 /* Filter duplicate entries ? (bug in pre rpm-3.0.4) */
2389 if (newdb->db_filter_dups) {
2390 const char * name, * version, * release;
2393 headerNVR(h, &name, &version, &release);
2395 { rpmdbMatchIterator mi;
2396 mi = rpmdbInitIterator(newdb, RPMTAG_NAME, name, 0);
2397 rpmdbSetIteratorVersion(mi, version);
2398 rpmdbSetIteratorRelease(mi, release);
2399 while (rpmdbNextIterator(mi)) {
2403 rpmdbFreeIterator(mi);
2410 /* Retrofit "Provide: name = EVR" for binary packages. */
2411 providePackageNVR(h);
2413 if (rpmdbAdd(newdb, h)) {
2414 rpmError(RPMERR_INTERNAL,
2415 _("cannot add record originally at %d"), _RECNUM);
2421 rpmdbFreeIterator(mi);
2426 olddb->db_remove_env = 1;
2427 newdb->db_remove_env = 1;
2433 rpmMessage(RPMMESS_NORMAL, _("failed to rebuild database: original database "
2434 "remains in place\n"));
2436 rpmdbRemoveDatabase(rootdir, newdbpath, _dbapi_rebuild);
2439 } else if (!nocleanup) {
2440 if (rpmdbMoveDatabase(rootdir, newdbpath, _dbapi_rebuild, dbpath, _dbapi)) {
2441 rpmMessage(RPMMESS_ERROR, _("failed to replace old database with new "
2443 rpmMessage(RPMMESS_ERROR, _("replace files in %s with files from %s "
2444 "to recover"), dbpath, newdbpath);
2452 if (removedir && !(rc == 0 && nocleanup)) {
2453 rpmMessage(RPMMESS_DEBUG, _("removing directory %s\n"), newrootdbpath);
2454 if (Rmdir(newrootdbpath))
2455 rpmMessage(RPMMESS_ERROR, _("failed to remove directory %s: %s\n"),
2456 newrootdbpath, strerror(errno));
2458 if (newrootdbpath) xfree(newrootdbpath);
2459 if (rootdbpath) xfree(rootdbpath);