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

Generated on Fri Oct 12 08:44:54 2007 for rpm by  doxygen 1.5.2