aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordan <dan@noemail.net>2010-06-23 15:55:43 +0000
committerdan <dan@noemail.net>2010-06-23 15:55:43 +0000
commit10f5a50e57d1f3e43bb86080dfd8d718f59ebefd (patch)
treeae59a407698d3196dd7022c19e06587920be1149 /src
parentb316cb22dead152c669f577f41f28cbd89776c7f (diff)
downloadsqlite-10f5a50e57d1f3e43bb86080dfd8d718f59ebefd.tar.gz
sqlite-10f5a50e57d1f3e43bb86080dfd8d718f59ebefd.zip
Add a version number to the wal-index header. If SQLite encounters a version number in either the wal or wal-index files that it does not understand, the operation is abandoned and SQLITE_CANTOPEN returned.
FossilOrigin-Name: 8d0f8a7f70d6fb42369411a934b30f8c8ca8322f
Diffstat (limited to 'src')
-rw-r--r--src/wal.c61
1 files changed, 53 insertions, 8 deletions
diff --git a/src/wal.c b/src/wal.c
index 0175c852c..83dd75837 100644
--- a/src/wal.c
+++ b/src/wal.c
@@ -40,6 +40,8 @@
** 12: Checkpoint sequence number
** 16: Salt-1, random integer incremented with each checkpoint
** 20: Salt-2, a different random integer changing with each ckpt
+** 24: Checksum-1 (first part of checksum for first 24 bytes of header).
+** 28: Checksum-2 (second part of checksum for first 24 bytes of header).
**
** Immediately following the wal-header are zero or more frames. Each
** frame consists of a 24-byte frame-header followed by a <page-size> bytes
@@ -246,6 +248,21 @@ int sqlite3WalTrace = 0;
# define WALTRACE(X)
#endif
+/*
+** The maximum (and only) versions of the wal and wal-index formats
+** that may be interpreted by this version of SQLite.
+**
+** If a client begins recovering a WAL file and finds that (a) the checksum
+** values in the wal-header are correct and (b) the version field is not
+** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN.
+**
+** Similarly, if a client successfully reads a wal-index header (i.e. the
+** checksum test is successful) and finds that the version field is not
+** WALINDEX_MAX_VERSION, then no read-transaction is opened and SQLite
+** returns SQLITE_CANTOPEN.
+*/
+#define WAL_MAX_VERSION 3007000
+#define WALINDEX_MAX_VERSION 3007000
/*
** Indices of various locking bytes. WAL_NREADER is the number
@@ -272,6 +289,8 @@ typedef struct WalCkptInfo WalCkptInfo;
** object.
*/
struct WalIndexHdr {
+ u32 iVersion; /* Wal-index version */
+ u32 unused; /* Unused (padding) field */
u32 iChange; /* Counter incremented each transaction */
u8 isInit; /* 1 when initialized */
u8 bigEndCksum; /* True if checksums in WAL are big-endian */
@@ -351,8 +370,9 @@ struct WalCkptInfo {
/* Size of header before each frame in wal */
#define WAL_FRAME_HDRSIZE 24
-/* Size of write ahead log header */
-#define WAL_HDRSIZE 24
+/* Size of write ahead log header, including checksum. */
+/* #define WAL_HDRSIZE 24 */
+#define WAL_HDRSIZE 32
/* WAL magic value. Either this value, or the same value with the least
** significant bit also set (WAL_MAGIC | 0x00000001) is stored in 32-bit
@@ -580,6 +600,7 @@ static void walIndexWriteHdr(Wal *pWal){
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));
sqlite3OsShmBarrier(pWal->pDbFd);
@@ -1029,6 +1050,7 @@ static int walIndexRecover(Wal *pWal){
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 */
/* Read in the WAL header. */
rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
@@ -1055,9 +1077,21 @@ static int walIndexRecover(Wal *pWal){
pWal->nCkpt = sqlite3Get4byte(&aBuf[12]);
memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN,
- aBuf, WAL_HDRSIZE, 0, pWal->hdr.aFrameCksum
+ 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;
+ }
+
+ 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);
@@ -1658,6 +1692,9 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
** being modified by another user.
*/
badHdr = (page0 ? walIndexTryHdr(pWal, pChanged) : 1);
+ if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
+ rc = SQLITE_CANTOPEN_BKPT;
+ }
/* If the first attempt failed, it might have been due to a race
** with a writer. So get a WRITE lock and try again.
@@ -2265,20 +2302,28 @@ int sqlite3WalFrames(
*/
iFrame = pWal->hdr.mxFrame;
if( iFrame==0 ){
- u8 aWalHdr[WAL_HDRSIZE]; /* Buffer to assembly wal-header in */
+ 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], 3007000);
+ sqlite3Put4byte(&aWalHdr[4], WAL_MAX_VERSION);
sqlite3Put4byte(&aWalHdr[8], szPage);
- pWal->szPage = szPage;
- pWal->hdr.bigEndCksum = SQLITE_BIGENDIAN;
sqlite3Put4byte(&aWalHdr[12], pWal->nCkpt);
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];
+
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;
}
- walChecksumBytes(1, aWalHdr, sizeof(aWalHdr), 0, pWal->hdr.aFrameCksum);
}
assert( pWal->szPage==szPage );