4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
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.
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
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
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:
49 ** sqlite3_open(":memory:", &db);
50 ** sqlite3_load_extension(db, "./cksumvfs");
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.
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:
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
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
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
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
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
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
163 #ifdef SQLITE_CKSUMVFS_STATIC
164 # include "sqlite3.h"
166 # include "sqlite3ext.h"
167 SQLITE_EXTENSION_INIT1
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
;
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))
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 */
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
= {
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 */
307 u32
*aData
= (u32
*)a
;
308 u32
*aEnd
= (u32
*)&a
[nByte
];
312 assert( (nByte
&0x00000007)==0 );
313 assert( nByte
<=65536 );
320 }while( aData
<aEnd
);
324 s1
+= BYTESWAP32(aData
[0]) + s2
;
325 s2
+= BYTESWAP32(aData
[1]) + s1
;
327 }while( aData
<aEnd
);
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
342 static void cksmVerifyFunc(
343 sqlite3_context
*context
,
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
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
,
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
);
392 #endif /* SQLITE_CKSUMBFS_INIT_FUNCNAME */
395 ** Close a cksm-file.
397 static int cksmClose(sqlite3_file
*pFile
){
398 CksmFile
*p
= (CksmFile
*)pFile
;
400 assert( p
->pPartner
->pPartner
==p
);
401 p
->pPartner
->pPartner
= 0;
404 pFile
= ORIGFILE(pFile
);
405 return pFile
->pMethods
->xClose(pFile
);
409 ** Set the computeCkSm and verifyCksm flags, if they need to be
412 static void cksmSetFlags(CksmFile
*p
, int hasCorrectReserveSize
){
413 if( hasCorrectReserveSize
!=p
->computeCksm
){
414 p
->computeCksm
= p
->verifyCksm
= hasCorrectReserveSize
;
416 p
->pPartner
->verifyCksm
= hasCorrectReserveSize
;
417 p
->pPartner
->computeCksm
= hasCorrectReserveSize
;
423 ** Read data from a cksm-file.
432 CksmFile
*p
= (CksmFile
*)pFile
;
433 pFile
= ORIGFILE(pFile
);
434 rc
= pFile
->pMethods
->xRead(pFile
, zBuf
, iAmt
, iOfst
);
436 if( iOfst
==0 && iAmt
>=100 && (
437 memcmp(zBuf
,"SQLite format 3",16)==0 || memcmp(zBuf
,"ZV-",3)==0
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
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) */
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\"",
459 rc
= SQLITE_IOERR_DATA
;
467 ** Write data to a cksm-file.
469 static int cksmWrite(
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
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.
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
);
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
;
521 return pFile
->pMethods
->xFileSize(pFile
, pSize
);
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
){
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];
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
;
570 if( p
->pPartner
) p
->pPartner
->verifyCksm
= p
->verifyCksm
;
572 azArg
[0] = sqlite3_mprintf("%d",p
->verifyCksm
);
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 */
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
591 sqlite3_file
**ppFile
= (sqlite3_file
**)pArg
;
592 *ppFile
= (sqlite3_file
*)p
;
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
);
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(
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(
655 CksmFile
*p
= (CksmFile
*)pFile
;
656 if( p
->computeCksm
){
660 pFile
= ORIGFILE(pFile
);
661 if( pFile
->pMethods
->iVersion
>2 && pFile
->pMethods
->xFetch
){
662 return pFile
->pMethods
->xFetch(pFile
, iOfst
, iAmt
, pp
);
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
);
678 ** Open a cksm file handle.
688 sqlite3_file
*pSubFile
;
689 sqlite3_vfs
*pSubVfs
;
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
;
709 p
->computeCksm
= p
->pPartner
->computeCksm
;
716 if( rc
) pFile
->pMethods
= 0;
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(
732 return ORIGVFS(pVfs
)->xAccess(ORIGVFS(pVfs
), zPath
, flags
, pResOut
);
734 static int cksmFullPathname(
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
);
769 assert( pOrig
->iVersion
>=2 );
770 if( pOrig
->xCurrentTimeInt64
){
771 rc
= pOrig
->xCurrentTimeInt64(pOrig
, p
);
774 rc
= pOrig
->xCurrentTime(pOrig
, &r
);
775 *p
= (sqlite3_int64
)(r
*86400000.0);
779 static int cksmSetSystemCall(
782 sqlite3_syscall_ptr pCall
784 return ORIGVFS(pVfs
)->xSetSystemCall(ORIGVFS(pVfs
),zName
,pCall
);
786 static sqlite3_syscall_ptr
cksmGetSystemCall(
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(
801 const sqlite3_api_routines
*pApi
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);
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){
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);
832 rc
= sqlite3_auto_extension((void(*)(void))cksmRegisterFunc
);
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
){
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
);
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.
859 __declspec(dllexport
)
862 ** This routine is called by sqlite3_load_extension() when the
863 ** extension is first loaded.
865 int sqlite3_cksumvfs_init(
868 const sqlite3_api_routines
*pApi
871 SQLITE_EXTENSION_INIT2(pApi
);
872 (void)pzErrMsg
; /* not used */
873 rc
= cksmRegisterFunc(db
, 0, 0);
875 rc
= cksmRegisterVfs();
877 if( rc
==SQLITE_OK
) rc
= SQLITE_OK_LOAD_PERMANENTLY
;
880 #endif /* !defined(SQLITE_CKSUMVFS_STATIC) */