rpmdb/db3.c

Go to the documentation of this file.
00001 /*@-type@*/ /* FIX: annotate db3 methods */
00006 /*@unchecked@*/
00007 static int _debug = 1;  /* XXX if < 0 debugging, > 0 unusual error returns */
00008 
00009 #include "system.h"
00010 
00011 #if defined(HAVE_FTOK) && defined(HAVE_SYS_IPC_H)
00012 #include <sys/ipc.h>
00013 #endif
00014 
00015 #if defined(__LCLINT__)
00016 /*@-redef@*/ /* FIX: rpmio/rpmio.c also declares */
00017 typedef unsigned int u_int32_t;
00018 typedef unsigned short u_int16_t;
00019 typedef unsigned char u_int8_t;
00020 /*@-incondefs@*/        /* LCLint 3.0.0.15 */
00021 typedef int int32_t;
00022 /*@=incondefs@*/
00023 /*@=redef@*/
00024 #endif
00025 
00026 #include <db3/db.h>
00027 
00028 #include <rpmlib.h>
00029 #include <rpmmacro.h>
00030 #include <rpmurl.h>     /* XXX urlPath proto */
00031 
00032 #include "rpmdb.h"
00033 
00034 #include "debug.h"
00035 
00036 /*@access rpmdb@*/
00037 /*@access dbiIndex@*/
00038 /*@access dbiIndexSet@*/
00039 
00043 /*@-fielduse@*/
00044 struct dbiHStats_s {
00045     unsigned int hash_magic;    
00046     unsigned int hash_version;  
00047     unsigned int hash_nkeys;    
00048     unsigned int hash_ndata;    
00049     unsigned int hash_pagesize; 
00050     unsigned int hash_nelem;    
00051     unsigned int hash_ffactor;  
00052     unsigned int hash_buckets;  
00053     unsigned int hash_free;     
00054     unsigned int hash_bfree;    
00055     unsigned int hash_bigpages; 
00056     unsigned int hash_big_bfree;
00057     unsigned int hash_overflows;
00058     unsigned int hash_ovfl_free;
00059     unsigned int hash_dup;      
00060     unsigned int hash_dup_free; 
00061 };
00062 
00066 struct dbiBStats_s {
00067     unsigned int bt_magic;      
00068     unsigned int bt_version;    
00069     unsigned int bt_nkeys;      
00070     unsigned int bt_ndata;      
00071     unsigned int bt_pagesize;   
00072     unsigned int bt_minkey;     
00073     unsigned int bt_re_len;     
00074     unsigned int bt_re_pad;     
00075     unsigned int bt_levels;     
00076     unsigned int bt_int_pg;     
00077     unsigned int bt_leaf_pg;    
00078     unsigned int bt_dup_pg;     
00079     unsigned int bt_over_pg;    
00080     unsigned int bt_free;       
00081     unsigned int bt_int_pgfree; 
00082     unsigned int bt_leaf_pgfree;
00083     unsigned int bt_dup_pgfree; 
00084     unsigned int bt_over_pgfree;
00085 };
00086 /*@=fielduse@*/
00087 
00088 /*@-globuse -mustmod @*/        /* FIX: rpmError not annotated yet. */
00089 static int cvtdberr(dbiIndex dbi, const char * msg, int error, int printit)
00090         /*@globals fileSystem @*/
00091         /*@modifies fileSystem @*/
00092 {
00093     int rc = 0;
00094 
00095     rc = error;
00096 
00097     if (printit && rc) {
00098         /*@-moduncon@*/ /* FIX: annotate db3 methods */
00099         if (msg)
00100             rpmError(RPMERR_DBERR, _("db%d error(%d) from %s: %s\n"),
00101                 dbi->dbi_api, rc, msg, db_strerror(error));
00102         else
00103             rpmError(RPMERR_DBERR, _("db%d error(%d): %s\n"),
00104                 dbi->dbi_api, rc, db_strerror(error));
00105         /*@=moduncon@*/
00106     }
00107 
00108     return rc;
00109 }
00110 /*@=globuse =mustmod @*/
00111 
00112 static int db_fini(dbiIndex dbi, const char * dbhome,
00113                 /*@null@*/ const char * dbfile,
00114                 /*@unused@*/ /*@null@*/ const char * dbsubfile)
00115         /*@globals fileSystem @*/
00116         /*@modifies fileSystem @*/
00117 {
00118     rpmdb rpmdb = dbi->dbi_rpmdb;
00119     DB_ENV * dbenv = rpmdb->db_dbenv;
00120     int rc;
00121 
00122     if (dbenv == NULL)
00123         return 0;
00124 
00125     rc = dbenv->close(dbenv, 0);
00126     rc = cvtdberr(dbi, "dbenv->close", rc, _debug);
00127 
00128     if (dbfile)
00129         rpmMessage(RPMMESS_DEBUG, _("closed   db environment %s/%s\n"),
00130                         dbhome, dbfile);
00131 
00132     if (rpmdb->db_remove_env || dbi->dbi_tear_down) {
00133         int xx;
00134 
00135         /*@-moduncon@*/ /* FIX: annotate db3 methods */
00136         xx = db_env_create(&dbenv, 0);
00137         /*@=moduncon@*/
00138         xx = cvtdberr(dbi, "db_env_create", rc, _debug);
00139 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
00140         xx = dbenv->remove(dbenv, dbhome, 0);
00141 #else
00142         xx = dbenv->remove(dbenv, dbhome, NULL, 0);
00143 #endif
00144         xx = cvtdberr(dbi, "dbenv->remove", rc, _debug);
00145 
00146         if (dbfile)
00147             rpmMessage(RPMMESS_DEBUG, _("removed  db environment %s/%s\n"),
00148                         dbhome, dbfile);
00149 
00150     }
00151     return rc;
00152 }
00153 
00154 static int db3_fsync_disable(/*@unused@*/ int fd)
00155         /*@*/
00156 {
00157     return 0;
00158 }
00159 
00160 /*@-moduncon@*/ /* FIX: annotate db3 methods */
00161 static int db_init(dbiIndex dbi, const char * dbhome,
00162                 /*@null@*/ const char * dbfile,
00163                 /*@unused@*/ /*@null@*/ const char * dbsubfile,
00164                 /*@out@*/ DB_ENV ** dbenvp)
00165         /*@globals rpmGlobalMacroContext,
00166                 fileSystem @*/
00167         /*@modifies dbi, *dbenvp, fileSystem @*/
00168 {
00169     rpmdb rpmdb = dbi->dbi_rpmdb;
00170     DB_ENV *dbenv = NULL;
00171     int eflags;
00172     int rc;
00173 
00174     if (dbenvp == NULL)
00175         return 1;
00176 
00177     /* XXX HACK */
00178     /*@-assignexpose@*/
00179     if (rpmdb->db_errfile == NULL)
00180         rpmdb->db_errfile = stderr;
00181     /*@=assignexpose@*/
00182 
00183     eflags = (dbi->dbi_oeflags | dbi->dbi_eflags);
00184     if (eflags & DB_JOINENV) eflags &= DB_JOINENV;
00185 
00186     if (dbfile)
00187         rpmMessage(RPMMESS_DEBUG, _("opening  db environment %s/%s %s\n"),
00188                 dbhome, dbfile, prDbiOpenFlags(eflags, 1));
00189 
00190     /* XXX Can't do RPC w/o host. */
00191     if (dbi->dbi_host == NULL)
00192         dbi->dbi_ecflags &= ~DB_CLIENT;
00193 
00194     /* XXX Set a default shm_key. */
00195     if ((dbi->dbi_eflags & DB_SYSTEM_MEM) && dbi->dbi_shmkey == 0) {
00196 #if defined(HAVE_FTOK)
00197         dbi->dbi_shmkey = ftok(dbhome, 0);
00198 #else
00199         dbi->dbi_shmkey = 0x44631380;
00200 #endif
00201     }
00202 
00203     rc = db_env_create(&dbenv, dbi->dbi_ecflags);
00204     rc = cvtdberr(dbi, "db_env_create", rc, _debug);
00205     if (rc)
00206         goto errxit;
00207 
00208     if (dbenv == NULL)
00209         return 1;
00210 
00211   { int xx;
00212     /*@-noeffectuncon@*/ /* FIX: annotate db3 methods */
00213     dbenv->set_errcall(dbenv, rpmdb->db_errcall);
00214     dbenv->set_errfile(dbenv, rpmdb->db_errfile);
00215     dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
00216  /* dbenv->set_paniccall(???) */
00217     /*@=noeffectuncon@*/
00218     xx = dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT,
00219                 (dbi->dbi_verbose & DB_VERB_CHKPOINT));
00220     xx = dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK,
00221                 (dbi->dbi_verbose & DB_VERB_DEADLOCK));
00222     xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY,
00223                 (dbi->dbi_verbose & DB_VERB_RECOVERY));
00224     xx = dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR,
00225                 (dbi->dbi_verbose & DB_VERB_WAITSFOR));
00226  /* dbenv->set_lg_max(???) */
00227  /* dbenv->set_lk_conflicts(???) */
00228  /* dbenv->set_lk_detect(???) */
00229  /* dbenv->set_lk_max(???) */
00230     xx = dbenv->set_mp_mmapsize(dbenv, dbi->dbi_mp_mmapsize);
00231     xx = cvtdberr(dbi, "dbenv->set_mp_mmapsize", xx, _debug);
00232     xx = dbenv->set_cachesize(dbenv, 0, dbi->dbi_mp_size, 0);
00233     xx = cvtdberr(dbi, "dbenv->set_cachesize", xx, _debug);
00234  /* dbenv->set_tx_max(???) */
00235  /* dbenv->set_tx_recover(???) */
00236     if (dbi->dbi_no_fsync) {
00237 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
00238         xx = db_env_set_func_fsync(db3_fsync_disable);
00239 #else
00240         xx = dbenv->set_func_fsync(dbenv, db3_fsync_disable);
00241 #endif
00242         xx = cvtdberr(dbi, "db_env_set_func_fsync", xx, _debug);
00243     }
00244 
00245 /* XXX 3.3.4 change. */
00246 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
00247     if ((dbi->dbi_ecflags & DB_CLIENT) && dbi->dbi_host) {
00248         xx = dbenv->set_rpc_server(dbenv, NULL, dbi->dbi_host,
00249                 dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
00250         xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
00251     }
00252 #else
00253     if ((dbi->dbi_ecflags & DB_CLIENT) && dbi->dbi_host) {
00254         xx = dbenv->set_server(dbenv, dbi->dbi_host,
00255                 dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
00256         xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
00257     }
00258 #endif
00259     if (dbi->dbi_shmkey) {
00260         xx = dbenv->set_shm_key(dbenv, dbi->dbi_shmkey);
00261         xx = cvtdberr(dbi, "dbenv->set_shm_key", xx, _debug);
00262     }
00263     if (dbi->dbi_tmpdir) {
00264         const char * root;
00265         const char * tmpdir;
00266 
00267         root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
00268         if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
00269             root = NULL;
00270         /*@-mods@*/
00271         tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
00272         /*@=mods@*/
00273         xx = dbenv->set_tmp_dir(dbenv, tmpdir);
00274         xx = cvtdberr(dbi, "dbenv->set_tmp_dir", rc, _debug);
00275         tmpdir = _free(tmpdir);
00276     }
00277   }
00278 
00279 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
00280     rc = dbenv->open(dbenv, dbhome, eflags, dbi->dbi_perms);
00281 #else
00282     rc = dbenv->open(dbenv, dbhome, NULL, eflags, dbi->dbi_perms);
00283 #endif
00284     rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
00285     if (rc)
00286         goto errxit;
00287 
00288     *dbenvp = dbenv;
00289 
00290     return 0;
00291 
00292 errxit:
00293     if (dbenv) {
00294         int xx;
00295         xx = dbenv->close(dbenv, 0);
00296         xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
00297     }
00298     return rc;
00299 }
00300 /*@=moduncon@*/
00301 
00302 static int db3sync(dbiIndex dbi, unsigned int flags)
00303         /*@globals fileSystem @*/
00304         /*@modifies fileSystem @*/
00305 {
00306     DB * db = dbi->dbi_db;
00307     int rc = 0;
00308     int _printit;
00309 
00310     if (db != NULL)
00311         rc = db->sync(db, flags);
00312     /* XXX DB_INCOMPLETE is returned occaisionally with multiple access. */
00313     _printit = (rc == DB_INCOMPLETE ? 0 : _debug);
00314     rc = cvtdberr(dbi, "db->sync", rc, _printit);
00315     return rc;
00316 }
00317 
00318 static int db3c_del(dbiIndex dbi, DBC * dbcursor, u_int32_t flags)
00319         /*@globals fileSystem @*/
00320         /*@modifies fileSystem @*/
00321 {
00322     int rc;
00323 
00324     rc = dbcursor->c_del(dbcursor, flags);
00325     rc = cvtdberr(dbi, "dbcursor->c_del", rc, _debug);
00326     return rc;
00327 }
00328 
00329 /*@unused@*/ static int db3c_dup(dbiIndex dbi, DBC * dbcursor, DBC ** dbcp,
00330                 u_int32_t flags)
00331         /*@globals fileSystem @*/
00332         /*@modifies *dbcp, fileSystem @*/
00333 {
00334     int rc;
00335 
00336     if (dbcp) *dbcp = NULL;
00337     rc = dbcursor->c_dup(dbcursor, dbcp, flags);
00338     rc = cvtdberr(dbi, "dbcursor->c_dup", rc, _debug);
00339     /*@-nullstate @*/ /* FIX: *dbcp can be NULL */
00340     return rc;
00341     /*@=nullstate @*/
00342 }
00343 
00344 static int db3c_get(dbiIndex dbi, DBC * dbcursor,
00345                 DBT * key, DBT * data, u_int32_t flags)
00346         /*@globals fileSystem @*/
00347         /*@modifies fileSystem @*/
00348 {
00349     int _printit;
00350     int rc;
00351     int rmw;
00352 
00353 #ifdef  NOTYET
00354     if ((dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY))
00355         rmw = DB_RMW;
00356     else
00357 #endif
00358         rmw = 0;
00359 
00360     rc = dbcursor->c_get(dbcursor, key, data, rmw | flags);
00361 
00362     /* XXX DB_NOTFOUND can be returned */
00363     _printit = (rc == DB_NOTFOUND ? 0 : _debug);
00364     rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit);
00365     return rc;
00366 }
00367 
00368 static int db3c_put(dbiIndex dbi, DBC * dbcursor,
00369                 DBT * key, DBT * data, u_int32_t flags)
00370         /*@globals fileSystem @*/
00371         /*@modifies fileSystem @*/
00372 {
00373     int rc;
00374 
00375     rc = dbcursor->c_put(dbcursor, key, data, flags);
00376 
00377     rc = cvtdberr(dbi, "dbcursor->c_put", rc, _debug);
00378     return rc;
00379 }
00380 
00381 static inline int db3c_close(dbiIndex dbi, /*@only@*/ /*@null@*/ DBC * dbcursor)
00382         /*@globals fileSystem @*/
00383         /*@modifies fileSystem @*/
00384 {
00385     int rc;
00386 
00387     if (dbcursor == NULL) return -2;
00388 
00389     rc = dbcursor->c_close(dbcursor);
00390     rc = cvtdberr(dbi, "dbcursor->c_close", rc, _debug);
00391     return rc;
00392 }
00393 
00394 static inline int db3c_open(dbiIndex dbi, /*@null@*/ /*@out@*/ DBC ** dbcp,
00395                 int dbiflags)
00396         /*@globals fileSystem @*/
00397         /*@modifies *dbcp, fileSystem @*/
00398 {
00399     DB * db = dbi->dbi_db;
00400     DB_TXN * txnid = NULL;
00401     int flags;
00402     int rc;
00403 
00404     if (db == NULL) return -2;
00405     if ((dbiflags & DBI_WRITECURSOR) &&
00406         (dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY))
00407     {
00408         flags = DB_WRITECURSOR;
00409     } else
00410         flags = 0;
00411     if (dbcp) *dbcp = NULL;
00412     rc = db->cursor(db, txnid, dbcp, flags);
00413     rc = cvtdberr(dbi, "db3c_open", rc, _debug);
00414 
00415     return rc;
00416 }
00417 
00418 static int db3cclose(dbiIndex dbi, /*@only@*/ /*@null@*/ DBC * dbcursor,
00419                 unsigned int flags)
00420         /*@globals fileSystem @*/
00421         /*@modifies dbi, fileSystem @*/
00422 {
00423     int rc = 0;
00424 
00425     /* XXX per-iterator cursors */
00426     if (flags & DBI_ITERATOR)
00427         return db3c_close(dbi, dbcursor);
00428 
00429     if (!dbi->dbi_use_cursors)
00430         return 0;
00431 
00432     /*@-branchstate@*/
00433     if (dbcursor == NULL)
00434         dbcursor = dbi->dbi_rmw;
00435     /*@=branchstate@*/
00436     if (dbcursor) {
00437         /*@-branchstate@*/
00438         if (dbcursor == dbi->dbi_rmw)
00439             dbi->dbi_rmw = NULL;
00440         /*@=branchstate@*/
00441         rc = db3c_close(dbi, dbcursor);
00442     }
00443     /*@-usereleased -compdef@*/ return rc; /*@=usereleased =compdef@*/
00444 }
00445 
00446 static int db3copen(dbiIndex dbi,
00447                 /*@null@*/ /*@out@*/ DBC ** dbcp, unsigned int flags)
00448         /*@globals fileSystem @*/
00449         /*@modifies dbi, *dbcp, fileSystem @*/
00450 {
00451     DBC * dbcursor;
00452     int rc = 0;
00453 
00454     /* XXX per-iterator cursors */
00455     if (flags & DBI_ITERATOR)
00456         return db3c_open(dbi, dbcp, flags);
00457 
00458     if (!dbi->dbi_use_cursors) {
00459         if (dbcp) *dbcp = NULL;
00460         return 0;
00461     }
00462 
00463     if ((dbcursor = dbi->dbi_rmw) == NULL) {
00464         if ((rc = db3c_open(dbi, &dbcursor, flags)) == 0)
00465             dbi->dbi_rmw = dbcursor;
00466     }
00467 
00468     if (dbcp)
00469         /*@-onlytrans@*/ *dbcp = dbi->dbi_rmw; /*@=onlytrans@*/
00470 
00471     return rc;
00472 }
00473 
00474 static int db3cput(dbiIndex dbi, DBC * dbcursor,
00475                 const void * keyp, size_t keylen,
00476                 const void * datap, size_t datalen,
00477                 /*@unused@*/ unsigned int flags)
00478         /*@globals fileSystem @*/
00479         /*@modifies fileSystem @*/
00480 {
00481     DB * db = dbi->dbi_db;
00482     DB_TXN * txnid = NULL;
00483     DBT key, data;
00484     int rc;
00485 
00486     memset(&key, 0, sizeof(key));
00487     memset(&data, 0, sizeof(data));
00488     key.data = (void *)keyp;
00489     key.size = keylen;
00490     data.data = (void *)datap;
00491     data.size = datalen;
00492 
00493     if (dbcursor == NULL) {
00494         if (db == NULL) return -2;
00495         rc = db->put(db, txnid, &key, &data, 0);
00496         rc = cvtdberr(dbi, "db->put", rc, _debug);
00497     } else {
00498 
00499         rc = db3c_put(dbi, dbcursor, &key, &data, DB_KEYLAST);
00500 
00501     }
00502 
00503     return rc;
00504 }
00505 
00506 static int db3cdel(dbiIndex dbi, DBC * dbcursor,
00507                 const void * keyp, size_t keylen,
00508                 /*@unused@*/ unsigned int flags)
00509         /*@globals fileSystem @*/
00510         /*@modifies fileSystem @*/
00511 {
00512     DB * db = dbi->dbi_db;
00513     DB_TXN * txnid = NULL;
00514     DBT key, data;
00515     int rc;
00516 
00517     memset(&key, 0, sizeof(key));
00518     memset(&data, 0, sizeof(data));
00519 
00520     key.data = (void *)keyp;
00521     key.size = keylen;
00522 
00523     if (dbcursor == NULL) {
00524         if (db == NULL) return -2;
00525         rc = db->del(db, txnid, &key, 0);
00526         rc = cvtdberr(dbi, "db->del", rc, _debug);
00527     } else {
00528 
00529         rc = db3c_get(dbi, dbcursor, &key, &data, DB_SET);
00530 
00531         if (rc == 0) {
00532             /* XXX TODO: loop over duplicates */
00533             rc = db3c_del(dbi, dbcursor, 0);
00534         }
00535 
00536     }
00537 
00538     return rc;
00539 }
00540 
00541 static int db3cget(dbiIndex dbi, DBC * dbcursor,
00542                 /*@null@*/ void ** keyp, /*@null@*/ size_t * keylen,
00543                 /*@null@*/ void ** datap, /*@null@*/ size_t * datalen,
00544                 /*@unused@*/ unsigned int flags)
00545         /*@globals fileSystem @*/
00546         /*@modifies *keyp, *keylen, *datap, *datalen, fileSystem @*/
00547 {
00548     DB * db = dbi->dbi_db;
00549     DB_TXN * txnid = NULL;
00550     DBT key, data;
00551     int rc;
00552 
00553     memset(&key, 0, sizeof(key));
00554     memset(&data, 0, sizeof(data));
00555     /*@-unqualifiedtrans@*/
00556     if (keyp)           key.data = *keyp;
00557     if (keylen)         key.size = *keylen;
00558     if (datap)          data.data = *datap;
00559     if (datalen)        data.size = *datalen;
00560     /*@=unqualifiedtrans@*/
00561 
00562     if (dbcursor == NULL) {
00563         int _printit;
00564         /*@-compmempass@*/
00565         if (db == NULL) return -2;
00566         /*@=compmempass@*/
00567         rc = db->get(db, txnid, &key, &data, 0);
00568         /* XXX DB_NOTFOUND can be returned */
00569         _printit = (rc == DB_NOTFOUND ? 0 : _debug);
00570         rc = cvtdberr(dbi, "db->get", rc, _printit);
00571     } else {
00572 
00573         /* XXX db3 does DB_FIRST on uninitialized cursor */
00574         rc = db3c_get(dbi, dbcursor, &key, &data,
00575                 key.data == NULL ? DB_NEXT : DB_SET);
00576 
00577     }
00578 
00579     if (rc == 0) {
00580         /*@-onlytrans@*/
00581         if (keyp)       *keyp = key.data;
00582         if (keylen)     *keylen = key.size;
00583         if (datap)      *datap = data.data;
00584         if (datalen)    *datalen = data.size;
00585         /*@=onlytrans@*/
00586     }
00587 
00588     /*@-compmempass -nullstate@*/
00589     return rc;
00590     /*@=compmempass =nullstate@*/
00591 }
00592 
00593 static int db3ccount(dbiIndex dbi, DBC * dbcursor,
00594                 /*@null@*/ /*@out@*/ unsigned int * countp,
00595                 /*@unused@*/ unsigned int flags)
00596         /*@globals fileSystem @*/
00597         /*@modifies *countp, fileSystem @*/
00598 {
00599     db_recno_t count = 0;
00600     int rc = 0;
00601 
00602     flags = 0;
00603     rc = dbcursor->c_count(dbcursor, &count, flags);
00604     rc = cvtdberr(dbi, "dbcursor->c_count", rc, _debug);
00605     if (rc) return rc;
00606     if (countp) *countp = count;
00607 
00608     return rc;
00609 }
00610 
00611 static int db3byteswapped(dbiIndex dbi) /*@*/
00612 {
00613     DB * db = dbi->dbi_db;
00614     int rc = 0;
00615 
00616     if (db != NULL) {
00617 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH == 11) \
00618  || (DB_VERSION_MAJOR == 4)
00619         int isswapped = 0;
00620         rc = db->get_byteswapped(db, &isswapped);
00621         if (rc == 0)
00622             rc = isswapped;
00623 #else
00624         rc = db->get_byteswapped(db);
00625 #endif
00626     }
00627 
00628     return rc;
00629 }
00630 
00631 static int db3stat(dbiIndex dbi, unsigned int flags)
00632         /*@globals fileSystem @*/
00633         /*@modifies dbi, fileSystem @*/
00634 {
00635     DB * db = dbi->dbi_db;
00636     int rc = 0;
00637 
00638     if (db == NULL) return -2;
00639 #if defined(DB_FAST_STAT)
00640     if (flags)
00641         flags = DB_FAST_STAT;
00642     else
00643 #endif
00644         flags = 0;
00645     dbi->dbi_stats = _free(dbi->dbi_stats);
00646 /* XXX 3.3.4 change. */
00647 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
00648     rc = db->stat(db, &dbi->dbi_stats, flags);
00649 #else
00650     rc = db->stat(db, &dbi->dbi_stats, NULL, flags);
00651 #endif
00652     rc = cvtdberr(dbi, "db->stat", rc, _debug);
00653     return rc;
00654 }
00655 
00656 /*@-moduncon@*/ /* FIX: annotate db3 methods */
00657 static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
00658         /*@globals rpmGlobalMacroContext,
00659                 fileSystem @*/
00660         /*@modifies dbi, fileSystem @*/
00661 {
00662     rpmdb rpmdb = dbi->dbi_rpmdb;
00663     const char * urlfn = NULL;
00664     const char * root;
00665     const char * home;
00666     const char * dbhome;
00667     const char * dbfile;
00668     const char * dbsubfile;
00669     DB * db = dbi->dbi_db;
00670     int rc = 0, xx;
00671 
00672     flags = 0;  /* XXX unused */
00673 
00674     /*
00675      * Get the prefix/root component and directory path.
00676      */
00677     root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
00678     if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
00679         root = NULL;
00680     home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
00681 
00682     /*
00683      * Either the root or directory components may be a URL. Concatenate,
00684      * convert the URL to a path, and add the name of the file.
00685      */
00686     /*@-mods@*/
00687     urlfn = rpmGenPath(root, home, NULL);
00688     /*@=mods@*/
00689     (void) urlPath(urlfn, &dbhome);
00690     if (dbi->dbi_temporary) {
00691         dbfile = NULL;
00692         dbsubfile = NULL;
00693     } else {
00694 #ifdef  HACK    /* XXX necessary to support dbsubfile */
00695         dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
00696         dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : tagName(dbi->dbi_rpmtag));
00697 #else
00698         dbfile = (dbi->dbi_file ? dbi->dbi_file : tagName(dbi->dbi_rpmtag));
00699         dbsubfile = NULL;
00700 #endif
00701     }
00702 
00703     if (dbi->dbi_rmw)
00704         rc = db3cclose(dbi, NULL, 0);
00705 
00706     if (db) {
00707         rc = db->close(db, 0);
00708         rc = cvtdberr(dbi, "db->close", rc, _debug);
00709         db = dbi->dbi_db = NULL;
00710 
00711         rpmMessage(RPMMESS_DEBUG, _("closed   db index       %s/%s\n"),
00712                 dbhome, (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)));
00713 
00714     }
00715 
00716     if (rpmdb->db_dbenv != NULL && dbi->dbi_use_dbenv) {
00717         if (rpmdb->db_opens == 1) {
00718             /*@-nullstate@*/
00719             xx = db_fini(dbi, (dbhome ? dbhome : ""), dbfile, dbsubfile);
00720             /*@=nullstate@*/
00721             rpmdb->db_dbenv = NULL;
00722         }
00723         rpmdb->db_opens--;
00724     }
00725 
00726     if (dbi->dbi_verify_on_close && !dbi->dbi_temporary) {
00727         DB_ENV * dbenv = NULL;
00728 
00729         /*@-moduncon@*/ /* FIX: annotate db3 methods */
00730         rc = db_env_create(&dbenv, 0);
00731         /*@=moduncon@*/
00732         rc = cvtdberr(dbi, "db_env_create", rc, _debug);
00733         if (rc || dbenv == NULL) goto exit;
00734 
00735         /*@-noeffectuncon@*/ /* FIX: annotate db3 methods */
00736         dbenv->set_errcall(dbenv, rpmdb->db_errcall);
00737         dbenv->set_errfile(dbenv, rpmdb->db_errfile);
00738         dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
00739  /*     dbenv->set_paniccall(???) */
00740         /*@=noeffectuncon@*/
00741         xx = dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT,
00742                 (dbi->dbi_verbose & DB_VERB_CHKPOINT));
00743         xx = dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK,
00744                 (dbi->dbi_verbose & DB_VERB_DEADLOCK));
00745         xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY,
00746                 (dbi->dbi_verbose & DB_VERB_RECOVERY));
00747         xx = dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR,
00748                 (dbi->dbi_verbose & DB_VERB_WAITSFOR));
00749 
00750         if (dbi->dbi_tmpdir) {
00751             /*@-mods@*/
00752             const char * tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
00753             /*@=mods@*/
00754             rc = dbenv->set_tmp_dir(dbenv, tmpdir);
00755             rc = cvtdberr(dbi, "dbenv->set_tmp_dir", rc, _debug);
00756             tmpdir = _free(tmpdir);
00757             if (rc) goto exit;
00758         }
00759             
00760         rc = dbenv->open(dbenv, dbhome,
00761             DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0);
00762         rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
00763         if (rc) goto exit;
00764 
00765         /*@-moduncon@*/ /* FIX: annotate db3 methods */
00766         rc = db_create(&db, dbenv, 0);
00767         /*@=moduncon@*/
00768         rc = cvtdberr(dbi, "db_create", rc, _debug);
00769 
00770         if (db != NULL) {
00771                 /*@-mods@*/
00772                 const char * dbf = rpmGetPath(dbhome, "/", dbfile, NULL);
00773                 /*@=mods@*/
00774 
00775                 rc = db->verify(db, dbf, NULL, NULL, flags);
00776                 rc = cvtdberr(dbi, "db->verify", rc, _debug);
00777 
00778                 rpmMessage(RPMMESS_DEBUG, _("verified db index       %s/%s\n"),
00779                         (dbhome ? dbhome : ""),
00780                         (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)));
00781 
00782                 xx = db->close(db, 0);
00783                 xx = cvtdberr(dbi, "db->close", xx, _debug);
00784                 db = NULL;
00785                 if (rc == 0 && xx) rc = xx;
00786 
00787                 dbf = _free(dbf);
00788         }
00789         xx = dbenv->close(dbenv, 0);
00790         xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
00791         if (rc == 0 && xx) rc = xx;
00792     }
00793 
00794 exit:
00795     dbi->dbi_db = NULL;
00796 
00797     urlfn = _free(urlfn);
00798 
00799     dbi = db3Free(dbi);
00800 
00801     return rc;
00802 }
00803 /*@=moduncon@*/
00804 
00805 static int db3open(/*@keep@*/ rpmdb rpmdb, int rpmtag, dbiIndex * dbip)
00806         /*@globals rpmGlobalMacroContext,
00807                 fileSystem @*/
00808         /*@modifies *dbip, fileSystem @*/
00809 {
00810     /*@-nestedextern@*/
00811     extern struct _dbiVec db3vec;
00812     /*@=nestedextern@*/
00813     const char * urlfn = NULL;
00814     const char * root;
00815     const char * home;
00816     const char * dbhome;
00817     const char * dbfile;
00818     const char * dbsubfile;
00819     dbiIndex dbi = NULL;
00820     int rc = 0;
00821     int xx;
00822 
00823     DB * db = NULL;
00824     DB_ENV * dbenv = NULL;
00825     DB_TXN * txnid = NULL;
00826     u_int32_t oflags;
00827     int _printit;
00828 
00829     if (dbip)
00830         *dbip = NULL;
00831 
00832     /*
00833      * Parse db configuration parameters.
00834      */
00835     /*@-mods@*/
00836     if ((dbi = db3New(rpmdb, rpmtag)) == NULL)
00837         /*@-nullstate@*/
00838         return 1;
00839         /*@=nullstate@*/
00840     /*@=mods@*/
00841     dbi->dbi_api = DB_VERSION_MAJOR;
00842 
00843     /*
00844      * Get the prefix/root component and directory path.
00845      */
00846     root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
00847     if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
00848         root = NULL;
00849     home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
00850 
00851     /*
00852      * Either the root or directory components may be a URL. Concatenate,
00853      * convert the URL to a path, and add the name of the file.
00854      */
00855     /*@-mods@*/
00856     urlfn = rpmGenPath(root, home, NULL);
00857     /*@=mods@*/
00858     (void) urlPath(urlfn, &dbhome);
00859     if (dbi->dbi_temporary) {
00860         dbfile = NULL;
00861         dbsubfile = NULL;
00862     } else {
00863 #ifdef  HACK    /* XXX necessary to support dbsubfile */
00864         dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
00865         dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : tagName(dbi->dbi_rpmtag));
00866 #else
00867         dbfile = (dbi->dbi_file ? dbi->dbi_file : tagName(dbi->dbi_rpmtag));
00868         dbsubfile = NULL;
00869 #endif
00870     }
00871 
00872     oflags = (dbi->dbi_oeflags | dbi->dbi_oflags);
00873     oflags &= ~DB_TRUNCATE;     /* XXX this is dangerous */
00874 
00875 #if 0   /* XXX rpmdb: illegal flag combination specified to DB->open */
00876     if ( dbi->dbi_mode & O_EXCL) oflags |= DB_EXCL;
00877 #endif
00878 
00879     /*
00880      * Map open mode flags onto configured database/environment flags.
00881      */
00882     if (dbi->dbi_temporary) {
00883         oflags |= DB_CREATE;
00884         dbi->dbi_oeflags |= DB_CREATE;
00885         oflags &= ~DB_RDONLY;
00886         dbi->dbi_oflags &= ~DB_RDONLY;
00887     } else {
00888         if (!(dbi->dbi_mode & (O_RDWR|O_WRONLY))) oflags |= DB_RDONLY;
00889         if (dbi->dbi_mode & O_CREAT) {
00890             oflags |= DB_CREATE;
00891             dbi->dbi_oeflags |= DB_CREATE;
00892         }
00893 #ifdef  DANGEROUS
00894         if ( dbi->dbi_mode & O_TRUNC) oflags |= DB_TRUNCATE;
00895 #endif
00896     }
00897 
00898     /*
00899      * Avoid incompatible DB_CREATE/DB_RDONLY flags on DBENV->open.
00900      */
00901     if (dbi->dbi_use_dbenv) {
00902         if (access(dbhome, W_OK) == -1) {
00903 
00904             /* dbhome is unwritable, don't attempt DB_CREATE on DB->open ... */
00905             oflags &= ~DB_CREATE;
00906 
00907             /* ... but DBENV->open might still need DB_CREATE ... */
00908             if (dbi->dbi_eflags & DB_PRIVATE) {
00909                 dbi->dbi_eflags &= ~DB_JOINENV;
00910             } else {
00911                 dbi->dbi_eflags |= DB_JOINENV;
00912                 dbi->dbi_oeflags &= ~DB_CREATE;
00913                 dbi->dbi_oeflags &= ~DB_THREAD;
00914                 /* ... but, unless DB_PRIVATE is used, skip DBENV. */
00915                 dbi->dbi_use_dbenv = 0;
00916             }
00917 
00918             /* ... DB_RDONLY maps dbhome perms across files ...  */
00919             if (dbi->dbi_temporary) {
00920                 oflags |= DB_CREATE;
00921                 dbi->dbi_oeflags |= DB_CREATE;
00922                 oflags &= ~DB_RDONLY;
00923                 dbi->dbi_oflags &= ~DB_RDONLY;
00924             } else {
00925                 oflags |= DB_RDONLY;
00926                 /* ... and DB_WRITECURSOR won't be needed ...  */
00927                 dbi->dbi_oflags |= DB_RDONLY;
00928             }
00929 
00930         } else {        /* dbhome is writable, check for persistent dbenv. */
00931             /*@-mods@*/
00932             const char * dbf = rpmGetPath(dbhome, "/__db.001", NULL);
00933             /*@=mods@*/
00934 
00935             if (access(dbf, F_OK) == -1) {
00936                 /* ... non-existent (or unwritable) DBENV, will create ... */
00937                 dbi->dbi_oeflags |= DB_CREATE;
00938                 dbi->dbi_eflags &= ~DB_JOINENV;
00939             } else {
00940                 /* ... pre-existent (or bogus) DBENV, will join ... */
00941                 if (dbi->dbi_eflags & DB_PRIVATE) {
00942                     dbi->dbi_eflags &= ~DB_JOINENV;
00943                 } else {
00944                     dbi->dbi_eflags |= DB_JOINENV;
00945                     dbi->dbi_oeflags &= ~DB_CREATE;
00946                     dbi->dbi_oeflags &= ~DB_THREAD;
00947                 }
00948             }
00949             dbf = _free(dbf);
00950         }
00951     }
00952 
00953     /*
00954      * Avoid incompatible DB_CREATE/DB_RDONLY flags on DB->open.
00955      */
00956     if ((oflags & DB_CREATE) && (oflags & DB_RDONLY)) {
00957         /* dbhome is writable, and DB->open flags may conflict. */
00958         const char * dbfn = (dbfile ? dbfile : tagName(dbi->dbi_rpmtag));
00959         /*@-mods@*/
00960         const char * dbf = rpmGetPath(dbhome, "/", dbfn, NULL);
00961         /*@=mods@*/
00962 
00963         if (access(dbf, F_OK) == -1) {
00964             /* File does not exist, DB->open might create ... */
00965             oflags &= ~DB_RDONLY;
00966         } else {
00967             /* File exists, DB->open need not create ... */
00968             oflags &= ~DB_CREATE;
00969         }
00970 
00971         /* Only writers need DB_WRITECURSOR ... */
00972         if (!(oflags & DB_RDONLY) && access(dbf, W_OK) == 0) {
00973             dbi->dbi_oflags &= ~DB_RDONLY;
00974         } else {
00975             dbi->dbi_oflags |= DB_RDONLY;
00976         }
00977         dbf = _free(dbf);
00978     }
00979 
00980     /*
00981      * Turn off verify-on-close if opening read-only.
00982      */
00983     if (oflags & DB_RDONLY)
00984         dbi->dbi_verify_on_close = 0;
00985 
00986     if (dbi->dbi_use_dbenv) {
00987         /*@-mods@*/
00988         if (rpmdb->db_dbenv == NULL) {
00989             rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
00990             if (rc == 0) {
00991                 rpmdb->db_dbenv = dbenv;
00992                 rpmdb->db_opens = 1;
00993             }
00994         } else {
00995             dbenv = rpmdb->db_dbenv;
00996             rpmdb->db_opens++;
00997         }
00998         /*@=mods@*/
00999     }
01000 
01001     rpmMessage(RPMMESS_DEBUG, _("opening  db index       %s/%s %s mode=0x%x\n"),
01002                 dbhome, (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)),
01003                 prDbiOpenFlags(oflags, 0), dbi->dbi_mode);
01004 
01005     if (rc == 0) {
01006         static int _lockdbfd = 0;
01007 
01008         /*@-moduncon@*/ /* FIX: annotate db3 methods */
01009         rc = db_create(&db, dbenv, dbi->dbi_cflags);
01010         /*@=moduncon@*/
01011         rc = cvtdberr(dbi, "db_create", rc, _debug);
01012         if (rc == 0 && db != NULL) {
01013             if (rc == 0 && dbi->dbi_lorder) {
01014                 rc = db->set_lorder(db, dbi->dbi_lorder);
01015                 rc = cvtdberr(dbi, "db->set_lorder", rc, _debug);
01016             }
01017             if (rc == 0 && dbi->dbi_cachesize) {
01018                 rc = db->set_cachesize(db, 0, dbi->dbi_cachesize, 0);
01019                 rc = cvtdberr(dbi, "db->set_cachesize", rc, _debug);
01020             }
01021             if (rc == 0 && dbi->dbi_pagesize) {
01022                 rc = db->set_pagesize(db, dbi->dbi_pagesize);
01023                 rc = cvtdberr(dbi, "db->set_pagesize", rc, _debug);
01024             }
01025 /* XXX 3.3.4 change. */
01026 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
01027             if (rc == 0 &&
01028                         rpmdb->db_malloc && rpmdb->db_realloc && rpmdb->db_free)
01029             {
01030                 rc = db->set_alloc(db,
01031                         rpmdb->db_malloc, rpmdb->db_realloc, rpmdb->db_free);
01032                 rc = cvtdberr(dbi, "db->set_alloc", rc, _debug);
01033             }
01034 #else
01035             if (rc == 0 && rpmdb->db_malloc) {
01036                 rc = db->set_malloc(db, rpmdb->db_malloc);
01037                 rc = cvtdberr(dbi, "db->set_malloc", rc, _debug);
01038             }
01039 #endif
01040             if (rc == 0 && oflags & DB_CREATE) {
01041                 switch(dbi->dbi_type) {
01042                 default:
01043                 case DB_HASH:
01044                     if (dbi->dbi_h_ffactor) {
01045                         rc = db->set_h_ffactor(db, dbi->dbi_h_ffactor);
01046                         rc = cvtdberr(dbi, "db->set_h_ffactor", rc, _debug);
01047                         if (rc) break;
01048                     }
01049                     if (dbi->dbi_h_nelem) {
01050                         rc = db->set_h_nelem(db, dbi->dbi_h_nelem);
01051                         rc = cvtdberr(dbi, "db->set_h_nelem", rc, _debug);
01052                         if (rc) break;
01053                     }
01054                     if (dbi->dbi_h_flags) {
01055                         rc = db->set_flags(db, dbi->dbi_h_flags);
01056                         rc = cvtdberr(dbi, "db->set_h_flags", rc, _debug);
01057                         if (rc) break;
01058                     }
01059 /* XXX db-3.2.9 has added a DB arg to the call. */
01060 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 2) || (DB_VERSION_MAJOR == 4)
01061                     if (dbi->dbi_h_hash_fcn) {
01062                         rc = db->set_h_hash(db, dbi->dbi_h_hash_fcn);
01063                         rc = cvtdberr(dbi, "db->set_h_hash", rc, _debug);
01064                         if (rc) break;
01065                     }
01066                     if (dbi->dbi_h_dup_compare_fcn) {
01067                         rc = db->set_dup_compare(db, dbi->dbi_h_dup_compare_fcn);
01068                         rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug);
01069                         if (rc) break;
01070                     }
01071 #endif
01072                     break;
01073                 case DB_BTREE:
01074                     if (dbi->dbi_bt_flags) {
01075                         rc = db->set_flags(db, dbi->dbi_bt_flags);
01076                         rc = cvtdberr(dbi, "db->set_bt_flags", rc, _debug);
01077                         if (rc) break;
01078                     }
01079                     if (dbi->dbi_bt_minkey) {
01080                         rc = db->set_bt_minkey(db, dbi->dbi_bt_minkey);
01081                         rc = cvtdberr(dbi, "db->set_bt_minkey", rc, _debug);
01082                         if (rc) break;
01083                     }
01084 /* XXX db-3.2.9 has added a DB arg to the call. */
01085 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 2) || (DB_VERSION_MAJOR == 4)
01086                     if (dbi->dbi_bt_compare_fcn) {
01087                         rc = db->set_bt_compare(db, dbi->dbi_bt_compare_fcn);
01088                         rc = cvtdberr(dbi, "db->set_bt_compare", rc, _debug);
01089                         if (rc) break;
01090                     }
01091                     if (dbi->dbi_bt_dup_compare_fcn) {
01092                         rc = db->set_dup_compare(db, dbi->dbi_bt_dup_compare_fcn);
01093                         rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug);
01094                         if (rc) break;
01095                     }
01096                     if (dbi->dbi_bt_prefix_fcn) {
01097                         rc = db->set_bt_prefix(db, dbi->dbi_bt_prefix_fcn);
01098                         rc = cvtdberr(dbi, "db->set_bt_prefix", rc, _debug);
01099                         if (rc) break;
01100                     }
01101 #endif
01102                     break;
01103                 case DB_RECNO:
01104                     if (dbi->dbi_re_delim) {
01105                         rc = db->set_re_delim(db, dbi->dbi_re_delim);
01106                         rc = cvtdberr(dbi, "db->set_re_selim", rc, _debug);
01107                         if (rc) break;
01108                     }
01109                     if (dbi->dbi_re_len) {
01110                         rc = db->set_re_len(db, dbi->dbi_re_len);
01111                         rc = cvtdberr(dbi, "db->set_re_len", rc, _debug);
01112                         if (rc) break;
01113                     }
01114                     if (dbi->dbi_re_pad) {
01115                         rc = db->set_re_pad(db, dbi->dbi_re_pad);
01116                         rc = cvtdberr(dbi, "db->set_re_pad", rc, _debug);
01117                         if (rc) break;
01118                     }
01119                     if (dbi->dbi_re_source) {
01120                         rc = db->set_re_source(db, dbi->dbi_re_source);
01121                         rc = cvtdberr(dbi, "db->set_re_source", rc, _debug);
01122                         if (rc) break;
01123                     }
01124                     break;
01125                 case DB_QUEUE:
01126                     if (dbi->dbi_q_extentsize) {
01127                         rc = db->set_q_extentsize(db, dbi->dbi_q_extentsize);
01128                         rc = cvtdberr(dbi, "db->set_q_extentsize", rc, _debug);
01129                         if (rc) break;
01130                     }
01131                     break;
01132                 }
01133             }
01134 
01135             if (rc == 0) {
01136                 const char * dbfullpath;
01137                 const char * dbpath;
01138                 char * t;
01139                 int nb;
01140 
01141                 nb = strlen(dbhome);
01142                 if (dbfile)     nb += 1 + strlen(dbfile);
01143                 dbfullpath = t = alloca(nb + 1);
01144 
01145                 t = stpcpy(t, dbhome);
01146                 if (dbfile)
01147                     t = stpcpy( stpcpy( t, "/"), dbfile);
01148 #ifdef  HACK    /* XXX necessary to support dbsubfile */
01149                 dbpath = (!dbi->dbi_use_dbenv && !dbi->dbi_temporary)
01150                         ? dbfullpath : dbfile;
01151 #else
01152                 dbpath = (!dbi->dbi_temporary)
01153                         ? dbfullpath : dbfile;
01154 #endif
01155 
01156                 rc = db->open(db, dbpath, dbsubfile,
01157                     dbi->dbi_type, oflags, dbi->dbi_perms);
01158 
01159                 if (rc == 0 && dbi->dbi_type == DB_UNKNOWN) {
01160 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH == 11) \
01161  || (DB_VERSION_MAJOR == 4)
01162                     DBTYPE dbi_type = DB_UNKNOWN;
01163                     xx = db->get_type(db, &dbi_type);
01164                     if (xx == 0)
01165                         dbi->dbi_type = dbi_type;
01166 #else
01167                     dbi->dbi_type = db->get_type(db);
01168 #endif
01169                 }
01170             }
01171 
01172             /* XXX return rc == errno without printing */
01173             _printit = (rc > 0 ? 0 : _debug);
01174             xx = cvtdberr(dbi, "db->open", rc, _printit);
01175 
01176             if (rc == 0 && dbi->dbi_use_dbenv
01177             && (dbi->dbi_eflags & DB_INIT_CDB) && dbi->dbi_get_rmw_cursor)
01178             {
01179                 DBC * dbcursor = NULL;
01180                 xx = db->cursor(db, txnid, &dbcursor,
01181                         ((oflags & DB_RDONLY) ? 0 : DB_WRITECURSOR));
01182                 xx = cvtdberr(dbi, "db->cursor", xx, _debug);
01183                 dbi->dbi_rmw = dbcursor;
01184             } else
01185                 dbi->dbi_rmw = NULL;
01186 
01187             /*
01188              * Lock a file using fcntl(2). Traditionally this is Packages,
01189              * the file used * to store metadata of installed header(s),
01190              * as Packages is always opened, and should be opened first,
01191              * for any rpmdb access.
01192              *
01193              * If no DBENV is used, then access is protected with a
01194              * shared/exclusive locking scheme, as always.
01195              *
01196              * With a DBENV, the fcntl(2) lock is necessary only to keep
01197              * the riff-raff from playing where they don't belong, as
01198              * the DBENV should provide it's own locking scheme. So try to
01199              * acquire a lock, but permit failures, as some other
01200              * DBENV player may already have acquired the lock.
01201              */
01202             if (rc == 0 && dbi->dbi_lockdbfd &&
01203                 (!dbi->dbi_use_dbenv || _lockdbfd++ == 0))
01204             {
01205                 int fdno = -1;
01206 
01207                 if (!(db->fd(db, &fdno) == 0 && fdno >= 0)) {
01208                     rc = 1;
01209                 } else {
01210                     struct flock l;
01211                     memset(&l, 0, sizeof(l));
01212                     l.l_whence = 0;
01213                     l.l_start = 0;
01214                     l.l_len = 0;
01215                     l.l_type = (dbi->dbi_mode & (O_RDWR|O_WRONLY))
01216                                 ? F_WRLCK : F_RDLCK;
01217                     l.l_pid = 0;
01218 
01219                     rc = fcntl(fdno, F_SETLK, (void *) &l);
01220                     if (rc) {
01221                         /* Warning only if using CDB locking. */
01222                         rc = ((dbi->dbi_use_dbenv &&
01223                                 (dbi->dbi_eflags & DB_INIT_CDB))
01224                             ? 0 : 1);
01225                         rpmError( (rc ? RPMERR_FLOCK : RPMWARN_FLOCK),
01226                                 _("cannot get %s lock on %s/%s\n"),
01227                                 ((dbi->dbi_mode & (O_RDWR|O_WRONLY))
01228                                         ? _("exclusive") : _("shared")),
01229                                 dbhome, (dbfile ? dbfile : ""));
01230                     } else if (dbfile) {
01231                         rpmMessage(RPMMESS_DEBUG,
01232                                 _("locked   db index       %s/%s\n"),
01233                                 dbhome, dbfile);
01234                     }
01235                 }
01236             }
01237         }
01238     }
01239 
01240     dbi->dbi_db = db;
01241 
01242     if (rc == 0 && dbi->dbi_db != NULL && dbip != NULL) {
01243         dbi->dbi_vec = &db3vec;
01244         *dbip = dbi;
01245     } else {
01246         dbi->dbi_verify_on_close = 0;
01247         (void) db3close(dbi, 0);
01248     }
01249 
01250     urlfn = _free(urlfn);
01251 
01252     /*@-nullstate -compmempass@*/
01253     return rc;
01254     /*@=nullstate =compmempass@*/
01255 }
01256 
01259 /*@-exportheadervar@*/
01260 /*@observer@*/ /*@unchecked@*/
01261 struct _dbiVec db3vec = {
01262     DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
01263     db3open, db3close, db3sync, db3copen, db3cclose, db3cdel, db3cget, db3cput,
01264     db3ccount, db3byteswapped, db3stat
01265 };
01266 /*@=exportheadervar@*/
01267 /*@=type@*/

Generated on Thu Jan 3 08:05:31 2008 for rpm by  doxygen 1.5.2