1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996,2008 Oracle.  All rights reserved.
5 */
6/*
7 * Copyright (c) 1990, 1993, 1994, 1995, 1996
8 *	Keith Bostic.  All rights reserved.
9 */
10/*
11 * Copyright (c) 1990, 1993, 1994, 1995
12 *	The Regents of the University of California.  All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 *    notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 *    notice, this list of conditions and the following disclaimer in the
21 *    documentation and/or other materials provided with the distribution.
22 * 3. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * $Id: db_conv.c,v 12.27 2008/04/19 15:30:35 mjc Exp $
39 */
40
41#include "db_config.h"
42
43#include "db_int.h"
44#include "dbinc/crypto.h"
45#include "dbinc/hmac.h"
46#include "dbinc/db_page.h"
47#include "dbinc/db_swap.h"
48#include "dbinc/btree.h"
49#include "dbinc/hash.h"
50#include "dbinc/log.h"
51#include "dbinc/qam.h"
52
53/*
54 * __db_pgin --
55 *	Primary page-swap routine.
56 *
57 * PUBLIC: int __db_pgin __P((DB_ENV *, db_pgno_t, void *, DBT *));
58 */
59int
60__db_pgin(dbenv, pg, pp, cookie)
61	DB_ENV *dbenv;
62	db_pgno_t pg;
63	void *pp;
64	DBT *cookie;
65{
66	DB dummydb, *dbp;
67	DB_CIPHER *db_cipher;
68	DB_LSN not_used;
69	DB_PGINFO *pginfo;
70	ENV *env;
71	PAGE *pagep;
72	size_t sum_len;
73	int is_hmac, ret;
74	u_int8_t *chksum;
75
76	pginfo = (DB_PGINFO *)cookie->data;
77	env = dbenv->env;
78	pagep = (PAGE *)pp;
79
80	ret = is_hmac = 0;
81	chksum = NULL;
82	memset(&dummydb, 0, sizeof(DB));
83	dbp = &dummydb;
84	dbp->dbenv = dbenv;
85	dbp->env = env;
86	dbp->flags = pginfo->flags;
87	dbp->pgsize = pginfo->db_pagesize;
88	db_cipher = env->crypto_handle;
89	switch (pagep->type) {
90	case P_HASHMETA:
91	case P_BTREEMETA:
92	case P_QAMMETA:
93		/*
94		 * If checksumming is set on the meta-page, we must set
95		 * it in the dbp.
96		 */
97		if (FLD_ISSET(((DBMETA *)pp)->metaflags, DBMETA_CHKSUM))
98			F_SET(dbp, DB_AM_CHKSUM);
99		else
100			F_CLR(dbp, DB_AM_CHKSUM);
101		if (((DBMETA *)pp)->encrypt_alg != 0 ||
102		    F_ISSET(dbp, DB_AM_ENCRYPT))
103			is_hmac = 1;
104		/*
105		 * !!!
106		 * For all meta pages it is required that the chksum
107		 * be at the same location.  Use BTMETA to get to it
108		 * for any meta type.
109		 */
110		chksum = ((BTMETA *)pp)->chksum;
111		sum_len = DBMETASIZE;
112		break;
113	case P_INVALID:
114		/*
115		 * We assume that we've read a file hole if we have
116		 * a zero LSN, zero page number and P_INVALID.  Otherwise
117		 * we have an invalid page that might contain real data.
118		 */
119		if (IS_ZERO_LSN(LSN(pagep)) && pagep->pgno == PGNO_INVALID) {
120			sum_len = 0;
121			break;
122		}
123		/* FALLTHROUGH */
124	default:
125		chksum = P_CHKSUM(dbp, pagep);
126		sum_len = pginfo->db_pagesize;
127		/*
128		 * If we are reading in a non-meta page, then if we have
129		 * a db_cipher then we are using hmac.
130		 */
131		is_hmac = CRYPTO_ON(env) ? 1 : 0;
132		break;
133	}
134
135	/*
136	 * We expect a checksum error if there was a configuration problem.
137	 * If there is no configuration problem and we don't get a match,
138	 * it's fatal: panic the system.
139	 */
140	if (F_ISSET(dbp, DB_AM_CHKSUM) && sum_len != 0) {
141		if (F_ISSET(dbp, DB_AM_SWAP) && is_hmac == 0)
142			P_32_SWAP(chksum);
143		switch (ret = __db_check_chksum(
144		    env, NULL, db_cipher, chksum, pp, sum_len, is_hmac)) {
145		case 0:
146			break;
147		case -1:
148			if (DBENV_LOGGING(env))
149				(void)__db_cksum_log(
150				    env, NULL, &not_used, DB_FLUSH);
151			__db_errx(env,
152	    "checksum error: page %lu: catastrophic recovery required",
153			    (u_long)pg);
154			return (__env_panic(env, DB_RUNRECOVERY));
155		default:
156			return (ret);
157		}
158	}
159	if ((ret = __db_decrypt_pg(env, dbp, pagep)) != 0)
160		return (ret);
161	switch (pagep->type) {
162	case P_INVALID:
163		if (pginfo->type == DB_QUEUE)
164			return (__qam_pgin_out(env, pg, pp, cookie));
165		else
166			return (__ham_pgin(dbp, pg, pp, cookie));
167	case P_HASH_UNSORTED:
168	case P_HASH:
169	case P_HASHMETA:
170		return (__ham_pgin(dbp, pg, pp, cookie));
171	case P_BTREEMETA:
172	case P_IBTREE:
173	case P_IRECNO:
174	case P_LBTREE:
175	case P_LDUP:
176	case P_LRECNO:
177	case P_OVERFLOW:
178		return (__bam_pgin(dbp, pg, pp, cookie));
179	case P_QAMMETA:
180	case P_QAMDATA:
181		return (__qam_pgin_out(env, pg, pp, cookie));
182	default:
183		break;
184	}
185	return (__db_pgfmt(env, pg));
186}
187
188/*
189 * __db_pgout --
190 *	Primary page-swap routine.
191 *
192 * PUBLIC: int __db_pgout __P((DB_ENV *, db_pgno_t, void *, DBT *));
193 */
194int
195__db_pgout(dbenv, pg, pp, cookie)
196	DB_ENV *dbenv;
197	db_pgno_t pg;
198	void *pp;
199	DBT *cookie;
200{
201	DB dummydb, *dbp;
202	DB_PGINFO *pginfo;
203	ENV *env;
204	PAGE *pagep;
205	int ret;
206
207	pginfo = (DB_PGINFO *)cookie->data;
208	env = dbenv->env;
209	pagep = (PAGE *)pp;
210
211	memset(&dummydb, 0, sizeof(DB));
212	dbp = &dummydb;
213	dbp->dbenv = dbenv;
214	dbp->env = env;
215	dbp->flags = pginfo->flags;
216	dbp->pgsize = pginfo->db_pagesize;
217	ret = 0;
218	switch (pagep->type) {
219	case P_INVALID:
220		if (pginfo->type == DB_QUEUE)
221			ret = __qam_pgin_out(env, pg, pp, cookie);
222		else
223			ret = __ham_pgout(dbp, pg, pp, cookie);
224		break;
225	case P_HASH:
226	case P_HASH_UNSORTED:
227		/*
228		 * Support pgout of unsorted hash pages - since online
229		 * replication upgrade can cause pages of this type to be
230		 * written out.
231		 *
232		 * FALLTHROUGH
233		 */
234	case P_HASHMETA:
235		ret = __ham_pgout(dbp, pg, pp, cookie);
236		break;
237	case P_BTREEMETA:
238	case P_IBTREE:
239	case P_IRECNO:
240	case P_LBTREE:
241	case P_LDUP:
242	case P_LRECNO:
243	case P_OVERFLOW:
244		ret = __bam_pgout(dbp, pg, pp, cookie);
245		break;
246	case P_QAMMETA:
247	case P_QAMDATA:
248		ret = __qam_pgin_out(env, pg, pp, cookie);
249		break;
250	default:
251		return (__db_pgfmt(env, pg));
252	}
253	if (ret)
254		return (ret);
255
256	return (__db_encrypt_and_checksum_pg(env, dbp, pagep));
257}
258
259/*
260 * __db_decrypt_pg --
261 *      Utility function to decrypt a db page.
262 *
263 * PUBLIC: int __db_decrypt_pg __P((ENV *, DB *, PAGE *));
264 */
265int
266__db_decrypt_pg (env, dbp, pagep)
267	ENV *env;
268	DB *dbp;
269	PAGE *pagep;
270{
271	DB_CIPHER *db_cipher;
272	size_t pg_len, pg_off;
273	u_int8_t *iv;
274	int ret;
275
276	db_cipher = env->crypto_handle;
277	ret = 0;
278	iv = NULL;
279	if (F_ISSET(dbp, DB_AM_ENCRYPT)) {
280		DB_ASSERT(env, db_cipher != NULL);
281		DB_ASSERT(env, F_ISSET(dbp, DB_AM_CHKSUM));
282
283		pg_off = P_OVERHEAD(dbp);
284		DB_ASSERT(env, db_cipher->adj_size(pg_off) == 0);
285
286		switch (pagep->type) {
287		case P_HASHMETA:
288		case P_BTREEMETA:
289		case P_QAMMETA:
290			/*
291			 * !!!
292			 * For all meta pages it is required that the iv
293			 * be at the same location.  Use BTMETA to get to it
294			 * for any meta type.
295			 */
296			iv = ((BTMETA *)pagep)->iv;
297			pg_len = DBMETASIZE;
298			break;
299		case P_INVALID:
300			if (IS_ZERO_LSN(LSN(pagep)) &&
301			    pagep->pgno == PGNO_INVALID) {
302				pg_len = 0;
303				break;
304			}
305			/* FALLTHROUGH */
306		default:
307			iv = P_IV(dbp, pagep);
308			pg_len = dbp->pgsize;
309			break;
310		}
311		if (pg_len != 0)
312			ret = db_cipher->decrypt(env, db_cipher->data,
313			    iv, ((u_int8_t *)pagep) + pg_off,
314			    pg_len - pg_off);
315	}
316	return (ret);
317}
318
319/*
320 * __db_encrypt_and_checksum_pg --
321 *	Utility function to encrypt and checksum a db page.
322 *
323 * PUBLIC: int __db_encrypt_and_checksum_pg
324 * PUBLIC:     __P((ENV *, DB *, PAGE *));
325 */
326int
327__db_encrypt_and_checksum_pg (env, dbp, pagep)
328	ENV *env;
329	DB *dbp;
330	PAGE *pagep;
331{
332	DB_CIPHER *db_cipher;
333	int ret;
334	size_t pg_off, pg_len, sum_len;
335	u_int8_t *chksum, *iv, *key;
336
337	chksum = iv = key = NULL;
338	db_cipher = env->crypto_handle;
339
340	if (F_ISSET(dbp, DB_AM_ENCRYPT)) {
341		DB_ASSERT(env, db_cipher != NULL);
342		DB_ASSERT(env, F_ISSET(dbp, DB_AM_CHKSUM));
343
344		pg_off = P_OVERHEAD(dbp);
345		DB_ASSERT(env, db_cipher->adj_size(pg_off) == 0);
346
347		key = db_cipher->mac_key;
348
349		switch (pagep->type) {
350		case P_HASHMETA:
351		case P_BTREEMETA:
352		case P_QAMMETA:
353			/*
354			 * !!!
355			 * For all meta pages it is required that the iv
356			 * be at the same location.  Use BTMETA to get to it
357			 * for any meta type.
358			 */
359			iv = ((BTMETA *)pagep)->iv;
360			pg_len = DBMETASIZE;
361			break;
362		default:
363			iv = P_IV(dbp, pagep);
364			pg_len = dbp->pgsize;
365			break;
366		}
367		if ((ret = db_cipher->encrypt(env, db_cipher->data,
368		    iv, ((u_int8_t *)pagep) + pg_off, pg_len - pg_off)) != 0)
369			return (ret);
370	}
371	if (F_ISSET(dbp, DB_AM_CHKSUM)) {
372		switch (pagep->type) {
373		case P_HASHMETA:
374		case P_BTREEMETA:
375		case P_QAMMETA:
376			/*
377			 * !!!
378			 * For all meta pages it is required that the chksum
379			 * be at the same location.  Use BTMETA to get to it
380			 * for any meta type.
381			 */
382			chksum = ((BTMETA *)pagep)->chksum;
383			sum_len = DBMETASIZE;
384			break;
385		default:
386			chksum = P_CHKSUM(dbp, pagep);
387			sum_len = dbp->pgsize;
388			break;
389		}
390		__db_chksum(NULL, (u_int8_t *)pagep, sum_len, key, chksum);
391		if (F_ISSET(dbp, DB_AM_SWAP) && !F_ISSET(dbp, DB_AM_ENCRYPT))
392			 P_32_SWAP(chksum);
393	}
394	return (0);
395}
396
397/*
398 * __db_metaswap --
399 *	Byteswap the common part of the meta-data page.
400 *
401 * PUBLIC: void __db_metaswap __P((PAGE *));
402 */
403void
404__db_metaswap(pg)
405	PAGE *pg;
406{
407	u_int8_t *p;
408
409	p = (u_int8_t *)pg;
410
411	/* Swap the meta-data information. */
412	SWAP32(p);	/* lsn.file */
413	SWAP32(p);	/* lsn.offset */
414	SWAP32(p);	/* pgno */
415	SWAP32(p);	/* magic */
416	SWAP32(p);	/* version */
417	SWAP32(p);	/* pagesize */
418	p += 4;		/* unused, page type, unused, unused */
419	SWAP32(p);	/* free */
420	SWAP32(p);	/* alloc_lsn part 1 */
421	SWAP32(p);	/* alloc_lsn part 2 */
422	SWAP32(p);	/* cached key count */
423	SWAP32(p);	/* cached record count */
424	SWAP32(p);	/* flags */
425}
426
427/*
428 * __db_byteswap --
429 *	Byteswap an ordinary database page.
430 *
431 * PUBLIC: int __db_byteswap
432 * PUBLIC:         __P((DB *, db_pgno_t, PAGE *, size_t, int));
433 */
434int
435__db_byteswap(dbp, pg, h, pagesize, pgin)
436	DB *dbp;
437	db_pgno_t pg;
438	PAGE *h;
439	size_t pagesize;
440	int pgin;
441{
442	ENV *env;
443	BINTERNAL *bi;
444	BKEYDATA *bk;
445	BOVERFLOW *bo;
446	RINTERNAL *ri;
447	db_indx_t i, *inp, len, tmp;
448	u_int8_t *end, *p, *pgend;
449
450	if (pagesize == 0)
451		return (0);
452
453	env = dbp->env;
454
455	if (pgin) {
456		M_32_SWAP(h->lsn.file);
457		M_32_SWAP(h->lsn.offset);
458		M_32_SWAP(h->pgno);
459		M_32_SWAP(h->prev_pgno);
460		M_32_SWAP(h->next_pgno);
461		M_16_SWAP(h->entries);
462		M_16_SWAP(h->hf_offset);
463	}
464
465	pgend = (u_int8_t *)h + pagesize;
466
467	inp = P_INP(dbp, h);
468	if ((u_int8_t *)inp >= pgend)
469		goto out;
470
471	switch (TYPE(h)) {
472	case P_HASH_UNSORTED:
473	case P_HASH:
474		for (i = 0; i < NUM_ENT(h); i++) {
475			if (pgin)
476				M_16_SWAP(inp[i]);
477
478			if (P_ENTRY(dbp, h, i) >= pgend)
479				continue;
480
481			switch (HPAGE_TYPE(dbp, h, i)) {
482			case H_KEYDATA:
483				break;
484			case H_DUPLICATE:
485				len = LEN_HKEYDATA(dbp, h, pagesize, i);
486				p = HKEYDATA_DATA(P_ENTRY(dbp, h, i));
487				for (end = p + len; p < end;) {
488					if (pgin) {
489						P_16_SWAP(p);
490						memcpy(&tmp,
491						    p, sizeof(db_indx_t));
492						p += sizeof(db_indx_t);
493					} else {
494						memcpy(&tmp,
495						    p, sizeof(db_indx_t));
496						SWAP16(p);
497					}
498					p += tmp;
499					SWAP16(p);
500				}
501				break;
502			case H_OFFDUP:
503				p = HOFFPAGE_PGNO(P_ENTRY(dbp, h, i));
504				SWAP32(p);			/* pgno */
505				break;
506			case H_OFFPAGE:
507				p = HOFFPAGE_PGNO(P_ENTRY(dbp, h, i));
508				SWAP32(p);			/* pgno */
509				SWAP32(p);			/* tlen */
510				break;
511			default:
512				return (__db_pgfmt(env, pg));
513			}
514
515		}
516
517		/*
518		 * The offsets in the inp array are used to determine
519		 * the size of entries on a page; therefore they
520		 * cannot be converted until we've done all the
521		 * entries.
522		 */
523		if (!pgin)
524			for (i = 0; i < NUM_ENT(h); i++)
525				M_16_SWAP(inp[i]);
526		break;
527	case P_LBTREE:
528	case P_LDUP:
529	case P_LRECNO:
530		for (i = 0; i < NUM_ENT(h); i++) {
531			if (pgin)
532				M_16_SWAP(inp[i]);
533
534			/*
535			 * In the case of on-page duplicates, key information
536			 * should only be swapped once.
537			 */
538			if (h->type == P_LBTREE && i > 1) {
539				if (pgin) {
540					if (inp[i] == inp[i - 2])
541						continue;
542				} else {
543					M_16_SWAP(inp[i]);
544					if (inp[i] == inp[i - 2])
545						continue;
546					M_16_SWAP(inp[i]);
547				}
548			}
549
550			bk = GET_BKEYDATA(dbp, h, i);
551			if ((u_int8_t *)bk >= pgend)
552				continue;
553			switch (B_TYPE(bk->type)) {
554			case B_KEYDATA:
555				M_16_SWAP(bk->len);
556				break;
557			case B_DUPLICATE:
558			case B_OVERFLOW:
559				bo = (BOVERFLOW *)bk;
560				M_32_SWAP(bo->pgno);
561				M_32_SWAP(bo->tlen);
562				break;
563			default:
564				return (__db_pgfmt(env, pg));
565			}
566
567			if (!pgin)
568				M_16_SWAP(inp[i]);
569		}
570		break;
571	case P_IBTREE:
572		for (i = 0; i < NUM_ENT(h); i++) {
573			if (pgin)
574				M_16_SWAP(inp[i]);
575
576			bi = GET_BINTERNAL(dbp, h, i);
577			if ((u_int8_t *)bi >= pgend)
578				continue;
579
580			M_16_SWAP(bi->len);
581			M_32_SWAP(bi->pgno);
582			M_32_SWAP(bi->nrecs);
583
584			switch (B_TYPE(bi->type)) {
585			case B_KEYDATA:
586				break;
587			case B_DUPLICATE:
588			case B_OVERFLOW:
589				bo = (BOVERFLOW *)bi->data;
590				M_32_SWAP(bo->pgno);
591				M_32_SWAP(bo->tlen);
592				break;
593			default:
594				return (__db_pgfmt(env, pg));
595			}
596
597			if (!pgin)
598				M_16_SWAP(inp[i]);
599		}
600		break;
601	case P_IRECNO:
602		for (i = 0; i < NUM_ENT(h); i++) {
603			if (pgin)
604				M_16_SWAP(inp[i]);
605
606			ri = GET_RINTERNAL(dbp, h, i);
607			if ((u_int8_t *)ri >= pgend)
608				continue;
609
610			M_32_SWAP(ri->pgno);
611			M_32_SWAP(ri->nrecs);
612
613			if (!pgin)
614				M_16_SWAP(inp[i]);
615		}
616		break;
617	case P_OVERFLOW:
618	case P_INVALID:
619		/* Nothing to do. */
620		break;
621	default:
622		return (__db_pgfmt(env, pg));
623	}
624
625out:	if (!pgin) {
626		/* Swap the header information. */
627		M_32_SWAP(h->lsn.file);
628		M_32_SWAP(h->lsn.offset);
629		M_32_SWAP(h->pgno);
630		M_32_SWAP(h->prev_pgno);
631		M_32_SWAP(h->next_pgno);
632		M_16_SWAP(h->entries);
633		M_16_SWAP(h->hf_offset);
634	}
635	return (0);
636}
637
638/*
639 * __db_pageswap --
640 *	Byteswap any database page.  Normally, the page to be swapped will be
641 *	referenced by the "pp" argument and the pdata argument will be NULL.
642 *	This function is also called by automatically generated log functions,
643 *	where the page may be split into separate header and data parts.  In
644 *	that case, pdata is not NULL we reconsitute
645 *
646 * PUBLIC: int __db_pageswap
647 * PUBLIC:         __P((DB *, void *, size_t, DBT *, int));
648 */
649int
650__db_pageswap(dbp, pp, len, pdata, pgin)
651	DB *dbp;
652	void *pp;
653	size_t len;
654	DBT *pdata;
655	int pgin;
656{
657	ENV *env;
658	db_pgno_t pg;
659	size_t pgsize;
660	void *pgcopy;
661	int ret;
662	u_int16_t hoffset;
663
664	env = dbp->env;
665
666	switch (TYPE(pp)) {
667	case P_BTREEMETA:
668		return (__bam_mswap(env, pp));
669
670	case P_HASHMETA:
671		return (__ham_mswap(env, pp));
672
673	case P_QAMMETA:
674		return (__qam_mswap(env, pp));
675
676	case P_INVALID:
677	case P_OVERFLOW:
678		/*
679		 * We may have been passed an invalid page, or an overflow page
680		 * where fields like hoffset have a special meaning.  In that
681		 * case, no swapping of the page data is required, just the
682		 * fields in the page header.
683		 */
684		pdata = NULL;
685		break;
686
687	default:
688		break;
689	}
690
691	if (pgin) {
692		P_32_COPYSWAP(&PGNO(pp), &pg);
693		P_16_COPYSWAP(&HOFFSET(pp), &hoffset);
694	} else {
695		pg = PGNO(pp);
696		hoffset = HOFFSET(pp);
697	}
698
699	if (pdata == NULL)
700		ret = __db_byteswap(dbp, pg, (PAGE *)pp, len, pgin);
701	else {
702		pgsize = hoffset + pdata->size;
703		if ((ret = __os_malloc(env, pgsize, &pgcopy)) != 0)
704			return (ret);
705		memset(pgcopy, 0, pgsize);
706		memcpy(pgcopy, pp, len);
707		memcpy((u_int8_t *)pgcopy + hoffset, pdata->data, pdata->size);
708
709		ret = __db_byteswap(dbp, pg, (PAGE *)pgcopy, pgsize, pgin);
710		memcpy(pp, pgcopy, len);
711
712		/*
713		 * If we are swapping data to be written to the log, we can't
714		 * overwrite the buffer that was passed in: it may be a pointer
715		 * into a page in cache.  We set DB_DBT_APPMALLOC here so that
716		 * the calling code can free the memory we allocate here.
717		 */
718		if (!pgin) {
719			if ((ret =
720			    __os_malloc(env, pdata->size, &pdata->data)) != 0) {
721				__os_free(env, pgcopy);
722				return (ret);
723			}
724			F_SET(pdata, DB_DBT_APPMALLOC);
725		}
726		memcpy(pdata->data, (u_int8_t *)pgcopy + hoffset, pdata->size);
727		__os_free(env, pgcopy);
728	}
729
730	return (ret);
731}
732