#include "db_config.h"
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_am.h"
#include "dbinc/db_verify.h"
#include "dbinc/mp.h"
int
__db_vrfy_overflow(dbp, vdp, h, pgno, flags)
DB *dbp;
VRFY_DBINFO *vdp;
PAGE *h;
db_pgno_t pgno;
u_int32_t flags;
{
VRFY_PAGEINFO *pip;
int isbad, ret, t_ret;
isbad = 0;
if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
return (ret);
if ((ret = __db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) {
if (ret == DB_VERIFY_BAD)
isbad = 1;
else
goto err;
}
pip->refcount = OV_REF(h);
if (pip->refcount < 1) {
EPRINT((dbp->env, DB_STR_A("0676",
"Page %lu: overflow page has zero reference count", "%lu"),
(u_long)pgno));
isbad = 1;
}
pip->olen = HOFFSET(h);
err: if ((t_ret = __db_vrfy_putpageinfo(dbp->env, vdp, pip)) != 0)
ret = t_ret;
return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
}
int
__db_vrfy_ovfl_structure(dbp, vdp, pgno, tlen, flags)
DB *dbp;
VRFY_DBINFO *vdp;
db_pgno_t pgno;
u_int32_t tlen;
u_int32_t flags;
{
DB *pgset;
ENV *env;
VRFY_PAGEINFO *pip;
db_pgno_t next, prev;
int isbad, ret, seen_cnt, t_ret;
u_int32_t refcount;
env = dbp->env;
pgset = vdp->pgset;
DB_ASSERT(env, pgset != NULL);
isbad = 0;
if (!IS_VALID_PGNO(pgno))
return (DB_VERIFY_BAD);
if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
return (ret);
refcount = pip->refcount;
if (pip->type != P_OVERFLOW) {
EPRINT((env, DB_STR_A("0677",
"Page %lu: overflow page of invalid type %lu", "%lu %lu"),
(u_long)pgno, (u_long)pip->type));
ret = DB_VERIFY_BAD;
goto err;
}
prev = pip->prev_pgno;
if (prev != PGNO_INVALID) {
EPRINT((env, DB_STR_A("0678",
"Page %lu: first page in overflow chain has a prev_pgno %lu",
"%lu %lu"), (u_long)pgno, (u_long)prev));
isbad = 1;
}
for (;;) {
if ((ret = __db_vrfy_pgset_get(pgset,
vdp->thread_info, vdp->txn, pgno, &seen_cnt)) != 0)
goto err;
if ((u_int32_t)seen_cnt > refcount) {
EPRINT((env, DB_STR_A("0679",
"Page %lu: encountered too many times in overflow traversal",
"%lu"), (u_long)pgno));
ret = DB_VERIFY_BAD;
goto err;
}
if ((ret = __db_vrfy_pgset_inc(
pgset, vdp->thread_info, vdp->txn, pgno)) != 0)
goto err;
if (LF_ISSET(DB_ST_OVFL_LEAF)) {
if (F_ISSET(pip, VRFY_OVFL_LEAFSEEN)) {
EPRINT((env, DB_STR_A("0680",
"Page %lu: overflow page linked twice from leaf or data page",
"%lu"), (u_long)pgno));
ret = DB_VERIFY_BAD;
goto err;
}
F_SET(pip, VRFY_OVFL_LEAFSEEN);
}
if (seen_cnt == 0) {
tlen -= pip->olen;
if (!LF_ISSET(DB_SALVAGE))
__db_vrfy_struct_feedback(dbp, vdp);
} else
goto done;
next = pip->next_pgno;
if (next == PGNO_INVALID)
break;
if (!IS_VALID_PGNO(next)) {
EPRINT((env, DB_STR_A("0681",
"Page %lu: bad next_pgno %lu on overflow page",
"%lu %lu"), (u_long)pgno, (u_long)next));
ret = DB_VERIFY_BAD;
goto err;
}
if ((ret = __db_vrfy_putpageinfo(env, vdp, pip)) != 0 ||
(ret = __db_vrfy_getpageinfo(vdp, next, &pip)) != 0)
return (ret);
if (pip->prev_pgno != pgno) {
EPRINT((env, DB_STR_A("0682",
"Page %lu: bad prev_pgno %lu on overflow page (should be %lu)",
"%lu %lu %lu"), (u_long)next,
(u_long)pip->prev_pgno, (u_long)pgno));
isbad = 1;
}
pgno = next;
}
if (tlen > 0) {
isbad = 1;
EPRINT((env, DB_STR_A("0683",
"Page %lu: overflow item incomplete", "%lu"),
(u_long)pgno));
}
done:
err: if ((t_ret =
__db_vrfy_putpageinfo(env, vdp, pip)) != 0 && ret == 0)
ret = t_ret;
return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
}
int
__db_safe_goff(dbp, vdp, pgno, dbt, buf, bufsz, flags)
DB *dbp;
VRFY_DBINFO *vdp;
db_pgno_t pgno;
DBT *dbt;
void *buf;
u_int32_t *bufsz;
u_int32_t flags;
{
DB_MPOOLFILE *mpf;
PAGE *h;
int ret, t_ret;
u_int32_t bytesgot, bytes;
u_int8_t *src, *dest;
mpf = dbp->mpf;
h = NULL;
ret = t_ret = 0;
bytesgot = bytes = 0;
DB_ASSERT(dbp->env, bufsz != NULL);
for (;;) {
if ((ret = __memp_fget(
mpf, &pgno, vdp->thread_info, NULL, 0, &h)) != 0)
return (ret);
if (PREV_PGNO(h) == PGNO_INVALID ||
!IS_VALID_PGNO(PREV_PGNO(h)))
break;
pgno = PREV_PGNO(h);
if ((ret = __memp_fput(mpf,
vdp->thread_info, h, DB_PRIORITY_UNCHANGED)) != 0)
return (ret);
}
if ((ret = __memp_fput(
mpf, vdp->thread_info, h, DB_PRIORITY_UNCHANGED)) != 0)
return (ret);
h = NULL;
while ((pgno != PGNO_INVALID) && (IS_VALID_PGNO(pgno))) {
if ((ret = __db_salvage_markdone(vdp, pgno)) != 0)
break;
if ((ret = __memp_fget(mpf, &pgno,
vdp->thread_info, NULL, 0, &h)) != 0)
break;
if (!LF_ISSET(DB_AGGRESSIVE) && TYPE(h) != P_OVERFLOW) {
ret = DB_VERIFY_BAD;
break;
}
src = (u_int8_t *)h + P_OVERHEAD(dbp);
bytes = OV_LEN(h);
if (bytes + P_OVERHEAD(dbp) > dbp->pgsize)
bytes = dbp->pgsize - P_OVERHEAD(dbp);
if (bytesgot + bytes > *bufsz) {
if ((ret =
__os_realloc(dbp->env, bytesgot + bytes, buf)) != 0)
break;
*bufsz = bytesgot + bytes;
}
dest = *(u_int8_t **)buf + bytesgot;
bytesgot += bytes;
memcpy(dest, src, bytes);
pgno = NEXT_PGNO(h);
if ((ret = __memp_fput(mpf,
vdp->thread_info, h, DB_PRIORITY_UNCHANGED)) != 0)
break;
h = NULL;
}
if (ret == 0 || LF_ISSET(DB_AGGRESSIVE)) {
dbt->size = bytesgot;
dbt->data = *(void **)buf;
}
if (h != NULL && (t_ret = __memp_fput(mpf,
vdp->thread_info, h, DB_PRIORITY_UNCHANGED)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}