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