db_overflow.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:18k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. /*
  8.  * Copyright (c) 1990, 1993, 1994, 1995, 1996
  9.  * Keith Bostic.  All rights reserved.
  10.  */
  11. /*
  12.  * Copyright (c) 1990, 1993, 1994, 1995
  13.  * The Regents of the University of California.  All rights reserved.
  14.  *
  15.  * This code is derived from software contributed to Berkeley by
  16.  * Mike Olson.
  17.  *
  18.  * Redistribution and use in source and binary forms, with or without
  19.  * modification, are permitted provided that the following conditions
  20.  * are met:
  21.  * 1. Redistributions of source code must retain the above copyright
  22.  *    notice, this list of conditions and the following disclaimer.
  23.  * 2. Redistributions in binary form must reproduce the above copyright
  24.  *    notice, this list of conditions and the following disclaimer in the
  25.  *    documentation and/or other materials provided with the distribution.
  26.  * 3. Neither the name of the University nor the names of its contributors
  27.  *    may be used to endorse or promote products derived from this software
  28.  *    without specific prior written permission.
  29.  *
  30.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  31.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  32.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  34.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  35.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  36.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  37.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  38.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  39.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  40.  * SUCH DAMAGE.
  41.  */
  42. #include "db_config.h"
  43. #ifndef lint
  44. static const char revid[] = "$Id: db_overflow.c,v 11.46 2002/08/08 03:57:48 bostic Exp $";
  45. #endif /* not lint */
  46. #ifndef NO_SYSTEM_INCLUDES
  47. #include <sys/types.h>
  48. #include <string.h>
  49. #endif
  50. #include "db_int.h"
  51. #include "dbinc/db_page.h"
  52. #include "dbinc/db_am.h"
  53. #include "dbinc/db_verify.h"
  54. /*
  55.  * Big key/data code.
  56.  *
  57.  * Big key and data entries are stored on linked lists of pages.  The initial
  58.  * reference is a structure with the total length of the item and the page
  59.  * number where it begins.  Each entry in the linked list contains a pointer
  60.  * to the next page of data, and so on.
  61.  */
  62. /*
  63.  * __db_goff --
  64.  * Get an offpage item.
  65.  *
  66.  * PUBLIC: int __db_goff __P((DB *, DBT *,
  67.  * PUBLIC:     u_int32_t, db_pgno_t, void **, u_int32_t *));
  68.  */
  69. int
  70. __db_goff(dbp, dbt, tlen, pgno, bpp, bpsz)
  71. DB *dbp;
  72. DBT *dbt;
  73. u_int32_t tlen;
  74. db_pgno_t pgno;
  75. void **bpp;
  76. u_int32_t *bpsz;
  77. {
  78. DB_ENV *dbenv;
  79. DB_MPOOLFILE *mpf;
  80. PAGE *h;
  81. db_indx_t bytes;
  82. u_int32_t curoff, needed, start;
  83. u_int8_t *p, *src;
  84. int ret;
  85. dbenv = dbp->dbenv;
  86. mpf = dbp->mpf;
  87. /*
  88.  * Check if the buffer is big enough; if it is not and we are
  89.  * allowed to malloc space, then we'll malloc it.  If we are
  90.  * not (DB_DBT_USERMEM), then we'll set the dbt and return
  91.  * appropriately.
  92.  */
  93. if (F_ISSET(dbt, DB_DBT_PARTIAL)) {
  94. start = dbt->doff;
  95. if (start > tlen)
  96. needed = 0;
  97. else if (dbt->dlen > tlen - start)
  98. needed = tlen - start;
  99. else
  100. needed = dbt->dlen;
  101. } else {
  102. start = 0;
  103. needed = tlen;
  104. }
  105. /* Allocate any necessary memory. */
  106. if (F_ISSET(dbt, DB_DBT_USERMEM)) {
  107. if (needed > dbt->ulen) {
  108. dbt->size = needed;
  109. return (ENOMEM);
  110. }
  111. } else if (F_ISSET(dbt, DB_DBT_MALLOC)) {
  112. if ((ret = __os_umalloc(dbenv, needed, &dbt->data)) != 0)
  113. return (ret);
  114. } else if (F_ISSET(dbt, DB_DBT_REALLOC)) {
  115. if ((ret = __os_urealloc(dbenv, needed, &dbt->data)) != 0)
  116. return (ret);
  117. } else if (*bpsz == 0 || *bpsz < needed) {
  118. if ((ret = __os_realloc(dbenv, needed, bpp)) != 0)
  119. return (ret);
  120. *bpsz = needed;
  121. dbt->data = *bpp;
  122. } else
  123. dbt->data = *bpp;
  124. /*
  125.  * Step through the linked list of pages, copying the data on each
  126.  * one into the buffer.  Never copy more than the total data length.
  127.  */
  128. dbt->size = needed;
  129. for (curoff = 0, p = dbt->data; pgno != PGNO_INVALID && needed > 0;) {
  130. if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
  131. return (ret);
  132. /* Check if we need any bytes from this page. */
  133. if (curoff + OV_LEN(h) >= start) {
  134. src = (u_int8_t *)h + P_OVERHEAD(dbp);
  135. bytes = OV_LEN(h);
  136. if (start > curoff) {
  137. src += start - curoff;
  138. bytes -= start - curoff;
  139. }
  140. if (bytes > needed)
  141. bytes = needed;
  142. memcpy(p, src, bytes);
  143. p += bytes;
  144. needed -= bytes;
  145. }
  146. curoff += OV_LEN(h);
  147. pgno = h->next_pgno;
  148. (void)mpf->put(mpf, h, 0);
  149. }
  150. return (0);
  151. }
  152. /*
  153.  * __db_poff --
  154.  * Put an offpage item.
  155.  *
  156.  * PUBLIC: int __db_poff __P((DBC *, const DBT *, db_pgno_t *));
  157.  */
  158. int
  159. __db_poff(dbc, dbt, pgnop)
  160. DBC *dbc;
  161. const DBT *dbt;
  162. db_pgno_t *pgnop;
  163. {
  164. DB *dbp;
  165. DBT tmp_dbt;
  166. DB_LSN new_lsn, null_lsn;
  167. DB_MPOOLFILE *mpf;
  168. PAGE *pagep, *lastp;
  169. db_indx_t pagespace;
  170. u_int32_t sz;
  171. u_int8_t *p;
  172. int ret, t_ret;
  173. /*
  174.  * Allocate pages and copy the key/data item into them.  Calculate the
  175.  * number of bytes we get for pages we fill completely with a single
  176.  * item.
  177.  */
  178. dbp = dbc->dbp;
  179. mpf = dbp->mpf;
  180. pagespace = P_MAXSPACE(dbp, dbp->pgsize);
  181. ret = 0;
  182. lastp = NULL;
  183. for (p = dbt->data,
  184.     sz = dbt->size; sz > 0; p += pagespace, sz -= pagespace) {
  185. /*
  186.  * Reduce pagespace so we terminate the loop correctly and
  187.  * don't copy too much data.
  188.  */
  189. if (sz < pagespace)
  190. pagespace = sz;
  191. /*
  192.  * Allocate and initialize a new page and copy all or part of
  193.  * the item onto the page.  If sz is less than pagespace, we
  194.  * have a partial record.
  195.  */
  196. if ((ret = __db_new(dbc, P_OVERFLOW, &pagep)) != 0)
  197. break;
  198. if (DBC_LOGGING(dbc)) {
  199. tmp_dbt.data = p;
  200. tmp_dbt.size = pagespace;
  201. ZERO_LSN(null_lsn);
  202. if ((ret = __db_big_log(dbp, dbc->txn,
  203.     &new_lsn, 0, DB_ADD_BIG, PGNO(pagep),
  204.     lastp ? PGNO(lastp) : PGNO_INVALID,
  205.     PGNO_INVALID, &tmp_dbt, &LSN(pagep),
  206.     lastp == NULL ? &null_lsn : &LSN(lastp),
  207.     &null_lsn)) != 0) {
  208. if (lastp != NULL)
  209. (void)mpf->put(mpf,
  210.     lastp, DB_MPOOL_DIRTY);
  211. lastp = pagep;
  212. break;
  213. }
  214. } else
  215. LSN_NOT_LOGGED(new_lsn);
  216. /* Move LSN onto page. */
  217. if (lastp != NULL)
  218. LSN(lastp) = new_lsn;
  219. LSN(pagep) = new_lsn;
  220. P_INIT(pagep, dbp->pgsize,
  221.     PGNO(pagep), PGNO_INVALID, PGNO_INVALID, 0, P_OVERFLOW);
  222. OV_LEN(pagep) = pagespace;
  223. OV_REF(pagep) = 1;
  224. memcpy((u_int8_t *)pagep + P_OVERHEAD(dbp), p, pagespace);
  225. /*
  226.  * If this is the first entry, update the user's info.
  227.  * Otherwise, update the entry on the last page filled
  228.  * in and release that page.
  229.  */
  230. if (lastp == NULL)
  231. *pgnop = PGNO(pagep);
  232. else {
  233. lastp->next_pgno = PGNO(pagep);
  234. pagep->prev_pgno = PGNO(lastp);
  235. (void)mpf->put(mpf, lastp, DB_MPOOL_DIRTY);
  236. }
  237. lastp = pagep;
  238. }
  239. if (lastp != NULL &&
  240.     (t_ret = mpf->put(mpf, lastp, DB_MPOOL_DIRTY)) != 0 && ret == 0)
  241. ret = t_ret;
  242. return (ret);
  243. }
  244. /*
  245.  * __db_ovref --
  246.  * Increment/decrement the reference count on an overflow page.
  247.  *
  248.  * PUBLIC: int __db_ovref __P((DBC *, db_pgno_t, int32_t));
  249.  */
  250. int
  251. __db_ovref(dbc, pgno, adjust)
  252. DBC *dbc;
  253. db_pgno_t pgno;
  254. int32_t adjust;
  255. {
  256. DB *dbp;
  257. DB_MPOOLFILE *mpf;
  258. PAGE *h;
  259. int ret;
  260. dbp = dbc->dbp;
  261. mpf = dbp->mpf;
  262. if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0) {
  263. __db_pgerr(dbp, pgno, ret);
  264. return (ret);
  265. }
  266. if (DBC_LOGGING(dbc)) {
  267. if ((ret = __db_ovref_log(dbp,
  268.     dbc->txn, &LSN(h), 0, h->pgno, adjust, &LSN(h))) != 0) {
  269. (void)mpf->put(mpf, h, 0);
  270. return (ret);
  271. }
  272. } else
  273. LSN_NOT_LOGGED(LSN(h));
  274. OV_REF(h) += adjust;
  275. (void)mpf->put(mpf, h, DB_MPOOL_DIRTY);
  276. return (0);
  277. }
  278. /*
  279.  * __db_doff --
  280.  * Delete an offpage chain of overflow pages.
  281.  *
  282.  * PUBLIC: int __db_doff __P((DBC *, db_pgno_t));
  283.  */
  284. int
  285. __db_doff(dbc, pgno)
  286. DBC *dbc;
  287. db_pgno_t pgno;
  288. {
  289. DB *dbp;
  290. PAGE *pagep;
  291. DB_LSN null_lsn;
  292. DB_MPOOLFILE *mpf;
  293. DBT tmp_dbt;
  294. int ret;
  295. dbp = dbc->dbp;
  296. mpf = dbp->mpf;
  297. do {
  298. if ((ret = mpf->get(mpf, &pgno, 0, &pagep)) != 0) {
  299. __db_pgerr(dbp, pgno, ret);
  300. return (ret);
  301. }
  302. DB_ASSERT(TYPE(pagep) == P_OVERFLOW);
  303. /*
  304.  * If it's referenced by more than one key/data item,
  305.  * decrement the reference count and return.
  306.  */
  307. if (OV_REF(pagep) > 1) {
  308. (void)mpf->put(mpf, pagep, 0);
  309. return (__db_ovref(dbc, pgno, -1));
  310. }
  311. if (DBC_LOGGING(dbc)) {
  312. tmp_dbt.data = (u_int8_t *)pagep + P_OVERHEAD(dbp);
  313. tmp_dbt.size = OV_LEN(pagep);
  314. ZERO_LSN(null_lsn);
  315. if ((ret = __db_big_log(dbp, dbc->txn,
  316.     &LSN(pagep), 0, DB_REM_BIG,
  317.     PGNO(pagep), PREV_PGNO(pagep),
  318.     NEXT_PGNO(pagep), &tmp_dbt,
  319.     &LSN(pagep), &null_lsn, &null_lsn)) != 0) {
  320. (void)mpf->put(mpf, pagep, 0);
  321. return (ret);
  322. }
  323. } else
  324. LSN_NOT_LOGGED(LSN(pagep));
  325. pgno = pagep->next_pgno;
  326. if ((ret = __db_free(dbc, pagep)) != 0)
  327. return (ret);
  328. } while (pgno != PGNO_INVALID);
  329. return (0);
  330. }
  331. /*
  332.  * __db_moff --
  333.  * Match on overflow pages.
  334.  *
  335.  * Given a starting page number and a key, return <0, 0, >0 to indicate if the
  336.  * key on the page is less than, equal to or greater than the key specified.
  337.  * We optimize this by doing chunk at a time comparison unless the user has
  338.  * specified a comparison function.  In this case, we need to materialize
  339.  * the entire object and call their comparison routine.
  340.  *
  341.  * PUBLIC: int __db_moff __P((DB *, const DBT *, db_pgno_t, u_int32_t,
  342.  * PUBLIC:     int (*)(DB *, const DBT *, const DBT *), int *));
  343.  */
  344. int
  345. __db_moff(dbp, dbt, pgno, tlen, cmpfunc, cmpp)
  346. DB *dbp;
  347. const DBT *dbt;
  348. db_pgno_t pgno;
  349. u_int32_t tlen;
  350. int (*cmpfunc) __P((DB *, const DBT *, const DBT *)), *cmpp;
  351. {
  352. DBT local_dbt;
  353. DB_MPOOLFILE *mpf;
  354. PAGE *pagep;
  355. void *buf;
  356. u_int32_t bufsize, cmp_bytes, key_left;
  357. u_int8_t *p1, *p2;
  358. int ret;
  359. mpf = dbp->mpf;
  360. /*
  361.  * If there is a user-specified comparison function, build a
  362.  * contiguous copy of the key, and call it.
  363.  */
  364. if (cmpfunc != NULL) {
  365. memset(&local_dbt, 0, sizeof(local_dbt));
  366. buf = NULL;
  367. bufsize = 0;
  368. if ((ret = __db_goff(dbp,
  369.     &local_dbt, tlen, pgno, &buf, &bufsize)) != 0)
  370. return (ret);
  371. /* Pass the key as the first argument */
  372. *cmpp = cmpfunc(dbp, dbt, &local_dbt);
  373. __os_free(dbp->dbenv, buf);
  374. return (0);
  375. }
  376. /* While there are both keys to compare. */
  377. for (*cmpp = 0, p1 = dbt->data,
  378.     key_left = dbt->size; key_left > 0 && pgno != PGNO_INVALID;) {
  379. if ((ret = mpf->get(mpf, &pgno, 0, &pagep)) != 0)
  380. return (ret);
  381. cmp_bytes = OV_LEN(pagep) < key_left ? OV_LEN(pagep) : key_left;
  382. tlen -= cmp_bytes;
  383. key_left -= cmp_bytes;
  384. for (p2 = (u_int8_t *)pagep + P_OVERHEAD(dbp);
  385.     cmp_bytes-- > 0; ++p1, ++p2)
  386. if (*p1 != *p2) {
  387. *cmpp = (long)*p1 - (long)*p2;
  388. break;
  389. }
  390. pgno = NEXT_PGNO(pagep);
  391. if ((ret = mpf->put(mpf, pagep, 0)) != 0)
  392. return (ret);
  393. if (*cmpp != 0)
  394. return (0);
  395. }
  396. if (key_left > 0) /* DBT is longer than the page key. */
  397. *cmpp = 1;
  398. else if (tlen > 0) /* DBT is shorter than the page key. */
  399. *cmpp = -1;
  400. else
  401. *cmpp = 0;
  402. return (0);
  403. }
  404. /*
  405.  * __db_vrfy_overflow --
  406.  * Verify overflow page.
  407.  *
  408.  * PUBLIC: int __db_vrfy_overflow __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t,
  409.  * PUBLIC:     u_int32_t));
  410.  */
  411. int
  412. __db_vrfy_overflow(dbp, vdp, h, pgno, flags)
  413. DB *dbp;
  414. VRFY_DBINFO *vdp;
  415. PAGE *h;
  416. db_pgno_t pgno;
  417. u_int32_t flags;
  418. {
  419. VRFY_PAGEINFO *pip;
  420. int isbad, ret, t_ret;
  421. isbad = 0;
  422. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  423. return (ret);
  424. if ((ret = __db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) {
  425. if (ret == DB_VERIFY_BAD)
  426. isbad = 1;
  427. else
  428. goto err;
  429. }
  430. pip->refcount = OV_REF(h);
  431. if (pip->refcount < 1) {
  432. EPRINT((dbp->dbenv,
  433.     "Page %lu: overflow page has zero reference count",
  434.     (u_long)pgno));
  435. isbad = 1;
  436. }
  437. /* Just store for now. */
  438. pip->olen = HOFFSET(h);
  439. err: if ((t_ret = __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0)
  440. ret = t_ret;
  441. return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
  442. }
  443. /*
  444.  * __db_vrfy_ovfl_structure --
  445.  * Walk a list of overflow pages, avoiding cycles and marking
  446.  * pages seen.
  447.  *
  448.  * PUBLIC: int __db_vrfy_ovfl_structure
  449.  * PUBLIC:     __P((DB *, VRFY_DBINFO *, db_pgno_t, u_int32_t, u_int32_t));
  450.  */
  451. int
  452. __db_vrfy_ovfl_structure(dbp, vdp, pgno, tlen, flags)
  453. DB *dbp;
  454. VRFY_DBINFO *vdp;
  455. db_pgno_t pgno;
  456. u_int32_t tlen;
  457. u_int32_t flags;
  458. {
  459. DB *pgset;
  460. VRFY_PAGEINFO *pip;
  461. db_pgno_t next, prev;
  462. int isbad, p, ret, t_ret;
  463. u_int32_t refcount;
  464. pgset = vdp->pgset;
  465. DB_ASSERT(pgset != NULL);
  466. isbad = 0;
  467. /* This shouldn't happen, but just to be sure. */
  468. if (!IS_VALID_PGNO(pgno))
  469. return (DB_VERIFY_BAD);
  470. /*
  471.  * Check the first prev_pgno;  it ought to be PGNO_INVALID,
  472.  * since there's no prev page.
  473.  */
  474. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  475. return (ret);
  476. /* The refcount is stored on the first overflow page. */
  477. refcount = pip->refcount;
  478. if (pip->type != P_OVERFLOW) {
  479. EPRINT((dbp->dbenv,
  480.     "Page %lu: overflow page of invalid type %lu",
  481.     (u_long)pgno, (u_long)pip->type));
  482. ret = DB_VERIFY_BAD;
  483. goto err; /* Unsafe to continue. */
  484. }
  485. prev = pip->prev_pgno;
  486. if (prev != PGNO_INVALID) {
  487. EPRINT((dbp->dbenv,
  488.     "Page %lu: first page in overflow chain has a prev_pgno %lu",
  489.     (u_long)pgno, (u_long)prev));
  490. isbad = 1;
  491. }
  492. for (;;) {
  493. /*
  494.  * This is slightly gross.  Btree leaf pages reference
  495.  * individual overflow trees multiple times if the overflow page
  496.  * is the key to a duplicate set.  The reference count does not
  497.  * reflect this multiple referencing.  Thus, if this is called
  498.  * during the structure verification of a btree leaf page, we
  499.  * check to see whether we've seen it from a leaf page before
  500.  * and, if we have, adjust our count of how often we've seen it
  501.  * accordingly.
  502.  *
  503.  * (This will screw up if it's actually referenced--and
  504.  * correctly refcounted--from two different leaf pages, but
  505.  * that's a very unlikely brokenness that we're not checking for
  506.  * anyway.)
  507.  */
  508. if (LF_ISSET(ST_OVFL_LEAF)) {
  509. if (F_ISSET(pip, VRFY_OVFL_LEAFSEEN)) {
  510. if ((ret =
  511.     __db_vrfy_pgset_dec(pgset, pgno)) != 0)
  512. goto err;
  513. } else
  514. F_SET(pip, VRFY_OVFL_LEAFSEEN);
  515. }
  516. if ((ret = __db_vrfy_pgset_get(pgset, pgno, &p)) != 0)
  517. goto err;
  518. /*
  519.  * We may have seen this elsewhere, if the overflow entry
  520.  * has been promoted to an internal page.
  521.  */
  522. if ((u_int32_t)p > refcount) {
  523. EPRINT((dbp->dbenv,
  524.     "Page %lu: encountered twice in overflow traversal",
  525.     (u_long)pgno));
  526. ret = DB_VERIFY_BAD;
  527. goto err;
  528. }
  529. if ((ret = __db_vrfy_pgset_inc(pgset, pgno)) != 0)
  530. goto err;
  531. /* Keep a running tab on how much of the item we've seen. */
  532. tlen -= pip->olen;
  533. /* Send feedback to the application about our progress. */
  534. if (!LF_ISSET(DB_SALVAGE))
  535. __db_vrfy_struct_feedback(dbp, vdp);
  536. next = pip->next_pgno;
  537. /* Are we there yet? */
  538. if (next == PGNO_INVALID)
  539. break;
  540. /*
  541.  * We've already checked this when we saved it, but just
  542.  * to be sure...
  543.  */
  544. if (!IS_VALID_PGNO(next)) {
  545. DB_ASSERT(0);
  546. EPRINT((dbp->dbenv,
  547.     "Page %lu: bad next_pgno %lu on overflow page",
  548.     (u_long)pgno, (u_long)next));
  549. ret = DB_VERIFY_BAD;
  550. goto err;
  551. }
  552. if ((ret = __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 ||
  553.     (ret = __db_vrfy_getpageinfo(vdp, next, &pip)) != 0)
  554. return (ret);
  555. if (pip->prev_pgno != pgno) {
  556. EPRINT((dbp->dbenv,
  557. "Page %lu: bad prev_pgno %lu on overflow page (should be %lu)",
  558.     (u_long)next, (u_long)pip->prev_pgno,
  559.     (u_long)pgno));
  560. isbad = 1;
  561. /*
  562.  * It's safe to continue because we have separate
  563.  * cycle detection.
  564.  */
  565. }
  566. pgno = next;
  567. }
  568. if (tlen > 0) {
  569. isbad = 1;
  570. EPRINT((dbp->dbenv,
  571.     "Page %lu: overflow item incomplete", (u_long)pgno));
  572. }
  573. err: if ((t_ret =
  574.     __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 && ret == 0)
  575. ret = t_ret;
  576. return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
  577. }
  578. /*
  579.  * __db_safe_goff --
  580.  * Get an overflow item, very carefully, from an untrusted database,
  581.  * in the context of the salvager.
  582.  *
  583.  * PUBLIC: int __db_safe_goff __P((DB *, VRFY_DBINFO *, db_pgno_t,
  584.  * PUBLIC:     DBT *, void **, u_int32_t));
  585.  */
  586. int
  587. __db_safe_goff(dbp, vdp, pgno, dbt, buf, flags)
  588. DB *dbp;
  589. VRFY_DBINFO *vdp;
  590. db_pgno_t pgno;
  591. DBT *dbt;
  592. void **buf;
  593. u_int32_t flags;
  594. {
  595. DB_MPOOLFILE *mpf;
  596. PAGE *h;
  597. int ret, t_ret;
  598. u_int32_t bytesgot, bytes;
  599. u_int8_t *src, *dest;
  600. mpf = dbp->mpf;
  601. h = NULL;
  602. ret = t_ret = 0;
  603. bytesgot = bytes = 0;
  604. while ((pgno != PGNO_INVALID) && (IS_VALID_PGNO(pgno))) {
  605. /*
  606.  * Mark that we're looking at this page;  if we've seen it
  607.  * already, quit.
  608.  */
  609. if ((ret = __db_salvage_markdone(vdp, pgno)) != 0)
  610. break;
  611. if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
  612. break;
  613. /*
  614.  * Make sure it's really an overflow page, unless we're
  615.  * being aggressive, in which case we pretend it is.
  616.  */
  617. if (!LF_ISSET(DB_AGGRESSIVE) && TYPE(h) != P_OVERFLOW) {
  618. ret = DB_VERIFY_BAD;
  619. break;
  620. }
  621. src = (u_int8_t *)h + P_OVERHEAD(dbp);
  622. bytes = OV_LEN(h);
  623. if (bytes + P_OVERHEAD(dbp) > dbp->pgsize)
  624. bytes = dbp->pgsize - P_OVERHEAD(dbp);
  625. if ((ret = __os_realloc(dbp->dbenv,
  626.     bytesgot + bytes, buf)) != 0)
  627. break;
  628. dest = (u_int8_t *)*buf + bytesgot;
  629. bytesgot += bytes;
  630. memcpy(dest, src, bytes);
  631. pgno = NEXT_PGNO(h);
  632. if ((ret = mpf->put(mpf, h, 0)) != 0)
  633. break;
  634. h = NULL;
  635. }
  636. /*
  637.  * If we're being aggressive, salvage a partial datum if there
  638.  * was an error somewhere along the way.
  639.  */
  640. if (ret == 0 || LF_ISSET(DB_AGGRESSIVE)) {
  641. dbt->size = bytesgot;
  642. dbt->data = *buf;
  643. }
  644. /* If we broke out on error, don't leave pages pinned. */
  645. if (h != NULL && (t_ret = mpf->put(mpf, h, 0)) != 0 && ret == 0)
  646. ret = t_ret;
  647. return (ret);
  648. }