--- sqlite3.c.sqlite	2013-11-09 12:42:08.623520057 +0100
+++ sqlite3.c	2013-11-09 12:41:58.695520274 +0100
@@ -12566,9 +12566,45 @@
 #endif /* _SQLITEINT_H_ */
 
 /************** End of sqliteInt.h *******************************************/
-/************** Begin file global.c ******************************************/
+/************** Begin file crypto.c ******************************************/
+/* 
+** SQLCipher
+** http://sqlcipher.net
+** 
+** Copyright (c) 2008 - 2013, ZETETIC LLC
+** All rights reserved.
+** 
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**     * Redistributions of source code must retain the above copyright
+**       notice, this list of conditions and the following disclaimer.
+**     * Redistributions in binary form must reproduce the above copyright
+**       notice, this list of conditions and the following disclaimer in the
+**       documentation and/or other materials provided with the distribution.
+**     * Neither the name of the ZETETIC LLC nor the
+**       names of its contributors may be used to endorse or promote products
+**       derived from this software without specific prior written permission.
+** 
+** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
+** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**  
+*/
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+
+/* #include <assert.h> */
+/************** Include btreeInt.h in the middle of crypto.c *****************/
+/************** Begin file btreeInt.h ****************************************/
 /*
-** 2008 June 13
+** 2004 April 6
 **
 ** The author disclaims copyright to this source code.  In place of
 ** a legal notice, here is a blessing:
@@ -12578,246 +12614,3589 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
+** This file implements a external (disk-based) database using BTrees.
+** For a detailed discussion of BTrees, refer to
 **
-** This file contains definitions of global variables and contants.
-*/
-
-/* An array to map all upper-case characters into their corresponding
-** lower-case character. 
+**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
+**     "Sorting And Searching", pages 473-480. Addison-Wesley
+**     Publishing Company, Reading, Massachusetts.
 **
-** SQLite only considers US-ASCII (or EBCDIC) characters.  We do not
-** handle case conversions for the UTF character set since the tables
-** involved are nearly as big or bigger than SQLite itself.
-*/
-SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
-#ifdef SQLITE_ASCII
-      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
-     18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
-     36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
-     54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
-    104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
-    122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
-    108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
-    126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
-    144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
-    162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
-    180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
-    198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
-    216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
-    234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
-    252,253,254,255
-#endif
-#ifdef SQLITE_EBCDIC
-      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, /* 0x */
-     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */
-     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 2x */
-     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */
-     64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */
-     80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */
-     96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */
-    112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */
-    128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */
-    144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */
-    160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */
-    176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */
-    192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */
-    208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */
-    224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */
-    239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */
-#endif
-};
-
-/*
-** The following 256 byte lookup table is used to support SQLites built-in
-** equivalents to the following standard library functions:
+** The basic idea is that each page of the file contains N database
+** entries and N+1 pointers to subpages.
 **
-**   isspace()                        0x01
-**   isalpha()                        0x02
-**   isdigit()                        0x04
-**   isalnum()                        0x06
-**   isxdigit()                       0x08
-**   toupper()                        0x20
-**   SQLite identifier character      0x40
+**   ----------------------------------------------------------------
+**   |  Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) |
+**   ----------------------------------------------------------------
 **
-** Bit 0x20 is set if the mapped character requires translation to upper
-** case. i.e. if the character is a lower-case ASCII character.
-** If x is a lower-case ASCII character, then its upper-case equivalent
-** is (x - 0x20). Therefore toupper() can be implemented as:
+** All of the keys on the page that Ptr(0) points to have values less
+** than Key(0).  All of the keys on page Ptr(1) and its subpages have
+** values greater than Key(0) and less than Key(1).  All of the keys
+** on Ptr(N) and its subpages have values greater than Key(N-1).  And
+** so forth.
 **
-**   (x & ~(map[x]&0x20))
+** Finding a particular key requires reading O(log(M)) pages from the 
+** disk where M is the number of entries in the tree.
 **
-** Standard function tolower() is implemented using the sqlite3UpperToLower[]
-** array. tolower() is used more often than toupper() by SQLite.
+** In this implementation, a single file can hold one or more separate 
+** BTrees.  Each BTree is identified by the index of its root page.  The
+** key and data for any entry are combined to form the "payload".  A
+** fixed amount of payload can be carried directly on the database
+** page.  If the payload is larger than the preset amount then surplus
+** bytes are stored on overflow pages.  The payload for an entry
+** and the preceding pointer are combined to form a "Cell".  Each 
+** page has a small header which contains the Ptr(N) pointer and other
+** information such as the size of key and data.
 **
-** Bit 0x40 is set if the character non-alphanumeric and can be used in an 
-** SQLite identifier.  Identifiers are alphanumerics, "_", "$", and any
-** non-ASCII UTF character. Hence the test for whether or not a character is
-** part of an identifier is 0x46.
+** FORMAT DETAILS
 **
-** SQLite's versions are identical to the standard versions assuming a
-** locale of "C". They are implemented as macros in sqliteInt.h.
+** The file is divided into pages.  The first page is called page 1,
+** the second is page 2, and so forth.  A page number of zero indicates
+** "no such page".  The page size can be any power of 2 between 512 and 65536.
+** Each page can be either a btree page, a freelist page, an overflow
+** page, or a pointer-map page.
+**
+** The first page is always a btree page.  The first 100 bytes of the first
+** page contain a special header (the "file header") that describes the file.
+** The format of the file header is as follows:
+**
+**   OFFSET   SIZE    DESCRIPTION
+**      0      16     Header string: "SQLite format 3\000"
+**     16       2     Page size in bytes.  
+**     18       1     File format write version
+**     19       1     File format read version
+**     20       1     Bytes of unused space at the end of each page
+**     21       1     Max embedded payload fraction
+**     22       1     Min embedded payload fraction
+**     23       1     Min leaf payload fraction
+**     24       4     File change counter
+**     28       4     Reserved for future use
+**     32       4     First freelist page
+**     36       4     Number of freelist pages in the file
+**     40      60     15 4-byte meta values passed to higher layers
+**
+**     40       4     Schema cookie
+**     44       4     File format of schema layer
+**     48       4     Size of page cache
+**     52       4     Largest root-page (auto/incr_vacuum)
+**     56       4     1=UTF-8 2=UTF16le 3=UTF16be
+**     60       4     User version
+**     64       4     Incremental vacuum mode
+**     68       4     unused
+**     72       4     unused
+**     76       4     unused
+**
+** All of the integer values are big-endian (most significant byte first).
+**
+** The file change counter is incremented when the database is changed
+** This counter allows other processes to know when the file has changed
+** and thus when they need to flush their cache.
+**
+** The max embedded payload fraction is the amount of the total usable
+** space in a page that can be consumed by a single cell for standard
+** B-tree (non-LEAFDATA) tables.  A value of 255 means 100%.  The default
+** is to limit the maximum cell size so that at least 4 cells will fit
+** on one page.  Thus the default max embedded payload fraction is 64.
+**
+** If the payload for a cell is larger than the max payload, then extra
+** payload is spilled to overflow pages.  Once an overflow page is allocated,
+** as many bytes as possible are moved into the overflow pages without letting
+** the cell size drop below the min embedded payload fraction.
+**
+** The min leaf payload fraction is like the min embedded payload fraction
+** except that it applies to leaf nodes in a LEAFDATA tree.  The maximum
+** payload fraction for a LEAFDATA tree is always 100% (or 255) and it
+** not specified in the header.
+**
+** Each btree pages is divided into three sections:  The header, the
+** cell pointer array, and the cell content area.  Page 1 also has a 100-byte
+** file header that occurs before the page header.
+**
+**      |----------------|
+**      | file header    |   100 bytes.  Page 1 only.
+**      |----------------|
+**      | page header    |   8 bytes for leaves.  12 bytes for interior nodes
+**      |----------------|
+**      | cell pointer   |   |  2 bytes per cell.  Sorted order.
+**      | array          |   |  Grows downward
+**      |                |   v
+**      |----------------|
+**      | unallocated    |
+**      | space          |
+**      |----------------|   ^  Grows upwards
+**      | cell content   |   |  Arbitrary order interspersed with freeblocks.
+**      | area           |   |  and free space fragments.
+**      |----------------|
+**
+** The page headers looks like this:
+**
+**   OFFSET   SIZE     DESCRIPTION
+**      0       1      Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf
+**      1       2      byte offset to the first freeblock
+**      3       2      number of cells on this page
+**      5       2      first byte of the cell content area
+**      7       1      number of fragmented free bytes
+**      8       4      Right child (the Ptr(N) value).  Omitted on leaves.
+**
+** The flags define the format of this btree page.  The leaf flag means that
+** this page has no children.  The zerodata flag means that this page carries
+** only keys and no data.  The intkey flag means that the key is a integer
+** which is stored in the key size entry of the cell header rather than in
+** the payload area.
+**
+** The cell pointer array begins on the first byte after the page header.
+** The cell pointer array contains zero or more 2-byte numbers which are
+** offsets from the beginning of the page to the cell content in the cell
+** content area.  The cell pointers occur in sorted order.  The system strives
+** to keep free space after the last cell pointer so that new cells can
+** be easily added without having to defragment the page.
+**
+** Cell content is stored at the very end of the page and grows toward the
+** beginning of the page.
+**
+** Unused space within the cell content area is collected into a linked list of
+** freeblocks.  Each freeblock is at least 4 bytes in size.  The byte offset
+** to the first freeblock is given in the header.  Freeblocks occur in
+** increasing order.  Because a freeblock must be at least 4 bytes in size,
+** any group of 3 or fewer unused bytes in the cell content area cannot
+** exist on the freeblock chain.  A group of 3 or fewer free bytes is called
+** a fragment.  The total number of bytes in all fragments is recorded.
+** in the page header at offset 7.
+**
+**    SIZE    DESCRIPTION
+**      2     Byte offset of the next freeblock
+**      2     Bytes in this freeblock
+**
+** Cells are of variable length.  Cells are stored in the cell content area at
+** the end of the page.  Pointers to the cells are in the cell pointer array
+** that immediately follows the page header.  Cells is not necessarily
+** contiguous or in order, but cell pointers are contiguous and in order.
+**
+** Cell content makes use of variable length integers.  A variable
+** length integer is 1 to 9 bytes where the lower 7 bits of each 
+** byte are used.  The integer consists of all bytes that have bit 8 set and
+** the first byte with bit 8 clear.  The most significant byte of the integer
+** appears first.  A variable-length integer may not be more than 9 bytes long.
+** As a special case, all 8 bytes of the 9th byte are used as data.  This
+** allows a 64-bit integer to be encoded in 9 bytes.
+**
+**    0x00                      becomes  0x00000000
+**    0x7f                      becomes  0x0000007f
+**    0x81 0x00                 becomes  0x00000080
+**    0x82 0x00                 becomes  0x00000100
+**    0x80 0x7f                 becomes  0x0000007f
+**    0x8a 0x91 0xd1 0xac 0x78  becomes  0x12345678
+**    0x81 0x81 0x81 0x81 0x01  becomes  0x10204081
+**
+** Variable length integers are used for rowids and to hold the number of
+** bytes of key and data in a btree cell.
+**
+** The content of a cell looks like this:
+**
+**    SIZE    DESCRIPTION
+**      4     Page number of the left child. Omitted if leaf flag is set.
+**     var    Number of bytes of data. Omitted if the zerodata flag is set.
+**     var    Number of bytes of key. Or the key itself if intkey flag is set.
+**      *     Payload
+**      4     First page of the overflow chain.  Omitted if no overflow
+**
+** Overflow pages form a linked list.  Each page except the last is completely
+** filled with data (pagesize - 4 bytes).  The last page can have as little
+** as 1 byte of data.
+**
+**    SIZE    DESCRIPTION
+**      4     Page number of next overflow page
+**      *     Data
+**
+** Freelist pages come in two subtypes: trunk pages and leaf pages.  The
+** file header points to the first in a linked list of trunk page.  Each trunk
+** page points to multiple leaf pages.  The content of a leaf page is
+** unspecified.  A trunk page looks like this:
+**
+**    SIZE    DESCRIPTION
+**      4     Page number of next trunk page
+**      4     Number of leaf pointers on this page
+**      *     zero or more pages numbers of leaves
 */
-#ifdef SQLITE_ASCII
-SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 00..07    ........ */
-  0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,  /* 08..0f    ........ */
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 10..17    ........ */
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 18..1f    ........ */
-  0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,  /* 20..27     !"#$%&' */
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 28..2f    ()*+,-./ */
-  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,  /* 30..37    01234567 */
-  0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 38..3f    89:;<=>? */
-
-  0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02,  /* 40..47    @ABCDEFG */
-  0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  /* 48..4f    HIJKLMNO */
-  0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  /* 50..57    PQRSTUVW */
-  0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40,  /* 58..5f    XYZ[\]^_ */
-  0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22,  /* 60..67    `abcdefg */
-  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,  /* 68..6f    hijklmno */
-  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,  /* 70..77    pqrstuvw */
-  0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 78..7f    xyz{|}~. */
 
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* 80..87    ........ */
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* 88..8f    ........ */
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* 90..97    ........ */
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* 98..9f    ........ */
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* a0..a7    ........ */
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* a8..af    ........ */
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* b0..b7    ........ */
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* b8..bf    ........ */
 
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* c0..c7    ........ */
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* c8..cf    ........ */
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* d0..d7    ........ */
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* d8..df    ........ */
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* e0..e7    ........ */
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* e8..ef    ........ */
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* f0..f7    ........ */
-  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40   /* f8..ff    ........ */
-};
-#endif
+/* The following value is the maximum cell size assuming a maximum page
+** size give above.
+*/
+#define MX_CELL_SIZE(pBt)  ((int)(pBt->pageSize-8))
 
-#ifndef SQLITE_USE_URI
-# define  SQLITE_USE_URI 0
-#endif
+/* The maximum number of cells on a single page of the database.  This
+** assumes a minimum cell size of 6 bytes  (4 bytes for the cell itself
+** plus 2 bytes for the index to the cell in the page header).  Such
+** small cells will be rare, but they are possible.
+*/
+#define MX_CELL(pBt) ((pBt->pageSize-8)/6)
 
-#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
-# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
-#endif
+/* Forward declarations */
+typedef struct MemPage MemPage;
+typedef struct BtLock BtLock;
 
 /*
-** The following singleton contains the global configuration for
-** the SQLite library.
+** This is a magic string that appears at the beginning of every
+** SQLite database in order to identify the file as a real database.
+**
+** You can change this value at compile-time by specifying a
+** -DSQLITE_FILE_HEADER="..." on the compiler command-line.  The
+** header must be exactly 16 bytes including the zero-terminator so
+** the string itself should be 15 characters long.  If you change
+** the header, then your custom library will not be able to read 
+** databases generated by the standard tools and the standard tools
+** will not be able to read databases created by your custom library.
 */
-SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
-   SQLITE_DEFAULT_MEMSTATUS,  /* bMemstat */
-   1,                         /* bCoreMutex */
-   SQLITE_THREADSAFE==1,      /* bFullMutex */
-   SQLITE_USE_URI,            /* bOpenUri */
-   SQLITE_ALLOW_COVERING_INDEX_SCAN,   /* bUseCis */
-   0x7ffffffe,                /* mxStrlen */
-   128,                       /* szLookaside */
-   500,                       /* nLookaside */
-   {0,0,0,0,0,0,0,0},         /* m */
-   {0,0,0,0,0,0,0,0,0},       /* mutex */
-   {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
-   (void*)0,                  /* pHeap */
-   0,                         /* nHeap */
-   0, 0,                      /* mnHeap, mxHeap */
-   SQLITE_DEFAULT_MMAP_SIZE,  /* szMmap */
-   SQLITE_MAX_MMAP_SIZE,      /* mxMmap */
-   (void*)0,                  /* pScratch */
-   0,                         /* szScratch */
-   0,                         /* nScratch */
-   (void*)0,                  /* pPage */
-   0,                         /* szPage */
-   0,                         /* nPage */
-   0,                         /* mxParserStack */
-   0,                         /* sharedCacheEnabled */
-   /* All the rest should always be initialized to zero */
-   0,                         /* isInit */
-   0,                         /* inProgress */
-   0,                         /* isMutexInit */
-   0,                         /* isMallocInit */
-   0,                         /* isPCacheInit */
-   0,                         /* pInitMutex */
-   0,                         /* nRefInitMutex */
-   0,                         /* xLog */
-   0,                         /* pLogArg */
-   0,                         /* bLocaltimeFault */
-#ifdef SQLITE_ENABLE_SQLLOG
-   0,                         /* xSqllog */
-   0                          /* pSqllogArg */
+#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
+#  define SQLITE_FILE_HEADER "SQLite format 3"
 #endif
-};
-
 
 /*
-** Hash table for global functions - functions common to all
-** database connections.  After initialization, this table is
-** read-only.
+** Page type flags.  An ORed combination of these flags appear as the
+** first byte of on-disk image of every BTree page.
 */
-SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
+#define PTF_INTKEY    0x01
+#define PTF_ZERODATA  0x02
+#define PTF_LEAFDATA  0x04
+#define PTF_LEAF      0x08
 
 /*
-** Constant tokens for values 0 and 1.
+** As each page of the file is loaded into memory, an instance of the following
+** structure is appended and initialized to zero.  This structure stores
+** information about the page that is decoded from the raw file page.
+**
+** The pParent field points back to the parent page.  This allows us to
+** walk up the BTree from any leaf to the root.  Care must be taken to
+** unref() the parent page pointer when this page is no longer referenced.
+** The pageDestructor() routine handles that chore.
+**
+** Access to all fields of this structure is controlled by the mutex
+** stored in MemPage.pBt->mutex.
 */
-SQLITE_PRIVATE const Token sqlite3IntTokens[] = {
-   { "0", 1 },
-   { "1", 1 }
+struct MemPage {
+  u8 isInit;           /* True if previously initialized. MUST BE FIRST! */
+  u8 nOverflow;        /* Number of overflow cell bodies in aCell[] */
+  u8 intKey;           /* True if intkey flag is set */
+  u8 leaf;             /* True if leaf flag is set */
+  u8 hasData;          /* True if this page stores data */
+  u8 hdrOffset;        /* 100 for page 1.  0 otherwise */
+  u8 childPtrSize;     /* 0 if leaf==1.  4 if leaf==0 */
+  u8 max1bytePayload;  /* min(maxLocal,127) */
+  u16 maxLocal;        /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
+  u16 minLocal;        /* Copy of BtShared.minLocal or BtShared.minLeaf */
+  u16 cellOffset;      /* Index in aData of first cell pointer */
+  u16 nFree;           /* Number of free bytes on the page */
+  u16 nCell;           /* Number of cells on this page, local and ovfl */
+  u16 maskPage;        /* Mask for page offset */
+  u16 aiOvfl[5];       /* Insert the i-th overflow cell before the aiOvfl-th
+                       ** non-overflow cell */
+  u8 *apOvfl[5];       /* Pointers to the body of overflow cells */
+  BtShared *pBt;       /* Pointer to BtShared that this page is part of */
+  u8 *aData;           /* Pointer to disk image of the page data */
+  u8 *aDataEnd;        /* One byte past the end of usable data */
+  u8 *aCellIdx;        /* The cell index area */
+  DbPage *pDbPage;     /* Pager page handle */
+  Pgno pgno;           /* Page number for this page */
 };
 
-
 /*
-** The value of the "pending" byte must be 0x40000000 (1 byte past the
-** 1-gibabyte boundary) in a compatible database.  SQLite never uses
-** the database page that contains the pending byte.  It never attempts
-** to read or write that page.  The pending byte page is set assign
-** for use by the VFS layers as space for managing file locks.
-**
-** During testing, it is often desirable to move the pending byte to
-** a different position in the file.  This allows code that has to
-** deal with the pending byte to run on files that are much smaller
-** than 1 GiB.  The sqlite3_test_control() interface can be used to
-** move the pending byte.
-**
-** IMPORTANT:  Changing the pending byte to any value other than
-** 0x40000000 results in an incompatible database file format!
-** Changing the pending byte during operating results in undefined
-** and dileterious behavior.
+** The in-memory image of a disk page has the auxiliary information appended
+** to the end.  EXTRA_SIZE is the number of bytes of space needed to hold
+** that extra information.
 */
-#ifndef SQLITE_OMIT_WSD
-SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
-#endif
+#define EXTRA_SIZE sizeof(MemPage)
 
 /*
-** Properties of opcodes.  The OPFLG_INITIALIZER macro is
-** created by mkopcodeh.awk during compilation.  Data is obtained
-** from the comments following the "case OP_xxxx:" statements in
-** the vdbe.c file.  
+** A linked list of the following structures is stored at BtShared.pLock.
+** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor 
+** is opened on the table with root page BtShared.iTable. Locks are removed
+** from this list when a transaction is committed or rolled back, or when
+** a btree handle is closed.
 */
-SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
+struct BtLock {
+  Btree *pBtree;        /* Btree handle holding this lock */
+  Pgno iTable;          /* Root page of table */
+  u8 eLock;             /* READ_LOCK or WRITE_LOCK */
+  BtLock *pNext;        /* Next in BtShared.pLock list */
+};
 
-/************** End of global.c **********************************************/
-/************** Begin file ctime.c *******************************************/
-/*
-** 2010 February 23
-**
-** The author disclaims copyright to this source code.  In place of
-** a legal notice, here is a blessing:
+/* Candidate values for BtLock.eLock */
+#define READ_LOCK     1
+#define WRITE_LOCK    2
+
+/* A Btree handle
 **
-**    May you do good and not evil.
-**    May you find forgiveness for yourself and forgive others.
-**    May you share freely, never taking more than you give.
+** A database connection contains a pointer to an instance of
+** this object for every database file that it has open.  This structure
+** is opaque to the database connection.  The database connection cannot
+** see the internals of this structure and only deals with pointers to
+** this structure.
 **
-*************************************************************************
+** For some database files, the same underlying database cache might be 
+** shared between multiple connections.  In that case, each connection
+** has it own instance of this object.  But each instance of this object
+** points to the same BtShared object.  The database cache and the
+** schema associated with the database file are all contained within
+** the BtShared object.
 **
-** This file implements routines used to report what compile-time options
-** SQLite was built with.
+** All fields in this structure are accessed under sqlite3.mutex.
+** The pBt pointer itself may not be changed while there exists cursors 
+** in the referenced BtShared that point back to this Btree since those
+** cursors have to go through this Btree to find their BtShared and
+** they often do so without holding sqlite3.mutex.
 */
+struct Btree {
+  sqlite3 *db;       /* The database connection holding this btree */
+  BtShared *pBt;     /* Sharable content of this btree */
+  u8 inTrans;        /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
+  u8 sharable;       /* True if we can share pBt with another db */
+  u8 locked;         /* True if db currently has pBt locked */
+  int wantToLock;    /* Number of nested calls to sqlite3BtreeEnter() */
+  int nBackup;       /* Number of backup operations reading this btree */
+  Btree *pNext;      /* List of other sharable Btrees from the same db */
+  Btree *pPrev;      /* Back pointer of the same list */
+#ifndef SQLITE_OMIT_SHARED_CACHE
+  BtLock lock;       /* Object used to lock page 1 */
+#endif
+};
+
+/*
+** Btree.inTrans may take one of the following values.
+**
+** If the shared-data extension is enabled, there may be multiple users
+** of the Btree structure. At most one of these may open a write transaction,
+** but any number may have active read transactions.
+*/
+#define TRANS_NONE  0
+#define TRANS_READ  1
+#define TRANS_WRITE 2
+
+/*
+** An instance of this object represents a single database file.
+** 
+** A single database file can be in use at the same time by two
+** or more database connections.  When two or more connections are
+** sharing the same database file, each connection has it own
+** private Btree object for the file and each of those Btrees points
+** to this one BtShared object.  BtShared.nRef is the number of
+** connections currently sharing this database file.
+**
+** Fields in this structure are accessed under the BtShared.mutex
+** mutex, except for nRef and pNext which are accessed under the
+** global SQLITE_MUTEX_STATIC_MASTER mutex.  The pPager field
+** may not be modified once it is initially set as long as nRef>0.
+** The pSchema field may be set once under BtShared.mutex and
+** thereafter is unchanged as long as nRef>0.
+**
+** isPending:
+**
+**   If a BtShared client fails to obtain a write-lock on a database
+**   table (because there exists one or more read-locks on the table),
+**   the shared-cache enters 'pending-lock' state and isPending is
+**   set to true.
+**
+**   The shared-cache leaves the 'pending lock' state when either of
+**   the following occur:
+**
+**     1) The current writer (BtShared.pWriter) concludes its transaction, OR
+**     2) The number of locks held by other connections drops to zero.
+**
+**   while in the 'pending-lock' state, no connection may start a new
+**   transaction.
+**
+**   This feature is included to help prevent writer-starvation.
+*/
+struct BtShared {
+  Pager *pPager;        /* The page cache */
+  sqlite3 *db;          /* Database connection currently using this Btree */
+  BtCursor *pCursor;    /* A list of all open cursors */
+  MemPage *pPage1;      /* First page of the database */
+  u8 openFlags;         /* Flags to sqlite3BtreeOpen() */
+#ifndef SQLITE_OMIT_AUTOVACUUM
+  u8 autoVacuum;        /* True if auto-vacuum is enabled */
+  u8 incrVacuum;        /* True if incr-vacuum is enabled */
+  u8 bDoTruncate;       /* True to truncate db on commit */
+#endif
+  u8 inTransaction;     /* Transaction state */
+  u8 max1bytePayload;   /* Maximum first byte of cell for a 1-byte payload */
+  u16 btsFlags;         /* Boolean parameters.  See BTS_* macros below */
+  u16 maxLocal;         /* Maximum local payload in non-LEAFDATA tables */
+  u16 minLocal;         /* Minimum local payload in non-LEAFDATA tables */
+  u16 maxLeaf;          /* Maximum local payload in a LEAFDATA table */
+  u16 minLeaf;          /* Minimum local payload in a LEAFDATA table */
+  u32 pageSize;         /* Total number of bytes on a page */
+  u32 usableSize;       /* Number of usable bytes on each page */
+  int nTransaction;     /* Number of open transactions (read + write) */
+  u32 nPage;            /* Number of pages in the database */
+  void *pSchema;        /* Pointer to space allocated by sqlite3BtreeSchema() */
+  void (*xFreeSchema)(void*);  /* Destructor for BtShared.pSchema */
+  sqlite3_mutex *mutex; /* Non-recursive mutex required to access this object */
+  Bitvec *pHasContent;  /* Set of pages moved to free-list this transaction */
+#ifndef SQLITE_OMIT_SHARED_CACHE
+  int nRef;             /* Number of references to this structure */
+  BtShared *pNext;      /* Next on a list of sharable BtShared structs */
+  BtLock *pLock;        /* List of locks held on this shared-btree struct */
+  Btree *pWriter;       /* Btree with currently open write transaction */
+#endif
+  u8 *pTmpSpace;        /* BtShared.pageSize bytes of space for tmp use */
+};
+
+/*
+** Allowed values for BtShared.btsFlags
+*/
+#define BTS_READ_ONLY        0x0001   /* Underlying file is readonly */
+#define BTS_PAGESIZE_FIXED   0x0002   /* Page size can no longer be changed */
+#define BTS_SECURE_DELETE    0x0004   /* PRAGMA secure_delete is enabled */
+#define BTS_INITIALLY_EMPTY  0x0008   /* Database was empty at trans start */
+#define BTS_NO_WAL           0x0010   /* Do not open write-ahead-log files */
+#define BTS_EXCLUSIVE        0x0020   /* pWriter has an exclusive lock */
+#define BTS_PENDING          0x0040   /* Waiting for read-locks to clear */
+
+/*
+** An instance of the following structure is used to hold information
+** about a cell.  The parseCellPtr() function fills in this structure
+** based on information extract from the raw disk page.
+*/
+typedef struct CellInfo CellInfo;
+struct CellInfo {
+  i64 nKey;      /* The key for INTKEY tables, or number of bytes in key */
+  u8 *pCell;     /* Pointer to the start of cell content */
+  u32 nData;     /* Number of bytes of data */
+  u32 nPayload;  /* Total amount of payload */
+  u16 nHeader;   /* Size of the cell content header in bytes */
+  u16 nLocal;    /* Amount of payload held locally */
+  u16 iOverflow; /* Offset to overflow page number.  Zero if no overflow */
+  u16 nSize;     /* Size of the cell content on the main b-tree page */
+};
+
+/*
+** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than
+** this will be declared corrupt. This value is calculated based on a
+** maximum database size of 2^31 pages a minimum fanout of 2 for a
+** root-node and 3 for all other internal nodes.
+**
+** If a tree that appears to be taller than this is encountered, it is
+** assumed that the database is corrupt.
+*/
+#define BTCURSOR_MAX_DEPTH 20
+
+/*
+** A cursor is a pointer to a particular entry within a particular
+** b-tree within a database file.
+**
+** The entry is identified by its MemPage and the index in
+** MemPage.aCell[] of the entry.
+**
+** A single database file can be shared by two more database connections,
+** but cursors cannot be shared.  Each cursor is associated with a
+** particular database connection identified BtCursor.pBtree.db.
+**
+** Fields in this structure are accessed under the BtShared.mutex
+** found at self->pBt->mutex. 
+*/
+struct BtCursor {
+  Btree *pBtree;            /* The Btree to which this cursor belongs */
+  BtShared *pBt;            /* The BtShared this cursor points to */
+  BtCursor *pNext, *pPrev;  /* Forms a linked list of all cursors */
+  struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
+#ifndef SQLITE_OMIT_INCRBLOB
+  Pgno *aOverflow;          /* Cache of overflow page locations */
+#endif
+  Pgno pgnoRoot;            /* The root page of this tree */
+  sqlite3_int64 cachedRowid; /* Next rowid cache.  0 means not valid */
+  CellInfo info;            /* A parse of the cell we are pointing at */
+  i64 nKey;        /* Size of pKey, or last integer key */
+  void *pKey;      /* Saved key that was cursor's last known position */
+  int skipNext;    /* Prev() is noop if negative. Next() is noop if positive */
+  u8 wrFlag;                /* True if writable */
+  u8 atLast;                /* Cursor pointing to the last entry */
+  u8 validNKey;             /* True if info.nKey is valid */
+  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
+#ifndef SQLITE_OMIT_INCRBLOB
+  u8 isIncrblobHandle;      /* True if this cursor is an incr. io handle */
+#endif
+  u8 hints;                             /* As configured by CursorSetHints() */
+  i16 iPage;                            /* Index of current page in apPage */
+  u16 aiIdx[BTCURSOR_MAX_DEPTH];        /* Current index in apPage[i] */
+  MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
+};
+
+/*
+** Potential values for BtCursor.eState.
+**
+** CURSOR_INVALID:
+**   Cursor does not point to a valid entry. This can happen (for example) 
+**   because the table is empty or because BtreeCursorFirst() has not been
+**   called.
+**
+** CURSOR_VALID:
+**   Cursor points to a valid entry. getPayload() etc. may be called.
+**
+** CURSOR_SKIPNEXT:
+**   Cursor is valid except that the Cursor.skipNext field is non-zero
+**   indicating that the next sqlite3BtreeNext() or sqlite3BtreePrevious()
+**   operation should be a no-op.
+**
+** CURSOR_REQUIRESEEK:
+**   The table that this cursor was opened on still exists, but has been 
+**   modified since the cursor was last used. The cursor position is saved
+**   in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in 
+**   this state, restoreCursorPosition() can be called to attempt to
+**   seek the cursor to the saved position.
+**
+** CURSOR_FAULT:
+**   A unrecoverable error (an I/O error or a malloc failure) has occurred
+**   on a different connection that shares the BtShared cache with this
+**   cursor.  The error has left the cache in an inconsistent state.
+**   Do nothing else with this cursor.  Any attempt to use the cursor
+**   should return the error code stored in BtCursor.skip
+*/
+#define CURSOR_INVALID           0
+#define CURSOR_VALID             1
+#define CURSOR_SKIPNEXT          2
+#define CURSOR_REQUIRESEEK       3
+#define CURSOR_FAULT             4
+
+/* 
+** The database page the PENDING_BYTE occupies. This page is never used.
+*/
+# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
+
+/*
+** These macros define the location of the pointer-map entry for a 
+** database page. The first argument to each is the number of usable
+** bytes on each page of the database (often 1024). The second is the
+** page number to look up in the pointer map.
+**
+** PTRMAP_PAGENO returns the database page number of the pointer-map
+** page that stores the required pointer. PTRMAP_PTROFFSET returns
+** the offset of the requested map entry.
+**
+** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
+** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
+** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
+** this test.
+*/
+#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
+#define PTRMAP_PTROFFSET(pgptrmap, pgno) (5*(pgno-pgptrmap-1))
+#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
+
+/*
+** The pointer map is a lookup table that identifies the parent page for
+** each child page in the database file.  The parent page is the page that
+** contains a pointer to the child.  Every page in the database contains
+** 0 or 1 parent pages.  (In this context 'database page' refers
+** to any page that is not part of the pointer map itself.)  Each pointer map
+** entry consists of a single byte 'type' and a 4 byte parent page number.
+** The PTRMAP_XXX identifiers below are the valid types.
+**
+** The purpose of the pointer map is to facility moving pages from one
+** position in the file to another as part of autovacuum.  When a page
+** is moved, the pointer in its parent must be updated to point to the
+** new location.  The pointer map is used to locate the parent page quickly.
+**
+** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
+**                  used in this case.
+**
+** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number 
+**                  is not used in this case.
+**
+** PTRMAP_OVERFLOW1: The database page is the first page in a list of 
+**                   overflow pages. The page number identifies the page that
+**                   contains the cell with a pointer to this overflow page.
+**
+** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of
+**                   overflow pages. The page-number identifies the previous
+**                   page in the overflow page list.
+**
+** PTRMAP_BTREE: The database page is a non-root btree page. The page number
+**               identifies the parent page in the btree.
+*/
+#define PTRMAP_ROOTPAGE 1
+#define PTRMAP_FREEPAGE 2
+#define PTRMAP_OVERFLOW1 3
+#define PTRMAP_OVERFLOW2 4
+#define PTRMAP_BTREE 5
+
+/* A bunch of assert() statements to check the transaction state variables
+** of handle p (type Btree*) are internally consistent.
+*/
+#define btreeIntegrity(p) \
+  assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
+  assert( p->pBt->inTransaction>=p->inTrans ); 
+
+
+/*
+** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
+** if the database supports auto-vacuum or not. Because it is used
+** within an expression that is an argument to another macro 
+** (sqliteMallocRaw), it is not possible to use conditional compilation.
+** So, this macro is defined instead.
+*/
+#ifndef SQLITE_OMIT_AUTOVACUUM
+#define ISAUTOVACUUM (pBt->autoVacuum)
+#else
+#define ISAUTOVACUUM 0
+#endif
+
+
+/*
+** This structure is passed around through all the sanity checking routines
+** in order to keep track of some global state information.
+**
+** The aRef[] array is allocated so that there is 1 bit for each page in
+** the database. As the integrity-check proceeds, for each page used in
+** the database the corresponding bit is set. This allows integrity-check to 
+** detect pages that are used twice and orphaned pages (both of which 
+** indicate corruption).
+*/
+typedef struct IntegrityCk IntegrityCk;
+struct IntegrityCk {
+  BtShared *pBt;    /* The tree being checked out */
+  Pager *pPager;    /* The associated pager.  Also accessible by pBt->pPager */
+  u8 *aPgRef;       /* 1 bit per page in the db (see above) */
+  Pgno nPage;       /* Number of pages in the database */
+  int mxErr;        /* Stop accumulating errors when this reaches zero */
+  int nErr;         /* Number of messages written to zErrMsg so far */
+  int mallocFailed; /* A memory allocation error has occurred */
+  StrAccum errMsg;  /* Accumulate the error message text here */
+};
+
+/*
+** Routines to read or write a two- and four-byte big-endian integer values.
+*/
+#define get2byte(x)   ((x)[0]<<8 | (x)[1])
+#define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v))
+#define get4byte sqlite3Get4byte
+#define put4byte sqlite3Put4byte
+
+/************** End of btreeInt.h ********************************************/
+/************** Continuing where we left off in crypto.c *********************/
+/************** Include crypto.h in the middle of crypto.c *******************/
+/************** Begin file crypto.h ******************************************/
+/* 
+** SQLCipher
+** crypto.h developed by Stephen Lombardo (Zetetic LLC) 
+** sjlombardo at zetetic dot net
+** http://zetetic.net
+** 
+** Copyright (c) 2008, ZETETIC LLC
+** All rights reserved.
+** 
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**     * Redistributions of source code must retain the above copyright
+**       notice, this list of conditions and the following disclaimer.
+**     * Redistributions in binary form must reproduce the above copyright
+**       notice, this list of conditions and the following disclaimer in the
+**       documentation and/or other materials provided with the distribution.
+**     * Neither the name of the ZETETIC LLC nor the
+**       names of its contributors may be used to endorse or promote products
+**       derived from this software without specific prior written permission.
+** 
+** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
+** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**  
+*/
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+#ifndef CRYPTO_H
+#define CRYPTO_H
+
+#if !defined (SQLCIPHER_CRYPTO_CC) \
+   && !defined (SQLCIPHER_CRYPTO_LIBTOMCRYPT) \
+   && !defined (SQLCIPHER_CRYPTO_OPENSSL)
+#define SQLCIPHER_CRYPTO_OPENSSL
+#endif
+
+#define FILE_HEADER_SZ 16
+
+#ifndef CIPHER_VERSION
+#define CIPHER_VERSION "3.0.0"
+#endif
+
+#ifndef CIPHER
+#define CIPHER "aes-256-cbc"
+#endif
+
+#define CIPHER_DECRYPT 0
+#define CIPHER_ENCRYPT 1
+
+#define CIPHER_READ_CTX 0
+#define CIPHER_WRITE_CTX 1
+#define CIPHER_READWRITE_CTX 2
+
+#ifndef PBKDF2_ITER
+#define PBKDF2_ITER 64000
+#endif
+
+/* possible flags for cipher_ctx->flags */
+#define CIPHER_FLAG_HMAC          0x01
+#define CIPHER_FLAG_LE_PGNO       0x02
+#define CIPHER_FLAG_BE_PGNO       0x04
+
+#ifndef DEFAULT_CIPHER_FLAGS
+#define DEFAULT_CIPHER_FLAGS CIPHER_FLAG_HMAC | CIPHER_FLAG_LE_PGNO
+#endif
+
+
+/* by default, sqlcipher will use a reduced number of iterations to generate
+   the HMAC key / or transform a raw cipher key 
+   */
+#ifndef FAST_PBKDF2_ITER
+#define FAST_PBKDF2_ITER 2
+#endif
+
+/* this if a fixed random array that will be xor'd with the database salt to ensure that the
+   salt passed to the HMAC key derivation function is not the same as that used to derive
+   the encryption key. This can be overridden at compile time but it will make the resulting
+   binary incompatible with the default builds when using HMAC. A future version of SQLcipher
+   will likely allow this to be defined at runtime via pragma */ 
+#ifndef HMAC_SALT_MASK
+#define HMAC_SALT_MASK 0x3a
+#endif
+
+#ifndef CIPHER_MAX_IV_SZ
+#define CIPHER_MAX_IV_SZ 16
+#endif
+
+#ifndef CIPHER_MAX_KEY_SZ
+#define CIPHER_MAX_KEY_SZ 64
+#endif
+
+
+#ifdef CODEC_DEBUG
+#define CODEC_TRACE(X)  {printf X;fflush(stdout);}
+#else
+#define CODEC_TRACE(X)
+#endif
+
+#ifdef CODEC_DEBUG_PAGEDATA
+#define CODEC_HEXDUMP(DESC,BUFFER,LEN)  \
+  { \
+    int __pctr; \
+    printf(DESC); \
+    for(__pctr=0; __pctr < LEN; __pctr++) { \
+      if(__pctr % 16 == 0) printf("\n%05x: ",__pctr); \
+      printf("%02x ",((unsigned char*) BUFFER)[__pctr]); \
+    } \
+    printf("\n"); \
+    fflush(stdout); \
+  }
+#else
+#define CODEC_HEXDUMP(DESC,BUFFER,LEN)
+#endif
+
+/* extensions defined in pager.c */ 
+SQLITE_PRIVATE void sqlite3pager_get_codec(Pager *pPager, void **ctx);
+SQLITE_PRIVATE int sqlite3pager_is_mj_pgno(Pager *pPager, Pgno pgno);
+SQLITE_PRIVATE sqlite3_file *sqlite3Pager_get_fd(Pager *pPager);
+SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetCodec(
+  Pager *pPager,
+  void *(*xCodec)(void*,void*,Pgno,int),
+  void (*xCodecSizeChng)(void*,int,int),
+  void (*xCodecFree)(void*),
+  void *pCodec
+);
+SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetError(Pager *pPager, int error);
+/* end extensions defined in pager.c */
+ 
+/*
+**  Simple shared routines for converting hex char strings to binary data
+ */
+static int cipher_hex2int(char c) {
+  return (c>='0' && c<='9') ? (c)-'0' :
+         (c>='A' && c<='F') ? (c)-'A'+10 :
+         (c>='a' && c<='f') ? (c)-'a'+10 : 0;
+}
+
+static void cipher_hex2bin(const unsigned char *hex, int sz, unsigned char *out){
+  int i;
+  for(i = 0; i < sz; i += 2){
+    out[i/2] = (cipher_hex2int(hex[i])<<4) | cipher_hex2int(hex[i+1]);
+  }
+}
+
+static void cipher_bin2hex(const unsigned char* in, int sz, char *out) {
+    int i;
+    for(i=0; i < sz; i++) {
+      sqlite3_snprintf(3, out + (i*2), "%02x ", in[i]);
+    } 
+}
+
+/* extensions defined in crypto_impl.c */
+typedef struct codec_ctx codec_ctx;
+
+/* activation and initialization */
+void sqlcipher_activate();
+void sqlcipher_deactivate();
+int sqlcipher_codec_ctx_init(codec_ctx **, Db *, Pager *, sqlite3_file *, const void *, int);
+void sqlcipher_codec_ctx_free(codec_ctx **);
+int sqlcipher_codec_key_derive(codec_ctx *);
+int sqlcipher_codec_key_copy(codec_ctx *, int);
+
+/* page cipher implementation */
+int sqlcipher_page_cipher(codec_ctx *, int, Pgno, int, int, unsigned char *, unsigned char *);
+
+/* context setters & getters */
+void sqlcipher_codec_ctx_set_error(codec_ctx *, int);
+
+int sqlcipher_codec_ctx_set_pass(codec_ctx *, const void *, int, int);
+void sqlcipher_codec_get_keyspec(codec_ctx *, void **zKey, int *nKey);
+
+int sqlcipher_codec_ctx_set_pagesize(codec_ctx *, int);
+int sqlcipher_codec_ctx_get_pagesize(codec_ctx *);
+int sqlcipher_codec_ctx_get_reservesize(codec_ctx *);
+
+void sqlcipher_set_default_kdf_iter(int iter);
+int sqlcipher_get_default_kdf_iter();
+
+int sqlcipher_codec_ctx_set_kdf_iter(codec_ctx *, int, int);
+int sqlcipher_codec_ctx_get_kdf_iter(codec_ctx *ctx, int);
+
+void* sqlcipher_codec_ctx_get_kdf_salt(codec_ctx *ctx);
+
+int sqlcipher_codec_ctx_set_fast_kdf_iter(codec_ctx *, int, int);
+int sqlcipher_codec_ctx_get_fast_kdf_iter(codec_ctx *, int);
+
+int sqlcipher_codec_ctx_set_cipher(codec_ctx *, const char *, int);
+const char* sqlcipher_codec_ctx_get_cipher(codec_ctx *ctx, int for_ctx);
+
+void* sqlcipher_codec_ctx_get_data(codec_ctx *);
+
+void sqlcipher_exportFunc(sqlite3_context *, int, sqlite3_value **);
+
+void sqlcipher_set_default_use_hmac(int use);
+int sqlcipher_get_default_use_hmac();
+
+void sqlcipher_set_hmac_salt_mask(unsigned char mask);
+unsigned char sqlcipher_get_hmac_salt_mask();
+
+int sqlcipher_codec_ctx_set_use_hmac(codec_ctx *ctx, int use);
+int sqlcipher_codec_ctx_get_use_hmac(codec_ctx *ctx, int for_ctx);
+
+int sqlcipher_codec_ctx_set_flag(codec_ctx *ctx, unsigned int flag);
+int sqlcipher_codec_ctx_unset_flag(codec_ctx *ctx, unsigned int flag);
+int sqlcipher_codec_ctx_get_flag(codec_ctx *ctx, unsigned int flag, int for_ctx);
+
+const char* sqlcipher_codec_get_cipher_provider(codec_ctx *ctx);
+int sqlcipher_codec_ctx_migrate(codec_ctx *ctx);
+#endif
+#endif
+/* END SQLCIPHER */
+
+/************** End of crypto.h **********************************************/
+/************** Continuing where we left off in crypto.c *********************/
+
+static const char* codec_get_cipher_version() {
+  return CIPHER_VERSION;
+}
+
+/* Generate code to return a string value */
+static void codec_vdbe_return_static_string(Parse *pParse, const char *zLabel, const char *value){
+  Vdbe *v = sqlite3GetVdbe(pParse);
+  sqlite3VdbeSetNumCols(v, 1);
+  sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLabel, SQLITE_STATIC);
+  sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, value, 0);
+  sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1);
+}
+
+static int codec_set_btree_to_codec_pagesize(sqlite3 *db, Db *pDb, codec_ctx *ctx) {
+  int rc, page_sz, reserve_sz; 
+
+  page_sz = sqlcipher_codec_ctx_get_pagesize(ctx);
+  reserve_sz = sqlcipher_codec_ctx_get_reservesize(ctx);
+
+  sqlite3_mutex_enter(db->mutex);
+  db->nextPagesize = page_sz; 
+
+  /* before forcing the page size we need to unset the BTS_PAGESIZE_FIXED flag, else  
+     sqliteBtreeSetPageSize will block the change  */
+  pDb->pBt->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED;
+  CODEC_TRACE(("codec_set_btree_to_codec_pagesize: sqlite3BtreeSetPageSize() size=%d reserve=%d\n", page_sz, reserve_sz));
+  rc = sqlite3BtreeSetPageSize(pDb->pBt, page_sz, reserve_sz, 0);
+  sqlite3_mutex_leave(db->mutex);
+  return rc;
+}
+
+static int codec_set_pass_key(sqlite3* db, int nDb, const void *zKey, int nKey, int for_ctx) {
+  struct Db *pDb = &db->aDb[nDb];
+  CODEC_TRACE(("codec_set_pass_key: entered db=%p nDb=%d zKey=%s nKey=%d for_ctx=%d\n", db, nDb, (char *)zKey, nKey, for_ctx));
+  if(pDb->pBt) {
+    codec_ctx *ctx;
+    sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
+    if(ctx) return sqlcipher_codec_ctx_set_pass(ctx, zKey, nKey, for_ctx);
+  }
+  return SQLITE_ERROR;
+} 
+
+int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLeft, const char *zRight) {
+  struct Db *pDb = &db->aDb[iDb];
+  codec_ctx *ctx = NULL;
+  int rc;
+
+  if(pDb->pBt) {
+    sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
+  }
+
+  CODEC_TRACE(("sqlcipher_codec_pragma: entered db=%p iDb=%d pParse=%p zLeft=%s zRight=%s ctx=%p\n", db, iDb, pParse, zLeft, zRight, ctx));
+  
+  if( sqlite3StrICmp(zLeft, "cipher_migrate")==0 && !zRight ){
+    if(ctx){
+      char *migrate_status = sqlite3_mprintf("%d", sqlcipher_codec_ctx_migrate(ctx));
+      codec_vdbe_return_static_string(pParse, "cipher_migrate", migrate_status);
+      sqlite3_free(migrate_status);
+    }
+  } else
+  if( sqlite3StrICmp(zLeft, "cipher_provider")==0 && !zRight ){
+    if(ctx) { codec_vdbe_return_static_string(pParse, "cipher_provider",
+                                              sqlcipher_codec_get_cipher_provider(ctx));
+    }
+  } else
+  if( sqlite3StrICmp(zLeft, "cipher_version")==0 && !zRight ){
+    codec_vdbe_return_static_string(pParse, "cipher_version", codec_get_cipher_version());
+  }else
+  if( sqlite3StrICmp(zLeft, "cipher")==0 ){
+    if(ctx) {
+      if( zRight ) {
+        sqlcipher_codec_ctx_set_cipher(ctx, zRight, 2); // change cipher for both
+      }else {
+        codec_vdbe_return_static_string(pParse, "cipher",
+          sqlcipher_codec_ctx_get_cipher(ctx, 2));
+      }
+    }
+  }else
+  if( sqlite3StrICmp(zLeft, "rekey_cipher")==0 && zRight ){
+    if(ctx) sqlcipher_codec_ctx_set_cipher(ctx, zRight, 1); // change write cipher only 
+  }else
+  if( sqlite3StrICmp(zLeft,"cipher_default_kdf_iter")==0 ){
+    if( zRight ) {
+      sqlcipher_set_default_kdf_iter(atoi(zRight)); // change default KDF iterations
+    } else {
+      char *kdf_iter = sqlite3_mprintf("%d", sqlcipher_get_default_kdf_iter());
+      codec_vdbe_return_static_string(pParse, "cipher_default_kdf_iter", kdf_iter);
+      sqlite3_free(kdf_iter);
+    }
+  }else
+  if( sqlite3StrICmp(zLeft, "kdf_iter")==0 ){
+    if(ctx) {
+      if( zRight ) {
+        sqlcipher_codec_ctx_set_kdf_iter(ctx, atoi(zRight), 2); // change of RW PBKDF2 iteration 
+      } else {
+        char *kdf_iter = sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_kdf_iter(ctx, 2));
+        codec_vdbe_return_static_string(pParse, "kdf_iter", kdf_iter);
+        sqlite3_free(kdf_iter);
+      }
+    }
+  }else
+  if( sqlite3StrICmp(zLeft, "fast_kdf_iter")==0){
+    if(ctx) {
+      if( zRight ) {
+        sqlcipher_codec_ctx_set_fast_kdf_iter(ctx, atoi(zRight), 2); // change of RW PBKDF2 iteration 
+      } else {
+        char *fast_kdf_iter = sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_fast_kdf_iter(ctx, 2));
+        codec_vdbe_return_static_string(pParse, "fast_kdf_iter", fast_kdf_iter);
+        sqlite3_free(fast_kdf_iter);
+      }
+    }
+  }else
+  if( sqlite3StrICmp(zLeft, "rekey_kdf_iter")==0 && zRight ){
+    if(ctx) sqlcipher_codec_ctx_set_kdf_iter(ctx, atoi(zRight), 1); // write iterations only
+  }else
+  if( sqlite3StrICmp(zLeft,"cipher_page_size")==0 ){
+    if(ctx) {
+      if( zRight ) {
+        int size = atoi(zRight);
+        rc = sqlcipher_codec_ctx_set_pagesize(ctx, size);
+        if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
+        rc = codec_set_btree_to_codec_pagesize(db, pDb, ctx);
+        if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
+      } else {
+        char * page_size = sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_pagesize(ctx));
+        codec_vdbe_return_static_string(pParse, "cipher_page_size", page_size);
+        sqlite3_free(page_size);
+      }
+    }
+  }else
+  if( sqlite3StrICmp(zLeft,"cipher_default_use_hmac")==0 ){
+    if( zRight ) {
+      sqlcipher_set_default_use_hmac(sqlite3GetBoolean(zRight,1));
+    } else {
+      char *default_use_hmac = sqlite3_mprintf("%d", sqlcipher_get_default_use_hmac());
+      codec_vdbe_return_static_string(pParse, "cipher_default_use_hmac", default_use_hmac);
+      sqlite3_free(default_use_hmac);
+    }
+  }else
+  if( sqlite3StrICmp(zLeft,"cipher_use_hmac")==0 ){
+    if(ctx) {
+      if( zRight ) {
+        rc = sqlcipher_codec_ctx_set_use_hmac(ctx, sqlite3GetBoolean(zRight,1));
+        if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
+        /* since the use of hmac has changed, the page size may also change */
+        rc = codec_set_btree_to_codec_pagesize(db, pDb, ctx);
+        if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
+      } else {
+        char *hmac_flag = sqlite3_mprintf("%d", sqlcipher_codec_ctx_get_use_hmac(ctx, 2));
+        codec_vdbe_return_static_string(pParse, "cipher_use_hmac", hmac_flag);
+        sqlite3_free(hmac_flag);
+      }
+    }
+  }else
+  if( sqlite3StrICmp(zLeft,"cipher_hmac_pgno")==0 ){
+    if(ctx) {
+      if(zRight) {
+        // clear both pgno endian flags
+        if(sqlite3StrICmp(zRight, "le") == 0) {
+          sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_BE_PGNO);
+          sqlcipher_codec_ctx_set_flag(ctx, CIPHER_FLAG_LE_PGNO);
+        } else if(sqlite3StrICmp(zRight, "be") == 0) {
+          sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_LE_PGNO);
+          sqlcipher_codec_ctx_set_flag(ctx, CIPHER_FLAG_BE_PGNO);
+        } else if(sqlite3StrICmp(zRight, "native") == 0) {
+          sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_LE_PGNO);
+          sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_BE_PGNO);
+        }
+      } else {
+        if(sqlcipher_codec_ctx_get_flag(ctx, CIPHER_FLAG_LE_PGNO, 2)) {
+          codec_vdbe_return_static_string(pParse, "cipher_hmac_pgno", "le");
+        } else if(sqlcipher_codec_ctx_get_flag(ctx, CIPHER_FLAG_BE_PGNO, 2)) {
+          codec_vdbe_return_static_string(pParse, "cipher_hmac_pgno", "be");
+        } else {
+          codec_vdbe_return_static_string(pParse, "cipher_hmac_pgno", "native");
+        }
+      }
+    }
+  }else
+  if( sqlite3StrICmp(zLeft,"cipher_hmac_salt_mask")==0 ){
+    if(ctx) {
+      if(zRight) {
+        if (sqlite3StrNICmp(zRight ,"x'", 2) == 0 && sqlite3Strlen30(zRight) == 5) {
+          unsigned char mask = 0;
+          const unsigned char *hex = (const unsigned char *)zRight+2;
+          cipher_hex2bin(hex,2,&mask);
+          sqlcipher_set_hmac_salt_mask(mask);
+        }
+      } else {
+          char *hmac_salt_mask = sqlite3_mprintf("%02x", sqlcipher_get_hmac_salt_mask());
+          codec_vdbe_return_static_string(pParse, "cipher_hmac_salt_mask", hmac_salt_mask);
+          sqlite3_free(hmac_salt_mask);
+      }
+    }
+  }else {
+    return 0;
+  }
+  return 1;
+}
+
+/*
+ * sqlite3Codec can be called in multiple modes.
+ * encrypt mode - expected to return a pointer to the 
+ *   encrypted data without altering pData.
+ * decrypt mode - expected to return a pointer to pData, with
+ *   the data decrypted in the input buffer
+ */
+void* sqlite3Codec(void *iCtx, void *data, Pgno pgno, int mode) {
+  codec_ctx *ctx = (codec_ctx *) iCtx;
+  int offset = 0, rc = 0;
+  int page_sz = sqlcipher_codec_ctx_get_pagesize(ctx); 
+  unsigned char *pData = (unsigned char *) data;
+  void *buffer = sqlcipher_codec_ctx_get_data(ctx);
+  void *kdf_salt = sqlcipher_codec_ctx_get_kdf_salt(ctx);
+  CODEC_TRACE(("sqlite3Codec: entered pgno=%d, mode=%d, page_sz=%d\n", pgno, mode, page_sz));
+
+  /* call to derive keys if not present yet */
+  if((rc = sqlcipher_codec_key_derive(ctx)) != SQLITE_OK) {
+   sqlcipher_codec_ctx_set_error(ctx, rc); 
+   return NULL;
+  }
+
+  if(pgno == 1) offset = FILE_HEADER_SZ; /* adjust starting pointers in data page for header offset on first page*/
+
+  CODEC_TRACE(("sqlite3Codec: switch mode=%d offset=%d\n",  mode, offset));
+  switch(mode) {
+    case 0: /* decrypt */
+    case 2:
+    case 3:
+      if(pgno == 1) memcpy(buffer, SQLITE_FILE_HEADER, FILE_HEADER_SZ); /* copy file header to the first 16 bytes of the page */ 
+      rc = sqlcipher_page_cipher(ctx, CIPHER_READ_CTX, pgno, CIPHER_DECRYPT, page_sz - offset, pData + offset, (unsigned char*)buffer + offset);
+      if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
+      memcpy(pData, buffer, page_sz); /* copy buffer data back to pData and return */
+      return pData;
+      break;
+    case 6: /* encrypt */
+      if(pgno == 1) memcpy(buffer, kdf_salt, FILE_HEADER_SZ); /* copy salt to output buffer */ 
+      rc = sqlcipher_page_cipher(ctx, CIPHER_WRITE_CTX, pgno, CIPHER_ENCRYPT, page_sz - offset, pData + offset, (unsigned char*)buffer + offset);
+      if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
+      return buffer; /* return persistent buffer data, pData remains intact */
+      break;
+    case 7:
+      if(pgno == 1) memcpy(buffer, kdf_salt, FILE_HEADER_SZ); /* copy salt to output buffer */ 
+      rc = sqlcipher_page_cipher(ctx, CIPHER_READ_CTX, pgno, CIPHER_ENCRYPT, page_sz - offset, pData + offset, (unsigned char*)buffer + offset);
+      if(rc != SQLITE_OK) sqlcipher_codec_ctx_set_error(ctx, rc);
+      return buffer; /* return persistent buffer data, pData remains intact */
+      break;
+    default:
+      return pData;
+      break;
+  }
+}
+
+SQLITE_PRIVATE void sqlite3FreeCodecArg(void *pCodecArg) {
+  codec_ctx *ctx = (codec_ctx *) pCodecArg;
+  if(pCodecArg == NULL) return;
+  sqlcipher_codec_ctx_free(&ctx); // wipe and free allocated memory for the context 
+  sqlcipher_deactivate(); /* cleanup related structures, OpenSSL etc, when codec is detatched */
+}
+
+SQLITE_PRIVATE int sqlite3CodecAttach(sqlite3* db, int nDb, const void *zKey, int nKey) {
+  struct Db *pDb = &db->aDb[nDb];
+
+  CODEC_TRACE(("sqlite3CodecAttach: entered nDb=%d zKey=%s, nKey=%d\n", nDb, (char *)zKey, nKey));
+
+
+  if(nKey && zKey && pDb->pBt) {
+    int rc;
+    Pager *pPager = pDb->pBt->pBt->pPager;
+    sqlite3_file *fd = sqlite3Pager_get_fd(pPager);
+    codec_ctx *ctx;
+
+    sqlcipher_activate(); /* perform internal initialization for sqlcipher */
+
+    sqlite3_mutex_enter(db->mutex);
+
+    /* point the internal codec argument against the contet to be prepared */
+    rc = sqlcipher_codec_ctx_init(&ctx, pDb, pDb->pBt->pBt->pPager, fd, zKey, nKey); 
+
+    if(rc != SQLITE_OK) return rc; /* initialization failed, do not attach potentially corrupted context */
+
+    sqlite3pager_sqlite3PagerSetCodec(sqlite3BtreePager(pDb->pBt), sqlite3Codec, NULL, sqlite3FreeCodecArg, (void *) ctx);
+
+    codec_set_btree_to_codec_pagesize(db, pDb, ctx);
+
+    /* force secure delete. This has the benefit of wiping internal data when deleted
+       and also ensures that all pages are written to disk (i.e. not skipped by
+       sqlite3PagerDontWrite optimizations) */ 
+    sqlite3BtreeSecureDelete(pDb->pBt, 1); 
+
+    /* if fd is null, then this is an in-memory database and
+       we dont' want to overwrite the AutoVacuum settings
+       if not null, then set to the default */
+    if(fd != NULL) { 
+      sqlite3BtreeSetAutoVacuum(pDb->pBt, SQLITE_DEFAULT_AUTOVACUUM);
+    }
+    sqlite3_mutex_leave(db->mutex);
+  }
+  return SQLITE_OK;
+}
+
+SQLITE_API void sqlite3_activate_see(const char* in) {
+  /* do nothing, security enhancements are always active */
+}
+
+static int sqlcipher_find_db_index(sqlite3 *db, const char *zDb) {
+  int db_index;
+  if(zDb == NULL){
+    return 0;
+  }
+  for(db_index = 0; db_index < db->nDb; db_index++) {
+    struct Db *pDb = &db->aDb[db_index];
+    if(strcmp(pDb->zName, zDb) == 0) {
+      return db_index;
+    }
+  }
+  return 0;
+}
+
+SQLITE_API int sqlite3_key(sqlite3 *db, const void *pKey, int nKey) {
+  CODEC_TRACE(("sqlite3_key entered: db=%p pKey=%s nKey=%d\n", db, (char *)pKey, nKey));
+  return sqlite3_key_v2(db, "main", pKey, nKey);
+}
+
+SQLITE_API int sqlite3_key_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey) {
+  CODEC_TRACE(("sqlite3_key_v2: entered db=%p zDb=%s pKey=%s nKey=%d\n", db, zDb, (char *)pKey, nKey));
+  /* attach key if db and pKey are not null and nKey is > 0 */
+  if(db && pKey && nKey) {
+    int db_index = sqlcipher_find_db_index(db, zDb);
+    return sqlite3CodecAttach(db, db_index, pKey, nKey); 
+  }
+  return SQLITE_ERROR;
+}
+
+SQLITE_API int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) {
+  CODEC_TRACE(("sqlite3_rekey entered: db=%p pKey=%s nKey=%d\n", db, (char *)pKey, nKey));
+  return sqlite3_rekey_v2(db, "main", pKey, nKey);
+}
+
+/* sqlite3_rekey_v2
+** Given a database, this will reencrypt the database using a new key.
+** There is only one possible modes of operation - to encrypt a database
+** that is already encrpyted. If the database is not already encrypted
+** this should do nothing
+** The proposed logic for this function follows:
+** 1. Determine if the database is already encryptped
+** 2. If there is NOT already a key present do nothing
+** 3. If there is a key present, re-encrypt the database with the new key
+*/
+SQLITE_API int sqlite3_rekey_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey) {
+  CODEC_TRACE(("sqlite3_rekey_v2: entered db=%p zDb=%s pKey=%s, nKey=%d\n", db, zDb, (char *)pKey, nKey));
+  if(db && pKey && nKey) {
+    int db_index = sqlcipher_find_db_index(db, zDb);
+    struct Db *pDb = &db->aDb[db_index];
+    CODEC_TRACE(("sqlite3_rekey_v2: database pDb=%p db_index:%d\n", pDb, db_index));
+    if(pDb->pBt) {
+      codec_ctx *ctx;
+      int rc, page_count;
+      Pgno pgno;
+      PgHdr *page;
+      Pager *pPager = pDb->pBt->pBt->pPager;
+
+      sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
+     
+      if(ctx == NULL) { 
+        /* there was no codec attached to this database, so this should do nothing! */ 
+        CODEC_TRACE(("sqlite3_rekey_v2: no codec attached to db, exiting\n"));
+        return SQLITE_OK;
+      }
+
+      sqlite3_mutex_enter(db->mutex);
+
+      codec_set_pass_key(db, db_index, pKey, nKey, CIPHER_WRITE_CTX);
+    
+      /* do stuff here to rewrite the database 
+      ** 1. Create a transaction on the database
+      ** 2. Iterate through each page, reading it and then writing it.
+      ** 3. If that goes ok then commit and put ctx->rekey into ctx->key
+      **    note: don't deallocate rekey since it may be used in a subsequent iteration 
+      */
+      rc = sqlite3BtreeBeginTrans(pDb->pBt, 1); /* begin write transaction */
+      sqlite3PagerPagecount(pPager, &page_count);
+      for(pgno = 1; rc == SQLITE_OK && pgno <= (unsigned int)page_count; pgno++) { /* pgno's start at 1 see pager.c:pagerAcquire */
+        if(!sqlite3pager_is_mj_pgno(pPager, pgno)) { /* skip this page (see pager.c:pagerAcquire for reasoning) */
+          rc = sqlite3PagerGet(pPager, pgno, &page);
+          if(rc == SQLITE_OK) { /* write page see pager_incr_changecounter for example */
+            rc = sqlite3PagerWrite(page);
+            if(rc == SQLITE_OK) {
+              sqlite3PagerUnref(page);
+            } else {
+             CODEC_TRACE(("sqlite3_rekey_v2: error %d occurred writing page %d\n", rc, pgno));  
+            }
+          } else {
+             CODEC_TRACE(("sqlite3_rekey_v2: error %d occurred getting page %d\n", rc, pgno));  
+          }
+        } 
+      }
+
+      /* if commit was successful commit and copy the rekey data to current key, else rollback to release locks */
+      if(rc == SQLITE_OK) { 
+        CODEC_TRACE(("sqlite3_rekey_v2: committing\n"));
+        rc = sqlite3BtreeCommit(pDb->pBt); 
+        sqlcipher_codec_key_copy(ctx, CIPHER_WRITE_CTX);
+      } else {
+        CODEC_TRACE(("sqlite3_rekey_v2: rollback\n"));
+        sqlite3BtreeRollback(pDb->pBt, SQLITE_ABORT_ROLLBACK);
+      }
+
+      sqlite3_mutex_leave(db->mutex);
+    }
+    return SQLITE_OK;
+  }
+  return SQLITE_ERROR;
+}
+
+SQLITE_PRIVATE void sqlite3CodecGetKey(sqlite3* db, int nDb, void **zKey, int *nKey) {
+  struct Db *pDb = &db->aDb[nDb];
+  CODEC_TRACE(("sqlite3CodecGetKey: entered db=%p, nDb=%d\n", db, nDb));
+  if( pDb->pBt ) {
+    codec_ctx *ctx;
+    sqlite3pager_get_codec(pDb->pBt->pBt->pPager, (void **) &ctx);
+    if(ctx) { /* if the codec has an attached codec_context user the raw key data */
+      sqlcipher_codec_get_keyspec(ctx, zKey, nKey);
+    } else {
+      *zKey = NULL;
+      *nKey = 0;
+    }
+  }
+}
+
+#ifndef OMIT_EXPORT
+
+/*
+ * Implementation of an "export" function that allows a caller
+ * to duplicate the main database to an attached database. This is intended
+ * as a conveneince for users who need to:
+ * 
+ *   1. migrate from an non-encrypted database to an encrypted database
+ *   2. move from an encrypted database to a non-encrypted database
+ *   3. convert beween the various flavors of encrypted databases.  
+ *
+ * This implementation is based heavily on the procedure and code used
+ * in vacuum.c, but is exposed as a function that allows export to any
+ * named attached database.
+ */
+
+/*
+** Finalize a prepared statement.  If there was an error, store the
+** text of the error message in *pzErrMsg.  Return the result code.
+** 
+** Based on vacuumFinalize from vacuum.c
+*/
+static int sqlcipher_finalize(sqlite3 *db, sqlite3_stmt *pStmt, char **pzErrMsg){
+  int rc;
+  rc = sqlite3VdbeFinalize((Vdbe*)pStmt);
+  if( rc ){
+    sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
+  }
+  return rc;
+}
+
+/*
+** Execute zSql on database db. Return an error code.
+** 
+** Based on execSql from vacuum.c
+*/
+static int sqlcipher_execSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
+  sqlite3_stmt *pStmt;
+  VVA_ONLY( int rc; )
+  if( !zSql ){
+    return SQLITE_NOMEM;
+  }
+  if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
+    sqlite3SetString(pzErrMsg, db, sqlite3_errmsg(db));
+    return sqlite3_errcode(db);
+  }
+  VVA_ONLY( rc = ) sqlite3_step(pStmt);
+  assert( rc!=SQLITE_ROW );
+  return sqlcipher_finalize(db, pStmt, pzErrMsg);
+}
+
+/*
+** Execute zSql on database db. The statement returns exactly
+** one column. Execute this as SQL on the same database.
+** 
+** Based on execExecSql from vacuum.c
+*/
+static int sqlcipher_execExecSql(sqlite3 *db, char **pzErrMsg, const char *zSql){
+  sqlite3_stmt *pStmt;
+  int rc;
+
+  rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
+  if( rc!=SQLITE_OK ) return rc;
+
+  while( SQLITE_ROW==sqlite3_step(pStmt) ){
+    rc = sqlcipher_execSql(db, pzErrMsg, (char*)sqlite3_column_text(pStmt, 0));
+    if( rc!=SQLITE_OK ){
+      sqlcipher_finalize(db, pStmt, pzErrMsg);
+      return rc;
+    }
+  }
+
+  return sqlcipher_finalize(db, pStmt, pzErrMsg);
+}
+
+/*
+ * copy database and schema from the main database to an attached database
+ * 
+ * Based on sqlite3RunVacuum from vacuum.c
+*/
+void sqlcipher_exportFunc(sqlite3_context *context, int argc, sqlite3_value **argv) {
+  sqlite3 *db = sqlite3_context_db_handle(context);
+  const char* attachedDb = (const char*) sqlite3_value_text(argv[0]);
+  int saved_flags;        /* Saved value of the db->flags */
+  int saved_nChange;      /* Saved value of db->nChange */
+  int saved_nTotalChange; /* Saved value of db->nTotalChange */
+  void (*saved_xTrace)(void*,const char*);  /* Saved db->xTrace */
+  int rc = SQLITE_OK;     /* Return code from service routines */
+  char *zSql = NULL;         /* SQL statements */
+  char *pzErrMsg = NULL;
+  
+  saved_flags = db->flags;
+  saved_nChange = db->nChange;
+  saved_nTotalChange = db->nTotalChange;
+  saved_xTrace = db->xTrace;
+  db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
+  db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
+  db->xTrace = 0;
+
+  /* Query the schema of the main database. Create a mirror schema
+  ** in the temporary database.
+  */
+  zSql = sqlite3_mprintf(
+    "SELECT 'CREATE TABLE %s.' || substr(sql,14) "
+    "  FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
+    "   AND rootpage>0"
+  , attachedDb);
+  rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); 
+  if( rc!=SQLITE_OK ) goto end_of_export;
+  sqlite3_free(zSql);
+
+  zSql = sqlite3_mprintf(
+    "SELECT 'CREATE INDEX %s.' || substr(sql,14)"
+    "  FROM sqlite_master WHERE sql LIKE 'CREATE INDEX %%' "
+  , attachedDb);
+  rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); 
+  if( rc!=SQLITE_OK ) goto end_of_export;
+  sqlite3_free(zSql);
+
+  zSql = sqlite3_mprintf(
+    "SELECT 'CREATE UNIQUE INDEX %s.' || substr(sql,21) "
+    "  FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %%'"
+  , attachedDb);
+  rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); 
+  if( rc!=SQLITE_OK ) goto end_of_export;
+  sqlite3_free(zSql);
+
+  /* Loop through the tables in the main database. For each, do
+  ** an "INSERT INTO rekey_db.xxx SELECT * FROM main.xxx;" to copy
+  ** the contents to the temporary database.
+  */
+  zSql = sqlite3_mprintf(
+    "SELECT 'INSERT INTO %s.' || quote(name) "
+    "|| ' SELECT * FROM main.' || quote(name) || ';'"
+    "FROM main.sqlite_master "
+    "WHERE type = 'table' AND name!='sqlite_sequence' "
+    "  AND rootpage>0"
+  , attachedDb);
+  rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); 
+  if( rc!=SQLITE_OK ) goto end_of_export;
+  sqlite3_free(zSql);
+
+  /* Copy over the sequence table
+  */
+  zSql = sqlite3_mprintf(
+    "SELECT 'DELETE FROM %s.' || quote(name) || ';' "
+    "FROM %s.sqlite_master WHERE name='sqlite_sequence' "
+  , attachedDb, attachedDb);
+  rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); 
+  if( rc!=SQLITE_OK ) goto end_of_export;
+  sqlite3_free(zSql);
+
+  zSql = sqlite3_mprintf(
+    "SELECT 'INSERT INTO %s.' || quote(name) "
+    "|| ' SELECT * FROM main.' || quote(name) || ';' "
+    "FROM %s.sqlite_master WHERE name=='sqlite_sequence';"
+  , attachedDb, attachedDb);
+  rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execExecSql(db, &pzErrMsg, zSql); 
+  if( rc!=SQLITE_OK ) goto end_of_export;
+  sqlite3_free(zSql);
+
+  /* Copy the triggers, views, and virtual tables from the main database
+  ** over to the temporary database.  None of these objects has any
+  ** associated storage, so all we have to do is copy their entries
+  ** from the SQLITE_MASTER table.
+  */
+  zSql = sqlite3_mprintf(
+    "INSERT INTO %s.sqlite_master "
+    "  SELECT type, name, tbl_name, rootpage, sql"
+    "    FROM main.sqlite_master"
+    "   WHERE type='view' OR type='trigger'"
+    "      OR (type='table' AND rootpage=0)"
+  , attachedDb);
+  rc = (zSql == NULL) ? SQLITE_NOMEM : sqlcipher_execSql(db, &pzErrMsg, zSql); 
+  if( rc!=SQLITE_OK ) goto end_of_export;
+  sqlite3_free(zSql);
+
+  zSql = NULL;
+end_of_export:
+  db->flags = saved_flags;
+  db->nChange = saved_nChange;
+  db->nTotalChange = saved_nTotalChange;
+  db->xTrace = saved_xTrace;
+
+  sqlite3_free(zSql);
+
+  if(rc) {
+    if(pzErrMsg != NULL) {
+      sqlite3_result_error(context, pzErrMsg, -1);
+      sqlite3DbFree(db, pzErrMsg);
+    } else {
+      sqlite3_result_error(context, sqlite3ErrStr(rc), -1);
+    }
+  }
+}
+
+#endif
+
+/* END SQLCIPHER */
+#endif
+
+/************** End of crypto.c **********************************************/
+/************** Begin file crypto_impl.c *************************************/
+/* 
+** SQLCipher
+** http://sqlcipher.net
+** 
+** Copyright (c) 2008 - 2013, ZETETIC LLC
+** All rights reserved.
+** 
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**     * Redistributions of source code must retain the above copyright
+**       notice, this list of conditions and the following disclaimer.
+**     * Redistributions in binary form must reproduce the above copyright
+**       notice, this list of conditions and the following disclaimer in the
+**       documentation and/or other materials provided with the distribution.
+**     * Neither the name of the ZETETIC LLC nor the
+**       names of its contributors may be used to endorse or promote products
+**       derived from this software without specific prior written permission.
+** 
+** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
+** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**  
+*/
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+
+/************** Include sqlcipher.h in the middle of crypto_impl.c ***********/
+/************** Begin file sqlcipher.h ***************************************/
+/* 
+** SQLCipher
+** sqlcipher.h developed by Stephen Lombardo (Zetetic LLC) 
+** sjlombardo at zetetic dot net
+** http://zetetic.net
+** 
+** Copyright (c) 2008, ZETETIC LLC
+** All rights reserved.
+** 
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**     * Redistributions of source code must retain the above copyright
+**       notice, this list of conditions and the following disclaimer.
+**     * Redistributions in binary form must reproduce the above copyright
+**       notice, this list of conditions and the following disclaimer in the
+**       documentation and/or other materials provided with the distribution.
+**     * Neither the name of the ZETETIC LLC nor the
+**       names of its contributors may be used to endorse or promote products
+**       derived from this software without specific prior written permission.
+** 
+** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
+** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**  
+*/
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+#ifndef SQLCIPHER_H
+#define SQLCIPHER_H
+
+
+typedef struct {
+  int (*activate)(void *ctx);
+  int (*deactivate)(void *ctx);
+  const char* (*get_provider_name)(void *ctx);
+  int (*add_random)(void *ctx, void *buffer, int length);
+  int (*random)(void *ctx, void *buffer, int length);
+  int (*hmac)(void *ctx, unsigned char *hmac_key, int key_sz, unsigned char *in, int in_sz, unsigned char *in2, int in2_sz, unsigned char *out);
+  int (*kdf)(void *ctx, const unsigned char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key);
+  int (*cipher)(void *ctx, int mode, unsigned char *key, int key_sz, unsigned char *iv, unsigned char *in, int in_sz, unsigned char *out);
+  int (*set_cipher)(void *ctx, const char *cipher_name);
+  const char* (*get_cipher)(void *ctx);
+  int (*get_key_sz)(void *ctx);
+  int (*get_iv_sz)(void *ctx);
+  int (*get_block_sz)(void *ctx);
+  int (*get_hmac_sz)(void *ctx);
+  int (*ctx_copy)(void *target_ctx, void *source_ctx);
+  int (*ctx_cmp)(void *c1, void *c2);
+  int (*ctx_init)(void **ctx);
+  int (*ctx_free)(void **ctx);
+} sqlcipher_provider;
+
+/* utility functions */
+void sqlcipher_free(void *ptr, int sz);
+void* sqlcipher_malloc(int sz);
+void* sqlcipher_memset(void *v, unsigned char value, int len);
+int sqlcipher_ismemset(const void *v, unsigned char value, int len);
+int sqlcipher_memcmp(const void *v0, const void *v1, int len);
+void sqlcipher_free(void *, int);
+
+/* provider interfaces */
+int sqlcipher_register_provider(sqlcipher_provider *p);
+sqlcipher_provider* sqlcipher_get_provider();
+
+#endif
+#endif
+/* END SQLCIPHER */
+
+
+/************** End of sqlcipher.h *******************************************/
+/************** Continuing where we left off in crypto_impl.c ****************/
+#ifndef OMIT_MEMLOCK
+#if defined(__unix__) || defined(__APPLE__) 
+#include <sys/mman.h>
+#elif defined(_WIN32)
+/* # include <windows.h> */
+#endif
+#endif
+
+/* the default implementation of SQLCipher uses a cipher_ctx
+   to keep track of read / write state separately. The following
+   struct and associated functions are defined here */
+typedef struct {
+  int derive_key;
+  int kdf_iter;
+  int fast_kdf_iter;
+  int key_sz;
+  int iv_sz;
+  int block_sz;
+  int pass_sz;
+  int reserve_sz;
+  int hmac_sz;
+  int keyspec_sz;
+  unsigned int flags;
+  unsigned char *key;
+  unsigned char *hmac_key;
+  unsigned char *pass;
+  char *keyspec;
+  sqlcipher_provider *provider;
+  void *provider_ctx;
+} cipher_ctx;
+
+static unsigned int default_flags = DEFAULT_CIPHER_FLAGS;
+static unsigned char hmac_salt_mask = HMAC_SALT_MASK;
+static int default_kdf_iter = PBKDF2_ITER;
+static unsigned int sqlcipher_activate_count = 0;
+static sqlite3_mutex* sqlcipher_provider_mutex = NULL;
+static sqlcipher_provider *default_provider = NULL;
+
+struct codec_ctx {
+  int kdf_salt_sz;
+  int page_sz;
+  unsigned char *kdf_salt;
+  unsigned char *hmac_kdf_salt;
+  unsigned char *buffer;
+  Btree *pBt;
+  cipher_ctx *read_ctx;
+  cipher_ctx *write_ctx;
+  unsigned int skip_read_hmac;
+};
+
+int sqlcipher_register_provider(sqlcipher_provider *p) {
+  sqlite3_mutex_enter(sqlcipher_provider_mutex);
+  if(default_provider != NULL && default_provider != p) {
+    /* only free the current registerd provider if it has been initialized
+       and it isn't a pointer to the same provider passed to the function
+       (i.e. protect against a caller calling register twice for the same provider) */
+    sqlcipher_free(default_provider, sizeof(sqlcipher_provider));
+  }
+  default_provider = p;   
+  sqlite3_mutex_leave(sqlcipher_provider_mutex);
+  return SQLITE_OK;
+}
+
+/* return a pointer to the currently registered provider. This will
+   allow an application to fetch the current registered provider and
+   make minor changes to it */
+sqlcipher_provider* sqlcipher_get_provider() {
+  return default_provider;
+}
+
+void sqlcipher_activate() {
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+
+  if(sqlcipher_provider_mutex == NULL) {
+    /* allocate a new mutex to guard access to the provider */
+    sqlcipher_provider_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+  }
+
+  /* check to see if there is a provider registered at this point
+     if there no provider registered at this point, register the 
+     default provider */
+  if(sqlcipher_get_provider() == NULL) {
+    sqlcipher_provider *p = sqlcipher_malloc(sizeof(sqlcipher_provider)); 
+#if defined (SQLCIPHER_CRYPTO_CC)
+    extern int sqlcipher_cc_setup(sqlcipher_provider *p);
+    sqlcipher_cc_setup(p);
+#elif defined (SQLCIPHER_CRYPTO_LIBTOMCRYPT)
+    extern int sqlcipher_ltc_setup(sqlcipher_provider *p);
+    sqlcipher_ltc_setup(p);
+#elif defined (SQLCIPHER_CRYPTO_OPENSSL)
+    extern int sqlcipher_openssl_setup(sqlcipher_provider *p);
+    sqlcipher_openssl_setup(p);
+#else
+#error "NO DEFAULT SQLCIPHER CRYPTO PROVIDER DEFINED"
+#endif
+    sqlcipher_register_provider(p);
+  }
+
+  sqlcipher_activate_count++; /* increment activation count */
+
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+
+void sqlcipher_deactivate() {
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  sqlcipher_activate_count--;
+  /* if no connections are using sqlcipher, cleanup globals */
+  if(sqlcipher_activate_count < 1) {
+    sqlite3_mutex_enter(sqlcipher_provider_mutex);
+    if(default_provider != NULL) {
+      sqlcipher_free(default_provider, sizeof(sqlcipher_provider));
+      default_provider = NULL;
+    }
+    sqlite3_mutex_leave(sqlcipher_provider_mutex);
+    
+    /* last connection closed, free provider mutex*/
+    sqlite3_mutex_free(sqlcipher_provider_mutex); 
+    sqlcipher_provider_mutex = NULL;
+
+    sqlcipher_activate_count = 0; /* reset activation count */
+  }
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+}
+
+/* constant time memset using volitile to avoid having the memset
+   optimized out by the compiler. 
+   Note: As suggested by Joachim Schipper (joachim.schipper@fox-it.com)
+*/
+void* sqlcipher_memset(void *v, unsigned char value, int len) {
+  int i = 0;
+  volatile unsigned char *a = v;
+
+  if (v == NULL) return v;
+
+  for(i = 0; i < len; i++) {
+    a[i] = value;
+  }
+
+  return v;
+}
+
+/* constant time memory check tests every position of a memory segement
+   matches a single value (i.e. the memory is all zeros)
+   returns 0 if match, 1 of no match */
+int sqlcipher_ismemset(const void *v, unsigned char value, int len) {
+  const unsigned char *a = v;
+  int i = 0, result = 0;
+
+  for(i = 0; i < len; i++) {
+    result |= a[i] ^ value;
+  }
+
+  return (result != 0);
+}
+
+/* constant time memory comparison routine. 
+   returns 0 if match, 1 if no match */
+int sqlcipher_memcmp(const void *v0, const void *v1, int len) {
+  const unsigned char *a0 = v0, *a1 = v1;
+  int i = 0, result = 0;
+
+  for(i = 0; i < len; i++) {
+    result |= a0[i] ^ a1[i];
+  }
+  
+  return (result != 0);
+}
+
+/**
+  * Free and wipe memory. Uses SQLites internal sqlite3_free so that memory
+  * can be countend and memory leak detection works in the test suite. 
+  * If ptr is not null memory will be freed. 
+  * If sz is greater than zero, the memory will be overwritten with zero before it is freed
+  * If sz is > 0, and not compiled with OMIT_MEMLOCK, system will attempt to unlock the
+  * memory segment so it can be paged
+  */
+void sqlcipher_free(void *ptr, int sz) {
+  if(ptr) {
+    if(sz > 0) {
+      sqlcipher_memset(ptr, 0, sz);
+#ifndef OMIT_MEMLOCK
+#if defined(__unix__) || defined(__APPLE__) 
+      munlock(ptr, sz);
+#elif defined(_WIN32)
+#if !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP))
+VirtualUnlock(ptr, sz);
+#endif
+#endif
+#endif
+    }
+    sqlite3_free(ptr);
+  }
+}
+
+/**
+  * allocate memory. Uses sqlite's internall malloc wrapper so memory can be 
+  * reference counted and leak detection works. Unless compiled with OMIT_MEMLOCK
+  * attempts to lock the memory pages so sensitive information won't be swapped
+  */
+void* sqlcipher_malloc(int sz) {
+  void *ptr = sqlite3Malloc(sz);
+  sqlcipher_memset(ptr, 0, sz);
+#ifndef OMIT_MEMLOCK
+  if(ptr) {
+#if defined(__unix__) || defined(__APPLE__) 
+    mlock(ptr, sz);
+#elif defined(_WIN32)
+#if !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP))
+    VirtualLock(ptr, sz);
+#endif
+#endif
+  }
+#endif
+  return ptr;
+}
+
+
+/**
+  * Initialize new cipher_ctx struct. This function will allocate memory
+  * for the cipher context and for the key
+  * 
+  * returns SQLITE_OK if initialization was successful
+  * returns SQLITE_NOMEM if an error occured allocating memory
+  */
+static int sqlcipher_cipher_ctx_init(cipher_ctx **iCtx) {
+  int rc;
+  cipher_ctx *ctx;
+  *iCtx = (cipher_ctx *) sqlcipher_malloc(sizeof(cipher_ctx));
+  ctx = *iCtx;
+  if(ctx == NULL) return SQLITE_NOMEM;
+
+  ctx->provider = (sqlcipher_provider *) sqlcipher_malloc(sizeof(sqlcipher_provider));
+  if(ctx->provider == NULL) return SQLITE_NOMEM;
+
+  /* make a copy of the provider to be used for the duration of the context */
+  sqlite3_mutex_enter(sqlcipher_provider_mutex);
+  memcpy(ctx->provider, default_provider, sizeof(sqlcipher_provider));
+  sqlite3_mutex_leave(sqlcipher_provider_mutex);
+
+  if((rc = ctx->provider->ctx_init(&ctx->provider_ctx)) != SQLITE_OK) return rc;
+  ctx->key = (unsigned char *) sqlcipher_malloc(CIPHER_MAX_KEY_SZ);
+  ctx->hmac_key = (unsigned char *) sqlcipher_malloc(CIPHER_MAX_KEY_SZ);
+  if(ctx->key == NULL) return SQLITE_NOMEM;
+  if(ctx->hmac_key == NULL) return SQLITE_NOMEM;
+
+  /* setup default flags */
+  ctx->flags = default_flags;
+
+  return SQLITE_OK;
+}
+
+/**
+  * Free and wipe memory associated with a cipher_ctx
+  */
+static void sqlcipher_cipher_ctx_free(cipher_ctx **iCtx) {
+  cipher_ctx *ctx = *iCtx;
+  CODEC_TRACE(("cipher_ctx_free: entered iCtx=%p\n", iCtx));
+  ctx->provider->ctx_free(&ctx->provider_ctx);
+  sqlcipher_free(ctx->provider, sizeof(sqlcipher_provider)); 
+  sqlcipher_free(ctx->key, ctx->key_sz);
+  sqlcipher_free(ctx->hmac_key, ctx->key_sz);
+  sqlcipher_free(ctx->pass, ctx->pass_sz);
+  sqlcipher_free(ctx->keyspec, ctx->keyspec_sz);
+  sqlcipher_free(ctx, sizeof(cipher_ctx)); 
+}
+
+/**
+  * Compare one cipher_ctx to another.
+  *
+  * returns 0 if all the parameters (except the derived key data) are the same
+  * returns 1 otherwise
+  */
+static int sqlcipher_cipher_ctx_cmp(cipher_ctx *c1, cipher_ctx *c2) {
+  CODEC_TRACE(("sqlcipher_cipher_ctx_cmp: entered c1=%p c2=%p\n", c1, c2));
+
+  if(
+    c1->iv_sz == c2->iv_sz
+    && c1->kdf_iter == c2->kdf_iter
+    && c1->fast_kdf_iter == c2->fast_kdf_iter
+    && c1->key_sz == c2->key_sz
+    && c1->pass_sz == c2->pass_sz
+    && c1->flags == c2->flags
+    && c1->hmac_sz == c2->hmac_sz
+    && c1->provider->ctx_cmp(c1->provider_ctx, c2->provider_ctx) 
+    && (
+      c1->pass == c2->pass
+      || !sqlcipher_memcmp((const unsigned char*)c1->pass,
+                           (const unsigned char*)c2->pass,
+                           c1->pass_sz)
+    ) 
+  ) return 0;
+  return 1;
+}
+
+/**
+  * Copy one cipher_ctx to another. For instance, assuming that read_ctx is a 
+  * fully initialized context, you could copy it to write_ctx and all yet data
+  * and pass information across
+  *
+  * returns SQLITE_OK if initialization was successful
+  * returns SQLITE_NOMEM if an error occured allocating memory
+  */
+static int sqlcipher_cipher_ctx_copy(cipher_ctx *target, cipher_ctx *source) {
+  void *key = target->key; 
+  void *hmac_key = target->hmac_key; 
+  void *provider = target->provider;
+  void *provider_ctx = target->provider_ctx;
+
+  CODEC_TRACE(("sqlcipher_cipher_ctx_copy: entered target=%p, source=%p\n", target, source));
+  sqlcipher_free(target->pass, target->pass_sz); 
+  sqlcipher_free(target->keyspec, target->keyspec_sz); 
+  memcpy(target, source, sizeof(cipher_ctx));
+
+  target->key = key; //restore pointer to previously allocated key data
+  memcpy(target->key, source->key, CIPHER_MAX_KEY_SZ);
+
+  target->hmac_key = hmac_key; //restore pointer to previously allocated hmac key data
+  memcpy(target->hmac_key, source->hmac_key, CIPHER_MAX_KEY_SZ);
+
+  target->provider = provider; // restore pointer to previouly allocated provider;
+  memcpy(target->provider, source->provider, sizeof(sqlcipher_provider));
+
+  target->provider_ctx = provider_ctx; // restore pointer to previouly allocated provider context;
+  target->provider->ctx_copy(target->provider_ctx, source->provider_ctx);
+
+  if(source->pass && source->pass_sz) {
+    target->pass = sqlcipher_malloc(source->pass_sz);
+    if(target->pass == NULL) return SQLITE_NOMEM;
+    memcpy(target->pass, source->pass, source->pass_sz);
+  }
+  if(source->keyspec && source->keyspec_sz) {
+    target->keyspec = sqlcipher_malloc(source->keyspec_sz);
+    if(target->keyspec == NULL) return SQLITE_NOMEM;
+    memcpy(target->keyspec, source->keyspec, source->keyspec_sz);
+  }
+  return SQLITE_OK;
+}
+
+/**
+  * Set the keyspec for the cipher_ctx
+  * 
+  * returns SQLITE_OK if assignment was successfull
+  * returns SQLITE_NOMEM if an error occured allocating memory
+  */
+static int sqlcipher_cipher_ctx_set_keyspec(cipher_ctx *ctx, const unsigned char *key, int key_sz, const unsigned char *salt, int salt_sz) {
+
+    /* free, zero existing pointers and size */
+  sqlcipher_free(ctx->keyspec, ctx->keyspec_sz);
+  ctx->keyspec = NULL;
+  ctx->keyspec_sz = 0;
+
+  /* establic a hex-formated key specification, containing the raw encryption key and
+     the salt used to generate it */
+  ctx->keyspec_sz = ((key_sz + salt_sz) * 2) + 3;
+  ctx->keyspec = sqlcipher_malloc(ctx->keyspec_sz);
+  if(ctx->keyspec == NULL) return SQLITE_NOMEM;
+
+  ctx->keyspec[0] = 'x';
+  ctx->keyspec[1] = '\'';
+  cipher_bin2hex(key, key_sz, ctx->keyspec + 2);
+  cipher_bin2hex(salt, salt_sz, ctx->keyspec + (key_sz * 2) + 2);
+  ctx->keyspec[ctx->keyspec_sz - 1] = '\'';
+  return SQLITE_OK;
+}
+
+/**
+  * Set the passphrase for the cipher_ctx
+  * 
+  * returns SQLITE_OK if assignment was successfull
+  * returns SQLITE_NOMEM if an error occured allocating memory
+  */
+static int sqlcipher_cipher_ctx_set_pass(cipher_ctx *ctx, const void *zKey, int nKey) {
+
+  /* free, zero existing pointers and size */
+  sqlcipher_free(ctx->pass, ctx->pass_sz);
+  ctx->pass = NULL;
+  ctx->pass_sz = 0;
+
+  if(zKey && nKey) { /* if new password is provided, copy it */
+    ctx->pass_sz = nKey;
+    ctx->pass = sqlcipher_malloc(nKey);
+    if(ctx->pass == NULL) return SQLITE_NOMEM;
+    memcpy(ctx->pass, zKey, nKey);
+  } 
+  return SQLITE_OK;
+}
+
+int sqlcipher_codec_ctx_set_pass(codec_ctx *ctx, const void *zKey, int nKey, int for_ctx) {
+  cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+  int rc;
+
+  if((rc = sqlcipher_cipher_ctx_set_pass(c_ctx, zKey, nKey)) != SQLITE_OK) return rc; 
+  c_ctx->derive_key = 1;
+
+  if(for_ctx == 2)
+    if((rc = sqlcipher_cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK) 
+      return rc; 
+
+  return SQLITE_OK;
+} 
+
+int sqlcipher_codec_ctx_set_cipher(codec_ctx *ctx, const char *cipher_name, int for_ctx) {
+  cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+  int rc;
+
+  c_ctx->provider->set_cipher(c_ctx->provider_ctx, cipher_name);
+
+  c_ctx->key_sz = c_ctx->provider->get_key_sz(c_ctx->provider_ctx);
+  c_ctx->iv_sz = c_ctx->provider->get_iv_sz(c_ctx->provider_ctx);
+  c_ctx->block_sz = c_ctx->provider->get_block_sz(c_ctx->provider_ctx);
+  c_ctx->hmac_sz = c_ctx->provider->get_hmac_sz(c_ctx->provider_ctx);
+  c_ctx->derive_key = 1;
+
+  if(for_ctx == 2)
+    if((rc = sqlcipher_cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK)
+      return rc; 
+
+  return SQLITE_OK;
+}
+
+const char* sqlcipher_codec_ctx_get_cipher(codec_ctx *ctx, int for_ctx) {
+  cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+  return c_ctx->provider->get_cipher(c_ctx->provider_ctx);
+}
+
+/* set the global default KDF iteration */
+void sqlcipher_set_default_kdf_iter(int iter) {
+  default_kdf_iter = iter; 
+}
+
+int sqlcipher_get_default_kdf_iter() {
+  return default_kdf_iter;
+}
+
+int sqlcipher_codec_ctx_set_kdf_iter(codec_ctx *ctx, int kdf_iter, int for_ctx) {
+  cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+  int rc;
+
+  c_ctx->kdf_iter = kdf_iter;
+  c_ctx->derive_key = 1;
+
+  if(for_ctx == 2)
+    if((rc = sqlcipher_cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK)
+      return rc; 
+
+  return SQLITE_OK;
+}
+
+int sqlcipher_codec_ctx_get_kdf_iter(codec_ctx *ctx, int for_ctx) {
+  cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+  return c_ctx->kdf_iter;
+}
+
+int sqlcipher_codec_ctx_set_fast_kdf_iter(codec_ctx *ctx, int fast_kdf_iter, int for_ctx) {
+  cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+  int rc;
+
+  c_ctx->fast_kdf_iter = fast_kdf_iter;
+  c_ctx->derive_key = 1;
+
+  if(for_ctx == 2)
+    if((rc = sqlcipher_cipher_ctx_copy( for_ctx ? ctx->read_ctx : ctx->write_ctx, c_ctx)) != SQLITE_OK)
+      return rc; 
+
+  return SQLITE_OK;
+}
+
+int sqlcipher_codec_ctx_get_fast_kdf_iter(codec_ctx *ctx, int for_ctx) {
+  cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+  return c_ctx->fast_kdf_iter;
+}
+
+/* set the global default flag for HMAC */
+void sqlcipher_set_default_use_hmac(int use) {
+  if(use) default_flags |= CIPHER_FLAG_HMAC; 
+  else default_flags &= ~CIPHER_FLAG_HMAC; 
+}
+
+int sqlcipher_get_default_use_hmac() {
+  return (default_flags & CIPHER_FLAG_HMAC) != 0;
+}
+
+void sqlcipher_set_hmac_salt_mask(unsigned char mask) {
+  hmac_salt_mask = mask;
+}
+
+unsigned char sqlcipher_get_hmac_salt_mask() {
+  return hmac_salt_mask;
+}
+
+/* set the codec flag for whether this individual database should be using hmac */
+int sqlcipher_codec_ctx_set_use_hmac(codec_ctx *ctx, int use) {
+  int reserve = CIPHER_MAX_IV_SZ; /* base reserve size will be IV only */ 
+
+  if(use) reserve += ctx->read_ctx->hmac_sz; /* if reserve will include hmac, update that size */
+
+  /* calculate the amount of reserve needed in even increments of the cipher block size */
+
+  reserve = ((reserve % ctx->read_ctx->block_sz) == 0) ? reserve :
+               ((reserve / ctx->read_ctx->block_sz) + 1) * ctx->read_ctx->block_sz;  
+
+  CODEC_TRACE(("sqlcipher_codec_ctx_set_use_hmac: use=%d block_sz=%d md_size=%d reserve=%d\n", 
+                use, ctx->read_ctx->block_sz, ctx->read_ctx->hmac_sz, reserve)); 
+
+  
+  if(use) {
+    sqlcipher_codec_ctx_set_flag(ctx, CIPHER_FLAG_HMAC);
+  } else {
+    sqlcipher_codec_ctx_unset_flag(ctx, CIPHER_FLAG_HMAC);
+  } 
+  
+  ctx->write_ctx->reserve_sz = ctx->read_ctx->reserve_sz = reserve;
+
+  return SQLITE_OK;
+}
+
+int sqlcipher_codec_ctx_get_use_hmac(codec_ctx *ctx, int for_ctx) {
+  cipher_ctx * c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+  return (c_ctx->flags & CIPHER_FLAG_HMAC) != 0;
+}
+
+int sqlcipher_codec_ctx_set_flag(codec_ctx *ctx, unsigned int flag) {
+  ctx->write_ctx->flags |= flag;
+  ctx->read_ctx->flags |= flag;
+  return SQLITE_OK;
+}
+
+int sqlcipher_codec_ctx_unset_flag(codec_ctx *ctx, unsigned int flag) {
+  ctx->write_ctx->flags &= ~flag;
+  ctx->read_ctx->flags &= ~flag;
+  return SQLITE_OK;
+}
+
+int sqlcipher_codec_ctx_get_flag(codec_ctx *ctx, unsigned int flag, int for_ctx) {
+  cipher_ctx * c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+  return (c_ctx->flags & flag) != 0;
+}
+
+void sqlcipher_codec_ctx_set_error(codec_ctx *ctx, int error) {
+  CODEC_TRACE(("sqlcipher_codec_ctx_set_error: ctx=%p, error=%d\n", ctx, error));
+  sqlite3pager_sqlite3PagerSetError(ctx->pBt->pBt->pPager, error);
+  ctx->pBt->pBt->db->errCode = error;
+}
+
+int sqlcipher_codec_ctx_get_reservesize(codec_ctx *ctx) {
+  return ctx->read_ctx->reserve_sz;
+}
+
+void* sqlcipher_codec_ctx_get_data(codec_ctx *ctx) {
+  return ctx->buffer;
+}
+
+void* sqlcipher_codec_ctx_get_kdf_salt(codec_ctx *ctx) {
+  return ctx->kdf_salt;
+}
+
+void sqlcipher_codec_get_keyspec(codec_ctx *ctx, void **zKey, int *nKey) {
+  *zKey = ctx->read_ctx->keyspec;
+  *nKey = ctx->read_ctx->keyspec_sz;
+}
+
+int sqlcipher_codec_ctx_set_pagesize(codec_ctx *ctx, int size) {
+  /* attempt to free the existing page buffer */
+  sqlcipher_free(ctx->buffer,ctx->page_sz);
+  ctx->page_sz = size;
+
+  /* pre-allocate a page buffer of PageSize bytes. This will
+     be used as a persistent buffer for encryption and decryption 
+     operations to avoid overhead of multiple memory allocations*/
+  ctx->buffer = sqlcipher_malloc(size);
+  if(ctx->buffer == NULL) return SQLITE_NOMEM;
+
+  return SQLITE_OK;
+}
+
+int sqlcipher_codec_ctx_get_pagesize(codec_ctx *ctx) {
+  return ctx->page_sz;
+}
+
+int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_file *fd, const void *zKey, int nKey) {
+  int rc;
+  codec_ctx *ctx;
+  *iCtx = sqlcipher_malloc(sizeof(codec_ctx));
+  ctx = *iCtx;
+
+  if(ctx == NULL) return SQLITE_NOMEM;
+
+  ctx->pBt = pDb->pBt; /* assign pointer to database btree structure */
+
+  /* allocate space for salt data. Then read the first 16 bytes 
+       directly off the database file. This is the salt for the
+       key derivation function. If we get a short read allocate
+       a new random salt value */
+  ctx->kdf_salt_sz = FILE_HEADER_SZ;
+  ctx->kdf_salt = sqlcipher_malloc(ctx->kdf_salt_sz);
+  if(ctx->kdf_salt == NULL) return SQLITE_NOMEM;
+
+  /* allocate space for separate hmac salt data. We want the
+     HMAC derivation salt to be different than the encryption
+     key derivation salt */
+  ctx->hmac_kdf_salt = sqlcipher_malloc(ctx->kdf_salt_sz);
+  if(ctx->hmac_kdf_salt == NULL) return SQLITE_NOMEM;
+
+
+  /*
+     Always overwrite page size and set to the default because the first page of the database
+     in encrypted and thus sqlite can't effectively determine the pagesize. this causes an issue in 
+     cases where bytes 16 & 17 of the page header are a power of 2 as reported by John Lehman
+  */
+  if((rc = sqlcipher_codec_ctx_set_pagesize(ctx, SQLITE_DEFAULT_PAGE_SIZE)) != SQLITE_OK) return rc;
+
+  if((rc = sqlcipher_cipher_ctx_init(&ctx->read_ctx)) != SQLITE_OK) return rc; 
+  if((rc = sqlcipher_cipher_ctx_init(&ctx->write_ctx)) != SQLITE_OK) return rc; 
+
+  if(fd == NULL || sqlite3OsRead(fd, ctx->kdf_salt, FILE_HEADER_SZ, 0) != SQLITE_OK) {
+    /* if unable to read the bytes, generate random salt */
+    if(ctx->read_ctx->provider->random(ctx->read_ctx->provider_ctx, ctx->kdf_salt, FILE_HEADER_SZ) != SQLITE_OK) return SQLITE_ERROR;
+  }
+
+  if((rc = sqlcipher_codec_ctx_set_cipher(ctx, CIPHER, 0)) != SQLITE_OK) return rc;
+  if((rc = sqlcipher_codec_ctx_set_kdf_iter(ctx, default_kdf_iter, 0)) != SQLITE_OK) return rc;
+  if((rc = sqlcipher_codec_ctx_set_fast_kdf_iter(ctx, FAST_PBKDF2_ITER, 0)) != SQLITE_OK) return rc;
+  if((rc = sqlcipher_codec_ctx_set_pass(ctx, zKey, nKey, 0)) != SQLITE_OK) return rc;
+
+  /* Note that use_hmac is a special case that requires recalculation of page size
+     so we call set_use_hmac to perform setup */
+  if((rc = sqlcipher_codec_ctx_set_use_hmac(ctx, default_flags & CIPHER_FLAG_HMAC)) != SQLITE_OK) return rc;
+
+  if((rc = sqlcipher_cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx)) != SQLITE_OK) return rc;
+
+  return SQLITE_OK;
+}
+
+/**
+  * Free and wipe memory associated with a cipher_ctx, including the allocated
+  * read_ctx and write_ctx.
+  */
+void sqlcipher_codec_ctx_free(codec_ctx **iCtx) {
+  codec_ctx *ctx = *iCtx;
+  CODEC_TRACE(("codec_ctx_free: entered iCtx=%p\n", iCtx));
+  sqlcipher_free(ctx->kdf_salt, ctx->kdf_salt_sz);
+  sqlcipher_free(ctx->hmac_kdf_salt, ctx->kdf_salt_sz);
+  sqlcipher_free(ctx->buffer, 0);
+  sqlcipher_cipher_ctx_free(&ctx->read_ctx);
+  sqlcipher_cipher_ctx_free(&ctx->write_ctx);
+  sqlcipher_free(ctx, sizeof(codec_ctx)); 
+}
+
+/** convert a 32bit unsigned integer to little endian byte ordering */
+static void sqlcipher_put4byte_le(unsigned char *p, u32 v) { 
+  p[0] = (u8)v;
+  p[1] = (u8)(v>>8);
+  p[2] = (u8)(v>>16);
+  p[3] = (u8)(v>>24);
+}
+
+static int sqlcipher_page_hmac(cipher_ctx *ctx, Pgno pgno, unsigned char *in, int in_sz, unsigned char *out) {
+  unsigned char pgno_raw[sizeof(pgno)];
+  /* we may convert page number to consistent representation before calculating MAC for
+     compatibility across big-endian and little-endian platforms. 
+
+     Note: The public release of sqlcipher 2.0.0 to 2.0.6 had a bug where the bytes of pgno 
+     were used directly in the MAC. SQLCipher convert's to little endian by default to preserve
+     backwards compatibility on the most popular platforms, but can optionally be configured
+     to use either big endian or native byte ordering via pragma. */
+
+  if(ctx->flags & CIPHER_FLAG_LE_PGNO) { /* compute hmac using little endian pgno*/
+    sqlcipher_put4byte_le(pgno_raw, pgno);
+  } else if(ctx->flags & CIPHER_FLAG_BE_PGNO) { /* compute hmac using big endian pgno */
+    sqlite3Put4byte(pgno_raw, pgno); /* sqlite3Put4byte converts 32bit uint to big endian  */
+  } else { /* use native byte ordering */
+    memcpy(pgno_raw, &pgno, sizeof(pgno));
+  }
+
+  /* include the encrypted page data,  initialization vector, and page number in HMAC. This will 
+     prevent both tampering with the ciphertext, manipulation of the IV, or resequencing otherwise
+     valid pages out of order in a database */ 
+  ctx->provider->hmac(
+    ctx->provider_ctx, ctx->hmac_key,
+    ctx->key_sz, in,
+    in_sz, (unsigned char*) &pgno_raw,
+    sizeof(pgno), out);
+  return SQLITE_OK; 
+}
+
+/*
+ * ctx - codec context
+ * pgno - page number in database
+ * size - size in bytes of input and output buffers
+ * mode - 1 to encrypt, 0 to decrypt
+ * in - pointer to input bytes
+ * out - pouter to output bytes
+ */
+int sqlcipher_page_cipher(codec_ctx *ctx, int for_ctx, Pgno pgno, int mode, int page_sz, unsigned char *in, unsigned char *out) {
+  cipher_ctx *c_ctx = for_ctx ? ctx->write_ctx : ctx->read_ctx;
+  unsigned char *iv_in, *iv_out, *hmac_in, *hmac_out, *out_start;
+  int size;
+
+  /* calculate some required positions into various buffers */
+  size = page_sz - c_ctx->reserve_sz; /* adjust size to useable size and memset reserve at end of page */
+  iv_out = out + size;
+  iv_in = in + size;
+
+  /* hmac will be written immediately after the initialization vector. the remainder of the page reserve will contain
+     random bytes. note, these pointers are only valid when using hmac */
+  hmac_in = in + size + c_ctx->iv_sz; 
+  hmac_out = out + size + c_ctx->iv_sz;
+  out_start = out; /* note the original position of the output buffer pointer, as out will be rewritten during encryption */
+
+  CODEC_TRACE(("codec_cipher:entered pgno=%d, mode=%d, size=%d\n", pgno, mode, size));
+  CODEC_HEXDUMP("codec_cipher: input page data", in, page_sz);
+
+  /* the key size should never be zero. If it is, error out. */
+  if(c_ctx->key_sz == 0) {
+    CODEC_TRACE(("codec_cipher: error possible context corruption, key_sz is zero for pgno=%d\n", pgno));
+    sqlcipher_memset(out, 0, page_sz); 
+    return SQLITE_ERROR;
+  } 
+
+  if(mode == CIPHER_ENCRYPT) {
+    /* start at front of the reserve block, write random data to the end */
+    if(c_ctx->provider->random(c_ctx->provider_ctx, iv_out, c_ctx->reserve_sz) != SQLITE_OK) return SQLITE_ERROR; 
+  } else { /* CIPHER_DECRYPT */
+    memcpy(iv_out, iv_in, c_ctx->iv_sz); /* copy the iv from the input to output buffer */
+  } 
+
+  if((c_ctx->flags & CIPHER_FLAG_HMAC) && (mode == CIPHER_DECRYPT) && !ctx->skip_read_hmac) {
+    if(sqlcipher_page_hmac(c_ctx, pgno, in, size + c_ctx->iv_sz, hmac_out) != SQLITE_OK) {
+      sqlcipher_memset(out, 0, page_sz); 
+      CODEC_TRACE(("codec_cipher: hmac operations failed for pgno=%d\n", pgno));
+      return SQLITE_ERROR;
+    }
+
+    CODEC_TRACE(("codec_cipher: comparing hmac on in=%p out=%p hmac_sz=%d\n", hmac_in, hmac_out, c_ctx->hmac_sz));
+    if(sqlcipher_memcmp(hmac_in, hmac_out, c_ctx->hmac_sz) != 0) { /* the hmac check failed */ 
+      if(sqlcipher_ismemset(in, 0, page_sz) == 0) {
+        /* first check if the entire contents of the page is zeros. If so, this page 
+           resulted from a short read (i.e. sqlite attempted to pull a page after the end of the file. these 
+           short read failures must be ignored for autovaccum mode to work so wipe the output buffer 
+           and return SQLITE_OK to skip the decryption step. */
+        CODEC_TRACE(("codec_cipher: zeroed page (short read) for pgno %d, encryption but returning SQLITE_OK\n", pgno));
+        sqlcipher_memset(out, 0, page_sz); 
+  	return SQLITE_OK;
+      } else {
+	/* if the page memory is not all zeros, it means the there was data and a hmac on the page. 
+           since the check failed, the page was either tampered with or corrupted. wipe the output buffer,
+           and return SQLITE_ERROR to the caller */
+      	CODEC_TRACE(("codec_cipher: hmac check failed for pgno=%d returning SQLITE_ERROR\n", pgno));
+        sqlcipher_memset(out, 0, page_sz); 
+      	return SQLITE_ERROR;
+      }
+    }
+  } 
+  
+  c_ctx->provider->cipher(c_ctx->provider_ctx, mode, c_ctx->key, c_ctx->key_sz, iv_out, in, size, out);
+
+  if((c_ctx->flags & CIPHER_FLAG_HMAC) && (mode == CIPHER_ENCRYPT)) {
+    sqlcipher_page_hmac(c_ctx, pgno, out_start, size + c_ctx->iv_sz, hmac_out); 
+  }
+
+  CODEC_HEXDUMP("codec_cipher: output page data", out_start, page_sz);
+
+  return SQLITE_OK;
+}
+
+/**
+  * Derive an encryption key for a cipher contex key based on the raw password.
+  *
+  * If the raw key data is formated as x'hex' and there are exactly enough hex chars to fill
+  * the key (i.e 64 hex chars for a 256 bit key) then the key data will be used directly. 
+
+  * Else, if the raw key data is formated as x'hex' and there are exactly enough hex chars to fill
+  * the key and the salt (i.e 92 hex chars for a 256 bit key and 16 byte salt) then it will be unpacked
+  * as the key followed by the salt.
+  * 
+  * Otherwise, a key data will be derived using PBKDF2
+  * 
+  * returns SQLITE_OK if initialization was successful
+  * returns SQLITE_ERROR if the key could't be derived (for instance if pass is NULL or pass_sz is 0)
+  */
+static int sqlcipher_cipher_ctx_key_derive(codec_ctx *ctx, cipher_ctx *c_ctx) {
+  int rc;
+  CODEC_TRACE(("cipher_ctx_key_derive: entered c_ctx->pass=%s, c_ctx->pass_sz=%d \
+                ctx->kdf_salt=%p ctx->kdf_salt_sz=%d c_ctx->kdf_iter=%d \
+                ctx->hmac_kdf_salt=%p, c_ctx->fast_kdf_iter=%d c_ctx->key_sz=%d\n", 
+                c_ctx->pass, c_ctx->pass_sz, ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->kdf_iter, 
+                ctx->hmac_kdf_salt, c_ctx->fast_kdf_iter, c_ctx->key_sz)); 
+                
+
+  if(c_ctx->pass && c_ctx->pass_sz) { // if pass is not null
+    if (c_ctx->pass_sz == ((c_ctx->key_sz * 2) + 3) && sqlite3StrNICmp((const char *)c_ctx->pass ,"x'", 2) == 0) { 
+      int n = c_ctx->pass_sz - 3; /* adjust for leading x' and tailing ' */
+      const unsigned char *z = c_ctx->pass + 2; /* adjust lead offset of x' */
+      CODEC_TRACE(("cipher_ctx_key_derive: using raw key from hex\n")); 
+      cipher_hex2bin(z, n, c_ctx->key);
+    } else if (c_ctx->pass_sz == (((c_ctx->key_sz + ctx->kdf_salt_sz) * 2) + 3) && sqlite3StrNICmp((const char *)c_ctx->pass ,"x'", 2) == 0) { 
+      const unsigned char *z = c_ctx->pass + 2; /* adjust lead offset of x' */
+      CODEC_TRACE(("cipher_ctx_key_derive: using raw key from hex\n")); 
+      cipher_hex2bin(z, (c_ctx->key_sz * 2), c_ctx->key);
+      cipher_hex2bin(z + (c_ctx->key_sz * 2), (ctx->kdf_salt_sz * 2), ctx->kdf_salt);
+    } else { 
+      CODEC_TRACE(("cipher_ctx_key_derive: deriving key using full PBKDF2 with %d iterations\n", c_ctx->kdf_iter)); 
+      c_ctx->provider->kdf(c_ctx->provider_ctx, c_ctx->pass, c_ctx->pass_sz, 
+                    ctx->kdf_salt, ctx->kdf_salt_sz, c_ctx->kdf_iter,
+                    c_ctx->key_sz, c_ctx->key);
+    }
+
+    /* set the context "keyspec" containing the hex-formatted key and salt to be used when attaching databases */
+    if((rc = sqlcipher_cipher_ctx_set_keyspec(c_ctx, c_ctx->key, c_ctx->key_sz, ctx->kdf_salt, ctx->kdf_salt_sz)) != SQLITE_OK) return rc;
+
+    /* if this context is setup to use hmac checks, generate a seperate and different 
+       key for HMAC. In this case, we use the output of the previous KDF as the input to 
+       this KDF run. This ensures a distinct but predictable HMAC key. */
+    if(c_ctx->flags & CIPHER_FLAG_HMAC) {
+      int i;
+
+      /* start by copying the kdf key into the hmac salt slot
+         then XOR it with the fixed hmac salt defined at compile time
+         this ensures that the salt passed in to derive the hmac key, while 
+         easy to derive and publically known, is not the same as the salt used 
+         to generate the encryption key */ 
+      memcpy(ctx->hmac_kdf_salt, ctx->kdf_salt, ctx->kdf_salt_sz);
+      for(i = 0; i < ctx->kdf_salt_sz; i++) {
+        ctx->hmac_kdf_salt[i] ^= hmac_salt_mask;
+      } 
+
+      CODEC_TRACE(("cipher_ctx_key_derive: deriving hmac key from encryption key using PBKDF2 with %d iterations\n", 
+        c_ctx->fast_kdf_iter)); 
+
+      
+      c_ctx->provider->kdf(c_ctx->provider_ctx, c_ctx->key, c_ctx->key_sz, 
+                    ctx->hmac_kdf_salt, ctx->kdf_salt_sz, c_ctx->fast_kdf_iter,
+                    c_ctx->key_sz, c_ctx->hmac_key); 
+    }
+
+    c_ctx->derive_key = 0;
+    return SQLITE_OK;
+  };
+  return SQLITE_ERROR;
+}
+
+int sqlcipher_codec_key_derive(codec_ctx *ctx) {
+  /* derive key on first use if necessary */
+  if(ctx->read_ctx->derive_key) {
+    if(sqlcipher_cipher_ctx_key_derive(ctx, ctx->read_ctx) != SQLITE_OK) return SQLITE_ERROR;
+  }
+
+  if(ctx->write_ctx->derive_key) {
+    if(sqlcipher_cipher_ctx_cmp(ctx->write_ctx, ctx->read_ctx) == 0) {
+      /* the relevant parameters are the same, just copy read key */
+      if(sqlcipher_cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx) != SQLITE_OK) return SQLITE_ERROR;
+    } else {
+      if(sqlcipher_cipher_ctx_key_derive(ctx, ctx->write_ctx) != SQLITE_OK) return SQLITE_ERROR;
+    }
+  }
+
+  /* TODO: wipe and free passphrase after key derivation */
+  sqlcipher_cipher_ctx_set_pass(ctx->read_ctx, NULL, 0);
+  sqlcipher_cipher_ctx_set_pass(ctx->write_ctx, NULL, 0);
+
+  return SQLITE_OK; 
+}
+
+int sqlcipher_codec_key_copy(codec_ctx *ctx, int source) {
+  if(source == CIPHER_READ_CTX) { 
+      return sqlcipher_cipher_ctx_copy(ctx->write_ctx, ctx->read_ctx); 
+  } else {
+      return sqlcipher_cipher_ctx_copy(ctx->read_ctx, ctx->write_ctx); 
+  }
+}
+
+const char* sqlcipher_codec_get_cipher_provider(codec_ctx *ctx) {
+  return ctx->read_ctx->provider->get_provider_name(ctx->read_ctx);
+}
+
+
+static int sqlcipher_check_connection(const char *filename, char *key, int key_sz, char *sql, int *user_version) {
+  int rc;
+  sqlite3 *db = NULL;
+  sqlite3_stmt *statement = NULL;
+  char *query_user_version = "PRAGMA user_version;";
+  
+  rc = sqlite3_open(filename, &db);
+  if(rc != SQLITE_OK){
+    goto cleanup;
+  }
+  rc = sqlite3_key(db, key, key_sz);
+  if(rc != SQLITE_OK){
+    goto cleanup;
+  }
+  rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
+  if(rc != SQLITE_OK){
+    goto cleanup;
+  }
+  rc = sqlite3_prepare(db, query_user_version, -1, &statement, NULL);
+  if(rc != SQLITE_OK){
+    goto cleanup;
+  }
+  rc = sqlite3_step(statement);
+  if(rc == SQLITE_ROW){
+    *user_version = sqlite3_column_int(statement, 0);
+    rc = SQLITE_OK;
+  }
+  
+cleanup:
+  if(statement){
+    sqlite3_finalize(statement);
+  }
+  if(db){
+    sqlite3_close(db);
+  }
+  return rc;
+}
+
+int sqlcipher_codec_ctx_migrate(codec_ctx *ctx) {
+  u32 meta;
+  int rc = 0;
+  int command_idx = 0;
+  int password_sz;
+  int saved_flags;
+  int saved_nChange;
+  int saved_nTotalChange;
+  void (*saved_xTrace)(void*,const char*);
+  Db *pDb = 0;
+  sqlite3 *db = ctx->pBt->db;
+  const char *db_filename = sqlite3_db_filename(db, "main");
+  char *migrated_db_filename = sqlite3_mprintf("%s-migrated", db_filename);
+  char *pragma_hmac_off = "PRAGMA cipher_use_hmac = OFF;";
+  char *pragma_4k_kdf_iter = "PRAGMA kdf_iter = 4000;";
+  char *pragma_1x_and_4k;
+  char *set_user_version;
+  char *key;
+  int key_sz;
+  int user_version = 0;
+  int upgrade_1x_format = 0;
+  int upgrade_4k_format = 0;
+  static const unsigned char aCopy[] = {
+    BTREE_SCHEMA_VERSION,     1,  /* Add one to the old schema cookie */
+    BTREE_DEFAULT_CACHE_SIZE, 0,  /* Preserve the default page cache size */
+    BTREE_TEXT_ENCODING,      0,  /* Preserve the text encoding */
+    BTREE_USER_VERSION,       0,  /* Preserve the user version */
+    BTREE_APPLICATION_ID,     0,  /* Preserve the application id */
+  };
+
+
+  key_sz = ctx->read_ctx->pass_sz + 1;
+  key = sqlcipher_malloc(key_sz);
+  memset(key, 0, key_sz);
+  memcpy(key, ctx->read_ctx->pass, ctx->read_ctx->pass_sz);
+
+  if(db_filename){
+    const char* commands[5];
+    char *attach_command = sqlite3_mprintf("ATTACH DATABASE '%s-migrated' as migrate KEY '%q';",
+                                            db_filename, key);
+
+    int rc = sqlcipher_check_connection(db_filename, key, key_sz, "", &user_version);
+    if(rc == SQLITE_OK){
+      CODEC_TRACE(("No upgrade required - exiting\n"));
+      goto exit;
+    }
+    
+    // Version 2 - check for 4k with hmac format 
+    rc = sqlcipher_check_connection(db_filename, key, key_sz, pragma_4k_kdf_iter, &user_version);
+    if(rc == SQLITE_OK) {
+      CODEC_TRACE(("Version 2 format found\n"));
+      upgrade_4k_format = 1;
+    }
+
+    // Version 1 - check both no hmac and 4k together
+    pragma_1x_and_4k = sqlite3_mprintf("%s%s", pragma_hmac_off,
+                                             pragma_4k_kdf_iter);
+    rc = sqlcipher_check_connection(db_filename, key, key_sz, pragma_1x_and_4k, &user_version);
+    sqlite3_free(pragma_1x_and_4k);
+    if(rc == SQLITE_OK) {
+      CODEC_TRACE(("Version 1 format found\n"));
+      upgrade_1x_format = 1;
+      upgrade_4k_format = 1;
+    }
+
+    if(upgrade_1x_format == 0 && upgrade_4k_format == 0) {
+      CODEC_TRACE(("Upgrade format not determined\n"));
+      goto handle_error;
+    }
+
+    set_user_version = sqlite3_mprintf("PRAGMA migrate.user_version = %d;", user_version);
+    commands[0] = upgrade_4k_format == 1 ? pragma_4k_kdf_iter : "";
+    commands[1] = upgrade_1x_format == 1 ? pragma_hmac_off : "";
+    commands[2] = attach_command;
+    commands[3] = "SELECT sqlcipher_export('migrate');";
+    commands[4] = set_user_version;
+      
+    for(command_idx = 0; command_idx < ArraySize(commands); command_idx++){
+      const char *command = commands[command_idx];
+      if(strcmp(command, "") == 0){
+        continue;
+      }
+      rc = sqlite3_exec(db, command, NULL, NULL, NULL);
+      if(rc != SQLITE_OK){
+        break;
+      }
+    }
+    sqlite3_free(attach_command);
+    sqlite3_free(set_user_version);
+    sqlcipher_free(key, key_sz);
+    
+    if(rc == SQLITE_OK){
+      Btree *pDest;
+      Btree *pSrc;
+      int i = 0;
+
+      if( !db->autoCommit ){
+        CODEC_TRACE(("cannot migrate from within a transaction"));
+        goto handle_error;
+      }
+      if( db->nVdbeActive>1 ){
+        CODEC_TRACE(("cannot migrate - SQL statements in progress"));
+        goto handle_error;
+      }
+
+      /* Save the current value of the database flags so that it can be
+      ** restored before returning. Then set the writable-schema flag, and
+      ** disable CHECK and foreign key constraints.  */
+      saved_flags = db->flags;
+      saved_nChange = db->nChange;
+      saved_nTotalChange = db->nTotalChange;
+      saved_xTrace = db->xTrace;
+      db->flags |= SQLITE_WriteSchema | SQLITE_IgnoreChecks | SQLITE_PreferBuiltin;
+      db->flags &= ~(SQLITE_ForeignKeys | SQLITE_ReverseOrder);
+      db->xTrace = 0;
+      
+      pDest = db->aDb[0].pBt;
+      pDb = &(db->aDb[db->nDb-1]);
+      pSrc = pDb->pBt;
+      
+      rc = sqlite3_exec(db, "BEGIN;", NULL, NULL, NULL);
+      rc = sqlite3BtreeBeginTrans(pSrc, 2);
+      rc = sqlite3BtreeBeginTrans(pDest, 2);
+      
+      assert( 1==sqlite3BtreeIsInTrans(pDest) );
+      assert( 1==sqlite3BtreeIsInTrans(pSrc) );
+
+      sqlite3CodecGetKey(db, db->nDb - 1, (void**)&key, &password_sz);
+      sqlite3CodecAttach(db, 0, key, password_sz);
+      sqlite3pager_get_codec(pDest->pBt->pPager, (void**)&ctx);
+      
+      ctx->skip_read_hmac = 1;      
+      for(i=0; i<ArraySize(aCopy); i+=2){
+        sqlite3BtreeGetMeta(pSrc, aCopy[i], &meta);
+        rc = sqlite3BtreeUpdateMeta(pDest, aCopy[i], meta+aCopy[i+1]);
+        if( NEVER(rc!=SQLITE_OK) ) goto handle_error; 
+      }
+      rc = sqlite3BtreeCopyFile(pDest, pSrc);
+      ctx->skip_read_hmac = 0;
+      if( rc!=SQLITE_OK ) goto handle_error;
+      rc = sqlite3BtreeCommit(pDest);
+
+      db->flags = saved_flags;
+      db->nChange = saved_nChange;
+      db->nTotalChange = saved_nTotalChange;
+      db->xTrace = saved_xTrace;
+      db->autoCommit = 1;
+      if( pDb ){
+        sqlite3BtreeClose(pDb->pBt);
+        pDb->pBt = 0;
+        pDb->pSchema = 0;
+      }
+      sqlite3ResetAllSchemasOfConnection(db);
+      remove(migrated_db_filename);
+      sqlite3_free(migrated_db_filename);
+    } else {
+      CODEC_TRACE(("*** migration failure** \n\n"));
+    }
+    
+  }
+  goto exit;
+
+ handle_error:
+  CODEC_TRACE(("An error occurred attempting to migrate the database\n"));
+  rc = SQLITE_ERROR;
+
+ exit:
+  return rc;
+}
+
+
+#endif
+/* END SQLCIPHER */
+
+/************** End of crypto_impl.c *****************************************/
+/************** Begin file crypto_libtomcrypt.c ******************************/
+/*
+** SQLCipher
+** http://sqlcipher.net
+**
+** Copyright (c) 2008 - 2013, ZETETIC LLC
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**     * Redistributions of source code must retain the above copyright
+**       notice, this list of conditions and the following disclaimer.
+**     * Redistributions in binary form must reproduce the above copyright
+**       notice, this list of conditions and the following disclaimer in the
+**       documentation and/or other materials provided with the distribution.
+**     * Neither the name of the ZETETIC LLC nor the
+**       names of its contributors may be used to endorse or promote products
+**       derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
+** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+*/
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+#ifdef SQLCIPHER_CRYPTO_LIBTOMCRYPT
+#include <tomcrypt.h>
+
+typedef struct {
+  prng_state prng;
+} ltc_ctx;
+
+static unsigned int ltc_init = 0;
+
+static int sqlcipher_ltc_add_random(void *ctx, void *buffer, int length) {
+  ltc_ctx *ltc = (ltc_ctx*)ctx;
+  int rc = fortuna_add_entropy(buffer, length, &(ltc->prng));
+  return rc != CRYPT_OK ? SQLITE_ERROR : SQLITE_OK;
+}
+
+static int sqlcipher_ltc_activate(void *ctx) {
+  ltc_ctx *ltc = (ltc_ctx*)ctx;
+  int random_buffer_sz = sizeof(char) * 32;
+  unsigned char *random_buffer = sqlcipher_malloc(random_buffer_sz);
+  sqlcipher_memset(random_buffer, 0, random_buffer_sz);
+  
+  if(ltc_init == 0) {
+    if(register_prng(&fortuna_desc) != CRYPT_OK) return SQLITE_ERROR;
+    if(register_cipher(&rijndael_desc) != CRYPT_OK) return SQLITE_ERROR;
+    if(register_hash(&sha1_desc) != CRYPT_OK) return SQLITE_ERROR;
+    ltc_init = 1;
+  }
+  if(fortuna_start(&(ltc->prng)) != CRYPT_OK) {
+    return SQLITE_ERROR;
+  }
+  sqlite3_randomness(random_buffer_sz, random_buffer);
+  if(sqlcipher_ltc_add_random(ctx, random_buffer, random_buffer_sz) != SQLITE_OK) {
+    return SQLITE_ERROR;
+  }
+  if(sqlcipher_ltc_add_random(ctx, &ltc, sizeof(ltc_ctx*)) != SQLITE_OK) {
+    return SQLITE_ERROR;
+  }
+  if(fortuna_ready(&(ltc->prng)) != CRYPT_OK) {
+    return SQLITE_ERROR;
+  }
+  sqlcipher_free(random_buffer, random_buffer_sz);
+  return SQLITE_OK;
+}
+
+static int sqlcipher_ltc_deactivate(void *ctx) {
+  ltc_ctx *ltc = (ltc_ctx*)ctx;
+  fortuna_done(&(ltc->prng));
+  return SQLITE_OK;
+}
+
+static const char* sqlcipher_ltc_get_provider_name(void *ctx) {
+  return "libtomcrypt";
+}
+
+static int sqlcipher_ltc_random(void *ctx, void *buffer, int length) {
+  ltc_ctx *ltc = (ltc_ctx*)ctx;
+  int rc;
+  
+  if((rc = fortuna_ready(&(ltc->prng))) != CRYPT_OK) {
+    return SQLITE_ERROR;
+  }
+  fortuna_read(buffer, length, &(ltc->prng));
+  return SQLITE_OK;
+}
+
+static int sqlcipher_ltc_hmac(void *ctx, unsigned char *hmac_key, int key_sz, unsigned char *in, int in_sz, unsigned char *in2, int in2_sz, unsigned char *out) {
+  int rc, hash_idx;
+  hmac_state hmac;
+  unsigned long outlen = key_sz;
+
+  hash_idx = find_hash("sha1");
+  if((rc = hmac_init(&hmac, hash_idx, hmac_key, key_sz)) != CRYPT_OK) return SQLITE_ERROR;
+  if((rc = hmac_process(&hmac, in, in_sz)) != CRYPT_OK) return SQLITE_ERROR;
+  if((rc = hmac_process(&hmac, in2, in2_sz)) != CRYPT_OK) return SQLITE_ERROR;
+  if((rc = hmac_done(&hmac, out, &outlen)) != CRYPT_OK) return SQLITE_ERROR;
+  return SQLITE_OK;
+}
+
+static int sqlcipher_ltc_kdf(void *ctx, const unsigned char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key) {
+  int rc, hash_idx;
+  ltc_ctx *ltc = (ltc_ctx*)ctx;
+  unsigned long outlen = key_sz;
+  unsigned long random_buffer_sz = sizeof(char) * 256;
+  unsigned char *random_buffer = sqlcipher_malloc(random_buffer_sz);
+  sqlcipher_memset(random_buffer, 0, random_buffer_sz);
+
+  hash_idx = find_hash("sha1");
+  if((rc = pkcs_5_alg2(pass, pass_sz, salt, salt_sz,
+                       workfactor, hash_idx, key, &outlen)) != CRYPT_OK) {
+    return SQLITE_ERROR;
+  }
+  if((rc = pkcs_5_alg2(key, key_sz, salt, salt_sz,
+                       1, hash_idx, random_buffer, &random_buffer_sz)) != CRYPT_OK) {
+    return SQLITE_ERROR;
+  }
+  sqlcipher_ltc_add_random(ctx, random_buffer, random_buffer_sz);
+  sqlcipher_free(random_buffer, random_buffer_sz);
+  return SQLITE_OK;
+}
+
+static const char* sqlcipher_ltc_get_cipher(void *ctx) {
+  return "rijndael";
+}
+
+static int sqlcipher_ltc_cipher(void *ctx, int mode, unsigned char *key, int key_sz, unsigned char *iv, unsigned char *in, int in_sz, unsigned char *out) {
+  int rc, cipher_idx;
+  symmetric_CBC cbc;
+
+  if((cipher_idx = find_cipher(sqlcipher_ltc_get_cipher(ctx))) == -1) return SQLITE_ERROR;
+  if((rc = cbc_start(cipher_idx, iv, key, key_sz, 0, &cbc)) != CRYPT_OK) return SQLITE_ERROR;
+  rc = mode == 1 ? cbc_encrypt(in, out, in_sz, &cbc) : cbc_decrypt(in, out, in_sz, &cbc);
+  if(rc != CRYPT_OK) return SQLITE_ERROR;
+  cbc_done(&cbc);
+  return SQLITE_OK;
+}
+
+static int sqlcipher_ltc_set_cipher(void *ctx, const char *cipher_name) {
+  return SQLITE_OK;
+}
+
+static int sqlcipher_ltc_get_key_sz(void *ctx) {
+  int cipher_idx = find_cipher(sqlcipher_ltc_get_cipher(ctx));
+  return cipher_descriptor[cipher_idx].max_key_length;
+}
+
+static int sqlcipher_ltc_get_iv_sz(void *ctx) {
+  int cipher_idx = find_cipher(sqlcipher_ltc_get_cipher(ctx));
+  return cipher_descriptor[cipher_idx].block_length;
+}
+
+static int sqlcipher_ltc_get_block_sz(void *ctx) {
+  int cipher_idx = find_cipher(sqlcipher_ltc_get_cipher(ctx));
+  return cipher_descriptor[cipher_idx].block_length;
+}
+
+static int sqlcipher_ltc_get_hmac_sz(void *ctx) {
+  int hash_idx = find_hash("sha1");
+  return hash_descriptor[hash_idx].hashsize;
+}
+
+static int sqlcipher_ltc_ctx_copy(void *target_ctx, void *source_ctx) {
+  memcpy(target_ctx, source_ctx, sizeof(ltc_ctx));
+  return SQLITE_OK;
+}
+
+static int sqlcipher_ltc_ctx_cmp(void *c1, void *c2) {
+  return 1;
+}
+
+static int sqlcipher_ltc_ctx_init(void **ctx) {
+  *ctx = sqlcipher_malloc(sizeof(ltc_ctx));
+  if(*ctx == NULL) return SQLITE_NOMEM;
+  sqlcipher_ltc_activate(*ctx);
+  return SQLITE_OK;
+}
+
+static int sqlcipher_ltc_ctx_free(void **ctx) {
+  sqlcipher_ltc_deactivate(&ctx);
+  sqlcipher_free(*ctx, sizeof(ltc_ctx));
+  return SQLITE_OK;
+}
+
+int sqlcipher_ltc_setup(sqlcipher_provider *p) {
+  p->activate = sqlcipher_ltc_activate;
+  p->deactivate = sqlcipher_ltc_deactivate;
+  p->get_provider_name = sqlcipher_ltc_get_provider_name;
+  p->random = sqlcipher_ltc_random;
+  p->hmac = sqlcipher_ltc_hmac;
+  p->kdf = sqlcipher_ltc_kdf;
+  p->cipher = sqlcipher_ltc_cipher;
+  p->set_cipher = sqlcipher_ltc_set_cipher;
+  p->get_cipher = sqlcipher_ltc_get_cipher;
+  p->get_key_sz = sqlcipher_ltc_get_key_sz;
+  p->get_iv_sz = sqlcipher_ltc_get_iv_sz;
+  p->get_block_sz = sqlcipher_ltc_get_block_sz;
+  p->get_hmac_sz = sqlcipher_ltc_get_hmac_sz;
+  p->ctx_copy = sqlcipher_ltc_ctx_copy;
+  p->ctx_cmp = sqlcipher_ltc_ctx_cmp;
+  p->ctx_init = sqlcipher_ltc_ctx_init;
+  p->ctx_free = sqlcipher_ltc_ctx_free;
+  p->add_random = sqlcipher_ltc_add_random;
+  return SQLITE_OK;
+}
+
+#endif
+#endif
+/* END SQLCIPHER */
+
+/************** End of crypto_libtomcrypt.c **********************************/
+/************** Begin file crypto_openssl.c **********************************/
+/*
+** SQLCipher
+** http://sqlcipher.net
+**
+** Copyright (c) 2008 - 2013, ZETETIC LLC
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**     * Redistributions of source code must retain the above copyright
+**       notice, this list of conditions and the following disclaimer.
+**     * Redistributions in binary form must reproduce the above copyright
+**       notice, this list of conditions and the following disclaimer in the
+**       documentation and/or other materials provided with the distribution.
+**     * Neither the name of the ZETETIC LLC nor the
+**       names of its contributors may be used to endorse or promote products
+**       derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
+** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+*/
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+#ifdef SQLCIPHER_CRYPTO_OPENSSL
+#include <openssl/rand.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+typedef struct {
+  EVP_CIPHER *evp_cipher;
+} openssl_ctx;
+
+
+static unsigned int openssl_external_init = 0;
+static unsigned int openssl_init_count = 0;
+static sqlite3_mutex* openssl_rand_mutex = NULL;
+
+static int sqlcipher_openssl_add_random(void *ctx, void *buffer, int length) {
+#ifndef SQLCIPHER_OPENSSL_NO_MUTEX_RAND
+  sqlite3_mutex_enter(openssl_rand_mutex);
+#endif
+  RAND_add(buffer, length, 0);
+#ifndef SQLCIPHER_OPENSSL_NO_MUTEX_RAND
+  sqlite3_mutex_leave(openssl_rand_mutex);
+#endif
+  return SQLITE_OK;
+}
+
+/* activate and initialize sqlcipher. Most importantly, this will automatically
+   intialize OpenSSL's EVP system if it hasn't already be externally. Note that 
+   this function may be called multiple times as new codecs are intiialized. 
+   Thus it performs some basic counting to ensure that only the last and final
+   sqlcipher_openssl_deactivate() will free the EVP structures. 
+*/
+static int sqlcipher_openssl_activate(void *ctx) {
+  /* initialize openssl and increment the internal init counter
+     but only if it hasn't been initalized outside of SQLCipher by this program 
+     e.g. on startup */
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+
+  if(openssl_init_count == 0 && EVP_get_cipherbyname(CIPHER) != NULL) {
+    /* if openssl has not yet been initialized by this library, but 
+       a call to get_cipherbyname works, then the openssl library
+       has been initialized externally already. */
+    openssl_external_init = 1;
+  }
+
+  if(openssl_init_count == 0 && openssl_external_init == 0)  {
+    /* if the library was not externally initialized, then should be now */
+    OpenSSL_add_all_algorithms();
+  } 
+
+#ifndef SQLCIPHER_OPENSSL_NO_MUTEX_RAND
+  if(openssl_rand_mutex == NULL) {
+    /* allocate a mutex to guard against concurrent calls to RAND_bytes() */
+    openssl_rand_mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
+  }
+#endif
+
+  openssl_init_count++; 
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  return SQLITE_OK;
+}
+
+/* deactivate SQLCipher, most imporantly decremeting the activation count and
+   freeing the EVP structures on the final deactivation to ensure that 
+   OpenSSL memory is cleaned up */
+static int sqlcipher_openssl_deactivate(void *ctx) {
+  sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  openssl_init_count--;
+
+  if(openssl_init_count == 0) {
+    if(openssl_external_init == 0) {
+    /* if OpenSSL hasn't be initialized externally, and the counter reaches zero 
+       after it's decremented, release EVP memory
+       Note: this code will only be reached if OpensSSL_add_all_algorithms()
+       is called by SQLCipher internally. This should prevent SQLCipher from 
+       "cleaning up" openssl when it was initialized externally by the program */
+      EVP_cleanup();
+    }
+#ifndef SQLCIPHER_OPENSSL_NO_MUTEX_RAND
+    sqlite3_mutex_free(openssl_rand_mutex);
+    openssl_rand_mutex = NULL;
+#endif
+  }
+  sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER));
+  return SQLITE_OK;
+}
+
+static const char* sqlcipher_openssl_get_provider_name(void *ctx) {
+  return "openssl";
+}
+
+/* generate a defined number of random bytes */
+static int sqlcipher_openssl_random (void *ctx, void *buffer, int length) {
+  int rc = 0;
+  /* concurrent calls to RAND_bytes can cause a crash under some openssl versions when a 
+     naive application doesn't use CRYPTO_set_locking_callback and
+     CRYPTO_THREADID_set_callback to ensure openssl thread safety. 
+     This is simple workaround to prevent this common crash
+     but a more proper solution is that applications setup platform-appropriate
+     thread saftey in openssl externally */
+#ifndef SQLCIPHER_OPENSSL_NO_MUTEX_RAND
+  sqlite3_mutex_enter(openssl_rand_mutex);
+#endif
+  rc = RAND_bytes((unsigned char *)buffer, length);
+#ifndef SQLCIPHER_OPENSSL_NO_MUTEX_RAND
+  sqlite3_mutex_leave(openssl_rand_mutex);
+#endif
+  return (rc == 1) ? SQLITE_OK : SQLITE_ERROR;
+}
+
+static int sqlcipher_openssl_hmac(void *ctx, unsigned char *hmac_key, int key_sz, unsigned char *in, int in_sz, unsigned char *in2, int in2_sz, unsigned char *out) {
+  HMAC_CTX hctx;
+  unsigned int outlen;
+  HMAC_CTX_init(&hctx);
+  HMAC_Init_ex(&hctx, hmac_key, key_sz, EVP_sha1(), NULL);
+  HMAC_Update(&hctx, in, in_sz);
+  HMAC_Update(&hctx, in2, in2_sz);
+  HMAC_Final(&hctx, out, &outlen);
+  HMAC_CTX_cleanup(&hctx);
+  return SQLITE_OK; 
+}
+
+static int sqlcipher_openssl_kdf(void *ctx, const unsigned char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key) {
+  PKCS5_PBKDF2_HMAC_SHA1((const char *)pass, pass_sz, salt, salt_sz, workfactor, key_sz, key);
+  return SQLITE_OK; 
+}
+
+static int sqlcipher_openssl_cipher(void *ctx, int mode, unsigned char *key, int key_sz, unsigned char *iv, unsigned char *in, int in_sz, unsigned char *out) {
+  EVP_CIPHER_CTX ectx;
+  int tmp_csz, csz;
+ 
+  EVP_CipherInit(&ectx, ((openssl_ctx *)ctx)->evp_cipher, NULL, NULL, mode);
+  EVP_CIPHER_CTX_set_padding(&ectx, 0); // no padding
+  EVP_CipherInit(&ectx, NULL, key, iv, mode);
+  EVP_CipherUpdate(&ectx, out, &tmp_csz, in, in_sz);
+  csz = tmp_csz;  
+  out += tmp_csz;
+  EVP_CipherFinal(&ectx, out, &tmp_csz);
+  csz += tmp_csz;
+  EVP_CIPHER_CTX_cleanup(&ectx);
+  assert(in_sz == csz);
+  return SQLITE_OK; 
+}
+
+static int sqlcipher_openssl_set_cipher(void *ctx, const char *cipher_name) {
+  openssl_ctx *o_ctx = (openssl_ctx *)ctx;
+  o_ctx->evp_cipher = (EVP_CIPHER *) EVP_get_cipherbyname(cipher_name);
+  return SQLITE_OK;
+}
+
+static const char* sqlcipher_openssl_get_cipher(void *ctx) {
+  return EVP_CIPHER_name(((openssl_ctx *)ctx)->evp_cipher);
+}
+
+static int sqlcipher_openssl_get_key_sz(void *ctx) {
+  return EVP_CIPHER_key_length(((openssl_ctx *)ctx)->evp_cipher);
+}
+
+static int sqlcipher_openssl_get_iv_sz(void *ctx) {
+  return EVP_CIPHER_iv_length(((openssl_ctx *)ctx)->evp_cipher);
+}
+
+static int sqlcipher_openssl_get_block_sz(void *ctx) {
+  return EVP_CIPHER_block_size(((openssl_ctx *)ctx)->evp_cipher);
+}
+
+static int sqlcipher_openssl_get_hmac_sz(void *ctx) {
+  return EVP_MD_size(EVP_sha1());
+}
+
+static int sqlcipher_openssl_ctx_copy(void *target_ctx, void *source_ctx) {
+  memcpy(target_ctx, source_ctx, sizeof(openssl_ctx));
+  return SQLITE_OK;
+}
+
+static int sqlcipher_openssl_ctx_cmp(void *c1, void *c2) {
+  return ((openssl_ctx *)c1)->evp_cipher == ((openssl_ctx *)c2)->evp_cipher;
+}
+
+static int sqlcipher_openssl_ctx_init(void **ctx) {
+  *ctx = sqlcipher_malloc(sizeof(openssl_ctx));
+  if(*ctx == NULL) return SQLITE_NOMEM;
+  sqlcipher_openssl_activate(*ctx);
+  return SQLITE_OK;
+}
+
+static int sqlcipher_openssl_ctx_free(void **ctx) {
+  sqlcipher_openssl_deactivate(*ctx);
+  sqlcipher_free(*ctx, sizeof(openssl_ctx));
+  return SQLITE_OK;
+}
+
+int sqlcipher_openssl_setup(sqlcipher_provider *p) {
+  p->activate = sqlcipher_openssl_activate;  
+  p->deactivate = sqlcipher_openssl_deactivate;
+  p->get_provider_name = sqlcipher_openssl_get_provider_name;
+  p->random = sqlcipher_openssl_random;
+  p->hmac = sqlcipher_openssl_hmac;
+  p->kdf = sqlcipher_openssl_kdf;
+  p->cipher = sqlcipher_openssl_cipher;
+  p->set_cipher = sqlcipher_openssl_set_cipher;
+  p->get_cipher = sqlcipher_openssl_get_cipher;
+  p->get_key_sz = sqlcipher_openssl_get_key_sz;
+  p->get_iv_sz = sqlcipher_openssl_get_iv_sz;
+  p->get_block_sz = sqlcipher_openssl_get_block_sz;
+  p->get_hmac_sz = sqlcipher_openssl_get_hmac_sz;
+  p->ctx_copy = sqlcipher_openssl_ctx_copy;
+  p->ctx_cmp = sqlcipher_openssl_ctx_cmp;
+  p->ctx_init = sqlcipher_openssl_ctx_init;
+  p->ctx_free = sqlcipher_openssl_ctx_free;
+  p->add_random = sqlcipher_openssl_add_random;
+  return SQLITE_OK;
+}
+
+#endif
+#endif
+/* END SQLCIPHER */
+
+/************** End of crypto_openssl.c **************************************/
+/************** Begin file crypto_cc.c ***************************************/
+/*
+** SQLCipher
+** http://sqlcipher.net
+**
+** Copyright (c) 2008 - 2013, ZETETIC LLC
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**     * Redistributions of source code must retain the above copyright
+**       notice, this list of conditions and the following disclaimer.
+**     * Redistributions in binary form must reproduce the above copyright
+**       notice, this list of conditions and the following disclaimer in the
+**       documentation and/or other materials provided with the distribution.
+**     * Neither the name of the ZETETIC LLC nor the
+**       names of its contributors may be used to endorse or promote products
+**       derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY ZETETIC LLC ''AS IS'' AND ANY
+** EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+** DISCLAIMED. IN NO EVENT SHALL ZETETIC LLC BE LIABLE FOR ANY
+** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+*/
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+#ifdef SQLCIPHER_CRYPTO_CC
+#include <CommonCrypto/CommonCrypto.h>
+#include <Security/SecRandom.h>
+
+/* generate a defined number of random bytes */
+static int sqlcipher_cc_random (void *ctx, void *buffer, int length) {
+  return (SecRandomCopyBytes(kSecRandomDefault, length, (uint8_t *)buffer) == 0) ? SQLITE_OK : SQLITE_ERROR;
+}
+
+static const char* sqlcipher_cc_get_provider_name(void *ctx) {
+  return "commoncrypto";
+}
+
+static int sqlcipher_cc_hmac(void *ctx, unsigned char *hmac_key, int key_sz, unsigned char *in, int in_sz, unsigned char *in2, int in2_sz, unsigned char *out) {
+  CCHmacContext hmac_context;
+  CCHmacInit(&hmac_context, kCCHmacAlgSHA1, hmac_key, key_sz);
+  CCHmacUpdate(&hmac_context, in, in_sz);
+  CCHmacUpdate(&hmac_context, in2, in2_sz);
+  CCHmacFinal(&hmac_context, out);
+  return SQLITE_OK; 
+}
+
+static int sqlcipher_cc_kdf(void *ctx, const unsigned char *pass, int pass_sz, unsigned char* salt, int salt_sz, int workfactor, int key_sz, unsigned char *key) {
+  CCKeyDerivationPBKDF(kCCPBKDF2, (const char *)pass, pass_sz, salt, salt_sz, kCCPRFHmacAlgSHA1, workfactor, key, key_sz);
+  return SQLITE_OK; 
+}
+
+static int sqlcipher_cc_cipher(void *ctx, int mode, unsigned char *key, int key_sz, unsigned char *iv, unsigned char *in, int in_sz, unsigned char *out) {
+  CCCryptorRef cryptor;
+  size_t tmp_csz, csz;
+  CCOperation op = mode == CIPHER_ENCRYPT ? kCCEncrypt : kCCDecrypt;
+
+  CCCryptorCreate(op, kCCAlgorithmAES128, 0, key, kCCKeySizeAES256, iv, &cryptor);
+  CCCryptorUpdate(cryptor, in, in_sz, out, in_sz, &tmp_csz);
+  csz = tmp_csz;
+  out += tmp_csz;
+  CCCryptorFinal(cryptor, out, in_sz - csz, &tmp_csz);
+  csz += tmp_csz;
+  CCCryptorRelease(cryptor);
+  assert(size == csz);
+
+  return SQLITE_OK; 
+}
+
+static int sqlcipher_cc_set_cipher(void *ctx, const char *cipher_name) {
+  return SQLITE_OK;
+}
+
+static const char* sqlcipher_cc_get_cipher(void *ctx) {
+  return "aes-256-cbc";
+}
+
+static int sqlcipher_cc_get_key_sz(void *ctx) {
+  return kCCKeySizeAES256;
+}
+
+static int sqlcipher_cc_get_iv_sz(void *ctx) {
+  return kCCBlockSizeAES128;
+}
+
+static int sqlcipher_cc_get_block_sz(void *ctx) {
+  return kCCBlockSizeAES128;
+}
+
+static int sqlcipher_cc_get_hmac_sz(void *ctx) {
+  return CC_SHA1_DIGEST_LENGTH;
+}
+
+static int sqlcipher_cc_ctx_copy(void *target_ctx, void *source_ctx) {
+  return SQLITE_OK;
+}
+
+static int sqlcipher_cc_ctx_cmp(void *c1, void *c2) {
+  return SQLITE_OK;
+}
+
+static int sqlcipher_cc_ctx_init(void **ctx) {
+  return SQLITE_OK;
+}
+
+static int sqlcipher_cc_ctx_free(void **ctx) {
+  return SQLITE_OK;
+}
+
+int sqlcipher_cc_setup(sqlcipher_provider *p) {
+  p->random = sqlcipher_cc_random;
+  p->get_provider_name = sqlcipher_cc_get_provider_name;
+  p->hmac = sqlcipher_cc_hmac;
+  p->kdf = sqlcipher_cc_kdf;
+  p->cipher = sqlcipher_cc_cipher;
+  p->set_cipher = sqlcipher_cc_set_cipher;
+  p->get_cipher = sqlcipher_cc_get_cipher;
+  p->get_key_sz = sqlcipher_cc_get_key_sz;
+  p->get_iv_sz = sqlcipher_cc_get_iv_sz;
+  p->get_block_sz = sqlcipher_cc_get_block_sz;
+  p->get_hmac_sz = sqlcipher_cc_get_hmac_sz;
+  p->ctx_copy = sqlcipher_cc_ctx_copy;
+  p->ctx_cmp = sqlcipher_cc_ctx_cmp;
+  p->ctx_init = sqlcipher_cc_ctx_init;
+  p->ctx_free = sqlcipher_cc_ctx_free;
+  return SQLITE_OK;
+}
+
+#endif
+#endif
+/* END SQLCIPHER */
+
+/************** End of crypto_cc.c *******************************************/
+/************** Begin file global.c ******************************************/
+/*
+** 2008 June 13
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file contains definitions of global variables and contants.
+*/
+
+/* An array to map all upper-case characters into their corresponding
+** lower-case character. 
+**
+** SQLite only considers US-ASCII (or EBCDIC) characters.  We do not
+** handle case conversions for the UTF character set since the tables
+** involved are nearly as big or bigger than SQLite itself.
+*/
+SQLITE_PRIVATE const unsigned char sqlite3UpperToLower[] = {
+#ifdef SQLITE_ASCII
+      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
+     18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
+     36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+     54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
+    104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
+    122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
+    108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
+    126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
+    144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
+    162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
+    180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
+    198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
+    216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
+    234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
+    252,253,254,255
+#endif
+#ifdef SQLITE_EBCDIC
+      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, /* 0x */
+     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */
+     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 2x */
+     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */
+     64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */
+     80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */
+     96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */
+    112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */
+    128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */
+    144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */
+    160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */
+    176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */
+    192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */
+    208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */
+    224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */
+    239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */
+#endif
+};
+
+/*
+** The following 256 byte lookup table is used to support SQLites built-in
+** equivalents to the following standard library functions:
+**
+**   isspace()                        0x01
+**   isalpha()                        0x02
+**   isdigit()                        0x04
+**   isalnum()                        0x06
+**   isxdigit()                       0x08
+**   toupper()                        0x20
+**   SQLite identifier character      0x40
+**
+** Bit 0x20 is set if the mapped character requires translation to upper
+** case. i.e. if the character is a lower-case ASCII character.
+** If x is a lower-case ASCII character, then its upper-case equivalent
+** is (x - 0x20). Therefore toupper() can be implemented as:
+**
+**   (x & ~(map[x]&0x20))
+**
+** Standard function tolower() is implemented using the sqlite3UpperToLower[]
+** array. tolower() is used more often than toupper() by SQLite.
+**
+** Bit 0x40 is set if the character non-alphanumeric and can be used in an 
+** SQLite identifier.  Identifiers are alphanumerics, "_", "$", and any
+** non-ASCII UTF character. Hence the test for whether or not a character is
+** part of an identifier is 0x46.
+**
+** SQLite's versions are identical to the standard versions assuming a
+** locale of "C". They are implemented as macros in sqliteInt.h.
+*/
+#ifdef SQLITE_ASCII
+SQLITE_PRIVATE const unsigned char sqlite3CtypeMap[256] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 00..07    ........ */
+  0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,  /* 08..0f    ........ */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 10..17    ........ */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 18..1f    ........ */
+  0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,  /* 20..27     !"#$%&' */
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 28..2f    ()*+,-./ */
+  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,  /* 30..37    01234567 */
+  0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 38..3f    89:;<=>? */
+
+  0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x02,  /* 40..47    @ABCDEFG */
+  0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  /* 48..4f    HIJKLMNO */
+  0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,  /* 50..57    PQRSTUVW */
+  0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x40,  /* 58..5f    XYZ[\]^_ */
+  0x00, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x22,  /* 60..67    `abcdefg */
+  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,  /* 68..6f    hijklmno */
+  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,  /* 70..77    pqrstuvw */
+  0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,  /* 78..7f    xyz{|}~. */
+
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* 80..87    ........ */
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* 88..8f    ........ */
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* 90..97    ........ */
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* 98..9f    ........ */
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* a0..a7    ........ */
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* a8..af    ........ */
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* b0..b7    ........ */
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* b8..bf    ........ */
+
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* c0..c7    ........ */
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* c8..cf    ........ */
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* d0..d7    ........ */
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* d8..df    ........ */
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* e0..e7    ........ */
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* e8..ef    ........ */
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,  /* f0..f7    ........ */
+  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40   /* f8..ff    ........ */
+};
+#endif
+
+#ifndef SQLITE_USE_URI
+# define  SQLITE_USE_URI 0
+#endif
+
+#ifndef SQLITE_ALLOW_COVERING_INDEX_SCAN
+# define SQLITE_ALLOW_COVERING_INDEX_SCAN 1
+#endif
+
+/*
+** The following singleton contains the global configuration for
+** the SQLite library.
+*/
+SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
+   SQLITE_DEFAULT_MEMSTATUS,  /* bMemstat */
+   1,                         /* bCoreMutex */
+   SQLITE_THREADSAFE==1,      /* bFullMutex */
+   SQLITE_USE_URI,            /* bOpenUri */
+   SQLITE_ALLOW_COVERING_INDEX_SCAN,   /* bUseCis */
+   0x7ffffffe,                /* mxStrlen */
+   128,                       /* szLookaside */
+   500,                       /* nLookaside */
+   {0,0,0,0,0,0,0,0},         /* m */
+   {0,0,0,0,0,0,0,0,0},       /* mutex */
+   {0,0,0,0,0,0,0,0,0,0,0,0,0},/* pcache2 */
+   (void*)0,                  /* pHeap */
+   0,                         /* nHeap */
+   0, 0,                      /* mnHeap, mxHeap */
+   SQLITE_DEFAULT_MMAP_SIZE,  /* szMmap */
+   SQLITE_MAX_MMAP_SIZE,      /* mxMmap */
+   (void*)0,                  /* pScratch */
+   0,                         /* szScratch */
+   0,                         /* nScratch */
+   (void*)0,                  /* pPage */
+   0,                         /* szPage */
+   0,                         /* nPage */
+   0,                         /* mxParserStack */
+   0,                         /* sharedCacheEnabled */
+   /* All the rest should always be initialized to zero */
+   0,                         /* isInit */
+   0,                         /* inProgress */
+   0,                         /* isMutexInit */
+   0,                         /* isMallocInit */
+   0,                         /* isPCacheInit */
+   0,                         /* pInitMutex */
+   0,                         /* nRefInitMutex */
+   0,                         /* xLog */
+   0,                         /* pLogArg */
+   0,                         /* bLocaltimeFault */
+#ifdef SQLITE_ENABLE_SQLLOG
+   0,                         /* xSqllog */
+   0                          /* pSqllogArg */
+#endif
+};
+
+
+/*
+** Hash table for global functions - functions common to all
+** database connections.  After initialization, this table is
+** read-only.
+*/
+SQLITE_PRIVATE SQLITE_WSD FuncDefHash sqlite3GlobalFunctions;
+
+/*
+** Constant tokens for values 0 and 1.
+*/
+SQLITE_PRIVATE const Token sqlite3IntTokens[] = {
+   { "0", 1 },
+   { "1", 1 }
+};
+
+
+/*
+** The value of the "pending" byte must be 0x40000000 (1 byte past the
+** 1-gibabyte boundary) in a compatible database.  SQLite never uses
+** the database page that contains the pending byte.  It never attempts
+** to read or write that page.  The pending byte page is set assign
+** for use by the VFS layers as space for managing file locks.
+**
+** During testing, it is often desirable to move the pending byte to
+** a different position in the file.  This allows code that has to
+** deal with the pending byte to run on files that are much smaller
+** than 1 GiB.  The sqlite3_test_control() interface can be used to
+** move the pending byte.
+**
+** IMPORTANT:  Changing the pending byte to any value other than
+** 0x40000000 results in an incompatible database file format!
+** Changing the pending byte during operating results in undefined
+** and dileterious behavior.
+*/
+#ifndef SQLITE_OMIT_WSD
+SQLITE_PRIVATE int sqlite3PendingByte = 0x40000000;
+#endif
+
+/*
+** Properties of opcodes.  The OPFLG_INITIALIZER macro is
+** created by mkopcodeh.awk during compilation.  Data is obtained
+** from the comments following the "case OP_xxxx:" statements in
+** the vdbe.c file.  
+*/
+SQLITE_PRIVATE const unsigned char sqlite3OpcodeProperty[] = OPFLG_INITIALIZER;
+
+/************** End of global.c **********************************************/
+/************** Begin file ctime.c *******************************************/
+/*
+** 2010 February 23
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file implements routines used to report what compile-time options
+** SQLite was built with.
+*/
+
+#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
 
-#ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS
-
 
 /*
 ** An array of names of all compile-time options.  This array should 
@@ -22968,7 +26347,7 @@
 #include <sys/time.h>
 #include <errno.h>
 #if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
-#include <sys/mman.h>
+/* #include <sys/mman.h> */
 #endif
 
 
@@ -45519,7 +48898,39 @@
 }
 #endif
 
-#endif /* SQLITE_OMIT_DISKIO */
+#endif /* SQLITE_OMIT_DISKIO */
+
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+SQLITE_PRIVATE void sqlite3pager_get_codec(Pager *pPager, void **ctx) {
+  *ctx = pPager->pCodec;
+}
+
+SQLITE_PRIVATE int sqlite3pager_is_mj_pgno(Pager *pPager, Pgno pgno) {
+  return (PAGER_MJ_PGNO(pPager) == pgno) ? 1 : 0;
+}
+
+SQLITE_PRIVATE sqlite3_file *sqlite3Pager_get_fd(Pager *pPager) {
+  return (isOpen(pPager->fd)) ? pPager->fd : NULL;
+}
+
+SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetCodec(
+  Pager *pPager,
+  void *(*xCodec)(void*,void*,Pgno,int),
+  void (*xCodecSizeChng)(void*,int,int),
+  void (*xCodecFree)(void*),
+  void *pCodec
+){
+  sqlite3PagerSetCodec(pPager, xCodec, xCodecSizeChng, xCodecFree, pCodec); 
+}
+
+SQLITE_PRIVATE void sqlite3pager_sqlite3PagerSetError( Pager *pPager, int error) {
+  pPager->errCode = error;
+}
+
+#endif
+/* END SQLCIPHER */
+
 
 /************** End of pager.c ***********************************************/
 /************** Begin file wal.c *********************************************/
@@ -46046,3267 +49457,2596 @@
   if( pWal->nWiData<=iPage ){
     int nByte = sizeof(u32*)*(iPage+1);
     volatile u32 **apNew;
-    apNew = (volatile u32 **)sqlite3_realloc((void *)pWal->apWiData, nByte);
-    if( !apNew ){
-      *ppPage = 0;
-      return SQLITE_NOMEM;
-    }
-    memset((void*)&apNew[pWal->nWiData], 0,
-           sizeof(u32*)*(iPage+1-pWal->nWiData));
-    pWal->apWiData = apNew;
-    pWal->nWiData = iPage+1;
-  }
-
-  /* Request a pointer to the required page from the VFS */
-  if( pWal->apWiData[iPage]==0 ){
-    if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
-      pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ);
-      if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM;
-    }else{
-      rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, 
-          pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
-      );
-      if( rc==SQLITE_READONLY ){
-        pWal->readOnly |= WAL_SHM_RDONLY;
-        rc = SQLITE_OK;
-      }
-    }
-  }
-
-  *ppPage = pWal->apWiData[iPage];
-  assert( iPage==0 || *ppPage || rc!=SQLITE_OK );
-  return rc;
-}
-
-/*
-** Return a pointer to the WalCkptInfo structure in the wal-index.
-*/
-static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
-  assert( pWal->nWiData>0 && pWal->apWiData[0] );
-  return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
-}
-
-/*
-** Return a pointer to the WalIndexHdr structure in the wal-index.
-*/
-static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
-  assert( pWal->nWiData>0 && pWal->apWiData[0] );
-  return (volatile WalIndexHdr*)pWal->apWiData[0];
-}
-
-/*
-** The argument to this macro must be of type u32. On a little-endian
-** architecture, it returns the u32 value that results from interpreting
-** the 4 bytes as a big-endian value. On a big-endian architecture, it
-** returns the value that would be produced by intepreting the 4 bytes
-** of the input value as a little-endian integer.
-*/
-#define BYTESWAP32(x) ( \
-    (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8)  \
-  + (((x)&0x00FF0000)>>8)  + (((x)&0xFF000000)>>24) \
-)
-
-/*
-** Generate or extend an 8 byte checksum based on the data in 
-** array aByte[] and the initial values of aIn[0] and aIn[1] (or
-** initial values of 0 and 0 if aIn==NULL).
-**
-** The checksum is written back into aOut[] before returning.
-**
-** nByte must be a positive multiple of 8.
-*/
-static void walChecksumBytes(
-  int nativeCksum, /* True for native byte-order, false for non-native */
-  u8 *a,           /* Content to be checksummed */
-  int nByte,       /* Bytes of content in a[].  Must be a multiple of 8. */
-  const u32 *aIn,  /* Initial checksum value input */
-  u32 *aOut        /* OUT: Final checksum value output */
-){
-  u32 s1, s2;
-  u32 *aData = (u32 *)a;
-  u32 *aEnd = (u32 *)&a[nByte];
-
-  if( aIn ){
-    s1 = aIn[0];
-    s2 = aIn[1];
-  }else{
-    s1 = s2 = 0;
-  }
-
-  assert( nByte>=8 );
-  assert( (nByte&0x00000007)==0 );
-
-  if( nativeCksum ){
-    do {
-      s1 += *aData++ + s2;
-      s2 += *aData++ + s1;
-    }while( aData<aEnd );
-  }else{
-    do {
-      s1 += BYTESWAP32(aData[0]) + s2;
-      s2 += BYTESWAP32(aData[1]) + s1;
-      aData += 2;
-    }while( aData<aEnd );
-  }
-
-  aOut[0] = s1;
-  aOut[1] = s2;
-}
-
-static void walShmBarrier(Wal *pWal){
-  if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
-    sqlite3OsShmBarrier(pWal->pDbFd);
-  }
-}
-
-/*
-** Write the header information in pWal->hdr into the wal-index.
-**
-** The checksum on pWal->hdr is updated before it is written.
-*/
-static void walIndexWriteHdr(Wal *pWal){
-  volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
-  const int nCksum = offsetof(WalIndexHdr, aCksum);
-
-  assert( pWal->writeLock );
-  pWal->hdr.isInit = 1;
-  pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
-  walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
-  memcpy((void *)&aHdr[1], (void *)&pWal->hdr, sizeof(WalIndexHdr));
-  walShmBarrier(pWal);
-  memcpy((void *)&aHdr[0], (void *)&pWal->hdr, sizeof(WalIndexHdr));
-}
-
-/*
-** This function encodes a single frame header and writes it to a buffer
-** supplied by the caller. A frame-header is made up of a series of 
-** 4-byte big-endian integers, as follows:
-**
-**     0: Page number.
-**     4: For commit records, the size of the database image in pages 
-**        after the commit. For all other records, zero.
-**     8: Salt-1 (copied from the wal-header)
-**    12: Salt-2 (copied from the wal-header)
-**    16: Checksum-1.
-**    20: Checksum-2.
-*/
-static void walEncodeFrame(
-  Wal *pWal,                      /* The write-ahead log */
-  u32 iPage,                      /* Database page number for frame */
-  u32 nTruncate,                  /* New db size (or 0 for non-commit frames) */
-  u8 *aData,                      /* Pointer to page data */
-  u8 *aFrame                      /* OUT: Write encoded frame here */
-){
-  int nativeCksum;                /* True for native byte-order checksums */
-  u32 *aCksum = pWal->hdr.aFrameCksum;
-  assert( WAL_FRAME_HDRSIZE==24 );
-  sqlite3Put4byte(&aFrame[0], iPage);
-  sqlite3Put4byte(&aFrame[4], nTruncate);
-  memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
-
-  nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
-  walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
-  walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
-
-  sqlite3Put4byte(&aFrame[16], aCksum[0]);
-  sqlite3Put4byte(&aFrame[20], aCksum[1]);
-}
-
-/*
-** Check to see if the frame with header in aFrame[] and content
-** in aData[] is valid.  If it is a valid frame, fill *piPage and
-** *pnTruncate and return true.  Return if the frame is not valid.
-*/
-static int walDecodeFrame(
-  Wal *pWal,                      /* The write-ahead log */
-  u32 *piPage,                    /* OUT: Database page number for frame */
-  u32 *pnTruncate,                /* OUT: New db size (or 0 if not commit) */
-  u8 *aData,                      /* Pointer to page data (for checksum) */
-  u8 *aFrame                      /* Frame data */
-){
-  int nativeCksum;                /* True for native byte-order checksums */
-  u32 *aCksum = pWal->hdr.aFrameCksum;
-  u32 pgno;                       /* Page number of the frame */
-  assert( WAL_FRAME_HDRSIZE==24 );
-
-  /* A frame is only valid if the salt values in the frame-header
-  ** match the salt values in the wal-header. 
-  */
-  if( memcmp(&pWal->hdr.aSalt, &aFrame[8], 8)!=0 ){
-    return 0;
-  }
-
-  /* A frame is only valid if the page number is creater than zero.
-  */
-  pgno = sqlite3Get4byte(&aFrame[0]);
-  if( pgno==0 ){
-    return 0;
-  }
-
-  /* A frame is only valid if a checksum of the WAL header,
-  ** all prior frams, the first 16 bytes of this frame-header, 
-  ** and the frame-data matches the checksum in the last 8 
-  ** bytes of this frame-header.
-  */
-  nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
-  walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
-  walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
-  if( aCksum[0]!=sqlite3Get4byte(&aFrame[16]) 
-   || aCksum[1]!=sqlite3Get4byte(&aFrame[20]) 
-  ){
-    /* Checksum failed. */
-    return 0;
-  }
-
-  /* If we reach this point, the frame is valid.  Return the page number
-  ** and the new database size.
-  */
-  *piPage = pgno;
-  *pnTruncate = sqlite3Get4byte(&aFrame[4]);
-  return 1;
-}
-
-
-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
-/*
-** Names of locks.  This routine is used to provide debugging output and is not
-** a part of an ordinary build.
-*/
-static const char *walLockName(int lockIdx){
-  if( lockIdx==WAL_WRITE_LOCK ){
-    return "WRITE-LOCK";
-  }else if( lockIdx==WAL_CKPT_LOCK ){
-    return "CKPT-LOCK";
-  }else if( lockIdx==WAL_RECOVER_LOCK ){
-    return "RECOVER-LOCK";
-  }else{
-    static char zName[15];
-    sqlite3_snprintf(sizeof(zName), zName, "READ-LOCK[%d]",
-                     lockIdx-WAL_READ_LOCK(0));
-    return zName;
-  }
-}
-#endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
-    
-
-/*
-** Set or release locks on the WAL.  Locks are either shared or exclusive.
-** A lock cannot be moved directly between shared and exclusive - it must go
-** through the unlocked state first.
-**
-** In locking_mode=EXCLUSIVE, all of these routines become no-ops.
-*/
-static int walLockShared(Wal *pWal, int lockIdx){
-  int rc;
-  if( pWal->exclusiveMode ) return SQLITE_OK;
-  rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
-                        SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
-  WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
-            walLockName(lockIdx), rc ? "failed" : "ok"));
-  VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
-  return rc;
-}
-static void walUnlockShared(Wal *pWal, int lockIdx){
-  if( pWal->exclusiveMode ) return;
-  (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
-                         SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
-  WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
-}
-static int walLockExclusive(Wal *pWal, int lockIdx, int n){
-  int rc;
-  if( pWal->exclusiveMode ) return SQLITE_OK;
-  rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
-                        SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
-  WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
-            walLockName(lockIdx), n, rc ? "failed" : "ok"));
-  VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
-  return rc;
-}
-static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
-  if( pWal->exclusiveMode ) return;
-  (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
-                         SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE);
-  WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal,
-             walLockName(lockIdx), n));
-}
-
-/*
-** Compute a hash on a page number.  The resulting hash value must land
-** between 0 and (HASHTABLE_NSLOT-1).  The walHashNext() function advances
-** the hash to the next value in the event of a collision.
-*/
-static int walHash(u32 iPage){
-  assert( iPage>0 );
-  assert( (HASHTABLE_NSLOT & (HASHTABLE_NSLOT-1))==0 );
-  return (iPage*HASHTABLE_HASH_1) & (HASHTABLE_NSLOT-1);
-}
-static int walNextHash(int iPriorHash){
-  return (iPriorHash+1)&(HASHTABLE_NSLOT-1);
-}
-
-/* 
-** Return pointers to the hash table and page number array stored on
-** page iHash of the wal-index. The wal-index is broken into 32KB pages
-** numbered starting from 0.
-**
-** Set output variable *paHash to point to the start of the hash table
-** in the wal-index file. Set *piZero to one less than the frame 
-** number of the first frame indexed by this hash table. If a
-** slot in the hash table is set to N, it refers to frame number 
-** (*piZero+N) in the log.
-**
-** Finally, set *paPgno so that *paPgno[1] is the page number of the
-** first frame indexed by the hash table, frame (*piZero+1).
-*/
-static int walHashGet(
-  Wal *pWal,                      /* WAL handle */
-  int iHash,                      /* Find the iHash'th table */
-  volatile ht_slot **paHash,      /* OUT: Pointer to hash index */
-  volatile u32 **paPgno,          /* OUT: Pointer to page number array */
-  u32 *piZero                     /* OUT: Frame associated with *paPgno[0] */
-){
-  int rc;                         /* Return code */
-  volatile u32 *aPgno;
-
-  rc = walIndexPage(pWal, iHash, &aPgno);
-  assert( rc==SQLITE_OK || iHash>0 );
-
-  if( rc==SQLITE_OK ){
-    u32 iZero;
-    volatile ht_slot *aHash;
-
-    aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE];
-    if( iHash==0 ){
-      aPgno = &aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
-      iZero = 0;
-    }else{
-      iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
-    }
-  
-    *paPgno = &aPgno[-1];
-    *paHash = aHash;
-    *piZero = iZero;
-  }
-  return rc;
-}
-
-/*
-** Return the number of the wal-index page that contains the hash-table
-** and page-number array that contain entries corresponding to WAL frame
-** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages 
-** are numbered starting from 0.
-*/
-static int walFramePage(u32 iFrame){
-  int iHash = (iFrame+HASHTABLE_NPAGE-HASHTABLE_NPAGE_ONE-1) / HASHTABLE_NPAGE;
-  assert( (iHash==0 || iFrame>HASHTABLE_NPAGE_ONE)
-       && (iHash>=1 || iFrame<=HASHTABLE_NPAGE_ONE)
-       && (iHash<=1 || iFrame>(HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE))
-       && (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
-       && (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
-  );
-  return iHash;
-}
-
-/*
-** Return the page number associated with frame iFrame in this WAL.
-*/
-static u32 walFramePgno(Wal *pWal, u32 iFrame){
-  int iHash = walFramePage(iFrame);
-  if( iHash==0 ){
-    return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1];
-  }
-  return pWal->apWiData[iHash][(iFrame-1-HASHTABLE_NPAGE_ONE)%HASHTABLE_NPAGE];
-}
-
-/*
-** Remove entries from the hash table that point to WAL slots greater
-** than pWal->hdr.mxFrame.
-**
-** This function is called whenever pWal->hdr.mxFrame is decreased due
-** to a rollback or savepoint.
-**
-** At most only the hash table containing pWal->hdr.mxFrame needs to be
-** updated.  Any later hash tables will be automatically cleared when
-** pWal->hdr.mxFrame advances to the point where those hash tables are
-** actually needed.
-*/
-static void walCleanupHash(Wal *pWal){
-  volatile ht_slot *aHash = 0;    /* Pointer to hash table to clear */
-  volatile u32 *aPgno = 0;        /* Page number array for hash table */
-  u32 iZero = 0;                  /* frame == (aHash[x]+iZero) */
-  int iLimit = 0;                 /* Zero values greater than this */
-  int nByte;                      /* Number of bytes to zero in aPgno[] */
-  int i;                          /* Used to iterate through aHash[] */
-
-  assert( pWal->writeLock );
-  testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 );
-  testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE );
-  testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE+1 );
-
-  if( pWal->hdr.mxFrame==0 ) return;
-
-  /* Obtain pointers to the hash-table and page-number array containing 
-  ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed
-  ** that the page said hash-table and array reside on is already mapped.
-  */
-  assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
-  assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
-  walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero);
-
-  /* Zero all hash-table entries that correspond to frame numbers greater
-  ** than pWal->hdr.mxFrame.
-  */
-  iLimit = pWal->hdr.mxFrame - iZero;
-  assert( iLimit>0 );
-  for(i=0; i<HASHTABLE_NSLOT; i++){
-    if( aHash[i]>iLimit ){
-      aHash[i] = 0;
-    }
-  }
-  
-  /* Zero the entries in the aPgno array that correspond to frames with
-  ** frame numbers greater than pWal->hdr.mxFrame. 
-  */
-  nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]);
-  memset((void *)&aPgno[iLimit+1], 0, nByte);
-
-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
-  /* Verify that the every entry in the mapping region is still reachable
-  ** via the hash table even after the cleanup.
-  */
-  if( iLimit ){
-    int i;           /* Loop counter */
-    int iKey;        /* Hash key */
-    for(i=1; i<=iLimit; i++){
-      for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
-        if( aHash[iKey]==i ) break;
-      }
-      assert( aHash[iKey]==i );
-    }
-  }
-#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
-}
-
-
-/*
-** Set an entry in the wal-index that will map database page number
-** pPage into WAL frame iFrame.
-*/
-static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
-  int rc;                         /* Return code */
-  u32 iZero = 0;                  /* One less than frame number of aPgno[1] */
-  volatile u32 *aPgno = 0;        /* Page number array */
-  volatile ht_slot *aHash = 0;    /* Hash table */
-
-  rc = walHashGet(pWal, walFramePage(iFrame), &aHash, &aPgno, &iZero);
-
-  /* Assuming the wal-index file was successfully mapped, populate the
-  ** page number array and hash table entry.
-  */
-  if( rc==SQLITE_OK ){
-    int iKey;                     /* Hash table key */
-    int idx;                      /* Value to write to hash-table slot */
-    int nCollide;                 /* Number of hash collisions */
-
-    idx = iFrame - iZero;
-    assert( idx <= HASHTABLE_NSLOT/2 + 1 );
-    
-    /* If this is the first entry to be added to this hash-table, zero the
-    ** entire hash table and aPgno[] array before proceding. 
-    */
-    if( idx==1 ){
-      int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]);
-      memset((void*)&aPgno[1], 0, nByte);
-    }
-
-    /* If the entry in aPgno[] is already set, then the previous writer
-    ** must have exited unexpectedly in the middle of a transaction (after
-    ** writing one or more dirty pages to the WAL to free up memory). 
-    ** Remove the remnants of that writers uncommitted transaction from 
-    ** the hash-table before writing any new entries.
-    */
-    if( aPgno[idx] ){
-      walCleanupHash(pWal);
-      assert( !aPgno[idx] );
-    }
-
-    /* Write the aPgno[] array entry and the hash-table slot. */
-    nCollide = idx;
-    for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){
-      if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT;
-    }
-    aPgno[idx] = iPage;
-    aHash[iKey] = (ht_slot)idx;
-
-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
-    /* Verify that the number of entries in the hash table exactly equals
-    ** the number of entries in the mapping region.
-    */
-    {
-      int i;           /* Loop counter */
-      int nEntry = 0;  /* Number of entries in the hash table */
-      for(i=0; i<HASHTABLE_NSLOT; i++){ if( aHash[i] ) nEntry++; }
-      assert( nEntry==idx );
+    apNew = (volatile u32 **)sqlite3_realloc((void *)pWal->apWiData, nByte);
+    if( !apNew ){
+      *ppPage = 0;
+      return SQLITE_NOMEM;
     }
+    memset((void*)&apNew[pWal->nWiData], 0,
+           sizeof(u32*)*(iPage+1-pWal->nWiData));
+    pWal->apWiData = apNew;
+    pWal->nWiData = iPage+1;
+  }
 
-    /* Verify that the every entry in the mapping region is reachable
-    ** via the hash table.  This turns out to be a really, really expensive
-    ** thing to check, so only do this occasionally - not on every
-    ** iteration.
-    */
-    if( (idx&0x3ff)==0 ){
-      int i;           /* Loop counter */
-      for(i=1; i<=idx; i++){
-        for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
-          if( aHash[iKey]==i ) break;
-        }
-        assert( aHash[iKey]==i );
+  /* Request a pointer to the required page from the VFS */
+  if( pWal->apWiData[iPage]==0 ){
+    if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
+      pWal->apWiData[iPage] = (u32 volatile *)sqlite3MallocZero(WALINDEX_PGSZ);
+      if( !pWal->apWiData[iPage] ) rc = SQLITE_NOMEM;
+    }else{
+      rc = sqlite3OsShmMap(pWal->pDbFd, iPage, WALINDEX_PGSZ, 
+          pWal->writeLock, (void volatile **)&pWal->apWiData[iPage]
+      );
+      if( rc==SQLITE_READONLY ){
+        pWal->readOnly |= WAL_SHM_RDONLY;
+        rc = SQLITE_OK;
       }
     }
-#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
   }
 
-
+  *ppPage = pWal->apWiData[iPage];
+  assert( iPage==0 || *ppPage || rc!=SQLITE_OK );
   return rc;
 }
 
+/*
+** Return a pointer to the WalCkptInfo structure in the wal-index.
+*/
+static volatile WalCkptInfo *walCkptInfo(Wal *pWal){
+  assert( pWal->nWiData>0 && pWal->apWiData[0] );
+  return (volatile WalCkptInfo*)&(pWal->apWiData[0][sizeof(WalIndexHdr)/2]);
+}
 
 /*
-** Recover the wal-index by reading the write-ahead log file. 
-**
-** This routine first tries to establish an exclusive lock on the
-** wal-index to prevent other threads/processes from doing anything
-** with the WAL or wal-index while recovery is running.  The
-** WAL_RECOVER_LOCK is also held so that other threads will know
-** that this thread is running recovery.  If unable to establish
-** the necessary locks, this routine returns SQLITE_BUSY.
+** Return a pointer to the WalIndexHdr structure in the wal-index.
 */
-static int walIndexRecover(Wal *pWal){
-  int rc;                         /* Return Code */
-  i64 nSize;                      /* Size of log file */
-  u32 aFrameCksum[2] = {0, 0};
-  int iLock;                      /* Lock offset to lock for checkpoint */
-  int nLock;                      /* Number of locks to hold */
+static volatile WalIndexHdr *walIndexHdr(Wal *pWal){
+  assert( pWal->nWiData>0 && pWal->apWiData[0] );
+  return (volatile WalIndexHdr*)pWal->apWiData[0];
+}
 
-  /* Obtain an exclusive lock on all byte in the locking range not already
-  ** locked by the caller. The caller is guaranteed to have locked the
-  ** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
-  ** If successful, the same bytes that are locked here are unlocked before
-  ** this function returns.
-  */
-  assert( pWal->ckptLock==1 || pWal->ckptLock==0 );
-  assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 );
-  assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
-  assert( pWal->writeLock );
-  iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
-  nLock = SQLITE_SHM_NLOCK - iLock;
-  rc = walLockExclusive(pWal, iLock, nLock);
-  if( rc ){
-    return rc;
-  }
-  WALTRACE(("WAL%p: recovery begin...\n", pWal));
+/*
+** The argument to this macro must be of type u32. On a little-endian
+** architecture, it returns the u32 value that results from interpreting
+** the 4 bytes as a big-endian value. On a big-endian architecture, it
+** returns the value that would be produced by intepreting the 4 bytes
+** of the input value as a little-endian integer.
+*/
+#define BYTESWAP32(x) ( \
+    (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8)  \
+  + (((x)&0x00FF0000)>>8)  + (((x)&0xFF000000)>>24) \
+)
 
-  memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
+/*
+** Generate or extend an 8 byte checksum based on the data in 
+** array aByte[] and the initial values of aIn[0] and aIn[1] (or
+** initial values of 0 and 0 if aIn==NULL).
+**
+** The checksum is written back into aOut[] before returning.
+**
+** nByte must be a positive multiple of 8.
+*/
+static void walChecksumBytes(
+  int nativeCksum, /* True for native byte-order, false for non-native */
+  u8 *a,           /* Content to be checksummed */
+  int nByte,       /* Bytes of content in a[].  Must be a multiple of 8. */
+  const u32 *aIn,  /* Initial checksum value input */
+  u32 *aOut        /* OUT: Final checksum value output */
+){
+  u32 s1, s2;
+  u32 *aData = (u32 *)a;
+  u32 *aEnd = (u32 *)&a[nByte];
 
-  rc = sqlite3OsFileSize(pWal->pWalFd, &nSize);
-  if( rc!=SQLITE_OK ){
-    goto recovery_error;
+  if( aIn ){
+    s1 = aIn[0];
+    s2 = aIn[1];
+  }else{
+    s1 = s2 = 0;
   }
 
-  if( nSize>WAL_HDRSIZE ){
-    u8 aBuf[WAL_HDRSIZE];         /* Buffer to load WAL header into */
-    u8 *aFrame = 0;               /* Malloc'd buffer to load entire frame */
-    int szFrame;                  /* Number of bytes in buffer aFrame[] */
-    u8 *aData;                    /* Pointer to data part of aFrame buffer */
-    int iFrame;                   /* Index of last frame read */
-    i64 iOffset;                  /* Next offset to read from log file */
-    int szPage;                   /* Page size according to the log */
-    u32 magic;                    /* Magic value read from WAL header */
-    u32 version;                  /* Magic value read from WAL header */
-    int isValid;                  /* True if this frame is valid */
-
-    /* Read in the WAL header. */
-    rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
-    if( rc!=SQLITE_OK ){
-      goto recovery_error;
-    }
-
-    /* If the database page size is not a power of two, or is greater than
-    ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid 
-    ** data. Similarly, if the 'magic' value is invalid, ignore the whole
-    ** WAL file.
-    */
-    magic = sqlite3Get4byte(&aBuf[0]);
-    szPage = sqlite3Get4byte(&aBuf[8]);
-    if( (magic&0xFFFFFFFE)!=WAL_MAGIC 
-     || szPage&(szPage-1) 
-     || szPage>SQLITE_MAX_PAGE_SIZE 
-     || szPage<512 
-    ){
-      goto finished;
-    }
-    pWal->hdr.bigEndCksum = (u8)(magic&0x00000001);
-    pWal->szPage = szPage;
-    pWal->nCkpt = sqlite3Get4byte(&aBuf[12]);
-    memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
-
-    /* Verify that the WAL header checksum is correct */
-    walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN, 
-        aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum
-    );
-    if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24])
-     || pWal->hdr.aFrameCksum[1]!=sqlite3Get4byte(&aBuf[28])
-    ){
-      goto finished;
-    }
-
-    /* Verify that the version number on the WAL format is one that
-    ** are able to understand */
-    version = sqlite3Get4byte(&aBuf[4]);
-    if( version!=WAL_MAX_VERSION ){
-      rc = SQLITE_CANTOPEN_BKPT;
-      goto finished;
-    }
-
-    /* Malloc a buffer to read frames into. */
-    szFrame = szPage + WAL_FRAME_HDRSIZE;
-    aFrame = (u8 *)sqlite3_malloc(szFrame);
-    if( !aFrame ){
-      rc = SQLITE_NOMEM;
-      goto recovery_error;
-    }
-    aData = &aFrame[WAL_FRAME_HDRSIZE];
-
-    /* Read all frames from the log file. */
-    iFrame = 0;
-    for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
-      u32 pgno;                   /* Database page number for frame */
-      u32 nTruncate;              /* dbsize field from frame header */
-
-      /* Read and decode the next log frame. */
-      iFrame++;
-      rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
-      if( rc!=SQLITE_OK ) break;
-      isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
-      if( !isValid ) break;
-      rc = walIndexAppend(pWal, iFrame, pgno);
-      if( rc!=SQLITE_OK ) break;
-
-      /* If nTruncate is non-zero, this is a commit record. */
-      if( nTruncate ){
-        pWal->hdr.mxFrame = iFrame;
-        pWal->hdr.nPage = nTruncate;
-        pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
-        testcase( szPage<=32768 );
-        testcase( szPage>=65536 );
-        aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
-        aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
-      }
-    }
+  assert( nByte>=8 );
+  assert( (nByte&0x00000007)==0 );
 
-    sqlite3_free(aFrame);
+  if( nativeCksum ){
+    do {
+      s1 += *aData++ + s2;
+      s2 += *aData++ + s1;
+    }while( aData<aEnd );
+  }else{
+    do {
+      s1 += BYTESWAP32(aData[0]) + s2;
+      s2 += BYTESWAP32(aData[1]) + s1;
+      aData += 2;
+    }while( aData<aEnd );
   }
 
-finished:
-  if( rc==SQLITE_OK ){
-    volatile WalCkptInfo *pInfo;
-    int i;
-    pWal->hdr.aFrameCksum[0] = aFrameCksum[0];
-    pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
-    walIndexWriteHdr(pWal);
-
-    /* Reset the checkpoint-header. This is safe because this thread is 
-    ** currently holding locks that exclude all other readers, writers and
-    ** checkpointers.
-    */
-    pInfo = walCkptInfo(pWal);
-    pInfo->nBackfill = 0;
-    pInfo->aReadMark[0] = 0;
-    for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
-    if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame;
+  aOut[0] = s1;
+  aOut[1] = s2;
+}
 
-    /* If more than one frame was recovered from the log file, report an
-    ** event via sqlite3_log(). This is to help with identifying performance
-    ** problems caused by applications routinely shutting down without
-    ** checkpointing the log file.
-    */
-    if( pWal->hdr.nPage ){
-      sqlite3_log(SQLITE_NOTICE_RECOVER_WAL,
-          "recovered %d frames from WAL file %s",
-          pWal->hdr.mxFrame, pWal->zWalName
-      );
-    }
+static void walShmBarrier(Wal *pWal){
+  if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
+    sqlite3OsShmBarrier(pWal->pDbFd);
   }
-
-recovery_error:
-  WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
-  walUnlockExclusive(pWal, iLock, nLock);
-  return rc;
 }
 
 /*
-** Close an open wal-index.
+** Write the header information in pWal->hdr into the wal-index.
+**
+** The checksum on pWal->hdr is updated before it is written.
 */
-static void walIndexClose(Wal *pWal, int isDelete){
-  if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
-    int i;
-    for(i=0; i<pWal->nWiData; i++){
-      sqlite3_free((void *)pWal->apWiData[i]);
-      pWal->apWiData[i] = 0;
-    }
-  }else{
-    sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
-  }
+static void walIndexWriteHdr(Wal *pWal){
+  volatile WalIndexHdr *aHdr = walIndexHdr(pWal);
+  const int nCksum = offsetof(WalIndexHdr, aCksum);
+
+  assert( pWal->writeLock );
+  pWal->hdr.isInit = 1;
+  pWal->hdr.iVersion = WALINDEX_MAX_VERSION;
+  walChecksumBytes(1, (u8*)&pWal->hdr, nCksum, 0, pWal->hdr.aCksum);
+  memcpy((void *)&aHdr[1], (void *)&pWal->hdr, sizeof(WalIndexHdr));
+  walShmBarrier(pWal);
+  memcpy((void *)&aHdr[0], (void *)&pWal->hdr, sizeof(WalIndexHdr));
 }
 
-/* 
-** Open a connection to the WAL file zWalName. The database file must 
-** already be opened on connection pDbFd. The buffer that zWalName points
-** to must remain valid for the lifetime of the returned Wal* handle.
-**
-** A SHARED lock should be held on the database file when this function
-** is called. The purpose of this SHARED lock is to prevent any other
-** client from unlinking the WAL or wal-index file. If another process
-** were to do this just after this client opened one of these files, the
-** system would be badly broken.
+/*
+** This function encodes a single frame header and writes it to a buffer
+** supplied by the caller. A frame-header is made up of a series of 
+** 4-byte big-endian integers, as follows:
 **
-** If the log file is successfully opened, SQLITE_OK is returned and 
-** *ppWal is set to point to a new WAL handle. If an error occurs,
-** an SQLite error code is returned and *ppWal is left unmodified.
+**     0: Page number.
+**     4: For commit records, the size of the database image in pages 
+**        after the commit. For all other records, zero.
+**     8: Salt-1 (copied from the wal-header)
+**    12: Salt-2 (copied from the wal-header)
+**    16: Checksum-1.
+**    20: Checksum-2.
 */
-SQLITE_PRIVATE int sqlite3WalOpen(
-  sqlite3_vfs *pVfs,              /* vfs module to open wal and wal-index */
-  sqlite3_file *pDbFd,            /* The open database file */
-  const char *zWalName,           /* Name of the WAL file */
-  int bNoShm,                     /* True to run in heap-memory mode */
-  i64 mxWalSize,                  /* Truncate WAL to this size on reset */
-  Wal **ppWal                     /* OUT: Allocated Wal handle */
+static void walEncodeFrame(
+  Wal *pWal,                      /* The write-ahead log */
+  u32 iPage,                      /* Database page number for frame */
+  u32 nTruncate,                  /* New db size (or 0 for non-commit frames) */
+  u8 *aData,                      /* Pointer to page data */
+  u8 *aFrame                      /* OUT: Write encoded frame here */
 ){
-  int rc;                         /* Return Code */
-  Wal *pRet;                      /* Object to allocate and return */
-  int flags;                      /* Flags passed to OsOpen() */
+  int nativeCksum;                /* True for native byte-order checksums */
+  u32 *aCksum = pWal->hdr.aFrameCksum;
+  assert( WAL_FRAME_HDRSIZE==24 );
+  sqlite3Put4byte(&aFrame[0], iPage);
+  sqlite3Put4byte(&aFrame[4], nTruncate);
+  memcpy(&aFrame[8], pWal->hdr.aSalt, 8);
 
-  assert( zWalName && zWalName[0] );
-  assert( pDbFd );
+  nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
+  walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
+  walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
 
-  /* In the amalgamation, the os_unix.c and os_win.c source files come before
-  ** this source file.  Verify that the #defines of the locking byte offsets
-  ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
-  */
-#ifdef WIN_SHM_BASE
-  assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET );
-#endif
-#ifdef UNIX_SHM_BASE
-  assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET );
-#endif
+  sqlite3Put4byte(&aFrame[16], aCksum[0]);
+  sqlite3Put4byte(&aFrame[20], aCksum[1]);
+}
 
+/*
+** Check to see if the frame with header in aFrame[] and content
+** in aData[] is valid.  If it is a valid frame, fill *piPage and
+** *pnTruncate and return true.  Return if the frame is not valid.
+*/
+static int walDecodeFrame(
+  Wal *pWal,                      /* The write-ahead log */
+  u32 *piPage,                    /* OUT: Database page number for frame */
+  u32 *pnTruncate,                /* OUT: New db size (or 0 if not commit) */
+  u8 *aData,                      /* Pointer to page data (for checksum) */
+  u8 *aFrame                      /* Frame data */
+){
+  int nativeCksum;                /* True for native byte-order checksums */
+  u32 *aCksum = pWal->hdr.aFrameCksum;
+  u32 pgno;                       /* Page number of the frame */
+  assert( WAL_FRAME_HDRSIZE==24 );
 
-  /* Allocate an instance of struct Wal to return. */
-  *ppWal = 0;
-  pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
-  if( !pRet ){
-    return SQLITE_NOMEM;
+  /* A frame is only valid if the salt values in the frame-header
+  ** match the salt values in the wal-header. 
+  */
+  if( memcmp(&pWal->hdr.aSalt, &aFrame[8], 8)!=0 ){
+    return 0;
   }
 
-  pRet->pVfs = pVfs;
-  pRet->pWalFd = (sqlite3_file *)&pRet[1];
-  pRet->pDbFd = pDbFd;
-  pRet->readLock = -1;
-  pRet->mxWalSize = mxWalSize;
-  pRet->zWalName = zWalName;
-  pRet->syncHeader = 1;
-  pRet->padToSectorBoundary = 1;
-  pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
-
-  /* Open file handle on the write-ahead log file. */
-  flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
-  rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
-  if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){
-    pRet->readOnly = WAL_RDONLY;
+  /* A frame is only valid if the page number is creater than zero.
+  */
+  pgno = sqlite3Get4byte(&aFrame[0]);
+  if( pgno==0 ){
+    return 0;
   }
 
-  if( rc!=SQLITE_OK ){
-    walIndexClose(pRet, 0);
-    sqlite3OsClose(pRet->pWalFd);
-    sqlite3_free(pRet);
-  }else{
-    int iDC = sqlite3OsDeviceCharacteristics(pRet->pWalFd);
-    if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->syncHeader = 0; }
-    if( iDC & SQLITE_IOCAP_POWERSAFE_OVERWRITE ){
-      pRet->padToSectorBoundary = 0;
-    }
-    *ppWal = pRet;
-    WALTRACE(("WAL%d: opened\n", pRet));
+  /* A frame is only valid if a checksum of the WAL header,
+  ** all prior frams, the first 16 bytes of this frame-header, 
+  ** and the frame-data matches the checksum in the last 8 
+  ** bytes of this frame-header.
+  */
+  nativeCksum = (pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN);
+  walChecksumBytes(nativeCksum, aFrame, 8, aCksum, aCksum);
+  walChecksumBytes(nativeCksum, aData, pWal->szPage, aCksum, aCksum);
+  if( aCksum[0]!=sqlite3Get4byte(&aFrame[16]) 
+   || aCksum[1]!=sqlite3Get4byte(&aFrame[20]) 
+  ){
+    /* Checksum failed. */
+    return 0;
   }
-  return rc;
+
+  /* If we reach this point, the frame is valid.  Return the page number
+  ** and the new database size.
+  */
+  *piPage = pgno;
+  *pnTruncate = sqlite3Get4byte(&aFrame[4]);
+  return 1;
 }
 
+
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
 /*
-** Change the size to which the WAL file is trucated on each reset.
+** Names of locks.  This routine is used to provide debugging output and is not
+** a part of an ordinary build.
 */
-SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){
-  if( pWal ) pWal->mxWalSize = iLimit;
+static const char *walLockName(int lockIdx){
+  if( lockIdx==WAL_WRITE_LOCK ){
+    return "WRITE-LOCK";
+  }else if( lockIdx==WAL_CKPT_LOCK ){
+    return "CKPT-LOCK";
+  }else if( lockIdx==WAL_RECOVER_LOCK ){
+    return "RECOVER-LOCK";
+  }else{
+    static char zName[15];
+    sqlite3_snprintf(sizeof(zName), zName, "READ-LOCK[%d]",
+                     lockIdx-WAL_READ_LOCK(0));
+    return zName;
+  }
 }
+#endif /*defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
+    
 
 /*
-** Find the smallest page number out of all pages held in the WAL that
-** has not been returned by any prior invocation of this method on the
-** same WalIterator object.   Write into *piFrame the frame index where
-** that page was last written into the WAL.  Write into *piPage the page
-** number.
+** Set or release locks on the WAL.  Locks are either shared or exclusive.
+** A lock cannot be moved directly between shared and exclusive - it must go
+** through the unlocked state first.
 **
-** Return 0 on success.  If there are no pages in the WAL with a page
-** number larger than *piPage, then return 1.
+** In locking_mode=EXCLUSIVE, all of these routines become no-ops.
 */
-static int walIteratorNext(
-  WalIterator *p,               /* Iterator */
-  u32 *piPage,                  /* OUT: The page number of the next page */
-  u32 *piFrame                  /* OUT: Wal frame index of next page */
-){
-  u32 iMin;                     /* Result pgno must be greater than iMin */
-  u32 iRet = 0xFFFFFFFF;        /* 0xffffffff is never a valid page number */
-  int i;                        /* For looping through segments */
-
-  iMin = p->iPrior;
-  assert( iMin<0xffffffff );
-  for(i=p->nSegment-1; i>=0; i--){
-    struct WalSegment *pSegment = &p->aSegment[i];
-    while( pSegment->iNext<pSegment->nEntry ){
-      u32 iPg = pSegment->aPgno[pSegment->aIndex[pSegment->iNext]];
-      if( iPg>iMin ){
-        if( iPg<iRet ){
-          iRet = iPg;
-          *piFrame = pSegment->iZero + pSegment->aIndex[pSegment->iNext];
-        }
-        break;
-      }
-      pSegment->iNext++;
-    }
-  }
-
-  *piPage = p->iPrior = iRet;
-  return (iRet==0xFFFFFFFF);
+static int walLockShared(Wal *pWal, int lockIdx){
+  int rc;
+  if( pWal->exclusiveMode ) return SQLITE_OK;
+  rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
+                        SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
+  WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
+            walLockName(lockIdx), rc ? "failed" : "ok"));
+  VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
+  return rc;
+}
+static void walUnlockShared(Wal *pWal, int lockIdx){
+  if( pWal->exclusiveMode ) return;
+  (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, 1,
+                         SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED);
+  WALTRACE(("WAL%p: release SHARED-%s\n", pWal, walLockName(lockIdx)));
+}
+static int walLockExclusive(Wal *pWal, int lockIdx, int n){
+  int rc;
+  if( pWal->exclusiveMode ) return SQLITE_OK;
+  rc = sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
+                        SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
+  WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
+            walLockName(lockIdx), n, rc ? "failed" : "ok"));
+  VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
+  return rc;
+}
+static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
+  if( pWal->exclusiveMode ) return;
+  (void)sqlite3OsShmLock(pWal->pDbFd, lockIdx, n,
+                         SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE);
+  WALTRACE(("WAL%p: release EXCLUSIVE-%s cnt=%d\n", pWal,
+             walLockName(lockIdx), n));
 }
 
 /*
-** This function merges two sorted lists into a single sorted list.
-**
-** aLeft[] and aRight[] are arrays of indices.  The sort key is
-** aContent[aLeft[]] and aContent[aRight[]].  Upon entry, the following
-** is guaranteed for all J<K:
-**
-**        aContent[aLeft[J]] < aContent[aLeft[K]]
-**        aContent[aRight[J]] < aContent[aRight[K]]
-**
-** This routine overwrites aRight[] with a new (probably longer) sequence
-** of indices such that the aRight[] contains every index that appears in
-** either aLeft[] or the old aRight[] and such that the second condition
-** above is still met.
-**
-** The aContent[aLeft[X]] values will be unique for all X.  And the
-** aContent[aRight[X]] values will be unique too.  But there might be
-** one or more combinations of X and Y such that
+** Compute a hash on a page number.  The resulting hash value must land
+** between 0 and (HASHTABLE_NSLOT-1).  The walHashNext() function advances
+** the hash to the next value in the event of a collision.
+*/
+static int walHash(u32 iPage){
+  assert( iPage>0 );
+  assert( (HASHTABLE_NSLOT & (HASHTABLE_NSLOT-1))==0 );
+  return (iPage*HASHTABLE_HASH_1) & (HASHTABLE_NSLOT-1);
+}
+static int walNextHash(int iPriorHash){
+  return (iPriorHash+1)&(HASHTABLE_NSLOT-1);
+}
+
+/* 
+** Return pointers to the hash table and page number array stored on
+** page iHash of the wal-index. The wal-index is broken into 32KB pages
+** numbered starting from 0.
 **
-**      aLeft[X]!=aRight[Y]  &&  aContent[aLeft[X]] == aContent[aRight[Y]]
+** Set output variable *paHash to point to the start of the hash table
+** in the wal-index file. Set *piZero to one less than the frame 
+** number of the first frame indexed by this hash table. If a
+** slot in the hash table is set to N, it refers to frame number 
+** (*piZero+N) in the log.
 **
-** When that happens, omit the aLeft[X] and use the aRight[Y] index.
+** Finally, set *paPgno so that *paPgno[1] is the page number of the
+** first frame indexed by the hash table, frame (*piZero+1).
 */
-static void walMerge(
-  const u32 *aContent,            /* Pages in wal - keys for the sort */
-  ht_slot *aLeft,                 /* IN: Left hand input list */
-  int nLeft,                      /* IN: Elements in array *paLeft */
-  ht_slot **paRight,              /* IN/OUT: Right hand input list */
-  int *pnRight,                   /* IN/OUT: Elements in *paRight */
-  ht_slot *aTmp                   /* Temporary buffer */
+static int walHashGet(
+  Wal *pWal,                      /* WAL handle */
+  int iHash,                      /* Find the iHash'th table */
+  volatile ht_slot **paHash,      /* OUT: Pointer to hash index */
+  volatile u32 **paPgno,          /* OUT: Pointer to page number array */
+  u32 *piZero                     /* OUT: Frame associated with *paPgno[0] */
 ){
-  int iLeft = 0;                  /* Current index in aLeft */
-  int iRight = 0;                 /* Current index in aRight */
-  int iOut = 0;                   /* Current index in output buffer */
-  int nRight = *pnRight;
-  ht_slot *aRight = *paRight;
+  int rc;                         /* Return code */
+  volatile u32 *aPgno;
 
-  assert( nLeft>0 && nRight>0 );
-  while( iRight<nRight || iLeft<nLeft ){
-    ht_slot logpage;
-    Pgno dbpage;
+  rc = walIndexPage(pWal, iHash, &aPgno);
+  assert( rc==SQLITE_OK || iHash>0 );
 
-    if( (iLeft<nLeft) 
-     && (iRight>=nRight || aContent[aLeft[iLeft]]<aContent[aRight[iRight]])
-    ){
-      logpage = aLeft[iLeft++];
+  if( rc==SQLITE_OK ){
+    u32 iZero;
+    volatile ht_slot *aHash;
+
+    aHash = (volatile ht_slot *)&aPgno[HASHTABLE_NPAGE];
+    if( iHash==0 ){
+      aPgno = &aPgno[WALINDEX_HDR_SIZE/sizeof(u32)];
+      iZero = 0;
     }else{
-      logpage = aRight[iRight++];
+      iZero = HASHTABLE_NPAGE_ONE + (iHash-1)*HASHTABLE_NPAGE;
     }
-    dbpage = aContent[logpage];
+  
+    *paPgno = &aPgno[-1];
+    *paHash = aHash;
+    *piZero = iZero;
+  }
+  return rc;
+}
 
-    aTmp[iOut++] = logpage;
-    if( iLeft<nLeft && aContent[aLeft[iLeft]]==dbpage ) iLeft++;
+/*
+** Return the number of the wal-index page that contains the hash-table
+** and page-number array that contain entries corresponding to WAL frame
+** iFrame. The wal-index is broken up into 32KB pages. Wal-index pages 
+** are numbered starting from 0.
+*/
+static int walFramePage(u32 iFrame){
+  int iHash = (iFrame+HASHTABLE_NPAGE-HASHTABLE_NPAGE_ONE-1) / HASHTABLE_NPAGE;
+  assert( (iHash==0 || iFrame>HASHTABLE_NPAGE_ONE)
+       && (iHash>=1 || iFrame<=HASHTABLE_NPAGE_ONE)
+       && (iHash<=1 || iFrame>(HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE))
+       && (iHash>=2 || iFrame<=HASHTABLE_NPAGE_ONE+HASHTABLE_NPAGE)
+       && (iHash<=2 || iFrame>(HASHTABLE_NPAGE_ONE+2*HASHTABLE_NPAGE))
+  );
+  return iHash;
+}
 
-    assert( iLeft>=nLeft || aContent[aLeft[iLeft]]>dbpage );
-    assert( iRight>=nRight || aContent[aRight[iRight]]>dbpage );
+/*
+** Return the page number associated with frame iFrame in this WAL.
+*/
+static u32 walFramePgno(Wal *pWal, u32 iFrame){
+  int iHash = walFramePage(iFrame);
+  if( iHash==0 ){
+    return pWal->apWiData[0][WALINDEX_HDR_SIZE/sizeof(u32) + iFrame - 1];
   }
-
-  *paRight = aLeft;
-  *pnRight = iOut;
-  memcpy(aLeft, aTmp, sizeof(aTmp[0])*iOut);
+  return pWal->apWiData[iHash][(iFrame-1-HASHTABLE_NPAGE_ONE)%HASHTABLE_NPAGE];
 }
 
 /*
-** Sort the elements in list aList using aContent[] as the sort key.
-** Remove elements with duplicate keys, preferring to keep the
-** larger aList[] values.
-**
-** The aList[] entries are indices into aContent[].  The values in
-** aList[] are to be sorted so that for all J<K:
-**
-**      aContent[aList[J]] < aContent[aList[K]]
-**
-** For any X and Y such that
+** Remove entries from the hash table that point to WAL slots greater
+** than pWal->hdr.mxFrame.
 **
-**      aContent[aList[X]] == aContent[aList[Y]]
+** This function is called whenever pWal->hdr.mxFrame is decreased due
+** to a rollback or savepoint.
 **
-** Keep the larger of the two values aList[X] and aList[Y] and discard
-** the smaller.
+** At most only the hash table containing pWal->hdr.mxFrame needs to be
+** updated.  Any later hash tables will be automatically cleared when
+** pWal->hdr.mxFrame advances to the point where those hash tables are
+** actually needed.
 */
-static void walMergesort(
-  const u32 *aContent,            /* Pages in wal */
-  ht_slot *aBuffer,               /* Buffer of at least *pnList items to use */
-  ht_slot *aList,                 /* IN/OUT: List to sort */
-  int *pnList                     /* IN/OUT: Number of elements in aList[] */
-){
-  struct Sublist {
-    int nList;                    /* Number of elements in aList */
-    ht_slot *aList;               /* Pointer to sub-list content */
-  };
+static void walCleanupHash(Wal *pWal){
+  volatile ht_slot *aHash = 0;    /* Pointer to hash table to clear */
+  volatile u32 *aPgno = 0;        /* Page number array for hash table */
+  u32 iZero = 0;                  /* frame == (aHash[x]+iZero) */
+  int iLimit = 0;                 /* Zero values greater than this */
+  int nByte;                      /* Number of bytes to zero in aPgno[] */
+  int i;                          /* Used to iterate through aHash[] */
 
-  const int nList = *pnList;      /* Size of input list */
-  int nMerge = 0;                 /* Number of elements in list aMerge */
-  ht_slot *aMerge = 0;            /* List to be merged */
-  int iList;                      /* Index into input list */
-  int iSub = 0;                   /* Index into aSub array */
-  struct Sublist aSub[13];        /* Array of sub-lists */
+  assert( pWal->writeLock );
+  testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE-1 );
+  testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE );
+  testcase( pWal->hdr.mxFrame==HASHTABLE_NPAGE_ONE+1 );
 
-  memset(aSub, 0, sizeof(aSub));
-  assert( nList<=HASHTABLE_NPAGE && nList>0 );
-  assert( HASHTABLE_NPAGE==(1<<(ArraySize(aSub)-1)) );
+  if( pWal->hdr.mxFrame==0 ) return;
 
-  for(iList=0; iList<nList; iList++){
-    nMerge = 1;
-    aMerge = &aList[iList];
-    for(iSub=0; iList & (1<<iSub); iSub++){
-      struct Sublist *p = &aSub[iSub];
-      assert( p->aList && p->nList<=(1<<iSub) );
-      assert( p->aList==&aList[iList&~((2<<iSub)-1)] );
-      walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
-    }
-    aSub[iSub].aList = aMerge;
-    aSub[iSub].nList = nMerge;
-  }
+  /* Obtain pointers to the hash-table and page-number array containing 
+  ** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed
+  ** that the page said hash-table and array reside on is already mapped.
+  */
+  assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
+  assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
+  walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &aHash, &aPgno, &iZero);
 
-  for(iSub++; iSub<ArraySize(aSub); iSub++){
-    if( nList & (1<<iSub) ){
-      struct Sublist *p = &aSub[iSub];
-      assert( p->nList<=(1<<iSub) );
-      assert( p->aList==&aList[nList&~((2<<iSub)-1)] );
-      walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
+  /* Zero all hash-table entries that correspond to frame numbers greater
+  ** than pWal->hdr.mxFrame.
+  */
+  iLimit = pWal->hdr.mxFrame - iZero;
+  assert( iLimit>0 );
+  for(i=0; i<HASHTABLE_NSLOT; i++){
+    if( aHash[i]>iLimit ){
+      aHash[i] = 0;
     }
   }
-  assert( aMerge==aList );
-  *pnList = nMerge;
+  
+  /* Zero the entries in the aPgno array that correspond to frames with
+  ** frame numbers greater than pWal->hdr.mxFrame. 
+  */
+  nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]);
+  memset((void *)&aPgno[iLimit+1], 0, nByte);
 
-#ifdef SQLITE_DEBUG
-  {
-    int i;
-    for(i=1; i<*pnList; i++){
-      assert( aContent[aList[i]] > aContent[aList[i-1]] );
+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+  /* Verify that the every entry in the mapping region is still reachable
+  ** via the hash table even after the cleanup.
+  */
+  if( iLimit ){
+    int i;           /* Loop counter */
+    int iKey;        /* Hash key */
+    for(i=1; i<=iLimit; i++){
+      for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
+        if( aHash[iKey]==i ) break;
+      }
+      assert( aHash[iKey]==i );
     }
   }
-#endif
+#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
 }
 
-/* 
-** Free an iterator allocated by walIteratorInit().
-*/
-static void walIteratorFree(WalIterator *p){
-  sqlite3ScratchFree(p);
-}
 
 /*
-** Construct a WalInterator object that can be used to loop over all 
-** pages in the WAL in ascending order. The caller must hold the checkpoint
-** lock.
-**
-** On success, make *pp point to the newly allocated WalInterator object
-** return SQLITE_OK. Otherwise, return an error code. If this routine
-** returns an error, the value of *pp is undefined.
-**
-** The calling routine should invoke walIteratorFree() to destroy the
-** WalIterator object when it has finished with it.
+** Set an entry in the wal-index that will map database page number
+** pPage into WAL frame iFrame.
 */
-static int walIteratorInit(Wal *pWal, WalIterator **pp){
-  WalIterator *p;                 /* Return value */
-  int nSegment;                   /* Number of segments to merge */
-  u32 iLast;                      /* Last frame in log */
-  int nByte;                      /* Number of bytes to allocate */
-  int i;                          /* Iterator variable */
-  ht_slot *aTmp;                  /* Temp space used by merge-sort */
-  int rc = SQLITE_OK;             /* Return Code */
+static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
+  int rc;                         /* Return code */
+  u32 iZero = 0;                  /* One less than frame number of aPgno[1] */
+  volatile u32 *aPgno = 0;        /* Page number array */
+  volatile ht_slot *aHash = 0;    /* Hash table */
 
-  /* This routine only runs while holding the checkpoint lock. And
-  ** it only runs if there is actually content in the log (mxFrame>0).
+  rc = walHashGet(pWal, walFramePage(iFrame), &aHash, &aPgno, &iZero);
+
+  /* Assuming the wal-index file was successfully mapped, populate the
+  ** page number array and hash table entry.
   */
-  assert( pWal->ckptLock && pWal->hdr.mxFrame>0 );
-  iLast = pWal->hdr.mxFrame;
+  if( rc==SQLITE_OK ){
+    int iKey;                     /* Hash table key */
+    int idx;                      /* Value to write to hash-table slot */
+    int nCollide;                 /* Number of hash collisions */
 
-  /* Allocate space for the WalIterator object. */
-  nSegment = walFramePage(iLast) + 1;
-  nByte = sizeof(WalIterator) 
-        + (nSegment-1)*sizeof(struct WalSegment)
-        + iLast*sizeof(ht_slot);
-  p = (WalIterator *)sqlite3ScratchMalloc(nByte);
-  if( !p ){
-    return SQLITE_NOMEM;
-  }
-  memset(p, 0, nByte);
-  p->nSegment = nSegment;
+    idx = iFrame - iZero;
+    assert( idx <= HASHTABLE_NSLOT/2 + 1 );
+    
+    /* If this is the first entry to be added to this hash-table, zero the
+    ** entire hash table and aPgno[] array before proceding. 
+    */
+    if( idx==1 ){
+      int nByte = (int)((u8 *)&aHash[HASHTABLE_NSLOT] - (u8 *)&aPgno[1]);
+      memset((void*)&aPgno[1], 0, nByte);
+    }
 
-  /* Allocate temporary space used by the merge-sort routine. This block
-  ** of memory will be freed before this function returns.
-  */
-  aTmp = (ht_slot *)sqlite3ScratchMalloc(
-      sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
-  );
-  if( !aTmp ){
-    rc = SQLITE_NOMEM;
-  }
+    /* If the entry in aPgno[] is already set, then the previous writer
+    ** must have exited unexpectedly in the middle of a transaction (after
+    ** writing one or more dirty pages to the WAL to free up memory). 
+    ** Remove the remnants of that writers uncommitted transaction from 
+    ** the hash-table before writing any new entries.
+    */
+    if( aPgno[idx] ){
+      walCleanupHash(pWal);
+      assert( !aPgno[idx] );
+    }
 
-  for(i=0; rc==SQLITE_OK && i<nSegment; i++){
-    volatile ht_slot *aHash;
-    u32 iZero;
-    volatile u32 *aPgno;
+    /* Write the aPgno[] array entry and the hash-table slot. */
+    nCollide = idx;
+    for(iKey=walHash(iPage); aHash[iKey]; iKey=walNextHash(iKey)){
+      if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT;
+    }
+    aPgno[idx] = iPage;
+    aHash[iKey] = (ht_slot)idx;
 
-    rc = walHashGet(pWal, i, &aHash, &aPgno, &iZero);
-    if( rc==SQLITE_OK ){
-      int j;                      /* Counter variable */
-      int nEntry;                 /* Number of entries in this segment */
-      ht_slot *aIndex;            /* Sorted index for this segment */
+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+    /* Verify that the number of entries in the hash table exactly equals
+    ** the number of entries in the mapping region.
+    */
+    {
+      int i;           /* Loop counter */
+      int nEntry = 0;  /* Number of entries in the hash table */
+      for(i=0; i<HASHTABLE_NSLOT; i++){ if( aHash[i] ) nEntry++; }
+      assert( nEntry==idx );
+    }
 
-      aPgno++;
-      if( (i+1)==nSegment ){
-        nEntry = (int)(iLast - iZero);
-      }else{
-        nEntry = (int)((u32*)aHash - (u32*)aPgno);
-      }
-      aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[iZero];
-      iZero++;
-  
-      for(j=0; j<nEntry; j++){
-        aIndex[j] = (ht_slot)j;
+    /* Verify that the every entry in the mapping region is reachable
+    ** via the hash table.  This turns out to be a really, really expensive
+    ** thing to check, so only do this occasionally - not on every
+    ** iteration.
+    */
+    if( (idx&0x3ff)==0 ){
+      int i;           /* Loop counter */
+      for(i=1; i<=idx; i++){
+        for(iKey=walHash(aPgno[i]); aHash[iKey]; iKey=walNextHash(iKey)){
+          if( aHash[iKey]==i ) break;
+        }
+        assert( aHash[iKey]==i );
       }
-      walMergesort((u32 *)aPgno, aTmp, aIndex, &nEntry);
-      p->aSegment[i].iZero = iZero;
-      p->aSegment[i].nEntry = nEntry;
-      p->aSegment[i].aIndex = aIndex;
-      p->aSegment[i].aPgno = (u32 *)aPgno;
     }
+#endif /* SQLITE_ENABLE_EXPENSIVE_ASSERT */
   }
-  sqlite3ScratchFree(aTmp);
 
-  if( rc!=SQLITE_OK ){
-    walIteratorFree(p);
-  }
-  *pp = p;
-  return rc;
-}
 
-/*
-** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
-** n. If the attempt fails and parameter xBusy is not NULL, then it is a
-** busy-handler function. Invoke it and retry the lock until either the
-** lock is successfully obtained or the busy-handler returns 0.
-*/
-static int walBusyLock(
-  Wal *pWal,                      /* WAL connection */
-  int (*xBusy)(void*),            /* Function to call when busy */
-  void *pBusyArg,                 /* Context argument for xBusyHandler */
-  int lockIdx,                    /* Offset of first byte to lock */
-  int n                           /* Number of bytes to lock */
-){
-  int rc;
-  do {
-    rc = walLockExclusive(pWal, lockIdx, n);
-  }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
   return rc;
 }
 
-/*
-** The cache of the wal-index header must be valid to call this function.
-** Return the page-size in bytes used by the database.
-*/
-static int walPagesize(Wal *pWal){
-  return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
-}
 
 /*
-** Copy as much content as we can from the WAL back into the database file
-** in response to an sqlite3_wal_checkpoint() request or the equivalent.
-**
-** The amount of information copies from WAL to database might be limited
-** by active readers.  This routine will never overwrite a database page
-** that a concurrent reader might be using.
-**
-** All I/O barrier operations (a.k.a fsyncs) occur in this routine when
-** SQLite is in WAL-mode in synchronous=NORMAL.  That means that if 
-** checkpoints are always run by a background thread or background 
-** process, foreground threads will never block on a lengthy fsync call.
-**
-** Fsync is called on the WAL before writing content out of the WAL and
-** into the database.  This ensures that if the new content is persistent
-** in the WAL and can be recovered following a power-loss or hard reset.
-**
-** Fsync is also called on the database file if (and only if) the entire
-** WAL content is copied into the database file.  This second fsync makes
-** it safe to delete the WAL since the new content will persist in the
-** database file.
-**
-** This routine uses and updates the nBackfill field of the wal-index header.
-** This is the only routine tha will increase the value of nBackfill.  
-** (A WAL reset or recovery will revert nBackfill to zero, but not increase
-** its value.)
+** Recover the wal-index by reading the write-ahead log file. 
 **
-** The caller must be holding sufficient locks to ensure that no other
-** checkpoint is running (in any other thread or process) at the same
-** time.
+** This routine first tries to establish an exclusive lock on the
+** wal-index to prevent other threads/processes from doing anything
+** with the WAL or wal-index while recovery is running.  The
+** WAL_RECOVER_LOCK is also held so that other threads will know
+** that this thread is running recovery.  If unable to establish
+** the necessary locks, this routine returns SQLITE_BUSY.
 */
-static int walCheckpoint(
-  Wal *pWal,                      /* Wal connection */
-  int eMode,                      /* One of PASSIVE, FULL or RESTART */
-  int (*xBusyCall)(void*),        /* Function to call when busy */
-  void *pBusyArg,                 /* Context argument for xBusyHandler */
-  int sync_flags,                 /* Flags for OsSync() (or 0) */
-  u8 *zBuf                        /* Temporary buffer to use */
-){
-  int rc;                         /* Return code */
-  int szPage;                     /* Database page-size */
-  WalIterator *pIter = 0;         /* Wal iterator context */
-  u32 iDbpage = 0;                /* Next database page to write */
-  u32 iFrame = 0;                 /* Wal frame containing data for iDbpage */
-  u32 mxSafeFrame;                /* Max frame that can be backfilled */
-  u32 mxPage;                     /* Max database page to write */
-  int i;                          /* Loop counter */
-  volatile WalCkptInfo *pInfo;    /* The checkpoint status information */
-  int (*xBusy)(void*) = 0;        /* Function to call when waiting for locks */
+static int walIndexRecover(Wal *pWal){
+  int rc;                         /* Return Code */
+  i64 nSize;                      /* Size of log file */
+  u32 aFrameCksum[2] = {0, 0};
+  int iLock;                      /* Lock offset to lock for checkpoint */
+  int nLock;                      /* Number of locks to hold */
 
-  szPage = walPagesize(pWal);
-  testcase( szPage<=32768 );
-  testcase( szPage>=65536 );
-  pInfo = walCkptInfo(pWal);
-  if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
+  /* Obtain an exclusive lock on all byte in the locking range not already
+  ** locked by the caller. The caller is guaranteed to have locked the
+  ** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
+  ** If successful, the same bytes that are locked here are unlocked before
+  ** this function returns.
+  */
+  assert( pWal->ckptLock==1 || pWal->ckptLock==0 );
+  assert( WAL_ALL_BUT_WRITE==WAL_WRITE_LOCK+1 );
+  assert( WAL_CKPT_LOCK==WAL_ALL_BUT_WRITE );
+  assert( pWal->writeLock );
+  iLock = WAL_ALL_BUT_WRITE + pWal->ckptLock;
+  nLock = SQLITE_SHM_NLOCK - iLock;
+  rc = walLockExclusive(pWal, iLock, nLock);
+  if( rc ){
+    return rc;
+  }
+  WALTRACE(("WAL%p: recovery begin...\n", pWal));
 
-  /* Allocate the iterator */
-  rc = walIteratorInit(pWal, &pIter);
+  memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
+
+  rc = sqlite3OsFileSize(pWal->pWalFd, &nSize);
   if( rc!=SQLITE_OK ){
-    return rc;
+    goto recovery_error;
   }
-  assert( pIter );
 
-  if( eMode!=SQLITE_CHECKPOINT_PASSIVE ) xBusy = xBusyCall;
+  if( nSize>WAL_HDRSIZE ){
+    u8 aBuf[WAL_HDRSIZE];         /* Buffer to load WAL header into */
+    u8 *aFrame = 0;               /* Malloc'd buffer to load entire frame */
+    int szFrame;                  /* Number of bytes in buffer aFrame[] */
+    u8 *aData;                    /* Pointer to data part of aFrame buffer */
+    int iFrame;                   /* Index of last frame read */
+    i64 iOffset;                  /* Next offset to read from log file */
+    int szPage;                   /* Page size according to the log */
+    u32 magic;                    /* Magic value read from WAL header */
+    u32 version;                  /* Magic value read from WAL header */
+    int isValid;                  /* True if this frame is valid */
+
+    /* Read in the WAL header. */
+    rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
+    if( rc!=SQLITE_OK ){
+      goto recovery_error;
+    }
 
-  /* Compute in mxSafeFrame the index of the last frame of the WAL that is
-  ** safe to write into the database.  Frames beyond mxSafeFrame might
-  ** overwrite database pages that are in use by active readers and thus
-  ** cannot be backfilled from the WAL.
-  */
-  mxSafeFrame = pWal->hdr.mxFrame;
-  mxPage = pWal->hdr.nPage;
-  for(i=1; i<WAL_NREADER; i++){
-    u32 y = pInfo->aReadMark[i];
-    if( mxSafeFrame>y ){
-      assert( y<=pWal->hdr.mxFrame );
-      rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
-      if( rc==SQLITE_OK ){
-        pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
-        walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
-      }else if( rc==SQLITE_BUSY ){
-        mxSafeFrame = y;
-        xBusy = 0;
-      }else{
-        goto walcheckpoint_out;
-      }
+    /* If the database page size is not a power of two, or is greater than
+    ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid 
+    ** data. Similarly, if the 'magic' value is invalid, ignore the whole
+    ** WAL file.
+    */
+    magic = sqlite3Get4byte(&aBuf[0]);
+    szPage = sqlite3Get4byte(&aBuf[8]);
+    if( (magic&0xFFFFFFFE)!=WAL_MAGIC 
+     || szPage&(szPage-1) 
+     || szPage>SQLITE_MAX_PAGE_SIZE 
+     || szPage<512 
+    ){
+      goto finished;
     }
-  }
+    pWal->hdr.bigEndCksum = (u8)(magic&0x00000001);
+    pWal->szPage = szPage;
+    pWal->nCkpt = sqlite3Get4byte(&aBuf[12]);
+    memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
 
-  if( pInfo->nBackfill<mxSafeFrame
-   && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
-  ){
-    i64 nSize;                    /* Current size of database file */
-    u32 nBackfill = pInfo->nBackfill;
+    /* Verify that the WAL header checksum is correct */
+    walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN, 
+        aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum
+    );
+    if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24])
+     || pWal->hdr.aFrameCksum[1]!=sqlite3Get4byte(&aBuf[28])
+    ){
+      goto finished;
+    }
 
-    /* Sync the WAL to disk */
-    if( sync_flags ){
-      rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
+    /* Verify that the version number on the WAL format is one that
+    ** are able to understand */
+    version = sqlite3Get4byte(&aBuf[4]);
+    if( version!=WAL_MAX_VERSION ){
+      rc = SQLITE_CANTOPEN_BKPT;
+      goto finished;
     }
 
-    /* If the database may grow as a result of this checkpoint, hint
-    ** about the eventual size of the db file to the VFS layer.
-    */
-    if( rc==SQLITE_OK ){
-      i64 nReq = ((i64)mxPage * szPage);
-      rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
-      if( rc==SQLITE_OK && nSize<nReq ){
-        sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
-      }
+    /* Malloc a buffer to read frames into. */
+    szFrame = szPage + WAL_FRAME_HDRSIZE;
+    aFrame = (u8 *)sqlite3_malloc(szFrame);
+    if( !aFrame ){
+      rc = SQLITE_NOMEM;
+      goto recovery_error;
     }
+    aData = &aFrame[WAL_FRAME_HDRSIZE];
 
+    /* Read all frames from the log file. */
+    iFrame = 0;
+    for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
+      u32 pgno;                   /* Database page number for frame */
+      u32 nTruncate;              /* dbsize field from frame header */
 
-    /* Iterate through the contents of the WAL, copying data to the db file. */
-    while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
-      i64 iOffset;
-      assert( walFramePgno(pWal, iFrame)==iDbpage );
-      if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
-      iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
-      /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
-      rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
+      /* Read and decode the next log frame. */
+      iFrame++;
+      rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
       if( rc!=SQLITE_OK ) break;
-      iOffset = (iDbpage-1)*(i64)szPage;
-      testcase( IS_BIG_INT(iOffset) );
-      rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
+      isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
+      if( !isValid ) break;
+      rc = walIndexAppend(pWal, iFrame, pgno);
       if( rc!=SQLITE_OK ) break;
-    }
 
-    /* If work was actually accomplished... */
-    if( rc==SQLITE_OK ){
-      if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
-        i64 szDb = pWal->hdr.nPage*(i64)szPage;
-        testcase( IS_BIG_INT(szDb) );
-        rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
-        if( rc==SQLITE_OK && sync_flags ){
-          rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
-        }
-      }
-      if( rc==SQLITE_OK ){
-        pInfo->nBackfill = mxSafeFrame;
+      /* If nTruncate is non-zero, this is a commit record. */
+      if( nTruncate ){
+        pWal->hdr.mxFrame = iFrame;
+        pWal->hdr.nPage = nTruncate;
+        pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
+        testcase( szPage<=32768 );
+        testcase( szPage>=65536 );
+        aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
+        aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
       }
     }
 
-    /* Release the reader lock held while backfilling */
-    walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
+    sqlite3_free(aFrame);
   }
 
-  if( rc==SQLITE_BUSY ){
-    /* Reset the return code so as not to report a checkpoint failure
-    ** just because there are active readers.  */
-    rc = SQLITE_OK;
-  }
+finished:
+  if( rc==SQLITE_OK ){
+    volatile WalCkptInfo *pInfo;
+    int i;
+    pWal->hdr.aFrameCksum[0] = aFrameCksum[0];
+    pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
+    walIndexWriteHdr(pWal);
 
-  /* If this is an SQLITE_CHECKPOINT_RESTART operation, and the entire wal
-  ** file has been copied into the database file, then block until all
-  ** readers have finished using the wal file. This ensures that the next
-  ** process to write to the database restarts the wal file.
-  */
-  if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
-    assert( pWal->writeLock );
-    if( pInfo->nBackfill<pWal->hdr.mxFrame ){
-      rc = SQLITE_BUSY;
-    }else if( eMode==SQLITE_CHECKPOINT_RESTART ){
-      assert( mxSafeFrame==pWal->hdr.mxFrame );
-      rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
-      if( rc==SQLITE_OK ){
-        walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
-      }
+    /* Reset the checkpoint-header. This is safe because this thread is 
+    ** currently holding locks that exclude all other readers, writers and
+    ** checkpointers.
+    */
+    pInfo = walCkptInfo(pWal);
+    pInfo->nBackfill = 0;
+    pInfo->aReadMark[0] = 0;
+    for(i=1; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
+    if( pWal->hdr.mxFrame ) pInfo->aReadMark[1] = pWal->hdr.mxFrame;
+
+    /* If more than one frame was recovered from the log file, report an
+    ** event via sqlite3_log(). This is to help with identifying performance
+    ** problems caused by applications routinely shutting down without
+    ** checkpointing the log file.
+    */
+    if( pWal->hdr.nPage ){
+      sqlite3_log(SQLITE_NOTICE_RECOVER_WAL,
+          "recovered %d frames from WAL file %s",
+          pWal->hdr.mxFrame, pWal->zWalName
+      );
     }
   }
 
- walcheckpoint_out:
-  walIteratorFree(pIter);
+recovery_error:
+  WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
+  walUnlockExclusive(pWal, iLock, nLock);
   return rc;
 }
 
 /*
-** If the WAL file is currently larger than nMax bytes in size, truncate
-** it to exactly nMax bytes. If an error occurs while doing so, ignore it.
-*/
-static void walLimitSize(Wal *pWal, i64 nMax){
-  i64 sz;
-  int rx;
-  sqlite3BeginBenignMalloc();
-  rx = sqlite3OsFileSize(pWal->pWalFd, &sz);
-  if( rx==SQLITE_OK && (sz > nMax ) ){
-    rx = sqlite3OsTruncate(pWal->pWalFd, nMax);
-  }
-  sqlite3EndBenignMalloc();
-  if( rx ){
-    sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
-  }
-}
-
-/*
-** Close a connection to a log file.
+** Close an open wal-index.
 */
-SQLITE_PRIVATE int sqlite3WalClose(
-  Wal *pWal,                      /* Wal to close */
-  int sync_flags,                 /* Flags to pass to OsSync() (or 0) */
-  int nBuf,
-  u8 *zBuf                        /* Buffer of at least nBuf bytes */
-){
-  int rc = SQLITE_OK;
-  if( pWal ){
-    int isDelete = 0;             /* True to unlink wal and wal-index files */
-
-    /* If an EXCLUSIVE lock can be obtained on the database file (using the
-    ** ordinary, rollback-mode locking methods, this guarantees that the
-    ** connection associated with this log file is the only connection to
-    ** the database. In this case checkpoint the database and unlink both
-    ** the wal and wal-index files.
-    **
-    ** The EXCLUSIVE lock is not released before returning.
-    */
-    rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
-    if( rc==SQLITE_OK ){
-      if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
-        pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
-      }
-      rc = sqlite3WalCheckpoint(
-          pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
-      );
-      if( rc==SQLITE_OK ){
-        int bPersist = -1;
-        sqlite3OsFileControlHint(
-            pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersist
-        );
-        if( bPersist!=1 ){
-          /* Try to delete the WAL file if the checkpoint completed and
-          ** fsyned (rc==SQLITE_OK) and if we are not in persistent-wal
-          ** mode (!bPersist) */
-          isDelete = 1;
-        }else if( pWal->mxWalSize>=0 ){
-          /* Try to truncate the WAL file to zero bytes if the checkpoint
-          ** completed and fsynced (rc==SQLITE_OK) and we are in persistent
-          ** WAL mode (bPersist) and if the PRAGMA journal_size_limit is a
-          ** non-negative value (pWal->mxWalSize>=0).  Note that we truncate
-          ** to zero bytes as truncating to the journal_size_limit might
-          ** leave a corrupt WAL file on disk. */
-          walLimitSize(pWal, 0);
-        }
-      }
-    }
-
-    walIndexClose(pWal, isDelete);
-    sqlite3OsClose(pWal->pWalFd);
-    if( isDelete ){
-      sqlite3BeginBenignMalloc();
-      sqlite3OsDelete(pWal->pVfs, pWal->zWalName, 0);
-      sqlite3EndBenignMalloc();
+static void walIndexClose(Wal *pWal, int isDelete){
+  if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
+    int i;
+    for(i=0; i<pWal->nWiData; i++){
+      sqlite3_free((void *)pWal->apWiData[i]);
+      pWal->apWiData[i] = 0;
     }
-    WALTRACE(("WAL%p: closed\n", pWal));
-    sqlite3_free((void *)pWal->apWiData);
-    sqlite3_free(pWal);
+  }else{
+    sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
   }
-  return rc;
 }
 
-/*
-** Try to read the wal-index header.  Return 0 on success and 1 if
-** there is a problem.
-**
-** The wal-index is in shared memory.  Another thread or process might
-** be writing the header at the same time this procedure is trying to
-** read it, which might result in inconsistency.  A dirty read is detected
-** by verifying that both copies of the header are the same and also by
-** a checksum on the header.
+/* 
+** Open a connection to the WAL file zWalName. The database file must 
+** already be opened on connection pDbFd. The buffer that zWalName points
+** to must remain valid for the lifetime of the returned Wal* handle.
 **
-** If and only if the read is consistent and the header is different from
-** pWal->hdr, then pWal->hdr is updated to the content of the new header
-** and *pChanged is set to 1.
+** A SHARED lock should be held on the database file when this function
+** is called. The purpose of this SHARED lock is to prevent any other
+** client from unlinking the WAL or wal-index file. If another process
+** were to do this just after this client opened one of these files, the
+** system would be badly broken.
 **
-** If the checksum cannot be verified return non-zero. If the header
-** is read successfully and the checksum verified, return zero.
+** If the log file is successfully opened, SQLITE_OK is returned and 
+** *ppWal is set to point to a new WAL handle. If an error occurs,
+** an SQLite error code is returned and *ppWal is left unmodified.
 */
-static int walIndexTryHdr(Wal *pWal, int *pChanged){
-  u32 aCksum[2];                  /* Checksum on the header content */
-  WalIndexHdr h1, h2;             /* Two copies of the header content */
-  WalIndexHdr volatile *aHdr;     /* Header in shared memory */
+SQLITE_PRIVATE int sqlite3WalOpen(
+  sqlite3_vfs *pVfs,              /* vfs module to open wal and wal-index */
+  sqlite3_file *pDbFd,            /* The open database file */
+  const char *zWalName,           /* Name of the WAL file */
+  int bNoShm,                     /* True to run in heap-memory mode */
+  i64 mxWalSize,                  /* Truncate WAL to this size on reset */
+  Wal **ppWal                     /* OUT: Allocated Wal handle */
+){
+  int rc;                         /* Return Code */
+  Wal *pRet;                      /* Object to allocate and return */
+  int flags;                      /* Flags passed to OsOpen() */
 
-  /* The first page of the wal-index must be mapped at this point. */
-  assert( pWal->nWiData>0 && pWal->apWiData[0] );
+  assert( zWalName && zWalName[0] );
+  assert( pDbFd );
 
-  /* Read the header. This might happen concurrently with a write to the
-  ** same area of shared memory on a different CPU in a SMP,
-  ** meaning it is possible that an inconsistent snapshot is read
-  ** from the file. If this happens, return non-zero.
-  **
-  ** There are two copies of the header at the beginning of the wal-index.
-  ** When reading, read [0] first then [1].  Writes are in the reverse order.
-  ** Memory barriers are used to prevent the compiler or the hardware from
-  ** reordering the reads and writes.
+  /* In the amalgamation, the os_unix.c and os_win.c source files come before
+  ** this source file.  Verify that the #defines of the locking byte offsets
+  ** in os_unix.c and os_win.c agree with the WALINDEX_LOCK_OFFSET value.
   */
-  aHdr = walIndexHdr(pWal);
-  memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
-  walShmBarrier(pWal);
-  memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
+#ifdef WIN_SHM_BASE
+  assert( WIN_SHM_BASE==WALINDEX_LOCK_OFFSET );
+#endif
+#ifdef UNIX_SHM_BASE
+  assert( UNIX_SHM_BASE==WALINDEX_LOCK_OFFSET );
+#endif
 
-  if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
-    return 1;   /* Dirty read */
-  }  
-  if( h1.isInit==0 ){
-    return 1;   /* Malformed header - probably all zeros */
+
+  /* Allocate an instance of struct Wal to return. */
+  *ppWal = 0;
+  pRet = (Wal*)sqlite3MallocZero(sizeof(Wal) + pVfs->szOsFile);
+  if( !pRet ){
+    return SQLITE_NOMEM;
   }
-  walChecksumBytes(1, (u8*)&h1, sizeof(h1)-sizeof(h1.aCksum), 0, aCksum);
-  if( aCksum[0]!=h1.aCksum[0] || aCksum[1]!=h1.aCksum[1] ){
-    return 1;   /* Checksum does not match */
+
+  pRet->pVfs = pVfs;
+  pRet->pWalFd = (sqlite3_file *)&pRet[1];
+  pRet->pDbFd = pDbFd;
+  pRet->readLock = -1;
+  pRet->mxWalSize = mxWalSize;
+  pRet->zWalName = zWalName;
+  pRet->syncHeader = 1;
+  pRet->padToSectorBoundary = 1;
+  pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
+
+  /* Open file handle on the write-ahead log file. */
+  flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL);
+  rc = sqlite3OsOpen(pVfs, zWalName, pRet->pWalFd, flags, &flags);
+  if( rc==SQLITE_OK && flags&SQLITE_OPEN_READONLY ){
+    pRet->readOnly = WAL_RDONLY;
   }
 
-  if( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){
-    *pChanged = 1;
-    memcpy(&pWal->hdr, &h1, sizeof(WalIndexHdr));
-    pWal->szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
-    testcase( pWal->szPage<=32768 );
-    testcase( pWal->szPage>=65536 );
+  if( rc!=SQLITE_OK ){
+    walIndexClose(pRet, 0);
+    sqlite3OsClose(pRet->pWalFd);
+    sqlite3_free(pRet);
+  }else{
+    int iDC = sqlite3OsDeviceCharacteristics(pRet->pWalFd);
+    if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->syncHeader = 0; }
+    if( iDC & SQLITE_IOCAP_POWERSAFE_OVERWRITE ){
+      pRet->padToSectorBoundary = 0;
+    }
+    *ppWal = pRet;
+    WALTRACE(("WAL%d: opened\n", pRet));
   }
+  return rc;
+}
 
-  /* The header was successfully read. Return zero. */
-  return 0;
+/*
+** Change the size to which the WAL file is trucated on each reset.
+*/
+SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){
+  if( pWal ) pWal->mxWalSize = iLimit;
 }
 
 /*
-** Read the wal-index header from the wal-index and into pWal->hdr.
-** If the wal-header appears to be corrupt, try to reconstruct the
-** wal-index from the WAL before returning.
-**
-** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
-** changed by this opertion.  If pWal->hdr is unchanged, set *pChanged
-** to 0.
+** Find the smallest page number out of all pages held in the WAL that
+** has not been returned by any prior invocation of this method on the
+** same WalIterator object.   Write into *piFrame the frame index where
+** that page was last written into the WAL.  Write into *piPage the page
+** number.
 **
-** If the wal-index header is successfully read, return SQLITE_OK. 
-** Otherwise an SQLite error code.
+** Return 0 on success.  If there are no pages in the WAL with a page
+** number larger than *piPage, then return 1.
 */
-static int walIndexReadHdr(Wal *pWal, int *pChanged){
-  int rc;                         /* Return code */
-  int badHdr;                     /* True if a header read failed */
-  volatile u32 *page0;            /* Chunk of wal-index containing header */
-
-  /* Ensure that page 0 of the wal-index (the page that contains the 
-  ** wal-index header) is mapped. Return early if an error occurs here.
-  */
-  assert( pChanged );
-  rc = walIndexPage(pWal, 0, &page0);
-  if( rc!=SQLITE_OK ){
-    return rc;
-  };
-  assert( page0 || pWal->writeLock==0 );
-
-  /* If the first page of the wal-index has been mapped, try to read the
-  ** wal-index header immediately, without holding any lock. This usually
-  ** works, but may fail if the wal-index header is corrupt or currently 
-  ** being modified by another thread or process.
-  */
-  badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
+static int walIteratorNext(
+  WalIterator *p,               /* Iterator */
+  u32 *piPage,                  /* OUT: The page number of the next page */
+  u32 *piFrame                  /* OUT: Wal frame index of next page */
+){
+  u32 iMin;                     /* Result pgno must be greater than iMin */
+  u32 iRet = 0xFFFFFFFF;        /* 0xffffffff is never a valid page number */
+  int i;                        /* For looping through segments */
 
-  /* If the first attempt failed, it might have been due to a race
-  ** with a writer.  So get a WRITE lock and try again.
-  */
-  assert( badHdr==0 || pWal->writeLock==0 );
-  if( badHdr ){
-    if( pWal->readOnly & WAL_SHM_RDONLY ){
-      if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
-        walUnlockShared(pWal, WAL_WRITE_LOCK);
-        rc = SQLITE_READONLY_RECOVERY;
-      }
-    }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
-      pWal->writeLock = 1;
-      if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
-        badHdr = walIndexTryHdr(pWal, pChanged);
-        if( badHdr ){
-          /* If the wal-index header is still malformed even while holding
-          ** a WRITE lock, it can only mean that the header is corrupted and
-          ** needs to be reconstructed.  So run recovery to do exactly that.
-          */
-          rc = walIndexRecover(pWal);
-          *pChanged = 1;
+  iMin = p->iPrior;
+  assert( iMin<0xffffffff );
+  for(i=p->nSegment-1; i>=0; i--){
+    struct WalSegment *pSegment = &p->aSegment[i];
+    while( pSegment->iNext<pSegment->nEntry ){
+      u32 iPg = pSegment->aPgno[pSegment->aIndex[pSegment->iNext]];
+      if( iPg>iMin ){
+        if( iPg<iRet ){
+          iRet = iPg;
+          *piFrame = pSegment->iZero + pSegment->aIndex[pSegment->iNext];
         }
+        break;
       }
-      pWal->writeLock = 0;
-      walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+      pSegment->iNext++;
+    }
+  }
+
+  *piPage = p->iPrior = iRet;
+  return (iRet==0xFFFFFFFF);
+}
+
+/*
+** This function merges two sorted lists into a single sorted list.
+**
+** aLeft[] and aRight[] are arrays of indices.  The sort key is
+** aContent[aLeft[]] and aContent[aRight[]].  Upon entry, the following
+** is guaranteed for all J<K:
+**
+**        aContent[aLeft[J]] < aContent[aLeft[K]]
+**        aContent[aRight[J]] < aContent[aRight[K]]
+**
+** This routine overwrites aRight[] with a new (probably longer) sequence
+** of indices such that the aRight[] contains every index that appears in
+** either aLeft[] or the old aRight[] and such that the second condition
+** above is still met.
+**
+** The aContent[aLeft[X]] values will be unique for all X.  And the
+** aContent[aRight[X]] values will be unique too.  But there might be
+** one or more combinations of X and Y such that
+**
+**      aLeft[X]!=aRight[Y]  &&  aContent[aLeft[X]] == aContent[aRight[Y]]
+**
+** When that happens, omit the aLeft[X] and use the aRight[Y] index.
+*/
+static void walMerge(
+  const u32 *aContent,            /* Pages in wal - keys for the sort */
+  ht_slot *aLeft,                 /* IN: Left hand input list */
+  int nLeft,                      /* IN: Elements in array *paLeft */
+  ht_slot **paRight,              /* IN/OUT: Right hand input list */
+  int *pnRight,                   /* IN/OUT: Elements in *paRight */
+  ht_slot *aTmp                   /* Temporary buffer */
+){
+  int iLeft = 0;                  /* Current index in aLeft */
+  int iRight = 0;                 /* Current index in aRight */
+  int iOut = 0;                   /* Current index in output buffer */
+  int nRight = *pnRight;
+  ht_slot *aRight = *paRight;
+
+  assert( nLeft>0 && nRight>0 );
+  while( iRight<nRight || iLeft<nLeft ){
+    ht_slot logpage;
+    Pgno dbpage;
+
+    if( (iLeft<nLeft) 
+     && (iRight>=nRight || aContent[aLeft[iLeft]]<aContent[aRight[iRight]])
+    ){
+      logpage = aLeft[iLeft++];
+    }else{
+      logpage = aRight[iRight++];
     }
-  }
+    dbpage = aContent[logpage];
 
-  /* If the header is read successfully, check the version number to make
-  ** sure the wal-index was not constructed with some future format that
-  ** this version of SQLite cannot understand.
-  */
-  if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
-    rc = SQLITE_CANTOPEN_BKPT;
+    aTmp[iOut++] = logpage;
+    if( iLeft<nLeft && aContent[aLeft[iLeft]]==dbpage ) iLeft++;
+
+    assert( iLeft>=nLeft || aContent[aLeft[iLeft]]>dbpage );
+    assert( iRight>=nRight || aContent[aRight[iRight]]>dbpage );
   }
 
-  return rc;
+  *paRight = aLeft;
+  *pnRight = iOut;
+  memcpy(aLeft, aTmp, sizeof(aTmp[0])*iOut);
 }
 
 /*
-** This is the value that walTryBeginRead returns when it needs to
-** be retried.
-*/
-#define WAL_RETRY  (-1)
-
-/*
-** Attempt to start a read transaction.  This might fail due to a race or
-** other transient condition.  When that happens, it returns WAL_RETRY to
-** indicate to the caller that it is safe to retry immediately.
+** Sort the elements in list aList using aContent[] as the sort key.
+** Remove elements with duplicate keys, preferring to keep the
+** larger aList[] values.
 **
-** On success return SQLITE_OK.  On a permanent failure (such an
-** I/O error or an SQLITE_BUSY because another process is running
-** recovery) return a positive error code.
+** The aList[] entries are indices into aContent[].  The values in
+** aList[] are to be sorted so that for all J<K:
 **
-** The useWal parameter is true to force the use of the WAL and disable
-** the case where the WAL is bypassed because it has been completely
-** checkpointed.  If useWal==0 then this routine calls walIndexReadHdr() 
-** to make a copy of the wal-index header into pWal->hdr.  If the 
-** wal-index header has changed, *pChanged is set to 1 (as an indication 
-** to the caller that the local paget cache is obsolete and needs to be 
-** flushed.)  When useWal==1, the wal-index header is assumed to already
-** be loaded and the pChanged parameter is unused.
+**      aContent[aList[J]] < aContent[aList[K]]
 **
-** The caller must set the cnt parameter to the number of prior calls to
-** this routine during the current read attempt that returned WAL_RETRY.
-** This routine will start taking more aggressive measures to clear the
-** race conditions after multiple WAL_RETRY returns, and after an excessive
-** number of errors will ultimately return SQLITE_PROTOCOL.  The
-** SQLITE_PROTOCOL return indicates that some other process has gone rogue
-** and is not honoring the locking protocol.  There is a vanishingly small
-** chance that SQLITE_PROTOCOL could be returned because of a run of really
-** bad luck when there is lots of contention for the wal-index, but that
-** possibility is so small that it can be safely neglected, we believe.
+** For any X and Y such that
 **
-** On success, this routine obtains a read lock on 
-** WAL_READ_LOCK(pWal->readLock).  The pWal->readLock integer is
-** in the range 0 <= pWal->readLock < WAL_NREADER.  If pWal->readLock==(-1)
-** that means the Wal does not hold any read lock.  The reader must not
-** access any database page that is modified by a WAL frame up to and
-** including frame number aReadMark[pWal->readLock].  The reader will
-** use WAL frames up to and including pWal->hdr.mxFrame if pWal->readLock>0
-** Or if pWal->readLock==0, then the reader will ignore the WAL
-** completely and get all content directly from the database file.
-** If the useWal parameter is 1 then the WAL will never be ignored and
-** this routine will always set pWal->readLock>0 on success.
-** When the read transaction is completed, the caller must release the
-** lock on WAL_READ_LOCK(pWal->readLock) and set pWal->readLock to -1.
+**      aContent[aList[X]] == aContent[aList[Y]]
 **
-** This routine uses the nBackfill and aReadMark[] fields of the header
-** to select a particular WAL_READ_LOCK() that strives to let the
-** checkpoint process do as much work as possible.  This routine might
-** update values of the aReadMark[] array in the header, but if it does
-** so it takes care to hold an exclusive lock on the corresponding
-** WAL_READ_LOCK() while changing values.
+** Keep the larger of the two values aList[X] and aList[Y] and discard
+** the smaller.
 */
-static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
-  volatile WalCkptInfo *pInfo;    /* Checkpoint information in wal-index */
-  u32 mxReadMark;                 /* Largest aReadMark[] value */
-  int mxI;                        /* Index of largest aReadMark[] value */
-  int i;                          /* Loop counter */
-  int rc = SQLITE_OK;             /* Return code  */
+static void walMergesort(
+  const u32 *aContent,            /* Pages in wal */
+  ht_slot *aBuffer,               /* Buffer of at least *pnList items to use */
+  ht_slot *aList,                 /* IN/OUT: List to sort */
+  int *pnList                     /* IN/OUT: Number of elements in aList[] */
+){
+  struct Sublist {
+    int nList;                    /* Number of elements in aList */
+    ht_slot *aList;               /* Pointer to sub-list content */
+  };
 
-  assert( pWal->readLock<0 );     /* Not currently locked */
+  const int nList = *pnList;      /* Size of input list */
+  int nMerge = 0;                 /* Number of elements in list aMerge */
+  ht_slot *aMerge = 0;            /* List to be merged */
+  int iList;                      /* Index into input list */
+  int iSub = 0;                   /* Index into aSub array */
+  struct Sublist aSub[13];        /* Array of sub-lists */
 
-  /* Take steps to avoid spinning forever if there is a protocol error.
-  **
-  ** Circumstances that cause a RETRY should only last for the briefest
-  ** instances of time.  No I/O or other system calls are done while the
-  ** locks are held, so the locks should not be held for very long. But 
-  ** if we are unlucky, another process that is holding a lock might get
-  ** paged out or take a page-fault that is time-consuming to resolve, 
-  ** during the few nanoseconds that it is holding the lock.  In that case,
-  ** it might take longer than normal for the lock to free.
-  **
-  ** After 5 RETRYs, we begin calling sqlite3OsSleep().  The first few
-  ** calls to sqlite3OsSleep() have a delay of 1 microsecond.  Really this
-  ** is more of a scheduler yield than an actual delay.  But on the 10th
-  ** an subsequent retries, the delays start becoming longer and longer, 
-  ** so that on the 100th (and last) RETRY we delay for 21 milliseconds.
-  ** The total delay time before giving up is less than 1 second.
-  */
-  if( cnt>5 ){
-    int nDelay = 1;                      /* Pause time in microseconds */
-    if( cnt>100 ){
-      VVA_ONLY( pWal->lockError = 1; )
-      return SQLITE_PROTOCOL;
-    }
-    if( cnt>=10 ) nDelay = (cnt-9)*238;  /* Max delay 21ms. Total delay 996ms */
-    sqlite3OsSleep(pWal->pVfs, nDelay);
-  }
+  memset(aSub, 0, sizeof(aSub));
+  assert( nList<=HASHTABLE_NPAGE && nList>0 );
+  assert( HASHTABLE_NPAGE==(1<<(ArraySize(aSub)-1)) );
 
-  if( !useWal ){
-    rc = walIndexReadHdr(pWal, pChanged);
-    if( rc==SQLITE_BUSY ){
-      /* If there is not a recovery running in another thread or process
-      ** then convert BUSY errors to WAL_RETRY.  If recovery is known to
-      ** be running, convert BUSY to BUSY_RECOVERY.  There is a race here
-      ** which might cause WAL_RETRY to be returned even if BUSY_RECOVERY
-      ** would be technically correct.  But the race is benign since with
-      ** WAL_RETRY this routine will be called again and will probably be
-      ** right on the second iteration.
-      */
-      if( pWal->apWiData[0]==0 ){
-        /* This branch is taken when the xShmMap() method returns SQLITE_BUSY.
-        ** We assume this is a transient condition, so return WAL_RETRY. The
-        ** xShmMap() implementation used by the default unix and win32 VFS 
-        ** modules may return SQLITE_BUSY due to a race condition in the 
-        ** code that determines whether or not the shared-memory region 
-        ** must be zeroed before the requested page is returned.
-        */
-        rc = WAL_RETRY;
-      }else if( SQLITE_OK==(rc = walLockShared(pWal, WAL_RECOVER_LOCK)) ){
-        walUnlockShared(pWal, WAL_RECOVER_LOCK);
-        rc = WAL_RETRY;
-      }else if( rc==SQLITE_BUSY ){
-        rc = SQLITE_BUSY_RECOVERY;
-      }
-    }
-    if( rc!=SQLITE_OK ){
-      return rc;
+  for(iList=0; iList<nList; iList++){
+    nMerge = 1;
+    aMerge = &aList[iList];
+    for(iSub=0; iList & (1<<iSub); iSub++){
+      struct Sublist *p = &aSub[iSub];
+      assert( p->aList && p->nList<=(1<<iSub) );
+      assert( p->aList==&aList[iList&~((2<<iSub)-1)] );
+      walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
     }
+    aSub[iSub].aList = aMerge;
+    aSub[iSub].nList = nMerge;
   }
 
-  pInfo = walCkptInfo(pWal);
-  if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame ){
-    /* The WAL has been completely backfilled (or it is empty).
-    ** and can be safely ignored.
-    */
-    rc = walLockShared(pWal, WAL_READ_LOCK(0));
-    walShmBarrier(pWal);
-    if( rc==SQLITE_OK ){
-      if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){
-        /* It is not safe to allow the reader to continue here if frames
-        ** may have been appended to the log before READ_LOCK(0) was obtained.
-        ** When holding READ_LOCK(0), the reader ignores the entire log file,
-        ** which implies that the database file contains a trustworthy
-        ** snapshoT. Since holding READ_LOCK(0) prevents a checkpoint from
-        ** happening, this is usually correct.
-        **
-        ** However, if frames have been appended to the log (or if the log 
-        ** is wrapped and written for that matter) before the READ_LOCK(0)
-        ** is obtained, that is not necessarily true. A checkpointer may
-        ** have started to backfill the appended frames but crashed before
-        ** it finished. Leaving a corrupt image in the database file.
-        */
-        walUnlockShared(pWal, WAL_READ_LOCK(0));
-        return WAL_RETRY;
-      }
-      pWal->readLock = 0;
-      return SQLITE_OK;
-    }else if( rc!=SQLITE_BUSY ){
-      return rc;
+  for(iSub++; iSub<ArraySize(aSub); iSub++){
+    if( nList & (1<<iSub) ){
+      struct Sublist *p = &aSub[iSub];
+      assert( p->nList<=(1<<iSub) );
+      assert( p->aList==&aList[nList&~((2<<iSub)-1)] );
+      walMerge(aContent, p->aList, p->nList, &aMerge, &nMerge, aBuffer);
     }
   }
+  assert( aMerge==aList );
+  *pnList = nMerge;
 
-  /* If we get this far, it means that the reader will want to use
-  ** the WAL to get at content from recent commits.  The job now is
-  ** to select one of the aReadMark[] entries that is closest to
-  ** but not exceeding pWal->hdr.mxFrame and lock that entry.
-  */
-  mxReadMark = 0;
-  mxI = 0;
-  for(i=1; i<WAL_NREADER; i++){
-    u32 thisMark = pInfo->aReadMark[i];
-    if( mxReadMark<=thisMark && thisMark<=pWal->hdr.mxFrame ){
-      assert( thisMark!=READMARK_NOT_USED );
-      mxReadMark = thisMark;
-      mxI = i;
-    }
-  }
-  /* There was once an "if" here. The extra "{" is to preserve indentation. */
+#ifdef SQLITE_DEBUG
   {
-    if( (pWal->readOnly & WAL_SHM_RDONLY)==0
-     && (mxReadMark<pWal->hdr.mxFrame || mxI==0)
-    ){
-      for(i=1; i<WAL_NREADER; i++){
-        rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
-        if( rc==SQLITE_OK ){
-          mxReadMark = pInfo->aReadMark[i] = pWal->hdr.mxFrame;
-          mxI = i;
-          walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
-          break;
-        }else if( rc!=SQLITE_BUSY ){
-          return rc;
-        }
-      }
-    }
-    if( mxI==0 ){
-      assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
-      return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
-    }
-
-    rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
-    if( rc ){
-      return rc==SQLITE_BUSY ? WAL_RETRY : rc;
-    }
-    /* Now that the read-lock has been obtained, check that neither the
-    ** value in the aReadMark[] array or the contents of the wal-index
-    ** header have changed.
-    **
-    ** It is necessary to check that the wal-index header did not change
-    ** between the time it was read and when the shared-lock was obtained
-    ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
-    ** that the log file may have been wrapped by a writer, or that frames
-    ** that occur later in the log than pWal->hdr.mxFrame may have been
-    ** copied into the database by a checkpointer. If either of these things
-    ** happened, then reading the database with the current value of
-    ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
-    ** instead.
-    **
-    ** This does not guarantee that the copy of the wal-index header is up to
-    ** date before proceeding. That would not be possible without somehow
-    ** blocking writers. It only guarantees that a dangerous checkpoint or 
-    ** log-wrap (either of which would require an exclusive lock on
-    ** WAL_READ_LOCK(mxI)) has not occurred since the snapshot was valid.
-    */
-    walShmBarrier(pWal);
-    if( pInfo->aReadMark[mxI]!=mxReadMark
-     || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
-    ){
-      walUnlockShared(pWal, WAL_READ_LOCK(mxI));
-      return WAL_RETRY;
-    }else{
-      assert( mxReadMark<=pWal->hdr.mxFrame );
-      pWal->readLock = (i16)mxI;
+    int i;
+    for(i=1; i<*pnList; i++){
+      assert( aContent[aList[i]] > aContent[aList[i-1]] );
     }
   }
-  return rc;
-}
-
-/*
-** Begin a read transaction on the database.
-**
-** This routine used to be called sqlite3OpenSnapshot() and with good reason:
-** it takes a snapshot of the state of the WAL and wal-index for the current
-** instant in time.  The current thread will continue to use this snapshot.
-** Other threads might append new content to the WAL and wal-index but
-** that extra content is ignored by the current thread.
-**
-** If the database contents have changes since the previous read
-** transaction, then *pChanged is set to 1 before returning.  The
-** Pager layer will use this to know that is cache is stale and
-** needs to be flushed.
-*/
-SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
-  int rc;                         /* Return code */
-  int cnt = 0;                    /* Number of TryBeginRead attempts */
-
-  do{
-    rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
-  }while( rc==WAL_RETRY );
-  testcase( (rc&0xff)==SQLITE_BUSY );
-  testcase( (rc&0xff)==SQLITE_IOERR );
-  testcase( rc==SQLITE_PROTOCOL );
-  testcase( rc==SQLITE_OK );
-  return rc;
+#endif
 }
 
-/*
-** Finish with a read transaction.  All this does is release the
-** read-lock.
+/* 
+** Free an iterator allocated by walIteratorInit().
 */
-SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
-  sqlite3WalEndWriteTransaction(pWal);
-  if( pWal->readLock>=0 ){
-    walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
-    pWal->readLock = -1;
-  }
+static void walIteratorFree(WalIterator *p){
+  sqlite3ScratchFree(p);
 }
 
 /*
-** Search the wal file for page pgno. If found, set *piRead to the frame that
-** contains the page. Otherwise, if pgno is not in the wal file, set *piRead
-** to zero.
+** Construct a WalInterator object that can be used to loop over all 
+** pages in the WAL in ascending order. The caller must hold the checkpoint
+** lock.
 **
-** Return SQLITE_OK if successful, or an error code if an error occurs. If an
-** error does occur, the final value of *piRead is undefined.
+** On success, make *pp point to the newly allocated WalInterator object
+** return SQLITE_OK. Otherwise, return an error code. If this routine
+** returns an error, the value of *pp is undefined.
+**
+** The calling routine should invoke walIteratorFree() to destroy the
+** WalIterator object when it has finished with it.
 */
-SQLITE_PRIVATE int sqlite3WalFindFrame(
-  Wal *pWal,                      /* WAL handle */
-  Pgno pgno,                      /* Database page number to read data for */
-  u32 *piRead                     /* OUT: Frame number (or zero) */
-){
-  u32 iRead = 0;                  /* If !=0, WAL frame to return data from */
-  u32 iLast = pWal->hdr.mxFrame;  /* Last page in WAL for this reader */
-  int iHash;                      /* Used to loop through N hash tables */
-
-  /* This routine is only be called from within a read transaction. */
-  assert( pWal->readLock>=0 || pWal->lockError );
+static int walIteratorInit(Wal *pWal, WalIterator **pp){
+  WalIterator *p;                 /* Return value */
+  int nSegment;                   /* Number of segments to merge */
+  u32 iLast;                      /* Last frame in log */
+  int nByte;                      /* Number of bytes to allocate */
+  int i;                          /* Iterator variable */
+  ht_slot *aTmp;                  /* Temp space used by merge-sort */
+  int rc = SQLITE_OK;             /* Return Code */
 
-  /* If the "last page" field of the wal-index header snapshot is 0, then
-  ** no data will be read from the wal under any circumstances. Return early
-  ** in this case as an optimization.  Likewise, if pWal->readLock==0, 
-  ** then the WAL is ignored by the reader so return early, as if the 
-  ** WAL were empty.
+  /* This routine only runs while holding the checkpoint lock. And
+  ** it only runs if there is actually content in the log (mxFrame>0).
   */
-  if( iLast==0 || pWal->readLock==0 ){
-    *piRead = 0;
-    return SQLITE_OK;
+  assert( pWal->ckptLock && pWal->hdr.mxFrame>0 );
+  iLast = pWal->hdr.mxFrame;
+
+  /* Allocate space for the WalIterator object. */
+  nSegment = walFramePage(iLast) + 1;
+  nByte = sizeof(WalIterator) 
+        + (nSegment-1)*sizeof(struct WalSegment)
+        + iLast*sizeof(ht_slot);
+  p = (WalIterator *)sqlite3ScratchMalloc(nByte);
+  if( !p ){
+    return SQLITE_NOMEM;
   }
+  memset(p, 0, nByte);
+  p->nSegment = nSegment;
 
-  /* Search the hash table or tables for an entry matching page number
-  ** pgno. Each iteration of the following for() loop searches one
-  ** hash table (each hash table indexes up to HASHTABLE_NPAGE frames).
-  **
-  ** This code might run concurrently to the code in walIndexAppend()
-  ** that adds entries to the wal-index (and possibly to this hash 
-  ** table). This means the value just read from the hash 
-  ** slot (aHash[iKey]) may have been added before or after the 
-  ** current read transaction was opened. Values added after the
-  ** read transaction was opened may have been written incorrectly -
-  ** i.e. these slots may contain garbage data. However, we assume
-  ** that any slots written before the current read transaction was
-  ** opened remain unmodified.
-  **
-  ** For the reasons above, the if(...) condition featured in the inner
-  ** loop of the following block is more stringent that would be required 
-  ** if we had exclusive access to the hash-table:
-  **
-  **   (aPgno[iFrame]==pgno): 
-  **     This condition filters out normal hash-table collisions.
-  **
-  **   (iFrame<=iLast): 
-  **     This condition filters out entries that were added to the hash
-  **     table after the current read-transaction had started.
+  /* Allocate temporary space used by the merge-sort routine. This block
+  ** of memory will be freed before this function returns.
   */
-  for(iHash=walFramePage(iLast); iHash>=0 && iRead==0; iHash--){
-    volatile ht_slot *aHash;      /* Pointer to hash table */
-    volatile u32 *aPgno;          /* Pointer to array of page numbers */
-    u32 iZero;                    /* Frame number corresponding to aPgno[0] */
-    int iKey;                     /* Hash slot index */
-    int nCollide;                 /* Number of hash collisions remaining */
-    int rc;                       /* Error code */
+  aTmp = (ht_slot *)sqlite3ScratchMalloc(
+      sizeof(ht_slot) * (iLast>HASHTABLE_NPAGE?HASHTABLE_NPAGE:iLast)
+  );
+  if( !aTmp ){
+    rc = SQLITE_NOMEM;
+  }
 
-    rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
-    if( rc!=SQLITE_OK ){
-      return rc;
-    }
-    nCollide = HASHTABLE_NSLOT;
-    for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
-      u32 iFrame = aHash[iKey] + iZero;
-      if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
-        /* assert( iFrame>iRead ); -- not true if there is corruption */
-        iRead = iFrame;
+  for(i=0; rc==SQLITE_OK && i<nSegment; i++){
+    volatile ht_slot *aHash;
+    u32 iZero;
+    volatile u32 *aPgno;
+
+    rc = walHashGet(pWal, i, &aHash, &aPgno, &iZero);
+    if( rc==SQLITE_OK ){
+      int j;                      /* Counter variable */
+      int nEntry;                 /* Number of entries in this segment */
+      ht_slot *aIndex;            /* Sorted index for this segment */
+
+      aPgno++;
+      if( (i+1)==nSegment ){
+        nEntry = (int)(iLast - iZero);
+      }else{
+        nEntry = (int)((u32*)aHash - (u32*)aPgno);
       }
-      if( (nCollide--)==0 ){
-        return SQLITE_CORRUPT_BKPT;
+      aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[iZero];
+      iZero++;
+  
+      for(j=0; j<nEntry; j++){
+        aIndex[j] = (ht_slot)j;
       }
+      walMergesort((u32 *)aPgno, aTmp, aIndex, &nEntry);
+      p->aSegment[i].iZero = iZero;
+      p->aSegment[i].nEntry = nEntry;
+      p->aSegment[i].aIndex = aIndex;
+      p->aSegment[i].aPgno = (u32 *)aPgno;
     }
   }
+  sqlite3ScratchFree(aTmp);
 
-#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
-  /* If expensive assert() statements are available, do a linear search
-  ** of the wal-index file content. Make sure the results agree with the
-  ** result obtained using the hash indexes above.  */
-  {
-    u32 iRead2 = 0;
-    u32 iTest;
-    for(iTest=iLast; iTest>0; iTest--){
-      if( walFramePgno(pWal, iTest)==pgno ){
-        iRead2 = iTest;
-        break;
-      }
-    }
-    assert( iRead==iRead2 );
+  if( rc!=SQLITE_OK ){
+    walIteratorFree(p);
   }
-#endif
-
-  *piRead = iRead;
-  return SQLITE_OK;
+  *pp = p;
+  return rc;
 }
 
 /*
-** Read the contents of frame iRead from the wal file into buffer pOut
-** (which is nOut bytes in size). Return SQLITE_OK if successful, or an
-** error code otherwise.
+** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
+** n. If the attempt fails and parameter xBusy is not NULL, then it is a
+** busy-handler function. Invoke it and retry the lock until either the
+** lock is successfully obtained or the busy-handler returns 0.
 */
-SQLITE_PRIVATE int sqlite3WalReadFrame(
-  Wal *pWal,                      /* WAL handle */
-  u32 iRead,                      /* Frame to read */
-  int nOut,                       /* Size of buffer pOut in bytes */
-  u8 *pOut                        /* Buffer to write page data to */
+static int walBusyLock(
+  Wal *pWal,                      /* WAL connection */
+  int (*xBusy)(void*),            /* Function to call when busy */
+  void *pBusyArg,                 /* Context argument for xBusyHandler */
+  int lockIdx,                    /* Offset of first byte to lock */
+  int n                           /* Number of bytes to lock */
 ){
-  int sz;
-  i64 iOffset;
-  sz = pWal->hdr.szPage;
-  sz = (sz&0xfe00) + ((sz&0x0001)<<16);
-  testcase( sz<=32768 );
-  testcase( sz>=65536 );
-  iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
-  /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
-  return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
+  int rc;
+  do {
+    rc = walLockExclusive(pWal, lockIdx, n);
+  }while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
+  return rc;
 }
 
-/* 
-** Return the size of the database in pages (or zero, if unknown).
+/*
+** The cache of the wal-index header must be valid to call this function.
+** Return the page-size in bytes used by the database.
 */
-SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){
-  if( pWal && ALWAYS(pWal->readLock>=0) ){
-    return pWal->hdr.nPage;
-  }
-  return 0;
+static int walPagesize(Wal *pWal){
+  return (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
 }
 
-
-/* 
-** This function starts a write transaction on the WAL.
+/*
+** Copy as much content as we can from the WAL back into the database file
+** in response to an sqlite3_wal_checkpoint() request or the equivalent.
 **
-** A read transaction must have already been started by a prior call
-** to sqlite3WalBeginReadTransaction().
+** The amount of information copies from WAL to database might be limited
+** by active readers.  This routine will never overwrite a database page
+** that a concurrent reader might be using.
 **
-** If another thread or process has written into the database since
-** the read transaction was started, then it is not possible for this
-** thread to write as doing so would cause a fork.  So this routine
-** returns SQLITE_BUSY in that case and no write transaction is started.
+** All I/O barrier operations (a.k.a fsyncs) occur in this routine when
+** SQLite is in WAL-mode in synchronous=NORMAL.  That means that if 
+** checkpoints are always run by a background thread or background 
+** process, foreground threads will never block on a lengthy fsync call.
 **
-** There can only be a single writer active at a time.
+** Fsync is called on the WAL before writing content out of the WAL and
+** into the database.  This ensures that if the new content is persistent
+** in the WAL and can be recovered following a power-loss or hard reset.
+**
+** Fsync is also called on the database file if (and only if) the entire
+** WAL content is copied into the database file.  This second fsync makes
+** it safe to delete the WAL since the new content will persist in the
+** database file.
+**
+** This routine uses and updates the nBackfill field of the wal-index header.
+** This is the only routine tha will increase the value of nBackfill.  
+** (A WAL reset or recovery will revert nBackfill to zero, but not increase
+** its value.)
+**
+** The caller must be holding sufficient locks to ensure that no other
+** checkpoint is running (in any other thread or process) at the same
+** time.
 */
-SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
-  int rc;
-
-  /* Cannot start a write transaction without first holding a read
-  ** transaction. */
-  assert( pWal->readLock>=0 );
+static int walCheckpoint(
+  Wal *pWal,                      /* Wal connection */
+  int eMode,                      /* One of PASSIVE, FULL or RESTART */
+  int (*xBusyCall)(void*),        /* Function to call when busy */
+  void *pBusyArg,                 /* Context argument for xBusyHandler */
+  int sync_flags,                 /* Flags for OsSync() (or 0) */
+  u8 *zBuf                        /* Temporary buffer to use */
+){
+  int rc;                         /* Return code */
+  int szPage;                     /* Database page-size */
+  WalIterator *pIter = 0;         /* Wal iterator context */
+  u32 iDbpage = 0;                /* Next database page to write */
+  u32 iFrame = 0;                 /* Wal frame containing data for iDbpage */
+  u32 mxSafeFrame;                /* Max frame that can be backfilled */
+  u32 mxPage;                     /* Max database page to write */
+  int i;                          /* Loop counter */
+  volatile WalCkptInfo *pInfo;    /* The checkpoint status information */
+  int (*xBusy)(void*) = 0;        /* Function to call when waiting for locks */
 
-  if( pWal->readOnly ){
-    return SQLITE_READONLY;
-  }
+  szPage = walPagesize(pWal);
+  testcase( szPage<=32768 );
+  testcase( szPage>=65536 );
+  pInfo = walCkptInfo(pWal);
+  if( pInfo->nBackfill>=pWal->hdr.mxFrame ) return SQLITE_OK;
 
-  /* Only one writer allowed at a time.  Get the write lock.  Return
-  ** SQLITE_BUSY if unable.
-  */
-  rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
-  if( rc ){
+  /* Allocate the iterator */
+  rc = walIteratorInit(pWal, &pIter);
+  if( rc!=SQLITE_OK ){
     return rc;
   }
-  pWal->writeLock = 1;
+  assert( pIter );
 
-  /* If another connection has written to the database file since the
-  ** time the read transaction on this connection was started, then
-  ** the write is disallowed.
+  if( eMode!=SQLITE_CHECKPOINT_PASSIVE ) xBusy = xBusyCall;
+
+  /* Compute in mxSafeFrame the index of the last frame of the WAL that is
+  ** safe to write into the database.  Frames beyond mxSafeFrame might
+  ** overwrite database pages that are in use by active readers and thus
+  ** cannot be backfilled from the WAL.
   */
-  if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
-    walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
-    pWal->writeLock = 0;
-    rc = SQLITE_BUSY_SNAPSHOT;
+  mxSafeFrame = pWal->hdr.mxFrame;
+  mxPage = pWal->hdr.nPage;
+  for(i=1; i<WAL_NREADER; i++){
+    u32 y = pInfo->aReadMark[i];
+    if( mxSafeFrame>y ){
+      assert( y<=pWal->hdr.mxFrame );
+      rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
+      if( rc==SQLITE_OK ){
+        pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
+        walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+      }else if( rc==SQLITE_BUSY ){
+        mxSafeFrame = y;
+        xBusy = 0;
+      }else{
+        goto walcheckpoint_out;
+      }
+    }
   }
 
-  return rc;
-}
+  if( pInfo->nBackfill<mxSafeFrame
+   && (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0), 1))==SQLITE_OK
+  ){
+    i64 nSize;                    /* Current size of database file */
+    u32 nBackfill = pInfo->nBackfill;
 
-/*
-** End a write transaction.  The commit has already been done.  This
-** routine merely releases the lock.
-*/
-SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
-  if( pWal->writeLock ){
-    walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
-    pWal->writeLock = 0;
-    pWal->truncateOnCommit = 0;
-  }
-  return SQLITE_OK;
-}
+    /* Sync the WAL to disk */
+    if( sync_flags ){
+      rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
+    }
 
-/*
-** If any data has been written (but not committed) to the log file, this
-** function moves the write-pointer back to the start of the transaction.
-**
-** Additionally, the callback function is invoked for each frame written
-** to the WAL since the start of the transaction. If the callback returns
-** other than SQLITE_OK, it is not invoked again and the error code is
-** returned to the caller.
-**
-** Otherwise, if the callback function does not return an error, this
-** function returns SQLITE_OK.
-*/
-SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
-  int rc = SQLITE_OK;
-  if( ALWAYS(pWal->writeLock) ){
-    Pgno iMax = pWal->hdr.mxFrame;
-    Pgno iFrame;
-  
-    /* Restore the clients cache of the wal-index header to the state it
-    ** was in before the client began writing to the database. 
+    /* If the database may grow as a result of this checkpoint, hint
+    ** about the eventual size of the db file to the VFS layer.
     */
-    memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
-
-    for(iFrame=pWal->hdr.mxFrame+1; 
-        ALWAYS(rc==SQLITE_OK) && iFrame<=iMax; 
-        iFrame++
-    ){
-      /* This call cannot fail. Unless the page for which the page number
-      ** is passed as the second argument is (a) in the cache and 
-      ** (b) has an outstanding reference, then xUndo is either a no-op
-      ** (if (a) is false) or simply expels the page from the cache (if (b)
-      ** is false).
-      **
-      ** If the upper layer is doing a rollback, it is guaranteed that there
-      ** are no outstanding references to any page other than page 1. And
-      ** page 1 is never written to the log until the transaction is
-      ** committed. As a result, the call to xUndo may not fail.
-      */
-      assert( walFramePgno(pWal, iFrame)!=1 );
-      rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
+    if( rc==SQLITE_OK ){
+      i64 nReq = ((i64)mxPage * szPage);
+      rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
+      if( rc==SQLITE_OK && nSize<nReq ){
+        sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
+      }
     }
-    if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
-  }
-  assert( rc==SQLITE_OK );
-  return rc;
-}
 
-/* 
-** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32 
-** values. This function populates the array with values required to 
-** "rollback" the write position of the WAL handle back to the current 
-** point in the event of a savepoint rollback (via WalSavepointUndo()).
-*/
-SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){
-  assert( pWal->writeLock );
-  aWalData[0] = pWal->hdr.mxFrame;
-  aWalData[1] = pWal->hdr.aFrameCksum[0];
-  aWalData[2] = pWal->hdr.aFrameCksum[1];
-  aWalData[3] = pWal->nCkpt;
-}
 
-/* 
-** Move the write position of the WAL back to the point identified by
-** the values in the aWalData[] array. aWalData must point to an array
-** of WAL_SAVEPOINT_NDATA u32 values that has been previously populated
-** by a call to WalSavepoint().
-*/
-SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
-  int rc = SQLITE_OK;
+    /* Iterate through the contents of the WAL, copying data to the db file. */
+    while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
+      i64 iOffset;
+      assert( walFramePgno(pWal, iFrame)==iDbpage );
+      if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
+      iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
+      /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
+      rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);
+      if( rc!=SQLITE_OK ) break;
+      iOffset = (iDbpage-1)*(i64)szPage;
+      testcase( IS_BIG_INT(iOffset) );
+      rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset);
+      if( rc!=SQLITE_OK ) break;
+    }
 
-  assert( pWal->writeLock );
-  assert( aWalData[3]!=pWal->nCkpt || aWalData[0]<=pWal->hdr.mxFrame );
+    /* If work was actually accomplished... */
+    if( rc==SQLITE_OK ){
+      if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
+        i64 szDb = pWal->hdr.nPage*(i64)szPage;
+        testcase( IS_BIG_INT(szDb) );
+        rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
+        if( rc==SQLITE_OK && sync_flags ){
+          rc = sqlite3OsSync(pWal->pDbFd, sync_flags);
+        }
+      }
+      if( rc==SQLITE_OK ){
+        pInfo->nBackfill = mxSafeFrame;
+      }
+    }
 
-  if( aWalData[3]!=pWal->nCkpt ){
-    /* This savepoint was opened immediately after the write-transaction
-    ** was started. Right after that, the writer decided to wrap around
-    ** to the start of the log. Update the savepoint values to match.
-    */
-    aWalData[0] = 0;
-    aWalData[3] = pWal->nCkpt;
+    /* Release the reader lock held while backfilling */
+    walUnlockExclusive(pWal, WAL_READ_LOCK(0), 1);
   }
 
-  if( aWalData[0]<pWal->hdr.mxFrame ){
-    pWal->hdr.mxFrame = aWalData[0];
-    pWal->hdr.aFrameCksum[0] = aWalData[1];
-    pWal->hdr.aFrameCksum[1] = aWalData[2];
-    walCleanupHash(pWal);
+  if( rc==SQLITE_BUSY ){
+    /* Reset the return code so as not to report a checkpoint failure
+    ** just because there are active readers.  */
+    rc = SQLITE_OK;
   }
 
-  return rc;
-}
-
-
-/*
-** This function is called just before writing a set of frames to the log
-** file (see sqlite3WalFrames()). It checks to see if, instead of appending
-** to the current log file, it is possible to overwrite the start of the
-** existing log file with the new frames (i.e. "reset" the log). If so,
-** it sets pWal->hdr.mxFrame to 0. Otherwise, pWal->hdr.mxFrame is left
-** unchanged.
-**
-** SQLITE_OK is returned if no error is encountered (regardless of whether
-** or not pWal->hdr.mxFrame is modified). An SQLite error code is returned
-** if an error occurs.
-*/
-static int walRestartLog(Wal *pWal){
-  int rc = SQLITE_OK;
-  int cnt;
-
-  if( pWal->readLock==0 ){
-    volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
-    assert( pInfo->nBackfill==pWal->hdr.mxFrame );
-    if( pInfo->nBackfill>0 ){
-      u32 salt1;
-      sqlite3_randomness(4, &salt1);
-      rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+  /* If this is an SQLITE_CHECKPOINT_RESTART operation, and the entire wal
+  ** file has been copied into the database file, then block until all
+  ** readers have finished using the wal file. This ensures that the next
+  ** process to write to the database restarts the wal file.
+  */
+  if( rc==SQLITE_OK && eMode!=SQLITE_CHECKPOINT_PASSIVE ){
+    assert( pWal->writeLock );
+    if( pInfo->nBackfill<pWal->hdr.mxFrame ){
+      rc = SQLITE_BUSY;
+    }else if( eMode==SQLITE_CHECKPOINT_RESTART ){
+      assert( mxSafeFrame==pWal->hdr.mxFrame );
+      rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(1), WAL_NREADER-1);
       if( rc==SQLITE_OK ){
-        /* If all readers are using WAL_READ_LOCK(0) (in other words if no
-        ** readers are currently using the WAL), then the transactions
-        ** frames will overwrite the start of the existing log. Update the
-        ** wal-index header to reflect this.
-        **
-        ** In theory it would be Ok to update the cache of the header only
-        ** at this point. But updating the actual wal-index header is also
-        ** safe and means there is no special case for sqlite3WalUndo()
-        ** to handle if this transaction is rolled back.
-        */
-        int i;                    /* Loop counter */
-        u32 *aSalt = pWal->hdr.aSalt;       /* Big-endian salt values */
-
-        pWal->nCkpt++;
-        pWal->hdr.mxFrame = 0;
-        sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
-        aSalt[1] = salt1;
-        walIndexWriteHdr(pWal);
-        pInfo->nBackfill = 0;
-        pInfo->aReadMark[1] = 0;
-        for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
-        assert( pInfo->aReadMark[0]==0 );
         walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
-      }else if( rc!=SQLITE_BUSY ){
-        return rc;
       }
     }
-    walUnlockShared(pWal, WAL_READ_LOCK(0));
-    pWal->readLock = -1;
-    cnt = 0;
-    do{
-      int notUsed;
-      rc = walTryBeginRead(pWal, &notUsed, 1, ++cnt);
-    }while( rc==WAL_RETRY );
-    assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */
-    testcase( (rc&0xff)==SQLITE_IOERR );
-    testcase( rc==SQLITE_PROTOCOL );
-    testcase( rc==SQLITE_OK );
   }
+
+ walcheckpoint_out:
+  walIteratorFree(pIter);
   return rc;
 }
 
 /*
-** Information about the current state of the WAL file and where
-** the next fsync should occur - passed from sqlite3WalFrames() into
-** walWriteToLog().
-*/
-typedef struct WalWriter {
-  Wal *pWal;                   /* The complete WAL information */
-  sqlite3_file *pFd;           /* The WAL file to which we write */
-  sqlite3_int64 iSyncPoint;    /* Fsync at this offset */
-  int syncFlags;               /* Flags for the fsync */
-  int szPage;                  /* Size of one page */
-} WalWriter;
-
-/*
-** Write iAmt bytes of content into the WAL file beginning at iOffset.
-** Do a sync when crossing the p->iSyncPoint boundary.
-**
-** In other words, if iSyncPoint is in between iOffset and iOffset+iAmt,
-** first write the part before iSyncPoint, then sync, then write the
-** rest.
+** If the WAL file is currently larger than nMax bytes in size, truncate
+** it to exactly nMax bytes. If an error occurs while doing so, ignore it.
 */
-static int walWriteToLog(
-  WalWriter *p,              /* WAL to write to */
-  void *pContent,            /* Content to be written */
-  int iAmt,                  /* Number of bytes to write */
-  sqlite3_int64 iOffset      /* Start writing at this offset */
-){
-  int rc;
-  if( iOffset<p->iSyncPoint && iOffset+iAmt>=p->iSyncPoint ){
-    int iFirstAmt = (int)(p->iSyncPoint - iOffset);
-    rc = sqlite3OsWrite(p->pFd, pContent, iFirstAmt, iOffset);
-    if( rc ) return rc;
-    iOffset += iFirstAmt;
-    iAmt -= iFirstAmt;
-    pContent = (void*)(iFirstAmt + (char*)pContent);
-    assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
-    rc = sqlite3OsSync(p->pFd, p->syncFlags);
-    if( iAmt==0 || rc ) return rc;
+static void walLimitSize(Wal *pWal, i64 nMax){
+  i64 sz;
+  int rx;
+  sqlite3BeginBenignMalloc();
+  rx = sqlite3OsFileSize(pWal->pWalFd, &sz);
+  if( rx==SQLITE_OK && (sz > nMax ) ){
+    rx = sqlite3OsTruncate(pWal->pWalFd, nMax);
+  }
+  sqlite3EndBenignMalloc();
+  if( rx ){
+    sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName);
   }
-  rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
-  return rc;
 }
 
 /*
-** Write out a single frame of the WAL
-*/
-static int walWriteOneFrame(
-  WalWriter *p,               /* Where to write the frame */
-  PgHdr *pPage,               /* The page of the frame to be written */
-  int nTruncate,              /* The commit flag.  Usually 0.  >0 for commit */
-  sqlite3_int64 iOffset       /* Byte offset at which to write */
-){
-  int rc;                         /* Result code from subfunctions */
-  void *pData;                    /* Data actually written */
-  u8 aFrame[WAL_FRAME_HDRSIZE];   /* Buffer to assemble frame-header in */
-#if defined(SQLITE_HAS_CODEC)
-  if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM;
-#else
-  pData = pPage->pData;
-#endif
-  walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
-  rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
-  if( rc ) return rc;
-  /* Write the page data */
-  rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame));
-  return rc;
-}
-
-/* 
-** Write a set of frames to the log. The caller must hold the write-lock
-** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
+** Close a connection to a log file.
 */
-SQLITE_PRIVATE int sqlite3WalFrames(
-  Wal *pWal,                      /* Wal handle to write to */
-  int szPage,                     /* Database page-size in bytes */
-  PgHdr *pList,                   /* List of dirty pages to write */
-  Pgno nTruncate,                 /* Database size after this commit */
-  int isCommit,                   /* True if this is a commit */
-  int sync_flags                  /* Flags to pass to OsSync() (or 0) */
+SQLITE_PRIVATE int sqlite3WalClose(
+  Wal *pWal,                      /* Wal to close */
+  int sync_flags,                 /* Flags to pass to OsSync() (or 0) */
+  int nBuf,
+  u8 *zBuf                        /* Buffer of at least nBuf bytes */
 ){
-  int rc;                         /* Used to catch return codes */
-  u32 iFrame;                     /* Next frame address */
-  PgHdr *p;                       /* Iterator to run through pList with. */
-  PgHdr *pLast = 0;               /* Last frame in list */
-  int nExtra = 0;                 /* Number of extra copies of last page */
-  int szFrame;                    /* The size of a single frame */
-  i64 iOffset;                    /* Next byte to write in WAL file */
-  WalWriter w;                    /* The writer */
-
-  assert( pList );
-  assert( pWal->writeLock );
+  int rc = SQLITE_OK;
+  if( pWal ){
+    int isDelete = 0;             /* True to unlink wal and wal-index files */
 
-  /* If this frame set completes a transaction, then nTruncate>0.  If
-  ** nTruncate==0 then this frame set does not complete the transaction. */
-  assert( (isCommit!=0)==(nTruncate!=0) );
+    /* If an EXCLUSIVE lock can be obtained on the database file (using the
+    ** ordinary, rollback-mode locking methods, this guarantees that the
+    ** connection associated with this log file is the only connection to
+    ** the database. In this case checkpoint the database and unlink both
+    ** the wal and wal-index files.
+    **
+    ** The EXCLUSIVE lock is not released before returning.
+    */
+    rc = sqlite3OsLock(pWal->pDbFd, SQLITE_LOCK_EXCLUSIVE);
+    if( rc==SQLITE_OK ){
+      if( pWal->exclusiveMode==WAL_NORMAL_MODE ){
+        pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
+      }
+      rc = sqlite3WalCheckpoint(
+          pWal, SQLITE_CHECKPOINT_PASSIVE, 0, 0, sync_flags, nBuf, zBuf, 0, 0
+      );
+      if( rc==SQLITE_OK ){
+        int bPersist = -1;
+        sqlite3OsFileControlHint(
+            pWal->pDbFd, SQLITE_FCNTL_PERSIST_WAL, &bPersist
+        );
+        if( bPersist!=1 ){
+          /* Try to delete the WAL file if the checkpoint completed and
+          ** fsyned (rc==SQLITE_OK) and if we are not in persistent-wal
+          ** mode (!bPersist) */
+          isDelete = 1;
+        }else if( pWal->mxWalSize>=0 ){
+          /* Try to truncate the WAL file to zero bytes if the checkpoint
+          ** completed and fsynced (rc==SQLITE_OK) and we are in persistent
+          ** WAL mode (bPersist) and if the PRAGMA journal_size_limit is a
+          ** non-negative value (pWal->mxWalSize>=0).  Note that we truncate
+          ** to zero bytes as truncating to the journal_size_limit might
+          ** leave a corrupt WAL file on disk. */
+          walLimitSize(pWal, 0);
+        }
+      }
+    }
 
-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
-  { int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){}
-    WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n",
-              pWal, cnt, pWal->hdr.mxFrame, isCommit ? "Commit" : "Spill"));
+    walIndexClose(pWal, isDelete);
+    sqlite3OsClose(pWal->pWalFd);
+    if( isDelete ){
+      sqlite3BeginBenignMalloc();
+      sqlite3OsDelete(pWal->pVfs, pWal->zWalName, 0);
+      sqlite3EndBenignMalloc();
+    }
+    WALTRACE(("WAL%p: closed\n", pWal));
+    sqlite3_free((void *)pWal->apWiData);
+    sqlite3_free(pWal);
   }
-#endif
+  return rc;
+}
 
-  /* See if it is possible to write these frames into the start of the
-  ** log file, instead of appending to it at pWal->hdr.mxFrame.
-  */
-  if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){
-    return rc;
-  }
+/*
+** Try to read the wal-index header.  Return 0 on success and 1 if
+** there is a problem.
+**
+** The wal-index is in shared memory.  Another thread or process might
+** be writing the header at the same time this procedure is trying to
+** read it, which might result in inconsistency.  A dirty read is detected
+** by verifying that both copies of the header are the same and also by
+** a checksum on the header.
+**
+** If and only if the read is consistent and the header is different from
+** pWal->hdr, then pWal->hdr is updated to the content of the new header
+** and *pChanged is set to 1.
+**
+** If the checksum cannot be verified return non-zero. If the header
+** is read successfully and the checksum verified, return zero.
+*/
+static int walIndexTryHdr(Wal *pWal, int *pChanged){
+  u32 aCksum[2];                  /* Checksum on the header content */
+  WalIndexHdr h1, h2;             /* Two copies of the header content */
+  WalIndexHdr volatile *aHdr;     /* Header in shared memory */
 
-  /* If this is the first frame written into the log, write the WAL
-  ** header to the start of the WAL file. See comments at the top of
-  ** this source file for a description of the WAL header format.
-  */
-  iFrame = pWal->hdr.mxFrame;
-  if( iFrame==0 ){
-    u8 aWalHdr[WAL_HDRSIZE];      /* Buffer to assemble wal-header in */
-    u32 aCksum[2];                /* Checksum for wal-header */
+  /* The first page of the wal-index must be mapped at this point. */
+  assert( pWal->nWiData>0 && pWal->apWiData[0] );
 
-    sqlite3Put4byte(&aWalHdr[0], (WAL_MAGIC | SQLITE_BIGENDIAN));
-    sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION);
-    sqlite3Put4byte(&aWalHdr[8], szPage);
-    sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt);
-    if( pWal->nCkpt==0 ) sqlite3_randomness(8, pWal->hdr.aSalt);
-    memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8);
-    walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum);
-    sqlite3Put4byte(&aWalHdr[24], aCksum[0]);
-    sqlite3Put4byte(&aWalHdr[28], aCksum[1]);
-    
-    pWal->szPage = szPage;
-    pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
-    pWal->hdr.aFrameCksum[0] = aCksum[0];
-    pWal->hdr.aFrameCksum[1] = aCksum[1];
-    pWal->truncateOnCommit = 1;
+  /* Read the header. This might happen concurrently with a write to the
+  ** same area of shared memory on a different CPU in a SMP,
+  ** meaning it is possible that an inconsistent snapshot is read
+  ** from the file. If this happens, return non-zero.
+  **
+  ** There are two copies of the header at the beginning of the wal-index.
+  ** When reading, read [0] first then [1].  Writes are in the reverse order.
+  ** Memory barriers are used to prevent the compiler or the hardware from
+  ** reordering the reads and writes.
+  */
+  aHdr = walIndexHdr(pWal);
+  memcpy(&h1, (void *)&aHdr[0], sizeof(h1));
+  walShmBarrier(pWal);
+  memcpy(&h2, (void *)&aHdr[1], sizeof(h2));
 
-    rc = sqlite3OsWrite(pWal->pWalFd, aWalHdr, sizeof(aWalHdr), 0);
-    WALTRACE(("WAL%p: wal-header write %s\n", pWal, rc ? "failed" : "ok"));
-    if( rc!=SQLITE_OK ){
-      return rc;
-    }
+  if( memcmp(&h1, &h2, sizeof(h1))!=0 ){
+    return 1;   /* Dirty read */
+  }  
+  if( h1.isInit==0 ){
+    return 1;   /* Malformed header - probably all zeros */
+  }
+  walChecksumBytes(1, (u8*)&h1, sizeof(h1)-sizeof(h1.aCksum), 0, aCksum);
+  if( aCksum[0]!=h1.aCksum[0] || aCksum[1]!=h1.aCksum[1] ){
+    return 1;   /* Checksum does not match */
+  }
 
-    /* Sync the header (unless SQLITE_IOCAP_SEQUENTIAL is true or unless
-    ** all syncing is turned off by PRAGMA synchronous=OFF).  Otherwise
-    ** an out-of-order write following a WAL restart could result in
-    ** database corruption.  See the ticket:
-    **
-    **     http://localhost:591/sqlite/info/ff5be73dee
-    */
-    if( pWal->syncHeader && sync_flags ){
-      rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
-      if( rc ) return rc;
-    }
+  if( memcmp(&pWal->hdr, &h1, sizeof(WalIndexHdr)) ){
+    *pChanged = 1;
+    memcpy(&pWal->hdr, &h1, sizeof(WalIndexHdr));
+    pWal->szPage = (pWal->hdr.szPage&0xfe00) + ((pWal->hdr.szPage&0x0001)<<16);
+    testcase( pWal->szPage<=32768 );
+    testcase( pWal->szPage>=65536 );
   }
-  assert( (int)pWal->szPage==szPage );
 
-  /* Setup information needed to write frames into the WAL */
-  w.pWal = pWal;
-  w.pFd = pWal->pWalFd;
-  w.iSyncPoint = 0;
-  w.syncFlags = sync_flags;
-  w.szPage = szPage;
-  iOffset = walFrameOffset(iFrame+1, szPage);
-  szFrame = szPage + WAL_FRAME_HDRSIZE;
+  /* The header was successfully read. Return zero. */
+  return 0;
+}
 
-  /* Write all frames into the log file exactly once */
-  for(p=pList; p; p=p->pDirty){
-    int nDbSize;   /* 0 normally.  Positive == commit flag */
-    iFrame++;
-    assert( iOffset==walFrameOffset(iFrame, szPage) );
-    nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
-    rc = walWriteOneFrame(&w, p, nDbSize, iOffset);
-    if( rc ) return rc;
-    pLast = p;
-    iOffset += szFrame;
-  }
+/*
+** Read the wal-index header from the wal-index and into pWal->hdr.
+** If the wal-header appears to be corrupt, try to reconstruct the
+** wal-index from the WAL before returning.
+**
+** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
+** changed by this opertion.  If pWal->hdr is unchanged, set *pChanged
+** to 0.
+**
+** If the wal-index header is successfully read, return SQLITE_OK. 
+** Otherwise an SQLite error code.
+*/
+static int walIndexReadHdr(Wal *pWal, int *pChanged){
+  int rc;                         /* Return code */
+  int badHdr;                     /* True if a header read failed */
+  volatile u32 *page0;            /* Chunk of wal-index containing header */
 
-  /* If this is the end of a transaction, then we might need to pad
-  ** the transaction and/or sync the WAL file.
-  **
-  ** Padding and syncing only occur if this set of frames complete a
-  ** transaction and if PRAGMA synchronous=FULL.  If synchronous==NORMAL
-  ** or synchonous==OFF, then no padding or syncing are needed.
-  **
-  ** If SQLITE_IOCAP_POWERSAFE_OVERWRITE is defined, then padding is not
-  ** needed and only the sync is done.  If padding is needed, then the
-  ** final frame is repeated (with its commit mark) until the next sector
-  ** boundary is crossed.  Only the part of the WAL prior to the last
-  ** sector boundary is synced; the part of the last frame that extends
-  ** past the sector boundary is written after the sync.
+  /* Ensure that page 0 of the wal-index (the page that contains the 
+  ** wal-index header) is mapped. Return early if an error occurs here.
   */
-  if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
-    if( pWal->padToSectorBoundary ){
-      int sectorSize = sqlite3SectorSize(pWal->pWalFd);
-      w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
-      while( iOffset<w.iSyncPoint ){
-        rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);
-        if( rc ) return rc;
-        iOffset += szFrame;
-        nExtra++;
-      }
-    }else{
-      rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK);
-    }
-  }
+  assert( pChanged );
+  rc = walIndexPage(pWal, 0, &page0);
+  if( rc!=SQLITE_OK ){
+    return rc;
+  };
+  assert( page0 || pWal->writeLock==0 );
 
-  /* If this frame set completes the first transaction in the WAL and
-  ** if PRAGMA journal_size_limit is set, then truncate the WAL to the
-  ** journal size limit, if possible.
+  /* If the first page of the wal-index has been mapped, try to read the
+  ** wal-index header immediately, without holding any lock. This usually
+  ** works, but may fail if the wal-index header is corrupt or currently 
+  ** being modified by another thread or process.
   */
-  if( isCommit && pWal->truncateOnCommit && pWal->mxWalSize>=0 ){
-    i64 sz = pWal->mxWalSize;
-    if( walFrameOffset(iFrame+nExtra+1, szPage)>pWal->mxWalSize ){
-      sz = walFrameOffset(iFrame+nExtra+1, szPage);
-    }
-    walLimitSize(pWal, sz);
-    pWal->truncateOnCommit = 0;
-  }
+  badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
 
-  /* Append data to the wal-index. It is not necessary to lock the 
-  ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index
-  ** guarantees that there are no other writers, and no data that may
-  ** be in use by existing readers is being overwritten.
+  /* If the first attempt failed, it might have been due to a race
+  ** with a writer.  So get a WRITE lock and try again.
   */
-  iFrame = pWal->hdr.mxFrame;
-  for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
-    iFrame++;
-    rc = walIndexAppend(pWal, iFrame, p->pgno);
-  }
-  while( rc==SQLITE_OK && nExtra>0 ){
-    iFrame++;
-    nExtra--;
-    rc = walIndexAppend(pWal, iFrame, pLast->pgno);
+  assert( badHdr==0 || pWal->writeLock==0 );
+  if( badHdr ){
+    if( pWal->readOnly & WAL_SHM_RDONLY ){
+      if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
+        walUnlockShared(pWal, WAL_WRITE_LOCK);
+        rc = SQLITE_READONLY_RECOVERY;
+      }
+    }else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
+      pWal->writeLock = 1;
+      if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
+        badHdr = walIndexTryHdr(pWal, pChanged);
+        if( badHdr ){
+          /* If the wal-index header is still malformed even while holding
+          ** a WRITE lock, it can only mean that the header is corrupted and
+          ** needs to be reconstructed.  So run recovery to do exactly that.
+          */
+          rc = walIndexRecover(pWal);
+          *pChanged = 1;
+        }
+      }
+      pWal->writeLock = 0;
+      walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+    }
   }
 
-  if( rc==SQLITE_OK ){
-    /* Update the private copy of the header. */
-    pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
-    testcase( szPage<=32768 );
-    testcase( szPage>=65536 );
-    pWal->hdr.mxFrame = iFrame;
-    if( isCommit ){
-      pWal->hdr.iChange++;
-      pWal->hdr.nPage = nTruncate;
-    }
-    /* If this is a commit, update the wal-index header too. */
-    if( isCommit ){
-      walIndexWriteHdr(pWal);
-      pWal->iCallback = iFrame;
-    }
+  /* If the header is read successfully, check the version number to make
+  ** sure the wal-index was not constructed with some future format that
+  ** this version of SQLite cannot understand.
+  */
+  if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
+    rc = SQLITE_CANTOPEN_BKPT;
   }
 
-  WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
   return rc;
 }
 
-/* 
-** This routine is called to implement sqlite3_wal_checkpoint() and
-** related interfaces.
+/*
+** This is the value that walTryBeginRead returns when it needs to
+** be retried.
+*/
+#define WAL_RETRY  (-1)
+
+/*
+** Attempt to start a read transaction.  This might fail due to a race or
+** other transient condition.  When that happens, it returns WAL_RETRY to
+** indicate to the caller that it is safe to retry immediately.
 **
-** Obtain a CHECKPOINT lock and then backfill as much information as
-** we can from WAL into the database.
+** On success return SQLITE_OK.  On a permanent failure (such an
+** I/O error or an SQLITE_BUSY because another process is running
+** recovery) return a positive error code.
 **
-** If parameter xBusy is not NULL, it is a pointer to a busy-handler
-** callback. In this case this function runs a blocking checkpoint.
+** The useWal parameter is true to force the use of the WAL and disable
+** the case where the WAL is bypassed because it has been completely
+** checkpointed.  If useWal==0 then this routine calls walIndexReadHdr() 
+** to make a copy of the wal-index header into pWal->hdr.  If the 
+** wal-index header has changed, *pChanged is set to 1 (as an indication 
+** to the caller that the local paget cache is obsolete and needs to be 
+** flushed.)  When useWal==1, the wal-index header is assumed to already
+** be loaded and the pChanged parameter is unused.
+**
+** The caller must set the cnt parameter to the number of prior calls to
+** this routine during the current read attempt that returned WAL_RETRY.
+** This routine will start taking more aggressive measures to clear the
+** race conditions after multiple WAL_RETRY returns, and after an excessive
+** number of errors will ultimately return SQLITE_PROTOCOL.  The
+** SQLITE_PROTOCOL return indicates that some other process has gone rogue
+** and is not honoring the locking protocol.  There is a vanishingly small
+** chance that SQLITE_PROTOCOL could be returned because of a run of really
+** bad luck when there is lots of contention for the wal-index, but that
+** possibility is so small that it can be safely neglected, we believe.
+**
+** On success, this routine obtains a read lock on 
+** WAL_READ_LOCK(pWal->readLock).  The pWal->readLock integer is
+** in the range 0 <= pWal->readLock < WAL_NREADER.  If pWal->readLock==(-1)
+** that means the Wal does not hold any read lock.  The reader must not
+** access any database page that is modified by a WAL frame up to and
+** including frame number aReadMark[pWal->readLock].  The reader will
+** use WAL frames up to and including pWal->hdr.mxFrame if pWal->readLock>0
+** Or if pWal->readLock==0, then the reader will ignore the WAL
+** completely and get all content directly from the database file.
+** If the useWal parameter is 1 then the WAL will never be ignored and
+** this routine will always set pWal->readLock>0 on success.
+** When the read transaction is completed, the caller must release the
+** lock on WAL_READ_LOCK(pWal->readLock) and set pWal->readLock to -1.
+**
+** This routine uses the nBackfill and aReadMark[] fields of the header
+** to select a particular WAL_READ_LOCK() that strives to let the
+** checkpoint process do as much work as possible.  This routine might
+** update values of the aReadMark[] array in the header, but if it does
+** so it takes care to hold an exclusive lock on the corresponding
+** WAL_READ_LOCK() while changing values.
 */
-SQLITE_PRIVATE int sqlite3WalCheckpoint(
-  Wal *pWal,                      /* Wal connection */
-  int eMode,                      /* PASSIVE, FULL or RESTART */
-  int (*xBusy)(void*),            /* Function to call when busy */
-  void *pBusyArg,                 /* Context argument for xBusyHandler */
-  int sync_flags,                 /* Flags to sync db file with (or 0) */
-  int nBuf,                       /* Size of temporary buffer */
-  u8 *zBuf,                       /* Temporary buffer to use */
-  int *pnLog,                     /* OUT: Number of frames in WAL */
-  int *pnCkpt                     /* OUT: Number of backfilled frames in WAL */
-){
-  int rc;                         /* Return code */
-  int isChanged = 0;              /* True if a new wal-index header is loaded */
-  int eMode2 = eMode;             /* Mode to pass to walCheckpoint() */
-
-  assert( pWal->ckptLock==0 );
-  assert( pWal->writeLock==0 );
+static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
+  volatile WalCkptInfo *pInfo;    /* Checkpoint information in wal-index */
+  u32 mxReadMark;                 /* Largest aReadMark[] value */
+  int mxI;                        /* Index of largest aReadMark[] value */
+  int i;                          /* Loop counter */
+  int rc = SQLITE_OK;             /* Return code  */
 
-  if( pWal->readOnly ) return SQLITE_READONLY;
-  WALTRACE(("WAL%p: checkpoint begins\n", pWal));
-  rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
-  if( rc ){
-    /* Usually this is SQLITE_BUSY meaning that another thread or process
-    ** is already running a checkpoint, or maybe a recovery.  But it might
-    ** also be SQLITE_IOERR. */
-    return rc;
-  }
-  pWal->ckptLock = 1;
+  assert( pWal->readLock<0 );     /* Not currently locked */
 
-  /* If this is a blocking-checkpoint, then obtain the write-lock as well
-  ** to prevent any writers from running while the checkpoint is underway.
-  ** This has to be done before the call to walIndexReadHdr() below.
+  /* Take steps to avoid spinning forever if there is a protocol error.
   **
-  ** If the writer lock cannot be obtained, then a passive checkpoint is
-  ** run instead. Since the checkpointer is not holding the writer lock,
-  ** there is no point in blocking waiting for any readers. Assuming no 
-  ** other error occurs, this function will return SQLITE_BUSY to the caller.
+  ** Circumstances that cause a RETRY should only last for the briefest
+  ** instances of time.  No I/O or other system calls are done while the
+  ** locks are held, so the locks should not be held for very long. But 
+  ** if we are unlucky, another process that is holding a lock might get
+  ** paged out or take a page-fault that is time-consuming to resolve, 
+  ** during the few nanoseconds that it is holding the lock.  In that case,
+  ** it might take longer than normal for the lock to free.
+  **
+  ** After 5 RETRYs, we begin calling sqlite3OsSleep().  The first few
+  ** calls to sqlite3OsSleep() have a delay of 1 microsecond.  Really this
+  ** is more of a scheduler yield than an actual delay.  But on the 10th
+  ** an subsequent retries, the delays start becoming longer and longer, 
+  ** so that on the 100th (and last) RETRY we delay for 21 milliseconds.
+  ** The total delay time before giving up is less than 1 second.
   */
-  if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
-    rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
+  if( cnt>5 ){
+    int nDelay = 1;                      /* Pause time in microseconds */
+    if( cnt>100 ){
+      VVA_ONLY( pWal->lockError = 1; )
+      return SQLITE_PROTOCOL;
+    }
+    if( cnt>=10 ) nDelay = (cnt-9)*238;  /* Max delay 21ms. Total delay 996ms */
+    sqlite3OsSleep(pWal->pVfs, nDelay);
+  }
+
+  if( !useWal ){
+    rc = walIndexReadHdr(pWal, pChanged);
+    if( rc==SQLITE_BUSY ){
+      /* If there is not a recovery running in another thread or process
+      ** then convert BUSY errors to WAL_RETRY.  If recovery is known to
+      ** be running, convert BUSY to BUSY_RECOVERY.  There is a race here
+      ** which might cause WAL_RETRY to be returned even if BUSY_RECOVERY
+      ** would be technically correct.  But the race is benign since with
+      ** WAL_RETRY this routine will be called again and will probably be
+      ** right on the second iteration.
+      */
+      if( pWal->apWiData[0]==0 ){
+        /* This branch is taken when the xShmMap() method returns SQLITE_BUSY.
+        ** We assume this is a transient condition, so return WAL_RETRY. The
+        ** xShmMap() implementation used by the default unix and win32 VFS 
+        ** modules may return SQLITE_BUSY due to a race condition in the 
+        ** code that determines whether or not the shared-memory region 
+        ** must be zeroed before the requested page is returned.
+        */
+        rc = WAL_RETRY;
+      }else if( SQLITE_OK==(rc = walLockShared(pWal, WAL_RECOVER_LOCK)) ){
+        walUnlockShared(pWal, WAL_RECOVER_LOCK);
+        rc = WAL_RETRY;
+      }else if( rc==SQLITE_BUSY ){
+        rc = SQLITE_BUSY_RECOVERY;
+      }
+    }
+    if( rc!=SQLITE_OK ){
+      return rc;
+    }
+  }
+
+  pInfo = walCkptInfo(pWal);
+  if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame ){
+    /* The WAL has been completely backfilled (or it is empty).
+    ** and can be safely ignored.
+    */
+    rc = walLockShared(pWal, WAL_READ_LOCK(0));
+    walShmBarrier(pWal);
     if( rc==SQLITE_OK ){
-      pWal->writeLock = 1;
-    }else if( rc==SQLITE_BUSY ){
-      eMode2 = SQLITE_CHECKPOINT_PASSIVE;
-      rc = SQLITE_OK;
+      if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){
+        /* It is not safe to allow the reader to continue here if frames
+        ** may have been appended to the log before READ_LOCK(0) was obtained.
+        ** When holding READ_LOCK(0), the reader ignores the entire log file,
+        ** which implies that the database file contains a trustworthy
+        ** snapshoT. Since holding READ_LOCK(0) prevents a checkpoint from
+        ** happening, this is usually correct.
+        **
+        ** However, if frames have been appended to the log (or if the log 
+        ** is wrapped and written for that matter) before the READ_LOCK(0)
+        ** is obtained, that is not necessarily true. A checkpointer may
+        ** have started to backfill the appended frames but crashed before
+        ** it finished. Leaving a corrupt image in the database file.
+        */
+        walUnlockShared(pWal, WAL_READ_LOCK(0));
+        return WAL_RETRY;
+      }
+      pWal->readLock = 0;
+      return SQLITE_OK;
+    }else if( rc!=SQLITE_BUSY ){
+      return rc;
     }
   }
 
-  /* Read the wal-index header. */
-  if( rc==SQLITE_OK ){
-    rc = walIndexReadHdr(pWal, &isChanged);
-    if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
-      sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
+  /* If we get this far, it means that the reader will want to use
+  ** the WAL to get at content from recent commits.  The job now is
+  ** to select one of the aReadMark[] entries that is closest to
+  ** but not exceeding pWal->hdr.mxFrame and lock that entry.
+  */
+  mxReadMark = 0;
+  mxI = 0;
+  for(i=1; i<WAL_NREADER; i++){
+    u32 thisMark = pInfo->aReadMark[i];
+    if( mxReadMark<=thisMark && thisMark<=pWal->hdr.mxFrame ){
+      assert( thisMark!=READMARK_NOT_USED );
+      mxReadMark = thisMark;
+      mxI = i;
     }
   }
+  /* There was once an "if" here. The extra "{" is to preserve indentation. */
+  {
+    if( (pWal->readOnly & WAL_SHM_RDONLY)==0
+     && (mxReadMark<pWal->hdr.mxFrame || mxI==0)
+    ){
+      for(i=1; i<WAL_NREADER; i++){
+        rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
+        if( rc==SQLITE_OK ){
+          mxReadMark = pInfo->aReadMark[i] = pWal->hdr.mxFrame;
+          mxI = i;
+          walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+          break;
+        }else if( rc!=SQLITE_BUSY ){
+          return rc;
+        }
+      }
+    }
+    if( mxI==0 ){
+      assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
+      return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
+    }
 
-  /* Copy data from the log to the database file. */
-  if( rc==SQLITE_OK ){
-    if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
-      rc = SQLITE_CORRUPT_BKPT;
+    rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
+    if( rc ){
+      return rc==SQLITE_BUSY ? WAL_RETRY : rc;
+    }
+    /* Now that the read-lock has been obtained, check that neither the
+    ** value in the aReadMark[] array or the contents of the wal-index
+    ** header have changed.
+    **
+    ** It is necessary to check that the wal-index header did not change
+    ** between the time it was read and when the shared-lock was obtained
+    ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
+    ** that the log file may have been wrapped by a writer, or that frames
+    ** that occur later in the log than pWal->hdr.mxFrame may have been
+    ** copied into the database by a checkpointer. If either of these things
+    ** happened, then reading the database with the current value of
+    ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
+    ** instead.
+    **
+    ** This does not guarantee that the copy of the wal-index header is up to
+    ** date before proceeding. That would not be possible without somehow
+    ** blocking writers. It only guarantees that a dangerous checkpoint or 
+    ** log-wrap (either of which would require an exclusive lock on
+    ** WAL_READ_LOCK(mxI)) has not occurred since the snapshot was valid.
+    */
+    walShmBarrier(pWal);
+    if( pInfo->aReadMark[mxI]!=mxReadMark
+     || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
+    ){
+      walUnlockShared(pWal, WAL_READ_LOCK(mxI));
+      return WAL_RETRY;
     }else{
-      rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags, zBuf);
-    }
-
-    /* If no error occurred, set the output variables. */
-    if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
-      if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
-      if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
+      assert( mxReadMark<=pWal->hdr.mxFrame );
+      pWal->readLock = (i16)mxI;
     }
   }
+  return rc;
+}
 
-  if( isChanged ){
-    /* If a new wal-index header was loaded before the checkpoint was 
-    ** performed, then the pager-cache associated with pWal is now
-    ** out of date. So zero the cached wal-index header to ensure that
-    ** next time the pager opens a snapshot on this database it knows that
-    ** the cache needs to be reset.
-    */
-    memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
-  }
+/*
+** Begin a read transaction on the database.
+**
+** This routine used to be called sqlite3OpenSnapshot() and with good reason:
+** it takes a snapshot of the state of the WAL and wal-index for the current
+** instant in time.  The current thread will continue to use this snapshot.
+** Other threads might append new content to the WAL and wal-index but
+** that extra content is ignored by the current thread.
+**
+** If the database contents have changes since the previous read
+** transaction, then *pChanged is set to 1 before returning.  The
+** Pager layer will use this to know that is cache is stale and
+** needs to be flushed.
+*/
+SQLITE_PRIVATE int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
+  int rc;                         /* Return code */
+  int cnt = 0;                    /* Number of TryBeginRead attempts */
 
-  /* Release the locks. */
-  sqlite3WalEndWriteTransaction(pWal);
-  walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
-  pWal->ckptLock = 0;
-  WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
-  return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
+  do{
+    rc = walTryBeginRead(pWal, pChanged, 0, ++cnt);
+  }while( rc==WAL_RETRY );
+  testcase( (rc&0xff)==SQLITE_BUSY );
+  testcase( (rc&0xff)==SQLITE_IOERR );
+  testcase( rc==SQLITE_PROTOCOL );
+  testcase( rc==SQLITE_OK );
+  return rc;
 }
 
-/* Return the value to pass to a sqlite3_wal_hook callback, the
-** number of frames in the WAL at the point of the last commit since
-** sqlite3WalCallback() was called.  If no commits have occurred since
-** the last call, then return 0.
+/*
+** Finish with a read transaction.  All this does is release the
+** read-lock.
 */
-SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
-  u32 ret = 0;
-  if( pWal ){
-    ret = pWal->iCallback;
-    pWal->iCallback = 0;
+SQLITE_PRIVATE void sqlite3WalEndReadTransaction(Wal *pWal){
+  sqlite3WalEndWriteTransaction(pWal);
+  if( pWal->readLock>=0 ){
+    walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
+    pWal->readLock = -1;
   }
-  return (int)ret;
 }
 
 /*
-** This function is called to change the WAL subsystem into or out
-** of locking_mode=EXCLUSIVE.
-**
-** If op is zero, then attempt to change from locking_mode=EXCLUSIVE
-** into locking_mode=NORMAL.  This means that we must acquire a lock
-** on the pWal->readLock byte.  If the WAL is already in locking_mode=NORMAL
-** or if the acquisition of the lock fails, then return 0.  If the
-** transition out of exclusive-mode is successful, return 1.  This
-** operation must occur while the pager is still holding the exclusive
-** lock on the main database file.
-**
-** If op is one, then change from locking_mode=NORMAL into 
-** locking_mode=EXCLUSIVE.  This means that the pWal->readLock must
-** be released.  Return 1 if the transition is made and 0 if the
-** WAL is already in exclusive-locking mode - meaning that this
-** routine is a no-op.  The pager must already hold the exclusive lock
-** on the main database file before invoking this operation.
+** Search the wal file for page pgno. If found, set *piRead to the frame that
+** contains the page. Otherwise, if pgno is not in the wal file, set *piRead
+** to zero.
 **
-** If op is negative, then do a dry-run of the op==1 case but do
-** not actually change anything. The pager uses this to see if it
-** should acquire the database exclusive lock prior to invoking
-** the op==1 case.
+** Return SQLITE_OK if successful, or an error code if an error occurs. If an
+** error does occur, the final value of *piRead is undefined.
 */
-SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
-  int rc;
-  assert( pWal->writeLock==0 );
-  assert( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE || op==-1 );
+SQLITE_PRIVATE int sqlite3WalFindFrame(
+  Wal *pWal,                      /* WAL handle */
+  Pgno pgno,                      /* Database page number to read data for */
+  u32 *piRead                     /* OUT: Frame number (or zero) */
+){
+  u32 iRead = 0;                  /* If !=0, WAL frame to return data from */
+  u32 iLast = pWal->hdr.mxFrame;  /* Last page in WAL for this reader */
+  int iHash;                      /* Used to loop through N hash tables */
 
-  /* pWal->readLock is usually set, but might be -1 if there was a 
-  ** prior error while attempting to acquire are read-lock. This cannot 
-  ** happen if the connection is actually in exclusive mode (as no xShmLock
-  ** locks are taken in this case). Nor should the pager attempt to
-  ** upgrade to exclusive-mode following such an error.
-  */
+  /* This routine is only be called from within a read transaction. */
   assert( pWal->readLock>=0 || pWal->lockError );
-  assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
 
-  if( op==0 ){
-    if( pWal->exclusiveMode ){
-      pWal->exclusiveMode = 0;
-      if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){
-        pWal->exclusiveMode = 1;
+  /* If the "last page" field of the wal-index header snapshot is 0, then
+  ** no data will be read from the wal under any circumstances. Return early
+  ** in this case as an optimization.  Likewise, if pWal->readLock==0, 
+  ** then the WAL is ignored by the reader so return early, as if the 
+  ** WAL were empty.
+  */
+  if( iLast==0 || pWal->readLock==0 ){
+    *piRead = 0;
+    return SQLITE_OK;
+  }
+
+  /* Search the hash table or tables for an entry matching page number
+  ** pgno. Each iteration of the following for() loop searches one
+  ** hash table (each hash table indexes up to HASHTABLE_NPAGE frames).
+  **
+  ** This code might run concurrently to the code in walIndexAppend()
+  ** that adds entries to the wal-index (and possibly to this hash 
+  ** table). This means the value just read from the hash 
+  ** slot (aHash[iKey]) may have been added before or after the 
+  ** current read transaction was opened. Values added after the
+  ** read transaction was opened may have been written incorrectly -
+  ** i.e. these slots may contain garbage data. However, we assume
+  ** that any slots written before the current read transaction was
+  ** opened remain unmodified.
+  **
+  ** For the reasons above, the if(...) condition featured in the inner
+  ** loop of the following block is more stringent that would be required 
+  ** if we had exclusive access to the hash-table:
+  **
+  **   (aPgno[iFrame]==pgno): 
+  **     This condition filters out normal hash-table collisions.
+  **
+  **   (iFrame<=iLast): 
+  **     This condition filters out entries that were added to the hash
+  **     table after the current read-transaction had started.
+  */
+  for(iHash=walFramePage(iLast); iHash>=0 && iRead==0; iHash--){
+    volatile ht_slot *aHash;      /* Pointer to hash table */
+    volatile u32 *aPgno;          /* Pointer to array of page numbers */
+    u32 iZero;                    /* Frame number corresponding to aPgno[0] */
+    int iKey;                     /* Hash slot index */
+    int nCollide;                 /* Number of hash collisions remaining */
+    int rc;                       /* Error code */
+
+    rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
+    if( rc!=SQLITE_OK ){
+      return rc;
+    }
+    nCollide = HASHTABLE_NSLOT;
+    for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
+      u32 iFrame = aHash[iKey] + iZero;
+      if( iFrame<=iLast && aPgno[aHash[iKey]]==pgno ){
+        /* assert( iFrame>iRead ); -- not true if there is corruption */
+        iRead = iFrame;
+      }
+      if( (nCollide--)==0 ){
+        return SQLITE_CORRUPT_BKPT;
       }
-      rc = pWal->exclusiveMode==0;
-    }else{
-      /* Already in locking_mode=NORMAL */
-      rc = 0;
     }
-  }else if( op>0 ){
-    assert( pWal->exclusiveMode==0 );
-    assert( pWal->readLock>=0 );
-    walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
-    pWal->exclusiveMode = 1;
-    rc = 1;
-  }else{
-    rc = pWal->exclusiveMode==0;
   }
-  return rc;
+
+#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
+  /* If expensive assert() statements are available, do a linear search
+  ** of the wal-index file content. Make sure the results agree with the
+  ** result obtained using the hash indexes above.  */
+  {
+    u32 iRead2 = 0;
+    u32 iTest;
+    for(iTest=iLast; iTest>0; iTest--){
+      if( walFramePgno(pWal, iTest)==pgno ){
+        iRead2 = iTest;
+        break;
+      }
+    }
+    assert( iRead==iRead2 );
+  }
+#endif
+
+  *piRead = iRead;
+  return SQLITE_OK;
 }
 
-/* 
-** Return true if the argument is non-NULL and the WAL module is using
-** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
-** WAL module is using shared-memory, return false. 
+/*
+** Read the contents of frame iRead from the wal file into buffer pOut
+** (which is nOut bytes in size). Return SQLITE_OK if successful, or an
+** error code otherwise.
 */
-SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
-  return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
+SQLITE_PRIVATE int sqlite3WalReadFrame(
+  Wal *pWal,                      /* WAL handle */
+  u32 iRead,                      /* Frame to read */
+  int nOut,                       /* Size of buffer pOut in bytes */
+  u8 *pOut                        /* Buffer to write page data to */
+){
+  int sz;
+  i64 iOffset;
+  sz = pWal->hdr.szPage;
+  sz = (sz&0xfe00) + ((sz&0x0001)<<16);
+  testcase( sz<=32768 );
+  testcase( sz>=65536 );
+  iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
+  /* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
+  return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
 }
 
-#ifdef SQLITE_ENABLE_ZIPVFS
-/*
-** If the argument is not NULL, it points to a Wal object that holds a
-** read-lock. This function returns the database page-size if it is known,
-** or zero if it is not (or if pWal is NULL).
+/* 
+** Return the size of the database in pages (or zero, if unknown).
 */
-SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
-  assert( pWal==0 || pWal->readLock>=0 );
-  return (pWal ? pWal->szPage : 0);
+SQLITE_PRIVATE Pgno sqlite3WalDbsize(Wal *pWal){
+  if( pWal && ALWAYS(pWal->readLock>=0) ){
+    return pWal->hdr.nPage;
+  }
+  return 0;
 }
-#endif
 
-#endif /* #ifndef SQLITE_OMIT_WAL */
 
-/************** End of wal.c *************************************************/
-/************** Begin file btmutex.c *****************************************/
-/*
-** 2007 August 27
-**
-** The author disclaims copyright to this source code.  In place of
-** a legal notice, here is a blessing:
+/* 
+** This function starts a write transaction on the WAL.
 **
-**    May you do good and not evil.
-**    May you find forgiveness for yourself and forgive others.
-**    May you share freely, never taking more than you give.
+** A read transaction must have already been started by a prior call
+** to sqlite3WalBeginReadTransaction().
 **
-*************************************************************************
+** If another thread or process has written into the database since
+** the read transaction was started, then it is not possible for this
+** thread to write as doing so would cause a fork.  So this routine
+** returns SQLITE_BUSY in that case and no write transaction is started.
 **
-** This file contains code used to implement mutexes on Btree objects.
-** This code really belongs in btree.c.  But btree.c is getting too
-** big and we want to break it down some.  This packaged seemed like
-** a good breakout.
+** There can only be a single writer active at a time.
 */
-/************** Include btreeInt.h in the middle of btmutex.c ****************/
-/************** Begin file btreeInt.h ****************************************/
-/*
-** 2004 April 6
-**
-** The author disclaims copyright to this source code.  In place of
-** a legal notice, here is a blessing:
-**
-**    May you do good and not evil.
-**    May you find forgiveness for yourself and forgive others.
-**    May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This file implements a external (disk-based) database using BTrees.
-** For a detailed discussion of BTrees, refer to
-**
-**     Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
-**     "Sorting And Searching", pages 473-480. Addison-Wesley
-**     Publishing Company, Reading, Massachusetts.
-**
-** The basic idea is that each page of the file contains N database
-** entries and N+1 pointers to subpages.
-**
-**   ----------------------------------------------------------------
-**   |  Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) |
-**   ----------------------------------------------------------------
-**
-** All of the keys on the page that Ptr(0) points to have values less
-** than Key(0).  All of the keys on page Ptr(1) and its subpages have
-** values greater than Key(0) and less than Key(1).  All of the keys
-** on Ptr(N) and its subpages have values greater than Key(N-1).  And
-** so forth.
-**
-** Finding a particular key requires reading O(log(M)) pages from the 
-** disk where M is the number of entries in the tree.
-**
-** In this implementation, a single file can hold one or more separate 
-** BTrees.  Each BTree is identified by the index of its root page.  The
-** key and data for any entry are combined to form the "payload".  A
-** fixed amount of payload can be carried directly on the database
-** page.  If the payload is larger than the preset amount then surplus
-** bytes are stored on overflow pages.  The payload for an entry
-** and the preceding pointer are combined to form a "Cell".  Each 
-** page has a small header which contains the Ptr(N) pointer and other
-** information such as the size of key and data.
-**
-** FORMAT DETAILS
-**
-** The file is divided into pages.  The first page is called page 1,
-** the second is page 2, and so forth.  A page number of zero indicates
-** "no such page".  The page size can be any power of 2 between 512 and 65536.
-** Each page can be either a btree page, a freelist page, an overflow
-** page, or a pointer-map page.
-**
-** The first page is always a btree page.  The first 100 bytes of the first
-** page contain a special header (the "file header") that describes the file.
-** The format of the file header is as follows:
-**
-**   OFFSET   SIZE    DESCRIPTION
-**      0      16     Header string: "SQLite format 3\000"
-**     16       2     Page size in bytes.  
-**     18       1     File format write version
-**     19       1     File format read version
-**     20       1     Bytes of unused space at the end of each page
-**     21       1     Max embedded payload fraction
-**     22       1     Min embedded payload fraction
-**     23       1     Min leaf payload fraction
-**     24       4     File change counter
-**     28       4     Reserved for future use
-**     32       4     First freelist page
-**     36       4     Number of freelist pages in the file
-**     40      60     15 4-byte meta values passed to higher layers
-**
-**     40       4     Schema cookie
-**     44       4     File format of schema layer
-**     48       4     Size of page cache
-**     52       4     Largest root-page (auto/incr_vacuum)
-**     56       4     1=UTF-8 2=UTF16le 3=UTF16be
-**     60       4     User version
-**     64       4     Incremental vacuum mode
-**     68       4     unused
-**     72       4     unused
-**     76       4     unused
-**
-** All of the integer values are big-endian (most significant byte first).
-**
-** The file change counter is incremented when the database is changed
-** This counter allows other processes to know when the file has changed
-** and thus when they need to flush their cache.
-**
-** The max embedded payload fraction is the amount of the total usable
-** space in a page that can be consumed by a single cell for standard
-** B-tree (non-LEAFDATA) tables.  A value of 255 means 100%.  The default
-** is to limit the maximum cell size so that at least 4 cells will fit
-** on one page.  Thus the default max embedded payload fraction is 64.
-**
-** If the payload for a cell is larger than the max payload, then extra
-** payload is spilled to overflow pages.  Once an overflow page is allocated,
-** as many bytes as possible are moved into the overflow pages without letting
-** the cell size drop below the min embedded payload fraction.
-**
-** The min leaf payload fraction is like the min embedded payload fraction
-** except that it applies to leaf nodes in a LEAFDATA tree.  The maximum
-** payload fraction for a LEAFDATA tree is always 100% (or 255) and it
-** not specified in the header.
-**
-** Each btree pages is divided into three sections:  The header, the
-** cell pointer array, and the cell content area.  Page 1 also has a 100-byte
-** file header that occurs before the page header.
-**
-**      |----------------|
-**      | file header    |   100 bytes.  Page 1 only.
-**      |----------------|
-**      | page header    |   8 bytes for leaves.  12 bytes for interior nodes
-**      |----------------|
-**      | cell pointer   |   |  2 bytes per cell.  Sorted order.
-**      | array          |   |  Grows downward
-**      |                |   v
-**      |----------------|
-**      | unallocated    |
-**      | space          |
-**      |----------------|   ^  Grows upwards
-**      | cell content   |   |  Arbitrary order interspersed with freeblocks.
-**      | area           |   |  and free space fragments.
-**      |----------------|
-**
-** The page headers looks like this:
-**
-**   OFFSET   SIZE     DESCRIPTION
-**      0       1      Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf
-**      1       2      byte offset to the first freeblock
-**      3       2      number of cells on this page
-**      5       2      first byte of the cell content area
-**      7       1      number of fragmented free bytes
-**      8       4      Right child (the Ptr(N) value).  Omitted on leaves.
-**
-** The flags define the format of this btree page.  The leaf flag means that
-** this page has no children.  The zerodata flag means that this page carries
-** only keys and no data.  The intkey flag means that the key is a integer
-** which is stored in the key size entry of the cell header rather than in
-** the payload area.
-**
-** The cell pointer array begins on the first byte after the page header.
-** The cell pointer array contains zero or more 2-byte numbers which are
-** offsets from the beginning of the page to the cell content in the cell
-** content area.  The cell pointers occur in sorted order.  The system strives
-** to keep free space after the last cell pointer so that new cells can
-** be easily added without having to defragment the page.
-**
-** Cell content is stored at the very end of the page and grows toward the
-** beginning of the page.
-**
-** Unused space within the cell content area is collected into a linked list of
-** freeblocks.  Each freeblock is at least 4 bytes in size.  The byte offset
-** to the first freeblock is given in the header.  Freeblocks occur in
-** increasing order.  Because a freeblock must be at least 4 bytes in size,
-** any group of 3 or fewer unused bytes in the cell content area cannot
-** exist on the freeblock chain.  A group of 3 or fewer free bytes is called
-** a fragment.  The total number of bytes in all fragments is recorded.
-** in the page header at offset 7.
-**
-**    SIZE    DESCRIPTION
-**      2     Byte offset of the next freeblock
-**      2     Bytes in this freeblock
-**
-** Cells are of variable length.  Cells are stored in the cell content area at
-** the end of the page.  Pointers to the cells are in the cell pointer array
-** that immediately follows the page header.  Cells is not necessarily
-** contiguous or in order, but cell pointers are contiguous and in order.
-**
-** Cell content makes use of variable length integers.  A variable
-** length integer is 1 to 9 bytes where the lower 7 bits of each 
-** byte are used.  The integer consists of all bytes that have bit 8 set and
-** the first byte with bit 8 clear.  The most significant byte of the integer
-** appears first.  A variable-length integer may not be more than 9 bytes long.
-** As a special case, all 8 bytes of the 9th byte are used as data.  This
-** allows a 64-bit integer to be encoded in 9 bytes.
-**
-**    0x00                      becomes  0x00000000
-**    0x7f                      becomes  0x0000007f
-**    0x81 0x00                 becomes  0x00000080
-**    0x82 0x00                 becomes  0x00000100
-**    0x80 0x7f                 becomes  0x0000007f
-**    0x8a 0x91 0xd1 0xac 0x78  becomes  0x12345678
-**    0x81 0x81 0x81 0x81 0x01  becomes  0x10204081
-**
-** Variable length integers are used for rowids and to hold the number of
-** bytes of key and data in a btree cell.
-**
-** The content of a cell looks like this:
-**
-**    SIZE    DESCRIPTION
-**      4     Page number of the left child. Omitted if leaf flag is set.
-**     var    Number of bytes of data. Omitted if the zerodata flag is set.
-**     var    Number of bytes of key. Or the key itself if intkey flag is set.
-**      *     Payload
-**      4     First page of the overflow chain.  Omitted if no overflow
-**
-** Overflow pages form a linked list.  Each page except the last is completely
-** filled with data (pagesize - 4 bytes).  The last page can have as little
-** as 1 byte of data.
-**
-**    SIZE    DESCRIPTION
-**      4     Page number of next overflow page
-**      *     Data
+SQLITE_PRIVATE int sqlite3WalBeginWriteTransaction(Wal *pWal){
+  int rc;
+
+  /* Cannot start a write transaction without first holding a read
+  ** transaction. */
+  assert( pWal->readLock>=0 );
+
+  if( pWal->readOnly ){
+    return SQLITE_READONLY;
+  }
+
+  /* Only one writer allowed at a time.  Get the write lock.  Return
+  ** SQLITE_BUSY if unable.
+  */
+  rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
+  if( rc ){
+    return rc;
+  }
+  pWal->writeLock = 1;
+
+  /* If another connection has written to the database file since the
+  ** time the read transaction on this connection was started, then
+  ** the write is disallowed.
+  */
+  if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
+    walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+    pWal->writeLock = 0;
+    rc = SQLITE_BUSY_SNAPSHOT;
+  }
+
+  return rc;
+}
+
+/*
+** End a write transaction.  The commit has already been done.  This
+** routine merely releases the lock.
+*/
+SQLITE_PRIVATE int sqlite3WalEndWriteTransaction(Wal *pWal){
+  if( pWal->writeLock ){
+    walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
+    pWal->writeLock = 0;
+    pWal->truncateOnCommit = 0;
+  }
+  return SQLITE_OK;
+}
+
+/*
+** If any data has been written (but not committed) to the log file, this
+** function moves the write-pointer back to the start of the transaction.
 **
-** Freelist pages come in two subtypes: trunk pages and leaf pages.  The
-** file header points to the first in a linked list of trunk page.  Each trunk
-** page points to multiple leaf pages.  The content of a leaf page is
-** unspecified.  A trunk page looks like this:
+** Additionally, the callback function is invoked for each frame written
+** to the WAL since the start of the transaction. If the callback returns
+** other than SQLITE_OK, it is not invoked again and the error code is
+** returned to the caller.
 **
-**    SIZE    DESCRIPTION
-**      4     Page number of next trunk page
-**      4     Number of leaf pointers on this page
-**      *     zero or more pages numbers of leaves
+** Otherwise, if the callback function does not return an error, this
+** function returns SQLITE_OK.
 */
+SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
+  int rc = SQLITE_OK;
+  if( ALWAYS(pWal->writeLock) ){
+    Pgno iMax = pWal->hdr.mxFrame;
+    Pgno iFrame;
+  
+    /* Restore the clients cache of the wal-index header to the state it
+    ** was in before the client began writing to the database. 
+    */
+    memcpy(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr));
 
+    for(iFrame=pWal->hdr.mxFrame+1; 
+        ALWAYS(rc==SQLITE_OK) && iFrame<=iMax; 
+        iFrame++
+    ){
+      /* This call cannot fail. Unless the page for which the page number
+      ** is passed as the second argument is (a) in the cache and 
+      ** (b) has an outstanding reference, then xUndo is either a no-op
+      ** (if (a) is false) or simply expels the page from the cache (if (b)
+      ** is false).
+      **
+      ** If the upper layer is doing a rollback, it is guaranteed that there
+      ** are no outstanding references to any page other than page 1. And
+      ** page 1 is never written to the log until the transaction is
+      ** committed. As a result, the call to xUndo may not fail.
+      */
+      assert( walFramePgno(pWal, iFrame)!=1 );
+      rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
+    }
+    if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
+  }
+  assert( rc==SQLITE_OK );
+  return rc;
+}
 
-/* The following value is the maximum cell size assuming a maximum page
-** size give above.
+/* 
+** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32 
+** values. This function populates the array with values required to 
+** "rollback" the write position of the WAL handle back to the current 
+** point in the event of a savepoint rollback (via WalSavepointUndo()).
 */
-#define MX_CELL_SIZE(pBt)  ((int)(pBt->pageSize-8))
+SQLITE_PRIVATE void sqlite3WalSavepoint(Wal *pWal, u32 *aWalData){
+  assert( pWal->writeLock );
+  aWalData[0] = pWal->hdr.mxFrame;
+  aWalData[1] = pWal->hdr.aFrameCksum[0];
+  aWalData[2] = pWal->hdr.aFrameCksum[1];
+  aWalData[3] = pWal->nCkpt;
+}
 
-/* The maximum number of cells on a single page of the database.  This
-** assumes a minimum cell size of 6 bytes  (4 bytes for the cell itself
-** plus 2 bytes for the index to the cell in the page header).  Such
-** small cells will be rare, but they are possible.
+/* 
+** Move the write position of the WAL back to the point identified by
+** the values in the aWalData[] array. aWalData must point to an array
+** of WAL_SAVEPOINT_NDATA u32 values that has been previously populated
+** by a call to WalSavepoint().
 */
-#define MX_CELL(pBt) ((pBt->pageSize-8)/6)
+SQLITE_PRIVATE int sqlite3WalSavepointUndo(Wal *pWal, u32 *aWalData){
+  int rc = SQLITE_OK;
+
+  assert( pWal->writeLock );
+  assert( aWalData[3]!=pWal->nCkpt || aWalData[0]<=pWal->hdr.mxFrame );
+
+  if( aWalData[3]!=pWal->nCkpt ){
+    /* This savepoint was opened immediately after the write-transaction
+    ** was started. Right after that, the writer decided to wrap around
+    ** to the start of the log. Update the savepoint values to match.
+    */
+    aWalData[0] = 0;
+    aWalData[3] = pWal->nCkpt;
+  }
+
+  if( aWalData[0]<pWal->hdr.mxFrame ){
+    pWal->hdr.mxFrame = aWalData[0];
+    pWal->hdr.aFrameCksum[0] = aWalData[1];
+    pWal->hdr.aFrameCksum[1] = aWalData[2];
+    walCleanupHash(pWal);
+  }
+
+  return rc;
+}
 
-/* Forward declarations */
-typedef struct MemPage MemPage;
-typedef struct BtLock BtLock;
 
 /*
-** This is a magic string that appears at the beginning of every
-** SQLite database in order to identify the file as a real database.
+** This function is called just before writing a set of frames to the log
+** file (see sqlite3WalFrames()). It checks to see if, instead of appending
+** to the current log file, it is possible to overwrite the start of the
+** existing log file with the new frames (i.e. "reset" the log). If so,
+** it sets pWal->hdr.mxFrame to 0. Otherwise, pWal->hdr.mxFrame is left
+** unchanged.
 **
-** You can change this value at compile-time by specifying a
-** -DSQLITE_FILE_HEADER="..." on the compiler command-line.  The
-** header must be exactly 16 bytes including the zero-terminator so
-** the string itself should be 15 characters long.  If you change
-** the header, then your custom library will not be able to read 
-** databases generated by the standard tools and the standard tools
-** will not be able to read databases created by your custom library.
+** SQLITE_OK is returned if no error is encountered (regardless of whether
+** or not pWal->hdr.mxFrame is modified). An SQLite error code is returned
+** if an error occurs.
 */
-#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
-#  define SQLITE_FILE_HEADER "SQLite format 3"
-#endif
+static int walRestartLog(Wal *pWal){
+  int rc = SQLITE_OK;
+  int cnt;
+
+  if( pWal->readLock==0 ){
+    volatile WalCkptInfo *pInfo = walCkptInfo(pWal);
+    assert( pInfo->nBackfill==pWal->hdr.mxFrame );
+    if( pInfo->nBackfill>0 ){
+      u32 salt1;
+      sqlite3_randomness(4, &salt1);
+      rc = walLockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+      if( rc==SQLITE_OK ){
+        /* If all readers are using WAL_READ_LOCK(0) (in other words if no
+        ** readers are currently using the WAL), then the transactions
+        ** frames will overwrite the start of the existing log. Update the
+        ** wal-index header to reflect this.
+        **
+        ** In theory it would be Ok to update the cache of the header only
+        ** at this point. But updating the actual wal-index header is also
+        ** safe and means there is no special case for sqlite3WalUndo()
+        ** to handle if this transaction is rolled back.
+        */
+        int i;                    /* Loop counter */
+        u32 *aSalt = pWal->hdr.aSalt;       /* Big-endian salt values */
+
+        pWal->nCkpt++;
+        pWal->hdr.mxFrame = 0;
+        sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0]));
+        aSalt[1] = salt1;
+        walIndexWriteHdr(pWal);
+        pInfo->nBackfill = 0;
+        pInfo->aReadMark[1] = 0;
+        for(i=2; i<WAL_NREADER; i++) pInfo->aReadMark[i] = READMARK_NOT_USED;
+        assert( pInfo->aReadMark[0]==0 );
+        walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
+      }else if( rc!=SQLITE_BUSY ){
+        return rc;
+      }
+    }
+    walUnlockShared(pWal, WAL_READ_LOCK(0));
+    pWal->readLock = -1;
+    cnt = 0;
+    do{
+      int notUsed;
+      rc = walTryBeginRead(pWal, &notUsed, 1, ++cnt);
+    }while( rc==WAL_RETRY );
+    assert( (rc&0xff)!=SQLITE_BUSY ); /* BUSY not possible when useWal==1 */
+    testcase( (rc&0xff)==SQLITE_IOERR );
+    testcase( rc==SQLITE_PROTOCOL );
+    testcase( rc==SQLITE_OK );
+  }
+  return rc;
+}
 
 /*
-** Page type flags.  An ORed combination of these flags appear as the
-** first byte of on-disk image of every BTree page.
+** Information about the current state of the WAL file and where
+** the next fsync should occur - passed from sqlite3WalFrames() into
+** walWriteToLog().
 */
-#define PTF_INTKEY    0x01
-#define PTF_ZERODATA  0x02
-#define PTF_LEAFDATA  0x04
-#define PTF_LEAF      0x08
+typedef struct WalWriter {
+  Wal *pWal;                   /* The complete WAL information */
+  sqlite3_file *pFd;           /* The WAL file to which we write */
+  sqlite3_int64 iSyncPoint;    /* Fsync at this offset */
+  int syncFlags;               /* Flags for the fsync */
+  int szPage;                  /* Size of one page */
+} WalWriter;
 
 /*
-** As each page of the file is loaded into memory, an instance of the following
-** structure is appended and initialized to zero.  This structure stores
-** information about the page that is decoded from the raw file page.
-**
-** The pParent field points back to the parent page.  This allows us to
-** walk up the BTree from any leaf to the root.  Care must be taken to
-** unref() the parent page pointer when this page is no longer referenced.
-** The pageDestructor() routine handles that chore.
+** Write iAmt bytes of content into the WAL file beginning at iOffset.
+** Do a sync when crossing the p->iSyncPoint boundary.
 **
-** Access to all fields of this structure is controlled by the mutex
-** stored in MemPage.pBt->mutex.
+** In other words, if iSyncPoint is in between iOffset and iOffset+iAmt,
+** first write the part before iSyncPoint, then sync, then write the
+** rest.
 */
-struct MemPage {
-  u8 isInit;           /* True if previously initialized. MUST BE FIRST! */
-  u8 nOverflow;        /* Number of overflow cell bodies in aCell[] */
-  u8 intKey;           /* True if intkey flag is set */
-  u8 leaf;             /* True if leaf flag is set */
-  u8 hasData;          /* True if this page stores data */
-  u8 hdrOffset;        /* 100 for page 1.  0 otherwise */
-  u8 childPtrSize;     /* 0 if leaf==1.  4 if leaf==0 */
-  u8 max1bytePayload;  /* min(maxLocal,127) */
-  u16 maxLocal;        /* Copy of BtShared.maxLocal or BtShared.maxLeaf */
-  u16 minLocal;        /* Copy of BtShared.minLocal or BtShared.minLeaf */
-  u16 cellOffset;      /* Index in aData of first cell pointer */
-  u16 nFree;           /* Number of free bytes on the page */
-  u16 nCell;           /* Number of cells on this page, local and ovfl */
-  u16 maskPage;        /* Mask for page offset */
-  u16 aiOvfl[5];       /* Insert the i-th overflow cell before the aiOvfl-th
-                       ** non-overflow cell */
-  u8 *apOvfl[5];       /* Pointers to the body of overflow cells */
-  BtShared *pBt;       /* Pointer to BtShared that this page is part of */
-  u8 *aData;           /* Pointer to disk image of the page data */
-  u8 *aDataEnd;        /* One byte past the end of usable data */
-  u8 *aCellIdx;        /* The cell index area */
-  DbPage *pDbPage;     /* Pager page handle */
-  Pgno pgno;           /* Page number for this page */
-};
+static int walWriteToLog(
+  WalWriter *p,              /* WAL to write to */
+  void *pContent,            /* Content to be written */
+  int iAmt,                  /* Number of bytes to write */
+  sqlite3_int64 iOffset      /* Start writing at this offset */
+){
+  int rc;
+  if( iOffset<p->iSyncPoint && iOffset+iAmt>=p->iSyncPoint ){
+    int iFirstAmt = (int)(p->iSyncPoint - iOffset);
+    rc = sqlite3OsWrite(p->pFd, pContent, iFirstAmt, iOffset);
+    if( rc ) return rc;
+    iOffset += iFirstAmt;
+    iAmt -= iFirstAmt;
+    pContent = (void*)(iFirstAmt + (char*)pContent);
+    assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
+    rc = sqlite3OsSync(p->pFd, p->syncFlags);
+    if( iAmt==0 || rc ) return rc;
+  }
+  rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
+  return rc;
+}
 
 /*
-** The in-memory image of a disk page has the auxiliary information appended
-** to the end.  EXTRA_SIZE is the number of bytes of space needed to hold
-** that extra information.
+** Write out a single frame of the WAL
 */
-#define EXTRA_SIZE sizeof(MemPage)
+static int walWriteOneFrame(
+  WalWriter *p,               /* Where to write the frame */
+  PgHdr *pPage,               /* The page of the frame to be written */
+  int nTruncate,              /* The commit flag.  Usually 0.  >0 for commit */
+  sqlite3_int64 iOffset       /* Byte offset at which to write */
+){
+  int rc;                         /* Result code from subfunctions */
+  void *pData;                    /* Data actually written */
+  u8 aFrame[WAL_FRAME_HDRSIZE];   /* Buffer to assemble frame-header in */
+#if defined(SQLITE_HAS_CODEC)
+  if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM;
+#else
+  pData = pPage->pData;
+#endif
+  walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
+  rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
+  if( rc ) return rc;
+  /* Write the page data */
+  rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame));
+  return rc;
+}
 
-/*
-** A linked list of the following structures is stored at BtShared.pLock.
-** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor 
-** is opened on the table with root page BtShared.iTable. Locks are removed
-** from this list when a transaction is committed or rolled back, or when
-** a btree handle is closed.
+/* 
+** Write a set of frames to the log. The caller must hold the write-lock
+** on the log file (obtained using sqlite3WalBeginWriteTransaction()).
 */
-struct BtLock {
-  Btree *pBtree;        /* Btree handle holding this lock */
-  Pgno iTable;          /* Root page of table */
-  u8 eLock;             /* READ_LOCK or WRITE_LOCK */
-  BtLock *pNext;        /* Next in BtShared.pLock list */
-};
+SQLITE_PRIVATE int sqlite3WalFrames(
+  Wal *pWal,                      /* Wal handle to write to */
+  int szPage,                     /* Database page-size in bytes */
+  PgHdr *pList,                   /* List of dirty pages to write */
+  Pgno nTruncate,                 /* Database size after this commit */
+  int isCommit,                   /* True if this is a commit */
+  int sync_flags                  /* Flags to pass to OsSync() (or 0) */
+){
+  int rc;                         /* Used to catch return codes */
+  u32 iFrame;                     /* Next frame address */
+  PgHdr *p;                       /* Iterator to run through pList with. */
+  PgHdr *pLast = 0;               /* Last frame in list */
+  int nExtra = 0;                 /* Number of extra copies of last page */
+  int szFrame;                    /* The size of a single frame */
+  i64 iOffset;                    /* Next byte to write in WAL file */
+  WalWriter w;                    /* The writer */
 
-/* Candidate values for BtLock.eLock */
-#define READ_LOCK     1
-#define WRITE_LOCK    2
+  assert( pList );
+  assert( pWal->writeLock );
 
-/* A Btree handle
-**
-** A database connection contains a pointer to an instance of
-** this object for every database file that it has open.  This structure
-** is opaque to the database connection.  The database connection cannot
-** see the internals of this structure and only deals with pointers to
-** this structure.
-**
-** For some database files, the same underlying database cache might be 
-** shared between multiple connections.  In that case, each connection
-** has it own instance of this object.  But each instance of this object
-** points to the same BtShared object.  The database cache and the
-** schema associated with the database file are all contained within
-** the BtShared object.
-**
-** All fields in this structure are accessed under sqlite3.mutex.
-** The pBt pointer itself may not be changed while there exists cursors 
-** in the referenced BtShared that point back to this Btree since those
-** cursors have to go through this Btree to find their BtShared and
-** they often do so without holding sqlite3.mutex.
-*/
-struct Btree {
-  sqlite3 *db;       /* The database connection holding this btree */
-  BtShared *pBt;     /* Sharable content of this btree */
-  u8 inTrans;        /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
-  u8 sharable;       /* True if we can share pBt with another db */
-  u8 locked;         /* True if db currently has pBt locked */
-  int wantToLock;    /* Number of nested calls to sqlite3BtreeEnter() */
-  int nBackup;       /* Number of backup operations reading this btree */
-  Btree *pNext;      /* List of other sharable Btrees from the same db */
-  Btree *pPrev;      /* Back pointer of the same list */
-#ifndef SQLITE_OMIT_SHARED_CACHE
-  BtLock lock;       /* Object used to lock page 1 */
+  /* If this frame set completes a transaction, then nTruncate>0.  If
+  ** nTruncate==0 then this frame set does not complete the transaction. */
+  assert( (isCommit!=0)==(nTruncate!=0) );
+
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+  { int cnt; for(cnt=0, p=pList; p; p=p->pDirty, cnt++){}
+    WALTRACE(("WAL%p: frame write begin. %d frames. mxFrame=%d. %s\n",
+              pWal, cnt, pWal->hdr.mxFrame, isCommit ? "Commit" : "Spill"));
+  }
 #endif
-};
 
-/*
-** Btree.inTrans may take one of the following values.
-**
-** If the shared-data extension is enabled, there may be multiple users
-** of the Btree structure. At most one of these may open a write transaction,
-** but any number may have active read transactions.
-*/
-#define TRANS_NONE  0
-#define TRANS_READ  1
-#define TRANS_WRITE 2
+  /* See if it is possible to write these frames into the start of the
+  ** log file, instead of appending to it at pWal->hdr.mxFrame.
+  */
+  if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){
+    return rc;
+  }
+
+  /* If this is the first frame written into the log, write the WAL
+  ** header to the start of the WAL file. See comments at the top of
+  ** this source file for a description of the WAL header format.
+  */
+  iFrame = pWal->hdr.mxFrame;
+  if( iFrame==0 ){
+    u8 aWalHdr[WAL_HDRSIZE];      /* Buffer to assemble wal-header in */
+    u32 aCksum[2];                /* Checksum for wal-header */
+
+    sqlite3Put4byte(&aWalHdr[0], (WAL_MAGIC | SQLITE_BIGENDIAN));
+    sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION);
+    sqlite3Put4byte(&aWalHdr[8], szPage);
+    sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt);
+    if( pWal->nCkpt==0 ) sqlite3_randomness(8, pWal->hdr.aSalt);
+    memcpy(&aWalHdr[16], pWal->hdr.aSalt, 8);
+    walChecksumBytes(1, aWalHdr, WAL_HDRSIZE-2*4, 0, aCksum);
+    sqlite3Put4byte(&aWalHdr[24], aCksum[0]);
+    sqlite3Put4byte(&aWalHdr[28], aCksum[1]);
+    
+    pWal->szPage = szPage;
+    pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
+    pWal->hdr.aFrameCksum[0] = aCksum[0];
+    pWal->hdr.aFrameCksum[1] = aCksum[1];
+    pWal->truncateOnCommit = 1;
+
+    rc = sqlite3OsWrite(pWal->pWalFd, aWalHdr, sizeof(aWalHdr), 0);
+    WALTRACE(("WAL%p: wal-header write %s\n", pWal, rc ? "failed" : "ok"));
+    if( rc!=SQLITE_OK ){
+      return rc;
+    }
+
+    /* Sync the header (unless SQLITE_IOCAP_SEQUENTIAL is true or unless
+    ** all syncing is turned off by PRAGMA synchronous=OFF).  Otherwise
+    ** an out-of-order write following a WAL restart could result in
+    ** database corruption.  See the ticket:
+    **
+    **     http://localhost:591/sqlite/info/ff5be73dee
+    */
+    if( pWal->syncHeader && sync_flags ){
+      rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
+      if( rc ) return rc;
+    }
+  }
+  assert( (int)pWal->szPage==szPage );
+
+  /* Setup information needed to write frames into the WAL */
+  w.pWal = pWal;
+  w.pFd = pWal->pWalFd;
+  w.iSyncPoint = 0;
+  w.syncFlags = sync_flags;
+  w.szPage = szPage;
+  iOffset = walFrameOffset(iFrame+1, szPage);
+  szFrame = szPage + WAL_FRAME_HDRSIZE;
+
+  /* Write all frames into the log file exactly once */
+  for(p=pList; p; p=p->pDirty){
+    int nDbSize;   /* 0 normally.  Positive == commit flag */
+    iFrame++;
+    assert( iOffset==walFrameOffset(iFrame, szPage) );
+    nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
+    rc = walWriteOneFrame(&w, p, nDbSize, iOffset);
+    if( rc ) return rc;
+    pLast = p;
+    iOffset += szFrame;
+  }
+
+  /* If this is the end of a transaction, then we might need to pad
+  ** the transaction and/or sync the WAL file.
+  **
+  ** Padding and syncing only occur if this set of frames complete a
+  ** transaction and if PRAGMA synchronous=FULL.  If synchronous==NORMAL
+  ** or synchonous==OFF, then no padding or syncing are needed.
+  **
+  ** If SQLITE_IOCAP_POWERSAFE_OVERWRITE is defined, then padding is not
+  ** needed and only the sync is done.  If padding is needed, then the
+  ** final frame is repeated (with its commit mark) until the next sector
+  ** boundary is crossed.  Only the part of the WAL prior to the last
+  ** sector boundary is synced; the part of the last frame that extends
+  ** past the sector boundary is written after the sync.
+  */
+  if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
+    if( pWal->padToSectorBoundary ){
+      int sectorSize = sqlite3SectorSize(pWal->pWalFd);
+      w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
+      while( iOffset<w.iSyncPoint ){
+        rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);
+        if( rc ) return rc;
+        iOffset += szFrame;
+        nExtra++;
+      }
+    }else{
+      rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK);
+    }
+  }
+
+  /* If this frame set completes the first transaction in the WAL and
+  ** if PRAGMA journal_size_limit is set, then truncate the WAL to the
+  ** journal size limit, if possible.
+  */
+  if( isCommit && pWal->truncateOnCommit && pWal->mxWalSize>=0 ){
+    i64 sz = pWal->mxWalSize;
+    if( walFrameOffset(iFrame+nExtra+1, szPage)>pWal->mxWalSize ){
+      sz = walFrameOffset(iFrame+nExtra+1, szPage);
+    }
+    walLimitSize(pWal, sz);
+    pWal->truncateOnCommit = 0;
+  }
+
+  /* Append data to the wal-index. It is not necessary to lock the 
+  ** wal-index to do this as the SQLITE_SHM_WRITE lock held on the wal-index
+  ** guarantees that there are no other writers, and no data that may
+  ** be in use by existing readers is being overwritten.
+  */
+  iFrame = pWal->hdr.mxFrame;
+  for(p=pList; p && rc==SQLITE_OK; p=p->pDirty){
+    iFrame++;
+    rc = walIndexAppend(pWal, iFrame, p->pgno);
+  }
+  while( rc==SQLITE_OK && nExtra>0 ){
+    iFrame++;
+    nExtra--;
+    rc = walIndexAppend(pWal, iFrame, pLast->pgno);
+  }
+
+  if( rc==SQLITE_OK ){
+    /* Update the private copy of the header. */
+    pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
+    testcase( szPage<=32768 );
+    testcase( szPage>=65536 );
+    pWal->hdr.mxFrame = iFrame;
+    if( isCommit ){
+      pWal->hdr.iChange++;
+      pWal->hdr.nPage = nTruncate;
+    }
+    /* If this is a commit, update the wal-index header too. */
+    if( isCommit ){
+      walIndexWriteHdr(pWal);
+      pWal->iCallback = iFrame;
+    }
+  }
 
-/*
-** An instance of this object represents a single database file.
-** 
-** A single database file can be in use at the same time by two
-** or more database connections.  When two or more connections are
-** sharing the same database file, each connection has it own
-** private Btree object for the file and each of those Btrees points
-** to this one BtShared object.  BtShared.nRef is the number of
-** connections currently sharing this database file.
-**
-** Fields in this structure are accessed under the BtShared.mutex
-** mutex, except for nRef and pNext which are accessed under the
-** global SQLITE_MUTEX_STATIC_MASTER mutex.  The pPager field
-** may not be modified once it is initially set as long as nRef>0.
-** The pSchema field may be set once under BtShared.mutex and
-** thereafter is unchanged as long as nRef>0.
-**
-** isPending:
-**
-**   If a BtShared client fails to obtain a write-lock on a database
-**   table (because there exists one or more read-locks on the table),
-**   the shared-cache enters 'pending-lock' state and isPending is
-**   set to true.
-**
-**   The shared-cache leaves the 'pending lock' state when either of
-**   the following occur:
-**
-**     1) The current writer (BtShared.pWriter) concludes its transaction, OR
-**     2) The number of locks held by other connections drops to zero.
+  WALTRACE(("WAL%p: frame write %s\n", pWal, rc ? "failed" : "ok"));
+  return rc;
+}
+
+/* 
+** This routine is called to implement sqlite3_wal_checkpoint() and
+** related interfaces.
 **
-**   while in the 'pending-lock' state, no connection may start a new
-**   transaction.
+** Obtain a CHECKPOINT lock and then backfill as much information as
+** we can from WAL into the database.
 **
-**   This feature is included to help prevent writer-starvation.
+** If parameter xBusy is not NULL, it is a pointer to a busy-handler
+** callback. In this case this function runs a blocking checkpoint.
 */
-struct BtShared {
-  Pager *pPager;        /* The page cache */
-  sqlite3 *db;          /* Database connection currently using this Btree */
-  BtCursor *pCursor;    /* A list of all open cursors */
-  MemPage *pPage1;      /* First page of the database */
-  u8 openFlags;         /* Flags to sqlite3BtreeOpen() */
-#ifndef SQLITE_OMIT_AUTOVACUUM
-  u8 autoVacuum;        /* True if auto-vacuum is enabled */
-  u8 incrVacuum;        /* True if incr-vacuum is enabled */
-  u8 bDoTruncate;       /* True to truncate db on commit */
-#endif
-  u8 inTransaction;     /* Transaction state */
-  u8 max1bytePayload;   /* Maximum first byte of cell for a 1-byte payload */
-  u16 btsFlags;         /* Boolean parameters.  See BTS_* macros below */
-  u16 maxLocal;         /* Maximum local payload in non-LEAFDATA tables */
-  u16 minLocal;         /* Minimum local payload in non-LEAFDATA tables */
-  u16 maxLeaf;          /* Maximum local payload in a LEAFDATA table */
-  u16 minLeaf;          /* Minimum local payload in a LEAFDATA table */
-  u32 pageSize;         /* Total number of bytes on a page */
-  u32 usableSize;       /* Number of usable bytes on each page */
-  int nTransaction;     /* Number of open transactions (read + write) */
-  u32 nPage;            /* Number of pages in the database */
-  void *pSchema;        /* Pointer to space allocated by sqlite3BtreeSchema() */
-  void (*xFreeSchema)(void*);  /* Destructor for BtShared.pSchema */
-  sqlite3_mutex *mutex; /* Non-recursive mutex required to access this object */
-  Bitvec *pHasContent;  /* Set of pages moved to free-list this transaction */
-#ifndef SQLITE_OMIT_SHARED_CACHE
-  int nRef;             /* Number of references to this structure */
-  BtShared *pNext;      /* Next on a list of sharable BtShared structs */
-  BtLock *pLock;        /* List of locks held on this shared-btree struct */
-  Btree *pWriter;       /* Btree with currently open write transaction */
-#endif
-  u8 *pTmpSpace;        /* BtShared.pageSize bytes of space for tmp use */
-};
+SQLITE_PRIVATE int sqlite3WalCheckpoint(
+  Wal *pWal,                      /* Wal connection */
+  int eMode,                      /* PASSIVE, FULL or RESTART */
+  int (*xBusy)(void*),            /* Function to call when busy */
+  void *pBusyArg,                 /* Context argument for xBusyHandler */
+  int sync_flags,                 /* Flags to sync db file with (or 0) */
+  int nBuf,                       /* Size of temporary buffer */
+  u8 *zBuf,                       /* Temporary buffer to use */
+  int *pnLog,                     /* OUT: Number of frames in WAL */
+  int *pnCkpt                     /* OUT: Number of backfilled frames in WAL */
+){
+  int rc;                         /* Return code */
+  int isChanged = 0;              /* True if a new wal-index header is loaded */
+  int eMode2 = eMode;             /* Mode to pass to walCheckpoint() */
 
-/*
-** Allowed values for BtShared.btsFlags
-*/
-#define BTS_READ_ONLY        0x0001   /* Underlying file is readonly */
-#define BTS_PAGESIZE_FIXED   0x0002   /* Page size can no longer be changed */
-#define BTS_SECURE_DELETE    0x0004   /* PRAGMA secure_delete is enabled */
-#define BTS_INITIALLY_EMPTY  0x0008   /* Database was empty at trans start */
-#define BTS_NO_WAL           0x0010   /* Do not open write-ahead-log files */
-#define BTS_EXCLUSIVE        0x0020   /* pWriter has an exclusive lock */
-#define BTS_PENDING          0x0040   /* Waiting for read-locks to clear */
+  assert( pWal->ckptLock==0 );
+  assert( pWal->writeLock==0 );
 
-/*
-** An instance of the following structure is used to hold information
-** about a cell.  The parseCellPtr() function fills in this structure
-** based on information extract from the raw disk page.
-*/
-typedef struct CellInfo CellInfo;
-struct CellInfo {
-  i64 nKey;      /* The key for INTKEY tables, or number of bytes in key */
-  u8 *pCell;     /* Pointer to the start of cell content */
-  u32 nData;     /* Number of bytes of data */
-  u32 nPayload;  /* Total amount of payload */
-  u16 nHeader;   /* Size of the cell content header in bytes */
-  u16 nLocal;    /* Amount of payload held locally */
-  u16 iOverflow; /* Offset to overflow page number.  Zero if no overflow */
-  u16 nSize;     /* Size of the cell content on the main b-tree page */
-};
+  if( pWal->readOnly ) return SQLITE_READONLY;
+  WALTRACE(("WAL%p: checkpoint begins\n", pWal));
+  rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
+  if( rc ){
+    /* Usually this is SQLITE_BUSY meaning that another thread or process
+    ** is already running a checkpoint, or maybe a recovery.  But it might
+    ** also be SQLITE_IOERR. */
+    return rc;
+  }
+  pWal->ckptLock = 1;
 
-/*
-** Maximum depth of an SQLite B-Tree structure. Any B-Tree deeper than
-** this will be declared corrupt. This value is calculated based on a
-** maximum database size of 2^31 pages a minimum fanout of 2 for a
-** root-node and 3 for all other internal nodes.
-**
-** If a tree that appears to be taller than this is encountered, it is
-** assumed that the database is corrupt.
-*/
-#define BTCURSOR_MAX_DEPTH 20
+  /* If this is a blocking-checkpoint, then obtain the write-lock as well
+  ** to prevent any writers from running while the checkpoint is underway.
+  ** This has to be done before the call to walIndexReadHdr() below.
+  **
+  ** If the writer lock cannot be obtained, then a passive checkpoint is
+  ** run instead. Since the checkpointer is not holding the writer lock,
+  ** there is no point in blocking waiting for any readers. Assuming no 
+  ** other error occurs, this function will return SQLITE_BUSY to the caller.
+  */
+  if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
+    rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
+    if( rc==SQLITE_OK ){
+      pWal->writeLock = 1;
+    }else if( rc==SQLITE_BUSY ){
+      eMode2 = SQLITE_CHECKPOINT_PASSIVE;
+      rc = SQLITE_OK;
+    }
+  }
 
-/*
-** A cursor is a pointer to a particular entry within a particular
-** b-tree within a database file.
-**
-** The entry is identified by its MemPage and the index in
-** MemPage.aCell[] of the entry.
-**
-** A single database file can be shared by two more database connections,
-** but cursors cannot be shared.  Each cursor is associated with a
-** particular database connection identified BtCursor.pBtree.db.
-**
-** Fields in this structure are accessed under the BtShared.mutex
-** found at self->pBt->mutex. 
-*/
-struct BtCursor {
-  Btree *pBtree;            /* The Btree to which this cursor belongs */
-  BtShared *pBt;            /* The BtShared this cursor points to */
-  BtCursor *pNext, *pPrev;  /* Forms a linked list of all cursors */
-  struct KeyInfo *pKeyInfo; /* Argument passed to comparison function */
-#ifndef SQLITE_OMIT_INCRBLOB
-  Pgno *aOverflow;          /* Cache of overflow page locations */
-#endif
-  Pgno pgnoRoot;            /* The root page of this tree */
-  sqlite3_int64 cachedRowid; /* Next rowid cache.  0 means not valid */
-  CellInfo info;            /* A parse of the cell we are pointing at */
-  i64 nKey;        /* Size of pKey, or last integer key */
-  void *pKey;      /* Saved key that was cursor's last known position */
-  int skipNext;    /* Prev() is noop if negative. Next() is noop if positive */
-  u8 wrFlag;                /* True if writable */
-  u8 atLast;                /* Cursor pointing to the last entry */
-  u8 validNKey;             /* True if info.nKey is valid */
-  u8 eState;                /* One of the CURSOR_XXX constants (see below) */
-#ifndef SQLITE_OMIT_INCRBLOB
-  u8 isIncrblobHandle;      /* True if this cursor is an incr. io handle */
-#endif
-  u8 hints;                             /* As configured by CursorSetHints() */
-  i16 iPage;                            /* Index of current page in apPage */
-  u16 aiIdx[BTCURSOR_MAX_DEPTH];        /* Current index in apPage[i] */
-  MemPage *apPage[BTCURSOR_MAX_DEPTH];  /* Pages from root to current page */
-};
+  /* Read the wal-index header. */
+  if( rc==SQLITE_OK ){
+    rc = walIndexReadHdr(pWal, &isChanged);
+    if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
+      sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
+    }
+  }
 
-/*
-** Potential values for BtCursor.eState.
-**
-** CURSOR_INVALID:
-**   Cursor does not point to a valid entry. This can happen (for example) 
-**   because the table is empty or because BtreeCursorFirst() has not been
-**   called.
-**
-** CURSOR_VALID:
-**   Cursor points to a valid entry. getPayload() etc. may be called.
-**
-** CURSOR_SKIPNEXT:
-**   Cursor is valid except that the Cursor.skipNext field is non-zero
-**   indicating that the next sqlite3BtreeNext() or sqlite3BtreePrevious()
-**   operation should be a no-op.
-**
-** CURSOR_REQUIRESEEK:
-**   The table that this cursor was opened on still exists, but has been 
-**   modified since the cursor was last used. The cursor position is saved
-**   in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in 
-**   this state, restoreCursorPosition() can be called to attempt to
-**   seek the cursor to the saved position.
-**
-** CURSOR_FAULT:
-**   A unrecoverable error (an I/O error or a malloc failure) has occurred
-**   on a different connection that shares the BtShared cache with this
-**   cursor.  The error has left the cache in an inconsistent state.
-**   Do nothing else with this cursor.  Any attempt to use the cursor
-**   should return the error code stored in BtCursor.skip
-*/
-#define CURSOR_INVALID           0
-#define CURSOR_VALID             1
-#define CURSOR_SKIPNEXT          2
-#define CURSOR_REQUIRESEEK       3
-#define CURSOR_FAULT             4
+  /* Copy data from the log to the database file. */
+  if( rc==SQLITE_OK ){
+    if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){
+      rc = SQLITE_CORRUPT_BKPT;
+    }else{
+      rc = walCheckpoint(pWal, eMode2, xBusy, pBusyArg, sync_flags, zBuf);
+    }
 
-/* 
-** The database page the PENDING_BYTE occupies. This page is never used.
-*/
-# define PENDING_BYTE_PAGE(pBt) PAGER_MJ_PGNO(pBt)
+    /* If no error occurred, set the output variables. */
+    if( rc==SQLITE_OK || rc==SQLITE_BUSY ){
+      if( pnLog ) *pnLog = (int)pWal->hdr.mxFrame;
+      if( pnCkpt ) *pnCkpt = (int)(walCkptInfo(pWal)->nBackfill);
+    }
+  }
 
-/*
-** These macros define the location of the pointer-map entry for a 
-** database page. The first argument to each is the number of usable
-** bytes on each page of the database (often 1024). The second is the
-** page number to look up in the pointer map.
-**
-** PTRMAP_PAGENO returns the database page number of the pointer-map
-** page that stores the required pointer. PTRMAP_PTROFFSET returns
-** the offset of the requested map entry.
-**
-** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
-** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
-** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
-** this test.
+  if( isChanged ){
+    /* If a new wal-index header was loaded before the checkpoint was 
+    ** performed, then the pager-cache associated with pWal is now
+    ** out of date. So zero the cached wal-index header to ensure that
+    ** next time the pager opens a snapshot on this database it knows that
+    ** the cache needs to be reset.
+    */
+    memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
+  }
+
+  /* Release the locks. */
+  sqlite3WalEndWriteTransaction(pWal);
+  walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
+  pWal->ckptLock = 0;
+  WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
+  return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
+}
+
+/* Return the value to pass to a sqlite3_wal_hook callback, the
+** number of frames in the WAL at the point of the last commit since
+** sqlite3WalCallback() was called.  If no commits have occurred since
+** the last call, then return 0.
 */
-#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
-#define PTRMAP_PTROFFSET(pgptrmap, pgno) (5*(pgno-pgptrmap-1))
-#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
+SQLITE_PRIVATE int sqlite3WalCallback(Wal *pWal){
+  u32 ret = 0;
+  if( pWal ){
+    ret = pWal->iCallback;
+    pWal->iCallback = 0;
+  }
+  return (int)ret;
+}
 
 /*
-** The pointer map is a lookup table that identifies the parent page for
-** each child page in the database file.  The parent page is the page that
-** contains a pointer to the child.  Every page in the database contains
-** 0 or 1 parent pages.  (In this context 'database page' refers
-** to any page that is not part of the pointer map itself.)  Each pointer map
-** entry consists of a single byte 'type' and a 4 byte parent page number.
-** The PTRMAP_XXX identifiers below are the valid types.
-**
-** The purpose of the pointer map is to facility moving pages from one
-** position in the file to another as part of autovacuum.  When a page
-** is moved, the pointer in its parent must be updated to point to the
-** new location.  The pointer map is used to locate the parent page quickly.
-**
-** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
-**                  used in this case.
-**
-** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number 
-**                  is not used in this case.
+** This function is called to change the WAL subsystem into or out
+** of locking_mode=EXCLUSIVE.
 **
-** PTRMAP_OVERFLOW1: The database page is the first page in a list of 
-**                   overflow pages. The page number identifies the page that
-**                   contains the cell with a pointer to this overflow page.
+** If op is zero, then attempt to change from locking_mode=EXCLUSIVE
+** into locking_mode=NORMAL.  This means that we must acquire a lock
+** on the pWal->readLock byte.  If the WAL is already in locking_mode=NORMAL
+** or if the acquisition of the lock fails, then return 0.  If the
+** transition out of exclusive-mode is successful, return 1.  This
+** operation must occur while the pager is still holding the exclusive
+** lock on the main database file.
 **
-** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of
-**                   overflow pages. The page-number identifies the previous
-**                   page in the overflow page list.
+** If op is one, then change from locking_mode=NORMAL into 
+** locking_mode=EXCLUSIVE.  This means that the pWal->readLock must
+** be released.  Return 1 if the transition is made and 0 if the
+** WAL is already in exclusive-locking mode - meaning that this
+** routine is a no-op.  The pager must already hold the exclusive lock
+** on the main database file before invoking this operation.
 **
-** PTRMAP_BTREE: The database page is a non-root btree page. The page number
-**               identifies the parent page in the btree.
+** If op is negative, then do a dry-run of the op==1 case but do
+** not actually change anything. The pager uses this to see if it
+** should acquire the database exclusive lock prior to invoking
+** the op==1 case.
 */
-#define PTRMAP_ROOTPAGE 1
-#define PTRMAP_FREEPAGE 2
-#define PTRMAP_OVERFLOW1 3
-#define PTRMAP_OVERFLOW2 4
-#define PTRMAP_BTREE 5
+SQLITE_PRIVATE int sqlite3WalExclusiveMode(Wal *pWal, int op){
+  int rc;
+  assert( pWal->writeLock==0 );
+  assert( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE || op==-1 );
 
-/* A bunch of assert() statements to check the transaction state variables
-** of handle p (type Btree*) are internally consistent.
-*/
-#define btreeIntegrity(p) \
-  assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
-  assert( p->pBt->inTransaction>=p->inTrans ); 
+  /* pWal->readLock is usually set, but might be -1 if there was a 
+  ** prior error while attempting to acquire are read-lock. This cannot 
+  ** happen if the connection is actually in exclusive mode (as no xShmLock
+  ** locks are taken in this case). Nor should the pager attempt to
+  ** upgrade to exclusive-mode following such an error.
+  */
+  assert( pWal->readLock>=0 || pWal->lockError );
+  assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
+
+  if( op==0 ){
+    if( pWal->exclusiveMode ){
+      pWal->exclusiveMode = 0;
+      if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){
+        pWal->exclusiveMode = 1;
+      }
+      rc = pWal->exclusiveMode==0;
+    }else{
+      /* Already in locking_mode=NORMAL */
+      rc = 0;
+    }
+  }else if( op>0 ){
+    assert( pWal->exclusiveMode==0 );
+    assert( pWal->readLock>=0 );
+    walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
+    pWal->exclusiveMode = 1;
+    rc = 1;
+  }else{
+    rc = pWal->exclusiveMode==0;
+  }
+  return rc;
+}
 
+/* 
+** Return true if the argument is non-NULL and the WAL module is using
+** heap-memory for the wal-index. Otherwise, if the argument is NULL or the
+** WAL module is using shared-memory, return false. 
+*/
+SQLITE_PRIVATE int sqlite3WalHeapMemory(Wal *pWal){
+  return (pWal && pWal->exclusiveMode==WAL_HEAPMEMORY_MODE );
+}
 
+#ifdef SQLITE_ENABLE_ZIPVFS
 /*
-** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
-** if the database supports auto-vacuum or not. Because it is used
-** within an expression that is an argument to another macro 
-** (sqliteMallocRaw), it is not possible to use conditional compilation.
-** So, this macro is defined instead.
+** If the argument is not NULL, it points to a Wal object that holds a
+** read-lock. This function returns the database page-size if it is known,
+** or zero if it is not (or if pWal is NULL).
 */
-#ifndef SQLITE_OMIT_AUTOVACUUM
-#define ISAUTOVACUUM (pBt->autoVacuum)
-#else
-#define ISAUTOVACUUM 0
+SQLITE_PRIVATE int sqlite3WalFramesize(Wal *pWal){
+  assert( pWal==0 || pWal->readLock>=0 );
+  return (pWal ? pWal->szPage : 0);
+}
 #endif
 
+#endif /* #ifndef SQLITE_OMIT_WAL */
 
+/************** End of wal.c *************************************************/
+/************** Begin file btmutex.c *****************************************/
 /*
-** This structure is passed around through all the sanity checking routines
-** in order to keep track of some global state information.
+** 2007 August 27
 **
-** The aRef[] array is allocated so that there is 1 bit for each page in
-** the database. As the integrity-check proceeds, for each page used in
-** the database the corresponding bit is set. This allows integrity-check to 
-** detect pages that are used twice and orphaned pages (both of which 
-** indicate corruption).
-*/
-typedef struct IntegrityCk IntegrityCk;
-struct IntegrityCk {
-  BtShared *pBt;    /* The tree being checked out */
-  Pager *pPager;    /* The associated pager.  Also accessible by pBt->pPager */
-  u8 *aPgRef;       /* 1 bit per page in the db (see above) */
-  Pgno nPage;       /* Number of pages in the database */
-  int mxErr;        /* Stop accumulating errors when this reaches zero */
-  int nErr;         /* Number of messages written to zErrMsg so far */
-  int mallocFailed; /* A memory allocation error has occurred */
-  StrAccum errMsg;  /* Accumulate the error message text here */
-};
-
-/*
-** Routines to read or write a two- and four-byte big-endian integer values.
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** This file contains code used to implement mutexes on Btree objects.
+** This code really belongs in btree.c.  But btree.c is getting too
+** big and we want to break it down some.  This packaged seemed like
+** a good breakout.
 */
-#define get2byte(x)   ((x)[0]<<8 | (x)[1])
-#define put2byte(p,v) ((p)[0] = (u8)((v)>>8), (p)[1] = (u8)(v))
-#define get4byte sqlite3Get4byte
-#define put4byte sqlite3Put4byte
-
-/************** End of btreeInt.h ********************************************/
-/************** Continuing where we left off in btmutex.c ********************/
 #ifndef SQLITE_OMIT_SHARED_CACHE
 #if SQLITE_THREADSAFE
 
@@ -88995,10 +91735,24 @@
 */
 SQLITE_PRIVATE void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
   int rc = sqlite3_overload_function(db, "MATCH", 2);
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+#ifndef OMIT_EXPORT
+  extern void sqlcipher_exportFunc(sqlite3_context *, int, sqlite3_value **);
+#endif
+#endif
+/* END SQLCIPHER */
   assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );
   if( rc==SQLITE_NOMEM ){
     db->mallocFailed = 1;
   }
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+#ifndef OMIT_EXPORT
+  sqlite3CreateFunc(db, "sqlcipher_export", 1, SQLITE_TEXT, 0, sqlcipher_exportFunc, 0, 0, 0);
+#endif
+#endif
+/* END SQLCIPHER */
 }
 
 /*
@@ -94082,6 +96836,12 @@
   sqlite3 *db = pParse->db;    /* The database connection */
   Db *pDb;                     /* The specific database being pragmaed */
   Vdbe *v = sqlite3GetVdbe(pParse);  /* Prepared statement */
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+  extern int sqlcipher_codec_pragma(sqlite3*, int, Parse *, const char *, const char *);
+#endif
+/* END SQLCIPHER */
+
 
   if( v==0 ) return;
   sqlite3VdbeRunOnlyOnce(v);
@@ -94142,6 +96902,13 @@
     pParse->rc = rc;
   }else
                             
+/* BEGIN SQLCIPHER */
+#ifdef SQLITE_HAS_CODEC
+  if(sqlcipher_codec_pragma(db, iDb, pParse, zLeft, zRight)) { 
+    /* sqlcipher_codec_pragma executes internal */
+  }else
+  #endif
+/* END SQLCIPHER */
  
 #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED)
   /*
@@ -94739,60 +97506,6 @@
 
 #ifndef SQLITE_OMIT_SCHEMA_PRAGMAS
   /*
-  **   PRAGMA proc_list
-  **
-  ** Return a single row for each procedure, the returned data set are:
-  **
-  ** name:         Procedure name
-  ** is_aggregate: True is procedure is an aggregate
-  ** nargs:        Number of arguments of the procedure, or -1 if unlimited
-  ** spe_name:     Specific name (unique procedure name)
-  */
-  if( sqlite3StrICmp(zLeft, "proc_list")==0 ){
-    if( sqlite3ReadSchema(pParse) ) goto pragma_out;
-
-    sqlite3VdbeSetNumCols(v, 4);
-    pParse->nMem = 4;
-    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "name", SQLITE_STATIC);
-    sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "is_aggregate", SQLITE_STATIC);
-    sqlite3VdbeSetColName(v, 2, COLNAME_NAME, "nargs", SQLITE_STATIC);
-    sqlite3VdbeSetColName(v, 3, COLNAME_NAME, "spe_name", SQLITE_STATIC);
-    int j;
-    for(j=0; j<ArraySize(db->aFunc.a); j++){
-      FuncDef *func;
-      for (func =db->aFunc.a[j]; func; func = func->pNext) {
-	char *sname;
-	int size;
-	size = strlen (func->zName) + 25;
-	sname = sqlite3_malloc (sizeof (char) * size);
-	snprintf (sname, size-1, "%s_%d_%d", func->zName, func->nArg, func->iPrefEnc);
-	sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, func->zName, 0);
-	sqlite3VdbeAddOp2(v, OP_Integer, func->xFinalize ? 1 : 0, 2);
-	sqlite3VdbeAddOp2(v, OP_Integer, func->nArg, 3);
-	sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, sname, 0);
-	sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
-	sqlite3_free (sname);
-      }
-    }
-    for(j=0; j<ArraySize(sqlite3GlobalFunctions.a); j++){
-      FuncDef *func;
-      for (func =sqlite3GlobalFunctions.a[j]; func; func = func->pNext) {
-	char *sname;
-	int size;
-	size = strlen (func->zName) + 25;
-	sname = sqlite3_malloc (sizeof (char) * size);
-	snprintf (sname, size-1, "%s_%d_%d", func->zName, func->nArg, func->iPrefEnc);
-	sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, func->zName, 0);
-	sqlite3VdbeAddOp2(v, OP_Integer, func->xFinalize ? 1 : 0, 2);
-	sqlite3VdbeAddOp2(v, OP_Integer, func->nArg, 3);
-	sqlite3VdbeAddOp4(v, OP_String8, 0, 4, 0, sname, 0);
-	sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 4);
-	sqlite3_free (sname);
-      }
-    }
-  }else
-
- /*
   **   PRAGMA table_info(<table>)
   **
   ** Return a single row for each column of the named table. The columns of
