1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2000,2008 Oracle. All rights reserved. 5 * 6 * $Id: db_vrfyutil.c,v 12.22 2008/03/18 17:29:39 mbrey Exp $ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12#include "dbinc/db_page.h" 13#include "dbinc/db_verify.h" 14#include "dbinc/db_am.h" 15 16static int __db_vrfy_childinc __P((DBC *, VRFY_CHILDINFO *)); 17static int __db_vrfy_pageinfo_create __P((ENV *, VRFY_PAGEINFO **)); 18 19/* 20 * __db_vrfy_dbinfo_create -- 21 * Allocate and initialize a VRFY_DBINFO structure. 22 * 23 * PUBLIC: int __db_vrfy_dbinfo_create 24 * PUBLIC: __P((ENV *, DB_THREAD_INFO *, u_int32_t, VRFY_DBINFO **)); 25 */ 26int 27__db_vrfy_dbinfo_create(env, ip, pgsize, vdpp) 28 ENV *env; 29 DB_THREAD_INFO *ip; 30 u_int32_t pgsize; 31 VRFY_DBINFO **vdpp; 32{ 33 DB *cdbp, *pgdbp, *pgset; 34 VRFY_DBINFO *vdp; 35 int ret; 36 37 vdp = NULL; 38 cdbp = pgdbp = pgset = NULL; 39 40 if ((ret = __os_calloc(NULL, 1, sizeof(VRFY_DBINFO), &vdp)) != 0) 41 goto err; 42 43 if ((ret = __db_create_internal(&cdbp, env, 0)) != 0) 44 goto err; 45 46 if ((ret = __db_set_flags(cdbp, DB_DUP)) != 0) 47 goto err; 48 49 if ((ret = __db_set_pagesize(cdbp, pgsize)) != 0) 50 goto err; 51 52 /* If transactional, make sure we don't log. */ 53 if (TXN_ON(env) && 54 (ret = __db_set_flags(cdbp, DB_TXN_NOT_DURABLE)) != 0) 55 goto err; 56 if ((ret = __db_open(cdbp, ip, 57 NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0600, PGNO_BASE_MD)) != 0) 58 goto err; 59 60 if ((ret = __db_create_internal(&pgdbp, env, 0)) != 0) 61 goto err; 62 63 if ((ret = __db_set_pagesize(pgdbp, pgsize)) != 0) 64 goto err; 65 66 /* If transactional, make sure we don't log. */ 67 if (TXN_ON(env) && 68 (ret = __db_set_flags(pgdbp, DB_TXN_NOT_DURABLE)) != 0) 69 goto err; 70 71 if ((ret = __db_open(pgdbp, ip, 72 NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0600, PGNO_BASE_MD)) != 0) 73 goto err; 74 75 if ((ret = __db_vrfy_pgset(env, ip, pgsize, &pgset)) != 0) 76 goto err; 77 78 LIST_INIT(&vdp->subdbs); 79 LIST_INIT(&vdp->activepips); 80 81 vdp->cdbp = cdbp; 82 vdp->pgdbp = pgdbp; 83 vdp->pgset = pgset; 84 vdp->thread_info = ip; 85 *vdpp = vdp; 86 return (0); 87 88err: if (cdbp != NULL) 89 (void)__db_close(cdbp, NULL, 0); 90 if (pgdbp != NULL) 91 (void)__db_close(pgdbp, NULL, 0); 92 if (vdp != NULL) 93 __os_free(env, vdp); 94 return (ret); 95} 96 97/* 98 * __db_vrfy_dbinfo_destroy -- 99 * Destructor for VRFY_DBINFO. Destroys VRFY_PAGEINFOs and deallocates 100 * structure. 101 * 102 * PUBLIC: int __db_vrfy_dbinfo_destroy __P((ENV *, VRFY_DBINFO *)); 103 */ 104int 105__db_vrfy_dbinfo_destroy(env, vdp) 106 ENV *env; 107 VRFY_DBINFO *vdp; 108{ 109 VRFY_CHILDINFO *c; 110 int t_ret, ret; 111 112 ret = 0; 113 114 /* 115 * Discard active page structures. Ideally there wouldn't be any, 116 * but in some error cases we may not have cleared them all out. 117 */ 118 while (LIST_FIRST(&vdp->activepips) != NULL) 119 if ((t_ret = __db_vrfy_putpageinfo( 120 env, vdp, LIST_FIRST(&vdp->activepips))) != 0) { 121 if (ret == 0) 122 ret = t_ret; 123 break; 124 } 125 126 /* Discard subdatabase list structures. */ 127 while ((c = LIST_FIRST(&vdp->subdbs)) != NULL) { 128 LIST_REMOVE(c, links); 129 __os_free(NULL, c); 130 } 131 132 if ((t_ret = __db_close(vdp->pgdbp, NULL, 0)) != 0) 133 ret = t_ret; 134 135 if ((t_ret = __db_close(vdp->cdbp, NULL, 0)) != 0 && ret == 0) 136 ret = t_ret; 137 138 if ((t_ret = __db_close(vdp->pgset, NULL, 0)) != 0 && ret == 0) 139 ret = t_ret; 140 141 if (vdp->extents != NULL) 142 __os_free(env, vdp->extents); 143 __os_free(env, vdp); 144 return (ret); 145} 146 147/* 148 * __db_vrfy_getpageinfo -- 149 * Get a PAGEINFO structure for a given page, creating it if necessary. 150 * 151 * PUBLIC: int __db_vrfy_getpageinfo 152 * PUBLIC: __P((VRFY_DBINFO *, db_pgno_t, VRFY_PAGEINFO **)); 153 */ 154int 155__db_vrfy_getpageinfo(vdp, pgno, pipp) 156 VRFY_DBINFO *vdp; 157 db_pgno_t pgno; 158 VRFY_PAGEINFO **pipp; 159{ 160 DB *pgdbp; 161 DBT key, data; 162 ENV *env; 163 VRFY_PAGEINFO *pip; 164 int ret; 165 166 /* 167 * We want a page info struct. There are three places to get it from, 168 * in decreasing order of preference: 169 * 170 * 1. vdp->activepips. If it's already "checked out", we're 171 * already using it, we return the same exact structure with a 172 * bumped refcount. This is necessary because this code is 173 * replacing array accesses, and it's common for f() to make some 174 * changes to a pip, and then call g() and h() which each make 175 * changes to the same pip. vdps are never shared between threads 176 * (they're never returned to the application), so this is safe. 177 * 2. The pgdbp. It's not in memory, but it's in the database, so 178 * get it, give it a refcount of 1, and stick it on activepips. 179 * 3. malloc. It doesn't exist yet; create it, then stick it on 180 * activepips. We'll put it in the database when we putpageinfo 181 * later. 182 */ 183 184 /* Case 1. */ 185 LIST_FOREACH(pip, &vdp->activepips, links) 186 if (pip->pgno == pgno) 187 goto found; 188 189 /* Case 2. */ 190 pgdbp = vdp->pgdbp; 191 env = pgdbp->env; 192 memset(&key, 0, sizeof(DBT)); 193 memset(&data, 0, sizeof(DBT)); 194 F_SET(&data, DB_DBT_MALLOC); 195 key.data = &pgno; 196 key.size = sizeof(db_pgno_t); 197 198 if ((ret = __db_get(pgdbp, 199 vdp->thread_info, NULL, &key, &data, 0)) == 0) { 200 /* Found it. */ 201 DB_ASSERT(env, data.size == sizeof(VRFY_PAGEINFO)); 202 pip = data.data; 203 LIST_INSERT_HEAD(&vdp->activepips, pip, links); 204 goto found; 205 } else if (ret != DB_NOTFOUND) /* Something nasty happened. */ 206 return (ret); 207 208 /* Case 3 */ 209 if ((ret = __db_vrfy_pageinfo_create(env, &pip)) != 0) 210 return (ret); 211 212 LIST_INSERT_HEAD(&vdp->activepips, pip, links); 213found: pip->pi_refcount++; 214 215 *pipp = pip; 216 return (0); 217} 218 219/* 220 * __db_vrfy_putpageinfo -- 221 * Put back a VRFY_PAGEINFO that we're done with. 222 * 223 * PUBLIC: int __db_vrfy_putpageinfo __P((ENV *, 224 * PUBLIC: VRFY_DBINFO *, VRFY_PAGEINFO *)); 225 */ 226int 227__db_vrfy_putpageinfo(env, vdp, pip) 228 ENV *env; 229 VRFY_DBINFO *vdp; 230 VRFY_PAGEINFO *pip; 231{ 232 DB *pgdbp; 233 DBT key, data; 234 VRFY_PAGEINFO *p; 235 int ret; 236 237 if (--pip->pi_refcount > 0) 238 return (0); 239 240 pgdbp = vdp->pgdbp; 241 memset(&key, 0, sizeof(DBT)); 242 memset(&data, 0, sizeof(DBT)); 243 244 key.data = &pip->pgno; 245 key.size = sizeof(db_pgno_t); 246 data.data = pip; 247 data.size = sizeof(VRFY_PAGEINFO); 248 249 if ((ret = __db_put(pgdbp, 250 vdp->thread_info, NULL, &key, &data, 0)) != 0) 251 return (ret); 252 253 LIST_FOREACH(p, &vdp->activepips, links) 254 if (p == pip) 255 break; 256 if (p != NULL) 257 LIST_REMOVE(p, links); 258 259 __os_ufree(env, p); 260 return (0); 261} 262 263/* 264 * __db_vrfy_pgset -- 265 * Create a temporary database for the storing of sets of page numbers. 266 * (A mapping from page number to int, used by the *_meta2pgset functions, 267 * as well as for keeping track of which pages the verifier has seen.) 268 * 269 * PUBLIC: int __db_vrfy_pgset __P((ENV *, 270 * PUBLIC: DB_THREAD_INFO *, u_int32_t, DB **)); 271 */ 272int 273__db_vrfy_pgset(env, ip, pgsize, dbpp) 274 ENV *env; 275 DB_THREAD_INFO *ip; 276 u_int32_t pgsize; 277 DB **dbpp; 278{ 279 DB *dbp; 280 int ret; 281 282 if ((ret = __db_create_internal(&dbp, env, 0)) != 0) 283 return (ret); 284 if ((ret = __db_set_pagesize(dbp, pgsize)) != 0) 285 goto err; 286 287 /* If transactional, make sure we don't log. */ 288 if (TXN_ON(env) && 289 (ret = __db_set_flags(dbp, DB_TXN_NOT_DURABLE)) != 0) 290 goto err; 291 if ((ret = __db_open(dbp, ip, 292 NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0600, PGNO_BASE_MD)) == 0) 293 *dbpp = dbp; 294 else 295err: (void)__db_close(dbp, NULL, 0); 296 297 return (ret); 298} 299 300/* 301 * __db_vrfy_pgset_get -- 302 * Get the value associated in a page set with a given pgno. Return 303 * a 0 value (and succeed) if we've never heard of this page. 304 * 305 * PUBLIC: int __db_vrfy_pgset_get __P((DB *, DB_THREAD_INFO *, db_pgno_t, 306 * PUBLIC: int *)); 307 */ 308int 309__db_vrfy_pgset_get(dbp, ip, pgno, valp) 310 DB *dbp; 311 DB_THREAD_INFO *ip; 312 db_pgno_t pgno; 313 int *valp; 314{ 315 DBT key, data; 316 int ret, val; 317 318 memset(&key, 0, sizeof(DBT)); 319 memset(&data, 0, sizeof(DBT)); 320 321 key.data = &pgno; 322 key.size = sizeof(db_pgno_t); 323 data.data = &val; 324 data.ulen = sizeof(int); 325 F_SET(&data, DB_DBT_USERMEM); 326 327 if ((ret = __db_get(dbp, ip, NULL, &key, &data, 0)) == 0) { 328 DB_ASSERT(dbp->env, data.size == sizeof(int)); 329 } else if (ret == DB_NOTFOUND) 330 val = 0; 331 else 332 return (ret); 333 334 *valp = val; 335 return (0); 336} 337 338/* 339 * __db_vrfy_pgset_inc -- 340 * Increment the value associated with a pgno by 1. 341 * 342 * PUBLIC: int __db_vrfy_pgset_inc __P((DB *, DB_THREAD_INFO *, db_pgno_t)); 343 */ 344int 345__db_vrfy_pgset_inc(dbp, ip, pgno) 346 DB *dbp; 347 DB_THREAD_INFO *ip; 348 db_pgno_t pgno; 349{ 350 DBT key, data; 351 int ret; 352 int val; 353 354 memset(&key, 0, sizeof(DBT)); 355 memset(&data, 0, sizeof(DBT)); 356 357 val = 0; 358 359 key.data = &pgno; 360 key.size = sizeof(db_pgno_t); 361 data.data = &val; 362 data.ulen = sizeof(int); 363 F_SET(&data, DB_DBT_USERMEM); 364 365 if ((ret = __db_get(dbp, ip, NULL, &key, &data, 0)) == 0) { 366 DB_ASSERT(dbp->env, data.size == sizeof(int)); 367 } else if (ret != DB_NOTFOUND) 368 return (ret); 369 370 data.size = sizeof(int); 371 ++val; 372 373 return (__db_put(dbp, ip, NULL, &key, &data, 0)); 374} 375 376/* 377 * __db_vrfy_pgset_next -- 378 * Given a cursor open in a pgset database, get the next page in the 379 * set. 380 * 381 * PUBLIC: int __db_vrfy_pgset_next __P((DBC *, db_pgno_t *)); 382 */ 383int 384__db_vrfy_pgset_next(dbc, pgnop) 385 DBC *dbc; 386 db_pgno_t *pgnop; 387{ 388 DBT key, data; 389 db_pgno_t pgno; 390 int ret; 391 392 memset(&key, 0, sizeof(DBT)); 393 memset(&data, 0, sizeof(DBT)); 394 /* We don't care about the data, just the keys. */ 395 F_SET(&data, DB_DBT_USERMEM | DB_DBT_PARTIAL); 396 F_SET(&key, DB_DBT_USERMEM); 397 key.data = &pgno; 398 key.ulen = sizeof(db_pgno_t); 399 400 if ((ret = __dbc_get(dbc, &key, &data, DB_NEXT)) != 0) 401 return (ret); 402 403 DB_ASSERT(dbc->env, key.size == sizeof(db_pgno_t)); 404 *pgnop = pgno; 405 406 return (0); 407} 408 409/* 410 * __db_vrfy_childcursor -- 411 * Create a cursor to walk the child list with. Returns with a nonzero 412 * final argument if the specified page has no children. 413 * 414 * PUBLIC: int __db_vrfy_childcursor __P((VRFY_DBINFO *, DBC **)); 415 */ 416int 417__db_vrfy_childcursor(vdp, dbcp) 418 VRFY_DBINFO *vdp; 419 DBC **dbcp; 420{ 421 DB *cdbp; 422 DBC *dbc; 423 int ret; 424 425 cdbp = vdp->cdbp; 426 427 if ((ret = __db_cursor(cdbp, vdp->thread_info, NULL, &dbc, 0)) == 0) 428 *dbcp = dbc; 429 430 return (ret); 431} 432 433/* 434 * __db_vrfy_childput -- 435 * Add a child structure to the set for a given page. 436 * 437 * PUBLIC: int __db_vrfy_childput 438 * PUBLIC: __P((VRFY_DBINFO *, db_pgno_t, VRFY_CHILDINFO *)); 439 */ 440int 441__db_vrfy_childput(vdp, pgno, cip) 442 VRFY_DBINFO *vdp; 443 db_pgno_t pgno; 444 VRFY_CHILDINFO *cip; 445{ 446 DB *cdbp; 447 DBC *cc; 448 DBT key, data; 449 VRFY_CHILDINFO *oldcip; 450 int ret; 451 452 cdbp = vdp->cdbp; 453 memset(&key, 0, sizeof(DBT)); 454 memset(&data, 0, sizeof(DBT)); 455 456 key.data = &pgno; 457 key.size = sizeof(db_pgno_t); 458 459 /* 460 * We want to avoid adding multiple entries for a single child page; 461 * we only need to verify each child once, even if a child (such 462 * as an overflow key) is multiply referenced. 463 * 464 * However, we also need to make sure that when walking the list 465 * of children, we encounter them in the order they're referenced 466 * on a page. (This permits us, for example, to verify the 467 * prev_pgno/next_pgno chain of Btree leaf pages.) 468 * 469 * Check the child database to make sure that this page isn't 470 * already a child of the specified page number. If it's not, 471 * put it at the end of the duplicate set. 472 */ 473 if ((ret = __db_vrfy_childcursor(vdp, &cc)) != 0) 474 return (ret); 475 for (ret = __db_vrfy_ccset(cc, pgno, &oldcip); ret == 0; 476 ret = __db_vrfy_ccnext(cc, &oldcip)) 477 if (oldcip->pgno == cip->pgno) { 478 /* 479 * Found a matching child. Increment its reference 480 * count--we've run into it again--but don't put it 481 * again. 482 */ 483 if ((ret = __db_vrfy_childinc(cc, oldcip)) != 0 || 484 (ret = __db_vrfy_ccclose(cc)) != 0) 485 return (ret); 486 return (0); 487 } 488 if (ret != DB_NOTFOUND) { 489 (void)__db_vrfy_ccclose(cc); 490 return (ret); 491 } 492 if ((ret = __db_vrfy_ccclose(cc)) != 0) 493 return (ret); 494 495 cip->refcnt = 1; 496 data.data = cip; 497 data.size = sizeof(VRFY_CHILDINFO); 498 499 return (__db_put(cdbp, vdp->thread_info, NULL, &key, &data, 0)); 500} 501 502/* 503 * __db_vrfy_childinc -- 504 * Increment the refcount of the VRFY_CHILDINFO struct that the child 505 * cursor is pointing to. (The caller has just retrieved this struct, and 506 * passes it in as cip to save us a get.) 507 */ 508static int 509__db_vrfy_childinc(dbc, cip) 510 DBC *dbc; 511 VRFY_CHILDINFO *cip; 512{ 513 DBT key, data; 514 515 memset(&key, 0, sizeof(DBT)); 516 memset(&data, 0, sizeof(DBT)); 517 518 cip->refcnt++; 519 data.data = cip; 520 data.size = sizeof(VRFY_CHILDINFO); 521 522 return (__dbc_put(dbc, &key, &data, DB_CURRENT)); 523} 524 525/* 526 * __db_vrfy_ccset -- 527 * Sets a cursor created with __db_vrfy_childcursor to the first 528 * child of the given pgno, and returns it in the third arg. 529 * 530 * PUBLIC: int __db_vrfy_ccset __P((DBC *, db_pgno_t, VRFY_CHILDINFO **)); 531 */ 532int 533__db_vrfy_ccset(dbc, pgno, cipp) 534 DBC *dbc; 535 db_pgno_t pgno; 536 VRFY_CHILDINFO **cipp; 537{ 538 DBT key, data; 539 int ret; 540 541 memset(&key, 0, sizeof(DBT)); 542 memset(&data, 0, sizeof(DBT)); 543 544 key.data = &pgno; 545 key.size = sizeof(db_pgno_t); 546 547 if ((ret = __dbc_get(dbc, &key, &data, DB_SET)) != 0) 548 return (ret); 549 550 DB_ASSERT(dbc->env, data.size == sizeof(VRFY_CHILDINFO)); 551 *cipp = (VRFY_CHILDINFO *)data.data; 552 553 return (0); 554} 555 556/* 557 * __db_vrfy_ccnext -- 558 * Gets the next child of the given cursor created with 559 * __db_vrfy_childcursor, and returns it in the memory provided in the 560 * second arg. 561 * 562 * PUBLIC: int __db_vrfy_ccnext __P((DBC *, VRFY_CHILDINFO **)); 563 */ 564int 565__db_vrfy_ccnext(dbc, cipp) 566 DBC *dbc; 567 VRFY_CHILDINFO **cipp; 568{ 569 DBT key, data; 570 int ret; 571 572 memset(&key, 0, sizeof(DBT)); 573 memset(&data, 0, sizeof(DBT)); 574 575 if ((ret = __dbc_get(dbc, &key, &data, DB_NEXT_DUP)) != 0) 576 return (ret); 577 578 DB_ASSERT(dbc->env, data.size == sizeof(VRFY_CHILDINFO)); 579 *cipp = (VRFY_CHILDINFO *)data.data; 580 581 return (0); 582} 583 584/* 585 * __db_vrfy_ccclose -- 586 * Closes the cursor created with __db_vrfy_childcursor. 587 * 588 * This doesn't actually do anything interesting now, but it's 589 * not inconceivable that we might change the internal database usage 590 * and keep the interfaces the same, and a function call here or there 591 * seldom hurts anyone. 592 * 593 * PUBLIC: int __db_vrfy_ccclose __P((DBC *)); 594 */ 595int 596__db_vrfy_ccclose(dbc) 597 DBC *dbc; 598{ 599 600 return (__dbc_close(dbc)); 601} 602 603/* 604 * __db_vrfy_pageinfo_create -- 605 * Constructor for VRFY_PAGEINFO; allocates and initializes. 606 */ 607static int 608__db_vrfy_pageinfo_create(env, pipp) 609 ENV *env; 610 VRFY_PAGEINFO **pipp; 611{ 612 VRFY_PAGEINFO *pip; 613 int ret; 614 615 /* 616 * pageinfo structs are sometimes allocated here and sometimes 617 * allocated by fetching them from a database with DB_DBT_MALLOC. 618 * There's no easy way for the destructor to tell which was 619 * used, and so we always allocate with __os_umalloc so we can free 620 * with __os_ufree. 621 */ 622 if ((ret = __os_umalloc(env, sizeof(VRFY_PAGEINFO), &pip)) != 0) 623 return (ret); 624 memset(pip, 0, sizeof(VRFY_PAGEINFO)); 625 626 *pipp = pip; 627 return (0); 628} 629 630/* 631 * __db_salvage_init -- 632 * Set up salvager database. 633 * 634 * PUBLIC: int __db_salvage_init __P((VRFY_DBINFO *)); 635 */ 636int 637__db_salvage_init(vdp) 638 VRFY_DBINFO *vdp; 639{ 640 DB *dbp; 641 int ret; 642 643 if ((ret = __db_create_internal(&dbp, NULL, 0)) != 0) 644 return (ret); 645 646 if ((ret = __db_set_pagesize(dbp, 1024)) != 0) 647 goto err; 648 649 if ((ret = __db_open(dbp, vdp->thread_info, 650 NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0, PGNO_BASE_MD)) != 0) 651 goto err; 652 653 vdp->salvage_pages = dbp; 654 return (0); 655 656err: (void)__db_close(dbp, NULL, 0); 657 return (ret); 658} 659 660/* 661 * __db_salvage_destroy -- 662 * Close salvager database. 663 * PUBLIC: void __db_salvage_destroy __P((VRFY_DBINFO *)); 664 */ 665void 666__db_salvage_destroy(vdp) 667 VRFY_DBINFO *vdp; 668{ 669 (void)__db_close(vdp->salvage_pages, NULL, 0); 670} 671 672/* 673 * __db_salvage_getnext -- 674 * Get the next (first) unprinted page in the database of pages we need to 675 * print still. Delete entries for any already-printed pages we encounter 676 * in this search, as well as the page we're returning. 677 * 678 * PUBLIC: int __db_salvage_getnext 679 * PUBLIC: __P((VRFY_DBINFO *, DBC **, db_pgno_t *, u_int32_t *, int)); 680 */ 681int 682__db_salvage_getnext(vdp, dbcp, pgnop, pgtypep, skip_overflow) 683 VRFY_DBINFO *vdp; 684 DBC **dbcp; 685 db_pgno_t *pgnop; 686 u_int32_t *pgtypep; 687 int skip_overflow; 688{ 689 DB *dbp; 690 DBT key, data; 691 int ret; 692 u_int32_t pgtype; 693 694 dbp = vdp->salvage_pages; 695 696 memset(&key, 0, sizeof(DBT)); 697 memset(&data, 0, sizeof(DBT)); 698 699 if (*dbcp == NULL && 700 (ret = __db_cursor(dbp, vdp->thread_info, NULL, dbcp, 0)) != 0) 701 return (ret); 702 703 while ((ret = __dbc_get(*dbcp, &key, &data, DB_NEXT)) == 0) { 704 DB_ASSERT(dbp->env, data.size == sizeof(u_int32_t)); 705 memcpy(&pgtype, data.data, sizeof(pgtype)); 706 707 if (skip_overflow && pgtype == SALVAGE_OVERFLOW) 708 continue; 709 710 if ((ret = __dbc_del(*dbcp, 0)) != 0) 711 return (ret); 712 if (pgtype != SALVAGE_IGNORE) { 713 DB_ASSERT(dbp->env, key.size == sizeof(db_pgno_t)); 714 DB_ASSERT(dbp->env, data.size == sizeof(u_int32_t)); 715 716 *pgnop = *(db_pgno_t *)key.data; 717 *pgtypep = *(u_int32_t *)data.data; 718 break; 719 } 720 } 721 722 return (ret); 723} 724 725/* 726 * __db_salvage_isdone -- 727 * Return whether or not the given pgno is already marked 728 * SALVAGE_IGNORE (meaning that we don't need to print it again). 729 * 730 * Returns DB_KEYEXIST if it is marked, 0 if not, or another error on 731 * error. 732 * 733 * PUBLIC: int __db_salvage_isdone __P((VRFY_DBINFO *, db_pgno_t)); 734 */ 735int 736__db_salvage_isdone(vdp, pgno) 737 VRFY_DBINFO *vdp; 738 db_pgno_t pgno; 739{ 740 DB *dbp; 741 DBT key, data; 742 int ret; 743 u_int32_t currtype; 744 745 dbp = vdp->salvage_pages; 746 747 memset(&key, 0, sizeof(DBT)); 748 memset(&data, 0, sizeof(DBT)); 749 750 currtype = SALVAGE_INVALID; 751 data.data = &currtype; 752 data.ulen = sizeof(u_int32_t); 753 data.flags = DB_DBT_USERMEM; 754 755 key.data = &pgno; 756 key.size = sizeof(db_pgno_t); 757 758 /* 759 * Put an entry for this page, with pgno as key and type as data, 760 * unless it's already there and is marked done. 761 * If it's there and is marked anything else, that's fine--we 762 * want to mark it done. 763 */ 764 if ((ret = __db_get(dbp, 765 vdp->thread_info, NULL, &key, &data, 0)) == 0) { 766 /* 767 * The key's already here. Check and see if it's already 768 * marked done. If it is, return DB_KEYEXIST. If it's not, 769 * return 0. 770 */ 771 if (currtype == SALVAGE_IGNORE) 772 return (DB_KEYEXIST); 773 else 774 return (0); 775 } else if (ret != DB_NOTFOUND) 776 return (ret); 777 778 /* The pgno is not yet marked anything; return 0. */ 779 return (0); 780} 781 782/* 783 * __db_salvage_markdone -- 784 * Mark as done a given page. 785 * 786 * PUBLIC: int __db_salvage_markdone __P((VRFY_DBINFO *, db_pgno_t)); 787 */ 788int 789__db_salvage_markdone(vdp, pgno) 790 VRFY_DBINFO *vdp; 791 db_pgno_t pgno; 792{ 793 DB *dbp; 794 DBT key, data; 795 int pgtype, ret; 796 u_int32_t currtype; 797 798 pgtype = SALVAGE_IGNORE; 799 dbp = vdp->salvage_pages; 800 801 memset(&key, 0, sizeof(DBT)); 802 memset(&data, 0, sizeof(DBT)); 803 804 currtype = SALVAGE_INVALID; 805 data.data = &currtype; 806 data.ulen = sizeof(u_int32_t); 807 data.flags = DB_DBT_USERMEM; 808 809 key.data = &pgno; 810 key.size = sizeof(db_pgno_t); 811 812 /* 813 * Put an entry for this page, with pgno as key and type as data, 814 * unless it's already there and is marked done. 815 * If it's there and is marked anything else, that's fine--we 816 * want to mark it done, but db_salvage_isdone only lets 817 * us know if it's marked IGNORE. 818 * 819 * We don't want to return DB_KEYEXIST, though; this will 820 * likely get passed up all the way and make no sense to the 821 * application. Instead, use DB_VERIFY_BAD to indicate that 822 * we've seen this page already--it probably indicates a 823 * multiply-linked page. 824 */ 825 if ((ret = __db_salvage_isdone(vdp, pgno)) != 0) 826 return (ret == DB_KEYEXIST ? DB_VERIFY_BAD : ret); 827 828 data.size = sizeof(u_int32_t); 829 data.data = &pgtype; 830 831 return (__db_put(dbp, vdp->thread_info, NULL, &key, &data, 0)); 832} 833 834/* 835 * __db_salvage_markneeded -- 836 * If it has not yet been printed, make note of the fact that a page 837 * must be dealt with later. 838 * 839 * PUBLIC: int __db_salvage_markneeded 840 * PUBLIC: __P((VRFY_DBINFO *, db_pgno_t, u_int32_t)); 841 */ 842int 843__db_salvage_markneeded(vdp, pgno, pgtype) 844 VRFY_DBINFO *vdp; 845 db_pgno_t pgno; 846 u_int32_t pgtype; 847{ 848 DB *dbp; 849 DBT key, data; 850 int ret; 851 852 dbp = vdp->salvage_pages; 853 854 memset(&key, 0, sizeof(DBT)); 855 memset(&data, 0, sizeof(DBT)); 856 857 key.data = &pgno; 858 key.size = sizeof(db_pgno_t); 859 860 data.data = &pgtype; 861 data.size = sizeof(u_int32_t); 862 863 /* 864 * Put an entry for this page, with pgno as key and type as data, 865 * unless it's already there, in which case it's presumably 866 * already been marked done. 867 */ 868 ret = __db_put(dbp, 869 vdp->thread_info, NULL, &key, &data, DB_NOOVERWRITE); 870 return (ret == DB_KEYEXIST ? 0 : ret); 871} 872 873/* 874 * __db_vrfy_prdbt -- 875 * Print out a DBT data element from a verification routine. 876 * 877 * PUBLIC: int __db_vrfy_prdbt __P((DBT *, int, const char *, void *, 878 * PUBLIC: int (*)(void *, const void *), int, VRFY_DBINFO *)); 879 */ 880int 881__db_vrfy_prdbt(dbtp, checkprint, prefix, handle, callback, is_recno, vdp) 882 DBT *dbtp; 883 int checkprint; 884 const char *prefix; 885 void *handle; 886 int (*callback) __P((void *, const void *)); 887 int is_recno; 888 VRFY_DBINFO *vdp; 889{ 890 if (vdp != NULL) { 891 /* 892 * If vdp is non-NULL, we might be the first key in the 893 * "fake" subdatabase used for key/data pairs we can't 894 * associate with a known subdb. 895 * 896 * Check and clear the SALVAGE_PRINTHEADER flag; if 897 * it was set, print a subdatabase header. 898 */ 899 if (F_ISSET(vdp, SALVAGE_PRINTHEADER)) { 900 (void)__db_prheader( 901 NULL, "__OTHER__", 0, 0, handle, callback, vdp, 0); 902 F_CLR(vdp, SALVAGE_PRINTHEADER); 903 F_SET(vdp, SALVAGE_PRINTFOOTER); 904 } 905 906 /* 907 * Even if the printable flag wasn't set by our immediate 908 * caller, it may be set on a salvage-wide basis. 909 */ 910 if (F_ISSET(vdp, SALVAGE_PRINTABLE)) 911 checkprint = 1; 912 } 913 return ( 914 __db_prdbt(dbtp, checkprint, prefix, handle, callback, is_recno)); 915} 916