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 contains code for a VFS layer that acts as a wrapper around
14 ** an existing VFS. The code in this file attempts to verify that SQLite
15 ** correctly populates and syncs a journal file before writing to a
16 ** corresponding database file.
20 ** The public interface to this wrapper VFS is two functions:
25 ** See header comments associated with those two functions below for
30 ** This wrapper will not work if "PRAGMA synchronous = off" is used.
34 ** Starting a Transaction:
36 ** When a write-transaction is started, the contents of the database is
37 ** inspected and the following data stored as part of the database file
38 ** handle (type struct jt_file):
40 ** a) The page-size of the database file.
41 ** b) The number of pages that are in the database file.
42 ** c) The set of page numbers corresponding to free-list leaf pages.
43 ** d) A check-sum for every page in the database file.
45 ** The start of a write-transaction is deemed to have occurred when a
46 ** 28-byte journal header is written to byte offset 0 of the journal
49 ** Syncing the Journal File:
51 ** Whenever the xSync method is invoked to sync a journal-file, the
52 ** contents of the journal file are read. For each page written to
53 ** the journal file, a check-sum is calculated and compared to the
54 ** check-sum calculated for the corresponding database page when the
55 ** write-transaction was initialized. The success of the comparison
56 ** is assert()ed. So if SQLite has written something other than the
57 ** original content to the database file, an assert() will fail.
59 ** Additionally, the set of page numbers for which records exist in
60 ** the journal file is added to (unioned with) the set of page numbers
61 ** corresponding to free-list leaf pages collected when the
62 ** write-transaction was initialized. This set comprises the page-numbers
63 ** corresponding to those pages that SQLite may now safely modify.
65 ** Writing to the Database File:
67 ** When a block of data is written to a database file, the following
68 ** invariants are asserted:
70 ** a) That the block of data is an aligned block of page-size bytes.
72 ** b) That if the page being written did not exist when the
73 ** transaction was started (i.e. the database file is growing), then
74 ** the journal-file must have been synced at least once since
75 ** the start of the transaction.
77 ** c) That if the page being written did exist when the transaction
78 ** was started, then the page must have either been a free-list
79 ** leaf page at the start of the transaction, or else must have
80 ** been stored in the journal file prior to the most recent sync.
82 ** Closing a Transaction:
84 ** When a transaction is closed, all data collected at the start of
85 ** the transaction, or following an xSync of a journal-file, is
86 ** discarded. The end of a transaction is recognized when any one
87 ** of the following occur:
89 ** a) A block of zeroes (or anything else that is not a valid
90 ** journal-header) is written to the start of the journal file.
92 ** b) A journal file is truncated to zero bytes in size using xTruncate.
94 ** c) The journal file is deleted using xDelete.
96 #if SQLITE_TEST /* This file is used for testing only */
99 #include "sqliteInt.h"
102 ** Maximum pathname length supported by the jt backend.
104 #define JT_MAX_PATHNAME 512
107 ** Name used to identify this VFS.
109 #define JT_VFS_NAME "jt"
111 typedef struct jt_file jt_file
;
114 const char *zName
; /* Name of open file */
115 int flags
; /* Flags the file was opened with */
117 /* The following are only used by database file file handles */
118 int eLock
; /* Current lock held on the file */
119 u32 nPage
; /* Size of file in pages when transaction started */
120 u32 nPagesize
; /* Page size when transaction started */
121 Bitvec
*pWritable
; /* Bitvec of pages that may be written to the file */
122 u32
*aCksum
; /* Checksum for first nPage pages */
123 int nSync
; /* Number of times journal file has been synced */
125 /* Only used by journal file-handles */
126 sqlite3_int64 iMaxOff
; /* Maximum offset written to this transaction */
128 jt_file
*pNext
; /* All files are stored in a linked list */
129 sqlite3_file
*pReal
; /* The file handle for the underlying vfs */
133 ** Method declarations for jt_file.
135 static int jtClose(sqlite3_file
*);
136 static int jtRead(sqlite3_file
*, void*, int iAmt
, sqlite3_int64 iOfst
);
137 static int jtWrite(sqlite3_file
*,const void*,int iAmt
, sqlite3_int64 iOfst
);
138 static int jtTruncate(sqlite3_file
*, sqlite3_int64 size
);
139 static int jtSync(sqlite3_file
*, int flags
);
140 static int jtFileSize(sqlite3_file
*, sqlite3_int64
*pSize
);
141 static int jtLock(sqlite3_file
*, int);
142 static int jtUnlock(sqlite3_file
*, int);
143 static int jtCheckReservedLock(sqlite3_file
*, int *);
144 static int jtFileControl(sqlite3_file
*, int op
, void *pArg
);
145 static int jtSectorSize(sqlite3_file
*);
146 static int jtDeviceCharacteristics(sqlite3_file
*);
149 ** Method declarations for jt_vfs.
151 static int jtOpen(sqlite3_vfs
*, const char *, sqlite3_file
*, int , int *);
152 static int jtDelete(sqlite3_vfs
*, const char *zName
, int syncDir
);
153 static int jtAccess(sqlite3_vfs
*, const char *zName
, int flags
, int *);
154 static int jtFullPathname(sqlite3_vfs
*, const char *zName
, int, char *zOut
);
155 static void *jtDlOpen(sqlite3_vfs
*, const char *zFilename
);
156 static void jtDlError(sqlite3_vfs
*, int nByte
, char *zErrMsg
);
157 static void (*jtDlSym(sqlite3_vfs
*,void*, const char *zSymbol
))(void);
158 static void jtDlClose(sqlite3_vfs
*, void*);
159 static int jtRandomness(sqlite3_vfs
*, int nByte
, char *zOut
);
160 static int jtSleep(sqlite3_vfs
*, int microseconds
);
161 static int jtCurrentTime(sqlite3_vfs
*, double*);
162 static int jtCurrentTimeInt64(sqlite3_vfs
*, sqlite3_int64
*);
163 static int jtGetLastError(sqlite3_vfs
*, int, char*);
165 static sqlite3_vfs jt_vfs
= {
167 sizeof(jt_file
), /* szOsFile */
168 JT_MAX_PATHNAME
, /* mxPathname */
170 JT_VFS_NAME
, /* zName */
173 jtDelete
, /* xDelete */
174 jtAccess
, /* xAccess */
175 jtFullPathname
, /* xFullPathname */
176 jtDlOpen
, /* xDlOpen */
177 jtDlError
, /* xDlError */
178 jtDlSym
, /* xDlSym */
179 jtDlClose
, /* xDlClose */
180 jtRandomness
, /* xRandomness */
181 jtSleep
, /* xSleep */
182 jtCurrentTime
, /* xCurrentTime */
183 jtGetLastError
, /* xGetLastError */
184 jtCurrentTimeInt64
/* xCurrentTimeInt64 */
187 static sqlite3_io_methods jt_io_methods
= {
189 jtClose
, /* xClose */
191 jtWrite
, /* xWrite */
192 jtTruncate
, /* xTruncate */
194 jtFileSize
, /* xFileSize */
196 jtUnlock
, /* xUnlock */
197 jtCheckReservedLock
, /* xCheckReservedLock */
198 jtFileControl
, /* xFileControl */
199 jtSectorSize
, /* xSectorSize */
200 jtDeviceCharacteristics
/* xDeviceCharacteristics */
204 sqlite3_vfs
*pVfs
; /* Parent VFS */
205 jt_file
*pList
; /* List of all open files */
207 static struct JtGlobal g
= {0, 0};
210 ** Functions to obtain and relinquish a mutex to protect g.pList. The
211 ** STATIC_PRNG mutex is reused, purely for the sake of convenience.
213 static void enterJtMutex(void){
214 sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG
));
216 static void leaveJtMutex(void){
217 sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG
));
220 extern int sqlite3_io_error_pending
;
221 extern int sqlite3_io_error_hit
;
222 static void stop_ioerr_simulation(int *piSave
, int *piSave2
){
223 *piSave
= sqlite3_io_error_pending
;
224 *piSave2
= sqlite3_io_error_hit
;
225 sqlite3_io_error_pending
= -1;
226 sqlite3_io_error_hit
= 0;
228 static void start_ioerr_simulation(int iSave
, int iSave2
){
229 sqlite3_io_error_pending
= iSave
;
230 sqlite3_io_error_hit
= iSave2
;
234 ** The jt_file pointed to by the argument may or may not be a file-handle
235 ** open on a main database file. If it is, and a transaction is currently
236 ** opened on the file, then discard all transaction related data.
238 static void closeTransaction(jt_file
*p
){
239 sqlite3BitvecDestroy(p
->pWritable
);
240 sqlite3_free(p
->aCksum
);
249 static int jtClose(sqlite3_file
*pFile
){
251 jt_file
*p
= (jt_file
*)pFile
;
256 for(pp
=&g
.pList
; *pp
!=p
; pp
=&(*pp
)->pNext
);
260 sqlite3OsClose(p
->pReal
);
265 ** Read data from an jt-file.
273 jt_file
*p
= (jt_file
*)pFile
;
274 return sqlite3OsRead(p
->pReal
, zBuf
, iAmt
, iOfst
);
278 ** Parameter zJournal is the name of a journal file that is currently
279 ** open. This function locates and returns the handle opened on the
280 ** corresponding database file by the pager that currently has the
281 ** journal file opened. This file-handle is identified by the
282 ** following properties:
284 ** a) SQLITE_OPEN_MAIN_DB was specified when the file was opened.
286 ** b) The file-name specified when the file was opened matches
287 ** all but the final 8 characters of the journal file name.
289 ** c) There is currently a reserved lock on the file. This
290 ** condition is waived if the noLock argument is non-zero.
292 static jt_file
*locateDatabaseHandle(const char *zJournal
, int noLock
){
295 for(pMain
=g
.pList
; pMain
; pMain
=pMain
->pNext
){
296 int nName
= (int)(strlen(zJournal
) - strlen("-journal"));
297 if( (pMain
->flags
&SQLITE_OPEN_MAIN_DB
)
298 && ((int)strlen(pMain
->zName
)==nName
)
299 && 0==memcmp(pMain
->zName
, zJournal
, nName
)
300 && ((pMain
->eLock
>=SQLITE_LOCK_RESERVED
) || noLock
)
310 ** Parameter z points to a buffer of 4 bytes in size containing a
311 ** unsigned 32-bit integer stored in big-endian format. Decode the
312 ** integer and return its value.
314 static u32
decodeUint32(const unsigned char *z
){
315 return (z
[0]<<24) + (z
[1]<<16) + (z
[2]<<8) + z
[3];
319 ** Calculate a checksum from the buffer of length n bytes pointed to
322 static u32
genCksum(const unsigned char *z
, int n
){
326 cksum
= cksum
+ z
[i
] + (cksum
<<3);
332 ** The first argument, zBuf, points to a buffer containing a 28 byte
333 ** serialized journal header. This function deserializes four of the
334 ** integer fields contained in the journal header and writes their
335 ** values to the output variables.
337 ** SQLITE_OK is returned if the journal-header is successfully
338 ** decoded. Otherwise, SQLITE_ERROR.
340 static int decodeJournalHdr(
341 const unsigned char *zBuf
, /* Input: 28 byte journal header */
342 u32
*pnRec
, /* Out: Number of journalled records */
343 u32
*pnPage
, /* Out: Original database page count */
344 u32
*pnSector
, /* Out: Sector size in bytes */
345 u32
*pnPagesize
/* Out: Page size in bytes */
347 unsigned char aMagic
[] = { 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd7 };
348 if( memcmp(aMagic
, zBuf
, 8) ) return SQLITE_ERROR
;
349 if( pnRec
) *pnRec
= decodeUint32(&zBuf
[8]);
350 if( pnPage
) *pnPage
= decodeUint32(&zBuf
[16]);
351 if( pnSector
) *pnSector
= decodeUint32(&zBuf
[20]);
352 if( pnPagesize
) *pnPagesize
= decodeUint32(&zBuf
[24]);
357 ** This function is called when a new transaction is opened, just after
358 ** the first journal-header is written to the journal file.
360 static int openTransaction(jt_file
*pMain
, jt_file
*pJournal
){
361 unsigned char *aData
;
362 sqlite3_file
*p
= pMain
->pReal
;
365 closeTransaction(pMain
);
366 aData
= sqlite3_malloc(pMain
->nPagesize
);
367 pMain
->pWritable
= sqlite3BitvecCreate(pMain
->nPage
);
368 pMain
->aCksum
= sqlite3_malloc(sizeof(u32
) * (pMain
->nPage
+ 1));
369 pJournal
->iMaxOff
= 0;
371 if( !pMain
->pWritable
|| !pMain
->aCksum
|| !aData
){
372 rc
= SQLITE_IOERR_NOMEM
;
373 }else if( pMain
->nPage
>0 ){
378 stop_ioerr_simulation(&iSave
, &iSave2
);
380 /* Read the database free-list. Add the page-number for each free-list
381 ** leaf to the jt_file.pWritable bitvec.
383 rc
= sqlite3OsRead(p
, aData
, pMain
->nPagesize
, 0);
385 u32 nDbsize
= decodeUint32(&aData
[28]);
386 if( nDbsize
>0 && memcmp(&aData
[24], &aData
[92], 4)==0 ){
388 for(iPg
=nDbsize
+1; iPg
<=pMain
->nPage
; iPg
++){
389 sqlite3BitvecSet(pMain
->pWritable
, iPg
);
393 iTrunk
= decodeUint32(&aData
[32]);
394 while( rc
==SQLITE_OK
&& iTrunk
>0 ){
397 sqlite3_int64 iOff
= (i64
)(iTrunk
-1)*pMain
->nPagesize
;
398 rc
= sqlite3OsRead(p
, aData
, pMain
->nPagesize
, iOff
);
399 nLeaf
= decodeUint32(&aData
[4]);
400 for(iLeaf
=0; rc
==SQLITE_OK
&& iLeaf
<nLeaf
; iLeaf
++){
401 u32 pgno
= decodeUint32(&aData
[8+4*iLeaf
]);
402 sqlite3BitvecSet(pMain
->pWritable
, pgno
);
404 iTrunk
= decodeUint32(aData
);
407 /* Calculate and store a checksum for each page in the database file. */
410 for(ii
=0; rc
==SQLITE_OK
&& ii
<(int)pMain
->nPage
; ii
++){
411 i64 iOff
= (i64
)(pMain
->nPagesize
) * (i64
)ii
;
412 if( iOff
==PENDING_BYTE
) continue;
413 rc
= sqlite3OsRead(pMain
->pReal
, aData
, pMain
->nPagesize
, iOff
);
414 pMain
->aCksum
[ii
] = genCksum(aData
, pMain
->nPagesize
);
415 if( ii
+1==(int)pMain
->nPage
&& rc
==SQLITE_IOERR_SHORT_READ
){
421 start_ioerr_simulation(iSave
, iSave2
);
429 ** The first argument to this function is a handle open on a journal file.
430 ** This function reads the journal file and adds the page number for each
431 ** page in the journal to the Bitvec object passed as the second argument.
433 static int readJournalFile(jt_file
*p
, jt_file
*pMain
){
435 unsigned char zBuf
[28];
436 sqlite3_file
*pReal
= p
->pReal
;
437 sqlite3_int64 iOff
= 0;
438 sqlite3_int64 iSize
= p
->iMaxOff
;
439 unsigned char *aPage
;
443 aPage
= sqlite3_malloc(pMain
->nPagesize
);
445 return SQLITE_IOERR_NOMEM
;
448 stop_ioerr_simulation(&iSave
, &iSave2
);
450 while( rc
==SQLITE_OK
&& iOff
<iSize
){
451 u32 nRec
, nPage
, nSector
, nPagesize
;
454 /* Read and decode the next journal-header from the journal file. */
455 rc
= sqlite3OsRead(pReal
, zBuf
, 28, iOff
);
457 || decodeJournalHdr(zBuf
, &nRec
, &nPage
, &nSector
, &nPagesize
)
464 /* A trick. There might be another journal-header immediately
465 ** following this one. In this case, 0 records means 0 records,
466 ** not "read until the end of the file". See also ticket #2565.
468 if( iSize
>=(iOff
+nSector
) ){
469 rc
= sqlite3OsRead(pReal
, zBuf
, 28, iOff
);
470 if( rc
!=SQLITE_OK
|| 0==decodeJournalHdr(zBuf
, 0, 0, 0, 0) ){
474 nRec
= (u32
)((iSize
-iOff
) / (pMain
->nPagesize
+8));
477 /* Read all the records that follow the journal-header just read. */
478 for(ii
=0; rc
==SQLITE_OK
&& ii
<nRec
&& iOff
<iSize
; ii
++){
480 rc
= sqlite3OsRead(pReal
, zBuf
, 4, iOff
);
482 pgno
= decodeUint32(zBuf
);
483 if( pgno
>0 && pgno
<=pMain
->nPage
){
484 if( 0==sqlite3BitvecTest(pMain
->pWritable
, pgno
) ){
485 rc
= sqlite3OsRead(pReal
, aPage
, pMain
->nPagesize
, iOff
+4);
487 u32 cksum
= genCksum(aPage
, pMain
->nPagesize
);
488 assert( cksum
==pMain
->aCksum
[pgno
-1] );
491 sqlite3BitvecSet(pMain
->pWritable
, pgno
);
493 iOff
+= (8 + pMain
->nPagesize
);
497 iOff
= ((iOff
+ (nSector
-1)) / nSector
) * nSector
;
501 start_ioerr_simulation(iSave
, iSave2
);
503 if( rc
==SQLITE_IOERR_SHORT_READ
){
510 ** Write data to an jt-file.
519 jt_file
*p
= (jt_file
*)pFile
;
520 if( p
->flags
&SQLITE_OPEN_MAIN_JOURNAL
){
522 jt_file
*pMain
= locateDatabaseHandle(p
->zName
, 0);
526 /* Zeroing the first journal-file header. This is the end of a
528 closeTransaction(pMain
);
529 }else if( iAmt
!=12 ){
530 /* Writing the first journal header to a journal file. This happens
531 ** when a transaction is first started. */
533 pMain
->nPage
= decodeUint32(&z
[16]);
534 pMain
->nPagesize
= decodeUint32(&z
[24]);
535 if( SQLITE_OK
!=(rc
=openTransaction(pMain
, p
)) ){
540 if( p
->iMaxOff
<(iOfst
+ iAmt
) ){
541 p
->iMaxOff
= iOfst
+ iAmt
;
545 if( p
->flags
&SQLITE_OPEN_MAIN_DB
&& p
->pWritable
){
546 if( iAmt
<(int)p
->nPagesize
547 && p
->nPagesize
%iAmt
==0
548 && iOfst
>=(PENDING_BYTE
+512)
549 && iOfst
+iAmt
<=PENDING_BYTE
+p
->nPagesize
551 /* No-op. This special case is hit when the backup code is copying a
552 ** to a database with a larger page-size than the source database and
553 ** it needs to fill in the non-locking-region part of the original
554 ** pending-byte page.
557 u32 pgno
= (u32
)(iOfst
/p
->nPagesize
+ 1);
558 assert( (iAmt
==1||iAmt
==(int)p
->nPagesize
) &&
559 ((iOfst
+iAmt
)%p
->nPagesize
)==0 );
560 /* The following assert() statements may fail if this layer is used
561 ** with a connection in "PRAGMA synchronous=off" mode. If they
562 ** fail with sync=normal or sync=full, this may indicate problem. */
563 assert( p
->nPage
==0 || pgno
<=p
->nPage
|| p
->nSync
>0 );
564 assert( pgno
>p
->nPage
|| sqlite3BitvecTest(p
->pWritable
, pgno
) );
568 rc
= sqlite3OsWrite(p
->pReal
, zBuf
, iAmt
, iOfst
);
569 if( (p
->flags
&SQLITE_OPEN_MAIN_JOURNAL
) && iAmt
==12 ){
570 jt_file
*pMain
= locateDatabaseHandle(p
->zName
, 0);
571 int rc2
= readJournalFile(p
, pMain
);
572 if( rc
==SQLITE_OK
) rc
= rc2
;
578 ** Truncate an jt-file.
580 static int jtTruncate(sqlite3_file
*pFile
, sqlite_int64 size
){
581 jt_file
*p
= (jt_file
*)pFile
;
582 if( p
->flags
&SQLITE_OPEN_MAIN_JOURNAL
&& size
==0 ){
583 /* Truncating a journal file. This is the end of a transaction. */
584 jt_file
*pMain
= locateDatabaseHandle(p
->zName
, 0);
585 closeTransaction(pMain
);
587 if( p
->flags
&SQLITE_OPEN_MAIN_DB
&& p
->pWritable
){
589 u32 locking_page
= (u32
)(PENDING_BYTE
/p
->nPagesize
+1);
590 for(pgno
=(u32
)(size
/p
->nPagesize
+1); pgno
<=p
->nPage
; pgno
++){
591 assert( pgno
==locking_page
|| sqlite3BitvecTest(p
->pWritable
, pgno
) );
594 return sqlite3OsTruncate(p
->pReal
, size
);
600 static int jtSync(sqlite3_file
*pFile
, int flags
){
601 jt_file
*p
= (jt_file
*)pFile
;
603 if( p
->flags
&SQLITE_OPEN_MAIN_JOURNAL
){
605 jt_file
*pMain
; /* The associated database file */
607 /* The journal file is being synced. At this point, we inspect the
608 ** contents of the file up to this point and set each bit in the
609 ** jt_file.pWritable bitvec of the main database file associated with
610 ** this journal file.
612 pMain
= locateDatabaseHandle(p
->zName
, 0);
614 /* Set the bitvec values */
615 if( pMain
&& pMain
->pWritable
){
617 rc
= readJournalFile(p
, pMain
);
624 return sqlite3OsSync(p
->pReal
, flags
);
628 ** Return the current file-size of an jt-file.
630 static int jtFileSize(sqlite3_file
*pFile
, sqlite_int64
*pSize
){
631 jt_file
*p
= (jt_file
*)pFile
;
632 return sqlite3OsFileSize(p
->pReal
, pSize
);
638 static int jtLock(sqlite3_file
*pFile
, int eLock
){
640 jt_file
*p
= (jt_file
*)pFile
;
641 rc
= sqlite3OsLock(p
->pReal
, eLock
);
642 if( rc
==SQLITE_OK
&& eLock
>p
->eLock
){
649 ** Unlock an jt-file.
651 static int jtUnlock(sqlite3_file
*pFile
, int eLock
){
653 jt_file
*p
= (jt_file
*)pFile
;
654 rc
= sqlite3OsUnlock(p
->pReal
, eLock
);
655 if( rc
==SQLITE_OK
&& eLock
<p
->eLock
){
662 ** Check if another file-handle holds a RESERVED lock on an jt-file.
664 static int jtCheckReservedLock(sqlite3_file
*pFile
, int *pResOut
){
665 jt_file
*p
= (jt_file
*)pFile
;
666 return sqlite3OsCheckReservedLock(p
->pReal
, pResOut
);
670 ** File control method. For custom operations on an jt-file.
672 static int jtFileControl(sqlite3_file
*pFile
, int op
, void *pArg
){
673 jt_file
*p
= (jt_file
*)pFile
;
674 return p
->pReal
->pMethods
->xFileControl(p
->pReal
, op
, pArg
);
678 ** Return the sector-size in bytes for an jt-file.
680 static int jtSectorSize(sqlite3_file
*pFile
){
681 jt_file
*p
= (jt_file
*)pFile
;
682 return sqlite3OsSectorSize(p
->pReal
);
686 ** Return the device characteristic flags supported by an jt-file.
688 static int jtDeviceCharacteristics(sqlite3_file
*pFile
){
689 jt_file
*p
= (jt_file
*)pFile
;
690 return sqlite3OsDeviceCharacteristics(p
->pReal
);
694 ** Open an jt file handle.
704 jt_file
*p
= (jt_file
*)pFile
;
706 p
->pReal
= (sqlite3_file
*)&p
[1];
707 p
->pReal
->pMethods
= 0;
708 rc
= sqlite3OsOpen(g
.pVfs
, zName
, p
->pReal
, flags
, pOutFlags
);
709 assert( rc
==SQLITE_OK
|| p
->pReal
->pMethods
==0 );
711 pFile
->pMethods
= &jt_io_methods
;
729 ** Delete the file located at zPath. If the dirSync argument is true,
730 ** ensure the file-system modifications are synced to disk before
733 static int jtDelete(sqlite3_vfs
*pVfs
, const char *zPath
, int dirSync
){
734 int nPath
= (int)strlen(zPath
);
735 if( nPath
>8 && 0==strcmp("-journal", &zPath
[nPath
-8]) ){
736 /* Deleting a journal file. The end of a transaction. */
737 jt_file
*pMain
= locateDatabaseHandle(zPath
, 0);
739 closeTransaction(pMain
);
743 return sqlite3OsDelete(g
.pVfs
, zPath
, dirSync
);
747 ** Test for access permissions. Return true if the requested permission
748 ** is available, or false otherwise.
756 return sqlite3OsAccess(g
.pVfs
, zPath
, flags
, pResOut
);
760 ** Populate buffer zOut with the full canonical pathname corresponding
761 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
762 ** of at least (JT_MAX_PATHNAME+1) bytes.
764 static int jtFullPathname(
770 return sqlite3OsFullPathname(g
.pVfs
, zPath
, nOut
, zOut
);
774 ** Open the dynamic library located at zPath and return a handle.
776 static void *jtDlOpen(sqlite3_vfs
*pVfs
, const char *zPath
){
777 return g
.pVfs
->xDlOpen(g
.pVfs
, zPath
);
781 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
782 ** utf-8 string describing the most recent error encountered associated
783 ** with dynamic libraries.
785 static void jtDlError(sqlite3_vfs
*pVfs
, int nByte
, char *zErrMsg
){
786 g
.pVfs
->xDlError(g
.pVfs
, nByte
, zErrMsg
);
790 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
792 static void (*jtDlSym(sqlite3_vfs
*pVfs
, void *p
, const char *zSym
))(void){
793 return g
.pVfs
->xDlSym(g
.pVfs
, p
, zSym
);
797 ** Close the dynamic library handle pHandle.
799 static void jtDlClose(sqlite3_vfs
*pVfs
, void *pHandle
){
800 g
.pVfs
->xDlClose(g
.pVfs
, pHandle
);
804 ** Populate the buffer pointed to by zBufOut with nByte bytes of
807 static int jtRandomness(sqlite3_vfs
*pVfs
, int nByte
, char *zBufOut
){
808 return sqlite3OsRandomness(g
.pVfs
, nByte
, zBufOut
);
812 ** Sleep for nMicro microseconds. Return the number of microseconds
815 static int jtSleep(sqlite3_vfs
*pVfs
, int nMicro
){
816 return sqlite3OsSleep(g
.pVfs
, nMicro
);
820 ** Return the current time as a Julian Day number in *pTimeOut.
822 static int jtCurrentTime(sqlite3_vfs
*pVfs
, double *pTimeOut
){
823 return g
.pVfs
->xCurrentTime(g
.pVfs
, pTimeOut
);
826 ** Return the current time as a Julian Day number in *pTimeOut.
828 static int jtCurrentTimeInt64(sqlite3_vfs
*pVfs
, sqlite3_int64
*pTimeOut
){
829 return g
.pVfs
->xCurrentTimeInt64(g
.pVfs
, pTimeOut
);
832 static int jtGetLastError(sqlite3_vfs
*pVfs
, int n
, char *z
){
833 return g
.pVfs
->xGetLastError(g
.pVfs
, n
, z
);
836 /**************************************************************************
837 ** Start of public API.
841 ** Configure the jt VFS as a wrapper around the VFS named by parameter
842 ** zWrap. If the isDefault parameter is true, then the jt VFS is installed
843 ** as the new default VFS for SQLite connections. If isDefault is not
844 ** true, then the jt VFS is installed as non-default. In this case it
845 ** is available via its name, "jt".
847 int jt_register(char *zWrap
, int isDefault
){
848 g
.pVfs
= sqlite3_vfs_find(zWrap
);
852 jt_vfs
.szOsFile
= sizeof(jt_file
) + g
.pVfs
->szOsFile
;
853 if( g
.pVfs
->iVersion
==1 ){
855 }else if( g
.pVfs
->xCurrentTimeInt64
==0 ){
856 jt_vfs
.xCurrentTimeInt64
= 0;
858 sqlite3_vfs_register(&jt_vfs
, isDefault
);
863 ** Uninstall the jt VFS, if it is installed.
865 void jt_unregister(void){
866 sqlite3_vfs_unregister(&jt_vfs
);