1From 90cffaced08c1214ad71a19837d04d70bea71e5d Mon Sep 17 00:00:00 2001 2From: MartinChoo <214582617@qq.com> 3Date: Sat, 26 Jul 2025 17:27:24 +0800 4Subject: [PATCH 1/4] Allow enable checksum through PRAGMA 5 6--- 7 ext/misc/cksumvfs.c | 190 ++++++++++++++++++++++++++++++++++++-------- 8 src/sqlite3.c | 175 ++++++++++++++++++++++++++++++++-------- 9 2 files changed, 296 insertions(+), 69 deletions(-) 10 11diff --git a/ext/misc/cksumvfs.c b/ext/misc/cksumvfs.c 12index 6f4c55c..8df1a5e 100644 13--- a/ext/misc/cksumvfs.c 14+++ b/ext/misc/cksumvfs.c 15@@ -73,12 +73,12 @@ 16 ** encountered that contains an invalid checksum. 17 ** 18 ** Checksumming only works on databases that have a reserve-bytes 19-** value of exactly 8. The default value for reserve-bytes is 0. 20+** value of exactly 10. The default value for reserve-bytes is 0. 21 ** Hence, newly created database files will omit the checksum by 22 ** default. To create a database that includes a checksum, change 23-** the reserve-bytes value to 8 by runing: 24+** the reserve-bytes value to 10 by runing: 25 ** 26-** int n = 8; 27+** int n = 10; 28 ** sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVE_BYTES, &n); 29 ** 30 ** If you do this immediately after creating a new database file, 31@@ -92,12 +92,12 @@ 32 ** If the database is in WAL mode, you should shutdown and 33 ** reopen all database connections before continuing. 34 ** 35-** From the CLI, use the ".filectrl reserve_bytes 8" command, 36+** From the CLI, use the ".filectrl reserve_bytes 10" command, 37 ** followed by "VACUUM;". 38 ** 39 ** Note that SQLite allows the number of reserve-bytes to be 40 ** increased but not decreased. So if a database file already 41-** has a reserve-bytes value greater than 8, there is no way to 42+** has a reserve-bytes value greater than 10, there is no way to 43 ** activate checksumming on that database, other than to dump 44 ** and restore the database file. Note also that other extensions 45 ** might also make use of the reserve-bytes. Checksumming will 46@@ -140,26 +140,29 @@ 47 ** "Verification" in this context means the feature that causes 48 ** SQLITE_IOERR_DATA errors if a checksum mismatch is detected while 49 ** reading. Checksums are always kept up-to-date as long as the 50-** reserve-bytes value of the database is 8, regardless of the setting 51+** reserve-bytes value of the database is 10, regardless of the setting 52 ** of this pragma. Checksum verification can be disabled (for example) 53 ** to do forensic analysis of a database that has previously reported 54 ** a checksum error. 55 ** 56 ** The "checksum_verification" pragma will always respond with "0" if 57-** the database file does not have a reserve-bytes value of 8. The 58+** the database file does not have a reserve-bytes value of 10. The 59 ** pragma will return no rows at all if the cksumvfs extension is 60 ** not loaded. 61 ** 62 ** IMPLEMENTATION NOTES 63 ** 64-** The checksum is stored in the last 8 bytes of each page. This 65+** The checksum is stored in the last 10 bytes of each page. This 66 ** module only operates if the "bytes of reserved space on each page" 67-** value at offset 20 the SQLite database header is exactly 8. If 68-** the reserved-space value is not 8, this module is a no-op. 69+** value at offset 20 the SQLite database header is exactly 10. If 70+** the reserved-space value is not 10, this module is a no-op. 71 */ 72 #if defined(SQLITE_AMALGAMATION) && !defined(SQLITE_CKSUMVFS_STATIC) 73 # define SQLITE_CKSUMVFS_STATIC 74 #endif 75+#ifndef SQLITE_EXPORT 76+# define SQLITE_EXPORT 77+#endif 78 #ifdef SQLITE_CKSUMVFS_STATIC 79 # include "sqlite3.h" 80 #else 81@@ -193,6 +196,21 @@ typedef struct CksmFile CksmFile; 82 typedef unsigned char u8; 83 typedef unsigned int u32; 84 #endif 85+typedef sqlite3_uint64 u64; 86+ 87+/* 88+** Cksumvfs reserved area, file format: 89+** ----------------------------------------------- 90+** |-- MagicNum --|-- CksumType --|--Checksum--| 91+** |--1 byte, 0xff--|--1 byte, 0/1--|-- 8 bytes--| 92+** ----------------------------------------------- 93+** MagicNum: 0xff, CksumType: 0 means without checksum, 1 means with checksum 94+*/ 95+#define CKSUMVFS_MAGIC_NUM 0xff 96+#define CKSUMVFS_WITHOUT_CHECKSUM 0 97+#define CKSUMVFS_CALC_CHECKSUM 1 98+#define CKSUMVFS_CHECKSUM_SIZE 8 99+#define CKSUMVFS_RESERVED_SIZE (1+1+CKSUMVFS_CHECKSUM_SIZE) 100 101 /* Access to a lower-level VFS that (might) implement dynamic loading, 102 ** access to randomness, etc. 103@@ -205,8 +223,9 @@ struct CksmFile { 104 sqlite3_file base; /* IO methods */ 105 const char *zFName; /* Original name of the file */ 106 char computeCksm; /* True to compute checksums. 107- ** Always true if reserve size is 8. */ 108+ ** Always true if reserve size is 10. */ 109 char verifyCksm; /* True to verify checksums */ 110+ char disableVerify; /* True if checksum verification is disabled */ 111 char isWal; /* True if processing a WAL file */ 112 char inCkpt; /* Currently doing a checkpoint */ 113 CksmFile *pPartner; /* Ptr from WAL to main-db, or from main-db to WAL */ 114@@ -307,6 +326,79 @@ static const sqlite3_io_methods cksm_io_methods = { 115 + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \ 116 ) 117 118+static u64 cksmComputeDeepFastLE(void *src, int srcLen){ 119+ u32 s1 = 0, s2 = 0; 120+ u32 s3 = 0, s4 = 0; 121+ u32 s5 = 0, s6 = 0; 122+ u32 s7 = 0, s8 = 0; 123+ u32 *aData = (u32*)src; 124+ u32 *aEnd = aData + srcLen/4; 125+ u64 aOut; 126+ u8 *u8p_aOut = (u8*)&aOut; 127+ while( aData + 32 <= aEnd ){ 128+ s1 += *aData++ + s2; 129+ s2 += *aData++ + s1; 130+ s1 += *aData++ + s2; 131+ s2 += *aData++ + s1; 132+ s1 += *aData++ + s2; 133+ s2 += *aData++ + s1; 134+ s1 += *aData++ + s2; 135+ s2 += *aData++ + s1; 136+ 137+ s3 += *aData++ + s4; 138+ s4 += *aData++ + s3; 139+ s3 += *aData++ + s4; 140+ s4 += *aData++ + s3; 141+ s3 += *aData++ + s4; 142+ s4 += *aData++ + s3; 143+ s3 += *aData++ + s4; 144+ s4 += *aData++ + s3; 145+ 146+ s5 += *aData++ + s6; 147+ s6 += *aData++ + s5; 148+ s5 += *aData++ + s6; 149+ s6 += *aData++ + s5; 150+ s5 += *aData++ + s6; 151+ s6 += *aData++ + s5; 152+ s5 += *aData++ + s6; 153+ s6 += *aData++ + s5; 154+ 155+ s7 += *aData++ + s8; 156+ s8 += *aData++ + s7; 157+ s7 += *aData++ + s8; 158+ s8 += *aData++ + s7; 159+ s7 += *aData++ + s8; 160+ s8 += *aData++ + s7; 161+ s7 += *aData++ + s8; 162+ s8 += *aData++ + s7; 163+ 164+ s3 += 13*s1 + 21*s2; 165+ s4 += 21*s1 + 34*s2; 166+ 167+ s5 += 13*s3 + 21*s4; 168+ s6 += 21*s3 + 34*s4; 169+ 170+ s7 += 13*s5 + 21*s6; 171+ s8 += 21*s5 + 34*s6; 172+ 173+ s1 = s7; 174+ s2 = s8; 175+ s3 = 0; 176+ s4 = 0; 177+ s5 = 0; 178+ s6 = 0; 179+ s7 = 0; 180+ s8 = 0; 181+ } 182+ while( aData < aEnd ){ 183+ s1 = *aData++ + s1 + s2; 184+ s2 = *aData++ + s1 + s2; 185+ } 186+ memcpy(u8p_aOut, &s1, 4); 187+ memcpy(u8p_aOut + 4, &s2, 4); 188+ return aOut; 189+} 190+ 191 /* Compute a checksum on a buffer */ 192 static void cksmCompute( 193 u8 *a, /* Content to be checksummed */ 194@@ -324,10 +416,8 @@ static void cksmCompute( 195 196 if( 1 == *(u8*)&x ){ 197 /* Little-endian */ 198- do { 199- s1 += *aData++ + s2; 200- s2 += *aData++ + s1; 201- }while( aData<aEnd ); 202+ *(u64*)aOut = cksmComputeDeepFastLE(a, nByte); 203+ return; 204 }else{ 205 /* Big-endian */ 206 do { 207@@ -356,14 +446,16 @@ static void cksmVerifyFunc( 208 ){ 209 int nByte; 210 u8 *data; 211- u8 cksum[8]; 212+ u8 cksum[CKSUMVFS_CHECKSUM_SIZE]; 213 data = (u8*)sqlite3_value_blob(argv[0]); 214 if( data==0 ) return; 215 if( sqlite3_value_type(argv[0])!=SQLITE_BLOB ) return; 216 nByte = sqlite3_value_bytes(argv[0]); 217 if( nByte<512 || nByte>65536 || (nByte & (nByte-1))!=0 ) return; 218- cksmCompute(data, nByte-8, cksum); 219- sqlite3_result_int(context, memcmp(data+nByte-8,cksum,8)==0); 220+ if( data[nByte-CKSUMVFS_RESERVED_SIZE]!=CKSUMVFS_MAGIC_NUM 221+ || data[nByte-CKSUMVFS_RESERVED_SIZE+1]!=CKSUMVFS_CALC_CHECKSUM ) return; 222+ cksmCompute(data, nByte-CKSUMVFS_CHECKSUM_SIZE, cksum); 223+ sqlite3_result_int(context, memcmp(data+nByte-CKSUMVFS_CHECKSUM_SIZE,cksum,CKSUMVFS_CHECKSUM_SIZE)==0); 224 } 225 226 #ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME 227@@ -375,7 +467,7 @@ static void cksmVerifyFunc( 228 ** 229 ** sqlite3_file_control(db, SCHEMANAME, SQLITE_FCNTL_RESERVE_BYTE, &n); 230 ** 231-** In order to set the reserve bytes value to 8, so that cksumvfs will 232+** In order to set the reserve bytes value to 10, so that cksumvfs will 233 ** operation. This feature is provided (if and only if the 234 ** SQLITE_CKSUMVFS_INIT_FUNCNAME compile-time option is set to a string 235 ** which is the name of the SQL function) so as to provide the ability 236@@ -393,7 +485,7 @@ static void cksmInitFunc( 237 int argc, 238 sqlite3_value **argv 239 ){ 240- int nByte = 8; 241+ int nByte = CKSUMVFS_RESERVED_SIZE; 242 const char *zSchemaName = (const char*)sqlite3_value_text(argv[0]); 243 sqlite3 *db = sqlite3_context_db_handle(context); 244 sqlite3_file_control(db, zSchemaName, SQLITE_FCNTL_RESERVE_BYTES, &nByte); 245@@ -422,9 +514,11 @@ static int cksmClose(sqlite3_file *pFile){ 246 static void cksmSetFlags(CksmFile *p, int hasCorrectReserveSize){ 247 if( hasCorrectReserveSize!=p->computeCksm ){ 248 p->computeCksm = p->verifyCksm = hasCorrectReserveSize; 249+ if( p->disableVerify ) p->verifyCksm = 0; 250 if( p->pPartner ){ 251 p->pPartner->verifyCksm = hasCorrectReserveSize; 252 p->pPartner->computeCksm = hasCorrectReserveSize; 253+ if( p->pPartner->disableVerify ) p->pPartner->verifyCksm = 0; 254 } 255 } 256 } 257@@ -435,9 +529,11 @@ static void EncodeReservedBytesIntoBase16(const u8 *reserved, int len, char *enc 258 *encodeStr++ = baseCode[(reserved[i] >> 4) & 0x0F]; 259 *encodeStr++ = baseCode[reserved[i] & 0x0F]; 260 } 261- *encodeStr = '0'; 262+ *encodeStr = '\0'; 263 } 264 265+#define CKSUM_HEX_LEN (CKSUMVFS_CHECKSUM_SIZE+1)*2 266+ 267 /* 268 ** Read data from a cksm-file. 269 */ 270@@ -452,11 +548,11 @@ static int cksmRead( 271 pFile = ORIGFILE(pFile); 272 rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst); 273 if( rc==SQLITE_OK ){ 274- if( iOfst==0 && iAmt>=100 && ( 275+ if( (iOfst==0 || p->isWal) && iAmt>=100 && ( 276 memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 277 )){ 278 u8 *d = (u8*)zBuf; 279- char hasCorrectReserveSize = (d[20]==8); 280+ char hasCorrectReserveSize = (d[20]==CKSUMVFS_RESERVED_SIZE); 281 cksmSetFlags(p, hasCorrectReserveSize); 282 } 283 /* Verify the checksum if 284@@ -464,18 +560,28 @@ static int cksmRead( 285 ** database page, only support pageSize:4K 286 ** (2) checksum verification is enabled 287 ** (3) we are not in the middle of checkpoint 288+ ** (4) magic number should be 0xff 289+ ** (5) checksum type should be 1, 0 means without checksum 290 */ 291 if( iAmt==4096 /* (1) */ 292 && p->verifyCksm /* (2) */ 293 && !p->inCkpt /* (3) */ 294 ){ 295- u8 cksum[8]; 296- cksmCompute((u8*)zBuf, iAmt-8, cksum); 297- if( memcmp((u8*)zBuf+iAmt-8, cksum, 8)!=0 ){ 298- char expect[18] = {0}; 299- char actual[18] = {0}; 300- EncodeReservedBytesIntoBase16((u8 *)zBuf+iAmt-8, 8, expect, 18); 301- EncodeReservedBytesIntoBase16(cksum, 8, actual, 18); 302+ if( ((u8*)zBuf)[iAmt-CKSUMVFS_RESERVED_SIZE]!=CKSUMVFS_MAGIC_NUM ){ /* (4) */ 303+ sqlite3_log(SQLITE_IOERR_DATA, "unrecognized format, offset %lld of \"%s\", amt:%d", iOfst, p->zFName, iAmt); 304+ return SQLITE_IOERR_DATA; 305+ } 306+ if( ((u8*)zBuf)[iAmt-CKSUMVFS_RESERVED_SIZE+1]==CKSUMVFS_WITHOUT_CHECKSUM ){ /* (5) */ 307+ return rc; 308+ } 309+ u8 cksum[CKSUMVFS_CHECKSUM_SIZE]; 310+ cksmCompute((u8*)zBuf, iAmt-CKSUMVFS_CHECKSUM_SIZE, cksum); 311+ if( memcmp((u8*)zBuf+iAmt-CKSUMVFS_CHECKSUM_SIZE, cksum, CKSUMVFS_CHECKSUM_SIZE)!=0 ){ 312+ char expect[CKSUM_HEX_LEN] = {0}; 313+ char actual[CKSUM_HEX_LEN] = {0}; 314+ EncodeReservedBytesIntoBase16((u8 *)zBuf+iAmt-CKSUMVFS_CHECKSUM_SIZE, CKSUMVFS_CHECKSUM_SIZE, expect, 315+ CKSUM_HEX_LEN); 316+ EncodeReservedBytesIntoBase16(cksum, CKSUMVFS_CHECKSUM_SIZE, actual, CKSUM_HEX_LEN); 317 sqlite3_log(SQLITE_IOERR_DATA, "checksum fault offset %lld of \"%s\", amt:%d, expect:%s, actual:%s", 318 iOfst, p->zFName, iAmt, expect, actual); 319 rc = SQLITE_IOERR_DATA; 320@@ -496,11 +602,11 @@ static int cksmWrite( 321 ){ 322 CksmFile *p = (CksmFile *)pFile; 323 pFile = ORIGFILE(pFile); 324- if( iOfst==0 && iAmt>=100 && ( 325+ if( (iOfst==0 || p->isWal) && iAmt>=100 && ( 326 memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 327 )){ 328 u8 *d = (u8*)zBuf; 329- char hasCorrectReserveSize = (d[20]==8); 330+ char hasCorrectReserveSize = (d[20]==CKSUMVFS_RESERVED_SIZE); 331 cksmSetFlags(p, hasCorrectReserveSize); 332 } 333 /* If the write size is appropriate for a database page and if 334@@ -513,7 +619,11 @@ static int cksmWrite( 335 && p->computeCksm 336 && !p->inCkpt 337 ){ 338- cksmCompute((u8*)zBuf, iAmt-8, ((u8*)zBuf)+iAmt-8); 339+ ((u8*)zBuf)[iAmt-CKSUMVFS_RESERVED_SIZE]=CKSUMVFS_MAGIC_NUM; 340+ ((u8*)zBuf)[iAmt-CKSUMVFS_RESERVED_SIZE+1]=p->verifyCksm ? CKSUMVFS_CALC_CHECKSUM : CKSUMVFS_WITHOUT_CHECKSUM; 341+ if( p->verifyCksm ){ /* do not compute checksum if verifyCksm is off */ 342+ cksmCompute((u8*)zBuf, iAmt-CKSUMVFS_CHECKSUM_SIZE, ((u8*)zBuf)+iAmt-CKSUMVFS_CHECKSUM_SIZE); 343+ } 344 } 345 return pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst); 346 } 347@@ -585,11 +695,16 @@ static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){ 348 || sqlite3_stricmp("yes",zArg)==0 349 || sqlite3_stricmp("on",zArg)==0 350 ){ 351+ p->disableVerify = 0; 352 p->verifyCksm = p->computeCksm; 353 }else{ 354+ p->disableVerify = 1; 355 p->verifyCksm = 0; 356 } 357- if( p->pPartner ) p->pPartner->verifyCksm = p->verifyCksm; 358+ if( p->pPartner ){ 359+ p->pPartner->disableVerify = p->disableVerify; 360+ p->pPartner->verifyCksm = p->verifyCksm; 361+ } 362 } 363 azArg[0] = sqlite3_mprintf("%d",p->verifyCksm); 364 return SQLITE_OK; 365@@ -729,9 +844,12 @@ static int cksmOpen( 366 p->pPartner->pPartner = p; 367 p->isWal = 1; 368 p->computeCksm = p->pPartner->computeCksm; 369+ p->verifyCksm = p->pPartner->verifyCksm; 370+ p->disableVerify = p->pPartner->disableVerify; 371 }else{ 372 p->isWal = 0; 373 p->computeCksm = 0; 374+ p->verifyCksm = 0; 375 } 376 p->zFName = zName; 377 cksm_open_done: 378@@ -902,6 +1020,10 @@ int sqlite3_cksumvfs_init( 379 #endif /* !defined(SQLITE_CKSUMVFS_STATIC) */ 380 381 #ifdef SQLITE_CKSUMVFS_STATIC 382+sqlite3_file *sqlite3_get_orig_file(sqlite3_file *file) { 383+ return ORIGFILE(file); 384+} 385+ 386 struct sqlite3_api_routines_cksumvfs { 387 int (*register_cksumvfs)(const char *); 388 int (*unregister_cksumvfs)(); 389diff --git a/src/sqlite3.c b/src/sqlite3.c 390index 4c538a1..c84348b 100644 391--- a/src/sqlite3.c 392+++ b/src/sqlite3.c 393@@ -139875,6 +139875,10 @@ static int integrityCheckResultRow(Vdbe *v){ 394 return addr; 395 } 396 397+#ifdef SQLITE_CKSUMVFS_STATIC 398+static int PragmaCksumPersistEnable(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight); 399+#endif 400+ 401 /* 402 ** Process a pragma statement. 403 ** 404@@ -139997,7 +140001,15 @@ SQLITE_PRIVATE void sqlite3Pragma( 405 /* PragmaMetaDoubleWrie executes internal */ 406 goto pragma_out; 407 } 408-#endif 409+#endif /* SQLITE_META_DWR */ 410+ 411+#ifdef SQLITE_CKSUMVFS_STATIC 412+ if( PragmaCksumPersistEnable(db, iDb, pParse, zLeft, zRight) ){ 413+ /* PragmaCksumPersistEnable executes internal */ 414+ goto pragma_out; 415+ } 416+#endif /* SQLITE_CKSUMVFS_STATIC */ 417+ 418 /* Locate the pragma in the lookup table */ 419 pPragma = pragmaLocate(zLeft); 420 if( pPragma==0 ){ 421@@ -184259,16 +184271,12 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo 422 *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager); 423 rc = SQLITE_OK; 424 }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){ 425-#ifndef SQLITE_CKSUMVFS_STATIC 426- rc = SQLITE_OK; 427-#else 428 int iNew = *(int*)pArg; 429 *(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree); 430 if( iNew>=0 && iNew<=255 ){ 431 sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0); 432 } 433 rc = SQLITE_OK; 434-#endif 435 }else if( op==SQLITE_FCNTL_RESET_CACHE ){ 436 sqlite3BtreeClearCache(pBtree); 437 rc = SQLITE_OK; 438@@ -256094,7 +256102,71 @@ export_finish: 439 return; 440 } 441 /************** End file hw_codec.c *****************************************/ 442-#endif 443+#endif /* SQLITE_HAS_CODEC */ 444+ 445+#ifdef SQLITE_CKSUMVFS_STATIC 446+#define SQLITE_CKSUMVFS_RESERVED_SIZE 10 447+static int PragmaCksumPersistEnable(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight){ 448+ Btree *pBt = db->aDb[iDb].pBt; 449+ if( pBt==NULL || zLeft==NULL || sqlite3StrICmp(zLeft, "checksum_persist_enable")!=0 ){ 450+ return 0; 451+ } 452+ sqlite3_mutex_enter(db->mutex); 453+ int reserved = sqlite3BtreeGetRequestedReserve(pBt); 454+ sqlite3_mutex_leave(db->mutex); 455+ if( zRight==NULL ){ 456+ // Try to get the state of cksumvfs enable 457+ Vdbe *v = sqlite3GetVdbe(parse); 458+ sqlite3VdbeSetNumCols(v, 1); 459+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "checksum_persist_enable", SQLITE_STATIC); 460+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, (reserved==SQLITE_CKSUMVFS_RESERVED_SIZE ? "ON" : "OFF"), 0); 461+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); 462+ }else if( sqlite3StrICmp(zRight, "on")==0 ){ 463+ // Enabled 464+ if( reserved==0 ){ 465+ Pager *pPager = pBt->pBt->pPager; 466+ if( (pPager->memDb!=0 && pPager->dbSize!=0) || sqlite3PcacheRefCount(pPager->pPCache)!=0 ){ 467+ parse->nErr++; 468+ parse->rc = SQLITE_MISUSE; 469+ sqlite3_log(SQLITE_MISUSE, "checksum_persist_enable can only be enabled before any other ops."); 470+ return 1; 471+ } 472+ int reservedTarget = SQLITE_CKSUMVFS_RESERVED_SIZE; 473+ int res = sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVE_BYTES, &reservedTarget); 474+ if( res!=SQLITE_OK ){ 475+ parse->nErr++; 476+ parse->rc = res; 477+ sqlite3_log(res, "try set reserved region to turn on checksum_persist_enable"); 478+ } 479+ }else if( reserved!=SQLITE_CKSUMVFS_RESERVED_SIZE ){ 480+ // undefined reserved bytes 481+ parse->nErr++; 482+ parse->rc = SQLITE_MISUSE; 483+ sqlite3_log(SQLITE_MISUSE, "unrecognized reserved region led to cksumvfs cannot enable"); 484+ } 485+ } 486+ return 1; 487+} 488+extern sqlite3_file *sqlite3_get_orig_file(sqlite3_file *file); 489+#else 490+static sqlite3_file *sqlite3_get_orig_file(sqlite3_file *file) { 491+ return file; 492+} 493+#endif /* SQLITE_CKSUMVFS_STATIC */ 494+ 495+#if SQLITE_OS_UNIX 496+#define SQLITE_CHECK_FILE_ID_UNIX 1 497+#define SQLITE_CHECK_FILE_ID_CKSM 2 498+ 499+// checkFileId should not be 0, it must be SQLITE_CHECK_FILE_ID_UNIX(1) or SQLITE_CHECK_FILE_ID_CKSM(2) 500+static unixFile *Sqlite3GetUnixFile(sqlite3_file *file, u8 checkFileId) { 501+ if (checkFileId == SQLITE_CHECK_FILE_ID_UNIX) { 502+ return (unixFile*)file; 503+ } 504+ return (unixFile*)sqlite3_get_orig_file(file); 505+} 506+#endif /* SQLITE_OS_UNIX */ 507+ 508 #ifdef SQLITE_META_DWR 509 #define META_DWR_MAX_PAGES 500 510 #define META_DWR_MAGIC 0x234A86D9 511@@ -256126,7 +256198,7 @@ typedef struct MetaDwrHdr { 512 Pgno *pages; 513 u32 pageBufSize; 514 u8 hdrValid; 515- u8 checkFileId; 516+ u8 checkFileId; /* 0, means no check, 1 means vfs:unix, 2 means vfs:cksm */ 517 u16 needSync; 518 i64 lastSyncTime; 519 } MetaDwrHdr; 520@@ -256140,7 +256212,7 @@ typedef struct MetaDwrHdr { 521 static int MetaDwrHeaderSimpleCheck(Pager *pPager, MetaDwrHdr *hdr) { 522 #if SQLITE_OS_UNIX 523 if (hdr->checkFileId) { 524- unixFile *fd = (unixFile *)pPager->fd; 525+ unixFile *fd = Sqlite3GetUnixFile(pPager->fd, hdr->checkFileId); 526 if (fd == NULL || fd->pInode == NULL || pPager->pVfs == NULL) { 527 return SQLITE_INTERNAL; 528 } 529@@ -256150,7 +256222,7 @@ static int MetaDwrHeaderSimpleCheck(Pager *pPager, MetaDwrHdr *hdr) { 530 return SQLITE_IOERR_DATA; 531 } 532 } 533-#endif 534+#endif /* SQLITE_OS_UNIX */ 535 if (hdr->pageCnt > META_DWR_MAX_PAGES || hdr->version != META_DWR_VERSION || 536 hdr->magic != META_DWR_MAGIC || hdr->checkSum != META_DWR_MAGIC) { 537 sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file check wrong pageCnt %u, version %u, magic %u, checkSum %u", 538@@ -256382,7 +256454,15 @@ static MetaDwrHdr *AllocInitMetaHeaderDwr(Pager *pPager) { 539 MetaDwrReleaseHdr(hdr); 540 return NULL; 541 } 542- hdr->checkFileId = (pPager->pVfs != NULL && sqlite3_stricmp(pPager->pVfs->zName, "unix") == 0); 543+ if (pPager->pVfs==NULL) { 544+ hdr->checkFileId = 0; 545+ } else if (sqlite3_stricmp(pPager->pVfs->zName, "unix") == 0) { 546+ hdr->checkFileId = SQLITE_CHECK_FILE_ID_UNIX; 547+ } else if (sqlite3_stricmp(pPager->pVfs->zName, "cksmvfs") == 0) { 548+ hdr->checkFileId = SQLITE_CHECK_FILE_ID_CKSM; 549+ } else { 550+ hdr->checkFileId = 0; 551+ } 552 return hdr; 553 } 554 555@@ -256395,7 +256475,7 @@ static void MetaDwrCloseFile(Pager *pPager) { 556 osMunmap(pPager->metaMapPage, META_DWR_HEADER_PAGE_SIZE); 557 pPager->metaMapPage = NULL; 558 } 559-#endif 560+#endif /* SQLITE_OS_UNIX */ 561 if (pPager->metaHdr && pPager->metaHdr->needSync > 0) { 562 (void)sqlite3OsSync(pPager->metaFd, SQLITE_SYNC_NORMAL); 563 } 564@@ -256490,10 +256570,10 @@ static void MetaDwrUpdateHeaderDbInfo(BtShared *pBt) { 565 } else { 566 hdr->mxFrameInWal = 0; 567 } 568-#endif 569+#endif /* SQLITE_OMIT_WAL */ 570 #if SQLITE_OS_UNIX 571 if (hdr->checkFileId) { 572- unixFile *fd = (unixFile *)pBt->pPager->fd; 573+ unixFile *fd = Sqlite3GetUnixFile(pBt->pPager->fd, hdr->checkFileId); 574 if (fd == NULL || fd->pInode == NULL) { 575 sqlite3_log(SQLITE_WARNING_DUMP, "update meta header invalid fd"); 576 hdr->hdrValid = 0; 577@@ -256501,7 +256581,7 @@ static void MetaDwrUpdateHeaderDbInfo(BtShared *pBt) { 578 } 579 hdr->dbFileInode = fd->pInode->fileId.ino; 580 } 581-#endif 582+#endif /* SQLITE_OS_UNIX */ 583 hdr->freeListPageNo = sqlite3Get4byte(dbHdrInfo + 4); 584 hdr->freeListPageCnt = sqlite3Get4byte(dbHdrInfo + 8); 585 hdr->schemaCookie = sqlite3Get4byte(dbHdrInfo + 12); 586@@ -256597,7 +256677,7 @@ static int MetaDwrWriteOnePage(Btree *pBt, PgHdr *pPage, MetaDwrHdr *hdr, u8 cur 587 return SQLITE_NOMEM; 588 #else 589 pData = pPage->pData; 590-#endif 591+#endif /* SQLITE_HAS_CODEC */ 592 rc = sqlite3OsWrite(pPager->metaFd, pData, pageSz, ofs); 593 if (rc != SQLITE_OK) { 594 return rc; 595@@ -256659,7 +256739,7 @@ static int MetaDwrCheckPerm(sqlite3_vfs *pVfs, u8 openCreate, char *metaPath) { 596 if (openCreate) { 597 sqlite3_log(SQLITE_WARNING_DUMP, "Meta double write disabled, sysno %d", errno); 598 } 599-#endif 600+#endif /* OS_FEATURE */ 601 return rc; 602 } 603 604@@ -256702,7 +256782,7 @@ static int MetaDwrOpenFile(Pager *pPager, u8 openCreate) { 605 pPager->metaMapPage = page; 606 } 607 } 608-#endif 609+#endif /* SQLITE_OS_UNIX */ 610 pPager->metaFd = metaFd; 611 INIT_META_OUT: 612 sqlite3EndBenignMalloc(); 613@@ -256826,7 +256906,7 @@ static int MetaDwrRecoverHeadPage( 614 goto RELEASE_OUT; 615 } 616 } 617-#endif 618+#endif /* SQLITE_OMIT_WAL */ 619 rc = SQLITE_NOTADB; 620 for (u32 i = 0; i < hdr->pageCnt; i++) { 621 if (hdr->pages[i] != pgno) { 622@@ -257076,15 +257156,24 @@ CHK_RESTORE_OUT: 623 static inline u8 IsConnectionValidForCheck(Pager *pPager) 624 { 625 #if SQLITE_OS_UNIX 626- unixFile *fd = (unixFile *)pPager->fd; 627- // unix and only one connection exist 628- if (fd == NULL || fd->pInode == NULL || pPager->pVfs == NULL || 629- sqlite3_stricmp(pPager->pVfs->zName, "unix") != 0 || fd->pInode->nRef != 1) { 630- return 0; 631- } 632- return 1; 633-#else 634+ if (pPager->pVfs == NULL) { 635 return 0; 636+ } 637+ if (sqlite3_stricmp(pPager->pVfs->zName, "unix") != 0 && sqlite3_stricmp(pPager->pVfs->zName, "cksmvfs") != 0) { 638+ return 0; 639+ } 640+ u8 checkFileId = SQLITE_CHECK_FILE_ID_UNIX; 641+ if (sqlite3_stricmp(pPager->pVfs->zName, "cksmvfs") == 0) { 642+ checkFileId = SQLITE_CHECK_FILE_ID_CKSM; 643+ } 644+ unixFile *fd = Sqlite3GetUnixFile(pPager->fd, checkFileId); 645+ // unix and only one connection exist 646+ if (fd == NULL || fd->pInode == NULL || fd->pInode->nRef != 1) { 647+ return 0; 648+ } 649+ return 1; 650+#else 651+ return 0; 652 #endif 653 } 654 655@@ -257099,7 +257188,7 @@ static int MetaDwrOpenAndCheck(Btree *pBt) 656 if (pPager->xCodec) { 657 return SQLITE_OK; 658 } 659-#endif 660+#endif /* SQLITE_HAS_CODEC */ 661 sqlite3BtreeEnter(pBt); 662 int rc = SQLITE_OK; 663 int openedTransaction = 0; 664@@ -257144,7 +257233,7 @@ static void MetaDwrDisable(Btree *pBt) 665 if (pPager->xCodec) { 666 return; 667 } 668-#endif 669+#endif /* SQLITE_HAS_CODEC */ 670 sqlite3BtreeEnter(pBt); 671 MetaDwrCloseFile(pPager); 672 MetaDwrReleaseHdr(pPager->metaHdr); 673@@ -257159,7 +257248,8 @@ static void MetaDwrDisable(Btree *pBt) 674 } 675 sqlite3BtreeLeave(pBt); 676 } 677-#endif 678+#endif /* SQLITE_META_DWR */ 679+ 680 #if SQLITE_OS_UNIX 681 #include <unistd.h> 682 #include <sys/syscall.h> 683@@ -257368,10 +257458,17 @@ static void DumpLocksByWal(Wal *pWal) 684 sqlite3_log(SQLITE_ERROR, "Wal ptr is NULL!"); 685 return; 686 } 687- if (pWal->pVfs == NULL || sqlite3_stricmp(pWal->pVfs->zName, "unix") != 0) { 688+ u8 checkFileId = 0; 689+ if (pWal->pVfs==NULL) { 690+ return; 691+ } else if (sqlite3_stricmp(pWal->pVfs->zName, "unix") == 0) { 692+ checkFileId = SQLITE_CHECK_FILE_ID_UNIX; 693+ } else if (sqlite3_stricmp(pWal->pVfs->zName, "cksmvfs") == 0) { 694+ checkFileId = SQLITE_CHECK_FILE_ID_CKSM; 695+ } else { 696 return; 697 } 698- DumpLocksInfo((unixFile *)(pWal->pDbFd), 1); 699+ DumpLocksInfo(Sqlite3GetUnixFile(pWal->pDbFd, checkFileId), 1); 700 } 701 #endif /* #ifndef SQLITE_OMIT_WAL */ 702 703@@ -257381,13 +257478,20 @@ static void DumpLocksByPager(Pager *pPager) 704 sqlite3_log(SQLITE_ERROR, "Pager ptr is NULL!"); 705 return; 706 } 707- if (pPager->pVfs == NULL || sqlite3_stricmp(pPager->pVfs->zName, "unix") != 0) { 708+ u8 checkFileId = 0; 709+ if (pPager->pVfs==NULL) { 710+ return; 711+ } else if (sqlite3_stricmp(pPager->pVfs->zName, "unix") == 0) { 712+ checkFileId = SQLITE_CHECK_FILE_ID_UNIX; 713+ } else if (sqlite3_stricmp(pPager->pVfs->zName, "cksmvfs") == 0) { 714+ checkFileId = SQLITE_CHECK_FILE_ID_CKSM; 715+ } else { 716 return; 717 } 718 #ifndef SQLITE_OMIT_WAL 719- DumpLocksInfo((unixFile *)(pPager->fd), pPager->pWal != NULL); 720+ DumpLocksInfo(Sqlite3GetUnixFile(pPager->fd, checkFileId), pPager->pWal != NULL); 721 #else /* #ifndef SQLITE_OMIT_WAL */ 722- DumpLocksInfo((unixFile *)(pPager->fd), 0); 723+ DumpLocksInfo(Sqlite3GetUnixFile(pPager->fd, checkFileId), 0); 724 #endif /* #ifndef SQLITE_OMIT_WAL */ 725 } 726 #endif /* SQLITE_OS_UNIX */ 727@@ -258499,7 +258603,8 @@ static const sqlite3_api_routines_cksumvfs sqlite3CksumvfsApis = { 728 }; 729 730 EXPORT_SYMBOLS const sqlite3_api_routines_cksumvfs *sqlite3_export_cksumvfs_symbols = &sqlite3CksumvfsApis; 731-#endif 732+#endif /* SQLITE_CKSUMVFS_STATIC */ 733+ 734 struct sqlite3_api_routines_extra { 735 int (*initialize)(); 736 int (*config)(int,...); 737-- 7382.47.0.windows.2 739 740