📄 db_vrfy.c
字号:
__db_vrfy_common(dbp, vdp, h, pgno, flags) DB *dbp; VRFY_DBINFO *vdp; PAGE *h; db_pgno_t pgno; u_int32_t flags;{ DB_ENV *dbenv; VRFY_PAGEINFO *pip; int ret, t_ret; u_int8_t *p; dbenv = dbp->dbenv; if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) return (ret); pip->pgno = pgno; F_CLR(pip, VRFY_IS_ALLZEROES); /* * Hash expands the table by leaving some pages between the * old last and the new last totally zeroed. Its pgin function * should fix things, but we might not be using that (e.g. if * we're a subdatabase). * * Queue will create sparse files if sparse record numbers are used. */ if (pgno != 0 && PGNO(h) == 0) { for (p = (u_int8_t *)h; p < (u_int8_t *)h + dbp->pgsize; p++) if (*p != 0) { EPRINT((dbenv, "Page %lu: partially zeroed page", (u_long)pgno)); ret = DB_VERIFY_BAD; goto err; } /* * It's totally zeroed; mark it as a hash, and we'll * check that that makes sense structurally later. * (The queue verification doesn't care, since queues * don't really have much in the way of structure.) */ pip->type = P_HASH; F_SET(pip, VRFY_IS_ALLZEROES); ret = 0; goto err; /* well, not really an err. */ } if (PGNO(h) != pgno) { EPRINT((dbenv, "Page %lu: bad page number %lu", (u_long)pgno, (u_long)h->pgno)); ret = DB_VERIFY_BAD; } if (!__db_is_valid_pagetype(h->type)) { EPRINT((dbenv, "Page %lu: bad page type %lu", (u_long)pgno, (u_long)h->type)); ret = DB_VERIFY_BAD; } pip->type = h->type;err: if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0) ret = t_ret; return (ret);}/* * __db_vrfy_invalid -- * Verify P_INVALID page. * (Yes, there's not much to do here.) */static int__db_vrfy_invalid(dbp, vdp, h, pgno, flags) DB *dbp; VRFY_DBINFO *vdp; PAGE *h; db_pgno_t pgno; u_int32_t flags;{ DB_ENV *dbenv; VRFY_PAGEINFO *pip; int ret, t_ret; dbenv = dbp->dbenv; if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) return (ret); pip->next_pgno = pip->prev_pgno = 0; if (!IS_VALID_PGNO(NEXT_PGNO(h))) { EPRINT((dbenv, "Page %lu: invalid next_pgno %lu", (u_long)pgno, (u_long)NEXT_PGNO(h))); ret = DB_VERIFY_BAD; } else pip->next_pgno = NEXT_PGNO(h); if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0) ret = t_ret; return (ret);}/* * __db_vrfy_datapage -- * Verify elements common to data pages (P_HASH, P_LBTREE, * P_IBTREE, P_IRECNO, P_LRECNO, P_OVERFLOW, P_DUPLICATE)--i.e., * those defined in the PAGE structure. * * Called from each of the per-page routines, after the * all-page-type-common elements of pip have been verified and filled * in. * * PUBLIC: int __db_vrfy_datapage * PUBLIC: __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t)); */int__db_vrfy_datapage(dbp, vdp, h, pgno, flags) DB *dbp; VRFY_DBINFO *vdp; PAGE *h; db_pgno_t pgno; u_int32_t flags;{ DB_ENV *dbenv; VRFY_PAGEINFO *pip; int isbad, ret, t_ret; dbenv = dbp->dbenv; if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) return (ret); isbad = 0; /* * prev_pgno and next_pgno: store for inter-page checks, * verify that they point to actual pages and not to self. * * !!! * Internal btree pages do not maintain these fields (indeed, * they overload them). Skip. */ if (TYPE(h) != P_IBTREE && TYPE(h) != P_IRECNO) { if (!IS_VALID_PGNO(PREV_PGNO(h)) || PREV_PGNO(h) == pip->pgno) { isbad = 1; EPRINT((dbenv, "Page %lu: invalid prev_pgno %lu", (u_long)pip->pgno, (u_long)PREV_PGNO(h))); } if (!IS_VALID_PGNO(NEXT_PGNO(h)) || NEXT_PGNO(h) == pip->pgno) { isbad = 1; EPRINT((dbenv, "Page %lu: invalid next_pgno %lu", (u_long)pip->pgno, (u_long)NEXT_PGNO(h))); } pip->prev_pgno = PREV_PGNO(h); pip->next_pgno = NEXT_PGNO(h); } /* * Verify the number of entries on the page. * There is no good way to determine if this is accurate; the * best we can do is verify that it's not more than can, in theory, * fit on the page. Then, we make sure there are at least * this many valid elements in inp[], and hope that this catches * most cases. */ if (TYPE(h) != P_OVERFLOW) { if (BKEYDATA_PSIZE(0) * NUM_ENT(h) > dbp->pgsize) { isbad = 1; EPRINT((dbenv, "Page %lu: too many entries: %lu", (u_long)pgno, (u_long)NUM_ENT(h))); } pip->entries = NUM_ENT(h); } /* * btree level. Should be zero unless we're a btree; * if we are a btree, should be between LEAFLEVEL and MAXBTREELEVEL, * and we need to save it off. */ switch (TYPE(h)) { case P_IBTREE: case P_IRECNO: if (LEVEL(h) < LEAFLEVEL + 1 || LEVEL(h) > MAXBTREELEVEL) { isbad = 1; EPRINT((dbenv, "Page %lu: bad btree level %lu", (u_long)pgno, (u_long)LEVEL(h))); } pip->bt_level = LEVEL(h); break; case P_LBTREE: case P_LDUP: case P_LRECNO: if (LEVEL(h) != LEAFLEVEL) { isbad = 1; EPRINT((dbenv, "Page %lu: btree leaf page has incorrect level %lu", (u_long)pgno, (u_long)LEVEL(h))); } break; default: if (LEVEL(h) != 0) { isbad = 1; EPRINT((dbenv, "Page %lu: nonzero level %lu in non-btree database", (u_long)pgno, (u_long)LEVEL(h))); } break; } /* * Even though inp[] occurs in all PAGEs, we look at it in the * access-method-specific code, since btree and hash treat * item lengths very differently, and one of the most important * things we want to verify is that the data--as specified * by offset and length--cover the right part of the page * without overlaps, gaps, or violations of the page boundary. */ if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0) ret = t_ret; return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);}/* * __db_vrfy_meta-- * Verify the access-method common parts of a meta page, using * normal mpool routines. * * PUBLIC: int __db_vrfy_meta * PUBLIC: __P((DB *, VRFY_DBINFO *, DBMETA *, db_pgno_t, u_int32_t)); */int__db_vrfy_meta(dbp, vdp, meta, pgno, flags) DB *dbp; VRFY_DBINFO *vdp; DBMETA *meta; db_pgno_t pgno; u_int32_t flags;{ DB_ENV *dbenv; DBTYPE dbtype, magtype; VRFY_PAGEINFO *pip; int isbad, ret, t_ret; isbad = 0; dbenv = dbp->dbenv; if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) return (ret); /* type plausible for a meta page */ switch (meta->type) { case P_BTREEMETA: dbtype = DB_BTREE; break; case P_HASHMETA: dbtype = DB_HASH; break; case P_QAMMETA: dbtype = DB_QUEUE; break; default: /* The verifier should never let us get here. */ DB_ASSERT(0); ret = EINVAL; goto err; } /* magic number valid */ if (!__db_is_valid_magicno(meta->magic, &magtype)) { isbad = 1; EPRINT((dbenv, "Page %lu: invalid magic number", (u_long)pgno)); } if (magtype != dbtype) { isbad = 1; EPRINT((dbenv, "Page %lu: magic number does not match database type", (u_long)pgno)); } /* version */ if ((dbtype == DB_BTREE && (meta->version > DB_BTREEVERSION || meta->version < DB_BTREEOLDVER)) || (dbtype == DB_HASH && (meta->version > DB_HASHVERSION || meta->version < DB_HASHOLDVER)) || (dbtype == DB_QUEUE && (meta->version > DB_QAMVERSION || meta->version < DB_QAMOLDVER))) { isbad = 1; EPRINT((dbenv, "Page %lu: unsupported database version %lu; extraneous errors may result", (u_long)pgno, (u_long)meta->version)); } /* pagesize */ if (meta->pagesize != dbp->pgsize) { isbad = 1; EPRINT((dbenv, "Page %lu: invalid pagesize %lu", (u_long)pgno, (u_long)meta->pagesize)); } /* free list */ /* * If this is not the main, master-database meta page, it * should not have a free list. */ if (pgno != PGNO_BASE_MD && meta->free != PGNO_INVALID) { isbad = 1; EPRINT((dbenv, "Page %lu: nonempty free list on subdatabase metadata page", (u_long)pgno)); } /* Can correctly be PGNO_INVALID--that's just the end of the list. */ if (meta->free != PGNO_INVALID && IS_VALID_PGNO(meta->free)) pip->free = meta->free; else if (!IS_VALID_PGNO(meta->free)) { isbad = 1; EPRINT((dbenv, "Page %lu: nonsensical free list pgno %lu", (u_long)pgno, (u_long)meta->free)); } /* * We have now verified the common fields of the metadata page. * Clear the flag that told us they had been incompletely checked. */ F_CLR(pip, VRFY_INCOMPLETE);err: if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0) ret = t_ret; return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);}/* * __db_vrfy_freelist -- * Walk free list, checking off pages and verifying absence of * loops. */static int__db_vrfy_freelist(dbp, vdp, meta, flags) DB *dbp; VRFY_DBINFO *vdp; db_pgno_t meta; u_int32_t flags;{ DB *pgset; DB_ENV *dbenv; VRFY_PAGEINFO *pip; db_pgno_t cur_pgno, next_pgno; int p, ret, t_ret; pgset = vdp->pgset; DB_ASSERT(pgset != NULL); dbenv = dbp->dbenv; if ((ret = __db_vrfy_getpageinfo(vdp, meta, &pip)) != 0) return (ret); for (next_pgno = pip->free; next_pgno != PGNO_INVALID; next_pgno = pip->next_pgno) { cur_pgno = pip->pgno; if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0) return (ret); /* This shouldn't happen, but just in case. */ if (!IS_VALID_PGNO(next_pgno)) { EPRINT((dbenv, "Page %lu: invalid next_pgno %lu on free list page", (u_long)cur_pgno, (u_long)next_pgno)); return (DB_VERIFY_BAD); } /* Detect cycles. */ if ((ret = __db_vrfy_pgset_get(pgset, next_pgno, &p)) != 0) return (ret); if (p != 0) { EPRINT((dbenv, "Page %lu: page %lu encountered a second time on free list", (u_long)cur_pgno, (u_long)next_pgno)); return (DB_VERIFY_BAD); } if ((ret = __db_vrfy_pgset_inc(pgset, next_pgno)) != 0) return (ret); if ((ret = __db_vrfy_getpageinfo(vdp, next_pgno, &pip)) != 0) return (ret); if (pip->type != P_INVALID) { EPRINT((dbenv, "Page %lu: non-invalid page %lu on free list", (u_long)cur_pgno, (u_long)next_pgno)); ret = DB_VERIFY_BAD; /* unsafe to continue */ break; } } if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0) ret = t_ret; return (ret);}/* * __db_vrfy_subdbs -- * Walk the known-safe master database of subdbs with a cursor, * verifying the structure of each subdatabase we encounter. */static int__db_vrfy_subdbs(dbp, vdp, dbname, flags) DB *dbp; VRFY_DBINFO *vdp; const char *dbname; u_int32_t flags;{ DB *mdbp; DBC *dbc; DBT key, data; DB_ENV *dbenv; VRFY_PAGEINFO *pip; db_pgno_t meta_pgno; int ret, t_ret, isbad; u_int8_t type; isbad = 0; dbc = NULL; dbenv = dbp->dbenv; if ((ret = __db_master_open(dbp, NULL, dbname, DB_RDONLY, 0, &mdbp)) != 0) return (ret); if ((ret = __db_icursor(mdbp, NULL, DB_BTREE, PGNO_INVALID, 0, DB_LOCK_INVALIDID, &dbc)) != 0) goto err; memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); while ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) == 0) { if (data.size != sizeof(db_pgno_t)) { EPRINT((dbenv, "Subdatabase entry not page-number size")); isbad = 1; goto err; } memcpy(&meta_pgno, data.data, data.size); /* * Subdatabase meta pgnos are stored in network byte * order for cross-endian compatibility. Swap if appropriate. */ DB_NTOHL(&meta_pgno); if (meta_pgno == PGNO_INVALID || meta_pgno > vdp->last_pgno) { EPRINT((dbenv, "Subdatabase entry references invalid page %lu", (u_long)meta_pgno)); isbad = 1; goto err; } if ((ret = __db_vrfy_getpageinfo(vdp, meta_pgno, &pip)) != 0) goto err; type = pip->type; if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0) goto err; switch (type) { case P_BTREEMETA: if ((ret = __bam_vrfy_structure( dbp, vdp, meta_pgno, flags)) != 0) { if (ret == DB_VERIFY_BAD) isbad = 1; else goto err; } break; case P_HASHMETA: if ((ret = __ham_vrfy_structure( dbp, vdp, meta_pgno, flags)) != 0) { if (ret == DB_VERIFY_BAD) isbad = 1; else goto err; } break; case P_QAMMETA: default: EPRINT((dbenv, "Subdatabase entry references page %lu of invalid type %lu", (u_long)meta_pgno, (u_long)type)); ret = DB_VERIFY_BAD; goto err; /* NOTREACHED */ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -