~ubuntu-branches/ubuntu/maverick/evolution-data-server/maverick-proposed

« back to all changes in this revision

Viewing changes to libdb/db/db_vrfyutil.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-05-17 17:02:06 UTC
  • mfrom: (1.1.79 upstream) (1.6.12 experimental)
  • Revision ID: james.westby@ubuntu.com-20100517170206-4ufr52vwrhh26yh0
Tags: 2.30.1-1ubuntu1
* Merge from debian experimental. Remaining change:
  (LP: #42199, #229669, #173703, #360344, #508494)
  + debian/control:
    - add Vcs-Bzr tag
    - don't use libgnome
    - Use Breaks instead of Conflicts against evolution 2.25 and earlier.
  + debian/evolution-data-server.install,
    debian/patches/45_libcamel_providers_version.patch:
    - use the upstream versioning, not a Debian-specific one 
  + debian/libedata-book1.2-dev.install, debian/libebackend-1.2-dev.install,
    debian/libcamel1.2-dev.install, debian/libedataserverui1.2-dev.install:
    - install html documentation
  + debian/rules:
    - don't build documentation it's shipped with the tarball

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) 2000-2002
5
 
 *      Sleepycat Software.  All rights reserved.
6
 
 *
7
 
 * $Id$
8
 
 */
9
 
 
10
 
#include "db_config.h"
11
 
 
12
 
#ifndef lint
13
 
static const char revid[] = "$Id$";
14
 
#endif /* not lint */
15
 
 
16
 
#ifndef NO_SYSTEM_INCLUDES
17
 
#include <sys/types.h>
18
 
 
19
 
#include <string.h>
20
 
#endif
21
 
 
22
 
#include "db_int.h"
23
 
#include "dbinc/db_page.h"
24
 
#include "dbinc/db_verify.h"
25
 
#include "dbinc/db_am.h"
26
 
 
27
 
static int __db_vrfy_pageinfo_create __P((DB_ENV *, VRFY_PAGEINFO **));
28
 
static int __db_vrfy_pgset_iinc __P((DB *, db_pgno_t, int));
29
 
 
30
 
/*
31
 
 * __db_vrfy_dbinfo_create --
32
 
 *      Allocate and initialize a VRFY_DBINFO structure.
33
 
 *
34
 
 * PUBLIC: int __db_vrfy_dbinfo_create
35
 
 * PUBLIC:     __P((DB_ENV *, u_int32_t, VRFY_DBINFO **));
36
 
 */
37
 
int
38
 
__db_vrfy_dbinfo_create(dbenv, pgsize, vdpp)
39
 
        DB_ENV *dbenv;
40
 
        u_int32_t pgsize;
41
 
        VRFY_DBINFO **vdpp;
42
 
{
43
 
        DB *cdbp, *pgdbp, *pgset;
44
 
        VRFY_DBINFO *vdp;
45
 
        int ret;
46
 
 
47
 
        vdp = NULL;
48
 
        cdbp = pgdbp = pgset = NULL;
49
 
 
50
 
        if ((ret = __os_calloc(NULL,
51
 
            1, sizeof(VRFY_DBINFO), (void **)&vdp)) != 0)
52
 
                goto err;
53
 
 
54
 
        if ((ret = db_create(&cdbp, dbenv, 0)) != 0)
55
 
                goto err;
56
 
 
57
 
        if ((ret = cdbp->set_flags(cdbp, DB_DUP)) != 0)
58
 
                goto err;
59
 
 
60
 
        if ((ret = cdbp->set_pagesize(cdbp, pgsize)) != 0)
61
 
                goto err;
62
 
 
63
 
        if ((ret =
64
 
            cdbp->open(cdbp, NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0600)) != 0)
65
 
                goto err;
66
 
 
67
 
        if ((ret = db_create(&pgdbp, dbenv, 0)) != 0)
68
 
                goto err;
69
 
 
70
 
        if ((ret = pgdbp->set_pagesize(pgdbp, pgsize)) != 0)
71
 
                goto err;
72
 
 
73
 
        if ((ret = pgdbp->open(pgdbp,
74
 
            NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0600)) != 0)
75
 
                goto err;
76
 
 
77
 
        if ((ret = __db_vrfy_pgset(dbenv, pgsize, &pgset)) != 0)
78
 
                goto err;
79
 
 
80
 
        LIST_INIT(&vdp->subdbs);
81
 
        LIST_INIT(&vdp->activepips);
82
 
 
83
 
        vdp->cdbp = cdbp;
84
 
        vdp->pgdbp = pgdbp;
85
 
        vdp->pgset = pgset;
86
 
        *vdpp = vdp;
87
 
        return (0);
88
 
 
89
 
err:    if (cdbp != NULL)
90
 
                (void)cdbp->close(cdbp, 0);
91
 
        if (pgdbp != NULL)
92
 
                (void)pgdbp->close(pgdbp, 0);
93
 
        if (vdp != NULL)
94
 
                __os_free(dbenv, vdp);
95
 
        return (ret);
96
 
}
97
 
 
98
 
/*
99
 
 * __db_vrfy_dbinfo_destroy --
100
 
 *      Destructor for VRFY_DBINFO.  Destroys VRFY_PAGEINFOs and deallocates
101
 
 *      structure.
102
 
 *
103
 
 * PUBLIC: int __db_vrfy_dbinfo_destroy __P((DB_ENV *, VRFY_DBINFO *));
104
 
 */
105
 
int
106
 
__db_vrfy_dbinfo_destroy(dbenv, vdp)
107
 
        DB_ENV *dbenv;
108
 
        VRFY_DBINFO *vdp;
109
 
{
110
 
        VRFY_CHILDINFO *c, *d;
111
 
        int t_ret, ret;
112
 
 
113
 
        ret = 0;
114
 
 
115
 
        for (c = LIST_FIRST(&vdp->subdbs); c != NULL; c = d) {
116
 
                d = LIST_NEXT(c, links);
117
 
                __os_free(NULL, c);
118
 
        }
119
 
 
120
 
        if ((t_ret = vdp->pgdbp->close(vdp->pgdbp, 0)) != 0)
121
 
                ret = t_ret;
122
 
 
123
 
        if ((t_ret = vdp->cdbp->close(vdp->cdbp, 0)) != 0 && ret == 0)
124
 
                ret = t_ret;
125
 
 
126
 
        if ((t_ret = vdp->pgset->close(vdp->pgset, 0)) != 0 && ret == 0)
127
 
                ret = t_ret;
128
 
 
129
 
        DB_ASSERT(LIST_FIRST(&vdp->activepips) == NULL);
130
 
 
131
 
        __os_free(dbenv, vdp);
132
 
        return (ret);
133
 
}
134
 
 
135
 
/*
136
 
 * __db_vrfy_getpageinfo --
137
 
 *      Get a PAGEINFO structure for a given page, creating it if necessary.
138
 
 *
139
 
 * PUBLIC: int __db_vrfy_getpageinfo
140
 
 * PUBLIC:     __P((VRFY_DBINFO *, db_pgno_t, VRFY_PAGEINFO **));
141
 
 */
142
 
int
143
 
__db_vrfy_getpageinfo(vdp, pgno, pipp)
144
 
        VRFY_DBINFO *vdp;
145
 
        db_pgno_t pgno;
146
 
        VRFY_PAGEINFO **pipp;
147
 
{
148
 
        DBT key, data;
149
 
        DB *pgdbp;
150
 
        VRFY_PAGEINFO *pip;
151
 
        int ret;
152
 
 
153
 
        /*
154
 
         * We want a page info struct.  There are three places to get it from,
155
 
         * in decreasing order of preference:
156
 
         *
157
 
         * 1. vdp->activepips.  If it's already "checked out", we're
158
 
         *      already using it, we return the same exact structure with a
159
 
         *      bumped refcount.  This is necessary because this code is
160
 
         *      replacing array accesses, and it's common for f() to make some
161
 
         *      changes to a pip, and then call g() and h() which each make
162
 
         *      changes to the same pip.  vdps are never shared between threads
163
 
         *      (they're never returned to the application), so this is safe.
164
 
         * 2. The pgdbp.  It's not in memory, but it's in the database, so
165
 
         *      get it, give it a refcount of 1, and stick it on activepips.
166
 
         * 3. malloc.  It doesn't exist yet;  create it, then stick it on
167
 
         *      activepips.  We'll put it in the database when we putpageinfo
168
 
         *      later.
169
 
         */
170
 
 
171
 
        /* Case 1. */
172
 
        for (pip = LIST_FIRST(&vdp->activepips); pip != NULL;
173
 
            pip = LIST_NEXT(pip, links))
174
 
                if (pip->pgno == pgno)
175
 
                        /* Found it. */
176
 
                        goto found;
177
 
 
178
 
        /* Case 2. */
179
 
        pgdbp = vdp->pgdbp;
180
 
        memset(&key, 0, sizeof(DBT));
181
 
        memset(&data, 0, sizeof(DBT));
182
 
        F_SET(&data, DB_DBT_MALLOC);
183
 
        key.data = &pgno;
184
 
        key.size = sizeof(db_pgno_t);
185
 
 
186
 
        if ((ret = pgdbp->get(pgdbp, NULL, &key, &data, 0)) == 0) {
187
 
                /* Found it. */
188
 
                DB_ASSERT(data.size = sizeof(VRFY_PAGEINFO));
189
 
                pip = data.data;
190
 
                DB_ASSERT(pip->pi_refcount == 0);
191
 
                LIST_INSERT_HEAD(&vdp->activepips, pip, links);
192
 
                goto found;
193
 
        } else if (ret != DB_NOTFOUND)  /* Something nasty happened. */
194
 
                return (ret);
195
 
 
196
 
        /* Case 3 */
197
 
        if ((ret = __db_vrfy_pageinfo_create(pgdbp->dbenv, &pip)) != 0)
198
 
                return (ret);
199
 
 
200
 
        LIST_INSERT_HEAD(&vdp->activepips, pip, links);
201
 
found:  pip->pi_refcount++;
202
 
 
203
 
        *pipp = pip;
204
 
 
205
 
        DB_ASSERT(pip->pi_refcount > 0);
206
 
        return (0);
207
 
}
208
 
 
209
 
/*
210
 
 * __db_vrfy_putpageinfo --
211
 
 *      Put back a VRFY_PAGEINFO that we're done with.
212
 
 *
213
 
 * PUBLIC: int __db_vrfy_putpageinfo __P((DB_ENV *,
214
 
 * PUBLIC:     VRFY_DBINFO *, VRFY_PAGEINFO *));
215
 
 */
216
 
int
217
 
__db_vrfy_putpageinfo(dbenv, vdp, pip)
218
 
        DB_ENV *dbenv;
219
 
        VRFY_DBINFO *vdp;
220
 
        VRFY_PAGEINFO *pip;
221
 
{
222
 
        DBT key, data;
223
 
        DB *pgdbp;
224
 
        VRFY_PAGEINFO *p;
225
 
        int ret;
226
 
#ifdef DIAGNOSTIC
227
 
        int found;
228
 
 
229
 
        found = 0;
230
 
#endif
231
 
 
232
 
        if (--pip->pi_refcount > 0)
233
 
                return (0);
234
 
 
235
 
        pgdbp = vdp->pgdbp;
236
 
        memset(&key, 0, sizeof(DBT));
237
 
        memset(&data, 0, sizeof(DBT));
238
 
 
239
 
        key.data = &pip->pgno;
240
 
        key.size = sizeof(db_pgno_t);
241
 
        data.data = pip;
242
 
        data.size = sizeof(VRFY_PAGEINFO);
243
 
 
244
 
        if ((ret = pgdbp->put(pgdbp, NULL, &key, &data, 0)) != 0)
245
 
                return (ret);
246
 
 
247
 
        for (p = LIST_FIRST(&vdp->activepips); p != NULL;
248
 
            p = LIST_NEXT(p, links))
249
 
                if (p == pip) {
250
 
#ifdef DIAGNOSTIC
251
 
                        found++;
252
 
#endif
253
 
                        DB_ASSERT(p->pi_refcount == 0);
254
 
                        LIST_REMOVE(p, links);
255
 
                        break;
256
 
                }
257
 
#ifdef DIAGNOSTIC
258
 
        DB_ASSERT(found == 1);
259
 
#endif
260
 
 
261
 
        DB_ASSERT(pip->pi_refcount == 0);
262
 
        __os_ufree(dbenv, pip);
263
 
        return (0);
264
 
}
265
 
 
266
 
/*
267
 
 * __db_vrfy_pgset --
268
 
 *      Create a temporary database for the storing of sets of page numbers.
269
 
 *      (A mapping from page number to int, used by the *_meta2pgset functions,
270
 
 *      as well as for keeping track of which pages the verifier has seen.)
271
 
 *
272
 
 * PUBLIC: int __db_vrfy_pgset __P((DB_ENV *, u_int32_t, DB **));
273
 
 */
274
 
int
275
 
__db_vrfy_pgset(dbenv, pgsize, dbpp)
276
 
        DB_ENV *dbenv;
277
 
        u_int32_t pgsize;
278
 
        DB **dbpp;
279
 
{
280
 
        DB *dbp;
281
 
        int ret;
282
 
 
283
 
        if ((ret = db_create(&dbp, dbenv, 0)) != 0)
284
 
                return (ret);
285
 
        if ((ret = dbp->set_pagesize(dbp, pgsize)) != 0)
286
 
                goto err;
287
 
        if ((ret = dbp->open(dbp,
288
 
            NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0600)) == 0)
289
 
                *dbpp = dbp;
290
 
        else
291
 
err:            (void)dbp->close(dbp, 0);
292
 
 
293
 
        return (ret);
294
 
}
295
 
 
296
 
/*
297
 
 * __db_vrfy_pgset_get --
298
 
 *      Get the value associated in a page set with a given pgno.  Return
299
 
 *      a 0 value (and succeed) if we've never heard of this page.
300
 
 *
301
 
 * PUBLIC: int __db_vrfy_pgset_get __P((DB *, db_pgno_t, int *));
302
 
 */
303
 
int
304
 
__db_vrfy_pgset_get(dbp, pgno, valp)
305
 
        DB *dbp;
306
 
        db_pgno_t pgno;
307
 
        int *valp;
308
 
{
309
 
        DBT key, data;
310
 
        int ret, val;
311
 
 
312
 
        memset(&key, 0, sizeof(DBT));
313
 
        memset(&data, 0, sizeof(DBT));
314
 
 
315
 
        key.data = &pgno;
316
 
        key.size = sizeof(db_pgno_t);
317
 
        data.data = &val;
318
 
        data.ulen = sizeof(int);
319
 
        F_SET(&data, DB_DBT_USERMEM);
320
 
 
321
 
        if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) == 0) {
322
 
                DB_ASSERT(data.size = sizeof(int));
323
 
                memcpy(&val, data.data, sizeof(int));
324
 
        } else if (ret == DB_NOTFOUND)
325
 
                val = 0;
326
 
        else
327
 
                return (ret);
328
 
 
329
 
        *valp = val;
330
 
        return (0);
331
 
}
332
 
 
333
 
/*
334
 
 * __db_vrfy_pgset_inc --
335
 
 *      Increment the value associated with a pgno by 1.
336
 
 *
337
 
 * PUBLIC: int __db_vrfy_pgset_inc __P((DB *, db_pgno_t));
338
 
 */
339
 
int
340
 
__db_vrfy_pgset_inc(dbp, pgno)
341
 
        DB *dbp;
342
 
        db_pgno_t pgno;
343
 
{
344
 
 
345
 
        return (__db_vrfy_pgset_iinc(dbp, pgno, 1));
346
 
}
347
 
 
348
 
/*
349
 
 * __db_vrfy_pgset_dec --
350
 
 *      Increment the value associated with a pgno by 1.
351
 
 *
352
 
 * PUBLIC: int __db_vrfy_pgset_dec __P((DB *, db_pgno_t));
353
 
 */
354
 
int
355
 
__db_vrfy_pgset_dec(dbp, pgno)
356
 
        DB *dbp;
357
 
        db_pgno_t pgno;
358
 
{
359
 
 
360
 
        return (__db_vrfy_pgset_iinc(dbp, pgno, -1));
361
 
}
362
 
 
363
 
/*
364
 
 * __db_vrfy_pgset_iinc --
365
 
 *      Increment the value associated with a pgno by i.
366
 
 *
367
 
 */
368
 
static int
369
 
__db_vrfy_pgset_iinc(dbp, pgno, i)
370
 
        DB *dbp;
371
 
        db_pgno_t pgno;
372
 
        int i;
373
 
{
374
 
        DBT key, data;
375
 
        int ret;
376
 
        int val;
377
 
 
378
 
        memset(&key, 0, sizeof(DBT));
379
 
        memset(&data, 0, sizeof(DBT));
380
 
 
381
 
        val = 0;
382
 
 
383
 
        key.data = &pgno;
384
 
        key.size = sizeof(db_pgno_t);
385
 
        data.data = &val;
386
 
        data.ulen = sizeof(int);
387
 
        F_SET(&data, DB_DBT_USERMEM);
388
 
 
389
 
        if ((ret = dbp->get(dbp, NULL, &key, &data, 0)) == 0) {
390
 
                DB_ASSERT(data.size == sizeof(int));
391
 
                memcpy(&val, data.data, sizeof(int));
392
 
        } else if (ret != DB_NOTFOUND)
393
 
                return (ret);
394
 
 
395
 
        data.size = sizeof(int);
396
 
        val += i;
397
 
 
398
 
        return (dbp->put(dbp, NULL, &key, &data, 0));
399
 
}
400
 
 
401
 
/*
402
 
 * __db_vrfy_pgset_next --
403
 
 *      Given a cursor open in a pgset database, get the next page in the
404
 
 *      set.
405
 
 *
406
 
 * PUBLIC: int __db_vrfy_pgset_next __P((DBC *, db_pgno_t *));
407
 
 */
408
 
int
409
 
__db_vrfy_pgset_next(dbc, pgnop)
410
 
        DBC *dbc;
411
 
        db_pgno_t *pgnop;
412
 
{
413
 
        DBT key, data;
414
 
        db_pgno_t pgno;
415
 
        int ret;
416
 
 
417
 
        memset(&key, 0, sizeof(DBT));
418
 
        memset(&data, 0, sizeof(DBT));
419
 
        /* We don't care about the data, just the keys. */
420
 
        F_SET(&data, DB_DBT_USERMEM | DB_DBT_PARTIAL);
421
 
        F_SET(&key, DB_DBT_USERMEM);
422
 
        key.data = &pgno;
423
 
        key.ulen = sizeof(db_pgno_t);
424
 
 
425
 
        if ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) != 0)
426
 
                return (ret);
427
 
 
428
 
        DB_ASSERT(key.size == sizeof(db_pgno_t));
429
 
        *pgnop = pgno;
430
 
 
431
 
        return (0);
432
 
}
433
 
 
434
 
/*
435
 
 * __db_vrfy_childcursor --
436
 
 *      Create a cursor to walk the child list with.  Returns with a nonzero
437
 
 *      final argument if the specified page has no children.
438
 
 *
439
 
 * PUBLIC: int __db_vrfy_childcursor __P((VRFY_DBINFO *, DBC **));
440
 
 */
441
 
int
442
 
__db_vrfy_childcursor(vdp, dbcp)
443
 
        VRFY_DBINFO *vdp;
444
 
        DBC **dbcp;
445
 
{
446
 
        DB *cdbp;
447
 
        DBC *dbc;
448
 
        int ret;
449
 
 
450
 
        cdbp = vdp->cdbp;
451
 
 
452
 
        if ((ret = cdbp->cursor(cdbp, NULL, &dbc, 0)) == 0)
453
 
                *dbcp = dbc;
454
 
 
455
 
        return (ret);
456
 
}
457
 
 
458
 
/*
459
 
 * __db_vrfy_childput --
460
 
 *      Add a child structure to the set for a given page.
461
 
 *
462
 
 * PUBLIC: int __db_vrfy_childput
463
 
 * PUBLIC:     __P((VRFY_DBINFO *, db_pgno_t, VRFY_CHILDINFO *));
464
 
 */
465
 
int
466
 
__db_vrfy_childput(vdp, pgno, cip)
467
 
        VRFY_DBINFO *vdp;
468
 
        db_pgno_t pgno;
469
 
        VRFY_CHILDINFO *cip;
470
 
{
471
 
        DB *cdbp;
472
 
        DBC *cc;
473
 
        DBT key, data;
474
 
        VRFY_CHILDINFO *oldcip;
475
 
        int ret;
476
 
 
477
 
        cdbp = vdp->cdbp;
478
 
        memset(&key, 0, sizeof(DBT));
479
 
        memset(&data, 0, sizeof(DBT));
480
 
 
481
 
        key.data = &pgno;
482
 
        key.size = sizeof(db_pgno_t);
483
 
 
484
 
        /*
485
 
         * We want to avoid adding multiple entries for a single child page;
486
 
         * we only need to verify each child once, even if a child (such
487
 
         * as an overflow key) is multiply referenced.
488
 
         *
489
 
         * However, we also need to make sure that when walking the list
490
 
         * of children, we encounter them in the order they're referenced
491
 
         * on a page.  (This permits us, for example, to verify the
492
 
         * prev_pgno/next_pgno chain of Btree leaf pages.)
493
 
         *
494
 
         * Check the child database to make sure that this page isn't
495
 
         * already a child of the specified page number.  If it's not,
496
 
         * put it at the end of the duplicate set.
497
 
         */
498
 
        if ((ret = __db_vrfy_childcursor(vdp, &cc)) != 0)
499
 
                return (ret);
500
 
        for (ret = __db_vrfy_ccset(cc, pgno, &oldcip); ret == 0;
501
 
            ret = __db_vrfy_ccnext(cc, &oldcip))
502
 
                if (oldcip->pgno == cip->pgno) {
503
 
                        /*
504
 
                         * Found a matching child.  Return without
505
 
                         * putting it again.
506
 
                         */
507
 
                        if ((ret = __db_vrfy_ccclose(cc)) != 0)
508
 
                                return (ret);
509
 
                        return (0);
510
 
                }
511
 
        if (ret != DB_NOTFOUND) {
512
 
                (void)__db_vrfy_ccclose(cc);
513
 
                return (ret);
514
 
        }
515
 
        if ((ret = __db_vrfy_ccclose(cc)) != 0)
516
 
                return (ret);
517
 
 
518
 
        data.data = cip;
519
 
        data.size = sizeof(VRFY_CHILDINFO);
520
 
 
521
 
        return (cdbp->put(cdbp, NULL, &key, &data, 0));
522
 
}
523
 
 
524
 
/*
525
 
 * __db_vrfy_ccset --
526
 
 *      Sets a cursor created with __db_vrfy_childcursor to the first
527
 
 *      child of the given pgno, and returns it in the third arg.
528
 
 *
529
 
 * PUBLIC: int __db_vrfy_ccset __P((DBC *, db_pgno_t, VRFY_CHILDINFO **));
530
 
 */
531
 
int
532
 
__db_vrfy_ccset(dbc, pgno, cipp)
533
 
        DBC *dbc;
534
 
        db_pgno_t pgno;
535
 
        VRFY_CHILDINFO **cipp;
536
 
{
537
 
        DBT key, data;
538
 
        int ret;
539
 
 
540
 
        memset(&key, 0, sizeof(DBT));
541
 
        memset(&data, 0, sizeof(DBT));
542
 
 
543
 
        key.data = &pgno;
544
 
        key.size = sizeof(db_pgno_t);
545
 
 
546
 
        if ((ret = dbc->c_get(dbc, &key, &data, DB_SET)) != 0)
547
 
                return (ret);
548
 
 
549
 
        DB_ASSERT(data.size == sizeof(VRFY_CHILDINFO));
550
 
        *cipp = (VRFY_CHILDINFO *)data.data;
551
 
 
552
 
        return (0);
553
 
}
554
 
 
555
 
/*
556
 
 * __db_vrfy_ccnext --
557
 
 *      Gets the next child of the given cursor created with
558
 
 *      __db_vrfy_childcursor, and returns it in the memory provided in the
559
 
 *      second arg.
560
 
 *
561
 
 * PUBLIC: int __db_vrfy_ccnext __P((DBC *, VRFY_CHILDINFO **));
562
 
 */
563
 
int
564
 
__db_vrfy_ccnext(dbc, cipp)
565
 
        DBC *dbc;
566
 
        VRFY_CHILDINFO **cipp;
567
 
{
568
 
        DBT key, data;
569
 
        int ret;
570
 
 
571
 
        memset(&key, 0, sizeof(DBT));
572
 
        memset(&data, 0, sizeof(DBT));
573
 
 
574
 
        if ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT_DUP)) != 0)
575
 
                return (ret);
576
 
 
577
 
        DB_ASSERT(data.size == sizeof(VRFY_CHILDINFO));
578
 
        *cipp = (VRFY_CHILDINFO *)data.data;
579
 
 
580
 
        return (0);
581
 
}
582
 
 
583
 
/*
584
 
 * __db_vrfy_ccclose --
585
 
 *      Closes the cursor created with __db_vrfy_childcursor.
586
 
 *
587
 
 *      This doesn't actually do anything interesting now, but it's
588
 
 *      not inconceivable that we might change the internal database usage
589
 
 *      and keep the interfaces the same, and a function call here or there
590
 
 *      seldom hurts anyone.
591
 
 *
592
 
 * PUBLIC: int __db_vrfy_ccclose __P((DBC *));
593
 
 */
594
 
int
595
 
__db_vrfy_ccclose(dbc)
596
 
        DBC *dbc;
597
 
{
598
 
 
599
 
        return (dbc->c_close(dbc));
600
 
}
601
 
 
602
 
/*
603
 
 * __db_vrfy_pageinfo_create --
604
 
 *      Constructor for VRFY_PAGEINFO;  allocates and initializes.
605
 
 */
606
 
static int
607
 
__db_vrfy_pageinfo_create(dbenv, pgipp)
608
 
        DB_ENV *dbenv;
609
 
        VRFY_PAGEINFO **pgipp;
610
 
{
611
 
        VRFY_PAGEINFO *pgip;
612
 
        int ret;
613
 
 
614
 
        /*
615
 
         * pageinfo structs are sometimes allocated here and sometimes
616
 
         * allocated by fetching them from a database with DB_DBT_MALLOC.
617
 
         * There's no easy way for the destructor to tell which was
618
 
         * used, and so we always allocate with __os_umalloc so we can free
619
 
         * with __os_ufree.
620
 
         */
621
 
        if ((ret = __os_umalloc(dbenv,
622
 
            sizeof(VRFY_PAGEINFO), (void **)&pgip)) != 0)
623
 
                return (ret);
624
 
        memset(pgip, 0, sizeof(VRFY_PAGEINFO));
625
 
 
626
 
        DB_ASSERT(pgip->pi_refcount == 0);
627
 
 
628
 
        *pgipp = pgip;
629
 
        return (0);
630
 
}
631
 
 
632
 
/*
633
 
 * __db_salvage_init --
634
 
 *      Set up salvager database.
635
 
 *
636
 
 * PUBLIC: int  __db_salvage_init __P((VRFY_DBINFO *));
637
 
 */
638
 
int
639
 
__db_salvage_init(vdp)
640
 
        VRFY_DBINFO *vdp;
641
 
{
642
 
        DB *dbp;
643
 
        int ret;
644
 
 
645
 
        if ((ret = db_create(&dbp, NULL, 0)) != 0)
646
 
                return (ret);
647
 
 
648
 
        if ((ret = dbp->set_pagesize(dbp, 1024)) != 0)
649
 
                goto err;
650
 
 
651
 
        if ((ret = dbp->open(dbp,
652
 
            NULL, NULL, NULL, DB_BTREE, DB_CREATE, 0)) != 0)
653
 
                goto err;
654
 
 
655
 
        vdp->salvage_pages = dbp;
656
 
        return (0);
657
 
 
658
 
err:    (void)dbp->close(dbp, 0);
659
 
        return (ret);
660
 
}
661
 
 
662
 
/*
663
 
 * __db_salvage_destroy --
664
 
 *      Close salvager database.
665
 
 * PUBLIC: void  __db_salvage_destroy __P((VRFY_DBINFO *));
666
 
 */
667
 
void
668
 
__db_salvage_destroy(vdp)
669
 
        VRFY_DBINFO *vdp;
670
 
{
671
 
        (void)vdp->salvage_pages->close(vdp->salvage_pages, 0);
672
 
}
673
 
 
674
 
/*
675
 
 * __db_salvage_getnext --
676
 
 *      Get the next (first) unprinted page in the database of pages we need to
677
 
 *      print still.  Delete entries for any already-printed pages we encounter
678
 
 *      in this search, as well as the page we're returning.
679
 
 *
680
 
 * PUBLIC: int __db_salvage_getnext
681
 
 * PUBLIC:     __P((VRFY_DBINFO *, db_pgno_t *, u_int32_t *));
682
 
 */
683
 
int
684
 
__db_salvage_getnext(vdp, pgnop, pgtypep)
685
 
        VRFY_DBINFO *vdp;
686
 
        db_pgno_t *pgnop;
687
 
        u_int32_t *pgtypep;
688
 
{
689
 
        DB *dbp;
690
 
        DBC *dbc;
691
 
        DBT key, data;
692
 
        int ret;
693
 
        u_int32_t pgtype;
694
 
 
695
 
        dbp = vdp->salvage_pages;
696
 
 
697
 
        memset(&key, 0, sizeof(DBT));
698
 
        memset(&data, 0, sizeof(DBT));
699
 
 
700
 
        if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
701
 
                return (ret);
702
 
 
703
 
        while ((ret = dbc->c_get(dbc, &key, &data, DB_NEXT)) == 0) {
704
 
                DB_ASSERT(data.size == sizeof(u_int32_t));
705
 
                memcpy(&pgtype, data.data, sizeof(pgtype));
706
 
 
707
 
                if ((ret = dbc->c_del(dbc, 0)) != 0)
708
 
                        goto err;
709
 
                if (pgtype != SALVAGE_IGNORE)
710
 
                        goto found;
711
 
        }
712
 
 
713
 
        /* No more entries--ret probably equals DB_NOTFOUND. */
714
 
 
715
 
        if (0) {
716
 
found:          DB_ASSERT(key.size == sizeof(db_pgno_t));
717
 
                DB_ASSERT(data.size == sizeof(u_int32_t));
718
 
 
719
 
                *pgnop = *(db_pgno_t *)key.data;
720
 
                *pgtypep = *(u_int32_t *)data.data;
721
 
        }
722
 
 
723
 
err:    (void)dbc->c_close(dbc);
724
 
        return (ret);
725
 
}
726
 
 
727
 
/*
728
 
 * __db_salvage_isdone --
729
 
 *      Return whether or not the given pgno is already marked
730
 
 *      SALVAGE_IGNORE (meaning that we don't need to print it again).
731
 
 *
732
 
 *      Returns DB_KEYEXIST if it is marked, 0 if not, or another error on
733
 
 *      error.
734
 
 *
735
 
 * PUBLIC: int __db_salvage_isdone __P((VRFY_DBINFO *, db_pgno_t));
736
 
 */
737
 
int
738
 
__db_salvage_isdone(vdp, pgno)
739
 
        VRFY_DBINFO *vdp;
740
 
        db_pgno_t pgno;
741
 
{
742
 
        DBT key, data;
743
 
        DB *dbp;
744
 
        int ret;
745
 
        u_int32_t currtype;
746
 
 
747
 
        dbp = vdp->salvage_pages;
748
 
 
749
 
        memset(&key, 0, sizeof(DBT));
750
 
        memset(&data, 0, sizeof(DBT));
751
 
 
752
 
        currtype = SALVAGE_INVALID;
753
 
        data.data = &currtype;
754
 
        data.ulen = sizeof(u_int32_t);
755
 
        data.flags = DB_DBT_USERMEM;
756
 
 
757
 
        key.data = &pgno;
758
 
        key.size = sizeof(db_pgno_t);
759
 
 
760
 
        /*
761
 
         * Put an entry for this page, with pgno as key and type as data,
762
 
         * unless it's already there and is marked done.
763
 
         * If it's there and is marked anything else, that's fine--we
764
 
         * want to mark it done.
765
 
         */
766
 
        ret = dbp->get(dbp, NULL, &key, &data, 0);
767
 
        if (ret == 0) {
768
 
                /*
769
 
                 * The key's already here.  Check and see if it's already
770
 
                 * marked done.  If it is, return DB_KEYEXIST.  If it's not,
771
 
                 * return 0.
772
 
                 */
773
 
                if (currtype == SALVAGE_IGNORE)
774
 
                        return (DB_KEYEXIST);
775
 
                else
776
 
                        return (0);
777
 
        } else if (ret != DB_NOTFOUND)
778
 
                return (ret);
779
 
 
780
 
        /* The pgno is not yet marked anything; return 0. */
781
 
        return (0);
782
 
}
783
 
 
784
 
/*
785
 
 * __db_salvage_markdone --
786
 
 *      Mark as done a given page.
787
 
 *
788
 
 * PUBLIC: int __db_salvage_markdone __P((VRFY_DBINFO *, db_pgno_t));
789
 
 */
790
 
int
791
 
__db_salvage_markdone(vdp, pgno)
792
 
        VRFY_DBINFO *vdp;
793
 
        db_pgno_t pgno;
794
 
{
795
 
        DBT key, data;
796
 
        DB *dbp;
797
 
        int pgtype, ret;
798
 
        u_int32_t currtype;
799
 
 
800
 
        pgtype = SALVAGE_IGNORE;
801
 
        dbp = vdp->salvage_pages;
802
 
 
803
 
        memset(&key, 0, sizeof(DBT));
804
 
        memset(&data, 0, sizeof(DBT));
805
 
 
806
 
        currtype = SALVAGE_INVALID;
807
 
        data.data = &currtype;
808
 
        data.ulen = sizeof(u_int32_t);
809
 
        data.flags = DB_DBT_USERMEM;
810
 
 
811
 
        key.data = &pgno;
812
 
        key.size = sizeof(db_pgno_t);
813
 
 
814
 
        /*
815
 
         * Put an entry for this page, with pgno as key and type as data,
816
 
         * unless it's already there and is marked done.
817
 
         * If it's there and is marked anything else, that's fine--we
818
 
         * want to mark it done, but db_salvage_isdone only lets
819
 
         * us know if it's marked IGNORE.
820
 
         *
821
 
         * We don't want to return DB_KEYEXIST, though;  this will
822
 
         * likely get passed up all the way and make no sense to the
823
 
         * application.  Instead, use DB_VERIFY_BAD to indicate that
824
 
         * we've seen this page already--it probably indicates a
825
 
         * multiply-linked page.
826
 
         */
827
 
        if ((ret = __db_salvage_isdone(vdp, pgno)) != 0)
828
 
                return (ret == DB_KEYEXIST ? DB_VERIFY_BAD : ret);
829
 
 
830
 
        data.size = sizeof(u_int32_t);
831
 
        data.data = &pgtype;
832
 
 
833
 
        return (dbp->put(dbp, NULL, &key, &data, 0));
834
 
}
835
 
 
836
 
/*
837
 
 * __db_salvage_markneeded --
838
 
 *      If it has not yet been printed, make note of the fact that a page
839
 
 *      must be dealt with later.
840
 
 *
841
 
 * PUBLIC: int __db_salvage_markneeded
842
 
 * PUBLIC:     __P((VRFY_DBINFO *, db_pgno_t, u_int32_t));
843
 
 */
844
 
int
845
 
__db_salvage_markneeded(vdp, pgno, pgtype)
846
 
        VRFY_DBINFO *vdp;
847
 
        db_pgno_t pgno;
848
 
        u_int32_t pgtype;
849
 
{
850
 
        DB *dbp;
851
 
        DBT key, data;
852
 
        int ret;
853
 
 
854
 
        dbp = vdp->salvage_pages;
855
 
 
856
 
        memset(&key, 0, sizeof(DBT));
857
 
        memset(&data, 0, sizeof(DBT));
858
 
 
859
 
        key.data = &pgno;
860
 
        key.size = sizeof(db_pgno_t);
861
 
 
862
 
        data.data = &pgtype;
863
 
        data.size = sizeof(u_int32_t);
864
 
 
865
 
        /*
866
 
         * Put an entry for this page, with pgno as key and type as data,
867
 
         * unless it's already there, in which case it's presumably
868
 
         * already been marked done.
869
 
         */
870
 
        ret = dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE);
871
 
        return (ret == DB_KEYEXIST ? 0 : ret);
872
 
}