00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "db_config.h"
00011
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #endif
00018
00019 #include "db_int.h"
00020 #include "dbinc/db_page.h"
00021 #include "dbinc/db_shash.h"
00022 #include "dbinc/db_swap.h"
00023 #include "dbinc/btree.h"
00024 #include "dbinc/crypto.h"
00025 #include "dbinc/hmac.h"
00026 #include "dbinc/fop.h"
00027 #include "dbinc/hash.h"
00028 #include "dbinc/lock.h"
00029 #include "dbinc/log.h"
00030 #include "dbinc/mp.h"
00031 #include "dbinc/qam.h"
00032 #include "dbinc/txn.h"
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 int
00059 __db_open(dbp, txn, fname, dname, type, flags, mode, meta_pgno)
00060 DB *dbp;
00061 DB_TXN *txn;
00062 const char *fname, *dname;
00063 DBTYPE type;
00064 u_int32_t flags;
00065 int mode;
00066 db_pgno_t meta_pgno;
00067 {
00068 DB_ENV *dbenv;
00069 int ret;
00070 u_int32_t id;
00071
00072 dbenv = dbp->dbenv;
00073 id = TXN_INVALID;
00074
00075 DB_TEST_RECOVERY(dbp, DB_TEST_PREOPEN, ret, fname);
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 if (F_ISSET(dbenv, DB_ENV_THREAD))
00086 LF_SET(DB_THREAD);
00087
00088
00089 if (LF_ISSET(DB_RDONLY))
00090 F_SET(dbp, DB_AM_RDONLY);
00091 if (LF_ISSET(DB_READ_UNCOMMITTED))
00092 F_SET(dbp, DB_AM_READ_UNCOMMITTED);
00093
00094 if (txn != NULL)
00095 F_SET(dbp, DB_AM_TXN);
00096
00097
00098 dbp->type = type;
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108 if (fname == NULL) {
00109 if (dname == NULL) {
00110 if (!LF_ISSET(DB_CREATE)) {
00111 __db_err(dbenv,
00112 "DB_CREATE must be specified to create databases.");
00113 return (ENOENT);
00114 }
00115
00116 F_SET(dbp, DB_AM_INMEM);
00117 F_SET(dbp, DB_AM_CREATED);
00118
00119 if (dbp->type == DB_UNKNOWN) {
00120 __db_err(dbenv,
00121 "DBTYPE of unknown without existing file");
00122 return (EINVAL);
00123 }
00124
00125 if (dbp->pgsize == 0)
00126 dbp->pgsize = DB_DEF_IOSIZE;
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148 if (LOCKING_ON(dbenv) && (ret = __lock_id(dbenv,
00149 (u_int32_t *)dbp->fileid, NULL)) != 0)
00150 return (ret);
00151 } else
00152 MAKE_INMEM(dbp);
00153
00154
00155
00156
00157
00158
00159 } else if (dname == NULL && meta_pgno == PGNO_BASE_MD) {
00160
00161 if ((ret =
00162 __fop_file_setup(dbp, txn, fname, mode, flags, &id)) != 0)
00163 return (ret);
00164 } else {
00165 if ((ret = __fop_subdb_setup(dbp,
00166 txn, fname, dname, mode, flags)) != 0)
00167 return (ret);
00168 meta_pgno = dbp->meta_pgno;
00169 }
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 if (dname == NULL && F_ISSET(dbp, DB_AM_CREATED))
00185 LF_SET(DB_TRUNCATE);
00186
00187
00188 if ((ret = __db_dbenv_setup(dbp, txn, fname, dname, id, flags)) != 0)
00189 return (ret);
00190
00191
00192 if (F_ISSET(dbp, DB_AM_INMEM)) {
00193 if (dname == NULL)
00194 ret = __db_new_file(dbp, txn, NULL, NULL);
00195 else {
00196 id = TXN_INVALID;
00197 if ((ret = __fop_file_setup(dbp,
00198 txn, dname, mode, flags, &id)) == 0 &&
00199 DBENV_LOGGING(dbenv) && !F_ISSET(dbp, DB_AM_RECOVER)
00200 #if !defined(DEBUG_ROP)
00201 && !F_ISSET(dbp, DB_AM_RDONLY)
00202 #endif
00203 )
00204 ret = __dbreg_log_id(dbp,
00205 txn, dbp->log_filename->id, 1);
00206 }
00207 if (ret != 0)
00208 goto err;
00209 }
00210
00211 switch (dbp->type) {
00212 case DB_BTREE:
00213 ret = __bam_open(dbp, txn, fname, meta_pgno, flags);
00214 break;
00215 case DB_HASH:
00216 ret = __ham_open(dbp, txn, fname, meta_pgno, flags);
00217 break;
00218 case DB_RECNO:
00219 ret = __ram_open(dbp, txn, fname, meta_pgno, flags);
00220 break;
00221 case DB_QUEUE:
00222 ret = __qam_open(
00223 dbp, txn, fname, meta_pgno, mode, flags);
00224 break;
00225 case DB_UNKNOWN:
00226 return (
00227 __db_unknown_type(dbenv, "__db_dbopen", dbp->type));
00228 }
00229 if (ret != 0)
00230 goto err;
00231
00232 DB_TEST_RECOVERY(dbp, DB_TEST_POSTOPEN, ret, fname);
00233
00234
00235
00236
00237
00238
00239 if (!F_ISSET(dbp, DB_AM_RECOVER) && (fname != NULL || dname != NULL)
00240 && LOCK_ISSET(dbp->handle_lock)) {
00241 if (txn != NULL)
00242 ret = __txn_lockevent(dbenv,
00243 txn, dbp, &dbp->handle_lock, dbp->lid);
00244 else if (LOCKING_ON(dbenv))
00245
00246 ret = __lock_downgrade(dbenv,
00247 &dbp->handle_lock, DB_LOCK_READ, 0);
00248 }
00249 DB_TEST_RECOVERY_LABEL
00250 err:
00251 return (ret);
00252 }
00253
00254
00255
00256
00257
00258
00259
00260 int
00261 __db_get_open_flags(dbp, flagsp)
00262 DB *dbp;
00263 u_int32_t *flagsp;
00264 {
00265 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_open_flags");
00266
00267 *flagsp = dbp->open_flags;
00268 return (0);
00269 }
00270
00271
00272
00273
00274
00275
00276
00277 int
00278 __db_new_file(dbp, txn, fhp, name)
00279 DB *dbp;
00280 DB_TXN *txn;
00281 DB_FH *fhp;
00282 const char *name;
00283 {
00284 int ret;
00285
00286 switch (dbp->type) {
00287 case DB_BTREE:
00288 case DB_RECNO:
00289 ret = __bam_new_file(dbp, txn, fhp, name);
00290 break;
00291 case DB_HASH:
00292 ret = __ham_new_file(dbp, txn, fhp, name);
00293 break;
00294 case DB_QUEUE:
00295 ret = __qam_new_file(dbp, txn, fhp, name);
00296 break;
00297 case DB_UNKNOWN:
00298 default:
00299 __db_err(dbp->dbenv,
00300 "%s: Invalid type %d specified", name, dbp->type);
00301 ret = EINVAL;
00302 break;
00303 }
00304
00305 DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOGMETA, ret, name);
00306
00307 if (ret == 0 && fhp != NULL)
00308 ret = __os_fsync(dbp->dbenv, fhp);
00309
00310 DB_TEST_RECOVERY(dbp, DB_TEST_POSTSYNC, ret, name);
00311
00312 DB_TEST_RECOVERY_LABEL
00313 return (ret);
00314 }
00315
00316
00317
00318
00319
00320
00321
00322 int
00323 __db_init_subdb(mdbp, dbp, name, txn)
00324 DB *mdbp, *dbp;
00325 const char *name;
00326 DB_TXN *txn;
00327 {
00328 DBMETA *meta;
00329 DB_MPOOLFILE *mpf;
00330 int ret, t_ret;
00331
00332 ret = 0;
00333 if (!F_ISSET(dbp, DB_AM_CREATED)) {
00334
00335 mpf = mdbp->mpf;
00336 if ((ret = __memp_fget(mpf, &dbp->meta_pgno, 0, &meta)) != 0)
00337 goto err;
00338 ret = __db_meta_setup(mdbp->dbenv, dbp, name, meta, 0, 0);
00339 if ((t_ret = __memp_fput(mpf, meta, 0)) != 0 && ret == 0)
00340 ret = t_ret;
00341
00342
00343
00344
00345 if (ret == ENOENT)
00346 ret = 0;
00347 goto err;
00348 }
00349
00350
00351 switch (dbp->type) {
00352 case DB_BTREE:
00353 case DB_RECNO:
00354 ret = __bam_new_subdb(mdbp, dbp, txn);
00355 break;
00356 case DB_HASH:
00357 ret = __ham_new_subdb(mdbp, dbp, txn);
00358 break;
00359 case DB_QUEUE:
00360 ret = EINVAL;
00361 break;
00362 case DB_UNKNOWN:
00363 default:
00364 __db_err(dbp->dbenv,
00365 "Invalid subdatabase type %d specified", dbp->type);
00366 return (EINVAL);
00367 }
00368
00369 err: return (ret);
00370 }
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381 int
00382 __db_chk_meta(dbenv, dbp, meta, do_metachk)
00383 DB_ENV *dbenv;
00384 DB *dbp;
00385 DBMETA *meta;
00386 int do_metachk;
00387 {
00388 DB_LSN cur_lsn, swap_lsn;
00389 int is_hmac, ret, swapped;
00390 u_int32_t magic, orig_chk;
00391 u_int8_t *chksum;
00392
00393 ret = 0;
00394 swapped = 0;
00395
00396 if (FLD_ISSET(meta->metaflags, DBMETA_CHKSUM)) {
00397 if (dbp != NULL)
00398 F_SET(dbp, DB_AM_CHKSUM);
00399
00400 is_hmac = meta->encrypt_alg == 0 ? 0 : 1;
00401 chksum = ((BTMETA *)meta)->chksum;
00402
00403
00404
00405
00406
00407
00408 orig_chk = *(u_int32_t *)chksum;
00409
00410
00411
00412
00413
00414 if (do_metachk) {
00415 swapped = 0;
00416 chk_retry: if ((ret = __db_check_chksum(dbenv,
00417 (DB_CIPHER *)dbenv->crypto_handle, chksum, meta,
00418 DBMETASIZE, is_hmac)) != 0) {
00419 if (is_hmac || swapped)
00420 return (ret);
00421
00422 M_32_SWAP(orig_chk);
00423 swapped = 1;
00424 *(u_int32_t *)chksum = orig_chk;
00425 goto chk_retry;
00426 }
00427 }
00428 } else if (dbp != NULL)
00429 F_CLR(dbp, DB_AM_CHKSUM);
00430
00431 #ifdef HAVE_CRYPTO
00432 ret = __crypto_decrypt_meta(dbenv, dbp, (u_int8_t *)meta, do_metachk);
00433 #endif
00434
00435
00436 if (LOGGING_ON(dbenv)) {
00437
00438
00439
00440
00441
00442
00443 swap_lsn = meta->lsn;
00444 magic = meta->magic;
00445 lsn_retry:
00446 if (swapped) {
00447 M_32_SWAP(swap_lsn.file);
00448 M_32_SWAP(swap_lsn.offset);
00449 M_32_SWAP(magic);
00450 }
00451 switch (magic) {
00452 case DB_BTREEMAGIC:
00453 case DB_HASHMAGIC:
00454 case DB_QAMMAGIC:
00455 case DB_RENAMEMAGIC:
00456 break;
00457 default:
00458 if (swapped)
00459 return (EINVAL);
00460 swapped = 1;
00461 goto lsn_retry;
00462 }
00463 if (!IS_REP_CLIENT(dbenv) &&
00464 !IS_NOT_LOGGED_LSN(swap_lsn) && !IS_ZERO_LSN(swap_lsn)) {
00465
00466 if ((ret = __log_current_lsn(dbenv,
00467 &cur_lsn, NULL, NULL)) != 0)
00468 return (ret);
00469 if (log_compare(&swap_lsn, &cur_lsn) > 0) {
00470 __db_err(dbenv,
00471 "file %s (meta pgno = %lu) has LSN [%lu][%lu].",
00472 dbp->fname == NULL
00473 ? "unknown" : dbp->fname,
00474 (u_long)dbp->meta_pgno,
00475 (u_long)swap_lsn.file,
00476 (u_long)swap_lsn.offset);
00477 __db_err(dbenv, "end of log is [%lu][%lu]",
00478 (u_long)cur_lsn.file,
00479 (u_long)cur_lsn.offset);
00480 return (EINVAL);
00481 }
00482 }
00483 }
00484 return (ret);
00485 }
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 int
00497 __db_meta_setup(dbenv, dbp, name, meta, oflags, do_metachk)
00498 DB_ENV *dbenv;
00499 DB *dbp;
00500 const char *name;
00501 DBMETA *meta;
00502 u_int32_t oflags;
00503 int do_metachk;
00504 {
00505 u_int32_t flags, magic;
00506 int ret;
00507
00508 ret = 0;
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518 F_CLR(dbp, DB_AM_SWAP | DB_AM_IN_RENAME);
00519 magic = meta->magic;
00520
00521 swap_retry:
00522 switch (magic) {
00523 case DB_BTREEMAGIC:
00524 case DB_HASHMAGIC:
00525 case DB_QAMMAGIC:
00526 case DB_RENAMEMAGIC:
00527 break;
00528 case 0:
00529
00530
00531
00532
00533
00534
00535 if (F_ISSET(dbp, DB_AM_SUBDB) && ((IS_RECOVERING(dbenv) &&
00536 F_ISSET((DB_LOG *) dbenv->lg_handle, DBLOG_FORCE_OPEN)) ||
00537 meta->pgno != PGNO_INVALID))
00538 return (ENOENT);
00539
00540 goto bad_format;
00541 default:
00542 if (F_ISSET(dbp, DB_AM_SWAP))
00543 goto bad_format;
00544
00545 M_32_SWAP(magic);
00546 F_SET(dbp, DB_AM_SWAP);
00547 goto swap_retry;
00548 }
00549
00550
00551
00552
00553
00554
00555
00556
00557 if ((ret = __db_chk_meta(dbenv, dbp, meta, do_metachk)) != 0) {
00558 if (ret == -1)
00559 __db_err(dbenv,
00560 "%s: metadata page checksum error", name);
00561 goto bad_format;
00562 }
00563
00564 switch (magic) {
00565 case DB_BTREEMAGIC:
00566 if (dbp->type != DB_UNKNOWN &&
00567 dbp->type != DB_RECNO && dbp->type != DB_BTREE)
00568 goto bad_format;
00569
00570 flags = meta->flags;
00571 if (F_ISSET(dbp, DB_AM_SWAP))
00572 M_32_SWAP(flags);
00573 if (LF_ISSET(BTM_RECNO))
00574 dbp->type = DB_RECNO;
00575 else
00576 dbp->type = DB_BTREE;
00577 if ((oflags & DB_TRUNCATE) == 0 && (ret =
00578 __bam_metachk(dbp, name, (BTMETA *)meta)) != 0)
00579 return (ret);
00580 break;
00581 case DB_HASHMAGIC:
00582 if (dbp->type != DB_UNKNOWN && dbp->type != DB_HASH)
00583 goto bad_format;
00584
00585 dbp->type = DB_HASH;
00586 if ((oflags & DB_TRUNCATE) == 0 && (ret =
00587 __ham_metachk(dbp, name, (HMETA *)meta)) != 0)
00588 return (ret);
00589 break;
00590 case DB_QAMMAGIC:
00591 if (dbp->type != DB_UNKNOWN && dbp->type != DB_QUEUE)
00592 goto bad_format;
00593 dbp->type = DB_QUEUE;
00594 if ((oflags & DB_TRUNCATE) == 0 && (ret =
00595 __qam_metachk(dbp, name, (QMETA *)meta)) != 0)
00596 return (ret);
00597 break;
00598 case DB_RENAMEMAGIC:
00599 F_SET(dbp, DB_AM_IN_RENAME);
00600
00601
00602 memcpy(dbp->fileid, ((DBMETA *)meta)->uid, DB_FILE_ID_LEN);
00603
00604 break;
00605 default:
00606 goto bad_format;
00607 }
00608 return (0);
00609
00610 bad_format:
00611 if (F_ISSET(dbp, DB_AM_RECOVER))
00612 ret = ENOENT;
00613 else
00614 __db_err(dbenv, "%s: unexpected file type or format", name);
00615 return (ret == 0 ? EINVAL : ret);
00616 }