Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

db_conv.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  */
00007 /*
00008  * Copyright (c) 1990, 1993, 1994, 1995, 1996
00009  *      Keith Bostic.  All rights reserved.
00010  */
00011 /*
00012  * Copyright (c) 1990, 1993, 1994, 1995
00013  *      The Regents of the University of California.  All rights reserved.
00014  *
00015  * Redistribution and use in source and binary forms, with or without
00016  * modification, are permitted provided that the following conditions
00017  * are met:
00018  * 1. Redistributions of source code must retain the above copyright
00019  *    notice, this list of conditions and the following disclaimer.
00020  * 2. Redistributions in binary form must reproduce the above copyright
00021  *    notice, this list of conditions and the following disclaimer in the
00022  *    documentation and/or other materials provided with the distribution.
00023  * 3. Neither the name of the University nor the names of its contributors
00024  *    may be used to endorse or promote products derived from this software
00025  *    without specific prior written permission.
00026  *
00027  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00028  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00030  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00031  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00032  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00033  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00034  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00035  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00036  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00037  * SUCH DAMAGE.
00038  *
00039  * $Id: db_conv.c,v 12.1 2005/06/16 20:21:09 bostic Exp $
00040  */
00041 
00042 #include "db_config.h"
00043 
00044 #ifndef NO_SYSTEM_INCLUDES
00045 #include <sys/types.h>
00046 
00047 #include <string.h>
00048 #endif
00049 
00050 #include "db_int.h"
00051 #include "dbinc/crypto.h"
00052 #include "dbinc/hmac.h"
00053 #include "dbinc/db_page.h"
00054 #include "dbinc/db_swap.h"
00055 #include "dbinc/btree.h"
00056 #include "dbinc/hash.h"
00057 #include "dbinc/log.h"
00058 #include "dbinc/qam.h"
00059 
00060 /*
00061  * __db_pgin --
00062  *      Primary page-swap routine.
00063  *
00064  * PUBLIC: int __db_pgin __P((DB_ENV *, db_pgno_t, void *, DBT *));
00065  */
00066 int
00067 __db_pgin(dbenv, pg, pp, cookie)
00068         DB_ENV *dbenv;
00069         db_pgno_t pg;
00070         void *pp;
00071         DBT *cookie;
00072 {
00073         DB dummydb, *dbp;
00074         DB_PGINFO *pginfo;
00075         DB_CIPHER *db_cipher;
00076         DB_LSN not_used;
00077         PAGE *pagep;
00078         size_t pg_off, pg_len, sum_len;
00079         int is_hmac, ret;
00080         u_int8_t *chksum, *iv;
00081 
00082         pginfo = (DB_PGINFO *)cookie->data;
00083         pagep = (PAGE *)pp;
00084 
00085         ret = is_hmac = 0;
00086         chksum = iv = NULL;
00087         memset(&dummydb, 0, sizeof(DB));
00088         dbp = &dummydb;
00089         dummydb.flags = pginfo->flags;
00090         db_cipher = (DB_CIPHER *)dbenv->crypto_handle;
00091         switch (pagep->type) {
00092         case P_HASHMETA:
00093         case P_BTREEMETA:
00094         case P_QAMMETA:
00095                 /*
00096                  * If checksumming is set on the meta-page, we must set
00097                  * it in the dbp.
00098                  */
00099                 if (FLD_ISSET(((DBMETA *)pp)->metaflags, DBMETA_CHKSUM))
00100                         F_SET(dbp, DB_AM_CHKSUM);
00101                 else
00102                         F_CLR(dbp, DB_AM_CHKSUM);
00103                 if (((DBMETA *)pp)->encrypt_alg != 0 ||
00104                     F_ISSET(dbp, DB_AM_ENCRYPT))
00105                         is_hmac = 1;
00106                 /*
00107                  * !!!
00108                  * For all meta pages it is required that the chksum
00109                  * be at the same location.  Use BTMETA to get to it
00110                  * for any meta type.
00111                  */
00112                 chksum = ((BTMETA *)pp)->chksum;
00113                 sum_len = DBMETASIZE;
00114                 break;
00115         case P_INVALID:
00116                 /*
00117                  * We assume that we've read a file hole if we have
00118                  * a zero LSN, zero page number and P_INVALID.  Otherwise
00119                  * we have an invalid page that might contain real data.
00120                  */
00121                 if (IS_ZERO_LSN(LSN(pagep)) && pagep->pgno == PGNO_INVALID) {
00122                         sum_len = 0;
00123                         break;
00124                 }
00125                 /* FALLTHROUGH */
00126         default:
00127                 chksum = P_CHKSUM(dbp, pagep);
00128                 sum_len = pginfo->db_pagesize;
00129                 /*
00130                  * If we are reading in a non-meta page, then if we have
00131                  * a db_cipher then we are using hmac.
00132                  */
00133                 is_hmac = CRYPTO_ON(dbenv) ? 1 : 0;
00134                 break;
00135         }
00136 
00137         /*
00138          * We expect a checksum error if there was a configuration problem.
00139          * If there is no configuration problem and we don't get a match,
00140          * it's fatal: panic the system.
00141          */
00142         if (F_ISSET(dbp, DB_AM_CHKSUM) && sum_len != 0) {
00143                 if (F_ISSET(dbp, DB_AM_SWAP) && is_hmac == 0)
00144                         P_32_SWAP(chksum);
00145                 switch (ret = __db_check_chksum(
00146                     dbenv, db_cipher, chksum, pp, sum_len, is_hmac)) {
00147                 case 0:
00148                         break;
00149                 case -1:
00150                         if (DBENV_LOGGING(dbenv))
00151                                 (void)__db_cksum_log(
00152                                     dbenv, NULL, &not_used, DB_FLUSH);
00153                         __db_err(dbenv,
00154             "checksum error: page %lu: catastrophic recovery required",
00155                             (u_long)pg);
00156                         return (__db_panic(dbenv, DB_RUNRECOVERY));
00157                 default:
00158                         return (ret);
00159                 }
00160         }
00161         if (F_ISSET(dbp, DB_AM_ENCRYPT)) {
00162                 DB_ASSERT(db_cipher != NULL);
00163                 DB_ASSERT(F_ISSET(dbp, DB_AM_CHKSUM));
00164 
00165                 pg_off = P_OVERHEAD(dbp);
00166                 DB_ASSERT(db_cipher->adj_size(pg_off) == 0);
00167 
00168                 switch (pagep->type) {
00169                 case P_HASHMETA:
00170                 case P_BTREEMETA:
00171                 case P_QAMMETA:
00172                         /*
00173                          * !!!
00174                          * For all meta pages it is required that the iv
00175                          * be at the same location.  Use BTMETA to get to it
00176                          * for any meta type.
00177                          */
00178                         iv = ((BTMETA *)pp)->iv;
00179                         pg_len = DBMETASIZE;
00180                         break;
00181                 case P_INVALID:
00182                         if (IS_ZERO_LSN(LSN(pagep)) &&
00183                             pagep->pgno == PGNO_INVALID) {
00184                                 pg_len = 0;
00185                                 break;
00186                         }
00187                         /* FALLTHROUGH */
00188                 default:
00189                         iv = P_IV(dbp, pagep);
00190                         pg_len = pginfo->db_pagesize;
00191                         break;
00192                 }
00193                 if (pg_len != 0 && (ret = db_cipher->decrypt(dbenv,
00194                     db_cipher->data, iv, ((u_int8_t *)pagep) + pg_off,
00195                     pg_len - pg_off)) != 0)
00196                         return (ret);
00197         }
00198         switch (pagep->type) {
00199         case P_INVALID:
00200                 if (pginfo->type == DB_QUEUE)
00201                         return (__qam_pgin_out(dbenv, pg, pp, cookie));
00202                 else
00203                         return (__ham_pgin(dbenv, dbp, pg, pp, cookie));
00204         case P_HASH:
00205         case P_HASHMETA:
00206                 return (__ham_pgin(dbenv, dbp, pg, pp, cookie));
00207         case P_BTREEMETA:
00208         case P_IBTREE:
00209         case P_IRECNO:
00210         case P_LBTREE:
00211         case P_LDUP:
00212         case P_LRECNO:
00213         case P_OVERFLOW:
00214                 return (__bam_pgin(dbenv, dbp, pg, pp, cookie));
00215         case P_QAMMETA:
00216         case P_QAMDATA:
00217                 return (__qam_pgin_out(dbenv, pg, pp, cookie));
00218         default:
00219                 break;
00220         }
00221         return (__db_pgfmt(dbenv, pg));
00222 }
00223 
00224 /*
00225  * __db_pgout --
00226  *      Primary page-swap routine.
00227  *
00228  * PUBLIC: int __db_pgout __P((DB_ENV *, db_pgno_t, void *, DBT *));
00229  */
00230 int
00231 __db_pgout(dbenv, pg, pp, cookie)
00232         DB_ENV *dbenv;
00233         db_pgno_t pg;
00234         void *pp;
00235         DBT *cookie;
00236 {
00237         DB dummydb, *dbp;
00238         DB_CIPHER *db_cipher;
00239         DB_PGINFO *pginfo;
00240         PAGE *pagep;
00241         size_t pg_off, pg_len, sum_len;
00242         int ret;
00243         u_int8_t *chksum, *iv, *key;
00244 
00245         pginfo = (DB_PGINFO *)cookie->data;
00246         pagep = (PAGE *)pp;
00247 
00248         chksum = iv = key = NULL;
00249         memset(&dummydb, 0, sizeof(DB));
00250         dbp = &dummydb;
00251         dummydb.flags = pginfo->flags;
00252         ret = 0;
00253         switch (pagep->type) {
00254         case P_INVALID:
00255                 if (pginfo->type == DB_QUEUE)
00256                         ret = __qam_pgin_out(dbenv, pg, pp, cookie);
00257                 else
00258                         ret = __ham_pgout(dbenv, dbp, pg, pp, cookie);
00259                 break;
00260         case P_HASH:
00261         case P_HASHMETA:
00262                 ret = __ham_pgout(dbenv, dbp, pg, pp, cookie);
00263                 break;
00264         case P_BTREEMETA:
00265         case P_IBTREE:
00266         case P_IRECNO:
00267         case P_LBTREE:
00268         case P_LDUP:
00269         case P_LRECNO:
00270         case P_OVERFLOW:
00271                 ret = __bam_pgout(dbenv, dbp, pg, pp, cookie);
00272                 break;
00273         case P_QAMMETA:
00274         case P_QAMDATA:
00275                 ret = __qam_pgin_out(dbenv, pg, pp, cookie);
00276                 break;
00277         default:
00278                 return (__db_pgfmt(dbenv, pg));
00279         }
00280         if (ret)
00281                 return (ret);
00282 
00283         db_cipher = (DB_CIPHER *)dbenv->crypto_handle;
00284         if (F_ISSET(dbp, DB_AM_ENCRYPT)) {
00285 
00286                 DB_ASSERT(db_cipher != NULL);
00287                 DB_ASSERT(F_ISSET(dbp, DB_AM_CHKSUM));
00288 
00289                 pg_off = P_OVERHEAD(dbp);
00290                 DB_ASSERT(db_cipher->adj_size(pg_off) == 0);
00291 
00292                 key = db_cipher->mac_key;
00293 
00294                 switch (pagep->type) {
00295                 case P_HASHMETA:
00296                 case P_BTREEMETA:
00297                 case P_QAMMETA:
00298                         /*
00299                          * !!!
00300                          * For all meta pages it is required that the iv
00301                          * be at the same location.  Use BTMETA to get to it
00302                          * for any meta type.
00303                          */
00304                         iv = ((BTMETA *)pp)->iv;
00305                         pg_len = DBMETASIZE;
00306                         break;
00307                 default:
00308                         iv = P_IV(dbp, pagep);
00309                         pg_len = pginfo->db_pagesize;
00310                         break;
00311                 }
00312                 if ((ret = db_cipher->encrypt(dbenv, db_cipher->data,
00313                     iv, ((u_int8_t *)pagep) + pg_off, pg_len - pg_off)) != 0)
00314                         return (ret);
00315         }
00316         if (F_ISSET(dbp, DB_AM_CHKSUM)) {
00317                 switch (pagep->type) {
00318                 case P_HASHMETA:
00319                 case P_BTREEMETA:
00320                 case P_QAMMETA:
00321                         /*
00322                          * !!!
00323                          * For all meta pages it is required that the chksum
00324                          * be at the same location.  Use BTMETA to get to it
00325                          * for any meta type.
00326                          */
00327                         chksum = ((BTMETA *)pp)->chksum;
00328                         sum_len = DBMETASIZE;
00329                         break;
00330                 default:
00331                         chksum = P_CHKSUM(dbp, pagep);
00332                         sum_len = pginfo->db_pagesize;
00333                         break;
00334                 }
00335                 __db_chksum(pp, sum_len, key, chksum);
00336                 if (F_ISSET(dbp, DB_AM_SWAP) && !F_ISSET(dbp, DB_AM_ENCRYPT))
00337                          P_32_SWAP(chksum);
00338         }
00339         return (0);
00340 }
00341 
00342 /*
00343  * __db_metaswap --
00344  *      Byteswap the common part of the meta-data page.
00345  *
00346  * PUBLIC: void __db_metaswap __P((PAGE *));
00347  */
00348 void
00349 __db_metaswap(pg)
00350         PAGE *pg;
00351 {
00352         u_int8_t *p;
00353 
00354         p = (u_int8_t *)pg;
00355 
00356         /* Swap the meta-data information. */
00357         SWAP32(p);      /* lsn.file */
00358         SWAP32(p);      /* lsn.offset */
00359         SWAP32(p);      /* pgno */
00360         SWAP32(p);      /* magic */
00361         SWAP32(p);      /* version */
00362         SWAP32(p);      /* pagesize */
00363         p += 4;         /* unused, page type, unused, unused */
00364         SWAP32(p);      /* free */
00365         SWAP32(p);      /* alloc_lsn part 1 */
00366         SWAP32(p);      /* alloc_lsn part 2 */
00367         SWAP32(p);      /* cached key count */
00368         SWAP32(p);      /* cached record count */
00369         SWAP32(p);      /* flags */
00370 }
00371 
00372 /*
00373  * __db_byteswap --
00374  *      Byteswap a page.
00375  *
00376  * PUBLIC: int __db_byteswap
00377  * PUBLIC:         __P((DB_ENV *, DB *, db_pgno_t, PAGE *, size_t, int));
00378  */
00379 int
00380 __db_byteswap(dbenv, dbp, pg, h, pagesize, pgin)
00381         DB_ENV *dbenv;
00382         DB *dbp;
00383         db_pgno_t pg;
00384         PAGE *h;
00385         size_t pagesize;
00386         int pgin;
00387 {
00388         BINTERNAL *bi;
00389         BKEYDATA *bk;
00390         BOVERFLOW *bo;
00391         RINTERNAL *ri;
00392         db_indx_t i, *inp, len, tmp;
00393         u_int8_t *p, *end;
00394 
00395         COMPQUIET(pg, 0);
00396 
00397         inp = P_INP(dbp, h);
00398         if (pgin) {
00399                 M_32_SWAP(h->lsn.file);
00400                 M_32_SWAP(h->lsn.offset);
00401                 M_32_SWAP(h->pgno);
00402                 M_32_SWAP(h->prev_pgno);
00403                 M_32_SWAP(h->next_pgno);
00404                 M_16_SWAP(h->entries);
00405                 M_16_SWAP(h->hf_offset);
00406         }
00407 
00408         switch (h->type) {
00409         case P_HASH:
00410                 for (i = 0; i < NUM_ENT(h); i++) {
00411                         if (pgin)
00412                                 M_16_SWAP(inp[i]);
00413 
00414                         switch (HPAGE_TYPE(dbp, h, i)) {
00415                         case H_KEYDATA:
00416                                 break;
00417                         case H_DUPLICATE:
00418                                 len = LEN_HKEYDATA(dbp, h, pagesize, i);
00419                                 p = HKEYDATA_DATA(P_ENTRY(dbp, h, i));
00420                                 for (end = p + len; p < end;) {
00421                                         if (pgin) {
00422                                                 P_16_SWAP(p);
00423                                                 memcpy(&tmp,
00424                                                     p, sizeof(db_indx_t));
00425                                                 p += sizeof(db_indx_t);
00426                                         } else {
00427                                                 memcpy(&tmp,
00428                                                     p, sizeof(db_indx_t));
00429                                                 SWAP16(p);
00430                                         }
00431                                         p += tmp;
00432                                         SWAP16(p);
00433                                 }
00434                                 break;
00435                         case H_OFFDUP:
00436                                 p = HOFFPAGE_PGNO(P_ENTRY(dbp, h, i));
00437                                 SWAP32(p);                      /* pgno */
00438                                 break;
00439                         case H_OFFPAGE:
00440                                 p = HOFFPAGE_PGNO(P_ENTRY(dbp, h, i));
00441                                 SWAP32(p);                      /* pgno */
00442                                 SWAP32(p);                      /* tlen */
00443                                 break;
00444                         default:
00445                                 return (__db_pgfmt(dbenv, pg));
00446                         }
00447 
00448                 }
00449 
00450                 /*
00451                  * The offsets in the inp array are used to determine
00452                  * the size of entries on a page; therefore they
00453                  * cannot be converted until we've done all the
00454                  * entries.
00455                  */
00456                 if (!pgin)
00457                         for (i = 0; i < NUM_ENT(h); i++)
00458                                 M_16_SWAP(inp[i]);
00459                 break;
00460         case P_LBTREE:
00461         case P_LDUP:
00462         case P_LRECNO:
00463                 for (i = 0; i < NUM_ENT(h); i++) {
00464                         if (pgin)
00465                                 M_16_SWAP(inp[i]);
00466 
00467                         /*
00468                          * In the case of on-page duplicates, key information
00469                          * should only be swapped once.
00470                          */
00471                         if (h->type == P_LBTREE && i > 1) {
00472                                 if (pgin) {
00473                                         if (inp[i] == inp[i - 2])
00474                                                 continue;
00475                                 } else {
00476                                         M_16_SWAP(inp[i]);
00477                                         if (inp[i] == inp[i - 2])
00478                                                 continue;
00479                                         M_16_SWAP(inp[i]);
00480                                 }
00481                         }
00482 
00483                         bk = GET_BKEYDATA(dbp, h, i);
00484                         switch (B_TYPE(bk->type)) {
00485                         case B_KEYDATA:
00486                                 M_16_SWAP(bk->len);
00487                                 break;
00488                         case B_DUPLICATE:
00489                         case B_OVERFLOW:
00490                                 bo = (BOVERFLOW *)bk;
00491                                 M_32_SWAP(bo->pgno);
00492                                 M_32_SWAP(bo->tlen);
00493                                 break;
00494                         default:
00495                                 return (__db_pgfmt(dbenv, pg));
00496                         }
00497 
00498                         if (!pgin)
00499                                 M_16_SWAP(inp[i]);
00500                 }
00501                 break;
00502         case P_IBTREE:
00503                 for (i = 0; i < NUM_ENT(h); i++) {
00504                         if (pgin)
00505                                 M_16_SWAP(inp[i]);
00506 
00507                         bi = GET_BINTERNAL(dbp, h, i);
00508                         M_16_SWAP(bi->len);
00509                         M_32_SWAP(bi->pgno);
00510                         M_32_SWAP(bi->nrecs);
00511 
00512                         switch (B_TYPE(bi->type)) {
00513                         case B_KEYDATA:
00514                                 break;
00515                         case B_DUPLICATE:
00516                         case B_OVERFLOW:
00517                                 bo = (BOVERFLOW *)bi->data;
00518                                 M_32_SWAP(bo->pgno);
00519                                 M_32_SWAP(bo->tlen);
00520                                 break;
00521                         default:
00522                                 return (__db_pgfmt(dbenv, pg));
00523                         }
00524 
00525                         if (!pgin)
00526                                 M_16_SWAP(inp[i]);
00527                 }
00528                 break;
00529         case P_IRECNO:
00530                 for (i = 0; i < NUM_ENT(h); i++) {
00531                         if (pgin)
00532                                 M_16_SWAP(inp[i]);
00533 
00534                         ri = GET_RINTERNAL(dbp, h, i);
00535                         M_32_SWAP(ri->pgno);
00536                         M_32_SWAP(ri->nrecs);
00537 
00538                         if (!pgin)
00539                                 M_16_SWAP(inp[i]);
00540                 }
00541                 break;
00542         case P_OVERFLOW:
00543         case P_INVALID:
00544                 /* Nothing to do. */
00545                 break;
00546         default:
00547                 return (__db_pgfmt(dbenv, pg));
00548         }
00549 
00550         if (!pgin) {
00551                 /* Swap the header information. */
00552                 M_32_SWAP(h->lsn.file);
00553                 M_32_SWAP(h->lsn.offset);
00554                 M_32_SWAP(h->pgno);
00555                 M_32_SWAP(h->prev_pgno);
00556                 M_32_SWAP(h->next_pgno);
00557                 M_16_SWAP(h->entries);
00558                 M_16_SWAP(h->hf_offset);
00559         }
00560         return (0);
00561 }

Generated on Sun Dec 25 12:14:19 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2