00001
00005 #include "system.h"
00006
00007 #define _USE_COPY_LOAD
00008
00009 #include <sys/file.h>
00010
00011 #ifndef DYING
00012
00013 #include <fnmatch.h>
00014
00015 #if defined(__LCLINT__)
00016
00017 extern int fnmatch (const char *__pattern, const char *__name, int __flags)
00018 ;
00019
00020 #endif
00021 #endif
00022
00023 #include <regex.h>
00024 #if defined(__LCLINT__)
00025
00026 extern void regfree ( regex_t *preg)
00027 ;
00028
00029 #endif
00030
00031 #include <rpmio_internal.h>
00032 #include <rpmmacro.h>
00033 #include <rpmsq.h>
00034
00035 #include "rpmdb.h"
00036 #include "fprint.h"
00037 #include "legacy.h"
00038 #include "header_internal.h"
00039 #include "debug.h"
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 int _rpmdb_debug = 0;
00050
00051
00052 static int _rebuildinprogress = 0;
00053
00054 static int _db_filter_dups = 0;
00055
00056 #define _DBI_FLAGS 0
00057 #define _DBI_PERMS 0644
00058 #define _DBI_MAJOR -1
00059
00060
00061 int * dbiTags = NULL;
00062
00063 int dbiTagsMax = 0;
00064
00065
00066
00067
00068
00069 unsigned int myinstall_instance = 0;
00070
00071
00072
00073 typedef unsigned int __pbm_bits;
00074
00075 #define __PBM_NBITS (8 * sizeof (__pbm_bits))
00076 #define __PBM_IX(d) ((d) / __PBM_NBITS)
00077 #define __PBM_MASK(d) ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS))
00078
00079 typedef struct {
00080 __pbm_bits bits[1];
00081 } pbm_set;
00082
00083 #define __PBM_BITS(set) ((set)->bits)
00084
00085 #define PBM_FREE(s) _free(s);
00086 #define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d))
00087 #define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d))
00088 #define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0)
00089
00090 #define PBM_ALLOC(d) xcalloc(__PBM_IX (d) + 1, sizeof(__pbm_bits))
00091
00098
00099 static inline pbm_set * PBM_REALLOC(pbm_set ** sp, int * odp, int nd)
00100
00101 {
00102 int i, nb;
00103
00104
00105 if (nd > (*odp)) {
00106 nd *= 2;
00107 nb = __PBM_IX(nd) + 1;
00108
00109 *sp = xrealloc(*sp, nb * sizeof(__pbm_bits));
00110
00111 for (i = __PBM_IX(*odp) + 1; i < nb; i++)
00112 __PBM_BITS(*sp)[i] = 0;
00113 *odp = nd;
00114 }
00115
00116
00117 return *sp;
00118
00119 }
00120
00126 static inline unsigned char nibble(char c)
00127
00128 {
00129 if (c >= '0' && c <= '9')
00130 return (c - '0');
00131 if (c >= 'A' && c <= 'F')
00132 return (c - 'A') + 10;
00133 if (c >= 'a' && c <= 'f')
00134 return (c - 'a') + 10;
00135 return 0;
00136 }
00137
00138 #ifdef DYING
00139
00145 static int printable(const void * ptr, size_t len)
00146 {
00147 const char * s = ptr;
00148 int i;
00149 for (i = 0; i < len; i++, s++)
00150 if (!(*s >= ' ' && *s <= '~')) return 0;
00151 return 1;
00152 }
00153 #endif
00154
00160 static int dbiTagToDbix(int rpmtag)
00161
00162 {
00163 int dbix;
00164
00165 if (dbiTags != NULL)
00166 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
00167
00168 if (rpmtag == dbiTags[dbix])
00169 return dbix;
00170
00171 }
00172 return -1;
00173 }
00174
00178 static void dbiTagsInit(void)
00179
00180
00181 {
00182
00183 static const char * const _dbiTagStr_default =
00184 "Packages:Name:Basenames:Group:Requirename:Providename:Conflictname:Triggername:Dirnames:Requireversion:Provideversion:Installtid:Sigmd5:Sha1header:Filemd5s:Depends:Pubkeys";
00185 char * dbiTagStr = NULL;
00186 char * o, * oe;
00187 int rpmtag;
00188
00189 dbiTagStr = rpmExpand("%{?_dbi_tags}", NULL);
00190 if (!(dbiTagStr && *dbiTagStr)) {
00191 dbiTagStr = _free(dbiTagStr);
00192 dbiTagStr = xstrdup(_dbiTagStr_default);
00193 }
00194
00195
00196 dbiTags = _free(dbiTags);
00197 dbiTagsMax = 0;
00198
00199
00200 dbiTags = xcalloc(1, sizeof(*dbiTags));
00201 dbiTags[dbiTagsMax++] = RPMDBI_PACKAGES;
00202
00203 for (o = dbiTagStr; o && *o; o = oe) {
00204 while (*o && xisspace(*o))
00205 o++;
00206 if (*o == '\0')
00207 break;
00208 for (oe = o; oe && *oe; oe++) {
00209 if (xisspace(*oe))
00210 break;
00211 if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/'))
00212 break;
00213 }
00214 if (oe && *oe)
00215 *oe++ = '\0';
00216 rpmtag = tagValue(o);
00217 if (rpmtag < 0) {
00218 rpmMessage(RPMMESS_WARNING,
00219 _("dbiTagsInit: unrecognized tag name: \"%s\" ignored\n"), o);
00220 continue;
00221 }
00222 if (dbiTagToDbix(rpmtag) >= 0)
00223 continue;
00224
00225 dbiTags = xrealloc(dbiTags, (dbiTagsMax + 1) * sizeof(*dbiTags));
00226 dbiTags[dbiTagsMax++] = rpmtag;
00227 }
00228
00229 dbiTagStr = _free(dbiTagStr);
00230 }
00231
00232
00233 #define DB1vec NULL
00234 #define DB2vec NULL
00235
00236 #ifdef HAVE_DB3_DB_H
00237
00238
00239 extern struct _dbiVec db3vec;
00240
00241 #define DB3vec &db3vec
00242
00243 #else
00244 #define DB3vec NULL
00245 #endif
00246
00247 #ifdef HAVE_SQLITE3_H
00248
00249
00250 extern struct _dbiVec sqlitevec;
00251
00252 #define SQLITEvec &sqlitevec
00253
00254 #else
00255 #define SQLITEvec NULL
00256 #endif
00257
00258
00259
00260 static struct _dbiVec *mydbvecs[] = {
00261 DB1vec, DB1vec, DB2vec, DB3vec, SQLITEvec, NULL
00262 };
00263
00264
00265 dbiIndex dbiOpen(rpmdb db, rpmTag rpmtag, unsigned int flags)
00266 {
00267 int dbix;
00268 dbiIndex dbi = NULL;
00269 int _dbapi, _dbapi_rebuild, _dbapi_wanted;
00270 int rc = 0;
00271
00272 if (db == NULL)
00273 return NULL;
00274
00275 dbix = dbiTagToDbix(rpmtag);
00276 if (dbix < 0 || dbix >= dbiTagsMax)
00277 return NULL;
00278
00279
00280
00281 if ((dbi = db->_dbi[dbix]) != NULL)
00282 return dbi;
00283
00284
00285 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
00286 if (_dbapi_rebuild < 1 || _dbapi_rebuild > 4)
00287 _dbapi_rebuild = 4;
00288
00289 _dbapi_wanted = (_rebuildinprogress ? _dbapi_rebuild : db->db_api);
00290
00291 switch (_dbapi_wanted) {
00292 default:
00293 _dbapi = _dbapi_wanted;
00294 if (_dbapi < 0 || _dbapi >= 5 || mydbvecs[_dbapi] == NULL) {
00295 rpmMessage(RPMMESS_DEBUG, "dbiOpen: _dbiapi failed\n");
00296 return NULL;
00297 }
00298 errno = 0;
00299 dbi = NULL;
00300 rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi);
00301 if (rc) {
00302 static int _printed[32];
00303 if (!_printed[dbix & 0x1f]++)
00304 rpmError(RPMERR_DBOPEN,
00305 _("cannot open %s index using db%d - %s (%d)\n"),
00306 tagName(rpmtag), _dbapi,
00307 (rc > 0 ? strerror(rc) : ""), rc);
00308 _dbapi = -1;
00309 }
00310 break;
00311 case -1:
00312 _dbapi = 5;
00313 while (_dbapi-- > 1) {
00314 if (mydbvecs[_dbapi] == NULL)
00315 continue;
00316 errno = 0;
00317 dbi = NULL;
00318 rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi);
00319 if (rc == 0 && dbi)
00320 break;
00321 }
00322 if (_dbapi <= 0) {
00323 static int _printed[32];
00324 if (!_printed[dbix & 0x1f]++)
00325 rpmError(RPMERR_DBOPEN, _("cannot open %s index\n"),
00326 tagName(rpmtag));
00327 rc = 1;
00328 goto exit;
00329 }
00330 if (db->db_api == -1 && _dbapi > 0)
00331 db->db_api = _dbapi;
00332 break;
00333 }
00334
00335
00336 #define SQLITE_HACK
00337 #ifdef SQLITE_HACK_XXX
00338
00339 if (rc && _dbapi_wanted >= 0 && _dbapi != _dbapi_wanted && _dbapi_wanted == _dbapi_rebuild) {
00340 rc = (_rebuildinprogress ? 0 : 1);
00341 goto exit;
00342 }
00343
00344
00345 if (_dbapi_wanted >= 0 && _dbapi != _dbapi_wanted) {
00346 rc = 1;
00347 goto exit;
00348 }
00349
00350
00351 if (_dbapi_wanted < 0 && _dbapi != _dbapi_rebuild) {
00352 rc = (_rebuildinprogress ? 0 : 1);
00353 goto exit;
00354 }
00355 #endif
00356
00357 exit:
00358 if (dbi != NULL && rc == 0) {
00359 db->_dbi[dbix] = dbi;
00360
00361 if (rpmtag == RPMDBI_PACKAGES && db->db_bits == NULL) {
00362 db->db_nbits = 1024;
00363 if (!dbiStat(dbi, DB_FAST_STAT)) {
00364 DB_HASH_STAT * hash = (DB_HASH_STAT *)dbi->dbi_stats;
00365 if (hash)
00366 db->db_nbits += hash->hash_nkeys;
00367 }
00368 db->db_bits = PBM_ALLOC(db->db_nbits);
00369 }
00370
00371 }
00372 #ifdef HAVE_DB3_DB_H
00373 else
00374 dbi = db3Free(dbi);
00375 #endif
00376
00377
00378 return dbi;
00379
00380 }
00381
00388 static dbiIndexItem dbiIndexNewItem(unsigned int hdrNum, unsigned int tagNum)
00389
00390 {
00391 dbiIndexItem rec = xcalloc(1, sizeof(*rec));
00392 rec->hdrNum = hdrNum;
00393 rec->tagNum = tagNum;
00394 return rec;
00395 }
00396
00397 union _dbswap {
00398 unsigned int ui;
00399 unsigned char uc[4];
00400 };
00401
00402 #define _DBSWAP(_a) \
00403 \
00404 { unsigned char _b, *_c = (_a).uc; \
00405 _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
00406 _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
00407 \
00408 }
00409
00410
00411
00412
00413
00414
00415 static inline void dbiGrowSet(dbiIndexSet set, unsigned int nrecs)
00416 {
00417 size_t need = (set->count + nrecs) * sizeof(*(set->recs));
00418 size_t alloced = set->alloced ? set->alloced : 1 << 4;
00419
00420 while (alloced < need)
00421 alloced <<= 1;
00422
00423 if (alloced != set->alloced) {
00424 set->recs = xrealloc(set->recs, alloced);
00425 set->alloced = alloced;
00426 }
00427 }
00428
00436 static int dbt2set(dbiIndex dbi, DBT * data, dbiIndexSet * setp)
00437
00438 {
00439 int _dbbyteswapped = dbiByteSwapped(dbi);
00440 const char * sdbir;
00441 dbiIndexSet set;
00442 int i;
00443
00444 if (dbi == NULL || data == NULL || setp == NULL)
00445 return -1;
00446
00447 if ((sdbir = data->data) == NULL) {
00448 *setp = NULL;
00449 return 0;
00450 }
00451
00452 set = xcalloc(1, sizeof(*set));
00453 dbiGrowSet(set, data->size / dbi->dbi_jlen);
00454 set->count = data->size / dbi->dbi_jlen;
00455
00456
00457 switch (dbi->dbi_jlen) {
00458 default:
00459 case 2*sizeof(int_32):
00460 for (i = 0; i < set->count; i++) {
00461 union _dbswap hdrNum, tagNum;
00462
00463 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
00464 sdbir += sizeof(hdrNum.ui);
00465 memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
00466 sdbir += sizeof(tagNum.ui);
00467 if (_dbbyteswapped) {
00468 _DBSWAP(hdrNum);
00469 _DBSWAP(tagNum);
00470 }
00471 set->recs[i].hdrNum = hdrNum.ui;
00472 set->recs[i].tagNum = tagNum.ui;
00473 set->recs[i].fpNum = 0;
00474 }
00475 break;
00476 case 1*sizeof(int_32):
00477 for (i = 0; i < set->count; i++) {
00478 union _dbswap hdrNum;
00479
00480 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
00481 sdbir += sizeof(hdrNum.ui);
00482 if (_dbbyteswapped) {
00483 _DBSWAP(hdrNum);
00484 }
00485 set->recs[i].hdrNum = hdrNum.ui;
00486 set->recs[i].tagNum = 0;
00487 set->recs[i].fpNum = 0;
00488 }
00489 break;
00490 }
00491 *setp = set;
00492
00493
00494 return 0;
00495
00496 }
00497
00505 static int set2dbt(dbiIndex dbi, DBT * data, dbiIndexSet set)
00506
00507 {
00508 int _dbbyteswapped = dbiByteSwapped(dbi);
00509 char * tdbir;
00510 int i;
00511
00512 if (dbi == NULL || data == NULL || set == NULL)
00513 return -1;
00514
00515 data->size = set->count * (dbi->dbi_jlen);
00516 if (data->size == 0) {
00517 data->data = NULL;
00518 return 0;
00519 }
00520 tdbir = data->data = xmalloc(data->size);
00521
00522
00523 switch (dbi->dbi_jlen) {
00524 default:
00525 case 2*sizeof(int_32):
00526 for (i = 0; i < set->count; i++) {
00527 union _dbswap hdrNum, tagNum;
00528
00529 memset(&hdrNum, 0, sizeof(hdrNum));
00530 memset(&tagNum, 0, sizeof(tagNum));
00531 hdrNum.ui = set->recs[i].hdrNum;
00532 tagNum.ui = set->recs[i].tagNum;
00533 if (_dbbyteswapped) {
00534 _DBSWAP(hdrNum);
00535 _DBSWAP(tagNum);
00536 }
00537 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
00538 tdbir += sizeof(hdrNum.ui);
00539 memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
00540 tdbir += sizeof(tagNum.ui);
00541 }
00542 break;
00543 case 1*sizeof(int_32):
00544 for (i = 0; i < set->count; i++) {
00545 union _dbswap hdrNum;
00546
00547 memset(&hdrNum, 0, sizeof(hdrNum));
00548 hdrNum.ui = set->recs[i].hdrNum;
00549 if (_dbbyteswapped) {
00550 _DBSWAP(hdrNum);
00551 }
00552 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
00553 tdbir += sizeof(hdrNum.ui);
00554 }
00555 break;
00556 }
00557
00558
00559
00560 return 0;
00561
00562 }
00563
00564
00565 static int hdrNumCmp(const void * one, const void * two)
00566
00567 {
00568 const int * a = one, * b = two;
00569 return (*a - *b);
00570 }
00571
00581 static int dbiAppendSet(dbiIndexSet set, const void * recs,
00582 int nrecs, size_t recsize, int sortset)
00583
00584 {
00585 const char * rptr = recs;
00586 size_t rlen = (recsize < sizeof(*(set->recs)))
00587 ? recsize : sizeof(*(set->recs));
00588
00589 if (set == NULL || recs == NULL || nrecs <= 0 || recsize == 0)
00590 return 1;
00591
00592 dbiGrowSet(set, nrecs);
00593 memset(set->recs + set->count, 0, nrecs * sizeof(*(set->recs)));
00594
00595 while (nrecs-- > 0) {
00596
00597 memcpy(set->recs + set->count, rptr, rlen);
00598
00599 rptr += recsize;
00600 set->count++;
00601 }
00602
00603 if (sortset && set->count > 1)
00604 qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
00605
00606 return 0;
00607 }
00608
00618 static int dbiPruneSet(dbiIndexSet set, void * recs, int nrecs,
00619 size_t recsize, int sorted)
00620
00621 {
00622 int from;
00623 int to = 0;
00624 int num = set->count;
00625 int numCopied = 0;
00626
00627 assert(set->count > 0);
00628 if (nrecs > 1 && !sorted)
00629 qsort(recs, nrecs, recsize, hdrNumCmp);
00630
00631 for (from = 0; from < num; from++) {
00632 if (bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) {
00633 set->count--;
00634 continue;
00635 }
00636 if (from != to)
00637 set->recs[to] = set->recs[from];
00638 to++;
00639 numCopied++;
00640 }
00641 return (numCopied == num);
00642 }
00643
00644
00645 unsigned int dbiIndexSetCount(dbiIndexSet set) {
00646 return set->count;
00647 }
00648
00649
00650 unsigned int dbiIndexRecordOffset(dbiIndexSet set, int recno) {
00651 return set->recs[recno].hdrNum;
00652 }
00653
00654
00655 unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, int recno) {
00656 return set->recs[recno].tagNum;
00657 }
00658
00659
00660 dbiIndexSet dbiFreeIndexSet(dbiIndexSet set) {
00661 if (set) {
00662 set->recs = _free(set->recs);
00663 set = _free(set);
00664 }
00665 return set;
00666 }
00667
00668 typedef struct miRE_s {
00669 rpmTag tag;
00670 rpmMireMode mode;
00671
00672 const char * pattern;
00673 int notmatch;
00674
00675 regex_t * preg;
00676 int cflags;
00677 int eflags;
00678 int fnflags;
00679 } * miRE;
00680
00681 struct _rpmdbMatchIterator {
00682
00683 rpmdbMatchIterator mi_next;
00684
00685 const void * mi_keyp;
00686 size_t mi_keylen;
00687
00688 rpmdb mi_db;
00689 rpmTag mi_rpmtag;
00690 dbiIndexSet mi_set;
00691 DBC * mi_dbc;
00692 DBT mi_key;
00693 DBT mi_data;
00694 int mi_setx;
00695
00696 Header mi_h;
00697 int mi_sorted;
00698 int mi_cflags;
00699 int mi_modified;
00700 unsigned int mi_prevoffset;
00701 unsigned int mi_offset;
00702 unsigned int mi_filenum;
00703 int mi_nre;
00704
00705 miRE mi_re;
00706
00707 rpmts mi_ts;
00708
00709 rpmRC (*mi_hdrchk) (rpmts ts, const void * uh, size_t uc, const char ** msg)
00710 ;
00711
00712 };
00713
00714
00715 static rpmdb rpmdbRock;
00716
00717
00718 static rpmdbMatchIterator rpmmiRock;
00719
00720 int rpmdbCheckTerminate(int terminate)
00721
00722
00723 {
00724 sigset_t newMask, oldMask;
00725 static int terminating = 0;
00726
00727 if (terminating) return 1;
00728
00729 (void) sigfillset(&newMask);
00730 (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
00731
00732 if (sigismember(&rpmsqCaught, SIGINT)
00733 || sigismember(&rpmsqCaught, SIGQUIT)
00734 || sigismember(&rpmsqCaught, SIGHUP)
00735 || sigismember(&rpmsqCaught, SIGTERM)
00736 || sigismember(&rpmsqCaught, SIGPIPE)
00737 || terminate)
00738 terminating = 1;
00739
00740 if (terminating) {
00741 rpmdb db;
00742 rpmdbMatchIterator mi;
00743
00744
00745 while ((mi = rpmmiRock) != NULL) {
00746 rpmmiRock = mi->mi_next;
00747 mi->mi_next = NULL;
00748 mi = rpmdbFreeIterator(mi);
00749 }
00750
00751
00752
00753 while ((db = rpmdbRock) != NULL) {
00754 rpmdbRock = db->db_next;
00755 db->db_next = NULL;
00756 (void) rpmdbClose(db);
00757 }
00758
00759 }
00760 sigprocmask(SIG_SETMASK, &oldMask, NULL);
00761 return terminating;
00762 }
00763
00764 int rpmdbCheckSignals(void)
00765 {
00766 if (rpmdbCheckTerminate(0)) {
00767
00768 rpmMessage(RPMMESS_DEBUG, "Exiting on signal(0x%lx) ...\n", *((unsigned long *)&rpmsqCaught));
00769 exit(EXIT_FAILURE);
00770
00771 }
00772 return 0;
00773 }
00774
00778 static int blockSignals( rpmdb db, sigset_t * oldMask)
00779
00780
00781 {
00782 sigset_t newMask;
00783
00784 (void) sigfillset(&newMask);
00785 (void) sigprocmask(SIG_BLOCK, &newMask, oldMask);
00786 (void) sigdelset(&newMask, SIGINT);
00787 (void) sigdelset(&newMask, SIGQUIT);
00788 (void) sigdelset(&newMask, SIGHUP);
00789 (void) sigdelset(&newMask, SIGTERM);
00790 (void) sigdelset(&newMask, SIGPIPE);
00791 return sigprocmask(SIG_BLOCK, &newMask, NULL);
00792 }
00793
00797
00798 static int unblockSignals( rpmdb db, sigset_t * oldMask)
00799
00800
00801 {
00802 (void) rpmdbCheckSignals();
00803 return sigprocmask(SIG_SETMASK, oldMask, NULL);
00804 }
00805
00806 #define _DB_ROOT "/"
00807 #define _DB_HOME "%{_dbpath}"
00808 #define _DB_FLAGS 0
00809 #define _DB_MODE 0
00810 #define _DB_PERMS 0644
00811
00812 #define _DB_MAJOR -1
00813 #define _DB_ERRPFX "rpmdb"
00814
00815
00816
00817 static struct rpmdb_s dbTemplate = {
00818 _DB_ROOT, _DB_HOME, _DB_FLAGS, _DB_MODE, _DB_PERMS,
00819 _DB_MAJOR, _DB_ERRPFX
00820 };
00821
00822
00823 static int isTemporaryDB(int rpmtag)
00824 {
00825 int rc = 0;
00826 switch (rpmtag) {
00827 case RPMDBI_AVAILABLE:
00828 case RPMDBI_ADDED:
00829 case RPMDBI_REMOVED:
00830 case RPMDBI_DEPENDS:
00831 rc = 1;
00832 break;
00833 default:
00834 break;
00835 }
00836 return rc;
00837 }
00838
00839 int rpmdbOpenAll(rpmdb db)
00840 {
00841 int dbix;
00842 int rc = 0;
00843
00844 if (db == NULL) return -2;
00845
00846 if (dbiTags != NULL)
00847 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
00848 if (db->_dbi[dbix] != NULL)
00849 continue;
00850
00851 if (isTemporaryDB(dbiTags[dbix]))
00852 continue;
00853 (void) dbiOpen(db, dbiTags[dbix], db->db_flags);
00854 }
00855 return rc;
00856 }
00857
00858 int rpmdbCloseDBI(rpmdb db, int rpmtag)
00859 {
00860 int dbix;
00861 int rc = 0;
00862
00863 if (db == NULL || db->_dbi == NULL || dbiTags == NULL)
00864 return 0;
00865
00866 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
00867 if (dbiTags[dbix] != rpmtag)
00868 continue;
00869
00870 if (db->_dbi[dbix] != NULL) {
00871 int xx;
00872
00873 xx = dbiClose(db->_dbi[dbix], 0);
00874 if (xx && rc == 0) rc = xx;
00875 db->_dbi[dbix] = NULL;
00876
00877 }
00878
00879 break;
00880 }
00881 return rc;
00882 }
00883
00884
00885
00886 int rpmdbClose(rpmdb db)
00887
00888
00889 {
00890 rpmdb * prev, next;
00891 int dbix;
00892 int rc = 0;
00893
00894 if (db == NULL)
00895 goto exit;
00896
00897 (void) rpmdbUnlink(db, "rpmdbClose");
00898
00899
00900 if (db->nrefs > 0)
00901 goto exit;
00902
00903 if (db->_dbi)
00904 for (dbix = db->db_ndbi; --dbix >= 0; ) {
00905 int xx;
00906 if (db->_dbi[dbix] == NULL)
00907 continue;
00908
00909 xx = dbiClose(db->_dbi[dbix], 0);
00910 if (xx && rc == 0) rc = xx;
00911 db->_dbi[dbix] = NULL;
00912
00913 }
00914 db->db_errpfx = _free(db->db_errpfx);
00915 db->db_root = _free(db->db_root);
00916 db->db_home = _free(db->db_home);
00917 db->db_bits = PBM_FREE(db->db_bits);
00918 db->_dbi = _free(db->_dbi);
00919
00920
00921 prev = &rpmdbRock;
00922 while ((next = *prev) != NULL && next != db)
00923 prev = &next->db_next;
00924 if (next) {
00925 *prev = next->db_next;
00926 next->db_next = NULL;
00927 }
00928
00929
00930 db = _free(db);
00931
00932
00933 exit:
00934 (void) rpmsqEnable(-SIGHUP, NULL);
00935 (void) rpmsqEnable(-SIGINT, NULL);
00936 (void) rpmsqEnable(-SIGTERM,NULL);
00937 (void) rpmsqEnable(-SIGQUIT,NULL);
00938 (void) rpmsqEnable(-SIGPIPE,NULL);
00939 return rc;
00940 }
00941
00942
00943 int rpmdbSync(rpmdb db)
00944 {
00945 int dbix;
00946 int rc = 0;
00947
00948 if (db == NULL) return 0;
00949 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
00950 int xx;
00951 if (db->_dbi[dbix] == NULL)
00952 continue;
00953 if (db->_dbi[dbix]->dbi_no_dbsync)
00954 continue;
00955 xx = dbiSync(db->_dbi[dbix], 0);
00956 if (xx && rc == 0) rc = xx;
00957 }
00958 return rc;
00959 }
00960
00961
00962 static
00963 rpmdb newRpmdb( const char * root,
00964 const char * home,
00965 int mode, int perms, int flags)
00966
00967
00968 {
00969 rpmdb db = xcalloc(sizeof(*db), 1);
00970 const char * epfx = _DB_ERRPFX;
00971 static int _initialized = 0;
00972
00973 if (!_initialized) {
00974 _db_filter_dups = rpmExpandNumeric("%{_filterdbdups}");
00975 _initialized = 1;
00976 }
00977
00978
00979
00980 *db = dbTemplate;
00981
00982
00983
00984 db->_dbi = NULL;
00985
00986 if (!(perms & 0600)) perms = 0644;
00987
00988 if (mode >= 0) db->db_mode = mode;
00989 if (perms >= 0) db->db_perms = perms;
00990 if (flags >= 0) db->db_flags = flags;
00991
00992
00993
00994 if (root && *root) {
00995 const char * rootpath = NULL;
00996 urltype ut = urlPath(root, &rootpath);
00997 switch (ut) {
00998 case URL_IS_PATH:
00999 case URL_IS_UNKNOWN:
01000 db->db_root = rpmGetPath(root, NULL);
01001 break;
01002 case URL_IS_HTTPS:
01003 case URL_IS_HTTP:
01004 case URL_IS_FTP:
01005 case URL_IS_HKP:
01006 case URL_IS_DASH:
01007 default:
01008 db->db_root = rpmGetPath(_DB_ROOT, NULL);
01009 break;
01010 }
01011 } else
01012 db->db_root = rpmGetPath(_DB_ROOT, NULL);
01013 db->db_home = rpmGetPath( (home && *home ? home : _DB_HOME), NULL);
01014
01015 if (!(db->db_home && db->db_home[0] != '%')) {
01016 rpmError(RPMERR_DBOPEN, _("no dbpath has been set\n"));
01017 db->db_root = _free(db->db_root);
01018 db->db_home = _free(db->db_home);
01019 db = _free(db);
01020 return NULL;
01021 }
01022 db->db_errpfx = rpmExpand( (epfx && *epfx ? epfx : _DB_ERRPFX), NULL);
01023 db->db_remove_env = 0;
01024 db->db_filter_dups = _db_filter_dups;
01025 db->db_ndbi = dbiTagsMax;
01026 db->_dbi = xcalloc(db->db_ndbi, sizeof(*db->_dbi));
01027 db->nrefs = 0;
01028
01029 return rpmdbLink(db, "rpmdbCreate");
01030
01031 }
01032
01033
01034 static int openDatabase( const char * prefix,
01035 const char * dbpath,
01036 int _dbapi, rpmdb *dbp,
01037 int mode, int perms, int flags)
01038
01039
01040
01041
01042
01043 {
01044 rpmdb db;
01045 int rc, xx;
01046 static int _tags_initialized = 0;
01047 int justCheck = flags & RPMDB_FLAG_JUSTCHECK;
01048 int minimal = flags & RPMDB_FLAG_MINIMAL;
01049
01050 if (!_tags_initialized || dbiTagsMax == 0) {
01051 dbiTagsInit();
01052 _tags_initialized++;
01053 }
01054
01055
01056 if (_dbapi < -1 || _dbapi > 4)
01057 _dbapi = -1;
01058 if (_dbapi == 0)
01059 _dbapi = 1;
01060
01061 if (dbp)
01062 *dbp = NULL;
01063 if (mode & O_WRONLY)
01064 return 1;
01065
01066 db = newRpmdb(prefix, dbpath, mode, perms, flags);
01067 if (db == NULL)
01068 return 1;
01069
01070 (void) rpmsqEnable(SIGHUP, NULL);
01071 (void) rpmsqEnable(SIGINT, NULL);
01072 (void) rpmsqEnable(SIGTERM,NULL);
01073 (void) rpmsqEnable(SIGQUIT,NULL);
01074 (void) rpmsqEnable(SIGPIPE,NULL);
01075
01076 db->db_api = _dbapi;
01077
01078 { int dbix;
01079
01080 rc = 0;
01081 if (dbiTags != NULL)
01082 for (dbix = 0; rc == 0 && dbix < dbiTagsMax; dbix++) {
01083 dbiIndex dbi;
01084 int rpmtag;
01085
01086
01087 if (isTemporaryDB((rpmtag = dbiTags[dbix])))
01088 continue;
01089
01090 dbi = dbiOpen(db, rpmtag, 0);
01091 if (dbi == NULL) {
01092 rc = -2;
01093 break;
01094 }
01095
01096 switch (rpmtag) {
01097 case RPMDBI_PACKAGES:
01098 if (dbi == NULL) rc |= 1;
01099 #if 0
01100
01101 if (db->db_api == 3)
01102 #endif
01103 goto exit;
01104 break;
01105 case RPMTAG_NAME:
01106 if (dbi == NULL) rc |= 1;
01107 if (minimal)
01108 goto exit;
01109 break;
01110 default:
01111 break;
01112 }
01113 }
01114 }
01115
01116 exit:
01117 if (rc || justCheck || dbp == NULL)
01118 xx = rpmdbClose(db);
01119 else {
01120
01121 db->db_next = rpmdbRock;
01122 rpmdbRock = db;
01123 *dbp = db;
01124
01125 }
01126
01127 return rc;
01128 }
01129
01130 rpmdb XrpmdbUnlink(rpmdb db, const char * msg, const char * fn, unsigned ln)
01131 {
01132
01133 if (_rpmdb_debug)
01134 fprintf(stderr, "--> db %p -- %d %s at %s:%u\n", db, db->nrefs, msg, fn, ln);
01135
01136 db->nrefs--;
01137 return NULL;
01138 }
01139
01140 rpmdb XrpmdbLink(rpmdb db, const char * msg, const char * fn, unsigned ln)
01141 {
01142 db->nrefs++;
01143
01144 if (_rpmdb_debug)
01145 fprintf(stderr, "--> db %p ++ %d %s at %s:%u\n", db, db->nrefs, msg, fn, ln);
01146
01147 return db;
01148 }
01149
01150
01151 int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, int perms)
01152 {
01153 int _dbapi = rpmExpandNumeric("%{_dbapi}");
01154
01155 return openDatabase(prefix, NULL, _dbapi, dbp, mode, perms, 0);
01156
01157 }
01158
01159 int rpmdbInit (const char * prefix, int perms)
01160 {
01161 rpmdb db = NULL;
01162 int _dbapi = rpmExpandNumeric("%{_dbapi}");
01163 int rc;
01164
01165
01166 rc = openDatabase(prefix, NULL, _dbapi, &db, (O_CREAT | O_RDWR),
01167 perms, RPMDB_FLAG_JUSTCHECK);
01168
01169 if (db != NULL) {
01170 int xx;
01171 xx = rpmdbOpenAll(db);
01172 if (xx && rc == 0) rc = xx;
01173 xx = rpmdbClose(db);
01174 if (xx && rc == 0) rc = xx;
01175 db = NULL;
01176 }
01177 return rc;
01178 }
01179
01180 int rpmdbVerify(const char * prefix)
01181 {
01182 rpmdb db = NULL;
01183 int _dbapi = rpmExpandNumeric("%{_dbapi}");
01184 int rc = 0;
01185
01186
01187 rc = openDatabase(prefix, NULL, _dbapi, &db, O_RDONLY, 0644, 0);
01188
01189
01190 if (db != NULL) {
01191 int dbix;
01192 int xx;
01193 rc = rpmdbOpenAll(db);
01194
01195 for (dbix = db->db_ndbi; --dbix >= 0; ) {
01196 if (db->_dbi[dbix] == NULL)
01197 continue;
01198
01199 xx = dbiVerify(db->_dbi[dbix], 0);
01200 if (xx && rc == 0) rc = xx;
01201 db->_dbi[dbix] = NULL;
01202
01203 }
01204
01205
01206 xx = rpmdbClose(db);
01207
01208 if (xx && rc == 0) rc = xx;
01209 db = NULL;
01210 }
01211 return rc;
01212 }
01213
01223 static int rpmdbFindByFile(rpmdb db, const char * filespec,
01224 DBT * key, DBT * data, dbiIndexSet * matches)
01225
01226
01227
01228
01229 {
01230 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
01231 HFD_t hfd = headerFreeData;
01232 const char * dirName;
01233 const char * baseName;
01234 rpmTagType bnt, dnt;
01235 fingerPrintCache fpc;
01236 fingerPrint fp1;
01237 dbiIndex dbi = NULL;
01238 DBC * dbcursor;
01239 dbiIndexSet allMatches = NULL;
01240 dbiIndexItem rec = NULL;
01241 int i;
01242 int rc;
01243 int xx;
01244
01245 *matches = NULL;
01246 if (filespec == NULL) return -2;
01247
01248
01249 if ((baseName = strrchr(filespec, '/')) != NULL) {
01250 char * t;
01251 size_t len;
01252
01253 len = baseName - filespec + 1;
01254
01255 t = strncpy(alloca(len + 1), filespec, len);
01256 t[len] = '\0';
01257
01258 dirName = t;
01259 baseName++;
01260 } else {
01261 dirName = "";
01262 baseName = filespec;
01263 }
01264
01265 if (baseName == NULL)
01266 return -2;
01267
01268 fpc = fpCacheCreate(20);
01269 fp1 = fpLookup(fpc, dirName, baseName, 1);
01270
01271 dbi = dbiOpen(db, RPMTAG_BASENAMES, 0);
01272
01273 if (dbi != NULL) {
01274 dbcursor = NULL;
01275 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
01276
01277
01278 key->data = (void *) baseName;
01279
01280 key->size = strlen(baseName);
01281 if (key->size == 0) key->size++;
01282
01283 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
01284 if (rc > 0) {
01285 rpmError(RPMERR_DBGETINDEX,
01286 _("error(%d) getting \"%s\" records from %s index\n"),
01287 rc, key->data, tagName(dbi->dbi_rpmtag));
01288 }
01289
01290 if (rc == 0)
01291 (void) dbt2set(dbi, data, &allMatches);
01292
01293 xx = dbiCclose(dbi, dbcursor, 0);
01294 dbcursor = NULL;
01295 } else
01296 rc = -2;
01297
01298
01299 if (rc) {
01300 allMatches = dbiFreeIndexSet(allMatches);
01301 fpc = fpCacheFree(fpc);
01302 return rc;
01303 }
01304
01305 *matches = xcalloc(1, sizeof(**matches));
01306 rec = dbiIndexNewItem(0, 0);
01307 i = 0;
01308 if (allMatches != NULL)
01309 while (i < allMatches->count) {
01310 const char ** baseNames, ** dirNames;
01311 int_32 * dirIndexes;
01312 unsigned int offset = dbiIndexRecordOffset(allMatches, i);
01313 unsigned int prevoff;
01314 Header h;
01315
01316 { rpmdbMatchIterator mi;
01317 mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &offset, sizeof(offset));
01318 h = rpmdbNextIterator(mi);
01319 if (h)
01320 h = headerLink(h);
01321 mi = rpmdbFreeIterator(mi);
01322 }
01323
01324 if (h == NULL) {
01325 i++;
01326 continue;
01327 }
01328
01329 xx = hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, NULL);
01330 xx = hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
01331 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
01332
01333 do {
01334 fingerPrint fp2;
01335 int num = dbiIndexRecordFileNumber(allMatches, i);
01336
01337 fp2 = fpLookup(fpc, dirNames[dirIndexes[num]], baseNames[num], 1);
01338
01339 if (FP_EQUAL(fp1, fp2)) {
01340
01341 rec->hdrNum = dbiIndexRecordOffset(allMatches, i);
01342 rec->tagNum = dbiIndexRecordFileNumber(allMatches, i);
01343 xx = dbiAppendSet(*matches, rec, 1, sizeof(*rec), 0);
01344 }
01345
01346 prevoff = offset;
01347 i++;
01348 if (i < allMatches->count)
01349 offset = dbiIndexRecordOffset(allMatches, i);
01350 } while (i < allMatches->count && offset == prevoff);
01351
01352 baseNames = hfd(baseNames, bnt);
01353 dirNames = hfd(dirNames, dnt);
01354 h = headerFree(h);
01355 }
01356
01357 rec = _free(rec);
01358 allMatches = dbiFreeIndexSet(allMatches);
01359
01360 fpc = fpCacheFree(fpc);
01361
01362 if ((*matches)->count == 0) {
01363 *matches = dbiFreeIndexSet(*matches);
01364 return 1;
01365 }
01366
01367 return 0;
01368 }
01369
01370
01371 int rpmdbCountPackages(rpmdb db, const char * name)
01372 {
01373 DBC * dbcursor = NULL;
01374 DBT * key = alloca(sizeof(*key));
01375 DBT * data = alloca(sizeof(*data));
01376 dbiIndex dbi;
01377 int rc;
01378 int xx;
01379
01380 if (db == NULL)
01381 return 0;
01382
01383 memset(key, 0, sizeof(*key));
01384 memset(data, 0, sizeof(*data));
01385
01386 dbi = dbiOpen(db, RPMTAG_NAME, 0);
01387 if (dbi == NULL)
01388 return 0;
01389
01390
01391 key->data = (void *) name;
01392
01393 key->size = strlen(name);
01394
01395 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
01396 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
01397 #ifndef SQLITE_HACK
01398 xx = dbiCclose(dbi, dbcursor, 0);
01399 dbcursor = NULL;
01400 #endif
01401
01402 if (rc == 0) {
01403 dbiIndexSet matches;
01404
01405 matches = NULL;
01406 (void) dbt2set(dbi, data, &matches);
01407 if (matches) {
01408 rc = dbiIndexSetCount(matches);
01409 matches = dbiFreeIndexSet(matches);
01410 }
01411
01412 } else
01413 if (rc == DB_NOTFOUND) {
01414 rc = 0;
01415 } else {
01416 rpmError(RPMERR_DBGETINDEX,
01417 _("error(%d) getting \"%s\" records from %s index\n"),
01418 rc, key->data, tagName(dbi->dbi_rpmtag));
01419 rc = -1;
01420 }
01421
01422 #ifdef SQLITE_HACK
01423 xx = dbiCclose(dbi, dbcursor, 0);
01424 dbcursor = NULL;
01425 #endif
01426
01427 return rc;
01428 }
01429
01442 static rpmRC dbiFindMatches(dbiIndex dbi, DBC * dbcursor,
01443 DBT * key, DBT * data,
01444 const char * name,
01445 const char * version,
01446 const char * release,
01447 dbiIndexSet * matches)
01448
01449
01450
01451
01452 {
01453 int gotMatches = 0;
01454 int rc;
01455 int i;
01456
01457
01458 key->data = (void *) name;
01459
01460 key->size = strlen(name);
01461
01462 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
01463
01464 if (rc == 0) {
01465 (void) dbt2set(dbi, data, matches);
01466 if (version == NULL && release == NULL)
01467 return RPMRC_OK;
01468 } else
01469 if (rc == DB_NOTFOUND) {
01470 return RPMRC_NOTFOUND;
01471 } else {
01472 rpmError(RPMERR_DBGETINDEX,
01473 _("error(%d) getting \"%s\" records from %s index\n"),
01474 rc, key->data, tagName(dbi->dbi_rpmtag));
01475 return RPMRC_FAIL;
01476 }
01477
01478
01479
01480 for (i = 0; i < dbiIndexSetCount(*matches); i++) {
01481 unsigned int recoff = dbiIndexRecordOffset(*matches, i);
01482 rpmdbMatchIterator mi;
01483 Header h;
01484
01485 if (recoff == 0)
01486 continue;
01487
01488 mi = rpmdbInitIterator(dbi->dbi_rpmdb,
01489 RPMDBI_PACKAGES, &recoff, sizeof(recoff));
01490
01491
01492 if (version &&
01493 rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version))
01494 {
01495 rc = RPMRC_FAIL;
01496 goto exit;
01497 }
01498 if (release &&
01499 rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release))
01500 {
01501 rc = RPMRC_FAIL;
01502 goto exit;
01503 }
01504
01505 h = rpmdbNextIterator(mi);
01506
01507 if (h)
01508 (*matches)->recs[gotMatches++] = (*matches)->recs[i];
01509 else
01510 (*matches)->recs[i].hdrNum = 0;
01511
01512 mi = rpmdbFreeIterator(mi);
01513 }
01514
01515
01516 if (gotMatches) {
01517 (*matches)->count = gotMatches;
01518 rc = RPMRC_OK;
01519 } else
01520 rc = RPMRC_NOTFOUND;
01521
01522 exit:
01523
01524 if (rc && matches && *matches)
01525 *matches = dbiFreeIndexSet(*matches);
01526
01527 return rc;
01528 }
01529
01542 static rpmRC dbiFindByLabel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
01543 const char * arg, dbiIndexSet * matches)
01544
01545
01546
01547
01548 {
01549 const char * release;
01550 char * localarg;
01551 char * s;
01552 char c;
01553 int brackets;
01554 rpmRC rc;
01555
01556 if (arg == NULL || strlen(arg) == 0) return RPMRC_NOTFOUND;
01557
01558
01559 rc = dbiFindMatches(dbi, dbcursor, key, data, arg, NULL, NULL, matches);
01560 if (rc != RPMRC_NOTFOUND) return rc;
01561
01562
01563 *matches = dbiFreeIndexSet(*matches);
01564
01565
01566
01567 localarg = alloca(strlen(arg) + 1);
01568 s = stpcpy(localarg, arg);
01569
01570 c = '\0';
01571 brackets = 0;
01572 for (s -= 1; s > localarg; s--) {
01573 switch (*s) {
01574 case '[':
01575 brackets = 1;
01576 break;
01577 case ']':
01578 if (c != '[') brackets = 0;
01579 break;
01580 }
01581 c = *s;
01582 if (!brackets && *s == '-')
01583 break;
01584 }
01585
01586
01587 if (s == localarg) return RPMRC_NOTFOUND;
01588
01589
01590 *s = '\0';
01591
01592 rc = dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, NULL, matches);
01593
01594 if (rc != RPMRC_NOTFOUND) return rc;
01595
01596
01597 *matches = dbiFreeIndexSet(*matches);
01598
01599
01600
01601
01602 release = s + 1;
01603
01604 c = '\0';
01605 brackets = 0;
01606 for (; s > localarg; s--) {
01607 switch (*s) {
01608 case '[':
01609 brackets = 1;
01610 break;
01611 case ']':
01612 if (c != '[') brackets = 0;
01613 break;
01614 }
01615 c = *s;
01616 if (!brackets && *s == '-')
01617 break;
01618 }
01619
01620 if (s == localarg) return RPMRC_NOTFOUND;
01621
01622
01623 *s = '\0';
01624
01625
01626 return dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, release, matches);
01627
01628 }
01629
01638 static int miFreeHeader(rpmdbMatchIterator mi, dbiIndex dbi)
01639
01640
01641 {
01642 int rc = 0;
01643
01644 if (mi == NULL || mi->mi_h == NULL)
01645 return 0;
01646
01647 if (dbi && mi->mi_dbc && mi->mi_modified && mi->mi_prevoffset) {
01648 DBT * key = &mi->mi_key;
01649 DBT * data = &mi->mi_data;
01650 sigset_t signalMask;
01651 rpmRC rpmrc = RPMRC_NOTFOUND;
01652 int xx;
01653
01654 key->data = (void *) &mi->mi_prevoffset;
01655 key->size = sizeof(mi->mi_prevoffset);
01656 data->data = headerUnload(mi->mi_h);
01657 data->size = headerSizeof(mi->mi_h, HEADER_MAGIC_NO);
01658
01659
01660 if (mi->mi_hdrchk && mi->mi_ts) {
01661 const char * msg = NULL;
01662 int lvl;
01663
01664 rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, data->data, data->size, &msg);
01665 lvl = (rpmrc == RPMRC_FAIL ? RPMMESS_ERROR : RPMMESS_DEBUG);
01666 rpmMessage(lvl, "%s h#%8u %s",
01667 (rpmrc == RPMRC_FAIL ? _("miFreeHeader: skipping") : "write"),
01668 mi->mi_prevoffset, (msg ? msg : "\n"));
01669 msg = _free(msg);
01670 }
01671
01672 if (data->data != NULL && rpmrc != RPMRC_FAIL) {
01673 (void) blockSignals(dbi->dbi_rpmdb, &signalMask);
01674 rc = dbiPut(dbi, mi->mi_dbc, key, data, DB_KEYLAST);
01675 if (rc) {
01676 rpmError(RPMERR_DBPUTINDEX,
01677 _("error(%d) storing record #%d into %s\n"),
01678 rc, mi->mi_prevoffset, tagName(dbi->dbi_rpmtag));
01679 }
01680 xx = dbiSync(dbi, 0);
01681 (void) unblockSignals(dbi->dbi_rpmdb, &signalMask);
01682 }
01683 data->data = _free(data->data);
01684 data->size = 0;
01685 }
01686
01687 mi->mi_h = headerFree(mi->mi_h);
01688
01689
01690 return rc;
01691
01692 }
01693
01694 rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi)
01695
01696
01697 {
01698 rpmdbMatchIterator * prev, next;
01699 dbiIndex dbi;
01700 int xx;
01701 int i;
01702
01703 if (mi == NULL)
01704 return NULL;
01705
01706 prev = &rpmmiRock;
01707 while ((next = *prev) != NULL && next != mi)
01708 prev = &next->mi_next;
01709 if (next) {
01710 *prev = next->mi_next;
01711 next->mi_next = NULL;
01712 }
01713
01714 dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0);
01715 if (dbi == NULL)
01716 return NULL;
01717
01718 xx = miFreeHeader(mi, dbi);
01719
01720 if (mi->mi_dbc)
01721 xx = dbiCclose(dbi, mi->mi_dbc, 0);
01722 mi->mi_dbc = NULL;
01723
01724 if (mi->mi_re != NULL)
01725 for (i = 0; i < mi->mi_nre; i++) {
01726 miRE mire = mi->mi_re + i;
01727 mire->pattern = _free(mire->pattern);
01728 if (mire->preg != NULL) {
01729 regfree(mire->preg);
01730
01731 mire->preg = _free(mire->preg);
01732
01733 }
01734 }
01735 mi->mi_re = _free(mi->mi_re);
01736
01737 mi->mi_set = dbiFreeIndexSet(mi->mi_set);
01738 mi->mi_keyp = _free(mi->mi_keyp);
01739 mi->mi_db = rpmdbUnlink(mi->mi_db, "matchIterator");
01740
01741 mi = _free(mi);
01742
01743 (void) rpmdbCheckSignals();
01744
01745 return mi;
01746 }
01747
01748 unsigned int rpmdbGetIteratorOffset(rpmdbMatchIterator mi) {
01749 return (mi ? mi->mi_offset : 0);
01750 }
01751
01752 unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi) {
01753 return (mi ? mi->mi_filenum : 0);
01754 }
01755
01756 int rpmdbGetIteratorCount(rpmdbMatchIterator mi) {
01757 return (mi && mi->mi_set ? mi->mi_set->count : 0);
01758 }
01759
01766 static int miregexec(miRE mire, const char * val)
01767
01768 {
01769 int rc = 0;
01770
01771 switch (mire->mode) {
01772 case RPMMIRE_STRCMP:
01773 rc = strcmp(mire->pattern, val);
01774 if (rc) rc = 1;
01775 break;
01776 case RPMMIRE_DEFAULT:
01777 case RPMMIRE_REGEX:
01778
01779 rc = regexec(mire->preg, val, 0, NULL, mire->eflags);
01780
01781 if (rc && rc != REG_NOMATCH) {
01782 char msg[256];
01783 (void) regerror(rc, mire->preg, msg, sizeof(msg)-1);
01784 msg[sizeof(msg)-1] = '\0';
01785 rpmError(RPMERR_REGEXEC, "%s: regexec failed: %s\n",
01786 mire->pattern, msg);
01787 rc = -1;
01788 }
01789 break;
01790 case RPMMIRE_GLOB:
01791 rc = fnmatch(mire->pattern, val, mire->fnflags);
01792 if (rc && rc != FNM_NOMATCH)
01793 rc = -1;
01794 break;
01795 default:
01796 rc = -1;
01797 break;
01798 }
01799
01800 return rc;
01801 }
01802
01809 static int mireCmp(const void * a, const void * b)
01810 {
01811 const miRE mireA = (const miRE) a;
01812 const miRE mireB = (const miRE) b;
01813 return (mireA->tag - mireB->tag);
01814 }
01815
01823 static char * mireDup(rpmTag tag, rpmMireMode *modep,
01824 const char * pattern)
01825
01826
01827 {
01828 const char * s;
01829 char * pat;
01830 char * t;
01831 int brackets;
01832 size_t nb;
01833 int c;
01834
01835
01836 switch (*modep) {
01837 default:
01838 case RPMMIRE_DEFAULT:
01839 if (tag == RPMTAG_DIRNAMES || tag == RPMTAG_BASENAMES) {
01840 *modep = RPMMIRE_GLOB;
01841 pat = xstrdup(pattern);
01842 break;
01843 }
01844
01845 nb = strlen(pattern) + sizeof("^$");
01846
01847
01848
01849 c = '\0';
01850 brackets = 0;
01851 for (s = pattern; *s != '\0'; s++) {
01852 switch (*s) {
01853 case '.':
01854 case '+':
01855 case '*':
01856 if (!brackets) nb++;
01857 break;
01858 case '\\':
01859 s++;
01860 break;
01861 case '[':
01862 brackets = 1;
01863 break;
01864 case ']':
01865 if (c != '[') brackets = 0;
01866 break;
01867 }
01868 c = *s;
01869 }
01870
01871 pat = t = xmalloc(nb);
01872
01873 if (pattern[0] != '^') *t++ = '^';
01874
01875
01876 c = '\0';
01877 brackets = 0;
01878 for (s = pattern; *s != '\0'; s++, t++) {
01879 switch (*s) {
01880 case '.':
01881 case '+':
01882 if (!brackets) *t++ = '\\';
01883 break;
01884 case '*':
01885 if (!brackets) *t++ = '.';
01886 break;
01887 case '\\':
01888 *t++ = *s++;
01889 break;
01890 case '[':
01891 brackets = 1;
01892 break;
01893 case ']':
01894 if (c != '[') brackets = 0;
01895 break;
01896 }
01897 c = *t = *s;
01898 }
01899
01900 if (s > pattern && s[-1] != '$') *t++ = '$';
01901 *t = '\0';
01902 *modep = RPMMIRE_REGEX;
01903 break;
01904 case RPMMIRE_STRCMP:
01905 case RPMMIRE_REGEX:
01906 case RPMMIRE_GLOB:
01907 pat = xstrdup(pattern);
01908 break;
01909 }
01910
01911
01912 return pat;
01913 }
01914
01915 int rpmdbSetIteratorRE(rpmdbMatchIterator mi, rpmTag tag,
01916 rpmMireMode mode, const char * pattern)
01917 {
01918 static rpmMireMode defmode = (rpmMireMode)-1;
01919 miRE mire = NULL;
01920 const char * allpat = NULL;
01921 int notmatch = 0;
01922 regex_t * preg = NULL;
01923 int cflags = 0;
01924 int eflags = 0;
01925 int fnflags = 0;
01926 int rc = 0;
01927
01928
01929 if (defmode == (rpmMireMode)-1) {
01930 const char *t = rpmExpand("%{?_query_selector_match}", NULL);
01931
01932 if (*t == '\0' || !strcmp(t, "default"))
01933 defmode = RPMMIRE_DEFAULT;
01934 else if (!strcmp(t, "strcmp"))
01935 defmode = RPMMIRE_STRCMP;
01936 else if (!strcmp(t, "regex"))
01937 defmode = RPMMIRE_REGEX;
01938 else if (!strcmp(t, "glob"))
01939 defmode = RPMMIRE_GLOB;
01940 else
01941 defmode = RPMMIRE_DEFAULT;
01942 t = _free(t);
01943 }
01944
01945 if (mi == NULL || pattern == NULL)
01946 return rc;
01947
01948
01949 if (*pattern == '!') {
01950 notmatch = 1;
01951 pattern++;
01952 }
01953
01954
01955
01956 allpat = mireDup(tag, &mode, pattern);
01957
01958
01959 if (mode == RPMMIRE_DEFAULT)
01960 mode = defmode;
01961
01962
01963 switch (mode) {
01964 case RPMMIRE_DEFAULT:
01965 case RPMMIRE_STRCMP:
01966 break;
01967 case RPMMIRE_REGEX:
01968
01969 preg = xcalloc(1, sizeof(*preg));
01970
01971 cflags = (REG_EXTENDED | REG_NOSUB);
01972 rc = regcomp(preg, allpat, cflags);
01973 if (rc) {
01974 char msg[256];
01975 (void) regerror(rc, preg, msg, sizeof(msg)-1);
01976 msg[sizeof(msg)-1] = '\0';
01977 rpmError(RPMERR_REGCOMP, "%s: regcomp failed: %s\n", allpat, msg);
01978 }
01979 break;
01980 case RPMMIRE_GLOB:
01981 fnflags = FNM_PATHNAME | FNM_PERIOD;
01982 break;
01983 default:
01984 rc = -1;
01985 break;
01986 }
01987
01988
01989 if (rc) {
01990
01991 allpat = _free(allpat);
01992 if (preg) {
01993 regfree(preg);
01994
01995 preg = _free(preg);
01996
01997 }
01998
01999 return rc;
02000 }
02001
02002 mi->mi_re = xrealloc(mi->mi_re, (mi->mi_nre + 1) * sizeof(*mi->mi_re));
02003 mire = mi->mi_re + mi->mi_nre;
02004 mi->mi_nre++;
02005
02006 mire->tag = tag;
02007 mire->mode = mode;
02008 mire->pattern = allpat;
02009 mire->notmatch = notmatch;
02010 mire->preg = preg;
02011 mire->cflags = cflags;
02012 mire->eflags = eflags;
02013 mire->fnflags = fnflags;
02014
02015
02016 if (mi->mi_nre > 1)
02017 qsort(mi->mi_re, mi->mi_nre, sizeof(*mi->mi_re), mireCmp);
02018
02019
02020 return rc;
02021 }
02022
02028 static int mireSkip (const rpmdbMatchIterator mi)
02029
02030 {
02031 HGE_t hge = (HGE_t) headerGetEntryMinMemory;
02032 HFD_t hfd = (HFD_t) headerFreeData;
02033 union {
02034 void * ptr;
02035 const char ** argv;
02036 const char * str;
02037 int_32 * i32p;
02038 int_16 * i16p;
02039 int_8 * i8p;
02040 } u;
02041 char numbuf[32];
02042 rpmTagType t;
02043 int_32 c;
02044 miRE mire;
02045 static int_32 zero = 0;
02046 int ntags = 0;
02047 int nmatches = 0;
02048 int i, j;
02049 int rc;
02050
02051 if (mi->mi_h == NULL)
02052 return 0;
02053
02054
02055
02056
02057
02058
02059 if ((mire = mi->mi_re) != NULL)
02060 for (i = 0; i < mi->mi_nre; i++, mire++) {
02061 int anymatch;
02062
02063 if (!hge(mi->mi_h, mire->tag, &t, (void **)&u, &c)) {
02064 if (mire->tag != RPMTAG_EPOCH) {
02065 ntags++;
02066 continue;
02067 }
02068 t = RPM_INT32_TYPE;
02069
02070 u.i32p = &zero;
02071
02072 c = 1;
02073 }
02074
02075 anymatch = 0;
02076 while (1) {
02077 switch (t) {
02078 case RPM_CHAR_TYPE:
02079 case RPM_INT8_TYPE:
02080 sprintf(numbuf, "%d", (int) *u.i8p);
02081 rc = miregexec(mire, numbuf);
02082 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
02083 anymatch++;
02084 break;
02085 case RPM_INT16_TYPE:
02086 sprintf(numbuf, "%d", (int) *u.i16p);
02087 rc = miregexec(mire, numbuf);
02088 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
02089 anymatch++;
02090 break;
02091 case RPM_INT32_TYPE:
02092 sprintf(numbuf, "%d", (int) *u.i32p);
02093 rc = miregexec(mire, numbuf);
02094 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
02095 anymatch++;
02096 break;
02097 case RPM_STRING_TYPE:
02098 rc = miregexec(mire, u.str);
02099 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
02100 anymatch++;
02101 break;
02102 case RPM_I18NSTRING_TYPE:
02103 case RPM_STRING_ARRAY_TYPE:
02104 for (j = 0; j < c; j++) {
02105 rc = miregexec(mire, u.argv[j]);
02106 if ((!rc && !mire->notmatch) || (rc && mire->notmatch)) {
02107 anymatch++;
02108 break;
02109 }
02110 }
02111 break;
02112 case RPM_BIN_TYPE:
02113 {
02114 const char * str = bin2hex((const char*) u.ptr, c);
02115 rc = miregexec(mire, str);
02116 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
02117 anymatch++;
02118 _free(str);
02119 }
02120 break;
02121 case RPM_NULL_TYPE:
02122 default:
02123 break;
02124 }
02125 if ((i+1) < mi->mi_nre && mire[0].tag == mire[1].tag) {
02126 i++;
02127 mire++;
02128 continue;
02129 }
02130 break;
02131 }
02132
02133
02134 if (t != RPM_BIN_TYPE)
02135 u.ptr = hfd(u.ptr, t);
02136
02137 ntags++;
02138 if (anymatch)
02139 nmatches++;
02140 }
02141
02142 return (ntags == nmatches ? 0 : 1);
02143 }
02144
02145 int rpmdbSetIteratorRewrite(rpmdbMatchIterator mi, int rewrite)
02146 {
02147 int rc;
02148 if (mi == NULL)
02149 return 0;
02150 rc = (mi->mi_cflags & DB_WRITECURSOR) ? 1 : 0;
02151 if (rewrite)
02152 mi->mi_cflags |= DB_WRITECURSOR;
02153 else
02154 mi->mi_cflags &= ~DB_WRITECURSOR;
02155 return rc;
02156 }
02157
02158 int rpmdbSetIteratorModified(rpmdbMatchIterator mi, int modified)
02159 {
02160 int rc;
02161 if (mi == NULL)
02162 return 0;
02163 rc = mi->mi_modified;
02164 mi->mi_modified = modified;
02165 return rc;
02166 }
02167
02168 int rpmdbSetHdrChk(rpmdbMatchIterator mi, rpmts ts,
02169 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg))
02170 {
02171 int rc = 0;
02172 if (mi == NULL)
02173 return 0;
02174
02175 mi->mi_ts = ts;
02176 mi->mi_hdrchk = hdrchk;
02177
02178 return rc;
02179 }
02180
02181
02182
02183 Header rpmdbNextIterator(rpmdbMatchIterator mi)
02184 {
02185 dbiIndex dbi;
02186 void * uh;
02187 size_t uhlen;
02188 DBT * key;
02189 DBT * data;
02190 void * keyp;
02191 size_t keylen;
02192 int rc;
02193 int xx;
02194
02195 if (mi == NULL)
02196 return NULL;
02197
02198 dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0);
02199 if (dbi == NULL)
02200 return NULL;
02201
02202
02203
02204
02205
02206
02207
02208 if (mi->mi_dbc == NULL)
02209 xx = dbiCopen(dbi, dbi->dbi_txnid, &mi->mi_dbc, mi->mi_cflags);
02210
02211
02212 key = &mi->mi_key;
02213 memset(key, 0, sizeof(*key));
02214 data = &mi->mi_data;
02215 memset(data, 0, sizeof(*data));
02216
02217
02218 top:
02219 uh = NULL;
02220 uhlen = 0;
02221
02222 do {
02223 union _dbswap mi_offset;
02224
02225
02226 if (mi->mi_set) {
02227 if (!(mi->mi_setx < mi->mi_set->count))
02228 return NULL;
02229 mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx);
02230 mi->mi_filenum = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx);
02231 mi_offset.ui = mi->mi_offset;
02232 if (dbiByteSwapped(dbi) == 1)
02233 _DBSWAP(mi_offset);
02234 keyp = &mi_offset;
02235 keylen = sizeof(mi_offset.ui);
02236 } else {
02237
02238 key->data = keyp = (void *)mi->mi_keyp;
02239 key->size = keylen = mi->mi_keylen;
02240 data->data = uh;
02241 data->size = uhlen;
02242 #if !defined(_USE_COPY_LOAD)
02243 data->flags |= DB_DBT_MALLOC;
02244 #endif
02245 rc = dbiGet(dbi, mi->mi_dbc, key, data,
02246 (key->data == NULL ? DB_NEXT : DB_SET));
02247 data->flags = 0;
02248 keyp = key->data;
02249 keylen = key->size;
02250 uh = data->data;
02251 uhlen = data->size;
02252
02253
02254
02255
02256
02257
02258
02259
02260
02261 if (keyp && mi->mi_setx && rc == 0) {
02262 memcpy(&mi_offset, keyp, sizeof(mi_offset.ui));
02263 if (dbiByteSwapped(dbi) == 1)
02264 _DBSWAP(mi_offset);
02265 mi->mi_offset = mi_offset.ui;
02266 }
02267
02268
02269
02270 if (rc || (mi->mi_setx && mi->mi_offset == 0))
02271 return NULL;
02272 }
02273
02274 mi->mi_setx++;
02275 } while (mi->mi_offset == 0);
02276
02277
02278
02279 if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset)
02280 return mi->mi_h;
02281
02282
02283
02284
02285 if (uh == NULL) {
02286 key->data = keyp;
02287 key->size = keylen;
02288 #if !defined(_USE_COPY_LOAD)
02289 data->flags |= DB_DBT_MALLOC;
02290 #endif
02291 rc = dbiGet(dbi, mi->mi_dbc, key, data, DB_SET);
02292 data->flags = 0;
02293 keyp = key->data;
02294 keylen = key->size;
02295 uh = data->data;
02296 uhlen = data->size;
02297 if (rc)
02298 return NULL;
02299 }
02300
02301
02302
02303 xx = miFreeHeader(mi, dbi);
02304
02305
02306 if (uh == NULL)
02307 return NULL;
02308
02309
02310
02311 if (mi->mi_hdrchk && mi->mi_ts) {
02312 rpmRC rpmrc = RPMRC_NOTFOUND;
02313
02314
02315 if (mi->mi_db->db_bits) {
02316 pbm_set * set;
02317
02318 set = PBM_REALLOC((pbm_set **)&mi->mi_db->db_bits,
02319 &mi->mi_db->db_nbits, mi->mi_offset);
02320 if (PBM_ISSET(mi->mi_offset, set))
02321 rpmrc = RPMRC_OK;
02322 }
02323
02324
02325 if (rpmrc != RPMRC_OK) {
02326 const char * msg = NULL;
02327 int lvl;
02328
02329 rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, uh, uhlen, &msg);
02330 lvl = (rpmrc == RPMRC_FAIL ? RPMMESS_ERROR : RPMMESS_DEBUG);
02331 rpmMessage(lvl, "%s h#%8u %s",
02332 (rpmrc == RPMRC_FAIL ? _("rpmdbNextIterator: skipping") : " read"),
02333 mi->mi_offset, (msg ? msg : "\n"));
02334 msg = _free(msg);
02335
02336
02337 if (mi->mi_db && mi->mi_db->db_bits && rpmrc == RPMRC_OK) {
02338 pbm_set * set;
02339
02340 set = PBM_REALLOC((pbm_set **)&mi->mi_db->db_bits,
02341 &mi->mi_db->db_nbits, mi->mi_offset);
02342 PBM_SET(mi->mi_offset, set);
02343 }
02344
02345
02346 if (rpmrc == RPMRC_FAIL)
02347 goto top;
02348 }
02349 }
02350
02351
02352
02353 #if !defined(_USE_COPY_LOAD)
02354
02355 mi->mi_h = headerLoad(uh);
02356
02357 if (mi->mi_h)
02358 mi->mi_h->flags |= HEADERFLAG_ALLOCATED;
02359 #else
02360 mi->mi_h = headerCopyLoad(uh);
02361 #endif
02362 if (mi->mi_h == NULL || !headerIsEntry(mi->mi_h, RPMTAG_NAME)) {
02363 rpmError(RPMERR_BADHEADER,
02364 _("rpmdb: damaged header #%u retrieved -- skipping.\n"),
02365 mi->mi_offset);
02366 goto top;
02367 }
02368
02369
02370
02371
02372 if (mireSkip(mi)) {
02373
02374 if (mi->mi_set || mi->mi_keyp == NULL)
02375 goto top;
02376 return NULL;
02377 }
02378
02379 mi->mi_prevoffset = mi->mi_offset;
02380 mi->mi_modified = 0;
02381
02382
02383 return mi->mi_h;
02384
02385 }
02386
02387
02388 static void rpmdbSortIterator( rpmdbMatchIterator mi)
02389
02390 {
02391 if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) {
02392
02393
02394
02395
02396 #if defined(__GLIBC__)
02397
02398 qsort(mi->mi_set->recs, mi->mi_set->count,
02399 sizeof(*mi->mi_set->recs), hdrNumCmp);
02400
02401 #else
02402 mergesort(mi->mi_set->recs, mi->mi_set->count,
02403 sizeof(*mi->mi_set->recs), hdrNumCmp);
02404 #endif
02405 mi->mi_sorted = 1;
02406 }
02407 }
02408
02409
02410 static int rpmdbGrowIterator( rpmdbMatchIterator mi, int fpNum)
02411
02412
02413 {
02414 DBC * dbcursor;
02415 DBT * key;
02416 DBT * data;
02417 dbiIndex dbi = NULL;
02418 dbiIndexSet set;
02419 int rc;
02420 int xx;
02421 int i;
02422
02423 if (mi == NULL)
02424 return 1;
02425
02426 dbcursor = mi->mi_dbc;
02427 key = &mi->mi_key;
02428 data = &mi->mi_data;
02429 if (key->data == NULL)
02430 return 1;
02431
02432 dbi = dbiOpen(mi->mi_db, mi->mi_rpmtag, 0);
02433 if (dbi == NULL)
02434 return 1;
02435
02436 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
02437 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
02438 #ifndef SQLITE_HACK
02439 xx = dbiCclose(dbi, dbcursor, 0);
02440 dbcursor = NULL;
02441 #endif
02442
02443 if (rc) {
02444 if (rc != DB_NOTFOUND)
02445 rpmError(RPMERR_DBGETINDEX,
02446 _("error(%d) getting \"%s\" records from %s index\n"),
02447 rc, key->data, tagName(dbi->dbi_rpmtag));
02448 #ifdef SQLITE_HACK
02449 xx = dbiCclose(dbi, dbcursor, 0);
02450 dbcursor = NULL;
02451 #endif
02452 return rc;
02453 }
02454
02455 set = NULL;
02456 (void) dbt2set(dbi, data, &set);
02457 for (i = 0; i < set->count; i++)
02458 set->recs[i].fpNum = fpNum;
02459
02460 #ifdef SQLITE_HACK
02461 xx = dbiCclose(dbi, dbcursor, 0);
02462 dbcursor = NULL;
02463 #endif
02464
02465
02466 if (mi->mi_set == NULL) {
02467 mi->mi_set = set;
02468 } else {
02469 dbiGrowSet(mi->mi_set, set->count);
02470 memcpy(mi->mi_set->recs + mi->mi_set->count, set->recs,
02471 set->count * sizeof(*(mi->mi_set->recs)));
02472 mi->mi_set->count += set->count;
02473 set = dbiFreeIndexSet(set);
02474 }
02475
02476
02477 return rc;
02478 }
02479
02480
02481 int rpmdbPruneIterator(rpmdbMatchIterator mi, int * hdrNums,
02482 int nHdrNums, int sorted)
02483 {
02484 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
02485 return 1;
02486
02487 if (mi->mi_set)
02488 (void) dbiPruneSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), sorted);
02489 return 0;
02490 }
02491
02492 int rpmdbAppendIterator(rpmdbMatchIterator mi, const int * hdrNums, int nHdrNums)
02493 {
02494 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
02495 return 1;
02496
02497 if (mi->mi_set == NULL)
02498 mi->mi_set = xcalloc(1, sizeof(*mi->mi_set));
02499 (void) dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0);
02500 return 0;
02501 }
02502
02503 rpmdbMatchIterator rpmdbInitIterator(rpmdb db, rpmTag rpmtag,
02504 const void * keyp, size_t keylen)
02505
02506
02507 {
02508 rpmdbMatchIterator mi;
02509 DBT * key;
02510 DBT * data;
02511 dbiIndexSet set = NULL;
02512 dbiIndex dbi;
02513 const void * mi_keyp = NULL;
02514 int isLabel = 0;
02515
02516 if (db == NULL)
02517 return NULL;
02518
02519 (void) rpmdbCheckSignals();
02520
02521
02522 if (rpmtag == RPMDBI_LABEL) {
02523 rpmtag = RPMTAG_NAME;
02524 isLabel = 1;
02525 }
02526
02527 dbi = dbiOpen(db, rpmtag, 0);
02528 if (dbi == NULL)
02529 return NULL;
02530
02531
02532 mi = xcalloc(1, sizeof(*mi));
02533 mi->mi_next = rpmmiRock;
02534 rpmmiRock = mi;
02535
02536 key = &mi->mi_key;
02537 data = &mi->mi_data;
02538
02539
02540
02541
02542
02543
02544 if (rpmtag != RPMDBI_PACKAGES && keyp) {
02545 DBC * dbcursor = NULL;
02546 int rc;
02547 int xx;
02548
02549 if (isLabel) {
02550 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
02551 rc = dbiFindByLabel(dbi, dbcursor, key, data, keyp, &set);
02552 xx = dbiCclose(dbi, dbcursor, 0);
02553 dbcursor = NULL;
02554 } else if (rpmtag == RPMTAG_BASENAMES) {
02555 rc = rpmdbFindByFile(db, keyp, key, data, &set);
02556 } else {
02557 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
02558
02559
02560 key->data = (void *) keyp;
02561
02562 key->size = keylen;
02563 if (key->data && key->size == 0) key->size = strlen((char *)key->data);
02564 if (key->data && key->size == 0) key->size++;
02565
02566
02567 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
02568
02569 if (rc > 0) {
02570 rpmError(RPMERR_DBGETINDEX,
02571 _("error(%d) getting \"%s\" records from %s index\n"),
02572 rc, (key->data ? key->data : "???"), tagName(dbi->dbi_rpmtag));
02573 }
02574
02575
02576 if (rc == 0)
02577 (void) dbt2set(dbi, data, &set);
02578
02579 xx = dbiCclose(dbi, dbcursor, 0);
02580 dbcursor = NULL;
02581 }
02582 if (rc) {
02583 set = dbiFreeIndexSet(set);
02584 rpmmiRock = mi->mi_next;
02585 mi->mi_next = NULL;
02586 mi = _free(mi);
02587 return NULL;
02588 }
02589 }
02590
02591
02592
02593 if (keyp) {
02594 switch (rpmtag) {
02595 case RPMDBI_PACKAGES:
02596 { union _dbswap *k;
02597
02598 assert(keylen == sizeof(k->ui));
02599 k = xmalloc(sizeof(*k));
02600 memcpy(k, keyp, keylen);
02601 if (dbiByteSwapped(dbi) == 1)
02602 _DBSWAP(*k);
02603 mi_keyp = k;
02604 } break;
02605 default:
02606 { char * k;
02607 if (keylen == 0)
02608 keylen = strlen(keyp);
02609 k = xmalloc(keylen + 1);
02610
02611 memcpy(k, keyp, keylen);
02612
02613 k[keylen] = '\0';
02614 mi_keyp = k;
02615 } break;
02616 }
02617 }
02618
02619 mi->mi_keyp = mi_keyp;
02620 mi->mi_keylen = keylen;
02621
02622 mi->mi_db = rpmdbLink(db, "matchIterator");
02623 mi->mi_rpmtag = rpmtag;
02624
02625 mi->mi_dbc = NULL;
02626 mi->mi_set = set;
02627 mi->mi_setx = 0;
02628 mi->mi_h = NULL;
02629 mi->mi_sorted = 0;
02630 mi->mi_cflags = 0;
02631 mi->mi_modified = 0;
02632 mi->mi_prevoffset = 0;
02633 mi->mi_offset = 0;
02634 mi->mi_filenum = 0;
02635 mi->mi_nre = 0;
02636 mi->mi_re = NULL;
02637
02638 mi->mi_ts = NULL;
02639 mi->mi_hdrchk = NULL;
02640
02641 return mi;
02642 }
02643
02644
02645 int rpmdbRemove(rpmdb db, int rid, unsigned int hdrNum,
02646 rpmts ts,
02647 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg))
02648 {
02649 DBC * dbcursor = NULL;
02650 DBT * key = alloca(sizeof(*key));
02651 DBT * data = alloca(sizeof(*data));
02652 union _dbswap mi_offset;
02653 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
02654 HFD_t hfd = headerFreeData;
02655 Header h;
02656 sigset_t signalMask;
02657 int ret = 0;
02658 int rc = 0;
02659
02660 if (db == NULL)
02661 return 0;
02662
02663 memset(key, 0, sizeof(*key));
02664 memset(data, 0, sizeof(*data));
02665
02666 { rpmdbMatchIterator mi;
02667 mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum));
02668 h = rpmdbNextIterator(mi);
02669 if (h)
02670 h = headerLink(h);
02671 mi = rpmdbFreeIterator(mi);
02672 }
02673
02674 if (h == NULL) {
02675 rpmError(RPMERR_DBCORRUPT, _("%s: cannot read header at 0x%x\n"),
02676 "rpmdbRemove", hdrNum);
02677 return 1;
02678 }
02679
02680 #ifdef DYING
02681
02682 if (rid != 0 && rid != -1) {
02683 int_32 tid = rid;
02684 (void) headerAddEntry(h, RPMTAG_REMOVETID, RPM_INT32_TYPE, &tid, 1);
02685 }
02686 #endif
02687
02688 { const char *n, *v, *r;
02689 (void) headerNVR(h, &n, &v, &r);
02690 rpmMessage(RPMMESS_DEBUG, " --- h#%8u %s-%s-%s\n", hdrNum, n, v, r);
02691 }
02692
02693 (void) blockSignals(db, &signalMask);
02694
02695
02696 { int dbix;
02697 dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
02698
02699 if (dbiTags != NULL)
02700 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
02701 dbiIndex dbi;
02702 const char *av[1];
02703 const char ** rpmvals = NULL;
02704 rpmTagType rpmtype = 0;
02705 int rpmcnt = 0;
02706 int rpmtag;
02707 int xx;
02708 int i, j;
02709
02710 dbi = NULL;
02711
02712 rpmtag = dbiTags[dbix];
02713
02714
02715
02716
02717 if (isTemporaryDB(rpmtag))
02718 continue;
02719
02720 switch (rpmtag) {
02721 case RPMDBI_PACKAGES:
02722 dbi = dbiOpen(db, rpmtag, 0);
02723 if (dbi == NULL)
02724 continue;
02725
02726
02727 mi_offset.ui = hdrNum;
02728 if (dbiByteSwapped(dbi) == 1)
02729 _DBSWAP(mi_offset);
02730 key->data = &mi_offset;
02731
02732 key->size = sizeof(mi_offset.ui);
02733
02734 rc = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
02735 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
02736 if (rc) {
02737 rpmError(RPMERR_DBGETINDEX,
02738 _("error(%d) setting header #%d record for %s removal\n"),
02739 rc, hdrNum, tagName(dbi->dbi_rpmtag));
02740 } else
02741 rc = dbiDel(dbi, dbcursor, key, data, 0);
02742 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
02743 dbcursor = NULL;
02744 if (!dbi->dbi_no_dbsync)
02745 xx = dbiSync(dbi, 0);
02746 continue;
02747 break;
02748 }
02749
02750
02751 if (!hge(h, rpmtag, &rpmtype, (void **) &rpmvals, &rpmcnt))
02752 continue;
02753
02754 dbi = dbiOpen(db, rpmtag, 0);
02755 if (dbi != NULL) {
02756 int printed;
02757
02758 if (rpmtype == RPM_STRING_TYPE) {
02759
02760 av[0] = (const char *) rpmvals;
02761 rpmvals = av;
02762 rpmcnt = 1;
02763 }
02764
02765 printed = 0;
02766 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
02767
02768 for (i = 0; i < rpmcnt; i++) {
02769 dbiIndexSet set;
02770 int stringvalued;
02771 byte bin[32];
02772
02773 switch (dbi->dbi_rpmtag) {
02774 case RPMTAG_FILEMD5S:
02775
02776 if (!(rpmvals[i] && *rpmvals[i] != '\0'))
02777 continue;
02778 break;
02779 default:
02780 break;
02781 }
02782
02783
02784 stringvalued = 0;
02785 switch (rpmtype) {
02786
02787 case RPM_CHAR_TYPE:
02788 case RPM_INT8_TYPE:
02789 key->size = sizeof(RPM_CHAR_TYPE);
02790 key->data = rpmvals + i;
02791 break;
02792 case RPM_INT16_TYPE:
02793 key->size = sizeof(int_16);
02794 key->data = rpmvals + i;
02795 break;
02796 case RPM_INT32_TYPE:
02797 key->size = sizeof(int_32);
02798 key->data = rpmvals + i;
02799 break;
02800
02801 case RPM_BIN_TYPE:
02802 key->size = rpmcnt;
02803 key->data = rpmvals;
02804 rpmcnt = 1;
02805 break;
02806 case RPM_STRING_TYPE:
02807 case RPM_I18NSTRING_TYPE:
02808 rpmcnt = 1;
02809
02810 case RPM_STRING_ARRAY_TYPE:
02811
02812
02813 if (dbi->dbi_rpmtag == RPMTAG_FILEMD5S) {
02814 const char * s;
02815 byte * t;
02816
02817 s = rpmvals[i];
02818 t = bin;
02819 for (j = 0; j < 16; j++, t++, s += 2)
02820 *t = (nibble(s[0]) << 4) | nibble(s[1]);
02821 key->data = bin;
02822 key->size = 16;
02823 break;
02824 }
02825
02826 if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
02827 pgpDig dig = pgpNewDig();
02828 const byte * pkt;
02829 ssize_t pktlen;
02830
02831 if (b64decode(rpmvals[i], (void **)&pkt, &pktlen))
02832 continue;
02833 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
02834 memcpy(bin, dig->pubkey.signid, 8);
02835 pkt = _free(pkt);
02836 dig = _free(dig);
02837 key->data = bin;
02838 key->size = 8;
02839 break;
02840 }
02841
02842
02843 default:
02844 key->data = (void *) rpmvals[i];
02845 key->size = strlen(rpmvals[i]);
02846 stringvalued = 1;
02847 break;
02848 }
02849
02850 if (!printed) {
02851 if (rpmcnt == 1 && stringvalued) {
02852 rpmMessage(RPMMESS_DEBUG,
02853 _("removing \"%s\" from %s index.\n"),
02854 (char *)key->data, tagName(dbi->dbi_rpmtag));
02855 } else {
02856 rpmMessage(RPMMESS_DEBUG,
02857 _("removing %d entries from %s index.\n"),
02858 rpmcnt, tagName(dbi->dbi_rpmtag));
02859 }
02860 printed++;
02861 }
02862
02863
02864
02865
02866
02867
02868
02869
02870
02871
02872 set = NULL;
02873
02874 if (key->size == 0) key->size = strlen((char *)key->data);
02875 if (key->size == 0) key->size++;
02876
02877
02878 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
02879 if (rc == 0) {
02880 (void) dbt2set(dbi, data, &set);
02881 } else if (rc == DB_NOTFOUND) {
02882 continue;
02883 } else {
02884 rpmError(RPMERR_DBGETINDEX,
02885 _("error(%d) setting \"%s\" records from %s index\n"),
02886 rc, key->data, tagName(dbi->dbi_rpmtag));
02887 ret += 1;
02888 continue;
02889 }
02890
02891
02892 rc = dbiPruneSet(set, rec, 1, sizeof(*rec), 1);
02893
02894
02895 if (rc) {
02896 set = dbiFreeIndexSet(set);
02897 continue;
02898 }
02899
02900
02901 if (set->count > 0) {
02902 (void) set2dbt(dbi, data, set);
02903 rc = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
02904 if (rc) {
02905 rpmError(RPMERR_DBPUTINDEX,
02906 _("error(%d) storing record \"%s\" into %s\n"),
02907 rc, key->data, tagName(dbi->dbi_rpmtag));
02908 ret += 1;
02909 }
02910 data->data = _free(data->data);
02911 data->size = 0;
02912 } else {
02913 rc = dbiDel(dbi, dbcursor, key, data, 0);
02914 if (rc) {
02915 rpmError(RPMERR_DBPUTINDEX,
02916 _("error(%d) removing record \"%s\" from %s\n"),
02917 rc, key->data, tagName(dbi->dbi_rpmtag));
02918 ret += 1;
02919 }
02920 }
02921
02922 set = dbiFreeIndexSet(set);
02923 }
02924
02925
02926 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
02927 dbcursor = NULL;
02928
02929 if (!dbi->dbi_no_dbsync)
02930 xx = dbiSync(dbi, 0);
02931 }
02932
02933 if (rpmtype != RPM_BIN_TYPE)
02934 rpmvals = hfd(rpmvals, rpmtype);
02935 rpmtype = 0;
02936 rpmcnt = 0;
02937 }
02938
02939 rec = _free(rec);
02940 }
02941
02942
02943 (void) unblockSignals(db, &signalMask);
02944
02945 h = headerFree(h);
02946
02947
02948 return 0;
02949 }
02950
02951
02952 int rpmdbAdd(rpmdb db, int iid, Header h,
02953 rpmts ts,
02954 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg))
02955 {
02956 DBC * dbcursor = NULL;
02957 DBT * key = alloca(sizeof(*key));
02958 DBT * data = alloca(sizeof(*data));
02959 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
02960 HFD_t hfd = headerFreeData;
02961 sigset_t signalMask;
02962 const char ** baseNames;
02963 rpmTagType bnt;
02964 int count = 0;
02965 dbiIndex dbi;
02966 int dbix;
02967 union _dbswap mi_offset;
02968 unsigned int hdrNum = 0;
02969 int ret = 0;
02970 int rc;
02971 int xx;
02972
02973
02974
02975
02976
02977
02978 myinstall_instance = 0;
02979
02980
02981 if (db == NULL)
02982 return 0;
02983
02984 memset(key, 0, sizeof(*key));
02985 memset(data, 0, sizeof(*data));
02986
02987 #ifdef NOTYET
02988 xx = headerRemoveEntry(h, RPMTAG_REMOVETID);
02989 #endif
02990 if (iid != 0 && iid != -1) {
02991 int_32 tid = iid;
02992 if (!headerIsEntry(h, RPMTAG_INSTALLTID))
02993 xx = headerAddEntry(h, RPMTAG_INSTALLTID, RPM_INT32_TYPE, &tid, 1);
02994 }
02995
02996
02997
02998
02999
03000
03001
03002 xx = hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, &count);
03003
03004 if (_noDirTokens)
03005 expandFilelist(h);
03006
03007 (void) blockSignals(db, &signalMask);
03008
03009 {
03010 unsigned int firstkey = 0;
03011 void * keyp = &firstkey;
03012 size_t keylen = sizeof(firstkey);
03013 void * datap = NULL;
03014 size_t datalen = 0;
03015
03016 dbi = dbiOpen(db, RPMDBI_PACKAGES, 0);
03017
03018 if (dbi != NULL) {
03019
03020
03021 datap = h;
03022 datalen = headerSizeof(h, HEADER_MAGIC_NO);
03023
03024 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
03025
03026
03027
03028
03029 key->data = keyp;
03030 key->size = keylen;
03031 data->data = datap;
03032 data->size = datalen;
03033 ret = dbiGet(dbi, dbcursor, key, data, DB_SET);
03034 keyp = key->data;
03035 keylen = key->size;
03036 datap = data->data;
03037 datalen = data->size;
03038
03039
03040
03041 hdrNum = 0;
03042 if (ret == 0 && datap) {
03043 memcpy(&mi_offset, datap, sizeof(mi_offset.ui));
03044 if (dbiByteSwapped(dbi) == 1)
03045 _DBSWAP(mi_offset);
03046 hdrNum = mi_offset.ui;
03047 }
03048 ++hdrNum;
03049 mi_offset.ui = hdrNum;
03050 if (dbiByteSwapped(dbi) == 1)
03051 _DBSWAP(mi_offset);
03052 if (ret == 0 && datap) {
03053 memcpy(datap, &mi_offset, sizeof(mi_offset.ui));
03054 } else {
03055 datap = &mi_offset;
03056 datalen = sizeof(mi_offset.ui);
03057 }
03058
03059
03060 key->data = keyp;
03061 key->size = keylen;
03062
03063 data->data = datap;
03064
03065 data->size = datalen;
03066
03067
03068 ret = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
03069
03070 xx = dbiSync(dbi, 0);
03071
03072 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
03073 dbcursor = NULL;
03074 }
03075
03076
03077 }
03078
03079 if (ret) {
03080 rpmError(RPMERR_DBCORRUPT,
03081 _("error(%d) allocating new package instance\n"), ret);
03082 goto exit;
03083 }
03084
03085
03086
03087 if (hdrNum)
03088 {
03089 dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
03090
03091
03092
03093 myinstall_instance = hdrNum;
03094
03095
03096 if (dbiTags != NULL)
03097 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
03098 const char *av[1];
03099 const char **rpmvals = NULL;
03100 rpmTagType rpmtype = 0;
03101 int rpmcnt = 0;
03102 int rpmtag;
03103 int_32 * requireFlags;
03104 rpmRC rpmrc;
03105 int i, j;
03106
03107 rpmrc = RPMRC_NOTFOUND;
03108 dbi = NULL;
03109 requireFlags = NULL;
03110
03111 rpmtag = dbiTags[dbix];
03112
03113
03114
03115 if (isTemporaryDB(rpmtag))
03116 continue;
03117
03118 switch (rpmtag) {
03119 case RPMDBI_PACKAGES:
03120 dbi = dbiOpen(db, rpmtag, 0);
03121 if (dbi == NULL)
03122 continue;
03123 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
03124
03125 mi_offset.ui = hdrNum;
03126 if (dbiByteSwapped(dbi) == 1)
03127 _DBSWAP(mi_offset);
03128
03129 key->data = (void *) &mi_offset;
03130
03131 key->size = sizeof(mi_offset.ui);
03132 data->data = headerUnload(h);
03133 data->size = headerSizeof(h, HEADER_MAGIC_NO);
03134
03135
03136 if (hdrchk && ts) {
03137 const char * msg = NULL;
03138 int lvl;
03139
03140 rpmrc = (*hdrchk) (ts, data->data, data->size, &msg);
03141 lvl = (rpmrc == RPMRC_FAIL ? RPMMESS_ERROR : RPMMESS_DEBUG);
03142 rpmMessage(lvl, "%s h#%8u %s",
03143 (rpmrc == RPMRC_FAIL ? _("rpmdbAdd: skipping") : " +++"),
03144 hdrNum, (msg ? msg : "\n"));
03145 msg = _free(msg);
03146 }
03147
03148 if (data->data != NULL && rpmrc != RPMRC_FAIL) {
03149
03150 xx = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
03151
03152 xx = dbiSync(dbi, 0);
03153 }
03154 data->data = _free(data->data);
03155 data->size = 0;
03156 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
03157 dbcursor = NULL;
03158 if (!dbi->dbi_no_dbsync)
03159 xx = dbiSync(dbi, 0);
03160 continue;
03161 break;
03162 case RPMTAG_BASENAMES:
03163 rpmtype = bnt;
03164 rpmvals = baseNames;
03165 rpmcnt = count;
03166 break;
03167 case RPMTAG_REQUIRENAME:
03168 xx = hge(h, rpmtag, &rpmtype, (void **)&rpmvals, &rpmcnt);
03169 xx = hge(h, RPMTAG_REQUIREFLAGS, NULL, (void **)&requireFlags, NULL);
03170 break;
03171 default:
03172 xx = hge(h, rpmtag, &rpmtype, (void **)&rpmvals, &rpmcnt);
03173 break;
03174 }
03175
03176
03177 if (rpmcnt <= 0) {
03178 if (rpmtag != RPMTAG_GROUP)
03179 continue;
03180
03181
03182 rpmtype = RPM_STRING_TYPE;
03183 rpmvals = (const char **) "Unknown";
03184 rpmcnt = 1;
03185 }
03186
03187
03188 dbi = dbiOpen(db, rpmtag, 0);
03189 if (dbi != NULL) {
03190 int printed;
03191
03192 if (rpmtype == RPM_STRING_TYPE) {
03193
03194
03195 av[0] = (const char *) rpmvals;
03196
03197 rpmvals = av;
03198 rpmcnt = 1;
03199 }
03200
03201 printed = 0;
03202 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
03203
03204 for (i = 0; i < rpmcnt; i++) {
03205 dbiIndexSet set;
03206 int stringvalued;
03207 byte bin[32];
03208 byte * t;
03209
03210
03211
03212
03213
03214 rec->tagNum = i;
03215 switch (dbi->dbi_rpmtag) {
03216 case RPMTAG_PUBKEYS:
03217 break;
03218 case RPMTAG_FILEMD5S:
03219
03220 if (!(rpmvals[i] && *rpmvals[i] != '\0'))
03221 continue;
03222 break;
03223 case RPMTAG_REQUIRENAME:
03224
03225 if (requireFlags && isInstallPreReq(requireFlags[i]))
03226 continue;
03227 break;
03228 case RPMTAG_TRIGGERNAME:
03229 if (i) {
03230
03231 for (j = 0; j < i; j++) {
03232 if (!strcmp(rpmvals[i], rpmvals[j]))
03233 break;
03234 }
03235
03236 if (j < i)
03237 continue;
03238 }
03239 break;
03240 default:
03241 break;
03242 }
03243
03244
03245 stringvalued = 0;
03246
03247 switch (rpmtype) {
03248
03249 case RPM_CHAR_TYPE:
03250 case RPM_INT8_TYPE:
03251 key->size = sizeof(int_8);
03252 key->data = rpmvals + i;
03253 break;
03254 case RPM_INT16_TYPE:
03255 key->size = sizeof(int_16);
03256 key->data = rpmvals + i;
03257 break;
03258 case RPM_INT32_TYPE:
03259 key->size = sizeof(int_32);
03260 key->data = rpmvals + i;
03261 break;
03262
03263 case RPM_BIN_TYPE:
03264 key->size = rpmcnt;
03265 key->data = rpmvals;
03266 rpmcnt = 1;
03267 break;
03268 case RPM_STRING_TYPE:
03269 case RPM_I18NSTRING_TYPE:
03270 rpmcnt = 1;
03271
03272 case RPM_STRING_ARRAY_TYPE:
03273
03274
03275 if (dbi->dbi_rpmtag == RPMTAG_FILEMD5S) {
03276 const char * s;
03277
03278 s = rpmvals[i];
03279 t = bin;
03280 for (j = 0; j < 16; j++, t++, s += 2)
03281 *t = (nibble(s[0]) << 4) | nibble(s[1]);
03282 key->data = bin;
03283 key->size = 16;
03284 break;
03285 }
03286
03287 if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
03288 pgpDig dig = pgpNewDig();
03289 const byte * pkt;
03290 ssize_t pktlen;
03291
03292 if (b64decode(rpmvals[i], (void **)&pkt, &pktlen))
03293 continue;
03294 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
03295 memcpy(bin, dig->pubkey.signid, 8);
03296 pkt = _free(pkt);
03297 dig = _free(dig);
03298 key->data = bin;
03299 key->size = 8;
03300 break;
03301 }
03302
03303
03304 default:
03305 key->data = (void *) rpmvals[i];
03306 key->size = strlen(rpmvals[i]);
03307 stringvalued = 1;
03308 break;
03309 }
03310
03311
03312 if (!printed) {
03313 if (rpmcnt == 1 && stringvalued) {
03314 rpmMessage(RPMMESS_DEBUG,
03315 _("adding \"%s\" to %s index.\n"),
03316 (char *)key->data, tagName(dbi->dbi_rpmtag));
03317 } else {
03318 rpmMessage(RPMMESS_DEBUG,
03319 _("adding %d entries to %s index.\n"),
03320 rpmcnt, tagName(dbi->dbi_rpmtag));
03321 }
03322 printed++;
03323 }
03324
03325
03326
03327 set = NULL;
03328
03329 if (key->size == 0) key->size = strlen((char *)key->data);
03330 if (key->size == 0) key->size++;
03331
03332
03333 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
03334 if (rc == 0) {
03335
03336 if (!dbi->dbi_permit_dups)
03337 (void) dbt2set(dbi, data, &set);
03338 } else if (rc != DB_NOTFOUND) {
03339 rpmError(RPMERR_DBGETINDEX,
03340 _("error(%d) getting \"%s\" records from %s index\n"),
03341 rc, key->data, tagName(dbi->dbi_rpmtag));
03342 ret += 1;
03343 continue;
03344 }
03345
03346
03347 if (set == NULL)
03348 set = xcalloc(1, sizeof(*set));
03349
03350 (void) dbiAppendSet(set, rec, 1, sizeof(*rec), 0);
03351
03352
03353 (void) set2dbt(dbi, data, set);
03354 rc = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
03355
03356
03357 if (rc) {
03358 rpmError(RPMERR_DBPUTINDEX,
03359 _("error(%d) storing record %s into %s\n"),
03360 rc, key->data, tagName(dbi->dbi_rpmtag));
03361 ret += 1;
03362 }
03363
03364 data->data = _free(data->data);
03365
03366 data->size = 0;
03367 set = dbiFreeIndexSet(set);
03368 }
03369
03370 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
03371 dbcursor = NULL;
03372
03373 if (!dbi->dbi_no_dbsync)
03374 xx = dbiSync(dbi, 0);
03375 }
03376
03377
03378 if (rpmtype != RPM_BIN_TYPE)
03379 rpmvals = hfd(rpmvals, rpmtype);
03380
03381 rpmtype = 0;
03382 rpmcnt = 0;
03383 }
03384
03385
03386 rec = _free(rec);
03387 }
03388
03389 exit:
03390 (void) unblockSignals(db, &signalMask);
03391
03392 return ret;
03393 }
03394
03395 #define _skip(_dn) { sizeof(_dn)-1, (_dn) }
03396
03397
03398 static struct skipDir_s {
03399 int dnlen;
03400
03401 const char * dn;
03402 } skipDirs[] = {
03403 { 0, NULL }
03404 };
03405
03406 static int skipDir(const char * dn)
03407
03408 {
03409 struct skipDir_s * sd = skipDirs;
03410 int dnlen;
03411
03412 dnlen = strlen(dn);
03413 for (sd = skipDirs; sd->dn != NULL; sd++) {
03414 if (dnlen < sd->dnlen)
03415 continue;
03416 if (strncmp(dn, sd->dn, sd->dnlen))
03417 continue;
03418 return 1;
03419 }
03420 return 0;
03421 }
03422
03423
03424
03425 int rpmdbFindFpList(rpmdb db, fingerPrint * fpList, dbiIndexSet * matchList,
03426 int numItems)
03427 {
03428 DBT * key;
03429 DBT * data;
03430 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
03431 HFD_t hfd = headerFreeData;
03432 rpmdbMatchIterator mi;
03433 fingerPrintCache fpc;
03434 Header h;
03435 int i, xx;
03436
03437 if (db == NULL) return 1;
03438
03439 mi = rpmdbInitIterator(db, RPMTAG_BASENAMES, NULL, 0);
03440 if (mi == NULL)
03441 return 1;
03442
03443 key = &mi->mi_key;
03444 data = &mi->mi_data;
03445
03446
03447 for (i = 0; i < numItems; i++) {
03448
03449
03450 matchList[i] = xcalloc(1, sizeof(*(matchList[i])));
03451
03452
03453
03454 key->data = (void *) fpList[i].baseName;
03455
03456 key->size = strlen((char *)key->data);
03457 if (key->size == 0) key->size++;
03458
03459 if (skipDir(fpList[i].entry->dirName))
03460 continue;
03461
03462 xx = rpmdbGrowIterator(mi, i);
03463
03464 }
03465
03466 if ((i = rpmdbGetIteratorCount(mi)) == 0) {
03467 mi = rpmdbFreeIterator(mi);
03468 return 0;
03469 }
03470 fpc = fpCacheCreate(i);
03471
03472 rpmdbSortIterator(mi);
03473
03474
03475
03476 if (mi != NULL)
03477 while ((h = rpmdbNextIterator(mi)) != NULL) {
03478 const char ** dirNames;
03479 const char ** baseNames;
03480 const char ** fullBaseNames;
03481 rpmTagType bnt, dnt;
03482 int_32 * dirIndexes;
03483 int_32 * fullDirIndexes;
03484 fingerPrint * fps;
03485 dbiIndexItem im;
03486 int start;
03487 int num;
03488 int end;
03489
03490 start = mi->mi_setx - 1;
03491 im = mi->mi_set->recs + start;
03492
03493
03494
03495 for (end = start + 1; end < mi->mi_set->count; end++) {
03496 if (im->hdrNum != mi->mi_set->recs[end].hdrNum)
03497 break;
03498 }
03499
03500 num = end - start;
03501
03502
03503 xx = hge(h, RPMTAG_BASENAMES, &bnt, (void **) &fullBaseNames, NULL);
03504 xx = hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
03505 xx = hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &fullDirIndexes, NULL);
03506
03507 baseNames = xcalloc(num, sizeof(*baseNames));
03508 dirIndexes = xcalloc(num, sizeof(*dirIndexes));
03509
03510 for (i = 0; i < num; i++) {
03511 baseNames[i] = fullBaseNames[im[i].tagNum];
03512 dirIndexes[i] = fullDirIndexes[im[i].tagNum];
03513 }
03514
03515
03516 fps = xcalloc(num, sizeof(*fps));
03517 fpLookupList(fpc, dirNames, baseNames, dirIndexes, num, fps);
03518
03519
03520
03521 for (i = 0; i < num; i++, im++) {
03522
03523 if (!FP_EQUAL(fps[i], fpList[im->fpNum]))
03524 continue;
03525
03526 xx = dbiAppendSet(matchList[im->fpNum], im, 1, sizeof(*im), 0);
03527 }
03528
03529
03530 fps = _free(fps);
03531 dirNames = hfd(dirNames, dnt);
03532 fullBaseNames = hfd(fullBaseNames, bnt);
03533 baseNames = _free(baseNames);
03534 dirIndexes = _free(dirIndexes);
03535
03536 mi->mi_setx = end;
03537 }
03538
03539 mi = rpmdbFreeIterator(mi);
03540
03541 fpc = fpCacheFree(fpc);
03542
03543 return 0;
03544
03545 }
03546
03547
03553 static int rpmioFileExists(const char * urlfn)
03554
03555
03556 {
03557 const char *fn;
03558 int urltype = urlPath(urlfn, &fn);
03559 struct stat buf;
03560
03561
03562 if (*fn == '\0') fn = "/";
03563
03564 switch (urltype) {
03565 case URL_IS_HTTPS:
03566 case URL_IS_HTTP:
03567 case URL_IS_FTP:
03568 case URL_IS_HKP:
03569 case URL_IS_PATH:
03570 case URL_IS_UNKNOWN:
03571 if (Stat(fn, &buf)) {
03572 switch(errno) {
03573 case ENOENT:
03574 case EINVAL:
03575 return 0;
03576 }
03577 }
03578 break;
03579 case URL_IS_DASH:
03580 default:
03581 return 0;
03582 break;
03583 }
03584
03585 return 1;
03586 }
03587
03588 static int rpmdbRemoveDatabase(const char * prefix,
03589 const char * dbpath, int _dbapi)
03590
03591
03592 {
03593 int i;
03594 char * filename;
03595 int xx;
03596
03597 i = strlen(dbpath);
03598
03599 if (dbpath[i - 1] != '/') {
03600 filename = alloca(i);
03601 strcpy(filename, dbpath);
03602 filename[i] = '/';
03603 filename[i + 1] = '\0';
03604 dbpath = filename;
03605 }
03606
03607
03608 filename = alloca(strlen(prefix) + strlen(dbpath) + 40);
03609
03610 switch (_dbapi) {
03611 case 4:
03612
03613 case 3:
03614 if (dbiTags != NULL)
03615 for (i = 0; i < dbiTagsMax; i++) {
03616
03617 const char * base = tagName(dbiTags[i]);
03618
03619 sprintf(filename, "%s/%s/%s", prefix, dbpath, base);
03620 (void)rpmCleanPath(filename);
03621 if (!rpmioFileExists(filename))
03622 continue;
03623 xx = unlink(filename);
03624 }
03625 for (i = 0; i < 16; i++) {
03626 sprintf(filename, "%s/%s/__db.%03d", prefix, dbpath, i);
03627 (void)rpmCleanPath(filename);
03628 if (!rpmioFileExists(filename))
03629 continue;
03630 xx = unlink(filename);
03631 }
03632 break;
03633 case 2:
03634 case 1:
03635 case 0:
03636 break;
03637 }
03638
03639 sprintf(filename, "%s/%s", prefix, dbpath);
03640 (void)rpmCleanPath(filename);
03641 xx = rmdir(filename);
03642
03643 return 0;
03644 }
03645
03646 static int rpmdbMoveDatabase(const char * prefix,
03647 const char * olddbpath, int _olddbapi,
03648 const char * newdbpath, int _newdbapi)
03649
03650
03651 {
03652 int i;
03653 char * ofilename, * nfilename;
03654 struct stat * nst = alloca(sizeof(*nst));
03655 int rc = 0;
03656 int xx;
03657
03658 i = strlen(olddbpath);
03659
03660 if (olddbpath[i - 1] != '/') {
03661 ofilename = alloca(i + 2);
03662 strcpy(ofilename, olddbpath);
03663 ofilename[i] = '/';
03664 ofilename[i + 1] = '\0';
03665 olddbpath = ofilename;
03666 }
03667
03668
03669 i = strlen(newdbpath);
03670
03671 if (newdbpath[i - 1] != '/') {
03672 nfilename = alloca(i + 2);
03673 strcpy(nfilename, newdbpath);
03674 nfilename[i] = '/';
03675 nfilename[i + 1] = '\0';
03676 newdbpath = nfilename;
03677 }
03678
03679
03680 ofilename = alloca(strlen(prefix) + strlen(olddbpath) + 40);
03681 nfilename = alloca(strlen(prefix) + strlen(newdbpath) + 40);
03682
03683 switch (_olddbapi) {
03684 case 4:
03685
03686 case 3:
03687 if (dbiTags != NULL)
03688 for (i = 0; i < dbiTagsMax; i++) {
03689 const char * base;
03690 int rpmtag;
03691
03692
03693 if (isTemporaryDB((rpmtag = dbiTags[i])))
03694 continue;
03695
03696 base = tagName(rpmtag);
03697 sprintf(ofilename, "%s/%s/%s", prefix, olddbpath, base);
03698 (void)rpmCleanPath(ofilename);
03699 if (!rpmioFileExists(ofilename))
03700 continue;
03701 sprintf(nfilename, "%s/%s/%s", prefix, newdbpath, base);
03702 (void)rpmCleanPath(nfilename);
03703
03704
03705
03706
03707
03708 if (stat(nfilename, nst) < 0)
03709 if (stat(ofilename, nst) < 0)
03710 continue;
03711
03712 if ((xx = rename(ofilename, nfilename)) != 0) {
03713 rc = 1;
03714 continue;
03715 }
03716 xx = chown(nfilename, nst->st_uid, nst->st_gid);
03717 xx = chmod(nfilename, (nst->st_mode & 07777));
03718 { struct utimbuf stamp;
03719 stamp.actime = nst->st_atime;
03720 stamp.modtime = nst->st_mtime;
03721 xx = utime(nfilename, &stamp);
03722 }
03723 }
03724 for (i = 0; i < 16; i++) {
03725 sprintf(ofilename, "%s/%s/__db.%03d", prefix, olddbpath, i);
03726 (void)rpmCleanPath(ofilename);
03727 if (rpmioFileExists(ofilename))
03728 xx = unlink(ofilename);
03729 sprintf(nfilename, "%s/%s/__db.%03d", prefix, newdbpath, i);
03730 (void)rpmCleanPath(nfilename);
03731 if (rpmioFileExists(nfilename))
03732 xx = unlink(nfilename);
03733 }
03734 break;
03735 case 2:
03736 case 1:
03737 case 0:
03738 break;
03739 }
03740 #ifdef SQLITE_HACK_XXX
03741 if (rc || _olddbapi == _newdbapi)
03742 return rc;
03743
03744 rc = rpmdbRemoveDatabase(prefix, newdbpath, _newdbapi);
03745
03746
03747
03748 if (rc == 0 && _newdbapi == 1 && _olddbapi == 3) {
03749 const char * mdb1 = "/etc/rpm/macros.db1";
03750 struct stat st;
03751 if (!stat(mdb1, &st) && S_ISREG(st.st_mode) && !unlink(mdb1))
03752 rpmMessage(RPMMESS_DEBUG,
03753 _("removing %s after successful db3 rebuild.\n"), mdb1);
03754 }
03755 #endif
03756 return rc;
03757 }
03758
03759 int rpmdbRebuild(const char * prefix, rpmts ts,
03760 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg))
03761
03762
03763 {
03764 rpmdb olddb;
03765 const char * dbpath = NULL;
03766 const char * rootdbpath = NULL;
03767 rpmdb newdb;
03768 const char * newdbpath = NULL;
03769 const char * newrootdbpath = NULL;
03770 const char * tfn;
03771 int nocleanup = 1;
03772 int failed = 0;
03773 int removedir = 0;
03774 int rc = 0, xx;
03775 int _dbapi;
03776 int _dbapi_rebuild;
03777
03778
03779 if (prefix == NULL) prefix = "/";
03780
03781
03782 _dbapi = rpmExpandNumeric("%{_dbapi}");
03783 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
03784
03785
03786 tfn = rpmGetPath("%{?_dbpath}", NULL);
03787
03788
03789 if (!(tfn && tfn[0] != '\0'))
03790
03791 {
03792 rpmMessage(RPMMESS_DEBUG, _("no dbpath has been set"));
03793 rc = 1;
03794 goto exit;
03795 }
03796 dbpath = rootdbpath = rpmGetPath(prefix, tfn, NULL);
03797 if (!(prefix[0] == '/' && prefix[1] == '\0'))
03798 dbpath += strlen(prefix) - 1;
03799 tfn = _free(tfn);
03800
03801
03802 tfn = rpmGetPath("%{?_dbpath_rebuild}", NULL);
03803
03804
03805 if (!(tfn && tfn[0] != '\0' && strcmp(tfn, dbpath)))
03806
03807 {
03808 char pidbuf[20];
03809 char *t;
03810 sprintf(pidbuf, "rebuilddb.%d", (int) getpid());
03811 t = xmalloc(strlen(dbpath) + strlen(pidbuf) + 1);
03812
03813 (void)stpcpy(stpcpy(t, dbpath), pidbuf);
03814
03815 tfn = _free(tfn);
03816 tfn = t;
03817 nocleanup = 0;
03818 }
03819 newdbpath = newrootdbpath = rpmGetPath(prefix, tfn, NULL);
03820 if (!(prefix[0] == '/' && prefix[1] == '\0'))
03821 newdbpath += strlen(prefix) - 1;
03822 tfn = _free(tfn);
03823
03824 rpmMessage(RPMMESS_DEBUG, _("rebuilding database %s into %s\n"),
03825 rootdbpath, newrootdbpath);
03826
03827 if (!access(newrootdbpath, F_OK)) {
03828 rpmError(RPMERR_MKDIR, _("temporary database %s already exists\n"),
03829 newrootdbpath);
03830 rc = 1;
03831 goto exit;
03832 }
03833
03834 rpmMessage(RPMMESS_DEBUG, _("creating directory %s\n"), newrootdbpath);
03835 if (Mkdir(newrootdbpath, 0755)) {
03836 rpmError(RPMERR_MKDIR, _("creating directory %s: %s\n"),
03837 newrootdbpath, strerror(errno));
03838 rc = 1;
03839 goto exit;
03840 }
03841 removedir = 1;
03842
03843 _rebuildinprogress = 0;
03844
03845 rpmMessage(RPMMESS_DEBUG, _("opening old database with dbapi %d\n"),
03846 _dbapi);
03847
03848 if (openDatabase(prefix, dbpath, _dbapi, &olddb, O_RDONLY, 0644,
03849 RPMDB_FLAG_MINIMAL)) {
03850 rc = 1;
03851 goto exit;
03852 }
03853
03854 _dbapi = olddb->db_api;
03855 _rebuildinprogress = 1;
03856 rpmMessage(RPMMESS_DEBUG, _("opening new database with dbapi %d\n"),
03857 _dbapi_rebuild);
03858 (void) rpmDefineMacro(NULL, "_rpmdb_rebuild %{nil}", -1);
03859
03860 if (openDatabase(prefix, newdbpath, _dbapi_rebuild, &newdb, O_RDWR | O_CREAT, 0644, 0)) {
03861 rc = 1;
03862 goto exit;
03863 }
03864
03865
03866 _rebuildinprogress = 0;
03867
03868 _dbapi_rebuild = newdb->db_api;
03869
03870 { Header h = NULL;
03871 rpmdbMatchIterator mi;
03872 #define _RECNUM rpmdbGetIteratorOffset(mi)
03873
03874 mi = rpmdbInitIterator(olddb, RPMDBI_PACKAGES, NULL, 0);
03875 if (ts && hdrchk)
03876 (void) rpmdbSetHdrChk(mi, ts, hdrchk);
03877
03878 while ((h = rpmdbNextIterator(mi)) != NULL) {
03879
03880
03881 if (!(headerIsEntry(h, RPMTAG_NAME) &&
03882 headerIsEntry(h, RPMTAG_VERSION) &&
03883 headerIsEntry(h, RPMTAG_RELEASE) &&
03884 headerIsEntry(h, RPMTAG_BUILDTIME)))
03885 {
03886 rpmError(RPMERR_INTERNAL,
03887 _("header #%u in the database is bad -- skipping.\n"),
03888 _RECNUM);
03889 continue;
03890 }
03891
03892
03893 if (_db_filter_dups || newdb->db_filter_dups) {
03894 const char * name, * version, * release;
03895 int skip = 0;
03896
03897 (void) headerNVR(h, &name, &version, &release);
03898
03899
03900 { rpmdbMatchIterator mi;
03901 mi = rpmdbInitIterator(newdb, RPMTAG_NAME, name, 0);
03902 (void) rpmdbSetIteratorRE(mi, RPMTAG_VERSION,
03903 RPMMIRE_DEFAULT, version);
03904 (void) rpmdbSetIteratorRE(mi, RPMTAG_RELEASE,
03905 RPMMIRE_DEFAULT, release);
03906 while (rpmdbNextIterator(mi)) {
03907 skip = 1;
03908 break;
03909 }
03910 mi = rpmdbFreeIterator(mi);
03911 }
03912
03913
03914 if (skip)
03915 continue;
03916 }
03917
03918
03919 { Header nh = (headerIsEntry(h, RPMTAG_HEADERIMAGE)
03920 ? headerCopy(h) : NULL);
03921 rc = rpmdbAdd(newdb, -1, (nh ? nh : h), ts, hdrchk);
03922 nh = headerFree(nh);
03923 }
03924
03925 if (rc) {
03926 rpmError(RPMERR_INTERNAL,
03927 _("cannot add record originally at %u\n"), _RECNUM);
03928 failed = 1;
03929 break;
03930 }
03931 }
03932
03933 mi = rpmdbFreeIterator(mi);
03934
03935 }
03936
03937 xx = rpmdbClose(olddb);
03938 xx = rpmdbClose(newdb);
03939
03940 if (failed) {
03941 rpmMessage(RPMMESS_NORMAL, _("failed to rebuild database: original database "
03942 "remains in place\n"));
03943
03944 xx = rpmdbRemoveDatabase(prefix, newdbpath, _dbapi_rebuild);
03945 rc = 1;
03946 goto exit;
03947 } else if (!nocleanup) {
03948 if (rpmdbMoveDatabase(prefix, newdbpath, _dbapi_rebuild, dbpath, _dbapi)) {
03949 rpmMessage(RPMMESS_ERROR, _("failed to replace old database with new "
03950 "database!\n"));
03951 rpmMessage(RPMMESS_ERROR, _("replace files in %s with files from %s "
03952 "to recover"), dbpath, newdbpath);
03953 rc = 1;
03954 goto exit;
03955 }
03956 }
03957 rc = 0;
03958
03959 exit:
03960 if (removedir && !(rc == 0 && nocleanup)) {
03961 rpmMessage(RPMMESS_DEBUG, _("removing directory %s\n"), newrootdbpath);
03962 if (Rmdir(newrootdbpath))
03963 rpmMessage(RPMMESS_ERROR, _("failed to remove directory %s: %s\n"),
03964 newrootdbpath, strerror(errno));
03965 }
03966 newrootdbpath = _free(newrootdbpath);
03967 rootdbpath = _free(rootdbpath);
03968
03969 return rc;
03970 }