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