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