1 /*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996, 2013 Oracle and/or its affiliates. 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$
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/heap.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 */
59 int
__db_pgin(dbenv,pg,pp,cookie)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_HEAPMETA:
92 case P_BTREEMETA:
93 case P_QAMMETA:
94 /*
95 * If checksumming is set on the meta-page, we must set
96 * it in the dbp.
97 */
98 if (FLD_ISSET(((DBMETA *)pp)->metaflags, DBMETA_CHKSUM))
99 F_SET(dbp, DB_AM_CHKSUM);
100 else
101 F_CLR(dbp, DB_AM_CHKSUM);
102 if (((DBMETA *)pp)->encrypt_alg != 0 ||
103 F_ISSET(dbp, DB_AM_ENCRYPT))
104 is_hmac = 1;
105 /*
106 * !!!
107 * For all meta pages it is required that the chksum
108 * be at the same location. Use BTMETA to get to it
109 * for any meta type.
110 */
111 chksum = ((BTMETA *)pp)->chksum;
112 sum_len = DBMETASIZE;
113 break;
114 case P_INVALID:
115 /*
116 * We assume that we've read a file hole if we have
117 * a zero LSN, zero page number and P_INVALID. Otherwise
118 * we have an invalid page that might contain real data.
119 */
120 if (IS_ZERO_LSN(LSN(pagep)) && pagep->pgno == PGNO_INVALID) {
121 sum_len = 0;
122 break;
123 }
124 /* FALLTHROUGH */
125 default:
126 chksum = P_CHKSUM(dbp, pagep);
127 sum_len = pginfo->db_pagesize;
128 /*
129 * If we are reading in a non-meta page, then if we have
130 * a db_cipher then we are using hmac.
131 */
132 is_hmac = CRYPTO_ON(env) ? 1 : 0;
133 break;
134 }
135
136 /*
137 * We expect a checksum error if there was a configuration problem.
138 * If there is no configuration problem and we don't get a match,
139 * it's fatal: panic the system.
140 */
141 if (F_ISSET(dbp, DB_AM_CHKSUM) && sum_len != 0) {
142 if (F_ISSET(dbp, DB_AM_SWAP) && is_hmac == 0)
143 P_32_SWAP(chksum);
144 switch (ret = __db_check_chksum(
145 env, NULL, db_cipher, chksum, pp, sum_len, is_hmac)) {
146 case 0:
147 break;
148 case -1:
149 if (DBENV_LOGGING(env))
150 (void)__db_cksum_log(
151 env, NULL, ¬_used, DB_FLUSH);
152 __db_errx(env, DB_STR_A("0684",
153 "checksum error: page %lu: catastrophic recovery required",
154 "%lu"), (u_long)pg);
155 return (__env_panic(env, DB_RUNRECOVERY));
156 default:
157 return (ret);
158 }
159 }
160 if ((ret = __db_decrypt_pg(env, dbp, pagep)) != 0)
161 return (ret);
162 switch (pagep->type) {
163 case P_INVALID:
164 if (pginfo->type == DB_QUEUE)
165 return (__qam_pgin_out(env, pg, pp, cookie));
166 else if (pginfo->type == DB_HEAP)
167 return (__heap_pgin(dbp, pg, pp, cookie));
168 /*
169 * This page is either newly allocated from the end of the
170 * file, or from the free list, or it is an as-yet unwritten
171 * hash bucket page. In this last case it needs to be
172 * initialized, but never byte-swapped. Otherwise the header
173 * may need swapping. It will not be a metadata page, so the
174 * byte swapping code of __ham_pgin is adequate. If hash
175 * is not configured fall back to btree swapping.
176 */
177 #ifdef HAVE_HASH
178 return (__ham_pgin(dbp, pg, pp, cookie));
179 #else
180 return (__bam_pgin(dbp, pg, pp, cookie));
181 #endif
182 /* NOTREACHED. */
183 break;
184 case P_HASH_UNSORTED:
185 case P_HASH:
186 case P_HASHMETA:
187 return (__ham_pgin(dbp, pg, pp, cookie));
188 case P_HEAP:
189 case P_HEAPMETA:
190 case P_IHEAP:
191 return (__heap_pgin(dbp, pg, pp, cookie));
192 case P_BTREEMETA:
193 case P_IBTREE:
194 case P_IRECNO:
195 case P_LBTREE:
196 case P_LDUP:
197 case P_LRECNO:
198 case P_OVERFLOW:
199 return (__bam_pgin(dbp, pg, pp, cookie));
200 case P_QAMMETA:
201 case P_QAMDATA:
202 return (__qam_pgin_out(env, pg, pp, cookie));
203 default:
204 break;
205 }
206 return (__db_pgfmt(env, pg));
207 }
208
209 /*
210 * __db_pgout --
211 * Primary page-swap routine.
212 *
213 * PUBLIC: int __db_pgout __P((DB_ENV *, db_pgno_t, void *, DBT *));
214 */
215 int
__db_pgout(dbenv,pg,pp,cookie)216 __db_pgout(dbenv, pg, pp, cookie)
217 DB_ENV *dbenv;
218 db_pgno_t pg;
219 void *pp;
220 DBT *cookie;
221 {
222 DB dummydb, *dbp;
223 DB_PGINFO *pginfo;
224 ENV *env;
225 PAGE *pagep;
226 int ret;
227
228 pginfo = (DB_PGINFO *)cookie->data;
229 env = dbenv->env;
230 pagep = (PAGE *)pp;
231
232 memset(&dummydb, 0, sizeof(DB));
233 dbp = &dummydb;
234 dbp->dbenv = dbenv;
235 dbp->env = env;
236 dbp->flags = pginfo->flags;
237 dbp->pgsize = pginfo->db_pagesize;
238 ret = 0;
239 switch (pagep->type) {
240 case P_INVALID:
241 switch (pginfo->type) {
242 case DB_QUEUE:
243 ret = __qam_pgin_out(env, pg, pp, cookie);
244 break;
245 #ifdef HAVE_HASH
246 case DB_HASH:
247 ret = __ham_pgout(dbp, pg, pp, cookie);
248 break;
249 #endif
250 #ifdef HAVE_HEAP
251 case DB_HEAP:
252 ret = __heap_pgout(dbp, pg, pp, cookie);
253 break;
254 #endif
255 case DB_BTREE:
256 case DB_RECNO:
257 ret = __bam_pgout(dbp, pg, pp, cookie);
258 break;
259 default:
260 return (__db_pgfmt(env, pg));
261 }
262 break;
263 case P_HASH:
264 case P_HASH_UNSORTED:
265 /*
266 * Support pgout of unsorted hash pages - since online
267 * replication upgrade can cause pages of this type to be
268 * written out.
269 *
270 * FALLTHROUGH
271 */
272 case P_HASHMETA:
273 ret = __ham_pgout(dbp, pg, pp, cookie);
274 break;
275 case P_HEAP:
276 case P_HEAPMETA:
277 case P_IHEAP:
278 ret = __heap_pgout(dbp, pg, pp, cookie);
279 break;
280 case P_BTREEMETA:
281 case P_IBTREE:
282 case P_IRECNO:
283 case P_LBTREE:
284 case P_LDUP:
285 case P_LRECNO:
286 case P_OVERFLOW:
287 ret = __bam_pgout(dbp, pg, pp, cookie);
288 break;
289 case P_QAMMETA:
290 case P_QAMDATA:
291 ret = __qam_pgin_out(env, pg, pp, cookie);
292 break;
293 default:
294 return (__db_pgfmt(env, pg));
295 }
296 if (ret)
297 return (ret);
298
299 return (__db_encrypt_and_checksum_pg(env, dbp, pagep));
300 }
301
302 /*
303 * __db_decrypt_pg --
304 * Utility function to decrypt a db page.
305 *
306 * PUBLIC: int __db_decrypt_pg __P((ENV *, DB *, PAGE *));
307 */
308 int
__db_decrypt_pg(env,dbp,pagep)309 __db_decrypt_pg (env, dbp, pagep)
310 ENV *env;
311 DB *dbp;
312 PAGE *pagep;
313 {
314 DB_CIPHER *db_cipher;
315 size_t pg_len, pg_off;
316 u_int8_t *iv;
317 int ret;
318
319 db_cipher = env->crypto_handle;
320 ret = 0;
321 iv = NULL;
322 if (F_ISSET(dbp, DB_AM_ENCRYPT)) {
323 DB_ASSERT(env, db_cipher != NULL);
324 DB_ASSERT(env, F_ISSET(dbp, DB_AM_CHKSUM));
325
326 pg_off = P_OVERHEAD(dbp);
327 DB_ASSERT(env, db_cipher->adj_size(pg_off) == 0);
328
329 switch (pagep->type) {
330 case P_HASHMETA:
331 case P_HEAPMETA:
332 case P_BTREEMETA:
333 case P_QAMMETA:
334 /*
335 * !!!
336 * For all meta pages it is required that the iv
337 * be at the same location. Use BTMETA to get to it
338 * for any meta type.
339 */
340 iv = ((BTMETA *)pagep)->iv;
341 pg_len = DBMETASIZE;
342 break;
343 case P_INVALID:
344 if (IS_ZERO_LSN(LSN(pagep)) &&
345 pagep->pgno == PGNO_INVALID) {
346 pg_len = 0;
347 break;
348 }
349 /* FALLTHROUGH */
350 default:
351 iv = P_IV(dbp, pagep);
352 pg_len = dbp->pgsize;
353 break;
354 }
355 if (pg_len != 0)
356 ret = db_cipher->decrypt(env, db_cipher->data,
357 iv, ((u_int8_t *)pagep) + pg_off,
358 pg_len - pg_off);
359 }
360 return (ret);
361 }
362
363 /*
364 * __db_encrypt_and_checksum_pg --
365 * Utility function to encrypt and checksum a db page.
366 *
367 * PUBLIC: int __db_encrypt_and_checksum_pg
368 * PUBLIC: __P((ENV *, DB *, PAGE *));
369 */
370 int
__db_encrypt_and_checksum_pg(env,dbp,pagep)371 __db_encrypt_and_checksum_pg (env, dbp, pagep)
372 ENV *env;
373 DB *dbp;
374 PAGE *pagep;
375 {
376 DB_CIPHER *db_cipher;
377 int ret;
378 size_t pg_off, pg_len, sum_len;
379 u_int8_t *chksum, *iv, *key;
380
381 chksum = iv = key = NULL;
382 db_cipher = env->crypto_handle;
383
384 if (F_ISSET(dbp, DB_AM_ENCRYPT)) {
385 DB_ASSERT(env, db_cipher != NULL);
386 DB_ASSERT(env, F_ISSET(dbp, DB_AM_CHKSUM));
387
388 pg_off = P_OVERHEAD(dbp);
389 DB_ASSERT(env, db_cipher->adj_size(pg_off) == 0);
390
391 key = db_cipher->mac_key;
392
393 switch (pagep->type) {
394 case P_HASHMETA:
395 case P_HEAPMETA:
396 case P_BTREEMETA:
397 case P_QAMMETA:
398 /*
399 * !!!
400 * For all meta pages it is required that the iv
401 * be at the same location. Use BTMETA to get to it
402 * for any meta type.
403 */
404 iv = ((BTMETA *)pagep)->iv;
405 pg_len = DBMETASIZE;
406 break;
407 default:
408 iv = P_IV(dbp, pagep);
409 pg_len = dbp->pgsize;
410 break;
411 }
412 if ((ret = db_cipher->encrypt(env, db_cipher->data,
413 iv, ((u_int8_t *)pagep) + pg_off, pg_len - pg_off)) != 0)
414 return (ret);
415 }
416 if (F_ISSET(dbp, DB_AM_CHKSUM)) {
417 switch (pagep->type) {
418 case P_HASHMETA:
419 case P_HEAPMETA:
420 case P_BTREEMETA:
421 case P_QAMMETA:
422 /*
423 * !!!
424 * For all meta pages it is required that the chksum
425 * be at the same location. Use BTMETA to get to it
426 * for any meta type.
427 */
428 chksum = ((BTMETA *)pagep)->chksum;
429 sum_len = DBMETASIZE;
430 break;
431 default:
432 chksum = P_CHKSUM(dbp, pagep);
433 sum_len = dbp->pgsize;
434 break;
435 }
436 __db_chksum(NULL, (u_int8_t *)pagep, sum_len, key, chksum);
437 if (F_ISSET(dbp, DB_AM_SWAP) && !F_ISSET(dbp, DB_AM_ENCRYPT))
438 P_32_SWAP(chksum);
439 }
440 return (0);
441 }
442
443 /*
444 * __db_metaswap --
445 * Byteswap the common part of the meta-data page.
446 *
447 * PUBLIC: void __db_metaswap __P((PAGE *));
448 */
449 void
__db_metaswap(pg)450 __db_metaswap(pg)
451 PAGE *pg;
452 {
453 u_int8_t *p;
454
455 p = (u_int8_t *)pg;
456
457 /* Swap the meta-data information. */
458 SWAP32(p); /* lsn.file */
459 SWAP32(p); /* lsn.offset */
460 SWAP32(p); /* pgno */
461 SWAP32(p); /* magic */
462 SWAP32(p); /* version */
463 SWAP32(p); /* pagesize */
464 p += 4; /* unused, page type, unused, unused */
465 SWAP32(p); /* free */
466 SWAP32(p); /* alloc_lsn part 1 */
467 SWAP32(p); /* alloc_lsn part 2 */
468 SWAP32(p); /* cached key count */
469 SWAP32(p); /* cached record count */
470 SWAP32(p); /* flags */
471 }
472
473 /*
474 * __db_byteswap --
475 * Byteswap an ordinary database page.
476 *
477 * PUBLIC: int __db_byteswap
478 * PUBLIC: __P((DB *, db_pgno_t, PAGE *, size_t, int));
479 */
480 int
__db_byteswap(dbp,pg,h,pagesize,pgin)481 __db_byteswap(dbp, pg, h, pagesize, pgin)
482 DB *dbp;
483 db_pgno_t pg;
484 PAGE *h;
485 size_t pagesize;
486 int pgin;
487 {
488 ENV *env;
489 BINTERNAL *bi;
490 BKEYDATA *bk;
491 BOVERFLOW *bo;
492 RINTERNAL *ri;
493 db_indx_t i, *inp, len, tmp;
494 u_int8_t *end, *p, *pgend;
495
496 if (pagesize == 0)
497 return (0);
498
499 if (pgin) {
500 M_32_SWAP(h->lsn.file);
501 M_32_SWAP(h->lsn.offset);
502 M_32_SWAP(h->pgno);
503 M_32_SWAP(h->prev_pgno);
504 M_32_SWAP(h->next_pgno);
505 M_16_SWAP(h->entries);
506 M_16_SWAP(h->hf_offset);
507 }
508
509 if (dbp == NULL)
510 return (0);
511 env = dbp->env;
512
513 pgend = (u_int8_t *)h + pagesize;
514
515 inp = P_INP(dbp, h);
516 if ((u_int8_t *)inp >= pgend)
517 goto out;
518
519 switch (TYPE(h)) {
520 case P_HASH_UNSORTED:
521 case P_HASH:
522 for (i = 0; i < NUM_ENT(h); i++) {
523 if (pgin)
524 M_16_SWAP(inp[i]);
525
526 if (P_ENTRY(dbp, h, i) >= pgend)
527 continue;
528
529 switch (HPAGE_TYPE(dbp, h, i)) {
530 case H_KEYDATA:
531 break;
532 case H_DUPLICATE:
533 len = LEN_HKEYDATA(dbp, h, pagesize, i);
534 p = HKEYDATA_DATA(P_ENTRY(dbp, h, i));
535 for (end = p + len; p < end;) {
536 if (pgin) {
537 P_16_SWAP(p);
538 memcpy(&tmp,
539 p, sizeof(db_indx_t));
540 p += sizeof(db_indx_t);
541 } else {
542 memcpy(&tmp,
543 p, sizeof(db_indx_t));
544 SWAP16(p);
545 }
546 p += tmp;
547 SWAP16(p);
548 }
549 break;
550 case H_OFFDUP:
551 p = HOFFPAGE_PGNO(P_ENTRY(dbp, h, i));
552 SWAP32(p); /* pgno */
553 break;
554 case H_OFFPAGE:
555 p = HOFFPAGE_PGNO(P_ENTRY(dbp, h, i));
556 SWAP32(p); /* pgno */
557 SWAP32(p); /* tlen */
558 break;
559 default:
560 return (__db_pgfmt(env, pg));
561 }
562
563 }
564
565 /*
566 * The offsets in the inp array are used to determine
567 * the size of entries on a page; therefore they
568 * cannot be converted until we've done all the
569 * entries.
570 */
571 if (!pgin)
572 for (i = 0; i < NUM_ENT(h); i++)
573 M_16_SWAP(inp[i]);
574 break;
575 case P_LBTREE:
576 case P_LDUP:
577 case P_LRECNO:
578 for (i = 0; i < NUM_ENT(h); i++) {
579 if (pgin)
580 M_16_SWAP(inp[i]);
581
582 /*
583 * In the case of on-page duplicates, key information
584 * should only be swapped once.
585 */
586 if (h->type == P_LBTREE && i > 1) {
587 if (pgin) {
588 if (inp[i] == inp[i - 2])
589 continue;
590 } else {
591 M_16_SWAP(inp[i]);
592 if (inp[i] == inp[i - 2])
593 continue;
594 M_16_SWAP(inp[i]);
595 }
596 }
597
598 bk = GET_BKEYDATA(dbp, h, i);
599 if ((u_int8_t *)bk >= pgend)
600 continue;
601 switch (B_TYPE(bk->type)) {
602 case B_KEYDATA:
603 M_16_SWAP(bk->len);
604 break;
605 case B_DUPLICATE:
606 case B_OVERFLOW:
607 bo = (BOVERFLOW *)bk;
608 M_32_SWAP(bo->pgno);
609 M_32_SWAP(bo->tlen);
610 break;
611 default:
612 return (__db_pgfmt(env, pg));
613 }
614
615 if (!pgin)
616 M_16_SWAP(inp[i]);
617 }
618 break;
619 case P_IBTREE:
620 for (i = 0; i < NUM_ENT(h); i++) {
621 if (pgin)
622 M_16_SWAP(inp[i]);
623
624 bi = GET_BINTERNAL(dbp, h, i);
625 if ((u_int8_t *)bi >= pgend)
626 continue;
627
628 M_16_SWAP(bi->len);
629 M_32_SWAP(bi->pgno);
630 M_32_SWAP(bi->nrecs);
631
632 switch (B_TYPE(bi->type)) {
633 case B_KEYDATA:
634 break;
635 case B_DUPLICATE:
636 case B_OVERFLOW:
637 bo = (BOVERFLOW *)bi->data;
638 M_32_SWAP(bo->pgno);
639 M_32_SWAP(bo->tlen);
640 break;
641 default:
642 return (__db_pgfmt(env, pg));
643 }
644
645 if (!pgin)
646 M_16_SWAP(inp[i]);
647 }
648 break;
649 case P_IRECNO:
650 for (i = 0; i < NUM_ENT(h); i++) {
651 if (pgin)
652 M_16_SWAP(inp[i]);
653
654 ri = GET_RINTERNAL(dbp, h, i);
655 if ((u_int8_t *)ri >= pgend)
656 continue;
657
658 M_32_SWAP(ri->pgno);
659 M_32_SWAP(ri->nrecs);
660
661 if (!pgin)
662 M_16_SWAP(inp[i]);
663 }
664 break;
665 case P_HEAP:
666 case P_IHEAP:
667 case P_INVALID:
668 case P_OVERFLOW:
669 case P_QAMDATA:
670 /* Nothing to do. */
671 break;
672 default:
673 return (__db_pgfmt(env, pg));
674 }
675
676 out: if (!pgin) {
677 /* Swap the header information. */
678 M_32_SWAP(h->lsn.file);
679 M_32_SWAP(h->lsn.offset);
680 M_32_SWAP(h->pgno);
681 M_32_SWAP(h->prev_pgno);
682 M_32_SWAP(h->next_pgno);
683 M_16_SWAP(h->entries);
684 M_16_SWAP(h->hf_offset);
685 }
686 return (0);
687 }
688
689 /*
690 * __db_pageswap --
691 * Byteswap any database page. Normally, the page to be swapped will be
692 * referenced by the "pp" argument and the pdata argument will be NULL.
693 * This function is also called by automatically generated log functions,
694 * where the page may be split into separate header and data parts. In
695 * that case, pdata is not NULL we reconsitute
696 *
697 * PUBLIC: int __db_pageswap
698 * PUBLIC: __P((ENV *, DB *, void *, size_t, DBT *, int));
699 */
700 int
__db_pageswap(env,dbp,pp,len,pdata,pgin)701 __db_pageswap(env, dbp, pp, len, pdata, pgin)
702 ENV *env;
703 DB *dbp;
704 void *pp;
705 size_t len;
706 DBT *pdata;
707 int pgin;
708 {
709 db_pgno_t pg;
710 size_t pgsize;
711 void *pgcopy;
712 int ret;
713 u_int16_t hoffset;
714
715 switch (TYPE(pp)) {
716 case P_BTREEMETA:
717 return (__bam_mswap(env, pp));
718
719 case P_HASHMETA:
720 return (__ham_mswap(env, pp));
721
722 case P_QAMMETA:
723 return (__qam_mswap(env, pp));
724
725 case P_INVALID:
726 case P_OVERFLOW:
727 case P_QAMDATA:
728 /*
729 * We may have been passed an invalid page, or a queue data
730 * page, or an overflow page where fields like hoffset have a
731 * special meaning. In that case, no swapping of the page data
732 * is required, just the fields in the page header.
733 */
734 pdata = NULL;
735 break;
736
737 default:
738 break;
739 }
740
741 if (pgin) {
742 P_32_COPYSWAP(&PGNO(pp), &pg);
743 P_16_COPYSWAP(&HOFFSET(pp), &hoffset);
744 } else {
745 pg = PGNO(pp);
746 hoffset = HOFFSET(pp);
747 }
748
749 if (pdata == NULL)
750 ret = __db_byteswap(dbp, pg, (PAGE *)pp, len, pgin);
751 else {
752 pgsize = hoffset + pdata->size;
753 if ((ret = __os_malloc(env, pgsize, &pgcopy)) != 0)
754 return (ret);
755 memset(pgcopy, 0, pgsize);
756 memcpy(pgcopy, pp, len);
757 memcpy((u_int8_t *)pgcopy + hoffset, pdata->data, pdata->size);
758
759 ret = __db_byteswap(dbp, pg, (PAGE *)pgcopy, pgsize, pgin);
760 memcpy(pp, pgcopy, len);
761
762 /*
763 * If we are swapping data to be written to the log, we can't
764 * overwrite the buffer that was passed in: it may be a pointer
765 * into a page in cache. We set DB_DBT_APPMALLOC here so that
766 * the calling code can free the memory we allocate here.
767 */
768 if (!pgin) {
769 if ((ret =
770 __os_malloc(env, pdata->size, &pdata->data)) != 0) {
771 __os_free(env, pgcopy);
772 return (ret);
773 }
774 F_SET(pdata, DB_DBT_APPMALLOC);
775 }
776 memcpy(pdata->data, (u_int8_t *)pgcopy + hoffset, pdata->size);
777 __os_free(env, pgcopy);
778 }
779
780 return (ret);
781 }
782
783 /*
784 * __db_recordswap --
785 * Byteswap any database record.
786 *
787 * PUBLIC: void __db_recordswap __P((u_int32_t,
788 * PUBLIC: u_int32_t, void *, void *, u_int32_t));
789 */
790 void
__db_recordswap(op,size,hdr,data,pgin)791 __db_recordswap(op, size, hdr, data, pgin)
792 u_int32_t op;
793 u_int32_t size;
794 void *hdr, *data;
795 u_int32_t pgin;
796 {
797 BKEYDATA *bk;
798 BOVERFLOW *bo;
799 BINTERNAL *bi;
800 RINTERNAL *ri;
801 db_indx_t tmp;
802 u_int8_t *p, *end;
803
804 if (size == 0)
805 return;
806 switch (OP_PAGE_GET(op)) {
807 case P_LDUP:
808 case P_LBTREE:
809 case P_LRECNO:
810 bk = (BKEYDATA *)hdr;
811 switch (B_TYPE(bk->type)) {
812 case B_KEYDATA:
813 M_16_SWAP(bk->len);
814 break;
815 case B_DUPLICATE:
816 case B_OVERFLOW:
817 bo = (BOVERFLOW *)hdr;
818 M_32_SWAP(bo->pgno);
819 M_32_SWAP(bo->tlen);
820 break;
821 default:
822 DB_ASSERT(NULL, bk->type != bk->type);
823 }
824 break;
825 case P_IBTREE:
826 bi = (BINTERNAL *)hdr;
827 M_16_SWAP(bi->len);
828 M_32_SWAP(bi->pgno);
829 M_32_SWAP(bi->nrecs);
830 if (B_TYPE(bi->type) == B_OVERFLOW) {
831 if (data == NULL) {
832 DB_ASSERT(NULL,
833 size == BINTERNAL_SIZE(BOVERFLOW_SIZE));
834 bo = (BOVERFLOW *)bi->data;
835 } else
836 bo = (BOVERFLOW *)data;
837 M_32_SWAP(bo->pgno);
838 }
839 break;
840 case P_IRECNO:
841 ri = (RINTERNAL *)hdr;
842 M_32_SWAP(ri->pgno);
843 M_32_SWAP(ri->nrecs);
844 break;
845 case P_OVERFLOW:
846 break;
847 case P_HASH:
848 case P_HASH_UNSORTED:
849 switch (OP_MODE_GET(op)) {
850 /* KEYDATA and DUPLICATE records do not include the header. */
851 case H_KEYDATA:
852 break;
853 case H_DUPLICATE:
854 p = (u_int8_t *)hdr;
855 for (end = p + size; p < end;) {
856 if (pgin) {
857 P_16_SWAP(p);
858 memcpy(&tmp,
859 p, sizeof(db_indx_t));
860 p += sizeof(db_indx_t);
861 } else {
862 memcpy(&tmp,
863 p, sizeof(db_indx_t));
864 SWAP16(p);
865 }
866 p += tmp;
867 SWAP16(p);
868 }
869 break;
870 /* These two record types include the full header. */
871 case H_OFFDUP:
872 p = (u_int8_t *)hdr;
873 p += SSZ(HOFFPAGE, pgno);
874 SWAP32(p); /* pgno */
875 break;
876 case H_OFFPAGE:
877 p = (u_int8_t *)hdr;
878 p += SSZ(HOFFPAGE, pgno);
879 SWAP32(p); /* pgno */
880 SWAP32(p); /* tlen */
881 break;
882 default:
883 DB_ASSERT(NULL, op != op);
884 }
885 break;
886
887 default:
888 DB_ASSERT(NULL, op != op);
889 }
890 }
891