rpmdb/rpmdb.c

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

Generated on Fri Aug 31 10:38:35 2007 for rpm by  doxygen 1.5.1