00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 1996, 1997, 1998, 1999, 2000 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 00043 #include "config.h" 00044 00045 #ifndef lint 00046 static const char revid[] = "$Id: db__overflow_8c-source.html,v 1.1 2008年06月08日 10:17:55 sebdiaz Exp $"; 00047 #endif /* not lint */ 00048 00049 #ifndef NO_SYSTEM_INCLUDES 00050 #include <sys/types.h> 00051 00052 #include <errno.h> 00053 #include <string.h> 00054 #endif 00055 00056 #include "db_int.h" 00057 #include "db_page.h" 00058 #include "db_am.h" 00059 #include "db_verify.h" 00060 00061 /* 00062 * Big key/data code. 00063 * 00064 * Big key and data entries are stored on linked lists of pages. The initial 00065 * reference is a structure with the total length of the item and the page 00066 * number where it begins. Each entry in the linked list contains a pointer 00067 * to the next page of data, and so on. 00068 */ 00069 00070 /* 00071 * CDB___db_goff -- 00072 * Get an offpage item. 00073 * 00074 * PUBLIC: int CDB___db_goff __P((DB *, DBT *, 00075 * PUBLIC: u_int32_t, db_pgno_t, void **, u_int32_t *)); 00076 */ 00077 int 00078 CDB___db_goff(dbp, dbt, tlen, pgno, bpp, bpsz) 00079 DB *dbp; 00080 DBT *dbt; 00081 u_int32_t tlen; 00082 db_pgno_t pgno; 00083 void **bpp; 00084 u_int32_t *bpsz; 00085 { 00086 DB_ENV *dbenv; 00087 PAGE *h; 00088 db_indx_t bytes; 00089 u_int32_t curoff, needed, start; 00090 u_int8_t *p, *src; 00091 int ret; 00092 00093 dbenv = dbp->dbenv; 00094 00095 /* 00096 * Check if the buffer is big enough; if it is not and we are 00097 * allowed to malloc space, then we'll malloc it. If we are 00098 * not (DB_DBT_USERMEM), then we'll set the dbt and return 00099 * appropriately. 00100 */ 00101 if (F_ISSET(dbt, DB_DBT_PARTIAL)) { 00102 start = dbt->doff; 00103 needed = dbt->dlen; 00104 } else { 00105 start = 0; 00106 needed = tlen; 00107 } 00108 00109 /* Allocate any necessary memory. */ 00110 if (F_ISSET(dbt, DB_DBT_USERMEM)) { 00111 if (needed > dbt->ulen) { 00112 dbt->size = needed; 00113 return (ENOMEM); 00114 } 00115 } else if (F_ISSET(dbt, DB_DBT_MALLOC)) { 00116 if ((ret = CDB___os_malloc(dbenv, 00117 needed, dbp->db_malloc, &dbt->data)) != 0) 00118 return (ret); 00119 } else if (F_ISSET(dbt, DB_DBT_REALLOC)) { 00120 if ((ret = CDB___os_realloc(dbenv, 00121 needed, dbp->db_realloc, &dbt->data)) != 0) 00122 return (ret); 00123 } else if (*bpsz == 0 || *bpsz < needed) { 00124 if ((ret = CDB___os_realloc(dbenv, needed, NULL, bpp)) != 0) 00125 return (ret); 00126 *bpsz = needed; 00127 dbt->data = *bpp; 00128 } else 00129 dbt->data = *bpp; 00130 00131 /* 00132 * Step through the linked list of pages, copying the data on each 00133 * one into the buffer. Never copy more than the total data length. 00134 */ 00135 dbt->size = needed; 00136 for (curoff = 0, p = dbt->data; pgno != PGNO_INVALID && needed > 0;) { 00137 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) { 00138 (void)CDB___db_pgerr(dbp, pgno); 00139 return (ret); 00140 } 00141 /* Check if we need any bytes from this page. */ 00142 if (curoff + OV_LEN(h) >= start) { 00143 src = (u_int8_t *)h + P_OVERHEAD; 00144 bytes = OV_LEN(h); 00145 if (start > curoff) { 00146 src += start - curoff; 00147 bytes -= start - curoff; 00148 } 00149 if (bytes > needed) 00150 bytes = needed; 00151 memcpy(p, src, bytes); 00152 p += bytes; 00153 needed -= bytes; 00154 } 00155 curoff += OV_LEN(h); 00156 pgno = h->next_pgno; 00157 CDB_memp_fput(dbp->mpf, h, 0); 00158 } 00159 return (0); 00160 } 00161 00162 /* 00163 * CDB___db_poff -- 00164 * Put an offpage item. 00165 * 00166 * PUBLIC: int CDB___db_poff __P((DBC *, const DBT *, db_pgno_t *)); 00167 */ 00168 int 00169 CDB___db_poff(dbc, dbt, pgnop) 00170 DBC *dbc; 00171 const DBT *dbt; 00172 db_pgno_t *pgnop; 00173 { 00174 DB *dbp; 00175 PAGE *pagep, *lastp; 00176 DB_LSN new_lsn, null_lsn; 00177 DBT tmp_dbt; 00178 db_indx_t pagespace; 00179 u_int32_t sz; 00180 u_int8_t *p; 00181 int ret; 00182 00183 /* 00184 * Allocate pages and copy the key/data item into them. Calculate the 00185 * number of bytes we get for pages we fill completely with a single 00186 * item. 00187 */ 00188 dbp = dbc->dbp; 00189 pagespace = P_MAXSPACE(dbp->pgsize); 00190 00191 lastp = NULL; 00192 for (p = dbt->data, 00193 sz = dbt->size; sz > 0; p += pagespace, sz -= pagespace) { 00194 /* 00195 * Reduce pagespace so we terminate the loop correctly and 00196 * don't copy too much data. 00197 */ 00198 if (sz < pagespace) 00199 pagespace = sz; 00200 00201 /* 00202 * Allocate and initialize a new page and copy all or part of 00203 * the item onto the page. If sz is less than pagespace, we 00204 * have a partial record. 00205 */ 00206 if ((ret = CDB___db_new(dbc, (P_OVERFLOW | dbp->tags), &pagep)) != 0) 00207 return (ret); 00208 if (DB_LOGGING(dbc)) { 00209 tmp_dbt.data = p; 00210 tmp_dbt.size = pagespace; 00211 ZERO_LSN(null_lsn); 00212 if ((ret = CDB___db_big_log(dbp->dbenv, dbc->txn, 00213 &new_lsn, 0, DB_ADD_BIG, dbp->log_fileid, 00214 PGNO(pagep), lastp ? PGNO(lastp) : PGNO_INVALID, 00215 PGNO_INVALID, &tmp_dbt, &LSN(pagep), 00216 lastp == NULL ? &null_lsn : &LSN(lastp), 00217 &null_lsn)) != 0) 00218 return (ret); 00219 00220 /* Move lsn onto page. */ 00221 if (lastp) 00222 LSN(lastp) = new_lsn; 00223 LSN(pagep) = new_lsn; 00224 } 00225 00226 P_INIT(pagep, dbp->pgsize, 00227 PGNO(pagep), PGNO_INVALID, PGNO_INVALID, 0, P_OVERFLOW, dbp->tags); 00228 OV_LEN(pagep) = pagespace; 00229 OV_REF(pagep) = 1; 00230 memcpy((u_int8_t *)pagep + P_OVERHEAD, p, pagespace); 00231 00232 /* 00233 * If this is the first entry, update the user's info. 00234 * Otherwise, update the entry on the last page filled 00235 * in and release that page. 00236 */ 00237 if (lastp == NULL) 00238 *pgnop = PGNO(pagep); 00239 else { 00240 lastp->next_pgno = PGNO(pagep); 00241 pagep->prev_pgno = PGNO(lastp); 00242 (void)CDB_memp_fput(dbp->mpf, lastp, DB_MPOOL_DIRTY); 00243 } 00244 lastp = pagep; 00245 } 00246 (void)CDB_memp_fput(dbp->mpf, lastp, DB_MPOOL_DIRTY); 00247 return (0); 00248 } 00249 00250 /* 00251 * CDB___db_ovref -- 00252 * Increment/decrement the reference count on an overflow page. 00253 * 00254 * PUBLIC: int CDB___db_ovref __P((DBC *, db_pgno_t, int32_t)); 00255 */ 00256 int 00257 CDB___db_ovref(dbc, pgno, adjust) 00258 DBC *dbc; 00259 db_pgno_t pgno; 00260 int32_t adjust; 00261 { 00262 DB *dbp; 00263 PAGE *h; 00264 int ret; 00265 00266 dbp = dbc->dbp; 00267 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) { 00268 (void)CDB___db_pgerr(dbp, pgno); 00269 return (ret); 00270 } 00271 00272 if (DB_LOGGING(dbc)) 00273 if ((ret = CDB___db_ovref_log(dbp->dbenv, dbc->txn, 00274 &LSN(h), 0, dbp->log_fileid, h->pgno, adjust, 00275 &LSN(h))) != 0) 00276 return (ret); 00277 OV_REF(h) += adjust; 00278 00279 (void)CDB_memp_fput(dbp->mpf, h, DB_MPOOL_DIRTY); 00280 return (0); 00281 } 00282 00283 /* 00284 * CDB___db_doff -- 00285 * Delete an offpage chain of overflow pages. 00286 * 00287 * PUBLIC: int CDB___db_doff __P((DBC *, db_pgno_t)); 00288 */ 00289 int 00290 CDB___db_doff(dbc, pgno) 00291 DBC *dbc; 00292 db_pgno_t pgno; 00293 { 00294 DB *dbp; 00295 PAGE *pagep; 00296 DB_LSN null_lsn; 00297 DBT tmp_dbt; 00298 int ret; 00299 00300 dbp = dbc->dbp; 00301 do { 00302 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &pagep)) != 0) { 00303 (void)CDB___db_pgerr(dbp, pgno); 00304 return (ret); 00305 } 00306 00307 /* 00308 * If it's an overflow page and it's referenced by more than 00309 * one key/data item, decrement the reference count and return. 00310 */ 00311 if (TYPE(pagep) == P_OVERFLOW && OV_REF(pagep) > 1) { 00312 (void)CDB_memp_fput(dbp->mpf, pagep, 0); 00313 return (CDB___db_ovref(dbc, pgno, -1)); 00314 } 00315 00316 if (DB_LOGGING(dbc)) { 00317 tmp_dbt.data = (u_int8_t *)pagep + P_OVERHEAD; 00318 tmp_dbt.size = OV_LEN(pagep); 00319 ZERO_LSN(null_lsn); 00320 if ((ret = CDB___db_big_log(dbp->dbenv, dbc->txn, 00321 &LSN(pagep), 0, DB_REM_BIG, dbp->log_fileid, 00322 PGNO(pagep), PREV_PGNO(pagep), NEXT_PGNO(pagep), 00323 &tmp_dbt, &LSN(pagep), &null_lsn, &null_lsn)) != 0) 00324 return (ret); 00325 } 00326 pgno = pagep->next_pgno; 00327 if ((ret = CDB___db_free(dbc, pagep)) != 0) 00328 return (ret); 00329 } while (pgno != PGNO_INVALID); 00330 00331 return (0); 00332 } 00333 00334 /* 00335 * CDB___db_moff -- 00336 * Match on overflow pages. 00337 * 00338 * Given a starting page number and a key, return <0, 0, >0 to indicate if the 00339 * key on the page is less than, equal to or greater than the key specified. 00340 * We optimize this by doing chunk at a time comparison unless the user has 00341 * specified a comparison function. In this case, we need to materialize 00342 * the entire object and call their comparison routine. 00343 * 00344 * PUBLIC: int CDB___db_moff __P((DB *, const DBT *, db_pgno_t, u_int32_t, 00345 * PUBLIC: int (*)(const DBT *, const DBT *), int *)); 00346 */ 00347 int 00348 CDB___db_moff(dbp, dbt, pgno, tlen, cmpfunc, cmpp) 00349 DB *dbp; 00350 const DBT *dbt; 00351 db_pgno_t pgno; 00352 u_int32_t tlen; 00353 int (*cmpfunc) __P((const DBT *, const DBT *)); 00354 int *cmpp; 00355 { 00356 PAGE *pagep; 00357 DBT local_dbt; 00358 void *buf; 00359 u_int32_t bufsize, cmp_bytes, key_left; 00360 u_int8_t *p1, *p2; 00361 int ret; 00362 00363 /* 00364 * If there is a user-specified comparison function, build a 00365 * contiguous copy of the key, and call it. 00366 */ 00367 if (cmpfunc != NULL) { 00368 memset(&local_dbt, 0, sizeof(local_dbt)); 00369 buf = NULL; 00370 bufsize = 0; 00371 00372 if ((ret = CDB___db_goff(dbp, 00373 &local_dbt, tlen, pgno, &buf, &bufsize)) != 0) 00374 return (ret); 00375 /* Pass the key as the first argument */ 00376 *cmpp = cmpfunc(dbt, &local_dbt); 00377 CDB___os_free(buf, bufsize); 00378 return (0); 00379 } 00380 00381 /* While there are both keys to compare. */ 00382 for (*cmpp = 0, p1 = dbt->data, 00383 key_left = dbt->size; key_left > 0 && pgno != PGNO_INVALID;) { 00384 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &pagep)) != 0) 00385 return (ret); 00386 00387 cmp_bytes = OV_LEN(pagep) < key_left ? OV_LEN(pagep) : key_left; 00388 tlen -= cmp_bytes; 00389 key_left -= cmp_bytes; 00390 for (p2 = 00391 (u_int8_t *)pagep + P_OVERHEAD; cmp_bytes-- > 0; ++p1, ++p2) 00392 if (*p1 != *p2) { 00393 *cmpp = (long)*p1 - (long)*p2; 00394 break; 00395 } 00396 pgno = NEXT_PGNO(pagep); 00397 if ((ret = CDB_memp_fput(dbp->mpf, pagep, 0)) != 0) 00398 return (ret); 00399 if (*cmpp != 0) 00400 return (0); 00401 } 00402 if (key_left > 0) /* DBT is longer than the page key. */ 00403 *cmpp = 1; 00404 else if (tlen > 0) /* DBT is shorter than the page key. */ 00405 *cmpp = -1; 00406 else 00407 *cmpp = 0; 00408 00409 return (0); 00410 } 00411 00412 /* 00413 * CDB___db_vrfy_overflow -- 00414 * Verify overflow page. 00415 * 00416 * PUBLIC: int CDB___db_vrfy_overflow __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t, 00417 * PUBLIC: u_int32_t)); 00418 */ 00419 int 00420 CDB___db_vrfy_overflow(dbp, vdp, h, pgno, flags) 00421 DB *dbp; 00422 VRFY_DBINFO *vdp; 00423 PAGE *h; 00424 db_pgno_t pgno; 00425 u_int32_t flags; 00426 { 00427 VRFY_PAGEINFO *pip; 00428 int isbad, ret, t_ret; 00429 00430 isbad = 0; 00431 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) 00432 return (ret); 00433 00434 if ((ret = CDB___db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) { 00435 if (ret == DB_VERIFY_BAD) 00436 isbad = 1; 00437 else 00438 goto err; 00439 } 00440 00441 pip->refcount = OV_REF(h); 00442 if (pip->refcount < 1) { 00443 EPRINT((dbp->dbenv, "Overflow page %lu has zero reference count", 00444 pgno)); 00445 isbad = 1; 00446 } 00447 00448 /* Just store for now. */ 00449 pip->olen = HOFFSET(h); 00450 00451 err: if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0) 00452 ret = t_ret; 00453 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); 00454 } 00455 00456 /* 00457 * CDB___db_vrfy_ovfl_structure -- 00458 * Walk a list of overflow pages, avoiding cycles and marking 00459 * pages seen. 00460 * 00461 * PUBLIC: int CDB___db_vrfy_ovfl_structure 00462 * PUBLIC: __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, u_int32_t)); 00463 */ 00464 int 00465 CDB___db_vrfy_ovfl_structure(dbp, vdp, pgno, tlen, flags) 00466 DB *dbp; 00467 VRFY_DBINFO *vdp; 00468 db_pgno_t pgno; 00469 u_int32_t tlen; 00470 u_int32_t flags; 00471 { 00472 DB *pgset; 00473 VRFY_PAGEINFO *pip; 00474 db_pgno_t next, prev; 00475 int isbad, p, ret, t_ret; 00476 u_int32_t refcount; 00477 00478 pgset = vdp->pgset; 00479 DB_ASSERT(pgset != NULL); 00480 isbad = 0; 00481 00482 /* This shouldn't happen, but just to be sure. */ 00483 if (!IS_VALID_PGNO(pgno)) 00484 return (DB_VERIFY_BAD); 00485 00486 /* 00487 * Check the first prev_pgno; it ought to be PGNO_INVALID, 00488 * since there's no prev page. 00489 */ 00490 if ((ret = CDB___db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0) 00491 return (ret); 00492 00493 /* The refcount is stored on the first overflow page. */ 00494 refcount = pip->refcount; 00495 00496 if (pip->type != P_OVERFLOW) { 00497 EPRINT((dbp->dbenv, 00498 "Overflow page %lu of invalid type", pgno, pip->type)); 00499 ret = DB_VERIFY_BAD; 00500 goto err; /* Unsafe to continue. */ 00501 } 00502 00503 prev = pip->prev_pgno; 00504 if (prev != PGNO_INVALID) { 00505 EPRINT((dbp->dbenv, 00506 "First overflow page %lu has a prev_pgno", pgno)); 00507 isbad = 1; 00508 } 00509 00510 for (;;) { 00511 /* 00512 * This is slightly gross. Btree leaf pages reference 00513 * individual overflow trees multiple times if the overflow page 00514 * is the key to a duplicate set. The reference count does not 00515 * reflect this multiple referencing. Thus, if this is called 00516 * during the structure verification of a btree leaf page, we 00517 * check to see whether we've seen it from a leaf page before 00518 * and, if we have, adjust our count of how often we've seen it 00519 * accordingly. 00520 * 00521 * (This will screw up if it's actually referenced--and 00522 * correctly refcounted--from two different leaf pages, but 00523 * that's a very unlikely brokenness that we're not checking for 00524 * anyway.) 00525 */ 00526 00527 if (LF_ISSET(ST_OVFL_LEAF)) { 00528 if (F_ISSET(pip, VRFY_OVFL_LEAFSEEN)) { 00529 if ((ret = 00530 CDB___db_vrfy_pgset_dec(pgset, pgno)) != 0) 00531 goto err; 00532 } else 00533 F_SET(pip, VRFY_OVFL_LEAFSEEN); 00534 } 00535 00536 if ((ret = CDB___db_vrfy_pgset_get(pgset, pgno, &p)) != 0) 00537 goto err; 00538 00539 /* 00540 * We may have seen this elsewhere, if the overflow entry 00541 * has been promoted to an internal page. 00542 */ 00543 if ((u_int32_t)p > refcount) { 00544 EPRINT((dbp->dbenv, 00545 "Page %lu encountered twice in overflow traversal", 00546 pgno)); 00547 ret = DB_VERIFY_BAD; 00548 goto err; 00549 } 00550 if ((ret = CDB___db_vrfy_pgset_inc(pgset, pgno)) != 0) 00551 goto err; 00552 00553 /* Keep a running tab on how much of the item we've seen. */ 00554 tlen -= pip->olen; 00555 00556 next = pip->next_pgno; 00557 00558 /* Are we there yet? */ 00559 if (next == PGNO_INVALID) 00560 break; 00561 00562 /* 00563 * We've already checked this when we saved it, but just 00564 * to be sure... 00565 */ 00566 if (!IS_VALID_PGNO(next)) { 00567 DB_ASSERT(0); 00568 EPRINT((dbp->dbenv, 00569 "Overflow page %lu has bad next_pgno", 00570 pgno)); 00571 ret = DB_VERIFY_BAD; 00572 goto err; 00573 } 00574 00575 if ((ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 || 00576 (ret = CDB___db_vrfy_getpageinfo(vdp, next, &pip)) != 0) 00577 return (ret); 00578 if (pip->prev_pgno != pgno) { 00579 EPRINT((dbp->dbenv, 00580 "Overflow page %lu has bogus prev_pgno value", 00581 next)); 00582 isbad = 1; 00583 /* 00584 * It's safe to continue because we have separate 00585 * cycle detection. 00586 */ 00587 } 00588 00589 pgno = next; 00590 } 00591 00592 if (tlen > 0) { 00593 isbad = 1; 00594 EPRINT((dbp->dbenv, 00595 "Overflow item incomplete on page %lu", pgno)); 00596 } 00597 00598 err: if ((t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) 00599 ret = t_ret; 00600 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret); 00601 } 00602 00603 /* 00604 * CDB___db_safe_goff -- 00605 * Get an overflow item, very carefully, from an untrusted database, 00606 * in the context of the salvager. 00607 * 00608 * PUBLIC: int CDB___db_safe_goff __P((DB *, VRFY_DBINFO *, db_pgno_t, 00609 * PUBLIC: DBT *, void **, u_int32_t)); 00610 */ 00611 int 00612 CDB___db_safe_goff(dbp, vdp, pgno, dbt, buf, flags) 00613 DB *dbp; 00614 VRFY_DBINFO *vdp; 00615 db_pgno_t pgno; 00616 DBT *dbt; 00617 void **buf; 00618 u_int32_t flags; 00619 { 00620 PAGE *h; 00621 int ret, err_ret; 00622 u_int32_t bytesgot, bytes; 00623 u_int8_t *src, *dest; 00624 00625 ret = DB_VERIFY_BAD; 00626 err_ret = 0; 00627 bytesgot = bytes = 0; 00628 00629 while ((pgno != PGNO_INVALID) && (IS_VALID_PGNO(pgno))) { 00630 /* 00631 * Mark that we're looking at this page; if we've seen it 00632 * already, quit. 00633 */ 00634 if ((ret = CDB___db_salvage_markdone(vdp, pgno)) != 0) 00635 break; 00636 00637 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) 00638 break; 00639 00640 /* 00641 * Make sure it's really an overflow page, unless we're 00642 * being aggressive, in which case we pretend it is. 00643 */ 00644 if (!LF_ISSET(DB_AGGRESSIVE) && TYPE(h) != P_OVERFLOW) { 00645 ret = DB_VERIFY_BAD; 00646 break; 00647 } 00648 00649 src = (u_int8_t *)h + P_OVERHEAD; 00650 bytes = OV_LEN(h); 00651 00652 if (bytes + P_OVERHEAD > dbp->pgsize) 00653 bytes = dbp->pgsize - P_OVERHEAD; 00654 00655 if ((ret = CDB___os_realloc(dbp->dbenv, 00656 bytesgot + bytes, 0, buf)) != 0) 00657 break; 00658 00659 dest = (u_int8_t *)*buf + bytesgot; 00660 bytesgot += bytes; 00661 00662 memcpy(dest, src, bytes); 00663 00664 pgno = NEXT_PGNO(h); 00665 /* Not much we can do here--we don't want to quit. */ 00666 if ((ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0) 00667 err_ret = ret; 00668 } 00669 00670 if (ret == 0) { 00671 dbt->size = bytesgot; 00672 dbt->data = *buf; 00673 } 00674 00675 return ((err_ret != 0 && ret == 0) ? err_ret : ret); 00676 }