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 mire->preg = _free(mire->preg);
01489 }
01490 }
01491 mi->mi_re = _free(mi->mi_re);
01492
01493 mi->mi_release = _free(mi->mi_release);
01494 mi->mi_version = _free(mi->mi_version);
01495 if (dbi && mi->mi_dbc)
01496 xx = dbiCclose(dbi, mi->mi_dbc, DBI_ITERATOR);
01497 mi->mi_dbc = NULL;
01498 mi->mi_set = dbiFreeIndexSet(mi->mi_set);
01499 mi->mi_keyp = _free(mi->mi_keyp);
01500 mi = _free(mi);
01501 return mi;
01502 }
01503
01504 rpmdb rpmdbGetIteratorRpmDB(rpmdbMatchIterator mi) {
01505 if (mi == NULL)
01506 return NULL;
01507
01508 return mi->mi_rpmdb;
01509
01510 }
01511
01512 unsigned int rpmdbGetIteratorOffset(rpmdbMatchIterator mi) {
01513 if (mi == NULL)
01514 return 0;
01515 return mi->mi_offset;
01516 }
01517
01518 unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi) {
01519 if (mi == NULL)
01520 return 0;
01521 return mi->mi_filenum;
01522 }
01523
01524 int rpmdbGetIteratorCount(rpmdbMatchIterator mi) {
01525 if (!(mi && mi->mi_set))
01526 return 0;
01527 return mi->mi_set->count;
01528 }
01529
01535 static int miregexec(miRE mire, const char * val)
01536
01537 {
01538 int rc = 0;
01539
01540 switch (mire->mode) {
01541 case RPMMIRE_STRCMP:
01542 rc = strcmp(mire->pattern, val);
01543 break;
01544 case RPMMIRE_DEFAULT:
01545 case RPMMIRE_REGEX:
01546 rc = regexec(mire->preg, val, 0, NULL, mire->eflags);
01547 if (rc && rc != REG_NOMATCH) {
01548 char msg[256];
01549 (void) regerror(rc, mire->preg, msg, sizeof(msg)-1);
01550 msg[sizeof(msg)-1] = '\0';
01551 rpmError(RPMERR_REGEXEC, "%s: regexec failed: %s\n",
01552 mire->pattern, msg);
01553 rc = -1;
01554 }
01555 break;
01556 case RPMMIRE_GLOB:
01557 rc = fnmatch(mire->pattern, val, mire->fnflags);
01558 if (rc && rc != FNM_NOMATCH)
01559 rc = -1;
01560 break;
01561 default:
01562 rc = -1;
01563 break;
01564 }
01565
01566 return rc;
01567 }
01568
01575 static int mireCmp(const void * a, const void * b)
01576 {
01577 const miRE mireA = (const miRE) a;
01578 const miRE mireB = (const miRE) b;
01579 return (mireA->tag - mireB->tag);
01580 }
01581
01589 static char * mireDup(rpmTag tag, rpmMireMode *modep,
01590 const char * pattern)
01591
01592 {
01593 const char * s;
01594 char * pat;
01595 char * t;
01596 int brackets;
01597 size_t nb;
01598 int c;
01599
01600 switch (*modep) {
01601 default:
01602 case RPMMIRE_DEFAULT:
01603 if (tag == RPMTAG_DIRNAMES || tag == RPMTAG_BASENAMES) {
01604 *modep = RPMMIRE_GLOB;
01605 pat = xstrdup(pattern);
01606 break;
01607 }
01608
01609 nb = strlen(pattern) + sizeof("^$");
01610
01611
01612 c = '\0';
01613 brackets = 0;
01614 for (s = pattern; *s != '\0'; s++) {
01615 switch (*s) {
01616 case '.':
01617 case '*': if (!brackets) nb++; break;
01618 case '\\': s++; break;
01619 case '[': brackets = 1; break;
01620 case ']': if (c != '[') brackets = 0; break;
01621 }
01622 c = *s;
01623 }
01624
01625 pat = t = xmalloc(nb);
01626
01627 if (pattern[0] != '^') *t++ = '^';
01628
01629
01630 c = '\0';
01631 brackets = 0;
01632 for (s = pattern; *s != '\0'; s++, t++) {
01633 switch (*s) {
01634 case '.': if (!brackets) *t++ = '\\'; break;
01635 case '*': if (!brackets) *t++ = '.'; break;
01636 case '\\': *t++ = *s++; break;
01637 case '[': brackets = 1; break;
01638 case ']': if (c != '[') brackets = 0; break;
01639 }
01640 c = *t = *s;
01641 }
01642
01643 if (pattern[nb-1] != '$') *t++ = '$';
01644 *t = '\0';
01645 *modep = RPMMIRE_REGEX;
01646 break;
01647 case RPMMIRE_STRCMP:
01648 case RPMMIRE_REGEX:
01649 case RPMMIRE_GLOB:
01650 pat = xstrdup(pattern);
01651 break;
01652 }
01653
01654 return pat;
01655 }
01656
01657 int rpmdbSetIteratorRE(rpmdbMatchIterator mi, rpmTag tag,
01658 rpmMireMode mode, const char * pattern)
01659 {
01660 static rpmMireMode defmode = (rpmMireMode)-1;
01661 miRE mire = NULL;
01662 const char * allpat = NULL;
01663 int notmatch = 0;
01664 regex_t * preg = NULL;
01665 int cflags = 0;
01666 int eflags = 0;
01667 int fnflags = 0;
01668 int rc = 0;
01669
01670 if (defmode == (rpmMireMode)-1) {
01671 const char *t = rpmExpand("%{?_query_selector_match}", NULL);
01672 if (*t == '\0' || !strcmp(t, "default"))
01673 defmode = RPMMIRE_DEFAULT;
01674 else if (!strcmp(t, "strcmp"))
01675 defmode = RPMMIRE_STRCMP;
01676 else if (!strcmp(t, "regex"))
01677 defmode = RPMMIRE_REGEX;
01678 else if (!strcmp(t, "glob"))
01679 defmode = RPMMIRE_GLOB;
01680 else
01681 defmode = RPMMIRE_DEFAULT;
01682 t = _free(t);
01683 }
01684
01685 if (mi == NULL || pattern == NULL)
01686 return rc;
01687
01688
01689 if (*pattern == '!') {
01690 notmatch = 1;
01691 pattern++;
01692 }
01693
01694
01695 allpat = mireDup(tag, &mode, pattern);
01696
01697
01698 if (mode == RPMMIRE_DEFAULT)
01699 mode = defmode;
01700
01701 switch (mode) {
01702 case RPMMIRE_DEFAULT:
01703 case RPMMIRE_STRCMP:
01704 break;
01705 case RPMMIRE_REGEX:
01706 preg = xcalloc(1, sizeof(*preg));
01707 cflags = (REG_EXTENDED | REG_NOSUB);
01708 rc = regcomp(preg, allpat, cflags);
01709 if (rc) {
01710 char msg[256];
01711 (void) regerror(rc, preg, msg, sizeof(msg)-1);
01712 msg[sizeof(msg)-1] = '\0';
01713 rpmError(RPMERR_REGCOMP, "%s: regcomp failed: %s\n", allpat, msg);
01714 }
01715 break;
01716 case RPMMIRE_GLOB:
01717 fnflags = FNM_PATHNAME | FNM_PERIOD;
01718 break;
01719 default:
01720 rc = -1;
01721 break;
01722 }
01723
01724 if (rc) {
01725
01726 allpat = _free(allpat);
01727 if (preg) {
01728 regfree(preg);
01729 preg = _free(preg);
01730 }
01731
01732 return rc;
01733 }
01734
01735 mi->mi_re = xrealloc(mi->mi_re, (mi->mi_nre + 1) * sizeof(*mi->mi_re));
01736 mire = mi->mi_re + mi->mi_nre;
01737 mi->mi_nre++;
01738
01739 mire->tag = tag;
01740 mire->mode = mode;
01741 mire->pattern = allpat;
01742 mire->notmatch = notmatch;
01743 mire->preg = preg;
01744 mire->cflags = cflags;
01745 mire->eflags = eflags;
01746 mire->fnflags = fnflags;
01747
01748 (void) qsort(mi->mi_re, mi->mi_nre, sizeof(*mi->mi_re), mireCmp);
01749
01750 return rc;
01751 }
01752
01758 static int mireSkip (const rpmdbMatchIterator mi)
01759
01760 {
01761
01762 HGE_t hge = (HGE_t) headerGetEntryMinMemory;
01763 HFD_t hfd = (HFD_t) headerFreeData;
01764 union {
01765 void * ptr;
01766 const char ** argv;
01767 const char * str;
01768 int_32 * i32p;
01769 int_16 * i16p;
01770 int_8 * i8p;
01771 } u;
01772 char numbuf[32];
01773 rpmTagType t;
01774 int_32 c;
01775 miRE mire;
01776 int ntags = 0;
01777 int nmatches = 0;
01778 int i, j;
01779 int rc;
01780
01781 if (mi->mi_h == NULL)
01782 return 0;
01783
01784
01785
01786
01787
01788 if ((mire = mi->mi_re) != NULL)
01789 for (i = 0; i < mi->mi_nre; i++, mire++) {
01790 int anymatch;
01791
01792 if (!hge(mi->mi_h, mire->tag, &t, (void **)&u, &c))
01793 continue;
01794
01795 anymatch = 0;
01796 while (1) {
01797 switch (t) {
01798 case RPM_CHAR_TYPE:
01799 case RPM_INT8_TYPE:
01800 sprintf(numbuf, "%d", (int) *u.i8p);
01801 rc = miregexec(mire, numbuf);
01802 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
01803 anymatch++;
01804 break;
01805 case RPM_INT16_TYPE:
01806 sprintf(numbuf, "%d", (int) *u.i16p);
01807 rc = miregexec(mire, numbuf);
01808 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
01809 anymatch++;
01810 break;
01811 case RPM_INT32_TYPE:
01812 sprintf(numbuf, "%d", (int) *u.i32p);
01813 rc = miregexec(mire, numbuf);
01814 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
01815 anymatch++;
01816 break;
01817 case RPM_STRING_TYPE:
01818 rc = miregexec(mire, u.str);
01819 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
01820 anymatch++;
01821 break;
01822 case RPM_I18NSTRING_TYPE:
01823 case RPM_STRING_ARRAY_TYPE:
01824 for (j = 0; j < c; j++) {
01825 rc = miregexec(mire, u.argv[j]);
01826 if ((!rc && !mire->notmatch) || (rc && mire->notmatch)) {
01827 anymatch++;
01828 break;
01829 }
01830 }
01831 break;
01832 case RPM_NULL_TYPE:
01833 case RPM_BIN_TYPE:
01834 default:
01835 break;
01836 }
01837 if ((i+1) < mi->mi_nre && mire[0].tag == mire[1].tag) {
01838 i++;
01839 mire++;
01840 continue;
01841 }
01842 break;
01843 }
01844
01845 u.ptr = hfd(u.ptr, t);
01846
01847 ntags++;
01848 if (anymatch)
01849 nmatches++;
01850 }
01851
01852 return (ntags == nmatches ? 0 : 1);
01853
01854 }
01855
01856 int rpmdbSetIteratorRelease(rpmdbMatchIterator mi, const char * release) {
01857 return rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release);
01858 }
01859
01860 int rpmdbSetIteratorVersion(rpmdbMatchIterator mi, const char * version) {
01861 return rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version);
01862 }
01863
01864 int rpmdbSetIteratorRewrite(rpmdbMatchIterator mi, int rewrite) {
01865 int rc;
01866 if (mi == NULL)
01867 return 0;
01868 rc = (mi->mi_cflags & DBI_WRITECURSOR) ? 1 : 0;
01869 if (rewrite)
01870 mi->mi_cflags |= DBI_WRITECURSOR;
01871 else
01872 mi->mi_cflags &= ~DBI_WRITECURSOR;
01873 return rc;
01874 }
01875
01876 int rpmdbSetIteratorModified(rpmdbMatchIterator mi, int modified) {
01877 int rc;
01878 if (mi == NULL)
01879 return 0;
01880 rc = mi->mi_modified;
01881 mi->mi_modified = modified;
01882 return rc;
01883 }
01884
01885 Header XrpmdbNextIterator(rpmdbMatchIterator mi,
01886 const char * f, unsigned int l)
01887 {
01888 return rpmdbNextIterator(mi);
01889 }
01890
01891 Header rpmdbNextIterator(rpmdbMatchIterator mi)
01892 {
01893 dbiIndex dbi;
01894 void * uh = NULL;
01895 size_t uhlen = 0;
01896 unsigned int gflags = 0;
01897 void * keyp;
01898 size_t keylen;
01899 int rc;
01900 int xx;
01901
01902 if (mi == NULL)
01903 return NULL;
01904
01905 dbi = dbiOpen(mi->mi_rpmdb, RPMDBI_PACKAGES, 0);
01906 if (dbi == NULL)
01907 return NULL;
01908
01909
01910
01911
01912
01913
01914
01915 if (mi->mi_dbc == NULL)
01916 xx = dbiCopen(dbi, &mi->mi_dbc, (mi->mi_cflags | DBI_ITERATOR));
01917 dbi->dbi_lastoffset = mi->mi_prevoffset;
01918
01919 top:
01920
01921 do {
01922 if (mi->mi_set) {
01923 if (!(mi->mi_setx < mi->mi_set->count))
01924 return NULL;
01925 mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx);
01926 mi->mi_filenum = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx);
01927 keyp = &mi->mi_offset;
01928 keylen = sizeof(mi->mi_offset);
01929 } else {
01930 keyp = (void *)mi->mi_keyp;
01931 keylen = mi->mi_keylen;
01932
01933 rc = dbiGet(dbi, mi->mi_dbc, &keyp, &keylen, &uh, &uhlen, gflags);
01934 if (dbi->dbi_api == 1 && dbi->dbi_rpmtag == RPMDBI_PACKAGES && rc == EFAULT) {
01935 rpmError(RPMERR_INTERNAL,
01936 _("record number %u in database is bad -- skipping.\n"), dbi->dbi_lastoffset);
01937 if (keyp && dbi->dbi_lastoffset)
01938 memcpy(&mi->mi_offset, keyp, sizeof(mi->mi_offset));
01939 continue;
01940 }
01941
01942
01943
01944
01945
01946
01947
01948
01949 if (rc == 0 && keyp && (dbi->dbi_lastoffset || mi->mi_setx))
01950 memcpy(&mi->mi_offset, keyp, sizeof(mi->mi_offset));
01951
01952
01953 if (rc || (mi->mi_setx && mi->mi_offset == 0))
01954 return NULL;
01955 }
01956 mi->mi_setx++;
01957 } while (mi->mi_offset == 0);
01958
01959 if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset)
01960 goto exit;
01961
01962
01963 if (uh == NULL) {
01964 rc = dbiGet(dbi, mi->mi_dbc, &keyp, &keylen, &uh, &uhlen, gflags);
01965 if (rc)
01966 return NULL;
01967 }
01968
01969
01970 if (mi->mi_h) {
01971 if (mi->mi_modified && mi->mi_prevoffset)
01972 (void)dbiUpdateRecord(dbi, mi->mi_dbc, mi->mi_prevoffset, mi->mi_h);
01973 mi->mi_h = headerFree(mi->mi_h);
01974 }
01975
01976
01977 if (uh == NULL)
01978 goto exit;
01979
01980 mi->mi_h = headerCopyLoad(uh);
01981
01982 if (dbi->dbi_api == 1) uh = _free(uh);
01983
01984
01985 if (mi->mi_h == NULL || !headerIsEntry(mi->mi_h, RPMTAG_NAME)) {
01986 rpmError(RPMERR_BADHEADER,
01987 _("rpmdb: damaged header instance #%u retrieved, skipping.\n"),
01988 mi->mi_offset);
01989 goto top;
01990 }
01991
01992
01993
01994
01995 if (mireSkip(mi)) {
01996
01997 if (mi->mi_set || mi->mi_keyp == NULL)
01998 goto top;
01999 return NULL;
02000 }
02001
02002 mi->mi_prevoffset = mi->mi_offset;
02003 mi->mi_modified = 0;
02004
02005 exit:
02006 #ifdef NOTNOW
02007 if (mi->mi_h) {
02008 const char *n, *v, *r;
02009 (void) headerNVR(mi->mi_h, &n, &v, &r);
02010 rpmMessage(RPMMESS_DEBUG, "%s-%s-%s at 0x%x, h %p\n", n, v, r,
02011 mi->mi_offset, mi->mi_h);
02012 }
02013 #endif
02014
02015 return mi->mi_h;
02016
02017 }
02018
02019 static void rpmdbSortIterator( rpmdbMatchIterator mi)
02020
02021 {
02022 if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) {
02023 qsort(mi->mi_set->recs, mi->mi_set->count, sizeof(*mi->mi_set->recs),
02024 hdrNumCmp);
02025 mi->mi_sorted = 1;
02026 }
02027 }
02028
02029 static int rpmdbGrowIterator( rpmdbMatchIterator mi,
02030 const void * keyp, size_t keylen, int fpNum)
02031
02032 {
02033 dbiIndex dbi = NULL;
02034 DBC * dbcursor = NULL;
02035 dbiIndexSet set = NULL;
02036 int rc;
02037 int xx;
02038
02039 if (!(mi && keyp))
02040 return 1;
02041
02042 dbi = dbiOpen(mi->mi_rpmdb, mi->mi_rpmtag, 0);
02043 if (dbi == NULL)
02044 return 1;
02045
02046 if (keylen == 0)
02047 keylen = strlen(keyp);
02048
02049 xx = dbiCopen(dbi, &dbcursor, 0);
02050 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
02051 xx = dbiCclose(dbi, dbcursor, 0);
02052 dbcursor = NULL;
02053
02054 if (rc == 0) {
02055 int i;
02056 for (i = 0; i < set->count; i++)
02057 set->recs[i].fpNum = fpNum;
02058
02059 if (mi->mi_set == NULL) {
02060 mi->mi_set = set;
02061 set = NULL;
02062 } else {
02063 mi->mi_set->recs = xrealloc(mi->mi_set->recs,
02064 (mi->mi_set->count + set->count) * sizeof(*(mi->mi_set->recs)));
02065 memcpy(mi->mi_set->recs + mi->mi_set->count, set->recs,
02066 set->count * sizeof(*(mi->mi_set->recs)));
02067 mi->mi_set->count += set->count;
02068 }
02069 }
02070
02071 set = dbiFreeIndexSet(set);
02072 return rc;
02073 }
02074
02075 int rpmdbPruneIterator(rpmdbMatchIterator mi, int * hdrNums,
02076 int nHdrNums, int sorted)
02077 {
02078 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
02079 return 1;
02080
02081 if (mi->mi_set)
02082 (void) dbiPruneSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), sorted);
02083 return 0;
02084 }
02085
02086 int rpmdbAppendIterator(rpmdbMatchIterator mi, const int * hdrNums, int nHdrNums)
02087 {
02088 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
02089 return 1;
02090
02091 if (mi->mi_set == NULL)
02092 mi->mi_set = xcalloc(1, sizeof(*mi->mi_set));
02093 (void) dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0);
02094 return 0;
02095 }
02096
02097 rpmdbMatchIterator rpmdbInitIterator(rpmdb rpmdb, int rpmtag,
02098 const void * keyp, size_t keylen)
02099 {
02100 rpmdbMatchIterator mi = NULL;
02101 dbiIndexSet set = NULL;
02102 dbiIndex dbi;
02103 const void * mi_keyp = NULL;
02104 int isLabel = 0;
02105
02106 if (rpmdb == NULL)
02107 return NULL;
02108
02109 switch (rpmtag) {
02110 case RPMDBI_LABEL:
02111 rpmtag = RPMTAG_NAME;
02112 isLabel = 1;
02113 break;
02114 }
02115
02116 dbi = dbiOpen(rpmdb, rpmtag, 0);
02117 if (dbi == NULL)
02118 return NULL;
02119
02120 #if 0
02121 assert(dbi->dbi_rmw == NULL);
02122 assert(dbi->dbi_lastoffset == 0);
02123 #else
02124 if (dbi->dbi_rmw)
02125 fprintf(stderr, "*** RMW %s %p\n", tagName(rpmtag), dbi->dbi_rmw);
02126 #endif
02127
02128 dbi->dbi_lastoffset = 0;
02129
02130 if (rpmtag != RPMDBI_PACKAGES && keyp) {
02131 DBC * dbcursor = NULL;
02132 int rc;
02133 int xx;
02134
02135 if (isLabel) {
02136
02137 xx = dbiCopen(dbi, &dbcursor, 0);
02138 rc = dbiFindByLabel(dbi, dbcursor, keyp, &set);
02139 xx = dbiCclose(dbi, dbcursor, 0);
02140 dbcursor = NULL;
02141 } else if (rpmtag == RPMTAG_BASENAMES) {
02142 rc = rpmdbFindByFile(rpmdb, keyp, &set);
02143 } else {
02144 xx = dbiCopen(dbi, &dbcursor, 0);
02145
02146 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
02147
02148 xx = dbiCclose(dbi, dbcursor, 0);
02149 dbcursor = NULL;
02150 }
02151 if (rc) {
02152 set = dbiFreeIndexSet(set);
02153 return NULL;
02154 }
02155 }
02156
02157 if (keyp) {
02158 char * k;
02159
02160 if (rpmtag != RPMDBI_PACKAGES && keylen == 0)
02161 keylen = strlen(keyp);
02162 k = xmalloc(keylen + 1);
02163 memcpy(k, keyp, keylen);
02164 k[keylen] = '\0';
02165 mi_keyp = k;
02166 }
02167
02168 mi = xcalloc(1, sizeof(*mi));
02169 mi->mi_keyp = mi_keyp;
02170 mi->mi_keylen = keylen;
02171
02172
02173 mi->mi_rpmdb = rpmdb;
02174
02175 mi->mi_rpmtag = rpmtag;
02176
02177 mi->mi_dbc = NULL;
02178 mi->mi_set = set;
02179 mi->mi_setx = 0;
02180 mi->mi_ndups = 0;
02181 mi->mi_h = NULL;
02182 mi->mi_sorted = 0;
02183 mi->mi_cflags = 0;
02184 mi->mi_modified = 0;
02185 mi->mi_prevoffset = 0;
02186 mi->mi_offset = 0;
02187 mi->mi_filenum = 0;
02188 mi->mi_fpnum = 0;
02189 mi->mi_dbnum = 0;
02190 mi->mi_nre = 0;
02191 mi->mi_re = NULL;
02192 mi->mi_version = NULL;
02193 mi->mi_release = NULL;
02194 return mi;
02195 }
02196
02206 static INLINE int removeIndexEntry(dbiIndex dbi, DBC * dbcursor,
02207 const void * keyp, size_t keylen, dbiIndexItem rec)
02208
02209 {
02210 dbiIndexSet set = NULL;
02211 int rc;
02212
02213 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
02214
02215 if (rc < 0)
02216 rc = 0;
02217 else if (rc > 0)
02218 rc = 1;
02219 else {
02220
02221 rc = dbiPruneSet(set, rec, 1, sizeof(*rec), 1);
02222
02223 if (rc == 0 && dbiUpdateIndex(dbi, dbcursor, keyp, keylen, set))
02224 rc = 1;
02225 }
02226
02227 set = dbiFreeIndexSet(set);
02228
02229 return rc;
02230 }
02231
02232
02233 int rpmdbRemove(rpmdb rpmdb, int rid, unsigned int hdrNum)
02234 {
02235 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
02236 HFD_t hfd = headerFreeData;
02237 Header h;
02238 sigset_t signalMask;
02239
02240 if (rpmdb == NULL)
02241 return 0;
02242
02243 { rpmdbMatchIterator mi;
02244 mi = rpmdbInitIterator(rpmdb, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum));
02245 h = rpmdbNextIterator(mi);
02246 if (h)
02247 h = headerLink(h);
02248 mi = rpmdbFreeIterator(mi);
02249 }
02250
02251 if (h == NULL) {
02252 rpmError(RPMERR_DBCORRUPT, _("%s: cannot read header at 0x%x\n"),
02253 "rpmdbRemove", hdrNum);
02254 return 1;
02255 }
02256
02257 #ifdef DYING
02258
02259 if (rid != 0 && rid != -1) {
02260 int_32 tid = rid;
02261 (void) headerAddEntry(h, RPMTAG_REMOVETID, RPM_INT32_TYPE, &tid, 1);
02262 }
02263 #endif
02264
02265 { const char *n, *v, *r;
02266 (void) headerNVR(h, &n, &v, &r);
02267 rpmMessage(RPMMESS_DEBUG, " --- %10u %s-%s-%s\n", hdrNum, n, v, r);
02268 }
02269
02270 (void) blockSignals(rpmdb, &signalMask);
02271
02272 { int dbix;
02273 dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
02274
02275 if (dbiTags != NULL)
02276 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
02277 dbiIndex dbi;
02278 DBC * dbcursor = NULL;
02279 const char *av[1];
02280 const char ** rpmvals = NULL;
02281 rpmTagType rpmtype = 0;
02282 int rpmcnt = 0;
02283 int rpmtag;
02284 int xx;
02285 int i;
02286
02287 dbi = NULL;
02288 rpmtag = dbiTags[dbix];
02289
02290 switch (rpmtag) {
02291
02292 case RPMDBI_AVAILABLE:
02293 case RPMDBI_ADDED:
02294 case RPMDBI_REMOVED:
02295 case RPMDBI_DEPENDS:
02296 continue;
02297 break;
02298 case RPMDBI_PACKAGES:
02299 dbi = dbiOpen(rpmdb, rpmtag, 0);
02300 if (dbi != NULL) {
02301 xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
02302 xx = dbiDel(dbi, dbcursor, &hdrNum, sizeof(hdrNum), 0);
02303 xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
02304 dbcursor = NULL;
02305 if (!dbi->dbi_no_dbsync)
02306 xx = dbiSync(dbi, 0);
02307 }
02308 continue;
02309 break;
02310 }
02311
02312 if (!hge(h, rpmtag, &rpmtype, (void **) &rpmvals, &rpmcnt))
02313 continue;
02314
02315 dbi = dbiOpen(rpmdb, rpmtag, 0);
02316 if (dbi != NULL) {
02317 xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
02318
02319 if (rpmtype == RPM_STRING_TYPE) {
02320
02321 rpmMessage(RPMMESS_DEBUG, _("removing \"%s\" from %s index.\n"),
02322 (const char *)rpmvals, tagName(dbi->dbi_rpmtag));
02323
02324
02325 av[0] = (const char *) rpmvals;
02326 rpmvals = av;
02327 rpmcnt = 1;
02328 } else {
02329
02330 rpmMessage(RPMMESS_DEBUG, _("removing %d entries from %s index.\n"),
02331 rpmcnt, tagName(dbi->dbi_rpmtag));
02332
02333 }
02334
02335 for (i = 0; i < rpmcnt; i++) {
02336 const void * valp;
02337 size_t vallen;
02338
02339
02340 switch (rpmtype) {
02341 case RPM_CHAR_TYPE:
02342 case RPM_INT8_TYPE:
02343 vallen = sizeof(RPM_CHAR_TYPE);
02344 valp = rpmvals + i;
02345 break;
02346 case RPM_INT16_TYPE:
02347 vallen = sizeof(int_16);
02348 valp = rpmvals + i;
02349 break;
02350 case RPM_INT32_TYPE:
02351 vallen = sizeof(int_32);
02352 valp = rpmvals + i;
02353 break;
02354 case RPM_BIN_TYPE:
02355 vallen = rpmcnt;
02356 valp = rpmvals;
02357 rpmcnt = 1;
02358 break;
02359 case RPM_STRING_TYPE:
02360 case RPM_I18NSTRING_TYPE:
02361 rpmcnt = 1;
02362
02363 case RPM_STRING_ARRAY_TYPE:
02364 default:
02365 vallen = strlen(rpmvals[i]);
02366 valp = rpmvals[i];
02367 break;
02368 }
02369
02370
02371
02372
02373
02374
02375
02376 xx = removeIndexEntry(dbi, dbcursor, valp, vallen, rec);
02377 }
02378
02379 xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
02380 dbcursor = NULL;
02381
02382 if (!dbi->dbi_no_dbsync)
02383 xx = dbiSync(dbi, 0);
02384 }
02385
02386 rpmvals = hfd(rpmvals, rpmtype);
02387 rpmtype = 0;
02388 rpmcnt = 0;
02389 }
02390
02391 rec = _free(rec);
02392 }
02393
02394 (void) unblockSignals(rpmdb, &signalMask);
02395
02396 h = headerFree(h);
02397
02398 return 0;
02399 }
02400
02410 static INLINE int addIndexEntry(dbiIndex dbi, DBC * dbcursor,
02411 const char * keyp, size_t keylen, dbiIndexItem rec)
02412
02413 {
02414 dbiIndexSet set = NULL;
02415 int rc;
02416
02417 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
02418
02419 if (rc > 0) {
02420 rc = 1;
02421 } else {
02422
02423
02424 if (rc == 0 && dbi->dbi_permit_dups)
02425 set = dbiFreeIndexSet(set);
02426
02427 if (set == NULL || rc < 0) {
02428 rc = 0;
02429 set = xcalloc(1, sizeof(*set));
02430 }
02431 (void) dbiAppendSet(set, rec, 1, sizeof(*rec), 0);
02432 if (dbiUpdateIndex(dbi, dbcursor, keyp, keylen, set))
02433 rc = 1;
02434 }
02435 set = dbiFreeIndexSet(set);
02436
02437 return 0;
02438 }
02439
02440
02441 int rpmdbAdd(rpmdb rpmdb, int iid, Header h)
02442 {
02443 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
02444 HFD_t hfd = headerFreeData;
02445 sigset_t signalMask;
02446 const char ** baseNames;
02447 rpmTagType bnt;
02448 int count = 0;
02449 dbiIndex dbi;
02450 int dbix;
02451 unsigned int gflags = 0;
02452 unsigned int pflags = 0;
02453 unsigned int hdrNum = 0;
02454 int rc = 0;
02455 int xx;
02456
02457 if (rpmdb == NULL)
02458 return 0;
02459
02460 if (iid != 0 && iid != -1) {
02461 int_32 tid = iid;
02462 (void) headerRemoveEntry(h, RPMTAG_REMOVETID);
02463 if (!headerIsEntry(h, RPMTAG_INSTALLTID))
02464 (void) headerAddEntry(h, RPMTAG_INSTALLTID, RPM_INT32_TYPE, &tid, 1);
02465 }
02466
02467
02468
02469
02470
02471
02472
02473 (void) hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, &count);
02474
02475 if (_noDirTokens)
02476 expandFilelist(h);
02477
02478 (void) blockSignals(rpmdb, &signalMask);
02479
02480 {
02481 unsigned int firstkey = 0;
02482 DBC * dbcursor = NULL;
02483 void * keyp = &firstkey;
02484 size_t keylen = sizeof(firstkey);
02485 void * datap = NULL;
02486 size_t datalen = 0;
02487
02488 dbi = dbiOpen(rpmdb, RPMDBI_PACKAGES, 0);
02489 if (dbi != NULL) {
02490
02491
02492 datap = h;
02493 datalen = headerSizeof(h, HEADER_MAGIC_NO);
02494
02495 xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
02496
02497
02498
02499 rc = dbiGet(dbi, dbcursor, &keyp, &keylen, &datap, &datalen, gflags);
02500
02501 hdrNum = 0;
02502 if (rc == 0 && datap)
02503 memcpy(&hdrNum, datap, sizeof(hdrNum));
02504 ++hdrNum;
02505 if (rc == 0 && datap) {
02506
02507 memcpy(datap, &hdrNum, sizeof(hdrNum));
02508
02509 } else {
02510 datap = &hdrNum;
02511 datalen = sizeof(hdrNum);
02512 }
02513
02514 rc = dbiPut(dbi, dbcursor, keyp, keylen, datap, datalen, pflags);
02515 xx = dbiSync(dbi, 0);
02516
02517 xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
02518 dbcursor = NULL;
02519 }
02520
02521 }
02522
02523 if (rc) {
02524 rpmError(RPMERR_DBCORRUPT,
02525 _("error(%d) allocating new package instance\n"), rc);
02526 goto exit;
02527 }
02528
02529
02530
02531 if (hdrNum)
02532 { dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
02533
02534 if (dbiTags != NULL)
02535 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
02536 DBC * dbcursor = NULL;
02537 const char *av[1];
02538 const char **rpmvals = NULL;
02539 rpmTagType rpmtype = 0;
02540 int rpmcnt = 0;
02541 int rpmtag;
02542 int_32 * requireFlags;
02543 int i, j;
02544
02545 dbi = NULL;
02546 requireFlags = NULL;
02547 rpmtag = dbiTags[dbix];
02548
02549 switch (rpmtag) {
02550
02551 case RPMDBI_AVAILABLE:
02552 case RPMDBI_ADDED:
02553 case RPMDBI_REMOVED:
02554 case RPMDBI_DEPENDS:
02555 continue;
02556 break;
02557 case RPMDBI_PACKAGES:
02558 dbi = dbiOpen(rpmdb, rpmtag, 0);
02559 if (dbi != NULL) {
02560 xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
02561 xx = dbiUpdateRecord(dbi, dbcursor, hdrNum, h);
02562 xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
02563 dbcursor = NULL;
02564 if (!dbi->dbi_no_dbsync)
02565 xx = dbiSync(dbi, 0);
02566 { const char *n, *v, *r;
02567 (void) headerNVR(h, &n, &v, &r);
02568 rpmMessage(RPMMESS_DEBUG, " +++ %10u %s-%s-%s\n", hdrNum, n, v, r);
02569 }
02570 }
02571 continue;
02572 break;
02573
02574 case RPMTAG_BASENAMES:
02575 rpmtype = bnt;
02576 rpmvals = baseNames;
02577 rpmcnt = count;
02578 break;
02579 case RPMTAG_REQUIRENAME:
02580 (void) hge(h, rpmtag, &rpmtype, (void **)&rpmvals, &rpmcnt);
02581 (void) hge(h, RPMTAG_REQUIREFLAGS, NULL, (void **)&requireFlags, NULL);
02582 break;
02583 default:
02584 (void) hge(h, rpmtag, &rpmtype, (void **)&rpmvals, &rpmcnt);
02585 break;
02586 }
02587
02588 if (rpmcnt <= 0) {
02589 if (rpmtag != RPMTAG_GROUP)
02590 continue;
02591
02592
02593 rpmtype = RPM_STRING_TYPE;
02594 rpmvals = (const char **) "Unknown";
02595 rpmcnt = 1;
02596 }
02597
02598 dbi = dbiOpen(rpmdb, rpmtag, 0);
02599 if (dbi != NULL) {
02600
02601 xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
02602 if (rpmtype == RPM_STRING_TYPE) {
02603 rpmMessage(RPMMESS_DEBUG, _("adding \"%s\" to %s index.\n"),
02604 (const char *)rpmvals, tagName(dbi->dbi_rpmtag));
02605
02606
02607
02608 av[0] = (const char *) rpmvals;
02609
02610 rpmvals = av;
02611 rpmcnt = 1;
02612 } else {
02613
02614 rpmMessage(RPMMESS_DEBUG, _("adding %d entries to %s index.\n"),
02615 rpmcnt, tagName(dbi->dbi_rpmtag));
02616
02617 }
02618
02619 for (i = 0; i < rpmcnt; i++) {
02620 const void * valp;
02621 size_t vallen;
02622
02623
02624
02625
02626
02627 switch (dbi->dbi_rpmtag) {
02628 case RPMTAG_REQUIRENAME:
02629
02630 if (requireFlags && isInstallPreReq(requireFlags[i]))
02631 continue;
02632 rec->tagNum = i;
02633 break;
02634 case RPMTAG_TRIGGERNAME:
02635 if (i) {
02636 for (j = 0; j < i; j++) {
02637 if (!strcmp(rpmvals[i], rpmvals[j]))
02638 break;
02639 }
02640 if (j < i)
02641 continue;
02642 }
02643 rec->tagNum = i;
02644 break;
02645 default:
02646 rec->tagNum = i;
02647 break;
02648 }
02649
02650
02651 switch (rpmtype) {
02652 case RPM_CHAR_TYPE:
02653 case RPM_INT8_TYPE:
02654 vallen = sizeof(int_8);
02655 valp = rpmvals + i;
02656 break;
02657 case RPM_INT16_TYPE:
02658 vallen = sizeof(int_16);
02659 valp = rpmvals + i;
02660 break;
02661 case RPM_INT32_TYPE:
02662 vallen = sizeof(int_32);
02663 valp = rpmvals + i;
02664 break;
02665 case RPM_BIN_TYPE:
02666 vallen = rpmcnt;
02667 valp = rpmvals;
02668 rpmcnt = 1;
02669 break;
02670 case RPM_STRING_TYPE:
02671 case RPM_I18NSTRING_TYPE:
02672 rpmcnt = 1;
02673
02674 case RPM_STRING_ARRAY_TYPE:
02675 default:
02676 valp = rpmvals[i];
02677 vallen = strlen(rpmvals[i]);
02678 break;
02679 }
02680
02681 rc += addIndexEntry(dbi, dbcursor, valp, vallen, rec);
02682 }
02683 xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
02684 dbcursor = NULL;
02685
02686 if (!dbi->dbi_no_dbsync)
02687 xx = dbiSync(dbi, 0);
02688 }
02689
02690
02691 rpmvals = hfd(rpmvals, rpmtype);
02692
02693 rpmtype = 0;
02694 rpmcnt = 0;
02695 }
02696
02697 rec = _free(rec);
02698 }
02699
02700 exit:
02701 (void) unblockSignals(rpmdb, &signalMask);
02702
02703 return rc;
02704 }
02705
02706
02707 int rpmdbFindFpList(rpmdb rpmdb, fingerPrint * fpList, dbiIndexSet * matchList,
02708 int numItems)
02709 {
02710 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
02711 HFD_t hfd = headerFreeData;
02712 rpmdbMatchIterator mi;
02713 fingerPrintCache fpc;
02714 Header h;
02715 int i;
02716
02717 if (rpmdb == NULL) return 0;
02718
02719 mi = rpmdbInitIterator(rpmdb, RPMTAG_BASENAMES, NULL, 0);
02720
02721
02722 for (i = 0; i < numItems; i++) {
02723 (void) rpmdbGrowIterator(mi, fpList[i].baseName, 0, i);
02724 matchList[i] = xcalloc(1, sizeof(*(matchList[i])));
02725 }
02726
02727 if ((i = rpmdbGetIteratorCount(mi)) == 0) {
02728 mi = rpmdbFreeIterator(mi);
02729 return 0;
02730 }
02731 fpc = fpCacheCreate(i);
02732
02733 rpmdbSortIterator(mi);
02734
02735
02736
02737 if (mi != NULL)
02738 while ((h = rpmdbNextIterator(mi)) != NULL) {
02739 const char ** dirNames;
02740 const char ** baseNames;
02741 const char ** fullBaseNames;
02742 rpmTagType bnt, dnt;
02743 int_32 * dirIndexes;
02744 int_32 * fullDirIndexes;
02745 fingerPrint * fps;
02746 dbiIndexItem im;
02747 int start;
02748 int num;
02749 int end;
02750
02751 start = mi->mi_setx - 1;
02752 im = mi->mi_set->recs + start;
02753
02754
02755 for (end = start + 1; end < mi->mi_set->count; end++) {
02756 if (im->hdrNum != mi->mi_set->recs[end].hdrNum)
02757 break;
02758 }
02759 num = end - start;
02760
02761
02762 (void) hge(h, RPMTAG_BASENAMES, &bnt, (void **) &fullBaseNames, NULL);
02763 (void) hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
02764 (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &fullDirIndexes, NULL);
02765
02766 baseNames = xcalloc(num, sizeof(*baseNames));
02767 dirIndexes = xcalloc(num, sizeof(*dirIndexes));
02768 for (i = 0; i < num; i++) {
02769 baseNames[i] = fullBaseNames[im[i].tagNum];
02770 dirIndexes[i] = fullDirIndexes[im[i].tagNum];
02771 }
02772
02773 fps = xcalloc(num, sizeof(*fps));
02774 fpLookupList(fpc, dirNames, baseNames, dirIndexes, num, fps);
02775
02776
02777 for (i = 0; i < num; i++, im++) {
02778
02779 if (FP_EQUAL(fps[i], fpList[im->fpNum])) {
02780
02781
02782 (void) dbiAppendSet(matchList[im->fpNum], im, 1, sizeof(*im), 0);
02783
02784 }
02785 }
02786
02787 fps = _free(fps);
02788 dirNames = hfd(dirNames, dnt);
02789 fullBaseNames = hfd(fullBaseNames, bnt);
02790 baseNames = _free(baseNames);
02791 dirIndexes = _free(dirIndexes);
02792
02793 mi->mi_setx = end;
02794 }
02795
02796 mi = rpmdbFreeIterator(mi);
02797
02798 fpCacheFree(fpc);
02799
02800 return 0;
02801
02802 }
02803
02804 char * db1basename (int rpmtag)
02805 {
02806 char * base = NULL;
02807 switch (rpmtag) {
02808 case RPMDBI_PACKAGES: base = "packages.rpm"; break;
02809 case RPMTAG_NAME: base = "nameindex.rpm"; break;
02810 case RPMTAG_BASENAMES: base = "fileindex.rpm"; break;
02811 case RPMTAG_GROUP: base = "groupindex.rpm"; break;
02812 case RPMTAG_REQUIRENAME: base = "requiredby.rpm"; break;
02813 case RPMTAG_PROVIDENAME: base = "providesindex.rpm"; break;
02814 case RPMTAG_CONFLICTNAME: base = "conflictsindex.rpm"; break;
02815 case RPMTAG_TRIGGERNAME: base = "triggerindex.rpm"; break;
02816 default:
02817 { const char * tn = tagName(rpmtag);
02818 base = alloca( strlen(tn) + sizeof(".idx") + 1 );
02819 (void) stpcpy( stpcpy(base, tn), ".idx");
02820 } break;
02821 }
02822 return xstrdup(base);
02823 }
02824
02825 static int rpmdbRemoveDatabase(const char * rootdir,
02826 const char * dbpath, int _dbapi)
02827
02828 {
02829 int i;
02830 char * filename;
02831 int xx;
02832
02833 i = strlen(dbpath);
02834 if (dbpath[i - 1] != '/') {
02835 filename = alloca(i);
02836 strcpy(filename, dbpath);
02837 filename[i] = '/';
02838 filename[i + 1] = '\0';
02839 dbpath = filename;
02840 }
02841
02842 filename = alloca(strlen(rootdir) + strlen(dbpath) + 40);
02843
02844 switch (_dbapi) {
02845 case 3:
02846 if (dbiTags != NULL)
02847 for (i = 0; i < dbiTagsMax; i++) {
02848 const char * base = tagName(dbiTags[i]);
02849 sprintf(filename, "%s/%s/%s", rootdir, dbpath, base);
02850 (void)rpmCleanPath(filename);
02851 if (!rpmfileexists(filename))
02852 continue;
02853 xx = unlink(filename);
02854 }
02855 for (i = 0; i < 16; i++) {
02856 sprintf(filename, "%s/%s/__db.%03d", rootdir, dbpath, i);
02857 (void)rpmCleanPath(filename);
02858 if (!rpmfileexists(filename))
02859 continue;
02860 xx = unlink(filename);
02861 }
02862 break;
02863 case 2:
02864 case 1:
02865 case 0:
02866 if (dbiTags != NULL)
02867 for (i = 0; i < dbiTagsMax; i++) {
02868 const char * base = db1basename(dbiTags[i]);
02869 sprintf(filename, "%s/%s/%s", rootdir, dbpath, base);
02870 (void)rpmCleanPath(filename);
02871 if (!rpmfileexists(filename))
02872 continue;
02873 xx = unlink(filename);
02874 base = _free(base);
02875 }
02876 break;
02877 }
02878
02879 sprintf(filename, "%s/%s", rootdir, dbpath);
02880 (void)rpmCleanPath(filename);
02881 xx = rmdir(filename);
02882
02883 return 0;
02884 }
02885
02886 static int rpmdbMoveDatabase(const char * rootdir,
02887 const char * olddbpath, int _olddbapi,
02888 const char * newdbpath, int _newdbapi)
02889
02890 {
02891 int i;
02892 char * ofilename, * nfilename;
02893 int rc = 0;
02894 int xx;
02895
02896 i = strlen(olddbpath);
02897 if (olddbpath[i - 1] != '/') {
02898 ofilename = alloca(i + 2);
02899 strcpy(ofilename, olddbpath);
02900 ofilename[i] = '/';
02901 ofilename[i + 1] = '\0';
02902 olddbpath = ofilename;
02903 }
02904
02905 i = strlen(newdbpath);
02906 if (newdbpath[i - 1] != '/') {
02907 nfilename = alloca(i + 2);
02908 strcpy(nfilename, newdbpath);
02909 nfilename[i] = '/';
02910 nfilename[i + 1] = '\0';
02911 newdbpath = nfilename;
02912 }
02913
02914 ofilename = alloca(strlen(rootdir) + strlen(olddbpath) + 40);
02915 nfilename = alloca(strlen(rootdir) + strlen(newdbpath) + 40);
02916
02917 switch (_olddbapi) {
02918 case 3:
02919 if (dbiTags != NULL)
02920 for (i = 0; i < dbiTagsMax; i++) {
02921 const char * base;
02922 int rpmtag;
02923
02924
02925 switch ((rpmtag = dbiTags[i])) {
02926 case RPMDBI_AVAILABLE:
02927 case RPMDBI_ADDED:
02928 case RPMDBI_REMOVED:
02929 case RPMDBI_DEPENDS:
02930 continue;
02931 break;
02932 default:
02933 break;
02934 }
02935
02936 base = tagName(rpmtag);
02937 sprintf(ofilename, "%s/%s/%s", rootdir, olddbpath, base);
02938 (void)rpmCleanPath(ofilename);
02939 if (!rpmfileexists(ofilename))
02940 continue;
02941 sprintf(nfilename, "%s/%s/%s", rootdir, newdbpath, base);
02942 (void)rpmCleanPath(nfilename);
02943 if ((xx = Rename(ofilename, nfilename)) != 0)
02944 rc = 1;
02945 }
02946 for (i = 0; i < 16; i++) {
02947 sprintf(ofilename, "%s/%s/__db.%03d", rootdir, olddbpath, i);
02948 (void)rpmCleanPath(ofilename);
02949 if (!rpmfileexists(ofilename))
02950 continue;
02951 xx = unlink(ofilename);
02952 sprintf(nfilename, "%s/%s/__db.%03d", rootdir, newdbpath, i);
02953 (void)rpmCleanPath(nfilename);
02954 #ifdef DYING
02955 if ((xx = Rename(ofilename, nfilename)) != 0)
02956 rc = 1;
02957 #else
02958 xx = unlink(nfilename);
02959 #endif
02960 }
02961 break;
02962 case 2:
02963 case 1:
02964 case 0:
02965 if (dbiTags != NULL)
02966 for (i = 0; i < dbiTagsMax; i++) {
02967 const char * base;
02968 int rpmtag;
02969
02970
02971 switch ((rpmtag = dbiTags[i])) {
02972 case RPMDBI_AVAILABLE:
02973 case RPMDBI_ADDED:
02974 case RPMDBI_REMOVED:
02975 case RPMDBI_DEPENDS:
02976 continue;
02977 break;
02978 default:
02979 break;
02980 }
02981
02982 base = db1basename(rpmtag);
02983 sprintf(ofilename, "%s/%s/%s", rootdir, olddbpath, base);
02984 (void)rpmCleanPath(ofilename);
02985 if (!rpmfileexists(ofilename))
02986 continue;
02987 sprintf(nfilename, "%s/%s/%s", rootdir, newdbpath, base);
02988 (void)rpmCleanPath(nfilename);
02989 if ((xx = Rename(ofilename, nfilename)) != 0)
02990 rc = 1;
02991 base = _free(base);
02992 }
02993 break;
02994 }
02995 if (rc || _olddbapi == _newdbapi)
02996 return rc;
02997
02998 rc = rpmdbRemoveDatabase(rootdir, newdbpath, _newdbapi);
02999
03000
03001
03002 if (rc == 0 && _newdbapi == 1 && _olddbapi == 3) {
03003 const char * mdb1 = "/etc/rpm/macros.db1";
03004 struct stat st;
03005 if (!stat(mdb1, &st) && S_ISREG(st.st_mode) && !unlink(mdb1))
03006 rpmMessage(RPMMESS_DEBUG,
03007 _("removing %s after successful db3 rebuild.\n"), mdb1);
03008 }
03009 return rc;
03010 }
03011
03012 int rpmdbRebuild(const char * rootdir)
03013 {
03014 rpmdb olddb;
03015 const char * dbpath = NULL;
03016 const char * rootdbpath = NULL;
03017 rpmdb newdb;
03018 const char * newdbpath = NULL;
03019 const char * newrootdbpath = NULL;
03020 const char * tfn;
03021 int nocleanup = 1;
03022 int failed = 0;
03023 int removedir = 0;
03024 int rc = 0, xx;
03025 int _dbapi;
03026 int _dbapi_rebuild;
03027
03028 if (rootdir == NULL) rootdir = "/";
03029
03030 _dbapi = rpmExpandNumeric("%{_dbapi}");
03031 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
03032
03033
03034 tfn = rpmGetPath("%{_dbpath}", NULL);
03035
03036 if (!(tfn && tfn[0] != '%')) {
03037 rpmMessage(RPMMESS_DEBUG, _("no dbpath has been set"));
03038 rc = 1;
03039 goto exit;
03040 }
03041 dbpath = rootdbpath = rpmGetPath(rootdir, tfn, NULL);
03042 if (!(rootdir[0] == '/' && rootdir[1] == '\0'))
03043 dbpath += strlen(rootdir);
03044 tfn = _free(tfn);
03045
03046
03047 tfn = rpmGetPath("%{_dbpath_rebuild}", NULL);
03048
03049 if (!(tfn && tfn[0] != '%' && strcmp(tfn, dbpath))) {
03050 char pidbuf[20];
03051 char *t;
03052 sprintf(pidbuf, "rebuilddb.%d", (int) getpid());
03053 t = xmalloc(strlen(dbpath) + strlen(pidbuf) + 1);
03054 (void)stpcpy(stpcpy(t, dbpath), pidbuf);
03055 tfn = _free(tfn);
03056 tfn = t;
03057 nocleanup = 0;
03058 }
03059 newdbpath = newrootdbpath = rpmGetPath(rootdir, tfn, NULL);
03060 if (!(rootdir[0] == '/' && rootdir[1] == '\0'))
03061 newdbpath += strlen(rootdir);
03062 tfn = _free(tfn);
03063
03064 rpmMessage(RPMMESS_DEBUG, _("rebuilding database %s into %s\n"),
03065 rootdbpath, newrootdbpath);
03066
03067 if (!access(newrootdbpath, F_OK)) {
03068 rpmError(RPMERR_MKDIR, _("temporary database %s already exists\n"),
03069 newrootdbpath);
03070 rc = 1;
03071 goto exit;
03072 }
03073
03074 rpmMessage(RPMMESS_DEBUG, _("creating directory %s\n"), newrootdbpath);
03075 if (Mkdir(newrootdbpath, 0755)) {
03076 rpmError(RPMERR_MKDIR, _("creating directory %s: %s\n"),
03077 newrootdbpath, strerror(errno));
03078 rc = 1;
03079 goto exit;
03080 }
03081 removedir = 1;
03082
03083 rpmMessage(RPMMESS_DEBUG, _("opening old database with dbapi %d\n"),
03084 _dbapi);
03085 _rebuildinprogress = 1;
03086 if (openDatabase(rootdir, dbpath, _dbapi, &olddb, O_RDONLY, 0644,
03087 RPMDB_FLAG_MINIMAL)) {
03088 rc = 1;
03089 goto exit;
03090 }
03091 _dbapi = olddb->db_api;
03092 _rebuildinprogress = 0;
03093
03094 rpmMessage(RPMMESS_DEBUG, _("opening new database with dbapi %d\n"),
03095 _dbapi_rebuild);
03096 (void) rpmDefineMacro(NULL, "_rpmdb_rebuild %{nil}", -1);
03097 if (openDatabase(rootdir, newdbpath, _dbapi_rebuild, &newdb, O_RDWR | O_CREAT, 0644, 0)) {
03098 rc = 1;
03099 goto exit;
03100 }
03101 _dbapi_rebuild = newdb->db_api;
03102
03103 { Header h = NULL;
03104 rpmdbMatchIterator mi;
03105 #define _RECNUM rpmdbGetIteratorOffset(mi)
03106
03107
03108 mi = rpmdbInitIterator(olddb, RPMDBI_PACKAGES, NULL, 0);
03109 while ((h = rpmdbNextIterator(mi)) != NULL) {
03110
03111
03112 if (!(headerIsEntry(h, RPMTAG_NAME) &&
03113 headerIsEntry(h, RPMTAG_VERSION) &&
03114 headerIsEntry(h, RPMTAG_RELEASE) &&
03115 headerIsEntry(h, RPMTAG_BUILDTIME)))
03116 {
03117 rpmError(RPMERR_INTERNAL,
03118 _("record number %u in database is bad -- skipping.\n"),
03119 _RECNUM);
03120 continue;
03121 }
03122
03123
03124 if (_db_filter_dups || newdb->db_filter_dups) {
03125 const char * name, * version, * release;
03126 int skip = 0;
03127
03128 (void) headerNVR(h, &name, &version, &release);
03129
03130
03131 { rpmdbMatchIterator mi;
03132 mi = rpmdbInitIterator(newdb, RPMTAG_NAME, name, 0);
03133 (void) rpmdbSetIteratorRE(mi, RPMTAG_VERSION,
03134 RPMMIRE_DEFAULT, version);
03135 (void) rpmdbSetIteratorRE(mi, RPMTAG_RELEASE,
03136 RPMMIRE_DEFAULT, release);
03137 while (rpmdbNextIterator(mi)) {
03138 skip = 1;
03139 break;
03140 }
03141 mi = rpmdbFreeIterator(mi);
03142 }
03143
03144
03145 if (skip)
03146 continue;
03147 }
03148
03149
03150 { Header nh = (headerIsEntry(h, RPMTAG_HEADERIMAGE)
03151 ? headerCopy(h) : NULL);
03152 rc = rpmdbAdd(newdb, -1, (nh ? nh : h));
03153 nh = headerFree(nh);
03154 }
03155
03156 if (rc) {
03157 rpmError(RPMERR_INTERNAL,
03158 _("cannot add record originally at %u\n"), _RECNUM);
03159 failed = 1;
03160 break;
03161 }
03162 }
03163
03164 mi = rpmdbFreeIterator(mi);
03165
03166 }
03167
03168 if (!nocleanup) {
03169 olddb->db_remove_env = 1;
03170 newdb->db_remove_env = 1;
03171 }
03172 xx = rpmdbClose(olddb);
03173 xx = rpmdbClose(newdb);
03174
03175 if (failed) {
03176 rpmMessage(RPMMESS_NORMAL, _("failed to rebuild database: original database "
03177 "remains in place\n"));
03178
03179 xx = rpmdbRemoveDatabase(rootdir, newdbpath, _dbapi_rebuild);
03180 rc = 1;
03181 goto exit;
03182 } else if (!nocleanup) {
03183 if (rpmdbMoveDatabase(rootdir, newdbpath, _dbapi_rebuild, dbpath, _dbapi)) {
03184 rpmMessage(RPMMESS_ERROR, _("failed to replace old database with new "
03185 "database!\n"));
03186 rpmMessage(RPMMESS_ERROR, _("replace files in %s with files from %s "
03187 "to recover"), dbpath, newdbpath);
03188 rc = 1;
03189 goto exit;
03190 }
03191 }
03192 rc = 0;
03193
03194 exit:
03195 if (removedir && !(rc == 0 && nocleanup)) {
03196 rpmMessage(RPMMESS_DEBUG, _("removing directory %s\n"), newrootdbpath);
03197 if (Rmdir(newrootdbpath))
03198 rpmMessage(RPMMESS_ERROR, _("failed to remove directory %s: %s\n"),
03199 newrootdbpath, strerror(errno));
03200 }
03201 newrootdbpath = _free(newrootdbpath);
03202 rootdbpath = _free(rootdbpath);
03203
03204 return rc;
03205 }