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

Generated on Wed Jan 28 12:45:25 2009 for rpm by  doxygen 1.4.7