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