hash_verify.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:27k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1999-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  *
  7.  * $Id: hash_verify.c,v 1.53 2002/08/06 05:35:02 bostic Exp $
  8.  */
  9. #include "db_config.h"
  10. #ifndef lint
  11. static const char revid[] = "$Id: hash_verify.c,v 1.53 2002/08/06 05:35:02 bostic Exp $";
  12. #endif /* not lint */
  13. #ifndef NO_SYSTEM_INCLUDES
  14. #include <sys/types.h>
  15. #include <string.h>
  16. #endif
  17. #include "db_int.h"
  18. #include "dbinc/db_page.h"
  19. #include "dbinc/db_verify.h"
  20. #include "dbinc/btree.h"
  21. #include "dbinc/hash.h"
  22. static int __ham_dups_unsorted __P((DB *, u_int8_t *, u_int32_t));
  23. static int __ham_vrfy_bucket __P((DB *, VRFY_DBINFO *, HMETA *, u_int32_t,
  24.     u_int32_t));
  25. static int __ham_vrfy_item __P((DB *,
  26.     VRFY_DBINFO *, db_pgno_t, PAGE *, u_int32_t, u_int32_t));
  27. /*
  28.  * __ham_vrfy_meta --
  29.  * Verify the hash-specific part of a metadata page.
  30.  *
  31.  * Note that unlike btree, we don't save things off, because we
  32.  * will need most everything again to verify each page and the
  33.  * amount of state here is significant.
  34.  *
  35.  * PUBLIC: int __ham_vrfy_meta __P((DB *, VRFY_DBINFO *, HMETA *,
  36.  * PUBLIC:     db_pgno_t, u_int32_t));
  37.  */
  38. int
  39. __ham_vrfy_meta(dbp, vdp, m, pgno, flags)
  40. DB *dbp;
  41. VRFY_DBINFO *vdp;
  42. HMETA *m;
  43. db_pgno_t pgno;
  44. u_int32_t flags;
  45. {
  46. HASH *hashp;
  47. VRFY_PAGEINFO *pip;
  48. int i, ret, t_ret, isbad;
  49. u_int32_t pwr, mbucket;
  50. u_int32_t (*hfunc) __P((DB *, const void *, u_int32_t));
  51. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  52. return (ret);
  53. isbad = 0;
  54. hashp = dbp->h_internal;
  55. if (hashp != NULL && hashp->h_hash != NULL)
  56. hfunc = hashp->h_hash;
  57. else
  58. hfunc = __ham_func5;
  59. /*
  60.  * If we haven't already checked the common fields in pagezero,
  61.  * check them.
  62.  */
  63. if (!F_ISSET(pip, VRFY_INCOMPLETE) &&
  64.     (ret = __db_vrfy_meta(dbp, vdp, &m->dbmeta, pgno, flags)) != 0) {
  65. if (ret == DB_VERIFY_BAD)
  66. isbad = 1;
  67. else
  68. goto err;
  69. }
  70. /* h_charkey */
  71. if (!LF_ISSET(DB_NOORDERCHK))
  72. if (m->h_charkey != hfunc(dbp, CHARKEY, sizeof(CHARKEY))) {
  73. EPRINT((dbp->dbenv,
  74. "Page %lu: database has different custom hash function; reverify with DB_NOORDERCHK set",
  75.     (u_long)pgno));
  76. /*
  77.  * Return immediately;  this is probably a sign
  78.  * of user error rather than database corruption, so
  79.  * we want to avoid extraneous errors.
  80.  */
  81. isbad = 1;
  82. goto err;
  83. }
  84. /* max_bucket must be less than the last pgno. */
  85. if (m->max_bucket > vdp->last_pgno) {
  86. EPRINT((dbp->dbenv,
  87.     "Page %lu: Impossible max_bucket %lu on meta page",
  88.     (u_long)pgno, (u_long)m->max_bucket));
  89. /*
  90.  * Most other fields depend somehow on max_bucket, so
  91.  * we just return--there will be lots of extraneous
  92.  * errors.
  93.  */
  94. isbad = 1;
  95. goto err;
  96. }
  97. /*
  98.  * max_bucket, high_mask and low_mask: high_mask must be one
  99.  * less than the next power of two above max_bucket, and
  100.  * low_mask must be one less than the power of two below it.
  101.  *
  102.  *
  103.  */
  104. pwr = (m->max_bucket == 0) ? 1 : 1 << __db_log2(m->max_bucket + 1);
  105. if (m->high_mask != pwr - 1) {
  106. EPRINT((dbp->dbenv,
  107.     "Page %lu: incorrect high_mask %lu, should be %lu",
  108.     (u_long)pgno, (u_long)m->high_mask, (u_long)pwr - 1));
  109. isbad = 1;
  110. }
  111. pwr >>= 1;
  112. if (m->low_mask != pwr - 1) {
  113. EPRINT((dbp->dbenv,
  114.     "Page %lu: incorrect low_mask %lu, should be %lu",
  115.     (u_long)pgno, (u_long)m->low_mask, (u_long)pwr - 1));
  116. isbad = 1;
  117. }
  118. /* ffactor: no check possible. */
  119. pip->h_ffactor = m->ffactor;
  120. /*
  121.  * nelem: just make sure it's not astronomical for now. This is the
  122.  * same check that hash_upgrade does, since there was a bug in 2.X
  123.  * which could make nelem go "negative".
  124.  */
  125. if (m->nelem > 0x80000000) {
  126. EPRINT((dbp->dbenv,
  127.     "Page %lu: suspiciously high nelem of %lu",
  128.     (u_long)pgno, (u_long)m->nelem));
  129. isbad = 1;
  130. pip->h_nelem = 0;
  131. } else
  132. pip->h_nelem = m->nelem;
  133. /* flags */
  134. if (F_ISSET(&m->dbmeta, DB_HASH_DUP))
  135. F_SET(pip, VRFY_HAS_DUPS);
  136. if (F_ISSET(&m->dbmeta, DB_HASH_DUPSORT))
  137. F_SET(pip, VRFY_HAS_DUPSORT);
  138. /* XXX: Why is the DB_HASH_SUBDB flag necessary? */
  139. /* spares array */
  140. for (i = 0; m->spares[i] != 0 && i < NCACHED; i++) {
  141. /*
  142.  * We set mbucket to the maximum bucket that would use a given
  143.  * spares entry;  we want to ensure that it's always less
  144.  * than last_pgno.
  145.  */
  146. mbucket = (1 << i) - 1;
  147. if (BS_TO_PAGE(mbucket, m->spares) > vdp->last_pgno) {
  148. EPRINT((dbp->dbenv,
  149.     "Page %lu: spares array entry %d is invalid",
  150.     (u_long)pgno, i));
  151. isbad = 1;
  152. }
  153. }
  154. err: if ((t_ret =
  155.     __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 && ret == 0)
  156. ret = t_ret;
  157. return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
  158. }
  159. /*
  160.  * __ham_vrfy --
  161.  * Verify hash page.
  162.  *
  163.  * PUBLIC: int __ham_vrfy __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t,
  164.  * PUBLIC:     u_int32_t));
  165.  */
  166. int
  167. __ham_vrfy(dbp, vdp, h, pgno, flags)
  168. DB *dbp;
  169. VRFY_DBINFO *vdp;
  170. PAGE *h;
  171. db_pgno_t pgno;
  172. u_int32_t flags;
  173. {
  174. VRFY_PAGEINFO *pip;
  175. u_int32_t ent, himark, inpend;
  176. db_indx_t *inp;
  177. int isbad, ret, t_ret;
  178. isbad = 0;
  179. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  180. return (ret);
  181. /* Sanity check our flags and page type. */
  182. if ((ret = __db_fchk(dbp->dbenv, "__ham_vrfy",
  183.     flags, DB_AGGRESSIVE | DB_NOORDERCHK | DB_SALVAGE)) != 0)
  184. goto err;
  185. if (TYPE(h) != P_HASH) {
  186. TYPE_ERR_PRINT(dbp->dbenv, "__ham_vrfy", pgno, TYPE(h));
  187. DB_ASSERT(0);
  188. ret = EINVAL;
  189. goto err;
  190. }
  191. /* Verify and save off fields common to all PAGEs. */
  192. if ((ret = __db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) {
  193. if (ret == DB_VERIFY_BAD)
  194. isbad = 1;
  195. else
  196. goto err;
  197. }
  198. /*
  199.  * Verify inp[].  Each offset from 0 to NUM_ENT(h) must be lower
  200.  * than the previous one, higher than the current end of the inp array,
  201.  * and lower than the page size.
  202.  *
  203.  * In any case, we return immediately if things are bad, as it would
  204.  * be unsafe to proceed.
  205.  */
  206. inp = P_INP(dbp, h);
  207. for (ent = 0, himark = dbp->pgsize,
  208.     inpend = (u_int32_t)((u_int8_t *)inp - (u_int8_t *)h);
  209.     ent < NUM_ENT(h); ent++)
  210. if (inp[ent] >= himark) {
  211. EPRINT((dbp->dbenv,
  212.     "Page %lu: item %lu is out of order or nonsensical",
  213.     (u_long)pgno, (u_long)ent));
  214. isbad = 1;
  215. goto err;
  216. } else if (inpend >= himark) {
  217. EPRINT((dbp->dbenv,
  218.     "Page %lu: entries array collided with data",
  219.     (u_long)pgno));
  220. isbad = 1;
  221. goto err;
  222. } else {
  223. himark = inp[ent];
  224. inpend += sizeof(db_indx_t);
  225. if ((ret = __ham_vrfy_item(
  226.     dbp, vdp, pgno, h, ent, flags)) != 0)
  227. goto err;
  228. }
  229. err: if ((t_ret =
  230.     __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 && ret == 0)
  231. ret = t_ret;
  232. return (ret == 0 && isbad == 1 ? DB_VERIFY_BAD : ret);
  233. }
  234. /*
  235.  * __ham_vrfy_item --
  236.  * Given a hash page and an offset, sanity-check the item itself,
  237.  * and save off any overflow items or off-page dup children as necessary.
  238.  */
  239. static int
  240. __ham_vrfy_item(dbp, vdp, pgno, h, i, flags)
  241. DB *dbp;
  242. VRFY_DBINFO *vdp;
  243. db_pgno_t pgno;
  244. PAGE *h;
  245. u_int32_t i, flags;
  246. {
  247. HOFFPAGE hop;
  248. HOFFDUP hod;
  249. VRFY_CHILDINFO child;
  250. VRFY_PAGEINFO *pip;
  251. db_indx_t offset, len, dlen, elen;
  252. int ret, t_ret;
  253. u_int8_t *databuf;
  254. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  255. return (ret);
  256. switch (HPAGE_TYPE(dbp, h, i)) {
  257. case H_KEYDATA:
  258. /* Nothing to do here--everything but the type field is data */
  259. break;
  260. case H_DUPLICATE:
  261. /* Are we a datum or a key?  Better be the former. */
  262. if (i % 2 == 0) {
  263. EPRINT((dbp->dbenv,
  264.     "Page %lu: hash key stored as duplicate item %lu",
  265.     (u_long)pip->pgno, (u_long)i));
  266. }
  267. /*
  268.  * Dups are encoded as a series within a single HKEYDATA,
  269.  * in which each dup is surrounded by a copy of its length
  270.  * on either side (so that the series can be walked in either
  271.  * direction.  We loop through this series and make sure
  272.  * each dup is reasonable.
  273.  *
  274.  * Note that at this point, we've verified item i-1, so
  275.  * it's safe to use LEN_HKEYDATA (which looks at inp[i-1]).
  276.  */
  277. len = LEN_HKEYDATA(dbp, h, dbp->pgsize, i);
  278. databuf = HKEYDATA_DATA(P_ENTRY(dbp, h, i));
  279. for (offset = 0; offset < len; offset += DUP_SIZE(dlen)) {
  280. memcpy(&dlen, databuf + offset, sizeof(db_indx_t));
  281. /* Make sure the length is plausible. */
  282. if (offset + DUP_SIZE(dlen) > len) {
  283. EPRINT((dbp->dbenv,
  284.     "Page %lu: duplicate item %lu has bad length",
  285.     (u_long)pip->pgno, (u_long)i));
  286. ret = DB_VERIFY_BAD;
  287. goto err;
  288. }
  289. /*
  290.  * Make sure the second copy of the length is the
  291.  * same as the first.
  292.  */
  293. memcpy(&elen,
  294.     databuf + offset + dlen + sizeof(db_indx_t),
  295.     sizeof(db_indx_t));
  296. if (elen != dlen) {
  297. EPRINT((dbp->dbenv,
  298. "Page %lu: duplicate item %lu has two different lengths",
  299.     (u_long)pip->pgno, (u_long)i));
  300. ret = DB_VERIFY_BAD;
  301. goto err;
  302. }
  303. }
  304. F_SET(pip, VRFY_HAS_DUPS);
  305. if (!LF_ISSET(DB_NOORDERCHK) &&
  306.     __ham_dups_unsorted(dbp, databuf, len))
  307. F_SET(pip, VRFY_DUPS_UNSORTED);
  308. break;
  309. case H_OFFPAGE:
  310. /* Offpage item.  Make sure pgno is sane, save off. */
  311. memcpy(&hop, P_ENTRY(dbp, h, i), HOFFPAGE_SIZE);
  312. if (!IS_VALID_PGNO(hop.pgno) || hop.pgno == pip->pgno ||
  313.     hop.pgno == PGNO_INVALID) {
  314. EPRINT((dbp->dbenv,
  315.     "Page %lu: offpage item %lu has bad pgno %lu",
  316.     (u_long)pip->pgno, (u_long)i, (u_long)hop.pgno));
  317. ret = DB_VERIFY_BAD;
  318. goto err;
  319. }
  320. memset(&child, 0, sizeof(VRFY_CHILDINFO));
  321. child.pgno = hop.pgno;
  322. child.type = V_OVERFLOW;
  323. child.tlen = hop.tlen; /* This will get checked later. */
  324. if ((ret = __db_vrfy_childput(vdp, pip->pgno, &child)) != 0)
  325. goto err;
  326. break;
  327. case H_OFFDUP:
  328. /* Offpage duplicate item.  Same drill. */
  329. memcpy(&hod, P_ENTRY(dbp, h, i), HOFFDUP_SIZE);
  330. if (!IS_VALID_PGNO(hod.pgno) || hod.pgno == pip->pgno ||
  331.     hod.pgno == PGNO_INVALID) {
  332. EPRINT((dbp->dbenv,
  333.     "Page %lu: offpage item %lu has bad page number",
  334.     (u_long)pip->pgno, (u_long)i));
  335. ret = DB_VERIFY_BAD;
  336. goto err;
  337. }
  338. memset(&child, 0, sizeof(VRFY_CHILDINFO));
  339. child.pgno = hod.pgno;
  340. child.type = V_DUPLICATE;
  341. if ((ret = __db_vrfy_childput(vdp, pip->pgno, &child)) != 0)
  342. goto err;
  343. F_SET(pip, VRFY_HAS_DUPS);
  344. break;
  345. default:
  346. EPRINT((dbp->dbenv,
  347.     "Page %lu: item %i has bad type",
  348.     (u_long)pip->pgno, (u_long)i));
  349. ret = DB_VERIFY_BAD;
  350. break;
  351. }
  352. err: if ((t_ret =
  353.     __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 && ret == 0)
  354. ret = t_ret;
  355. return (ret);
  356. }
  357. /*
  358.  * __ham_vrfy_structure --
  359.  * Verify the structure of a hash database.
  360.  *
  361.  * PUBLIC: int __ham_vrfy_structure __P((DB *, VRFY_DBINFO *, db_pgno_t,
  362.  * PUBLIC:     u_int32_t));
  363.  */
  364. int
  365. __ham_vrfy_structure(dbp, vdp, meta_pgno, flags)
  366. DB *dbp;
  367. VRFY_DBINFO *vdp;
  368. db_pgno_t meta_pgno;
  369. u_int32_t flags;
  370. {
  371. DB *pgset;
  372. DB_MPOOLFILE *mpf;
  373. HMETA *m;
  374. PAGE *h;
  375. VRFY_PAGEINFO *pip;
  376. int isbad, p, ret, t_ret;
  377. db_pgno_t pgno;
  378. u_int32_t bucket, spares_entry;
  379. mpf = dbp->mpf;
  380. pgset = vdp->pgset;
  381. h = NULL;
  382. ret = isbad = 0;
  383. if ((ret = __db_vrfy_pgset_get(pgset, meta_pgno, &p)) != 0)
  384. return (ret);
  385. if (p != 0) {
  386. EPRINT((dbp->dbenv,
  387.     "Page %lu: Hash meta page referenced twice",
  388.     (u_long)meta_pgno));
  389. return (DB_VERIFY_BAD);
  390. }
  391. if ((ret = __db_vrfy_pgset_inc(pgset, meta_pgno)) != 0)
  392. return (ret);
  393. /* Get the meta page;  we'll need it frequently. */
  394. if ((ret = mpf->get(mpf, &meta_pgno, 0, &m)) != 0)
  395. return (ret);
  396. /* Loop through bucket by bucket. */
  397. for (bucket = 0; bucket <= m->max_bucket; bucket++)
  398. if ((ret =
  399.     __ham_vrfy_bucket(dbp, vdp, m, bucket, flags)) != 0) {
  400. if (ret == DB_VERIFY_BAD)
  401. isbad = 1;
  402. else
  403. goto err;
  404.     }
  405. /*
  406.  * There may be unused hash pages corresponding to buckets
  407.  * that have been allocated but not yet used.  These may be
  408.  * part of the current doubling above max_bucket, or they may
  409.  * correspond to buckets that were used in a transaction
  410.  * that then aborted.
  411.  *
  412.  * Loop through them, as far as the spares array defines them,
  413.  * and make sure they're all empty.
  414.  *
  415.  * Note that this should be safe, since we've already verified
  416.  * that the spares array is sane.
  417.  */
  418. for (bucket = m->max_bucket + 1; spares_entry = __db_log2(bucket + 1),
  419.     spares_entry < NCACHED && m->spares[spares_entry] != 0; bucket++) {
  420. pgno = BS_TO_PAGE(bucket, m->spares);
  421. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  422. goto err;
  423. /* It's okay if these pages are totally zeroed;  unmark it. */
  424. F_CLR(pip, VRFY_IS_ALLZEROES);
  425. /* It's also OK if this page is simply invalid. */
  426. if (pip->type == P_INVALID) {
  427. if ((ret = __db_vrfy_putpageinfo(dbp->dbenv,
  428.     vdp, pip)) != 0)
  429. goto err;
  430. continue;
  431. }
  432. if (pip->type != P_HASH) {
  433. EPRINT((dbp->dbenv,
  434.     "Page %lu: hash bucket %lu maps to non-hash page",
  435.     (u_long)pgno, (u_long)bucket));
  436. isbad = 1;
  437. } else if (pip->entries != 0) {
  438. EPRINT((dbp->dbenv,
  439.     "Page %lu: non-empty page in unused hash bucket %lu",
  440.     (u_long)pgno, (u_long)bucket));
  441. isbad = 1;
  442. } else {
  443. if ((ret = __db_vrfy_pgset_get(pgset, pgno, &p)) != 0)
  444. goto err;
  445. if (p != 0) {
  446. EPRINT((dbp->dbenv,
  447.     "Page %lu: above max_bucket referenced",
  448.     (u_long)pgno));
  449. isbad = 1;
  450. } else {
  451. if ((ret =
  452.     __db_vrfy_pgset_inc(pgset, pgno)) != 0)
  453. goto err;
  454. if ((ret = __db_vrfy_putpageinfo(dbp->dbenv,
  455.     vdp, pip)) != 0)
  456. goto err;
  457. continue;
  458. }
  459. }
  460. /* If we got here, it's an error. */
  461. (void)__db_vrfy_putpageinfo(dbp->dbenv, vdp, pip);
  462. goto err;
  463. }
  464. err: if ((t_ret = mpf->put(mpf, m, 0)) != 0)
  465. return (t_ret);
  466. if (h != NULL && (t_ret = mpf->put(mpf, h, 0)) != 0)
  467. return (t_ret);
  468. return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD: ret);
  469. }
  470. /*
  471.  * __ham_vrfy_bucket --
  472.  * Verify a given bucket.
  473.  */
  474. static int
  475. __ham_vrfy_bucket(dbp, vdp, m, bucket, flags)
  476. DB *dbp;
  477. VRFY_DBINFO *vdp;
  478. HMETA *m;
  479. u_int32_t bucket, flags;
  480. {
  481. HASH *hashp;
  482. VRFY_CHILDINFO *child;
  483. VRFY_PAGEINFO *mip, *pip;
  484. int ret, t_ret, isbad, p;
  485. db_pgno_t pgno, next_pgno;
  486. DBC *cc;
  487. u_int32_t (*hfunc) __P((DB *, const void *, u_int32_t));
  488. isbad = 0;
  489. pip = NULL;
  490. cc = NULL;
  491. hashp = dbp->h_internal;
  492. if (hashp != NULL && hashp->h_hash != NULL)
  493. hfunc = hashp->h_hash;
  494. else
  495. hfunc = __ham_func5;
  496. if ((ret = __db_vrfy_getpageinfo(vdp, PGNO(m), &mip)) != 0)
  497. return (ret);
  498. /* Calculate the first pgno for this bucket. */
  499. pgno = BS_TO_PAGE(bucket, m->spares);
  500. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  501. goto err;
  502. /* Make sure we got a plausible page number. */
  503. if (pgno > vdp->last_pgno || pip->type != P_HASH) {
  504. EPRINT((dbp->dbenv,
  505.     "Page %lu: impossible first page in bucket %lu",
  506.     (u_long)pgno, (u_long)bucket));
  507. /* Unsafe to continue. */
  508. isbad = 1;
  509. goto err;
  510. }
  511. if (pip->prev_pgno != PGNO_INVALID) {
  512. EPRINT((dbp->dbenv,
  513.     "Page %lu: first page in hash bucket %lu has a prev_pgno",
  514.     (u_long)pgno, (u_long)bucket));
  515. isbad = 1;
  516. }
  517. /*
  518.  * Set flags for dups and sorted dups.
  519.  */
  520. flags |= F_ISSET(mip, VRFY_HAS_DUPS) ? ST_DUPOK : 0;
  521. flags |= F_ISSET(mip, VRFY_HAS_DUPSORT) ? ST_DUPSORT : 0;
  522. /* Loop until we find a fatal bug, or until we run out of pages. */
  523. for (;;) {
  524. /* Provide feedback on our progress to the application. */
  525. if (!LF_ISSET(DB_SALVAGE))
  526. __db_vrfy_struct_feedback(dbp, vdp);
  527. if ((ret = __db_vrfy_pgset_get(vdp->pgset, pgno, &p)) != 0)
  528. goto err;
  529. if (p != 0) {
  530. EPRINT((dbp->dbenv,
  531.     "Page %lu: hash page referenced twice",
  532.     (u_long)pgno));
  533. isbad = 1;
  534. /* Unsafe to continue. */
  535. goto err;
  536. } else if ((ret = __db_vrfy_pgset_inc(vdp->pgset, pgno)) != 0)
  537. goto err;
  538. /*
  539.  * Hash pages that nothing has ever hashed to may never
  540.  * have actually come into existence, and may appear to be
  541.  * entirely zeroed.  This is acceptable, and since there's
  542.  * no real way for us to know whether this has actually
  543.  * occurred, we clear the "wholly zeroed" flag on every
  544.  * hash page.  A wholly zeroed page, by nature, will appear
  545.  * to have no flags set and zero entries, so should
  546.  * otherwise verify correctly.
  547.  */
  548. F_CLR(pip, VRFY_IS_ALLZEROES);
  549. /* If we have dups, our meta page had better know about it. */
  550. if (F_ISSET(pip, VRFY_HAS_DUPS) &&
  551.     !F_ISSET(mip, VRFY_HAS_DUPS)) {
  552. EPRINT((dbp->dbenv,
  553.     "Page %lu: duplicates present in non-duplicate database",
  554.     (u_long)pgno));
  555. isbad = 1;
  556. }
  557. /*
  558.  * If the database has sorted dups, this page had better
  559.  * not have unsorted ones.
  560.  */
  561. if (F_ISSET(mip, VRFY_HAS_DUPSORT) &&
  562.     F_ISSET(pip, VRFY_DUPS_UNSORTED)) {
  563. EPRINT((dbp->dbenv,
  564.     "Page %lu: unsorted dups in sorted-dup database",
  565.     (u_long)pgno));
  566. isbad = 1;
  567. }
  568. /* Walk overflow chains and offpage dup trees. */
  569. if ((ret = __db_vrfy_childcursor(vdp, &cc)) != 0)
  570. goto err;
  571. for (ret = __db_vrfy_ccset(cc, pip->pgno, &child); ret == 0;
  572.     ret = __db_vrfy_ccnext(cc, &child))
  573. if (child->type == V_OVERFLOW) {
  574. if ((ret = __db_vrfy_ovfl_structure(dbp, vdp,
  575.     child->pgno, child->tlen, flags)) != 0) {
  576. if (ret == DB_VERIFY_BAD)
  577. isbad = 1;
  578. else
  579. goto err;
  580. }
  581. } else if (child->type == V_DUPLICATE) {
  582. if ((ret = __db_vrfy_duptype(dbp,
  583.     vdp, child->pgno, flags)) != 0) {
  584. isbad = 1;
  585. continue;
  586. }
  587. if ((ret = __bam_vrfy_subtree(dbp, vdp,
  588.     child->pgno, NULL, NULL,
  589.     flags | ST_RECNUM | ST_DUPSET | ST_TOPLEVEL,
  590.     NULL, NULL, NULL)) != 0) {
  591. if (ret == DB_VERIFY_BAD)
  592. isbad = 1;
  593. else
  594. goto err;
  595. }
  596. }
  597. if ((ret = __db_vrfy_ccclose(cc)) != 0)
  598. goto err;
  599. cc = NULL;
  600. /* If it's safe to check that things hash properly, do so. */
  601. if (isbad == 0 && !LF_ISSET(DB_NOORDERCHK) &&
  602.     (ret = __ham_vrfy_hashing(dbp, pip->entries,
  603.     m, bucket, pgno, flags, hfunc)) != 0) {
  604. if (ret == DB_VERIFY_BAD)
  605. isbad = 1;
  606. else
  607. goto err;
  608. }
  609. next_pgno = pip->next_pgno;
  610. ret = __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip);
  611. pip = NULL;
  612. if (ret != 0)
  613. goto err;
  614. if (next_pgno == PGNO_INVALID)
  615. break; /* End of the bucket. */
  616. /* We already checked this, but just in case... */
  617. if (!IS_VALID_PGNO(next_pgno)) {
  618. DB_ASSERT(0);
  619. EPRINT((dbp->dbenv,
  620.     "Page %lu: hash page has bad next_pgno",
  621.     (u_long)pgno));
  622. isbad = 1;
  623. goto err;
  624. }
  625. if ((ret = __db_vrfy_getpageinfo(vdp, next_pgno, &pip)) != 0)
  626. goto err;
  627. if (pip->prev_pgno != pgno) {
  628. EPRINT((dbp->dbenv,
  629.     "Page %lu: hash page has bad prev_pgno",
  630.     (u_long)next_pgno));
  631. isbad = 1;
  632. }
  633. pgno = next_pgno;
  634. }
  635. err: if (cc != NULL && ((t_ret = __db_vrfy_ccclose(cc)) != 0) && ret == 0)
  636. ret = t_ret;
  637. if (mip != NULL && ((t_ret =
  638.     __db_vrfy_putpageinfo(dbp->dbenv, vdp, mip)) != 0) && ret == 0)
  639. ret = t_ret;
  640. if (pip != NULL && ((t_ret =
  641.     __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0) && ret == 0)
  642. ret = t_ret;
  643. return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
  644. }
  645. /*
  646.  * __ham_vrfy_hashing --
  647.  * Verify that all items on a given hash page hash correctly.
  648.  *
  649.  * PUBLIC: int __ham_vrfy_hashing __P((DB *,
  650.  * PUBLIC:     u_int32_t, HMETA *, u_int32_t, db_pgno_t, u_int32_t,
  651.  * PUBLIC:     u_int32_t (*) __P((DB *, const void *, u_int32_t))));
  652.  */
  653. int
  654. __ham_vrfy_hashing(dbp, nentries, m, thisbucket, pgno, flags, hfunc)
  655. DB *dbp;
  656. u_int32_t nentries;
  657. HMETA *m;
  658. u_int32_t thisbucket;
  659. db_pgno_t pgno;
  660. u_int32_t flags;
  661. u_int32_t (*hfunc) __P((DB *, const void *, u_int32_t));
  662. {
  663. DBT dbt;
  664. DB_MPOOLFILE *mpf;
  665. PAGE *h;
  666. db_indx_t i;
  667. int ret, t_ret, isbad;
  668. u_int32_t hval, bucket;
  669. mpf = dbp->mpf;
  670. ret = isbad = 0;
  671. memset(&dbt, 0, sizeof(DBT));
  672. F_SET(&dbt, DB_DBT_REALLOC);
  673. if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
  674. return (ret);
  675. for (i = 0; i < nentries; i += 2) {
  676. /*
  677.  * We've already verified the page integrity and that of any
  678.  * overflow chains linked off it;  it is therefore safe to use
  679.  * __db_ret.  It's also not all that much slower, since we have
  680.  * to copy every hash item to deal with alignment anyway;  we
  681.  * can tweak this a bit if this proves to be a bottleneck,
  682.  * but for now, take the easy route.
  683.  */
  684. if ((ret = __db_ret(dbp, h, i, &dbt, NULL, NULL)) != 0)
  685. goto err;
  686. hval = hfunc(dbp, dbt.data, dbt.size);
  687. bucket = hval & m->high_mask;
  688. if (bucket > m->max_bucket)
  689. bucket = bucket & m->low_mask;
  690. if (bucket != thisbucket) {
  691. EPRINT((dbp->dbenv,
  692.     "Page %lu: item %lu hashes incorrectly",
  693.     (u_long)pgno, (u_long)i));
  694. isbad = 1;
  695. }
  696. }
  697. err: if (dbt.data != NULL)
  698. __os_ufree(dbp->dbenv, dbt.data);
  699. if ((t_ret = mpf->put(mpf, h, 0)) != 0)
  700. return (t_ret);
  701. return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
  702. }
  703. /*
  704.  * __ham_salvage --
  705.  * Safely dump out anything that looks like a key on an alleged
  706.  * hash page.
  707.  *
  708.  * PUBLIC: int __ham_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, PAGE *,
  709.  * PUBLIC:     void *, int (*)(void *, const void *), u_int32_t));
  710.  */
  711. int
  712. __ham_salvage(dbp, vdp, pgno, h, handle, callback, flags)
  713. DB *dbp;
  714. VRFY_DBINFO *vdp;
  715. db_pgno_t pgno;
  716. PAGE *h;
  717. void *handle;
  718. int (*callback) __P((void *, const void *));
  719. u_int32_t flags;
  720. {
  721. DBT dbt, unkdbt;
  722. db_pgno_t dpgno;
  723. int ret, err_ret, t_ret;
  724. u_int32_t himark, tlen;
  725. u_int8_t *hk;
  726. void *buf;
  727. u_int32_t dlen, len, i;
  728. memset(&dbt, 0, sizeof(DBT));
  729. dbt.flags = DB_DBT_REALLOC;
  730. memset(&unkdbt, 0, sizeof(DBT));
  731. unkdbt.size = (u_int32_t)strlen("UNKNOWN") + 1;
  732. unkdbt.data = "UNKNOWN";
  733. err_ret = 0;
  734. /*
  735.  * Allocate a buffer for overflow items.  Start at one page;
  736.  * __db_safe_goff will realloc as needed.
  737.  */
  738. if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, &buf)) != 0)
  739. return (ret);
  740. himark = dbp->pgsize;
  741. for (i = 0;; i++) {
  742. /* If we're not aggressive, break when we hit NUM_ENT(h). */
  743. if (!LF_ISSET(DB_AGGRESSIVE) && i >= NUM_ENT(h))
  744. break;
  745. /* Verify the current item. */
  746. ret = __db_vrfy_inpitem(dbp,
  747.     h, pgno, i, 0, flags, &himark, NULL);
  748. /* If this returned a fatality, it's time to break. */
  749. if (ret == DB_VERIFY_FATAL)
  750. break;
  751. if (ret == 0) {
  752. hk = P_ENTRY(dbp, h, i);
  753. len = LEN_HKEYDATA(dbp, h, dbp->pgsize, i);
  754. if ((u_int32_t)(hk + len - (u_int8_t *)h) >
  755.     dbp->pgsize) {
  756. /*
  757.  * Item is unsafely large;  either continue
  758.  * or set it to the whole page, depending on
  759.  * aggressiveness.
  760.  */
  761. if (!LF_ISSET(DB_AGGRESSIVE))
  762. continue;
  763. len = dbp->pgsize -
  764.     (u_int32_t)(hk - (u_int8_t *)h);
  765. err_ret = DB_VERIFY_BAD;
  766. }
  767. switch (HPAGE_PTYPE(hk)) {
  768. default:
  769. if (!LF_ISSET(DB_AGGRESSIVE))
  770. break;
  771. err_ret = DB_VERIFY_BAD;
  772. /* FALLTHROUGH */
  773. case H_KEYDATA:
  774. keydata: memcpy(buf, HKEYDATA_DATA(hk), len);
  775. dbt.size = len;
  776. dbt.data = buf;
  777. if ((ret = __db_prdbt(&dbt,
  778.     0, " ", handle, callback, 0, vdp)) != 0)
  779. err_ret = ret;
  780. break;
  781. case H_OFFPAGE:
  782. if (len < HOFFPAGE_SIZE) {
  783. err_ret = DB_VERIFY_BAD;
  784. continue;
  785. }
  786. memcpy(&dpgno,
  787.     HOFFPAGE_PGNO(hk), sizeof(dpgno));
  788. if ((ret = __db_safe_goff(dbp, vdp,
  789.     dpgno, &dbt, &buf, flags)) != 0) {
  790. err_ret = ret;
  791. (void)__db_prdbt(&unkdbt, 0, " ",
  792.     handle, callback, 0, vdp);
  793. break;
  794. }
  795. if ((ret = __db_prdbt(&dbt,
  796.     0, " ", handle, callback, 0, vdp)) != 0)
  797. err_ret = ret;
  798. break;
  799. case H_OFFDUP:
  800. if (len < HOFFPAGE_SIZE) {
  801. err_ret = DB_VERIFY_BAD;
  802. continue;
  803. }
  804. memcpy(&dpgno,
  805.     HOFFPAGE_PGNO(hk), sizeof(dpgno));
  806. /* UNKNOWN iff pgno is bad or we're a key. */
  807. if (!IS_VALID_PGNO(dpgno) || (i % 2 == 0)) {
  808. if ((ret = __db_prdbt(&unkdbt, 0, " ",
  809.     handle, callback, 0, vdp)) != 0)
  810. err_ret = ret;
  811. } else if ((ret = __db_salvage_duptree(dbp,
  812.     vdp, dpgno, &dbt, handle, callback,
  813.     flags | SA_SKIPFIRSTKEY)) != 0)
  814. err_ret = ret;
  815. break;
  816. case H_DUPLICATE:
  817. /*
  818.  * We're a key;  printing dups will seriously
  819.  * foul the output.  If we're being aggressive,
  820.  * pretend this is a key and let the app.
  821.  * programmer sort out the mess.
  822.  */
  823. if (i % 2 == 0) {
  824. err_ret = ret;
  825. if (LF_ISSET(DB_AGGRESSIVE))
  826. goto keydata;
  827. break;
  828. }
  829. /* Too small to have any data. */
  830. if (len <
  831.     HKEYDATA_SIZE(2 * sizeof(db_indx_t))) {
  832. err_ret = DB_VERIFY_BAD;
  833. continue;
  834. }
  835. /* Loop until we hit the total length. */
  836. for (tlen = 0; tlen + sizeof(db_indx_t) < len;
  837.     tlen += dlen) {
  838. tlen += sizeof(db_indx_t);
  839. memcpy(&dlen, hk, sizeof(db_indx_t));
  840. /*
  841.  * If dlen is too long, print all the
  842.  * rest of the dup set in a chunk.
  843.  */
  844. if (dlen + tlen > len)
  845. dlen = len - tlen;
  846. memcpy(buf, hk + tlen, dlen);
  847. dbt.size = dlen;
  848. dbt.data = buf;
  849. if ((ret = __db_prdbt(&dbt, 0, " ",
  850.     handle, callback, 0, vdp)) != 0)
  851. err_ret = ret;
  852. tlen += sizeof(db_indx_t);
  853. }
  854. break;
  855. }
  856. }
  857. }
  858. __os_free(dbp->dbenv, buf);
  859. if ((t_ret = __db_salvage_markdone(vdp, pgno)) != 0)
  860. return (t_ret);
  861. return ((ret == 0 && err_ret != 0) ? err_ret : ret);
  862. }
  863. /*
  864.  * __ham_meta2pgset --
  865.  * Return the set of hash pages corresponding to the given
  866.  * known-good meta page.
  867.  *
  868.  * PUBLIC: int __ham_meta2pgset __P((DB *, VRFY_DBINFO *, HMETA *, u_int32_t,
  869.  * PUBLIC:     DB *));
  870.  */
  871. int __ham_meta2pgset(dbp, vdp, hmeta, flags, pgset)
  872. DB *dbp;
  873. VRFY_DBINFO *vdp;
  874. HMETA *hmeta;
  875. u_int32_t flags;
  876. DB *pgset;
  877. {
  878. DB_MPOOLFILE *mpf;
  879. PAGE *h;
  880. db_pgno_t pgno;
  881. u_int32_t bucket, totpgs;
  882. int ret, val;
  883. /*
  884.  * We don't really need flags, but leave them for consistency with
  885.  * __bam_meta2pgset.
  886.  */
  887. COMPQUIET(flags, 0);
  888. DB_ASSERT(pgset != NULL);
  889. mpf = dbp->mpf;
  890. totpgs = 0;
  891. /*
  892.  * Loop through all the buckets, pushing onto pgset the corresponding
  893.  * page(s) for each one.
  894.  */
  895. for (bucket = 0; bucket <= hmeta->max_bucket; bucket++) {
  896. pgno = BS_TO_PAGE(bucket, hmeta->spares);
  897. /*
  898.  * We know the initial pgno is safe because the spares array has
  899.  * been verified.
  900.  *
  901.  * Safely walk the list of pages in this bucket.
  902.  */
  903. for (;;) {
  904. if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
  905. return (ret);
  906. if (TYPE(h) == P_HASH) {
  907. /*
  908.  * Make sure we don't go past the end of
  909.  * pgset.
  910.  */
  911. if (++totpgs > vdp->last_pgno) {
  912. (void)mpf->put(mpf, h, 0);
  913. return (DB_VERIFY_BAD);
  914. }
  915. if ((ret =
  916.     __db_vrfy_pgset_inc(pgset, pgno)) != 0) {
  917. (void)mpf->put(mpf, h, 0);
  918. return (ret);
  919. }
  920. pgno = NEXT_PGNO(h);
  921. } else
  922. pgno = PGNO_INVALID;
  923. if ((ret = mpf->put(mpf, h, 0)) != 0)
  924. return (ret);
  925. /* If the new pgno is wonky, go onto the next bucket. */
  926. if (!IS_VALID_PGNO(pgno) ||
  927.     pgno == PGNO_INVALID)
  928. break;
  929. /*
  930.  * If we've touched this page before, we have a cycle;
  931.  * go on to the next bucket.
  932.  */
  933. if ((ret = __db_vrfy_pgset_get(pgset, pgno, &val)) != 0)
  934. return (ret);
  935. if (val != 0)
  936. break;
  937. }
  938. }
  939. return (0);
  940. }
  941. /*
  942.  * __ham_dups_unsorted --
  943.  * Takes a known-safe hash duplicate set and its total length.
  944.  * Returns 1 if there are out-of-order duplicates in this set,
  945.  * 0 if there are not.
  946.  */
  947. static int
  948. __ham_dups_unsorted(dbp, buf, len)
  949. DB *dbp;
  950. u_int8_t *buf;
  951. u_int32_t len;
  952. {
  953. DBT a, b;
  954. db_indx_t offset, dlen;
  955. int (*func) __P((DB *, const DBT *, const DBT *));
  956. memset(&a, 0, sizeof(DBT));
  957. memset(&b, 0, sizeof(DBT));
  958. func = (dbp->dup_compare == NULL) ? __bam_defcmp : dbp->dup_compare;
  959. /*
  960.  * Loop through the dup set until we hit the end or we find
  961.  * a pair of dups that's out of order.  b is always the current
  962.  * dup, a the one before it.
  963.  */
  964. for (offset = 0; offset < len; offset += DUP_SIZE(dlen)) {
  965. memcpy(&dlen, buf + offset, sizeof(db_indx_t));
  966. b.data = buf + offset + sizeof(db_indx_t);
  967. b.size = dlen;
  968. if (a.data != NULL && func(dbp, &a, &b) > 0)
  969. return (1);
  970. a.data = b.data;
  971. a.size = b.size;
  972. }
  973. return (0);
  974. }