Main Page Modules Data Structures File List Data Fields Globals Related Pages

# rpmdb/rpmdb.c

Go to the documentation of this file.

    00001 /*@-sizeoftype @*/
    00006 #include "system.h"
    00007
    00008 #include <sys/file.h>
    00009 #include <signal.h>
    00010 #include <sys/signal.h>
    00011
    00012 #ifndef DYING   /* XXX already in "system.h" */
    00013 /*@-noparams@*/
    00014 #include <fnmatch.h>
    00015 /*@=noparams@*/
    00016 #if defined(__LCLINT__)
    00017 /*@-declundef -exportheader -redecl @*/ /* LCL: missing annotation */
    00018 extern int fnmatch (const char *pattern, const char *string, int flags)
    00019         /*@*/;
    00020 /*@=declundef =exportheader =redecl @*/
    00021 #endif
    00022 #endif
    00023
    00024 #include <regex.h>
    00025 #if defined(__LCLINT__)
    00026 /*@-declundef -exportheader @*/ /* LCL: missing modifies (only is bogus) */
    00027 extern void regfree (/*@only@*/ regex_t *preg)
    00028         /*@modifies *preg @*/;
    00029 /*@=declundef =exportheader @*/
    00030 #endif
    00031
    00032 #include <rpmcli.h>
    00033
    00034 #include "rpmdb.h"
    00035 #include "fprint.h"
    00036 #include "misc.h"
    00037 #include "debug.h"
    00038
    00039 /*@access dbiIndexSet@*/
    00040 /*@access dbiIndexItem@*/
    00041 /*@access Header@*/             /* XXX compared with NULL */
    00042 /*@access rpmdbMatchIterator@*/
    00043
    00044 /*@unchecked@*/
    00045 static int _debug = 0;
    00046 #define INLINE
    00047
    00048 /*@-redecl@*/
    00049 extern int _noDirTokens;
    00050 /*@=redecl@*/
    00051 /*@unchecked@*/
    00052 static int _rebuildinprogress = 0;
    00053 /*@unchecked@*/
    00054 static int _db_filter_dups = 0;
    00055
    00056 #define _DBI_FLAGS      0
    00057 #define _DBI_PERMS      0644
    00058 #define _DBI_MAJOR      -1
    00059
    00060 /*@unchecked@*/
    00061 /*@globstate@*/ /*@null@*/ int * dbiTags = NULL;
    00062 /*@unchecked@*/
    00063 int dbiTagsMax = 0;
    00064
    00070 static inline unsigned char nibble(char c)
    00071         /*@*/
    00072 {
    00073     if (c >= '0' && c <= '9')
    00074         return (c - '0');
    00075     if (c >= 'A' && c <= 'F')
    00076         return (c - 'A') + 10;
    00077     if (c >= 'a' && c <= 'f')
    00078         return (c - 'a') + 10;
    00079     return 0;
    00080 }
    00081
    00088 static int printable(const void * ptr, size_t len)      /*@*/
    00089 {
    00090     const char * s = ptr;
    00091     int i;
    00092     for (i = 0; i < len; i++, s++)
    00093         if (!(*s >= ' ' && *s <= '~')) return 0;
    00094     return 1;
    00095 }
    00096
    00102 static int dbiTagToDbix(int rpmtag)
    00103         /*@*/
    00104 {
    00105     int dbix;
    00106
    00107     if (dbiTags != NULL)
    00108     for (dbix = 0; dbix < dbiTagsMax; dbix++) {
    00109         if (rpmtag == dbiTags[dbix])
    00110             return dbix;
    00111     }
    00112     return -1;
    00113 }
    00114
    00118 static void dbiTagsInit(void)
    00119         /*@globals rpmGlobalMacroContext, dbiTags, dbiTagsMax @*/
    00120         /*@modifies rpmGlobalMacroContext, dbiTags, dbiTagsMax @*/
    00121 {
    00122 /*@observer@*/ static const char * const _dbiTagStr_default =
    00123         "Packages:Name:Basenames:Group:Requirename:Providename:Conflictname:Triggername:Dirnames:Requireversion:Provideversion:Installtid:Removetid";
    00124     char * dbiTagStr = NULL;
    00125     char * o, * oe;
    00126     int rpmtag;
    00127
    00128     /*@-nullpass@*/
    00129     dbiTagStr = rpmExpand("%{_dbi_tags}", NULL);
    00130     /*@=nullpass@*/
    00131     if (!(dbiTagStr && *dbiTagStr && *dbiTagStr != '%')) {
    00132         dbiTagStr = _free(dbiTagStr);
    00133         dbiTagStr = xstrdup(_dbiTagStr_default);
    00134     }
    00135
    00136     /* Discard previous values. */
    00137     dbiTags = _free(dbiTags);
    00138     dbiTagsMax = 0;
    00139
    00140     /* Always allocate package index */
    00141     dbiTags = xcalloc(1, sizeof(*dbiTags));
    00142     dbiTags[dbiTagsMax++] = RPMDBI_PACKAGES;
    00143
    00144     for (o = dbiTagStr; o && *o; o = oe) {
    00145         while (*o && xisspace(*o))
    00146             o++;
    00147         if (*o == '\0')
    00148             break;
    00149         for (oe = o; oe && *oe; oe++) {
    00150             if (xisspace(*oe))
    00151                 /*@innerbreak@*/ break;
    00152             if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/'))
    00153                 /*@innerbreak@*/ break;
    00154         }
    00155         if (oe && *oe)
    00156             *oe++ = '\0';
    00157         rpmtag = tagValue(o);
    00158         if (rpmtag < 0) {
    00159
    00160 /*@-modfilesys@*/
    00161             fprintf(stderr, _("dbiTagsInit: unrecognized tag name: \"%s\" ignored\n"), o);
    00162 /*@=modfilesys@*/
    00163             continue;
    00164         }
    00165         if (dbiTagToDbix(rpmtag) >= 0)
    00166             continue;
    00167
    00168         dbiTags = xrealloc(dbiTags, (dbiTagsMax + 1) * sizeof(*dbiTags)); /* XXX memory leak */
    00169         dbiTags[dbiTagsMax++] = rpmtag;
    00170     }
    00171
    00172     dbiTagStr = _free(dbiTagStr);
    00173 }
    00174
    00175 /*@-redecl@*/
    00176 #if USE_DB1
    00177 /*@unchecked@*/
    00178 extern struct _dbiVec db1vec;
    00179 #define DB1vec          &db1vec
    00180 #else
    00181 #define DB1vec          NULL
    00182 #endif
    00183
    00184 #if USE_DB2
    00185 /*@unchecked@*/
    00186 extern struct _dbiVec db2vec;
    00187 #define DB2vec          &db2vec
    00188 #else
    00189 #define DB2vec          NULL
    00190 #endif
    00191
    00192 #if USE_DB3
    00193 /*@unchecked@*/
    00194 extern struct _dbiVec db3vec;
    00195 #define DB3vec          &db3vec
    00196 #else
    00197 #define DB3vec          NULL
    00198 #endif
    00199 /*@=redecl@*/
    00200
    00201 /*@-nullassign@*/
    00202 /*@observer@*/ /*@unchecked@*/
    00203 static struct _dbiVec *mydbvecs[] = {
    00204     DB1vec, DB1vec, DB2vec, DB3vec, NULL
    00205 };
    00206 /*@=nullassign@*/
    00207
    00208 INLINE int dbiSync(dbiIndex dbi, unsigned int flags)
    00209 {
    00210 if (_debug < 0 || dbi->dbi_debug)
    00211 fprintf(stderr, "    Sync %s\n", tagName(dbi->dbi_rpmtag));
    00212     return (*dbi->dbi_vec->sync) (dbi, flags);
    00213 }
    00214
    00215 INLINE int dbiByteSwapped(dbiIndex dbi)
    00216 {
    00217     return (*dbi->dbi_vec->byteswapped) (dbi);
    00218 }
    00219
    00220 INLINE int dbiCopen(dbiIndex dbi, /*@out@*/ DBC ** dbcp, unsigned int flags)
    00221 {
    00222 if (_debug < 0 || dbi->dbi_debug)
    00223 fprintf(stderr, "+++ RMW %s %s\n", tagName(dbi->dbi_rpmtag), ((flags & DBI_WRITECURSOR) ? "WRITECURSOR" : ""));
    00224     return (*dbi->dbi_vec->copen) (dbi, dbcp, flags);
    00225 }
    00226
    00227 INLINE int dbiCclose(dbiIndex dbi, /*@only@*/DBC * dbcursor, unsigned int flags)
    00228 {
    00229 if (_debug < 0 || dbi->dbi_debug)
    00230 fprintf(stderr, "--- RMW %s\n", tagName(dbi->dbi_rpmtag));
    00231     return (*dbi->dbi_vec->cclose) (dbi, dbcursor, flags);
    00232 }
    00233
    00234 INLINE int dbiDel(dbiIndex dbi, DBC * dbcursor,
    00235         const void * keyp, size_t keylen, unsigned int flags)
    00236 {
    00237     int NULkey;
    00238     int rc;
    00239
    00240     /* Make sure that keylen is correct for "" lookup. */
    00241     NULkey = (keyp && *((char *)keyp) == '\0' && keylen == 0);
    00242     if (NULkey) keylen++;
    00243     rc = (*dbi->dbi_vec->cdel) (dbi, dbcursor, keyp, keylen, flags);
    00244     if (NULkey) keylen--;
    00245
    00246 if (_debug < 0 || dbi->dbi_debug)
    00247 fprintf(stderr, "    Del %s key (%p,%ld) %s rc %d\n", tagName(dbi->dbi_rpmtag), keyp, (long)keylen, (dbi->dbi_rpmtag != RPMDBI_PACKAGES ? (char *)keyp : ""), rc);
    00248
    00249     return rc;
    00250 }
    00251
    00252 INLINE int dbiGet(dbiIndex dbi, DBC * dbcursor, void ** keypp, size_t * keylenp,
    00253         void ** datapp, size_t * datalenp, unsigned int flags)
    00254 {
    00255     int NULkey;
    00256     int rc;
    00257
    00258     /* Make sure that keylen is correct for "" lookup. */
    00259     NULkey = (keypp && *keypp && *((char *)(*keypp)) == '\0');
    00260     NULkey = (keylenp && *keylenp == 0 && NULkey);
    00261     if (keylenp && NULkey) (*keylenp)++;
    00262     rc = (*dbi->dbi_vec->cget) (dbi, dbcursor,
    00263                 keypp, keylenp, datapp, datalenp, flags);
    00264     if (keylenp && NULkey) (*keylenp)--;
    00265
    00266 /*@-nullderef -nullpass@*/
    00267 if (_debug < 0 || dbi->dbi_debug) {
    00268  int dataval = 0xdeadbeef;
    00269  const char * kvp;
    00270  char keyval[64];
    00271  keyval[0] = '\0';
    00272  if (keypp && *keypp && keylenp) {
    00273   if (printable(*keypp, *keylenp)) {
    00274     kvp = *keypp;
    00275   } else if (*keylenp <= sizeof(int)) {
    00276     int keyint = 0;
    00277     memcpy(&keyint, *keypp, sizeof(keyint));
    00278     sprintf(keyval, "#%d", keyint);
    00279     kvp = keyval;
    00280   } else {
    00281     static const char hex[] = "0123456789abcdef";
    00282     const unsigned char * s = *keypp;
    00283     char * t = keyval;
    00284     int i;
    00285     for (i = 0; i < *keylenp && t < (keyval+sizeof(keyval)-2); i++) {
    00286       *t++ = hex[ (unsigned)((*s >> 4) & 0x0f) ];
    00287       *t++ = hex[ (unsigned)((*s++   ) & 0x0f) ];
    00288     }
    00289     *t = '\0';
    00290     kvp = keyval;
    00291   }
    00292  } else
    00293    kvp = keyval;
    00294  if (rc == 0 && datapp && *datapp && datalenp && *datalenp >= sizeof(dataval)) {
    00295     memcpy(&dataval, *datapp, sizeof(dataval));
    00296  }
    00297  fprintf(stderr, "    Get %s key (%p,%ld) data (%p,%ld) \"%s\" %x rc %d\n",
    00298     tagName(dbi->dbi_rpmtag), *keypp, (long)*keylenp, *datapp, (long)*datalenp,
    00299     kvp, (unsigned)dataval, rc);
    00300 }
    00301 /*@=nullderef =nullpass@*/
    00302     return rc;
    00303 }
    00304
    00305 INLINE int dbiPut(dbiIndex dbi, DBC * dbcursor,
    00306         const void * keyp, size_t keylen,
    00307         const void * datap, size_t datalen, unsigned int flags)
    00308 {
    00309     int NULkey;
    00310     int rc;
    00311
    00312     /* XXX make sure that keylen is correct for "" lookup */
    00313     NULkey = (keyp && *((char *)keyp) == '\0' && keylen == 0);
    00314     if (NULkey) keylen++;
    00315     rc = (*dbi->dbi_vec->cput) (dbi, dbcursor, keyp, keylen, datap, datalen, flags);
    00316     if (NULkey) keylen--;
    00317
    00318 /*@-nullderef -nullpass@*/
    00319 if (_debug < 0 || dbi->dbi_debug) {
    00320  int dataval = 0xdeadbeef;
    00321  const char * kvp;
    00322  char keyval[64];
    00323  keyval[0] = '\0';
    00324  if (keyp) {
    00325   if (printable(keyp, keylen)) {
    00326     kvp = keyp;
    00327   } else if (keylen <= sizeof(int)) {
    00328     int keyint = 0;
    00329     memcpy(&keyint, keyp, sizeof(keyint));
    00330     sprintf(keyval, "#%d", keyint);
    00331     kvp = keyval;
    00332   } else {
    00333     static const char hex[] = "0123456789abcdef";
    00334     const unsigned char * s = keyp;
    00335     char * t = keyval;
    00336     int i;
    00337     for (i = 0; i < keylen && t < (keyval+sizeof(keyval)-2); i++) {
    00338       *t++ = hex[ (unsigned)((*s >> 4) & 0x0f) ];
    00339       *t++ = hex[ (unsigned)((*s++   ) & 0x0f) ];
    00340     }
    00341     *t = '\0';
    00342     kvp = keyval;
    00343   }
    00344  } else
    00345    kvp = keyval;
    00346  if (rc == 0 && datap && datalen >= sizeof(dataval)) {
    00347     memcpy(&dataval, datap, sizeof(dataval));
    00348  }
    00349  fprintf(stderr, "    Put %s key (%p,%ld) data (%p,%ld) \"%s\" %x rc %d\n", tagName(dbi->dbi_rpmtag), keyp, (long)keylen, (datap ? datap : NULL), (long)datalen, kvp, (unsigned)dataval, rc);
    00350 }
    00351 /*@=nullderef =nullpass@*/
    00352
    00353     return rc;
    00354 }
    00355
    00356 INLINE int dbiCount(dbiIndex dbi, DBC * dbcursor,
    00357         unsigned int * countp, unsigned int flags)
    00358 {
    00359     int rc = (*dbi->dbi_vec->ccount) (dbi, dbcursor, countp, flags);
    00360
    00361 if (rc == 0 && countp && *countp > 1)
    00362 fprintf(stderr, "    Count %s: %u rc %d\n", tagName(dbi->dbi_rpmtag), *countp, rc);
    00363
    00364     return rc;
    00365 }
    00366
    00367 INLINE int dbiVerify(dbiIndex dbi, unsigned int flags)
    00368 {
    00369     int dbi_debug = dbi->dbi_debug;
    00370     int dbi_rpmtag = dbi->dbi_rpmtag;
    00371     int rc;
    00372
    00373     dbi->dbi_verify_on_close = 1;
    00374     rc = (*dbi->dbi_vec->close) (dbi, flags);
    00375
    00376 if (_debug < 0 || dbi_debug)
    00377 fprintf(stderr, "    Verify %s rc %d\n", tagName(dbi_rpmtag), rc);
    00378
    00379     return rc;
    00380 }
    00381
    00382 INLINE int dbiClose(dbiIndex dbi, unsigned int flags) {
    00383 if (_debug < 0 || dbi->dbi_debug)
    00384 fprintf(stderr, "    Close %s\n", tagName(dbi->dbi_rpmtag));
    00385     return (*dbi->dbi_vec->close) (dbi, flags);
    00386 }
    00387
    00388 dbiIndex dbiOpen(rpmdb db, int rpmtag, /*@unused@*/ unsigned int flags)
    00389 {
    00390     int dbix;
    00391     dbiIndex dbi = NULL;
    00392     int _dbapi, _dbapi_rebuild, _dbapi_wanted;
    00393     int rc = 0;
    00394
    00395     if (db == NULL)
    00396         return NULL;
    00397
    00398     dbix = dbiTagToDbix(rpmtag);
    00399     if (dbix < 0 || dbix >= dbiTagsMax)
    00400         return NULL;
    00401
    00402     /* Is this index already open ? */
    00403     if ((dbi = db->_dbi[dbix]) != NULL)
    00404         return dbi;
    00405
    00406 /*@-globs -mods @*/ /* FIX: rpmGlobalMacroContext not in <rpmlib.h> */
    00407     _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
    00408 /*@=globs =mods @*/
    00409     if (_dbapi_rebuild < 1 || _dbapi_rebuild > 3)
    00410         _dbapi_rebuild = 3;
    00411     _dbapi_wanted = (_rebuildinprogress ? -1 : db->db_api);
    00412
    00413     switch (_dbapi_wanted) {
    00414     default:
    00415         _dbapi = _dbapi_wanted;
    00416         if (_dbapi < 0 || _dbapi >= 4 || mydbvecs[_dbapi] == NULL) {
    00417             return NULL;
    00418         }
    00419         /*@-mods@*/
    00420         errno = 0;
    00421         /*@=mods@*/
    00422         dbi = NULL;
    00423         rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi);
    00424         if (rc) {
    00425             static int _printed[32];
    00426             if (!_printed[dbix & 0x1f]++)
    00427                 rpmError(RPMERR_DBOPEN,
    00428                         _("cannot open %s index using db%d - %s (%d)\n"),
    00429                         tagName(rpmtag), _dbapi,
    00430                         (rc > 0 ? strerror(rc) : ""), rc);
    00431             _dbapi = -1;
    00432         }
    00433         break;
    00434     case -1:
    00435         _dbapi = 4;
    00436         while (_dbapi-- > 1) {
    00437             if (mydbvecs[_dbapi] == NULL)
    00438                 continue;
    00439             /*@-mods@*/
    00440             errno = 0;
    00441             /*@=mods@*/
    00442             dbi = NULL;
    00443             rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi);
    00444             if (rc == 0 && dbi)
    00445                 /*@loopbreak@*/ break;
    00446         }
    00447         if (_dbapi <= 0) {
    00448             static int _printed[32];
    00449             if (!_printed[dbix & 0x1f]++)
    00450                 rpmError(RPMERR_DBOPEN, _("cannot open %s index\n"),
    00451                         tagName(rpmtag));
    00452             rc = 1;
    00453             goto exit;
    00454         }
    00455         if (db->db_api == -1 && _dbapi > 0)
    00456             db->db_api = _dbapi;
    00457         break;
    00458     }
    00459
    00460     /* Require conversion. */
    00461     if (rc && _dbapi_wanted >= 0 && _dbapi != _dbapi_wanted && _dbapi_wanted == _dbapi_rebuild) {
    00462         rc = (_rebuildinprogress ? 0 : 1);
    00463         goto exit;
    00464     }
    00465
    00466     /* Suggest possible configuration */
    00467     if (_dbapi_wanted >= 0 && _dbapi != _dbapi_wanted) {
    00468         rc = 1;
    00469         goto exit;
    00470     }
    00471
    00472     /* Suggest possible configuration */
    00473     if (_dbapi_wanted < 0 && _dbapi != _dbapi_rebuild) {
    00474         rc = (_rebuildinprogress ? 0 : 1);
    00475         goto exit;
    00476     }
    00477
    00478 exit:
    00479     if (rc == 0 && dbi)
    00480         db->_dbi[dbix] = dbi;
    00481     else
    00482         dbi = db3Free(dbi);
    00483
    00484     return dbi;
    00485 }
    00486
    00493 static INLINE dbiIndexItem dbiIndexNewItem(unsigned int hdrNum, unsigned int tagNum)
    00494         /*@*/
    00495 {
    00496     dbiIndexItem rec = xcalloc(1, sizeof(*rec));
    00497     rec->hdrNum = hdrNum;
    00498     rec->tagNum = tagNum;
    00499     return rec;
    00500 }
    00501
    00502 union _dbswap {
    00503     unsigned int ui;
    00504     unsigned char uc[4];
    00505 };
    00506
    00507 #define _DBSWAP(_a) \
    00508   { unsigned char _b, *_c = (_a).uc; \
    00509     _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
    00510     _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
    00511   }
    00512
    00522 static int dbiSearch(dbiIndex dbi, DBC * dbcursor,
    00523                 const char * keyp, size_t keylen, /*@out@*/ dbiIndexSet * setp)
    00524         /*@globals fileSystem @*/
    00525         /*@modifies *dbcursor, *setp, fileSystem @*/
    00526 {
    00527     unsigned int gflags = 0;    /* dbiGet() flags */
    00528     void * datap = NULL;
    00529     size_t datalen = 0;
    00530     int rc;
    00531
    00532     if (setp) *setp = NULL;
    00533     if (keylen == 0) keylen = strlen(keyp);
    00534
    00535     /*@-mods@*/         /* FIX: indirection @*/
    00536     rc = dbiGet(dbi, dbcursor, (void **)&keyp, &keylen, &datap, &datalen,
    00537                 gflags);
    00538     /*@=mods@*/
    00539
    00540     if (rc > 0) {
    00541         rpmError(RPMERR_DBGETINDEX,
    00542                 _("error(%d) getting \"%s\" records from %s index\n"),
    00543                 rc, keyp, tagName(dbi->dbi_rpmtag));
    00544     } else
    00545     if (rc == 0 && setp) {
    00546         int _dbbyteswapped = dbiByteSwapped(dbi);
    00547         const char * sdbir = datap;
    00548         dbiIndexSet set;
    00549         int i;
    00550
    00551         set = xmalloc(sizeof(*set));
    00552
    00553         /* Convert to database internal format */
    00554         if (sdbir)
    00555         switch (dbi->dbi_jlen) {
    00556         default:
    00557         case 2*sizeof(int_32):
    00558             set->count = datalen / (2*sizeof(int_32));
    00559             set->recs = xmalloc(set->count * sizeof(*(set->recs)));
    00560             for (i = 0; i < set->count; i++) {
    00561                 union _dbswap hdrNum, tagNum;
    00562
    00563                 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
    00564                 sdbir += sizeof(hdrNum.ui);
    00565                 memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
    00566                 sdbir += sizeof(tagNum.ui);
    00567                 if (_dbbyteswapped) {
    00568                     _DBSWAP(hdrNum);
    00569                     _DBSWAP(tagNum);
    00570                 }
    00571                 set->recs[i].hdrNum = hdrNum.ui;
    00572                 set->recs[i].tagNum = tagNum.ui;
    00573                 set->recs[i].fpNum = 0;
    00574                 set->recs[i].dbNum = 0;
    00575             }
    00576             break;
    00577         case 1*sizeof(int_32):
    00578             set->count = datalen / (1*sizeof(int_32));
    00579             set->recs = xmalloc(set->count * sizeof(*(set->recs)));
    00580             for (i = 0; i < set->count; i++) {
    00581                 union _dbswap hdrNum;
    00582
    00583                 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
    00584                 sdbir += sizeof(hdrNum.ui);
    00585                 if (_dbbyteswapped) {
    00586                     _DBSWAP(hdrNum);
    00587                 }
    00588                 set->recs[i].hdrNum = hdrNum.ui;
    00589                 set->recs[i].tagNum = 0;
    00590                 set->recs[i].fpNum = 0;
    00591                 set->recs[i].dbNum = 0;
    00592             }
    00593             break;
    00594         }
    00595         /*@-branchstate@*/
    00596         if (setp) *setp = set;
    00597         /*@=branchstate@*/
    00598     }
    00599     return rc;
    00600 }
    00601
    00611 /*@-compmempass -mustmod@*/
    00612 static int dbiUpdateIndex(dbiIndex dbi, DBC * dbcursor,
    00613                 const void * keyp, size_t keylen, dbiIndexSet set)
    00614         /*@globals fileSystem @*/
    00615         /*@modifies *dbcursor, set, fileSystem @*/
    00616 {
    00617     unsigned int pflags = 0;    /* dbiPut() flags */
    00618     unsigned int dflags = 0;    /* dbiDel() flags */
    00619     void * datap;
    00620     size_t datalen;
    00621     int rc;
    00622
    00623     if (set->count) {
    00624         char * tdbir;
    00625         int i;
    00626         int _dbbyteswapped = dbiByteSwapped(dbi);
    00627
    00628         /* Convert to database internal format */
    00629
    00630         switch (dbi->dbi_jlen) {
    00631         default:
    00632         case 2*sizeof(int_32):
    00633             datalen = set->count * (2 * sizeof(int_32));
    00634             datap = tdbir = alloca(datalen);
    00635             for (i = 0; i < set->count; i++) {
    00636                 union _dbswap hdrNum, tagNum;
    00637
    00638                 memset(&hdrNum, 0, sizeof(hdrNum));
    00639                 memset(&tagNum, 0, sizeof(tagNum));
    00640                 hdrNum.ui = set->recs[i].hdrNum;
    00641                 tagNum.ui = set->recs[i].tagNum;
    00642                 if (_dbbyteswapped) {
    00643                     _DBSWAP(hdrNum);
    00644                     _DBSWAP(tagNum);
    00645                 }
    00646                 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
    00647                 tdbir += sizeof(hdrNum.ui);
    00648                 memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
    00649                 tdbir += sizeof(tagNum.ui);
    00650             }
    00651             break;
    00652         case 1*sizeof(int_32):
    00653             datalen = set->count * (1 * sizeof(int_32));
    00654             datap = tdbir = alloca(datalen);
    00655             for (i = 0; i < set->count; i++) {
    00656                 union _dbswap hdrNum;
    00657
    00658                 memset(&hdrNum, 0, sizeof(hdrNum));
    00659                 hdrNum.ui = set->recs[i].hdrNum;
    00660                 if (_dbbyteswapped) {
    00661                     _DBSWAP(hdrNum);
    00662                 }
    00663                 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
    00664                 tdbir += sizeof(hdrNum.ui);
    00665             }
    00666             break;
    00667         }
    00668
    00669         rc = dbiPut(dbi, dbcursor, keyp, keylen, datap, datalen, pflags);
    00670
    00671         if (rc) {
    00672             rpmError(RPMERR_DBPUTINDEX,
    00673                 _("error(%d) storing record %s into %s\n"),
    00674                 rc, keyp, tagName(dbi->dbi_rpmtag));
    00675         }
    00676
    00677     } else {
    00678
    00679         rc = dbiDel(dbi, dbcursor, keyp, keylen, dflags);
    00680
    00681         if (rc) {
    00682             rpmError(RPMERR_DBPUTINDEX,
    00683                 _("error(%d) removing record %s from %s\n"),
    00684                 rc, keyp, tagName(dbi->dbi_rpmtag));
    00685         }
    00686
    00687     }
    00688
    00689     return rc;
    00690 }
    00691 /*@=compmempass =mustmod@*/
    00692
    00693 /* XXX assumes hdrNum is first int in dbiIndexItem */
    00694 static int hdrNumCmp(const void * one, const void * two)
    00695         /*@*/
    00696 {
    00697     const int * a = one, * b = two;
    00698     return (*a - *b);
    00699 }
    00700
    00710 static INLINE int dbiAppendSet(dbiIndexSet set, const void * recs,
    00711         int nrecs, size_t recsize, int sortset)
    00712         /*@modifies *set @*/
    00713 {
    00714     const char * rptr = recs;
    00715     size_t rlen = (recsize < sizeof(*(set->recs)))
    00716                 ? recsize : sizeof(*(set->recs));
    00717
    00718     if (set == NULL || recs == NULL || nrecs <= 0 || recsize == 0)
    00719         return 1;
    00720
    00721     set->recs = xrealloc(set->recs,
    00722                         (set->count + nrecs) * sizeof(*(set->recs)));
    00723
    00724     memset(set->recs + set->count, 0, nrecs * sizeof(*(set->recs)));
    00725
    00726     while (nrecs-- > 0) {
    00727         /*@-mayaliasunique@*/
    00728         memcpy(set->recs + set->count, rptr, rlen);
    00729         /*@=mayaliasunique@*/
    00730         rptr += recsize;
    00731         set->count++;
    00732     }
    00733
    00734     if (set->count > 1 && sortset)
    00735         qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
    00736
    00737     /*@-compmempass@*/ /* FIX: set->recs.{hdrNum,tagNum,fpNum,dbNum} undef */
    00738     return 0;
    00739     /*@=compmempass@*/
    00740 }
    00741
    00751 static INLINE int dbiPruneSet(dbiIndexSet set, void * recs, int nrecs,
    00752                 size_t recsize, int sorted)
    00753         /*@modifies set, recs @*/
    00754 {
    00755     int from;
    00756     int to = 0;
    00757     int num = set->count;
    00758     int numCopied = 0;
    00759
    00760     if (nrecs > 1 && !sorted)
    00761         qsort(recs, nrecs, recsize, hdrNumCmp);
    00762
    00763     for (from = 0; from < num; from++) {
    00764         if (bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) {
    00765             set->count--;
    00766             continue;
    00767         }
    00768         if (from != to)
    00769             set->recs[to] = set->recs[from]; /* structure assignment */
    00770         to++;
    00771         numCopied++;
    00772     }
    00773
    00774     return (numCopied == num);
    00775 }
    00776
    00777 /* XXX transaction.c */
    00778 unsigned int dbiIndexSetCount(dbiIndexSet set) {
    00779     return set->count;
    00780 }
    00781
    00782 /* XXX transaction.c */
    00783 unsigned int dbiIndexRecordOffset(dbiIndexSet set, int recno) {
    00784     return set->recs[recno].hdrNum;
    00785 }
    00786
    00787 /* XXX transaction.c */
    00788 unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, int recno) {
    00789     return set->recs[recno].tagNum;
    00790 }
    00791
    00792 /* XXX transaction.c */
    00793 dbiIndexSet dbiFreeIndexSet(dbiIndexSet set) {
    00794     if (set) {
    00795         set->recs = _free(set->recs);
    00796         set = _free(set);
    00797     }
    00798     return set;
    00799 }
    00800
    00804 static int blockSignals(/*@unused@*/ rpmdb db, /*@out@*/ sigset_t * oldMask)
    00805         /*@globals fileSystem @*/
    00806         /*@modifies *oldMask, fileSystem @*/
    00807 {
    00808     sigset_t newMask;
    00809
    00810     (void) sigfillset(&newMask);                /* block all signals */
    00811     return sigprocmask(SIG_BLOCK, &newMask, oldMask);
    00812 }
    00813
    00817 static int unblockSignals(/*@unused@*/ rpmdb db, sigset_t * oldMask)
    00818         /*@globals fileSystem @*/
    00819         /*@modifies fileSystem @*/
    00820 {
    00821     return sigprocmask(SIG_SETMASK, oldMask, NULL);
    00822 }
    00823
    00824 #define _DB_ROOT        "/"
    00825 #define _DB_HOME        "%{_dbpath}"
    00826 #define _DB_FLAGS       0
    00827 #define _DB_MODE        0
    00828 #define _DB_PERMS       0644
    00829
    00830 #define _DB_MAJOR       -1
    00831 #define _DB_ERRPFX      "rpmdb"
    00832
    00833 /*@-fullinitblock@*/
    00834 /*@observer@*/ /*@unchecked@*/
    00835 static struct rpmdb_s dbTemplate = {
    00836     _DB_ROOT,   _DB_HOME, _DB_FLAGS, _DB_MODE, _DB_PERMS,
    00837     _DB_MAJOR,  _DB_ERRPFX
    00838 };
    00839 /*@=fullinitblock@*/
    00840
    00841 int rpmdbOpenAll(rpmdb db)
    00842 {
    00843     int dbix;
    00844     int rc = 0;
    00845
    00846     if (db == NULL) return -2;
    00847
    00848     if (dbiTags != NULL)
    00849     for (dbix = 0; dbix < dbiTagsMax; dbix++) {
    00850         if (db->_dbi[dbix] != NULL)
    00851             continue;
    00852         (void) dbiOpen(db, dbiTags[dbix], db->db_flags);
    00853     }
    00854     return rc;
    00855 }
    00856
    00857 /* XXX query.c, rpminstall.c, verify.c */
    00858 int rpmdbClose(rpmdb db)
    00859 {
    00860     int dbix;
    00861     int rc = 0;
    00862
    00863     if (db == NULL)
    00864         return 0;
    00865
    00866     if (db->_dbi)
    00867     for (dbix = db->db_ndbi; --dbix >= 0; ) {
    00868         int xx;
    00869         if (db->_dbi[dbix] == NULL)
    00870             continue;
    00871         /*@-unqualifiedtrans@*/         /* FIX: double indirection. */
    00872         xx = dbiClose(db->_dbi[dbix], 0);
    00873         if (xx && rc == 0) rc = xx;
    00874         db->_dbi[dbix] = NULL;
    00875         /*@=unqualifiedtrans@*/
    00876     }
    00877     db->db_errpfx = _free(db->db_errpfx);
    00878     db->db_root = _free(db->db_root);
    00879     db->db_home = _free(db->db_home);
    00880     db->_dbi = _free(db->_dbi);
    00881     db = _free(db);
    00882     return rc;
    00883 }
    00884
    00885 int rpmdbSync(rpmdb db)
    00886 {
    00887     int dbix;
    00888     int rc = 0;
    00889
    00890     if (db == NULL) return 0;
    00891     for (dbix = 0; dbix < db->db_ndbi; dbix++) {
    00892         int xx;
    00893         if (db->_dbi[dbix] == NULL)
    00894             continue;
    00895         xx = dbiSync(db->_dbi[dbix], 0);
    00896         if (xx && rc == 0) rc = xx;
    00897     }
    00898     return rc;
    00899 }
    00900
    00901 /*@-mods@*/
    00902 static /*@only@*/ /*@null@*/
    00903 rpmdb newRpmdb(/*@kept@*/ /*@null@*/ const char * root,
    00904                 /*@kept@*/ /*@null@*/ const char * home,
    00905                 int mode, int perms, int flags)
    00906         /*@globals _db_filter_dups, rpmGlobalMacroContext @*/
    00907         /*@modifies _db_filter_dups, rpmGlobalMacroContext @*/
    00908 {
    00909     rpmdb db = xcalloc(sizeof(*db), 1);
    00910     const char * epfx = _DB_ERRPFX;
    00911     static int _initialized = 0;
    00912
    00913     if (!_initialized) {
    00914         _db_filter_dups = rpmExpandNumeric("%{_filterdbdups}");
    00915         _initialized = 1;
    00916     }
    00917
    00918     /*@-assignexpose@*/
    00919     *db = dbTemplate;   /* structure assignment */
    00920     /*@=assignexpose@*/
    00921
    00922     db->_dbi = NULL;
    00923
    00924     if (!(perms & 0600)) perms = 0644;  /* XXX sanity */
    00925
    00926     if (mode >= 0)      db->db_mode = mode;
    00927     if (perms >= 0)     db->db_perms = perms;
    00928     if (flags >= 0)     db->db_flags = flags;
    00929
    00930     /*@-nullpass@*/
    00931     db->db_root = rpmGetPath( (root && *root ? root : _DB_ROOT), NULL);
    00932     db->db_home = rpmGetPath( (home && *home ? home : _DB_HOME), NULL);
    00933     /*@=nullpass@*/
    00934     if (!(db->db_home && db->db_home[0] != '%')) {
    00935         rpmError(RPMERR_DBOPEN, _("no dbpath has been set\n"));
    00936         db->db_root = _free(db->db_root);
    00937         db->db_home = _free(db->db_home);
    00938         db = _free(db);
    00939         /*@-globstate@*/ return NULL; /*@=globstate@*/
    00940     }
    00941     /*@-nullpass@*/
    00942     db->db_errpfx = rpmExpand( (epfx && *epfx ? epfx : _DB_ERRPFX), NULL);
    00943     /*@=nullpass@*/
    00944     db->db_remove_env = 0;
    00945     db->db_filter_dups = _db_filter_dups;
    00946     db->db_ndbi = dbiTagsMax;
    00947     db->_dbi = xcalloc(db->db_ndbi, sizeof(*db->_dbi));
    00948     /*@-globstate@*/ return db; /*@=globstate@*/
    00949 }
    00950
    00951 static int openDatabase(/*@null@*/ const char * prefix,
    00952                 /*@null@*/ const char * dbpath,
    00953                 int _dbapi, /*@null@*/ /*@out@*/ rpmdb *dbp,
    00954                 int mode, int perms, int flags)
    00955         /*@globals rpmGlobalMacroContext,
    00956                 fileSystem @*/
    00957         /*@modifies *dbp, fileSystem @*/
    00958 {
    00959     rpmdb db;
    00960     int rc, xx;
    00961     unsigned int gflags = 0;    /* dbiGet() flags */
    00962     static int _tags_initialized = 0;
    00963     static int _dbenv_removed = 0;
    00964     int justCheck = flags & RPMDB_FLAG_JUSTCHECK;
    00965     int minimal = flags & RPMDB_FLAG_MINIMAL;
    00966
    00967     if (!_tags_initialized || dbiTagsMax == 0) {
    00968         /*@-mods@*/
    00969         dbiTagsInit();
    00970         /*@=mods@*/
    00971         _tags_initialized++;
    00972     }
    00973
    00974     /* Insure that _dbapi has one of -1, 1, 2, or 3 */
    00975     if (_dbapi < -1 || _dbapi > 3)
    00976         _dbapi = -1;
    00977     if (_dbapi == 0)
    00978         _dbapi = 1;
    00979
    00980     if (dbp)
    00981         *dbp = NULL;
    00982     if (mode & O_WRONLY)
    00983         return 1;
    00984
    00985     /*@-mods@*/
    00986     db = newRpmdb(prefix, dbpath, mode, perms, flags);
    00987     /*@=mods@*/
    00988     if (db == NULL)
    00989         return 1;
    00990
    00991     if (!_dbenv_removed) {
    00992         static int _enable_cdb = -1;
    00993
    00994         /* XXX hack in suoport for CDB, otherwise nuke the state. */
    00995         /*@-mods@*/
    00996         if (_enable_cdb < 0)
    00997             _enable_cdb = rpmExpandNumeric("%{?__dbi_cdb:1}");
    00998         /*@=mods@*/
    00999
    01000         if (!_enable_cdb) {
    01001             char * fn;
    01002             int i;
    01003
    01004             i = sizeof("//__db.000");
    01005             if (db->db_root) i += strlen(db->db_root);
    01006             if (db->db_home) i += strlen(db->db_home);
    01007             fn = alloca(i);
    01008             for (i = 0; i < 16; i++) {
    01009                 sprintf(fn, "%s/%s/__db.%03d",
    01010                         (db->db_root ? db->db_root : ""),
    01011                         (db->db_home ? db->db_home : ""),  i);
    01012                 (void) rpmCleanPath(fn);
    01013                 (void) unlink(fn);
    01014             }
    01015         }
    01016         _dbenv_removed++;
    01017     }
    01018
    01019     db->db_api = _dbapi;
    01020
    01021     {   int dbix;
    01022
    01023         rc = 0;
    01024         if (dbiTags != NULL)
    01025         for (dbix = 0; rc == 0 && dbix < dbiTagsMax; dbix++) {
    01026             dbiIndex dbi;
    01027             int rpmtag;
    01028
    01029             /* Filter out temporary databases */
    01030             switch ((rpmtag = dbiTags[dbix])) {
    01031             case RPMDBI_AVAILABLE:
    01032             case RPMDBI_ADDED:
    01033             case RPMDBI_REMOVED:
    01034             case RPMDBI_DEPENDS:
    01035                 continue;
    01036                 /*@notreached@*/ /*@switchbreak@*/ break;
    01037             default:
    01038                 /*@switchbreak@*/ break;
    01039             }
    01040
    01041             dbi = dbiOpen(db, rpmtag, 0);
    01042             if (dbi == NULL) {
    01043                 rc = -2;
    01044                 break;
    01045             }
    01046
    01047             switch (rpmtag) {
    01048             case RPMDBI_PACKAGES:
    01049                 if (dbi == NULL) rc |= 1;
    01050                 /* XXX open only Packages, indices created on the fly. */
    01051 #if 0
    01052                 if (db->db_api == 3)
    01053 #endif
    01054                     goto exit;
    01055                 /*@notreached@*/ /*@switchbreak@*/ break;
    01056             case RPMTAG_NAME:
    01057                 if (dbi == NULL) rc |= 1;
    01058                 if (minimal)
    01059                     goto exit;
    01060                 /*@switchbreak@*/ break;
    01061             case RPMTAG_BASENAMES:
    01062             {   void * keyp = NULL;
    01063                 DBC * dbcursor;
    01064
    01065     /* We used to store the fileindexes as complete paths, rather then
    01066        plain basenames. Let's see which version we are... */
    01067     /*
    01068      * XXX FIXME: db->fileindex can be NULL under pathological (e.g. mixed
    01069      * XXX db1/db2 linkage) conditions.
    01070      */
    01071                 if (justCheck)
    01072                     /*@switchbreak@*/ break;
    01073                 dbcursor = NULL;
    01074                 xx = dbiCopen(dbi, &dbcursor, 0);
    01075                 xx = dbiGet(dbi, dbcursor, &keyp, NULL, NULL, NULL, gflags);
    01076                 if (xx == 0) {
    01077                     const char * akey = keyp;
    01078                     if (akey && strchr(akey, '/')) {
    01079                         rpmError(RPMERR_OLDDB, _("old format database is present; "
    01080                                 "use --rebuilddb to generate a new format database\n"));
    01081                         rc |= 1;
    01082                     }
    01083                 }
    01084                 xx = dbiCclose(dbi, dbcursor, 0);
    01085                 dbcursor = NULL;
    01086             }   /*@switchbreak@*/ break;
    01087             default:
    01088                 /*@switchbreak@*/ break;
    01089             }
    01090         }
    01091     }
    01092
    01093 exit:
    01094     if (rc || justCheck || dbp == NULL)
    01095         xx = rpmdbClose(db);
    01096     else
    01097         *dbp = db;
    01098
    01099     return rc;
    01100 }
    01101
    01102 /* XXX python/rpmmodule.c */
    01103 /*@-globs@*/ /* FIX: rpmGlobalMacroContext not in <rpmlib.h> */
    01104 int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, int perms)
    01105 {
    01106     /*@-mods@*/
    01107     int _dbapi = rpmExpandNumeric("%{_dbapi}");
    01108     /*@=mods@*/
    01109     return openDatabase(prefix, NULL, _dbapi, dbp, mode, perms, 0);
    01110 }
    01111
    01112 int rpmdbInit (const char * prefix, int perms)
    01113 {
    01114     rpmdb db = NULL;
    01115     /*@-mods@*/
    01116     int _dbapi = rpmExpandNumeric("%{_dbapi}");
    01117     /*@=mods@*/
    01118     int rc;
    01119
    01120     rc = openDatabase(prefix, NULL, _dbapi, &db, (O_CREAT | O_RDWR),
    01121                 perms, RPMDB_FLAG_JUSTCHECK);
    01122     if (db != NULL) {
    01123         int xx;
    01124         xx = rpmdbOpenAll(db);
    01125         if (xx && rc == 0) rc = xx;
    01126         xx = rpmdbClose(db);
    01127         if (xx && rc == 0) rc = xx;
    01128         db = NULL;
    01129     }
    01130     return rc;
    01131 }
    01132
    01133 int rpmdbVerify(const char * prefix)
    01134 {
    01135     rpmdb db = NULL;
    01136     /*@-mods@*/
    01137     int _dbapi = rpmExpandNumeric("%{_dbapi}");
    01138     /*@=mods@*/
    01139     int rc = 0;
    01140
    01141     rc = openDatabase(prefix, NULL, _dbapi, &db, O_RDONLY, 0644, 0);
    01142     if (rc) return rc;
    01143
    01144     if (db != NULL) {
    01145         int dbix;
    01146         int xx;
    01147         rc = rpmdbOpenAll(db);
    01148
    01149         for (dbix = db->db_ndbi; --dbix >= 0; ) {
    01150             if (db->_dbi[dbix] == NULL)
    01151                 continue;
    01152             /*@-unqualifiedtrans@*/             /* FIX: double indirection. */
    01153             xx = dbiVerify(db->_dbi[dbix], 0);
    01154             if (xx && rc == 0) rc = xx;
    01155             db->_dbi[dbix] = NULL;
    01156             /*@=unqualifiedtrans@*/
    01157         }
    01158
    01159         /*@-nullstate@*/        /* FIX: db->_dbi[] may be NULL. */
    01160         xx = rpmdbClose(db);
    01161         /*@=nullstate@*/
    01162         if (xx && rc == 0) rc = xx;
    01163         db = NULL;
    01164     }
    01165     return rc;
    01166 }
    01167 /*@=globs@*/
    01168
    01169 static int rpmdbFindByFile(rpmdb db, /*@null@*/ const char * filespec,
    01170                         /*@out@*/ dbiIndexSet * matches)
    01171         /*@globals fileSystem @*/
    01172         /*@modifies db, *matches, fileSystem @*/
    01173 {
    01174     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    01175     HFD_t hfd = headerFreeData;
    01176     const char * dirName;
    01177     const char * baseName;
    01178     rpmTagType bnt, dnt;
    01179     fingerPrintCache fpc;
    01180     fingerPrint fp1;
    01181     dbiIndex dbi = NULL;
    01182     DBC * dbcursor;
    01183     dbiIndexSet allMatches = NULL;
    01184     dbiIndexItem rec = NULL;
    01185     int i;
    01186     int rc;
    01187     int xx;
    01188
    01189     *matches = NULL;
    01190     if (filespec == NULL) return -2;
    01191     /*@-branchstate@*/
    01192     if ((baseName = strrchr(filespec, '/')) != NULL) {
    01193         char * t;
    01194         size_t len;
    01195
    01196         len = baseName - filespec + 1;
    01197         t = strncpy(alloca(len + 1), filespec, len);
    01198         t[len] = '\0';
    01199         dirName = t;
    01200         baseName++;
    01201     } else {
    01202         dirName = "";
    01203         baseName = filespec;
    01204     }
    01205     /*@=branchstate@*/
    01206     if (baseName == NULL)
    01207         return -2;
    01208
    01209     fpc = fpCacheCreate(20);
    01210     fp1 = fpLookup(fpc, dirName, baseName, 1);
    01211
    01212     dbi = dbiOpen(db, RPMTAG_BASENAMES, 0);
    01213     if (dbi != NULL) {
    01214         dbcursor = NULL;
    01215         xx = dbiCopen(dbi, &dbcursor, 0);
    01216         rc = dbiSearch(dbi, dbcursor, baseName, strlen(baseName), &allMatches);
    01217         xx = dbiCclose(dbi, dbcursor, 0);
    01218         dbcursor = NULL;
    01219     } else
    01220         rc = -2;
    01221
    01222     if (rc) {
    01223         allMatches = dbiFreeIndexSet(allMatches);
    01224         fpCacheFree(fpc);
    01225         return rc;
    01226     }
    01227
    01228     *matches = xcalloc(1, sizeof(**matches));
    01229     rec = dbiIndexNewItem(0, 0);
    01230     i = 0;
    01231     if (allMatches != NULL)
    01232     while (i < allMatches->count) {
    01233         const char ** baseNames, ** dirNames;
    01234         int_32 * dirIndexes;
    01235         unsigned int offset = dbiIndexRecordOffset(allMatches, i);
    01236         unsigned int prevoff;
    01237         Header h;
    01238
    01239         {   rpmdbMatchIterator mi;
    01240             mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &offset, sizeof(offset));
    01241             h = rpmdbNextIterator(mi);
    01242             if (h)
    01243                 h = headerLink(h);
    01244             mi = rpmdbFreeIterator(mi);
    01245         }
    01246
    01247         if (h == NULL) {
    01248             i++;
    01249             continue;
    01250         }
    01251
    01252         xx = hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, NULL);
    01253         xx = hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
    01254         xx = hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
    01255
    01256         do {
    01257             fingerPrint fp2;
    01258             int num = dbiIndexRecordFileNumber(allMatches, i);
    01259
    01260             fp2 = fpLookup(fpc, dirNames[dirIndexes[num]], baseNames[num], 1);
    01261             /*@-nullpass@*/
    01262             if (FP_EQUAL(fp1, fp2)) {
    01263             /*@=nullpass@*/
    01264                 rec->hdrNum = dbiIndexRecordOffset(allMatches, i);
    01265                 rec->tagNum = dbiIndexRecordFileNumber(allMatches, i);
    01266                 xx = dbiAppendSet(*matches, rec, 1, sizeof(*rec), 0);
    01267             }
    01268
    01269             prevoff = offset;
    01270             i++;
    01271             offset = dbiIndexRecordOffset(allMatches, i);
    01272         } while (i < allMatches->count &&
    01273                 (i == 0 || offset == prevoff));
    01274
    01275         baseNames = hfd(baseNames, bnt);
    01276         dirNames = hfd(dirNames, dnt);
    01277         h = headerFree(h);
    01278     }
    01279
    01280     rec = _free(rec);
    01281     allMatches = dbiFreeIndexSet(allMatches);
    01282
    01283     fpCacheFree(fpc);
    01284
    01285     if ((*matches)->count == 0) {
    01286         *matches = dbiFreeIndexSet(*matches);
    01287         return 1;
    01288     }
    01289
    01290     return 0;
    01291 }
    01292
    01293 /* XXX python/upgrade.c, install.c, uninstall.c */
    01294 int rpmdbCountPackages(rpmdb db, const char * name)
    01295 {
    01296     dbiIndex dbi;
    01297     dbiIndexSet matches = NULL;
    01298     int rc = -1;
    01299     int xx;
    01300
    01301     if (db == NULL)
    01302         return 0;
    01303
    01304     /* XXX
    01305      * There's a segfault here with CDB access, let's treat the symptom
    01306      * while diagnosing the disease.
    01307      */
    01308     if (name == NULL || *name == '\0')
    01309         return 0;
    01310
    01311     dbi = dbiOpen(db, RPMTAG_NAME, 0);
    01312     if (dbi) {
    01313         DBC * dbcursor = NULL;
    01314         xx = dbiCopen(dbi, &dbcursor, 0);
    01315         rc = dbiSearch(dbi, dbcursor, name, strlen(name), &matches);
    01316         xx = dbiCclose(dbi, dbcursor, 0);
    01317         dbcursor = NULL;
    01318     }
    01319
    01320     /*@-nullpass@*/ /* FIX: matches might be NULL */
    01321     if (rc == 0)        /* success */
    01322         rc = dbiIndexSetCount(matches);
    01323     else if (rc > 0)    /* error */
    01324         rpmError(RPMERR_DBCORRUPT, _("error(%d) counting packages\n"), rc);
    01325     else                /* not found */
    01326         rc = 0;
    01327     /*@=nullpass@*/
    01328
    01329     matches = dbiFreeIndexSet(matches);
    01330
    01331     return rc;
    01332 }
    01333
    01334 /* XXX transaction.c */
    01335 /* 0 found matches */
    01336 /* 1 no matches */
    01337 /* 2 error */
    01348 static int dbiFindMatches(dbiIndex dbi, DBC * dbcursor,
    01349                 const char * name,
    01350                 /*@null@*/ const char * version,
    01351                 /*@null@*/ const char * release,
    01352                 /*@out@*/ dbiIndexSet * matches)
    01353         /*@globals fileSystem @*/
    01354         /*@modifies dbi, *dbcursor, *matches, fileSystem @*/
    01355 {
    01356     int gotMatches;
    01357     int rc;
    01358     int i;
    01359
    01360     rc = dbiSearch(dbi, dbcursor, name, strlen(name), matches);
    01361
    01362     if (rc != 0) {
    01363         rc = ((rc == -1) ? 2 : 1);
    01364         goto exit;
    01365     }
    01366
    01367     if (version == NULL && release == NULL) {
    01368         rc = 0;
    01369         goto exit;
    01370     }
    01371
    01372     gotMatches = 0;
    01373
    01374     /* Make sure the version and release match. */
    01375     /*@-branchstate@*/
    01376     for (i = 0; i < dbiIndexSetCount(*matches); i++) {
    01377         unsigned int recoff = dbiIndexRecordOffset(*matches, i);
    01378         Header h;
    01379
    01380         if (recoff == 0)
    01381             continue;
    01382
    01383         {   rpmdbMatchIterator mi;
    01384             mi = rpmdbInitIterator(dbi->dbi_rpmdb,
    01385                         RPMDBI_PACKAGES, &recoff, sizeof(recoff));
    01386
    01387             /* Set iterator selectors for version/release if available. */
    01388             if (version &&
    01389                 rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version))
    01390             {
    01391                 rc = 2;
    01392                 goto exit;
    01393             }
    01394             if (release &&
    01395                 rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release))
    01396             {
    01397                 rc = 2;
    01398                 goto exit;
    01399             }
    01400
    01401             h = rpmdbNextIterator(mi);
    01402             if (h)
    01403                 h = headerLink(h);
    01404             mi = rpmdbFreeIterator(mi);
    01405         }
    01406
    01407         if (h)  /* structure assignment */
    01408             (*matches)->recs[gotMatches++] = (*matches)->recs[i];
    01409         else
    01410             (*matches)->recs[i].hdrNum = 0;
    01411
    01412         h = headerFree(h);
    01413     }
    01414     /*@=branchstate@*/
    01415
    01416     if (gotMatches) {
    01417         (*matches)->count = gotMatches;
    01418         rc = 0;
    01419     } else
    01420         rc = 1;
    01421
    01422 exit:
    01423     if (rc && matches && *matches) {
    01424         /*@-unqualifiedtrans@*/         /* FIX: double indirection */
    01425         *matches = dbiFreeIndexSet(*matches);
    01426         /*@=unqualifiedtrans@*/
    01427     }
    01428     return rc;
    01429 }
    01430
    01441 static int dbiFindByLabel(dbiIndex dbi, DBC * dbcursor,
    01442                 /*@null@*/ const char * arg, /*@out@*/ dbiIndexSet * matches)
    01443         /*@globals fileSystem @*/
    01444         /*@modifies dbi, *dbcursor, *matches, fileSystem @*/
    01445 {
    01446     const char * release;
    01447     char * localarg;
    01448     char * s;
    01449     char c;
    01450     int brackets;
    01451     int rc;
    01452
    01453     if (arg == NULL || strlen(arg) == 0) return 1;
    01454
    01455     /* did they give us just a name? */
    01456     rc = dbiFindMatches(dbi, dbcursor, arg, NULL, NULL, matches);
    01457     if (rc != 1) return rc;
    01458
    01459     /*@-unqualifiedtrans@*/
    01460     *matches = dbiFreeIndexSet(*matches);
    01461     /*@=unqualifiedtrans@*/
    01462
    01463     /* maybe a name and a release */
    01464     localarg = alloca(strlen(arg) + 1);
    01465     s = stpcpy(localarg, arg);
    01466
    01467     c = '\0';
    01468     brackets = 0;
    01469     for (s -= 1; s > localarg; s--) {
    01470         switch (*s) {
    01471         case '[':
    01472             brackets = 1;
    01473             /*@switchbreak@*/ break;
    01474         case ']':
    01475             if (c != '[') brackets = 0;
    01476             /*@switchbreak@*/ break;
    01477         }
    01478         c = *s;
    01479         if (!brackets && *s == '-')
    01480             break;
    01481     }
    01482
    01483     /*@-nullstate@*/    /* FIX: *matches may be NULL. */
    01484     if (s == localarg) return 1;
    01485
    01486     *s = '\0';
    01487     rc = dbiFindMatches(dbi, dbcursor, localarg, s + 1, NULL, matches);
    01488     if (rc != 1) return rc;
    01489
    01490     /*@-unqualifiedtrans@*/
    01491     *matches = dbiFreeIndexSet(*matches);
    01492     /*@=unqualifiedtrans@*/
    01493
    01494     /* how about name-version-release? */
    01495
    01496     release = s + 1;
    01497
    01498     c = '\0';
    01499     brackets = 0;
    01500     for (; s > localarg; s--) {
    01501         switch (*s) {
    01502         case '[':
    01503             brackets = 1;
    01504             /*@switchbreak@*/ break;
    01505         case ']':
    01506             if (c != '[') brackets = 0;
    01507             /*@switchbreak@*/ break;
    01508         }
    01509         c = *s;
    01510         if (!brackets && *s == '-')
    01511             break;
    01512     }
    01513
    01514     if (s == localarg) return 1;
    01515
    01516     *s = '\0';
    01517     return dbiFindMatches(dbi, dbcursor, localarg, s + 1, release, matches);
    01518     /*@=nullstate@*/
    01519 }
    01520
    01531 static int dbiUpdateRecord(dbiIndex dbi, DBC * dbcursor, int offset, Header h)
    01532         /*@globals fileSystem @*/
    01533         /*@modifies *dbcursor, h, fileSystem @*/
    01534 {
    01535     sigset_t signalMask;
    01536     void * uh;
    01537     size_t uhlen;
    01538     int rc = EINVAL;    /* XXX W2DO? */
    01539     unsigned int pflags = 0;    /* dbiPut() flags */
    01540     int xx;
    01541
    01542     if (_noDirTokens)
    01543         expandFilelist(h);
    01544
    01545     uhlen = headerSizeof(h, HEADER_MAGIC_NO);
    01546     uh = headerUnload(h);
    01547     if (uh) {
    01548         (void) blockSignals(dbi->dbi_rpmdb, &signalMask);
    01549         rc = dbiPut(dbi, dbcursor, &offset, sizeof(offset), uh, uhlen, pflags);
    01550         xx = dbiSync(dbi, 0);
    01551         (void) unblockSignals(dbi->dbi_rpmdb, &signalMask);
    01552         uh = _free(uh);
    01553     } else
    01554 fprintf(stderr, "*** dbiUpdateRecord: uh is NULL\n");
    01555     return rc;
    01556 }
    01557
    01558 typedef struct miRE_s {
    01559     rpmTag              tag;
    01560     rpmMireMode         mode;
    01561 /*@only@*/ const char * pattern;
    01562     int                 notmatch;
    01563 /*@only@*/ regex_t *    preg;
    01564     int                 cflags;
    01565     int                 eflags;
    01566     int                 fnflags;
    01567 } * miRE;
    01568
    01569 struct _rpmdbMatchIterator {
    01570 /*@only@*/ const void * mi_keyp;
    01571     size_t              mi_keylen;
    01572 /*@kept@*/ rpmdb        mi_db;
    01573     int                 mi_rpmtag;
    01574     dbiIndexSet         mi_set;
    01575     DBC *               mi_dbc;
    01576     unsigned int        mi_ndups;
    01577     int                 mi_setx;
    01578 /*@null@*/ Header       mi_h;
    01579     int                 mi_sorted;
    01580     int                 mi_cflags;
    01581     int                 mi_modified;
    01582     unsigned int        mi_prevoffset;
    01583     unsigned int        mi_offset;
    01584     unsigned int        mi_filenum;
    01585     unsigned int        mi_fpnum;
    01586     unsigned int        mi_dbnum;
    01587     int                 mi_nre;
    01588 /*@only@*//*@null@*/ miRE mi_re;
    01589 /*@only@*//*@null@*/ const char * mi_version;
    01590 /*@only@*//*@null@*/ const char * mi_release;
    01591 };
    01592
    01593 rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi)
    01594 {
    01595     dbiIndex dbi = NULL;
    01596     int xx;
    01597     int i;
    01598
    01599     if (mi == NULL)
    01600         return mi;
    01601
    01602     dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0);
    01603     /*@-branchstate@*/
    01604     if (mi->mi_h) {
    01605         if (dbi && mi->mi_dbc && mi->mi_modified && mi->mi_prevoffset) {
    01606             xx = dbiUpdateRecord(dbi, mi->mi_dbc, mi->mi_prevoffset, mi->mi_h);
    01607         }
    01608         mi->mi_h = headerFree(mi->mi_h);
    01609     }
    01610     /*@=branchstate@*/
    01611     if (dbi) {
    01612         if (dbi->dbi_rmw)
    01613             xx = dbiCclose(dbi, dbi->dbi_rmw, 0);
    01614         dbi->dbi_rmw = NULL;
    01615     }
    01616
    01617     if (mi->mi_re != NULL)
    01618     for (i = 0; i < mi->mi_nre; i++) {
    01619         miRE mire = mi->mi_re + i;
    01620         mire->pattern = _free(mire->pattern);
    01621         if (mire->preg != NULL) {
    01622             regfree(mire->preg);
    01623             /*@+voidabstract -usereleased @*/ /* LCL: regfree has bogus only */
    01624             mire->preg = _free(mire->preg);
    01625             /*@=voidabstract =usereleased @*/
    01626         }
    01627     }
    01628     mi->mi_re = _free(mi->mi_re);
    01629
    01630     mi->mi_release = _free(mi->mi_release);
    01631     mi->mi_version = _free(mi->mi_version);
    01632     /*@-branchstate@*/
    01633     if (dbi && mi->mi_dbc)
    01634         xx = dbiCclose(dbi, mi->mi_dbc, DBI_ITERATOR);
    01635     /*@=branchstate@*/
    01636     mi->mi_dbc = NULL;
    01637     mi->mi_set = dbiFreeIndexSet(mi->mi_set);
    01638     mi->mi_keyp = _free(mi->mi_keyp);
    01639     mi = _free(mi);
    01640     return mi;
    01641 }
    01642
    01643 rpmdb rpmdbGetIteratorRpmDB(rpmdbMatchIterator mi) {
    01644     if (mi == NULL)
    01645         return NULL;
    01646     /*@-retexpose -retalias@*/
    01647     return mi->mi_db;
    01648     /*@=retexpose =retalias@*/
    01649 }
    01650
    01651 unsigned int rpmdbGetIteratorOffset(rpmdbMatchIterator mi) {
    01652     if (mi == NULL)
    01653         return 0;
    01654     return mi->mi_offset;
    01655 }
    01656
    01657 unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi) {
    01658     if (mi == NULL)
    01659         return 0;
    01660     return mi->mi_filenum;
    01661 }
    01662
    01663 int rpmdbGetIteratorCount(rpmdbMatchIterator mi) {
    01664     if (!(mi && mi->mi_set))
    01665         return 0;       /* XXX W2DO? */
    01666     return mi->mi_set->count;
    01667 }
    01668
    01675 static int miregexec(miRE mire, const char * val)
    01676         /*@*/
    01677 {
    01678     int rc = 0;
    01679
    01680     switch (mire->mode) {
    01681     case RPMMIRE_STRCMP:
    01682         rc = strcmp(mire->pattern, val);
    01683         break;
    01684     case RPMMIRE_DEFAULT:
    01685     case RPMMIRE_REGEX:
    01686         /*@-nullpass@*/ /* LCL: annotation needs fix */
    01687         rc = regexec(mire->preg, val, 0, NULL, mire->eflags);
    01688         /*@=nullpass@*/
    01689         if (rc && rc != REG_NOMATCH) {
    01690             char msg[256];
    01691             (void) regerror(rc, mire->preg, msg, sizeof(msg)-1);
    01692             msg[sizeof(msg)-1] = '\0';
    01693             rpmError(RPMERR_REGEXEC, "%s: regexec failed: %s\n",
    01694                         mire->pattern, msg);
    01695             rc = -1;
    01696         }
    01697         break;
    01698     case RPMMIRE_GLOB:
    01699         /*@-moduncon@*/
    01700         rc = fnmatch(mire->pattern, val, mire->fnflags);
    01701         /*@=moduncon@*/
    01702         if (rc && rc != FNM_NOMATCH)
    01703             rc = -1;
    01704         break;
    01705     default:
    01706         rc = -1;
    01707         break;
    01708     }
    01709
    01710     return rc;
    01711 }
    01712
    01719 static int mireCmp(const void * a, const void * b)
    01720 {
    01721     const miRE mireA = (const miRE) a;
    01722     const miRE mireB = (const miRE) b;
    01723     return (mireA->tag - mireB->tag);
    01724 }
    01725
    01733 static /*@only@*/ char * mireDup(rpmTag tag, rpmMireMode *modep,
    01734                         const char * pattern)
    01735         /*@modifies *modep @*/
    01736 {
    01737     const char * s;
    01738     char * pat;
    01739     char * t;
    01740     int brackets;
    01741     size_t nb;
    01742     int c;
    01743
    01744     switch (*modep) {
    01745     default:
    01746     case RPMMIRE_DEFAULT:
    01747         if (tag == RPMTAG_DIRNAMES || tag == RPMTAG_BASENAMES) {
    01748             *modep = RPMMIRE_GLOB;
    01749             pat = xstrdup(pattern);
    01750             break;
    01751         }
    01752
    01753         nb = strlen(pattern) + sizeof("^$");
    01754
    01755         /* periods are escaped, splats become '.*' */
    01756         c = '\0';
    01757         brackets = 0;
    01758         for (s = pattern; *s != '\0'; s++) {
    01759             switch (*s) {
    01760             case '.':
    01761             case '*':
    01762                 if (!brackets) nb++;
    01763                 /*@switchbreak@*/ break;
    01764             case '\\':
    01765                 s++;
    01766                 /*@switchbreak@*/ break;
    01767             case '[':
    01768                 brackets = 1;
    01769                 /*@switchbreak@*/ break;
    01770             case ']':
    01771                 if (c != '[') brackets = 0;
    01772                 /*@switchbreak@*/ break;
    01773             }
    01774             c = *s;
    01775         }
    01776
    01777         pat = t = xmalloc(nb);
    01778
    01779         if (pattern[0] != '^') *t++ = '^';
    01780
    01781         /* periods are escaped, splats become '.*' */
    01782         c = '\0';
    01783         brackets = 0;
    01784         for (s = pattern; *s != '\0'; s++, t++) {
    01785             switch (*s) {
    01786             case '.':
    01787                 if (!brackets) *t++ = '\\';
    01788                 /*@switchbreak@*/ break;
    01789             case '*':
    01790                 if (!brackets) *t++ = '.';
    01791                 /*@switchbreak@*/ break;
    01792             case '\\':
    01793                 *t++ = *s++;
    01794                 /*@switchbreak@*/ break;
    01795             case '[':
    01796                 brackets = 1;
    01797                 /*@switchbreak@*/ break;
    01798             case ']':
    01799                 if (c != '[') brackets = 0;
    01800                 /*@switchbreak@*/ break;
    01801             }
    01802             c = *t = *s;
    01803         }
    01804
    01805         if (pattern[nb-1] != '$') *t++ = '$';
    01806         *t = '\0';
    01807         *modep = RPMMIRE_REGEX;
    01808         break;
    01809     case RPMMIRE_STRCMP:
    01810     case RPMMIRE_REGEX:
    01811     case RPMMIRE_GLOB:
    01812         pat = xstrdup(pattern);
    01813         break;
    01814     }
    01815
    01816     return pat;
    01817 }
    01818
    01819 /*@-globs@*/ /* FIX: rpmGlobalMacroContext not in <rpmlib.h> */
    01820 int rpmdbSetIteratorRE(rpmdbMatchIterator mi, rpmTag tag,
    01821                 rpmMireMode mode, const char * pattern)
    01822 {
    01823     static rpmMireMode defmode = (rpmMireMode)-1;
    01824     miRE mire = NULL;
    01825     const char * allpat = NULL;
    01826     int notmatch = 0;
    01827     regex_t * preg = NULL;
    01828     int cflags = 0;
    01829     int eflags = 0;
    01830     int fnflags = 0;
    01831     int rc = 0;
    01832
    01833     if (defmode == (rpmMireMode)-1) {
    01834         /*@-mods -nullpass @*/
    01835         const char *t = rpmExpand("%{?_query_selector_match}", NULL);
    01836         /*@=mods =nullpass @*/
    01837         if (*t == '\0' || !strcmp(t, "default"))
    01838             defmode = RPMMIRE_DEFAULT;
    01839         else if (!strcmp(t, "strcmp"))
    01840             defmode = RPMMIRE_STRCMP;
    01841         else if (!strcmp(t, "regex"))
    01842             defmode = RPMMIRE_REGEX;
    01843         else if (!strcmp(t, "glob"))
    01844             defmode = RPMMIRE_GLOB;
    01845         else
    01846             defmode = RPMMIRE_DEFAULT;
    01847         t = _free(t);
    01848      }
    01849
    01850     if (mi == NULL || pattern == NULL)
    01851         return rc;
    01852
    01853     /* Leading '!' inverts pattern match sense, like "grep -v". */
    01854     if (*pattern == '!') {
    01855         notmatch = 1;
    01856         pattern++;
    01857     }
    01858
    01859     /*@-mods@*/         /* FIX: WTFO? */
    01860     allpat = mireDup(tag, &mode, pattern);
    01861     /*@=mods@*/
    01862
    01863     if (mode == RPMMIRE_DEFAULT)
    01864         mode = defmode;
    01865
    01866     /*@-branchstate@*/
    01867     switch (mode) {
    01868     case RPMMIRE_DEFAULT:
    01869     case RPMMIRE_STRCMP:
    01870         break;
    01871     case RPMMIRE_REGEX:
    01872         /*@-type@*/
    01873         preg = xcalloc(1, sizeof(*preg));
    01874         /*@=type@*/
    01875         cflags = (REG_EXTENDED | REG_NOSUB);
    01876         rc = regcomp(preg, allpat, cflags);
    01877         if (rc) {
    01878             char msg[256];
    01879             (void) regerror(rc, preg, msg, sizeof(msg)-1);
    01880             msg[sizeof(msg)-1] = '\0';
    01881             rpmError(RPMERR_REGCOMP, "%s: regcomp failed: %s\n", allpat, msg);
    01882         }
    01883         break;
    01884     case RPMMIRE_GLOB:
    01885         fnflags = FNM_PATHNAME | FNM_PERIOD;
    01886         break;
    01887     default:
    01888         rc = -1;
    01889         break;
    01890     }
    01891     /*@=branchstate@*/
    01892
    01893     if (rc) {
    01894         /*@=kepttrans@*/        /* FIX: mire has kept values */
    01895         allpat = _free(allpat);
    01896         if (preg) {
    01897             regfree(preg);
    01898             /*@+voidabstract -usereleased @*/ /* LCL: regfree has bogus only */
    01899             preg = _free(preg);
    01900             /*@=voidabstract =usereleased @*/
    01901         }
    01902         /*@=kepttrans@*/
    01903         return rc;
    01904     }
    01905
    01906     mi->mi_re = xrealloc(mi->mi_re, (mi->mi_nre + 1) * sizeof(*mi->mi_re));
    01907     mire = mi->mi_re + mi->mi_nre;
    01908     mi->mi_nre++;
    01909
    01910     mire->tag = tag;
    01911     mire->mode = mode;
    01912     mire->pattern = allpat;
    01913     mire->notmatch = notmatch;
    01914     mire->preg = preg;
    01915     mire->cflags = cflags;
    01916     mire->eflags = eflags;
    01917     mire->fnflags = fnflags;
    01918
    01919     (void) qsort(mi->mi_re, mi->mi_nre, sizeof(*mi->mi_re), mireCmp);
    01920
    01921     /*@-nullstate@*/ /* FIX: mi->mi_re->preg may be NULL */
    01922     return rc;
    01923     /*@=nullstate@*/
    01924 }
    01925 /*@=globs@*/
    01926
    01932 static int mireSkip (const rpmdbMatchIterator mi)
    01933         /*@*/
    01934 {
    01935
    01936     HGE_t hge = (HGE_t) headerGetEntryMinMemory;
    01937     HFD_t hfd = (HFD_t) headerFreeData;
    01938     union {
    01939         void * ptr;
    01940         const char ** argv;
    01941         const char * str;
    01942         int_32 * i32p;
    01943         int_16 * i16p;
    01944         int_8 * i8p;
    01945     } u;
    01946     char numbuf[32];
    01947     rpmTagType t;
    01948     int_32 c;
    01949     miRE mire;
    01950     int ntags = 0;
    01951     int nmatches = 0;
    01952     int i, j;
    01953     int rc;
    01954
    01955     if (mi->mi_h == NULL)       /* XXX can't happen */
    01956         return 0;
    01957
    01958     /*
    01959      * Apply tag tests, implictly "||" for multiple patterns/values of a
    01960      * single tag, implictly "&&" between multiple tag patterns.
    01961      */
    01962     if ((mire = mi->mi_re) != NULL)
    01963     for (i = 0; i < mi->mi_nre; i++, mire++) {
    01964         int anymatch;
    01965
    01966         if (!hge(mi->mi_h, mire->tag, &t, (void **)&u, &c))
    01967             continue;
    01968
    01969         anymatch = 0;           /* no matches yet */
    01970         while (1) {
    01971             switch (t) {
    01972             case RPM_CHAR_TYPE:
    01973             case RPM_INT8_TYPE:
    01974                 sprintf(numbuf, "%d", (int) *u.i8p);
    01975                 rc = miregexec(mire, numbuf);
    01976                 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
    01977                     anymatch++;
    01978                 /*@switchbreak@*/ break;
    01979             case RPM_INT16_TYPE:
    01980                 sprintf(numbuf, "%d", (int) *u.i16p);
    01981                 rc = miregexec(mire, numbuf);
    01982                 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
    01983                     anymatch++;
    01984                 /*@switchbreak@*/ break;
    01985             case RPM_INT32_TYPE:
    01986                 sprintf(numbuf, "%d", (int) *u.i32p);
    01987                 rc = miregexec(mire, numbuf);
    01988                 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
    01989                     anymatch++;
    01990                 /*@switchbreak@*/ break;
    01991             case RPM_STRING_TYPE:
    01992                 rc = miregexec(mire, u.str);
    01993                 if ((!rc && !mire->notmatch) || (rc && mire->notmatch))
    01994                     anymatch++;
    01995                 /*@switchbreak@*/ break;
    01996             case RPM_I18NSTRING_TYPE:
    01997             case RPM_STRING_ARRAY_TYPE:
    01998                 for (j = 0; j < c; j++) {
    01999                     rc = miregexec(mire, u.argv[j]);
    02000                     if ((!rc && !mire->notmatch) || (rc && mire->notmatch)) {
    02001                         anymatch++;
    02002                         /*@innerbreak@*/ break;
    02003                     }
    02004                 }
    02005                 /*@switchbreak@*/ break;
    02006             case RPM_NULL_TYPE:
    02007             case RPM_BIN_TYPE:
    02008             default:
    02009                 /*@switchbreak@*/ break;
    02010             }
    02011             if ((i+1) < mi->mi_nre && mire[0].tag == mire[1].tag) {
    02012                 i++;
    02013                 mire++;
    02014                 /*@innercontinue@*/ continue;
    02015             }
    02016             /*@innerbreak@*/ break;
    02017         }
    02018
    02019         u.ptr = hfd(u.ptr, t);
    02020
    02021         ntags++;
    02022         if (anymatch)
    02023             nmatches++;
    02024     }
    02025
    02026     return (ntags == nmatches ? 0 : 1);
    02027
    02028 }
    02029
    02030 int rpmdbSetIteratorRelease(rpmdbMatchIterator mi, const char * release) {
    02031     return rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release);
    02032 }
    02033
    02034 int rpmdbSetIteratorVersion(rpmdbMatchIterator mi, const char * version) {
    02035     return rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version);
    02036 }
    02037
    02038 int rpmdbSetIteratorRewrite(rpmdbMatchIterator mi, int rewrite) {
    02039     int rc;
    02040     if (mi == NULL)
    02041         return 0;
    02042     rc = (mi->mi_cflags & DBI_WRITECURSOR) ? 1 : 0;
    02043     if (rewrite)
    02044         mi->mi_cflags |= DBI_WRITECURSOR;
    02045     else
    02046         mi->mi_cflags &= ~DBI_WRITECURSOR;
    02047     return rc;
    02048 }
    02049
    02050 int rpmdbSetIteratorModified(rpmdbMatchIterator mi, int modified) {
    02051     int rc;
    02052     if (mi == NULL)
    02053         return 0;
    02054     rc = mi->mi_modified;
    02055     mi->mi_modified = modified;
    02056     return rc;
    02057 }
    02058
    02059 Header XrpmdbNextIterator(rpmdbMatchIterator mi,
    02060                 /*@unused@*/ const char * f, /*@unused@*/ unsigned int l)
    02061 {
    02062     return rpmdbNextIterator(mi);
    02063 }
    02064
    02065 Header rpmdbNextIterator(rpmdbMatchIterator mi)
    02066 {
    02067     dbiIndex dbi;
    02068     void * uh = NULL;
    02069     size_t uhlen = 0;
    02070     unsigned int gflags = 0;    /* dbiGet() flags */
    02071     void * keyp;
    02072     size_t keylen;
    02073     int rc;
    02074     int xx;
    02075
    02076     if (mi == NULL)
    02077         return NULL;
    02078
    02079     dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0);
    02080     if (dbi == NULL)
    02081         return NULL;
    02082
    02083     /*
    02084      * Cursors are per-iterator, not per-dbi, so get a cursor for the
    02085      * iterator on 1st call. If the iteration is to rewrite headers, and the
    02086      * CDB model is used for the database, then the cursor needs to
    02087      * marked with DB_WRITECURSOR as well.
    02088      */
    02089     if (mi->mi_dbc == NULL)
    02090         xx = dbiCopen(dbi, &mi->mi_dbc, (mi->mi_cflags | DBI_ITERATOR));
    02091     dbi->dbi_lastoffset = mi->mi_prevoffset;
    02092
    02093 top:
    02094     /* XXX skip over instances with 0 join key */
    02095     do {
    02096         if (mi->mi_set) {
    02097             if (!(mi->mi_setx < mi->mi_set->count))
    02098                 return NULL;
    02099             mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx);
    02100             mi->mi_filenum = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx);
    02101             keyp = &mi->mi_offset;
    02102             keylen = sizeof(mi->mi_offset);
    02103         } else {
    02104             keyp = (void *)mi->mi_keyp;         /* XXX FIXME const */
    02105             keylen = mi->mi_keylen;
    02106
    02107             rc = dbiGet(dbi, mi->mi_dbc, &keyp, &keylen, &uh, &uhlen, gflags);
    02108 if (dbi->dbi_api == 1 && dbi->dbi_rpmtag == RPMDBI_PACKAGES && rc == EFAULT) {
    02109     rpmError(RPMERR_INTERNAL,
    02110         _("record number %u in database is bad -- skipping.\n"), dbi->dbi_lastoffset);
    02111     if (keyp && dbi->dbi_lastoffset)
    02112         memcpy(&mi->mi_offset, keyp, sizeof(mi->mi_offset));
    02113     continue;
    02114 }
    02115
    02116             /*
    02117              * If we got the next key, save the header instance number.
    02118              * For db1 Packages (db1->dbi_lastoffset != 0), always copy.
    02119              * For db3 Packages, instance 0 (i.e. mi->mi_setx == 0) is the
    02120              * largest header instance in the database, and should be
    02121              * skipped.
    02122              */
    02123             if (rc == 0 && keyp && (dbi->dbi_lastoffset || mi->mi_setx))
    02124                 memcpy(&mi->mi_offset, keyp, sizeof(mi->mi_offset));
    02125
    02126             /* Terminate on error or end of keys */
    02127             if (rc || (mi->mi_setx && mi->mi_offset == 0))
    02128                 return NULL;
    02129         }
    02130         mi->mi_setx++;
    02131     } while (mi->mi_offset == 0);
    02132
    02133     if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset)
    02134         goto exit;
    02135
    02136     /* Retrieve next header */
    02137     if (uh == NULL) {
    02138         rc = dbiGet(dbi, mi->mi_dbc, &keyp, &keylen, &uh, &uhlen, gflags);
    02139         if (rc)
    02140             return NULL;
    02141     }
    02142
    02143     /* Free current header */
    02144     if (mi->mi_h) {
    02145         if (mi->mi_modified && mi->mi_prevoffset)
    02146             (void)dbiUpdateRecord(dbi, mi->mi_dbc, mi->mi_prevoffset, mi->mi_h);
    02147         mi->mi_h = headerFree(mi->mi_h);
    02148     }
    02149
    02150     /* Is this the end of the iteration? */
    02151     if (uh == NULL)
    02152         goto exit;
    02153
    02154     mi->mi_h = headerCopyLoad(uh);
    02155     /* XXX db1 with hybrid, simulated db interface on falloc.c needs free. */
    02156     /*@-branchstate@*/
    02157     if (dbi->dbi_api == 1) uh = _free(uh);
    02158     /*@=branchstate@*/
    02159
    02160     /* Did the header load correctly? */
    02161     if (mi->mi_h == NULL || !headerIsEntry(mi->mi_h, RPMTAG_NAME)) {
    02162         rpmError(RPMERR_BADHEADER,
    02163                 _("rpmdb: damaged header instance #%u retrieved, skipping.\n"),
    02164                 mi->mi_offset);
    02165         goto top;
    02166     }
    02167
    02168     /*
    02169      * Skip this header if iterator selector (if any) doesn't match.
    02170      */
    02171     if (mireSkip(mi)) {
    02172         /* XXX hack, can't restart with Packages locked on single instance. */
    02173         if (mi->mi_set || mi->mi_keyp == NULL)
    02174             goto top;
    02175         return NULL;
    02176     }
    02177
    02178     mi->mi_prevoffset = mi->mi_offset;
    02179     mi->mi_modified = 0;
    02180
    02181 exit:
    02182 #ifdef  NOTNOW
    02183     if (mi->mi_h) {
    02184         const char *n, *v, *r;
    02185         (void) headerNVR(mi->mi_h, &n, &v, &r);
    02186         rpmMessage(RPMMESS_DEBUG, "%s-%s-%s at 0x%x, h %p\n", n, v, r,
    02187                 mi->mi_offset, mi->mi_h);
    02188     }
    02189 #endif
    02190     /*@-retexpose -retalias@*/
    02191     /*@-compdef -usereleased@*/ return mi->mi_h; /*@=compdef =usereleased@*/
    02192     /*@=retexpose =retalias@*/
    02193 }
    02194
    02195 static void rpmdbSortIterator(/*@null@*/ rpmdbMatchIterator mi)
    02196         /*@modifies mi @*/
    02197 {
    02198     if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) {
    02199     /*
    02200      * mergesort is much (~10x with lots of identical basenames) faster
    02201      * than pure quicksort, but glibc uses msort_with_tmp() on stack.
    02202      */
    02203 #if defined(__GLIBC__)
    02204         qsort(mi->mi_set->recs, mi->mi_set->count,
    02205                 sizeof(*mi->mi_set->recs), hdrNumCmp);
    02206 #else
    02207         mergesort(mi->mi_set->recs, mi->mi_set->count,
    02208                 sizeof(*mi->mi_set->recs), hdrNumCmp);
    02209 #endif
    02210         mi->mi_sorted = 1;
    02211     }
    02212 }
    02213
    02214 static int rpmdbGrowIterator(/*@null@*/ rpmdbMatchIterator mi,
    02215                 const void * keyp, size_t keylen, int fpNum)
    02216         /*@globals fileSystem @*/
    02217         /*@modifies mi, fileSystem @*/
    02218 {
    02219     dbiIndex dbi = NULL;
    02220     DBC * dbcursor = NULL;
    02221     dbiIndexSet set = NULL;
    02222     int rc;
    02223     int xx;
    02224
    02225     if (!(mi && keyp))
    02226         return 1;
    02227
    02228     dbi = dbiOpen(mi->mi_db, mi->mi_rpmtag, 0);
    02229     if (dbi == NULL)
    02230         return 1;
    02231
    02232     if (keylen == 0)
    02233         keylen = strlen(keyp);
    02234
    02235     xx = dbiCopen(dbi, &dbcursor, 0);
    02236     rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
    02237     xx = dbiCclose(dbi, dbcursor, 0);
    02238     dbcursor = NULL;
    02239
    02240     if (rc == 0) {      /* success */
    02241         int i;
    02242         for (i = 0; i < set->count; i++)
    02243             set->recs[i].fpNum = fpNum;
    02244
    02245         if (mi->mi_set == NULL) {
    02246             mi->mi_set = set;
    02247             set = NULL;
    02248         } else {
    02249             mi->mi_set->recs = xrealloc(mi->mi_set->recs,
    02250                 (mi->mi_set->count + set->count) * sizeof(*(mi->mi_set->recs)));
    02251             memcpy(mi->mi_set->recs + mi->mi_set->count, set->recs,
    02252                 set->count * sizeof(*(mi->mi_set->recs)));
    02253             mi->mi_set->count += set->count;
    02254         }
    02255     }
    02256
    02257     set = dbiFreeIndexSet(set);
    02258     return rc;
    02259 }
    02260
    02261 int rpmdbPruneIterator(rpmdbMatchIterator mi, int * hdrNums,
    02262         int nHdrNums, int sorted)
    02263 {
    02264     if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
    02265         return 1;
    02266
    02267     if (mi->mi_set)
    02268         (void) dbiPruneSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), sorted);
    02269     return 0;
    02270 }
    02271
    02272 int rpmdbAppendIterator(rpmdbMatchIterator mi, const int * hdrNums, int nHdrNums)
    02273 {
    02274     if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
    02275         return 1;
    02276
    02277     if (mi->mi_set == NULL)
    02278         mi->mi_set = xcalloc(1, sizeof(*mi->mi_set));
    02279     (void) dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0);
    02280     return 0;
    02281 }
    02282
    02283 rpmdbMatchIterator rpmdbInitIterator(rpmdb db, int rpmtag,
    02284         const void * keyp, size_t keylen)
    02285 {
    02286     rpmdbMatchIterator mi = NULL;
    02287     dbiIndexSet set = NULL;
    02288     dbiIndex dbi;
    02289     const void * mi_keyp = NULL;
    02290     int isLabel = 0;
    02291
    02292     if (db == NULL)
    02293         return NULL;
    02294     /* XXX HACK to remove rpmdbFindByLabel/findMatches from the API */
    02295     switch (rpmtag) {
    02296     case RPMDBI_LABEL:
    02297         rpmtag = RPMTAG_NAME;
    02298         isLabel = 1;
    02299         break;
    02300     }
    02301
    02302     dbi = dbiOpen(db, rpmtag, 0);
    02303     if (dbi == NULL)
    02304         return NULL;
    02305
    02306 #if 0
    02307     assert(dbi->dbi_rmw == NULL);       /* db3: avoid "lost" cursors */
    02308     assert(dbi->dbi_lastoffset == 0);   /* db0: avoid "lost" cursors */
    02309 #else
    02310 if (dbi->dbi_rmw)
    02311 fprintf(stderr, "*** RMW %s %p\n", tagName(rpmtag), dbi->dbi_rmw);
    02312 #endif
    02313
    02314     dbi->dbi_lastoffset = 0;            /* db0: rewind to beginning */
    02315
    02316     if (rpmtag != RPMDBI_PACKAGES && keyp) {
    02317         DBC * dbcursor = NULL;
    02318         int rc;
    02319         int xx;
    02320
    02321         if (isLabel) {
    02322             /* XXX HACK to get rpmdbFindByLabel out of the API */
    02323             xx = dbiCopen(dbi, &dbcursor, 0);
    02324             rc = dbiFindByLabel(dbi, dbcursor, keyp, &set);
    02325             xx = dbiCclose(dbi, dbcursor, 0);
    02326             dbcursor = NULL;
    02327         } else if (rpmtag == RPMTAG_BASENAMES) {
    02328             rc = rpmdbFindByFile(db, keyp, &set);
    02329         } else {
    02330             xx = dbiCopen(dbi, &dbcursor, 0);
    02331             /*@-nullpass@*/     /* LCL: keyp != NULL here. */
    02332             rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
    02333             /*@=nullpass@*/
    02334             xx = dbiCclose(dbi, dbcursor, 0);
    02335             dbcursor = NULL;
    02336         }
    02337         if (rc) {       /* error/not found */
    02338             set = dbiFreeIndexSet(set);
    02339             return NULL;
    02340         }
    02341     }
    02342
    02343     if (keyp) {
    02344         char * k;
    02345
    02346         if (rpmtag != RPMDBI_PACKAGES && keylen == 0)
    02347             keylen = strlen(keyp);
    02348         k = xmalloc(keylen + 1);
    02349         memcpy(k, keyp, keylen);
    02350         k[keylen] = '\0';       /* XXX for strings */
    02351         mi_keyp = k;
    02352     }
    02353
    02354     mi = xcalloc(1, sizeof(*mi));
    02355     mi->mi_keyp = mi_keyp;
    02356     mi->mi_keylen = keylen;
    02357
    02358     /*@-assignexpose@*/
    02359     mi->mi_db = db;
    02360     /*@=assignexpose@*/
    02361     mi->mi_rpmtag = rpmtag;
    02362
    02363     mi->mi_dbc = NULL;
    02364     mi->mi_set = set;
    02365     mi->mi_setx = 0;
    02366     mi->mi_ndups = 0;
    02367     mi->mi_h = NULL;
    02368     mi->mi_sorted = 0;
    02369     mi->mi_cflags = 0;
    02370     mi->mi_modified = 0;
    02371     mi->mi_prevoffset = 0;
    02372     mi->mi_offset = 0;
    02373     mi->mi_filenum = 0;
    02374     mi->mi_fpnum = 0;
    02375     mi->mi_dbnum = 0;
    02376     mi->mi_nre = 0;
    02377     mi->mi_re = NULL;
    02378     mi->mi_version = NULL;
    02379     mi->mi_release = NULL;
    02380     /*@-nullret@*/ /* FIX: mi->mi_{keyp,dbc,set,re->preg} are NULL */
    02381     return mi;
    02382     /*@=nullret@*/
    02383 }
    02384
    02394 static INLINE int removeIndexEntry(dbiIndex dbi, DBC * dbcursor,
    02395                 const void * keyp, size_t keylen, dbiIndexItem rec)
    02396         /*@globals fileSystem @*/
    02397         /*@modifies *dbcursor, fileSystem @*/
    02398 {
    02399     dbiIndexSet set = NULL;
    02400     int rc;
    02401
    02402     rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
    02403
    02404     if (rc < 0)                 /* not found */
    02405         rc = 0;
    02406     else if (rc > 0)            /* error */
    02407         rc = 1;         /* error message already generated from dbindex.c */
    02408     else {                      /* success */
    02409         /*@-mods@*/     /* a single rec is not modified */
    02410         rc = dbiPruneSet(set, rec, 1, sizeof(*rec), 1);
    02411         /*@=mods@*/
    02412         if (rc == 0 && dbiUpdateIndex(dbi, dbcursor, keyp, keylen, set))
    02413             rc = 1;
    02414     }
    02415
    02416     set = dbiFreeIndexSet(set);
    02417
    02418     return rc;
    02419 }
    02420
    02421 /*@-mods@*/
    02422 /* XXX install.c uninstall.c */
    02423 int rpmdbRemove(rpmdb db, /*@unused@*/ int rid, unsigned int hdrNum)
    02424 {
    02425     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    02426     HFD_t hfd = headerFreeData;
    02427     Header h;
    02428     sigset_t signalMask;
    02429
    02430     if (db == NULL)
    02431         return 0;
    02432
    02433     {   rpmdbMatchIterator mi;
    02434         mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum));
    02435         h = rpmdbNextIterator(mi);
    02436         if (h)
    02437             h = headerLink(h);
    02438         mi = rpmdbFreeIterator(mi);
    02439     }
    02440
    02441     if (h == NULL) {
    02442         rpmError(RPMERR_DBCORRUPT, _("%s: cannot read header at 0x%x\n"),
    02443               "rpmdbRemove", hdrNum);
    02444         return 1;
    02445     }
    02446
    02447 #ifdef  DYING
    02448     /* Add remove transaction id to header. */
    02449     if (rid != 0 && rid != -1) {
    02450         int_32 tid = rid;
    02451         (void) headerAddEntry(h, RPMTAG_REMOVETID, RPM_INT32_TYPE, &tid, 1);
    02452     }
    02453 #endif
    02454
    02455     {   const char *n, *v, *r;
    02456         (void) headerNVR(h, &n, &v, &r);
    02457         rpmMessage(RPMMESS_DEBUG, "  --- %10u %s-%s-%s\n", hdrNum, n, v, r);
    02458     }
    02459
    02460     (void) blockSignals(db, &signalMask);
    02461
    02462         /*@-nullpass -nullptrarith -nullderef @*/ /* FIX: rpmvals heartburn */
    02463     {   int dbix;
    02464         dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
    02465
    02466         if (dbiTags != NULL)
    02467         for (dbix = 0; dbix < dbiTagsMax; dbix++) {
    02468             dbiIndex dbi;
    02469             DBC * dbcursor = NULL;
    02470             const char *av[1];
    02471             const char ** rpmvals = NULL;
    02472             rpmTagType rpmtype = 0;
    02473             int rpmcnt = 0;
    02474             int rpmtag;
    02475             int xx;
    02476             int i, j;
    02477
    02478             dbi = NULL;
    02479             rpmtag = dbiTags[dbix];
    02480
    02481             /*@-branchstate@*/
    02482             switch (rpmtag) {
    02483             /* Filter out temporary databases */
    02484             case RPMDBI_AVAILABLE:
    02485             case RPMDBI_ADDED:
    02486             case RPMDBI_REMOVED:
    02487             case RPMDBI_DEPENDS:
    02488                 continue;
    02489                 /*@notreached@*/ /*@switchbreak@*/ break;
    02490             case RPMDBI_PACKAGES:
    02491               dbi = dbiOpen(db, rpmtag, 0);
    02492               if (dbi != NULL) {
    02493                 xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
    02494                 xx = dbiDel(dbi, dbcursor, &hdrNum, sizeof(hdrNum), 0);
    02495                 xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
    02496                 dbcursor = NULL;
    02497                 if (!dbi->dbi_no_dbsync)
    02498                     xx = dbiSync(dbi, 0);
    02499               }
    02500                 continue;
    02501                 /*@notreached@*/ /*@switchbreak@*/ break;
    02502             }
    02503             /*@=branchstate@*/
    02504
    02505             if (!hge(h, rpmtag, &rpmtype, (void **) &rpmvals, &rpmcnt))
    02506                 continue;
    02507
    02508           dbi = dbiOpen(db, rpmtag, 0);
    02509           if (dbi != NULL) {
    02510             int printed;
    02511
    02512             if (rpmtype == RPM_STRING_TYPE) {
    02513                 /* XXX force uniform headerGetEntry return */
    02514                 av[0] = (const char *) rpmvals;
    02515                 rpmvals = av;
    02516                 rpmcnt = 1;
    02517             }
    02518
    02519             printed = 0;
    02520             xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
    02521             for (i = 0; i < rpmcnt; i++) {
    02522                 const void * valp;
    02523                 size_t vallen;
    02524                 int stringvalued;
    02525                 unsigned char bin[32];
    02526
    02527                 switch (dbi->dbi_rpmtag) {
    02528                 case RPMTAG_FILEMD5S:
    02529                     /* Filter out empty MD5 strings. */
    02530                     if (!(rpmvals[i] && *rpmvals[i] != '\0'))
    02531                         /*@innercontinue@*/ continue;
    02532                     /*@switchbreak@*/ break;
    02533                 default:
    02534                     /*@switchbreak@*/ break;
    02535                 }
    02536
    02537                 /* Identify value pointer and length. */
    02538                 stringvalued = 0;
    02539                 switch (rpmtype) {
    02540                 case RPM_CHAR_TYPE:
    02541                 case RPM_INT8_TYPE:
    02542                     vallen = sizeof(RPM_CHAR_TYPE);
    02543                     valp = rpmvals + i;
    02544                     /*@switchbreak@*/ break;
    02545                 case RPM_INT16_TYPE:
    02546                     vallen = sizeof(int_16);
    02547                     valp = rpmvals + i;
    02548                     /*@switchbreak@*/ break;
    02549                 case RPM_INT32_TYPE:
    02550                     vallen = sizeof(int_32);
    02551                     valp = rpmvals + i;
    02552                     /*@switchbreak@*/ break;
    02553                 case RPM_BIN_TYPE:
    02554                     vallen = rpmcnt;
    02555                     valp = rpmvals;
    02556                     rpmcnt = 1;         /* XXX break out of loop. */
    02557                     /*@switchbreak@*/ break;
    02558                 case RPM_STRING_TYPE:
    02559                 case RPM_I18NSTRING_TYPE:
    02560                     rpmcnt = 1;         /* XXX break out of loop. */
    02561                     /*@fallthrough@*/
    02562                 case RPM_STRING_ARRAY_TYPE:
    02563                     /* Convert from hex to binary. */
    02564                     if (dbi->dbi_rpmtag == RPMTAG_FILEMD5S) {
    02565                         const char * s;
    02566                         unsigned char * t;
    02567
    02568                         s = rpmvals[i];
    02569                         t = bin;
    02570                         for (j = 0; j < 16; j++, t++, s += 2)
    02571                             *t = (nibble(s[0]) << 4) | nibble(s[1]);
    02572                         valp = bin;
    02573                         vallen = 16;
    02574                         /*@switchbreak@*/ break;
    02575                     }
    02576 #ifdef  NOTYET
    02577                     /* Extract the pubkey id from the base64 blob. */
    02578                     if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
    02579                         pgpDig dig = pgpNewDig();
    02580                         const byte * pkt;
    02581                         ssize_t pktlen;
    02582
    02583                         if (b64decode(rpmvals[i], (void **)&pkt, &pktlen))
    02584                             /*@innercontinue@*/ continue;
    02585                         (void) pgpPrtPkts(pkt, pktlen, dig, 0);
    02586                         memcpy(bin, dig->pubkey.signid, 8);
    02587                         pkt = _free(pkt);
    02588                         dig = _free(dig);
    02589                         valp = bin;
    02590                         vallen = 8;
    02591                         /*@switchbreak@*/ break;
    02592                     }
    02593 #endif
    02594                     /*@fallthrough@*/
    02595                 default:
    02596                     valp = rpmvals[i];
    02597                     vallen = strlen(rpmvals[i]);
    02598                     stringvalued = 1;
    02599                     /*@switchbreak@*/ break;
    02600                 }
    02601
    02602                 if (!printed) {
    02603                     if (rpmcnt == 1 && stringvalued) {
    02604                         rpmMessage(RPMMESS_DEBUG,
    02605                                 _("removing \"%s\" from %s index.\n"),
    02606                                 valp, tagName(dbi->dbi_rpmtag));
    02607                     } else {
    02608                         rpmMessage(RPMMESS_DEBUG,
    02609                                 _("removing %d entries from %s index.\n"),
    02610                                 rpmcnt, tagName(dbi->dbi_rpmtag));
    02611                     }
    02612                     printed++;
    02613                 }
    02614
    02615                 /*
    02616                  * This is almost right, but, if there are duplicate tag
    02617                  * values, there will be duplicate attempts to remove
    02618                  * the header instance. It's easier to just ignore errors
    02619                  * than to do things correctly.
    02620                  */
    02621                 xx = removeIndexEntry(dbi, dbcursor, valp, vallen, rec);
    02622             }
    02623
    02624             xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
    02625             dbcursor = NULL;
    02626
    02627             if (!dbi->dbi_no_dbsync)
    02628                 xx = dbiSync(dbi, 0);
    02629           }
    02630
    02631             if (rpmtype != RPM_BIN_TYPE)        /* XXX WTFO? HACK ALERT */
    02632                 rpmvals = hfd(rpmvals, rpmtype);
    02633             rpmtype = 0;
    02634             rpmcnt = 0;
    02635         }
    02636
    02637         rec = _free(rec);
    02638     }
    02639     /*@=nullpass =nullptrarith =nullderef @*/
    02640
    02641     (void) unblockSignals(db, &signalMask);
    02642
    02643     h = headerFree(h);
    02644
    02645     return 0;
    02646 }
    02647
    02657 static INLINE int addIndexEntry(dbiIndex dbi, DBC * dbcursor,
    02658                 const char * keyp, size_t keylen, dbiIndexItem rec)
    02659         /*@globals fileSystem @*/
    02660         /*@modifies *dbcursor, fileSystem @*/
    02661 {
    02662     dbiIndexSet set = NULL;
    02663     int rc;
    02664
    02665     rc = dbiSearch(dbi, dbcursor, keyp, keylen, &set);
    02666
    02667     if (rc > 0) {               /* error */
    02668         rc = 1;
    02669     } else {
    02670
    02671         /* With duplicates, cursor is positioned, discard the record. */
    02672         /*@-branchstate@*/
    02673         if (rc == 0 && dbi->dbi_permit_dups)
    02674             set = dbiFreeIndexSet(set);
    02675         /*@=branchstate@*/
    02676
    02677         if (set == NULL || rc < 0) {            /* not found */
    02678             rc = 0;
    02679             set = xcalloc(1, sizeof(*set));
    02680         }
    02681         (void) dbiAppendSet(set, rec, 1, sizeof(*rec), 0);
    02682         if (dbiUpdateIndex(dbi, dbcursor, keyp, keylen, set))
    02683             rc = 1;
    02684     }
    02685     set = dbiFreeIndexSet(set);
    02686
    02687     return 0;
    02688 }
    02689
    02690 /* XXX install.c */
    02691 int rpmdbAdd(rpmdb db, int iid, Header h)
    02692 {
    02693     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    02694     HFD_t hfd = headerFreeData;
    02695     sigset_t signalMask;
    02696     const char ** baseNames;
    02697     rpmTagType bnt;
    02698     int count = 0;
    02699     dbiIndex dbi;
    02700     int dbix;
    02701     unsigned int gflags = 0;    /* dbiGet() flags */
    02702     unsigned int pflags = 0;    /* dbiPut() flags */
    02703     unsigned int hdrNum = 0;
    02704     int rc = 0;
    02705     int xx;
    02706
    02707     if (db == NULL)
    02708         return 0;
    02709
    02710 #ifdef  NOTYET  /* XXX headerRemoveEntry() broken on dribbles. */
    02711     xx = headerRemoveEntry(h, RPMTAG_REMOVETID);
    02712 #endif
    02713     if (iid != 0 && iid != -1) {
    02714         int_32 tid = iid;
    02715         if (!headerIsEntry(h, RPMTAG_INSTALLTID))
    02716            xx = headerAddEntry(h, RPMTAG_INSTALLTID, RPM_INT32_TYPE, &tid, 1);
    02717     }
    02718
    02719     /*
    02720      * If old style filename tags is requested, the basenames need to be
    02721      * retrieved early, and the header needs to be converted before
    02722      * being written to the package header database.
    02723      */
    02724
    02725     xx = hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, &count);
    02726
    02727     if (_noDirTokens)
    02728         expandFilelist(h);
    02729
    02730     (void) blockSignals(db, &signalMask);
    02731
    02732     {
    02733         unsigned int firstkey = 0;
    02734         DBC * dbcursor = NULL;
    02735         void * keyp = &firstkey;
    02736         size_t keylen = sizeof(firstkey);
    02737         void * datap = NULL;
    02738         size_t datalen = 0;
    02739
    02740       dbi = dbiOpen(db, RPMDBI_PACKAGES, 0);
    02741       /*@-branchstate@*/
    02742       if (dbi != NULL) {
    02743
    02744         /* XXX db0: hack to pass sizeof header to fadAlloc */
    02745         datap = h;
    02746         datalen = headerSizeof(h, HEADER_MAGIC_NO);
    02747
    02748         xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
    02749
    02750         /* Retrieve join key for next header instance. */
    02751
    02752         rc = dbiGet(dbi, dbcursor, &keyp, &keylen, &datap, &datalen, gflags);
    02753
    02754         hdrNum = 0;
    02755         if (rc == 0 && datap)
    02756             memcpy(&hdrNum, datap, sizeof(hdrNum));
    02757         ++hdrNum;
    02758         if (rc == 0 && datap) {
    02759             /*@-refcounttrans@*/        /* FIX: datap aliases h */
    02760             memcpy(datap, &hdrNum, sizeof(hdrNum));
    02761             /*@=refcounttrans@*/
    02762         } else {
    02763             datap = &hdrNum;
    02764             datalen = sizeof(hdrNum);
    02765         }
    02766
    02767         rc = dbiPut(dbi, dbcursor, keyp, keylen, datap, datalen, pflags);
    02768         xx = dbiSync(dbi, 0);
    02769
    02770         xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
    02771         dbcursor = NULL;
    02772       }
    02773       /*@=branchstate@*/
    02774
    02775     }
    02776
    02777     if (rc) {
    02778         rpmError(RPMERR_DBCORRUPT,
    02779                 _("error(%d) allocating new package instance\n"), rc);
    02780         goto exit;
    02781     }
    02782
    02783     /* Now update the indexes */
    02784
    02785     if (hdrNum)
    02786     {   dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
    02787
    02788         /*@-nullpass -nullptrarith -nullderef @*/ /* FIX: rpmvals heartburn */
    02789         if (dbiTags != NULL)
    02790         for (dbix = 0; dbix < dbiTagsMax; dbix++) {
    02791             DBC * dbcursor = NULL;
    02792             const char *av[1];
    02793             const char **rpmvals = NULL;
    02794             rpmTagType rpmtype = 0;
    02795             int rpmcnt = 0;
    02796             int rpmtag;
    02797             int_32 * requireFlags;
    02798             int i, j;
    02799
    02800             dbi = NULL;
    02801             requireFlags = NULL;
    02802             rpmtag = dbiTags[dbix];
    02803
    02804             switch (rpmtag) {
    02805             /* Filter out temporary databases */
    02806             case RPMDBI_AVAILABLE:
    02807             case RPMDBI_ADDED:
    02808             case RPMDBI_REMOVED:
    02809             case RPMDBI_DEPENDS:
    02810                 continue;
    02811                 /*@notreached@*/ /*@switchbreak@*/ break;
    02812             case RPMDBI_PACKAGES:
    02813               dbi = dbiOpen(db, rpmtag, 0);
    02814               if (dbi != NULL) {
    02815                 xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
    02816                 xx = dbiUpdateRecord(dbi, dbcursor, hdrNum, h);
    02817                 xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
    02818                 dbcursor = NULL;
    02819                 if (!dbi->dbi_no_dbsync)
    02820                     xx = dbiSync(dbi, 0);
    02821                 {   const char *n, *v, *r;
    02822                     xx = headerNVR(h, &n, &v, &r);
    02823                     rpmMessage(RPMMESS_DEBUG, "  +++ %10u %s-%s-%s\n", hdrNum, n, v, r);
    02824                 }
    02825               }
    02826                 continue;
    02827                 /*@notreached@*/ /*@switchbreak@*/ break;
    02828             /* XXX preserve legacy behavior */
    02829             case RPMTAG_BASENAMES:
    02830                 rpmtype = bnt;
    02831                 rpmvals = baseNames;
    02832                 rpmcnt = count;
    02833                 /*@switchbreak@*/ break;
    02834             case RPMTAG_REQUIRENAME:
    02835                 xx = hge(h, rpmtag, &rpmtype, (void **)&rpmvals, &rpmcnt);
    02836                 xx = hge(h, RPMTAG_REQUIREFLAGS, NULL, (void **)&requireFlags, NULL);
    02837                 /*@switchbreak@*/ break;
    02838             default:
    02839                 xx = hge(h, rpmtag, &rpmtype, (void **)&rpmvals, &rpmcnt);
    02840                 /*@switchbreak@*/ break;
    02841             }
    02842
    02843             /*@-branchstate@*/
    02844             if (rpmcnt <= 0) {
    02845                 if (rpmtag != RPMTAG_GROUP)
    02846                     continue;
    02847
    02848                 /* XXX preserve legacy behavior */
    02849                 rpmtype = RPM_STRING_TYPE;
    02850                 rpmvals = (const char **) "Unknown";
    02851                 rpmcnt = 1;
    02852             }
    02853             /*@=branchstate@*/
    02854
    02855           dbi = dbiOpen(db, rpmtag, 0);
    02856           if (dbi != NULL) {
    02857             int printed;
    02858
    02859             if (rpmtype == RPM_STRING_TYPE) {
    02860                 /* XXX force uniform headerGetEntry return */
    02861                 /*@-observertrans@*/
    02862                 av[0] = (const char *) rpmvals;
    02863                 /*@=observertrans@*/
    02864                 rpmvals = av;
    02865                 rpmcnt = 1;
    02866             }
    02867
    02868             printed = 0;
    02869             xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
    02870             for (i = 0; i < rpmcnt; i++) {
    02871                 const void * valp;
    02872                 size_t vallen;
    02873                 int stringvalued;
    02874                 unsigned char bin[32];
    02875
    02876                 /*
    02877                  * Include the tagNum in all indices. rpm-3.0.4 and earlier
    02878                  * included the tagNum only for files.
    02879                  */
    02880                 rec->tagNum = i;
    02881                 switch (dbi->dbi_rpmtag) {
    02882 #ifdef  NOTYET
    02883                 case RPMTAG_PUBKEYS:
    02884                     /*@switchbreak@*/ break;
    02885 #endif
    02886                 case RPMTAG_FILEMD5S:
    02887                     /* Filter out empty MD5 strings. */
    02888                     if (!(rpmvals[i] && *rpmvals[i] != '\0'))
    02889                         /*@innercontinue@*/ continue;
    02890                     /*@switchbreak@*/ break;
    02891                 case RPMTAG_REQUIRENAME:
    02892                     /* Filter out install prerequisites. */
    02893                     if (requireFlags && isInstallPreReq(requireFlags[i]))
    02894                         /*@innercontinue@*/ continue;
    02895                     /*@switchbreak@*/ break;
    02896                 case RPMTAG_TRIGGERNAME:
    02897                     if (i) {    /* don't add duplicates */
    02898                         for (j = 0; j < i; j++) {
    02899                             if (!strcmp(rpmvals[i], rpmvals[j]))
    02900                                 /*@innerbreak@*/ break;
    02901                         }
    02902                         if (j < i)
    02903                             /*@innercontinue@*/ continue;
    02904                     }
    02905                     /*@switchbreak@*/ break;
    02906                 default:
    02907                     /*@switchbreak@*/ break;
    02908                 }
    02909
    02910                 /* Identify value pointer and length. */
    02911                 stringvalued = 0;
    02912                 switch (rpmtype) {
    02913                 case RPM_CHAR_TYPE:
    02914                 case RPM_INT8_TYPE:
    02915                     vallen = sizeof(int_8);
    02916                     valp = rpmvals + i;
    02917                     /*@switchbreak@*/ break;
    02918                 case RPM_INT16_TYPE:
    02919                     vallen = sizeof(int_16);
    02920                     valp = rpmvals + i;
    02921                     /*@switchbreak@*/ break;
    02922                 case RPM_INT32_TYPE:
    02923                     vallen = sizeof(int_32);
    02924                     valp = rpmvals + i;
    02925                     /*@switchbreak@*/ break;
    02926                 case RPM_BIN_TYPE:
    02927                     vallen = rpmcnt;
    02928                     valp = rpmvals;
    02929                     rpmcnt = 1;         /* XXX break out of loop. */
    02930                     /*@switchbreak@*/ break;
    02931                 case RPM_STRING_TYPE:
    02932                 case RPM_I18NSTRING_TYPE:
    02933                     rpmcnt = 1;         /* XXX break out of loop. */
    02934                     /*@fallthrough@*/
    02935                 case RPM_STRING_ARRAY_TYPE:
    02936                     /* Convert from hex to binary. */
    02937                     if (dbi->dbi_rpmtag == RPMTAG_FILEMD5S) {
    02938                         const char * s;
    02939                         unsigned char * t;
    02940
    02941                         s = rpmvals[i];
    02942                         t = bin;
    02943                         for (j = 0; j < 16; j++, t++, s += 2)
    02944                             *t = (nibble(s[0]) << 4) | nibble(s[1]);
    02945                         valp = bin;
    02946                         vallen = 16;
    02947                         /*@switchbreak@*/ break;
    02948                     }
    02949 #ifdef  NOTYET
    02950                     /* Extract the pubkey id from the base64 blob. */
    02951                     if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
    02952                         pgpDig dig = pgpNewDig();
    02953                         const byte * pkt;
    02954                         ssize_t pktlen;
    02955
    02956                         if (b64decode(rpmvals[i], (void **)&pkt, &pktlen))
    02957                             /*@innercontinue@*/ continue;
    02958                         (void) pgpPrtPkts(pkt, pktlen, dig, 0);
    02959                         memcpy(bin, dig->pubkey.signid, 8);
    02960                         pkt = _free(pkt);
    02961                         dig = _free(dig);
    02962                         valp = bin;
    02963                         vallen = 8;
    02964                         /*@switchbreak@*/ break;
    02965                     }
    02966 #endif
    02967                     /*@fallthrough@*/
    02968                 default:
    02969                     valp = rpmvals[i];
    02970                     vallen = strlen(rpmvals[i]);
    02971                     stringvalued = 1;
    02972                     /*@switchbreak@*/ break;
    02973                 }
    02974
    02975                 if (!printed) {
    02976                     if (rpmcnt == 1 && stringvalued) {
    02977                         rpmMessage(RPMMESS_DEBUG,
    02978                                 _("adding \"%s\" to %s index.\n"),
    02979                                 valp, tagName(dbi->dbi_rpmtag));
    02980                     } else {
    02981                         rpmMessage(RPMMESS_DEBUG,
    02982                                 _("adding %d entries to %s index.\n"),
    02983                                 rpmcnt, tagName(dbi->dbi_rpmtag));
    02984                     }
    02985                     printed++;
    02986                 }
    02987                 rc += addIndexEntry(dbi, dbcursor, valp, vallen, rec);
    02988             }
    02989             xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
    02990             dbcursor = NULL;
    02991
    02992             if (!dbi->dbi_no_dbsync)
    02993                 xx = dbiSync(dbi, 0);
    02994           }
    02995
    02996         /*@-observertrans@*/
    02997             if (rpmtype != RPM_BIN_TYPE)        /* XXX WTFO? HACK ALERT */
    02998                 rpmvals = hfd(rpmvals, rpmtype);
    02999         /*@=observertrans@*/
    03000             rpmtype = 0;
    03001             rpmcnt = 0;
    03002         }
    03003         /*@=nullpass =nullptrarith =nullderef @*/
    03004
    03005         rec = _free(rec);
    03006     }
    03007
    03008 exit:
    03009     (void) unblockSignals(db, &signalMask);
    03010
    03011     return rc;
    03012 }
    03013
    03014 /* XXX transaction.c */
    03015 int rpmdbFindFpList(rpmdb db, fingerPrint * fpList, dbiIndexSet * matchList,
    03016                     int numItems)
    03017 {
    03018     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    03019     HFD_t hfd = headerFreeData;
    03020     rpmdbMatchIterator mi;
    03021     fingerPrintCache fpc;
    03022     Header h;
    03023     int i, xx;
    03024
    03025     if (db == NULL) return 0;
    03026
    03027     mi = rpmdbInitIterator(db, RPMTAG_BASENAMES, NULL, 0);
    03028
    03029     /* Gather all matches from the database */
    03030     for (i = 0; i < numItems; i++) {
    03031         xx = rpmdbGrowIterator(mi, fpList[i].baseName, 0, i);
    03032         matchList[i] = xcalloc(1, sizeof(*(matchList[i])));
    03033     }
    03034
    03035     if ((i = rpmdbGetIteratorCount(mi)) == 0) {
    03036         mi = rpmdbFreeIterator(mi);
    03037         return 0;
    03038     }
    03039     fpc = fpCacheCreate(i);
    03040
    03041     rpmdbSortIterator(mi);
    03042     /* iterator is now sorted by (recnum, filenum) */
    03043
    03044     /* For each set of files matched in a package ... */
    03045     if (mi != NULL)
    03046     while ((h = rpmdbNextIterator(mi)) != NULL) {
    03047         const char ** dirNames;
    03048         const char ** baseNames;
    03049         const char ** fullBaseNames;
    03050         rpmTagType bnt, dnt;
    03051         int_32 * dirIndexes;
    03052         int_32 * fullDirIndexes;
    03053         fingerPrint * fps;
    03054         dbiIndexItem im;
    03055         int start;
    03056         int num;
    03057         int end;
    03058
    03059         start = mi->mi_setx - 1;
    03060         im = mi->mi_set->recs + start;
    03061
    03062         /* Find the end of the set of matched files in this package. */
    03063         for (end = start + 1; end < mi->mi_set->count; end++) {
    03064             if (im->hdrNum != mi->mi_set->recs[end].hdrNum)
    03065                 /*@innerbreak@*/ break;
    03066         }
    03067         num = end - start;
    03068
    03069         /* Compute fingerprints for this header's matches */
    03070         xx = hge(h, RPMTAG_BASENAMES, &bnt, (void **) &fullBaseNames, NULL);
    03071         xx = hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
    03072         xx = hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &fullDirIndexes, NULL);
    03073
    03074         baseNames = xcalloc(num, sizeof(*baseNames));
    03075         dirIndexes = xcalloc(num, sizeof(*dirIndexes));
    03076         for (i = 0; i < num; i++) {
    03077             baseNames[i] = fullBaseNames[im[i].tagNum];
    03078             dirIndexes[i] = fullDirIndexes[im[i].tagNum];
    03079         }
    03080
    03081         fps = xcalloc(num, sizeof(*fps));
    03082         fpLookupList(fpc, dirNames, baseNames, dirIndexes, num, fps);
    03083
    03084         /* Add db (recnum,filenum) to list for fingerprint matches. */
    03085         for (i = 0; i < num; i++, im++) {
    03086             /*@-nullpass@*/
    03087             if (FP_EQUAL(fps[i], fpList[im->fpNum])) {
    03088             /*@=nullpass@*/
    03089                 /*@-usedef@*/
    03090                 xx = dbiAppendSet(matchList[im->fpNum], im, 1, sizeof(*im), 0);
    03091                 /*@=usedef@*/
    03092             }
    03093         }
    03094
    03095         fps = _free(fps);
    03096         dirNames = hfd(dirNames, dnt);
    03097         fullBaseNames = hfd(fullBaseNames, bnt);
    03098         baseNames = _free(baseNames);
    03099         dirIndexes = _free(dirIndexes);
    03100
    03101         mi->mi_setx = end;
    03102     }
    03103
    03104     mi = rpmdbFreeIterator(mi);
    03105
    03106     fpCacheFree(fpc);
    03107
    03108     return 0;
    03109
    03110 }
    03111
    03112 char * db1basename (int rpmtag)
    03113 {
    03114     char * base = NULL;
    03115     /*@-branchstate@*/
    03116     switch (rpmtag) {
    03117     case RPMDBI_PACKAGES:       base = "packages.rpm";          break;
    03118     case RPMTAG_NAME:           base = "nameindex.rpm";         break;
    03119     case RPMTAG_BASENAMES:      base = "fileindex.rpm";         break;
    03120     case RPMTAG_GROUP:          base = "groupindex.rpm";        break;
    03121     case RPMTAG_REQUIRENAME:    base = "requiredby.rpm";        break;
    03122     case RPMTAG_PROVIDENAME:    base = "providesindex.rpm";     break;
    03123     case RPMTAG_CONFLICTNAME:   base = "conflictsindex.rpm";    break;
    03124     case RPMTAG_TRIGGERNAME:    base = "triggerindex.rpm";      break;
    03125     default:
    03126       { const char * tn = tagName(rpmtag);
    03127         base = alloca( strlen(tn) + sizeof(".idx") + 1 );
    03128         (void) stpcpy( stpcpy(base, tn), ".idx");
    03129       } break;
    03130     }
    03131     /*@=branchstate@*/
    03132     return xstrdup(base);
    03133 }
    03134
    03140 static int rpmioFileExists(const char * urlfn)
    03141         /*@globals fileSystem @*/
    03142         /*@modifies fileSystem @*/
    03143 {
    03144     const char *fn;
    03145     int urltype = urlPath(urlfn, &fn);
    03146     struct stat buf;
    03147
    03148     /*@-branchstate@*/
    03149     if (*fn == '\0') fn = "/";
    03150     /*@=branchstate@*/
    03151     switch (urltype) {
    03152     case URL_IS_FTP:    /* XXX WRONG WRONG WRONG */
    03153     case URL_IS_HTTP:   /* XXX WRONG WRONG WRONG */
    03154     case URL_IS_PATH:
    03155     case URL_IS_UNKNOWN:
    03156         if (Stat(fn, &buf)) {
    03157             switch(errno) {
    03158             case ENOENT:
    03159             case EINVAL:
    03160                 return 0;
    03161             }
    03162         }
    03163         break;
    03164     case URL_IS_DASH:
    03165     default:
    03166         return 0;
    03167         /*@notreached@*/ break;
    03168     }
    03169
    03170     return 1;
    03171 }
    03172
    03173 static int rpmdbRemoveDatabase(const char * prefix,
    03174                 const char * dbpath, int _dbapi)
    03175         /*@globals fileSystem @*/
    03176         /*@modifies fileSystem @*/
    03177 {
    03178     int i;
    03179     char * filename;
    03180     int xx;
    03181
    03182     i = strlen(dbpath);
    03183     /*@-branchstate@*/
    03184     if (dbpath[i - 1] != '/') {
    03185         filename = alloca(i);
    03186         strcpy(filename, dbpath);
    03187         filename[i] = '/';
    03188         filename[i + 1] = '\0';
    03189         dbpath = filename;
    03190     }
    03191     /*@=branchstate@*/
    03192
    03193     filename = alloca(strlen(prefix) + strlen(dbpath) + 40);
    03194
    03195     switch (_dbapi) {
    03196     case 3:
    03197         if (dbiTags != NULL)
    03198         for (i = 0; i < dbiTagsMax; i++) {
    03199             const char * base = tagName(dbiTags[i]);
    03200             sprintf(filename, "%s/%s/%s", prefix, dbpath, base);
    03201             (void)rpmCleanPath(filename);
    03202             if (!rpmioFileExists(filename))
    03203                 continue;
    03204             xx = unlink(filename);
    03205         }
    03206         for (i = 0; i < 16; i++) {
    03207             sprintf(filename, "%s/%s/__db.%03d", prefix, dbpath, i);
    03208             (void)rpmCleanPath(filename);
    03209             if (!rpmioFileExists(filename))
    03210                 continue;
    03211             xx = unlink(filename);
    03212         }
    03213         break;
    03214     case 2:
    03215     case 1:
    03216     case 0:
    03217         if (dbiTags != NULL)
    03218         for (i = 0; i < dbiTagsMax; i++) {
    03219             const char * base = db1basename(dbiTags[i]);
    03220             sprintf(filename, "%s/%s/%s", prefix, dbpath, base);
    03221             (void)rpmCleanPath(filename);
    03222             if (!rpmioFileExists(filename))
    03223                 continue;
    03224             xx = unlink(filename);
    03225             base = _free(base);
    03226         }
    03227         break;
    03228     }
    03229
    03230     sprintf(filename, "%s/%s", prefix, dbpath);
    03231     (void)rpmCleanPath(filename);
    03232     xx = rmdir(filename);
    03233
    03234     return 0;
    03235 }
    03236
    03237 static int rpmdbMoveDatabase(const char * prefix,
    03238                 const char * olddbpath, int _olddbapi,
    03239                 const char * newdbpath, int _newdbapi)
    03240         /*@globals fileSystem @*/
    03241         /*@modifies fileSystem @*/
    03242 {
    03243     int i;
    03244     char * ofilename, * nfilename;
    03245     int rc = 0;
    03246     int xx;
    03247
    03248     i = strlen(olddbpath);
    03249     /*@-branchstate@*/
    03250     if (olddbpath[i - 1] != '/') {
    03251         ofilename = alloca(i + 2);
    03252         strcpy(ofilename, olddbpath);
    03253         ofilename[i] = '/';
    03254         ofilename[i + 1] = '\0';
    03255         olddbpath = ofilename;
    03256     }
    03257     /*@=branchstate@*/
    03258
    03259     i = strlen(newdbpath);
    03260     /*@-branchstate@*/
    03261     if (newdbpath[i - 1] != '/') {
    03262         nfilename = alloca(i + 2);
    03263         strcpy(nfilename, newdbpath);
    03264         nfilename[i] = '/';
    03265         nfilename[i + 1] = '\0';
    03266         newdbpath = nfilename;
    03267     }
    03268     /*@=branchstate@*/
    03269
    03270     ofilename = alloca(strlen(prefix) + strlen(olddbpath) + 40);
    03271     nfilename = alloca(strlen(prefix) + strlen(newdbpath) + 40);
    03272
    03273     switch (_olddbapi) {
    03274     case 3:
    03275         if (dbiTags != NULL)
    03276         for (i = 0; i < dbiTagsMax; i++) {
    03277             const char * base;
    03278             int rpmtag;
    03279
    03280             /* Filter out temporary databases */
    03281             switch ((rpmtag = dbiTags[i])) {
    03282             case RPMDBI_AVAILABLE:
    03283             case RPMDBI_ADDED:
    03284             case RPMDBI_REMOVED:
    03285             case RPMDBI_DEPENDS:
    03286                 continue;
    03287                 /*@notreached@*/ /*@switchbreak@*/ break;
    03288             default:
    03289                 /*@switchbreak@*/ break;
    03290             }
    03291
    03292             base = tagName(rpmtag);
    03293             sprintf(ofilename, "%s/%s/%s", prefix, olddbpath, base);
    03294             (void)rpmCleanPath(ofilename);
    03295             if (!rpmioFileExists(ofilename))
    03296                 continue;
    03297             sprintf(nfilename, "%s/%s/%s", prefix, newdbpath, base);
    03298             (void)rpmCleanPath(nfilename);
    03299             if ((xx = Rename(ofilename, nfilename)) != 0)
    03300                 rc = 1;
    03301         }
    03302         for (i = 0; i < 16; i++) {
    03303             sprintf(ofilename, "%s/%s/__db.%03d", prefix, olddbpath, i);
    03304             (void)rpmCleanPath(ofilename);
    03305             if (!rpmioFileExists(ofilename))
    03306                 continue;
    03307             xx = unlink(ofilename);
    03308             sprintf(nfilename, "%s/%s/__db.%03d", prefix, newdbpath, i);
    03309             (void)rpmCleanPath(nfilename);
    03310 #ifdef  DYING
    03311             if ((xx = Rename(ofilename, nfilename)) != 0)
    03312                 rc = 1;
    03313 #else
    03314             xx = unlink(nfilename);
    03315 #endif
    03316         }
    03317         break;
    03318     case 2:
    03319     case 1:
    03320     case 0:
    03321         if (dbiTags != NULL)
    03322         for (i = 0; i < dbiTagsMax; i++) {
    03323             const char * base;
    03324             int rpmtag;
    03325
    03326             /* Filter out temporary databases */
    03327             switch ((rpmtag = dbiTags[i])) {
    03328             case RPMDBI_AVAILABLE:
    03329             case RPMDBI_ADDED:
    03330             case RPMDBI_REMOVED:
    03331             case RPMDBI_DEPENDS:
    03332                 continue;
    03333                 /*@notreached@*/ /*@switchbreak@*/ break;
    03334             default:
    03335                 /*@switchbreak@*/ break;
    03336             }
    03337
    03338             base = db1basename(rpmtag);
    03339             sprintf(ofilename, "%s/%s/%s", prefix, olddbpath, base);
    03340             (void)rpmCleanPath(ofilename);
    03341             if (!rpmioFileExists(ofilename))
    03342                 continue;
    03343             sprintf(nfilename, "%s/%s/%s", prefix, newdbpath, base);
    03344             (void)rpmCleanPath(nfilename);
    03345             if ((xx = Rename(ofilename, nfilename)) != 0)
    03346                 rc = 1;
    03347             base = _free(base);
    03348         }
    03349         break;
    03350     }
    03351     if (rc || _olddbapi == _newdbapi)
    03352         return rc;
    03353
    03354     rc = rpmdbRemoveDatabase(prefix, newdbpath, _newdbapi);
    03355
    03356
    03357     /* Remove /etc/rpm/macros.db1 configuration file if db3 rebuilt. */
    03358     if (rc == 0 && _newdbapi == 1 && _olddbapi == 3) {
    03359         const char * mdb1 = "/etc/rpm/macros.db1";
    03360         struct stat st;
    03361         if (!stat(mdb1, &st) && S_ISREG(st.st_mode) && !unlink(mdb1))
    03362             rpmMessage(RPMMESS_DEBUG,
    03363                 _("removing %s after successful db3 rebuild.\n"), mdb1);
    03364     }
    03365     return rc;
    03366 }
    03367
    03368 /*@-globs@*/ /* FIX: rpmGlobalMacroContext not in <rpmlib.h> */
    03369 int rpmdbRebuild(const char * prefix)
    03370 {
    03371     rpmdb olddb;
    03372     const char * dbpath = NULL;
    03373     const char * rootdbpath = NULL;
    03374     rpmdb newdb;
    03375     const char * newdbpath = NULL;
    03376     const char * newrootdbpath = NULL;
    03377     const char * tfn;
    03378     int nocleanup = 1;
    03379     int failed = 0;
    03380     int removedir = 0;
    03381     int rc = 0, xx;
    03382     int _dbapi;
    03383     int _dbapi_rebuild;
    03384
    03385     /*@-branchstate@*/
    03386     if (prefix == NULL) prefix = "/";
    03387     /*@=branchstate@*/
    03388
    03389     _dbapi = rpmExpandNumeric("%{_dbapi}");
    03390     _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
    03391
    03392     /*@-nullpass@*/
    03393     tfn = rpmGetPath("%{_dbpath}", NULL);
    03394     /*@=nullpass@*/
    03395     if (!(tfn && tfn[0] != '%')) {
    03396         rpmMessage(RPMMESS_DEBUG, _("no dbpath has been set"));
    03397         rc = 1;
    03398         goto exit;
    03399     }
    03400     dbpath = rootdbpath = rpmGetPath(prefix, tfn, NULL);
    03401     if (!(prefix[0] == '/' && prefix[1] == '\0'))
    03402         dbpath += strlen(prefix);
    03403     tfn = _free(tfn);
    03404
    03405     /*@-nullpass@*/
    03406     tfn = rpmGetPath("%{_dbpath_rebuild}", NULL);
    03407     /*@=nullpass@*/
    03408     if (!(tfn && tfn[0] != '%' && strcmp(tfn, dbpath))) {
    03409         char pidbuf[20];
    03410         char *t;
    03411         sprintf(pidbuf, "rebuilddb.%d", (int) getpid());
    03412         t = xmalloc(strlen(dbpath) + strlen(pidbuf) + 1);
    03413         (void)stpcpy(stpcpy(t, dbpath), pidbuf);
    03414         tfn = _free(tfn);
    03415         tfn = t;
    03416         nocleanup = 0;
    03417     }
    03418     newdbpath = newrootdbpath = rpmGetPath(prefix, tfn, NULL);
    03419     if (!(prefix[0] == '/' && prefix[1] == '\0'))
    03420         newdbpath += strlen(prefix);
    03421     tfn = _free(tfn);
    03422
    03423     rpmMessage(RPMMESS_DEBUG, _("rebuilding database %s into %s\n"),
    03424         rootdbpath, newrootdbpath);
    03425
    03426     if (!access(newrootdbpath, F_OK)) {
    03427         rpmError(RPMERR_MKDIR, _("temporary database %s already exists\n"),
    03428               newrootdbpath);
    03429         rc = 1;
    03430         goto exit;
    03431     }
    03432
    03433     rpmMessage(RPMMESS_DEBUG, _("creating directory %s\n"), newrootdbpath);
    03434     if (Mkdir(newrootdbpath, 0755)) {
    03435         rpmError(RPMERR_MKDIR, _("creating directory %s: %s\n"),
    03436               newrootdbpath, strerror(errno));
    03437         rc = 1;
    03438         goto exit;
    03439     }
    03440     removedir = 1;
    03441
    03442     rpmMessage(RPMMESS_DEBUG, _("opening old database with dbapi %d\n"),
    03443                 _dbapi);
    03444     _rebuildinprogress = 1;
    03445     if (openDatabase(prefix, dbpath, _dbapi, &olddb, O_RDONLY, 0644,
    03446                      RPMDB_FLAG_MINIMAL)) {
    03447         rc = 1;
    03448         goto exit;
    03449     }
    03450     _dbapi = olddb->db_api;
    03451     _rebuildinprogress = 0;
    03452
    03453     rpmMessage(RPMMESS_DEBUG, _("opening new database with dbapi %d\n"),
    03454                 _dbapi_rebuild);
    03455     (void) rpmDefineMacro(NULL, "_rpmdb_rebuild %{nil}", -1);
    03456     if (openDatabase(prefix, newdbpath, _dbapi_rebuild, &newdb, O_RDWR | O_CREAT, 0644, 0)) {
    03457         rc = 1;
    03458         goto exit;
    03459     }
    03460     _dbapi_rebuild = newdb->db_api;
    03461
    03462     {   Header h = NULL;
    03463         rpmdbMatchIterator mi;
    03464 #define _RECNUM rpmdbGetIteratorOffset(mi)
    03465
    03466         /* RPMDBI_PACKAGES */
    03467         mi = rpmdbInitIterator(olddb, RPMDBI_PACKAGES, NULL, 0);
    03468         while ((h = rpmdbNextIterator(mi)) != NULL) {
    03469
    03470             /* let's sanity check this record a bit, otherwise just skip it */
    03471             if (!(headerIsEntry(h, RPMTAG_NAME) &&
    03472                 headerIsEntry(h, RPMTAG_VERSION) &&
    03473                 headerIsEntry(h, RPMTAG_RELEASE) &&
    03474                 headerIsEntry(h, RPMTAG_BUILDTIME)))
    03475             {
    03476                 rpmError(RPMERR_INTERNAL,
    03477                         _("record number %u in database is bad -- skipping.\n"),
    03478                         _RECNUM);
    03479                 continue;
    03480             }
    03481
    03482             /* Filter duplicate entries ? (bug in pre rpm-3.0.4) */
    03483             if (_db_filter_dups || newdb->db_filter_dups) {
    03484                 const char * name, * version, * release;
    03485                 int skip = 0;
    03486
    03487                 (void) headerNVR(h, &name, &version, &release);
    03488
    03489                 /*@-shadow@*/
    03490                 {   rpmdbMatchIterator mi;
    03491                     mi = rpmdbInitIterator(newdb, RPMTAG_NAME, name, 0);
    03492                     (void) rpmdbSetIteratorRE(mi, RPMTAG_VERSION,
    03493                                 RPMMIRE_DEFAULT, version);
    03494                     (void) rpmdbSetIteratorRE(mi, RPMTAG_RELEASE,
    03495                                 RPMMIRE_DEFAULT, release);
    03496                     while (rpmdbNextIterator(mi)) {
    03497                         skip = 1;
    03498                         /*@innerbreak@*/ break;
    03499                     }
    03500                     mi = rpmdbFreeIterator(mi);
    03501                 }
    03502                 /*@=shadow@*/
    03503
    03504                 if (skip)
    03505                     continue;
    03506             }
    03507
    03508             /* Deleted entries are eliminated in legacy headers by copy. */
    03509             {   Header nh = (headerIsEntry(h, RPMTAG_HEADERIMAGE)
    03510                                 ? headerCopy(h) : NULL);
    03511                 rc = rpmdbAdd(newdb, -1, (nh ? nh : h));
    03512                 nh = headerFree(nh);
    03513             }
    03514
    03515             if (rc) {
    03516                 rpmError(RPMERR_INTERNAL,
    03517                         _("cannot add record originally at %u\n"), _RECNUM);
    03518                 failed = 1;
    03519                 break;
    03520             }
    03521         }
    03522
    03523         mi = rpmdbFreeIterator(mi);
    03524
    03525     }
    03526
    03527     if (!nocleanup) {
    03528         olddb->db_remove_env = 1;
    03529         newdb->db_remove_env = 1;
    03530     }
    03531     xx = rpmdbClose(olddb);
    03532     xx = rpmdbClose(newdb);
    03533
    03534     if (failed) {
    03535         rpmMessage(RPMMESS_NORMAL, _("failed to rebuild database: original database "
    03536                 "remains in place\n"));
    03537
    03538         xx = rpmdbRemoveDatabase(prefix, newdbpath, _dbapi_rebuild);
    03539         rc = 1;
    03540         goto exit;
    03541     } else if (!nocleanup) {
    03542         if (rpmdbMoveDatabase(prefix, newdbpath, _dbapi_rebuild, dbpath, _dbapi)) {
    03543             rpmMessage(RPMMESS_ERROR, _("failed to replace old database with new "
    03544                         "database!\n"));
    03545             rpmMessage(RPMMESS_ERROR, _("replace files in %s with files from %s "
    03546                         "to recover"), dbpath, newdbpath);
    03547             rc = 1;
    03548             goto exit;
    03549         }
    03550     }
    03551     rc = 0;
    03552
    03553 exit:
    03554     if (removedir && !(rc == 0 && nocleanup)) {
    03555         rpmMessage(RPMMESS_DEBUG, _("removing directory %s\n"), newrootdbpath);
    03556         if (Rmdir(newrootdbpath))
    03557             rpmMessage(RPMMESS_ERROR, _("failed to remove directory %s: %s\n"),
    03558                         newrootdbpath, strerror(errno));
    03559     }
    03560     newrootdbpath = _free(newrootdbpath);
    03561     rootdbpath = _free(rootdbpath);
    03562
    03563     return rc;
    03564 }
    03565 /*@=globs@*/
    03566 /*@=mods@*/
    03567 /*@=sizeoftype @*/