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