1 /* 2 ** 2020-04-20 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** a legal notice, here is a blessing: 6 ** 7 ** May you do good and not evil. 8 ** May you find forgiveness for yourself and forgive others. 9 ** May you share freely, never taking more than you give. 10 ** 11 ****************************************************************************** 12 ** 13 ** This file implements a VFS shim that writes a checksum on each page 14 ** of an SQLite database file. When reading pages, the checksum is verified 15 ** and an error is raised if the checksum is incorrect. 16 ** 17 ** COMPILING 18 ** 19 ** This extension requires SQLite 3.32.0 or later. It uses the 20 ** sqlite3_database_file_object() interface which was added in 21 ** version 3.32.0, so it will not link with an earlier version of 22 ** SQLite. 23 ** 24 ** To build this extension as a separately loaded shared library or 25 ** DLL, use compiler command-lines similar to the following: 26 ** 27 ** (linux) gcc -fPIC -shared cksumvfs.c -o cksumvfs.so 28 ** (mac) clang -fPIC -dynamiclib cksumvfs.c -o cksumvfs.dylib 29 ** (windows) cl cksumvfs.c -link -dll -out:cksumvfs.dll 30 ** 31 ** You may want to add additional compiler options, of course, 32 ** according to the needs of your project. 33 ** 34 ** If you want to statically link this extension with your product, 35 ** then compile it like any other C-language module but add the 36 ** "-DSQLITE_CKSUMVFS_STATIC" option so that this module knows that 37 ** it is being statically linked rather than dynamically linked 38 ** 39 ** LOADING 40 ** 41 ** To load this extension as a shared library, you first have to 42 ** bring up a dummy SQLite database connection to use as the argument 43 ** to the sqlite3_load_extension() API call. Then you invoke the 44 ** sqlite3_load_extension() API and shutdown the dummy database 45 ** connection. All subsequent database connections that are opened 46 ** will include this extension. For example: 47 ** 48 ** sqlite3 *db; 49 ** sqlite3_open(":memory:", &db); 50 ** sqlite3_load_extension(db, "./cksumvfs"); 51 ** sqlite3_close(db); 52 ** 53 ** If this extension is compiled with -DSQLITE_CKSUMVFS_STATIC and 54 ** statically linked against the application, initialize it using 55 ** a single API call as follows: 56 ** 57 ** sqlite3_register_cksumvfs(); 58 ** 59 ** Cksumvfs is a VFS Shim. When loaded, "cksmvfs" becomes the new 60 ** default VFS and it uses the prior default VFS as the next VFS 61 ** down in the stack. This is normally what you want. However, in 62 ** complex situations where multiple VFS shims are being loaded, 63 ** it might be important to ensure that cksumvfs is loaded in the 64 ** correct order so that it sequences itself into the default VFS 65 ** Shim stack in the right order. 66 ** 67 ** USING 68 ** 69 ** Open database connections using the sqlite3_open() or 70 ** sqlite3_open_v2() interfaces, as normal. Ordinary database files 71 ** (without a checksum) will operate normally. Databases with 72 ** checksums will return an SQLITE_IOERR_DATA error if a page is 73 ** encountered that contains an invalid checksum. 74 ** 75 ** Checksumming only works on databases that have a reserve-bytes 76 ** value of exactly 8. The default value for reserve-bytes is 0. 77 ** Hence, newly created database files will omit the checksum by 78 ** default. To create a database that includes a checksum, change 79 ** the reserve-bytes value to 8 by runing: 80 ** 81 ** int n = 8; 82 ** sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVE_BYTES, &n); 83 ** 84 ** If you do this immediately after creating a new database file, 85 ** before anything else has been written into the file, then that 86 ** might be all that you need to do. Otherwise, the API call 87 ** above should be followed by: 88 ** 89 ** sqlite3_exec(db, "VACUUM", 0, 0, 0); 90 ** 91 ** It never hurts to run the VACUUM, even if you don't need it. 92 ** If the database is in WAL mode, you should shutdown and 93 ** reopen all database connections before continuing. 94 ** 95 ** From the CLI, use the ".filectrl reserve_bytes 8" command, 96 ** followed by "VACUUM;". 97 ** 98 ** Note that SQLite allows the number of reserve-bytes to be 99 ** increased but not decreased. So if a database file already 100 ** has a reserve-bytes value greater than 8, there is no way to 101 ** activate checksumming on that database, other than to dump 102 ** and restore the database file. Note also that other extensions 103 ** might also make use of the reserve-bytes. Checksumming will 104 ** be incompatible with those other extensions. 105 ** 106 ** VERIFICATION OF CHECKSUMS 107 ** 108 ** If any checksum is incorrect, the "PRAGMA quick_check" command 109 ** will find it. To verify that checksums are actually enabled 110 ** and running, use the following query: 111 ** 112 ** SELECT count(*), verify_checksum(data) 113 ** FROM sqlite_dbpage 114 ** GROUP BY 2; 115 ** 116 ** There are three possible outputs form the verify_checksum() 117 ** function: 1, 0, and NULL. 1 is returned if the checksum is 118 ** correct. 0 is returned if the checksum is incorrect. NULL 119 ** is returned if the page is unreadable. If checksumming is 120 ** enabled, the read will fail if the checksum is wrong, so the 121 ** usual result from verify_checksum() on a bad checksum is NULL. 122 ** 123 ** If everything is OK, the query above should return a single 124 ** row where the second column is 1. Any other result indicates 125 ** either that there is a checksum error, or checksum validation 126 ** is disabled. 127 ** 128 ** CONTROLLING CHECKSUM VERIFICATION 129 ** 130 ** The cksumvfs extension implements a new PRAGMA statement that can 131 ** be used to disable, re-enable, or query the status of checksum 132 ** verification: 133 ** 134 ** PRAGMA checksum_verification; -- query status 135 ** PRAGMA checksum_verification=OFF; -- disable verification 136 ** PRAGMA checksum_verification=ON; -- re-enable verification 137 ** 138 ** The "checksum_verification" pragma will return "1" (true) or "0" 139 ** (false) if checksum verification is enabled or disabled, respectively. 140 ** "Verification" in this context means the feature that causes 141 ** SQLITE_IOERR_DATA errors if a checksum mismatch is detected while 142 ** reading. Checksums are always kept up-to-date as long as the 143 ** reserve-bytes value of the database is 8, regardless of the setting 144 ** of this pragma. Checksum verification can be disabled (for example) 145 ** to do forensic analysis of a database that has previously reported 146 ** a checksum error. 147 ** 148 ** The "checksum_verification" pragma will always respond with "0" if 149 ** the database file does not have a reserve-bytes value of 8. The 150 ** pragma will return no rows at all if the cksumvfs extension is 151 ** not loaded. 152 ** 153 ** IMPLEMENTATION NOTES 154 ** 155 ** The checksum is stored in the last 8 bytes of each page. This 156 ** module only operates if the "bytes of reserved space on each page" 157 ** value at offset 20 the SQLite database header is exactly 8. If 158 ** the reserved-space value is not 8, this module is a no-op. 159 */ 160 #if defined(SQLITE_AMALGAMATION) && !defined(SQLITE_CKSUMVFS_STATIC) 161 # define SQLITE_CKSUMVFS_STATIC 162 #endif 163 #ifdef SQLITE_CKSUMVFS_STATIC 164 # include "sqlite3.h" 165 #else 166 # include "sqlite3ext.h" 167 SQLITE_EXTENSION_INIT1 168 #endif 169 #include <string.h> 170 #include <assert.h> 171 172 173 /* 174 ** Forward declaration of objects used by this utility 175 */ 176 typedef struct sqlite3_vfs CksmVfs; 177 typedef struct CksmFile CksmFile; 178 179 /* 180 ** Useful datatype abbreviations 181 */ 182 #if !defined(SQLITE_AMALGAMATION) 183 typedef unsigned char u8; 184 typedef unsigned int u32; 185 #endif 186 187 /* Access to a lower-level VFS that (might) implement dynamic loading, 188 ** access to randomness, etc. 189 */ 190 #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) 191 #define ORIGFILE(p) ((sqlite3_file*)(((CksmFile*)(p))+1)) 192 193 /* An open file */ 194 struct CksmFile { 195 sqlite3_file base; /* IO methods */ 196 const char *zFName; /* Original name of the file */ 197 char computeCksm; /* True to compute checksums. 198 ** Always true if reserve size is 8. */ 199 char verifyCksm; /* True to verify checksums */ 200 char isWal; /* True if processing a WAL file */ 201 char inCkpt; /* Currently doing a checkpoint */ 202 CksmFile *pPartner; /* Ptr from WAL to main-db, or from main-db to WAL */ 203 }; 204 205 /* 206 ** Methods for CksmFile 207 */ 208 static int cksmClose(sqlite3_file*); 209 static int cksmRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); 210 static int cksmWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); 211 static int cksmTruncate(sqlite3_file*, sqlite3_int64 size); 212 static int cksmSync(sqlite3_file*, int flags); 213 static int cksmFileSize(sqlite3_file*, sqlite3_int64 *pSize); 214 static int cksmLock(sqlite3_file*, int); 215 static int cksmUnlock(sqlite3_file*, int); 216 static int cksmCheckReservedLock(sqlite3_file*, int *pResOut); 217 static int cksmFileControl(sqlite3_file*, int op, void *pArg); 218 static int cksmSectorSize(sqlite3_file*); 219 static int cksmDeviceCharacteristics(sqlite3_file*); 220 static int cksmShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**); 221 static int cksmShmLock(sqlite3_file*, int offset, int n, int flags); 222 static void cksmShmBarrier(sqlite3_file*); 223 static int cksmShmUnmap(sqlite3_file*, int deleteFlag); 224 static int cksmFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); 225 static int cksmUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p); 226 227 /* 228 ** Methods for CksmVfs 229 */ 230 static int cksmOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); 231 static int cksmDelete(sqlite3_vfs*, const char *zName, int syncDir); 232 static int cksmAccess(sqlite3_vfs*, const char *zName, int flags, int *); 233 static int cksmFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); 234 static void *cksmDlOpen(sqlite3_vfs*, const char *zFilename); 235 static void cksmDlError(sqlite3_vfs*, int nByte, char *zErrMsg); 236 static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void); 237 static void cksmDlClose(sqlite3_vfs*, void*); 238 static int cksmRandomness(sqlite3_vfs*, int nByte, char *zOut); 239 static int cksmSleep(sqlite3_vfs*, int microseconds); 240 static int cksmCurrentTime(sqlite3_vfs*, double*); 241 static int cksmGetLastError(sqlite3_vfs*, int, char *); 242 static int cksmCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); 243 static int cksmSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr); 244 static sqlite3_syscall_ptr cksmGetSystemCall(sqlite3_vfs*, const char *z); 245 static const char *cksmNextSystemCall(sqlite3_vfs*, const char *zName); 246 247 static sqlite3_vfs cksm_vfs = { 248 3, /* iVersion (set when registered) */ 249 0, /* szOsFile (set when registered) */ 250 1024, /* mxPathname */ 251 0, /* pNext */ 252 "cksmvfs", /* zName */ 253 0, /* pAppData (set when registered) */ 254 cksmOpen, /* xOpen */ 255 cksmDelete, /* xDelete */ 256 cksmAccess, /* xAccess */ 257 cksmFullPathname, /* xFullPathname */ 258 cksmDlOpen, /* xDlOpen */ 259 cksmDlError, /* xDlError */ 260 cksmDlSym, /* xDlSym */ 261 cksmDlClose, /* xDlClose */ 262 cksmRandomness, /* xRandomness */ 263 cksmSleep, /* xSleep */ 264 cksmCurrentTime, /* xCurrentTime */ 265 cksmGetLastError, /* xGetLastError */ 266 cksmCurrentTimeInt64, /* xCurrentTimeInt64 */ 267 cksmSetSystemCall, /* xSetSystemCall */ 268 cksmGetSystemCall, /* xGetSystemCall */ 269 cksmNextSystemCall /* xNextSystemCall */ 270 }; 271 272 static const sqlite3_io_methods cksm_io_methods = { 273 3, /* iVersion */ 274 cksmClose, /* xClose */ 275 cksmRead, /* xRead */ 276 cksmWrite, /* xWrite */ 277 cksmTruncate, /* xTruncate */ 278 cksmSync, /* xSync */ 279 cksmFileSize, /* xFileSize */ 280 cksmLock, /* xLock */ 281 cksmUnlock, /* xUnlock */ 282 cksmCheckReservedLock, /* xCheckReservedLock */ 283 cksmFileControl, /* xFileControl */ 284 cksmSectorSize, /* xSectorSize */ 285 cksmDeviceCharacteristics, /* xDeviceCharacteristics */ 286 cksmShmMap, /* xShmMap */ 287 cksmShmLock, /* xShmLock */ 288 cksmShmBarrier, /* xShmBarrier */ 289 cksmShmUnmap, /* xShmUnmap */ 290 cksmFetch, /* xFetch */ 291 cksmUnfetch /* xUnfetch */ 292 }; 293 294 /* Do byte swapping on a unsigned 32-bit integer */ 295 #define BYTESWAP32(x) ( \ 296 (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \ 297 + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \ 298 ) 299 300 /* Compute a checksum on a buffer */ 301 static void cksmCompute( 302 u8 *a, /* Content to be checksummed */ 303 int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */ 304 u8 *aOut /* OUT: Final 8-byte checksum value output */ 305 ){ 306 u32 s1 = 0, s2 = 0; 307 u32 *aData = (u32*)a; 308 u32 *aEnd = (u32*)&a[nByte]; 309 u32 x = 1; 310 311 assert( nByte>=8 ); 312 assert( (nByte&0x00000007)==0 ); 313 assert( nByte<=65536 ); 314 315 if( 1 == *(u8*)&x ){ 316 /* Little-endian */ 317 do { 318 s1 += *aData++ + s2; 319 s2 += *aData++ + s1; 320 }while( aData<aEnd ); 321 }else{ 322 /* Big-endian */ 323 do { 324 s1 += BYTESWAP32(aData[0]) + s2; 325 s2 += BYTESWAP32(aData[1]) + s1; 326 aData += 2; 327 }while( aData<aEnd ); 328 s1 = BYTESWAP32(s1); 329 s2 = BYTESWAP32(s2); 330 } 331 memcpy(aOut, &s1, 4); 332 memcpy(aOut+4, &s2, 4); 333 } 334 335 /* 336 ** SQL function: verify_checksum(BLOB) 337 ** 338 ** Return 0 or 1 if the checksum is invalid or valid. Or return 339 ** NULL if the input is not a BLOB that is the right size for a 340 ** database page. 341 */ 342 static void cksmVerifyFunc( 343 sqlite3_context *context, 344 int argc, 345 sqlite3_value **argv 346 ){ 347 int nByte; 348 u8 *data; 349 u8 cksum[8]; 350 data = (u8*)sqlite3_value_blob(argv[0]); 351 if( data==0 ) return; 352 if( sqlite3_value_type(argv[0])!=SQLITE_BLOB ) return; 353 nByte = sqlite3_value_bytes(argv[0]); 354 if( nByte<512 || nByte>65536 || (nByte & (nByte-1))!=0 ) return; 355 cksmCompute(data, nByte-8, cksum); 356 sqlite3_result_int(context, memcmp(data+nByte-8,cksum,8)==0); 357 } 358 359 #ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME 360 /* 361 ** SQL function: initialize_cksumvfs(SCHEMANAME) 362 ** 363 ** This SQL functions (whose name is actually determined at compile-time 364 ** by the value of the SQLITE_CKSUMVFS_INIT_FUNCNAME macro) invokes: 365 ** 366 ** sqlite3_file_control(db, SCHEMANAME, SQLITE_FCNTL_RESERVE_BYTE, &n); 367 ** 368 ** In order to set the reserve bytes value to 8, so that cksumvfs will 369 ** operation. This feature is provided (if and only if the 370 ** SQLITE_CKSUMVFS_INIT_FUNCNAME compile-time option is set to a string 371 ** which is the name of the SQL function) so as to provide the ability 372 ** to invoke the file-control in programming languages that lack 373 ** direct access to the sqlite3_file_control() interface (ex: Java). 374 ** 375 ** This interface is undocumented, apart from this comment. Usage 376 ** example: 377 ** 378 ** 1. Compile with -DSQLITE_CKSUMVFS_INIT_FUNCNAME="ckvfs_init" 379 ** 2. Run: "SELECT cksum_init('main'); VACUUM;" 380 */ 381 static void cksmInitFunc( 382 sqlite3_context *context, 383 int argc, 384 sqlite3_value **argv 385 ){ 386 int nByte = 8; 387 const char *zSchemaName = (const char*)sqlite3_value_text(argv[0]); 388 sqlite3 *db = sqlite3_context_db_handle(context); 389 sqlite3_file_control(db, zSchemaName, SQLITE_FCNTL_RESERVE_BYTES, &nByte); 390 /* Return NULL */ 391 } 392 #endif /* SQLITE_CKSUMBFS_INIT_FUNCNAME */ 393 394 /* 395 ** Close a cksm-file. 396 */ 397 static int cksmClose(sqlite3_file *pFile){ 398 CksmFile *p = (CksmFile *)pFile; 399 if( p->pPartner ){ 400 assert( p->pPartner->pPartner==p ); 401 p->pPartner->pPartner = 0; 402 p->pPartner = 0; 403 } 404 pFile = ORIGFILE(pFile); 405 return pFile->pMethods->xClose(pFile); 406 } 407 408 /* 409 ** Set the computeCkSm and verifyCksm flags, if they need to be 410 ** changed. 411 */ 412 static void cksmSetFlags(CksmFile *p, int hasCorrectReserveSize){ 413 if( hasCorrectReserveSize!=p->computeCksm ){ 414 p->computeCksm = p->verifyCksm = hasCorrectReserveSize; 415 if( p->pPartner ){ 416 p->pPartner->verifyCksm = hasCorrectReserveSize; 417 p->pPartner->computeCksm = hasCorrectReserveSize; 418 } 419 } 420 } 421 422 /* 423 ** Read data from a cksm-file. 424 */ 425 static int cksmRead( 426 sqlite3_file *pFile, 427 void *zBuf, 428 int iAmt, 429 sqlite_int64 iOfst 430 ){ 431 int rc; 432 CksmFile *p = (CksmFile *)pFile; 433 pFile = ORIGFILE(pFile); 434 rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst); 435 if( rc==SQLITE_OK ){ 436 if( iOfst==0 && iAmt>=100 && ( 437 memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 438 )){ 439 u8 *d = (u8*)zBuf; 440 char hasCorrectReserveSize = (d[20]==8); 441 cksmSetFlags(p, hasCorrectReserveSize); 442 } 443 /* Verify the checksum if 444 ** (1) the size indicates that we are dealing with a complete 445 ** database page 446 ** (2) checksum verification is enabled 447 ** (3) we are not in the middle of checkpoint 448 */ 449 if( iAmt>=512 /* (1) */ 450 && p->verifyCksm /* (2) */ 451 && !p->inCkpt /* (3) */ 452 ){ 453 u8 cksum[8]; 454 cksmCompute((u8*)zBuf, iAmt-8, cksum); 455 if( memcmp((u8*)zBuf+iAmt-8, cksum, 8)!=0 ){ 456 sqlite3_log(SQLITE_IOERR_DATA, 457 "checksum fault offset %lld of \"%s\"", 458 iOfst, p->zFName); 459 rc = SQLITE_IOERR_DATA; 460 } 461 } 462 } 463 return rc; 464 } 465 466 /* 467 ** Write data to a cksm-file. 468 */ 469 static int cksmWrite( 470 sqlite3_file *pFile, 471 const void *zBuf, 472 int iAmt, 473 sqlite_int64 iOfst 474 ){ 475 CksmFile *p = (CksmFile *)pFile; 476 pFile = ORIGFILE(pFile); 477 if( iOfst==0 && iAmt>=100 && ( 478 memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 479 )){ 480 u8 *d = (u8*)zBuf; 481 char hasCorrectReserveSize = (d[20]==8); 482 cksmSetFlags(p, hasCorrectReserveSize); 483 } 484 /* If the write size is appropriate for a database page and if 485 ** checksums where ever enabled, then it will be safe to compute 486 ** the checksums. The reserve byte size might have increased, but 487 ** it will never decrease. And because it cannot decrease, the 488 ** checksum will not overwrite anything. 489 */ 490 if( iAmt>=512 491 && p->computeCksm 492 && !p->inCkpt 493 ){ 494 cksmCompute((u8*)zBuf, iAmt-8, ((u8*)zBuf)+iAmt-8); 495 } 496 return pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst); 497 } 498 499 /* 500 ** Truncate a cksm-file. 501 */ 502 static int cksmTruncate(sqlite3_file *pFile, sqlite_int64 size){ 503 pFile = ORIGFILE(pFile); 504 return pFile->pMethods->xTruncate(pFile, size); 505 } 506 507 /* 508 ** Sync a cksm-file. 509 */ 510 static int cksmSync(sqlite3_file *pFile, int flags){ 511 pFile = ORIGFILE(pFile); 512 return pFile->pMethods->xSync(pFile, flags); 513 } 514 515 /* 516 ** Return the current file-size of a cksm-file. 517 */ 518 static int cksmFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ 519 CksmFile *p = (CksmFile *)pFile; 520 pFile = ORIGFILE(p); 521 return pFile->pMethods->xFileSize(pFile, pSize); 522 } 523 524 /* 525 ** Lock a cksm-file. 526 */ 527 static int cksmLock(sqlite3_file *pFile, int eLock){ 528 pFile = ORIGFILE(pFile); 529 return pFile->pMethods->xLock(pFile, eLock); 530 } 531 532 /* 533 ** Unlock a cksm-file. 534 */ 535 static int cksmUnlock(sqlite3_file *pFile, int eLock){ 536 pFile = ORIGFILE(pFile); 537 return pFile->pMethods->xUnlock(pFile, eLock); 538 } 539 540 /* 541 ** Check if another file-handle holds a RESERVED lock on a cksm-file. 542 */ 543 static int cksmCheckReservedLock(sqlite3_file *pFile, int *pResOut){ 544 pFile = ORIGFILE(pFile); 545 return pFile->pMethods->xCheckReservedLock(pFile, pResOut); 546 } 547 548 /* 549 ** File control method. For custom operations on a cksm-file. 550 */ 551 static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){ 552 int rc; 553 CksmFile *p = (CksmFile*)pFile; 554 pFile = ORIGFILE(pFile); 555 if( op==SQLITE_FCNTL_PRAGMA ){ 556 char **azArg = (char**)pArg; 557 assert( azArg[1]!=0 ); 558 if( sqlite3_stricmp(azArg[1],"checksum_verification")==0 ){ 559 char *zArg = azArg[2]; 560 if( zArg!=0 ){ 561 if( (zArg[0]>='1' && zArg[0]<='9') 562 || sqlite3_strlike("enable%",zArg,0)==0 563 || sqlite3_stricmp("yes",zArg)==0 564 || sqlite3_stricmp("on",zArg)==0 565 ){ 566 p->verifyCksm = p->computeCksm; 567 }else{ 568 p->verifyCksm = 0; 569 } 570 if( p->pPartner ) p->pPartner->verifyCksm = p->verifyCksm; 571 } 572 azArg[0] = sqlite3_mprintf("%d",p->verifyCksm); 573 return SQLITE_OK; 574 }else if( p->computeCksm && azArg[2]!=0 575 && sqlite3_stricmp(azArg[1], "page_size")==0 ){ 576 /* Do not allow page size changes on a checksum database */ 577 return SQLITE_OK; 578 } 579 }else if( op==SQLITE_FCNTL_CKPT_START || op==SQLITE_FCNTL_CKPT_DONE ){ 580 p->inCkpt = op==SQLITE_FCNTL_CKPT_START; 581 if( p->pPartner ) p->pPartner->inCkpt = p->inCkpt; 582 }else if( op==SQLITE_FCNTL_CKSM_FILE ){ 583 /* This VFS needs to obtain a pointer to the corresponding database 584 ** file handle from within xOpen() calls to open wal files. To do this, 585 ** it uses the sqlite3_database_file_object() API to obtain a pointer 586 ** to the file-handle used by SQLite to access the db file. This is 587 ** fine if cksmvfs happens to be the top-level VFS, but not if there 588 ** are one or more wrapper VFS. To handle this case, this file-control 589 ** is used to extract the cksmvfs file-handle from any wrapper file 590 ** handle. */ 591 sqlite3_file **ppFile = (sqlite3_file**)pArg; 592 *ppFile = (sqlite3_file*)p; 593 return SQLITE_OK; 594 } 595 rc = pFile->pMethods->xFileControl(pFile, op, pArg); 596 if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){ 597 *(char**)pArg = sqlite3_mprintf("cksm/%z", *(char**)pArg); 598 } 599 return rc; 600 } 601 602 /* 603 ** Return the sector-size in bytes for a cksm-file. 604 */ 605 static int cksmSectorSize(sqlite3_file *pFile){ 606 pFile = ORIGFILE(pFile); 607 return pFile->pMethods->xSectorSize(pFile); 608 } 609 610 /* 611 ** Return the device characteristic flags supported by a cksm-file. 612 */ 613 static int cksmDeviceCharacteristics(sqlite3_file *pFile){ 614 pFile = ORIGFILE(pFile); 615 return pFile->pMethods->xDeviceCharacteristics(pFile); 616 } 617 618 /* Create a shared memory file mapping */ 619 static int cksmShmMap( 620 sqlite3_file *pFile, 621 int iPg, 622 int pgsz, 623 int bExtend, 624 void volatile **pp 625 ){ 626 pFile = ORIGFILE(pFile); 627 return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp); 628 } 629 630 /* Perform locking on a shared-memory segment */ 631 static int cksmShmLock(sqlite3_file *pFile, int offset, int n, int flags){ 632 pFile = ORIGFILE(pFile); 633 return pFile->pMethods->xShmLock(pFile,offset,n,flags); 634 } 635 636 /* Memory barrier operation on shared memory */ 637 static void cksmShmBarrier(sqlite3_file *pFile){ 638 pFile = ORIGFILE(pFile); 639 pFile->pMethods->xShmBarrier(pFile); 640 } 641 642 /* Unmap a shared memory segment */ 643 static int cksmShmUnmap(sqlite3_file *pFile, int deleteFlag){ 644 pFile = ORIGFILE(pFile); 645 return pFile->pMethods->xShmUnmap(pFile,deleteFlag); 646 } 647 648 /* Fetch a page of a memory-mapped file */ 649 static int cksmFetch( 650 sqlite3_file *pFile, 651 sqlite3_int64 iOfst, 652 int iAmt, 653 void **pp 654 ){ 655 CksmFile *p = (CksmFile *)pFile; 656 if( p->computeCksm ){ 657 *pp = 0; 658 return SQLITE_OK; 659 } 660 pFile = ORIGFILE(pFile); 661 if( pFile->pMethods->iVersion>2 && pFile->pMethods->xFetch ){ 662 return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp); 663 } 664 *pp = 0; 665 return SQLITE_OK; 666 } 667 668 /* Release a memory-mapped page */ 669 static int cksmUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ 670 pFile = ORIGFILE(pFile); 671 if( pFile->pMethods->iVersion>2 && pFile->pMethods->xUnfetch ){ 672 return pFile->pMethods->xUnfetch(pFile, iOfst, pPage); 673 } 674 return SQLITE_OK; 675 } 676 677 /* 678 ** Open a cksm file handle. 679 */ 680 static int cksmOpen( 681 sqlite3_vfs *pVfs, 682 const char *zName, 683 sqlite3_file *pFile, 684 int flags, 685 int *pOutFlags 686 ){ 687 CksmFile *p; 688 sqlite3_file *pSubFile; 689 sqlite3_vfs *pSubVfs; 690 int rc; 691 pSubVfs = ORIGVFS(pVfs); 692 if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){ 693 return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags); 694 } 695 p = (CksmFile*)pFile; 696 memset(p, 0, sizeof(*p)); 697 pSubFile = ORIGFILE(pFile); 698 pFile->pMethods = &cksm_io_methods; 699 rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags); 700 if( rc ) goto cksm_open_done; 701 if( flags & SQLITE_OPEN_WAL ){ 702 sqlite3_file *pDb = sqlite3_database_file_object(zName); 703 rc = pDb->pMethods->xFileControl(pDb, SQLITE_FCNTL_CKSM_FILE, (void*)&pDb); 704 assert( rc==SQLITE_OK ); 705 p->pPartner = (CksmFile*)pDb; 706 assert( p->pPartner->pPartner==0 ); 707 p->pPartner->pPartner = p; 708 p->isWal = 1; 709 p->computeCksm = p->pPartner->computeCksm; 710 }else{ 711 p->isWal = 0; 712 p->computeCksm = 0; 713 } 714 p->zFName = zName; 715 cksm_open_done: 716 if( rc ) pFile->pMethods = 0; 717 return rc; 718 } 719 720 /* 721 ** All other VFS methods are pass-thrus. 722 */ 723 static int cksmDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ 724 return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync); 725 } 726 static int cksmAccess( 727 sqlite3_vfs *pVfs, 728 const char *zPath, 729 int flags, 730 int *pResOut 731 ){ 732 return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut); 733 } 734 static int cksmFullPathname( 735 sqlite3_vfs *pVfs, 736 const char *zPath, 737 int nOut, 738 char *zOut 739 ){ 740 return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut); 741 } 742 static void *cksmDlOpen(sqlite3_vfs *pVfs, const char *zPath){ 743 return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath); 744 } 745 static void cksmDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ 746 ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg); 747 } 748 static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ 749 return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym); 750 } 751 static void cksmDlClose(sqlite3_vfs *pVfs, void *pHandle){ 752 ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle); 753 } 754 static int cksmRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ 755 return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut); 756 } 757 static int cksmSleep(sqlite3_vfs *pVfs, int nMicro){ 758 return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro); 759 } 760 static int cksmCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ 761 return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut); 762 } 763 static int cksmGetLastError(sqlite3_vfs *pVfs, int a, char *b){ 764 return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b); 765 } 766 static int cksmCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){ 767 sqlite3_vfs *pOrig = ORIGVFS(pVfs); 768 int rc; 769 assert( pOrig->iVersion>=2 ); 770 if( pOrig->xCurrentTimeInt64 ){ 771 rc = pOrig->xCurrentTimeInt64(pOrig, p); 772 }else{ 773 double r; 774 rc = pOrig->xCurrentTime(pOrig, &r); 775 *p = (sqlite3_int64)(r*86400000.0); 776 } 777 return rc; 778 } 779 static int cksmSetSystemCall( 780 sqlite3_vfs *pVfs, 781 const char *zName, 782 sqlite3_syscall_ptr pCall 783 ){ 784 return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall); 785 } 786 static sqlite3_syscall_ptr cksmGetSystemCall( 787 sqlite3_vfs *pVfs, 788 const char *zName 789 ){ 790 return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName); 791 } 792 static const char *cksmNextSystemCall(sqlite3_vfs *pVfs, const char *zName){ 793 return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName); 794 } 795 796 /* Register the verify_checksum() SQL function. 797 */ 798 static int cksmRegisterFunc( 799 sqlite3 *db, 800 char **pzErrMsg, 801 const sqlite3_api_routines *pApi 802 ){ 803 int rc; 804 if( db==0 ) return SQLITE_OK; 805 rc = sqlite3_create_function(db, "verify_checksum", 1, 806 SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 807 0, cksmVerifyFunc, 0, 0); 808 #ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME 809 (void)sqlite3_create_function(db, SQLITE_CKSUMVFS_INIT_FUNCNAME, 1, 810 SQLITE_UTF8|SQLITE_DIRECTONLY, 811 0, cksmInitFunc, 0, 0); 812 #endif 813 return rc; 814 } 815 816 /* 817 ** Register the cksum VFS as the default VFS for the system. 818 ** Also make arrangements to automatically register the "verify_checksum()" 819 ** SQL function on each new database connection. 820 */ 821 static int cksmRegisterVfs(void){ 822 int rc = SQLITE_OK; 823 sqlite3_vfs *pOrig; 824 if( sqlite3_vfs_find("cksmvfs")!=0 ) return SQLITE_OK; 825 pOrig = sqlite3_vfs_find(0); 826 if( pOrig==0 ) return SQLITE_ERROR; 827 cksm_vfs.iVersion = pOrig->iVersion; 828 cksm_vfs.pAppData = pOrig; 829 cksm_vfs.szOsFile = pOrig->szOsFile + sizeof(CksmFile); 830 rc = sqlite3_vfs_register(&cksm_vfs, 1); 831 if( rc==SQLITE_OK ){ 832 rc = sqlite3_auto_extension((void(*)(void))cksmRegisterFunc); 833 } 834 return rc; 835 } 836 837 #if defined(SQLITE_CKSUMVFS_STATIC) 838 /* This variant of the initializer runs when the extension is 839 ** statically linked. 840 */ 841 int sqlite3_register_cksumvfs(const char *NotUsed){ 842 (void)NotUsed; 843 return cksmRegisterVfs(); 844 } 845 int sqlite3_unregister_cksumvfs(void){ 846 if( sqlite3_vfs_find("cksmvfs") ){ 847 sqlite3_vfs_unregister(&cksm_vfs); 848 sqlite3_cancel_auto_extension((void(*)(void))cksmRegisterFunc); 849 } 850 return SQLITE_OK; 851 } 852 #endif /* defined(SQLITE_CKSUMVFS_STATIC */ 853 854 #if !defined(SQLITE_CKSUMVFS_STATIC) 855 /* This variant of the initializer function is used when the 856 ** extension is shared library to be loaded at run-time. 857 */ 858 #ifdef _WIN32 859 __declspec(dllexport) 860 #endif 861 /* 862 ** This routine is called by sqlite3_load_extension() when the 863 ** extension is first loaded. 864 ***/ 865 int sqlite3_cksumvfs_init( 866 sqlite3 *db, 867 char **pzErrMsg, 868 const sqlite3_api_routines *pApi 869 ){ 870 int rc; 871 SQLITE_EXTENSION_INIT2(pApi); 872 (void)pzErrMsg; /* not used */ 873 rc = cksmRegisterFunc(db, 0, 0); 874 if( rc==SQLITE_OK ){ 875 rc = cksmRegisterVfs(); 876 } 877 if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; 878 return rc; 879 } 880 #endif /* !defined(SQLITE_CKSUMVFS_STATIC) */ 881