00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "config.h"
00011
00012 #ifndef lint
00013 static const char revid[] = "$Id: db__vrfy_8c-source.html,v 1.1 2008/06/08 10:18:28 sebdiaz Exp $";
00014 #endif
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_swap.h"
00026 #include "db_verify.h"
00027 #include "db_ext.h"
00028 #include "btree.h"
00029 #include "hash.h"
00030 #include "qam.h"
00031
00032 static int __db_guesspgsize __P((DB_ENV *, DB_FH *));
00033 static int __db_is_valid_magicno __P((u_int32_t, DBTYPE *));
00034 static int __db_is_valid_pagetype __P((u_int32_t));
00035 static int __db_meta2pgset
00036 __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, DB *));
00037 static int __db_salvage_subdbs
00038 __P((DB *, VRFY_DBINFO *, void *,
00039 int(*)(void *, const void *), u_int32_t, int *));
00040 static int __db_salvage_unknowns
00041 __P((DB *, VRFY_DBINFO *, void *,
00042 int (*)(void *, const void *), u_int32_t));
00043 static int __db_vrfy_common
00044 __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t));
00045 static int __db_vrfy_freelist __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t));
00046 static int __db_vrfy_invalid
00047 __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, u_int32_t));
00048 static int __db_vrfy_orderchkonly __P((DB *,
00049 VRFY_DBINFO *, const char *, const char *, u_int32_t));
00050 static int __db_vrfy_pagezero __P((DB *, VRFY_DBINFO *, DB_FH *, u_int32_t));
00051 static int __db_vrfy_subdbs __P((DB *, VRFY_DBINFO *, char *, u_int32_t));
00052 static int __db_vrfy_structure
00053 __P((DB *, VRFY_DBINFO *, char *, db_pgno_t, u_int32_t));
00054 static int __db_vrfy_walkpages
00055 __P((DB *, VRFY_DBINFO *, void *, int (*)(void *, const void *),
00056 u_int32_t));
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086 int
00087 CDB___db_verify(dbp, file, database, outfile, flags)
00088 DB *dbp;
00089 const char *file, *database;
00090 FILE *outfile;
00091 u_int32_t flags;
00092 {
00093
00094 return (CDB___db_verify_internal(dbp,
00095 file, database, outfile, CDB___db_verify_callback, flags));
00096 }
00097
00098
00099
00100
00101
00102
00103
00104 int
00105 CDB___db_verify_callback(handle, str_arg)
00106 void *handle;
00107 const void *str_arg;
00108 {
00109 char *str;
00110 FILE *f;
00111
00112 str = (char *)str_arg;
00113 f = (FILE *)handle;
00114
00115 if (fprintf(f, str) != (int)strlen(str))
00116 return (EIO);
00117
00118 return (0);
00119 }
00120
00121
00122
00123
00124
00125
00126
00127
00128 int
00129 CDB___db_verify_internal(dbp_orig, name, subdb, handle, callback, flags)
00130 DB *dbp_orig;
00131 const char *name, *subdb;
00132 void *handle;
00133 int (*callback) __P((void *, const void *));
00134 u_int32_t flags;
00135 {
00136 DB *dbp;
00137 DB_ENV *dbenv;
00138 DB_FH fh, *fhp;
00139 PAGE *h;
00140 VRFY_DBINFO *vdp;
00141 db_pgno_t last;
00142 int has, ret, isbad;
00143 char *real_name;
00144
00145 dbenv = dbp_orig->dbenv;
00146 vdp = NULL;
00147 real_name = NULL;
00148 ret = isbad = 0;
00149
00150 memset(&fh, 0, sizeof(fh));
00151 fhp = &fh;
00152
00153 PANIC_CHECK(dbenv);
00154 DB_ILLEGAL_AFTER_OPEN(dbp_orig, "verify");
00155
00156 #define OKFLAGS (DB_AGGRESSIVE | DB_NOORDERCHK | DB_ORDERCHKONLY | DB_SALVAGE)
00157 if ((ret = CDB___db_fchk(dbenv, "DB->verify", flags, OKFLAGS)) != 0)
00158 return (ret);
00159
00160
00161
00162
00163
00164 if (LF_ISSET(DB_SALVAGE) &&
00165 (flags & ~DB_AGGRESSIVE) != DB_SALVAGE)
00166 return (CDB___db_ferr(dbenv, "CDB___db_verify", 1));
00167
00168 if (LF_ISSET(DB_ORDERCHKONLY) && flags != DB_ORDERCHKONLY)
00169 return (CDB___db_ferr(dbenv, "CDB___db_verify", 1));
00170
00171 if (LF_ISSET(DB_ORDERCHKONLY) && subdb == NULL) {
00172 CDB___db_err(dbenv, "DB_ORDERCHKONLY requires a database name");
00173 return (EINVAL);
00174 }
00175
00176
00177
00178
00179
00180
00181
00182 if (TXN_ON(dbenv) || LOCKING_ON(dbenv) || LOGGING_ON(dbenv)) {
00183 dbp_orig->errx(dbp_orig,
00184 "verify may not be used with transactions, logging, or locking");
00185 return (EINVAL);
00186
00187 }
00188
00189
00190 if ((ret = CDB_db_create(&dbp, dbenv, 0)) != 0)
00191 goto err;
00192
00193
00194 if (dbp_orig->pgsize >= DB_MIN_PGSIZE &&
00195 dbp_orig->pgsize <= DB_MAX_PGSIZE)
00196 dbp->set_pagesize(dbp, dbp_orig->pgsize);
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207 if ((ret = CDB___db_vrfy_dbinfo_create(dbenv, 1024, &vdp)) != 0)
00208 goto err;
00209
00210
00211 if ((ret = CDB___db_appname(dbenv,
00212 DB_APP_DATA, NULL, name, 0, NULL, &real_name)) != 0)
00213 goto err;
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226 if ((ret = CDB___os_open(dbenv, real_name, DB_OSO_RDONLY, 0444, fhp)) != 0)
00227 goto err;
00228
00229
00230 if ((ret = __db_vrfy_pagezero(dbp, vdp, fhp, flags)) != 0) {
00231 if (ret == DB_VERIFY_BAD)
00232 isbad = 1;
00233 else
00234 goto err;
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 if ((ret = CDB___db_dbenv_setup(dbp,
00250 name, DB_ODDFILESIZE | DB_RDONLY)) != 0)
00251 return (ret);
00252
00253
00254
00255
00256
00257
00258
00259 if ((ret = CDB_memp_fget(dbp->mpf, &last, DB_MPOOL_LAST, &h)) != 0)
00260 goto err;
00261 if ((ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0)
00262 goto err;
00263
00264 vdp->last_pgno = last;
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275 if (LF_ISSET(DB_ORDERCHKONLY)) {
00276 ret = __db_vrfy_orderchkonly(dbp, vdp, name, subdb, flags);
00277 goto done;
00278 }
00279
00280
00281
00282
00283
00284
00285
00286 if (LF_ISSET(DB_SALVAGE)) {
00287 if ((ret = CDB___db_salvage_init(vdp)) != 0)
00288 return (ret);
00289
00290
00291
00292
00293
00294
00295
00296
00297 has = 0;
00298 if (!LF_ISSET(DB_AGGRESSIVE) && (__db_salvage_subdbs(dbp,
00299 vdp, handle, callback, flags, &has)) != 0)
00300 isbad = 1;
00301
00302
00303
00304
00305
00306
00307
00308
00309 if (has == 1)
00310 F_SET(vdp, SALVAGE_PRINTHEADER);
00311 else if ((ret = CDB___db_prheader(dbp,
00312 NULL, 0, 0, handle, callback, vdp, PGNO_BASE_MD)) != 0)
00313 goto err;
00314 }
00315
00316 if ((ret =
00317 __db_vrfy_walkpages(dbp, vdp, handle, callback, flags)) != 0) {
00318 if (ret == DB_VERIFY_BAD)
00319 isbad = 1;
00320 else if (ret != 0)
00321 goto err;
00322 }
00323
00324
00325 if (!LF_ISSET(DB_SALVAGE) && isbad == 0)
00326 if ((ret =
00327 __db_vrfy_structure(dbp, vdp, real_name, 0, flags)) != 0) {
00328 if (ret == DB_VERIFY_BAD)
00329 isbad = 1;
00330 else if (ret != 0)
00331 goto err;
00332 }
00333
00334
00335
00336
00337
00338
00339 if (LF_ISSET(DB_SALVAGE)) {
00340 if ((ret = __db_salvage_unknowns(dbp,
00341 vdp, handle, callback, flags)) != 0)
00342 isbad = 1;
00343
00344 CDB___db_salvage_destroy(vdp);
00345 }
00346
00347 if (0) {
00348 err: (void)CDB___db_err(dbenv, "%s: %s", name, CDB_db_strerror(ret));
00349 }
00350
00351 if (LF_ISSET(DB_SALVAGE) &&
00352 (has == 0 || F_ISSET(vdp, SALVAGE_PRINTFOOTER)))
00353 (void)CDB___db_prfooter(handle, callback);
00354
00355 done: if (F_ISSET(fhp, DB_FH_VALID))
00356 (void)CDB___os_closehandle(fhp);
00357 if (dbp)
00358 (void)dbp->close(dbp, 0);
00359 if (vdp)
00360 (void)CDB___db_vrfy_dbinfo_destroy(vdp);
00361 if (real_name)
00362 CDB___os_freestr(real_name);
00363
00364 if ((ret == 0 && isbad == 1) || ret == DB_VERIFY_FATAL)
00365 ret = DB_VERIFY_BAD;
00366
00367 return (ret);
00368 }
00369
00370
00371
00372
00373
00374
00375
00376
00377 static int
00378 __db_vrfy_pagezero(dbp, vdp, fhp, flags)
00379 DB *dbp;
00380 VRFY_DBINFO *vdp;
00381 DB_FH *fhp;
00382 u_int32_t flags;
00383 {
00384 DBMETA *meta;
00385 DB_ENV *dbenv;
00386 VRFY_PAGEINFO *pip;
00387 db_pgno_t freelist;
00388 int t_ret, ret, nr, swapped;
00389 u_int8_t mbuf[DBMETASIZE];
00390
00391 swapped = ret = t_ret = 0;
00392 freelist = 0;
00393 dbenv = dbp->dbenv;
00394 meta = (DBMETA *)mbuf;
00395 dbp->type = DB_UNKNOWN;
00396
00397
00398
00399
00400
00401
00402
00403 if ((ret = CDB___os_seek(dbenv, fhp, 0, 0, 0, 0, DB_OS_SEEK_SET)) != 0)
00404 goto err;
00405
00406 if ((ret = CDB___os_read(dbenv, fhp, mbuf, DBMETASIZE, (size_t *)&nr)) != 0)
00407 goto err;
00408
00409 if (nr != DBMETASIZE) {
00410 EPRINT((dbp->dbenv,
00411 "Incomplete metadata page %lu", PGNO_BASE_MD));
00412 t_ret = DB_VERIFY_FATAL;
00413 goto err;
00414 }
00415
00416
00417
00418
00419
00420
00421
00422 if (meta->pgno != PGNO_BASE_MD) {
00423 EPRINT((dbp->dbenv, "Bad pgno: was %lu, should be %lu",
00424 meta->pgno, PGNO_BASE_MD));
00425 ret = DB_VERIFY_BAD;
00426 }
00427
00428
00429 if (__db_is_valid_magicno(meta->magic, &dbp->type))
00430 swapped = 0;
00431 else {
00432 M_32_SWAP(meta->magic);
00433 if (__db_is_valid_magicno(meta->magic,
00434 &dbp->type))
00435 swapped = 1;
00436 else {
00437 EPRINT((dbp->dbenv, "Bad magic no.: %lu", meta->magic));
00438 ret = DB_VERIFY_BAD;
00439 }
00440 }
00441
00442
00443
00444
00445
00446 if (swapped)
00447 M_32_SWAP(meta->version);
00448 if ((dbp->type == DB_BTREE && meta->version != DB_BTREEVERSION) ||
00449 (dbp->type == DB_HASH && meta->version != DB_HASHVERSION) ||
00450 (dbp->type == DB_QUEUE && meta->version != DB_QAMVERSION)) {
00451 ret = DB_VERIFY_BAD;
00452 EPRINT((dbp->dbenv, "%s%s", "Old or incorrect DB ",
00453 "version; extraneous errors may result"));
00454 }
00455
00456
00457
00458
00459
00460 if (swapped)
00461 M_32_SWAP(meta->pagesize);
00462 if (IS_VALID_PAGESIZE(meta->pagesize))
00463 dbp->pgsize = meta->pagesize;
00464 else {
00465 EPRINT((dbp->dbenv, "Bad page size: %lu",
00466 meta->pagesize));
00467 ret = DB_VERIFY_BAD;
00468
00469
00470
00471
00472
00473
00474 if (!IS_VALID_PAGESIZE(dbp->pgsize))
00475 dbp->pgsize = __db_guesspgsize(dbenv, fhp);
00476 }
00477
00478
00479
00480
00481
00482
00483 if ((dbp->type == DB_BTREE && meta->type != P_BTREEMETA) ||
00484 (dbp->type == DB_HASH && meta->type != P_HASHMETA) ||
00485 (dbp->type == DB_QUEUE && meta->type != P_QAMMETA)) {
00486 ret = DB_VERIFY_BAD;
00487 EPRINT((dbp->dbenv, "Bad page type: %lu", meta->type));
00488 }
00489
00490
00491
00492
00493
00494
00495 if (swapped)
00496 M_32_SWAP(meta->free);
00497 freelist = meta->free;
00498
00499
00500
00501
00502
00503
00504 if ((ret = CDB___db_vrfy_getpageinfo(vdp, PGNO_BASE_MD, &pip)) != 0)
00505 return (ret);
00506 pip->pgno = PGNO_BASE_MD;
00507 pip->type = meta->type;
00508
00509
00510
00511
00512
00513 F_SET(pip, VRFY_INCOMPLETE);
00514
00515 pip->free = freelist;
00516
00517 if ((ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0)
00518 return (ret);
00519
00520 if (0) {
00521 err: CDB___db_err(dbenv, "%s", CDB_db_strerror(ret));
00522 }
00523
00524 if (swapped == 1)
00525 F_SET(dbp, DB_AM_SWAP);
00526 if (t_ret != 0)
00527 ret = t_ret;
00528 return (ret);
00529 }
00530
00531
00532
00533
00534
00535
00536 static int
00537 __db_vrfy_walkpages(dbp, vdp, handle, callback, flags)
00538 DB *dbp;
00539 VRFY_DBINFO *vdp;
00540 void *handle;
00541 int (*callback) __P((void *, const void *));
00542 u_int32_t flags;
00543 {
00544 DB_ENV *dbenv;
00545 PAGE *h;
00546 db_pgno_t i;
00547 int ret, t_ret, isbad;
00548
00549 ret = isbad = t_ret = 0;
00550 dbenv = dbp->dbenv;
00551
00552 if ((ret = CDB___db_fchk(dbenv,
00553 "__db_vrfy_walkpages", flags, OKFLAGS)) != 0)
00554 return (ret);
00555
00556 for (i = 0; i <= vdp->last_pgno; i++) {
00557
00558
00559
00560
00561
00562 if (LF_ISSET(DB_SALVAGE) && (CDB___db_salvage_isdone(vdp, i) != 0))
00563 continue;
00564
00565
00566 if ((t_ret = CDB_memp_fget(dbp->mpf, &i, 0, &h)) != 0) {
00567 if (ret == 0)
00568 ret = t_ret;
00569 continue;
00570 }
00571
00572 if (LF_ISSET(DB_SALVAGE)) {
00573
00574
00575
00576
00577
00578 if ((t_ret = CDB___db_salvage(dbp,
00579 vdp, i, h, handle, callback, flags)) != 0) {
00580 if (ret == 0)
00581 ret = t_ret;
00582 isbad = 1;
00583 }
00584 } else {
00585
00586
00587
00588
00589 if (i != PGNO_BASE_MD)
00590 if ((t_ret = __db_vrfy_common(dbp,
00591 vdp, h, i, flags)) == DB_VERIFY_BAD)
00592 isbad = 1;
00593
00594 switch (TYPE(h)) {
00595 case P_INVALID:
00596 t_ret = __db_vrfy_invalid(dbp,
00597 vdp, h, i, flags);
00598 break;
00599 case __P_DUPLICATE:
00600 isbad = 1;
00601 EPRINT((dbp->dbenv,
00602 "Old-style dup page %lu", i));
00603 break;
00604 case P_HASH:
00605 t_ret = CDB___ham_vrfy(dbp,
00606 vdp, h, i, flags);
00607 break;
00608 case P_IBTREE:
00609 case P_IRECNO:
00610 case P_LBTREE:
00611 case P_LDUP:
00612 t_ret = CDB___bam_vrfy(dbp,
00613 vdp, h, i, flags);
00614 break;
00615 case P_LRECNO:
00616 t_ret = CDB___ram_vrfy_leaf(dbp,
00617 vdp, h, i, flags);
00618 break;
00619 case P_OVERFLOW:
00620 t_ret = CDB___db_vrfy_overflow(dbp,
00621 vdp, h, i, flags);
00622 break;
00623 case P_HASHMETA:
00624 t_ret = CDB___ham_vrfy_meta(dbp,
00625 vdp, (HMETA *)h, i, flags);
00626 break;
00627 case P_BTREEMETA:
00628 t_ret = CDB___bam_vrfy_meta(dbp,
00629 vdp, (BTMETA *)h, i, flags);
00630 break;
00631 case P_QAMMETA:
00632 t_ret = CDB___qam_vrfy_meta(dbp,
00633 vdp, (QMETA *)h, i, flags);
00634 break;
00635 case P_QAMDATA:
00636 t_ret = CDB___qam_vrfy_data(dbp,
00637 vdp, (QPAGE *)h, i, flags);
00638 break;
00639 default:
00640 EPRINT((dbp->dbenv,
00641 "Unknown page type: %lu", TYPE(h)));
00642 isbad = 1;
00643 break;
00644 }
00645
00646
00647
00648
00649 if (t_ret == DB_VERIFY_BAD)
00650 isbad = 1;
00651 else if (t_ret == DB_VERIFY_FATAL)
00652 goto err;
00653 else
00654 ret = t_ret;
00655 }
00656
00657 if ((t_ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0 && ret == 0)
00658 ret = t_ret;
00659 }
00660
00661 if (0) {
00662 err: if ((t_ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0)
00663 return (ret == 0 ? t_ret : ret);
00664 return (DB_VERIFY_BAD);
00665 }
00666
00667 return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret);
00668 }
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679 static int
00680 __db_vrfy_structure(dbp, vdp, dbname, meta_pgno, flags)
00681 DB *dbp;
00682 VRFY_DBINFO *vdp;
00683 char *dbname;
00684 db_pgno_t meta_pgno;
00685 u_int32_t flags;
00686 {
00687 DB *pgset;
00688 DB_ENV *dbenv;
00689 VRFY_PAGEINFO *pip;
00690 db_pgno_t i;
00691 int ret, isbad, hassubs, p;
00692
00693 isbad = 0;
00694 pip = NULL;
00695 dbenv = dbp->dbenv;
00696 pgset = vdp->pgset;
00697
00698 if ((ret = CDB___db_fchk(dbenv, "DB->verify", flags, OKFLAGS)) != 0)
00699 return (ret);
00700 if (LF_ISSET(DB_SALVAGE)) {
00701 CDB___db_err(dbenv, "__db_vrfy_structure called with DB_SALVAGE");
00702 return (EINVAL);
00703 }
00704
00705
00706
00707
00708 switch(dbp->type) {
00709 case DB_BTREE:
00710 case DB_RECNO:
00711 if ((ret = CDB___bam_vrfy_structure(dbp, vdp, 0, flags)) != 0) {
00712 if (ret == DB_VERIFY_BAD)
00713 isbad = 1;
00714 else
00715 goto err;
00716 }
00717
00718
00719
00720
00721
00722
00723 if ((ret = CDB___db_vrfy_getpageinfo(vdp, 0, &pip)) != 0)
00724 goto err;
00725 hassubs = F_ISSET(pip, VRFY_HAS_SUBDBS);
00726 if ((ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0)
00727 goto err;
00728
00729 if (isbad == 0 && hassubs)
00730 if ((ret =
00731 __db_vrfy_subdbs(dbp, vdp, dbname, flags)) != 0) {
00732 if (ret == DB_VERIFY_BAD)
00733 isbad = 1;
00734 else
00735 goto err;
00736 }
00737 break;
00738 case DB_HASH:
00739 if ((ret = CDB___ham_vrfy_structure(dbp, vdp, 0, flags)) != 0) {
00740 if (ret == DB_VERIFY_BAD)
00741 isbad = 1;
00742 else
00743 goto err;
00744 }
00745 break;
00746 case DB_QUEUE:
00747 if ((ret = CDB___qam_vrfy_structure(dbp, vdp, flags)) != 0) {
00748 if (ret == DB_VERIFY_BAD)
00749 isbad = 1;
00750 }
00751
00752
00753
00754
00755
00756
00757
00758 goto err;
00759
00760 default:
00761
00762 DB_ASSERT(0);
00763 ret = EINVAL;
00764 goto err;
00765
00766 }
00767
00768
00769 if ((ret =
00770 __db_vrfy_freelist(dbp, vdp, meta_pgno, flags)) == DB_VERIFY_BAD)
00771 isbad = 1;
00772
00773
00774
00775
00776
00777
00778
00779
00780 if (ret != 0 || isbad == 1)
00781 goto err;
00782
00783
00784
00785
00786
00787
00788 for (i = 0; i < vdp->last_pgno + 1; i++) {
00789 if ((ret = CDB___db_vrfy_getpageinfo(vdp, i, &pip)) != 0)
00790 goto err;
00791 if ((ret = CDB___db_vrfy_pgset_get(pgset, i, &p)) != 0)
00792 goto err;
00793 if (p == 0) {
00794 EPRINT((dbp->dbenv, "Unreferenced page %lu", i));
00795
00796
00797 if (pip->type != P_LRECNO && pip->type != P_LDUP)
00798 isbad = 1;
00799 }
00800
00801 if (F_ISSET(pip, VRFY_IS_ALLZEROES)) {
00802 EPRINT((dbp->dbenv, "Totally zeroed page %lu", i));
00803 isbad = 1;
00804 }
00805 if ((ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0)
00806 goto err;
00807 pip = NULL;
00808 }
00809
00810 err: if (pip != NULL)
00811 (void)CDB___db_vrfy_putpageinfo(vdp, pip);
00812
00813 return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret);
00814 }
00815
00816
00817
00818
00819 static int
00820 __db_is_valid_pagetype(type)
00821 u_int32_t type;
00822 {
00823 switch (type) {
00824 case P_INVALID:
00825 case P_HASH:
00826 case P_IBTREE:
00827 case P_IRECNO:
00828 case P_LBTREE:
00829 case P_LRECNO:
00830 case P_OVERFLOW:
00831 case P_HASHMETA:
00832 case P_BTREEMETA:
00833 case P_QAMMETA:
00834 case P_QAMDATA:
00835 case P_LDUP:
00836 return (1);
00837 }
00838 return (0);
00839 }
00840
00841
00842
00843
00844 static int
00845 __db_is_valid_magicno(magic, typep)
00846 u_int32_t magic;
00847 DBTYPE *typep;
00848 {
00849 switch (magic) {
00850 case DB_BTREEMAGIC:
00851 *typep = DB_BTREE;
00852 return (1);
00853 case DB_HASHMAGIC:
00854 *typep = DB_HASH;
00855 return (1);
00856 case DB_QAMMAGIC:
00857 *typep = DB_QUEUE;
00858 return (1);
00859 }
00860 *typep = DB_UNKNOWN;
00861 return (0);
00862 }
00863
00864
00865
00866
00867
00868 static int
00869 __db_vrfy_common(dbp, vdp, h, pgno, flags)
00870 DB *dbp;
00871 VRFY_DBINFO *vdp;
00872 PAGE *h;
00873 db_pgno_t pgno;
00874 u_int32_t flags;
00875 {
00876 VRFY_PAGEINFO *pip;
00877 int ret, t_ret;
00878 u_int8_t *p;
00879
00880 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
00881 return (ret);
00882
00883 pip->pgno = pgno;
00884 F_CLR(pip, VRFY_IS_ALLZEROES);
00885
00886
00887
00888
00889
00890
00891
00892 if (pgno != 0 && PGNO(h) == 0) {
00893 for (p = (u_int8_t *)h; p < (u_int8_t *)h + dbp->pgsize; p++)
00894 if (*p != 0) {
00895 EPRINT((dbp->dbenv,
00896 "Hash page %lu should be zeroed and is not",
00897 pgno));
00898 ret = DB_VERIFY_BAD;
00899 goto err;
00900 }
00901
00902
00903
00904
00905 pip->type = P_HASH;
00906 F_SET(pip, VRFY_IS_ALLZEROES);
00907 ret = 0;
00908 goto err;
00909 }
00910
00911 if (PGNO(h) != pgno) {
00912 EPRINT((dbp->dbenv,
00913 "Bad page number: %lu should be %lu", h->pgno, pgno));
00914 ret = DB_VERIFY_BAD;
00915 }
00916
00917 if (!__db_is_valid_pagetype(h->type)) {
00918 EPRINT((dbp->dbenv, "Bad page type: %lu", h->type));
00919 ret = DB_VERIFY_BAD;
00920 }
00921 pip->type = h->type;
00922
00923 err: if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0)
00924 ret = t_ret;
00925
00926 return (ret);
00927 }
00928
00929
00930
00931
00932
00933
00934 static int
00935 __db_vrfy_invalid(dbp, vdp, h, pgno, flags)
00936 DB *dbp;
00937 VRFY_DBINFO *vdp;
00938 PAGE *h;
00939 db_pgno_t pgno;
00940 u_int32_t flags;
00941 {
00942 VRFY_PAGEINFO *pip;
00943 int ret, t_ret;
00944
00945 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
00946 return (ret);
00947 pip->next_pgno = pip->prev_pgno = 0;
00948
00949 if (!IS_VALID_PGNO(NEXT_PGNO(h))) {
00950 EPRINT((dbp->dbenv,
00951 "Invalid next_pgno %lu on page %lu", NEXT_PGNO(h), pgno));
00952 ret = DB_VERIFY_BAD;
00953 } else
00954 pip->next_pgno = NEXT_PGNO(h);
00955
00956 if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0)
00957 ret = t_ret;
00958 return (ret);
00959 }
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974 int
00975 CDB___db_vrfy_datapage(dbp, vdp, h, pgno, flags)
00976 DB *dbp;
00977 VRFY_DBINFO *vdp;
00978 PAGE *h;
00979 db_pgno_t pgno;
00980 u_int32_t flags;
00981 {
00982 VRFY_PAGEINFO *pip;
00983 int isbad, ret, t_ret;
00984
00985 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
00986 return (ret);
00987 isbad = 0;
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997 if (TYPE(h) != P_IBTREE && TYPE(h) != P_IRECNO) {
00998 if (!IS_VALID_PGNO(PREV_PGNO(h)) || PREV_PGNO(h) == pip->pgno) {
00999 isbad = 1;
01000 EPRINT((dbp->dbenv, "Page %lu: Invalid prev_pgno %lu",
01001 pip->pgno, PREV_PGNO(h)));
01002 }
01003 if (!IS_VALID_PGNO(NEXT_PGNO(h)) || NEXT_PGNO(h) == pip->pgno) {
01004 isbad = 1;
01005 EPRINT((dbp->dbenv, "Page %lu: Invalid next_pgno %lu",
01006 pip->pgno, NEXT_PGNO(h)));
01007 }
01008 pip->prev_pgno = PREV_PGNO(h);
01009 pip->next_pgno = NEXT_PGNO(h);
01010 }
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020 if (TYPE(h) != P_OVERFLOW) {
01021 if (BKEYDATA_PSIZE(0) * NUM_ENT(h) > dbp->pgsize) {
01022 isbad = 1;
01023 EPRINT((dbp->dbenv,
01024 "Page %lu: Too many entries: %lu",
01025 pgno, NUM_ENT(h)));
01026 }
01027 pip->entries = NUM_ENT(h);
01028 }
01029
01030
01031
01032
01033
01034
01035 switch (TYPE(h)) {
01036 case P_IBTREE:
01037 case P_IRECNO:
01038 if (LEVEL(h) < LEAFLEVEL + 1 || LEVEL(h) > MAXBTREELEVEL) {
01039 isbad = 1;
01040 EPRINT((dbp->dbenv, "Bad btree level %lu on page %lu",
01041 LEVEL(h), pgno));
01042 }
01043 pip->bt_level = LEVEL(h);
01044 break;
01045 case P_LBTREE:
01046 case P_LDUP:
01047 case P_LRECNO:
01048 if (LEVEL(h) != LEAFLEVEL) {
01049 isbad = 1;
01050 EPRINT((dbp->dbenv,
01051 "Btree leaf page %lu has incorrect level %lu",
01052 pgno, LEVEL(h)));
01053 }
01054 break;
01055 default:
01056 if (LEVEL(h) != 0) {
01057 isbad = 1;
01058 EPRINT((dbp->dbenv,
01059 "Nonzero level %lu in non-btree database page %lu",
01060 LEVEL(h), pgno));
01061 }
01062 break;
01063 }
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073 if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0)
01074 ret = t_ret;
01075
01076 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
01077 }
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087 int
01088 CDB___db_vrfy_meta(dbp, vdp, meta, pgno, flags)
01089 DB *dbp;
01090 VRFY_DBINFO *vdp;
01091 DBMETA *meta;
01092 db_pgno_t pgno;
01093 u_int32_t flags;
01094 {
01095 DBTYPE dbtype, magtype;
01096 VRFY_PAGEINFO *pip;
01097 int isbad, ret, t_ret;
01098
01099 isbad = 0;
01100 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
01101 return (ret);
01102
01103
01104 switch (meta->type) {
01105 case P_BTREEMETA:
01106 dbtype = DB_BTREE;
01107 break;
01108 case P_HASHMETA:
01109 dbtype = DB_HASH;
01110 break;
01111 case P_QAMMETA:
01112 dbtype = DB_QUEUE;
01113 break;
01114 default:
01115
01116 DB_ASSERT(0);
01117 ret = EINVAL;
01118 goto err;
01119 }
01120
01121
01122 if (!__db_is_valid_magicno(meta->magic, &magtype)) {
01123 isbad = 1;
01124 EPRINT((dbp->dbenv, "Magic number invalid on page %lu", pgno));
01125 }
01126 if (magtype != dbtype) {
01127 isbad = 1;
01128 EPRINT((dbp->dbenv,
01129 "Magic number does not match type of page %lu", pgno));
01130 }
01131
01132
01133 if ((dbtype == DB_BTREE && meta->version != DB_BTREEVERSION) ||
01134 (dbtype == DB_HASH && meta->version != DB_HASHVERSION) ||
01135 (dbtype == DB_QUEUE && meta->version != DB_QAMVERSION)) {
01136 isbad = 1;
01137 EPRINT((dbp->dbenv, "%s%s", "Old of incorrect DB ",
01138 "version; extraneous errors may result"));
01139 }
01140
01141
01142 if (meta->pagesize != dbp->pgsize) {
01143 isbad = 1;
01144 EPRINT((dbp->dbenv,
01145 "Invalid pagesize %lu on page %lu", meta->pagesize, pgno));
01146 }
01147
01148
01149
01150 if (meta->free != PGNO_INVALID && IS_VALID_PGNO(meta->free))
01151 pip->free = meta->free;
01152 else if (!IS_VALID_PGNO(meta->free)) {
01153 isbad = 1;
01154 EPRINT((dbp->dbenv,
01155 "Nonsensical free list pgno %lu on page %lu",
01156 meta->free, pgno));
01157 }
01158
01159 err: if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0)
01160 ret = t_ret;
01161
01162 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
01163 }
01164
01165
01166
01167
01168
01169
01170 static int
01171 __db_vrfy_freelist(dbp, vdp, meta, flags)
01172 DB *dbp;
01173 VRFY_DBINFO *vdp;
01174 db_pgno_t meta;
01175 u_int32_t flags;
01176 {
01177 DB *pgset;
01178 VRFY_PAGEINFO *pip;
01179 db_pgno_t pgno;
01180 int p, ret, t_ret;
01181
01182 pgset = vdp->pgset;
01183 DB_ASSERT(pgset != NULL);
01184
01185 if ((ret = CDB___db_vrfy_getpageinfo(vdp, meta, &pip)) != 0)
01186 return (ret);
01187 for (pgno = pip->free; pgno != PGNO_INVALID; pgno = pip->next_pgno) {
01188 if ((ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0)
01189 return (ret);
01190
01191
01192 if (!IS_VALID_PGNO(pgno)) {
01193 EPRINT((dbp->dbenv,
01194 "Invalid next_pgno on free list page %lu", pgno));
01195 return (DB_VERIFY_BAD);
01196 }
01197
01198
01199 if ((ret = CDB___db_vrfy_pgset_get(pgset, pgno, &p)) != 0)
01200 return (ret);
01201 if (p != 0) {
01202 EPRINT((dbp->dbenv,
01203 "Page %lu encountered a second time on free list",
01204 pgno));
01205 return (DB_VERIFY_BAD);
01206 }
01207 if ((ret = CDB___db_vrfy_pgset_inc(pgset, pgno)) != 0)
01208 return (ret);
01209
01210 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
01211 return (ret);
01212
01213 if (pip->type != P_INVALID) {
01214 EPRINT((dbp->dbenv, "Non-invalid page %lu on free list",
01215 pgno, pip->type));
01216 ret = DB_VERIFY_BAD;
01217 break;
01218 }
01219 }
01220
01221 if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0)
01222 ret = t_ret;
01223 return (ret);
01224 }
01225
01226
01227
01228
01229
01230
01231 static int
01232 __db_vrfy_subdbs(dbp, vdp, dbname, flags)
01233 DB *dbp;
01234 VRFY_DBINFO *vdp;
01235 char *dbname;
01236 u_int32_t flags;
01237 {
01238 DB *mdbp;
01239 DBC *dbc;
01240 DBT key, data;
01241 VRFY_PAGEINFO *pip;
01242 db_pgno_t meta_pgno;
01243 int ret, t_ret, isbad;
01244 u_int8_t type;
01245
01246 isbad = 0;
01247 dbc = NULL;
01248
01249 if ((ret = CDB___db_master_open(dbp, dbname, DB_RDONLY, 0, &mdbp)) != 0)
01250 return (ret);
01251
01252 if ((ret =
01253 CDB___db_icursor(mdbp, NULL, DB_BTREE, PGNO_INVALID, 0, &dbc)) != 0)
01254 goto err;
01255
01256 memset(&key, 0, sizeof(key));
01257 memset(&data, 0, sizeof(data));
01258 while ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) == 0) {
01259 if (data.size != sizeof(db_pgno_t)) {
01260 EPRINT((dbp->dbenv, "Database entry of invalid size"));
01261 isbad = 1;
01262 goto err;
01263 }
01264 memcpy(&meta_pgno, data.data, data.size);
01265
01266
01267
01268
01269 DB_NTOHL(&meta_pgno);
01270 if (meta_pgno == PGNO_INVALID || meta_pgno > vdp->last_pgno) {
01271 EPRINT((dbp->dbenv,
01272 "Database entry references invalid page %lu",
01273 meta_pgno));
01274 isbad = 1;
01275 goto err;
01276 }
01277 if ((ret = CDB___db_vrfy_getpageinfo(vdp, meta_pgno, &pip)) != 0)
01278 goto err;
01279 type = pip->type;
01280 if ((ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0)
01281 goto err;
01282 switch (type) {
01283 case P_BTREEMETA:
01284 if ((ret = CDB___bam_vrfy_structure(
01285 dbp, vdp, meta_pgno, flags)) != 0) {
01286 if (ret == DB_VERIFY_BAD)
01287 isbad = 1;
01288 else
01289 goto err;
01290 }
01291 break;
01292 case P_HASHMETA:
01293 if ((ret = CDB___ham_vrfy_structure(
01294 dbp, vdp, meta_pgno, flags)) != 0) {
01295 if (ret == DB_VERIFY_BAD)
01296 isbad = 1;
01297 else
01298 goto err;
01299 }
01300 break;
01301 case P_QAMMETA:
01302 default:
01303 EPRINT((dbp->dbenv,
01304 "Database entry references page %lu of invalid type %lu",
01305 meta_pgno, type));
01306 ret = DB_VERIFY_BAD;
01307 goto err;
01308
01309 }
01310 }
01311
01312 if (ret == DB_NOTFOUND)
01313 ret = 0;
01314
01315 err: if (dbc != NULL && (t_ret = CDB___db_c_close(dbc)) != 0 && ret == 0)
01316 ret = t_ret;
01317
01318 if ((t_ret = mdbp->close(mdbp, 0)) != 0 && ret == 0)
01319 ret = t_ret;
01320
01321 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
01322 }
01323
01324
01325
01326
01327
01328 static int
01329 __db_vrfy_orderchkonly(dbp, vdp, name, subdb, flags)
01330 DB *dbp;
01331 VRFY_DBINFO *vdp;
01332 const char *name, *subdb;
01333 u_int32_t flags;
01334 {
01335 BTMETA *btmeta;
01336 DB *mdbp, *pgset;
01337 DBC *pgsc;
01338 DBT key, data;
01339 HASH *h_internal;
01340 HMETA *hmeta;
01341 PAGE *h, *currpg;
01342 db_pgno_t meta_pgno, p, pgno;
01343 u_int32_t bucket;
01344 int t_ret, ret;
01345
01346 currpg = h = NULL;
01347 pgsc = NULL;
01348 pgset = NULL;
01349
01350 LF_CLR(DB_NOORDERCHK);
01351
01352
01353 if ((ret = CDB_db_create(&mdbp, NULL, 0)) != 0)
01354 return (ret);
01355 if ((ret = CDB___db_master_open(dbp, name, DB_RDONLY, 0, &mdbp)) != 0)
01356 goto err;
01357
01358 memset(&key, 0, sizeof(key));
01359 key.data = (void *)subdb;
01360 memset(&data, 0, sizeof(data));
01361 if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) != 0)
01362 goto err;
01363
01364 if (data.size != sizeof(db_pgno_t)) {
01365 EPRINT((dbp->dbenv, "Database entry of invalid size"));
01366 ret = DB_VERIFY_BAD;
01367 goto err;
01368 }
01369
01370 memcpy(&meta_pgno, data.data, data.size);
01371
01372 if ((ret = CDB_memp_fget(dbp->mpf, &meta_pgno, 0, &h)) != 0)
01373 goto err;
01374
01375 if ((ret = CDB___db_vrfy_pgset(dbp->dbenv, dbp->pgsize, &pgset)) != 0)
01376 goto err;
01377
01378 switch (TYPE(h)) {
01379 case P_BTREEMETA:
01380 btmeta = (BTMETA *)h;
01381 if (F_ISSET(&btmeta->dbmeta, BTM_RECNO)) {
01382
01383 ret = 0;
01384 goto err;
01385 }
01386 if ((ret =
01387 __db_meta2pgset(dbp, vdp, meta_pgno, flags, pgset)) != 0)
01388 goto err;
01389 if ((ret = pgset->cursor(pgset, NULL, &pgsc, 0)) != 0)
01390 goto err;
01391 while ((ret = CDB___db_vrfy_pgset_next(pgsc, &p)) == 0) {
01392 if ((ret = CDB_memp_fget(dbp->mpf, &p, 0, &currpg)) != 0)
01393 goto err;
01394 if ((ret = CDB___bam_vrfy_itemorder(dbp,
01395 NULL, currpg, p, NUM_ENT(currpg), 1,
01396 F_ISSET(&btmeta->dbmeta, BTM_DUP), flags)) != 0)
01397 goto err;
01398 if ((ret = CDB_memp_fput(dbp->mpf, currpg, 0)) != 0)
01399 goto err;
01400 currpg = NULL;
01401 }
01402 if ((ret = pgsc->c_close(pgsc)) != 0)
01403 goto err;
01404 break;
01405 case P_HASHMETA:
01406 hmeta = (HMETA *)h;
01407 h_internal = (HASH *)dbp->h_internal;
01408
01409
01410
01411 if (h_internal == NULL || h_internal->h_hash == NULL) {
01412 EPRINT((dbp->dbenv,
01413 "DB_ORDERCHKONLY requires that a hash function be set"));
01414 ret = DB_VERIFY_BAD;
01415 goto err;
01416 }
01417 if (hmeta->h_charkey !=
01418 h_internal->h_hash(CHARKEY, sizeof(CHARKEY))) {
01419 EPRINT((dbp->dbenv,
01420 "Incorrect hash function for database"));
01421 ret = DB_VERIFY_BAD;
01422 goto err;
01423 }
01424
01425
01426
01427
01428
01429 for (bucket = 0; bucket <= hmeta->max_bucket; bucket++) {
01430 pgno = hmeta->spares[CDB___db_log2(bucket + 1)];
01431 while (pgno != PGNO_INVALID) {
01432 if ((ret = CDB_memp_fget(dbp->mpf,
01433 &pgno, 0, &currpg)) != 0)
01434 goto err;
01435 if ((ret = CDB___ham_vrfy_hashing(dbp,
01436 NUM_ENT(currpg),hmeta, bucket, pgno,
01437 flags, h_internal->h_hash)) != 0)
01438 goto err;
01439 pgno = NEXT_PGNO(currpg);
01440 if ((ret = CDB_memp_fput(dbp->mpf, currpg, 0)) != 0)
01441 goto err;
01442 currpg = NULL;
01443 }
01444 }
01445 break;
01446 default:
01447 EPRINT((dbp->dbenv, "Database meta page %lu of bad type %lu",
01448 meta_pgno, TYPE(h)));
01449 ret = DB_VERIFY_BAD;
01450 break;
01451 }
01452
01453 err: if (pgsc != NULL)
01454 (void)pgsc->c_close(pgsc);
01455 if (pgset != NULL)
01456 (void)pgset->close(pgset, 0);
01457 if (h != NULL && (t_ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0)
01458 ret = t_ret;
01459 if (currpg != NULL && (t_ret = CDB_memp_fput(dbp->mpf, currpg, 0)) != 0)
01460 ret = t_ret;
01461 if ((t_ret = mdbp->close(mdbp, 0)) != 0)
01462 ret = t_ret;
01463 return (ret);
01464 }
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474 int
01475 CDB___db_salvage(dbp, vdp, pgno, h, handle, callback, flags)
01476 DB *dbp;
01477 VRFY_DBINFO *vdp;
01478 db_pgno_t pgno;
01479 PAGE *h;
01480 void *handle;
01481 int (*callback) __P((void *, const void *));
01482 u_int32_t flags;
01483 {
01484 DB_ASSERT(LF_ISSET(DB_SALVAGE));
01485
01486
01487 if (CDB___db_salvage_isdone(vdp, pgno))
01488 return (0);
01489
01490 switch (TYPE(h)) {
01491 case P_HASH:
01492 return (CDB___ham_salvage(dbp,
01493 vdp, pgno, h, handle, callback, flags));
01494
01495 case P_LBTREE:
01496 return (CDB___bam_salvage(dbp,
01497 vdp, pgno, P_LBTREE, h, handle, callback, NULL, flags));
01498
01499 case P_LDUP:
01500 return (CDB___db_salvage_markneeded(vdp, pgno, SALVAGE_LDUP));
01501
01502 case P_OVERFLOW:
01503 return (CDB___db_salvage_markneeded(vdp, pgno, SALVAGE_OVERFLOW));
01504
01505 case P_LRECNO:
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518 return (CDB___db_salvage_markneeded(vdp, pgno, SALVAGE_LRECNO));
01519
01520 case P_IBTREE:
01521 case P_INVALID:
01522 case P_IRECNO:
01523 case __P_DUPLICATE:
01524 default:
01525
01526 break;
01527 }
01528 return (0);
01529 }
01530
01531
01532
01533
01534
01535
01536 static int
01537 __db_salvage_unknowns(dbp, vdp, handle, callback, flags)
01538 DB *dbp;
01539 VRFY_DBINFO *vdp;
01540 void *handle;
01541 int (*callback) __P((void *, const void *));
01542 u_int32_t flags;
01543 {
01544 DBT unkdbt, key, *dbt;
01545 PAGE *h;
01546 db_pgno_t pgno;
01547 u_int32_t pgtype;
01548 int ret, err_ret;
01549 void *ovflbuf;
01550
01551 memset(&unkdbt, 0, sizeof(DBT));
01552 unkdbt.size = strlen("UNKNOWN") + 1;
01553 unkdbt.data = "UNKNOWN";
01554
01555 if ((ret = CDB___os_malloc(dbp->dbenv, dbp->pgsize, 0, &ovflbuf)) != 0)
01556 return (ret);
01557
01558 err_ret = 0;
01559 while ((ret = CDB___db_salvage_getnext(vdp, &pgno, &pgtype)) == 0) {
01560 dbt = NULL;
01561
01562 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) {
01563 err_ret = ret;
01564 continue;
01565 }
01566
01567 switch (pgtype) {
01568 case SALVAGE_LDUP:
01569 case SALVAGE_LRECNODUP:
01570 dbt = &unkdbt;
01571
01572 case SALVAGE_LBTREE:
01573 case SALVAGE_LRECNO:
01574 if ((ret = CDB___bam_salvage(dbp, vdp, pgno, pgtype,
01575 h, handle, callback, dbt, flags)) != 0)
01576 err_ret = ret;
01577 break;
01578 case SALVAGE_OVERFLOW:
01579
01580
01581
01582
01583
01584 if ((ret = CDB___db_safe_goff(dbp,
01585 vdp, pgno, &key, &ovflbuf, flags)) != 0) {
01586 err_ret = ret;
01587 continue;
01588 }
01589 if ((ret = CDB___db_prdbt(&key,
01590 0, " ", handle, callback, 0, NULL)) != 0) {
01591 err_ret = ret;
01592 continue;
01593 }
01594 if ((ret = CDB___db_prdbt(&unkdbt,
01595 0, " ", handle, callback, 0, NULL)) != 0)
01596 err_ret = ret;
01597 break;
01598 case SALVAGE_HASH:
01599 if ((ret = CDB___ham_salvage(
01600 dbp, vdp, pgno, h, handle, callback, flags)) != 0)
01601 err_ret = ret;
01602 break;
01603 case SALVAGE_INVALID:
01604 case SALVAGE_IGNORE:
01605 default:
01606
01607
01608
01609
01610 DB_ASSERT(0);
01611 break;
01612 }
01613 if ((ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0)
01614 err_ret = ret;
01615 }
01616
01617 CDB___os_free(ovflbuf, 0);
01618
01619 if (err_ret != 0 && ret == 0)
01620 ret = err_ret;
01621
01622 return (ret == DB_NOTFOUND ? 0 : ret);
01623 }
01624
01625
01626
01627
01628
01629 #define INP_OFFSET(h, i) \
01630 ((db_indx_t)((u_int8_t *)(h)->inp + (i) - (u_int8_t *)(h)))
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646 int
01647 CDB___db_vrfy_inpitem(dbp, h, pgno, i, is_btree, flags, himarkp, offsetp)
01648 DB *dbp;
01649 PAGE *h;
01650 db_pgno_t pgno;
01651 u_int32_t i;
01652 int is_btree;
01653 u_int32_t flags, *himarkp, *offsetp;
01654 {
01655 BKEYDATA *bk;
01656 db_indx_t offset, len;
01657
01658 DB_ASSERT(himarkp != NULL);
01659
01660
01661
01662
01663
01664
01665 if ((u_int8_t *)h->inp + i >= (u_int8_t *)h + *himarkp) {
01666
01667 EPRINT((dbp->dbenv,
01668 "Page %lu entries listing %lu overlaps data", pgno, i));
01669 return (DB_VERIFY_FATAL);
01670 }
01671
01672 offset = h->inp[i];
01673
01674
01675
01676
01677
01678 if (offset <= INP_OFFSET(h, i) || offset > dbp->pgsize) {
01679 EPRINT((dbp->dbenv,
01680 "Bad offset %lu at page %lu index %lu", offset, pgno, i));
01681 return (DB_VERIFY_BAD);
01682 }
01683
01684
01685 if (offset < *himarkp)
01686 *himarkp = offset;
01687
01688 if (is_btree) {
01689
01690
01691
01692 bk = GET_BKEYDATA(h, i);
01693 len = B_TYPE(bk->type) == B_KEYDATA ? bk->len : BOVERFLOW_SIZE;
01694 if ((size_t)(offset + len) > dbp->pgsize) {
01695 EPRINT((dbp->dbenv,
01696 "Item %lu on page %lu extends past page boundary",
01697 i, pgno));
01698 return (DB_VERIFY_BAD);
01699 }
01700 }
01701
01702 if (offsetp != NULL)
01703 *offsetp = offset;
01704 return (0);
01705 }
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716 int
01717 CDB___db_vrfy_duptype(dbp, vdp, pgno, flags)
01718 DB *dbp;
01719 VRFY_DBINFO *vdp;
01720 db_pgno_t pgno;
01721 u_int32_t flags;
01722 {
01723 VRFY_PAGEINFO *pip;
01724 int ret, isbad;
01725
01726 isbad = 0;
01727
01728 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
01729 return (ret);
01730
01731 switch (pip->type) {
01732 case P_IBTREE:
01733 case P_LDUP:
01734 if (!LF_ISSET(ST_DUPSORT)) {
01735 EPRINT((dbp->dbenv,
01736 "Sorted duplicate set at page %lu in unsorted-dup database",
01737 pgno));
01738 isbad = 1;
01739 }
01740 break;
01741 case P_IRECNO:
01742 case P_LRECNO:
01743 if (LF_ISSET(ST_DUPSORT)) {
01744 EPRINT((dbp->dbenv,
01745 "Unsorted duplicate set at page %lu in sorted-dup database",
01746 pgno));
01747 isbad = 1;
01748 }
01749 break;
01750 default:
01751 EPRINT((dbp->dbenv, "Duplicate page %lu of inappropriate type %lu",
01752 pgno, pip->type));
01753 isbad = 1;
01754 break;
01755 }
01756
01757 if ((ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0)
01758 return (ret);
01759 return (isbad == 1 ? DB_VERIFY_BAD : 0);
01760 }
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785 int
01786 CDB___db_salvage_duptree(dbp, vdp, pgno, key, handle, callback, flags)
01787 DB *dbp;
01788 VRFY_DBINFO *vdp;
01789 db_pgno_t pgno;
01790 DBT *key;
01791 void *handle;
01792 int (*callback) __P((void *, const void *));
01793 u_int32_t flags;
01794 {
01795 PAGE *h;
01796 int ret, t_ret;
01797
01798 if (pgno == PGNO_INVALID || !IS_VALID_PGNO(pgno))
01799 return (DB_VERIFY_BAD);
01800
01801
01802 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
01803 return (ret);
01804
01805 switch (TYPE(h)) {
01806 case P_IBTREE:
01807 case P_IRECNO:
01808 if ((ret = __db_vrfy_common(dbp, vdp, h, pgno, flags)) != 0)
01809 goto err;
01810 if ((ret = CDB___bam_vrfy(dbp,
01811 vdp, h, pgno, flags | DB_NOORDERCHK)) != 0 ||
01812 (ret = CDB___db_salvage_markdone(vdp, pgno)) != 0)
01813 goto err;
01814
01815
01816
01817 if ((ret = CDB___bam_salvage_walkdupint(dbp, vdp, h, key,
01818 handle, callback, flags)) != 0)
01819 goto err;
01820 break;
01821 case P_LRECNO:
01822 case P_LDUP:
01823 if ((ret = CDB___bam_salvage(dbp,
01824 vdp, pgno, TYPE(h), h, handle, callback, key, flags)) != 0)
01825 goto err;
01826 break;
01827 default:
01828 ret = DB_VERIFY_BAD;
01829 goto err;
01830
01831 }
01832
01833 err: if ((t_ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0 && ret == 0)
01834 ret = t_ret;
01835 return (ret);
01836 }
01837
01838
01839
01840
01841
01842
01843 static int
01844 __db_salvage_subdbs(dbp, vdp, handle, callback, flags, hassubsp)
01845 DB *dbp;
01846 VRFY_DBINFO *vdp;
01847 void *handle;
01848 int (*callback) __P((void *, const void *));
01849 u_int32_t flags;
01850 int *hassubsp;
01851 {
01852 BTMETA *btmeta;
01853 DB *pgset;
01854 DBC *pgsc;
01855 PAGE *h;
01856 db_pgno_t p, meta_pgno;
01857 int ret, err_ret;
01858
01859 err_ret = 0;
01860 pgsc = NULL;
01861 pgset = NULL;
01862
01863 meta_pgno = PGNO_BASE_MD;
01864 if ((ret = CDB_memp_fget(dbp->mpf, &meta_pgno, 0, &h)) != 0)
01865 return (ret);
01866
01867 if (TYPE(h) == P_BTREEMETA)
01868 btmeta = (BTMETA *)h;
01869 else {
01870
01871 ret = 0;
01872 goto err;
01873 }
01874
01875
01876 if ((ret = __db_vrfy_common(dbp, vdp, h, PGNO_BASE_MD, flags)) != 0 ||
01877 (ret = CDB___bam_vrfy_meta(dbp, vdp, btmeta, PGNO_BASE_MD, flags)) != 0)
01878 goto err;
01879
01880 if (!F_ISSET(&btmeta->dbmeta, BTM_SUBDB)) {
01881
01882 ret = 0;
01883 goto err;
01884 }
01885
01886
01887 *hassubsp = 1;
01888
01889 if ((ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0)
01890 return (ret);
01891
01892
01893
01894
01895
01896
01897
01898
01899
01900 if ((ret = CDB___db_vrfy_pgset(dbp->dbenv, dbp->pgsize, &pgset)) != 0)
01901 return (ret);
01902 if ((ret =
01903 __db_meta2pgset(dbp, vdp, PGNO_BASE_MD, flags, pgset)) != 0)
01904 goto err;
01905
01906 if ((ret = pgset->cursor(pgset, NULL, &pgsc, 0)) != 0)
01907 goto err;
01908 while ((ret = CDB___db_vrfy_pgset_next(pgsc, &p)) == 0) {
01909 if ((ret = CDB_memp_fget(dbp->mpf, &p, 0, &h)) != 0) {
01910 err_ret = ret;
01911 continue;
01912 }
01913 if ((ret = __db_vrfy_common(dbp, vdp, h, p, flags)) != 0 ||
01914 (ret = CDB___bam_vrfy(dbp,
01915 vdp, h, p, flags | DB_NOORDERCHK)) != 0)
01916 goto nextpg;
01917 if (TYPE(h) != P_LBTREE)
01918 goto nextpg;
01919 else if ((ret = CDB___db_salvage_subdbpg(
01920 dbp, vdp, h, handle, callback, flags)) != 0)
01921 err_ret = ret;
01922 nextpg: if ((ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0)
01923 err_ret = ret;
01924 }
01925
01926 if (ret != DB_NOTFOUND)
01927 goto err;
01928 if ((ret = pgsc->c_close(pgsc)) != 0)
01929 goto err;
01930
01931 ret = pgset->close(pgset, 0);
01932 return ((ret == 0 && err_ret != 0) ? err_ret : ret);
01933
01934
01935
01936 err: if (pgsc != NULL)
01937 (void)pgsc->c_close(pgsc);
01938 if (pgset != NULL)
01939 (void)pgset->close(pgset, 0);
01940 (void)CDB_memp_fput(dbp->mpf, h, 0);
01941 return (ret);
01942 }
01943
01944
01945
01946
01947
01948
01949
01950
01951
01952
01953 int
01954 CDB___db_salvage_subdbpg(dbp, vdp, master, handle, callback, flags)
01955 DB *dbp;
01956 VRFY_DBINFO *vdp;
01957 PAGE *master;
01958 void *handle;
01959 int (*callback) __P((void *, const void *));
01960 u_int32_t flags;
01961 {
01962 BKEYDATA *bkkey, *bkdata;
01963 BOVERFLOW *bo;
01964 DB *pgset;
01965 DBC *pgsc;
01966 DBT key;
01967 PAGE *subpg;
01968 db_indx_t i;
01969 db_pgno_t meta_pgno, p;
01970 int ret, err_ret, t_ret;
01971 char *subdbname;
01972
01973 ret = err_ret = 0;
01974 subdbname = NULL;
01975
01976 if ((ret = CDB___db_vrfy_pgset(dbp->dbenv, dbp->pgsize, &pgset)) != 0)
01977 return (ret);
01978
01979
01980
01981
01982
01983 for (i = 0; i < NUM_ENT(master); i += P_INDX) {
01984 bkkey = GET_BKEYDATA(master, i);
01985 bkdata = GET_BKEYDATA(master, i + O_INDX);
01986
01987
01988 if (B_TYPE(bkkey->type) == B_OVERFLOW) {
01989
01990
01991
01992
01993 bo = (BOVERFLOW *)bkkey;
01994 if ((ret = CDB___db_safe_goff(dbp, vdp, bo->pgno, &key,
01995 (void **)&subdbname, flags)) != 0) {
01996 err_ret = DB_VERIFY_BAD;
01997 continue;
01998 }
01999
02000
02001 if ((ret = CDB___os_realloc(dbp->dbenv,
02002 key.size + 1, NULL, &subdbname)) != 0)
02003 goto err;
02004 subdbname[key.size] = '\0';
02005 } else if (B_TYPE(bkkey->type == B_KEYDATA)) {
02006 if ((ret = CDB___os_realloc(dbp->dbenv,
02007 bkkey->len + 1, NULL, &subdbname)) != 0)
02008 goto err;
02009 memcpy(subdbname, bkkey->data, bkkey->len);
02010 subdbname[bkkey->len] = '\0';
02011 }
02012
02013
02014 if (bkdata->len != sizeof(db_pgno_t)) {
02015 err_ret = DB_VERIFY_BAD;
02016 continue;
02017 }
02018 memcpy(&meta_pgno, bkdata->data, sizeof(db_pgno_t));
02019
02020
02021 if (!IS_VALID_PGNO(meta_pgno) ||
02022 (ret = CDB_memp_fget(dbp->mpf, &meta_pgno, 0, &subpg)) != 0) {
02023 err_ret = ret;
02024 continue;
02025 }
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035 if ((ret =
02036 __db_vrfy_common(dbp, vdp, subpg, meta_pgno, flags)) != 0) {
02037 err_ret = ret;
02038 (void)CDB_memp_fput(dbp->mpf, subpg, 0);
02039 continue;
02040 }
02041 switch (TYPE(subpg)) {
02042 case P_BTREEMETA:
02043 if ((ret = CDB___bam_vrfy_meta(dbp,
02044 vdp, (BTMETA *)subpg, meta_pgno, flags)) != 0) {
02045 err_ret = ret;
02046 (void)CDB_memp_fput(dbp->mpf, subpg, 0);
02047 continue;
02048 }
02049 break;
02050 case P_HASHMETA:
02051 if ((ret = CDB___ham_vrfy_meta(dbp,
02052 vdp, (HMETA *)subpg, meta_pgno, flags)) != 0) {
02053 err_ret = ret;
02054 (void)CDB_memp_fput(dbp->mpf, subpg, 0);
02055 continue;
02056 }
02057 break;
02058 default:
02059
02060 err_ret = DB_VERIFY_BAD;
02061 continue;
02062
02063 }
02064
02065 if ((ret = CDB_memp_fput(dbp->mpf, subpg, 0)) != 0) {
02066 err_ret = ret;
02067 continue;
02068 }
02069
02070
02071 if ((ret = CDB___db_prheader(dbp,
02072 subdbname, 0, 0, handle, callback, vdp, meta_pgno)) != 0)
02073 goto err;
02074
02075 if ((ret = __db_meta2pgset(dbp, vdp, meta_pgno,
02076 flags, pgset)) != 0) {
02077 err_ret = ret;
02078 continue;
02079 }
02080
02081 if ((ret = pgset->cursor(pgset, NULL, &pgsc, 0)) != 0)
02082 goto err;
02083 while ((ret = CDB___db_vrfy_pgset_next(pgsc, &p)) == 0) {
02084 if ((ret = CDB_memp_fget(dbp->mpf, &p, 0, &subpg)) != 0) {
02085 err_ret = ret;
02086 continue;
02087 }
02088 if ((ret = CDB___db_salvage(dbp, vdp, p, subpg,
02089 handle, callback, flags)) != 0)
02090 err_ret = ret;
02091 if ((ret = CDB_memp_fput(dbp->mpf, subpg, 0)) != 0)
02092 err_ret = ret;
02093 }
02094
02095 if (ret != DB_NOTFOUND)
02096 goto err;
02097
02098 if ((ret = pgsc->c_close(pgsc)) != 0)
02099 goto err;
02100 if ((ret = CDB___db_prfooter(handle, callback)) != 0)
02101 goto err;
02102 }
02103 err: if (subdbname)
02104 CDB___os_free(subdbname, 0);
02105
02106 if ((t_ret = pgset->close(pgset, 0)) != 0)
02107 ret = t_ret;
02108
02109 if ((t_ret = CDB___db_salvage_markdone(vdp, PGNO(master))) != 0)
02110 return (t_ret);
02111
02112 return ((err_ret != 0) ? err_ret : ret);
02113 }
02114
02115
02116
02117
02118
02119
02120
02121 static int
02122 __db_meta2pgset(dbp, vdp, pgno, flags, pgset)
02123 DB *dbp;
02124 VRFY_DBINFO *vdp;
02125 db_pgno_t pgno;
02126 u_int32_t flags;
02127 DB *pgset;
02128 {
02129 PAGE *h;
02130 int ret, t_ret;
02131
02132 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
02133 return (ret);
02134
02135 switch (TYPE(h)) {
02136 case P_BTREEMETA:
02137 ret = CDB___bam_meta2pgset(dbp, vdp, (BTMETA *)h, flags, pgset);
02138 break;
02139 case P_HASHMETA:
02140 ret = CDB___ham_meta2pgset(dbp, vdp, (HMETA *)h, flags, pgset);
02141 break;
02142 default:
02143 ret = DB_VERIFY_BAD;
02144 break;
02145 }
02146
02147 if ((t_ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0)
02148 return (t_ret);
02149 return (ret);
02150 }
02151
02152
02153
02154
02155
02156
02157 static int
02158 __db_guesspgsize(dbenv, fhp)
02159 DB_ENV *dbenv;
02160 DB_FH *fhp;
02161 {
02162 db_pgno_t i;
02163 size_t nr;
02164 u_int32_t guess;
02165 u_int8_t type;
02166 int ret;
02167
02168 for (guess = DB_MAX_PGSIZE; guess >= DB_MIN_PGSIZE; guess >>= 1) {
02169
02170
02171
02172
02173
02174
02175
02176
02177
02178
02179
02180
02181 for (i = 1; i <= 3; i++) {
02182 if ((ret = CDB___os_seek(dbenv, fhp, guess,
02183 i, SSZ(DBMETA, type), 0, DB_OS_SEEK_SET)) != 0)
02184 break;
02185 if ((ret = CDB___os_read(dbenv,
02186 fhp, &type, 1, &nr)) != 0 || nr == 0)
02187 break;
02188 if (type == P_INVALID || type >= P_PAGETYPE_MAX)
02189 break;
02190 }
02191 }
02192
02193 return (guess);
02194 }