00001
00005 #include "system.h"
00006
00007 static int _debug = 0;
00008 #define INLINE
00009
00010 #include <sys/file.h>
00011 #include <signal.h>
00012 #include <sys/signal.h>
00013
00014 #include <fnmatch.h>
00015 #include <regex.h>
00016
00017 #include <rpmcli.h>
00018
00019 #include "rpmdb.h"
00020 #include "fprint.h"
00021 #include "misc.h"
00022 #include "debug.h"
00023
00024
00025
00026
00027
00028
00029
00030 extern int _noDirTokens;
00031
00032 static int _rebuildinprogress = 0;
00033 static int _db_filter_dups = 0;
00034
00035 #define _DBI_FLAGS 0
00036 #define _DBI_PERMS 0644
00037 #define _DBI_MAJOR -1
00038
00039 int * dbiTags = NULL;
00040 int dbiTagsMax = 0;
00041
00047 static int dbiTagToDbix(int rpmtag)
00048
00049 {
00050 int dbix;
00051
00052 if (dbiTags != NULL)
00053 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
00054 if (rpmtag == dbiTags[dbix])
00055 return dbix;
00056 }
00057 return -1;
00058 }
00059
00063 static void dbiTagsInit(void)
00064
00065 {
00066 static const char * const _dbiTagStr_default =
00067 "Packages:Name:Basenames:Group:Requirename:Providename:Conflictname:Triggername:Dirnames:Requireversion:Provideversion:Installtid:Removetid";
00068 char * dbiTagStr = NULL;
00069 char * o, * oe;
00070 int rpmtag;
00071
00072
00073 dbiTagStr = rpmExpand("%{_dbi_tags}", NULL);
00074
00075 if (!(dbiTagStr && *dbiTagStr && *dbiTagStr != '%')) {
00076 dbiTagStr = _free(dbiTagStr);
00077 dbiTagStr = xstrdup(_dbiTagStr_default);
00078 }
00079
00080
00081 dbiTags = _free(dbiTags);
00082 dbiTagsMax = 0;
00083
00084
00085 dbiTags = xcalloc(1, sizeof(*dbiTags));
00086 dbiTags[dbiTagsMax++] = RPMDBI_PACKAGES;
00087
00088 for (o = dbiTagStr; o && *o; o = oe) {
00089 while (*o && xisspace(*o))
00090 o++;
00091 if (*o == '\0')
00092 break;
00093 for (oe = o; oe && *oe; oe++) {
00094 if (xisspace(*oe))
00095 break;
00096 if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/'))
00097 break;
00098 }
00099 if (oe && *oe)
00100 *oe++ = '\0';
00101 rpmtag = tagValue(o);
00102 if (rpmtag < 0) {
00103
00104 fprintf(stderr, _("dbiTagsInit: unrecognized tag name: \"%s\" ignored\n"), o);
00105 continue;
00106 }
00107 if (dbiTagToDbix(rpmtag) >= 0)
00108 continue;
00109
00110 dbiTags = xrealloc(dbiTags, (dbiTagsMax + 1) * sizeof(*dbiTags));
00111 dbiTags[dbiTagsMax++] = rpmtag;
00112 }
00113
00114 dbiTagStr = _free(dbiTagStr);
00115 }
00116
00117
00118 #if USE_DB1
00119 extern struct _dbiVec db1vec;
00120 #define DB1vec &db1vec
00121 #else
00122 #define DB1vec NULL
00123 #endif
00124
00125 #if USE_DB2
00126 extern struct _dbiVec db2vec;
00127 #define DB2vec &db2vec
00128 #else
00129 #define DB2vec NULL
00130 #endif
00131
00132 #if USE_DB3
00133 extern struct _dbiVec db3vec;
00134 #define DB3vec &db3vec
00135 #else
00136 #define DB3vec NULL
00137 #endif
00138
00139
00140
00141 static struct _dbiVec *mydbvecs[] = {
00142 DB1vec, DB1vec, DB2vec, DB3vec, NULL
00143 };
00144
00145
00146 INLINE int dbiSync(dbiIndex dbi, unsigned int flags)
00147 {
00148 if (_debug < 0 || dbi->dbi_debug)
00149 fprintf(stderr, " Sync %s\n", tagName(dbi->dbi_rpmtag));
00150 return (*dbi->dbi_vec->sync) (dbi, flags);
00151 }
00152
00153 INLINE int dbiByteSwapped(dbiIndex dbi)
00154 {
00155 return (*dbi->dbi_vec->byteswapped) (dbi);
00156 }
00157
00158 INLINE int dbiCopen(dbiIndex dbi, DBC ** dbcp, unsigned int flags)
00159 {
00160 if (_debug < 0 || dbi->dbi_debug)
00161 fprintf(stderr, "+++ RMW %s %s\n", tagName(dbi->dbi_rpmtag), ((flags & DBI_WRITECURSOR) ? "WRITECURSOR" : ""));
00162 return (*dbi->dbi_vec->copen) (dbi, dbcp, flags);
00163 }
00164
00165 INLINE int dbiCclose(dbiIndex dbi, DBC * dbcursor, unsigned int flags)
00166 {
00167 if (_debug < 0 || dbi->dbi_debug)
00168 fprintf(stderr, "--- RMW %s\n", tagName(dbi->dbi_rpmtag));
00169 return (*dbi->dbi_vec->cclose) (dbi, dbcursor, flags);
00170 }
00171
00172 static int printable(const void * ptr, size_t len)
00173 {
00174 const char * s = ptr;
00175 int i;
00176 for (i = 0; i < len; i++, s++)
00177 if (!(*s >= ' ' && *s <= '~')) return 0;
00178 return 1;
00179 }
00180
00181 INLINE int dbiDel(dbiIndex dbi, DBC * dbcursor,
00182 const void * keyp, size_t keylen, unsigned int flags)
00183 {
00184 int NULkey;
00185 int rc;
00186
00187
00188 NULkey = (keyp && *((char *)keyp) == '\0' && keylen == 0);
00189 if (NULkey) keylen++;
00190 rc = (*dbi->dbi_vec->cdel) (dbi, dbcursor, keyp, keylen, flags);
00191 if (NULkey) keylen--;
00192
00193 if (_debug < 0 || dbi->dbi_debug)
00194 fprintf(stderr, " Del %s key (%p,%ld) %s rc %d\n", tagName(dbi->dbi_rpmtag), keyp, (long)keylen, (dbi->dbi_rpmtag != RPMDBI_PACKAGES ? (char *)keyp : ""), rc);
00195
00196 return rc;
00197 }
00198
00199 INLINE int dbiGet(dbiIndex dbi, DBC * dbcursor, void ** keypp, size_t * keylenp,
00200 void ** datapp, size_t * datalenp, unsigned int flags)
00201 {
00202 int NULkey;
00203 int rc;
00204
00205
00206 NULkey = (keypp && *keypp && *((char *)(*keypp)) == '\0');
00207 NULkey = (keylenp && *keylenp == 0 && NULkey);
00208 if (keylenp && NULkey) (*keylenp)++;
00209 rc = (*dbi->dbi_vec->cget) (dbi, dbcursor,
00210 keypp, keylenp, datapp, datalenp, flags);
00211 if (keylenp && NULkey) (*keylenp)--;
00212
00213
00214 if (_debug < 0 || dbi->dbi_debug) {
00215 int dataval = 0xdeadbeef;
00216 const char * kvp;
00217 char keyval[64];
00218 keyval[0] = '\0';
00219 if (keypp && *keypp && keylenp) {
00220 if (*keylenp <= sizeof(int) && !printable(*keypp, *keylenp)) {
00221 int keyint = 0;
00222 memcpy(&keyint, *keypp, sizeof(keyint));
00223 sprintf(keyval, "#%d", keyint);
00224 kvp = keyval;
00225 } else {
00226 kvp = *keypp;
00227 }
00228 } else
00229 kvp = keyval;
00230 if (rc == 0 && datapp && *datapp && datalenp && *datalenp >= sizeof(dataval)) {
00231 memcpy(&dataval, *datapp, sizeof(dataval));
00232 }
00233 fprintf(stderr, " Get %s key (%p,%ld) data (%p,%ld) \"%s\" %x rc %d\n",
00234 tagName(dbi->dbi_rpmtag), *keypp, (long)*keylenp, *datapp, (long)*datalenp,
00235 kvp, (unsigned)dataval, rc);
00236 }
00237
00238 return rc;
00239 }
00240
00241 INLINE int dbiPut(dbiIndex dbi, DBC * dbcursor,
00242 const void * keyp, size_t keylen,
00243 const void * datap, size_t datalen, unsigned int flags)
00244 {
00245 int NULkey;
00246 int rc;
00247
00248
00249 NULkey = (keyp && *((char *)keyp) == '\0' && keylen == 0);
00250 if (NULkey) keylen++;
00251 rc = (*dbi->dbi_vec->cput) (dbi, dbcursor, keyp, keylen, datap, datalen, flags);
00252 if (NULkey) keylen--;
00253
00254
00255 if (_debug < 0 || dbi->dbi_debug) {
00256 int dataval = 0xdeadbeef;
00257 const char * kvp;
00258 char keyval[64];
00259 keyval[0] = '\0';
00260 if (keyp) {
00261 if (keylen == sizeof(int) && !printable(keyp, keylen)) {
00262 int keyint = 0;
00263 memcpy(&keyint, keyp, sizeof(keyint));
00264 sprintf(keyval, "#%d", keyint);
00265 kvp = keyval;
00266 } else {
00267 kvp = keyp;
00268 }
00269 } else
00270 kvp = keyval;
00271 if (rc == 0 && datap && datalen >= sizeof(dataval)) {
00272 memcpy(&dataval, datap, sizeof(dataval));
00273 }
00274 fprintf(stderr, " Put %s key (%p,%ld) data (%p,%ld) \"%s\" %x rc %d\n", tagName(dbi->dbi_rpmtag), keyp, (long)keylen, (datap ? datap : NULL), (long)datalen, kvp, (unsigned)dataval, rc);
00275 }
00276
00277
00278 return rc;
00279 }
00280
00281 INLINE int dbiCount(dbiIndex dbi, DBC * dbcursor,
00282 unsigned int * countp, unsigned int flags)
00283 {
00284 int rc = (*dbi->dbi_vec->ccount) (dbi, dbcursor, countp, flags);
00285
00286 if (rc == 0 && countp && *countp > 1)
00287 fprintf(stderr, " Count %s: %u rc %d\n", tagName(dbi->dbi_rpmtag), *countp, rc);
00288
00289 return rc;
00290 }
00291
00292 INLINE int dbiVerify(dbiIndex dbi, unsigned int flags)
00293 {
00294 int dbi_debug = dbi->dbi_debug;
00295 int dbi_rpmtag = dbi->dbi_rpmtag;
00296 int rc;
00297
00298 dbi->dbi_verify_on_close = 1;
00299 rc = (*dbi->dbi_vec->close) (dbi, flags);
00300
00301 if (_debug < 0 || dbi_debug)
00302 fprintf(stderr, " Verify %s rc %d\n", tagName(dbi_rpmtag), rc);
00303
00304 return rc;
00305 }
00306
00307 INLINE int dbiClose(dbiIndex dbi, unsigned int flags) {
00308 if (_debug < 0 || dbi->dbi_debug)
00309 fprintf(stderr, " Close %s\n", tagName(dbi->dbi_rpmtag));
00310 return (*dbi->dbi_vec->close) (dbi, flags);
00311 }
00312
00313 dbiIndex dbiOpen(rpmdb db, int rpmtag, unsigned int flags)
00314 {
00315 int dbix;
00316 dbiIndex dbi = NULL;
00317 int _dbapi, _dbapi_rebuild, _dbapi_wanted;
00318 int rc = 0;
00319
00320 if (db == NULL)
00321 return NULL;
00322
00323 dbix = dbiTagToDbix(rpmtag);
00324 if (dbix < 0 || dbix >= dbiTagsMax)
00325 return NULL;
00326
00327
00328 if ((dbi = db->_dbi[dbix]) != NULL)
00329 return dbi;
00330
00331 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
00332 if (_dbapi_rebuild < 1 || _dbapi_rebuild > 3)
00333 _dbapi_rebuild = 3;
00334 _dbapi_wanted = (_rebuildinprogress ? -1 : db->db_api);
00335
00336 switch (_dbapi_wanted) {
00337 default:
00338 _dbapi = _dbapi_wanted;
00339 if (_dbapi < 0 || _dbapi >= 4 || mydbvecs[_dbapi] == NULL) {
00340 return NULL;
00341 }
00342 errno = 0;
00343 dbi = NULL;
00344 rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi);
00345 if (rc) {
00346 static int _printed[32];
00347 if (!_printed[dbix & 0x1f]++)
00348 rpmError(RPMERR_DBOPEN,
00349 _("cannot open %s index using db%d - %s (%d)\n"),
00350 tagName(rpmtag), _dbapi,
00351 (rc > 0 ? strerror(rc) : ""), rc);
00352 _dbapi = -1;
00353 }
00354 break;
00355 case -1:
00356 _dbapi = 4;
00357 while (_dbapi-- > 1) {
00358 if (mydbvecs[_dbapi] == NULL)
00359 continue;
00360 errno = 0;
00361 dbi = NULL;
00362 rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi);
00363 if (rc == 0 && dbi)
00364 break;
00365 }
00366 if (_dbapi <= 0) {
00367 static int _printed[32];
00368 if (!_printed[dbix & 0x1f]++)
00369 rpmError(RPMERR_DBOPEN, _("cannot open %s index\n"),
00370 tagName(rpmtag));
00371 rc = 1;
00372 goto exit;
00373 }
00374 if (db->db_api == -1 && _dbapi > 0)
00375 db->db_api = _dbapi;
00376 break;
00377 }
00378
00379
00380 if (rc && _dbapi_wanted >= 0 && _dbapi != _dbapi_wanted && _dbapi_wanted == _dbapi_rebuild) {
00381 rc = (_rebuildinprogress ? 0 : 1);
00382 goto exit;
00383 }
00384
00385
00386 if (_dbapi_wanted >= 0 && _dbapi != _dbapi_wanted) {
00387 rc = 1;
00388 goto exit;
00389 }
00390
00391
00392 if (_dbapi_wanted < 0 && _dbapi != _dbapi_rebuild) {
00393 rc = (_rebuildinprogress ? 0 : 1);
00394 goto exit;
00395 }
00396
00397 exit:
00398 if (rc == 0 && dbi)
00399 db->_dbi[dbix] = dbi;
00400 else
00401 dbi = db3Free(dbi);
00402
00403 return dbi;
00404 }
00405
00412 static INLINE dbiIndexItem dbiIndexNewItem(unsigned int hdrNum, unsigned int tagNum)
00413
00414 {
00415 dbiIndexItem rec = xcalloc(1, sizeof(*rec));
00416 rec->hdrNum = hdrNum;
00417 rec->tagNum = tagNum;
00418 return rec;
00419 }
00420
00421 union _dbswap {
00422 unsigned int ui;
00423 unsigned char uc[4];
00424 };
00425
00426 #define _DBSWAP(_a) \
00427 { unsigned char _b, *_c = (_a).uc; \
00428 _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
00429 _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
00430 }
00431
00441 static int dbiSearch(dbiIndex dbi, DBC * dbcursor,
00442 const char * keyp, size_t keylen, dbiIndexSet * setp)
00443
00444 {
00445 unsigned int gflags = 0;
00446 void * datap = NULL;
00447 size_t datalen = 0;
00448 int rc;
00449
00450 if (setp) *setp = NULL;
00451 if (keylen == 0) keylen = strlen(keyp);
00452
00453
00454 rc = dbiGet(dbi, dbcursor, (void **)&keyp, &keylen, &datap, &datalen,
00455 gflags);
00456
00457
00458 if (rc > 0) {
00459 rpmError(RPMERR_DBGETINDEX,
00460 _("error(%d) getting \"%s\" records from %s index\n"),
00461 rc, keyp, tagName(dbi->dbi_rpmtag));
00462 } else
00463 if (rc == 0 && setp) {
00464 int _dbbyteswapped = dbiByteSwapped(dbi);
00465 const char * sdbir = datap;
00466 dbiIndexSet set;
00467 int i;
00468
00469 set = xmalloc(sizeof(*set));
00470
00471
00472 if (sdbir)
00473 switch (dbi->dbi_jlen) {
00474 default:
00475 case 2*sizeof(int_32):
00476 set->count = datalen / (2*sizeof(int_32));
00477 set->recs = xmalloc(set->count * sizeof(*(set->recs)));
00478 for (i = 0; i < set->count; i++) {
00479 union _dbswap hdrNum, tagNum;
00480
00481 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
00482 sdbir += sizeof(hdrNum.ui);
00483 memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
00484 sdbir += sizeof(tagNum.ui);
00485 if (_dbbyteswapped) {
00486 _DBSWAP(hdrNum);
00487 _DBSWAP(tagNum);
00488 }
00489 set->recs[i].hdrNum = hdrNum.ui;
00490 set->recs[i].tagNum = tagNum.ui;
00491 set->recs[i].fpNum = 0;
00492 set->recs[i].dbNum = 0;
00493 }
00494 break;
00495 case 1*sizeof(int_32):
00496 set->count = datalen / (1*sizeof(int_32));
00497 set->recs = xmalloc(set->count * sizeof(*(set->recs)));
00498 for (i = 0; i < set->count; i++) {
00499 union _dbswap hdrNum;
00500
00501 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
00502 sdbir += sizeof(hdrNum.ui);
00503 if (_dbbyteswapped) {
00504 _DBSWAP(hdrNum);
00505 }
00506 set->recs[i].hdrNum = hdrNum.ui;
00507 set->recs[i].tagNum = 0;
00508 set->recs[i].fpNum = 0;
00509 set->recs[i].dbNum = 0;
00510 }
00511 break;
00512 }
00513 if (setp) *setp = set;
00514 }
00515 return rc;
00516 }
00517
00527
00528 static int dbiUpdateIndex(dbiIndex dbi, DBC * dbcursor,
00529 const void * keyp, size_t keylen, dbiIndexSet set)
00530
00531 {
00532 unsigned int pflags = 0;
00533 unsigned int dflags = 0;
00534 void * datap;
00535 size_t datalen;
00536 int rc;
00537
00538 if (set->count) {
00539 char * tdbir;
00540 int i;
00541 int _dbbyteswapped = dbiByteSwapped(dbi);
00542
00543
00544
00545 switch (dbi->dbi_jlen) {
00546 default:
00547 case 2*sizeof(int_32):
00548 datalen = set->count * (2 * sizeof(int_32));
00549 datap = tdbir = alloca(datalen);
00550 for (i = 0; i < set->count; i++) {
00551 union _dbswap hdrNum, tagNum;
00552
00553 memset(&hdrNum, 0, sizeof(hdrNum));
00554 memset(&tagNum, 0, sizeof(tagNum));
00555 hdrNum.ui = set->recs[i].hdrNum;
00556 tagNum.ui = set->recs[i].tagNum;
00557 if (_dbbyteswapped) {
00558 _DBSWAP(hdrNum);
00559 _DBSWAP(tagNum);
00560 }
00561 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
00562 tdbir += sizeof(hdrNum.ui);
00563 memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
00564 tdbir += sizeof(tagNum.ui);
00565 }
00566 break;
00567 case 1*sizeof(int_32):
00568 datalen = set->count * (1 * sizeof(int_32));
00569 datap = tdbir = alloca(datalen);
00570 for (i = 0; i < set->count; i++) {
00571 union _dbswap hdrNum;
00572
00573 memset(&hdrNum, 0, sizeof(hdrNum));
00574 hdrNum.ui = set->recs[i].hdrNum;
00575 if (_dbbyteswapped) {
00576 _DBSWAP(hdrNum);
00577 }
00578 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
00579 tdbir += sizeof(hdrNum.ui);
00580 }
00581 break;
00582 }
00583
00584 rc = dbiPut(dbi, dbcursor, keyp, keylen, datap, datalen, pflags);
00585
00586 if (rc) {
00587 rpmError(RPMERR_DBPUTINDEX,
00588 _("error(%d) storing record %s into %s\n"),
00589 rc, keyp, tagName(dbi->dbi_rpmtag));
00590 }
00591
00592 } else {
00593
00594 rc = dbiDel(dbi, dbcursor, keyp, keylen, dflags);
00595
00596 if (rc) {
00597 rpmError(RPMERR_DBPUTINDEX,
00598 _("error(%d) removing record %s from %s\n"),
00599 rc, keyp, tagName(dbi->dbi_rpmtag));
00600 }
00601
00602 }
00603
00604 return rc;
00605 }
00606
00607
00608
00609 static int hdrNumCmp(const void * one, const void * two)
00610
00611 {
00612 const int * a = one, * b = two;
00613 return (*a - *b);
00614 }
00615
00625 static INLINE int dbiAppendSet(dbiIndexSet set, const void * recs,
00626 int nrecs, size_t recsize, int sortset)
00627
00628 {
00629 const char * rptr = recs;
00630 size_t rlen = (recsize < sizeof(*(set->recs)))
00631 ? recsize : sizeof(*(set->recs));
00632
00633 if (set == NULL || recs == NULL || nrecs <= 0 || recsize == 0)
00634 return 1;
00635
00636 if (set->count == 0)
00637 set->recs = xmalloc(nrecs * sizeof(*(set->recs)));
00638 else
00639 set->recs = xrealloc(set->recs,
00640 (set->count + nrecs) * sizeof(*(set->recs)));
00641
00642 memset(set->recs + set->count, 0, nrecs * sizeof(*(set->recs)));
00643
00644 while (nrecs-- > 0) {
00645
00646 memcpy(set->recs + set->count, rptr, rlen);
00647
00648 rptr += recsize;
00649 set->count++;
00650 }
00651
00652 if (set->count > 1 && sortset)
00653 qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
00654
00655 return 0;
00656 }
00657
00667 static INLINE int dbiPruneSet(dbiIndexSet set, void * recs, int nrecs,
00668 size_t recsize, int sorted)
00669
00670 {
00671 int from;
00672 int to = 0;
00673 int num = set->count;
00674 int numCopied = 0;
00675
00676 if (nrecs > 1 && !sorted)
00677 qsort(recs, nrecs, recsize, hdrNumCmp);
00678
00679 for (from = 0; from < num; from++) {
00680 if (bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) {
00681 set->count--;
00682 continue;
00683 }
00684 if (from != to)
00685 set->recs[to] = set->recs[from];
00686 to++;
00687 numCopied++;
00688 }
00689
00690 return (numCopied == num);
00691 }
00692
00693
00694 unsigned int dbiIndexSetCount(dbiIndexSet set) {
00695 return set->count;
00696 }
00697
00698
00699 unsigned int dbiIndexRecordOffset(dbiIndexSet set, int recno) {
00700 return set->recs[recno].hdrNum;
00701 }
00702
00703
00704 unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, int recno) {
00705 return set->recs[recno].tagNum;
00706 }
00707
00708
00709 dbiIndexSet dbiFreeIndexSet(dbiIndexSet set) {
00710 if (set) {
00711 set->recs = _free(set->recs);
00712 set = _free(set);
00713 }
00714 return set;
00715 }
00716
00720 static int blockSignals( rpmdb db, sigset_t * oldMask)
00721
00722 {
00723 sigset_t newMask;
00724
00725 (void) sigfillset(&newMask);
00726 return sigprocmask(SIG_BLOCK, &newMask, oldMask);
00727 }
00728
00732 static int unblockSignals( rpmdb db, sigset_t * oldMask)
00733
00734 {
00735 return sigprocmask(SIG_SETMASK, oldMask, NULL);
00736 }
00737
00738 #define _DB_ROOT "/"
00739 #define _DB_HOME "%{_dbpath}"
00740 #define _DB_FLAGS 0
00741 #define _DB_MODE 0
00742 #define _DB_PERMS 0644
00743
00744 #define _DB_MAJOR -1
00745 #define _DB_ERRPFX "rpmdb"
00746
00747
00748 static struct rpmdb_s dbTemplate = {
00749 _DB_ROOT, _DB_HOME, _DB_FLAGS, _DB_MODE, _DB_PERMS,
00750 _DB_MAJOR, _DB_ERRPFX
00751 };
00752
00753
00754 int rpmdbOpenAll(rpmdb db)
00755 {
00756 int dbix;
00757 int rc = 0;
00758
00759 if (db == NULL) return -2;
00760
00761 if (dbiTags != NULL)
00762 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
00763 if (db->_dbi[dbix] != NULL)
00764 continue;
00765 (void) dbiOpen(db, dbiTags[dbix], db->db_flags);
00766 }
00767 return rc;
00768 }
00769
00770
00771 int rpmdbClose(rpmdb db)
00772 {
00773 int dbix;
00774 int rc = 0;
00775
00776 if (db == NULL) return 0;
00777 if (db->_dbi)
00778 for (dbix = db->db_ndbi; --dbix >= 0; ) {
00779 int xx;
00780 if (db->_dbi[dbix] == NULL)
00781 continue;
00782
00783 xx = dbiClose(db->_dbi[dbix], 0);
00784 if (xx && rc == 0) rc = xx;
00785 db->_dbi[dbix] = NULL;
00786
00787 }
00788 db->db_errpfx = _free(db->db_errpfx);
00789 db->db_root = _free(db->db_root);
00790 db->db_home = _free(db->db_home);
00791 db->_dbi = _free(db->_dbi);
00792 db = _free(db);
00793 return rc;
00794 }
00795
00796 int rpmdbSync(rpmdb db)
00797 {
00798 int dbix;
00799 int rc = 0;
00800
00801 if (db == NULL) return 0;
00802 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
00803 int xx;
00804 if (db->_dbi[dbix] == NULL)
00805 continue;
00806 xx = dbiSync(db->_dbi[dbix], 0);
00807 if (xx && rc == 0) rc = xx;
00808 }
00809 return rc;
00810 }
00811
00812 static
00813 rpmdb newRpmdb( const char * root,
00814 const char * home,
00815 int mode, int perms, int flags)
00816
00817 {
00818 rpmdb db = xcalloc(sizeof(*db), 1);
00819 const char * epfx = _DB_ERRPFX;
00820 static int _initialized = 0;
00821
00822 if (!_initialized) {
00823 _db_filter_dups = rpmExpandNumeric("%{_filterdbdups}");
00824 _initialized = 1;
00825 }
00826
00827
00828 *db = dbTemplate;
00829
00830
00831 if (!(perms & 0600)) perms = 0644;
00832
00833 if (mode >= 0) db->db_mode = mode;
00834 if (perms >= 0) db->db_perms = perms;
00835 if (flags >= 0) db->db_flags = flags;
00836
00837
00838 db->db_root = rpmGetPath( (root && *root ? root : _DB_ROOT), NULL);
00839 db->db_home = rpmGetPath( (home && *home ? home : _DB_HOME), NULL);
00840
00841 if (!(db->db_home && db->db_home[0] != '%')) {
00842 rpmError(RPMERR_DBOPEN, _("no dbpath has been set\n"));
00843 (void) rpmdbClose(db);
00844 return NULL;
00845 }
00846
00847 db->db_errpfx = rpmExpand( (epfx && *epfx ? epfx : _DB_ERRPFX), NULL);
00848
00849 db->db_remove_env = 0;
00850 db->db_filter_dups = _db_filter_dups;
00851 db->db_ndbi = dbiTagsMax;
00852 db->_dbi = xcalloc(db->db_ndbi, sizeof(*db->_dbi));
00853 return db;
00854 }
00855
00856 static int openDatabase( const char * prefix,
00857 const char * dbpath,
00858 int _dbapi, rpmdb *dbp,
00859 int mode, int perms, int flags)
00860
00861 {
00862 rpmdb db;
00863 int rc;
00864 unsigned int gflags = 0;
00865 static int _initialized = 0;
00866 int justCheck = flags & RPMDB_FLAG_JUSTCHECK;
00867 int minimal = flags & RPMDB_FLAG_MINIMAL;
00868
00869 if (!_initialized || dbiTagsMax == 0) {
00870
00871 #if 1
00872 static int _enable_cdb = -1;
00873
00874
00875 if (_enable_cdb < 0)
00876 _enable_cdb = rpmExpandNumeric("%{?__dbi_cdb:1}");
00877
00878 if (!_enable_cdb) {
00879 char * filename;
00880 int i;
00881
00882 i = sizeof("//__db.000");
00883 if (prefix) i += strlen(prefix);
00884 if (dbpath) i += strlen(dbpath);
00885 filename = alloca(i);
00886 for (i = 0; i < 16; i++) {
00887 sprintf(filename, "%s/%s/__db.%03d",
00888 (prefix ? prefix : ""), (dbpath ? dbpath : ""), i);
00889 (void) rpmCleanPath(filename);
00890 (void) unlink(filename);
00891 }
00892 }
00893 #endif
00894 dbiTagsInit();
00895 _initialized++;
00896 }
00897
00898
00899 if (_dbapi < -1 || _dbapi > 3)
00900 _dbapi = -1;
00901 if (_dbapi == 0)
00902 _dbapi = 1;
00903
00904 if (dbp)
00905 *dbp = NULL;
00906 if (mode & O_WRONLY)
00907 return 1;
00908
00909 db = newRpmdb(prefix, dbpath, mode, perms, flags);
00910 if (db == NULL)
00911 return 1;
00912 db->db_api = _dbapi;
00913
00914 { int dbix;
00915
00916 rc = 0;
00917 if (dbiTags != NULL)
00918 for (dbix = 0; rc == 0 && dbix < dbiTagsMax; dbix++) {
00919 dbiIndex dbi;
00920 int rpmtag;
00921
00922
00923 switch ((rpmtag = dbiTags[dbix])) {
00924 case RPMDBI_AVAILABLE:
00925 case RPMDBI_ADDED:
00926 case RPMDBI_REMOVED:
00927 case RPMDBI_DEPENDS:
00928 continue;
00929 break;
00930 default:
00931 break;
00932 }
00933
00934 dbi = dbiOpen(db, rpmtag, 0);
00935 if (dbi == NULL) {
00936 rc = -2;
00937 break;
00938 }
00939
00940 switch (rpmtag) {
00941 case RPMDBI_PACKAGES:
00942 if (dbi == NULL) rc |= 1;
00943
00944 #if 0
00945 if (db->db_api == 3)
00946 #endif
00947 goto exit;
00948 break;
00949 case RPMTAG_NAME:
00950 if (dbi == NULL) rc |= 1;
00951 if (minimal)
00952 goto exit;
00953 break;
00954 case RPMTAG_BASENAMES:
00955 { void * keyp = NULL;
00956 DBC * dbcursor;
00957 int xx;
00958
00959
00960
00961
00962
00963
00964
00965 if (justCheck)
00966 break;
00967 dbcursor = NULL;
00968 xx = dbiCopen(dbi, &dbcursor, 0);
00969 xx = dbiGet(dbi, dbcursor, &keyp, NULL, NULL, NULL, gflags);
00970 if (xx == 0) {
00971 const char * akey = keyp;
00972 if (akey && strchr(akey, '/')) {
00973 rpmError(RPMERR_OLDDB, _("old format database is present; "
00974 "use --rebuilddb to generate a new format database\n"));
00975 rc |= 1;
00976 }
00977 }
00978 xx = dbiCclose(dbi, dbcursor, 0);
00979 dbcursor = NULL;
00980 } break;
00981 default:
00982 break;
00983 }
00984 }
00985 }
00986
00987 exit:
00988 if (rc || justCheck || dbp == NULL)
00989 (void) rpmdbClose(db);
00990 else
00991 *dbp = db;
00992
00993 return rc;
00994 }
00995
00996
00997 int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, int perms)
00998 {
00999 int _dbapi = rpmExpandNumeric("%{_dbapi}");
01000 return openDatabase(prefix, NULL, _dbapi, dbp, mode, perms, 0);
01001 }
01002
01003 int rpmdbInit (const char * prefix, int perms)
01004 {
01005 rpmdb db = NULL;
01006 int _dbapi = rpmExpandNumeric("%{_dbapi}");
01007 int rc;
01008
01009 rc = openDatabase(prefix, NULL, _dbapi, &db, (O_CREAT | O_RDWR),
01010 perms, RPMDB_FLAG_JUSTCHECK);
01011 if (db != NULL) {
01012 int xx;
01013 xx = rpmdbOpenAll(db);
01014 if (xx && rc == 0) rc = xx;
01015 xx = rpmdbClose(db);
01016 if (xx && rc == 0) rc = xx;
01017 db = NULL;
01018 }
01019 return rc;
01020 }
01021
01022 int rpmdbVerify(const char * prefix)
01023 {
01024 rpmdb db = NULL;
01025 int _dbapi = rpmExpandNumeric("%{_dbapi}");
01026 int rc = 0;
01027
01028 rc = openDatabase(prefix, NULL, _dbapi, &db, O_RDONLY, 0644, 0);
01029 if (rc) return rc;
01030
01031 if (db != NULL) {
01032 int dbix;
01033 int xx;
01034 rc = rpmdbOpenAll(db);
01035
01036 for (dbix = db->db_ndbi; --dbix >= 0; ) {
01037 if (db->_dbi[dbix] == NULL)
01038 continue;
01039
01040 xx = dbiVerify(db->_dbi[dbix], 0);
01041 if (xx && rc == 0) rc = xx;
01042 db->_dbi[dbix] = NULL;
01043
01044 }
01045
01046
01047 xx = rpmdbClose(db);
01048
01049 if (xx && rc == 0) rc = xx;
01050 db = NULL;
01051 }
01052 return rc;
01053 }
01054
01055 static int rpmdbFindByFile(rpmdb db, const char * filespec,
01056 dbiIndexSet * matches)
01057
01058 {
01059 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
01060 HFD_t hfd = headerFreeData;
01061 const char * dirName;
01062 const char * baseName;
01063 rpmTagType bnt, dnt;
01064 fingerPrintCache fpc;
01065 fingerPrint fp1;
01066 dbiIndex dbi = NULL;
01067 DBC * dbcursor;
01068 dbiIndexSet allMatches = NULL;
01069 dbiIndexItem rec = NULL;
01070 int i;
01071 int rc;
01072 int xx;
01073
01074 *matches = NULL;
01075 if (filespec == NULL) return -2;
01076 if ((baseName = strrchr(filespec, '/')) != NULL) {
01077 char * t;
01078 size_t len;
01079
01080 len = baseName - filespec + 1;
01081 t = strncpy(alloca(len + 1), filespec, len);
01082 t[len] = '\0';
01083 dirName = t;
01084 baseName++;
01085 } else {
01086 dirName = "";
01087 baseName = filespec;
01088 }
01089 if (baseName == NULL)
01090 return -2;
01091
01092 fpc = fpCacheCreate(20);
01093 fp1 = fpLookup(fpc, dirName, baseName, 1);
01094
01095 dbi = dbiOpen(db, RPMTAG_BASENAMES, 0);
01096 if (dbi != NULL) {
01097 dbcursor = NULL;
01098 xx = dbiCopen(dbi, &dbcursor, 0);
01099 rc = dbiSearch(dbi, dbcursor, baseName, strlen(baseName), &allMatches);
01100 xx = dbiCclose(dbi, dbcursor, 0);
01101 dbcursor = NULL;
01102 } else
01103 rc = -2;
01104
01105 if (rc) {
01106 allMatches = dbiFreeIndexSet(allMatches);
01107 fpCacheFree(fpc);
01108 return rc;
01109 }
01110
01111 *matches = xcalloc(1, sizeof(**matches));
01112 rec = dbiIndexNewItem(0, 0);
01113 i = 0;
01114 if (allMatches != NULL)
01115 while (i < allMatches->count) {
01116 const char ** baseNames, ** dirNames;
01117 int_32 * dirIndexes;
01118 unsigned int offset = dbiIndexRecordOffset(allMatches, i);
01119 unsigned int prevoff;
01120 Header h;
01121
01122 { rpmdbMatchIterator mi;
01123 mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &offset, sizeof(offset));
01124 h = rpmdbNextIterator(mi);
01125 if (h)
01126 h = headerLink(h);
01127 mi = rpmdbFreeIterator(mi);
01128 }
01129
01130 if (h == NULL) {
01131 i++;
01132 continue;
01133 }
01134
01135 (void) hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, NULL);
01136 (void) hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
01137 (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
01138
01139 do {
01140 fingerPrint fp2;
01141 int num = dbiIndexRecordFileNumber(allMatches, i);
01142
01143 fp2 = fpLookup(fpc, dirNames[dirIndexes[num]], baseNames[num], 1);
01144
01145 if (FP_EQUAL(fp1, fp2)) {
01146
01147 rec->hdrNum = dbiIndexRecordOffset(allMatches, i);
01148 rec->tagNum = dbiIndexRecordFileNumber(allMatches, i);
01149 (void) dbiAppendSet(*matches, rec, 1, sizeof(*rec), 0);
01150 }
01151
01152 prevoff = offset;
01153 i++;
01154 offset = dbiIndexRecordOffset(allMatches, i);
01155 } while (i < allMatches->count &&
01156 (i == 0 || offset == prevoff));
01157
01158 baseNames = hfd(baseNames, bnt);
01159 dirNames = hfd(dirNames, dnt);
01160 h = headerFree(h);
01161 }
01162
01163 rec = _free(rec);
01164 allMatches = dbiFreeIndexSet(allMatches);
01165
01166 fpCacheFree(fpc);
01167
01168 if ((*matches)->count == 0) {
01169 *matches = dbiFreeIndexSet(*matches);
01170 return 1;
01171 }
01172
01173 return 0;
01174 }
01175
01176
01177 int rpmdbCountPackages(rpmdb db, const char * name)
01178 {
01179 dbiIndex dbi;
01180 dbiIndexSet matches = NULL;
01181 int rc = -1;
01182 int xx;
01183
01184 if (db == NULL)
01185 return 0;
01186
01187
01188
01189
01190
01191 if (name == NULL || *name == '\0')
01192 return 0;
01193
01194 dbi = dbiOpen(db, RPMTAG_NAME, 0);
01195 if (dbi) {
01196 DBC * dbcursor = NULL;
01197 xx = dbiCopen(dbi, &dbcursor, 0);
01198 rc = dbiSearch(dbi, dbcursor, name, strlen(name), &matches);
01199 xx = dbiCclose(dbi, dbcursor, 0);
01200 dbcursor = NULL;
01201 }
01202
01203 if (rc == 0)
01204 rc = dbiIndexSetCount(matches);
01205 else if (rc > 0)
01206 rpmError(RPMERR_DBCORRUPT, _("error(%d) counting packages\n"), rc);
01207 else
01208 rc = 0;
01209
01210 matches = dbiFreeIndexSet(matches);
01211
01212 return rc;
01213 }
01214
01215
01216
01217
01218
01229 static int dbiFindMatches(dbiIndex dbi, DBC * dbcursor,
01230 const char * name,
01231 const char * version,
01232 const char * release,
01233 dbiIndexSet * matches)
01234
01235 {
01236 int gotMatches;
01237 int rc;
01238 int i;
01239
01240 rc = dbiSearch(dbi, dbcursor, name, strlen(name), matches);
01241
01242 if (rc != 0) {
01243 rc = ((rc == -1) ? 2 : 1);
01244 goto exit;
01245 }
01246
01247 if (version == NULL && release == NULL) {
01248 rc = 0;
01249 goto exit;
01250 }
01251
01252 gotMatches = 0;
01253
01254
01255 for (i = 0; i < dbiIndexSetCount(*matches); i++) {
01256 unsigned int recoff = dbiIndexRecordOffset(*matches, i);
01257 Header h;
01258
01259 if (recoff == 0)
01260 continue;
01261
01262 { rpmdbMatchIterator mi;
01263 mi = rpmdbInitIterator(dbi->dbi_rpmdb,
01264 RPMDBI_PACKAGES, &recoff, sizeof(recoff));
01265
01266
01267 if (version &&
01268 rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version))
01269 {
01270 rc = 2;
01271 goto exit;
01272 }
01273 if (release &&
01274 rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release))
01275 {
01276 rc = 2;
01277 goto exit;
01278 }
01279
01280 h = rpmdbNextIterator(mi);
01281 if (h)
01282 h = headerLink(h);
01283 mi = rpmdbFreeIterator(mi);
01284 }
01285
01286 if (h)
01287 (*matches)->recs[gotMatches++] = (*matches)->recs[i];
01288 else
01289 (*matches)->recs[i].hdrNum = 0;
01290
01291 h = headerFree(h);
01292 }
01293
01294 if (gotMatches) {
01295 (*matches)->count = gotMatches;
01296 rc = 0;
01297 } else
01298 rc = 1;
01299
01300 exit:
01301 if (rc && matches && *matches) {
01302
01303 *matches = dbiFreeIndexSet(*matches);
01304
01305 }
01306 return rc;
01307 }
01308
01319 static int dbiFindByLabel(dbiIndex dbi, DBC * dbcursor,
01320 const char * arg, dbiIndexSet * matches)
01321
01322 {
01323 const char * release;
01324 char * localarg;
01325 char * s;
01326 char c;
01327 int brackets;
01328 int rc;
01329
01330 if (arg == NULL || strlen(arg) == 0) return 1;
01331
01332
01333 rc = dbiFindMatches(dbi, dbcursor, arg, NULL, NULL, matches);
01334 if (rc != 1) return rc;
01335
01336
01337 *matches = dbiFreeIndexSet(*matches);
01338
01339
01340
01341 localarg = alloca(strlen(arg) + 1);
01342 s = stpcpy(localarg, arg);
01343
01344 c = '\0';
01345 brackets = 0;
01346 for (s -= 1; s > localarg; s--) {
01347 switch (*s) {
01348 case '[': brackets = 1; break;
01349 case ']': if (c != '[') brackets = 0; break;
01350 }
01351 c = *s;
01352 if (!brackets && *s == '-')
01353 break;
01354 }
01355
01356
01357 if (s == localarg) return 1;
01358
01359 *s = '\0';
01360 rc = dbiFindMatches(dbi, dbcursor, localarg, s + 1, NULL, matches);
01361 if (rc != 1) return rc;
01362
01363
01364 *matches = dbiFreeIndexSet(*matches);
01365
01366
01367
01368
01369 release = s + 1;
01370
01371 c = '\0';
01372 brackets = 0;
01373 for (; s > localarg; s--) {
01374 switch (*s) {
01375 case '[': brackets = 1; break;
01376 case ']': if (c != '[') brackets = 0; break;
01377 }
01378 c = *s;
01379 if (!brackets && *s == '-')
01380 break;
01381 }
01382
01383 if (s == localarg) return 1;
01384
01385 *s = '\0';
01386 return dbiFindMatches(dbi, dbcursor, localarg, s + 1, release, matches);
01387
01388 }
01389
01400 static int dbiUpdateRecord(dbiIndex dbi, DBC * dbcursor, int offset, Header h)
01401
01402 {
01403 sigset_t signalMask;
01404 void * uh;
01405 size_t uhlen;
01406 int rc = EINVAL;
01407 unsigned int pflags = 0;
01408 int xx;
01409
01410 if (_noDirTokens)
01411 expandFilelist(h);
01412
01413 uhlen = headerSizeof(h, HEADER_MAGIC_NO);
01414 uh = headerUnload(h);
01415 if (uh) {
01416 (void) blockSignals(dbi->dbi_rpmdb, &signalMask);
01417 rc = dbiPut(dbi, dbcursor, &offset, sizeof(offset), uh, uhlen, pflags);
01418 xx = dbiSync(dbi, 0);
01419 (void) unblockSignals(dbi->dbi_rpmdb, &signalMask);
01420 uh = _free(uh);
01421 }
01422 return rc;
01423 }
01424
01425 typedef struct miRE_s {
01426 rpmTag tag;
01427 rpmMireMode mode;
01428 const char * pattern;
01429 int notmatch;
01430 regex_t * preg;
01431 int cflags;
01432 int eflags;
01433 int fnflags;
01434 } * miRE;
01435
01436 struct _rpmdbMatchIterator {
01437 const void * mi_keyp;
01438 size_t mi_keylen;
01439 rpmdb mi_rpmdb;
01440 int mi_rpmtag;
01441 dbiIndexSet mi_set;
01442 DBC * mi_dbc;
01443 unsigned int mi_ndups;
01444 int mi_setx;
01445 Header mi_h;
01446 int mi_sorted;
01447 int mi_cflags;
01448 int mi_modified;
01449 unsigned int mi_prevoffset;
01450 unsigned int mi_offset;
01451 unsigned int mi_filenum;
01452 unsigned int mi_fpnum;
01453 unsigned int mi_dbnum;
01454 int mi_nre;
01455 miRE mi_re;
01456 const char * mi_version;
01457 const char * mi_release;
01458 };
01459
01460 rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi)
01461 {
01462 dbiIndex dbi = NULL;
01463 int xx;
01464 int i;
01465
01466 if (mi == NULL)
01467 return mi;
01468
01469 dbi = dbiOpen(mi->mi_rpmdb, RPMDBI_PACKAGES, 0);
01470 if (mi->mi_h) {
01471 if (dbi && mi->mi_dbc && mi->mi_modified && mi->mi_prevoffset) {
01472 xx = dbiUpdateRecord(dbi, mi->mi_dbc, mi->mi_prevoffset, mi->mi_h);
01473 }
01474 mi->mi_h = headerFree(mi->mi_h);
01475 }
01476 if (dbi) {
01477 if (dbi->dbi_rmw)
01478 xx = dbiCclose(dbi, dbi->dbi_rmw, 0);
01479 dbi->dbi_rmw = NULL;
01480 }
01481
01482 if (mi->mi_re != NULL)
01483 for (i = 0; i < mi->mi_nre; i++) {
01484 miRE mire = mi->mi_re + i;
01485 mire->pattern = _free(mire->pattern);
01486 if (mire->preg != NULL) {
01487 regfree(mire->preg);
01488
01489 mire->preg = _free(mire->preg);
01490
01491 }
01492 }
01493 mi->mi_re = _free(mi->mi_re);
01494
01495 mi->mi_release = _free(mi->mi_release);
01496 mi->mi_version = _free(mi->mi_version);
01497 if (dbi && mi->mi_dbc)
01498 xx = dbiCclose(dbi, mi->mi_dbc, DBI_ITERATOR);
01499 mi->mi_dbc = NULL;
01500 mi->mi_set = dbiFreeIndexSet(mi->mi_set);
01501 mi->mi_keyp = _free(mi->mi_keyp);
01502 mi = _free(mi);
01503 return mi;
01504 }
01505
01506 rpmdb rpmdbGetIteratorRpmDB(rpmdbMatchIterator mi) {
01507 if (mi == NULL)
01508 return NULL;
01509
01510 return mi->mi_rpmdb;
01511
01512 }
01513
01514 unsigned int rpmdbGetIteratorOffset(rpmdbMatchIterator mi) {
01515 if (mi == NULL)
01516 return 0;
01517 return mi->mi_offset;
01518 }
01519
01520 unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi) {
01521 if (mi == NULL)
01522 return 0;
01523 return mi->mi_filenum;
01524 }
01525
01526 int rpmdbGetIteratorCount(rpmdbMatchIterator mi) {
01527 if (!(mi && mi->mi_set))
01528 return 0;
01529 return mi->mi_set->count;
01530 }
01531
01537 static int miregexec(miRE mire, const char * val)
01538
01539 {
01540 int rc = 0;
01541
01542 switch (mire->mode) {
01543 case RPMMIRE_STRCMP:
01544 rc = strcmp(mire->pattern, val);
01545 break;
01546 case RPMMIRE_DEFAULT:
01547 case RPMMIRE_REGEX:
01548 rc = regexec(mire->preg, val, 0, NULL, mire->eflags);
01549 if (rc && rc != REG_NOMATCH) {
01550 char msg[256];
01551 (void) regerror(rc, mire->preg, msg, sizeof(msg)-1);
01552 msg[sizeof(msg)-1] = '\0';
01553 rpmError(RPMERR_REGEXEC, "%s: regexec failed: %s\n",
01554 mire->pattern, msg);
01555 rc = -1;
01556 }
01557 break;
01558 case RPMMIRE_GLOB:
01559 rc = fnmatch(mire->pattern, val, mire->fnflags);
01560 if (rc && rc != FNM_NOMATCH)
01561 rc = -1;
01562 break;
01563 default:
01564 rc = -1;
01565 break;
01566 }
01567
01568 return rc;
01569 }
01570
01577 static int mireCmp(const void * a, const void * b)
01578 {
01579 const miRE mireA = (const miRE) a;
01580 const miRE mireB = (const miRE) b;
01581 return (mireA->tag - mireB->tag);
01582 }
01583
01591 static char * mireDup(rpmTag tag, rpmMireMode *modep,
01592 const char * pattern)
01593
01594 {
01595 const char * s;
01596 char * pat;
01597 char * t;
01598 int brackets;
01599 size_t nb;
01600 int c;
01601
01602 switch (*modep) {
01603 default:
01604 case RPMMIRE_DEFAULT:
01605 if (tag == RPMTAG_DIRNAMES || tag == RPMTAG_BASENAMES) {
01606 *modep = RPMMIRE_GLOB;
01607 pat = xstrdup(pattern);
01608 break;
01609 }
01610
01611 nb = strlen(pattern) + sizeof("^$");
01612
01613
01614 c = '\0';
01615 brackets = 0;
01616 for (s = pattern; *s != '\0'; s++) {
01617 switch (*s) {
01618 case '.':
01619 case '*': if (!brackets) nb++; break;
01620 case '\\': s++; break;
01621 case '[': brackets = 1; break;
01622 case ']': if (c != '[') brackets = 0; break;
01623 }
01624 c = *s;
01625 }
01626
01627 pat = t = xmalloc(nb);
01628
01629 if (pattern[0] != '^') *t++ = '^';
01630
01631
01632 c = '\0';
01633 brackets = 0;
01634 for (s = pattern; *s != '\0'; s++, t++) {
01635 switch (*s) {
01636 case '.': if (!brackets) *t++ = '\\'; break;
01637 case '*': if (!brackets) *t++ = '.'; break;
01638 case '\\': *t++ = *s++; break;
01639 case '[': brackets = 1; break;
01640 case ']': if (c != '[') brackets = 0; break;
01641 }
01642 c = *t = *s;
01643 }
01644
01645 if (pattern[nb-1] != '$') *t++ = '$';
01646 *t = '\0';
01647 *modep = RPMMIRE_REGEX;
01648 break;
01649 case RPMMIRE_STRCMP:
01650 case RPMMIRE_REGEX:
01651 case RPMMIRE_GLOB:
01652 pat = xstrdup(pattern);
01653 break;
01654 }
01655
01656 return pat;
01657 }
01658
01659 int rpmdbSetIteratorRE(rpmdbMatchIterator mi, rpmTag tag,
01660 rpmMireMode mode, const char * pattern)
01661 {
01662 static rpmMireMode defmode = (rpmMireMode)-1;
01663 miRE mire = NULL;
01664 const char * allpat = NULL;
01665 int notmatch = 0;
01666 regex_t * preg = NULL;
01667 int cflags = 0;
01668 int eflags = 0;
01669 int fnflags = 0;
01670 int rc = 0;
01671
01672 if (defmode == (rpmMireMode)-1) {
01673 const char *t = rpmExpand("%{?_query_selector_match}", NULL);
01674 if (*t == '\0' || !strcmp(t, "default"))
01675 defmode = RPMMIRE_DEFAULT;
01676 else if (!strcmp(t, "strcmp"))
01677 defmode = RPMMIRE_STRCMP;
01678 else if (!strcmp(t, "regex"))
01679 defmode = RPMMIRE_REGEX;
01680 else if (!strcmp(t, "glob"))
01681 defmode = RPMMIRE_GLOB;
01682 else
01683 defmode = RPMMIRE_DEFAULT;
01684 t = _free(t);
01685 }
01686
01687 if (mi == NULL || pattern == NULL)
01688 return rc;
01689
01690
01691 if (*pattern == '!') {
01692 notmatch = 1;
01693 pattern++;
01694 }
01695
01696
01697 allpat = mireDup(tag, &mode, pattern);
01698
01699
01700 if (mode == RPMMIRE_DEFAULT)
01701 mode = defmode;
01702
01703 switch (mode) {
01704 case RPMMIRE_DEFAULT:
01705 case RPMMIRE_STRCMP:
01706 break;
01707 case RPMMIRE_REGEX:
01708 preg = xcalloc(1, sizeof(*preg));
01709 cflags = (REG_EXTENDED | REG_NOSUB);
01710 rc = regcomp(preg, allpat, cflags);
01711 if (rc) {
01712 char msg[256];
01713 (void) regerror(rc, preg, msg, sizeof(msg)-1);
01714 msg[sizeof(msg)-1] = '\0';
01715 rpmError(RPMERR_REGCOMP, "%s: regcomp failed: %s\n", allpat, msg);
01716 }
01717 break;
01718 case RPMMIRE_GLOB:
01719 fnflags = FNM_PATHNAME | FNM_PERIOD;
01720 break;
01721 default:
01722 rc = -1;
01723 break;
01724 }
01725
01726 if (rc) {
01727
01728 allpat = _free(allpat);
01729 if (preg) {
01730 regfree(preg);
01731
01732 preg = _free(preg);
01733
01734 }
01735
01736 return rc;
01737 }
01738
01739 mi->mi_re = xrealloc(mi->mi_re, (mi->mi_nre + 1) * sizeof(*mi->mi_re));
01740 mire = mi->mi_re + mi->mi_nre;
01741 mi->mi_nre++;
01742
01743 mire->tag = tag;
01744 mire->mode = mode;
01745 mire->pattern = allpat;
01746 mire->notmatch = notmatch;
01747 mire->preg = preg;
01748 mire->cflags = cflags;
01749 mire->eflags = eflags;
01750 mire->fnflags = fnflags;
01751
01752 (void) qsort(mi->mi_re, mi->mi_nre, sizeof(*mi->mi_re), mireCmp);
01753
01754 return rc;
01755 }
01756
01762 static int mireSkip (const rpmdbMatchIterator mi)
01763
01764 {
01765
01766 HGE_t hge = (HGE_t) headerGetEntryMinMemory;
01767 HFD_t hfd = (HFD_t) headerFreeData;
01768 union {
01769 void * ptr;
01770 const char ** argv;
01771 const char * str;
01772 int_32 * i32p;
01773 int_16 * i16p;
01774 int_8 * i8p;
01775 } u;
01776 char numbuf[32];
01777 rpmTagType t;
01778 int_32 c;
01779 miRE mire;
01780 int ntags = 0;
01781 int nmatches = 0;
01782 int i, j;
01783 int rc;
01784
01785 if (mi->mi_h == NULL)
01786 return 0;
01787
01788
01789
01790
01791
01792 if ((mire = mi->mi_re) != NULL)
01793 for (i = 0; i < mi->mi_nre; i++, mire++) {
01794 int anymatch;
01795
01796 if (!hge(mi->mi_h, mire->tag, &t, (void **)&u, &c))
01797 continue;
01798
01799 anymatch = 0;
01800 while (1) {
01801 switch (t) {
01802 case RPM_CHAR_TYPE:
01803 case RPM_INT8_TYPE:
01804 sprintf(numbuf, "%d", (int) *u.i8p);
01805 rc = miregexec(mire, numbuf);
01806 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
01807 anymatch++;
01808 break;
01809 case RPM_INT16_TYPE:
01810 sprintf(numbuf, "%d", (int) *u.i16p);
01811 rc = miregexec(mire, numbuf);
01812 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
01813 anymatch++;
01814 break;
01815 case RPM_INT32_TYPE:
01816 sprintf(numbuf, "%d", (int) *u.i32p);
01817 rc = miregexec(mire, numbuf);
01818 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
01819 anymatch++;
01820 break;
01821 case RPM_STRING_TYPE:
01822 rc = miregexec(mire, u.str);
01823 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
01824 anymatch++;
01825 break;
01826 case RPM_I18NSTRING_TYPE:
01827 case RPM_STRING_ARRAY_TYPE:
01828 for (j = 0; j < c; j++) {
01829 rc = miregexec(mire, u.argv[j]);
01830 if ((!rc && !mire->notmatch) || (rc && mire->notmatch)) {
01831 anymatch++;
01832 break;
01833 }
01834 }
01835 break;
01836 case RPM_NULL_TYPE:
01837 case RPM_BIN_TYPE:
01838 default:
01839 break;
01840 }
01841 if ((i+1) < mi->mi_nre && mire[0].tag == mire[1].tag) {
01842 i++;
01843 mire++;
01844 continue;
01845 }
01846 break;
01847 }
01848
01849 u.ptr = hfd(u.ptr, t);
01850
01851 ntags++;
01852 if (anymatch)
01853 nmatches++;
01854 }
01855
01856 return (ntags == nmatches ? 0 : 1);
01857
01858 }
01859
01860 int rpmdbSetIteratorRelease(rpmdbMatchIterator mi, const char * release) {
01861 return rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release);
01862 }
01863
01864 int rpmdbSetIteratorVersion(rpmdbMatchIterator mi, const char * version) {
01865 return rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version);
01866 }
01867
01868 int rpmdbSetIteratorRewrite(rpmdbMatchIterator mi, int rewrite) {
01869 int rc;
01870 if (mi == NULL)
01871 return 0;
01872 rc = (mi->mi_cflags & DBI_WRITECURSOR) ? 1 : 0;
01873 if (rewrite)
01874 mi->mi_cflags |= DBI_WRITECURSOR;
01875 else
01876 mi->mi_cflags &= ~DBI_WRITECURSOR;
01877 return rc;
01878 }
01879
01880 int rpmdbSetIteratorModified(rpmdbMatchIterator mi, int modified) {
01881 int rc;
01882 if (mi == NULL)
01883 return 0;
01884 rc = mi->mi_modified;
01885 mi->mi_modified = modified;
01886 return rc;
01887 }
01888
01889 Header XrpmdbNextIterator(rpmdbMatchIterator mi,
01890 const char * f, unsigned int l)
01891 {
01892 return rpmdbNextIterator(mi);
01893 }
01894
01895 Header rpmdbNextIterator(rpmdbMatchIterator mi)
01896 {
01897 dbiIndex dbi;
01898 void * uh = NULL;
01899 size_t uhlen = 0;
01900 unsigned int gflags = 0;
01901 void * keyp;
01902 size_t keylen;
01903 int rc;
01904 int xx;
01905
01906 if (mi == NULL)
01907 return NULL;
01908
01909 dbi = dbiOpen(mi->mi_rpmdb, RPMDBI_PACKAGES, 0);
01910 if (dbi == NULL)
01911 return NULL;
01912
01913
01914
01915
01916
01917
01918
01919 if (mi->mi_dbc == NULL)
01920 xx = dbiCopen(dbi, &mi->mi_dbc, (mi->mi_cflags | DBI_ITERATOR));
01921 dbi->dbi_lastoffset = mi->mi_prevoffset;
01922
01923 top:
01924
01925 do {
01926 if (mi->mi_set) {
01927 if (!(mi->mi_setx < mi->mi_set->count))
01928 return NULL;
01929 mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx);
01930 mi->mi_filenum = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx);
01931 keyp = &mi->mi_offset;
01932 keylen = sizeof(mi->mi_offset);
01933 } else {
01934 keyp = (void *)mi->mi_keyp;
01935 keylen = mi->mi_keylen;
01936
01937 rc = dbiGet(dbi, mi->mi_dbc, &keyp, &keylen, &uh, &uhlen, gflags);
01938 if (dbi->dbi_api == 1 && dbi->dbi_rpmtag == RPMDBI_PACKAGES && rc == EFAULT) {
01939 rpmError(RPMERR_INTERNAL,
01940 _("record number %u in database is bad -- skipping.\n"), dbi->dbi_lastoffset);
01941 if (keyp && dbi->dbi_lastoffset)
01942 memcpy(&mi->mi_offset, keyp, sizeof(mi->mi_offset));
01943 continue;
01944 }
01945
01946
01947
01948
01949
01950
01951
01952
01953 if (rc == 0 && keyp && (dbi->dbi_lastoffset || mi->mi_setx))
01954 memcpy(&mi->mi_offset, keyp, sizeof(mi->mi_offset));
01955
01956
01957 if (rc || (mi->mi_setx && mi->mi_offset == 0))
01958 return NULL;
01959 }
01960 mi->mi_setx++;
01961 } while (mi->mi_offset == 0);
01962
01963 if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset)
01964 goto exit;
01965
01966
01967 if (uh == NULL) {
01968 rc = dbiGet(dbi, mi->mi_dbc, &keyp, &keylen, &uh, &uhlen, gflags);
01969 if (rc)
01970 return NULL;
01971 }
01972
01973
01974 if (mi->mi_h) {
01975 if (mi->mi_modified && mi->mi_prevoffset)
01976 (void)dbiUpdateRecord(dbi, mi->mi_dbc, mi->mi_prevoffset, mi->mi_h);
01977 mi->mi_h = headerFree(mi->mi_h);
01978 }
01979
01980
01981 if (uh == NULL)
01982 goto exit;
01983
01984 mi->mi_h = headerCopyLoad(uh);
01985
01986 if (dbi->dbi_api == 1) uh = _free(uh);
01987
01988
01989 if (mi->mi_h == NULL || !headerIsEntry(mi->mi_h, RPMTAG_NAME)) {
01990 rpmError(RPMERR_BADHEADER,
01991 _("rpmdb: damaged header instance #%u retrieved, skipping.\n"),
01992 mi->mi_offset);
01993 goto top;
01994 }
01995
01996
01997
01998
01999 if (mireSkip(mi)) {
02000
02001 if (mi->mi_set || mi->mi_keyp == NULL)
02002 goto top;
02003 return NULL;
02004 }
02005
02006 mi->mi_prevoffset = mi->mi_offset;
02007 mi->mi_modified = 0;
02008
02009 exit:
02010 #ifdef NOTNOW
02011 if (mi->mi_h) {
02012 const char *n, *v, *r;
02013 (void) headerNVR(mi->mi_h, &n, &v, &r);
02014 rpmMessage(RPMMESS_DEBUG, "%s-%s-%s at 0x%x, h %p\n", n, v, r,
02015 mi->mi_offset, mi->mi_h);
02016 }
02017 #endif
02018
02019 return mi->mi_h;
02020
02021 }
02022
02023 static void rpmdbSortIterator( rpmdbMatchIterator mi)
02024
02025 {
02026 if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) {
02027 qsort(mi->mi_set->recs, mi->mi_set->count, sizeof(*mi->mi_set->recs),
02028 hdrNumCmp);
02029 mi->mi_sorted = 1;
02030 }
02031 }
02032
02033 static int rpmdbGrowIterator( rpmdbMatchIterator mi,
02034 const void * keyp, size_t keylen, int fpNum)
02035
02036 {
02037 dbiIndex dbi = NULL;
02038 DBC * dbcursor = NULL;
02039 dbiIndexSet set = NULL;
02040 int rc;
02041 int xx;
02042
02043 if (!(mi && keyp))
02044 return 1;
02045
02046 dbi = dbiOpen(mi->mi_rpmdb, mi->mi_rpmtag, 0);
02047 if (dbi == NULL)
02048 return 1;
02049
02050 if (keylen == 0)
02051 keylen = strlen(keyp);
02052
02053 xx = dbiCopen(dbi, &dbcursor, 0);
02054 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
02055 xx = dbiCclose(dbi, dbcursor, 0);
02056 dbcursor = NULL;
02057
02058 if (rc == 0) {
02059 int i;
02060 for (i = 0; i < set->count; i++)
02061 set->recs[i].fpNum = fpNum;
02062
02063 if (mi->mi_set == NULL) {
02064 mi->mi_set = set;
02065 set = NULL;
02066 } else {
02067 mi->mi_set->recs = xrealloc(mi->mi_set->recs,
02068 (mi->mi_set->count + set->count) * sizeof(*(mi->mi_set->recs)));
02069 memcpy(mi->mi_set->recs + mi->mi_set->count, set->recs,
02070 set->count * sizeof(*(mi->mi_set->recs)));
02071 mi->mi_set->count += set->count;
02072 }
02073 }
02074
02075 set = dbiFreeIndexSet(set);
02076 return rc;
02077 }
02078
02079 int rpmdbPruneIterator(rpmdbMatchIterator mi, int * hdrNums,
02080 int nHdrNums, int sorted)
02081 {
02082 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
02083 return 1;
02084
02085 if (mi->mi_set)
02086 (void) dbiPruneSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), sorted);
02087 return 0;
02088 }
02089
02090 int rpmdbAppendIterator(rpmdbMatchIterator mi, const int * hdrNums, int nHdrNums)
02091 {
02092 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
02093 return 1;
02094
02095 if (mi->mi_set == NULL)
02096 mi->mi_set = xcalloc(1, sizeof(*mi->mi_set));
02097 (void) dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0);
02098 return 0;
02099 }
02100
02101 rpmdbMatchIterator rpmdbInitIterator(rpmdb rpmdb, int rpmtag,
02102 const void * keyp, size_t keylen)
02103 {
02104 rpmdbMatchIterator mi = NULL;
02105 dbiIndexSet set = NULL;
02106 dbiIndex dbi;
02107 const void * mi_keyp = NULL;
02108 int isLabel = 0;
02109
02110 if (rpmdb == NULL)
02111 return NULL;
02112
02113 switch (rpmtag) {
02114 case RPMDBI_LABEL:
02115 rpmtag = RPMTAG_NAME;
02116 isLabel = 1;
02117 break;
02118 }
02119
02120 dbi = dbiOpen(rpmdb, rpmtag, 0);
02121 if (dbi == NULL)
02122 return NULL;
02123
02124 #if 0
02125 assert(dbi->dbi_rmw == NULL);
02126 assert(dbi->dbi_lastoffset == 0);
02127 #else
02128 if (dbi->dbi_rmw)
02129 fprintf(stderr, "*** RMW %s %p\n", tagName(rpmtag), dbi->dbi_rmw);
02130 #endif
02131
02132 dbi->dbi_lastoffset = 0;
02133
02134 if (rpmtag != RPMDBI_PACKAGES && keyp) {
02135 DBC * dbcursor = NULL;
02136 int rc;
02137 int xx;
02138
02139 if (isLabel) {
02140
02141 xx = dbiCopen(dbi, &dbcursor, 0);
02142 rc = dbiFindByLabel(dbi, dbcursor, keyp, &set);
02143 xx = dbiCclose(dbi, dbcursor, 0);
02144 dbcursor = NULL;
02145 } else if (rpmtag == RPMTAG_BASENAMES) {
02146 rc = rpmdbFindByFile(rpmdb, keyp, &set);
02147 } else {
02148 xx = dbiCopen(dbi, &dbcursor, 0);
02149
02150 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
02151
02152 xx = dbiCclose(dbi, dbcursor, 0);
02153 dbcursor = NULL;
02154 }
02155 if (rc) {
02156 set = dbiFreeIndexSet(set);
02157 return NULL;
02158 }
02159 }
02160
02161 if (keyp) {
02162 char * k;
02163
02164 if (rpmtag != RPMDBI_PACKAGES && keylen == 0)
02165 keylen = strlen(keyp);
02166 k = xmalloc(keylen + 1);
02167 memcpy(k, keyp, keylen);
02168 k[keylen] = '\0';
02169 mi_keyp = k;
02170 }
02171
02172 mi = xcalloc(1, sizeof(*mi));
02173 mi->mi_keyp = mi_keyp;
02174 mi->mi_keylen = keylen;
02175
02176
02177 mi->mi_rpmdb = rpmdb;
02178
02179 mi->mi_rpmtag = rpmtag;
02180
02181 mi->mi_dbc = NULL;
02182 mi->mi_set = set;
02183 mi->mi_setx = 0;
02184 mi->mi_ndups = 0;
02185 mi->mi_h = NULL;
02186 mi->mi_sorted = 0;
02187 mi->mi_cflags = 0;
02188 mi->mi_modified = 0;
02189 mi->mi_prevoffset = 0;
02190 mi->mi_offset = 0;
02191 mi->mi_filenum = 0;
02192 mi->mi_fpnum = 0;
02193 mi->mi_dbnum = 0;
02194 mi->mi_nre = 0;
02195 mi->mi_re = NULL;
02196 mi->mi_version = NULL;
02197 mi->mi_release = NULL;
02198 return mi;
02199 }
02200
02210 static INLINE int removeIndexEntry(dbiIndex dbi, DBC * dbcursor,
02211 const void * keyp, size_t keylen, dbiIndexItem rec)
02212
02213 {
02214 dbiIndexSet set = NULL;
02215 int rc;
02216
02217 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
02218
02219 if (rc < 0)
02220 rc = 0;
02221 else if (rc > 0)
02222 rc = 1;
02223 else {
02224
02225 rc = dbiPruneSet(set, rec, 1, sizeof(*rec), 1);
02226
02227 if (rc == 0 && dbiUpdateIndex(dbi, dbcursor, keyp, keylen, set))
02228 rc = 1;
02229 }
02230
02231 set = dbiFreeIndexSet(set);
02232
02233 return rc;
02234 }
02235
02236
02237 int rpmdbRemove(rpmdb rpmdb, int rid, unsigned int hdrNum)
02238 {
02239 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
02240 HFD_t hfd = headerFreeData;
02241 Header h;
02242 sigset_t signalMask;
02243
02244 if (rpmdb == NULL)
02245 return 0;
02246
02247 { rpmdbMatchIterator mi;
02248 mi = rpmdbInitIterator(rpmdb, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum));
02249 h = rpmdbNextIterator(mi);
02250 if (h)
02251 h = headerLink(h);
02252 mi = rpmdbFreeIterator(mi);
02253 }
02254
02255 if (h == NULL) {
02256 rpmError(RPMERR_DBCORRUPT, _("%s: cannot read header at 0x%x\n"),
02257 "rpmdbRemove", hdrNum);
02258 return 1;
02259 }
02260
02261 #ifdef DYING
02262
02263 if (rid != 0 && rid != -1) {
02264 int_32 tid = rid;
02265 (void) headerAddEntry(h, RPMTAG_REMOVETID, RPM_INT32_TYPE, &tid, 1);
02266 }
02267 #endif
02268
02269 { const char *n, *v, *r;
02270 (void) headerNVR(h, &n, &v, &r);
02271 rpmMessage(RPMMESS_DEBUG, " --- %10u %s-%s-%s\n", hdrNum, n, v, r);
02272 }
02273
02274 (void) blockSignals(rpmdb, &signalMask);
02275
02276 { int dbix;
02277 dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
02278
02279 if (dbiTags != NULL)
02280 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
02281 dbiIndex dbi;
02282 DBC * dbcursor = NULL;
02283 const char *av[1];
02284 const char ** rpmvals = NULL;
02285 rpmTagType rpmtype = 0;
02286 int rpmcnt = 0;
02287 int rpmtag;
02288 int xx;
02289 int i;
02290
02291 dbi = NULL;
02292 rpmtag = dbiTags[dbix];
02293
02294 switch (rpmtag) {
02295
02296 case RPMDBI_AVAILABLE:
02297 case RPMDBI_ADDED:
02298 case RPMDBI_REMOVED:
02299 case RPMDBI_DEPENDS:
02300 continue;
02301 break;
02302 case RPMDBI_PACKAGES:
02303 dbi = dbiOpen(rpmdb, rpmtag, 0);
02304 if (dbi != NULL) {
02305 xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
02306 xx = dbiDel(dbi, dbcursor, &hdrNum, sizeof(hdrNum), 0);
02307 xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
02308 dbcursor = NULL;
02309 if (!dbi->dbi_no_dbsync)
02310 xx = dbiSync(dbi, 0);
02311 }
02312 continue;
02313 break;
02314 }
02315
02316 if (!hge(h, rpmtag, &rpmtype, (void **) &rpmvals, &rpmcnt))
02317 continue;
02318
02319 dbi = dbiOpen(rpmdb, rpmtag, 0);
02320 if (dbi != NULL) {
02321 xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
02322
02323 if (rpmtype == RPM_STRING_TYPE) {
02324
02325 rpmMessage(RPMMESS_DEBUG, _("removing \"%s\" from %s index.\n"),
02326 (const char *)rpmvals, tagName(dbi->dbi_rpmtag));
02327
02328
02329 av[0] = (const char *) rpmvals;
02330 rpmvals = av;
02331 rpmcnt = 1;
02332 } else {
02333
02334 rpmMessage(RPMMESS_DEBUG, _("removing %d entries from %s index.\n"),
02335 rpmcnt, tagName(dbi->dbi_rpmtag));
02336
02337 }
02338
02339 for (i = 0; i < rpmcnt; i++) {
02340 const void * valp;
02341 size_t vallen;
02342
02343
02344 switch (rpmtype) {
02345 case RPM_CHAR_TYPE:
02346 case RPM_INT8_TYPE:
02347 vallen = sizeof(RPM_CHAR_TYPE);
02348 valp = rpmvals + i;
02349 break;
02350 case RPM_INT16_TYPE:
02351 vallen = sizeof(int_16);
02352 valp = rpmvals + i;
02353 break;
02354 case RPM_INT32_TYPE:
02355 vallen = sizeof(int_32);
02356 valp = rpmvals + i;
02357 break;
02358 case RPM_BIN_TYPE:
02359 vallen = rpmcnt;
02360 valp = rpmvals;
02361 rpmcnt = 1;
02362 break;
02363 case RPM_STRING_TYPE:
02364 case RPM_I18NSTRING_TYPE:
02365 rpmcnt = 1;
02366
02367 case RPM_STRING_ARRAY_TYPE:
02368 default:
02369 vallen = strlen(rpmvals[i]);
02370 valp = rpmvals[i];
02371 break;
02372 }
02373
02374
02375
02376
02377
02378
02379
02380 xx = removeIndexEntry(dbi, dbcursor, valp, vallen, rec);
02381 }
02382
02383 xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
02384 dbcursor = NULL;
02385
02386 if (!dbi->dbi_no_dbsync)
02387 xx = dbiSync(dbi, 0);
02388 }
02389
02390 rpmvals = hfd(rpmvals, rpmtype);
02391 rpmtype = 0;
02392 rpmcnt = 0;
02393 }
02394
02395 rec = _free(rec);
02396 }
02397
02398 (void) unblockSignals(rpmdb, &signalMask);
02399
02400 h = headerFree(h);
02401
02402 return 0;
02403 }
02404
02414 static INLINE int addIndexEntry(dbiIndex dbi, DBC * dbcursor,
02415 const char * keyp, size_t keylen, dbiIndexItem rec)
02416
02417 {
02418 dbiIndexSet set = NULL;
02419 int rc;
02420
02421 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
02422
02423 if (rc > 0) {
02424 rc = 1;
02425 } else {
02426
02427
02428 if (rc == 0 && dbi->dbi_permit_dups)
02429 set = dbiFreeIndexSet(set);
02430
02431 if (set == NULL || rc < 0) {
02432 rc = 0;
02433 set = xcalloc(1, sizeof(*set));
02434 }
02435 (void) dbiAppendSet(set, rec, 1, sizeof(*rec), 0);
02436 if (dbiUpdateIndex(dbi, dbcursor, keyp, keylen, set))
02437 rc = 1;
02438 }
02439 set = dbiFreeIndexSet(set);
02440
02441 return 0;
02442 }
02443
02444
02445 int rpmdbAdd(rpmdb rpmdb, int iid, Header h)
02446 {
02447 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
02448 HFD_t hfd = headerFreeData;
02449 sigset_t signalMask;
02450 const char ** baseNames;
02451 rpmTagType bnt;
02452 int count = 0;
02453 dbiIndex dbi;
02454 int dbix;
02455 unsigned int gflags = 0;
02456 unsigned int pflags = 0;
02457 unsigned int hdrNum = 0;
02458 int rc = 0;
02459 int xx;
02460
02461 if (rpmdb == NULL)
02462 return 0;
02463
02464 if (iid != 0 && iid != -1) {
02465 int_32 tid = iid;
02466 (void) headerRemoveEntry(h, RPMTAG_REMOVETID);
02467 if (!headerIsEntry(h, RPMTAG_INSTALLTID))
02468 (void) headerAddEntry(h, RPMTAG_INSTALLTID, RPM_INT32_TYPE, &tid, 1);
02469 }
02470
02471
02472
02473
02474
02475
02476
02477 (void) hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, &count);
02478
02479 if (_noDirTokens)
02480 expandFilelist(h);
02481
02482 (void) blockSignals(rpmdb, &signalMask);
02483
02484 {
02485 unsigned int firstkey = 0;
02486 DBC * dbcursor = NULL;
02487 void * keyp = &firstkey;
02488 size_t keylen = sizeof(firstkey);
02489 void * datap = NULL;
02490 size_t datalen = 0;
02491
02492 dbi = dbiOpen(rpmdb, RPMDBI_PACKAGES, 0);
02493 if (dbi != NULL) {
02494
02495
02496 datap = h;
02497 datalen = headerSizeof(h, HEADER_MAGIC_NO);
02498
02499 xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
02500
02501
02502
02503 rc = dbiGet(dbi, dbcursor, &keyp, &keylen, &datap, &datalen, gflags);
02504
02505 hdrNum = 0;
02506 if (rc == 0 && datap)
02507 memcpy(&hdrNum, datap, sizeof(hdrNum));
02508 ++hdrNum;
02509 if (rc == 0 && datap) {
02510
02511 memcpy(datap, &hdrNum, sizeof(hdrNum));
02512
02513 } else {
02514 datap = &hdrNum;
02515 datalen = sizeof(hdrNum);
02516 }
02517
02518 rc = dbiPut(dbi, dbcursor, keyp, keylen, datap, datalen, pflags);
02519 xx = dbiSync(dbi, 0);
02520
02521 xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
02522 dbcursor = NULL;
02523 }
02524
02525 }
02526
02527 if (rc) {
02528 rpmError(RPMERR_DBCORRUPT,
02529 _("error(%d) allocating new package instance\n"), rc);
02530 goto exit;
02531 }
02532
02533
02534
02535 if (hdrNum)
02536 { dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
02537
02538 if (dbiTags != NULL)
02539 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
02540 DBC * dbcursor = NULL;
02541 const char *av[1];
02542 const char **rpmvals = NULL;
02543 rpmTagType rpmtype = 0;
02544 int rpmcnt = 0;
02545 int rpmtag;
02546 int_32 * requireFlags;
02547 int i, j;
02548
02549 dbi = NULL;
02550 requireFlags = NULL;
02551 rpmtag = dbiTags[dbix];
02552
02553 switch (rpmtag) {
02554
02555 case RPMDBI_AVAILABLE:
02556 case RPMDBI_ADDED:
02557 case RPMDBI_REMOVED:
02558 case RPMDBI_DEPENDS:
02559 continue;
02560 break;
02561 case RPMDBI_PACKAGES:
02562 dbi = dbiOpen(rpmdb, rpmtag, 0);
02563 if (dbi != NULL) {
02564 xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
02565 xx = dbiUpdateRecord(dbi, dbcursor, hdrNum, h);
02566 xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
02567 dbcursor = NULL;
02568 if (!dbi->dbi_no_dbsync)
02569 xx = dbiSync(dbi, 0);
02570 { const char *n, *v, *r;
02571 (void) headerNVR(h, &n, &v, &r);
02572 rpmMessage(RPMMESS_DEBUG, " +++ %10u %s-%s-%s\n", hdrNum, n, v, r);
02573 }
02574 }
02575 continue;
02576 break;
02577
02578 case RPMTAG_BASENAMES:
02579 rpmtype = bnt;
02580 rpmvals = baseNames;
02581 rpmcnt = count;
02582 break;
02583 case RPMTAG_REQUIRENAME:
02584 (void) hge(h, rpmtag, &rpmtype, (void **)&rpmvals, &rpmcnt);
02585 (void) hge(h, RPMTAG_REQUIREFLAGS, NULL, (void **)&requireFlags, NULL);
02586 break;
02587 default:
02588 (void) hge(h, rpmtag, &rpmtype, (void **)&rpmvals, &rpmcnt);
02589 break;
02590 }
02591
02592 if (rpmcnt <= 0) {
02593 if (rpmtag != RPMTAG_GROUP)
02594 continue;
02595
02596
02597 rpmtype = RPM_STRING_TYPE;
02598 rpmvals = (const char **) "Unknown";
02599 rpmcnt = 1;
02600 }
02601
02602 dbi = dbiOpen(rpmdb, rpmtag, 0);
02603 if (dbi != NULL) {
02604
02605 xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
02606 if (rpmtype == RPM_STRING_TYPE) {
02607 rpmMessage(RPMMESS_DEBUG, _("adding \"%s\" to %s index.\n"),
02608 (const char *)rpmvals, tagName(dbi->dbi_rpmtag));
02609
02610
02611
02612 av[0] = (const char *) rpmvals;
02613
02614 rpmvals = av;
02615 rpmcnt = 1;
02616 } else {
02617
02618 rpmMessage(RPMMESS_DEBUG, _("adding %d entries to %s index.\n"),
02619 rpmcnt, tagName(dbi->dbi_rpmtag));
02620
02621 }
02622
02623 for (i = 0; i < rpmcnt; i++) {
02624 const void * valp;
02625 size_t vallen;
02626
02627
02628
02629
02630
02631 switch (dbi->dbi_rpmtag) {
02632 case RPMTAG_REQUIRENAME:
02633
02634 if (requireFlags && isInstallPreReq(requireFlags[i]))
02635 continue;
02636 rec->tagNum = i;
02637 break;
02638 case RPMTAG_TRIGGERNAME:
02639 if (i) {
02640 for (j = 0; j < i; j++) {
02641 if (!strcmp(rpmvals[i], rpmvals[j]))
02642 break;
02643 }
02644 if (j < i)
02645 continue;
02646 }
02647 rec->tagNum = i;
02648 break;
02649 default:
02650 rec->tagNum = i;
02651 break;
02652 }
02653
02654
02655 switch (rpmtype) {
02656 case RPM_CHAR_TYPE:
02657 case RPM_INT8_TYPE:
02658 vallen = sizeof(int_8);
02659 valp = rpmvals + i;
02660 break;
02661 case RPM_INT16_TYPE:
02662 vallen = sizeof(int_16);
02663 valp = rpmvals + i;
02664 break;
02665 case RPM_INT32_TYPE:
02666 vallen = sizeof(int_32);
02667 valp = rpmvals + i;
02668 break;
02669 case RPM_BIN_TYPE:
02670 vallen = rpmcnt;
02671 valp = rpmvals;
02672 rpmcnt = 1;
02673 break;
02674 case RPM_STRING_TYPE:
02675 case RPM_I18NSTRING_TYPE:
02676 rpmcnt = 1;
02677
02678 case RPM_STRING_ARRAY_TYPE:
02679 default:
02680 valp = rpmvals[i];
02681 vallen = strlen(rpmvals[i]);
02682 break;
02683 }
02684
02685 rc += addIndexEntry(dbi, dbcursor, valp, vallen, rec);
02686 }
02687 xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
02688 dbcursor = NULL;
02689
02690 if (!dbi->dbi_no_dbsync)
02691 xx = dbiSync(dbi, 0);
02692 }
02693
02694
02695 rpmvals = hfd(rpmvals, rpmtype);
02696
02697 rpmtype = 0;
02698 rpmcnt = 0;
02699 }
02700
02701 rec = _free(rec);
02702 }
02703
02704 exit:
02705 (void) unblockSignals(rpmdb, &signalMask);
02706
02707 return rc;
02708 }
02709
02710
02711 int rpmdbFindFpList(rpmdb rpmdb, fingerPrint * fpList, dbiIndexSet * matchList,
02712 int numItems)
02713 {
02714 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
02715 HFD_t hfd = headerFreeData;
02716 rpmdbMatchIterator mi;
02717 fingerPrintCache fpc;
02718 Header h;
02719 int i;
02720
02721 if (rpmdb == NULL) return 0;
02722
02723 mi = rpmdbInitIterator(rpmdb, RPMTAG_BASENAMES, NULL, 0);
02724
02725
02726 for (i = 0; i < numItems; i++) {
02727 (void) rpmdbGrowIterator(mi, fpList[i].baseName, 0, i);
02728 matchList[i] = xcalloc(1, sizeof(*(matchList[i])));
02729 }
02730
02731 if ((i = rpmdbGetIteratorCount(mi)) == 0) {
02732 mi = rpmdbFreeIterator(mi);
02733 return 0;
02734 }
02735 fpc = fpCacheCreate(i);
02736
02737 rpmdbSortIterator(mi);
02738
02739
02740
02741 if (mi != NULL)
02742 while ((h = rpmdbNextIterator(mi)) != NULL) {
02743 const char ** dirNames;
02744 const char ** baseNames;
02745 const char ** fullBaseNames;
02746 rpmTagType bnt, dnt;
02747 int_32 * dirIndexes;
02748 int_32 * fullDirIndexes;
02749 fingerPrint * fps;
02750 dbiIndexItem im;
02751 int start;
02752 int num;
02753 int end;
02754
02755 start = mi->mi_setx - 1;
02756 im = mi->mi_set->recs + start;
02757
02758
02759 for (end = start + 1; end < mi->mi_set->count; end++) {
02760 if (im->hdrNum != mi->mi_set->recs[end].hdrNum)
02761 break;
02762 }
02763 num = end - start;
02764
02765
02766 (void) hge(h, RPMTAG_BASENAMES, &bnt, (void **) &fullBaseNames, NULL);
02767 (void) hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
02768 (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &fullDirIndexes, NULL);
02769
02770 baseNames = xcalloc(num, sizeof(*baseNames));
02771 dirIndexes = xcalloc(num, sizeof(*dirIndexes));
02772 for (i = 0; i < num; i++) {
02773 baseNames[i] = fullBaseNames[im[i].tagNum];
02774 dirIndexes[i] = fullDirIndexes[im[i].tagNum];
02775 }
02776
02777 fps = xcalloc(num, sizeof(*fps));
02778 fpLookupList(fpc, dirNames, baseNames, dirIndexes, num, fps);
02779
02780
02781 for (i = 0; i < num; i++, im++) {
02782
02783 if (FP_EQUAL(fps[i], fpList[im->fpNum])) {
02784
02785
02786 (void) dbiAppendSet(matchList[im->fpNum], im, 1, sizeof(*im), 0);
02787
02788 }
02789 }
02790
02791 fps = _free(fps);
02792 dirNames = hfd(dirNames, dnt);
02793 fullBaseNames = hfd(fullBaseNames, bnt);
02794 baseNames = _free(baseNames);
02795 dirIndexes = _free(dirIndexes);
02796
02797 mi->mi_setx = end;
02798 }
02799
02800 mi = rpmdbFreeIterator(mi);
02801
02802 fpCacheFree(fpc);
02803
02804 return 0;
02805
02806 }
02807
02808 char * db1basename (int rpmtag)
02809 {
02810 char * base = NULL;
02811 switch (rpmtag) {
02812 case RPMDBI_PACKAGES: base = "packages.rpm"; break;
02813 case RPMTAG_NAME: base = "nameindex.rpm"; break;
02814 case RPMTAG_BASENAMES: base = "fileindex.rpm"; break;
02815 case RPMTAG_GROUP: base = "groupindex.rpm"; break;
02816 case RPMTAG_REQUIRENAME: base = "requiredby.rpm"; break;
02817 case RPMTAG_PROVIDENAME: base = "providesindex.rpm"; break;
02818 case RPMTAG_CONFLICTNAME: base = "conflictsindex.rpm"; break;
02819 case RPMTAG_TRIGGERNAME: base = "triggerindex.rpm"; break;
02820 default:
02821 { const char * tn = tagName(rpmtag);
02822 base = alloca( strlen(tn) + sizeof(".idx") + 1 );
02823 (void) stpcpy( stpcpy(base, tn), ".idx");
02824 } break;
02825 }
02826 return xstrdup(base);
02827 }
02828
02829 static int rpmdbRemoveDatabase(const char * rootdir,
02830 const char * dbpath, int _dbapi)
02831
02832 {
02833 int i;
02834 char * filename;
02835 int xx;
02836
02837 i = strlen(dbpath);
02838 if (dbpath[i - 1] != '/') {
02839 filename = alloca(i);
02840 strcpy(filename, dbpath);
02841 filename[i] = '/';
02842 filename[i + 1] = '\0';
02843 dbpath = filename;
02844 }
02845
02846 filename = alloca(strlen(rootdir) + strlen(dbpath) + 40);
02847
02848 switch (_dbapi) {
02849 case 3:
02850 if (dbiTags != NULL)
02851 for (i = 0; i < dbiTagsMax; i++) {
02852 const char * base = tagName(dbiTags[i]);
02853 sprintf(filename, "%s/%s/%s", rootdir, dbpath, base);
02854 (void)rpmCleanPath(filename);
02855 if (!rpmfileexists(filename))
02856 continue;
02857 xx = unlink(filename);
02858 }
02859 for (i = 0; i < 16; i++) {
02860 sprintf(filename, "%s/%s/__db.%03d", rootdir, dbpath, i);
02861 (void)rpmCleanPath(filename);
02862 if (!rpmfileexists(filename))
02863 continue;
02864 xx = unlink(filename);
02865 }
02866 break;
02867 case 2:
02868 case 1:
02869 case 0:
02870 if (dbiTags != NULL)
02871 for (i = 0; i < dbiTagsMax; i++) {
02872 const char * base = db1basename(dbiTags[i]);
02873 sprintf(filename, "%s/%s/%s", rootdir, dbpath, base);
02874 (void)rpmCleanPath(filename);
02875 if (!rpmfileexists(filename))
02876 continue;
02877 xx = unlink(filename);
02878 base = _free(base);
02879 }
02880 break;
02881 }
02882
02883 sprintf(filename, "%s/%s", rootdir, dbpath);
02884 (void)rpmCleanPath(filename);
02885 xx = rmdir(filename);
02886
02887 return 0;
02888 }
02889
02890 static int rpmdbMoveDatabase(const char * rootdir,
02891 const char * olddbpath, int _olddbapi,
02892 const char * newdbpath, int _newdbapi)
02893
02894 {
02895 int i;
02896 char * ofilename, * nfilename;
02897 int rc = 0;
02898 int xx;
02899
02900 i = strlen(olddbpath);
02901 if (olddbpath[i - 1] != '/') {
02902 ofilename = alloca(i + 2);
02903 strcpy(ofilename, olddbpath);
02904 ofilename[i] = '/';
02905 ofilename[i + 1] = '\0';
02906 olddbpath = ofilename;
02907 }
02908
02909 i = strlen(newdbpath);
02910 if (newdbpath[i - 1] != '/') {
02911 nfilename = alloca(i + 2);
02912 strcpy(nfilename, newdbpath);
02913 nfilename[i] = '/';
02914 nfilename[i + 1] = '\0';
02915 newdbpath = nfilename;
02916 }
02917
02918 ofilename = alloca(strlen(rootdir) + strlen(olddbpath) + 40);
02919 nfilename = alloca(strlen(rootdir) + strlen(newdbpath) + 40);
02920
02921 switch (_olddbapi) {
02922 case 3:
02923 if (dbiTags != NULL)
02924 for (i = 0; i < dbiTagsMax; i++) {
02925 const char * base;
02926 int rpmtag;
02927
02928
02929 switch ((rpmtag = dbiTags[i])) {
02930 case RPMDBI_AVAILABLE:
02931 case RPMDBI_ADDED:
02932 case RPMDBI_REMOVED:
02933 case RPMDBI_DEPENDS:
02934 continue;
02935 break;
02936 default:
02937 break;
02938 }
02939
02940 base = tagName(rpmtag);
02941 sprintf(ofilename, "%s/%s/%s", rootdir, olddbpath, base);
02942 (void)rpmCleanPath(ofilename);
02943 if (!rpmfileexists(ofilename))
02944 continue;
02945 sprintf(nfilename, "%s/%s/%s", rootdir, newdbpath, base);
02946 (void)rpmCleanPath(nfilename);
02947 if ((xx = Rename(ofilename, nfilename)) != 0)
02948 rc = 1;
02949 }
02950 for (i = 0; i < 16; i++) {
02951 sprintf(ofilename, "%s/%s/__db.%03d", rootdir, olddbpath, i);
02952 (void)rpmCleanPath(ofilename);
02953 if (!rpmfileexists(ofilename))
02954 continue;
02955 xx = unlink(ofilename);
02956 sprintf(nfilename, "%s/%s/__db.%03d", rootdir, newdbpath, i);
02957 (void)rpmCleanPath(nfilename);
02958 #ifdef DYING
02959 if ((xx = Rename(ofilename, nfilename)) != 0)
02960 rc = 1;
02961 #else
02962 xx = unlink(nfilename);
02963 #endif
02964 }
02965 break;
02966 case 2:
02967 case 1:
02968 case 0:
02969 if (dbiTags != NULL)
02970 for (i = 0; i < dbiTagsMax; i++) {
02971 const char * base;
02972 int rpmtag;
02973
02974
02975 switch ((rpmtag = dbiTags[i])) {
02976 case RPMDBI_AVAILABLE:
02977 case RPMDBI_ADDED:
02978 case RPMDBI_REMOVED:
02979 case RPMDBI_DEPENDS:
02980 continue;
02981 break;
02982 default:
02983 break;
02984 }
02985
02986 base = db1basename(rpmtag);
02987 sprintf(ofilename, "%s/%s/%s", rootdir, olddbpath, base);
02988 (void)rpmCleanPath(ofilename);
02989 if (!rpmfileexists(ofilename))
02990 continue;
02991 sprintf(nfilename, "%s/%s/%s", rootdir, newdbpath, base);
02992 (void)rpmCleanPath(nfilename);
02993 if ((xx = Rename(ofilename, nfilename)) != 0)
02994 rc = 1;
02995 base = _free(base);
02996 }
02997 break;
02998 }
02999 if (rc || _olddbapi == _newdbapi)
03000 return rc;
03001
03002 rc = rpmdbRemoveDatabase(rootdir, newdbpath, _newdbapi);
03003
03004
03005
03006 if (rc == 0 && _newdbapi == 1 && _olddbapi == 3) {
03007 const char * mdb1 = "/etc/rpm/macros.db1";
03008 struct stat st;
03009 if (!stat(mdb1, &st) && S_ISREG(st.st_mode) && !unlink(mdb1))
03010 rpmMessage(RPMMESS_DEBUG,
03011 _("removing %s after successful db3 rebuild.\n"), mdb1);
03012 }
03013 return rc;
03014 }
03015
03016 int rpmdbRebuild(const char * rootdir)
03017 {
03018 rpmdb olddb;
03019 const char * dbpath = NULL;
03020 const char * rootdbpath = NULL;
03021 rpmdb newdb;
03022 const char * newdbpath = NULL;
03023 const char * newrootdbpath = NULL;
03024 const char * tfn;
03025 int nocleanup = 1;
03026 int failed = 0;
03027 int removedir = 0;
03028 int rc = 0, xx;
03029 int _dbapi;
03030 int _dbapi_rebuild;
03031
03032 if (rootdir == NULL) rootdir = "/";
03033
03034 _dbapi = rpmExpandNumeric("%{_dbapi}");
03035 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
03036
03037
03038 tfn = rpmGetPath("%{_dbpath}", NULL);
03039
03040 if (!(tfn && tfn[0] != '%')) {
03041 rpmMessage(RPMMESS_DEBUG, _("no dbpath has been set"));
03042 rc = 1;
03043 goto exit;
03044 }
03045 dbpath = rootdbpath = rpmGetPath(rootdir, tfn, NULL);
03046 if (!(rootdir[0] == '/' && rootdir[1] == '\0'))
03047 dbpath += strlen(rootdir);
03048 tfn = _free(tfn);
03049
03050
03051 tfn = rpmGetPath("%{_dbpath_rebuild}", NULL);
03052
03053 if (!(tfn && tfn[0] != '%' && strcmp(tfn, dbpath))) {
03054 char pidbuf[20];
03055 char *t;
03056 sprintf(pidbuf, "rebuilddb.%d", (int) getpid());
03057 t = xmalloc(strlen(dbpath) + strlen(pidbuf) + 1);
03058 (void)stpcpy(stpcpy(t, dbpath), pidbuf);
03059 tfn = _free(tfn);
03060 tfn = t;
03061 nocleanup = 0;
03062 }
03063 newdbpath = newrootdbpath = rpmGetPath(rootdir, tfn, NULL);
03064 if (!(rootdir[0] == '/' && rootdir[1] == '\0'))
03065 newdbpath += strlen(rootdir);
03066 tfn = _free(tfn);
03067
03068 rpmMessage(RPMMESS_DEBUG, _("rebuilding database %s into %s\n"),
03069 rootdbpath, newrootdbpath);
03070
03071 if (!access(newrootdbpath, F_OK)) {
03072 rpmError(RPMERR_MKDIR, _("temporary database %s already exists\n"),
03073 newrootdbpath);
03074 rc = 1;
03075 goto exit;
03076 }
03077
03078 rpmMessage(RPMMESS_DEBUG, _("creating directory %s\n"), newrootdbpath);
03079 if (Mkdir(newrootdbpath, 0755)) {
03080 rpmError(RPMERR_MKDIR, _("creating directory %s: %s\n"),
03081 newrootdbpath, strerror(errno));
03082 rc = 1;
03083 goto exit;
03084 }
03085 removedir = 1;
03086
03087 rpmMessage(RPMMESS_DEBUG, _("opening old database with dbapi %d\n"),
03088 _dbapi);
03089 _rebuildinprogress = 1;
03090 if (openDatabase(rootdir, dbpath, _dbapi, &olddb, O_RDONLY, 0644,
03091 RPMDB_FLAG_MINIMAL)) {
03092 rc = 1;
03093 goto exit;
03094 }
03095 _dbapi = olddb->db_api;
03096 _rebuildinprogress = 0;
03097
03098 rpmMessage(RPMMESS_DEBUG, _("opening new database with dbapi %d\n"),
03099 _dbapi_rebuild);
03100 (void) rpmDefineMacro(NULL, "_rpmdb_rebuild %{nil}", -1);
03101 if (openDatabase(rootdir, newdbpath, _dbapi_rebuild, &newdb, O_RDWR | O_CREAT, 0644, 0)) {
03102 rc = 1;
03103 goto exit;
03104 }
03105 _dbapi_rebuild = newdb->db_api;
03106
03107 { Header h = NULL;
03108 rpmdbMatchIterator mi;
03109 #define _RECNUM rpmdbGetIteratorOffset(mi)
03110
03111
03112 mi = rpmdbInitIterator(olddb, RPMDBI_PACKAGES, NULL, 0);
03113 while ((h = rpmdbNextIterator(mi)) != NULL) {
03114
03115
03116 if (!(headerIsEntry(h, RPMTAG_NAME) &&
03117 headerIsEntry(h, RPMTAG_VERSION) &&
03118 headerIsEntry(h, RPMTAG_RELEASE) &&
03119 headerIsEntry(h, RPMTAG_BUILDTIME)))
03120 {
03121 rpmError(RPMERR_INTERNAL,
03122 _("record number %u in database is bad -- skipping.\n"),
03123 _RECNUM);
03124 continue;
03125 }
03126
03127
03128 if (_db_filter_dups || newdb->db_filter_dups) {
03129 const char * name, * version, * release;
03130 int skip = 0;
03131
03132 (void) headerNVR(h, &name, &version, &release);
03133
03134
03135 { rpmdbMatchIterator mi;
03136 mi = rpmdbInitIterator(newdb, RPMTAG_NAME, name, 0);
03137 (void) rpmdbSetIteratorRE(mi, RPMTAG_VERSION,
03138 RPMMIRE_DEFAULT, version);
03139 (void) rpmdbSetIteratorRE(mi, RPMTAG_RELEASE,
03140 RPMMIRE_DEFAULT, release);
03141 while (rpmdbNextIterator(mi)) {
03142 skip = 1;
03143 break;
03144 }
03145 mi = rpmdbFreeIterator(mi);
03146 }
03147
03148
03149 if (skip)
03150 continue;
03151 }
03152
03153
03154 { Header nh = (headerIsEntry(h, RPMTAG_HEADERIMAGE)
03155 ? headerCopy(h) : NULL);
03156 rc = rpmdbAdd(newdb, -1, (nh ? nh : h));
03157 nh = headerFree(nh);
03158 }
03159
03160 if (rc) {
03161 rpmError(RPMERR_INTERNAL,
03162 _("cannot add record originally at %u\n"), _RECNUM);
03163 failed = 1;
03164 break;
03165 }
03166 }
03167
03168 mi = rpmdbFreeIterator(mi);
03169
03170 }
03171
03172 if (!nocleanup) {
03173 olddb->db_remove_env = 1;
03174 newdb->db_remove_env = 1;
03175 }
03176 xx = rpmdbClose(olddb);
03177 xx = rpmdbClose(newdb);
03178
03179 if (failed) {
03180 rpmMessage(RPMMESS_NORMAL, _("failed to rebuild database: original database "
03181 "remains in place\n"));
03182
03183 xx = rpmdbRemoveDatabase(rootdir, newdbpath, _dbapi_rebuild);
03184 rc = 1;
03185 goto exit;
03186 } else if (!nocleanup) {
03187 if (rpmdbMoveDatabase(rootdir, newdbpath, _dbapi_rebuild, dbpath, _dbapi)) {
03188 rpmMessage(RPMMESS_ERROR, _("failed to replace old database with new "
03189 "database!\n"));
03190 rpmMessage(RPMMESS_ERROR, _("replace files in %s with files from %s "
03191 "to recover"), dbpath, newdbpath);
03192 rc = 1;
03193 goto exit;
03194 }
03195 }
03196 rc = 0;
03197
03198 exit:
03199 if (removedir && !(rc == 0 && nocleanup)) {
03200 rpmMessage(RPMMESS_DEBUG, _("removing directory %s\n"), newrootdbpath);
03201 if (Rmdir(newrootdbpath))
03202 rpmMessage(RPMMESS_ERROR, _("failed to remove directory %s: %s\n"),
03203 newrootdbpath, strerror(errno));
03204 }
03205 newrootdbpath = _free(newrootdbpath);
03206 rootdbpath = _free(rootdbpath);
03207
03208 return rc;
03209 }