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