cksumvfs.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881
  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. ** Forward declaration of objects used by this utility
  173. */
  174. typedef struct sqlite3_vfs CksmVfs;
  175. typedef struct CksmFile CksmFile;
  176. /*
  177. ** Useful datatype abbreviations
  178. */
  179. #if !defined(SQLITE_AMALGAMATION)
  180. typedef unsigned char u8;
  181. typedef unsigned int u32;
  182. #endif
  183. /* Access to a lower-level VFS that (might) implement dynamic loading,
  184. ** access to randomness, etc.
  185. */
  186. #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
  187. #define ORIGFILE(p) ((sqlite3_file*)(((CksmFile*)(p))+1))
  188. /* An open file */
  189. struct CksmFile {
  190. sqlite3_file base; /* IO methods */
  191. const char *zFName; /* Original name of the file */
  192. char computeCksm; /* True to compute checksums.
  193. ** Always true if reserve size is 8. */
  194. char verifyCksm; /* True to verify checksums */
  195. char isWal; /* True if processing a WAL file */
  196. char inCkpt; /* Currently doing a checkpoint */
  197. CksmFile *pPartner; /* Ptr from WAL to main-db, or from main-db to WAL */
  198. };
  199. /*
  200. ** Methods for CksmFile
  201. */
  202. static int cksmClose(sqlite3_file*);
  203. static int cksmRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
  204. static int cksmWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
  205. static int cksmTruncate(sqlite3_file*, sqlite3_int64 size);
  206. static int cksmSync(sqlite3_file*, int flags);
  207. static int cksmFileSize(sqlite3_file*, sqlite3_int64 *pSize);
  208. static int cksmLock(sqlite3_file*, int);
  209. static int cksmUnlock(sqlite3_file*, int);
  210. static int cksmCheckReservedLock(sqlite3_file*, int *pResOut);
  211. static int cksmFileControl(sqlite3_file*, int op, void *pArg);
  212. static int cksmSectorSize(sqlite3_file*);
  213. static int cksmDeviceCharacteristics(sqlite3_file*);
  214. static int cksmShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**);
  215. static int cksmShmLock(sqlite3_file*, int offset, int n, int flags);
  216. static void cksmShmBarrier(sqlite3_file*);
  217. static int cksmShmUnmap(sqlite3_file*, int deleteFlag);
  218. static int cksmFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
  219. static int cksmUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p);
  220. /*
  221. ** Methods for CksmVfs
  222. */
  223. static int cksmOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
  224. static int cksmDelete(sqlite3_vfs*, const char *zName, int syncDir);
  225. static int cksmAccess(sqlite3_vfs*, const char *zName, int flags, int *);
  226. static int cksmFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
  227. static void *cksmDlOpen(sqlite3_vfs*, const char *zFilename);
  228. static void cksmDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
  229. static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void);
  230. static void cksmDlClose(sqlite3_vfs*, void*);
  231. static int cksmRandomness(sqlite3_vfs*, int nByte, char *zOut);
  232. static int cksmSleep(sqlite3_vfs*, int microseconds);
  233. static int cksmCurrentTime(sqlite3_vfs*, double*);
  234. static int cksmGetLastError(sqlite3_vfs*, int, char *);
  235. static int cksmCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
  236. static int cksmSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr);
  237. static sqlite3_syscall_ptr cksmGetSystemCall(sqlite3_vfs*, const char *z);
  238. static const char *cksmNextSystemCall(sqlite3_vfs*, const char *zName);
  239. static sqlite3_vfs cksm_vfs = {
  240. 3, /* iVersion (set when registered) */
  241. 0, /* szOsFile (set when registered) */
  242. 1024, /* mxPathname */
  243. 0, /* pNext */
  244. "cksmvfs", /* zName */
  245. 0, /* pAppData (set when registered) */
  246. cksmOpen, /* xOpen */
  247. cksmDelete, /* xDelete */
  248. cksmAccess, /* xAccess */
  249. cksmFullPathname, /* xFullPathname */
  250. cksmDlOpen, /* xDlOpen */
  251. cksmDlError, /* xDlError */
  252. cksmDlSym, /* xDlSym */
  253. cksmDlClose, /* xDlClose */
  254. cksmRandomness, /* xRandomness */
  255. cksmSleep, /* xSleep */
  256. cksmCurrentTime, /* xCurrentTime */
  257. cksmGetLastError, /* xGetLastError */
  258. cksmCurrentTimeInt64, /* xCurrentTimeInt64 */
  259. cksmSetSystemCall, /* xSetSystemCall */
  260. cksmGetSystemCall, /* xGetSystemCall */
  261. cksmNextSystemCall /* xNextSystemCall */
  262. };
  263. static const sqlite3_io_methods cksm_io_methods = {
  264. 3, /* iVersion */
  265. cksmClose, /* xClose */
  266. cksmRead, /* xRead */
  267. cksmWrite, /* xWrite */
  268. cksmTruncate, /* xTruncate */
  269. cksmSync, /* xSync */
  270. cksmFileSize, /* xFileSize */
  271. cksmLock, /* xLock */
  272. cksmUnlock, /* xUnlock */
  273. cksmCheckReservedLock, /* xCheckReservedLock */
  274. cksmFileControl, /* xFileControl */
  275. cksmSectorSize, /* xSectorSize */
  276. cksmDeviceCharacteristics, /* xDeviceCharacteristics */
  277. cksmShmMap, /* xShmMap */
  278. cksmShmLock, /* xShmLock */
  279. cksmShmBarrier, /* xShmBarrier */
  280. cksmShmUnmap, /* xShmUnmap */
  281. cksmFetch, /* xFetch */
  282. cksmUnfetch /* xUnfetch */
  283. };
  284. /* Do byte swapping on a unsigned 32-bit integer */
  285. #define BYTESWAP32(x) ( \
  286. (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \
  287. + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \
  288. )
  289. /* Compute a checksum on a buffer */
  290. static void cksmCompute(
  291. u8 *a, /* Content to be checksummed */
  292. int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */
  293. u8 *aOut /* OUT: Final 8-byte checksum value output */
  294. ){
  295. u32 s1 = 0, s2 = 0;
  296. u32 *aData = (u32*)a;
  297. u32 *aEnd = (u32*)&a[nByte];
  298. u32 x = 1;
  299. assert( nByte>=8 );
  300. assert( (nByte&0x00000007)==0 );
  301. assert( nByte<=65536 );
  302. if( 1 == *(u8*)&x ){
  303. /* Little-endian */
  304. do {
  305. s1 += *aData++ + s2;
  306. s2 += *aData++ + s1;
  307. }while( aData<aEnd );
  308. }else{
  309. /* Big-endian */
  310. do {
  311. s1 += BYTESWAP32(aData[0]) + s2;
  312. s2 += BYTESWAP32(aData[1]) + s1;
  313. aData += 2;
  314. }while( aData<aEnd );
  315. s1 = BYTESWAP32(s1);
  316. s2 = BYTESWAP32(s2);
  317. }
  318. memcpy(aOut, &s1, 4);
  319. memcpy(aOut+4, &s2, 4);
  320. }
  321. /*
  322. ** SQL function: verify_checksum(BLOB)
  323. **
  324. ** Return 0 or 1 if the checksum is invalid or valid. Or return
  325. ** NULL if the input is not a BLOB that is the right size for a
  326. ** database page.
  327. */
  328. static void cksmVerifyFunc(
  329. sqlite3_context *context,
  330. int argc,
  331. sqlite3_value **argv
  332. ){
  333. int nByte;
  334. u8 *data;
  335. u8 cksum[8];
  336. data = (u8*)sqlite3_value_blob(argv[0]);
  337. if( data==0 ) return;
  338. if( sqlite3_value_type(argv[0])!=SQLITE_BLOB ) return;
  339. nByte = sqlite3_value_bytes(argv[0]);
  340. if( nByte<512 || nByte>65536 || (nByte & (nByte-1))!=0 ) return;
  341. cksmCompute(data, nByte-8, cksum);
  342. sqlite3_result_int(context, memcmp(data+nByte-8,cksum,8)==0);
  343. }
  344. #ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME
  345. /*
  346. ** SQL function: initialize_cksumvfs(SCHEMANAME)
  347. **
  348. ** This SQL functions (whose name is actually determined at compile-time
  349. ** by the value of the SQLITE_CKSUMVFS_INIT_FUNCNAME macro) invokes:
  350. **
  351. ** sqlite3_file_control(db, SCHEMANAME, SQLITE_FCNTL_RESERVE_BYTE, &n);
  352. **
  353. ** In order to set the reserve bytes value to 8, so that cksumvfs will
  354. ** operation. This feature is provided (if and only if the
  355. ** SQLITE_CKSUMVFS_INIT_FUNCNAME compile-time option is set to a string
  356. ** which is the name of the SQL function) so as to provide the ability
  357. ** to invoke the file-control in programming languages that lack
  358. ** direct access to the sqlite3_file_control() interface (ex: Java).
  359. **
  360. ** This interface is undocumented, apart from this comment. Usage
  361. ** example:
  362. **
  363. ** 1. Compile with -DSQLITE_CKSUMVFS_INIT_FUNCNAME="ckvfs_init"
  364. ** 2. Run: "SELECT cksum_init('main'); VACUUM;"
  365. */
  366. static void cksmInitFunc(
  367. sqlite3_context *context,
  368. int argc,
  369. sqlite3_value **argv
  370. ){
  371. int nByte = 8;
  372. const char *zSchemaName = (const char*)sqlite3_value_text(argv[0]);
  373. sqlite3 *db = sqlite3_context_db_handle(context);
  374. sqlite3_file_control(db, zSchemaName, SQLITE_FCNTL_RESERVE_BYTES, &nByte);
  375. /* Return NULL */
  376. }
  377. #endif /* SQLITE_CKSUMBFS_INIT_FUNCNAME */
  378. /*
  379. ** Close a cksm-file.
  380. */
  381. static int cksmClose(sqlite3_file *pFile){
  382. CksmFile *p = (CksmFile *)pFile;
  383. if( p->pPartner ){
  384. assert( p->pPartner->pPartner==p );
  385. p->pPartner->pPartner = 0;
  386. p->pPartner = 0;
  387. }
  388. pFile = ORIGFILE(pFile);
  389. return pFile->pMethods->xClose(pFile);
  390. }
  391. /*
  392. ** Set the computeCkSm and verifyCksm flags, if they need to be
  393. ** changed.
  394. */
  395. static void cksmSetFlags(CksmFile *p, int hasCorrectReserveSize){
  396. if( hasCorrectReserveSize!=p->computeCksm ){
  397. p->computeCksm = p->verifyCksm = hasCorrectReserveSize;
  398. if( p->pPartner ){
  399. p->pPartner->verifyCksm = hasCorrectReserveSize;
  400. p->pPartner->computeCksm = hasCorrectReserveSize;
  401. }
  402. }
  403. }
  404. /*
  405. ** Read data from a cksm-file.
  406. */
  407. static int cksmRead(
  408. sqlite3_file *pFile,
  409. void *zBuf,
  410. int iAmt,
  411. sqlite_int64 iOfst
  412. ){
  413. int rc;
  414. CksmFile *p = (CksmFile *)pFile;
  415. pFile = ORIGFILE(pFile);
  416. rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst);
  417. if( rc==SQLITE_OK ){
  418. if( iOfst==0 && iAmt>=100 && (
  419. memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0
  420. )){
  421. u8 *d = (u8*)zBuf;
  422. char hasCorrectReserveSize = (d[20]==8);
  423. cksmSetFlags(p, hasCorrectReserveSize);
  424. }
  425. /* Verify the checksum if
  426. ** (1) the size indicates that we are dealing with a complete
  427. ** database page
  428. ** (2) checksum verification is enabled
  429. ** (3) we are not in the middle of checkpoint
  430. */
  431. if( iAmt>=512 && (iAmt & (iAmt-1))==0 /* (1) */
  432. && p->verifyCksm /* (2) */
  433. && !p->inCkpt /* (3) */
  434. ){
  435. u8 cksum[8];
  436. cksmCompute((u8*)zBuf, iAmt-8, cksum);
  437. if( memcmp((u8*)zBuf+iAmt-8, cksum, 8)!=0 ){
  438. sqlite3_log(SQLITE_IOERR_DATA,
  439. "checksum fault offset %lld of \"%s\"",
  440. iOfst, p->zFName);
  441. rc = SQLITE_IOERR_DATA;
  442. }
  443. }
  444. }
  445. return rc;
  446. }
  447. /*
  448. ** Write data to a cksm-file.
  449. */
  450. static int cksmWrite(
  451. sqlite3_file *pFile,
  452. const void *zBuf,
  453. int iAmt,
  454. sqlite_int64 iOfst
  455. ){
  456. CksmFile *p = (CksmFile *)pFile;
  457. pFile = ORIGFILE(pFile);
  458. if( iOfst==0 && iAmt>=100 && (
  459. memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0
  460. )){
  461. u8 *d = (u8*)zBuf;
  462. char hasCorrectReserveSize = (d[20]==8);
  463. cksmSetFlags(p, hasCorrectReserveSize);
  464. }
  465. /* If the write size is appropriate for a database page and if
  466. ** checksums where ever enabled, then it will be safe to compute
  467. ** the checksums. The reserve byte size might have increased, but
  468. ** it will never decrease. And because it cannot decrease, the
  469. ** checksum will not overwrite anything.
  470. */
  471. if( iAmt>=512
  472. && p->computeCksm
  473. && !p->inCkpt
  474. ){
  475. cksmCompute((u8*)zBuf, iAmt-8, ((u8*)zBuf)+iAmt-8);
  476. }
  477. return pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst);
  478. }
  479. /*
  480. ** Truncate a cksm-file.
  481. */
  482. static int cksmTruncate(sqlite3_file *pFile, sqlite_int64 size){
  483. pFile = ORIGFILE(pFile);
  484. return pFile->pMethods->xTruncate(pFile, size);
  485. }
  486. /*
  487. ** Sync a cksm-file.
  488. */
  489. static int cksmSync(sqlite3_file *pFile, int flags){
  490. pFile = ORIGFILE(pFile);
  491. return pFile->pMethods->xSync(pFile, flags);
  492. }
  493. /*
  494. ** Return the current file-size of a cksm-file.
  495. */
  496. static int cksmFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
  497. CksmFile *p = (CksmFile *)pFile;
  498. pFile = ORIGFILE(p);
  499. return pFile->pMethods->xFileSize(pFile, pSize);
  500. }
  501. /*
  502. ** Lock a cksm-file.
  503. */
  504. static int cksmLock(sqlite3_file *pFile, int eLock){
  505. pFile = ORIGFILE(pFile);
  506. return pFile->pMethods->xLock(pFile, eLock);
  507. }
  508. /*
  509. ** Unlock a cksm-file.
  510. */
  511. static int cksmUnlock(sqlite3_file *pFile, int eLock){
  512. pFile = ORIGFILE(pFile);
  513. return pFile->pMethods->xUnlock(pFile, eLock);
  514. }
  515. /*
  516. ** Check if another file-handle holds a RESERVED lock on a cksm-file.
  517. */
  518. static int cksmCheckReservedLock(sqlite3_file *pFile, int *pResOut){
  519. pFile = ORIGFILE(pFile);
  520. return pFile->pMethods->xCheckReservedLock(pFile, pResOut);
  521. }
  522. /*
  523. ** File control method. For custom operations on a cksm-file.
  524. */
  525. static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){
  526. int rc;
  527. CksmFile *p = (CksmFile*)pFile;
  528. pFile = ORIGFILE(pFile);
  529. if( op==SQLITE_FCNTL_PRAGMA ){
  530. char **azArg = (char**)pArg;
  531. assert( azArg[1]!=0 );
  532. if( sqlite3_stricmp(azArg[1],"checksum_verification")==0 ){
  533. char *zArg = azArg[2];
  534. if( zArg!=0 ){
  535. if( (zArg[0]>='1' && zArg[0]<='9')
  536. || sqlite3_strlike("enable%",zArg,0)==0
  537. || sqlite3_stricmp("yes",zArg)==0
  538. || sqlite3_stricmp("on",zArg)==0
  539. ){
  540. p->verifyCksm = p->computeCksm;
  541. }else{
  542. p->verifyCksm = 0;
  543. }
  544. if( p->pPartner ) p->pPartner->verifyCksm = p->verifyCksm;
  545. }
  546. azArg[0] = sqlite3_mprintf("%d",p->verifyCksm);
  547. return SQLITE_OK;
  548. }else if( p->computeCksm && azArg[2]!=0
  549. && sqlite3_stricmp(azArg[1], "page_size")==0 ){
  550. /* Do not allow page size changes on a checksum database */
  551. return SQLITE_OK;
  552. }
  553. }else if( op==SQLITE_FCNTL_CKPT_START || op==SQLITE_FCNTL_CKPT_DONE ){
  554. p->inCkpt = op==SQLITE_FCNTL_CKPT_START;
  555. if( p->pPartner ) p->pPartner->inCkpt = p->inCkpt;
  556. }else if( op==SQLITE_FCNTL_CKSM_FILE ){
  557. /* This VFS needs to obtain a pointer to the corresponding database
  558. ** file handle from within xOpen() calls to open wal files. To do this,
  559. ** it uses the sqlite3_database_file_object() API to obtain a pointer
  560. ** to the file-handle used by SQLite to access the db file. This is
  561. ** fine if cksmvfs happens to be the top-level VFS, but not if there
  562. ** are one or more wrapper VFS. To handle this case, this file-control
  563. ** is used to extract the cksmvfs file-handle from any wrapper file
  564. ** handle. */
  565. sqlite3_file **ppFile = (sqlite3_file**)pArg;
  566. *ppFile = (sqlite3_file*)p;
  567. return SQLITE_OK;
  568. }
  569. rc = pFile->pMethods->xFileControl(pFile, op, pArg);
  570. if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){
  571. *(char**)pArg = sqlite3_mprintf("cksm/%z", *(char**)pArg);
  572. }
  573. return rc;
  574. }
  575. /*
  576. ** Return the sector-size in bytes for a cksm-file.
  577. */
  578. static int cksmSectorSize(sqlite3_file *pFile){
  579. pFile = ORIGFILE(pFile);
  580. return pFile->pMethods->xSectorSize(pFile);
  581. }
  582. /*
  583. ** Return the device characteristic flags supported by a cksm-file.
  584. */
  585. static int cksmDeviceCharacteristics(sqlite3_file *pFile){
  586. pFile = ORIGFILE(pFile);
  587. return pFile->pMethods->xDeviceCharacteristics(pFile);
  588. }
  589. /* Create a shared memory file mapping */
  590. static int cksmShmMap(
  591. sqlite3_file *pFile,
  592. int iPg,
  593. int pgsz,
  594. int bExtend,
  595. void volatile **pp
  596. ){
  597. pFile = ORIGFILE(pFile);
  598. return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp);
  599. }
  600. /* Perform locking on a shared-memory segment */
  601. static int cksmShmLock(sqlite3_file *pFile, int offset, int n, int flags){
  602. pFile = ORIGFILE(pFile);
  603. return pFile->pMethods->xShmLock(pFile,offset,n,flags);
  604. }
  605. /* Memory barrier operation on shared memory */
  606. static void cksmShmBarrier(sqlite3_file *pFile){
  607. pFile = ORIGFILE(pFile);
  608. pFile->pMethods->xShmBarrier(pFile);
  609. }
  610. /* Unmap a shared memory segment */
  611. static int cksmShmUnmap(sqlite3_file *pFile, int deleteFlag){
  612. pFile = ORIGFILE(pFile);
  613. return pFile->pMethods->xShmUnmap(pFile,deleteFlag);
  614. }
  615. /* Fetch a page of a memory-mapped file */
  616. static int cksmFetch(
  617. sqlite3_file *pFile,
  618. sqlite3_int64 iOfst,
  619. int iAmt,
  620. void **pp
  621. ){
  622. CksmFile *p = (CksmFile *)pFile;
  623. if( p->computeCksm ){
  624. *pp = 0;
  625. return SQLITE_OK;
  626. }
  627. pFile = ORIGFILE(pFile);
  628. if( pFile->pMethods->iVersion>2 && pFile->pMethods->xFetch ){
  629. return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp);
  630. }
  631. *pp = 0;
  632. return SQLITE_OK;
  633. }
  634. /* Release a memory-mapped page */
  635. static int cksmUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){
  636. pFile = ORIGFILE(pFile);
  637. if( pFile->pMethods->iVersion>2 && pFile->pMethods->xUnfetch ){
  638. return pFile->pMethods->xUnfetch(pFile, iOfst, pPage);
  639. }
  640. return SQLITE_OK;
  641. }
  642. /*
  643. ** Open a cksm file handle.
  644. */
  645. static int cksmOpen(
  646. sqlite3_vfs *pVfs,
  647. const char *zName,
  648. sqlite3_file *pFile,
  649. int flags,
  650. int *pOutFlags
  651. ){
  652. CksmFile *p;
  653. sqlite3_file *pSubFile;
  654. sqlite3_vfs *pSubVfs;
  655. int rc;
  656. pSubVfs = ORIGVFS(pVfs);
  657. if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){
  658. return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags);
  659. }
  660. p = (CksmFile*)pFile;
  661. memset(p, 0, sizeof(*p));
  662. pSubFile = ORIGFILE(pFile);
  663. pFile->pMethods = &cksm_io_methods;
  664. rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags);
  665. if( rc ) goto cksm_open_done;
  666. if( flags & SQLITE_OPEN_WAL ){
  667. sqlite3_file *pDb = sqlite3_database_file_object(zName);
  668. rc = pDb->pMethods->xFileControl(pDb, SQLITE_FCNTL_CKSM_FILE, (void*)&pDb);
  669. assert( rc==SQLITE_OK );
  670. p->pPartner = (CksmFile*)pDb;
  671. assert( p->pPartner->pPartner==0 );
  672. p->pPartner->pPartner = p;
  673. p->isWal = 1;
  674. p->computeCksm = p->pPartner->computeCksm;
  675. }else{
  676. p->isWal = 0;
  677. p->computeCksm = 0;
  678. }
  679. p->zFName = zName;
  680. cksm_open_done:
  681. if( rc ) pFile->pMethods = 0;
  682. return rc;
  683. }
  684. /*
  685. ** All other VFS methods are pass-thrus.
  686. */
  687. static int cksmDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
  688. return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync);
  689. }
  690. static int cksmAccess(
  691. sqlite3_vfs *pVfs,
  692. const char *zPath,
  693. int flags,
  694. int *pResOut
  695. ){
  696. return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut);
  697. }
  698. static int cksmFullPathname(
  699. sqlite3_vfs *pVfs,
  700. const char *zPath,
  701. int nOut,
  702. char *zOut
  703. ){
  704. return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut);
  705. }
  706. static void *cksmDlOpen(sqlite3_vfs *pVfs, const char *zPath){
  707. return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
  708. }
  709. static void cksmDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
  710. ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
  711. }
  712. static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
  713. return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
  714. }
  715. static void cksmDlClose(sqlite3_vfs *pVfs, void *pHandle){
  716. ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
  717. }
  718. static int cksmRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
  719. return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
  720. }
  721. static int cksmSleep(sqlite3_vfs *pVfs, int nMicro){
  722. return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
  723. }
  724. static int cksmCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
  725. return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
  726. }
  727. static int cksmGetLastError(sqlite3_vfs *pVfs, int a, char *b){
  728. return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
  729. }
  730. static int cksmCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
  731. sqlite3_vfs *pOrig = ORIGVFS(pVfs);
  732. int rc;
  733. assert( pOrig->iVersion>=2 );
  734. if( pOrig->xCurrentTimeInt64 ){
  735. rc = pOrig->xCurrentTimeInt64(pOrig, p);
  736. }else{
  737. double r;
  738. rc = pOrig->xCurrentTime(pOrig, &r);
  739. *p = (sqlite3_int64)(r*86400000.0);
  740. }
  741. return rc;
  742. }
  743. static int cksmSetSystemCall(
  744. sqlite3_vfs *pVfs,
  745. const char *zName,
  746. sqlite3_syscall_ptr pCall
  747. ){
  748. return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall);
  749. }
  750. static sqlite3_syscall_ptr cksmGetSystemCall(
  751. sqlite3_vfs *pVfs,
  752. const char *zName
  753. ){
  754. return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName);
  755. }
  756. static const char *cksmNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
  757. return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName);
  758. }
  759. /* Register the verify_checksum() SQL function.
  760. */
  761. static int cksmRegisterFunc(
  762. sqlite3 *db,
  763. char **pzErrMsg,
  764. const sqlite3_api_routines *pApi
  765. ){
  766. int rc;
  767. if( db==0 ) return SQLITE_OK;
  768. rc = sqlite3_create_function(db, "verify_checksum", 1,
  769. SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC,
  770. 0, cksmVerifyFunc, 0, 0);
  771. #ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME
  772. (void)sqlite3_create_function(db, SQLITE_CKSUMVFS_INIT_FUNCNAME, 1,
  773. SQLITE_UTF8|SQLITE_DIRECTONLY,
  774. 0, cksmInitFunc, 0, 0);
  775. #endif
  776. return rc;
  777. }
  778. /*
  779. ** Register the cksum VFS as the default VFS for the system.
  780. ** Also make arrangements to automatically register the "verify_checksum()"
  781. ** SQL function on each new database connection.
  782. */
  783. static int cksmRegisterVfs(void){
  784. int rc = SQLITE_OK;
  785. sqlite3_vfs *pOrig;
  786. if( sqlite3_vfs_find("cksmvfs")!=0 ) return SQLITE_OK;
  787. pOrig = sqlite3_vfs_find(0);
  788. if( pOrig==0 ) return SQLITE_ERROR;
  789. cksm_vfs.iVersion = pOrig->iVersion;
  790. cksm_vfs.pAppData = pOrig;
  791. cksm_vfs.szOsFile = pOrig->szOsFile + sizeof(CksmFile);
  792. rc = sqlite3_vfs_register(&cksm_vfs, 1);
  793. if( rc==SQLITE_OK ){
  794. rc = sqlite3_auto_extension((void(*)(void))cksmRegisterFunc);
  795. }
  796. return rc;
  797. }
  798. #if defined(SQLITE_CKSUMVFS_STATIC)
  799. /* This variant of the initializer runs when the extension is
  800. ** statically linked.
  801. */
  802. int sqlite3_register_cksumvfs(const char *NotUsed){
  803. (void)NotUsed;
  804. return cksmRegisterVfs();
  805. }
  806. int sqlite3_unregister_cksumvfs(void){
  807. if( sqlite3_vfs_find("cksmvfs") ){
  808. sqlite3_vfs_unregister(&cksm_vfs);
  809. sqlite3_cancel_auto_extension((void(*)(void))cksmRegisterFunc);
  810. }
  811. return SQLITE_OK;
  812. }
  813. #endif /* defined(SQLITE_CKSUMVFS_STATIC */
  814. #if !defined(SQLITE_CKSUMVFS_STATIC)
  815. /* This variant of the initializer function is used when the
  816. ** extension is shared library to be loaded at run-time.
  817. */
  818. #ifdef _WIN32
  819. __declspec(dllexport)
  820. #endif
  821. /*
  822. ** This routine is called by sqlite3_load_extension() when the
  823. ** extension is first loaded.
  824. ***/
  825. int sqlite3_cksumvfs_init(
  826. sqlite3 *db,
  827. char **pzErrMsg,
  828. const sqlite3_api_routines *pApi
  829. ){
  830. int rc;
  831. SQLITE_EXTENSION_INIT2(pApi);
  832. (void)pzErrMsg; /* not used */
  833. rc = cksmRegisterFunc(db, 0, 0);
  834. if( rc==SQLITE_OK ){
  835. rc = cksmRegisterVfs();
  836. }
  837. if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
  838. return rc;
  839. }
  840. #endif /* !defined(SQLITE_CKSUMVFS_STATIC) */