📄 bt_verify.c
字号:
if ((ret = __bam_cmp(dbp, &dbt, h, 0, func, &cmp)) == 0) { if (cmp > 0) { EPRINT((dbp->dbenv, "Page %lu: first item on page sorted greater than parent entry", (u_long)PGNO(h))); ret = DB_VERIFY_BAD; } } else EPRINT((dbp->dbenv, "Page %lu: first item on page had comparison error", (u_long)PGNO(h))); if (dbt.data != lp->data) __os_ufree(dbp->dbenv, dbt.data); if (ret != 0) return (ret); } if (rp != NULL) { if (rp->type == B_KEYDATA) { dbt.data = rp->data; dbt.size = rp->len; } else if (rp->type == B_OVERFLOW) { bo = (BOVERFLOW *)rp->data; if ((ret = __db_goff(dbp, &dbt, bo->tlen, bo->pgno, NULL, NULL)) != 0) return (ret); } else { DB_ASSERT(0); EPRINT((dbp->dbenv, "Page %lu: unknown type for internal record", (u_long)PGNO(h))); return (EINVAL); } /* On error, fall through, free if neeeded, and return. */ if ((ret = __bam_cmp(dbp, &dbt, h, last, func, &cmp)) == 0) { if (cmp < 0) { EPRINT((dbp->dbenv, "Page %lu: last item on page sorted greater than parent entry", (u_long)PGNO(h))); ret = DB_VERIFY_BAD; } } else EPRINT((dbp->dbenv, "Page %lu: last item on page had comparison error", (u_long)PGNO(h))); if (dbt.data != rp->data) __os_ufree(dbp->dbenv, dbt.data); } return (ret);}/* * __bam_salvage -- * Safely dump out anything that looks like a key on an alleged * btree leaf page. * * PUBLIC: int __bam_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, * PUBLIC: PAGE *, void *, int (*)(void *, const void *), DBT *, * PUBLIC: u_int32_t)); */int__bam_salvage(dbp, vdp, pgno, pgtype, h, handle, callback, key, flags) DB *dbp; VRFY_DBINFO *vdp; db_pgno_t pgno; u_int32_t pgtype; PAGE *h; void *handle; int (*callback) __P((void *, const void *)); DBT *key; u_int32_t flags;{ DBT dbt, unkdbt; BKEYDATA *bk; BOVERFLOW *bo; db_indx_t i, beg, end, *inp; u_int32_t himark; u_int8_t *pgmap; void *ovflbuf; int t_ret, ret, err_ret; /* Shut up lint. */ COMPQUIET(end, 0); ovflbuf = pgmap = NULL; err_ret = ret = 0; inp = P_INP(dbp, h); memset(&dbt, 0, sizeof(DBT)); dbt.flags = DB_DBT_REALLOC; memset(&unkdbt, 0, sizeof(DBT)); unkdbt.size = (u_int32_t)(strlen("UNKNOWN") + 1); unkdbt.data = "UNKNOWN"; /* * Allocate a buffer for overflow items. Start at one page; * __db_safe_goff will realloc as needed. */ if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, &ovflbuf)) != 0) return (ret); if (LF_ISSET(DB_AGGRESSIVE)) { if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, &pgmap)) != 0) goto err; memset(pgmap, 0, dbp->pgsize); } /* * Loop through the inp array, spitting out key/data pairs. * * If we're salvaging normally, loop from 0 through NUM_ENT(h). * If we're being aggressive, loop until we hit the end of the page-- * NUM_ENT() may be bogus. */ himark = dbp->pgsize; for (i = 0;; i += O_INDX) { /* If we're not aggressive, break when we hit NUM_ENT(h). */ if (!LF_ISSET(DB_AGGRESSIVE) && i >= NUM_ENT(h)) break; /* Verify the current item. */ ret = __db_vrfy_inpitem(dbp, h, pgno, i, 1, flags, &himark, NULL); /* If this returned a fatality, it's time to break. */ if (ret == DB_VERIFY_FATAL) { /* * Don't return DB_VERIFY_FATAL; it's private * and means only that we can't go on with this * page, not with the whole database. It's * not even an error if we've run into it * after NUM_ENT(h). */ ret = (i < NUM_ENT(h)) ? DB_VERIFY_BAD : 0; break; } /* * If this returned 0, it's safe to print or (carefully) * try to fetch. */ if (ret == 0) { /* * We only want to print deleted items if * DB_AGGRESSIVE is set. */ bk = GET_BKEYDATA(dbp, h, i); if (!LF_ISSET(DB_AGGRESSIVE) && B_DISSET(bk->type)) continue; /* * We're going to go try to print the next item. If * key is non-NULL, we're a dup page, so we've got to * print the key first, unless SA_SKIPFIRSTKEY is set * and we're on the first entry. */ if (key != NULL && (i != 0 || !LF_ISSET(SA_SKIPFIRSTKEY))) if ((ret = __db_prdbt(key, 0, " ", handle, callback, 0, vdp)) != 0) err_ret = ret; beg = inp[i]; switch (B_TYPE(bk->type)) { case B_DUPLICATE: end = beg + BOVERFLOW_SIZE - 1; /* * If we're not on a normal btree leaf page, * there shouldn't be off-page * dup sets. Something's confused; just * drop it, and the code to pick up unlinked * offpage dup sets will print it out * with key "UNKNOWN" later. */ if (pgtype != P_LBTREE) break; bo = (BOVERFLOW *)bk; /* * If the page number is unreasonable, or * if this is supposed to be a key item, * just spit out "UNKNOWN"--the best we * can do is run into the data items in the * unlinked offpage dup pass. */ if (!IS_VALID_PGNO(bo->pgno) || (i % P_INDX == 0)) { /* Not much to do on failure. */ if ((ret = __db_prdbt(&unkdbt, 0, " ", handle, callback, 0, vdp)) != 0) err_ret = ret; break; } if ((ret = __db_salvage_duptree(dbp, vdp, bo->pgno, &dbt, handle, callback, flags | SA_SKIPFIRSTKEY)) != 0) err_ret = ret; break; case B_KEYDATA: end = ALIGN(beg + bk->len, sizeof(u_int32_t)) - 1; dbt.data = bk->data; dbt.size = bk->len; if ((ret = __db_prdbt(&dbt, 0, " ", handle, callback, 0, vdp)) != 0) err_ret = ret; break; case B_OVERFLOW: end = beg + BOVERFLOW_SIZE - 1; bo = (BOVERFLOW *)bk; if ((ret = __db_safe_goff(dbp, vdp, bo->pgno, &dbt, &ovflbuf, flags)) != 0) { err_ret = ret; /* We care about err_ret more. */ (void)__db_prdbt(&unkdbt, 0, " ", handle, callback, 0, vdp); break; } if ((ret = __db_prdbt(&dbt, 0, " ", handle, callback, 0, vdp)) != 0) err_ret = ret; break; default: /* * We should never get here; __db_vrfy_inpitem * should not be returning 0 if bk->type * is unrecognizable. */ DB_ASSERT(0); return (EINVAL); } /* * If we're being aggressive, mark the beginning * and end of the item; we'll come back and print * whatever "junk" is in the gaps in case we had * any bogus inp elements and thereby missed stuff. */ if (LF_ISSET(DB_AGGRESSIVE)) { pgmap[beg] = ITEM_BEGIN; pgmap[end] = ITEM_END; } } } /* * If i is odd and this is a btree leaf, we've printed out a key but not * a datum; fix this imbalance by printing an "UNKNOWN". */ if (pgtype == P_LBTREE && (i % P_INDX == 1) && ((ret = __db_prdbt(&unkdbt, 0, " ", handle, callback, 0, vdp)) != 0)) err_ret = ret;err: if (pgmap != NULL) __os_free(dbp->dbenv, pgmap); __os_free(dbp->dbenv, ovflbuf); /* Mark this page as done. */ if ((t_ret = __db_salvage_markdone(vdp, pgno)) != 0) return (t_ret); return ((err_ret != 0) ? err_ret : ret);}/* * __bam_salvage_walkdupint -- * Walk a known-good btree or recno internal page which is part of * a dup tree, calling __db_salvage_duptree on each child page. * * PUBLIC: int __bam_salvage_walkdupint __P((DB *, VRFY_DBINFO *, PAGE *, * PUBLIC: DBT *, void *, int (*)(void *, const void *), u_int32_t)); */int__bam_salvage_walkdupint(dbp, vdp, h, key, handle, callback, flags) DB *dbp; VRFY_DBINFO *vdp; PAGE *h; DBT *key; void *handle; int (*callback) __P((void *, const void *)); u_int32_t flags;{ RINTERNAL *ri; BINTERNAL *bi; int ret, t_ret; db_indx_t i; ret = 0; for (i = 0; i < NUM_ENT(h); i++) { switch (TYPE(h)) { case P_IBTREE: bi = GET_BINTERNAL(dbp, h, i); if ((t_ret = __db_salvage_duptree(dbp, vdp, bi->pgno, key, handle, callback, flags)) != 0) ret = t_ret; break; case P_IRECNO: ri = GET_RINTERNAL(dbp, h, i); if ((t_ret = __db_salvage_duptree(dbp, vdp, ri->pgno, key, handle, callback, flags)) != 0) ret = t_ret; break; default: __db_err(dbp->dbenv, "__bam_salvage_walkdupint called on non-int. page"); DB_ASSERT(0); return (EINVAL); } /* Pass SA_SKIPFIRSTKEY, if set, on to the 0th child only. */ flags &= ~LF_ISSET(SA_SKIPFIRSTKEY); } return (ret);}/* * __bam_meta2pgset -- * Given a known-good meta page, return in pgsetp a 0-terminated list of * db_pgno_t's corresponding to the pages in the btree. * * We do this by a somewhat sleazy method, to avoid having to traverse the * btree structure neatly: we walk down the left side to the very * first leaf page, then we mark all the pages in the chain of * NEXT_PGNOs (being wary of cycles and invalid ones), then we * consolidate our scratch array into a nice list, and return. This * avoids the memory management hassles of recursion and the * trouble of walking internal pages--they just don't matter, except * for the left branch. * * PUBLIC: int __bam_meta2pgset __P((DB *, VRFY_DBINFO *, BTMETA *, * PUBLIC: u_int32_t, DB *)); */int__bam_meta2pgset(dbp, vdp, btmeta, flags, pgset) DB *dbp; VRFY_DBINFO *vdp; BTMETA *btmeta; u_int32_t flags; DB *pgset;{ BINTERNAL *bi; DB_MPOOLFILE *mpf; PAGE *h; RINTERNAL *ri; db_pgno_t current, p; int err_ret, ret; mpf = dbp->mpf; h = NULL; ret = err_ret = 0; DB_ASSERT(pgset != NULL); for (current = btmeta->root;;) { if (!IS_VALID_PGNO(current) || current == PGNO(btmeta)) { err_ret = DB_VERIFY_BAD; goto err; } if ((ret = mpf->get(mpf, ¤t, 0, &h)) != 0) { err_ret = ret; goto err; } switch (TYPE(h)) { case P_IBTREE: case P_IRECNO: if ((ret = __bam_vrfy(dbp, vdp, h, current, flags | DB_NOORDERCHK)) != 0) { err_ret = ret; goto err; } if (TYPE(h) == P_IBTREE) { bi = GET_BINTERNAL(dbp, h, 0); current = bi->pgno; } else { /* P_IRECNO */ ri = GET_RINTERNAL(dbp, h, 0); current = ri->pgno; } break; case P_LBTREE: case P_LRECNO: goto traverse; default: err_ret = DB_VERIFY_BAD; goto err; } if ((ret = mpf->put(mpf, h, 0)) != 0) err_ret = ret; h = NULL; } /* * At this point, current is the pgno of leaf page h, the 0th in the * tree we're concerned with. */traverse: while (IS_VALID_PGNO(current) && current != PGNO_INVALID) { if (h == NULL && (ret = mpf->get(mpf, ¤t, 0, &h)) != 0) { err_ret = ret; break; } if ((ret = __db_vrfy_pgset_get(pgset, current, (int *)&p)) != 0) goto err; if (p != 0) { /* * We've found a cycle. Return success anyway-- * our caller may as well use however much of * the pgset we've come up with. */ break; } if ((ret = __db_vrfy_pgset_inc(pgset, current)) != 0) goto err; current = NEXT_PGNO(h); if ((ret = mpf->put(mpf, h, 0)) != 0) err_ret = ret; h = NULL; }err: if (h != NULL) (void)mpf->put(mpf, h, 0); return (ret == 0 ? err_ret : ret);}/* * __bam_safe_getdata -- * * Utility function for __bam_vrfy_itemorder. Safely gets the datum at * index i, page h, and sticks it in DBT dbt. If ovflok is 1 and i's an * overflow item, we do a safe_goff to get the item and signal that we need * to free dbt->data; if ovflok is 0, we leaves the DBT zeroed. */static int__bam_safe_getdata(dbp, h, i, ovflok, dbt, freedbtp) DB *dbp; PAGE *h; u_int32_t i; int ovflok; DBT *dbt; int *freedbtp;{ BKEYDATA *bk; BOVERFLOW *bo; memset(dbt, 0, sizeof(DBT)); *freedbtp = 0; bk = GET_BKEYDATA(dbp, h, i); if (B_TYPE(bk->type) == B_OVERFLOW) { if (!ovflok) return (0); bo = (BOVERFLOW *)bk; F_SET(dbt, DB_DBT_MALLOC); *freedbtp = 1; return (__db_goff(dbp, dbt, bo->tlen, bo->pgno, NULL, NULL)); } else { dbt->data = bk->data; dbt->size = bk->len; } return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -