#include "db_config.h"
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_swap.h"
#include "dbinc/btree.h"
#include "dbinc/hash.h"
#include "dbinc/qam.h"
int
__db_upgrade_pp(dbp, fname, flags)
DB *dbp;
const char *fname;
u_int32_t flags;
{
#ifdef HAVE_UPGRADE_SUPPORT
DB_THREAD_INFO *ip;
ENV *env;
int ret;
env = dbp->env;
if ((ret = __db_fchk(env, "DB->upgrade", flags, DB_DUPSORT)) != 0)
return (ret);
ENV_ENTER(env, ip);
ret = __db_upgrade(dbp, fname, flags);
ENV_LEAVE(env, ip);
return (ret);
#else
COMPQUIET(dbp, NULL);
COMPQUIET(fname, NULL);
COMPQUIET(flags, 0);
__db_errx(dbp->env, "upgrade not supported");
return (EINVAL);
#endif
}
#ifdef HAVE_UPGRADE_SUPPORT
static int (* const func_31_list[P_PAGETYPE_MAX])
__P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)) = {
NULL,
NULL,
__ham_31_hash,
NULL,
NULL,
__bam_31_lbtree,
NULL,
NULL,
__ham_31_hashmeta,
__bam_31_btreemeta,
NULL,
NULL,
NULL,
NULL,
};
static int (* const func_46_list[P_PAGETYPE_MAX])
__P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *)) = {
NULL,
NULL,
__ham_46_hash,
NULL,
NULL,
NULL,
NULL,
NULL,
__ham_46_hashmeta,
NULL,
NULL,
NULL,
NULL,
NULL,
};
static int __db_page_pass __P((DB *, char *, u_int32_t, int (* const [])
(DB *, char *, u_int32_t, DB_FH *, PAGE *, int *), DB_FH *));
static int __db_set_lastpgno __P((DB *, char *, DB_FH *));
int
__db_upgrade(dbp, fname, flags)
DB *dbp;
const char *fname;
u_int32_t flags;
{
DBMETA *meta;
DB_FH *fhp;
ENV *env;
size_t n;
int ret, t_ret, use_mp_open;
u_int8_t mbuf[256], tmpflags;
char *real_name;
use_mp_open = 0;
env = dbp->env;
fhp = NULL;
if ((ret = __db_appname(env,
DB_APP_DATA, fname, 0, NULL, &real_name)) != 0)
return (ret);
if ((ret = __os_open(env, real_name, 0, 0, 0, &fhp)) != 0) {
__db_err(env, ret, "%s", real_name);
return (ret);
}
if (dbp->db_feedback != NULL)
dbp->db_feedback(dbp, DB_UPGRADE, 0);
if ((ret = __os_read(env, fhp, mbuf, sizeof(mbuf), &n)) != 0)
goto err;
switch (((DBMETA *)mbuf)->magic) {
case DB_BTREEMAGIC:
switch (((DBMETA *)mbuf)->version) {
case 6:
if ((ret =
__bam_30_btreemeta(dbp, real_name, mbuf)) != 0)
goto err;
if ((ret = __os_seek(env, fhp, 0, 0, 0)) != 0)
goto err;
if ((ret = __os_write(env, fhp, mbuf, 256, &n)) != 0)
goto err;
case 7:
memcpy(&dbp->pgsize, mbuf + 20, sizeof(u_int32_t));
if ((ret = __db_page_pass(
dbp, real_name, flags, func_31_list, fhp)) != 0)
goto err;
case 8:
if ((ret =
__db_set_lastpgno(dbp, real_name, fhp)) != 0)
goto err;
case 9:
break;
default:
__db_errx(env, "%s: unsupported btree version: %lu",
real_name, (u_long)((DBMETA *)mbuf)->version);
ret = DB_OLD_VERSION;
goto err;
}
break;
case DB_HASHMAGIC:
switch (((DBMETA *)mbuf)->version) {
case 4:
case 5:
if ((ret =
__ham_30_hashmeta(dbp, real_name, mbuf)) != 0)
goto err;
if ((ret = __os_seek(env, fhp, 0, 0, 0)) != 0)
goto err;
if ((ret = __os_write(env, fhp, mbuf, 256, &n)) != 0)
goto err;
if ((ret =
__ham_30_sizefix(dbp, fhp, real_name, mbuf)) != 0)
goto err;
case 6:
memcpy(&dbp->pgsize, mbuf + 20, sizeof(u_int32_t));
if ((ret = __db_page_pass(
dbp, real_name, flags, func_31_list, fhp)) != 0)
goto err;
case 7:
if ((ret =
__db_set_lastpgno(dbp, real_name, fhp)) != 0)
goto err;
case 8:
meta = (DBMETA*)mbuf;
memcpy(&dbp->pgsize, &meta->pagesize,
sizeof(u_int32_t));
memcpy(&tmpflags, &meta->metaflags, sizeof(u_int8_t));
if (FLD_ISSET(tmpflags, DBMETA_CHKSUM))
F_SET(dbp, DB_AM_CHKSUM);
memcpy(&tmpflags, &meta->encrypt_alg, sizeof(u_int8_t));
if (tmpflags != 0) {
if (!CRYPTO_ON(dbp->env)) {
__db_errx(env,
"Attempt to upgrade an encrypted database without providing a password.");
ret = EINVAL;
goto err;
}
F_SET(dbp, DB_AM_ENCRYPT);
}
use_mp_open = 1;
if ((ret = __os_closehandle(env, fhp)) != 0)
return (ret);
dbp->type = DB_HASH;
if ((ret = __env_mpool(dbp, fname,
DB_AM_NOT_DURABLE | DB_AM_VERIFYING)) != 0)
return (ret);
fhp = dbp->mpf->fhp;
if ((ret = __db_page_pass(
dbp, real_name, flags, func_46_list, fhp)) != 0)
goto err;
case 9:
break;
default:
__db_errx(env, "%s: unsupported hash version: %lu",
real_name, (u_long)((DBMETA *)mbuf)->version);
ret = DB_OLD_VERSION;
goto err;
}
break;
case DB_QAMMAGIC:
switch (((DBMETA *)mbuf)->version) {
case 1:
if ((ret = __qam_31_qammeta(dbp, real_name, mbuf)) != 0)
return (ret);
case 2:
if ((ret = __qam_32_qammeta(dbp, real_name, mbuf)) != 0)
return (ret);
if ((ret = __os_seek(env, fhp, 0, 0, 0)) != 0)
goto err;
if ((ret = __os_write(env, fhp, mbuf, 256, &n)) != 0)
goto err;
case 3:
case 4:
break;
default:
__db_errx(env, "%s: unsupported queue version: %lu",
real_name, (u_long)((DBMETA *)mbuf)->version);
ret = DB_OLD_VERSION;
goto err;
}
break;
default:
M_32_SWAP(((DBMETA *)mbuf)->magic);
switch (((DBMETA *)mbuf)->magic) {
case DB_BTREEMAGIC:
case DB_HASHMAGIC:
case DB_QAMMAGIC:
__db_errx(env,
"%s: DB->upgrade only supported on native byte-order systems",
real_name);
break;
default:
__db_errx(env,
"%s: unrecognized file type", real_name);
break;
}
ret = EINVAL;
goto err;
}
ret = __os_fsync(env, fhp);
err: if (use_mp_open == 0 && fhp != NULL &&
(t_ret = __os_closehandle(env, fhp)) != 0 && ret == 0)
ret = t_ret;
__os_free(env, real_name);
if (dbp->db_feedback != NULL)
dbp->db_feedback(dbp, DB_UPGRADE, 100);
return (ret);
}
static int
__db_page_pass(dbp, real_name, flags, fl, fhp)
DB *dbp;
char *real_name;
u_int32_t flags;
int (* const fl[P_PAGETYPE_MAX])
__P((DB *, char *, u_int32_t, DB_FH *, PAGE *, int *));
DB_FH *fhp;
{
ENV *env;
PAGE *page;
db_pgno_t i, pgno_last;
size_t n;
int dirty, ret;
env = dbp->env;
if ((ret = __db_lastpgno(dbp, real_name, fhp, &pgno_last)) != 0)
return (ret);
if ((ret = __os_malloc(env, dbp->pgsize, &page)) != 0)
return (ret);
for (i = 0; i < pgno_last; ++i) {
if (dbp->db_feedback != NULL)
dbp->db_feedback(
dbp, DB_UPGRADE, (int)((i * 100)/pgno_last));
if ((ret = __os_seek(env, fhp, i, dbp->pgsize, 0)) != 0)
break;
if ((ret = __os_read(env, fhp, page, dbp->pgsize, &n)) != 0)
break;
dirty = 0;
if ((ret = __db_decrypt_pg(env, dbp, page)) != 0)
break;
if (fl[TYPE(page)] != NULL && (ret = fl[TYPE(page)]
(dbp, real_name, flags, fhp, page, &dirty)) != 0)
break;
if (dirty) {
if ((ret = __db_encrypt_and_checksum_pg(
env, dbp, page)) != 0)
break;
if ((ret =
__os_seek(env, fhp, i, dbp->pgsize, 0)) != 0)
break;
if ((ret = __os_write(env,
fhp, page, dbp->pgsize, &n)) != 0)
break;
}
}
__os_free(dbp->env, page);
return (ret);
}
int
__db_lastpgno(dbp, real_name, fhp, pgno_lastp)
DB *dbp;
char *real_name;
DB_FH *fhp;
db_pgno_t *pgno_lastp;
{
ENV *env;
db_pgno_t pgno_last;
u_int32_t mbytes, bytes;
int ret;
env = dbp->env;
if ((ret = __os_ioinfo(env,
real_name, fhp, &mbytes, &bytes, NULL)) != 0) {
__db_err(env, ret, "%s", real_name);
return (ret);
}
if (bytes % dbp->pgsize != 0) {
__db_errx(env,
"%s: file size not a multiple of the pagesize", real_name);
return (EINVAL);
}
pgno_last = mbytes * (MEGABYTE / dbp->pgsize);
pgno_last += bytes / dbp->pgsize;
*pgno_lastp = pgno_last;
return (0);
}
static int
__db_set_lastpgno(dbp, real_name, fhp)
DB *dbp;
char *real_name;
DB_FH *fhp;
{
DBMETA meta;
ENV *env;
int ret;
size_t n;
env = dbp->env;
if ((ret = __os_seek(env, fhp, 0, 0, 0)) != 0)
return (ret);
if ((ret = __os_read(env, fhp, &meta, sizeof(meta), &n)) != 0)
return (ret);
dbp->pgsize = meta.pagesize;
if ((ret = __db_lastpgno(dbp, real_name, fhp, &meta.last_pgno)) != 0)
return (ret);
if ((ret = __os_seek(env, fhp, 0, 0, 0)) != 0)
return (ret);
if ((ret = __os_write(env, fhp, &meta, sizeof(meta), &n)) != 0)
return (ret);
return (0);
}
#endif