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