#include "db_config.h"
#include "db_int.h"
#include "dbinc/db_page.h"
#include "dbinc/db_verify.h"
#include "dbinc/db_am.h"
#include "dbinc/mp.h"
#include "dbinc/qam.h"
int
__qam_vrfy_meta(dbp, vdp, meta, pgno, flags)
DB *dbp;
VRFY_DBINFO *vdp;
QMETA *meta;
db_pgno_t pgno;
u_int32_t flags;
{
ENV *env;
QUEUE *qp;
VRFY_PAGEINFO *pip;
db_pgno_t *extents, extid, first, last;
size_t len;
int count, i, isbad, nextents, ret, t_ret;
char *buf, **names;
COMPQUIET(count, 0);
env = dbp->env;
qp = (QUEUE *)dbp->q_internal;
extents = NULL;
first = last = 0;
isbad = 0;
buf = NULL;
names = NULL;
if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
return (ret);
if (!F_ISSET(pip, VRFY_INCOMPLETE))
EPRINT((env, DB_STR_A("1146",
"Page %lu: queue databases must be one-per-file",
"%lu"), (u_long)pgno));
if ((ret = __db_vrfy_meta(dbp, vdp, &meta->dbmeta, pgno, flags)) != 0) {
if (ret == DB_VERIFY_BAD)
isbad = 1;
else
goto err;
}
if (DB_ALIGN(meta->re_len + sizeof(QAMDATA) - 1, sizeof(u_int32_t)) *
meta->rec_page + QPAGE_SZ(dbp) > dbp->pgsize) {
EPRINT((env, DB_STR_A("1147",
"Page %lu: queue record length %lu too high for page size and recs/page",
"%lu %lu"), (u_long)pgno, (u_long)meta->re_len));
ret = DB_VERIFY_FATAL;
goto err;
} else {
vdp->re_pad = meta->re_pad;
qp->re_pad = (int)meta->re_pad;
qp->re_len = vdp->re_len = meta->re_len;
qp->rec_page = vdp->rec_page = meta->rec_page;
qp->page_ext = vdp->page_ext = meta->page_ext;
}
if (F_ISSET(vdp, VRFY_QMETA_SET)) {
isbad = 1;
EPRINT((env, DB_STR_A("1148",
"Page %lu: database contains multiple Queue metadata pages",
"%lu"), (u_long)pgno));
goto err;
}
F_SET(vdp, VRFY_QMETA_SET);
qp->page_ext = meta->page_ext;
dbp->pgsize = meta->dbmeta.pagesize;
qp->q_meta = pgno;
qp->q_root = pgno + 1;
vdp->first_recno = meta->first_recno;
vdp->last_recno = meta->cur_recno;
if (qp->page_ext != 0) {
first = QAM_RECNO_EXTENT(dbp, vdp->first_recno);
last = QAM_RECNO_EXTENT(dbp, vdp->last_recno);
}
if ((ret = __db_appname(env,
DB_APP_DATA, qp->dir, NULL, &buf)) != 0)
goto err;
if ((ret = __os_dirlist(env, buf, 0, &names, &count)) != 0)
goto err;
__os_free(env, buf);
buf = NULL;
nextents = 0;
if (!F_ISSET(dbp, DB_AM_INMEM)) {
len = strlen(QUEUE_EXTENT_HEAD) + strlen(qp->name) + 1;
if ((ret = __os_malloc(env, len, &buf)) != 0)
goto err;
len = (size_t)snprintf(buf, len, QUEUE_EXTENT_HEAD, qp->name);
for (i = 0; i < count; i++) {
if (strncmp(names[i], buf, len) == 0) {
extid = (db_pgno_t)strtoul(
&names[i][len], NULL, 10);
if (qp->page_ext != 0 &&
(last > first ?
(extid >= first && extid <= last) :
(extid >= first || extid <= last)))
continue;
if (extents == NULL && (ret = __os_malloc(
env, (size_t)(count - i) * sizeof(extid),
&extents)) != 0)
goto err;
extents[nextents] = extid;
nextents++;
}
}
}
if (nextents > 0)
__db_errx(env, DB_STR_A("1149",
"Warning: %d extra extent files found", "%d"), nextents);
vdp->nextents = nextents;
vdp->extents = extents;
err: if ((t_ret = __db_vrfy_putpageinfo(env, vdp, pip)) != 0 && ret == 0)
ret = t_ret;
if (names != NULL)
__os_dirfree(env, names, count);
if (buf != NULL)
__os_free(env, buf);
if (ret != 0 && extents != NULL)
__os_free(env, extents);
if (LF_ISSET(DB_SALVAGE) &&
(t_ret = __db_salvage_markdone(vdp, pgno)) != 0 && ret == 0)
ret = t_ret;
return (ret == 0 && isbad == 1 ? DB_VERIFY_BAD : ret);
}
int
__qam_meta2pgset(dbp, vdp, pgset)
DB *dbp;
VRFY_DBINFO *vdp;
DB *pgset;
{
DBC *dbc;
PAGE *h;
db_pgno_t first, last, pgno, pg_ext, stop;
int ret, t_ret;
u_int32_t i;
ret = 0;
h = NULL;
if (vdp->last_recno <= vdp->first_recno)
return (0);
pg_ext = vdp->page_ext;
first = QAM_RECNO_PAGE(dbp, vdp->first_recno);
last = QAM_RECNO_PAGE(dbp, vdp->last_recno - 1);
if (first == PGNO_INVALID || last == PGNO_INVALID)
return (DB_VERIFY_BAD);
pgno = first;
if (first > last)
stop = QAM_RECNO_PAGE(dbp, UINT32_MAX);
else
stop = last;
if (pg_ext == 0) {
for (pgno = first; pgno <= stop; pgno++)
if ((ret = __db_vrfy_pgset_inc(
pgset, vdp->thread_info, vdp->txn, pgno)) != 0)
break;
if (first > last)
for (pgno = 1; pgno <= last; pgno++)
if ((ret = __db_vrfy_pgset_inc(pgset,
vdp->thread_info, vdp->txn, pgno)) != 0)
break;
return (ret);
}
if ((ret = __db_cursor(dbp, vdp->thread_info, NULL, &dbc, 0)) != 0)
return (ret);
begin: for (; pgno <= stop; pgno += pg_ext) {
if ((ret = __qam_fget(dbc, &pgno, 0, &h)) != 0) {
if (ret == ENOENT || ret == DB_PAGE_NOTFOUND) {
ret = 0;
continue;
}
goto err;
}
if ((ret = __qam_fput(dbc, pgno, h, dbp->priority)) != 0)
goto err;
for (i = 0; i < pg_ext && pgno + i <= last; i++)
if ((ret = __db_vrfy_pgset_inc(
pgset, vdp->thread_info, vdp->txn, pgno + i)) != 0)
goto err;
if (pgno == first)
pgno = pgno % pg_ext + 1;
}
if (first > last) {
pgno = 1;
first = last;
stop = last;
goto begin;
}
err:
if ((t_ret = __dbc_close(dbc)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
int
__qam_vrfy_data(dbp, vdp, h, pgno, flags)
DB *dbp;
VRFY_DBINFO *vdp;
QPAGE *h;
db_pgno_t pgno;
u_int32_t flags;
{
DB fakedb;
struct __queue fakeq;
QAMDATA *qp;
db_recno_t i;
fakedb.q_internal = &fakeq;
fakedb.flags = dbp->flags;
fakeq.re_len = vdp->re_len;
for (i = 0; i < vdp->rec_page; i++) {
qp = QAM_GET_RECORD(&fakedb, h, i);
if ((u_int8_t *)qp >= (u_int8_t *)h + dbp->pgsize) {
EPRINT((dbp->env, DB_STR_A("1150",
"Page %lu: queue record %lu extends past end of page",
"%lu %lu"), (u_long)pgno, (u_long)i));
return (DB_VERIFY_BAD);
}
if (qp->flags & ~(QAM_VALID | QAM_SET)) {
EPRINT((dbp->env, DB_STR_A("1151",
"Page %lu: queue record %lu has bad flags (%#lx)",
"%lu %lu %#lx"), (u_long)pgno, (u_long)i,
(u_long)qp->flags));
return (DB_VERIFY_BAD);
}
}
return (0);
}
int
__qam_vrfy_structure(dbp, vdp, flags)
DB *dbp;
VRFY_DBINFO *vdp;
u_int32_t flags;
{
VRFY_PAGEINFO *pip;
db_pgno_t i;
int ret, isbad;
isbad = 0;
if ((ret = __db_vrfy_getpageinfo(vdp, PGNO_BASE_MD, &pip)) != 0)
return (ret);
if (pip->type != P_QAMMETA) {
EPRINT((dbp->env, DB_STR_A("1152",
"Page %lu: queue database has no meta page", "%lu"),
(u_long)PGNO_BASE_MD));
isbad = 1;
goto err;
}
if ((ret = __db_vrfy_pgset_inc(
vdp->pgset, vdp->thread_info, vdp->txn, 0)) != 0)
goto err;
for (i = 1; i <= vdp->last_pgno; i++) {
if (!LF_ISSET(DB_SALVAGE))
__db_vrfy_struct_feedback(dbp, vdp);
if ((ret = __db_vrfy_putpageinfo(dbp->env, vdp, pip)) != 0 ||
(ret = __db_vrfy_getpageinfo(vdp, i, &pip)) != 0)
return (ret);
if (!F_ISSET(pip, VRFY_IS_ALLZEROES) &&
pip->type != P_QAMDATA && !F_ISSET(pip, VRFY_NONEXISTENT)) {
EPRINT((dbp->env, DB_STR_A("1153",
"Page %lu: queue database page of incorrect type %lu",
"%lu %lu"), (u_long)i, (u_long)pip->type));
isbad = 1;
goto err;
} else if ((ret = __db_vrfy_pgset_inc(vdp->pgset,
vdp->thread_info, vdp->txn, i)) != 0)
goto err;
}
err: if ((ret = __db_vrfy_putpageinfo(dbp->env, vdp, pip)) != 0)
return (ret);
return (isbad == 1 ? DB_VERIFY_BAD : 0);
}
int
__qam_vrfy_walkqueue(dbp, vdp, handle, callback, flags)
DB *dbp;
VRFY_DBINFO *vdp;
void *handle;
int (*callback) __P((void *, const void *));
u_int32_t flags;
{
DBC *dbc;
ENV *env;
PAGE *h;
QUEUE *qp;
VRFY_PAGEINFO *pip;
db_pgno_t first, i, last, pg_ext, stop;
int isbad, nextents, ret, t_ret;
COMPQUIET(h, NULL);
env = dbp->env;
qp = dbp->q_internal;
pip = NULL;
pg_ext = qp->page_ext;
isbad = ret = t_ret = 0;
h = NULL;
if (pg_ext == 0)
return (0);
first = QAM_RECNO_PAGE(dbp, vdp->first_recno);
last = QAM_RECNO_PAGE(dbp, vdp->last_recno);
i = first;
if (first > last)
stop = QAM_RECNO_PAGE(dbp, UINT32_MAX);
else
stop = last;
nextents = vdp->nextents;
if ((ret = __db_cursor(dbp, vdp->thread_info, NULL, &dbc, 0)) != 0)
return (ret);
begin: for (; i <= stop; i++) {
if (LF_ISSET(DB_SALVAGE) && (__db_salvage_isdone(vdp, i) != 0))
continue;
if ((t_ret = __qam_fget(dbc, &i, 0, &h)) != 0) {
if (t_ret == ENOENT || t_ret == DB_PAGE_NOTFOUND) {
i += (pg_ext - ((i - 1) % pg_ext)) - 1;
continue;
}
if (LF_ISSET(DB_SALVAGE)) {
if (ret == 0)
ret = t_ret;
continue;
}
h = NULL;
ret = t_ret;
goto err;
}
if (LF_ISSET(DB_SALVAGE)) {
if ((t_ret = __db_salvage_pg(dbp,
vdp, i, h, handle, callback, flags)) != 0) {
if (ret == 0)
ret = t_ret;
isbad = 1;
}
} else {
if ((ret = __db_vrfy_common(dbp,
vdp, h, i, flags)) == DB_VERIFY_BAD)
isbad = 1;
else if (ret != 0)
goto err;
__db_vrfy_struct_feedback(dbp, vdp);
if ((ret = __db_vrfy_getpageinfo(vdp, i, &pip)) != 0)
goto err;
if (F_ISSET(pip, VRFY_IS_ALLZEROES))
goto put;
if (pip->type != P_QAMDATA) {
EPRINT((env, DB_STR_A("1154",
"Page %lu: queue database page of incorrect type %lu",
"%lu %lu"), (u_long)i, (u_long)pip->type));
isbad = 1;
goto err;
}
if ((ret = __db_vrfy_pgset_inc(vdp->pgset,
vdp->thread_info, vdp->txn, i)) != 0)
goto err;
if ((ret = __qam_vrfy_data(dbp, vdp,
(QPAGE *)h, i, flags)) == DB_VERIFY_BAD)
isbad = 1;
else if (ret != 0)
goto err;
put: if ((ret = __db_vrfy_putpageinfo(env, vdp, pip)) != 0)
goto err1;
pip = NULL;
}
if ((t_ret = __qam_fput(dbc, i, h, dbp->priority)) != 0) {
if (LF_ISSET(DB_SALVAGE)) {
if (ret == 0)
ret = t_ret;
continue;
}
ret = t_ret;
goto err1;
}
}
if (first > last) {
i = 1;
stop = last;
first = last;
goto begin;
}
if (LF_ISSET(DB_SALVAGE) && nextents != 0) {
nextents--;
i = 1 +
vdp->extents[nextents] * vdp->page_ext;
stop = i + vdp->page_ext;
goto begin;
}
if (0) {
err: if (h != NULL && (t_ret =
__qam_fput(dbc, i, h, dbp->priority)) != 0 && ret == 0)
ret = t_ret;
if (pip != NULL && (t_ret =
__db_vrfy_putpageinfo(env, vdp, pip)) != 0 && ret == 0)
ret = t_ret;
}
err1: if (dbc != NULL && (t_ret = __dbc_close(dbc)) != 0 && ret == 0)
ret = t_ret;
return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret);
}
int
__qam_salvage(dbp, vdp, pgno, h, handle, callback, flags)
DB *dbp;
VRFY_DBINFO *vdp;
db_pgno_t pgno;
PAGE *h;
void *handle;
int (*callback) __P((void *, const void *));
u_int32_t flags;
{
DBT dbt, key;
QAMDATA *qp, *qep;
db_recno_t recno;
int ret, err_ret, t_ret;
u_int32_t pagesize, qlen;
u_int32_t i;
memset(&dbt, 0, sizeof(DBT));
memset(&key, 0, sizeof(DBT));
err_ret = ret = 0;
pagesize = (u_int32_t)dbp->mpf->mfp->pagesize;
qlen = ((QUEUE *)dbp->q_internal)->re_len;
dbt.size = qlen;
key.data = &recno;
key.size = sizeof(recno);
recno = (pgno - 1) * QAM_RECNO_PER_PAGE(dbp) + 1;
i = 0;
qep = (QAMDATA *)((u_int8_t *)h + pagesize - qlen);
for (qp = QAM_GET_RECORD(dbp, h, i); qp < qep;
recno++, i++, qp = QAM_GET_RECORD(dbp, h, i)) {
if (F_ISSET(qp, ~(QAM_VALID|QAM_SET)))
continue;
if (!F_ISSET(qp, QAM_SET))
continue;
if (!LF_ISSET(DB_AGGRESSIVE) && !F_ISSET(qp, QAM_VALID))
continue;
dbt.data = qp->data;
if ((ret = __db_vrfy_prdbt(&key,
0, " ", handle, callback, 1, 0, vdp)) != 0)
err_ret = ret;
if ((ret = __db_vrfy_prdbt(&dbt,
0, " ", handle, callback, 0, 0, vdp)) != 0)
err_ret = ret;
}
if ((t_ret = __db_salvage_markdone(vdp, pgno)) != 0)
return (t_ret);
return ((ret == 0 && err_ret != 0) ? err_ret : ret);
}