#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: db_open.c,v 1.2 2004/03/30 01:21:24 jtownsen Exp $";
#endif
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#endif
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_shash.h"
#include "dbinc/db_swap.h"
#include "dbinc/btree.h"
#include "dbinc/crypto.h"
#include "dbinc/hmac.h"
#include "dbinc/fop.h"
#include "dbinc/hash.h"
#include "dbinc/lock.h"
#include "dbinc/log.h"
#include "dbinc/mp.h"
#include "dbinc/qam.h"
#include "dbinc/txn.h"
int
__db_open(dbp, txn, fname, dname, type, flags, mode, meta_pgno)
DB *dbp;
DB_TXN *txn;
const char *fname, *dname;
DBTYPE type;
u_int32_t flags;
int mode;
db_pgno_t meta_pgno;
{
DB_ENV *dbenv;
int ret;
u_int32_t id;
dbenv = dbp->dbenv;
id = TXN_INVALID;
DB_TEST_RECOVERY(dbp, DB_TEST_PREOPEN, ret, fname);
if (F_ISSET(dbenv, DB_ENV_THREAD))
LF_SET(DB_THREAD);
if (LF_ISSET(DB_RDONLY))
F_SET(dbp, DB_AM_RDONLY);
if (LF_ISSET(DB_DIRTY_READ))
F_SET(dbp, DB_AM_DIRTY);
if (txn != NULL)
F_SET(dbp, DB_AM_TXN);
dbp->type = type;
if (fname == NULL) {
F_SET(dbp, DB_AM_INMEM);
if (dbp->type == DB_UNKNOWN) {
__db_err(dbenv,
"DBTYPE of unknown without existing file");
return (EINVAL);
}
if (dbp->pgsize == 0)
dbp->pgsize = DB_DEF_IOSIZE;
if (LOCKING_ON(dbenv) &&
(ret = __lock_id(dbenv, (u_int32_t *)dbp->fileid)) != 0)
return (ret);
} else if (dname == NULL && meta_pgno == PGNO_BASE_MD) {
if ((ret =
__fop_file_setup(dbp, txn, fname, mode, flags, &id)) != 0)
return (ret);
} else {
if ((ret = __fop_subdb_setup(dbp,
txn, fname, dname, mode, flags)) != 0)
return (ret);
meta_pgno = dbp->meta_pgno;
}
if (dname == NULL && F_ISSET(dbp, DB_AM_CREATED))
LF_SET(DB_TRUNCATE);
if ((ret = __db_dbenv_setup(dbp, txn, fname, id, flags)) != 0)
return (ret);
F_SET(dbp, DB_AM_OPEN_CALLED);
if (fname == NULL && (ret = __db_new_file(dbp, txn, NULL, NULL)) != 0)
return (ret);
switch (dbp->type) {
case DB_BTREE:
ret = __bam_open(dbp, txn, fname, meta_pgno, flags);
break;
case DB_HASH:
ret = __ham_open(dbp, txn, fname, meta_pgno, flags);
break;
case DB_RECNO:
ret = __ram_open(dbp, txn, fname, meta_pgno, flags);
break;
case DB_QUEUE:
ret = __qam_open(dbp, txn, fname, meta_pgno, mode, flags);
break;
case DB_UNKNOWN:
return (__db_unknown_type(dbenv, "__db_dbopen", dbp->type));
}
if (ret != 0)
goto err;
DB_TEST_RECOVERY(dbp, DB_TEST_POSTOPEN, ret, fname);
if (!F_ISSET(dbp, DB_AM_RECOVER) &&
fname != NULL && LOCK_ISSET(dbp->handle_lock)) {
if (txn != NULL) {
ret = __txn_lockevent(dbenv,
txn, dbp, &dbp->handle_lock, dbp->lid);
} else if (LOCKING_ON(dbenv))
ret = __lock_downgrade(dbenv,
&dbp->handle_lock, DB_LOCK_READ, 0);
}
DB_TEST_RECOVERY_LABEL
err:
return (ret);
}
int
__db_get_open_flags(dbp, flagsp)
DB *dbp;
u_int32_t *flagsp;
{
DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get_open_flags");
*flagsp = dbp->open_flags;
return (0);
}
int
__db_new_file(dbp, txn, fhp, name)
DB *dbp;
DB_TXN *txn;
DB_FH *fhp;
const char *name;
{
int ret;
switch (dbp->type) {
case DB_BTREE:
case DB_RECNO:
ret = __bam_new_file(dbp, txn, fhp, name);
break;
case DB_HASH:
ret = __ham_new_file(dbp, txn, fhp, name);
break;
case DB_QUEUE:
ret = __qam_new_file(dbp, txn, fhp, name);
break;
case DB_UNKNOWN:
default:
__db_err(dbp->dbenv,
"%s: Invalid type %d specified", name, dbp->type);
ret = EINVAL;
break;
}
DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOGMETA, ret, name);
if (ret == 0 && fhp != NULL)
ret = __os_fsync(dbp->dbenv, fhp);
DB_TEST_RECOVERY(dbp, DB_TEST_POSTSYNC, ret, name);
DB_TEST_RECOVERY_LABEL
return (ret);
}
int
__db_init_subdb(mdbp, dbp, name, txn)
DB *mdbp, *dbp;
const char *name;
DB_TXN *txn;
{
DBMETA *meta;
DB_MPOOLFILE *mpf;
int ret, t_ret;
ret = 0;
if (!F_ISSET(dbp, DB_AM_CREATED)) {
mpf = mdbp->mpf;
if ((ret = __memp_fget(mpf, &dbp->meta_pgno, 0, &meta)) != 0)
goto err;
ret = __db_meta_setup(mdbp->dbenv, dbp, name, meta, 0, 0);
if ((t_ret = __memp_fput(mpf, meta, 0)) != 0 && ret == 0)
ret = t_ret;
if (ret == ENOENT)
ret = 0;
goto err;
}
switch (dbp->type) {
case DB_BTREE:
case DB_RECNO:
ret = __bam_new_subdb(mdbp, dbp, txn);
break;
case DB_HASH:
ret = __ham_new_subdb(mdbp, dbp, txn);
break;
case DB_QUEUE:
ret = EINVAL;
break;
case DB_UNKNOWN:
default:
__db_err(dbp->dbenv,
"Invalid subdatabase type %d specified", dbp->type);
return (EINVAL);
}
err: return (ret);
}
int
__db_chk_meta(dbenv, dbp, meta, do_metachk)
DB_ENV *dbenv;
DB *dbp;
DBMETA *meta;
int do_metachk;
{
int is_hmac, ret, swapped;
u_int8_t *chksum;
u_int32_t orig_chk;
ret = 0;
if (FLD_ISSET(meta->metaflags, DBMETA_CHKSUM)) {
if (dbp != NULL)
F_SET(dbp, DB_AM_CHKSUM);
is_hmac = meta->encrypt_alg == 0 ? 0 : 1;
chksum = ((BTMETA *)meta)->chksum;
if (do_metachk) {
if (is_hmac == 0)
orig_chk = *(u_int32_t *)chksum;
swapped = 0;
chk_retry:
if ((ret = __db_check_chksum(dbenv,
(DB_CIPHER *)dbenv->crypto_handle, chksum, meta,
DBMETASIZE, is_hmac)) != 0) {
if (is_hmac || swapped)
return (ret);
M_32_SWAP(orig_chk);
swapped = 1;
*(u_int32_t *)chksum = orig_chk;
goto chk_retry;
}
}
} else if (dbp != NULL)
F_CLR(dbp, DB_AM_CHKSUM);
#ifdef HAVE_CRYPTO
ret = __crypto_decrypt_meta(dbenv, dbp, (u_int8_t *)meta, do_metachk);
#endif
return (ret);
}
int
__db_meta_setup(dbenv, dbp, name, meta, oflags, do_metachk)
DB_ENV *dbenv;
DB *dbp;
const char *name;
DBMETA *meta;
u_int32_t oflags;
int do_metachk;
{
u_int32_t flags, magic;
int ret;
ret = 0;
F_CLR(dbp, DB_AM_SWAP);
magic = meta->magic;
swap_retry:
switch (magic) {
case DB_BTREEMAGIC:
case DB_HASHMAGIC:
case DB_QAMMAGIC:
case DB_RENAMEMAGIC:
break;
case 0:
if (F_ISSET(dbp, DB_AM_SUBDB) && ((IS_RECOVERING(dbenv) &&
F_ISSET((DB_LOG *) dbenv->lg_handle, DBLOG_FORCE_OPEN)) ||
meta->pgno != PGNO_INVALID))
return (ENOENT);
goto bad_format;
default:
if (F_ISSET(dbp, DB_AM_SWAP))
goto bad_format;
M_32_SWAP(magic);
F_SET(dbp, DB_AM_SWAP);
goto swap_retry;
}
if ((ret = __db_chk_meta(dbenv, dbp, meta, do_metachk)) != 0) {
if (ret == -1)
__db_err(dbenv,
"%s: metadata page checksum error", name);
goto bad_format;
}
switch (magic) {
case DB_BTREEMAGIC:
if (dbp->type != DB_UNKNOWN &&
dbp->type != DB_RECNO && dbp->type != DB_BTREE)
goto bad_format;
flags = meta->flags;
if (F_ISSET(dbp, DB_AM_SWAP))
M_32_SWAP(flags);
if (LF_ISSET(BTM_RECNO))
dbp->type = DB_RECNO;
else
dbp->type = DB_BTREE;
if ((oflags & DB_TRUNCATE) == 0 && (ret =
__bam_metachk(dbp, name, (BTMETA *)meta)) != 0)
return (ret);
break;
case DB_HASHMAGIC:
if (dbp->type != DB_UNKNOWN && dbp->type != DB_HASH)
goto bad_format;
dbp->type = DB_HASH;
if ((oflags & DB_TRUNCATE) == 0 && (ret =
__ham_metachk(dbp, name, (HMETA *)meta)) != 0)
return (ret);
break;
case DB_QAMMAGIC:
if (dbp->type != DB_UNKNOWN && dbp->type != DB_QUEUE)
goto bad_format;
dbp->type = DB_QUEUE;
if ((oflags & DB_TRUNCATE) == 0 && (ret =
__qam_metachk(dbp, name, (QMETA *)meta)) != 0)
return (ret);
break;
case DB_RENAMEMAGIC:
F_SET(dbp, DB_AM_IN_RENAME);
memcpy(dbp->fileid, ((DBMETA *)meta)->uid, DB_FILE_ID_LEN);
break;
default:
goto bad_format;
}
return (0);
bad_format:
__db_err(dbenv, "%s: unexpected file type or format", name);
return (ret == 0 ? EINVAL : ret);
}