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

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