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 @*/

Generated on Tue Oct 18 05:41:30 2005 for rpm by  doxygen 1.4.1