00001
00005 #include "system.h"
00006
00007 #define _USE_COPY_LOAD
00008
00009 #include <sys/file.h>
00010
00011 #include <rpmio.h>
00012 #include <rpmlog.h>
00013 #include <rpmpgp.h>
00014 #include <rpmurl.h>
00015 #define _MIRE_INTERNAL
00016 #include <rpmmacro.h>
00017 #include <rpmsq.h>
00018
00019 #define _RPMTAG_INTERNAL
00020 #include "header_internal.h"
00021
00022 #define _RPMEVR_INTERNAL
00023 #include <rpmevr.h>
00024
00025
00026
00027 extern pgpDig rpmtsDig(void * ts)
00028 ;
00029 extern void rpmtsCleanDig(void * ts)
00030 ;
00031
00032
00033 #define _RPMDB_INTERNAL
00034 #include "rpmdb.h"
00035 #include "pkgio.h"
00036 #include "fprint.h"
00037 #include "legacy.h"
00038
00039 #include "debug.h"
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 int _rpmdb_debug = 0;
00050
00051
00052 static int _rebuildinprogress = 0;
00053
00054 static int _db_filter_dups = 0;
00055
00056
00057
00058
00059 #define _DB_TAGGED_FILE_INDICES 1
00060
00061 static int _db_tagged_file_indices = _DB_TAGGED_FILE_INDICES;
00062
00063 #define _DBI_FLAGS 0
00064 #define _DBI_PERMS 0644
00065 #define _DBI_MAJOR -1
00066
00067
00068
00069 typedef unsigned int __pbm_bits;
00070
00071 #define __PBM_NBITS (8 * sizeof(__pbm_bits))
00072 #define __PBM_IX(d) ((d) / __PBM_NBITS)
00073 #define __PBM_MASK(d) ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS))
00074
00075 typedef struct {
00076 __pbm_bits bits[1];
00077 } pbm_set;
00078
00079 #define __PBM_BITS(set) ((set)->bits)
00080
00081 #define PBM_FREE(s) _free(s);
00082 #define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d))
00083 #define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d))
00084 #define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0)
00085
00086 #define PBM_ALLOC(d) xcalloc(__PBM_IX (d) + 1, __PBM_NBITS/8)
00087
00094
00095 static inline pbm_set * PBM_REALLOC(pbm_set ** sp, int * odp, int nd)
00096
00097 {
00098 int i, nb;
00099
00100 if (nd > (*odp)) {
00101 nd *= 2;
00102 nb = __PBM_IX(nd) + 1;
00103
00104 *sp = xrealloc(*sp, nb * (__PBM_NBITS/8));
00105
00106 for (i = __PBM_IX(*odp) + 1; i < nb; i++)
00107 __PBM_BITS(*sp)[i] = 0;
00108 *odp = nd;
00109 }
00110
00111 return *sp;
00112
00113 }
00114
00120 static inline unsigned char nibble(char c)
00121
00122 {
00123 if (c >= '0' && c <= '9')
00124 return (unsigned char)(c - '0');
00125 if (c >= 'A' && c <= 'F')
00126 return (unsigned char)((int)(c - 'A') + 10);
00127 if (c >= 'a' && c <= 'f')
00128 return (unsigned char)((int)(c - 'a') + 10);
00129 return '\0';
00130 }
00131
00138
00139 static char * bin2hex(const void *data, size_t size)
00140
00141 {
00142 static char hex[] = "0123456789abcdef";
00143 const char * s = data;
00144 char * t, * val;
00145 val = t = xmalloc(size * 2 + 1);
00146 while (size-- > 0) {
00147 unsigned i;
00148 i = (unsigned) *s++;
00149 *t++ = hex[ (i >> 4) & 0xf ];
00150 *t++ = hex[ (i ) & 0xf ];
00151 }
00152 *t = '\0';
00153
00154 return val;
00155 }
00156
00157 #ifdef DYING
00158
00164 static int printable(const void * ptr, size_t len)
00165 {
00166 const char * s = ptr;
00167 int i;
00168 for (i = 0; i < len; i++, s++)
00169 if (!(*s >= ' ' && *s <= '~')) return 0;
00170 return 1;
00171 }
00172 #endif
00173
00180 static size_t dbiTagToDbix(rpmdb db, rpmTag rpmtag)
00181
00182 {
00183 size_t dbix;
00184
00185 if (db->db_tags != NULL)
00186 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
00187 if (rpmtag != db->db_tags[dbix].tag)
00188 continue;
00189 return dbix;
00190 }
00191 return 0xffffffff;
00192 }
00193
00197
00198 static void dbiTagsInit( tagStore_t * dbiTagsP,
00199 size_t * dbiNTagsP)
00200
00201
00202 {
00203
00204 static const char * const _dbiTagStr_default =
00205 "Packages:Name:Basenames:Group:Requirename:Providename:Conflictname:Triggername:Dirnames:Requireversion:Provideversion:Installtid:Sigmd5:Sha1header:Filemd5s:Depends:Pubkeys";
00206 tagStore_t dbiTags = NULL;
00207 size_t dbiNTags = 0;
00208 char * dbiTagStr = NULL;
00209 char * o, * oe;
00210 rpmTag rpmtag;
00211 size_t dbix;
00212 int bingo;
00213
00214 dbiTagStr = rpmExpand("%{?_dbi_tags}", NULL);
00215 if (!(dbiTagStr && *dbiTagStr)) {
00216 dbiTagStr = _free(dbiTagStr);
00217 dbiTagStr = xstrdup(_dbiTagStr_default);
00218 }
00219
00220
00221 dbiTags = xcalloc(1, sizeof(*dbiTags));
00222 dbiTags[dbiNTags].str = xstrdup("Packages");
00223 dbiTags[dbiNTags].tag = RPMDBI_PACKAGES;
00224 dbiTags[dbiNTags].val = NULL;
00225 dbiNTags++;
00226
00227 for (o = dbiTagStr; o && *o; o = oe) {
00228 while (*o && xisspace((int)*o))
00229 o++;
00230 if (*o == '\0')
00231 break;
00232 for (oe = o; oe && *oe; oe++) {
00233 if (xisspace((int)*oe))
00234 break;
00235 if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/'))
00236 break;
00237 }
00238 if (oe && *oe)
00239 *oe++ = '\0';
00240 rpmtag = tagValue(o);
00241
00242 bingo = 0;
00243 if (dbiTags != NULL)
00244 for (dbix = 0; dbix < dbiNTags; dbix++) {
00245 if (rpmtag == dbiTags[dbix].tag) {
00246 bingo = 1;
00247 break;
00248 }
00249 }
00250 if (bingo)
00251 continue;
00252
00253 dbiTags = xrealloc(dbiTags, (dbiNTags + 1) * sizeof(*dbiTags));
00254 dbiTags[dbiNTags].str = xstrdup(o);
00255 dbiTags[dbiNTags].tag = rpmtag;
00256 dbiTags[dbiNTags].val = NULL;
00257 dbiNTags++;
00258 }
00259
00260 if (dbiNTagsP != NULL)
00261 *dbiNTagsP = dbiNTags;
00262 if (dbiTagsP != NULL)
00263 *dbiTagsP = dbiTags;
00264 else
00265 dbiTags = tagStoreFree(dbiTags, dbiNTags);
00266 dbiTagStr = _free(dbiTagStr);
00267 }
00268
00269
00270
00271 #define DB1vec NULL
00272 #define DB2vec NULL
00273
00274 #ifdef HAVE_DB_H
00275
00276
00277 extern struct _dbiVec db3vec;
00278
00279 #define DB3vec &db3vec
00280
00281 #else
00282 #define DB3vec NULL
00283 #endif
00284
00285 #ifdef HAVE_SQLITE3_H
00286 #define SQLITE_HACK
00287
00288
00289 extern struct _dbiVec sqlitevec;
00290
00291 #define SQLITEvec &sqlitevec
00292
00293 #else
00294 #define SQLITEvec NULL
00295 #endif
00296
00297
00298
00299 static struct _dbiVec *mydbvecs[] = {
00300 DB1vec, DB1vec, DB2vec, DB3vec, SQLITEvec, NULL
00301 };
00302
00303
00304 static inline int checkfd(const char * devnull, int fdno, int flags)
00305 {
00306 struct stat sb;
00307 int ret = 0;
00308
00309 if (fstat(fdno, &sb) == -1 && errno == EBADF)
00310 ret = (open(devnull, flags) == fdno) ? 1 : 2;
00311 return ret;
00312 }
00313
00314 dbiIndex dbiOpen(rpmdb db, rpmTag rpmtag, unsigned int flags)
00315 {
00316 static int _oneshot = 0;
00317 size_t dbix;
00318 tagStore_t dbiTag;
00319 const char * dbiBN;
00320 dbiIndex dbi = NULL;
00321 int _dbapi, _dbapi_rebuild, _dbapi_wanted;
00322 int rc = 0;
00323
00324
00325 if (!_oneshot) {
00326 static const char _devnull[] = "/dev/null";
00327 #if defined(STDIN_FILENO)
00328 (void) checkfd(_devnull, STDIN_FILENO, O_RDONLY);
00329 #endif
00330 #if defined(STDOUT_FILENO)
00331 (void) checkfd(_devnull, STDOUT_FILENO, O_WRONLY);
00332 #endif
00333 #if defined(STDERR_FILENO)
00334 (void) checkfd(_devnull, STDERR_FILENO, O_WRONLY);
00335 #endif
00336 _oneshot++;
00337 }
00338
00339
00340 if (_rpmdb_debug)
00341 fprintf(stderr, "==> dbiOpen(%p, %u, 0x%x)\n", db, rpmtag, flags);
00342
00343
00344 if (db == NULL)
00345 return NULL;
00346
00347 dbix = dbiTagToDbix(db, rpmtag);
00348 if (dbix >= db->db_ndbi)
00349 return NULL;
00350 dbiTag = db->db_tags + dbix;
00351 dbiBN = (dbiTag->str != NULL ? dbiTag->str : tagName(rpmtag));
00352
00353
00354
00355 if (db->_dbi != NULL && (dbi = db->_dbi[dbix]) != NULL)
00356 return dbi;
00357
00358
00359 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
00360 if (_dbapi_rebuild < 1 || _dbapi_rebuild > 4)
00361 _dbapi_rebuild = 4;
00362
00363 _dbapi_wanted = (_rebuildinprogress ? _dbapi_rebuild : db->db_api);
00364
00365 switch (_dbapi_wanted) {
00366 default:
00367 _dbapi = _dbapi_wanted;
00368 if (_dbapi < 0 || _dbapi >= 5 || mydbvecs[_dbapi] == NULL) {
00369 rpmlog(RPMLOG_DEBUG, D_("dbiOpen: _dbiapi failed\n"));
00370 return NULL;
00371 }
00372 errno = 0;
00373 dbi = NULL;
00374 rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi);
00375 if (rc) {
00376 static int _printed[32];
00377 if (!_printed[dbix & 0x1f]++)
00378 rpmlog(RPMLOG_ERR,
00379 _("cannot open %s(%u) index using db%d - %s (%d)\n"),
00380 dbiBN, rpmtag, _dbapi,
00381 (rc > 0 ? strerror(rc) : ""), rc);
00382 _dbapi = -1;
00383 }
00384 break;
00385 case -1:
00386 _dbapi = 5;
00387 while (_dbapi-- > 1) {
00388 if (mydbvecs[_dbapi] == NULL)
00389 continue;
00390 errno = 0;
00391 dbi = NULL;
00392 rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi);
00393 if (rc == 0 && dbi)
00394 break;
00395 }
00396 if (_dbapi <= 0) {
00397 static int _printed[32];
00398 if (!_printed[dbix & 0x1f]++)
00399 rpmlog(RPMLOG_ERR, _("cannot open %s(%u) index\n"),
00400 dbiBN, rpmtag);
00401 rc = 1;
00402 goto exit;
00403 }
00404 if (db->db_api == -1 && _dbapi > 0)
00405 db->db_api = _dbapi;
00406 break;
00407 }
00408
00409 exit:
00410 if (dbi != NULL && rc == 0) {
00411 if (db->_dbi != NULL)
00412 db->_dbi[dbix] = dbi;
00413
00414 if (rpmtag == RPMDBI_PACKAGES && db->db_bits == NULL) {
00415 db->db_nbits = 1024;
00416 if (!dbiStat(dbi, DB_FAST_STAT)) {
00417 DB_HASH_STAT * hash = (DB_HASH_STAT *)dbi->dbi_stats;
00418 if (hash)
00419 db->db_nbits += hash->hash_nkeys;
00420 }
00421 db->db_bits = PBM_ALLOC(db->db_nbits);
00422 }
00423
00424 }
00425 #ifdef HAVE_DB_H
00426 else
00427 dbi = db3Free(dbi);
00428 #endif
00429
00430
00431 return dbi;
00432
00433 }
00434
00441 static dbiIndexItem dbiIndexNewItem(unsigned int hdrNum, unsigned int tagNum)
00442
00443 {
00444 dbiIndexItem rec = xcalloc(1, sizeof(*rec));
00445 rec->hdrNum = hdrNum;
00446 rec->tagNum = tagNum;
00447 return rec;
00448 }
00449
00450 union _dbswap {
00451 uint32_t ui;
00452 unsigned char uc[4];
00453 };
00454
00455 #define _DBSWAP(_a) \
00456 { unsigned char _b, *_c = (_a).uc; \
00457 _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
00458 _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
00459 }
00460
00468 static int dbt2set(dbiIndex dbi, DBT * data, dbiIndexSet * setp)
00469
00470 {
00471 int _dbbyteswapped;
00472 const char * sdbir;
00473 dbiIndexSet set;
00474 int i;
00475
00476 if (dbi == NULL || data == NULL || setp == NULL)
00477 return -1;
00478 _dbbyteswapped = dbiByteSwapped(dbi);
00479
00480 if ((sdbir = data->data) == NULL) {
00481 *setp = NULL;
00482 return 0;
00483 }
00484
00485 set = xmalloc(sizeof(*set));
00486 set->count = (int) (data->size / dbi->dbi_jlen);
00487 set->recs = xmalloc(set->count * sizeof(*(set->recs)));
00488
00489
00490 switch (dbi->dbi_jlen) {
00491 default:
00492 case 2*sizeof(uint32_t):
00493 for (i = 0; i < set->count; i++) {
00494 union _dbswap hdrNum, tagNum;
00495
00496 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
00497 sdbir += sizeof(hdrNum.ui);
00498 memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
00499 sdbir += sizeof(tagNum.ui);
00500 if (_dbbyteswapped) {
00501 _DBSWAP(hdrNum);
00502 _DBSWAP(tagNum);
00503 }
00504 set->recs[i].hdrNum = hdrNum.ui;
00505 set->recs[i].tagNum = tagNum.ui;
00506 set->recs[i].fpNum = 0;
00507 }
00508 break;
00509 case 1*sizeof(uint32_t):
00510 for (i = 0; i < set->count; i++) {
00511 union _dbswap hdrNum;
00512
00513 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
00514 sdbir += sizeof(hdrNum.ui);
00515 if (_dbbyteswapped) {
00516 _DBSWAP(hdrNum);
00517 }
00518 set->recs[i].hdrNum = hdrNum.ui;
00519 set->recs[i].tagNum = 0;
00520 set->recs[i].fpNum = 0;
00521 }
00522 break;
00523 }
00524 *setp = set;
00525
00526
00527 return 0;
00528
00529 }
00530
00538 static int set2dbt(dbiIndex dbi, DBT * data, dbiIndexSet set)
00539
00540 {
00541 int _dbbyteswapped;
00542 char * tdbir;
00543 unsigned i;
00544
00545 if (dbi == NULL || data == NULL || set == NULL)
00546 return -1;
00547 _dbbyteswapped = dbiByteSwapped(dbi);
00548
00549 data->size = (u_int32_t)(set->count * (dbi->dbi_jlen));
00550 if (data->size == 0) {
00551 data->data = NULL;
00552 return 0;
00553 }
00554 tdbir = data->data = xmalloc(data->size);
00555
00556
00557 switch (dbi->dbi_jlen) {
00558 default:
00559 case 2*sizeof(uint32_t):
00560 for (i = 0; i < set->count; i++) {
00561 union _dbswap hdrNum, tagNum;
00562
00563 memset(&hdrNum, 0, sizeof(hdrNum));
00564 memset(&tagNum, 0, sizeof(tagNum));
00565 hdrNum.ui = set->recs[i].hdrNum;
00566 tagNum.ui = set->recs[i].tagNum;
00567 if (_dbbyteswapped) {
00568 _DBSWAP(hdrNum);
00569 _DBSWAP(tagNum);
00570 }
00571 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
00572 tdbir += sizeof(hdrNum.ui);
00573 memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
00574 tdbir += sizeof(tagNum.ui);
00575 }
00576 break;
00577 case 1*sizeof(uint32_t):
00578 for (i = 0; i < set->count; i++) {
00579 union _dbswap hdrNum;
00580
00581 memset(&hdrNum, 0, sizeof(hdrNum));
00582 hdrNum.ui = set->recs[i].hdrNum;
00583 if (_dbbyteswapped) {
00584 _DBSWAP(hdrNum);
00585 }
00586 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
00587 tdbir += sizeof(hdrNum.ui);
00588 }
00589 break;
00590 }
00591
00592
00593
00594 return 0;
00595
00596 }
00597
00598
00599 static int hdrNumCmp(const void * one, const void * two)
00600
00601 {
00602 const int * a = one, * b = two;
00603 return (*a - *b);
00604 }
00605
00615 static int dbiAppendSet(dbiIndexSet set, const void * recs,
00616 int nrecs, size_t recsize, int sortset)
00617
00618 {
00619 const char * rptr = recs;
00620 size_t rlen = (recsize < sizeof(*(set->recs)))
00621 ? recsize : sizeof(*(set->recs));
00622
00623 if (set == NULL || recs == NULL || nrecs <= 0 || recsize == 0)
00624 return 1;
00625
00626 set->recs = xrealloc(set->recs,
00627 (set->count + nrecs) * sizeof(*(set->recs)));
00628
00629 memset(set->recs + set->count, 0, nrecs * sizeof(*(set->recs)));
00630
00631 while (nrecs-- > 0) {
00632
00633 memcpy(set->recs + set->count, rptr, rlen);
00634
00635 rptr += recsize;
00636 set->count++;
00637 }
00638
00639 if (sortset && set->count > 1)
00640 qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
00641
00642 return 0;
00643 }
00644
00654 static int dbiPruneSet(dbiIndexSet set, void * recs, int nrecs,
00655 size_t recsize, int sorted)
00656
00657 {
00658 int from;
00659 int to = 0;
00660 int num = set->count;
00661 int numCopied = 0;
00662
00663 assert(set->count > 0);
00664 if (nrecs > 1 && !sorted)
00665 qsort(recs, nrecs, recsize, hdrNumCmp);
00666
00667 for (from = 0; from < num; from++) {
00668 if (bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) {
00669 set->count--;
00670 continue;
00671 }
00672 if (from != to)
00673 set->recs[to] = set->recs[from];
00674 to++;
00675 numCopied++;
00676 }
00677 return (numCopied == num);
00678 }
00679
00680
00681 unsigned int dbiIndexSetCount(dbiIndexSet set) {
00682 return set->count;
00683 }
00684
00685
00686 unsigned int dbiIndexRecordOffset(dbiIndexSet set, int recno) {
00687 return (unsigned) set->recs[recno].hdrNum;
00688 }
00689
00690
00691 unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, int recno) {
00692 return (unsigned) set->recs[recno].tagNum;
00693 }
00694
00695
00696 dbiIndexSet dbiFreeIndexSet(dbiIndexSet set) {
00697 if (set) {
00698 set->recs = _free(set->recs);
00699 set = _free(set);
00700 }
00701 return set;
00702 }
00703
00704 struct rpmdbMatchIterator_s {
00705
00706 rpmdbMatchIterator mi_next;
00707
00708 const void * mi_keyp;
00709 size_t mi_keylen;
00710
00711 rpmdb mi_db;
00712 rpmTag mi_rpmtag;
00713 dbiIndexSet mi_set;
00714 DBC * mi_dbc;
00715 DBT mi_key;
00716 DBT mi_data;
00717 int mi_setx;
00718
00719 Header mi_h;
00720 int mi_sorted;
00721 int mi_cflags;
00722 int mi_modified;
00723 unsigned int mi_prevoffset;
00724 unsigned int mi_offset;
00725 unsigned int mi_filenum;
00726 int mi_nre;
00727
00728 miRE mi_re;
00729
00730 rpmts mi_ts;
00731
00732 };
00733
00734
00735 static rpmdb rpmdbRock;
00736
00737
00738 static rpmdbMatchIterator rpmmiRock;
00739
00740 int rpmdbCheckTerminate(int terminate)
00741
00742
00743 {
00744 sigset_t newMask, oldMask;
00745 static int terminating = 0;
00746
00747 if (terminating) return 1;
00748
00749 (void) sigfillset(&newMask);
00750 (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
00751
00752 if (sigismember(&rpmsqCaught, SIGINT)
00753 || sigismember(&rpmsqCaught, SIGQUIT)
00754 || sigismember(&rpmsqCaught, SIGHUP)
00755 || sigismember(&rpmsqCaught, SIGTERM)
00756 || sigismember(&rpmsqCaught, SIGPIPE)
00757 || terminate)
00758 terminating = 1;
00759
00760 if (terminating) {
00761 rpmdb db;
00762 rpmdbMatchIterator mi;
00763
00764 while ((mi = rpmmiRock) != NULL) {
00765 rpmmiRock = mi->mi_next;
00766 mi->mi_next = NULL;
00767 mi = rpmdbFreeIterator(mi);
00768 }
00769
00770
00771 while ((db = rpmdbRock) != NULL) {
00772 rpmdbRock = db->db_next;
00773 db->db_next = NULL;
00774 (void) rpmdbClose(db);
00775 }
00776
00777 }
00778
00779 (void) sigprocmask(SIG_SETMASK, &oldMask, NULL);
00780 return terminating;
00781 }
00782
00783 int rpmdbCheckSignals(void)
00784 {
00785
00786 if (rpmdbCheckTerminate(0)) {
00787
00788 rpmlog(RPMLOG_DEBUG, D_("Exiting on signal(0x%lx) ...\n"), *((unsigned long *)&rpmsqCaught));
00789
00790 exit(EXIT_FAILURE);
00791 }
00792 return 0;
00793 }
00794
00801 static int blockSignals( rpmdb db, sigset_t * oldMask)
00802
00803
00804 {
00805 sigset_t newMask;
00806
00807 (void) sigfillset(&newMask);
00808 (void) sigprocmask(SIG_BLOCK, &newMask, oldMask);
00809 (void) sigdelset(&newMask, SIGINT);
00810 (void) sigdelset(&newMask, SIGQUIT);
00811 (void) sigdelset(&newMask, SIGHUP);
00812 (void) sigdelset(&newMask, SIGTERM);
00813 (void) sigdelset(&newMask, SIGPIPE);
00814 return sigprocmask(SIG_BLOCK, &newMask, NULL);
00815 }
00816
00823
00824 static int unblockSignals( rpmdb db, sigset_t * oldMask)
00825
00826
00827 {
00828 (void) rpmdbCheckSignals();
00829 return sigprocmask(SIG_SETMASK, oldMask, NULL);
00830 }
00831
00839 static inline const char * queryHeader(Header h, const char * qfmt)
00840
00841
00842 {
00843 const char * errstr = "(unkown error)";
00844 const char * str;
00845
00846
00847 str = headerSprintf(h, qfmt, NULL, headerCompoundFormats, &errstr);
00848
00849 if (str == NULL)
00850 rpmlog(RPMLOG_ERR, _("incorrect format: \"%s\": %s\n"), qfmt, errstr);
00851 return str;
00852 }
00853
00861 static int rpmdbExportInfo( rpmdb db, Header h, int adding)
00862
00863
00864
00865
00866 {
00867 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00868 const char * fn = NULL;
00869 int xx;
00870
00871 { const char * fnfmt = rpmGetPath("%{?_hrmib_path}", NULL);
00872 if (fnfmt && *fnfmt)
00873 fn = queryHeader(h, fnfmt);
00874 fnfmt = _free(fnfmt);
00875 }
00876
00877 if (fn == NULL)
00878 goto exit;
00879
00880 if (adding) {
00881 FD_t fd = Fopen(fn, "w.fdio");
00882
00883 if (fd != NULL) {
00884 xx = Fclose(fd);
00885 fd = NULL;
00886 he->tag = RPMTAG_INSTALLTID;
00887 if (headerGet(h, he, 0)) {
00888 struct utimbuf stamp;
00889 stamp.actime = he->p.ui32p[0];
00890 stamp.modtime = he->p.ui32p[0];
00891 if (!Utime(fn, &stamp))
00892 rpmlog(RPMLOG_DEBUG, " +++ %s\n", fn);
00893 }
00894 he->p.ptr = _free(he->p.ptr);
00895 }
00896 } else {
00897 if (!Unlink(fn))
00898 rpmlog(RPMLOG_DEBUG, " --- %s\n", fn);
00899 }
00900
00901 exit:
00902 fn = _free(fn);
00903 return 0;
00904 }
00905
00906 #define _DB_ROOT "/"
00907 #define _DB_HOME "%{?_dbpath}"
00908 #define _DB_FLAGS 0
00909 #define _DB_MODE 0
00910 #define _DB_PERMS 0644
00911
00912 #define _DB_MAJOR -1
00913 #define _DB_ERRPFX "rpmdb"
00914
00915
00916
00917 static struct rpmdb_s dbTemplate = {
00918 _DB_ROOT, _DB_HOME, _DB_FLAGS, _DB_MODE, _DB_PERMS,
00919 _DB_MAJOR, _DB_ERRPFX
00920 };
00921
00922
00923 int rpmdbOpenAll(rpmdb db)
00924 {
00925 size_t dbix;
00926 int rc = 0;
00927
00928 if (db == NULL) return -2;
00929
00930 if (db->db_tags != NULL && db->_dbi != NULL)
00931 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
00932 tagStore_t dbiTag = db->db_tags + dbix;
00933 int rpmtag = dbiTag->tag;
00934 if (rpmtag < 0)
00935 continue;
00936 if (db->_dbi[dbix] != NULL)
00937 continue;
00938 switch (rpmtag) {
00939 case RPMDBI_AVAILABLE:
00940 case RPMDBI_ADDED:
00941 case RPMDBI_REMOVED:
00942 case RPMDBI_DEPENDS:
00943 continue;
00944 break;
00945 default:
00946 break;
00947 }
00948 (void) dbiOpen(db, rpmtag, db->db_flags);
00949 }
00950 return rc;
00951 }
00952
00953 int rpmdbBlockDBI(rpmdb db, int rpmtag)
00954 {
00955 int tagn = (rpmtag >= 0 ? rpmtag : -rpmtag);
00956 size_t dbix;
00957
00958 if (db == NULL || db->_dbi == NULL)
00959 return 0;
00960
00961 if (db->db_tags != NULL)
00962 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
00963 if (db->db_tags[dbix].tag != tagn)
00964 continue;
00965 db->db_tags[dbix].tag = rpmtag;
00966 return 0;
00967 }
00968 return 0;
00969 }
00970
00971 int rpmdbCloseDBI(rpmdb db, int rpmtag)
00972 {
00973 size_t dbix;
00974 int rc = 0;
00975
00976 if (db == NULL || db->_dbi == NULL)
00977 return 0;
00978
00979 if (db->db_tags != NULL)
00980 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
00981 if (db->db_tags[dbix].tag != rpmtag)
00982 continue;
00983 if (db->_dbi[dbix] != NULL) {
00984 int xx;
00985
00986 xx = dbiClose(db->_dbi[dbix], 0);
00987 if (xx && rc == 0) rc = xx;
00988 db->_dbi[dbix] = NULL;
00989
00990 }
00991 break;
00992 }
00993 return rc;
00994 }
00995
00996
00997
00998 int rpmdbClose(rpmdb db)
00999
01000
01001 {
01002 rpmdb * prev, next;
01003 size_t dbix;
01004 int rc = 0;
01005
01006 if (db == NULL)
01007 goto exit;
01008
01009 (void) rpmdbUnlink(db, "rpmdbClose");
01010
01011
01012 if (db->nrefs > 0)
01013 goto exit;
01014
01015 if (db->_dbi)
01016 for (dbix = db->db_ndbi; dbix;) {
01017 int xx;
01018 dbix--;
01019 if (db->_dbi[dbix] == NULL)
01020 continue;
01021
01022 xx = dbiClose(db->_dbi[dbix], 0);
01023 if (xx && rc == 0) rc = xx;
01024 db->_dbi[dbix] = NULL;
01025
01026 }
01027 db->db_errpfx = _free(db->db_errpfx);
01028 db->db_root = _free(db->db_root);
01029 db->db_home = _free(db->db_home);
01030 db->db_bits = PBM_FREE(db->db_bits);
01031 db->db_tags = tagStoreFree(db->db_tags, db->db_ndbi);
01032 db->_dbi = _free(db->_dbi);
01033 db->db_ndbi = 0;
01034
01035
01036 prev = &rpmdbRock;
01037 while ((next = *prev) != NULL && next != db)
01038 prev = &next->db_next;
01039 if (next) {
01040 *prev = next->db_next;
01041 next->db_next = NULL;
01042 }
01043
01044
01045 db = _free(db);
01046
01047
01048 exit:
01049 (void) rpmsqEnable(-SIGHUP, NULL);
01050 (void) rpmsqEnable(-SIGINT, NULL);
01051 (void) rpmsqEnable(-SIGTERM,NULL);
01052 (void) rpmsqEnable(-SIGQUIT,NULL);
01053 (void) rpmsqEnable(-SIGPIPE,NULL);
01054 return rc;
01055 }
01056
01057
01058 int rpmdbSync(rpmdb db)
01059 {
01060 size_t dbix;
01061 int rc = 0;
01062
01063 if (db == NULL) return 0;
01064 if (db->_dbi != NULL)
01065 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
01066 int xx;
01067 if (db->_dbi[dbix] == NULL)
01068 continue;
01069 if (db->_dbi[dbix]->dbi_no_dbsync)
01070 continue;
01071 xx = dbiSync(db->_dbi[dbix], 0);
01072 if (xx && rc == 0) rc = xx;
01073 }
01074 return rc;
01075 }
01076
01082 static const char * rpmdbURIPath(const char *uri)
01083
01084
01085 {
01086 const char * s = rpmGetPath(uri, NULL);
01087 const char * fn = NULL;
01088 urltype ut = urlPath(s, &fn);
01089
01090 switch (ut) {
01091 case URL_IS_PATH:
01092 case URL_IS_UNKNOWN:
01093 fn = s;
01094 s = NULL;
01095 break;
01096 case URL_IS_HTTPS:
01097 case URL_IS_HTTP:
01098 case URL_IS_FTP:
01099 case URL_IS_HKP:
01100 case URL_IS_DASH:
01101 default:
01102
01103 fn = rpmGetPath(fn, NULL);
01104 break;
01105 }
01106
01107
01108 if (ut != URL_IS_PATH)
01109 if (fn && *fn && *fn != '/') {
01110 char dn[PATH_MAX];
01111 char *t;
01112 dn[0] = '\0';
01113 if ((t = realpath(".", dn)) != NULL) {
01114 t += strlen(dn);
01115 if (t > dn && t[-1] != '/')
01116 *t++ = '/';
01117 t = stpncpy(t, fn, (sizeof(dn) - (t - dn)));
01118 *t = '\0';
01119 fn = _free(fn);
01120 fn = rpmGetPath(dn, NULL);
01121 }
01122 }
01123
01124 s = _free(s);
01125 assert(fn != NULL);
01126 return fn;
01127 }
01128
01129
01130
01131
01132 rpmdb rpmdbNew( const char * root,
01133 const char * home,
01134 int mode, int perms, int flags)
01135
01136
01137 {
01138 rpmdb db = xcalloc(sizeof(*db), 1);
01139 const char * epfx = _DB_ERRPFX;
01140 static int oneshot = 0;
01141
01142
01143 if (_rpmdb_debug)
01144 fprintf(stderr, "==> rpmdbNew(%s, %s, 0x%x, 0%o, 0x%x) db %p\n", root, home, mode, perms, flags, db);
01145
01146
01147 if (!oneshot) {
01148 _db_filter_dups = rpmExpandNumeric("%{_filterdbdups}");
01149 oneshot = 1;
01150 }
01151
01152
01153 *db = dbTemplate;
01154
01155
01156 db->_dbi = NULL;
01157
01158 if (!(perms & 0600)) perms = 0644;
01159
01160 if (mode >= 0) db->db_mode = mode;
01161 if (perms >= 0) db->db_perms = perms;
01162 if (flags >= 0) db->db_flags = flags;
01163
01164 db->db_root = rpmdbURIPath( (root && *root ? root : _DB_ROOT) );
01165 db->db_home = rpmdbURIPath( (home && *home ? home : _DB_HOME) );
01166
01167 if (!(db->db_home && db->db_home[0])) {
01168 rpmlog(RPMLOG_ERR, _("no dbpath has been set\n"));
01169 db->db_root = _free(db->db_root);
01170 db->db_home = _free(db->db_home);
01171 db = _free(db);
01172 return NULL;
01173 }
01174
01175 db->db_export = rpmdbExportInfo;
01176 db->db_errpfx = rpmExpand( (epfx && *epfx ? epfx : _DB_ERRPFX), NULL);
01177 db->db_remove_env = 0;
01178 db->db_filter_dups = _db_filter_dups;
01179 dbiTagsInit(&db->db_tags, &db->db_ndbi);
01180 db->_dbi = xcalloc(db->db_ndbi, sizeof(*db->_dbi));
01181 db->nrefs = 0;
01182
01183 return rpmdbLink(db, "rpmdbCreate");
01184
01185 }
01186
01187
01188
01189
01190 int rpmdbOpenDatabase( const char * prefix,
01191 const char * dbpath,
01192 int _dbapi, rpmdb *dbp,
01193 int mode, int perms, int flags)
01194
01195
01196
01197
01198 {
01199 rpmdb db;
01200 int rc, xx;
01201 int justCheck = flags & RPMDB_FLAG_JUSTCHECK;
01202 int minimal = flags & RPMDB_FLAG_MINIMAL;
01203
01204
01205 if (_dbapi < -1 || _dbapi > 4)
01206 _dbapi = -1;
01207 if (_dbapi == 0)
01208 _dbapi = 1;
01209
01210 if (dbp)
01211 *dbp = NULL;
01212 if (mode & O_WRONLY)
01213 return 1;
01214
01215 db = rpmdbNew(prefix, dbpath, mode, perms, flags);
01216 if (db == NULL)
01217 return 1;
01218
01219 (void) rpmsqEnable(SIGHUP, NULL);
01220 (void) rpmsqEnable(SIGINT, NULL);
01221 (void) rpmsqEnable(SIGTERM, NULL);
01222 (void) rpmsqEnable(SIGQUIT, NULL);
01223 (void) rpmsqEnable(SIGPIPE, NULL);
01224
01225 db->db_api = _dbapi;
01226
01227 { size_t dbix;
01228
01229 rc = 0;
01230 if (db->db_tags != NULL)
01231 for (dbix = 0; rc == 0 && dbix < db->db_ndbi; dbix++) {
01232 tagStore_t dbiTag = db->db_tags + dbix;
01233 rpmTag rpmtag = dbiTag->tag;
01234 dbiIndex dbi;
01235
01236
01237 switch (rpmtag) {
01238 case RPMDBI_AVAILABLE:
01239 case RPMDBI_ADDED:
01240 case RPMDBI_REMOVED:
01241 case RPMDBI_DEPENDS:
01242 continue;
01243 break;
01244 default:
01245 break;
01246 }
01247
01248 dbi = dbiOpen(db, rpmtag, 0);
01249 if (dbi == NULL) {
01250 rc = -2;
01251 break;
01252 }
01253
01254 switch (rpmtag) {
01255 case RPMDBI_PACKAGES:
01256 if (dbi == NULL) rc |= 1;
01257 #if 0
01258
01259 if (db->db_api == 3)
01260 #endif
01261 goto exit;
01262 break;
01263 case RPMTAG_NAME:
01264 if (dbi == NULL) rc |= 1;
01265 if (minimal)
01266 goto exit;
01267 break;
01268 default:
01269 break;
01270 }
01271 }
01272 }
01273
01274 exit:
01275 if (rc || justCheck || dbp == NULL)
01276 xx = rpmdbClose(db);
01277 else {
01278
01279 db->db_next = rpmdbRock;
01280 rpmdbRock = db;
01281 *dbp = db;
01282
01283 }
01284
01285 return rc;
01286 }
01287
01288
01289 rpmdb XrpmdbUnlink(rpmdb db, const char * msg, const char * fn, unsigned ln)
01290 {
01291
01292 if (_rpmdb_debug)
01293 fprintf(stderr, "--> db %p -- %d %s at %s:%u\n", db, db->nrefs, msg, fn, ln);
01294
01295 db->nrefs--;
01296 return NULL;
01297 }
01298
01299 rpmdb XrpmdbLink(rpmdb db, const char * msg, const char * fn, unsigned ln)
01300 {
01301 db->nrefs++;
01302
01303 if (_rpmdb_debug)
01304 fprintf(stderr, "--> db %p ++ %d %s at %s:%u\n", db, db->nrefs, msg, fn, ln);
01305
01306 return db;
01307 }
01308
01309
01310 int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, int perms)
01311 {
01312 int _dbapi = rpmExpandNumeric("%{_dbapi}");
01313 return rpmdbOpenDatabase(prefix, NULL, _dbapi, dbp, mode, perms, 0);
01314 }
01315
01316 int rpmdbInit (const char * prefix, int perms)
01317 {
01318 int rc = -1;
01319 #ifdef SUPPORT_INITDB
01320 rpmdb db = NULL;
01321 int _dbapi = rpmExpandNumeric("%{_dbapi}");
01322
01323 rc = rpmdbOpenDatabase(prefix, NULL, _dbapi, &db, (O_CREAT | O_RDWR),
01324 perms, RPMDB_FLAG_JUSTCHECK);
01325 if (db != NULL) {
01326 int xx;
01327 xx = rpmdbOpenAll(db);
01328 if (xx && rc == 0) rc = xx;
01329 xx = rpmdbClose(db);
01330 if (xx && rc == 0) rc = xx;
01331 db = NULL;
01332 }
01333 #endif
01334 return rc;
01335 }
01336
01337 int rpmdbVerifyAllDBI(rpmdb db)
01338 {
01339 int rc = -1;
01340
01341 #if defined(SUPPORT_VERIFYDB)
01342 if (db != NULL) {
01343 size_t dbix;
01344 int xx;
01345 rc = rpmdbOpenAll(db);
01346
01347 if (db->_dbi != NULL)
01348 for (dbix = db->db_ndbi; dbix;) {
01349 dbix--;
01350 if (db->_dbi[dbix] == NULL)
01351 continue;
01352
01353 xx = dbiVerify(db->_dbi[dbix], 0);
01354 if (xx && rc == 0) rc = xx;
01355 db->_dbi[dbix] = NULL;
01356
01357 }
01358
01359
01360 xx = rpmdbClose(db);
01361
01362 if (xx && rc == 0) rc = xx;
01363 db = NULL;
01364 }
01365 #endif
01366 return rc;
01367 }
01368
01369 int rpmdbVerify(const char * prefix)
01370 {
01371 int rc = -1;
01372 #if defined(SUPPORT_VERIFYDB)
01373 rpmdb db = NULL;
01374 int _dbapi = rpmExpandNumeric("%{_dbapi}");
01375
01376 rc = rpmdbOpenDatabase(prefix, NULL, _dbapi, &db, O_RDONLY, 0644, 0);
01377 if (!rc && db != NULL)
01378 rc = rpmdbVerifyAllDBI(db);
01379 #endif
01380 return rc;
01381 }
01382
01388 static inline unsigned taghash(const char * s)
01389
01390 {
01391 unsigned int r = 0;
01392 int c;
01393 while ((c = (int) *s++) != 0) {
01394
01395 if (c != (int) '/')
01396 r += (r << 3) + c;
01397 }
01398 return ((r & 0x7fff) | 0x8000) << 16;
01399 }
01400
01410 static int rpmdbFindByFile(rpmdb db, const char * filespec,
01411 DBT * key, DBT * data, dbiIndexSet * matches)
01412
01413
01414
01415
01416 {
01417 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01418 const char * dirName;
01419 const char * baseName;
01420 fingerPrintCache fpc;
01421 fingerPrint fp1;
01422 dbiIndex dbi = NULL;
01423 DBC * dbcursor;
01424 dbiIndexSet allMatches = NULL;
01425 dbiIndexItem rec = NULL;
01426 int i;
01427 int rc;
01428 int xx;
01429
01430 *matches = NULL;
01431 if (filespec == NULL) return -2;
01432
01433 if ((baseName = strrchr(filespec, '/')) != NULL) {
01434 char * t;
01435 size_t len;
01436
01437 len = baseName - filespec + 1;
01438 t = strncpy(alloca(len + 1), filespec, len);
01439 t[len] = '\0';
01440 dirName = t;
01441 baseName++;
01442 } else {
01443 dirName = "";
01444 baseName = filespec;
01445 }
01446 if (baseName == NULL)
01447 return -2;
01448
01449 fpc = fpCacheCreate(20);
01450 fp1 = fpLookup(fpc, dirName, baseName, 1);
01451
01452 dbi = dbiOpen(db, RPMTAG_BASENAMES, 0);
01453 if (dbi != NULL) {
01454 dbcursor = NULL;
01455 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
01456
01457
01458 key->data = (void *) baseName;
01459
01460 key->size = (u_int32_t) strlen(baseName);
01461 if (key->size == 0) key->size++;
01462
01463 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
01464 if (rc > 0) {
01465 rpmlog(RPMLOG_ERR,
01466 _("error(%d) getting \"%s\" records from %s index\n"),
01467 rc, key->data, tagName(dbi->dbi_rpmtag));
01468 }
01469
01470 if (rc == 0)
01471 (void) dbt2set(dbi, data, &allMatches);
01472
01473
01474 if (_db_tagged_file_indices && allMatches != NULL)
01475 for (i = 0; i < allMatches->count; i++) {
01476 if (allMatches->recs[i].tagNum & 0x80000000)
01477 allMatches->recs[i].tagNum &= 0x0000ffff;
01478 }
01479
01480 xx = dbiCclose(dbi, dbcursor, 0);
01481 dbcursor = NULL;
01482 } else
01483 rc = -2;
01484
01485 if (rc) {
01486 allMatches = dbiFreeIndexSet(allMatches);
01487 fpc = fpCacheFree(fpc);
01488 return rc;
01489 }
01490
01491 *matches = xcalloc(1, sizeof(**matches));
01492 rec = dbiIndexNewItem(0, 0);
01493 i = 0;
01494 if (allMatches != NULL)
01495 while (i < allMatches->count) {
01496 const char ** baseNames;
01497 const char ** dirNames;
01498 uint32_t * dirIndexes;
01499 unsigned int offset = dbiIndexRecordOffset(allMatches, i);
01500 unsigned int prevoff;
01501 Header h;
01502
01503 { rpmdbMatchIterator mi;
01504 mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &offset, sizeof(offset));
01505 h = rpmdbNextIterator(mi);
01506 if (h)
01507 h = headerLink(h);
01508 mi = rpmdbFreeIterator(mi);
01509 }
01510
01511 if (h == NULL) {
01512 i++;
01513 continue;
01514 }
01515
01516 he->tag = RPMTAG_BASENAMES;
01517 xx = headerGet(h, he, 0);
01518 baseNames = he->p.argv;
01519 he->tag = RPMTAG_DIRNAMES;
01520 xx = headerGet(h, he, 0);
01521 dirNames = he->p.argv;
01522 he->tag = RPMTAG_DIRINDEXES;
01523 xx = headerGet(h, he, 0);
01524 dirIndexes = he->p.ui32p;
01525
01526 do {
01527 fingerPrint fp2;
01528 int num = dbiIndexRecordFileNumber(allMatches, i);
01529
01530 fp2 = fpLookup(fpc, dirNames[dirIndexes[num]], baseNames[num], 1);
01531
01532 if (FP_EQUAL(fp1, fp2)) {
01533
01534 rec->hdrNum = dbiIndexRecordOffset(allMatches, i);
01535 rec->tagNum = dbiIndexRecordFileNumber(allMatches, i);
01536 xx = dbiAppendSet(*matches, rec, 1, sizeof(*rec), 0);
01537 }
01538
01539 prevoff = offset;
01540 i++;
01541 if (i < allMatches->count)
01542 offset = dbiIndexRecordOffset(allMatches, i);
01543 } while (i < allMatches->count && offset == prevoff);
01544
01545 baseNames = _free(baseNames);
01546
01547 dirNames = _free(dirNames);
01548
01549 dirIndexes = _free(dirIndexes);
01550 h = headerFree(h);
01551 }
01552
01553 rec = _free(rec);
01554 allMatches = dbiFreeIndexSet(allMatches);
01555
01556 fpc = fpCacheFree(fpc);
01557
01558 if ((*matches)->count == 0) {
01559 *matches = dbiFreeIndexSet(*matches);
01560 return 1;
01561 }
01562
01563 return 0;
01564 }
01565
01566
01567 int rpmdbCountPackages(rpmdb db, const char * name)
01568 {
01569 DBC * dbcursor = NULL;
01570 DBT * key = alloca(sizeof(*key));
01571 DBT * data = alloca(sizeof(*data));
01572 dbiIndex dbi;
01573 int rc;
01574 int xx;
01575
01576 if (db == NULL)
01577 return 0;
01578
01579 memset(key, 0, sizeof(*key));
01580 memset(data, 0, sizeof(*data));
01581
01582 dbi = dbiOpen(db, RPMTAG_NAME, 0);
01583 if (dbi == NULL)
01584 return 0;
01585
01586
01587 key->data = (void *) name;
01588
01589 key->size = (u_int32_t) strlen(name);
01590
01591 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
01592 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
01593 #ifndef SQLITE_HACK
01594 xx = dbiCclose(dbi, dbcursor, 0);
01595 dbcursor = NULL;
01596 #endif
01597
01598 if (rc == 0) {
01599 dbiIndexSet matches;
01600
01601 matches = NULL;
01602 (void) dbt2set(dbi, data, &matches);
01603 if (matches) {
01604 rc = dbiIndexSetCount(matches);
01605 matches = dbiFreeIndexSet(matches);
01606 }
01607
01608 } else
01609 if (rc == DB_NOTFOUND) {
01610 rc = 0;
01611 } else {
01612 rpmlog(RPMLOG_ERR,
01613 _("error(%d) getting \"%s\" records from %s index\n"),
01614 rc, key->data, tagName(dbi->dbi_rpmtag));
01615 rc = -1;
01616 }
01617
01618 #ifdef SQLITE_HACK
01619 xx = dbiCclose(dbi, dbcursor, 0);
01620 dbcursor = NULL;
01621 #endif
01622
01623 return rc;
01624 }
01625
01638 static rpmRC dbiFindMatches(dbiIndex dbi, DBC * dbcursor,
01639 DBT * key, DBT * data,
01640 const char * name,
01641 const char * version,
01642 const char * release,
01643 dbiIndexSet * matches)
01644
01645
01646
01647
01648 {
01649 int gotMatches = 0;
01650 int rc;
01651 int i;
01652
01653
01654 key->data = (void *) name;
01655
01656 key->size = (u_int32_t) strlen(name);
01657
01658 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
01659
01660 if (rc == 0) {
01661 (void) dbt2set(dbi, data, matches);
01662 if (version == NULL && release == NULL)
01663 return RPMRC_OK;
01664 } else
01665 if (rc == DB_NOTFOUND) {
01666 return RPMRC_NOTFOUND;
01667 } else {
01668 rpmlog(RPMLOG_ERR,
01669 _("error(%d) getting \"%s\" records from %s index\n"),
01670 rc, key->data, tagName(dbi->dbi_rpmtag));
01671 return RPMRC_FAIL;
01672 }
01673
01674
01675 for (i = 0; i < dbiIndexSetCount(*matches); i++) {
01676 unsigned int recoff = dbiIndexRecordOffset(*matches, i);
01677 rpmdbMatchIterator mi;
01678 Header h;
01679
01680 if (recoff == 0)
01681 continue;
01682
01683 mi = rpmdbInitIterator(dbi->dbi_rpmdb,
01684 RPMDBI_PACKAGES, &recoff, sizeof(recoff));
01685
01686
01687 if (version &&
01688 rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version))
01689 {
01690 rc = RPMRC_FAIL;
01691 goto exit;
01692 }
01693 if (release &&
01694 rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release))
01695 {
01696 rc = RPMRC_FAIL;
01697 goto exit;
01698 }
01699
01700 h = rpmdbNextIterator(mi);
01701 if (h)
01702 (*matches)->recs[gotMatches++] = (*matches)->recs[i];
01703 else
01704 (*matches)->recs[i].hdrNum = 0;
01705 mi = rpmdbFreeIterator(mi);
01706 }
01707
01708 if (gotMatches) {
01709 (*matches)->count = gotMatches;
01710 rc = RPMRC_OK;
01711 } else
01712 rc = RPMRC_NOTFOUND;
01713
01714 exit:
01715
01716 if (rc && matches && *matches)
01717 *matches = dbiFreeIndexSet(*matches);
01718
01719 return rc;
01720 }
01721
01734 static rpmRC dbiFindByLabel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
01735 const char * arg, dbiIndexSet * matches)
01736
01737
01738
01739
01740 {
01741 const char * release;
01742 char * localarg;
01743 char * s;
01744 char c;
01745 int brackets;
01746 rpmRC rc;
01747
01748 if (arg == NULL || strlen(arg) == 0) return RPMRC_NOTFOUND;
01749
01750
01751 rc = dbiFindMatches(dbi, dbcursor, key, data, arg, NULL, NULL, matches);
01752 if (rc != RPMRC_NOTFOUND) return rc;
01753
01754
01755 *matches = dbiFreeIndexSet(*matches);
01756
01757
01758
01759 localarg = alloca(strlen(arg) + 1);
01760 s = stpcpy(localarg, arg);
01761
01762 c = '\0';
01763 brackets = 0;
01764 for (s -= 1; s > localarg; s--) {
01765 switch (*s) {
01766 case '[':
01767 brackets = 1;
01768 break;
01769 case ']':
01770 if (c != '[') brackets = 0;
01771 break;
01772 }
01773 c = *s;
01774 if (!brackets && *s == '-')
01775 break;
01776 }
01777
01778
01779 if (s == localarg) return RPMRC_NOTFOUND;
01780
01781 *s = '\0';
01782 rc = dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, NULL, matches);
01783
01784 if (rc != RPMRC_NOTFOUND) return rc;
01785
01786
01787 *matches = dbiFreeIndexSet(*matches);
01788
01789
01790
01791
01792 release = s + 1;
01793
01794 c = '\0';
01795 brackets = 0;
01796 for (; s > localarg; s--) {
01797 switch (*s) {
01798 case '[':
01799 brackets = 1;
01800 break;
01801 case ']':
01802 if (c != '[') brackets = 0;
01803 break;
01804 }
01805 c = *s;
01806 if (!brackets && *s == '-')
01807 break;
01808 }
01809
01810 if (s == localarg) return RPMRC_NOTFOUND;
01811
01812 *s = '\0';
01813
01814 return dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, release, matches);
01815
01816 }
01817
01818 void * dbiStatsAccumulator(dbiIndex dbi, int opx)
01819 {
01820 void * sw = NULL;
01821 switch (opx) {
01822 case 14:
01823 sw = &dbi->dbi_rpmdb->db_getops;
01824 break;
01825 case 15:
01826 sw = &dbi->dbi_rpmdb->db_putops;
01827 break;
01828 default:
01829 case 16:
01830 sw = &dbi->dbi_rpmdb->db_delops;
01831 break;
01832 }
01833 return sw;
01834 }
01835
01844 static int miFreeHeader(rpmdbMatchIterator mi, dbiIndex dbi)
01845
01846
01847 {
01848 int rc = 0;
01849
01850 if (mi == NULL || mi->mi_h == NULL)
01851 return 0;
01852
01853 if (dbi && mi->mi_dbc && mi->mi_modified && mi->mi_prevoffset) {
01854 DBT * key = &mi->mi_key;
01855 DBT * data = &mi->mi_data;
01856 sigset_t signalMask;
01857 rpmRC rpmrc = RPMRC_NOTFOUND;
01858 size_t nb = 0;
01859 int xx;
01860
01861 (void) headerGetMagic(mi->mi_h, NULL, &nb);
01862 key->data = (void *) &mi->mi_prevoffset;
01863 key->size = (u_int32_t) sizeof(mi->mi_prevoffset);
01864 { size_t len;
01865 len = 0;
01866 data->data = headerUnload(mi->mi_h, &len);
01867 data->size = (u_int32_t) len;
01868 #ifdef DYING
01869 data->size -= nb;
01870 #endif
01871 }
01872
01873
01874 if (mi->mi_ts) {
01875 const char * msg = NULL;
01876 int lvl;
01877
01878 assert(data->data != NULL);
01879 rpmrc = headerCheck(rpmtsDig(mi->mi_ts), data->data, data->size, &msg);
01880 rpmtsCleanDig(mi->mi_ts);
01881 lvl = (rpmrc == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG);
01882 rpmlog(lvl, "%s h#%8u %s",
01883 (rpmrc == RPMRC_FAIL ? _("miFreeHeader: skipping") : "write"),
01884 mi->mi_prevoffset, (msg ? msg : "\n"));
01885 msg = _free(msg);
01886 }
01887
01888 if (data->data != NULL && rpmrc != RPMRC_FAIL) {
01889 (void) blockSignals(dbi->dbi_rpmdb, &signalMask);
01890 rc = dbiPut(dbi, mi->mi_dbc, key, data, DB_KEYLAST);
01891 if (rc) {
01892 rpmlog(RPMLOG_ERR,
01893 _("error(%d) storing record #%d into %s\n"),
01894 rc, mi->mi_prevoffset, tagName(dbi->dbi_rpmtag));
01895 }
01896 xx = dbiSync(dbi, 0);
01897 (void) unblockSignals(dbi->dbi_rpmdb, &signalMask);
01898 }
01899 data->data = _free(data->data);
01900 data->size = 0;
01901 }
01902
01903 mi->mi_h = headerFree(mi->mi_h);
01904
01905
01906 return rc;
01907
01908 }
01909
01910 rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi)
01911
01912
01913 {
01914 rpmdbMatchIterator * prev, next;
01915 dbiIndex dbi;
01916 int xx;
01917 int i;
01918
01919 if (mi == NULL)
01920 return NULL;
01921
01922 prev = &rpmmiRock;
01923 while ((next = *prev) != NULL && next != mi)
01924 prev = &next->mi_next;
01925 if (next) {
01926 *prev = next->mi_next;
01927 next->mi_next = NULL;
01928 }
01929
01930 dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0);
01931 if (dbi == NULL)
01932 return NULL;
01933
01934 xx = miFreeHeader(mi, dbi);
01935
01936 if (mi->mi_dbc)
01937 xx = dbiCclose(dbi, mi->mi_dbc, 0);
01938 mi->mi_dbc = NULL;
01939
01940 if (mi->mi_re != NULL)
01941 for (i = 0; i < mi->mi_nre; i++)
01942 xx = mireClean(mi->mi_re + i);
01943 mi->mi_re = _free(mi->mi_re);
01944
01945 mi->mi_set = dbiFreeIndexSet(mi->mi_set);
01946 mi->mi_keyp = _free(mi->mi_keyp);
01947 mi->mi_db = rpmdbUnlink(mi->mi_db, "matchIterator");
01948
01949 mi = _free(mi);
01950
01951 (void) rpmdbCheckSignals();
01952
01953 return mi;
01954 }
01955
01956 unsigned int rpmdbGetIteratorOffset(rpmdbMatchIterator mi) {
01957 return (mi ? mi->mi_offset : 0);
01958 }
01959
01960 unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi) {
01961 return (mi ? mi->mi_filenum : 0);
01962 }
01963
01964 int rpmdbGetIteratorCount(rpmdbMatchIterator mi) {
01965 return (mi && mi->mi_set ? mi->mi_set->count : 0);
01966 }
01967
01974 static int mireCmp(const void * a, const void * b)
01975 {
01976
01977 const miRE mireA = (const miRE) a;
01978 const miRE mireB = (const miRE) b;
01979
01980 return (mireA->tag - mireB->tag);
01981 }
01982
01990 static char * mireDup(rpmTag tag, rpmMireMode *modep,
01991 const char * pattern)
01992
01993
01994 {
01995 const char * s;
01996 char * pat;
01997 char * t;
01998 int brackets;
01999 size_t nb;
02000 int c;
02001
02002 switch (*modep) {
02003 default:
02004 case RPMMIRE_DEFAULT:
02005 if (tag == RPMTAG_DIRNAMES || tag == RPMTAG_BASENAMES) {
02006 *modep = RPMMIRE_GLOB;
02007 pat = xstrdup(pattern);
02008 break;
02009 }
02010
02011 nb = strlen(pattern) + sizeof("^$");
02012
02013
02014
02015 c = (int) '\0';
02016 brackets = 0;
02017 for (s = pattern; *s != '\0'; s++) {
02018 switch (*s) {
02019 case '.':
02020 case '+':
02021 case '*':
02022 if (!brackets) nb++;
02023 break;
02024 case '\\':
02025 s++;
02026 break;
02027 case '[':
02028 brackets = 1;
02029 break;
02030 case ']':
02031 if (c != (int) '[') brackets = 0;
02032 break;
02033 }
02034 c = (int) *s;
02035 }
02036
02037 pat = t = xmalloc(nb);
02038
02039 if (pattern[0] != '^') *t++ = '^';
02040
02041
02042 c = (int) '\0';
02043 brackets = 0;
02044 for (s = pattern; *s != '\0'; s++, t++) {
02045 switch (*s) {
02046 case '.':
02047 case '+':
02048 if (!brackets) *t++ = '\\';
02049 break;
02050 case '*':
02051 if (!brackets) *t++ = '.';
02052 break;
02053 case '\\':
02054 *t++ = *s++;
02055 break;
02056 case '[':
02057 brackets = 1;
02058 break;
02059 case ']':
02060 if (c != (int) '[') brackets = 0;
02061 break;
02062 }
02063 *t = *s;
02064 c = (int) *t;
02065 }
02066
02067 if (s > pattern && s[-1] != '$') *t++ = '$';
02068 *t = '\0';
02069 *modep = RPMMIRE_REGEX;
02070 break;
02071 case RPMMIRE_STRCMP:
02072 case RPMMIRE_REGEX:
02073 case RPMMIRE_GLOB:
02074 pat = xstrdup(pattern);
02075 break;
02076 }
02077
02078 return pat;
02079 }
02080
02081 int rpmdbSetIteratorRE(rpmdbMatchIterator mi, rpmTag tag,
02082 rpmMireMode mode, const char * pattern)
02083 {
02084 static rpmMireMode defmode = (rpmMireMode)-1;
02085 miRE nmire = NULL;
02086 miRE mire = NULL;
02087 const char * allpat = NULL;
02088 int notmatch = 0;
02089 int rc = 0;
02090
02091 if (defmode == (rpmMireMode)-1) {
02092 const char *t = rpmExpand("%{?_query_selector_match}", NULL);
02093
02094 if (*t == '\0' || !strcmp(t, "default"))
02095 defmode = RPMMIRE_DEFAULT;
02096 else if (!strcmp(t, "strcmp"))
02097 defmode = RPMMIRE_STRCMP;
02098 else if (!strcmp(t, "regex"))
02099 defmode = RPMMIRE_REGEX;
02100 else if (!strcmp(t, "glob"))
02101 defmode = RPMMIRE_GLOB;
02102 else
02103 defmode = RPMMIRE_DEFAULT;
02104 t = _free(t);
02105 }
02106
02107 if (mi == NULL || pattern == NULL)
02108 return rc;
02109
02110
02111 if (*pattern == '!') {
02112 notmatch = 1;
02113 pattern++;
02114 }
02115
02116 nmire = mireNew(mode, tag);
02117 assert(nmire != NULL);
02118 allpat = mireDup(nmire->tag, &nmire->mode, pattern);
02119
02120 if (nmire->mode == RPMMIRE_DEFAULT)
02121 nmire->mode = defmode;
02122
02123 rc = mireRegcomp(nmire, allpat);
02124 if (rc)
02125 goto exit;
02126
02127 mi->mi_re = xrealloc(mi->mi_re, (mi->mi_nre + 1) * sizeof(*mi->mi_re));
02128 mire = mi->mi_re + mi->mi_nre;
02129 mi->mi_nre++;
02130
02131 mire->mode = nmire->mode;
02132 mire->pattern = nmire->pattern; nmire->pattern = NULL;
02133 mire->preg = nmire->preg; nmire->preg = NULL;
02134 mire->cflags = nmire->cflags;
02135 mire->eflags = nmire->eflags;
02136 mire->fnflags = nmire->fnflags;
02137 mire->tag = nmire->tag;
02138 mire->notmatch = notmatch;
02139
02140 if (mi->mi_nre > 1)
02141 qsort(mi->mi_re, mi->mi_nre, sizeof(*mi->mi_re), mireCmp);
02142
02143 exit:
02144 allpat = _free(allpat);
02145 nmire = mireFree(nmire);
02146 return rc;
02147 }
02148
02154
02155 static int mireSkip (const rpmdbMatchIterator mi)
02156
02157 {
02158 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
02159 char numbuf[32];
02160 miRE mire;
02161 int ntags = 0;
02162 int nmatches = 0;
02163 int i;
02164 int rc;
02165
02166 if (mi->mi_h == NULL)
02167 return 1;
02168
02169
02170
02171
02172
02173 if ((mire = mi->mi_re) == NULL)
02174 return 0;
02175
02176 for (i = 0; i < mi->mi_nre; i++, mire++) {
02177 int anymatch;
02178
02179 he->tag = mire->tag;
02180
02181 if (!headerGet(mi->mi_h, he, 0)) {
02182 if (he->tag != RPMTAG_EPOCH) {
02183 ntags++;
02184 continue;
02185 }
02186 he->t = RPM_UINT32_TYPE;
02187 he->p.ui32p = xcalloc(1, sizeof(*he->p.ui32p));
02188 he->c = 1;
02189 }
02190
02191 anymatch = 0;
02192 while (1) {
02193 unsigned j;
02194 switch (he->t) {
02195 case RPM_UINT8_TYPE:
02196 for (j = 0; j < (unsigned) he->c; j++) {
02197 sprintf(numbuf, "%u", (unsigned) he->p.ui8p[j]);
02198 rc = mireRegexec(mire, numbuf);
02199 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
02200 anymatch++;
02201 }
02202 break;
02203 case RPM_UINT16_TYPE:
02204 for (j = 0; j < (unsigned) he->c; j++) {
02205 sprintf(numbuf, "%u", (unsigned) he->p.ui16p[j]);
02206 rc = mireRegexec(mire, numbuf);
02207 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
02208 anymatch++;
02209 }
02210 break;
02211 case RPM_UINT32_TYPE:
02212 for (j = 0; j < (unsigned) he->c; j++) {
02213 sprintf(numbuf, "%u", (unsigned) he->p.ui32p[j]);
02214 rc = mireRegexec(mire, numbuf);
02215 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
02216 anymatch++;
02217 }
02218 break;
02219 case RPM_UINT64_TYPE:
02220
02221 for (j = 0; j < (unsigned) he->c; j++) {
02222 sprintf(numbuf, "%llu", (unsigned long long)he->p.ui64p[j]);
02223 rc = mireRegexec(mire, numbuf);
02224 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
02225 anymatch++;
02226 }
02227
02228 break;
02229 case RPM_STRING_TYPE:
02230 rc = mireRegexec(mire, he->p.str);
02231 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
02232 anymatch++;
02233 break;
02234 case RPM_STRING_ARRAY_TYPE:
02235 for (j = 0; j < (unsigned) he->c; j++) {
02236 rc = mireRegexec(mire, he->p.argv[j]);
02237 if ((!rc && !mire->notmatch) || (rc && mire->notmatch)) {
02238 anymatch++;
02239 break;
02240 }
02241 }
02242 break;
02243 case RPM_BIN_TYPE:
02244 { const char * s = bin2hex(he->p.ptr, he->c);
02245 rc = mireRegexec(mire, s);
02246 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
02247 anymatch++;
02248 s = _free(s);
02249 } break;
02250 case RPM_I18NSTRING_TYPE:
02251 default:
02252 break;
02253 }
02254 if ((i+1) < mi->mi_nre && mire[0].tag == mire[1].tag) {
02255 i++;
02256 mire++;
02257 continue;
02258 }
02259 break;
02260 }
02261
02262 he->p.ptr = _free(he->p.ptr);
02263
02264 if (anymatch)
02265 nmatches++;
02266 ntags++;
02267 }
02268
02269 return (ntags > 0 && ntags == nmatches ? 0 : 1);
02270 }
02271
02272
02273 int rpmdbSetIteratorRewrite(rpmdbMatchIterator mi, int rewrite)
02274 {
02275 int rc;
02276 if (mi == NULL)
02277 return 0;
02278 rc = (mi->mi_cflags & DB_WRITECURSOR) ? 1 : 0;
02279 if (rewrite)
02280 mi->mi_cflags |= DB_WRITECURSOR;
02281 else
02282 mi->mi_cflags &= ~DB_WRITECURSOR;
02283 return rc;
02284 }
02285
02286 int rpmdbSetIteratorModified(rpmdbMatchIterator mi, int modified)
02287 {
02288 int rc;
02289 if (mi == NULL)
02290 return 0;
02291 rc = mi->mi_modified;
02292 mi->mi_modified = modified;
02293 return rc;
02294 }
02295
02296 int rpmdbSetHdrChk(rpmdbMatchIterator mi, rpmts ts)
02297 {
02298 int rc = 0;
02299 if (mi == NULL)
02300 return 0;
02301
02302 mi->mi_ts = ts;
02303
02304 return rc;
02305 }
02306
02307
02308
02309 Header rpmdbNextIterator(rpmdbMatchIterator mi)
02310 {
02311 dbiIndex dbi;
02312 void * uh;
02313 size_t uhlen;
02314 DBT * key;
02315 DBT * data;
02316 void * keyp;
02317 size_t keylen;
02318 int rc;
02319 int xx;
02320
02321 if (mi == NULL)
02322 return NULL;
02323
02324 dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0);
02325 if (dbi == NULL)
02326 return NULL;
02327
02328
02329
02330
02331
02332
02333
02334 if (mi->mi_dbc == NULL)
02335 xx = dbiCopen(dbi, dbi->dbi_txnid, &mi->mi_dbc, mi->mi_cflags);
02336
02337 key = &mi->mi_key;
02338 memset(key, 0, sizeof(*key));
02339 data = &mi->mi_data;
02340 memset(data, 0, sizeof(*data));
02341
02342 top:
02343 uh = NULL;
02344 uhlen = 0;
02345
02346 do {
02347 union _dbswap mi_offset;
02348
02349 if (mi->mi_set) {
02350 if (!(mi->mi_setx < mi->mi_set->count))
02351 return NULL;
02352 mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx);
02353 mi->mi_filenum = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx);
02354 mi_offset.ui = mi->mi_offset;
02355 if (dbiByteSwapped(dbi) == 1)
02356 _DBSWAP(mi_offset);
02357 keyp = &mi_offset;
02358 keylen = sizeof(mi_offset.ui);
02359 } else {
02360 key->data = (void *)mi->mi_keyp;
02361 key->size = (u_int32_t) mi->mi_keylen;
02362 data->data = uh;
02363 data->size = (u_int32_t) uhlen;
02364 #if !defined(_USE_COPY_LOAD)
02365 data->flags |= DB_DBT_MALLOC;
02366 #endif
02367 rc = dbiGet(dbi, mi->mi_dbc, key, data,
02368 (key->data == NULL ? DB_NEXT : DB_SET));
02369 data->flags = 0;
02370 keyp = key->data;
02371 keylen = key->size;
02372 uh = data->data;
02373 uhlen = data->size;
02374
02375
02376
02377
02378
02379
02380
02381
02382 if (keyp && mi->mi_setx && rc == 0) {
02383 memcpy(&mi_offset, keyp, sizeof(mi_offset.ui));
02384 if (dbiByteSwapped(dbi) == 1)
02385 _DBSWAP(mi_offset);
02386 mi->mi_offset = (unsigned) mi_offset.ui;
02387 }
02388
02389
02390
02391 if (rc || (mi->mi_setx && mi->mi_offset == 0))
02392 return NULL;
02393
02394 }
02395 mi->mi_setx++;
02396 } while (mi->mi_offset == 0);
02397
02398
02399
02400 if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset)
02401 return mi->mi_h;
02402
02403
02404
02405 if (uh == NULL) {
02406 key->data = keyp;
02407 key->size = (u_int32_t) keylen;
02408 #if !defined(_USE_COPY_LOAD)
02409 data->flags |= DB_DBT_MALLOC;
02410 #endif
02411
02412 rc = dbiGet(dbi, mi->mi_dbc, key, data, DB_SET);
02413 data->flags = 0;
02414 keyp = key->data;
02415 keylen = key->size;
02416 uh = data->data;
02417 uhlen = data->size;
02418 if (rc)
02419 return NULL;
02420
02421 }
02422
02423
02424 xx = miFreeHeader(mi, dbi);
02425
02426
02427 if (uh == NULL)
02428 return NULL;
02429
02430
02431 if (mi->mi_ts) {
02432 rpmRC rpmrc = RPMRC_NOTFOUND;
02433
02434
02435 if (mi->mi_db->db_bits) {
02436 pbm_set * set;
02437
02438 set = PBM_REALLOC((pbm_set **)&mi->mi_db->db_bits,
02439 &mi->mi_db->db_nbits, mi->mi_offset);
02440 if (PBM_ISSET(mi->mi_offset, set))
02441 rpmrc = RPMRC_OK;
02442 }
02443
02444
02445 if (rpmrc != RPMRC_OK) {
02446 const char * msg = NULL;
02447 int lvl;
02448
02449 assert(data->data != NULL);
02450 rpmrc = headerCheck(rpmtsDig(mi->mi_ts), uh, uhlen, &msg);
02451 rpmtsCleanDig(mi->mi_ts);
02452 lvl = (rpmrc == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG);
02453 rpmlog(lvl, "%s h#%8u %s\n",
02454 (rpmrc == RPMRC_FAIL ? _("rpmdb: skipping") : _("rpmdb: read")),
02455 mi->mi_offset, (msg ? msg : ""));
02456 msg = _free(msg);
02457
02458
02459 if (mi->mi_db && mi->mi_db->db_bits && rpmrc == RPMRC_OK) {
02460 pbm_set * set;
02461
02462 set = PBM_REALLOC((pbm_set **)&mi->mi_db->db_bits,
02463 &mi->mi_db->db_nbits, mi->mi_offset);
02464 PBM_SET(mi->mi_offset, set);
02465 }
02466
02467
02468 if (rpmrc == RPMRC_FAIL) {
02469
02470 if (mi->mi_set == NULL && mi->mi_keyp != NULL && mi->mi_keylen == 4)
02471 return NULL;
02472 goto top;
02473 }
02474 }
02475 }
02476
02477
02478 #if !defined(_USE_COPY_LOAD)
02479
02480 mi->mi_h = headerLoad(uh);
02481
02482 if (mi->mi_h)
02483 mi->mi_h->flags |= HEADERFLAG_ALLOCATED;
02484 #else
02485 mi->mi_h = headerCopyLoad(uh);
02486 #endif
02487 if (mi->mi_h == NULL || !headerIsEntry(mi->mi_h, RPMTAG_NAME)) {
02488 rpmlog(RPMLOG_ERR,
02489 _("rpmdb: damaged header #%u retrieved -- skipping.\n"),
02490 mi->mi_offset);
02491 goto top;
02492 }
02493
02494
02495
02496
02497 if (mireSkip(mi)) {
02498
02499 if (mi->mi_set || mi->mi_keyp == NULL)
02500 goto top;
02501 return NULL;
02502 }
02503
02504
02505 { char origin[32];
02506 sprintf(origin, "rpmdb (h#%u)", mi->mi_offset);
02507 (void) headerSetOrigin(mi->mi_h, origin);
02508 (void) headerSetInstance(mi->mi_h, mi->mi_offset);
02509 }
02510
02511 mi->mi_prevoffset = mi->mi_offset;
02512 mi->mi_modified = 0;
02513
02514
02515 return mi->mi_h;
02516
02517 }
02518
02519
02520 static void rpmdbSortIterator( rpmdbMatchIterator mi)
02521
02522 {
02523 if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) {
02524
02525
02526
02527
02528 #if defined(__GLIBC__)
02529 qsort(mi->mi_set->recs, mi->mi_set->count,
02530 sizeof(*mi->mi_set->recs), hdrNumCmp);
02531 #else
02532 rpm_mergesort(mi->mi_set->recs, mi->mi_set->count,
02533 sizeof(*mi->mi_set->recs), hdrNumCmp);
02534 #endif
02535 mi->mi_sorted = 1;
02536 }
02537 }
02538
02539 static int rpmdbGrowIterator( rpmdbMatchIterator mi, int fpNum,
02540 unsigned int exclude, unsigned int tag)
02541
02542
02543 {
02544 DBC * dbcursor;
02545 DBT * key;
02546 DBT * data;
02547 dbiIndex dbi = NULL;
02548 dbiIndexSet set;
02549 int rc;
02550 int xx;
02551 int i, j;
02552
02553 if (mi == NULL)
02554 return 1;
02555
02556 dbcursor = mi->mi_dbc;
02557 key = &mi->mi_key;
02558 data = &mi->mi_data;
02559 if (key->data == NULL)
02560 return 1;
02561
02562 dbi = dbiOpen(mi->mi_db, mi->mi_rpmtag, 0);
02563 if (dbi == NULL)
02564 return 1;
02565
02566 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
02567 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
02568 #ifndef SQLITE_HACK
02569 xx = dbiCclose(dbi, dbcursor, 0);
02570 dbcursor = NULL;
02571 #endif
02572
02573 if (rc) {
02574 if (rc != DB_NOTFOUND)
02575 rpmlog(RPMLOG_ERR,
02576 _("error(%d) getting \"%s\" records from %s index\n"),
02577 rc, key->data, tagName(dbi->dbi_rpmtag));
02578 #ifdef SQLITE_HACK
02579 xx = dbiCclose(dbi, dbcursor, 0);
02580 dbcursor = NULL;
02581 #endif
02582 return rc;
02583 }
02584
02585 set = NULL;
02586 (void) dbt2set(dbi, data, &set);
02587
02588
02589 for (i = j = 0; i < set->count; i++) {
02590 if (exclude && set->recs[i].hdrNum == exclude)
02591 continue;
02592 if (_db_tagged_file_indices && set->recs[i].tagNum & 0x80000000) {
02593
02594 if ((set->recs[i].tagNum & 0xffff0000) != tag)
02595 continue;
02596 set->recs[i].tagNum &= 0x0000ffff;
02597 }
02598 if (i > j)
02599 set->recs[j] = set->recs[i];
02600 j++;
02601 }
02602 if (j == 0) {
02603 #ifdef SQLITE_HACK
02604 xx = dbiCclose(dbi, dbcursor, 0);
02605 dbcursor = NULL;
02606 #endif
02607 set = dbiFreeIndexSet(set);
02608 return DB_NOTFOUND;
02609 }
02610 set->count = j;
02611
02612 for (i = 0; i < set->count; i++)
02613 set->recs[i].fpNum = fpNum;
02614
02615 #ifdef SQLITE_HACK
02616 xx = dbiCclose(dbi, dbcursor, 0);
02617 dbcursor = NULL;
02618 #endif
02619
02620 if (mi->mi_set == NULL) {
02621 mi->mi_set = set;
02622 } else {
02623 #if 0
02624 fprintf(stderr, "+++ %d = %d + %d\t\"%s\"\n", (mi->mi_set->count + set->count), mi->mi_set->count, set->count, ((char *)key->data));
02625 #endif
02626 mi->mi_set->recs = xrealloc(mi->mi_set->recs,
02627 (mi->mi_set->count + set->count) * sizeof(*(mi->mi_set->recs)));
02628 memcpy(mi->mi_set->recs + mi->mi_set->count, set->recs,
02629 set->count * sizeof(*(mi->mi_set->recs)));
02630 mi->mi_set->count += set->count;
02631 set = dbiFreeIndexSet(set);
02632 }
02633
02634 return rc;
02635 }
02636
02637 int rpmdbPruneIterator(rpmdbMatchIterator mi, int * hdrNums,
02638 int nHdrNums, int sorted)
02639 {
02640 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
02641 return 1;
02642
02643 if (mi->mi_set)
02644 (void) dbiPruneSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), sorted);
02645 return 0;
02646 }
02647
02648 int rpmdbAppendIterator(rpmdbMatchIterator mi, const int * hdrNums, int nHdrNums)
02649 {
02650 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
02651 return 1;
02652
02653 if (mi->mi_set == NULL)
02654 mi->mi_set = xcalloc(1, sizeof(*mi->mi_set));
02655 (void) dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0);
02656 return 0;
02657 }
02658
02659 rpmdbMatchIterator rpmdbInitIterator(rpmdb db, rpmTag rpmtag,
02660 const void * keyp, size_t keylen)
02661
02662
02663 {
02664 rpmdbMatchIterator mi;
02665 DBT * key;
02666 DBT * data;
02667 dbiIndexSet set = NULL;
02668 dbiIndex dbi;
02669 const void * mi_keyp = NULL;
02670 int isLabel = 0;
02671
02672 if (db == NULL)
02673 return NULL;
02674
02675 (void) rpmdbCheckSignals();
02676
02677
02678 if (rpmtag == RPMDBI_LABEL) {
02679 rpmtag = RPMTAG_NAME;
02680 isLabel = 1;
02681 }
02682
02683 dbi = dbiOpen(db, rpmtag, 0);
02684 if (dbi == NULL)
02685 return NULL;
02686
02687
02688 mi = xcalloc(1, sizeof(*mi));
02689 mi->mi_next = rpmmiRock;
02690 rpmmiRock = mi;
02691
02692 key = &mi->mi_key;
02693 data = &mi->mi_data;
02694
02695
02696
02697
02698
02699 if (rpmtag != RPMDBI_PACKAGES && keyp) {
02700 DBC * dbcursor = NULL;
02701 int rc;
02702 int xx;
02703
02704 if (isLabel) {
02705 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
02706 rc = dbiFindByLabel(dbi, dbcursor, key, data, keyp, &set);
02707 xx = dbiCclose(dbi, dbcursor, 0);
02708 dbcursor = NULL;
02709 } else if (rpmtag == RPMTAG_BASENAMES) {
02710 rc = rpmdbFindByFile(db, keyp, key, data, &set);
02711 } else {
02712 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
02713
02714
02715 key->data = (void *) keyp;
02716
02717 key->size = (u_int32_t) keylen;
02718 if (key->data && key->size == 0) key->size = (u_int32_t) strlen((char *)key->data);
02719 if (key->data && key->size == 0) key->size++;
02720
02721
02722 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
02723
02724 if (rc > 0) {
02725 rpmlog(RPMLOG_ERR,
02726 _("error(%d) getting \"%s\" records from %s index\n"),
02727 rc, (key->data ? key->data : "???"), tagName(dbi->dbi_rpmtag));
02728 }
02729
02730
02731 if (rc == 0)
02732 (void) dbt2set(dbi, data, &set);
02733
02734 xx = dbiCclose(dbi, dbcursor, 0);
02735 dbcursor = NULL;
02736 }
02737 if (rc) {
02738 set = dbiFreeIndexSet(set);
02739 rpmmiRock = mi->mi_next;
02740 mi->mi_next = NULL;
02741 mi = _free(mi);
02742 return NULL;
02743 }
02744 }
02745
02746
02747 if (keyp) {
02748 switch (rpmtag) {
02749 case RPMDBI_PACKAGES:
02750 { union _dbswap *k;
02751
02752 assert(keylen == sizeof(k->ui));
02753 k = xmalloc(sizeof(*k));
02754 memcpy(k, keyp, keylen);
02755 if (dbiByteSwapped(dbi) == 1)
02756 _DBSWAP(*k);
02757 mi_keyp = k;
02758 } break;
02759 default:
02760 { char * k;
02761 if (keylen == 0)
02762 keylen = strlen(keyp);
02763 k = xmalloc(keylen + 1);
02764 memcpy(k, keyp, keylen);
02765 k[keylen] = '\0';
02766 mi_keyp = k;
02767 } break;
02768 }
02769 }
02770
02771 mi->mi_keyp = mi_keyp;
02772 mi->mi_keylen = keylen;
02773
02774 mi->mi_db = rpmdbLink(db, "matchIterator");
02775 mi->mi_rpmtag = rpmtag;
02776
02777 mi->mi_dbc = NULL;
02778 mi->mi_set = set;
02779 mi->mi_setx = 0;
02780 mi->mi_h = NULL;
02781 mi->mi_sorted = 0;
02782 mi->mi_cflags = 0;
02783 mi->mi_modified = 0;
02784 mi->mi_prevoffset = 0;
02785 mi->mi_offset = 0;
02786 mi->mi_filenum = 0;
02787 mi->mi_nre = 0;
02788 mi->mi_re = NULL;
02789
02790 mi->mi_ts = NULL;
02791
02792 return mi;
02793 }
02794
02795
02796 int rpmdbRemove(rpmdb db, int rid, unsigned int hdrNum,
02797 rpmts ts)
02798 {
02799 DBC * dbcursor = NULL;
02800 DBT * key = alloca(sizeof(*key));
02801 DBT * data = alloca(sizeof(*data));
02802 union _dbswap mi_offset;
02803 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
02804 Header h;
02805 sigset_t signalMask;
02806 int ret = 0;
02807 int rc = 0;
02808 int xx;
02809
02810 if (db == NULL)
02811 return 0;
02812
02813 memset(key, 0, sizeof(*key));
02814 memset(data, 0, sizeof(*data));
02815
02816 { rpmdbMatchIterator mi;
02817 mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum));
02818 h = rpmdbNextIterator(mi);
02819 if (h)
02820 h = headerLink(h);
02821 mi = rpmdbFreeIterator(mi);
02822 }
02823
02824 if (h == NULL) {
02825 rpmlog(RPMLOG_ERR, _("%s: cannot read header at 0x%x\n"),
02826 "rpmdbRemove", hdrNum);
02827 return 1;
02828 }
02829
02830 #ifdef DYING
02831
02832 if (rid != 0 && rid != -1) {
02833 uint32_t tid = rid;
02834 he->tag = RPMTAG_REMOVETID;
02835 he->t = RPM_UINT32_TYPE;
02836 he->p.ui32p = &tid;
02837 he->c = 1;
02838 xx = headerPut(h, he, 0);
02839 }
02840 #endif
02841
02842 he->tag = RPMTAG_NVRA;
02843 xx = headerGet(h, he, 0);
02844 rpmlog(RPMLOG_DEBUG, " --- h#%8u %s\n", hdrNum, he->p.str);
02845 he->p.ptr = _free(he->p.ptr);
02846
02847 (void) blockSignals(db, &signalMask);
02848
02849
02850 { dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
02851 size_t dbix;
02852
02853 if (db->db_tags != NULL)
02854 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
02855 tagStore_t dbiTag = db->db_tags + dbix;
02856 rpmTag rpmtag = dbiTag->tag;
02857 const char * dbiBN = (dbiTag->str != NULL
02858 ? dbiTag->str : tagName(rpmtag));
02859 dbiIndex dbi;
02860 uint8_t * bin = NULL;
02861 int i;
02862
02863 dbi = NULL;
02864 he->tag = rpmtag;
02865 he->t = 0;
02866 he->p.ptr = NULL;
02867 he->c = 0;
02868
02869 switch (he->tag) {
02870
02871 case RPMDBI_AVAILABLE:
02872 case RPMDBI_ADDED:
02873 case RPMDBI_REMOVED:
02874 case RPMDBI_DEPENDS:
02875 continue;
02876 break;
02877 case RPMDBI_PACKAGES:
02878 if (db->db_export != NULL)
02879 xx = db->db_export(db, h, 0);
02880 dbi = dbiOpen(db, he->tag, 0);
02881 if (dbi == NULL)
02882 continue;
02883
02884
02885 mi_offset.ui = hdrNum;
02886 if (dbiByteSwapped(dbi) == 1)
02887 _DBSWAP(mi_offset);
02888 key->data = &mi_offset;
02889
02890 key->size = (u_int32_t) sizeof(mi_offset.ui);
02891
02892 rc = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
02893 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
02894 if (rc) {
02895 rpmlog(RPMLOG_ERR,
02896 _("error(%d) setting header #%d record for %s removal\n"),
02897 rc, hdrNum, dbiBN);
02898 } else
02899 rc = dbiDel(dbi, dbcursor, key, data, 0);
02900 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
02901 dbcursor = NULL;
02902 if (!dbi->dbi_no_dbsync)
02903 xx = dbiSync(dbi, 0);
02904 continue;
02905 break;
02906 default:
02907 xx = headerGet(h, he, 0);
02908 if (!xx)
02909 continue;
02910 break;
02911
02912 }
02913
02914 dbi = dbiOpen(db, he->tag, 0);
02915 if (dbi != NULL) {
02916 int printed;
02917
02918
02919 if (he->t == RPM_STRING_TYPE) {
02920 const char * s = he->p.str;
02921 char * t;
02922 he->c = 1;
02923 he->p.argv = xcalloc(1, sizeof(*he->p.argv)+strlen(s)+1);
02924 he->p.argv[0] = t = (char *) &he->p.argv[1];
02925 (void) strcpy(t, s);
02926 s = _free(s);
02927 }
02928
02929 printed = 0;
02930 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
02931 for (i = 0; i < (unsigned) he->c; i++) {
02932 dbiIndexSet set;
02933 int stringvalued;
02934
02935 bin = _free(bin);
02936 switch (dbi->dbi_rpmtag) {
02937 case RPMTAG_FILEDIGESTS:
02938
02939 if (!(he->p.argv[i] && *he->p.argv[i] != '\0'))
02940 continue;
02941 break;
02942 default:
02943 break;
02944 }
02945
02946
02947 stringvalued = 0;
02948 switch (he->t) {
02949 case RPM_UINT8_TYPE:
02950 key->size = (u_int32_t) sizeof(*he->p.ui8p);
02951 key->data = he->p.ui8p + i;
02952 break;
02953 case RPM_UINT16_TYPE:
02954 key->size = (u_int32_t) sizeof(*he->p.ui16p);
02955 key->data = he->p.ui16p + i;
02956 break;
02957 case RPM_UINT32_TYPE:
02958 key->size = (u_int32_t) sizeof(*he->p.ui32p);
02959 key->data = he->p.ui32p + i;
02960 break;
02961 case RPM_UINT64_TYPE:
02962 key->size = (u_int32_t) sizeof(*he->p.ui64p);
02963 key->data = he->p.ui64p + i;
02964 break;
02965 case RPM_BIN_TYPE:
02966 key->size = (u_int32_t) he->c;
02967 key->data = he->p.ptr;
02968 he->c = 1;
02969 break;
02970 case RPM_I18NSTRING_TYPE:
02971 case RPM_STRING_TYPE:
02972 he->c = 1;
02973
02974 case RPM_STRING_ARRAY_TYPE:
02975
02976 if (dbi->dbi_rpmtag == RPMTAG_FILEDIGESTS) {
02977 const char * s = he->p.argv[i];
02978 size_t dlen = strlen(s);
02979 uint8_t * t;
02980 unsigned j;
02981 assert((dlen & 1) == 0);
02982 dlen /= 2;
02983 bin = t = xcalloc(1, dlen);
02984
02985 for (j = 0; j < (unsigned) dlen; j++, t++, s += 2)
02986 *t = (uint8_t) (nibble(s[0]) << 4) | nibble(s[1]);
02987
02988 key->data = bin;
02989 key->size = (u_int32_t) dlen;
02990 break;
02991 }
02992
02993 if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
02994 int nbin;
02995 bin = xcalloc(1, 32);
02996 nbin = pgpExtractPubkeyFingerprint(he->p.argv[i], bin);
02997 if (nbin <= 0)
02998 continue;
02999 key->data = bin;
03000 key->size = (u_int32_t) nbin;
03001 break;
03002 }
03003
03004 default:
03005 key->data = (void *) he->p.argv[i];
03006 key->size = (u_int32_t) strlen(he->p.argv[i]);
03007 stringvalued = 1;
03008 break;
03009 }
03010
03011 if (!printed) {
03012 if (he->c == 1 && stringvalued) {
03013 rpmlog(RPMLOG_DEBUG,
03014 D_("removing \"%s\" from %s index.\n"),
03015 (char *)key->data, dbiBN);
03016 } else {
03017 rpmlog(RPMLOG_DEBUG,
03018 D_("removing %u entries from %s index.\n"),
03019 (unsigned) he->c, dbiBN);
03020 }
03021 printed++;
03022 }
03023
03024
03025
03026
03027
03028
03029
03030
03031
03032
03033 set = NULL;
03034
03035 if (key->size == 0) key->size = (u_int32_t) strlen((char *)key->data);
03036 if (key->size == 0) key->size++;
03037
03038
03039 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
03040 if (rc == 0) {
03041 (void) dbt2set(dbi, data, &set);
03042 } else if (rc == DB_NOTFOUND) {
03043 continue;
03044 } else {
03045 rpmlog(RPMLOG_ERR,
03046 _("error(%d) setting \"%s\" records from %s index\n"),
03047 rc, key->data, dbiBN);
03048 ret += 1;
03049 continue;
03050 }
03051
03052
03053 rc = dbiPruneSet(set, rec, 1, sizeof(*rec), 1);
03054
03055
03056 if (rc) {
03057 set = dbiFreeIndexSet(set);
03058 continue;
03059 }
03060
03061
03062 if (set->count > 0) {
03063 (void) set2dbt(dbi, data, set);
03064 rc = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
03065 if (rc) {
03066 rpmlog(RPMLOG_ERR,
03067 _("error(%d) storing record \"%s\" into %s\n"),
03068 rc, key->data, dbiBN);
03069 ret += 1;
03070 }
03071 data->data = _free(data->data);
03072 data->size = 0;
03073 } else {
03074 rc = dbiDel(dbi, dbcursor, key, data, 0);
03075 if (rc) {
03076 rpmlog(RPMLOG_ERR,
03077 _("error(%d) removing record \"%s\" from %s\n"),
03078 rc, key->data, dbiBN);
03079 ret += 1;
03080 }
03081 }
03082
03083 set = dbiFreeIndexSet(set);
03084 }
03085
03086 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
03087 dbcursor = NULL;
03088
03089 if (!dbi->dbi_no_dbsync)
03090 xx = dbiSync(dbi, 0);
03091 }
03092
03093 he->tag = 0;
03094 he->t = 0;
03095 he->p.ptr = _free(he->p.ptr);
03096 he->c = 0;
03097 bin = _free(bin);
03098 }
03099
03100 rec = _free(rec);
03101 }
03102
03103
03104 (void) unblockSignals(db, &signalMask);
03105
03106 h = headerFree(h);
03107
03108
03109 return 0;
03110 }
03111
03112
03113 int rpmdbAdd(rpmdb db, int iid, Header h, rpmts ts)
03114 {
03115 DBC * dbcursor = NULL;
03116 DBT * key = alloca(sizeof(*key));
03117 DBT * data = alloca(sizeof(*data));
03118 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
03119 sigset_t signalMask;
03120 const char ** dirNames;
03121 uint32_t * dirIndexes;
03122 dbiIndex dbi;
03123 size_t dbix;
03124 union _dbswap mi_offset;
03125 unsigned int hdrNum = 0;
03126 size_t nb;
03127 int ret = 0;
03128 int rc;
03129 int xx;
03130
03131
03132 (void) headerSetInstance(h, 0);
03133
03134 if (db == NULL)
03135 return 0;
03136
03137 memset(key, 0, sizeof(*key));
03138 memset(data, 0, sizeof(*data));
03139
03140 #ifdef NOTYET
03141 he->tag = RPMTAG_REMOVETID;
03142 xx = headerDel(h, he, 0);
03143 #endif
03144 if (iid != 0 && iid != -1) {
03145 uint32_t tid = iid;
03146 he->tag = RPMTAG_INSTALLTID;
03147 he->t = RPM_UINT32_TYPE;
03148 he->p.ui32p = &tid;
03149 he->c = 1;
03150 if (!headerIsEntry(h, he->tag))
03151
03152 xx = headerPut(h, he, 0);
03153
03154 }
03155
03156
03157 if (!headerIsEntry(h, RPMTAG_PACKAGECOLOR)) {
03158 uint32_t hcolor = hGetColor(h);
03159 he->tag = RPMTAG_PACKAGECOLOR;
03160 he->t = RPM_UINT32_TYPE;
03161 he->p.ui32p = &hcolor;
03162 he->c = 1;
03163
03164 xx = headerPut(h, he, 0);
03165
03166 }
03167
03168 he->tag = RPMTAG_DIRNAMES;
03169
03170 xx = headerGet(h, he, 0);
03171
03172 dirNames = he->p.argv;
03173 he->tag = RPMTAG_DIRINDEXES;
03174
03175 xx = headerGet(h, he, 0);
03176
03177 dirIndexes = he->p.ui32p;
03178
03179 (void) blockSignals(db, &signalMask);
03180
03181 {
03182 unsigned int firstkey = 0;
03183 void * keyp = &firstkey;
03184 size_t keylen = sizeof(firstkey);
03185 void * datap = NULL;
03186 size_t datalen = 0;
03187
03188 dbi = dbiOpen(db, RPMDBI_PACKAGES, 0);
03189 if (dbi != NULL) {
03190
03191 nb = 0;
03192 (void) headerGetMagic(h, NULL, &nb);
03193
03194 datap = h;
03195 datalen = headerSizeof(h);
03196 datalen -= nb;
03197
03198 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
03199
03200
03201
03202
03203 key->data = keyp;
03204 key->size = (u_int32_t) keylen;
03205 data->data = datap;
03206 data->size = (u_int32_t) datalen;
03207 ret = dbiGet(dbi, dbcursor, key, data, DB_SET);
03208 keyp = key->data;
03209 keylen = key->size;
03210 datap = data->data;
03211 datalen = data->size;
03212
03213
03214 hdrNum = 0;
03215 if (ret == 0 && datap) {
03216 memcpy(&mi_offset, datap, sizeof(mi_offset.ui));
03217 if (dbiByteSwapped(dbi) == 1)
03218 _DBSWAP(mi_offset);
03219 hdrNum = (unsigned) mi_offset.ui;
03220 }
03221 ++hdrNum;
03222 mi_offset.ui = hdrNum;
03223 if (dbiByteSwapped(dbi) == 1)
03224 _DBSWAP(mi_offset);
03225 if (ret == 0 && datap) {
03226 memcpy(datap, &mi_offset, sizeof(mi_offset.ui));
03227 } else {
03228 datap = &mi_offset;
03229 datalen = sizeof(mi_offset.ui);
03230 }
03231
03232 key->data = keyp;
03233 key->size = (u_int32_t) keylen;
03234
03235 data->data = datap;
03236
03237 data->size = (u_int32_t) datalen;
03238
03239
03240 ret = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
03241
03242 xx = dbiSync(dbi, 0);
03243
03244 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
03245 dbcursor = NULL;
03246 }
03247
03248 }
03249
03250 if (ret) {
03251 rpmlog(RPMLOG_ERR,
03252 _("error(%d) allocating new package instance\n"), ret);
03253 goto exit;
03254 }
03255
03256
03257
03258 if (hdrNum)
03259 { dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
03260
03261
03262 (void) headerSetInstance(h, hdrNum);
03263
03264 if (db->db_tags != NULL)
03265 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
03266 tagStore_t dbiTags = db->db_tags + dbix;
03267 const char * dbiBN = (dbiTags->str != NULL
03268 ? dbiTags->str : tagName(dbiTags->tag));
03269 uint8_t * bin = NULL;
03270 rpmTagData requireFlags;
03271 rpmRC rpmrc;
03272 int i;
03273
03274 rpmrc = RPMRC_NOTFOUND;
03275 requireFlags.ptr = NULL;
03276 dbi = NULL;
03277 he->tag = dbiTags->tag;
03278 he->t = 0;
03279 he->p.ptr = NULL;
03280 he->c = 0;
03281
03282 switch (he->tag) {
03283
03284 case RPMDBI_AVAILABLE:
03285 case RPMDBI_ADDED:
03286 case RPMDBI_REMOVED:
03287 case RPMDBI_DEPENDS:
03288 continue;
03289 break;
03290 case RPMDBI_PACKAGES:
03291 if (db->db_export != NULL)
03292 xx = db->db_export(db, h, 1);
03293 dbi = dbiOpen(db, he->tag, 0);
03294 if (dbi == NULL)
03295 continue;
03296 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
03297
03298 mi_offset.ui = hdrNum;
03299 if (dbiByteSwapped(dbi) == 1)
03300 _DBSWAP(mi_offset);
03301
03302 key->data = (void *) &mi_offset;
03303
03304 key->size = (u_int32_t) sizeof(mi_offset.ui);
03305 { size_t len;
03306 nb = 0;
03307 (void) headerGetMagic(h, NULL, &nb);
03308 len = 0;
03309 data->data = headerUnload(h, &len);
03310 data->size = (u_int32_t) len;
03311 #ifdef DYING
03312 data->size -= nb;
03313 #endif
03314 }
03315
03316
03317 if (ts) {
03318 const char * msg = NULL;
03319 int lvl;
03320
03321 assert(data->data != NULL);
03322 rpmrc = headerCheck(rpmtsDig(ts), data->data, data->size, &msg);
03323 rpmtsCleanDig(ts);
03324 lvl = (rpmrc == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG);
03325 rpmlog(lvl, "%s h#%8u %s",
03326 (rpmrc == RPMRC_FAIL ? _("rpmdbAdd: skipping") : " +++"),
03327 hdrNum, (msg ? msg : "\n"));
03328 msg = _free(msg);
03329 }
03330
03331 if (data->data != NULL && rpmrc != RPMRC_FAIL) {
03332
03333 xx = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
03334
03335 xx = dbiSync(dbi, 0);
03336 }
03337 data->data = _free(data->data);
03338 data->size = 0;
03339 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
03340 dbcursor = NULL;
03341 if (!dbi->dbi_no_dbsync)
03342 xx = dbiSync(dbi, 0);
03343 continue;
03344 break;
03345 case RPMTAG_REQUIRENAME:
03346 he->tag = RPMTAG_REQUIREFLAGS;
03347
03348 xx = headerGet(h, he, 0);
03349
03350 requireFlags.ptr = he->p.ptr;
03351 he->tag = RPMTAG_REQUIRENAME;
03352
03353 xx = headerGet(h, he, 0);
03354
03355 break;
03356 default:
03357
03358 xx = headerGet(h, he, 0);
03359
03360 break;
03361 }
03362
03363
03364 if (he->c == 0)
03365 continue;
03366
03367 dbi = dbiOpen(db, he->tag, 0);
03368 if (dbi != NULL) {
03369 int printed;
03370
03371
03372 if (he->t == RPM_STRING_TYPE) {
03373 const char * s = he->p.str;
03374 char * t;
03375 he->c = 1;
03376 he->p.argv = xcalloc(1, sizeof(*he->p.argv)+strlen(s)+1);
03377 he->p.argv[0] = t = (char *) &he->p.argv[1];
03378 (void) strcpy(t, s);
03379 s = _free(s);
03380 }
03381
03382 printed = 0;
03383 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
03384
03385 for (i = 0; i < (unsigned) he->c; i++) {
03386 dbiIndexSet set;
03387 int stringvalued;
03388
03389 bin = _free(bin);
03390
03391
03392
03393
03394 rec->tagNum = i;
03395 switch (dbi->dbi_rpmtag) {
03396 case RPMTAG_BASENAMES:
03397
03398 if (_db_tagged_file_indices && i < 0x010000)
03399 rec->tagNum |= taghash(dirNames[dirIndexes[i]]);
03400 break;
03401 case RPMTAG_PUBKEYS:
03402 break;
03403 case RPMTAG_FILEDIGESTS:
03404
03405 if (!(he->p.argv[i] && *he->p.argv[i] != '\0'))
03406 continue;
03407 break;
03408 case RPMTAG_REQUIRENAME:
03409
03410 if (requireFlags.ui32p
03411 && isInstallPreReq(requireFlags.ui32p[i]))
03412 continue;
03413 break;
03414 case RPMTAG_TRIGGERNAME:
03415 if (i) {
03416 int j;
03417 for (j = 0; j < i; j++) {
03418 if (!strcmp(he->p.argv[i], he->p.argv[j]))
03419 break;
03420 }
03421 if (j < i)
03422 continue;
03423 }
03424 break;
03425 default:
03426 break;
03427 }
03428
03429
03430 stringvalued = 0;
03431 switch (he->t) {
03432 case RPM_UINT8_TYPE:
03433 key->size = (u_int32_t) sizeof(*he->p.ui8p);
03434 key->data = he->p.ui8p + i;
03435 break;
03436 case RPM_UINT16_TYPE:
03437 key->size = (u_int32_t) sizeof(*he->p.ui16p);
03438 key->data = he->p.ui16p + i;
03439 break;
03440 case RPM_UINT32_TYPE:
03441 key->size = (u_int32_t) sizeof(*he->p.ui32p);
03442 key->data = he->p.ui32p + i;
03443 break;
03444 case RPM_UINT64_TYPE:
03445 key->size = (u_int32_t) sizeof(*he->p.ui64p);
03446 key->data = he->p.ui64p + i;
03447 break;
03448 case RPM_BIN_TYPE:
03449 key->size = (u_int32_t) he->c;
03450 key->data = he->p.ptr;
03451 he->c = 1;
03452 break;
03453 case RPM_I18NSTRING_TYPE:
03454 case RPM_STRING_TYPE:
03455 he->c = 1;
03456
03457 case RPM_STRING_ARRAY_TYPE:
03458
03459 if (dbi->dbi_rpmtag == RPMTAG_FILEDIGESTS) {
03460 const char * s = he->p.argv[i];
03461 size_t dlen = strlen(s);
03462 uint8_t * t;
03463 unsigned j;
03464 assert((dlen & 1) == 0);
03465 dlen /= 2;
03466 bin = t = xcalloc(1, dlen);
03467
03468 for (j = 0; j < (unsigned) dlen; j++, t++, s += 2)
03469 *t = (uint8_t) (nibble(s[0]) << 4) | nibble(s[1]);
03470
03471 key->data = bin;
03472 key->size = (u_int32_t) dlen;
03473 break;
03474 }
03475
03476 if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
03477 int nbin;
03478 bin = xcalloc(1, 32);
03479 nbin = pgpExtractPubkeyFingerprint(he->p.argv[i], bin);
03480 if (nbin <= 0)
03481 continue;
03482 key->data = bin;
03483 key->size = (u_int32_t) nbin;
03484 break;
03485 }
03486
03487 default:
03488 key->data = (void *) he->p.argv[i];
03489 key->size = (u_int32_t) strlen(he->p.argv[i]);
03490 stringvalued = 1;
03491 break;
03492 }
03493
03494 if (!printed) {
03495 if (he->c == 1 && stringvalued) {
03496 rpmlog(RPMLOG_DEBUG,
03497 D_("adding \"%s\" to %s index.\n"),
03498 (char *)key->data, dbiBN);
03499 } else {
03500 rpmlog(RPMLOG_DEBUG,
03501 D_("adding %u entries to %s index.\n"),
03502 (unsigned)he->c, dbiBN);
03503 }
03504 printed++;
03505 }
03506
03507
03508
03509 set = NULL;
03510
03511 if (key->size == 0) key->size = (u_int32_t) strlen((char *)key->data);
03512 if (key->size == 0) key->size++;
03513
03514
03515 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
03516 if (rc == 0) {
03517
03518 if (!dbi->dbi_permit_dups)
03519 (void) dbt2set(dbi, data, &set);
03520 } else if (rc != DB_NOTFOUND) {
03521 rpmlog(RPMLOG_ERR,
03522 _("error(%d) getting \"%s\" records from %s index\n"),
03523 rc, key->data, dbiBN);
03524 ret += 1;
03525 continue;
03526 }
03527
03528
03529 if (set == NULL)
03530 set = xcalloc(1, sizeof(*set));
03531
03532 (void) dbiAppendSet(set, rec, 1, sizeof(*rec), 0);
03533
03534
03535 (void) set2dbt(dbi, data, set);
03536 rc = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST);
03537
03538
03539 if (rc) {
03540 rpmlog(RPMLOG_ERR,
03541 _("error(%d) storing record %s into %s\n"),
03542 rc, key->data, dbiBN);
03543 ret += 1;
03544 }
03545
03546 data->data = _free(data->data);
03547
03548 data->size = 0;
03549 set = dbiFreeIndexSet(set);
03550 }
03551
03552 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
03553 dbcursor = NULL;
03554
03555 if (!dbi->dbi_no_dbsync)
03556 xx = dbiSync(dbi, 0);
03557 }
03558
03559 he->tag = 0;
03560 he->t = 0;
03561
03562 he->p.ptr = _free(he->p.ptr);
03563
03564 he->c = 0;
03565 bin = _free(bin);
03566 requireFlags.ptr = _free(requireFlags.ptr);
03567 }
03568
03569 rec = _free(rec);
03570 }
03571
03572 exit:
03573 (void) unblockSignals(db, &signalMask);
03574 dirIndexes = _free(dirIndexes);
03575 dirNames = _free(dirNames);
03576
03577 return ret;
03578 }
03579
03580
03581
03582 int rpmdbFindFpList(rpmdb db, fingerPrint * fpList, dbiIndexSet * matchList,
03583 int numItems, unsigned int exclude)
03584 {
03585 DBT * key;
03586 DBT * data;
03587 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
03588 rpmdbMatchIterator mi;
03589 fingerPrintCache fpc;
03590 Header h;
03591 int i, xx;
03592
03593 if (db == NULL) return 0;
03594
03595 mi = rpmdbInitIterator(db, RPMTAG_BASENAMES, NULL, 0);
03596 assert(mi != NULL);
03597 if (mi == NULL)
03598 return 2;
03599
03600 key = &mi->mi_key;
03601 data = &mi->mi_data;
03602
03603
03604 for (i = 0; i < numItems; i++) {
03605 unsigned int tag;
03606
03607 matchList[i] = xcalloc(1, sizeof(*(matchList[i])));
03608
03609
03610 key->data = (void *) fpList[i].baseName;
03611
03612 key->size = (u_int32_t) strlen((char *)key->data);
03613 if (key->size == 0) key->size++;
03614
03615 tag = (_db_tagged_file_indices ? taghash(fpList[i].entry->dirName) : 0);
03616 xx = rpmdbGrowIterator(mi, i, exclude, tag);
03617
03618 }
03619
03620 if ((i = rpmdbGetIteratorCount(mi)) == 0) {
03621 mi = rpmdbFreeIterator(mi);
03622 return 0;
03623 }
03624 fpc = fpCacheCreate(i);
03625
03626 rpmdbSortIterator(mi);
03627
03628
03629
03630 if (mi != NULL)
03631 while ((h = rpmdbNextIterator(mi)) != NULL) {
03632 const char ** dirNames;
03633 const char ** baseNames;
03634 const char ** fullBaseNames;
03635 uint32_t * dirIndexes;
03636 uint32_t * fullDirIndexes;
03637 fingerPrint * fps;
03638 dbiIndexItem im;
03639 int start;
03640 int num;
03641 int end;
03642
03643 start = mi->mi_setx - 1;
03644 im = mi->mi_set->recs + start;
03645
03646
03647 for (end = start + 1; end < mi->mi_set->count; end++) {
03648 if (im->hdrNum != mi->mi_set->recs[end].hdrNum)
03649 break;
03650 }
03651 num = end - start;
03652
03653
03654 he->tag = RPMTAG_BASENAMES;
03655 xx = headerGet(h, he, 0);
03656 fullBaseNames = he->p.argv;
03657 he->tag = RPMTAG_DIRNAMES;
03658 xx = headerGet(h, he, 0);
03659 dirNames = he->p.argv;
03660 he->tag = RPMTAG_DIRINDEXES;
03661 xx = headerGet(h, he, 0);
03662 fullDirIndexes = he->p.ui32p;
03663
03664 baseNames = xcalloc(num, sizeof(*baseNames));
03665 dirIndexes = xcalloc(num, sizeof(*dirIndexes));
03666 for (i = 0; i < num; i++) {
03667 baseNames[i] = fullBaseNames[im[i].tagNum];
03668 dirIndexes[i] = fullDirIndexes[im[i].tagNum];
03669 }
03670
03671 fps = xcalloc(num, sizeof(*fps));
03672 fpLookupList(fpc, dirNames, baseNames, dirIndexes, num, fps);
03673
03674
03675 for (i = 0; i < num; i++, im++) {
03676
03677 if (!FP_EQUAL(fps[i], fpList[im->fpNum]))
03678 continue;
03679
03680 xx = dbiAppendSet(matchList[im->fpNum], im, 1, sizeof(*im), 0);
03681 }
03682
03683 fps = _free(fps);
03684 fullBaseNames = _free(fullBaseNames);
03685
03686 dirNames = _free(dirNames);
03687
03688 fullDirIndexes = _free(fullDirIndexes);
03689 baseNames = _free(baseNames);
03690 dirIndexes = _free(dirIndexes);
03691
03692 mi->mi_setx = end;
03693 }
03694
03695 mi = rpmdbFreeIterator(mi);
03696
03697 fpc = fpCacheFree(fpc);
03698
03699 return 0;
03700
03701 }
03702
03703
03709 static int rpmioFileExists(const char * urlfn)
03710
03711
03712 {
03713 const char *fn;
03714 int urltype = urlPath(urlfn, &fn);
03715
03716 if (*fn == '\0') fn = "/";
03717 switch (urltype) {
03718 case URL_IS_HTTPS:
03719 case URL_IS_HTTP:
03720 case URL_IS_FTP:
03721 case URL_IS_HKP:
03722 case URL_IS_PATH:
03723 case URL_IS_UNKNOWN:
03724 { struct stat sb;
03725 if (Stat(fn, &sb) < 0) {
03726 switch(errno) {
03727 case ENOENT:
03728 case EINVAL:
03729 return 0;
03730 }
03731 }
03732 } break;
03733 case URL_IS_DASH:
03734 default:
03735 return 0;
03736 break;
03737 }
03738
03739 return 1;
03740 }
03741
03742 static int rpmdbRemoveDatabase(const char * prefix,
03743 const char * dbpath, int _dbapi,
03744 const tagStore_t dbiTags, size_t dbiNTags)
03745
03746
03747 {
03748 const char * fn;
03749 int xx;
03750
03751 switch (_dbapi) {
03752 default:
03753 case 4:
03754
03755 case 3:
03756 { char * suffix;
03757 size_t i;
03758
03759 if (dbiTags != NULL)
03760 for (i = 0; i < dbiNTags; i++) {
03761 const char * dbiBN = (dbiTags[i].str != NULL
03762 ? dbiTags[i].str : tagName(dbiTags[i].tag));
03763 fn = rpmGetPath(prefix, dbpath, "/", dbiBN, NULL);
03764 if (rpmioFileExists(fn))
03765 xx = Unlink(fn);
03766 fn = _free(fn);
03767 }
03768
03769 fn = rpmGetPath(prefix, dbpath, "/", "__db.000", NULL);
03770 suffix = (char *)(fn + strlen(fn) - (sizeof("000") - 1));
03771 for (i = 0; i < 16; i++) {
03772 (void) snprintf(suffix, sizeof("000"), "%03u", (unsigned)i);
03773 if (rpmioFileExists(fn))
03774 xx = Unlink(fn);
03775 }
03776 fn = _free(fn);
03777
03778 } break;
03779 case 2:
03780 case 1:
03781 case 0:
03782 break;
03783 }
03784
03785 fn = rpmGetPath(prefix, dbpath, NULL);
03786 xx = Rmdir(fn);
03787 fn = _free(fn);
03788
03789 return 0;
03790 }
03791
03792 static int rpmdbMoveDatabase(const char * prefix,
03793 const char * olddbpath, int _olddbapi,
03794 const char * newdbpath, int _newdbapi,
03795 const tagStore_t dbiTags, size_t dbiNTags)
03796
03797
03798 {
03799 struct stat nsb, * nst = &nsb;
03800 const char * ofn, * nfn;
03801 int rc = 0;
03802 int xx;
03803
03804 switch (_olddbapi) {
03805 default:
03806 case 4:
03807
03808 case 3:
03809 { char *osuffix, *nsuffix;
03810 size_t i;
03811 if (dbiTags != NULL)
03812 for (i = 0; i < dbiNTags; i++) {
03813 rpmTag rpmtag = dbiTags[i].tag;
03814 const char * dbiBN = (dbiTags[i].str != NULL
03815 ? dbiTags[i].str : tagName(rpmtag));
03816
03817
03818 switch (rpmtag) {
03819 case RPMDBI_AVAILABLE:
03820 case RPMDBI_ADDED:
03821 case RPMDBI_REMOVED:
03822 case RPMDBI_DEPENDS:
03823 continue;
03824 break;
03825 default:
03826 break;
03827 }
03828
03829 ofn = rpmGetPath(prefix, olddbpath, "/", dbiBN, NULL);
03830 nfn = rpmGetPath(prefix, newdbpath, "/", dbiBN, NULL);
03831
03832 if (!rpmioFileExists(ofn)) {
03833 if (rpmioFileExists(nfn)) {
03834 rpmlog(RPMLOG_DEBUG, D_("removing file \"%s\"\n"), nfn);
03835 xx = Unlink(nfn);
03836 }
03837 goto bottom;
03838 }
03839
03840
03841
03842
03843
03844 if (Stat(nfn, nst) < 0 && Stat(ofn, nst) < 0)
03845 goto bottom;
03846
03847 rpmlog(RPMLOG_DEBUG, D_("moving file from \"%s\"\n"), ofn);
03848 rpmlog(RPMLOG_DEBUG, D_("moving file to \"%s\"\n"), nfn);
03849 if ((xx = Rename(ofn, nfn)) != 0) {
03850 rc = 1;
03851 goto bottom;
03852 }
03853 xx = Chown(nfn, nst->st_uid, nst->st_gid);
03854 xx = Chmod(nfn, (nst->st_mode & 07777));
03855 { struct utimbuf stamp;
03856 stamp.actime = nst->st_atime;
03857 stamp.modtime = nst->st_mtime;
03858 xx = Utime(nfn, &stamp);
03859 }
03860 bottom:
03861 ofn = _free(ofn);
03862 nfn = _free(nfn);
03863 }
03864
03865 ofn = rpmGetPath(prefix, olddbpath, "/", "__db.000", NULL);
03866 osuffix = (char *)(ofn + strlen(ofn) - (sizeof("000") - 1));
03867 nfn = rpmGetPath(prefix, newdbpath, "/", "__db.000", NULL);
03868 nsuffix = (char *)(nfn + strlen(nfn) - (sizeof("000") - 1));
03869
03870 for (i = 0; i < 16; i++) {
03871 (void) snprintf(osuffix, sizeof("000"), "%03u", (unsigned)i);
03872 if (rpmioFileExists(ofn)) {
03873 rpmlog(RPMLOG_DEBUG, D_("removing region file \"%s\"\n"), ofn);
03874 xx = Unlink(ofn);
03875 }
03876 (void) snprintf(nsuffix, sizeof("000"), "%03u", (unsigned)i);
03877 if (rpmioFileExists(nfn)) {
03878 rpmlog(RPMLOG_DEBUG, D_("removing region file \"%s\"\n"), nfn);
03879 xx = Unlink(nfn);
03880 }
03881 }
03882 ofn = _free(ofn);
03883 nfn = _free(ofn);
03884 } break;
03885 case 2:
03886 case 1:
03887 case 0:
03888 break;
03889 }
03890 return rc;
03891 }
03892
03893 int rpmdbRebuild(const char * prefix, rpmts ts)
03894
03895
03896 {
03897 const char * myprefix;
03898 rpmdb olddb;
03899 const char * dbpath = NULL;
03900 const char * rootdbpath = NULL;
03901 rpmdb newdb;
03902 const char * newdbpath = NULL;
03903 const char * newrootdbpath = NULL;
03904 const char * tfn;
03905 int nocleanup = 1;
03906 int failed = 0;
03907 int removedir = 0;
03908 int rc = 0, xx;
03909 int _dbapi;
03910 int _dbapi_rebuild;
03911 tagStore_t dbiTags = NULL;
03912 size_t dbiNTags = 0;
03913
03914 _dbapi = rpmExpandNumeric("%{_dbapi}");
03915 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
03916
03917 dbiTagsInit(&dbiTags, &dbiNTags);
03918
03919
03920 tfn = rpmGetPath("%{?_dbpath}", NULL);
03921
03922 if (!(tfn && tfn[0] != '\0'))
03923 {
03924 rpmlog(RPMLOG_DEBUG, D_("no dbpath has been set"));
03925 rc = 1;
03926 goto exit;
03927 }
03928
03929
03930 switch (urlPath(tfn, NULL)) {
03931 default:
03932 myprefix = xstrdup("");
03933 break;
03934 case URL_IS_UNKNOWN:
03935 myprefix = rpmGetPath((prefix ? prefix : "/"), NULL);
03936 break;
03937 }
03938
03939 dbpath = rootdbpath = rpmGetPath(myprefix, tfn, NULL);
03940 if (!(myprefix[0] == '/' && myprefix[1] == '\0'))
03941 dbpath += strlen(myprefix);
03942 tfn = _free(tfn);
03943
03944
03945 tfn = rpmGetPath("%{?_dbpath_rebuild}", NULL);
03946
03947 if (!(tfn && tfn[0] != '\0' && strcmp(tfn, dbpath)))
03948 {
03949 char pidbuf[20];
03950 char *t;
03951 sprintf(pidbuf, "rebuilddb.%d", (int) getpid());
03952 t = xmalloc(strlen(dbpath) + strlen(pidbuf) + 1);
03953 (void)stpcpy(stpcpy(t, dbpath), pidbuf);
03954 tfn = _free(tfn);
03955 tfn = t;
03956 nocleanup = 0;
03957 }
03958 newdbpath = newrootdbpath = rpmGetPath(myprefix, tfn, NULL);
03959 if (!(myprefix[0] == '/' && myprefix[1] == '\0'))
03960 newdbpath += strlen(myprefix);
03961 tfn = _free(tfn);
03962
03963 rpmlog(RPMLOG_DEBUG, D_("rebuilding database %s into %s\n"),
03964 rootdbpath, newrootdbpath);
03965
03966 if (!Access(newrootdbpath, F_OK)) {
03967 rpmlog(RPMLOG_ERR, _("temporary database %s already exists\n"),
03968 newrootdbpath);
03969 rc = 1;
03970 goto exit;
03971 }
03972
03973 rpmlog(RPMLOG_DEBUG, D_("creating directory %s\n"), newrootdbpath);
03974 if (Mkdir(newrootdbpath, 0755)) {
03975 rpmlog(RPMLOG_ERR, _("creating directory %s: %s\n"),
03976 newrootdbpath, strerror(errno));
03977 rc = 1;
03978 goto exit;
03979 }
03980 removedir = 1;
03981
03982 _rebuildinprogress = 0;
03983
03984 rpmlog(RPMLOG_DEBUG, D_("opening old database with dbapi %d\n"),
03985 _dbapi);
03986 if (rpmdbOpenDatabase(myprefix, dbpath, _dbapi, &olddb, O_RDONLY, 0644,
03987 RPMDB_FLAG_MINIMAL)) {
03988 rc = 1;
03989 goto exit;
03990 }
03991 _dbapi = olddb->db_api;
03992 _rebuildinprogress = 1;
03993 rpmlog(RPMLOG_DEBUG, D_("opening new database with dbapi %d\n"),
03994 _dbapi_rebuild);
03995 (void) rpmDefineMacro(NULL, "_rpmdb_rebuild %{nil}", -1);
03996 if (rpmdbOpenDatabase(myprefix, newdbpath, _dbapi_rebuild, &newdb, O_RDWR | O_CREAT, 0644, 0)) {
03997 rc = 1;
03998 goto exit;
03999 }
04000
04001 _rebuildinprogress = 0;
04002
04003 _dbapi_rebuild = newdb->db_api;
04004
04005 { Header h = NULL;
04006 rpmdbMatchIterator mi;
04007 #define _RECNUM rpmdbGetIteratorOffset(mi)
04008
04009 mi = rpmdbInitIterator(olddb, RPMDBI_PACKAGES, NULL, 0);
04010 if (ts)
04011 (void) rpmdbSetHdrChk(mi, ts);
04012
04013 while ((h = rpmdbNextIterator(mi)) != NULL) {
04014
04015
04016 if (!(headerIsEntry(h, RPMTAG_NAME) &&
04017 headerIsEntry(h, RPMTAG_VERSION) &&
04018 headerIsEntry(h, RPMTAG_RELEASE) &&
04019 headerIsEntry(h, RPMTAG_BUILDTIME)))
04020 {
04021 rpmlog(RPMLOG_WARNING,
04022 _("header #%u in the database is bad -- skipping.\n"),
04023 _RECNUM);
04024 continue;
04025 }
04026 if (!headerIsEntry(h, RPMTAG_SOURCERPM)
04027 && headerIsEntry(h, RPMTAG_ARCH))
04028 {
04029 rpmlog(RPMLOG_WARNING,
04030 _("header #%u in the database is SRPM -- skipping.\n"),
04031 _RECNUM);
04032 continue;
04033 }
04034
04035
04036 if (_db_filter_dups || newdb->db_filter_dups) {
04037 const char * name, * version, * release;
04038 int skip = 0;
04039
04040 (void) headerNEVRA(h, &name, NULL, &version, &release, NULL);
04041
04042
04043 { rpmdbMatchIterator mi;
04044 mi = rpmdbInitIterator(newdb, RPMTAG_NAME, name, 0);
04045 (void) rpmdbSetIteratorRE(mi, RPMTAG_VERSION,
04046 RPMMIRE_DEFAULT, version);
04047 (void) rpmdbSetIteratorRE(mi, RPMTAG_RELEASE,
04048 RPMMIRE_DEFAULT, release);
04049 while (rpmdbNextIterator(mi)) {
04050 skip = 1;
04051 break;
04052 }
04053 mi = rpmdbFreeIterator(mi);
04054 }
04055
04056
04057 if (skip)
04058 continue;
04059 }
04060
04061
04062 { Header nh = (headerIsEntry(h, RPMTAG_HEADERIMAGE)
04063 ? headerCopy(h) : NULL);
04064 rc = rpmdbAdd(newdb, -1, (nh ? nh : h), ts);
04065 nh = headerFree(nh);
04066 }
04067
04068 if (rc) {
04069 rpmlog(RPMLOG_ERR,
04070 _("cannot add record originally at %u\n"), _RECNUM);
04071 failed = 1;
04072 break;
04073 }
04074 }
04075
04076 mi = rpmdbFreeIterator(mi);
04077
04078 }
04079
04080 xx = rpmdbClose(olddb);
04081 xx = rpmdbClose(newdb);
04082
04083 if (failed) {
04084 rpmlog(RPMLOG_NOTICE, _("failed to rebuild database: original database "
04085 "remains in place\n"));
04086
04087 xx = rpmdbRemoveDatabase(myprefix, newdbpath, _dbapi_rebuild,
04088 dbiTags, dbiNTags);
04089 rc = 1;
04090 goto exit;
04091 } else if (!nocleanup) {
04092 xx = rpmdbMoveDatabase(myprefix, newdbpath, _dbapi_rebuild, dbpath, _dbapi,
04093 dbiTags, dbiNTags);
04094
04095 if (xx) {
04096 rpmlog(RPMLOG_ERR, _("failed to replace old database with new "
04097 "database!\n"));
04098 rpmlog(RPMLOG_ERR, _("replace files in %s with files from %s "
04099 "to recover"), dbpath, newdbpath);
04100 rc = 1;
04101 goto exit;
04102 }
04103 }
04104 rc = 0;
04105
04106 exit:
04107 if (removedir && !(rc == 0 && nocleanup)) {
04108 rpmlog(RPMLOG_DEBUG, D_("removing directory %s\n"), newrootdbpath);
04109 if (Rmdir(newrootdbpath))
04110 rpmlog(RPMLOG_ERR, _("failed to remove directory %s: %s\n"),
04111 newrootdbpath, strerror(errno));
04112 }
04113 newrootdbpath = _free(newrootdbpath);
04114 rootdbpath = _free(rootdbpath);
04115 dbiTags = tagStoreFree(dbiTags, dbiNTags);
04116 myprefix = _free(myprefix);
04117
04118 return rc;
04119 }