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

Generated on Thu Sep 3 20:25:02 2009 for rpm by  doxygen 1.4.7