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

Generated on Mon Nov 29 2010 05:18:46 for rpm by  doxygen 1.7.2