Index: third_party/sqlite/src/src/recover.c |
diff --git a/third_party/sqlite/src/src/recover.c b/third_party/sqlite/src/src/recover.c |
index 9e6c35c542dbeee82e2b51dd8aa6426479bca8bc..5ff6f78c90065131eaa6135c15687d14877ea9d8 100644 |
--- a/third_party/sqlite/src/src/recover.c |
+++ b/third_party/sqlite/src/src/recover.c |
@@ -237,6 +237,15 @@ |
static const unsigned char kTableLeafPage = 0x0D; |
static const unsigned char kTableInteriorPage = 0x05; |
+/* From section 1.2. */ |
+static const unsigned kiHeaderPageSizeOffset = 16; |
+static const unsigned kiHeaderReservedSizeOffset = 20; |
+static const unsigned kiHeaderEncodingOffset = 56; |
+/* TODO(shess) |static const unsigned| fails creating the header in GetPager() |
+** because |knHeaderSize| isn't |constexpr|. But this isn't C++, either. |
+*/ |
+enum { knHeaderSize = 100}; |
+ |
/* From section 1.5. */ |
static const unsigned kiPageTypeOffset = 0; |
static const unsigned kiPageFreeBlockOffset = 1; |
@@ -478,8 +487,7 @@ static const unsigned char *PageData(RecoverPage *pPage, unsigned iOffset){ |
*/ |
static const unsigned char *PageHeader(RecoverPage *pPage){ |
if( pPage->pgno==1 ){ |
- const unsigned nDatabaseHeader = 100; |
- return PageData(pPage, nDatabaseHeader); |
+ return PageData(pPage, knHeaderSize); |
}else{ |
return PageData(pPage, 0); |
} |
@@ -487,21 +495,13 @@ static const unsigned char *PageHeader(RecoverPage *pPage){ |
/* Helper to fetch the pager and page size for the named database. */ |
static int GetPager(sqlite3 *db, const char *zName, |
- RecoverPager **ppPager, unsigned *pnPageSize){ |
- int i, rc; |
+ RecoverPager **ppPager, unsigned *pnPageSize, |
+ int *piEncoding){ |
+ int rc, iEncoding; |
unsigned nPageSize, nReservedSize; |
+ unsigned char header[knHeaderSize]; |
sqlite3_file *pFile = NULL; |
- Btree *pBt = NULL; |
RecoverPager *pPager; |
- for( i=0; i<db->nDb; ++i ){ |
- if( ascii_strcasecmp(db->aDb[i].zName, zName)==0 ){ |
- pBt = db->aDb[i].pBt; |
- break; |
- } |
- } |
- if( !pBt ){ |
- return SQLITE_ERROR; |
- } |
rc = sqlite3_file_control(db, zName, SQLITE_FCNTL_FILE_POINTER, &pFile); |
if( rc!=SQLITE_OK ) { |
@@ -519,8 +519,41 @@ static int GetPager(sqlite3 *db, const char *zName, |
return rc; |
} |
- nPageSize = sqlite3BtreeGetPageSize(pBt); |
- nReservedSize = sqlite3BtreeGetOptimalReserve(pBt); |
+ /* Read the Initial header information. In case of SQLITE_IOERR_SHORT_READ, |
+ ** the header is incomplete, which means no data could be recovered anyhow. |
+ */ |
+ rc = pFile->pMethods->xRead(pFile, header, sizeof(header), 0); |
+ if( rc != SQLITE_OK ){ |
+ pFile->pMethods->xUnlock(pFile, SQLITE_LOCK_NONE); |
+ if( rc==SQLITE_IOERR_SHORT_READ ){ |
+ return SQLITE_CORRUPT; |
+ } |
+ return rc; |
+ } |
+ |
+ /* Page size must be a power of two between 512 and 32768 inclusive. */ |
+ nPageSize = decodeUnsigned16(header + kiHeaderPageSizeOffset); |
+ if( (nPageSize&(nPageSize-1)) || nPageSize>32768 || nPageSize<512 ){ |
+ pFile->pMethods->xUnlock(pFile, SQLITE_LOCK_NONE); |
+ return rc; |
+ } |
+ |
+ /* Space reserved a the end of the page for extensions. Usually 0. */ |
+ nReservedSize = header[kiHeaderReservedSizeOffset]; |
+ |
+ /* 1 for UTF-8, 2 for UTF-16le, 3 for UTF-16be. */ |
+ iEncoding = decodeUnsigned32(header + kiHeaderEncodingOffset); |
+ if( iEncoding==3 ){ |
+ *piEncoding = SQLITE_UTF16BE; |
+ } else if( iEncoding==2 ){ |
+ *piEncoding = SQLITE_UTF16LE; |
+ } else if( iEncoding==1 ){ |
+ *piEncoding = SQLITE_UTF8; |
+ } else { |
+ /* This case should not be possible. */ |
+ *piEncoding = SQLITE_UTF8; |
+ } |
+ |
rc = pagerCreate(pFile, nPageSize, &pPager); |
if( rc!=SQLITE_OK ){ |
pFile->pMethods->xUnlock(pFile, SQLITE_LOCK_NONE); |
@@ -529,6 +562,7 @@ static int GetPager(sqlite3 *db, const char *zName, |
*ppPager = pPager; |
*pnPageSize = nPageSize - nReservedSize; |
+ *piEncoding = iEncoding; |
return SQLITE_OK; |
} |
@@ -655,57 +689,6 @@ static int getRootPage(sqlite3 *db, const char *zDb, const char *zTable, |
return rc; |
} |
-static int getEncoding(sqlite3 *db, const char *zDb, int* piEncoding){ |
- sqlite3_stmt *pStmt; |
- int rc; |
- char *zSql = sqlite3_mprintf("PRAGMA %s.encoding", zDb); |
- if( !zSql ){ |
- return SQLITE_NOMEM; |
- } |
- |
- rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); |
- sqlite3_free(zSql); |
- if( rc!=SQLITE_OK ){ |
- return rc; |
- } |
- |
- /* Require a result. */ |
- rc = sqlite3_step(pStmt); |
- if( rc==SQLITE_DONE ){ |
- /* This case should not be possible. */ |
- rc = SQLITE_CORRUPT; |
- }else if( rc==SQLITE_ROW ){ |
- if( sqlite3_column_type(pStmt, 0)==SQLITE_TEXT ){ |
- const char* z = (const char *)sqlite3_column_text(pStmt, 0); |
- /* These strings match the literals in pragma.c. */ |
- if( !strcmp(z, "UTF-16le") ){ |
- *piEncoding = SQLITE_UTF16LE; |
- }else if( !strcmp(z, "UTF-16be") ){ |
- *piEncoding = SQLITE_UTF16BE; |
- }else if( !strcmp(z, "UTF-8") ){ |
- *piEncoding = SQLITE_UTF8; |
- }else{ |
- /* This case should not be possible. */ |
- *piEncoding = SQLITE_UTF8; |
- } |
- }else{ |
- /* This case should not be possible. */ |
- *piEncoding = SQLITE_UTF8; |
- } |
- |
- /* Require only one result. */ |
- rc = sqlite3_step(pStmt); |
- if( rc==SQLITE_DONE ){ |
- rc = SQLITE_OK; |
- }else if( rc==SQLITE_ROW ){ |
- /* This case should not be possible. */ |
- rc = SQLITE_CORRUPT; |
- } |
- } |
- sqlite3_finalize(pStmt); |
- return rc; |
-} |
- |
/* Cursor for iterating interior nodes. Interior page cells contain a |
* child page number and a rowid. The child page contains items left |
* of the rowid (less than). The rightmost page of the subtree is |
@@ -1761,13 +1744,7 @@ static int recoverOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ |
return rc; |
} |
- iEncoding = 0; |
- rc = getEncoding(pRecover->db, pRecover->zDb, &iEncoding); |
- if( rc!=SQLITE_OK ){ |
- return rc; |
- } |
- |
- rc = GetPager(pRecover->db, pRecover->zDb, &pPager, &nPageSize); |
+ rc = GetPager(pRecover->db, pRecover->zDb, &pPager, &nPageSize, &iEncoding); |
if( rc!=SQLITE_OK ){ |
return rc; |
} |