Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

db_ovfl_vrfy.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  */
00007 /*
00008  * Copyright (c) 1990, 1993, 1994, 1995, 1996
00009  *      Keith Bostic.  All rights reserved.
00010  */
00011 /*
00012  * Copyright (c) 1990, 1993, 1994, 1995
00013  *      The Regents of the University of California.  All rights reserved.
00014  *
00015  * This code is derived from software contributed to Berkeley by
00016  * Mike Olson.
00017  *
00018  * Redistribution and use in source and binary forms, with or without
00019  * modification, are permitted provided that the following conditions
00020  * are met:
00021  * 1. Redistributions of source code must retain the above copyright
00022  *    notice, this list of conditions and the following disclaimer.
00023  * 2. Redistributions in binary form must reproduce the above copyright
00024  *    notice, this list of conditions and the following disclaimer in the
00025  *    documentation and/or other materials provided with the distribution.
00026  * 3. Neither the name of the University nor the names of its contributors
00027  *    may be used to endorse or promote products derived from this software
00028  *    without specific prior written permission.
00029  *
00030  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00031  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00032  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00033  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00034  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00035  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00036  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00037  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00038  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00039  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00040  * SUCH DAMAGE.
00041  *
00042  * $Id: db_ovfl_vrfy.c,v 12.1 2005/06/16 20:21:13 bostic Exp $
00043  */
00044 
00045 #include "db_config.h"
00046 
00047 #ifndef NO_SYSTEM_INCLUDES
00048 #include <sys/types.h>
00049 #include <string.h>
00050 #endif
00051 
00052 #include "db_int.h"
00053 #include "dbinc/db_page.h"
00054 #include "dbinc/db_shash.h"
00055 #include "dbinc/db_am.h"
00056 #include "dbinc/db_verify.h"
00057 #include "dbinc/mp.h"
00058 
00059 /*
00060  * __db_vrfy_overflow --
00061  *      Verify overflow page.
00062  *
00063  * PUBLIC: int __db_vrfy_overflow __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t,
00064  * PUBLIC:     u_int32_t));
00065  */
00066 int
00067 __db_vrfy_overflow(dbp, vdp, h, pgno, flags)
00068         DB *dbp;
00069         VRFY_DBINFO *vdp;
00070         PAGE *h;
00071         db_pgno_t pgno;
00072         u_int32_t flags;
00073 {
00074         VRFY_PAGEINFO *pip;
00075         int isbad, ret, t_ret;
00076 
00077         isbad = 0;
00078         if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
00079                 return (ret);
00080 
00081         if ((ret = __db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) {
00082                 if (ret == DB_VERIFY_BAD)
00083                         isbad = 1;
00084                 else
00085                         goto err;
00086         }
00087 
00088         pip->refcount = OV_REF(h);
00089         if (pip->refcount < 1) {
00090                 EPRINT((dbp->dbenv,
00091                     "Page %lu: overflow page has zero reference count",
00092                     (u_long)pgno));
00093                 isbad = 1;
00094         }
00095 
00096         /* Just store for now. */
00097         pip->olen = HOFFSET(h);
00098 
00099 err:    if ((t_ret = __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0)
00100                 ret = t_ret;
00101         return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
00102 }
00103 
00104 /*
00105  * __db_vrfy_ovfl_structure --
00106  *      Walk a list of overflow pages, avoiding cycles and marking
00107  *      pages seen.
00108  *
00109  * PUBLIC: int __db_vrfy_ovfl_structure
00110  * PUBLIC:     __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, u_int32_t));
00111  */
00112 int
00113 __db_vrfy_ovfl_structure(dbp, vdp, pgno, tlen, flags)
00114         DB *dbp;
00115         VRFY_DBINFO *vdp;
00116         db_pgno_t pgno;
00117         u_int32_t tlen;
00118         u_int32_t flags;
00119 {
00120         DB *pgset;
00121         VRFY_PAGEINFO *pip;
00122         db_pgno_t next, prev;
00123         int isbad, ret, seen_cnt, t_ret;
00124         u_int32_t refcount;
00125 
00126         pgset = vdp->pgset;
00127         DB_ASSERT(pgset != NULL);
00128         isbad = 0;
00129 
00130         /* This shouldn't happen, but just to be sure. */
00131         if (!IS_VALID_PGNO(pgno))
00132                 return (DB_VERIFY_BAD);
00133 
00134         /*
00135          * Check the first prev_pgno;  it ought to be PGNO_INVALID,
00136          * since there's no prev page.
00137          */
00138         if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
00139                 return (ret);
00140 
00141         /* The refcount is stored on the first overflow page. */
00142         refcount = pip->refcount;
00143 
00144         if (pip->type != P_OVERFLOW) {
00145                 EPRINT((dbp->dbenv,
00146                     "Page %lu: overflow page of invalid type %lu",
00147                     (u_long)pgno, (u_long)pip->type));
00148                 ret = DB_VERIFY_BAD;
00149                 goto err;               /* Unsafe to continue. */
00150         }
00151 
00152         prev = pip->prev_pgno;
00153         if (prev != PGNO_INVALID) {
00154                 EPRINT((dbp->dbenv,
00155             "Page %lu: first page in overflow chain has a prev_pgno %lu",
00156                     (u_long)pgno, (u_long)prev));
00157                 isbad = 1;
00158         }
00159 
00160         for (;;) {
00161                 /*
00162                  * We may have seen this page elsewhere, if the overflow entry
00163                  * has been promoted to an internal page;  we just want to
00164                  * make sure that each overflow page is seen exactly as many
00165                  * times as its refcount dictates.
00166                  *
00167                  * Note that this code also serves to keep us from looping
00168                  * infinitely if there's a cycle in an overflow chain.
00169                  */
00170                 if ((ret = __db_vrfy_pgset_get(pgset, pgno, &seen_cnt)) != 0)
00171                         goto err;
00172                 if ((u_int32_t)seen_cnt > refcount) {
00173                         EPRINT((dbp->dbenv,
00174                 "Page %lu: encountered too many times in overflow traversal",
00175                             (u_long)pgno));
00176                         ret = DB_VERIFY_BAD;
00177                         goto err;
00178                 }
00179                 if ((ret = __db_vrfy_pgset_inc(pgset, pgno)) != 0)
00180                         goto err;
00181 
00182                 /*
00183                  * Each overflow page can be referenced multiple times,
00184                  * because it's possible for overflow Btree keys to get
00185                  * promoted to internal pages.  We want to make sure that
00186                  * each page is referenced from a Btree leaf (or Hash data
00187                  * page, which we consider a "leaf" here) exactly once; if
00188                  * the parent was a leaf, set a flag to indicate that we've
00189                  * seen this page in a leaf context.
00190                  *
00191                  * If the parent is not a leaf--in which case it's a Btree
00192                  * internal page--we don't need to bother doing any further
00193                  * verification, as we'll do it when we hit the leaf (or
00194                  * complain that we never saw the leaf).  Only the first
00195                  * page in an overflow chain should ever have a refcount
00196                  * greater than 1, and the combination of the LEAFSEEN check
00197                  * and the fact that we bail after the first page for
00198                  * non-leaves should ensure this.
00199                  *
00200                  * Note that each "child" of a page, such as an overflow page,
00201                  * is stored and verified in a structure check exactly once,
00202                  * so this code does not need to contend with the fact that
00203                  * overflow chains used as Btree duplicate keys may be
00204                  * referenced multiply from a single Btree leaf page.
00205                  */
00206                 if (LF_ISSET(ST_OVFL_LEAF)) {
00207                         if (F_ISSET(pip, VRFY_OVFL_LEAFSEEN)) {
00208                                 EPRINT((dbp->dbenv,
00209                 "Page %lu: overflow page linked twice from leaf or data page",
00210                                     (u_long)pgno));
00211                                 ret = DB_VERIFY_BAD;
00212                                 goto err;
00213                         }
00214                         F_SET(pip, VRFY_OVFL_LEAFSEEN);
00215                 }
00216 
00217                 /*
00218                  * We want to verify each overflow chain only once, and
00219                  * although no chain should be linked more than once from a
00220                  * leaf page, we can't guarantee that it'll be linked that
00221                  * once if it's linked from an internal page and the key
00222                  * is gone.
00223                  *
00224                  * seen_cnt is the number of times we'd encountered this page
00225                  * before calling this function.
00226                  */
00227                 if (seen_cnt == 0) {
00228                         /*
00229                          * Keep a running tab on how much of the item we've
00230                          * seen.
00231                          */
00232                         tlen -= pip->olen;
00233 
00234                         /* Send the application feedback about our progress. */
00235                         if (!LF_ISSET(DB_SALVAGE))
00236                                 __db_vrfy_struct_feedback(dbp, vdp);
00237                 } else
00238                         goto done;
00239 
00240                 next = pip->next_pgno;
00241 
00242                 /* Are we there yet? */
00243                 if (next == PGNO_INVALID)
00244                         break;
00245 
00246                 /*
00247                  * We've already checked this when we saved it, but just
00248                  * to be sure...
00249                  */
00250                 if (!IS_VALID_PGNO(next)) {
00251                         DB_ASSERT(0);
00252                         EPRINT((dbp->dbenv,
00253                             "Page %lu: bad next_pgno %lu on overflow page",
00254                             (u_long)pgno, (u_long)next));
00255                         ret = DB_VERIFY_BAD;
00256                         goto err;
00257                 }
00258 
00259                 if ((ret = __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 ||
00260                     (ret = __db_vrfy_getpageinfo(vdp, next, &pip)) != 0)
00261                         return (ret);
00262                 if (pip->prev_pgno != pgno) {
00263                         EPRINT((dbp->dbenv,
00264                 "Page %lu: bad prev_pgno %lu on overflow page (should be %lu)",
00265                             (u_long)next, (u_long)pip->prev_pgno,
00266                             (u_long)pgno));
00267                         isbad = 1;
00268                         /*
00269                          * It's safe to continue because we have separate
00270                          * cycle detection.
00271                          */
00272                 }
00273 
00274                 pgno = next;
00275         }
00276 
00277         if (tlen > 0) {
00278                 isbad = 1;
00279                 EPRINT((dbp->dbenv,
00280                     "Page %lu: overflow item incomplete", (u_long)pgno));
00281         }
00282 
00283 done:
00284 err:    if ((t_ret =
00285             __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 && ret == 0)
00286                 ret = t_ret;
00287         return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
00288 }
00289 
00290 /*
00291  * __db_safe_goff --
00292  *      Get an overflow item, very carefully, from an untrusted database,
00293  *      in the context of the salvager.
00294  *
00295  * PUBLIC: int __db_safe_goff __P((DB *, VRFY_DBINFO *, db_pgno_t,
00296  * PUBLIC:     DBT *, void *, u_int32_t));
00297  */
00298 int
00299 __db_safe_goff(dbp, vdp, pgno, dbt, buf, flags)
00300         DB *dbp;
00301         VRFY_DBINFO *vdp;
00302         db_pgno_t pgno;
00303         DBT *dbt;
00304         void *buf;
00305         u_int32_t flags;
00306 {
00307         DB_MPOOLFILE *mpf;
00308         PAGE *h;
00309         int ret, t_ret;
00310         u_int32_t bytesgot, bytes;
00311         u_int8_t *src, *dest;
00312 
00313         mpf = dbp->mpf;
00314         h = NULL;
00315         ret = t_ret = 0;
00316         bytesgot = bytes = 0;
00317 
00318         while ((pgno != PGNO_INVALID) && (IS_VALID_PGNO(pgno))) {
00319                 /*
00320                  * Mark that we're looking at this page;  if we've seen it
00321                  * already, quit.
00322                  */
00323                 if ((ret = __db_salvage_markdone(vdp, pgno)) != 0)
00324                         break;
00325 
00326                 if ((ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
00327                         break;
00328 
00329                 /*
00330                  * Make sure it's really an overflow page, unless we're
00331                  * being aggressive, in which case we pretend it is.
00332                  */
00333                 if (!LF_ISSET(DB_AGGRESSIVE) && TYPE(h) != P_OVERFLOW) {
00334                         ret = DB_VERIFY_BAD;
00335                         break;
00336                 }
00337 
00338                 src = (u_int8_t *)h + P_OVERHEAD(dbp);
00339                 bytes = OV_LEN(h);
00340 
00341                 if (bytes + P_OVERHEAD(dbp) > dbp->pgsize)
00342                         bytes = dbp->pgsize - P_OVERHEAD(dbp);
00343 
00344                 if ((ret = __os_realloc(dbp->dbenv,
00345                     bytesgot + bytes, buf)) != 0)
00346                         break;
00347 
00348                 dest = *(u_int8_t **)buf + bytesgot;
00349                 bytesgot += bytes;
00350 
00351                 memcpy(dest, src, bytes);
00352 
00353                 pgno = NEXT_PGNO(h);
00354 
00355                 if ((ret = __memp_fput(mpf, h, 0)) != 0)
00356                         break;
00357                 h = NULL;
00358         }
00359 
00360         /*
00361          * If we're being aggressive, salvage a partial datum if there
00362          * was an error somewhere along the way.
00363          */
00364         if (ret == 0 || LF_ISSET(DB_AGGRESSIVE)) {
00365                 dbt->size = bytesgot;
00366                 dbt->data = *(void **)buf;
00367         }
00368 
00369         /* If we broke out on error, don't leave pages pinned. */
00370         if (h != NULL && (t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
00371                 ret = t_ret;
00372 
00373         return (ret);
00374 }

Generated on Sun Dec 25 12:14:20 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2