00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 1999, 2000 00005 * Sleepycat Software. All rights reserved. 00006 * 00007 * $Id: bt__verify_8c-source.html,v 1.1 2008年06月08日 10:13:47 sebdiaz Exp $ 00008 */ 00009 00010 #include "config.h" 00011 00012 #ifndef lint 00013 static const char revid[] = "$Id: bt__verify_8c-source.html,v 1.1 2008年06月08日 10:13:47 sebdiaz Exp $"; 00014 #endif /* not lint */ 00015 00016 #ifndef NO_SYSTEM_INCLUDES 00017 #include <sys/types.h> 00018 00019 #include <errno.h> 00020 #include <string.h> 00021 #endif 00022 00023 #include "db_int.h" 00024 #include "db_page.h" 00025 #include "db_verify.h" 00026 #include "btree.h" 00027 00028 static int __bam_safe_getdata __P((DB *, PAGE *, u_int32_t, int, DBT *, int *)); 00029 static int __bam_vrfy_inp __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, 00030 db_indx_t *, u_int32_t)); 00031 static int __bam_vrfy_treeorder __P((DB *, db_pgno_t, PAGE *, BINTERNAL *, 00032 BINTERNAL *, u_int32_t)); 00033 static int __ram_vrfy_inp __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, 00034 db_indx_t *, u_int32_t)); 00035 00036 #define OKFLAGS (DB_AGGRESSIVE | DB_NOORDERCHK | DB_SALVAGE) 00037 00038 /* 00039 * CDB___bam_vrfy_meta -- 00040 * Verify the btree-specific part of a metadata page. 00041 * 00042 * PUBLIC: int CDB___bam_vrfy_meta __P((DB *, VRFY_DBINFO *, BTMETA *, 00043 * PUBLIC: db_pgno_t, u_int32_t)); 00044 */ 00045 int 00046 CDB___bam_vrfy_meta(dbp, vdp, meta, pgno, flags) 00047 DB *dbp; 00048 VRFY_DBINFO *vdp; 00049 BTMETA *meta; 00050 db_pgno_t pgno; 00051 u_int32_t flags; 00052 { 00053 VRFY_PAGEINFO *pip; 00054 int isbad, t_ret, ret; 00055 00056 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) 00057 return (ret); 00058 00059 isbad = 0; 00060 00061 /* 00062 * If VRFY_INCOMPLETE is not set, then we didn't come through 00063 * __db_vrfy_pagezero and didn't incompletely 00064 * check this page--we haven't checked it at all. 00065 * Thus we need to call CDB___db_vrfy_meta and check the common fields. 00066 * 00067 * If VRFY_INCOMPLETE is set, we've already done all the same work 00068 * in __db_vrfy_pagezero, so skip the check. 00069 */ 00070 if (!F_ISSET(pip, VRFY_INCOMPLETE) && 00071 (ret = CDB___db_vrfy_meta(dbp, vdp, &meta->dbmeta, pgno, flags)) != 0) { 00072 if (ret == DB_VERIFY_BAD) 00073 isbad = 1; 00074 else 00075 goto err; 00076 } 00077 00078 /* bt_minkey: must be >= 2, < (pagesize / BKEYDATA_PSIZE(0) */ 00079 if (meta->minkey < 2 || 00080 meta->minkey > (dbp->pgsize / BKEYDATA_PSIZE(0))) { 00081 pip->bt_minkey = 0; 00082 isbad = 1; 00083 EPRINT((dbp->dbenv, 00084 "Nonsensical bt_minkey value %lu on metadata page %lu", 00085 meta->minkey, pgno)); 00086 } else 00087 pip->bt_minkey = meta->minkey; 00088 00089 /* bt_maxkey: no constraints (XXX: right?) */ 00090 pip->bt_maxkey = meta->maxkey; 00091 00092 /* re_len: no constraints on this (may be zero or huge--we make rope) */ 00093 pip->re_len = meta->re_len; 00094 00095 /* 00096 * The root must not be current page or 0 and it must be within 00097 * database. If this metadata page is the master meta data page 00098 * of the file, then the root page had better be page 1. 00099 */ 00100 pip->root = 0; 00101 if (meta->root == PGNO_INVALID 00102 || meta->root == pgno || !IS_VALID_PGNO(meta->root) || 00103 (pgno == PGNO_BASE_MD && meta->root != 1)) { 00104 isbad = 1; 00105 EPRINT((dbp->dbenv, 00106 "Nonsensical root page %lu on metadata page %lu", 00107 meta->root, vdp->last_pgno)); 00108 } else 00109 pip->root = meta->root; 00110 00111 /* Flags. */ 00112 if (F_ISSET(&meta->dbmeta, BTM_RENUMBER)) 00113 F_SET(pip, VRFY_IS_RRECNO); 00114 00115 if (F_ISSET(&meta->dbmeta, BTM_SUBDB)) { 00116 /* 00117 * If this is a master db meta page, it had better not have 00118 * duplicates. 00119 */ 00120 if (F_ISSET(&meta->dbmeta, BTM_DUP) && pgno == PGNO_BASE_MD) { 00121 isbad = 1; 00122 EPRINT((dbp->dbenv, 00123 "Btree metadata page %lu has both duplicates and multiple databases", 00124 pgno)); 00125 } 00126 F_SET(pip, VRFY_HAS_SUBDBS); 00127 } 00128 00129 if (F_ISSET(&meta->dbmeta, BTM_DUP)) 00130 F_SET(pip, VRFY_HAS_DUPS); 00131 if (F_ISSET(&meta->dbmeta, BTM_DUPSORT)) 00132 F_SET(pip, VRFY_HAS_DUPSORT); 00133 if (F_ISSET(&meta->dbmeta, BTM_RECNUM)) 00134 F_SET(pip, VRFY_HAS_RECNUMS); 00135 if (F_ISSET(pip, VRFY_HAS_RECNUMS) && F_ISSET(pip, VRFY_HAS_DUPS)) { 00136 EPRINT((dbp->dbenv, 00137 "Btree metadata page %lu illegally has both recnums and dups", 00138 pgno)); 00139 isbad = 1; 00140 } 00141 00142 if (F_ISSET(&meta->dbmeta, BTM_RECNO)) { 00143 F_SET(pip, VRFY_IS_RECNO); 00144 dbp->type = DB_RECNO; 00145 } else if (F_ISSET(pip, VRFY_IS_RRECNO)) { 00146 isbad = 1; 00147 EPRINT((dbp->dbenv, 00148 "Metadata page %lu has renumber flag set but is not recno", 00149 pgno)); 00150 } 00151 00152 if (F_ISSET(pip, VRFY_IS_RECNO) && F_ISSET(pip, VRFY_HAS_DUPS)) { 00153 EPRINT((dbp->dbenv, 00154 "Recno metadata page %lu specifies duplicates", pgno)); 00155 isbad = 1; 00156 } 00157 00158 if (F_ISSET(&meta->dbmeta, BTM_FIXEDLEN)) 00159 F_SET(pip, VRFY_IS_FIXEDLEN); 00160 else if (pip->re_len > 0) { 00161 /* 00162 * It's wrong to have an re_len if it's not a fixed-length 00163 * database 00164 */ 00165 isbad = 1; 00166 EPRINT((dbp->dbenv, 00167 "re_len of %lu in non-fixed-length database", 00168 pip->re_len)); 00169 } 00170 00171 /* 00172 * We do not check that the rest of the page is 0, because it may 00173 * not be and may still be correct. 00174 */ 00175 00176 err: if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) 00177 ret = t_ret; 00178 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); 00179 } 00180 00181 /* 00182 * CDB___ram_vrfy_leaf -- 00183 * Verify a recno leaf page. 00184 * 00185 * PUBLIC: int CDB___ram_vrfy_leaf __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, 00186 * PUBLIC: u_int32_t)); 00187 */ 00188 int 00189 CDB___ram_vrfy_leaf(dbp, vdp, h, pgno, flags) 00190 DB *dbp; 00191 VRFY_DBINFO *vdp; 00192 PAGE *h; 00193 db_pgno_t pgno; 00194 u_int32_t flags; 00195 { 00196 BKEYDATA *bk; 00197 VRFY_PAGEINFO *pip; 00198 db_indx_t i; 00199 int ret, t_ret, isbad; 00200 u_int32_t re_len_guess, len; 00201 00202 isbad = 0; 00203 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) 00204 return (ret); 00205 00206 if ((ret = CDB___db_fchk(dbp->dbenv, 00207 "CDB___ram_vrfy_leaf", flags, OKFLAGS)) != 0) 00208 goto err; 00209 00210 if (TYPE(h) != P_LRECNO) { 00211 /* We should not have been called. */ 00212 TYPE_ERR_PRINT(dbp->dbenv, "CDB___ram_vrfy_leaf", pgno, TYPE(h)); 00213 DB_ASSERT(0); 00214 ret = EINVAL; 00215 goto err; 00216 } 00217 00218 /* 00219 * Verify (and, if relevant, save off) page fields common to 00220 * all PAGEs. 00221 */ 00222 if ((ret = CDB___db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) { 00223 if (ret == DB_VERIFY_BAD) 00224 isbad = 1; 00225 else 00226 goto err; 00227 } 00228 00229 /* 00230 * Verify inp[]. Return immediately if it returns DB_VERIFY_BAD; 00231 * further checks are dangerous. 00232 */ 00233 if ((ret = __bam_vrfy_inp(dbp, 00234 vdp, h, pgno, &pip->entries, flags)) != 0) 00235 goto err; 00236 00237 if (F_ISSET(pip, VRFY_HAS_DUPS)) { 00238 EPRINT((dbp->dbenv, 00239 "Recno database has dups on page %lu", pgno)); 00240 ret = DB_VERIFY_BAD; 00241 goto err; 00242 } 00243 00244 /* 00245 * Walk through inp and see if the lengths of all the records are the 00246 * same--if so, this may be a fixed-length database, and we want to 00247 * save off this value. We know inp to be safe if we've gotten this 00248 * far. 00249 */ 00250 re_len_guess = 0; 00251 for (i = 0; i < NUM_ENT(h); i++) { 00252 bk = GET_BKEYDATA(h, i); 00253 /* KEYEMPTY. Go on. */ 00254 if (B_DISSET(bk->type)) 00255 continue; 00256 if (bk->type == B_OVERFLOW) 00257 len = ((BOVERFLOW *)bk)->tlen; 00258 else if (bk->type == B_KEYDATA) 00259 len = bk->len; 00260 else { 00261 isbad = 1; 00262 EPRINT((dbp->dbenv, "Nonsensical type for item %lu, page %lu", 00263 i, pgno)); 00264 continue; 00265 } 00266 if (re_len_guess == 0) 00267 re_len_guess = len; 00268 00269 /* 00270 * Is this item's len the same as the last one's? If not, 00271 * reset to 0 and break--we don't have a single re_len. 00272 * Otherwise, go on to the next item. 00273 */ 00274 if (re_len_guess != len) { 00275 re_len_guess = 0; 00276 break; 00277 } 00278 } 00279 pip->re_len = re_len_guess; 00280 00281 /* Save off record count. */ 00282 pip->rec_cnt = NUM_ENT(h); 00283 00284 err: if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) 00285 ret = t_ret; 00286 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : 0); 00287 } 00288 00289 /* 00290 * CDB___bam_vrfy -- 00291 * Verify a btree leaf or internal page. 00292 * 00293 * PUBLIC: int CDB___bam_vrfy __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, 00294 * PUBLIC: u_int32_t)); 00295 */ 00296 int 00297 CDB___bam_vrfy(dbp, vdp, h, pgno, flags) 00298 DB *dbp; 00299 VRFY_DBINFO *vdp; 00300 PAGE *h; 00301 db_pgno_t pgno; 00302 u_int32_t flags; 00303 { 00304 VRFY_PAGEINFO *pip; 00305 int ret, t_ret, isbad; 00306 00307 isbad = 0; 00308 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) 00309 return (ret); 00310 00311 switch (TYPE(h)) { 00312 case P_IBTREE: 00313 case P_IRECNO: 00314 case P_LBTREE: 00315 case P_LDUP: 00316 break; 00317 default: 00318 TYPE_ERR_PRINT(dbp->dbenv, "CDB___bam_vrfy", pgno, TYPE(h)); 00319 DB_ASSERT(0); 00320 ret = EINVAL; 00321 goto err; 00322 } 00323 00324 /* 00325 * Verify (and, if relevant, save off) page fields common to 00326 * all PAGEs. 00327 */ 00328 if ((ret = CDB___db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) { 00329 if (ret == DB_VERIFY_BAD) 00330 isbad = 1; 00331 else 00332 goto err; 00333 } 00334 00335 /* 00336 * The record count is, on internal pages, stored in an overloaded 00337 * next_pgno field. Save it off; we'll verify it when we check 00338 * overall database structure. We could overload the field 00339 * in VRFY_PAGEINFO, too, but this seems gross, and space 00340 * is not at such a premium. 00341 */ 00342 pip->rec_cnt = RE_NREC(h); 00343 00344 /* 00345 * Verify inp[]. 00346 */ 00347 if (TYPE(h) == P_IRECNO) { 00348 if ((ret = __ram_vrfy_inp(dbp, 00349 vdp, h, pgno, &pip->entries, flags)) != 0) 00350 goto err; 00351 } else if ((ret = __bam_vrfy_inp(dbp, 00352 vdp, h, pgno, &pip->entries, flags)) != 0) { 00353 if (ret == DB_VERIFY_BAD) 00354 isbad = 1; 00355 else 00356 goto err; 00357 EPRINT((dbp->dbenv, 00358 "item order check on page %lu unsafe: skipping", pgno)); 00359 } else if (!LF_ISSET(DB_NOORDERCHK) && (ret = 00360 CDB___bam_vrfy_itemorder(dbp, vdp, h, pgno, 0, 0, 0, flags)) != 0) { 00361 /* 00362 * We know that the elements of inp are reasonable. 00363 * 00364 * Check that elements fall in the proper order. 00365 */ 00366 if (ret == DB_VERIFY_BAD) 00367 isbad = 1; 00368 else 00369 goto err; 00370 } 00371 00372 err: if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) 00373 ret = t_ret; 00374 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : 0); 00375 } 00376 00377 /* 00378 * __ram_vrfy_inp -- 00379 * Verify that all entries in a P_IRECNO inp[] array are reasonable, 00380 * and count them. Note that P_LRECNO uses __bam_vrfy_inp; 00381 * P_IRECNOs are a special, and simpler, case, since they have 00382 * RINTERNALs rather than BKEYDATA/BINTERNALs. 00383 */ 00384 static int 00385 __ram_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags) 00386 DB *dbp; 00387 VRFY_DBINFO *vdp; 00388 PAGE *h; 00389 db_pgno_t pgno; 00390 db_indx_t *nentriesp; 00391 u_int32_t flags; 00392 { 00393 RINTERNAL *ri; 00394 VRFY_CHILDINFO child; 00395 VRFY_PAGEINFO *pip; 00396 int ret, t_ret, isbad; 00397 db_indx_t himark, i, offset, nentries; 00398 u_int8_t *pagelayout, *p; 00399 00400 isbad = 0; 00401 memset(&child, 0, sizeof(VRFY_CHILDINFO)); 00402 nentries = 0; 00403 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) 00404 return (ret); 00405 00406 if (TYPE(h) != P_IRECNO) { 00407 TYPE_ERR_PRINT(dbp->dbenv, "__ram_vrfy_inp", pgno, TYPE(h)); 00408 DB_ASSERT(0); 00409 ret = EINVAL; 00410 goto err; 00411 } 00412 00413 himark = dbp->pgsize; 00414 if ((ret = 00415 CDB___os_malloc(dbp->dbenv, dbp->pgsize, NULL, &pagelayout)) != 0) 00416 goto err; 00417 memset(pagelayout, 0, dbp->pgsize); 00418 for (i = 0; i < NUM_ENT(h); i++) { 00419 if ((u_int8_t *)h->inp + i >= (u_int8_t *)h + himark) { 00420 EPRINT((dbp->dbenv, 00421 "Page %lu entries listing %lu overlaps data", 00422 pgno, i)); 00423 ret = DB_VERIFY_BAD; 00424 goto err; 00425 } 00426 offset = h->inp[i]; 00427 /* 00428 * Check that the item offset is reasonable: it points 00429 * somewhere after the inp array and before the end of the 00430 * page. 00431 */ 00432 if (offset <= ((u_int8_t *)h->inp + i - (u_int8_t *)h) || 00433 offset > dbp->pgsize - RINTERNAL_SIZE) { 00434 isbad = 1; 00435 EPRINT((dbp->dbenv, 00436 "Bad offset %lu at page %lu index %lu", 00437 offset, pgno, i)); 00438 continue; 00439 } 00440 00441 /* Update the high-water mark (what HOFFSET should be) */ 00442 if (offset < himark) 00443 himark = offset; 00444 00445 nentries++; 00446 00447 /* Make sure this RINTERNAL is not multiply referenced. */ 00448 ri = GET_RINTERNAL(h, i); 00449 if (pagelayout[offset] == 0) { 00450 pagelayout[offset] = 1; 00451 child.pgno = ri->pgno; 00452 child.type = V_RECNO; 00453 child.nrecs = ri->nrecs; 00454 if ((ret = CDB___db_vrfy_childput(vdp, pgno, &child)) != 0) 00455 goto err; 00456 } else { 00457 EPRINT((dbp->dbenv, 00458 "RINTERNAL structure at offset %lu, page %lu referenced twice", 00459 offset, pgno)); 00460 isbad = 1; 00461 } 00462 } 00463 00464 for (p = pagelayout + himark; 00465 p < pagelayout + dbp->pgsize; 00466 p += RINTERNAL_SIZE) 00467 if (*p != 1) { 00468 EPRINT((dbp->dbenv, 00469 "Gap between items at offset %lu, page %lu", 00470 p - pagelayout, pgno)); 00471 isbad = 1; 00472 } 00473 00474 if (himark != HOFFSET(h)) { 00475 EPRINT((dbp->dbenv, "Bad HOFFSET %lu, appears to be %lu", 00476 HOFFSET(h), himark)); 00477 isbad = 1; 00478 } 00479 00480 *nentriesp = nentries; 00481 00482 err: if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) 00483 ret = t_ret; 00484 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); 00485 } 00486 00487 /* 00488 * __bam_vrfy_inp -- 00489 * Verify that all entries in inp[] array are reasonable; 00490 * count them. 00491 */ 00492 static int 00493 __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags) 00494 DB *dbp; 00495 VRFY_DBINFO *vdp; 00496 PAGE *h; 00497 db_pgno_t pgno; 00498 db_indx_t *nentriesp; 00499 u_int32_t flags; 00500 { 00501 BKEYDATA *bk; 00502 BOVERFLOW *bo; 00503 VRFY_CHILDINFO child; 00504 VRFY_PAGEINFO *pip; 00505 int isbad, initem, isdupitem, ret, t_ret; 00506 u_int32_t himark, offset; /* These would be db_indx_ts but for algnmt.*/ 00507 db_indx_t i, endoff, nentries; 00508 u_int8_t *pagelayout; 00509 00510 isbad = isdupitem = 0; 00511 nentries = 0; 00512 memset(&child, 0, sizeof(VRFY_CHILDINFO)); 00513 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) 00514 return (ret); 00515 00516 switch (TYPE(h)) { 00517 case P_IBTREE: 00518 case P_LBTREE: 00519 case P_LDUP: 00520 case P_LRECNO: 00521 break; 00522 default: 00523 /* 00524 * In the salvager, we might call this from a page which 00525 * we merely suspect is a btree page. Otherwise, it 00526 * shouldn't get called--if it is, that's a verifier bug. 00527 */ 00528 if (LF_ISSET(DB_SALVAGE)) 00529 break; 00530 TYPE_ERR_PRINT(dbp->dbenv, "__bam_vrfy_inp", pgno, TYPE(h)); 00531 DB_ASSERT(0); 00532 ret = EINVAL; 00533 goto err; 00534 } 00535 00536 /* 00537 * Loop through inp[], the array of items, until we either 00538 * run out of entries or collide with the data. Keep track 00539 * of h_offset in himark. 00540 * 00541 * For each element in inp[i], make sure it references a region 00542 * that starts after the end of the inp array (as defined by 00543 * NUM_ENT(h)), ends before the beginning of the page, doesn't 00544 * overlap any other regions, and doesn't have a gap between 00545 * it and the region immediately after it. 00546 */ 00547 himark = dbp->pgsize; 00548 if ((ret = CDB___os_malloc(dbp->dbenv, 00549 dbp->pgsize, NULL, &pagelayout)) != 0) 00550 goto err; 00551 memset(pagelayout, 0, dbp->pgsize); 00552 for (i = 0; i < NUM_ENT(h); i++) { 00553 00554 ret = CDB___db_vrfy_inpitem(dbp, 00555 h, pgno, i, 1, flags, &himark, &offset); 00556 if (ret == DB_VERIFY_BAD) { 00557 isbad = 1; 00558 continue; 00559 } else if (ret == DB_VERIFY_FATAL) { 00560 isbad = 1; 00561 goto err; 00562 } else if (ret != 0) 00563 DB_ASSERT(0); 00564 00565 /* 00566 * We now have a plausible beginning for the item, and we know 00567 * its length is safe. 00568 * 00569 * Mark the beginning and end in pagelayout so we can make sure 00570 * items have no overlaps or gaps. 00571 */ 00572 bk = GET_BKEYDATA(h, i); 00573 #define ITEM_BEGIN 1 00574 #define ITEM_END 2 00575 if (pagelayout[offset] == 0) 00576 pagelayout[offset] = ITEM_BEGIN; 00577 else if (pagelayout[offset] == ITEM_BEGIN) { 00578 /* 00579 * Having two inp entries that point at the same patch 00580 * of page is legal if and only if the page is 00581 * a btree leaf and they're onpage duplicate keys-- 00582 * that is, if (i % P_INDX) == 0. 00583 */ 00584 if ((i % P_INDX == 0) && (TYPE(h) == P_LBTREE)) { 00585 /* Flag for later. */ 00586 F_SET(pip, VRFY_HAS_DUPS); 00587 00588 /* Bump up nentries so we don't undercount. */ 00589 nentries++; 00590 00591 /* 00592 * We'll check to make sure the end is 00593 * equal, too. 00594 */ 00595 isdupitem = 1; 00596 } else { 00597 isbad = 1; 00598 EPRINT((dbp->dbenv, "Duplicated item %lu on page %lu", 00599 i, pgno)); 00600 } 00601 } 00602 00603 /* 00604 * Mark the end. Its location varies with the page type 00605 * and the item type. 00606 * 00607 * If the end already has a sign other than 0, do nothing-- 00608 * it's an overlap that we'll catch later. 00609 */ 00610 switch(B_TYPE(bk->type)) { 00611 case B_KEYDATA: 00612 if (TYPE(h) == P_IBTREE) 00613 /* It's a BINTERNAL. */ 00614 endoff = offset + BINTERNAL_SIZE(bk->len) - 1; 00615 else 00616 endoff = offset + BKEYDATA_SIZE(bk->len) - 1; 00617 break; 00618 case B_DUPLICATE: 00619 /* 00620 * Flag that we have dups; we'll check whether 00621 * that's okay during the structure check. 00622 */ 00623 F_SET(pip, VRFY_HAS_DUPS); 00624 /* FALLTHROUGH */ 00625 case B_OVERFLOW: 00626 /* 00627 * Overflow entries on internal pages are stored 00628 * as the _data_ of a BINTERNAL; overflow entries 00629 * on leaf pages are stored as the entire entry. 00630 */ 00631 endoff = offset + 00632 ((TYPE(h) == P_IBTREE) ? 00633 BINTERNAL_SIZE(BOVERFLOW_SIZE) : 00634 BOVERFLOW_SIZE) - 1; 00635 break; 00636 default: 00637 /* 00638 * We'll complain later; for now, just mark 00639 * a minimum. 00640 */ 00641 endoff = offset + BKEYDATA_SIZE(0) - 1; 00642 break; 00643 } 00644 00645 /* 00646 * If this is an onpage duplicate key we've seen before, 00647 * the end had better coincide too. 00648 */ 00649 if (isdupitem && pagelayout[endoff] != ITEM_END) { 00650 EPRINT((dbp->dbenv, "Duplicated item %lu on page %lu", i, 00651 pgno)); 00652 isbad = 1; 00653 } else if (pagelayout[endoff] == 0) 00654 pagelayout[endoff] = ITEM_END; 00655 isdupitem = 0; 00656 00657 /* 00658 * There should be no deleted items in a quiescent tree, 00659 * except in recno. 00660 */ 00661 if (B_DISSET(bk->type) && TYPE(h) != P_LRECNO) { 00662 isbad = 1; 00663 EPRINT((dbp->dbenv, 00664 "Item %lu on page %lu marked deleted", i, pgno)); 00665 } 00666 00667 /* 00668 * Check the type and such of bk--make sure it's reasonable 00669 * for the pagetype. 00670 */ 00671 switch (B_TYPE(bk->type)) { 00672 case B_KEYDATA: 00673 /* 00674 * This is a normal, non-overflow BKEYDATA or BINTERNAL. 00675 * The only thing to check is the len, and that's 00676 * already been done. 00677 */ 00678 break; 00679 case B_DUPLICATE: 00680 if (TYPE(h) == P_IBTREE) { 00681 isbad = 1; 00682 EPRINT((dbp->dbenv, 00683 "Duplicate page referenced by internal btree page %lu at item %lu", 00684 pgno, i)); 00685 break; 00686 } else if (TYPE(h) == P_LRECNO) { 00687 isbad = 1; 00688 EPRINT((dbp->dbenv, 00689 "Duplicate page referenced by recno page %lu at item %lu", 00690 pgno, i)); 00691 break; 00692 } 00693 /* FALLTHROUGH */ 00694 case B_OVERFLOW: 00695 bo = (TYPE(h) == P_IBTREE) ? 00696 (BOVERFLOW *)(((BINTERNAL *)bk)->data) : 00697 (BOVERFLOW *)bk; 00698 00699 if (B_TYPE(bk->type) == B_OVERFLOW) 00700 /* Make sure tlen is reasonable. */ 00701 if (bo->tlen > dbp->pgsize * vdp->last_pgno) { 00702 isbad = 1; 00703 EPRINT((dbp->dbenv, 00704 "Impossible tlen %lu, item %lu, page %lu", 00705 bo->tlen, i, pgno)); 00706 /* Don't save as a child. */ 00707 break; 00708 } 00709 00710 if (!IS_VALID_PGNO(bo->pgno) || bo->pgno == pgno || 00711 bo->pgno == PGNO_INVALID) { 00712 isbad = 1; 00713 EPRINT((dbp->dbenv, 00714 "Offpage item %lu, page %lu has bad pgno", 00715 i, pgno)); 00716 /* Don't save as a child. */ 00717 break; 00718 } 00719 00720 child.pgno = bo->pgno; 00721 child.type = (B_TYPE(bk->type) == B_OVERFLOW ? 00722 V_OVERFLOW : V_DUPLICATE); 00723 child.tlen = bo->tlen; 00724 if ((ret = CDB___db_vrfy_childput(vdp, pgno, &child)) != 0) 00725 goto err; 00726 break; 00727 default: 00728 isbad = 1; 00729 EPRINT((dbp->dbenv, 00730 "Item %lu on page %lu of invalid type %lu", 00731 i, pgno)); 00732 break; 00733 } 00734 } 00735 00736 /* 00737 * Now, loop through and make sure the items are contiguous and 00738 * non-overlapping. 00739 */ 00740 initem = 0; 00741 for (i = himark; i < dbp->pgsize; i++) 00742 if (initem == 0) 00743 switch (pagelayout[i]) { 00744 case 0: 00745 /* May be just for alignment. */ 00746 if (i != ALIGN(i, 4)) 00747 continue; 00748 00749 isbad = 1; 00750 EPRINT((dbp->dbenv, 00751 "Gap between items, page %lu offset %lu", 00752 pgno, i)); 00753 /* Find the end of the gap */ 00754 for ( ; pagelayout[i + 1] == 0 && 00755 (size_t)(i + 1) < dbp->pgsize; i++) 00756 ; 00757 break; 00758 case ITEM_BEGIN: 00759 /* We've found an item. Check its alignment. */ 00760 if (i != ALIGN(i, 4)) { 00761 isbad = 1; 00762 EPRINT((dbp->dbenv, 00763 "Offset %lu page %lu unaligned", 00764 i, pgno)); 00765 } 00766 initem = 1; 00767 nentries++; 00768 break; 00769 case ITEM_END: 00770 /* 00771 * We've hit the end of an item even though 00772 * we don't think we're in one; must 00773 * be an overlap. 00774 */ 00775 isbad = 1; 00776 EPRINT((dbp->dbenv, 00777 "Overlapping items, page %lu offset %lu", 00778 pgno, i)); 00779 break; 00780 default: 00781 /* Should be impossible. */ 00782 DB_ASSERT(0); 00783 ret = EINVAL; 00784 goto err; 00785 } 00786 else 00787 switch (pagelayout[i]) { 00788 case 0: 00789 /* In the middle of an item somewhere. Okay. */ 00790 break; 00791 case ITEM_END: 00792 /* End of an item; switch to out-of-item mode.*/ 00793 initem = 0; 00794 break; 00795 case ITEM_BEGIN: 00796 /* 00797 * Hit a second item beginning without an 00798 * end. Overlap. 00799 */ 00800 isbad = 1; 00801 EPRINT((dbp->dbenv, 00802 "Overlapping items, page %lu offset %lu", 00803 pgno, i)); 00804 break; 00805 } 00806 00807 (void)CDB___os_free(pagelayout, dbp->pgsize); 00808 00809 /* Verify HOFFSET. */ 00810 if (himark != HOFFSET(h)) { 00811 EPRINT((dbp->dbenv, "Bad HOFFSET %lu, appears to be %lu", 00812 HOFFSET(h), himark)); 00813 isbad = 1; 00814 } 00815 00816 err: if (nentriesp != NULL) 00817 *nentriesp = nentries; 00818 00819 if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) 00820 ret = t_ret; 00821 00822 return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret); 00823 } 00824 00825 /* 00826 * CDB___bam_vrfy_itemorder -- 00827 * Make sure the items on a page sort correctly. 00828 * 00829 * Assumes that NUM_ENT(h) and inp[0]..inp[NUM_ENT(h) - 1] are 00830 * reasonable; be sure that __bam_vrfy_inp has been called first. 00831 * 00832 * If ovflok is set, it also assumes that overflow page chains 00833 * hanging off the current page have been sanity-checked, and so we 00834 * can use CDB___bam_cmp to verify their ordering. If it is not set, 00835 * and we run into an overflow page, carp and return DB_VERIFY_BAD; 00836 * we shouldn't be called if any exist. 00837 * 00838 * PUBLIC: int CDB___bam_vrfy_itemorder __P((DB *, VRFY_DBINFO *, PAGE *, 00839 * PUBLIC: db_pgno_t, u_int32_t, int, int, u_int32_t)); 00840 */ 00841 int 00842 CDB___bam_vrfy_itemorder(dbp, vdp, h, pgno, nentries, ovflok, hasdups, flags) 00843 DB *dbp; 00844 VRFY_DBINFO *vdp; 00845 PAGE *h; 00846 db_pgno_t pgno; 00847 u_int32_t nentries; 00848 int ovflok, hasdups; 00849 u_int32_t flags; 00850 { 00851 DBT dbta, dbtb, dup1, dup2, *p1, *p2, *tmp; 00852 BTREE *bt; 00853 BINTERNAL *bi; 00854 BKEYDATA *bk; 00855 BOVERFLOW *bo; 00856 VRFY_PAGEINFO *pip; 00857 db_indx_t i; 00858 int cmp, freedup1, freedup2, isbad, ret, t_ret; 00859 int (*dupfunc) __P((const DBT *, const DBT *)); 00860 int (*func) __P((const DBT *, const DBT *)); 00861 void *buf1, *buf2, *tmpbuf; 00862 00863 /* 00864 * We need to work in the ORDERCHKONLY environment where we might 00865 * not have a pip, but we also may need to work in contexts where 00866 * NUM_ENT isn't safe. 00867 */ 00868 if (vdp != NULL) { 00869 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) 00870 return (ret); 00871 nentries = pip->entries; 00872 } else 00873 pip = NULL; 00874 00875 ret = isbad = 0; 00876 bo = NULL; /* Shut up compiler. */ 00877 00878 memset(&dbta, 0, sizeof(DBT)); 00879 F_SET(&dbta, DB_DBT_REALLOC); 00880 00881 memset(&dbtb, 0, sizeof(DBT)); 00882 F_SET(&dbtb, DB_DBT_REALLOC); 00883 00884 buf1 = buf2 = NULL; 00885 00886 DB_ASSERT(!LF_ISSET(DB_NOORDERCHK)); 00887 00888 dupfunc = (dbp->dup_compare == NULL) ? CDB___bam_defcmp : dbp->dup_compare; 00889 if (TYPE(h) == P_LDUP) 00890 func = dupfunc; 00891 else { 00892 func = CDB___bam_defcmp; 00893 if (dbp->bt_internal != NULL) { 00894 bt = (BTREE *)dbp->bt_internal; 00895 if (bt->bt_compare != NULL) 00896 func = bt->bt_compare; 00897 } 00898 } 00899 00900 /* 00901 * We alternate our use of dbta and dbtb so that we can walk 00902 * through the page key-by-key without copying a dbt twice. 00903 * p1 is always the dbt for index i - 1, and p2 for index i. 00904 */ 00905 p1 = &dbta; 00906 p2 = &dbtb; 00907 00908 /* 00909 * Loop through the entries. nentries ought to contain the 00910 * actual count, and so is a safe way to terminate the loop; whether 00911 * we inc. by one or two depends on whether we're a leaf page-- 00912 * on a leaf page, we care only about keys. On internal pages 00913 * and LDUP pages, we want to check the order of all entries. 00914 * 00915 * Note that on IBTREE pages, we start with item 1, since item 00916 * 0 doesn't get looked at by CDB___bam_cmp. 00917 */ 00918 for (i = (TYPE(h) == P_IBTREE) ? 1 : 0; i < nentries; 00919 i += (TYPE(h) == P_LBTREE) ? P_INDX : O_INDX) { 00920 /* 00921 * Put key i-1, now in p2, into p1, by swapping DBTs and bufs. 00922 */ 00923 tmp = p1; 00924 p1 = p2; 00925 p2 = tmp; 00926 tmpbuf = buf1; 00927 buf1 = buf2; 00928 buf2 = tmpbuf; 00929 00930 /* 00931 * Get key i into p2. 00932 */ 00933 switch (TYPE(h)) { 00934 case P_IBTREE: 00935 bi = GET_BINTERNAL(h, i); 00936 if (B_TYPE(bi->type) == B_OVERFLOW) { 00937 bo = (BOVERFLOW *)(bi->data); 00938 goto overflow; 00939 } else { 00940 p2->data = bi->data; 00941 p2->size = bi->len; 00942 } 00943 00944 /* 00945 * The leftmost key on an internal page must be 00946 * len 0, since it's just a placeholder and 00947 * automatically sorts less than all keys. 00948 * 00949 * XXX 00950 * This criterion does not currently hold! 00951 * See todo list item #1686. Meanwhile, it's harmless 00952 * to just not check for it. 00953 */ 00954 #if 0 00955 if (i == 0 && bi->len != 0) { 00956 isbad = 1; 00957 EPRINT((dbp->dbenv, 00958 "Lowest key on internal page %lu of nonzero length", 00959 pgno)); 00960 } 00961 #endif 00962 break; 00963 case P_LBTREE: 00964 case P_LDUP: 00965 bk = GET_BKEYDATA(h, i); 00966 if (B_TYPE(bk->type) == B_OVERFLOW) { 00967 bo = (BOVERFLOW *)bk; 00968 goto overflow; 00969 } else { 00970 p2->data = bk->data; 00971 p2->size = bk->len; 00972 } 00973 break; 00974 default: 00975 /* 00976 * This means our caller screwed up and sent us 00977 * an inappropriate page. 00978 */ 00979 TYPE_ERR_PRINT(dbp->dbenv, 00980 "CDB___bam_vrfy_itemorder", pgno, TYPE(h)) 00981 DB_ASSERT(0); 00982 ret = EINVAL; 00983 goto err; 00984 /* NOTREACHED */ 00985 } 00986 00987 if (0) { 00988 /* 00989 * If ovflok != 1, we can't safely go chasing 00990 * overflow pages with the normal routines now; 00991 * they might be unsafe or nonexistent. Mark this 00992 * page as incomplete and return. 00993 * 00994 * Note that we don't need to worry about freeing 00995 * buffers, since they can't have been allocated 00996 * if overflow items are unsafe. 00997 */ 00998 overflow: if (!ovflok) { 00999 F_SET(pip, VRFY_INCOMPLETE); 01000 goto err; 01001 } 01002 01003 /* 01004 * Overflow items are safe to chase. Do so. 01005 * Fetch the overflow item into p2->data, 01006 * NULLing it or reallocing it as appropriate. 01007 * 01008 * (We set p2->data to buf2 before the call 01009 * so we're sure to realloc if we can and if p2 01010 * was just pointing at a non-overflow item.) 01011 */ 01012 p2->data = buf2; 01013 if ((ret = CDB___db_goff(dbp, 01014 p2, bo->tlen, bo->pgno, NULL, NULL)) != 0) { 01015 isbad = 1; 01016 EPRINT((dbp->dbenv, 01017 "Error %lu in fetching overflow item %lu, page %lu", 01018 ret, i, pgno)); 01019 } 01020 /* In case it got realloc'ed and thus changed. */ 01021 buf2 = p2->data; 01022 } 01023 01024 /* Compare with the last key. */ 01025 if (p1->data != NULL && p2->data != NULL) { 01026 cmp = func(p1, p2); 01027 01028 /* comparison succeeded */ 01029 if (cmp > 0) { 01030 isbad = 1; 01031 EPRINT((dbp->dbenv, 01032 "Out-of-order key, page %lu item %lu", 01033 pgno, i)); 01034 /* proceed */ 01035 } else if (cmp == 0) { 01036 /* 01037 * If they compared equally, this 01038 * had better be a (sub)database with dups. 01039 * Mark it so we can check during the 01040 * structure check. 01041 */ 01042 if (pip != NULL) 01043 F_SET(pip, VRFY_HAS_DUPS); 01044 else if (hasdups == 0) { 01045 isbad = 1; 01046 EPRINT((dbp->dbenv, 01047 "Database with no duplicates has duplicated keys on page %lu", pgno)); 01048 } 01049 01050 /* 01051 * If we're a btree leaf, check to see 01052 * if the data items of these on-page dups are 01053 * in sorted order. If not, flag this, so 01054 * that we can make sure during the 01055 * structure checks that the DUPSORT flag 01056 * is unset. 01057 * 01058 * At this point i points to a duplicate key. 01059 * Compare the datum before it (same key) 01060 * to the datum after it, i.e. i-1 to i+1. 01061 */ 01062 if (TYPE(h) == P_LBTREE) { 01063 /* 01064 * Unsafe; continue and we'll pick 01065 * up the bogus nentries later. 01066 */ 01067 if (i + 1 >= (db_indx_t)nentries) 01068 continue; 01069 01070 /* 01071 * We don't bother with clever memory 01072 * management with on-page dups, 01073 * as it's only really a big win 01074 * in the overflow case, and overflow 01075 * dups are probably (?) rare. 01076 */ 01077 if (((ret = __bam_safe_getdata(dbp, 01078 h, i - 1, ovflok, &dup1, 01079 &freedup1)) != 0) || 01080 ((ret = __bam_safe_getdata(dbp, 01081 h, i + 1, ovflok, &dup2, 01082 &freedup2)) != 0)) 01083 goto err; 01084 01085 /* 01086 * If either of the data are NULL, 01087 * it's because they're overflows and 01088 * it's not safe to chase them now. 01089 * Mark an incomplete and return. 01090 */ 01091 if (dup1.data == NULL || 01092 dup2.data == NULL) { 01093 DB_ASSERT(!ovflok); 01094 F_SET(pip, VRFY_INCOMPLETE); 01095 goto err; 01096 } 01097 01098 /* 01099 * If the dups are out of order, 01100 * flag this. It's not an error 01101 * until we do the structure check 01102 * and see whether DUPSORT is set. 01103 */ 01104 if (dupfunc(&dup1, &dup2) > 0) 01105 F_SET(pip, VRFY_DUPS_UNSORTED); 01106 01107 if (freedup1) 01108 CDB___os_free(dup1.data, 0); 01109 if (freedup2) 01110 CDB___os_free(dup2.data, 0); 01111 } 01112 } 01113 } 01114 } 01115 01116 err: if (pip != NULL && 01117 ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0) && ret == 0) 01118 ret = t_ret; 01119 01120 if (buf1 != NULL) 01121 CDB___os_free(buf1, 0); 01122 if (buf2 != NULL) 01123 CDB___os_free(buf2, 0); 01124 01125 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); 01126 } 01127 01128 /* 01129 * CDB___bam_vrfy_structure -- 01130 * Verify the tree structure of a btree database (including the master 01131 * database containing subdbs). 01132 * 01133 * PUBLIC: int CDB___bam_vrfy_structure __P((DB *, VRFY_DBINFO *, db_pgno_t, 01134 * PUBLIC: u_int32_t)); 01135 */ 01136 int 01137 CDB___bam_vrfy_structure(dbp, vdp, meta_pgno, flags) 01138 DB *dbp; 01139 VRFY_DBINFO *vdp; 01140 db_pgno_t meta_pgno; 01141 u_int32_t flags; 01142 { 01143 DB *pgset; 01144 VRFY_PAGEINFO *mip, *rip; 01145 db_pgno_t root, p; 01146 int t_ret, ret; 01147 u_int32_t nrecs, level, relen, stflags; 01148 01149 mip = rip = 0; 01150 pgset = vdp->pgset; 01151 01152 if ((ret = CDB___db_vrfy_getpageinfo(vdp, meta_pgno, &mip)) != 0) 01153 return (ret); 01154 01155 if ((ret = CDB___db_vrfy_pgset_get(pgset, meta_pgno, (int *)&p)) != 0) 01156 goto err; 01157 if (p != 0) { 01158 EPRINT((dbp->dbenv, 01159 "Btree metadata page number %lu observed twice", 01160 meta_pgno)); 01161 ret = DB_VERIFY_BAD; 01162 goto err; 01163 } 01164 if ((ret = CDB___db_vrfy_pgset_inc(pgset, meta_pgno)) != 0) 01165 goto err; 01166 01167 root = mip->root; 01168 01169 if (root == 0) { 01170 EPRINT((dbp->dbenv, 01171 "Btree metadata page %lu has no root", meta_pgno)); 01172 ret = DB_VERIFY_BAD; 01173 goto err; 01174 } 01175 01176 if ((ret = CDB___db_vrfy_getpageinfo(vdp, root, &rip)) != 0) 01177 goto err; 01178 01179 switch (rip->type) { 01180 case P_IBTREE: 01181 case P_LBTREE: 01182 stflags = flags | ST_TOPLEVEL; 01183 if (F_ISSET(mip, VRFY_HAS_DUPS)) 01184 stflags |= ST_DUPOK; 01185 if (F_ISSET(mip, VRFY_HAS_DUPSORT)) 01186 stflags |= ST_DUPSORT; 01187 if (F_ISSET(mip, VRFY_HAS_RECNUMS)) 01188 stflags |= ST_RECNUM; 01189 ret = CDB___bam_vrfy_subtree(dbp, 01190 vdp, root, NULL, NULL, stflags, NULL, NULL, NULL); 01191 break; 01192 case P_IRECNO: 01193 case P_LRECNO: 01194 stflags = flags | ST_RECNUM | ST_IS_RECNO | ST_TOPLEVEL; 01195 if (mip->re_len > 0) 01196 stflags |= ST_RELEN; 01197 if ((ret = CDB___bam_vrfy_subtree(dbp, vdp, 01198 root, NULL, NULL, stflags, &level, &nrecs, &relen)) != 0) 01199 goto err; 01200 /* 01201 * Even if mip->re_len > 0, re_len may come back zero if the 01202 * tree is empty. It should be okay to just skip the check in 01203 * this case, as if there are any non-deleted keys at all, 01204 * that should never happen. 01205 */ 01206 if (mip->re_len > 0 && relen > 0 && mip->re_len != relen) { 01207 EPRINT((dbp->dbenv, 01208 "Recno database with meta page %lu has bad re_len %lu", 01209 meta_pgno, relen)); 01210 ret = DB_VERIFY_BAD; 01211 goto err; 01212 } 01213 ret = 0; 01214 break; 01215 case P_LDUP: 01216 EPRINT((dbp->dbenv, 01217 "Duplicate tree referenced from metadata page %lu", 01218 meta_pgno)); 01219 ret = DB_VERIFY_BAD; 01220 break; 01221 default: 01222 EPRINT((dbp->dbenv, "%s%s", "Btree root of incorrect type ", 01223 "%lu specified on meta page %lu", rip->type, meta_pgno)); 01224 ret = DB_VERIFY_BAD; 01225 break; 01226 } 01227 01228 err: if (mip != NULL && 01229 ((t_ret = CDB___db_vrfy_putpageinfo(vdp, mip)) != 0) && ret == 0) 01230 t_ret = ret; 01231 if (rip != NULL && 01232 ((t_ret = CDB___db_vrfy_putpageinfo(vdp, rip)) != 0) && ret == 0) 01233 t_ret = ret; 01234 return (ret); 01235 } 01236 01237 /* 01238 * CDB___bam_vrfy_subtree-- 01239 * Verify a subtree (or entire) btree with specified root. 01240 * 01241 * Note that this is public because it must be called to verify 01242 * offpage dup trees, including from hash. 01243 * 01244 * PUBLIC: int CDB___bam_vrfy_subtree __P((DB *, VRFY_DBINFO *, db_pgno_t, void *, 01245 * PUBLIC: void *, u_int32_t, u_int32_t *, u_int32_t *, u_int32_t *)); 01246 */ 01247 int 01248 CDB___bam_vrfy_subtree(dbp, 01249 vdp, pgno, l, r, flags, levelp, nrecsp, relenp) 01250 DB *dbp; 01251 VRFY_DBINFO *vdp; 01252 db_pgno_t pgno; 01253 void *l, *r; 01254 u_int32_t flags, *levelp, *nrecsp, *relenp; 01255 { 01256 BINTERNAL *li, *ri, *lp, *rp; 01257 DB *pgset; 01258 PAGE *h; 01259 VRFY_CHILDINFO *child; 01260 VRFY_PAGEINFO *pip; 01261 db_recno_t nrecs, child_nrecs; 01262 db_indx_t i; 01263 int ret, t_ret, isbad, toplevel, p; 01264 u_int32_t level, child_level, stflags, child_relen, relen; 01265 DBC *cc; 01266 01267 ret = isbad = 0; 01268 nrecs = 0; 01269 h = NULL; 01270 relen = 0; 01271 rp = (BINTERNAL *)r; 01272 lp = (BINTERNAL *)l; 01273 01274 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) 01275 return (ret); 01276 01277 cc = NULL; 01278 level = pip->bt_level; 01279 01280 toplevel = LF_ISSET(ST_TOPLEVEL); 01281 LF_CLR(ST_TOPLEVEL); 01282 01283 /* 01284 * We are recursively descending a btree, starting from the root 01285 * and working our way out to the leaves. 01286 * 01287 * There are four cases we need to deal with: 01288 * 1. pgno is a recno leaf page. Any children are overflows. 01289 * 2. pgno is a duplicate leaf page. Any children 01290 * are overflow pages; traverse them, and then return 01291 * level and nrecs. 01292 * 3. pgno is an ordinary leaf page. Check whether dups are 01293 * allowed, and if so, traverse any off-page dups or 01294 * overflows. Then return nrecs and level. 01295 * 4. pgno is a recno internal page. Recursively check any 01296 * child pages, making sure their levels are one lower 01297 * and their nrecs sum to ours. 01298 * 5. pgno is a btree internal page. Same as #4, plus we 01299 * must verify that for each pair of BINTERNAL entries 01300 * N and N+1, the leftmost item on N's child sorts 01301 * greater than N, and the rightmost item on N's child 01302 * sorts less than N+1. 01303 * 01304 * Furthermore, in any sorted page type (P_LDUP, P_LBTREE, P_IBTREE), 01305 * we need to verify the internal sort order is correct if, 01306 * due to overflow items, we were not able to do so earlier. 01307 */ 01308 switch (pip->type) { 01309 case P_LRECNO: 01310 case P_LDUP: 01311 case P_LBTREE: 01312 /* 01313 * Cases 1, 2 and 3 (overflow pages are common to all three); 01314 * traverse child list, looking for overflows. 01315 */ 01316 if ((ret = CDB___db_vrfy_childcursor(vdp, &cc)) != 0) 01317 goto err; 01318 for (ret = CDB___db_vrfy_ccset(cc, pgno, &child); ret == 0; 01319 ret = CDB___db_vrfy_ccnext(cc, &child)) 01320 if (child->type == V_OVERFLOW && 01321 (ret = CDB___db_vrfy_ovfl_structure(dbp, vdp, 01322 child->pgno, child->tlen, 01323 flags | ST_OVFL_LEAF)) != 0) { 01324 if (ret == DB_VERIFY_BAD) 01325 isbad = 1; 01326 else 01327 goto done; 01328 } 01329 01330 if ((ret = CDB___db_vrfy_ccclose(cc)) != 0) 01331 goto err; 01332 cc = NULL; 01333 01334 /* Case 1 */ 01335 if (pip->type == P_LRECNO) { 01336 if (!LF_ISSET(ST_IS_RECNO) && 01337 !(LF_ISSET(ST_DUPOK) && !LF_ISSET(ST_DUPSORT))) { 01338 isbad = 1; 01339 EPRINT((dbp->dbenv, 01340 "Recno leaf page %lu in non-recno tree", 01341 pgno)); 01342 goto done; 01343 } 01344 goto leaf; 01345 } else if (LF_ISSET(ST_IS_RECNO)){ 01346 /* 01347 * It's a non-recno leaf. Had better not be a recno 01348 * subtree. 01349 */ 01350 isbad = 1; 01351 EPRINT((dbp->dbenv, 01352 "Non-recno leaf page %lu in recno tree", 01353 pgno)); 01354 goto done; 01355 } 01356 01357 /* Case 2--no more work. */ 01358 if (pip->type == P_LDUP) 01359 goto leaf; 01360 01361 /* Case 3 */ 01362 01363 /* Check if we have any dups. */ 01364 if (F_ISSET(pip, VRFY_HAS_DUPS)) { 01365 /* If dups aren't allowed in this btree, trouble. */ 01366 if (!LF_ISSET(ST_DUPOK)) { 01367 isbad = 1; 01368 EPRINT((dbp->dbenv, 01369 "Duplicates on page %lu in non-dup btree", 01370 pgno)); 01371 } else { 01372 /* 01373 * We correctly have dups. If any are off-page, 01374 * traverse those btrees recursively. 01375 */ 01376 if ((ret = 01377 CDB___db_vrfy_childcursor(vdp, &cc)) != 0) 01378 goto err; 01379 for (ret = CDB___db_vrfy_ccset(cc, pgno, &child); 01380 ret == 0; 01381 ret = CDB___db_vrfy_ccnext(cc, &child)) { 01382 stflags = flags | ST_RECNUM; 01383 /* Skip any overflow entries. */ 01384 if (child->type == V_DUPLICATE) { 01385 if ((ret = CDB___db_vrfy_duptype( 01386 dbp, vdp, child->pgno, 01387 stflags)) != 0) { 01388 isbad = 1; 01389 /* Next child. */ 01390 continue; 01391 } 01392 if ((ret = CDB___bam_vrfy_subtree( 01393 dbp, vdp, child->pgno, NULL, 01394 NULL, stflags, NULL, NULL, 01395 NULL)) != 0) { 01396 if (ret != 01397 DB_VERIFY_BAD) 01398 goto err; 01399 else 01400 isbad = 1; 01401 } 01402 } 01403 } 01404 01405 if ((ret = CDB___db_vrfy_ccclose(cc)) != 0) 01406 goto err; 01407 cc = NULL; 01408 01409 /* 01410 * If VRFY_DUPS_UNSORTED is set, 01411 * ST_DUPSORT had better not be. 01412 */ 01413 if (F_ISSET(pip, VRFY_DUPS_UNSORTED) && 01414 LF_ISSET(ST_DUPSORT)) { 01415 EPRINT((dbp->dbenv, 01416 "Unsorted duplicate set at page %lu in sorted-dup database", 01417 pgno)); 01418 isbad = 1; 01419 } 01420 } 01421 } 01422 goto leaf; 01423 break; 01424 case P_IBTREE: 01425 case P_IRECNO: 01426 /* We handle these below. */ 01427 break; 01428 default: 01429 /* This should never get called if there's any doubt. */ 01430 TYPE_ERR_PRINT(dbp->dbenv, "CDB___bam_vrfy_subtree", pgno, pip->type); 01431 DB_ASSERT(0); 01432 ret = EINVAL; 01433 goto done; 01434 /* NOTREACHED */ 01435 } 01436 01437 /* 01438 * Cases 4 & 5: This is a btree or recno internal page. For each child, 01439 * recurse, keeping a running count of nrecs and making sure the level 01440 * is always reasonable. 01441 */ 01442 if ((ret = CDB___db_vrfy_childcursor(vdp, &cc)) != 0) 01443 goto err; 01444 for (ret = CDB___db_vrfy_ccset(cc, pgno, &child); ret == 0; 01445 ret = CDB___db_vrfy_ccnext(cc, &child)) 01446 if (child->type == V_RECNO) { 01447 if (pip->type != P_IRECNO) { 01448 TYPE_ERR_PRINT(dbp->dbenv, "CDB___bam_vrfy_subtree", 01449 pgno, pip->type); 01450 DB_ASSERT(0); 01451 ret = EINVAL; 01452 goto err; 01453 } 01454 if ((ret = CDB___bam_vrfy_subtree(dbp, vdp, child->pgno, 01455 NULL, NULL, flags, &child_level, &child_nrecs, 01456 &child_relen)) != 0) { 01457 if (ret != DB_VERIFY_BAD) 01458 goto done; 01459 else 01460 isbad = 1; 01461 } 01462 01463 if (LF_ISSET(ST_RELEN)) { 01464 if (relen == 0) 01465 relen = child_relen; 01466 /* 01467 * child_relen may be zero if the child subtree 01468 * is empty. 01469 */ 01470 else if (child_relen > 0 && 01471 relen != child_relen) { 01472 isbad = 1; 01473 EPRINT((dbp->dbenv, 01474 "Recno page %lu returned bad re_len", 01475 child->pgno)); 01476 } 01477 if (relenp) 01478 *relenp = relen; 01479 } 01480 if (LF_ISSET(ST_RECNUM)) 01481 nrecs += child_nrecs; 01482 if (level != child_level + 1) { 01483 isbad = 1; 01484 EPRINT((dbp->dbenv, "%s%lu%s%lu%s%lu", 01485 "Recno level incorrect on page ", 01486 child->pgno, ": got ", child_level, 01487 ", expected ", level - 1)); 01488 } 01489 } else if (child->type == V_OVERFLOW && 01490 (ret = CDB___db_vrfy_ovfl_structure(dbp, vdp, 01491 child->pgno, child->tlen, flags)) != 0) { 01492 if (ret == DB_VERIFY_BAD) 01493 isbad = 1; 01494 else 01495 goto done; 01496 } 01497 01498 if ((ret = CDB___db_vrfy_ccclose(cc)) != 0) 01499 goto err; 01500 cc = NULL; 01501 01502 /* We're done with case 4. */ 01503 if (pip->type == P_IRECNO) 01504 goto done; 01505 01506 /* 01507 * Case 5. Btree internal pages. 01508 * As described above, we need to iterate through all the 01509 * items on the page and make sure that our children sort appropriately 01510 * with respect to them. 01511 * 01512 * For each entry, li will be the "left-hand" key for the entry 01513 * itself, which must sort lower than all entries on its child; 01514 * ri will be the key to its right, which must sort greater. 01515 */ 01516 if (h == NULL && (ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) 01517 goto err; 01518 for (i = 0; i < pip->entries; i += O_INDX) { 01519 li = GET_BINTERNAL(h, i); 01520 ri = (i + O_INDX < pip->entries) ? 01521 GET_BINTERNAL(h, i + O_INDX) : NULL; 01522 01523 /* 01524 * The leftmost key is forcibly sorted less than all entries, 01525 * so don't bother passing it. 01526 */ 01527 if ((ret = CDB___bam_vrfy_subtree(dbp, vdp, li->pgno, 01528 i == 0 ? NULL : li, ri, flags, &child_level, 01529 &child_nrecs, NULL)) != 0) { 01530 if (ret != DB_VERIFY_BAD) 01531 goto done; 01532 else 01533 isbad = 1; 01534 } 01535 01536 if (LF_ISSET(ST_RECNUM)) { 01537 /* 01538 * Keep a running tally on the actual record count so 01539 * we can return it to our parent (if we have one) or 01540 * compare it to the NRECS field if we're a root page. 01541 */ 01542 nrecs += child_nrecs; 01543 01544 /* 01545 * Make sure the actual record count of the child 01546 * is equal to the value in the BINTERNAL structure. 01547 */ 01548 if (li->nrecs != child_nrecs) { 01549 isbad = 1; 01550 EPRINT((dbp->dbenv, 01551 "Item %lu page %lu has incorrect record count of %lu, should be %lu", 01552 i, pgno, li->nrecs, child_nrecs)); 01553 } 01554 } 01555 01556 if (level != child_level + 1) { 01557 isbad = 1; 01558 EPRINT((dbp->dbenv, "%s%lu%s%lu%s%lu", 01559 "Btree level incorrect on page ", li->pgno, 01560 ": got ", child_level, ", expected ", level - 1)); 01561 } 01562 } 01563 01564 if (0) { 01565 leaf: level = LEAFLEVEL; 01566 if (LF_ISSET(ST_RECNUM)) 01567 nrecs = pip->rec_cnt; 01568 01569 /* XXX 01570 * We should verify that the record count on a leaf page 01571 * is the sum of the number of keys and the number of 01572 * records in its off-page dups. This requires looking 01573 * at the page again, however, and it may all be changing 01574 * soon, so for now we don't bother. 01575 */ 01576 01577 if (LF_ISSET(ST_RELEN) && relenp) 01578 *relenp = pip->re_len; 01579 } 01580 done: if (F_ISSET(pip, VRFY_INCOMPLETE) && isbad == 0 && ret == 0) { 01581 /* 01582 * During the page-by-page pass, item order verification was 01583 * not finished due to the presence of overflow items. If 01584 * isbad == 0, though, it's now safe to do so, as we've 01585 * traversed any child overflow pages. Do it. 01586 */ 01587 if (h == NULL && (ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) 01588 goto err; 01589 if ((ret = CDB___bam_vrfy_itemorder(dbp, 01590 vdp, h, pgno, 0, 1, 0, flags)) != 0) 01591 goto err; 01592 F_CLR(pip, VRFY_INCOMPLETE); 01593 } 01594 01595 /* 01596 * Our parent has sent us BINTERNAL pointers to parent records 01597 * so that we can verify our place with respect to them. If it's 01598 * appropriate--we have a default sort function--verify this. 01599 */ 01600 if (isbad == 0 && ret == 0 && !LF_ISSET(DB_NOORDERCHK) && lp != NULL) { 01601 if (h == NULL && (ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) 01602 goto err; 01603 if ((ret = 01604 __bam_vrfy_treeorder(dbp, pgno, h, lp, rp, flags)) != 0) { 01605 if (ret == DB_VERIFY_BAD) 01606 isbad = 1; 01607 else 01608 goto err; 01609 } 01610 } 01611 01612 /* 01613 * This is guaranteed to succeed for leaf pages, but no harm done. 01614 * 01615 * Internal pages below the top level do not store their own 01616 * record numbers, so we skip them. 01617 */ 01618 if (LF_ISSET(ST_RECNUM) && nrecs != pip->rec_cnt && toplevel) { 01619 isbad = 1; 01620 EPRINT((dbp->dbenv, 01621 "Bad record count on page %lu: got %lu, expected %lu", 01622 pgno, nrecs, pip->rec_cnt)); 01623 } 01624 01625 if (levelp) 01626 *levelp = level; 01627 if (nrecsp) 01628 *nrecsp = nrecs; 01629 01630 pgset = vdp->pgset; 01631 if ((ret = CDB___db_vrfy_pgset_get(pgset, pgno, &p)) != 0) 01632 goto err; 01633 if (p != 0) { 01634 isbad = 1; 01635 EPRINT((dbp->dbenv, "Page %lu linked twice", pgno)); 01636 } else if ((ret = CDB___db_vrfy_pgset_inc(pgset, pgno)) != 0) 01637 goto err; 01638 01639 err: if (h != NULL && (t_ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0 && ret == 0) 01640 ret = t_ret; 01641 if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) 01642 ret = t_ret; 01643 if (cc != NULL && ((t_ret = CDB___db_vrfy_ccclose(cc)) != 0) && ret == 0) 01644 ret = t_ret; 01645 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); 01646 } 01647 01648 /* 01649 * __bam_vrfy_treeorder -- 01650 * Verify that the lowest key on a page sorts greater than the 01651 * BINTERNAL which points to it (lp), and the highest key 01652 * sorts less than the BINTERNAL above that (rp). 01653 * 01654 * If lp is NULL, this means that it was the leftmost key on the 01655 * parent, which (regardless of sort function) sorts less than 01656 * all keys. No need to check it. 01657 * 01658 * If rp is NULL, lp was the highest key on the parent, so there's 01659 * no higher key we must sort less than. 01660 */ 01661 static int 01662 __bam_vrfy_treeorder(dbp, pgno, h, lp, rp, flags) 01663 DB *dbp; 01664 db_pgno_t pgno; 01665 PAGE *h; 01666 BINTERNAL *lp, *rp; 01667 u_int32_t flags; 01668 { 01669 BOVERFLOW *bo; 01670 BTREE *t; 01671 DBT dbt; 01672 db_indx_t last; 01673 int (*func)__P((const DBT *, const DBT *)); 01674 int ret, cmp; 01675 01676 memset(&dbt, 0, sizeof(DBT)); 01677 F_SET(&dbt, DB_DBT_MALLOC); 01678 t = dbp->bt_internal; 01679 func = (t->bt_compare != NULL) ? t->bt_compare : CDB___bam_defcmp; 01680 ret = 0; 01681 01682 switch (TYPE(h)) { 01683 case P_IBTREE: 01684 case P_LDUP: 01685 last = NUM_ENT(h) - O_INDX; 01686 break; 01687 case P_LBTREE: 01688 last = NUM_ENT(h) - P_INDX; 01689 break; 01690 default: 01691 TYPE_ERR_PRINT(dbp->dbenv, "__bam_vrfy_treeorder", pgno, TYPE(h)); 01692 DB_ASSERT(0); 01693 return (EINVAL); 01694 } 01695 01696 /* 01697 * The key on page h, the child page, is more likely to be 01698 * an overflow page, so we pass its offset, rather than lp/rp's, 01699 * into CDB___bam_cmp. This will take advantage of CDB___db_moff. 01700 */ 01701 01702 /* 01703 * Skip first-item check if we're an internal page--the first 01704 * entry on an internal page is treated specially by CDB___bam_cmp, 01705 * so what's on the page shouldn't matter. (Plus, since we're passing 01706 * our page and item 0 as to CDB___bam_cmp, we'll sort before our 01707 * parent and falsely report a failure.) 01708 */ 01709 if (lp != NULL && TYPE(h) != P_IBTREE) { 01710 if (lp->type == B_KEYDATA) { 01711 dbt.data = lp->data; 01712 dbt.size = lp->len; 01713 } else if (lp->type == B_OVERFLOW) { 01714 bo = (BOVERFLOW *)lp->data; 01715 if ((ret = CDB___db_goff(dbp, &dbt, bo->tlen, bo->pgno, 01716 NULL, NULL)) != 0) 01717 return (ret); 01718 } else { 01719 DB_ASSERT(0); 01720 EPRINT((dbp->dbenv, "Unknown type for internal record")); 01721 return (EINVAL); 01722 } 01723 01724 /* On error, fall through, free if neeeded, and return. */ 01725 if ((ret = CDB___bam_cmp(dbp, &dbt, h, 0, func, &cmp)) == 0) { 01726 if (cmp > 0) { 01727 EPRINT((dbp->dbenv, 01728 "First item on page %lu sorted greater than parent entry", 01729 PGNO(h))); 01730 ret = DB_VERIFY_BAD; 01731 } 01732 } else 01733 EPRINT((dbp->dbenv, 01734 "First item on page %lu had comparison error", 01735 PGNO(h))); 01736 01737 if (dbt.data != lp->data) 01738 CDB___os_free(dbt.data, 0); 01739 if (ret != 0) 01740 return (ret); 01741 } 01742 01743 if (rp != NULL) { 01744 if (rp->type == B_KEYDATA) { 01745 dbt.data = rp->data; 01746 dbt.size = rp->len; 01747 } else if (rp->type == B_OVERFLOW) { 01748 bo = (BOVERFLOW *)rp->data; 01749 if ((ret = CDB___db_goff(dbp, &dbt, bo->tlen, bo->pgno, 01750 NULL, NULL)) != 0) 01751 return (ret); 01752 } else { 01753 DB_ASSERT(0); 01754 EPRINT((dbp->dbenv, "Unknown type for internal record")); 01755 return (EINVAL); 01756 } 01757 01758 /* On error, fall through, free if neeeded, and return. */ 01759 if ((ret = CDB___bam_cmp(dbp, &dbt, h, last, func, &cmp)) == 0) { 01760 if (cmp < 0) { 01761 EPRINT((dbp->dbenv, 01762 "Last item on page %lu sorted greater than parent entry", 01763 PGNO(h))); 01764 ret = DB_VERIFY_BAD; 01765 } 01766 } else 01767 EPRINT((dbp->dbenv, 01768 "Last item on page %lu had comparison error", 01769 PGNO(h))); 01770 01771 if (dbt.data != rp->data) 01772 CDB___os_free(dbt.data, 0); 01773 } 01774 01775 return (ret); 01776 } 01777 01778 /* 01779 * CDB___bam_salvage -- 01780 * Safely dump out anything that looks like a key on an alleged 01781 * btree leaf page. 01782 * 01783 * PUBLIC: int CDB___bam_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, 01784 * PUBLIC: PAGE *, void *, int (*)(void *, const void *), DBT *, 01785 * PUBLIC: u_int32_t)); 01786 */ 01787 int 01788 CDB___bam_salvage(dbp, vdp, pgno, pgtype, h, handle, callback, key, flags) 01789 DB *dbp; 01790 VRFY_DBINFO *vdp; 01791 db_pgno_t pgno; 01792 u_int32_t pgtype; 01793 PAGE *h; 01794 void *handle; 01795 int (*callback) __P((void *, const void *)); 01796 DBT *key; 01797 u_int32_t flags; 01798 { 01799 DBT dbt, unkdbt; 01800 BKEYDATA *bk; 01801 BOVERFLOW *bo; 01802 db_indx_t i, beg, end; 01803 u_int32_t himark; 01804 u_int8_t *pgmap; 01805 void *ovflbuf; 01806 int t_ret, ret, err_ret; 01807 01808 /* Shut up lint. */ 01809 COMPQUIET(end, 0); 01810 01811 ovflbuf = pgmap = NULL; 01812 err_ret = ret = 0; 01813 01814 memset(&dbt, 0, sizeof(DBT)); 01815 dbt.flags = DB_DBT_REALLOC; 01816 01817 memset(&unkdbt, 0, sizeof(DBT)); 01818 unkdbt.size = strlen("UNKNOWN") + 1; 01819 unkdbt.data = "UNKNOWN"; 01820 01821 /* 01822 * Allocate a buffer for overflow items. Start at one page; 01823 * CDB___db_safe_goff will realloc as needed. 01824 */ 01825 if ((ret = CDB___os_malloc(dbp->dbenv, dbp->pgsize, NULL, &ovflbuf)) != 0) 01826 return (ret); 01827 01828 if (LF_ISSET(DB_AGGRESSIVE)) { 01829 if ((ret = 01830 CDB___os_malloc(dbp->dbenv, dbp->pgsize, NULL, &pgmap)) != 0) 01831 goto err; 01832 memset(pgmap, 0, dbp->pgsize); 01833 } 01834 01835 /* 01836 * Loop through the inp array, spitting out key/data pairs. 01837 * 01838 * If we're salvaging normally, loop from 0 through NUM_ENT(h). 01839 * If we're being aggressive, loop until we hit the end of the page-- 01840 * NUM_ENT() may be bogus. 01841 */ 01842 i = 0; 01843 himark = dbp->pgsize; 01844 for (;;) { 01845 /* If we're not aggressive, break when we hit NUM_ENT(h). */ 01846 if (!LF_ISSET(DB_AGGRESSIVE) && i >= NUM_ENT(h)) 01847 break; 01848 01849 /* Verify the current item. */ 01850 ret = CDB___db_vrfy_inpitem(dbp, 01851 h, pgno, i, 1, flags, &himark, NULL); 01852 /* If this returned a fatality, it's time to break. */ 01853 if (ret == DB_VERIFY_FATAL) 01854 break; 01855 /* 01856 * If this returned 0, it's safe to print or (carefully) 01857 * try to fetch. 01858 */ 01859 if (ret == 0) { 01860 /* 01861 * We're going to go try to print the next item. If 01862 * key is non-NULL, we're a dup page, so we've got to 01863 * print the key first, unless SA_SKIPFIRSTKEY is set 01864 * and we're on the first entry. 01865 */ 01866 if (key != NULL && 01867 (i != 0 || !LF_ISSET(SA_SKIPFIRSTKEY))) 01868 if ((ret = CDB___db_prdbt(key, 01869 0, " ", handle, callback, 0, NULL)) != 0) 01870 err_ret = ret; 01871 01872 bk = GET_BKEYDATA(h, i); 01873 beg = h->inp[i]; 01874 switch (bk->type) { 01875 case B_DUPLICATE: 01876 end = beg + BOVERFLOW_SIZE - 1; 01877 /* 01878 * If we're not on a normal btree leaf page, 01879 * there shouldn't be off-page 01880 * dup sets. Something's confused; just 01881 * drop it, and the code to pick up unlinked 01882 * offpage dup sets will print it out 01883 * with key "UNKNOWN" later. 01884 */ 01885 if (pgtype != P_LBTREE) 01886 break; 01887 01888 bo = (BOVERFLOW *)bk; 01889 01890 /* 01891 * If the page number is unreasonable, or 01892 * if this is supposed to be a key item, 01893 * just spit out "UNKNOWN"--the best we 01894 * can do is run into the data items in the 01895 * unlinked offpage dup pass. 01896 */ 01897 if (!IS_VALID_PGNO(bo->pgno) || 01898 (i % P_INDX == 0)) { 01899 /* Not much to do on failure. */ 01900 if ((ret = CDB___db_prdbt(&unkdbt, 0, " ", 01901 handle, callback, 0, NULL)) != 0) 01902 err_ret = ret; 01903 break; 01904 } 01905 01906 if ((ret = CDB___db_salvage_duptree(dbp, 01907 vdp, bo->pgno, &dbt, handle, callback, 01908 flags | SA_SKIPFIRSTKEY)) != 0) 01909 err_ret = ret; 01910 01911 break; 01912 default: 01913 /* 01914 * If we're being aggressive, fall through 01915 * and treat as a B_KEYDATA. Seems unlikely 01916 * that the length would be okay and the type 01917 * bogus, but we can never be sure. 01918 */ 01919 if (!LF_ISSET(DB_AGGRESSIVE)) 01920 break; 01921 /* FALLTHROUGH */ 01922 case B_KEYDATA: 01923 end = ALIGN(beg + bk->len, 4) - 1; 01924 dbt.data = bk->data; 01925 dbt.size = bk->len; 01926 if ((ret = CDB___db_prdbt(&dbt, 01927 0, " ", handle, callback, 0, NULL)) != 0) 01928 err_ret = ret; 01929 break; 01930 case B_OVERFLOW: 01931 end = beg + BOVERFLOW_SIZE - 1; 01932 bo = (BOVERFLOW *)bk; 01933 if ((ret = CDB___db_safe_goff(dbp, vdp, 01934 bo->pgno, &dbt, &ovflbuf, flags)) != 0) { 01935 err_ret = ret; 01936 /* We care about err_ret more. */ 01937 (void)CDB___db_prdbt(&unkdbt, 0, " ", 01938 handle, callback, 0, NULL); 01939 break; 01940 } 01941 if ((ret = CDB___db_prdbt(&dbt, 01942 0, " ", handle, callback, 0, NULL)) != 0) 01943 err_ret = ret; 01944 break; 01945 } 01946 01947 /* 01948 * If we're being aggressive, mark the beginning 01949 * and end of the item; we'll come back and print 01950 * whatever "junk" is in the gaps in case we had 01951 * any bogus inp elements and thereby missed stuff. 01952 */ 01953 if (LF_ISSET(DB_AGGRESSIVE)) { 01954 pgmap[beg] = ITEM_BEGIN; 01955 pgmap[end] = ITEM_END; 01956 } 01957 } 01958 i += O_INDX; 01959 } 01960 01961 /* 01962 * If i is odd and this is a btree leaf, we've printed out a key but not 01963 * a datum; fix this imbalance by printing an "UNKNOWN". 01964 */ 01965 if (pgtype == P_LBTREE && (i % P_INDX == 1) && ((ret = 01966 CDB___db_prdbt(&unkdbt, 0, " ", handle, callback, 0, NULL)) != 0)) 01967 err_ret = ret; 01968 01969 err: if (pgmap != NULL) 01970 CDB___os_free(pgmap, 0); 01971 CDB___os_free(ovflbuf, 0); 01972 01973 /* Mark this page as done. */ 01974 if ((t_ret = CDB___db_salvage_markdone(vdp, pgno)) != 0) 01975 return (t_ret); 01976 01977 return ((err_ret != 0) ? err_ret : ret); 01978 } 01979 01980 /* 01981 * CDB___bam_salvage_walkdupint -- 01982 * Walk a known-good btree or recno internal page which is part of 01983 * a dup tree, calling CDB___db_salvage_duptree on each child page. 01984 * 01985 * PUBLIC: int CDB___bam_salvage_walkdupint __P((DB *, VRFY_DBINFO *, PAGE *, 01986 * PUBLIC: DBT *, void *, int (*)(void *, const void *), u_int32_t)); 01987 */ 01988 int 01989 CDB___bam_salvage_walkdupint(dbp, vdp, h, key, handle, callback, flags) 01990 DB *dbp; 01991 VRFY_DBINFO *vdp; 01992 PAGE *h; 01993 DBT *key; 01994 void *handle; 01995 int (*callback) __P((void *, const void *)); 01996 u_int32_t flags; 01997 { 01998 RINTERNAL *ri; 01999 BINTERNAL *bi; 02000 int ret, t_ret; 02001 db_indx_t i; 02002 02003 ret = 0; 02004 for (i = 0; i < NUM_ENT(h); i++) { 02005 switch (TYPE(h)) { 02006 case P_IBTREE: 02007 bi = GET_BINTERNAL(h, i); 02008 if ((t_ret = CDB___db_salvage_duptree(dbp, 02009 vdp, bi->pgno, key, handle, callback, flags)) != 0) 02010 ret = t_ret; 02011 case P_IRECNO: 02012 ri = GET_RINTERNAL(h, i); 02013 if ((t_ret = CDB___db_salvage_duptree(dbp, 02014 vdp, ri->pgno, key, handle, callback, flags)) != 0) 02015 ret = t_ret; 02016 break; 02017 default: 02018 CDB___db_err(dbp->dbenv, 02019 "CDB___bam_salvage_walkdupint called on non-int. page"); 02020 DB_ASSERT(0); 02021 return (EINVAL); 02022 } 02023 /* Pass SA_SKIPFIRSTKEY, if set, on to the 0th child only. */ 02024 flags &= ~LF_ISSET(SA_SKIPFIRSTKEY); 02025 } 02026 02027 return (ret); 02028 } 02029 02030 /* 02031 * CDB___bam_meta2pgset -- 02032 * Given a known-good meta page, return in pgsetp a 0-terminated list of 02033 * db_pgno_t's corresponding to the pages in the btree. 02034 * 02035 * We do this by a somewhat sleazy method, to avoid having to traverse the 02036 * btree structure neatly: we walk down the left side to the very 02037 * first leaf page, then we mark all the pages in the chain of 02038 * NEXT_PGNOs (being wary of cycles and invalid ones), then we 02039 * consolidate our scratch array into a nice list, and return. This 02040 * avoids the memory management hassles of recursion and the 02041 * trouble of walking internal pages--they just don't matter, except 02042 * for the left branch. 02043 * 02044 * PUBLIC: int CDB___bam_meta2pgset __P((DB *, VRFY_DBINFO *, BTMETA *, 02045 * PUBLIC: u_int32_t, DB *)); 02046 */ 02047 int 02048 CDB___bam_meta2pgset(dbp, vdp, btmeta, flags, pgset) 02049 DB *dbp; 02050 VRFY_DBINFO *vdp; 02051 BTMETA *btmeta; 02052 u_int32_t flags; 02053 DB *pgset; 02054 { 02055 BINTERNAL *bi; 02056 PAGE *h; 02057 RINTERNAL *ri; 02058 db_pgno_t current, p; 02059 int err_ret, ret; 02060 02061 h = NULL; 02062 ret = err_ret = 0; 02063 DB_ASSERT(pgset != NULL); 02064 for (current = btmeta->root;;) { 02065 if (!IS_VALID_PGNO(current) || current == PGNO(btmeta)) { 02066 err_ret = DB_VERIFY_BAD; 02067 goto err; 02068 } 02069 if ((ret = CDB_memp_fget(dbp->mpf, ¤t, 0, &h)) != 0) { 02070 err_ret = ret; 02071 goto err; 02072 } 02073 02074 switch (TYPE(h)) { 02075 case P_IBTREE: 02076 case P_IRECNO: 02077 if ((ret = CDB___bam_vrfy(dbp, 02078 vdp, h, current, flags | DB_NOORDERCHK)) != 0) { 02079 err_ret = ret; 02080 goto err; 02081 } 02082 if (TYPE(h) == P_IBTREE) { 02083 bi = GET_BINTERNAL(h, 0); 02084 current = bi->pgno; 02085 } else { /* P_IRECNO */ 02086 ri = GET_RINTERNAL(h, 0); 02087 current = ri->pgno; 02088 } 02089 break; 02090 case P_LBTREE: 02091 case P_LRECNO: 02092 goto traverse; 02093 /* NOTREACHED */ 02094 default: 02095 err_ret = DB_VERIFY_BAD; 02096 goto err; 02097 } 02098 02099 if ((ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0) 02100 err_ret = ret; 02101 h = NULL; 02102 } 02103 02104 /* 02105 * At this point, current is the pgno of leaf page h, the 0th in the 02106 * tree we're concerned with. 02107 */ 02108 traverse: 02109 while (IS_VALID_PGNO(current) && current != PGNO_INVALID) { 02110 if (h == NULL && 02111 (ret = CDB_memp_fget(dbp->mpf, ¤t, 0, &h) != 0)) { 02112 err_ret = ret; 02113 break; 02114 } 02115 02116 if ((ret = CDB___db_vrfy_pgset_get(pgset, current, (int *)&p)) != 0) 02117 goto err; 02118 02119 if (p != 0) { 02120 /* 02121 * We've found a cycle. Return success anyway-- 02122 * our caller may as well use however much of 02123 * the pgset we've come up with. 02124 */ 02125 break; 02126 } 02127 if ((ret = CDB___db_vrfy_pgset_inc(pgset, current)) != 0) 02128 goto err; 02129 02130 current = NEXT_PGNO(h); 02131 if ((ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0) 02132 err_ret = ret; 02133 h = NULL; 02134 } 02135 02136 err: if (h != NULL) 02137 (void)CDB_memp_fput(dbp->mpf, h, 0); 02138 02139 return (ret == 0 ? err_ret : ret); 02140 } 02141 02142 /* 02143 * __bam_safe_getdata -- 02144 * 02145 * Utility function for CDB___bam_vrfy_itemorder. Safely gets the datum at 02146 * index i, page h, and sticks it in DBT dbt. If ovflok is 1 and i's an 02147 * overflow item, we do a safe_goff to get the item and signal that we need 02148 * to free dbt->data; if ovflok is 0, we leaves the DBT zeroed. 02149 */ 02150 static int 02151 __bam_safe_getdata(dbp, h, i, ovflok, dbt, freedbtp) 02152 DB *dbp; 02153 PAGE *h; 02154 u_int32_t i; 02155 int ovflok; 02156 DBT *dbt; 02157 int *freedbtp; 02158 { 02159 BKEYDATA *bk; 02160 BOVERFLOW *bo; 02161 02162 memset(dbt, 0, sizeof(DBT)); 02163 *freedbtp = 0; 02164 02165 bk = GET_BKEYDATA(h, i); 02166 if (B_TYPE(bk->type) == B_OVERFLOW) { 02167 if (!ovflok) 02168 return(0); 02169 02170 bo = (BOVERFLOW *)bk; 02171 F_SET(dbt, DB_DBT_MALLOC); 02172 02173 *freedbtp = 1; 02174 return (CDB___db_goff(dbp, dbt, bo->tlen, bo->pgno, NULL, NULL)); 02175 /* NOTREACHED */ 02176 } else { 02177 dbt->data = bk->data; 02178 dbt->size = bk->len; 02179 } 02180 02181 return (0); 02182 }