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