📄 db_vrfy.c
字号:
else { isbad = 1; EPRINT((dbenv, "Page %lu: bad magic number %lu", (u_long)PGNO_BASE_MD, (u_long)meta->magic)); } } /* * 16-19: Version. Must be current; for now, we * don't support verification of old versions. */ if (swapped) M_32_SWAP(meta->version); if ((dbp->type == DB_BTREE && (meta->version > DB_BTREEVERSION || meta->version < DB_BTREEOLDVER)) || (dbp->type == DB_HASH && (meta->version > DB_HASHVERSION || meta->version < DB_HASHOLDVER)) || (dbp->type == DB_QUEUE && (meta->version > DB_QAMVERSION || meta->version < DB_QAMOLDVER))) { isbad = 1; EPRINT((dbenv, "Page %lu: unsupported DB version %lu; extraneous errors may result", (u_long)PGNO_BASE_MD, (u_long)meta->version)); } /* * 20-23: Pagesize. Must be power of two, * greater than 512, and less than 64K. */ if (swapped) M_32_SWAP(meta->pagesize); if (IS_VALID_PAGESIZE(meta->pagesize)) dbp->pgsize = meta->pagesize; else { isbad = 1; EPRINT((dbenv, "Page %lu: bad page size %lu", (u_long)PGNO_BASE_MD, (u_long)meta->pagesize)); /* * Now try to settle on a pagesize to use. * If the user-supplied one is reasonable, * use it; else, guess. */ if (!IS_VALID_PAGESIZE(dbp->pgsize)) dbp->pgsize = __db_guesspgsize(dbenv, fhp); } /* * 25: Page type. Must be correct for dbp->type, * which is by now set as well as it can be. */ /* Needs no swapping--only one byte! */ if ((dbp->type == DB_BTREE && meta->type != P_BTREEMETA) || (dbp->type == DB_HASH && meta->type != P_HASHMETA) || (dbp->type == DB_QUEUE && meta->type != P_QAMMETA)) { isbad = 1; EPRINT((dbenv, "Page %lu: bad page type %lu", (u_long)PGNO_BASE_MD, (u_long)meta->type)); } /* * 28-31: Free list page number. * We'll verify its sensibility when we do inter-page * verification later; for now, just store it. */ if (swapped) M_32_SWAP(meta->free); freelist = meta->free; /* * Initialize vdp->pages to fit a single pageinfo structure for * this one page. We'll realloc later when we know how many * pages there are. */ if ((ret = __db_vrfy_getpageinfo(vdp, PGNO_BASE_MD, &pip)) != 0) return (ret); pip->pgno = PGNO_BASE_MD; pip->type = meta->type; /* * Signal that we still have to check the info specific to * a given type of meta page. */ F_SET(pip, VRFY_INCOMPLETE); pip->free = freelist; if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0) return (ret); /* Set up the dbp's fileid. We don't use the regular open path. */ memcpy(dbp->fileid, meta->uid, DB_FILE_ID_LEN); if (swapped == 1) F_SET(dbp, DB_AM_SWAP); return (isbad ? DB_VERIFY_BAD : 0);}/* * __db_vrfy_walkpages -- * Main loop of the verifier/salvager. Walks through, * page by page, and verifies all pages and/or prints all data pages. */static int__db_vrfy_walkpages(dbp, vdp, handle, callback, flags) DB *dbp; VRFY_DBINFO *vdp; void *handle; int (*callback) __P((void *, const void *)); u_int32_t flags;{ DB_ENV *dbenv; DB_MPOOLFILE *mpf; PAGE *h; db_pgno_t i; int ret, t_ret, isbad; dbenv = dbp->dbenv; mpf = dbp->mpf; ret = isbad = t_ret = 0; if ((ret = __db_fchk(dbenv, "__db_vrfy_walkpages", flags, OKFLAGS)) != 0) return (ret); for (i = 0; i <= vdp->last_pgno; i++) { /* * If DB_SALVAGE is set, we inspect our database of * completed pages, and skip any we've already printed in * the subdb pass. */ if (LF_ISSET(DB_SALVAGE) && (__db_salvage_isdone(vdp, i) != 0)) continue; /* * If an individual page get fails, keep going if and only * if we're salvaging. */ if ((t_ret = mpf->get(mpf, &i, 0, &h)) != 0) { if (ret == 0) ret = t_ret; if (LF_ISSET(DB_SALVAGE)) continue; else return (ret); } if (LF_ISSET(DB_SALVAGE)) { /* * We pretty much don't want to quit unless a * bomb hits. May as well return that something * was screwy, however. */ if ((t_ret = __db_salvage(dbp, vdp, i, h, handle, callback, flags)) != 0) { if (ret == 0) ret = t_ret; isbad = 1; } } else { /* * If we are not salvaging, and we get any error * other than DB_VERIFY_BAD, return immediately; * it may not be safe to proceed. If we get * DB_VERIFY_BAD, keep going; listing more errors * may make it easier to diagnose problems and * determine the magnitude of the corruption. */ /* * Verify info common to all page * types. */ if (i != PGNO_BASE_MD) { ret = __db_vrfy_common(dbp, vdp, h, i, flags); if (ret == DB_VERIFY_BAD) isbad = 1; else if (ret != 0) goto err; } switch (TYPE(h)) { case P_INVALID: ret = __db_vrfy_invalid(dbp, vdp, h, i, flags); break; case __P_DUPLICATE: isbad = 1; EPRINT((dbenv, "Page %lu: old-style duplicate page", (u_long)i)); break; case P_HASH: ret = __ham_vrfy(dbp, vdp, h, i, flags); break; case P_IBTREE: case P_IRECNO: case P_LBTREE: case P_LDUP: ret = __bam_vrfy(dbp, vdp, h, i, flags); break; case P_LRECNO: ret = __ram_vrfy_leaf(dbp, vdp, h, i, flags); break; case P_OVERFLOW: ret = __db_vrfy_overflow(dbp, vdp, h, i, flags); break; case P_HASHMETA: ret = __ham_vrfy_meta(dbp, vdp, (HMETA *)h, i, flags); break; case P_BTREEMETA: ret = __bam_vrfy_meta(dbp, vdp, (BTMETA *)h, i, flags); break; case P_QAMMETA: ret = __qam_vrfy_meta(dbp, vdp, (QMETA *)h, i, flags); break; case P_QAMDATA: ret = __qam_vrfy_data(dbp, vdp, (QPAGE *)h, i, flags); break; default: EPRINT((dbenv, "Page %lu: unknown page type %lu", (u_long)i, (u_long)TYPE(h))); isbad = 1; break; } /* * Set up error return. */ if (ret == DB_VERIFY_BAD) isbad = 1; else if (ret != 0) goto err; /* * Provide feedback to the application about our * progress. The range 0-50% comes from the fact * that this is the first of two passes through the * database (front-to-back, then top-to-bottom). */ if (dbp->db_feedback != NULL) dbp->db_feedback(dbp, DB_VERIFY, (i + 1) * 50 / (vdp->last_pgno + 1)); } /* * Just as with the page get, bail if and only if we're * not salvaging. */ if ((t_ret = mpf->put(mpf, h, 0)) != 0) { if (ret == 0) ret = t_ret; if (!LF_ISSET(DB_SALVAGE)) return (ret); } } if (0) {err: if ((t_ret = mpf->put(mpf, h, 0)) != 0) return (ret == 0 ? t_ret : ret); } return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret);}/* * __db_vrfy_structure-- * After a beginning-to-end walk through the database has been * completed, put together the information that has been collected * to verify the overall database structure. * * Should only be called if we want to do a database verification, * i.e. if DB_SALVAGE is not set. */static int__db_vrfy_structure(dbp, vdp, dbname, meta_pgno, flags) DB *dbp; VRFY_DBINFO *vdp; const char *dbname; db_pgno_t meta_pgno; u_int32_t flags;{ DB *pgset; DB_ENV *dbenv; VRFY_PAGEINFO *pip; db_pgno_t i; int ret, isbad, hassubs, p; isbad = 0; pip = NULL; dbenv = dbp->dbenv; pgset = vdp->pgset; if ((ret = __db_fchk(dbenv, "DB->verify", flags, OKFLAGS)) != 0) return (ret); if (LF_ISSET(DB_SALVAGE)) { __db_err(dbenv, "__db_vrfy_structure called with DB_SALVAGE"); return (EINVAL); } /* * Providing feedback here is tricky; in most situations, * we fetch each page one more time, but we do so in a top-down * order that depends on the access method. Worse, we do this * recursively in btree, such that on any call where we're traversing * a subtree we don't know where that subtree is in the whole database; * worse still, any given database may be one of several subdbs. * * The solution is to decrement a counter vdp->pgs_remaining each time * we verify (and call feedback on) a page. We may over- or * under-count, but the structure feedback function will ensure that we * never give a percentage under 50 or over 100. (The first pass * covered the range 0-50%.) */ if (dbp->db_feedback != NULL) vdp->pgs_remaining = vdp->last_pgno + 1; /* * Call the appropriate function to downwards-traverse the db type. */ switch(dbp->type) { case DB_BTREE: case DB_RECNO: if ((ret = __bam_vrfy_structure(dbp, vdp, 0, flags)) != 0) { if (ret == DB_VERIFY_BAD) isbad = 1; else goto err; } /* * If we have subdatabases and we know that the database is, * thus far, sound, it's safe to walk the tree of subdatabases. * Do so, and verify the structure of the databases within. */ if ((ret = __db_vrfy_getpageinfo(vdp, 0, &pip)) != 0) goto err; hassubs = F_ISSET(pip, VRFY_HAS_SUBDBS) ? 1 : 0; if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0) goto err; if (isbad == 0 && hassubs) if ((ret = __db_vrfy_subdbs(dbp, vdp, dbname, flags)) != 0) { if (ret == DB_VERIFY_BAD) isbad = 1; else goto err; } break; case DB_HASH: if ((ret = __ham_vrfy_structure(dbp, vdp, 0, flags)) != 0) { if (ret == DB_VERIFY_BAD) isbad = 1; else goto err; } break; case DB_QUEUE: if ((ret = __qam_vrfy_structure(dbp, vdp, flags)) != 0) { if (ret == DB_VERIFY_BAD) isbad = 1; } /* * Queue pages may be unreferenced and totally zeroed, if * they're empty; queue doesn't have much structure, so * this is unlikely to be wrong in any troublesome sense. * Skip to "err". */ goto err; /* NOTREACHED */ default: /* This should only happen if the verifier is somehow broken. */ DB_ASSERT(0); ret = EINVAL; goto err; /* NOTREACHED */ } /* Walk free list. */ if ((ret = __db_vrfy_freelist(dbp, vdp, meta_pgno, flags)) == DB_VERIFY_BAD) isbad = 1; /* * If structure checks up until now have failed, it's likely that * checking what pages have been missed will result in oodles of * extraneous error messages being EPRINTed. Skip to the end * if this is the case; we're going to be printing at least one * error anyway, and probably all the more salient ones. */ if (ret != 0 || isbad == 1) goto err; /* * Make sure no page has been missed and that no page is still marked * "all zeroes" (only certain hash pages can be, and they're unmarked * in __ham_vrfy_structure). */ for (i = 0; i < vdp->last_pgno + 1; i++) { if ((ret = __db_vrfy_getpageinfo(vdp, i, &pip)) != 0) goto err; if ((ret = __db_vrfy_pgset_get(pgset, i, &p)) != 0) goto err; if (p == 0) { EPRINT((dbenv, "Page %lu: unreferenced page", (u_long)i)); isbad = 1; } if (F_ISSET(pip, VRFY_IS_ALLZEROES)) { EPRINT((dbenv, "Page %lu: totally zeroed page", (u_long)i)); isbad = 1; } if ((ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0) goto err; pip = NULL; }err: if (pip != NULL) (void)__db_vrfy_putpageinfo(dbenv, vdp, pip); return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret);}/* * __db_is_valid_pagetype */static int__db_is_valid_pagetype(type) u_int32_t type;{ switch (type) { case P_INVALID: /* Order matches ordinal value. */ case P_HASH: case P_IBTREE: case P_IRECNO: case P_LBTREE: case P_LRECNO: case P_OVERFLOW: case P_HASHMETA: case P_BTREEMETA: case P_QAMMETA: case P_QAMDATA: case P_LDUP: return (1); } return (0);}/* * __db_is_valid_magicno */static int__db_is_valid_magicno(magic, typep) u_int32_t magic; DBTYPE *typep;{ switch (magic) { case DB_BTREEMAGIC: *typep = DB_BTREE; return (1); case DB_HASHMAGIC: *typep = DB_HASH; return (1); case DB_QAMMAGIC: *typep = DB_QUEUE; return (1); } *typep = DB_UNKNOWN; return (0);}/* * __db_vrfy_common -- * Verify info common to all page types. */static int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -