Fixes default log output to console for macOS
[sqlcipher.git] / ext / misc / cksumvfs.c
blob2d7f6584ea1b48740ec0ec4be012bcf6617ca632
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.
11 ******************************************************************************
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.
17 ** COMPILING
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.
24 ** To build this extension as a separately loaded shared library or
25 ** DLL, use compiler command-lines similar to the following:
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
31 ** You may want to add additional compiler options, of course,
32 ** according to the needs of your project.
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
39 ** LOADING
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:
48 ** sqlite3 *db;
49 ** sqlite3_open(":memory:", &db);
50 ** sqlite3_load_extension(db, "./cksumvfs");
51 ** sqlite3_close(db);
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:
57 ** sqlite3_register_cksumvfs();
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.
67 ** USING
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.
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:
81 ** int n = 8;
82 ** sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVE_BYTES, &n);
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:
89 ** sqlite3_exec(db, "VACUUM", 0, 0, 0);
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.
95 ** From the CLI, use the ".filectrl reserve_bytes 8" command,
96 ** followed by "VACUUM;".
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.
106 ** VERIFICATION OF CHECKSUMS
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:
112 ** SELECT count(*), verify_checksum(data)
113 ** FROM sqlite_dbpage
114 ** GROUP BY 2;
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.
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.
128 ** CONTROLLING CHECKSUM VERIFICATION
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:
134 ** PRAGMA checksum_verification; -- query status
135 ** PRAGMA checksum_verification=OFF; -- disable verification
136 ** PRAGMA checksum_verification=ON; -- re-enable verification
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.
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.
153 ** IMPLEMENTATION NOTES
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.
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>
174 ** Forward declaration of objects used by this utility
176 typedef struct sqlite3_vfs CksmVfs;
177 typedef struct CksmFile CksmFile;
180 ** Useful datatype abbreviations
182 #if !defined(SQLITE_AMALGAMATION)
183 typedef unsigned char u8;
184 typedef unsigned int u32;
185 #endif
187 /* Access to a lower-level VFS that (might) implement dynamic loading,
188 ** access to randomness, etc.
190 #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
191 #define ORIGFILE(p) ((sqlite3_file*)(((CksmFile*)(p))+1))
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 */
206 ** Methods for CksmFile
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);
228 ** Methods for CksmVfs
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);
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 */
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 */
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) \
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 */
306 u32 s1 = 0, s2 = 0;
307 u32 *aData = (u32*)a;
308 u32 *aEnd = (u32*)&a[nByte];
309 u32 x = 1;
311 assert( nByte>=8 );
312 assert( (nByte&0x00000007)==0 );
313 assert( nByte<=65536 );
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);
331 memcpy(aOut, &s1, 4);
332 memcpy(aOut+4, &s2, 4);
336 ** SQL function: verify_checksum(BLOB)
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.
342 static void cksmVerifyFunc(
343 sqlite3_context *context,
344 int argc,
345 sqlite3_value **argv
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);
359 #ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME
361 ** SQL function: initialize_cksumvfs(SCHEMANAME)
363 ** This SQL functions (whose name is actually determined at compile-time
364 ** by the value of the SQLITE_CKSUMVFS_INIT_FUNCNAME macro) invokes:
366 ** sqlite3_file_control(db, SCHEMANAME, SQLITE_FCNTL_RESERVE_BYTE, &n);
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).
375 ** This interface is undocumented, apart from this comment. Usage
376 ** example:
378 ** 1. Compile with -DSQLITE_CKSUMVFS_INIT_FUNCNAME="ckvfs_init"
379 ** 2. Run: "SELECT cksum_init('main'); VACUUM;"
381 static void cksmInitFunc(
382 sqlite3_context *context,
383 int argc,
384 sqlite3_value **argv
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 */
392 #endif /* SQLITE_CKSUMBFS_INIT_FUNCNAME */
395 ** Close a cksm-file.
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;
404 pFile = ORIGFILE(pFile);
405 return pFile->pMethods->xClose(pFile);
409 ** Set the computeCkSm and verifyCksm flags, if they need to be
410 ** changed.
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;
423 ** Read data from a cksm-file.
425 static int cksmRead(
426 sqlite3_file *pFile,
427 void *zBuf,
428 int iAmt,
429 sqlite_int64 iOfst
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
439 u8 *d = (u8*)zBuf;
440 char hasCorrectReserveSize = (d[20]==8);
441 cksmSetFlags(p, hasCorrectReserveSize);
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
449 if( iAmt>=512 && (iAmt & (iAmt-1))==0 /* (1) */
450 && p->verifyCksm /* (2) */
451 && !p->inCkpt /* (3) */
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;
463 return rc;
467 ** Write data to a cksm-file.
469 static int cksmWrite(
470 sqlite3_file *pFile,
471 const void *zBuf,
472 int iAmt,
473 sqlite_int64 iOfst
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
480 u8 *d = (u8*)zBuf;
481 char hasCorrectReserveSize = (d[20]==8);
482 cksmSetFlags(p, hasCorrectReserveSize);
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.
490 if( iAmt>=512
491 && p->computeCksm
492 && !p->inCkpt
494 cksmCompute((u8*)zBuf, iAmt-8, ((u8*)zBuf)+iAmt-8);
496 return pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst);
500 ** Truncate a cksm-file.
502 static int cksmTruncate(sqlite3_file *pFile, sqlite_int64 size){
503 pFile = ORIGFILE(pFile);
504 return pFile->pMethods->xTruncate(pFile, size);
508 ** Sync a cksm-file.
510 static int cksmSync(sqlite3_file *pFile, int flags){
511 pFile = ORIGFILE(pFile);
512 return pFile->pMethods->xSync(pFile, flags);
516 ** Return the current file-size of a cksm-file.
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);
525 ** Lock a cksm-file.
527 static int cksmLock(sqlite3_file *pFile, int eLock){
528 pFile = ORIGFILE(pFile);
529 return pFile->pMethods->xLock(pFile, eLock);
533 ** Unlock a cksm-file.
535 static int cksmUnlock(sqlite3_file *pFile, int eLock){
536 pFile = ORIGFILE(pFile);
537 return pFile->pMethods->xUnlock(pFile, eLock);
541 ** Check if another file-handle holds a RESERVED lock on a cksm-file.
543 static int cksmCheckReservedLock(sqlite3_file *pFile, int *pResOut){
544 pFile = ORIGFILE(pFile);
545 return pFile->pMethods->xCheckReservedLock(pFile, pResOut);
549 ** File control method. For custom operations on a cksm-file.
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
566 p->verifyCksm = p->computeCksm;
567 }else{
568 p->verifyCksm = 0;
570 if( p->pPartner ) p->pPartner->verifyCksm = p->verifyCksm;
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;
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;
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);
599 return rc;
603 ** Return the sector-size in bytes for a cksm-file.
605 static int cksmSectorSize(sqlite3_file *pFile){
606 pFile = ORIGFILE(pFile);
607 return pFile->pMethods->xSectorSize(pFile);
611 ** Return the device characteristic flags supported by a cksm-file.
613 static int cksmDeviceCharacteristics(sqlite3_file *pFile){
614 pFile = ORIGFILE(pFile);
615 return pFile->pMethods->xDeviceCharacteristics(pFile);
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
626 pFile = ORIGFILE(pFile);
627 return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp);
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);
636 /* Memory barrier operation on shared memory */
637 static void cksmShmBarrier(sqlite3_file *pFile){
638 pFile = ORIGFILE(pFile);
639 pFile->pMethods->xShmBarrier(pFile);
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);
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
655 CksmFile *p = (CksmFile *)pFile;
656 if( p->computeCksm ){
657 *pp = 0;
658 return SQLITE_OK;
660 pFile = ORIGFILE(pFile);
661 if( pFile->pMethods->iVersion>2 && pFile->pMethods->xFetch ){
662 return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp);
664 *pp = 0;
665 return SQLITE_OK;
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);
674 return SQLITE_OK;
678 ** Open a cksm file handle.
680 static int cksmOpen(
681 sqlite3_vfs *pVfs,
682 const char *zName,
683 sqlite3_file *pFile,
684 int flags,
685 int *pOutFlags
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);
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;
714 p->zFName = zName;
715 cksm_open_done:
716 if( rc ) pFile->pMethods = 0;
717 return rc;
721 ** All other VFS methods are pass-thrus.
723 static int cksmDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
724 return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync);
726 static int cksmAccess(
727 sqlite3_vfs *pVfs,
728 const char *zPath,
729 int flags,
730 int *pResOut
732 return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut);
734 static int cksmFullPathname(
735 sqlite3_vfs *pVfs,
736 const char *zPath,
737 int nOut,
738 char *zOut
740 return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut);
742 static void *cksmDlOpen(sqlite3_vfs *pVfs, const char *zPath){
743 return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
745 static void cksmDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
746 ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
748 static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
749 return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
751 static void cksmDlClose(sqlite3_vfs *pVfs, void *pHandle){
752 ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
754 static int cksmRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
755 return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
757 static int cksmSleep(sqlite3_vfs *pVfs, int nMicro){
758 return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
760 static int cksmCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
761 return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
763 static int cksmGetLastError(sqlite3_vfs *pVfs, int a, char *b){
764 return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
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);
777 return rc;
779 static int cksmSetSystemCall(
780 sqlite3_vfs *pVfs,
781 const char *zName,
782 sqlite3_syscall_ptr pCall
784 return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall);
786 static sqlite3_syscall_ptr cksmGetSystemCall(
787 sqlite3_vfs *pVfs,
788 const char *zName
790 return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName);
792 static const char *cksmNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
793 return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName);
796 /* Register the verify_checksum() SQL function.
798 static int cksmRegisterFunc(
799 sqlite3 *db,
800 char **pzErrMsg,
801 const sqlite3_api_routines *pApi
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;
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.
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);
834 return rc;
837 #if defined(SQLITE_CKSUMVFS_STATIC)
838 /* This variant of the initializer runs when the extension is
839 ** statically linked.
841 int sqlite3_register_cksumvfs(const char *NotUsed){
842 (void)NotUsed;
843 return cksmRegisterVfs();
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);
850 return SQLITE_OK;
852 #endif /* defined(SQLITE_CKSUMVFS_STATIC */
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.
858 #ifdef _WIN32
859 __declspec(dllexport)
860 #endif
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
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();
877 if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
878 return rc;
880 #endif /* !defined(SQLITE_CKSUMVFS_STATIC) */