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