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