rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

rpmdb/rpmdb.c
Go to the documentation of this file.

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