~ubuntu-branches/ubuntu/edgy/rpm/edgy

« back to all changes in this revision

Viewing changes to db/db/db_overflow.c

  • Committer: Bazaar Package Importer
  • Author(s): Joey Hess
  • Date: 2002-01-22 20:56:57 UTC
  • Revision ID: james.westby@ubuntu.com-20020122205657-l74j50mr9z8ofcl5
Tags: upstream-4.0.3
ImportĀ upstreamĀ versionĀ 4.0.3

Show diffs side-by-side

added added

removed removed

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