rpmdb/rpmdb.c

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

Generated on Wed Oct 29 02:19:51 2008 for rpm by  doxygen 1.5.1