- 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 }