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