📄 db_vrfy.c
字号:
} if (ret == DB_NOTFOUND) ret = 0;err: if (dbc != NULL && (t_ret = __db_c_close(dbc)) != 0 && ret == 0) ret = t_ret; if ((t_ret = mdbp->close(mdbp, 0)) != 0 && ret == 0) ret = t_ret; return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);}/* * __db_vrfy_struct_feedback -- * Provide feedback during top-down database structure traversal. * (See comment at the beginning of __db_vrfy_structure.) * * PUBLIC: void __db_vrfy_struct_feedback __P((DB *, VRFY_DBINFO *)); */void__db_vrfy_struct_feedback(dbp, vdp) DB *dbp; VRFY_DBINFO *vdp;{ int progress; if (dbp->db_feedback == NULL) return; if (vdp->pgs_remaining > 0) vdp->pgs_remaining--; /* Don't allow a feedback call of 100 until we're really done. */ progress = 100 - (vdp->pgs_remaining * 50 / (vdp->last_pgno + 1)); dbp->db_feedback(dbp, DB_VERIFY, progress == 100 ? 99 : progress);}/* * __db_vrfy_orderchkonly -- * Do an sort-order/hashing check on a known-otherwise-good subdb. */static int__db_vrfy_orderchkonly(dbp, vdp, name, subdb, flags) DB *dbp; VRFY_DBINFO *vdp; const char *name, *subdb; u_int32_t flags;{ BTMETA *btmeta; DB *mdbp, *pgset; DBC *pgsc; DBT key, data; DB_ENV *dbenv; DB_MPOOLFILE *mpf; HASH *h_internal; HMETA *hmeta; PAGE *h, *currpg; db_pgno_t meta_pgno, p, pgno; u_int32_t bucket; int t_ret, ret; pgset = NULL; pgsc = NULL; dbenv = dbp->dbenv; mpf = dbp->mpf; currpg = h = NULL; LF_CLR(DB_NOORDERCHK); /* Open the master database and get the meta_pgno for the subdb. */ if ((ret = db_create(&mdbp, NULL, 0)) != 0) return (ret); if ((ret = __db_master_open(dbp, NULL, name, DB_RDONLY, 0, &mdbp)) != 0) goto err; memset(&key, 0, sizeof(key)); key.data = (void *)subdb; key.size = (u_int32_t)strlen(subdb); memset(&data, 0, sizeof(data)); if ((ret = mdbp->get(mdbp, NULL, &key, &data, 0)) != 0) goto err; if (data.size != sizeof(db_pgno_t)) { EPRINT((dbenv, "Subdatabase entry of invalid size")); ret = DB_VERIFY_BAD; 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 ((ret = mpf->get(mpf, &meta_pgno, 0, &h)) != 0) goto err; if ((ret = __db_vrfy_pgset(dbenv, dbp->pgsize, &pgset)) != 0) goto err; switch (TYPE(h)) { case P_BTREEMETA: btmeta = (BTMETA *)h; if (F_ISSET(&btmeta->dbmeta, BTM_RECNO)) { /* Recnos have no order to check. */ ret = 0; goto err; } if ((ret = __db_meta2pgset(dbp, vdp, meta_pgno, flags, pgset)) != 0) goto err; if ((ret = pgset->cursor(pgset, NULL, &pgsc, 0)) != 0) goto err; while ((ret = __db_vrfy_pgset_next(pgsc, &p)) == 0) { if ((ret = mpf->get(mpf, &p, 0, &currpg)) != 0) goto err; if ((ret = __bam_vrfy_itemorder(dbp, NULL, currpg, p, NUM_ENT(currpg), 1, F_ISSET(&btmeta->dbmeta, BTM_DUP), flags)) != 0) goto err; if ((ret = mpf->put(mpf, currpg, 0)) != 0) goto err; currpg = NULL; } /* * The normal exit condition for the loop above is DB_NOTFOUND. * If we see that, zero it and continue on to cleanup. * Otherwise, it's a real error and will be returned. */ if (ret == DB_NOTFOUND) ret = 0; break; case P_HASHMETA: hmeta = (HMETA *)h; h_internal = (HASH *)dbp->h_internal; /* * Make sure h_charkey is right. */ if (h_internal == NULL) { EPRINT((dbenv, "Page %lu: DB->h_internal field is NULL", (u_long)meta_pgno)); ret = DB_VERIFY_BAD; goto err; } if (h_internal->h_hash == NULL) h_internal->h_hash = hmeta->dbmeta.version < 5 ? __ham_func4 : __ham_func5; if (hmeta->h_charkey != h_internal->h_hash(dbp, CHARKEY, sizeof(CHARKEY))) { EPRINT((dbenv, "Page %lu: incorrect hash function for database", (u_long)meta_pgno)); ret = DB_VERIFY_BAD; goto err; } /* * Foreach bucket, verify hashing on each page in the * corresponding chain of pages. */ for (bucket = 0; bucket <= hmeta->max_bucket; bucket++) { pgno = BS_TO_PAGE(bucket, hmeta->spares); while (pgno != PGNO_INVALID) { if ((ret = mpf->get(mpf, &pgno, 0, &currpg)) != 0) goto err; if ((ret = __ham_vrfy_hashing(dbp, NUM_ENT(currpg), hmeta, bucket, pgno, flags, h_internal->h_hash)) != 0) goto err; pgno = NEXT_PGNO(currpg); if ((ret = mpf->put(mpf, currpg, 0)) != 0) goto err; currpg = NULL; } } break; default: EPRINT((dbenv, "Page %lu: database metapage of bad type %lu", (u_long)meta_pgno, (u_long)TYPE(h))); ret = DB_VERIFY_BAD; break; }err: if (pgsc != NULL && (t_ret = pgsc->c_close(pgsc)) != 0 && ret == 0) ret = t_ret; if (pgset != NULL && (t_ret = pgset->close(pgset, 0)) != 0 && ret == 0) ret = t_ret; if (h != NULL && (t_ret = mpf->put(mpf, h, 0)) != 0) ret = t_ret; if (currpg != NULL && (t_ret = mpf->put(mpf, currpg, 0)) != 0) ret = t_ret; if ((t_ret = mdbp->close(mdbp, 0)) != 0) ret = t_ret; return (ret);}/* * __db_salvage -- * Walk through a page, salvaging all likely or plausible (w/ * DB_AGGRESSIVE) key/data pairs. */static int__db_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;{ DB_ASSERT(LF_ISSET(DB_SALVAGE)); /* If we got this page in the subdb pass, we can safely skip it. */ if (__db_salvage_isdone(vdp, pgno)) return (0); switch (TYPE(h)) { case P_HASH: return (__ham_salvage(dbp, vdp, pgno, h, handle, callback, flags)); /* NOTREACHED */ case P_LBTREE: return (__bam_salvage(dbp, vdp, pgno, P_LBTREE, h, handle, callback, NULL, flags)); /* NOTREACHED */ case P_LDUP: return (__db_salvage_markneeded(vdp, pgno, SALVAGE_LDUP)); /* NOTREACHED */ case P_OVERFLOW: return (__db_salvage_markneeded(vdp, pgno, SALVAGE_OVERFLOW)); /* NOTREACHED */ case P_LRECNO: /* * Recnos are tricky -- they may represent dup pages, or * they may be subdatabase/regular database pages in their * own right. If the former, they need to be printed with a * key, preferably when we hit the corresponding datum in * a btree/hash page. If the latter, there is no key. * * If a database is sufficiently frotzed, we're not going * to be able to get this right, so we best-guess: just * mark it needed now, and if we're really a normal recno * database page, the "unknowns" pass will pick us up. */ return (__db_salvage_markneeded(vdp, pgno, SALVAGE_LRECNO)); /* NOTREACHED */ case P_IBTREE: case P_INVALID: case P_IRECNO: case __P_DUPLICATE: default: /* XXX: Should we be more aggressive here? */ break; } return (0);}/* * __db_salvage_unknowns -- * Walk through the salvager database, printing with key "UNKNOWN" * any pages we haven't dealt with. */static int__db_salvage_unknowns(dbp, vdp, handle, callback, flags) DB *dbp; VRFY_DBINFO *vdp; void *handle; int (*callback) __P((void *, const void *)); u_int32_t flags;{ DBT unkdbt, key, *dbt; DB_ENV *dbenv; DB_MPOOLFILE *mpf; PAGE *h; db_pgno_t pgno; u_int32_t pgtype; int ret, err_ret; void *ovflbuf; dbenv = dbp->dbenv; mpf = dbp->mpf; memset(&unkdbt, 0, sizeof(DBT)); unkdbt.size = (u_int32_t)strlen("UNKNOWN") + 1; unkdbt.data = "UNKNOWN"; if ((ret = __os_malloc(dbenv, dbp->pgsize, &ovflbuf)) != 0) return (ret); err_ret = 0; while ((ret = __db_salvage_getnext(vdp, &pgno, &pgtype)) == 0) { dbt = NULL; if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0) { err_ret = ret; continue; } switch (pgtype) { case SALVAGE_LDUP: case SALVAGE_LRECNODUP: dbt = &unkdbt; /* FALLTHROUGH */ case SALVAGE_LBTREE: case SALVAGE_LRECNO: if ((ret = __bam_salvage(dbp, vdp, pgno, pgtype, h, handle, callback, dbt, flags)) != 0) err_ret = ret; break; case SALVAGE_OVERFLOW: /* * XXX: * This may generate multiple "UNKNOWN" keys in * a database with no dups. What to do? */ if ((ret = __db_safe_goff(dbp, vdp, pgno, &key, &ovflbuf, flags)) != 0 || (ret = __db_prdbt(&key, 0, " ", handle, callback, 0, vdp)) != 0 || (ret = __db_prdbt(&unkdbt, 0, " ", handle, callback, 0, vdp)) != 0) err_ret = ret; break; case SALVAGE_HASH: if ((ret = __ham_salvage( dbp, vdp, pgno, h, handle, callback, flags)) != 0) err_ret = ret; break; case SALVAGE_INVALID: case SALVAGE_IGNORE: default: /* * Shouldn't happen, but if it does, just do what the * nice man says. */ DB_ASSERT(0); break; } if ((ret = mpf->put(mpf, h, 0)) != 0) err_ret = ret; } __os_free(dbenv, ovflbuf); if (err_ret != 0 && ret == 0) ret = err_ret; return (ret == DB_NOTFOUND ? 0 : ret);}/* * Offset of the ith inp array entry, which we can compare to the offset * the entry stores. */#define INP_OFFSET(dbp, h, i) \ ((db_indx_t)((u_int8_t *)((P_INP(dbp,(h))) + (i)) - (u_int8_t *)(h)))/* * __db_vrfy_inpitem -- * Verify that a single entry in the inp array is sane, and update * the high water mark and current item offset. (The former of these is * used for state information between calls, and is required; it must * be initialized to the pagesize before the first call.) * * Returns DB_VERIFY_FATAL if inp has collided with the data, * since verification can't continue from there; returns DB_VERIFY_BAD * if anything else is wrong. * * PUBLIC: int __db_vrfy_inpitem __P((DB *, PAGE *, * PUBLIC: db_pgno_t, u_int32_t, int, u_int32_t, u_int32_t *, u_int32_t *)); */int__db_vrfy_inpitem(dbp, h, pgno, i, is_btree, flags, himarkp, offsetp) DB *dbp; PAGE *h; db_pgno_t pgno; u_int32_t i; int is_btree; u_int32_t flags, *himarkp, *offsetp;{ BKEYDATA *bk; DB_ENV *dbenv; db_indx_t *inp, offset, len; dbenv = dbp->dbenv; DB_ASSERT(himarkp != NULL); inp = P_INP(dbp, h); /* * Check that the inp array, which grows from the beginning of the * page forward, has not collided with the data, which grow from the * end of the page backward. */ if (inp + i >= (db_indx_t *)((u_int8_t *)h + *himarkp)) { /* We've collided with the data. We need to bail. */ EPRINT((dbenv, "Page %lu: entries listing %lu overlaps data", (u_long)pgno, (u_long)i)); return (DB_VERIFY_FATAL); } offset = inp[i]; /* * Check that the item offset is reasonable: it points somewhere * after the inp array and before the end of the page. */ if (offset <= INP_OFFSET(dbp, h, i) || offset > dbp->pgsize) { EPRINT((dbenv, "Page %lu: bad offset %lu at page index %lu", (u_long)pgno, (u_long)offset, (u_long)i)); return (DB_VERIFY_BAD); } /* Update the high-water mark (what HOFFSET should be) */ if (offset < *himarkp) *himarkp = offset; if (is_btree) { /* * Check that the item length remains on-page. */ bk = GET_BKEYDATA(dbp, h, i); /* * We need to verify the type of the item here; * we can't simply assume that it will be one of the * expected three. If it's not a recognizable type, * it can't be considered to have a verifiable * length, so it's not possible to certify it as safe. */ switch (B_TYPE(bk->type)) { case B_KEYDATA: len = bk->len; break; case B_DUPLICATE: case B_OVERFLOW: len = BOVERFLOW_SIZE; break; default: EPRINT((dbenv, "Page %lu: item %lu of unrecognizable type", (u_long)pgno, (u_long)i)); return (DB_VERIFY_BAD); } if ((size_t)(offset + len) > dbp->pgsize) { EPRINT((dbenv, "Page %lu: item %lu extends past page boundary", (u_long)pgno, (u_long)i)); return (DB_VERIFY_BAD); } } if (offsetp != NULL) *offsetp = offset; return (0);}/* * __db_vrfy_duptype-- * Given a page number and a set of flags to __bam_vrfy_subtree, * verify that the dup tree type is correct--i.e., it's a recno * if DUPSORT is not set and a btree if it is. * * PUBLIC: int __db_vrfy_duptype * PUBLIC: __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t)); */int__db_vrfy_duptype(dbp, vdp, pgno, flags) DB *dbp; VRFY_DBINFO *vdp; db_pgno_t pgno; u_int32_t flags;{ DB_ENV *dbenv; VRFY_PAGEINFO *pip; int ret, isbad; dbenv = dbp->dbenv; isbad = 0; if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) return (ret);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -