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