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 <rpmlib.h>
00015 #include <rpmmacro.h>
00016
00017 #include "rpmdb.h"
00018 #include "fprint.h"
00019 #include "misc.h"
00020 #include "debug.h"
00021
00022
00023
00024
00025
00026
00027 extern int _noDirTokens;
00028 static int _rebuildinprogress = 0;
00029 static int _db_filter_dups = 0;
00030
00031 int _filterDbDups = 0;
00032
00033 #define _DBI_FLAGS 0
00034 #define _DBI_PERMS 0644
00035 #define _DBI_MAJOR -1
00036
00037 static int dbiTagsMax = 0;
00038 static int *dbiTags = NULL;
00039
00045 static int dbiTagToDbix(int rpmtag)
00046 {
00047 int dbix;
00048
00049 if (!(dbiTagsMax > 0 && dbiTags))
00050 return -1;
00051 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
00052 if (rpmtag == dbiTags[dbix])
00053 return dbix;
00054 }
00055 return -1;
00056 }
00057
00061 static void dbiTagsInit(void)
00062 {
00063 static const char * _dbiTagStr_default =
00064 "Packages:Name:Basenames:Group:Requirename:Providename:Conflictname:Triggername";
00065 char * dbiTagStr;
00066 char * o, * oe;
00067 int rpmtag;
00068
00069 dbiTagStr = rpmExpand("%{_dbi_tags}", NULL);
00070 if (!(dbiTagStr && *dbiTagStr && *dbiTagStr != '%')) {
00071 free((void *)dbiTagStr);
00072 dbiTagStr = xstrdup(_dbiTagStr_default);
00073 }
00074
00075 if (dbiTagsMax || dbiTags) {
00076 free(dbiTags);
00077 dbiTags = NULL;
00078 dbiTagsMax = 0;
00079 }
00080
00081
00082 dbiTagsMax = 1;
00083 dbiTags = xcalloc(1, dbiTagsMax * sizeof(*dbiTags));
00084
00085 for (o = dbiTagStr; o && *o; o = oe) {
00086 while (*o && isspace(*o))
00087 o++;
00088 if (*o == '\0')
00089 break;
00090 for (oe = o; oe && *oe; oe++) {
00091 if (isspace(*oe))
00092 break;
00093 if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/'))
00094 break;
00095 }
00096 if (oe && *oe)
00097 *oe++ = '\0';
00098 rpmtag = tagValue(o);
00099 if (rpmtag < 0) {
00100
00101 fprintf(stderr, _("dbiTagsInit: unrecognized tag name: \"%s\" ignored\n"), o);
00102 continue;
00103 }
00104 if (dbiTagToDbix(rpmtag) >= 0)
00105 continue;
00106
00107 dbiTags = xrealloc(dbiTags, (dbiTagsMax + 1) * sizeof(*dbiTags));
00108 dbiTags[dbiTagsMax++] = rpmtag;
00109 }
00110
00111 free(dbiTagStr);
00112 }
00113
00114 #if USE_DB1
00115 extern struct _dbiVec db1vec;
00116 #define DB1vec &db1vec
00117 #else
00118 #define DB1vec NULL
00119 #endif
00120
00121 #if USE_DB2
00122 extern struct _dbiVec db2vec;
00123 #define DB2vec &db2vec
00124 #else
00125 #define DB2vec NULL
00126 #endif
00127
00128 #if USE_DB3
00129 extern struct _dbiVec db3vec;
00130 #define DB3vec &db3vec
00131 #else
00132 #define DB3vec NULL
00133 #endif
00134
00135 static struct _dbiVec *mydbvecs[] = {
00136 DB1vec, DB1vec, DB2vec, DB3vec, NULL
00137 };
00138
00139 INLINE int dbiSync(dbiIndex dbi, unsigned int flags) {
00140 if (_debug < 0 || dbi->dbi_debug)
00141 fprintf(stderr, " Sync %s\n", tagName(dbi->dbi_rpmtag));
00142 return (*dbi->dbi_vec->sync) (dbi, flags);
00143 }
00144
00145 INLINE int dbiByteSwapped(dbiIndex dbi) {
00146 return (*dbi->dbi_vec->byteswapped) (dbi);
00147 }
00148
00149 INLINE int XdbiCopen(dbiIndex dbi, DBC ** dbcp, unsigned int flags,
00150 const char * f, unsigned int l)
00151 {
00152 if (_debug < 0 || dbi->dbi_debug)
00153 fprintf(stderr, "+++ RMW %s (%s:%u)\n", tagName(dbi->dbi_rpmtag), f, l);
00154 return (*dbi->dbi_vec->copen) (dbi, dbcp, flags);
00155 }
00156
00157 INLINE int XdbiCclose(dbiIndex dbi, DBC * dbcursor, unsigned int flags,
00158 const char * f, unsigned int l)
00159 {
00160 if (_debug < 0 || dbi->dbi_debug)
00161 fprintf(stderr, "--- RMW %s (%s:%u)\n", tagName(dbi->dbi_rpmtag), f, l);
00162 return (*dbi->dbi_vec->cclose) (dbi, dbcursor, flags);
00163 }
00164
00165 INLINE int dbiDel(dbiIndex dbi, DBC * dbcursor, const void * keyp, size_t keylen, unsigned int flags)
00166 {
00167 int NULkey;
00168 int rc;
00169
00170
00171 NULkey = (keyp && *((char *)keyp) == '\0' && keylen == 0);
00172 if (NULkey) keylen++;
00173 rc = (*dbi->dbi_vec->cdel) (dbi, dbcursor, keyp, keylen, flags);
00174 if (NULkey) keylen--;
00175
00176 if (_debug < 0 || dbi->dbi_debug)
00177 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);
00178
00179 return rc;
00180 }
00181
00182 INLINE int dbiGet(dbiIndex dbi, DBC * dbcursor, void ** keypp, size_t * keylenp,
00183 void ** datapp, size_t * datalenp, unsigned int flags)
00184 {
00185 int NULkey;
00186 int rc;
00187
00188
00189 NULkey = (keypp && *keypp && *((char *)(*keypp)) == '\0' && keylenp && *keylenp == 0);
00190 if (NULkey) (*keylenp)++;
00191 rc = (*dbi->dbi_vec->cget) (dbi, dbcursor, keypp, keylenp, datapp, datalenp, flags);
00192 if (NULkey) (*keylenp)--;
00193
00194 if (_debug < 0 || dbi->dbi_debug) {
00195 char keyval[32];
00196 int dataval = 0xdeadbeef;
00197 if (dbi->dbi_rpmtag == RPMDBI_PACKAGES && keypp && *keypp && keylenp && *keylenp >= sizeof(keyval)) {
00198 int keyint;
00199 memcpy(&keyint, *keypp, sizeof(keyint));
00200 sprintf(keyval, "%d", keyint);
00201 } else keyval[0] = '\0';
00202 if (rc == 0 && datapp && *datapp && datalenp && *datalenp >= sizeof(dataval))
00203 memcpy(&dataval, *datapp, sizeof(dataval));
00204 fprintf(stderr, " Get %s key (%p,%ld) data (%p,%ld) \"%s\" %x rc %d\n",
00205 tagName(dbi->dbi_rpmtag), *keypp, (long)*keylenp, *datapp, (long)*datalenp,
00206 (dbi->dbi_rpmtag != RPMDBI_PACKAGES ? (char *)*keypp : keyval), dataval, rc);
00207 }
00208 return rc;
00209 }
00210
00211 INLINE int dbiPut(dbiIndex dbi, DBC * dbcursor, const void * keyp, size_t keylen,
00212 const void * datap, size_t datalen, 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->cput) (dbi, dbcursor, keyp, keylen, datap, datalen, flags);
00221 if (NULkey) keylen--;
00222
00223 if (_debug < 0 || dbi->dbi_debug) {
00224 int dataval = 0xdeadbeef;
00225 if (datap) memcpy(&dataval, datap, sizeof(dataval));
00226 fprintf(stderr, " Put %s key (%p,%ld) data (%p,%ld) \"%s\" %x rc %d\n", tagName(dbi->dbi_rpmtag), keyp, (long)keylen, datap, (long)datalen, (dbi->dbi_rpmtag != RPMDBI_PACKAGES ? (char *)keyp : ""), dataval, rc);
00227 }
00228
00229 return rc;
00230 }
00231
00232 INLINE int dbiClose(dbiIndex dbi, unsigned int flags) {
00233 if (_debug < 0 || dbi->dbi_debug)
00234 fprintf(stderr, " %s Close\n", tagName(dbi->dbi_rpmtag));
00235 return (*dbi->dbi_vec->close) (dbi, flags);
00236 }
00237
00238 dbiIndex dbiOpen(rpmdb rpmdb, int rpmtag, unsigned int flags)
00239 {
00240 int dbix;
00241 dbiIndex dbi = NULL;
00242 int _dbapi, _dbapi_rebuild, _dbapi_wanted;
00243 int rc = 0;
00244
00245 dbix = dbiTagToDbix(rpmtag);
00246 if (dbix < 0 || dbix >= dbiTagsMax)
00247 return NULL;
00248
00249
00250 if ((dbi = rpmdb->_dbi[dbix]) != NULL)
00251 return dbi;
00252
00253 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
00254 if (_dbapi_rebuild < 1 || _dbapi_rebuild > 3)
00255 _dbapi_rebuild = 3;
00256 _dbapi_wanted = (_rebuildinprogress ? -1 : rpmdb->db_api);
00257
00258 switch (_dbapi_wanted) {
00259 default:
00260 _dbapi = _dbapi_wanted;
00261 if (_dbapi < 0 || _dbapi >= 4 || mydbvecs[_dbapi] == NULL) {
00262 return NULL;
00263 }
00264 errno = 0;
00265 dbi = NULL;
00266 rc = (*mydbvecs[_dbapi]->open) (rpmdb, rpmtag, &dbi);
00267 if (rc) {
00268 static int _printed[32];
00269 if (!_printed[dbix & 0x1f]++)
00270 rpmError(RPMERR_DBOPEN,
00271 _("cannot open %s index using db%d - %s (%d)\n"),
00272 tagName(rpmtag), _dbapi,
00273 (rc > 0 ? strerror(rc) : ""), rc);
00274 _dbapi = -1;
00275 }
00276 break;
00277 case -1:
00278 _dbapi = 4;
00279 while (_dbapi-- > 1) {
00280 if (mydbvecs[_dbapi] == NULL)
00281 continue;
00282 errno = 0;
00283 dbi = NULL;
00284 rc = (*mydbvecs[_dbapi]->open) (rpmdb, rpmtag, &dbi);
00285 if (rc == 0 && dbi)
00286 break;
00287 }
00288 if (_dbapi <= 0) {
00289 static int _printed[32];
00290 if (!_printed[dbix & 0x1f]++)
00291 rpmError(RPMERR_DBOPEN, _("cannot open %s index\n"),
00292 tagName(rpmtag));
00293 rc = 1;
00294 goto exit;
00295 }
00296 if (rpmdb->db_api == -1 && _dbapi > 0)
00297 rpmdb->db_api = _dbapi;
00298 break;
00299 }
00300
00301
00302 if (rc && _dbapi_wanted >= 0 && _dbapi != _dbapi_wanted && _dbapi_wanted == _dbapi_rebuild) {
00303 rc = (_rebuildinprogress ? 0 : 1);
00304 goto exit;
00305 }
00306
00307
00308 if (_dbapi_wanted >= 0 && _dbapi != _dbapi_wanted) {
00309 rc = 1;
00310 goto exit;
00311 }
00312
00313
00314 if (_dbapi_wanted < 0 && _dbapi != _dbapi_rebuild) {
00315 rc = (_rebuildinprogress ? 0 : 1);
00316 goto exit;
00317 }
00318
00319 exit:
00320 if (rc == 0 && dbi) {
00321 rpmdb->_dbi[dbix] = dbi;
00322 } else if (dbi) {
00323 db3Free(dbi);
00324 dbi = NULL;
00325 }
00326
00327 return dbi;
00328 }
00329
00336 static INLINE dbiIndexItem dbiIndexNewItem(unsigned int hdrNum, unsigned int tagNum) {
00337 dbiIndexItem rec = xcalloc(1, sizeof(*rec));
00338 rec->hdrNum = hdrNum;
00339 rec->tagNum = tagNum;
00340 return rec;
00341 }
00342
00343 union _dbswap {
00344 unsigned int ui;
00345 unsigned char uc[4];
00346 };
00347
00348 #define _DBSWAP(_a) \
00349 { unsigned char _b, *_c = (_a).uc; \
00350 _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
00351 _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
00352 }
00353
00362 static int dbiSearch(dbiIndex dbi, DBC * dbcursor, const char * keyp, size_t keylen,
00363 dbiIndexSet * setp)
00364 {
00365 void * datap;
00366 size_t datalen;
00367 int rc;
00368
00369 if (setp) *setp = NULL;
00370 if (keylen == 0) keylen = strlen(keyp);
00371
00372 rc = dbiGet(dbi, dbcursor, (void **)&keyp, &keylen, &datap, &datalen, 0);
00373
00374 if (rc > 0) {
00375 rpmError(RPMERR_DBGETINDEX,
00376 _("error(%d) getting \"%s\" records from %s index\n"),
00377 rc, keyp, tagName(dbi->dbi_rpmtag));
00378 } else
00379 if (rc == 0 && setp) {
00380 int _dbbyteswapped = dbiByteSwapped(dbi);
00381 const char * sdbir = datap;
00382 dbiIndexSet set;
00383 int i;
00384
00385 set = xmalloc(sizeof(*set));
00386
00387
00388 switch (dbi->dbi_jlen) {
00389 default:
00390 case 2*sizeof(int_32):
00391 set->count = datalen / (2*sizeof(int_32));
00392 set->recs = xmalloc(set->count * sizeof(*(set->recs)));
00393 for (i = 0; i < set->count; i++) {
00394 union _dbswap hdrNum, tagNum;
00395
00396 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
00397 sdbir += sizeof(hdrNum.ui);
00398 memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
00399 sdbir += sizeof(tagNum.ui);
00400 if (_dbbyteswapped) {
00401 _DBSWAP(hdrNum);
00402 _DBSWAP(tagNum);
00403 }
00404 set->recs[i].hdrNum = hdrNum.ui;
00405 set->recs[i].tagNum = tagNum.ui;
00406 set->recs[i].fpNum = 0;
00407 set->recs[i].dbNum = 0;
00408 }
00409 break;
00410 case 1*sizeof(int_32):
00411 set->count = datalen / (1*sizeof(int_32));
00412 set->recs = xmalloc(set->count * sizeof(*(set->recs)));
00413 for (i = 0; i < set->count; i++) {
00414 union _dbswap hdrNum;
00415
00416 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
00417 sdbir += sizeof(hdrNum.ui);
00418 if (_dbbyteswapped) {
00419 _DBSWAP(hdrNum);
00420 }
00421 set->recs[i].hdrNum = hdrNum.ui;
00422 set->recs[i].tagNum = 0;
00423 set->recs[i].fpNum = 0;
00424 set->recs[i].dbNum = 0;
00425 }
00426 break;
00427 }
00428 *setp = set;
00429 }
00430 return rc;
00431 }
00432
00440
00441 static int dbiUpdateIndex(dbiIndex dbi, DBC * dbcursor, const char * keyp, dbiIndexSet set)
00442 {
00443 size_t keylen = strlen(keyp);
00444 void * datap;
00445 size_t datalen;
00446 int rc;
00447
00448 if (set->count) {
00449 char * tdbir;
00450 int i;
00451 int _dbbyteswapped = dbiByteSwapped(dbi);
00452
00453
00454
00455 switch (dbi->dbi_jlen) {
00456 default:
00457 case 2*sizeof(int_32):
00458 datalen = set->count * (2 * sizeof(int_32));
00459 datap = tdbir = alloca(datalen);
00460 for (i = 0; i < set->count; i++) {
00461 union _dbswap hdrNum, tagNum;
00462
00463 hdrNum.ui = set->recs[i].hdrNum;
00464 tagNum.ui = set->recs[i].tagNum;
00465 if (_dbbyteswapped) {
00466 _DBSWAP(hdrNum);
00467 _DBSWAP(tagNum);
00468 }
00469 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
00470 tdbir += sizeof(hdrNum.ui);
00471 memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
00472 tdbir += sizeof(tagNum.ui);
00473 }
00474 break;
00475 case 1*sizeof(int_32):
00476 datalen = set->count * (1 * sizeof(int_32));
00477 datap = tdbir = alloca(datalen);
00478 for (i = 0; i < set->count; i++) {
00479 union _dbswap hdrNum;
00480
00481 hdrNum.ui = set->recs[i].hdrNum;
00482 if (_dbbyteswapped) {
00483 _DBSWAP(hdrNum);
00484 }
00485 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
00486 tdbir += sizeof(hdrNum.ui);
00487 }
00488 break;
00489 }
00490
00491 rc = dbiPut(dbi, dbcursor, keyp, keylen, datap, datalen, 0);
00492
00493 if (rc) {
00494 rpmError(RPMERR_DBPUTINDEX,
00495 _("error(%d) storing record %s into %s\n"),
00496 rc, keyp, tagName(dbi->dbi_rpmtag));
00497 }
00498
00499 } else {
00500
00501 rc = dbiDel(dbi, dbcursor, keyp, keylen, 0);
00502
00503 if (rc) {
00504 rpmError(RPMERR_DBPUTINDEX,
00505 _("error(%d) removing record %s from %s\n"),
00506 rc, keyp, tagName(dbi->dbi_rpmtag));
00507 }
00508
00509 }
00510
00511 return rc;
00512 }
00513
00514
00515
00516 static int hdrNumCmp(const void * one, const void * two) {
00517 const int * a = one, * b = two;
00518 return (*a - *b);
00519 }
00520
00530 static INLINE int dbiAppendSet(dbiIndexSet set, const void * recs,
00531 int nrecs, size_t recsize, int sortset)
00532 {
00533 const char * rptr = recs;
00534 size_t rlen = (recsize < sizeof(*(set->recs)))
00535 ? recsize : sizeof(*(set->recs));
00536
00537 if (set == NULL || recs == NULL || nrecs <= 0 || recsize <= 0)
00538 return 1;
00539
00540 set->recs = (set->count == 0)
00541 ? xmalloc(nrecs * sizeof(*(set->recs)))
00542 : xrealloc(set->recs, (set->count + nrecs) * sizeof(*(set->recs)));
00543
00544 memset(set->recs + set->count, 0, nrecs * sizeof(*(set->recs)));
00545
00546 while (nrecs-- > 0) {
00547 memcpy(set->recs + set->count, rptr, rlen);
00548 rptr += recsize;
00549 set->count++;
00550 }
00551
00552 if (set->count > 1 && sortset)
00553 qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
00554
00555 return 0;
00556 }
00557
00567 static INLINE int dbiPruneSet(dbiIndexSet set, void * recs, int nrecs,
00568 size_t recsize, int sorted)
00569 {
00570 int from;
00571 int to = 0;
00572 int num = set->count;
00573 int numCopied = 0;
00574
00575 if (nrecs > 1 && !sorted)
00576 qsort(recs, nrecs, recsize, hdrNumCmp);
00577
00578 for (from = 0; from < num; from++) {
00579 if (bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) {
00580 set->count--;
00581 continue;
00582 }
00583 if (from != to)
00584 set->recs[to] = set->recs[from];
00585 to++;
00586 numCopied++;
00587 }
00588
00589 return (numCopied == num);
00590 }
00591
00592
00593 unsigned int dbiIndexSetCount(dbiIndexSet set) {
00594 return set->count;
00595 }
00596
00597
00598 unsigned int dbiIndexRecordOffset(dbiIndexSet set, int recno) {
00599 return set->recs[recno].hdrNum;
00600 }
00601
00602
00603 unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, int recno) {
00604 return set->recs[recno].tagNum;
00605 }
00606
00607
00608 void dbiFreeIndexSet(dbiIndexSet set) {
00609 if (set) {
00610 if (set->recs) free(set->recs);
00611 free(set);
00612 }
00613 }
00614
00618 static void blockSignals(rpmdb rpmdb, sigset_t * oldMask)
00619 {
00620 sigset_t newMask;
00621
00622
00623 if (!(rpmdb && rpmdb->db_api == 4)) {
00624 sigfillset(&newMask);
00625 sigprocmask(SIG_BLOCK, &newMask, oldMask);
00626 }
00627 }
00628
00632 static void unblockSignals(rpmdb rpmdb, sigset_t * oldMask)
00633 {
00634
00635 if (!(rpmdb && rpmdb->db_api == 4)) {
00636 sigprocmask(SIG_SETMASK, oldMask, NULL);
00637 }
00638 }
00639
00640 #define _DB_ROOT "/"
00641 #define _DB_HOME "%{_dbpath}"
00642 #define _DB_FLAGS 0
00643 #define _DB_MODE 0
00644 #define _DB_PERMS 0644
00645
00646 #define _DB_MAJOR -1
00647 #define _DB_REMOVE_ENV 0
00648 #define _DB_FILTER_DUPS 0
00649 #define _DB_ERRPFX "rpmdb"
00650
00651 static struct rpmdb_s dbTemplate = {
00652 _DB_ROOT, _DB_HOME, _DB_FLAGS, _DB_MODE, _DB_PERMS,
00653 _DB_MAJOR, _DB_REMOVE_ENV, _DB_FILTER_DUPS, _DB_ERRPFX
00654 };
00655
00656 int rpmdbOpenAll (rpmdb rpmdb)
00657 {
00658 int dbix;
00659
00660 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
00661 if (rpmdb->_dbi[dbix] != NULL)
00662 continue;
00663 (void) dbiOpen(rpmdb, dbiTags[dbix], rpmdb->db_flags);
00664 }
00665 return 0;
00666 }
00667
00668
00669 int rpmdbClose (rpmdb rpmdb)
00670 {
00671 int dbix;
00672
00673 for (dbix = rpmdb->db_ndbi; --dbix >= 0; ) {
00674 if (rpmdb->_dbi[dbix] == NULL)
00675 continue;
00676 dbiClose(rpmdb->_dbi[dbix], 0);
00677 rpmdb->_dbi[dbix] = NULL;
00678 }
00679 if (rpmdb->db_errpfx) {
00680 free((void *)rpmdb->db_errpfx);
00681 rpmdb->db_errpfx = NULL;
00682 }
00683 if (rpmdb->db_root) {
00684 free((void *)rpmdb->db_root);
00685 rpmdb->db_root = NULL;
00686 }
00687 if (rpmdb->db_home) {
00688 free((void *)rpmdb->db_home);
00689 rpmdb->db_home = NULL;
00690 }
00691 if (rpmdb->_dbi) {
00692 free((void *)rpmdb->_dbi);
00693 rpmdb->_dbi = NULL;
00694 }
00695 free(rpmdb);
00696 return 0;
00697 }
00698
00699 int rpmdbSync(rpmdb rpmdb)
00700 {
00701 int dbix;
00702
00703 for (dbix = 0; dbix < rpmdb->db_ndbi; dbix++) {
00704 int xx;
00705 if (rpmdb->_dbi[dbix] == NULL)
00706 continue;
00707 xx = dbiSync(rpmdb->_dbi[dbix], 0);
00708 }
00709 return 0;
00710 }
00711
00712 static rpmdb newRpmdb(const char * root, const char * home,
00713 int mode, int perms, int flags)
00714 {
00715 rpmdb rpmdb = xcalloc(sizeof(*rpmdb), 1);
00716 static int _initialized = 0;
00717
00718 if (!_initialized) {
00719 _filterDbDups = rpmExpandNumeric("%{_filterdbdups}");
00720 _initialized = 1;
00721 }
00722
00723 *rpmdb = dbTemplate;
00724
00725 if (!(perms & 0600)) perms = 0644;
00726
00727 if (root)
00728 rpmdb->db_root = (*root ? root : _DB_ROOT);
00729 if (home)
00730 rpmdb->db_home = (*home ? home : _DB_HOME);
00731 if (mode >= 0) rpmdb->db_mode = mode;
00732 if (perms >= 0) rpmdb->db_perms = perms;
00733 if (flags >= 0) rpmdb->db_flags = flags;
00734
00735 if (rpmdb->db_root)
00736 rpmdb->db_root = rpmGetPath(rpmdb->db_root, NULL);
00737 if (rpmdb->db_home) {
00738 rpmdb->db_home = rpmGetPath(rpmdb->db_home, NULL);
00739 if (!(rpmdb->db_home && rpmdb->db_home[0] != '%')) {
00740 rpmError(RPMERR_DBOPEN, _("no dbpath has been set\n"));
00741 goto errxit;
00742 }
00743 }
00744 if (rpmdb->db_errpfx)
00745 rpmdb->db_errpfx = xstrdup(rpmdb->db_errpfx);
00746 rpmdb->db_remove_env = 0;
00747 rpmdb->db_filter_dups = _filterDbDups;
00748 rpmdb->db_ndbi = dbiTagsMax;
00749 rpmdb->_dbi = xcalloc(rpmdb->db_ndbi, sizeof(*rpmdb->_dbi));
00750 return rpmdb;
00751
00752 errxit:
00753 if (rpmdb)
00754 rpmdbClose(rpmdb);
00755 return NULL;
00756 }
00757
00758 static int openDatabase(const char * prefix, const char * dbpath, int _dbapi,
00759 rpmdb *dbp, int mode, int perms, int flags)
00760 {
00761 rpmdb rpmdb;
00762 int rc;
00763 static int _initialized = 0;
00764 int justCheck = flags & RPMDB_FLAG_JUSTCHECK;
00765 int minimal = flags & RPMDB_FLAG_MINIMAL;
00766
00767 if (!_initialized || dbiTagsMax == 0) {
00768 dbiTagsInit();
00769 _initialized++;
00770 }
00771
00772
00773 if (_dbapi < -1 || _dbapi > 3)
00774 _dbapi = -1;
00775 if (_dbapi == 0)
00776 _dbapi = 1;
00777
00778 if (dbp)
00779 *dbp = NULL;
00780 if (mode & O_WRONLY)
00781 return 1;
00782
00783 rpmdb = newRpmdb(prefix, dbpath, mode, perms, flags);
00784 rpmdb->db_api = _dbapi;
00785
00786 { int dbix;
00787
00788 rc = 0;
00789 for (dbix = 0; rc == 0 && dbix < dbiTagsMax; dbix++) {
00790 dbiIndex dbi;
00791 int rpmtag;
00792
00793
00794 switch ((rpmtag = dbiTags[dbix])) {
00795 case RPMDBI_AVAILABLE:
00796 case RPMDBI_ADDED:
00797 case RPMDBI_REMOVED:
00798 case RPMDBI_DEPENDS:
00799 continue;
00800 break;
00801 default:
00802 break;
00803 }
00804
00805 dbi = dbiOpen(rpmdb, rpmtag, 0);
00806
00807 switch (rpmtag) {
00808 case RPMDBI_PACKAGES:
00809 if (dbi == NULL) rc |= 1;
00810 #if 0
00811 if (rpmdb->db_api == 3)
00812 #endif
00813 goto exit;
00814 break;
00815 case RPMTAG_NAME:
00816 if (dbi == NULL) rc |= 1;
00817 if (minimal)
00818 goto exit;
00819 break;
00820 case RPMTAG_BASENAMES:
00821 { void * keyp = NULL;
00822 DBC * dbcursor;
00823 int xx;
00824
00825
00826
00827
00828
00829
00830
00831 if (justCheck)
00832 break;
00833 dbcursor = NULL;
00834 xx = dbiCopen(dbi, &dbcursor, 0);
00835 xx = dbiGet(dbi, dbcursor, &keyp, NULL, NULL, NULL, 0);
00836 if (xx == 0) {
00837 const char * akey = keyp;
00838 if (strchr(akey, '/')) {
00839 rpmError(RPMERR_OLDDB, _("old format database is present; "
00840 "use --rebuilddb to generate a new format database\n"));
00841 rc |= 1;
00842 }
00843 }
00844 xx = dbiCclose(dbi, dbcursor, 0);
00845 dbcursor = NULL;
00846 } break;
00847 default:
00848 break;
00849 }
00850 }
00851 }
00852
00853 exit:
00854 if (rc || justCheck || dbp == NULL)
00855 rpmdbClose(rpmdb);
00856 else
00857 *dbp = rpmdb;
00858
00859 return rc;
00860 }
00861
00862
00863 int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, int perms)
00864 {
00865 int _dbapi = rpmExpandNumeric("%{_dbapi}");
00866 return openDatabase(prefix, NULL, _dbapi, dbp, mode, perms, 0);
00867 }
00868
00869 int rpmdbInit (const char * prefix, int perms)
00870 {
00871 rpmdb rpmdb = NULL;
00872 int _dbapi = rpmExpandNumeric("%{_dbapi}");
00873 int rc;
00874
00875 rc = openDatabase(prefix, NULL, _dbapi, &rpmdb, (O_CREAT | O_RDWR),
00876 perms, RPMDB_FLAG_JUSTCHECK);
00877 if (rpmdb) {
00878 rpmdbOpenAll(rpmdb);
00879 rpmdbClose(rpmdb);
00880 rpmdb = NULL;
00881 }
00882 return rc;
00883 }
00884
00885 static int rpmdbFindByFile(rpmdb rpmdb, const char * filespec,
00886 dbiIndexSet * matches)
00887 {
00888 const char * dirName;
00889 const char * baseName;
00890 fingerPrintCache fpc;
00891 fingerPrint fp1;
00892 dbiIndex dbi = NULL;
00893 DBC * dbcursor;
00894 dbiIndexSet allMatches = NULL;
00895 dbiIndexItem rec = NULL;
00896 int i;
00897 int rc;
00898 int xx;
00899
00900 *matches = NULL;
00901 if ((baseName = strrchr(filespec, '/')) != NULL) {
00902 char * t;
00903 size_t len;
00904
00905 len = baseName - filespec + 1;
00906 t = strncpy(alloca(len + 1), filespec, len);
00907 t[len] = '\0';
00908 dirName = t;
00909 baseName++;
00910 } else {
00911 dirName = "";
00912 baseName = filespec;
00913 }
00914
00915 fpc = fpCacheCreate(20);
00916 fp1 = fpLookup(fpc, dirName, baseName, 1);
00917
00918 dbi = dbiOpen(rpmdb, RPMTAG_BASENAMES, 0);
00919 dbcursor = NULL;
00920 xx = dbiCopen(dbi, &dbcursor, 0);
00921 rc = dbiSearch(dbi, dbcursor, baseName, 0, &allMatches);
00922 xx = dbiCclose(dbi, dbcursor, 0);
00923 dbcursor = NULL;
00924 if (rc) {
00925 dbiFreeIndexSet(allMatches);
00926 allMatches = NULL;
00927 fpCacheFree(fpc);
00928 return rc;
00929 }
00930
00931 *matches = xcalloc(1, sizeof(**matches));
00932 rec = dbiIndexNewItem(0, 0);
00933 i = 0;
00934 while (i < allMatches->count) {
00935 const char ** baseNames, ** dirNames;
00936 int_32 * dirIndexes;
00937 unsigned int offset = dbiIndexRecordOffset(allMatches, i);
00938 unsigned int prevoff;
00939 Header h;
00940
00941 { rpmdbMatchIterator mi;
00942 mi = rpmdbInitIterator(rpmdb, RPMDBI_PACKAGES, &offset, sizeof(offset));
00943 h = rpmdbNextIterator(mi);
00944 if (h)
00945 h = headerLink(h);
00946 rpmdbFreeIterator(mi);
00947 }
00948
00949 if (h == NULL) {
00950 i++;
00951 continue;
00952 }
00953
00954 headerGetEntryMinMemory(h, RPMTAG_BASENAMES, NULL,
00955 (const void **) &baseNames, NULL);
00956 headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
00957 (const void **) &dirNames, NULL);
00958 headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
00959 (const void **) &dirIndexes, NULL);
00960
00961 do {
00962 fingerPrint fp2;
00963 int num = dbiIndexRecordFileNumber(allMatches, i);
00964
00965 fp2 = fpLookup(fpc, dirNames[dirIndexes[num]], baseNames[num], 1);
00966 if (FP_EQUAL(fp1, fp2)) {
00967 rec->hdrNum = dbiIndexRecordOffset(allMatches, i);
00968 rec->tagNum = dbiIndexRecordFileNumber(allMatches, i);
00969 dbiAppendSet(*matches, rec, 1, sizeof(*rec), 0);
00970 }
00971
00972 prevoff = offset;
00973 i++;
00974 offset = dbiIndexRecordOffset(allMatches, i);
00975 } while (i < allMatches->count &&
00976 (i == 0 || offset == prevoff));
00977
00978 free(baseNames);
00979 free(dirNames);
00980 headerFree(h);
00981 }
00982
00983 if (rec) {
00984 free(rec);
00985 rec = NULL;
00986 }
00987 if (allMatches) {
00988 dbiFreeIndexSet(allMatches);
00989 allMatches = NULL;
00990 }
00991
00992 fpCacheFree(fpc);
00993
00994 if ((*matches)->count == 0) {
00995 dbiFreeIndexSet(*matches);
00996 *matches = NULL;
00997 return 1;
00998 }
00999
01000 return 0;
01001 }
01002
01003
01004 int rpmdbCountPackages(rpmdb rpmdb, const char * name)
01005 {
01006 dbiIndex dbi;
01007 dbiIndexSet matches = NULL;
01008 int rc = -1;
01009 int xx;
01010
01011 dbi = dbiOpen(rpmdb, RPMTAG_NAME, 0);
01012 if (dbi) {
01013 DBC * dbcursor = NULL;
01014 xx = dbiCopen(dbi, &dbcursor, 0);
01015 rc = dbiSearch(dbi, dbcursor, name, 0, &matches);
01016 xx = dbiCclose(dbi, dbcursor, 0);
01017 dbcursor = NULL;
01018 }
01019
01020 if (rc == 0)
01021 rc = dbiIndexSetCount(matches);
01022 else if (rc > 0)
01023 rpmError(RPMERR_DBCORRUPT, _("error(%d) counting packages\n"), rc);
01024 else
01025 rc = 0;
01026
01027 if (matches)
01028 dbiFreeIndexSet(matches);
01029
01030 return rc;
01031 }
01032
01033
01034
01035
01036
01037 static int dbiFindMatches(dbiIndex dbi, DBC * dbcursor,
01038 const char * name, const char * version, const char * release,
01039 dbiIndexSet * matches)
01040 {
01041 int gotMatches;
01042 int rc;
01043 int i;
01044
01045 rc = dbiSearch(dbi, dbcursor, name, 0, matches);
01046
01047 if (rc != 0) {
01048 rc = ((rc == -1) ? 2 : 1);
01049 goto exit;
01050 }
01051
01052 if (!version && !release) {
01053 rc = 0;
01054 goto exit;
01055 }
01056
01057 gotMatches = 0;
01058
01059
01060 for (i = 0; i < dbiIndexSetCount(*matches); i++) {
01061 unsigned int recoff = dbiIndexRecordOffset(*matches, i);
01062 int goodRelease, goodVersion;
01063 const char * pkgVersion;
01064 const char * pkgRelease;
01065 Header h;
01066
01067 if (recoff == 0)
01068 continue;
01069
01070 { rpmdbMatchIterator mi;
01071 mi = rpmdbInitIterator(dbi->dbi_rpmdb, RPMDBI_PACKAGES, &recoff, sizeof(recoff));
01072 h = rpmdbNextIterator(mi);
01073 if (h)
01074 h = headerLink(h);
01075 rpmdbFreeIterator(mi);
01076 }
01077
01078 if (h == NULL) {
01079 rpmError(RPMERR_DBCORRUPT, _("%s: cannot read header at 0x%x\n"),
01080 "findMatches", recoff);
01081 rc = 2;
01082 goto exit;
01083 }
01084
01085 headerNVR(h, NULL, &pkgVersion, &pkgRelease);
01086
01087 goodRelease = goodVersion = 1;
01088
01089 if (release && strcmp(release, pkgRelease)) goodRelease = 0;
01090 if (version && strcmp(version, pkgVersion)) goodVersion = 0;
01091
01092 if (goodRelease && goodVersion) {
01093
01094 (*matches)->recs[gotMatches++] = (*matches)->recs[i];
01095 } else
01096 (*matches)->recs[i].hdrNum = 0;
01097
01098 headerFree(h);
01099 }
01100
01101 if (gotMatches) {
01102 (*matches)->count = gotMatches;
01103 rc = 0;
01104 } else {
01105 rc = 1;
01106 }
01107
01108 exit:
01109 if (rc && matches && *matches) {
01110 dbiFreeIndexSet(*matches);
01111 *matches = NULL;
01112 }
01113 return rc;
01114 }
01115
01116
01117
01118
01119 static int dbiFindByLabel(dbiIndex dbi, DBC * dbcursor, const char * arg, dbiIndexSet * matches)
01120 {
01121 char * localarg, * chptr;
01122 char * release;
01123 int rc;
01124
01125 if (!strlen(arg)) return 1;
01126
01127
01128 rc = dbiFindMatches(dbi, dbcursor, arg, NULL, NULL, matches);
01129 if (rc != 1) return rc;
01130 if (*matches) {
01131 dbiFreeIndexSet(*matches);
01132 *matches = NULL;
01133 }
01134
01135
01136 localarg = alloca(strlen(arg) + 1);
01137 strcpy(localarg, arg);
01138
01139 chptr = (localarg + strlen(localarg)) - 1;
01140 while (chptr > localarg && *chptr != '-') chptr--;
01141 if (chptr == localarg) return 1;
01142
01143 *chptr = '\0';
01144 rc = dbiFindMatches(dbi, dbcursor, localarg, chptr + 1, NULL, matches);
01145 if (rc != 1) return rc;
01146 if (*matches) dbiFreeIndexSet(*matches);
01147
01148
01149
01150 release = chptr + 1;
01151 while (chptr > localarg && *chptr != '-') chptr--;
01152 if (chptr == localarg) return 1;
01153
01154 *chptr = '\0';
01155 return dbiFindMatches(dbi, dbcursor, localarg, chptr + 1, release, matches);
01156 }
01157
01167 static int dbiUpdateRecord(dbiIndex dbi, DBC * dbcursor, int offset, Header h)
01168 {
01169 sigset_t signalMask;
01170 void * uh;
01171 size_t uhlen;
01172 int rc;
01173 int xx;
01174
01175 if (_noDirTokens)
01176 expandFilelist(h);
01177
01178 uhlen = headerSizeof(h, HEADER_MAGIC_NO);
01179 uh = headerUnload(h);
01180 blockSignals(dbi->dbi_rpmdb, &signalMask);
01181 rc = dbiPut(dbi, dbcursor, &offset, sizeof(offset), uh, uhlen, 0);
01182 xx = dbiSync(dbi, 0);
01183 unblockSignals(dbi->dbi_rpmdb, &signalMask);
01184 free(uh);
01185
01186 return rc;
01187 }
01188
01189 struct _rpmdbMatchIterator {
01190 const void * mi_keyp;
01191 size_t mi_keylen;
01192 rpmdb mi_rpmdb;
01193 int mi_rpmtag;
01194 dbiIndexSet mi_set;
01195 DBC * mi_dbc;
01196 int mi_setx;
01197 Header mi_h;
01198 int mi_sorted;
01199 int mi_modified;
01200 unsigned int mi_prevoffset;
01201 unsigned int mi_offset;
01202 unsigned int mi_filenum;
01203 unsigned int mi_fpnum;
01204 unsigned int mi_dbnum;
01205 const char * mi_version;
01206 const char * mi_release;
01207 };
01208
01209 void rpmdbFreeIterator(rpmdbMatchIterator mi)
01210 {
01211 dbiIndex dbi = NULL;
01212 int xx;
01213
01214 if (mi == NULL)
01215 return;
01216
01217 dbi = dbiOpen(mi->mi_rpmdb, RPMDBI_PACKAGES, 0);
01218 if (mi->mi_h) {
01219 if (mi->mi_modified && mi->mi_prevoffset) {
01220 DBC * dbcursor = NULL;
01221 xx = dbiCopen(dbi, &dbcursor, 0);
01222 dbiUpdateRecord(dbi, dbcursor, mi->mi_prevoffset, mi->mi_h);
01223 xx = dbiCclose(dbi, dbcursor, 0);
01224 dbcursor = NULL;
01225 }
01226 headerFree(mi->mi_h);
01227 mi->mi_h = NULL;
01228 }
01229 if (dbi->dbi_rmw) {
01230 xx = dbiCclose(dbi, dbi->dbi_rmw, 0);
01231 dbi->dbi_rmw = NULL;
01232 }
01233
01234 if (mi->mi_release) {
01235 free((void *)mi->mi_release);
01236 mi->mi_release = NULL;
01237 }
01238 if (mi->mi_version) {
01239 free((void *)mi->mi_version);
01240 mi->mi_version = NULL;
01241 }
01242 if (mi->mi_dbc) {
01243 int xx = dbiCclose(dbi, mi->mi_dbc, 1);
01244 mi->mi_dbc = NULL;
01245 }
01246 if (mi->mi_set) {
01247 dbiFreeIndexSet(mi->mi_set);
01248 mi->mi_set = NULL;
01249 }
01250 if (mi->mi_keyp) {
01251 free((void *)mi->mi_keyp);
01252 mi->mi_keyp = NULL;
01253 }
01254 free(mi);
01255 }
01256
01257 rpmdb rpmdbGetIteratorRpmDB(rpmdbMatchIterator mi) {
01258 if (mi == NULL)
01259 return 0;
01260 return mi->mi_rpmdb;
01261 }
01262
01263 unsigned int rpmdbGetIteratorOffset(rpmdbMatchIterator mi) {
01264 if (mi == NULL)
01265 return 0;
01266 return mi->mi_offset;
01267 }
01268
01269 unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi) {
01270 if (mi == NULL)
01271 return 0;
01272 return mi->mi_filenum;
01273 }
01274
01275 int rpmdbGetIteratorCount(rpmdbMatchIterator mi) {
01276 if (!(mi && mi->mi_set))
01277 return 0;
01278 return mi->mi_set->count;
01279 }
01280
01281 void rpmdbSetIteratorRelease(rpmdbMatchIterator mi, const char * release) {
01282 if (mi == NULL)
01283 return;
01284 if (mi->mi_release) {
01285 free((void *)mi->mi_release);
01286 mi->mi_release = NULL;
01287 }
01288 mi->mi_release = (release ? xstrdup(release) : NULL);
01289 }
01290
01291 void rpmdbSetIteratorVersion(rpmdbMatchIterator mi, const char * version) {
01292 if (mi == NULL)
01293 return;
01294 if (mi->mi_version) {
01295 free((void *)mi->mi_version);
01296 mi->mi_version = NULL;
01297 }
01298 mi->mi_version = (version ? xstrdup(version) : NULL);
01299 }
01300
01301 int rpmdbSetIteratorModified(rpmdbMatchIterator mi, int modified) {
01302 int rc;
01303 if (mi == NULL)
01304 return 0;
01305 rc = mi->mi_modified;
01306 mi->mi_modified = modified;
01307 return rc;
01308 }
01309
01310 Header XrpmdbNextIterator(rpmdbMatchIterator mi, const char * f, unsigned l)
01311 {
01312 dbiIndex dbi;
01313 void * uh = NULL;
01314 size_t uhlen = 0;
01315 void * keyp;
01316 size_t keylen;
01317 int rc;
01318 int xx;
01319
01320 if (mi == NULL)
01321 return NULL;
01322
01323 dbi = dbiOpen(mi->mi_rpmdb, RPMDBI_PACKAGES, 0);
01324 if (dbi == NULL)
01325 return NULL;
01326
01327 if (mi->mi_dbc == NULL) {
01328 xx = XdbiCopen(dbi, &mi->mi_dbc, 1, f, l);
01329 }
01330 dbi->dbi_lastoffset = mi->mi_prevoffset;
01331
01332 top:
01333
01334 do {
01335 if (mi->mi_set) {
01336 if (!(mi->mi_setx < mi->mi_set->count))
01337 return NULL;
01338 mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx);
01339 mi->mi_filenum = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx);
01340 keyp = &mi->mi_offset;
01341 keylen = sizeof(mi->mi_offset);
01342 } else {
01343 keyp = (void *)mi->mi_keyp;
01344 keylen = mi->mi_keylen;
01345
01346 rc = dbiGet(dbi, mi->mi_dbc, &keyp, &keylen, &uh, &uhlen, 0);
01347
01348
01349
01350
01351
01352
01353
01354
01355 if (rc == 0 && keyp && (dbi->dbi_lastoffset || mi->mi_setx))
01356 memcpy(&mi->mi_offset, keyp, sizeof(mi->mi_offset));
01357
01358
01359 if (rc || (mi->mi_setx && mi->mi_offset == 0))
01360 return NULL;
01361 }
01362 mi->mi_setx++;
01363 } while (mi->mi_offset == 0);
01364
01365 if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset)
01366 goto exit;
01367
01368
01369 if (uh == NULL) {
01370 rc = dbiGet(dbi, mi->mi_dbc, &keyp, &keylen, &uh, &uhlen, 0);
01371 if (rc)
01372 return NULL;
01373 }
01374
01375
01376 if (mi->mi_h) {
01377 if (mi->mi_modified && mi->mi_prevoffset)
01378 dbiUpdateRecord(dbi, mi->mi_dbc, mi->mi_prevoffset, mi->mi_h);
01379 headerFree(mi->mi_h);
01380 mi->mi_h = NULL;
01381 }
01382
01383 mi->mi_h = headerCopyLoad(uh);
01384
01385 if (dbi->dbi_api <= 1) free(uh);
01386
01387 if (mi->mi_release) {
01388 const char *release;
01389 headerNVR(mi->mi_h, NULL, NULL, &release);
01390 if (strcmp(mi->mi_release, release))
01391 goto top;
01392 }
01393
01394 if (mi->mi_version) {
01395 const char *version;
01396 headerNVR(mi->mi_h, NULL, &version, NULL);
01397 if (strcmp(mi->mi_version, version))
01398 goto top;
01399 }
01400
01401 mi->mi_prevoffset = mi->mi_offset;
01402 mi->mi_modified = 0;
01403
01404 exit:
01405 #ifdef NOTNOW
01406 if (mi->mi_h) {
01407 const char *n, *v, *r;
01408 headerNVR(mi->mi_h, &n, &v, &r);
01409 rpmMessage(RPMMESS_DEBUG, "%s-%s-%s at 0x%x, h %p\n", n, v, r,
01410 mi->mi_offset, mi->mi_h);
01411 }
01412 #endif
01413 return mi->mi_h;
01414 }
01415
01416 static void rpmdbSortIterator(rpmdbMatchIterator mi) {
01417 if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) {
01418 qsort(mi->mi_set->recs, mi->mi_set->count, sizeof(*mi->mi_set->recs),
01419 hdrNumCmp);
01420 mi->mi_sorted = 1;
01421 }
01422 }
01423
01424 static int rpmdbGrowIterator(rpmdbMatchIterator mi,
01425 const void * keyp, size_t keylen, int fpNum)
01426 {
01427 dbiIndex dbi = NULL;
01428 DBC * dbcursor = NULL;
01429 dbiIndexSet set = NULL;
01430 int rc;
01431 int xx;
01432
01433 if (!(mi && keyp))
01434 return 1;
01435
01436 dbi = dbiOpen(mi->mi_rpmdb, mi->mi_rpmtag, 0);
01437 if (dbi == NULL)
01438 return 1;
01439
01440 if (keylen == 0)
01441 keylen = strlen(keyp);
01442
01443 xx = dbiCopen(dbi, &dbcursor, 0);
01444 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
01445 xx = dbiCclose(dbi, dbcursor, 0);
01446 dbcursor = NULL;
01447
01448 if (rc == 0) {
01449 int i;
01450 for (i = 0; i < set->count; i++)
01451 set->recs[i].fpNum = fpNum;
01452
01453 if (mi->mi_set == NULL) {
01454 mi->mi_set = set;
01455 set = NULL;
01456 } else {
01457 mi->mi_set->recs = xrealloc(mi->mi_set->recs,
01458 (mi->mi_set->count + set->count) * sizeof(*(mi->mi_set->recs)));
01459 memcpy(mi->mi_set->recs + mi->mi_set->count, set->recs,
01460 set->count * sizeof(*(mi->mi_set->recs)));
01461 mi->mi_set->count += set->count;
01462 }
01463 }
01464
01465 if (set)
01466 dbiFreeIndexSet(set);
01467 return rc;
01468 }
01469
01470 int rpmdbPruneIterator(rpmdbMatchIterator mi, int * hdrNums,
01471 int nHdrNums, int sorted)
01472 {
01473 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
01474 return 1;
01475
01476 if (mi->mi_set)
01477 dbiPruneSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), sorted);
01478 return 0;
01479 }
01480
01481 int rpmdbAppendIterator(rpmdbMatchIterator mi, int * hdrNums, int nHdrNums)
01482 {
01483 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
01484 return 1;
01485
01486 if (mi->mi_set == NULL)
01487 mi->mi_set = xcalloc(1, sizeof(*mi->mi_set));
01488 dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0);
01489 return 0;
01490 }
01491
01492 rpmdbMatchIterator rpmdbInitIterator(rpmdb rpmdb, int rpmtag,
01493 const void * keyp, size_t keylen)
01494 {
01495 rpmdbMatchIterator mi = NULL;
01496 dbiIndexSet set = NULL;
01497 dbiIndex dbi;
01498 int isLabel = 0;
01499
01500
01501 switch (rpmtag) {
01502 case RPMDBI_LABEL:
01503 rpmtag = RPMTAG_NAME;
01504 isLabel = 1;
01505 break;
01506 }
01507
01508 dbi = dbiOpen(rpmdb, rpmtag, 0);
01509 if (dbi == NULL)
01510 return NULL;
01511
01512 #if 0
01513 assert(dbi->dbi_rmw == NULL);
01514 assert(dbi->dbi_lastoffset == 0);
01515 #else
01516 if (dbi->dbi_rmw)
01517 fprintf(stderr, "*** RMW %s %p\n", tagName(rpmtag), dbi->dbi_rmw);
01518 #endif
01519
01520 dbi->dbi_lastoffset = 0;
01521
01522 if (rpmtag != RPMDBI_PACKAGES && keyp) {
01523 DBC * dbcursor = NULL;
01524 int rc;
01525 int xx;
01526
01527 if (isLabel) {
01528
01529 xx = dbiCopen(dbi, &dbcursor, 0);
01530 rc = dbiFindByLabel(dbi, dbcursor, keyp, &set);
01531 xx = dbiCclose(dbi, dbcursor, 0);
01532 dbcursor = NULL;
01533 } else if (rpmtag == RPMTAG_BASENAMES) {
01534 rc = rpmdbFindByFile(rpmdb, keyp, &set);
01535 } else {
01536 xx = dbiCopen(dbi, &dbcursor, 0);
01537 rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
01538 xx = dbiCclose(dbi, dbcursor, 0);
01539 dbcursor = NULL;
01540 }
01541 if (rc) {
01542 if (set)
01543 dbiFreeIndexSet(set);
01544 return NULL;
01545 }
01546 }
01547
01548 if (keyp) {
01549 char * k;
01550
01551 if (rpmtag != RPMDBI_PACKAGES && keylen == 0)
01552 keylen = strlen(keyp);
01553 k = xmalloc(keylen + 1);
01554 memcpy(k, keyp, keylen);
01555 k[keylen] = '\0';
01556 keyp = k;
01557 }
01558
01559 mi = xcalloc(sizeof(*mi), 1);
01560 mi->mi_keyp = keyp;
01561 mi->mi_keylen = keylen;
01562
01563 mi->mi_rpmdb = rpmdb;
01564 mi->mi_rpmtag = rpmtag;
01565
01566 mi->mi_dbc = NULL;
01567 mi->mi_set = set;
01568 mi->mi_setx = 0;
01569 mi->mi_h = NULL;
01570 mi->mi_sorted = 0;
01571 mi->mi_modified = 0;
01572 mi->mi_prevoffset = 0;
01573 mi->mi_offset = 0;
01574 mi->mi_filenum = 0;
01575 mi->mi_fpnum = 0;
01576 mi->mi_dbnum = 0;
01577 mi->mi_version = NULL;
01578 mi->mi_release = NULL;
01579 return mi;
01580 }
01581
01582 static INLINE int removeIndexEntry(dbiIndex dbi, DBC * dbcursor, const char * keyp,
01583 dbiIndexItem rec)
01584 {
01585 dbiIndexSet set = NULL;
01586 int rc;
01587
01588 rc = dbiSearch(dbi, dbcursor, keyp, 0, &set);
01589
01590 if (rc < 0)
01591 rc = 0;
01592 else if (rc > 0)
01593 rc = 1;
01594 else {
01595 if (!dbiPruneSet(set, rec, 1, sizeof(*rec), 1) &&
01596 dbiUpdateIndex(dbi, dbcursor, keyp, set))
01597 rc = 1;
01598 }
01599
01600 if (set) {
01601 dbiFreeIndexSet(set);
01602 set = NULL;
01603 }
01604
01605 return rc;
01606 }
01607
01608
01609 int rpmdbRemove(rpmdb rpmdb, int rid, unsigned int hdrNum)
01610 {
01611 Header h;
01612 sigset_t signalMask;
01613
01614 { rpmdbMatchIterator mi;
01615 mi = rpmdbInitIterator(rpmdb, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum));
01616 h = rpmdbNextIterator(mi);
01617 if (h)
01618 h = headerLink(h);
01619 rpmdbFreeIterator(mi);
01620 }
01621
01622 if (h == NULL) {
01623 rpmError(RPMERR_DBCORRUPT, _("%s: cannot read header at 0x%x\n"),
01624 "rpmdbRemove", hdrNum);
01625 return 1;
01626 }
01627
01628
01629 if (rid > 0) {
01630 int_32 tid = rid;
01631 headerAddEntry(h, RPMTAG_REMOVETID, RPM_INT32_TYPE, &tid, 1);
01632 }
01633
01634 { const char *n, *v, *r;
01635 headerNVR(h, &n, &v, &r);
01636 rpmMessage(RPMMESS_DEBUG, " --- %10d %s-%s-%s\n", hdrNum, n, v, r);
01637 }
01638
01639 blockSignals(rpmdb, &signalMask);
01640
01641 { int dbix;
01642 dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
01643
01644 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
01645 dbiIndex dbi;
01646 DBC * dbcursor = NULL;
01647 const char *av[1];
01648 const char ** rpmvals = NULL;
01649 int rpmtype = 0;
01650 int rpmcnt = 0;
01651 int rpmtag;
01652 int xx;
01653 int i;
01654
01655 dbi = NULL;
01656 rpmtag = dbiTags[dbix];
01657
01658 switch (rpmtag) {
01659
01660 case RPMDBI_AVAILABLE:
01661 case RPMDBI_ADDED:
01662 case RPMDBI_REMOVED:
01663 case RPMDBI_DEPENDS:
01664 continue;
01665 break;
01666 case RPMDBI_PACKAGES:
01667 dbi = dbiOpen(rpmdb, rpmtag, 0);
01668 xx = dbiCopen(dbi, &dbcursor, 0);
01669 xx = dbiDel(dbi, dbcursor, &hdrNum, sizeof(hdrNum), 0);
01670 xx = dbiCclose(dbi, dbcursor, 0);
01671 dbcursor = NULL;
01672
01673 if (!dbi->dbi_no_dbsync)
01674 xx = dbiSync(dbi, 0);
01675 continue;
01676 break;
01677 }
01678
01679 if (!headerGetEntry(h, rpmtag, &rpmtype,
01680 (void **) &rpmvals, &rpmcnt))
01681 continue;
01682
01683 dbi = dbiOpen(rpmdb, rpmtag, 0);
01684 xx = dbiCopen(dbi, &dbcursor, 0);
01685
01686 if (rpmtype == RPM_STRING_TYPE) {
01687
01688 rpmMessage(RPMMESS_DEBUG, _("removing \"%s\" from %s index.\n"),
01689 (const char *)rpmvals, tagName(dbi->dbi_rpmtag));
01690
01691
01692 av[0] = (const char *) rpmvals;
01693 rpmvals = av;
01694 rpmcnt = 1;
01695 } else {
01696
01697 rpmMessage(RPMMESS_DEBUG, _("removing %d entries from %s index.\n"),
01698 rpmcnt, tagName(dbi->dbi_rpmtag));
01699
01700 }
01701
01702 for (i = 0; i < rpmcnt; i++) {
01703
01704
01705
01706
01707
01708
01709 xx = removeIndexEntry(dbi, dbcursor, rpmvals[i], rec);
01710 }
01711
01712 xx = dbiCclose(dbi, dbcursor, 0);
01713 dbcursor = NULL;
01714
01715
01716 if (!dbi->dbi_no_dbsync)
01717 xx = dbiSync(dbi, 0);
01718
01719 headerFreeData(rpmvals, rpmtype);
01720 rpmvals = NULL;
01721 rpmtype = 0;
01722 rpmcnt = 0;
01723 }
01724
01725 if (rec) {
01726 free(rec);
01727 rec = NULL;
01728 }
01729 }
01730
01731 unblockSignals(rpmdb, &signalMask);
01732
01733 headerFree(h);
01734
01735 return 0;
01736 }
01737
01738 static INLINE int addIndexEntry(dbiIndex dbi, DBC * dbcursor, const char *index, dbiIndexItem rec)
01739 {
01740 dbiIndexSet set = NULL;
01741 int rc;
01742
01743 rc = dbiSearch(dbi, dbcursor, index, 0, &set);
01744
01745 if (rc > 0) {
01746 rc = 1;
01747 } else {
01748 if (rc < 0) {
01749 rc = 0;
01750 set = xcalloc(1, sizeof(*set));
01751 }
01752 dbiAppendSet(set, rec, 1, sizeof(*rec), 0);
01753 if (dbiUpdateIndex(dbi, dbcursor, index, set))
01754 rc = 1;
01755 }
01756
01757 if (set) {
01758 dbiFreeIndexSet(set);
01759 set = NULL;
01760 }
01761
01762 return 0;
01763 }
01764
01765
01766 int rpmdbAdd(rpmdb rpmdb, int iid, Header h)
01767 {
01768 sigset_t signalMask;
01769 const char ** baseNames;
01770 int count = 0;
01771 int type;
01772 dbiIndex dbi;
01773 int dbix;
01774 unsigned int hdrNum;
01775 int rc = 0;
01776 int xx;
01777
01778 if (iid > 0) {
01779 int_32 tid = iid;
01780 headerRemoveEntry(h, RPMTAG_REMOVETID);
01781 headerAddEntry(h, RPMTAG_INSTALLTID, RPM_INT32_TYPE, &tid, 1);
01782 }
01783
01784
01785
01786
01787
01788
01789
01790 headerGetEntry(h, RPMTAG_BASENAMES, &type, (void **) &baseNames, &count);
01791
01792 if (_noDirTokens)
01793 expandFilelist(h);
01794
01795 blockSignals(rpmdb, &signalMask);
01796
01797 {
01798 unsigned int firstkey = 0;
01799 DBC * dbcursor = NULL;
01800 void * keyp = &firstkey;
01801 size_t keylen = sizeof(firstkey);
01802 void * datap = NULL;
01803 size_t datalen = 0;
01804
01805 dbi = dbiOpen(rpmdb, RPMDBI_PACKAGES, 0);
01806
01807
01808 datap = h;
01809 datalen = headerSizeof(h, HEADER_MAGIC_NO);
01810
01811 xx = dbiCopen(dbi, &dbcursor, 0);
01812
01813
01814
01815 rc = dbiGet(dbi, dbcursor, &keyp, &keylen, &datap, &datalen, 0);
01816
01817 hdrNum = 0;
01818 if (rc == 0 && datap)
01819 memcpy(&hdrNum, datap, sizeof(hdrNum));
01820 ++hdrNum;
01821 if (rc == 0 && datap) {
01822 memcpy(datap, &hdrNum, sizeof(hdrNum));
01823 } else {
01824 datap = &hdrNum;
01825 datalen = sizeof(hdrNum);
01826 }
01827
01828 rc = dbiPut(dbi, dbcursor, keyp, keylen, datap, datalen, 0);
01829 xx = dbiSync(dbi, 0);
01830
01831 xx = dbiCclose(dbi, dbcursor, 0);
01832 dbcursor = NULL;
01833
01834 }
01835
01836 if (rc) {
01837 rpmError(RPMERR_DBCORRUPT,
01838 _("error(%d) allocating new package instance\n"), rc);
01839 goto exit;
01840 }
01841
01842
01843
01844 { dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
01845
01846 for (dbix = 0; dbix < dbiTagsMax; dbix++) {
01847 DBC * dbcursor = NULL;
01848 const char *av[1];
01849 const char **rpmvals = NULL;
01850 int rpmtype = 0;
01851 int rpmcnt = 0;
01852 int rpmtag;
01853 int_32 * requireFlags;
01854 int i, j;
01855
01856 dbi = NULL;
01857 requireFlags = NULL;
01858 rpmtag = dbiTags[dbix];
01859
01860 switch (rpmtag) {
01861
01862 case RPMDBI_AVAILABLE:
01863 case RPMDBI_ADDED:
01864 case RPMDBI_REMOVED:
01865 case RPMDBI_DEPENDS:
01866 continue;
01867 break;
01868 case RPMDBI_PACKAGES:
01869 dbi = dbiOpen(rpmdb, rpmtag, 0);
01870 xx = dbiCopen(dbi, &dbcursor, 0);
01871 xx = dbiUpdateRecord(dbi, dbcursor, hdrNum, h);
01872 xx = dbiCclose(dbi, dbcursor, 0);
01873 dbcursor = NULL;
01874 if (!dbi->dbi_no_dbsync)
01875 xx = dbiSync(dbi, 0);
01876 { const char *n, *v, *r;
01877 headerNVR(h, &n, &v, &r);
01878 rpmMessage(RPMMESS_DEBUG, " +++ %10d %s-%s-%s\n", hdrNum, n, v, r);
01879 }
01880 continue;
01881 break;
01882
01883 case RPMTAG_BASENAMES:
01884 rpmtype = type;
01885 rpmvals = baseNames;
01886 rpmcnt = count;
01887 break;
01888 case RPMTAG_REQUIRENAME:
01889 headerGetEntry(h, rpmtag, &rpmtype, (void **)&rpmvals, &rpmcnt);
01890 headerGetEntry(h, RPMTAG_REQUIREFLAGS, NULL,
01891 (void **)&requireFlags, NULL);
01892 break;
01893 default:
01894 headerGetEntry(h, rpmtag, &rpmtype, (void **)&rpmvals, &rpmcnt);
01895 break;
01896 }
01897
01898 if (rpmcnt <= 0) {
01899 if (rpmtag != RPMTAG_GROUP)
01900 continue;
01901
01902
01903 rpmtype = RPM_STRING_TYPE;
01904 rpmvals = (const char **) "Unknown";
01905 rpmcnt = 1;
01906 }
01907
01908 dbi = dbiOpen(rpmdb, rpmtag, 0);
01909
01910 xx = dbiCopen(dbi, &dbcursor, 0);
01911 if (rpmtype == RPM_STRING_TYPE) {
01912 rpmMessage(RPMMESS_DEBUG, _("adding \"%s\" to %s index.\n"),
01913 (const char *)rpmvals, tagName(dbi->dbi_rpmtag));
01914
01915
01916 av[0] = (const char *) rpmvals;
01917 rpmvals = av;
01918 rpmcnt = 1;
01919 } else {
01920
01921 rpmMessage(RPMMESS_DEBUG, _("adding %d entries to %s index.\n"),
01922 rpmcnt, tagName(dbi->dbi_rpmtag));
01923
01924 }
01925
01926 for (i = 0; i < rpmcnt; i++) {
01927
01928
01929
01930
01931
01932 switch (dbi->dbi_rpmtag) {
01933 case RPMTAG_REQUIRENAME:
01934
01935 if (requireFlags && isInstallPreReq(requireFlags[i]))
01936 continue;
01937 rec->tagNum = i;
01938 break;
01939 case RPMTAG_TRIGGERNAME:
01940 if (i) {
01941 for (j = 0; j < i; j++) {
01942 if (!strcmp(rpmvals[i], rpmvals[j]))
01943 break;
01944 }
01945 if (j < i)
01946 continue;
01947 }
01948 rec->tagNum = i;
01949 break;
01950 default:
01951 rec->tagNum = i;
01952 break;
01953 }
01954
01955 rc += addIndexEntry(dbi, dbcursor, rpmvals[i], rec);
01956 }
01957 xx = dbiCclose(dbi, dbcursor, 0);
01958 dbcursor = NULL;
01959
01960
01961 if (!dbi->dbi_no_dbsync)
01962 xx = dbiSync(dbi, 0);
01963
01964 headerFreeData(rpmvals, rpmtype);
01965 rpmvals = NULL;
01966 rpmtype = 0;
01967 rpmcnt = 0;
01968 }
01969
01970 if (rec) {
01971 free(rec);
01972 rec = NULL;
01973 }
01974 }
01975
01976 exit:
01977 unblockSignals(rpmdb, &signalMask);
01978
01979 return rc;
01980 }
01981
01982
01983 int rpmdbFindFpList(rpmdb rpmdb, fingerPrint * fpList, dbiIndexSet * matchList,
01984 int numItems)
01985 {
01986 rpmdbMatchIterator mi;
01987 fingerPrintCache fpc;
01988 Header h;
01989 int i;
01990
01991 mi = rpmdbInitIterator(rpmdb, RPMTAG_BASENAMES, NULL, 0);
01992
01993
01994 for (i = 0; i < numItems; i++) {
01995 rpmdbGrowIterator(mi, fpList[i].baseName, 0, i);
01996 matchList[i] = xcalloc(1, sizeof(*(matchList[i])));
01997 }
01998
01999 if ((i = rpmdbGetIteratorCount(mi)) == 0) {
02000 rpmdbFreeIterator(mi);
02001 return 0;
02002 }
02003 fpc = fpCacheCreate(i);
02004
02005 rpmdbSortIterator(mi);
02006
02007
02008
02009 while ((h = rpmdbNextIterator(mi)) != NULL) {
02010 const char ** dirNames;
02011 const char ** baseNames;
02012 const char ** fullBaseNames;
02013 int_32 * dirIndexes;
02014 int_32 * fullDirIndexes;
02015 fingerPrint * fps;
02016 dbiIndexItem im;
02017 int start;
02018 int num;
02019 int end;
02020
02021 start = mi->mi_setx - 1;
02022 im = mi->mi_set->recs + start;
02023
02024
02025 for (end = start + 1; end < mi->mi_set->count; end++) {
02026 if (im->hdrNum != mi->mi_set->recs[end].hdrNum)
02027 break;
02028 }
02029 num = end - start;
02030
02031
02032 headerGetEntryMinMemory(h, RPMTAG_BASENAMES, NULL,
02033 (const void **) &fullBaseNames, NULL);
02034 headerGetEntryMinMemory(h, RPMTAG_DIRNAMES, NULL,
02035 (const void **) &dirNames, NULL);
02036 headerGetEntryMinMemory(h, RPMTAG_DIRINDEXES, NULL,
02037 (const void **) &fullDirIndexes, NULL);
02038
02039 baseNames = xcalloc(num, sizeof(*baseNames));
02040 dirIndexes = xcalloc(num, sizeof(*dirIndexes));
02041 for (i = 0; i < num; i++) {
02042 baseNames[i] = fullBaseNames[im[i].tagNum];
02043 dirIndexes[i] = fullDirIndexes[im[i].tagNum];
02044 }
02045
02046 fps = xcalloc(num, sizeof(*fps));
02047 fpLookupList(fpc, dirNames, baseNames, dirIndexes, num, fps);
02048
02049
02050 for (i = 0; i < num; i++, im++) {
02051 if (FP_EQUAL(fps[i], fpList[im->fpNum]))
02052 dbiAppendSet(matchList[im->fpNum], im, 1, sizeof(*im), 0);
02053 }
02054
02055 free(fps);
02056 free(dirNames);
02057 free(fullBaseNames);
02058 free(baseNames);
02059 free(dirIndexes);
02060
02061 mi->mi_setx = end;
02062 }
02063
02064 rpmdbFreeIterator(mi);
02065
02066 fpCacheFree(fpc);
02067
02068 return 0;
02069
02070 }
02071
02072 char * db1basename (int rpmtag) {
02073 char * base = NULL;
02074 switch (rpmtag) {
02075 case RPMDBI_PACKAGES: base = "packages.rpm"; break;
02076 case RPMTAG_NAME: base = "nameindex.rpm"; break;
02077 case RPMTAG_BASENAMES: base = "fileindex.rpm"; break;
02078 case RPMTAG_GROUP: base = "groupindex.rpm"; break;
02079 case RPMTAG_REQUIRENAME: base = "requiredby.rpm"; break;
02080 case RPMTAG_PROVIDENAME: base = "providesindex.rpm"; break;
02081 case RPMTAG_CONFLICTNAME: base = "conflictsindex.rpm"; break;
02082 case RPMTAG_TRIGGERNAME: base = "triggerindex.rpm"; break;
02083 default:
02084 { const char * tn = tagName(rpmtag);
02085 base = alloca( strlen(tn) + sizeof(".idx") + 1 );
02086 (void) stpcpy( stpcpy(base, tn), ".idx");
02087 } break;
02088 }
02089 return xstrdup(base);
02090 }
02091
02092 static int rpmdbRemoveDatabase(const char * rootdir,
02093 const char * dbpath, int _dbapi)
02094 {
02095 int i;
02096 char * filename;
02097 int xx;
02098
02099 i = strlen(dbpath);
02100 if (dbpath[i - 1] != '/') {
02101 filename = alloca(i);
02102 strcpy(filename, dbpath);
02103 filename[i] = '/';
02104 filename[i + 1] = '\0';
02105 dbpath = filename;
02106 }
02107
02108 filename = alloca(strlen(rootdir) + strlen(dbpath) + 40);
02109
02110 switch (_dbapi) {
02111 case 3:
02112 for (i = 0; i < dbiTagsMax; i++) {
02113 const char * base = tagName(dbiTags[i]);
02114 sprintf(filename, "%s/%s/%s", rootdir, dbpath, base);
02115 (void)rpmCleanPath(filename);
02116 xx = unlink(filename);
02117 }
02118 for (i = 0; i < 16; i++) {
02119 sprintf(filename, "%s/%s/__db.%03d", rootdir, dbpath, i);
02120 (void)rpmCleanPath(filename);
02121 xx = unlink(filename);
02122 }
02123 break;
02124 case 2:
02125 case 1:
02126 case 0:
02127 for (i = 0; i < dbiTagsMax; i++) {
02128 const char * base = db1basename(dbiTags[i]);
02129 sprintf(filename, "%s/%s/%s", rootdir, dbpath, base);
02130 (void)rpmCleanPath(filename);
02131 xx = unlink(filename);
02132 free((void *)base);
02133 }
02134 break;
02135 }
02136
02137 sprintf(filename, "%s/%s", rootdir, dbpath);
02138 (void)rpmCleanPath(filename);
02139 xx = rmdir(filename);
02140
02141 return 0;
02142 }
02143
02144 static int rpmdbMoveDatabase(const char * rootdir,
02145 const char * olddbpath, int _olddbapi,
02146 const char * newdbpath, int _newdbapi)
02147 {
02148 int i;
02149 char * ofilename, * nfilename;
02150 int rc = 0;
02151 int xx;
02152
02153 i = strlen(olddbpath);
02154 if (olddbpath[i - 1] != '/') {
02155 ofilename = alloca(i + 2);
02156 strcpy(ofilename, olddbpath);
02157 ofilename[i] = '/';
02158 ofilename[i + 1] = '\0';
02159 olddbpath = ofilename;
02160 }
02161
02162 i = strlen(newdbpath);
02163 if (newdbpath[i - 1] != '/') {
02164 nfilename = alloca(i + 2);
02165 strcpy(nfilename, newdbpath);
02166 nfilename[i] = '/';
02167 nfilename[i + 1] = '\0';
02168 newdbpath = nfilename;
02169 }
02170
02171 ofilename = alloca(strlen(rootdir) + strlen(olddbpath) + 40);
02172 nfilename = alloca(strlen(rootdir) + strlen(newdbpath) + 40);
02173
02174 switch (_olddbapi) {
02175 case 3:
02176 for (i = 0; i < dbiTagsMax; i++) {
02177 const char * base;
02178 int rpmtag;
02179
02180
02181 switch ((rpmtag = dbiTags[i])) {
02182 case RPMDBI_AVAILABLE:
02183 case RPMDBI_ADDED:
02184 case RPMDBI_REMOVED:
02185 case RPMDBI_DEPENDS:
02186 continue;
02187 break;
02188 default:
02189 break;
02190 }
02191
02192 base = tagName(rpmtag);
02193 sprintf(ofilename, "%s/%s/%s", rootdir, olddbpath, base);
02194 (void)rpmCleanPath(ofilename);
02195 if (!rpmfileexists(ofilename))
02196 continue;
02197 sprintf(nfilename, "%s/%s/%s", rootdir, newdbpath, base);
02198 (void)rpmCleanPath(nfilename);
02199 if ((xx = Rename(ofilename, nfilename)) != 0)
02200 rc = 1;
02201 }
02202 for (i = 0; i < 16; i++) {
02203 sprintf(ofilename, "%s/%s/__db.%03d", rootdir, olddbpath, i);
02204 (void)rpmCleanPath(ofilename);
02205 if (!rpmfileexists(ofilename))
02206 continue;
02207 sprintf(nfilename, "%s/%s/__db.%03d", rootdir, newdbpath, i);
02208 (void)rpmCleanPath(nfilename);
02209 if ((xx = Rename(ofilename, nfilename)) != 0)
02210 rc = 1;
02211 }
02212 break;
02213 case 2:
02214 case 1:
02215 case 0:
02216 for (i = 0; i < dbiTagsMax; i++) {
02217 const char * base;
02218 int rpmtag;
02219
02220
02221 switch ((rpmtag = dbiTags[i])) {
02222 case RPMDBI_AVAILABLE:
02223 case RPMDBI_ADDED:
02224 case RPMDBI_REMOVED:
02225 case RPMDBI_DEPENDS:
02226 continue;
02227 break;
02228 default:
02229 break;
02230 }
02231
02232 base = db1basename(rpmtag);
02233 sprintf(ofilename, "%s/%s/%s", rootdir, olddbpath, base);
02234 (void)rpmCleanPath(ofilename);
02235 if (!rpmfileexists(ofilename))
02236 continue;
02237 sprintf(nfilename, "%s/%s/%s", rootdir, newdbpath, base);
02238 (void)rpmCleanPath(nfilename);
02239 if ((xx = Rename(ofilename, nfilename)) != 0)
02240 rc = 1;
02241 free((void *)base);
02242 }
02243 break;
02244 }
02245 if (rc || _olddbapi == _newdbapi)
02246 return rc;
02247
02248 rc = rpmdbRemoveDatabase(rootdir, newdbpath, _newdbapi);
02249
02250
02251
02252 if (rc == 0 && _newdbapi == 1 && _olddbapi == 3) {
02253 const char * mdb1 = "/etc/rpm/macros.db1";
02254 struct stat st;
02255 if (!stat(mdb1, &st) && S_ISREG(st.st_mode) && !unlink(mdb1))
02256 rpmMessage(RPMMESS_DEBUG,
02257 _("removing %s after successful db3 rebuild.\n"), mdb1);
02258 }
02259 return rc;
02260 }
02261
02262 int rpmdbRebuild(const char * rootdir)
02263 {
02264 rpmdb olddb;
02265 const char * dbpath = NULL;
02266 const char * rootdbpath = NULL;
02267 rpmdb newdb;
02268 const char * newdbpath = NULL;
02269 const char * newrootdbpath = NULL;
02270 const char * tfn;
02271 int nocleanup = 1;
02272 int failed = 0;
02273 int removedir = 0;
02274 int rc = 0;
02275 int _dbapi;
02276 int _dbapi_rebuild;
02277
02278 _dbapi = rpmExpandNumeric("%{_dbapi}");
02279 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
02280
02281 tfn = rpmGetPath("%{_dbpath}", NULL);
02282 if (!(tfn && tfn[0] != '%')) {
02283 rpmMessage(RPMMESS_DEBUG, _("no dbpath has been set"));
02284 rc = 1;
02285 goto exit;
02286 }
02287 dbpath = rootdbpath = rpmGetPath(rootdir, tfn, NULL);
02288 if (!(rootdir[0] == '/' && rootdir[1] == '\0'))
02289 dbpath += strlen(rootdir);
02290 free((void *)tfn);
02291
02292 tfn = rpmGetPath("%{_dbpath_rebuild}", NULL);
02293 if (!(tfn && tfn[0] != '%' && strcmp(tfn, dbpath))) {
02294 char pidbuf[20];
02295 char *t;
02296 sprintf(pidbuf, "rebuilddb.%d", (int) getpid());
02297 t = xmalloc(strlen(dbpath) + strlen(pidbuf) + 1);
02298 (void)stpcpy(stpcpy(t, dbpath), pidbuf);
02299 if (tfn) free((void *)tfn);
02300 tfn = t;
02301 nocleanup = 0;
02302 }
02303 newdbpath = newrootdbpath = rpmGetPath(rootdir, tfn, NULL);
02304 if (!(rootdir[0] == '/' && rootdir[1] == '\0'))
02305 newdbpath += strlen(rootdir);
02306 free((void *)tfn);
02307
02308 rpmMessage(RPMMESS_DEBUG, _("rebuilding database %s into %s\n"),
02309 rootdbpath, newrootdbpath);
02310
02311 if (!access(newrootdbpath, F_OK)) {
02312 rpmError(RPMERR_MKDIR, _("temporary database %s already exists\n"),
02313 newrootdbpath);
02314 rc = 1;
02315 goto exit;
02316 }
02317
02318 rpmMessage(RPMMESS_DEBUG, _("creating directory %s\n"), newrootdbpath);
02319 if (Mkdir(newrootdbpath, 0755)) {
02320 rpmError(RPMERR_MKDIR, _("creating directory %s: %s\n"),
02321 newrootdbpath, strerror(errno));
02322 rc = 1;
02323 goto exit;
02324 }
02325 removedir = 1;
02326
02327 rpmMessage(RPMMESS_DEBUG, _("opening old database with dbapi %d\n"),
02328 _dbapi);
02329 _rebuildinprogress = 1;
02330 if (openDatabase(rootdir, dbpath, _dbapi, &olddb, O_RDONLY, 0644,
02331 RPMDB_FLAG_MINIMAL)) {
02332 rc = 1;
02333 goto exit;
02334 }
02335 _dbapi = olddb->db_api;
02336 _rebuildinprogress = 0;
02337
02338 rpmMessage(RPMMESS_DEBUG, _("opening new database with dbapi %d\n"),
02339 _dbapi_rebuild);
02340 if (openDatabase(rootdir, newdbpath, _dbapi_rebuild, &newdb, O_RDWR | O_CREAT, 0644, 0)) {
02341 rc = 1;
02342 goto exit;
02343 }
02344 _dbapi_rebuild = newdb->db_api;
02345
02346 { Header h = NULL;
02347 rpmdbMatchIterator mi;
02348 #define _RECNUM rpmdbGetIteratorOffset(mi)
02349
02350
02351 mi = rpmdbInitIterator(olddb, RPMDBI_PACKAGES, NULL, 0);
02352 while ((h = rpmdbNextIterator(mi)) != NULL) {
02353
02354
02355 if (!(headerIsEntry(h, RPMTAG_NAME) &&
02356 headerIsEntry(h, RPMTAG_VERSION) &&
02357 headerIsEntry(h, RPMTAG_RELEASE) &&
02358 headerIsEntry(h, RPMTAG_BUILDTIME)))
02359 {
02360 rpmError(RPMERR_INTERNAL,
02361 _("record number %d in database is bad -- skipping.\n"),
02362 _RECNUM);
02363 continue;
02364 }
02365
02366
02367 if (_db_filter_dups || newdb->db_filter_dups) {
02368 const char * name, * version, * release;
02369 int skip = 0;
02370
02371 headerNVR(h, &name, &version, &release);
02372
02373 { rpmdbMatchIterator mi;
02374 mi = rpmdbInitIterator(newdb, RPMTAG_NAME, name, 0);
02375 rpmdbSetIteratorVersion(mi, version);
02376 rpmdbSetIteratorRelease(mi, release);
02377 while (rpmdbNextIterator(mi)) {
02378 skip = 1;
02379 break;
02380 }
02381 rpmdbFreeIterator(mi);
02382 }
02383
02384 if (skip)
02385 continue;
02386 }
02387
02388
02389 { Header nh = (headerIsEntry(h, RPMTAG_HEADERIMAGE)
02390 ? headerCopy(h) : NULL);
02391 rc = rpmdbAdd(newdb, -1, (nh ? nh : h));
02392 if (nh)
02393 headerFree(nh);
02394 }
02395
02396 if (rc) {
02397 rpmError(RPMERR_INTERNAL,
02398 _("cannot add record originally at %d\n"), _RECNUM);
02399 failed = 1;
02400 break;
02401 }
02402 }
02403
02404 rpmdbFreeIterator(mi);
02405
02406 }
02407
02408 if (!nocleanup) {
02409 olddb->db_remove_env = 1;
02410 newdb->db_remove_env = 1;
02411 }
02412 rpmdbClose(olddb);
02413 rpmdbClose(newdb);
02414
02415 if (failed) {
02416 rpmMessage(RPMMESS_NORMAL, _("failed to rebuild database: original database "
02417 "remains in place\n"));
02418
02419 rpmdbRemoveDatabase(rootdir, newdbpath, _dbapi_rebuild);
02420 rc = 1;
02421 goto exit;
02422 } else if (!nocleanup) {
02423 if (rpmdbMoveDatabase(rootdir, newdbpath, _dbapi_rebuild, dbpath, _dbapi)) {
02424 rpmMessage(RPMMESS_ERROR, _("failed to replace old database with new "
02425 "database!\n"));
02426 rpmMessage(RPMMESS_ERROR, _("replace files in %s with files from %s "
02427 "to recover"), dbpath, newdbpath);
02428 rc = 1;
02429 goto exit;
02430 }
02431 }
02432 rc = 0;
02433
02434 exit:
02435 if (removedir && !(rc == 0 && nocleanup)) {
02436 rpmMessage(RPMMESS_DEBUG, _("removing directory %s\n"), newrootdbpath);
02437 if (Rmdir(newrootdbpath))
02438 rpmMessage(RPMMESS_ERROR, _("failed to remove directory %s: %s\n"),
02439 newrootdbpath, strerror(errno));
02440 }
02441 if (newrootdbpath) free((void *)newrootdbpath);
02442 if (rootdbpath) free((void *)rootdbpath);
02443
02444 return rc;
02445 }