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
*);
164 static sqlite3_vfs jt_vfs
= {
166 sizeof(jt_file
), /* szOsFile */
167 JT_MAX_PATHNAME
, /* mxPathname */
169 JT_VFS_NAME
, /* zName */
172 jtDelete
, /* xDelete */
173 jtAccess
, /* xAccess */
174 jtFullPathname
, /* xFullPathname */
175 jtDlOpen
, /* xDlOpen */
176 jtDlError
, /* xDlError */
177 jtDlSym
, /* xDlSym */
178 jtDlClose
, /* xDlClose */
179 jtRandomness
, /* xRandomness */
180 jtSleep
, /* xSleep */
181 jtCurrentTime
, /* xCurrentTime */
182 0, /* xGetLastError */
183 jtCurrentTimeInt64
/* xCurrentTimeInt64 */
186 static sqlite3_io_methods jt_io_methods
= {
188 jtClose
, /* xClose */
190 jtWrite
, /* xWrite */
191 jtTruncate
, /* xTruncate */
193 jtFileSize
, /* xFileSize */
195 jtUnlock
, /* xUnlock */
196 jtCheckReservedLock
, /* xCheckReservedLock */
197 jtFileControl
, /* xFileControl */
198 jtSectorSize
, /* xSectorSize */
199 jtDeviceCharacteristics
/* xDeviceCharacteristics */
203 sqlite3_vfs
*pVfs
; /* Parent VFS */
204 jt_file
*pList
; /* List of all open files */
206 static struct JtGlobal g
= {0, 0};
209 ** Functions to obtain and relinquish a mutex to protect g.pList. The
210 ** STATIC_PRNG mutex is reused, purely for the sake of convenience.
212 static void enterJtMutex(void){
213 sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG
));
215 static void leaveJtMutex(void){
216 sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG
));
219 extern int sqlite3_io_error_pending
;
220 extern int sqlite3_io_error_hit
;
221 static void stop_ioerr_simulation(int *piSave
, int *piSave2
){
222 *piSave
= sqlite3_io_error_pending
;
223 *piSave2
= sqlite3_io_error_hit
;
224 sqlite3_io_error_pending
= -1;
225 sqlite3_io_error_hit
= 0;
227 static void start_ioerr_simulation(int iSave
, int iSave2
){
228 sqlite3_io_error_pending
= iSave
;
229 sqlite3_io_error_hit
= iSave2
;
233 ** The jt_file pointed to by the argument may or may not be a file-handle
234 ** open on a main database file. If it is, and a transaction is currently
235 ** opened on the file, then discard all transaction related data.
237 static void closeTransaction(jt_file
*p
){
238 sqlite3BitvecDestroy(p
->pWritable
);
239 sqlite3_free(p
->aCksum
);
248 static int jtClose(sqlite3_file
*pFile
){
250 jt_file
*p
= (jt_file
*)pFile
;
255 for(pp
=&g
.pList
; *pp
!=p
; pp
=&(*pp
)->pNext
);
259 return sqlite3OsClose(p
->pReal
);
263 ** Read data from an jt-file.
271 jt_file
*p
= (jt_file
*)pFile
;
272 return sqlite3OsRead(p
->pReal
, zBuf
, iAmt
, iOfst
);
276 ** Parameter zJournal is the name of a journal file that is currently
277 ** open. This function locates and returns the handle opened on the
278 ** corresponding database file by the pager that currently has the
279 ** journal file opened. This file-handle is identified by the
280 ** following properties:
282 ** a) SQLITE_OPEN_MAIN_DB was specified when the file was opened.
284 ** b) The file-name specified when the file was opened matches
285 ** all but the final 8 characters of the journal file name.
287 ** c) There is currently a reserved lock on the file.
289 static jt_file
*locateDatabaseHandle(const char *zJournal
){
292 for(pMain
=g
.pList
; pMain
; pMain
=pMain
->pNext
){
293 int nName
= (int)(strlen(zJournal
) - strlen("-journal"));
294 if( (pMain
->flags
&SQLITE_OPEN_MAIN_DB
)
295 && ((int)strlen(pMain
->zName
)==nName
)
296 && 0==memcmp(pMain
->zName
, zJournal
, nName
)
297 && (pMain
->eLock
>=SQLITE_LOCK_RESERVED
)
307 ** Parameter z points to a buffer of 4 bytes in size containing a
308 ** unsigned 32-bit integer stored in big-endian format. Decode the
309 ** integer and return its value.
311 static u32
decodeUint32(const unsigned char *z
){
312 return (z
[0]<<24) + (z
[1]<<16) + (z
[2]<<8) + z
[3];
316 ** Calculate a checksum from the buffer of length n bytes pointed to
319 static u32
genCksum(const unsigned char *z
, int n
){
323 cksum
= cksum
+ z
[i
] + (cksum
<<3);
329 ** The first argument, zBuf, points to a buffer containing a 28 byte
330 ** serialized journal header. This function deserializes four of the
331 ** integer fields contained in the journal header and writes their
332 ** values to the output variables.
334 ** SQLITE_OK is returned if the journal-header is successfully
335 ** decoded. Otherwise, SQLITE_ERROR.
337 static int decodeJournalHdr(
338 const unsigned char *zBuf
, /* Input: 28 byte journal header */
339 u32
*pnRec
, /* Out: Number of journalled records */
340 u32
*pnPage
, /* Out: Original database page count */
341 u32
*pnSector
, /* Out: Sector size in bytes */
342 u32
*pnPagesize
/* Out: Page size in bytes */
344 unsigned char aMagic
[] = { 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd7 };
345 if( memcmp(aMagic
, zBuf
, 8) ) return SQLITE_ERROR
;
346 if( pnRec
) *pnRec
= decodeUint32(&zBuf
[8]);
347 if( pnPage
) *pnPage
= decodeUint32(&zBuf
[16]);
348 if( pnSector
) *pnSector
= decodeUint32(&zBuf
[20]);
349 if( pnPagesize
) *pnPagesize
= decodeUint32(&zBuf
[24]);
354 ** This function is called when a new transaction is opened, just after
355 ** the first journal-header is written to the journal file.
357 static int openTransaction(jt_file
*pMain
, jt_file
*pJournal
){
358 unsigned char *aData
;
359 sqlite3_file
*p
= pMain
->pReal
;
362 closeTransaction(pMain
);
363 aData
= sqlite3_malloc(pMain
->nPagesize
);
364 pMain
->pWritable
= sqlite3BitvecCreate(pMain
->nPage
);
365 pMain
->aCksum
= sqlite3_malloc(sizeof(u32
) * (pMain
->nPage
+ 1));
366 pJournal
->iMaxOff
= 0;
368 if( !pMain
->pWritable
|| !pMain
->aCksum
|| !aData
){
369 rc
= SQLITE_IOERR_NOMEM
;
370 }else if( pMain
->nPage
>0 ){
375 stop_ioerr_simulation(&iSave
, &iSave2
);
377 /* Read the database free-list. Add the page-number for each free-list
378 ** leaf to the jt_file.pWritable bitvec.
380 rc
= sqlite3OsRead(p
, aData
, pMain
->nPagesize
, 0);
382 u32 nDbsize
= decodeUint32(&aData
[28]);
383 if( nDbsize
>0 && memcmp(&aData
[24], &aData
[92], 4)==0 ){
385 for(iPg
=nDbsize
+1; iPg
<=pMain
->nPage
; iPg
++){
386 sqlite3BitvecSet(pMain
->pWritable
, iPg
);
390 iTrunk
= decodeUint32(&aData
[32]);
391 while( rc
==SQLITE_OK
&& iTrunk
>0 ){
394 sqlite3_int64 iOff
= (i64
)(iTrunk
-1)*pMain
->nPagesize
;
395 rc
= sqlite3OsRead(p
, aData
, pMain
->nPagesize
, iOff
);
396 nLeaf
= decodeUint32(&aData
[4]);
397 for(iLeaf
=0; rc
==SQLITE_OK
&& iLeaf
<nLeaf
; iLeaf
++){
398 u32 pgno
= decodeUint32(&aData
[8+4*iLeaf
]);
399 sqlite3BitvecSet(pMain
->pWritable
, pgno
);
401 iTrunk
= decodeUint32(aData
);
404 /* Calculate and store a checksum for each page in the database file. */
407 for(ii
=0; rc
==SQLITE_OK
&& ii
<(int)pMain
->nPage
; ii
++){
408 i64 iOff
= (i64
)(pMain
->nPagesize
) * (i64
)ii
;
409 if( iOff
==PENDING_BYTE
) continue;
410 rc
= sqlite3OsRead(pMain
->pReal
, aData
, pMain
->nPagesize
, iOff
);
411 pMain
->aCksum
[ii
] = genCksum(aData
, pMain
->nPagesize
);
412 if( ii
+1==pMain
->nPage
&& rc
==SQLITE_IOERR_SHORT_READ
) rc
= SQLITE_OK
;
416 start_ioerr_simulation(iSave
, iSave2
);
424 ** The first argument to this function is a handle open on a journal file.
425 ** This function reads the journal file and adds the page number for each
426 ** page in the journal to the Bitvec object passed as the second argument.
428 static int readJournalFile(jt_file
*p
, jt_file
*pMain
){
430 unsigned char zBuf
[28];
431 sqlite3_file
*pReal
= p
->pReal
;
432 sqlite3_int64 iOff
= 0;
433 sqlite3_int64 iSize
= p
->iMaxOff
;
434 unsigned char *aPage
;
438 aPage
= sqlite3_malloc(pMain
->nPagesize
);
440 return SQLITE_IOERR_NOMEM
;
443 stop_ioerr_simulation(&iSave
, &iSave2
);
445 while( rc
==SQLITE_OK
&& iOff
<iSize
){
446 u32 nRec
, nPage
, nSector
, nPagesize
;
449 /* Read and decode the next journal-header from the journal file. */
450 rc
= sqlite3OsRead(pReal
, zBuf
, 28, iOff
);
452 || decodeJournalHdr(zBuf
, &nRec
, &nPage
, &nSector
, &nPagesize
)
459 /* A trick. There might be another journal-header immediately
460 ** following this one. In this case, 0 records means 0 records,
461 ** not "read until the end of the file". See also ticket #2565.
463 if( iSize
>=(iOff
+nSector
) ){
464 rc
= sqlite3OsRead(pReal
, zBuf
, 28, iOff
);
465 if( rc
!=SQLITE_OK
|| 0==decodeJournalHdr(zBuf
, 0, 0, 0, 0) ){
469 nRec
= (u32
)((iSize
-iOff
) / (pMain
->nPagesize
+8));
472 /* Read all the records that follow the journal-header just read. */
473 for(ii
=0; rc
==SQLITE_OK
&& ii
<nRec
&& iOff
<iSize
; ii
++){
475 rc
= sqlite3OsRead(pReal
, zBuf
, 4, iOff
);
477 pgno
= decodeUint32(zBuf
);
478 if( pgno
>0 && pgno
<=pMain
->nPage
){
479 if( 0==sqlite3BitvecTest(pMain
->pWritable
, pgno
) ){
480 rc
= sqlite3OsRead(pReal
, aPage
, pMain
->nPagesize
, iOff
+4);
482 u32 cksum
= genCksum(aPage
, pMain
->nPagesize
);
483 assert( cksum
==pMain
->aCksum
[pgno
-1] );
486 sqlite3BitvecSet(pMain
->pWritable
, pgno
);
488 iOff
+= (8 + pMain
->nPagesize
);
492 iOff
= ((iOff
+ (nSector
-1)) / nSector
) * nSector
;
496 start_ioerr_simulation(iSave
, iSave2
);
498 if( rc
==SQLITE_IOERR_SHORT_READ
){
505 ** Write data to an jt-file.
514 jt_file
*p
= (jt_file
*)pFile
;
515 if( p
->flags
&SQLITE_OPEN_MAIN_JOURNAL
){
517 jt_file
*pMain
= locateDatabaseHandle(p
->zName
);
521 /* Zeroing the first journal-file header. This is the end of a
523 closeTransaction(pMain
);
524 }else if( iAmt
!=12 ){
525 /* Writing the first journal header to a journal file. This happens
526 ** when a transaction is first started. */
528 pMain
->nPage
= decodeUint32(&z
[16]);
529 pMain
->nPagesize
= decodeUint32(&z
[24]);
530 if( SQLITE_OK
!=(rc
=openTransaction(pMain
, p
)) ){
535 if( p
->iMaxOff
<(iOfst
+ iAmt
) ){
536 p
->iMaxOff
= iOfst
+ iAmt
;
540 if( p
->flags
&SQLITE_OPEN_MAIN_DB
&& p
->pWritable
){
541 if( iAmt
<(int)p
->nPagesize
542 && p
->nPagesize
%iAmt
==0
543 && iOfst
>=(PENDING_BYTE
+512)
544 && iOfst
+iAmt
<=PENDING_BYTE
+p
->nPagesize
546 /* No-op. This special case is hit when the backup code is copying a
547 ** to a database with a larger page-size than the source database and
548 ** it needs to fill in the non-locking-region part of the original
549 ** pending-byte page.
552 u32 pgno
= (u32
)(iOfst
/p
->nPagesize
+ 1);
553 assert( (iAmt
==1||iAmt
==p
->nPagesize
) && ((iOfst
+iAmt
)%p
->nPagesize
)==0 );
554 assert( pgno
<=p
->nPage
|| p
->nSync
>0 );
555 assert( pgno
>p
->nPage
|| sqlite3BitvecTest(p
->pWritable
, pgno
) );
559 rc
= sqlite3OsWrite(p
->pReal
, zBuf
, iAmt
, iOfst
);
560 if( (p
->flags
&SQLITE_OPEN_MAIN_JOURNAL
) && iAmt
==12 ){
561 jt_file
*pMain
= locateDatabaseHandle(p
->zName
);
562 int rc2
= readJournalFile(p
, pMain
);
563 if( rc
==SQLITE_OK
) rc
= rc2
;
569 ** Truncate an jt-file.
571 static int jtTruncate(sqlite3_file
*pFile
, sqlite_int64 size
){
572 jt_file
*p
= (jt_file
*)pFile
;
573 if( p
->flags
&SQLITE_OPEN_MAIN_JOURNAL
&& size
==0 ){
574 /* Truncating a journal file. This is the end of a transaction. */
575 jt_file
*pMain
= locateDatabaseHandle(p
->zName
);
576 closeTransaction(pMain
);
578 if( p
->flags
&SQLITE_OPEN_MAIN_DB
&& p
->pWritable
){
580 u32 locking_page
= (u32
)(PENDING_BYTE
/p
->nPagesize
+1);
581 for(pgno
=(u32
)(size
/p
->nPagesize
+1); pgno
<=p
->nPage
; pgno
++){
582 assert( pgno
==locking_page
|| sqlite3BitvecTest(p
->pWritable
, pgno
) );
585 return sqlite3OsTruncate(p
->pReal
, size
);
591 static int jtSync(sqlite3_file
*pFile
, int flags
){
592 jt_file
*p
= (jt_file
*)pFile
;
594 if( p
->flags
&SQLITE_OPEN_MAIN_JOURNAL
){
596 jt_file
*pMain
; /* The associated database file */
598 /* The journal file is being synced. At this point, we inspect the
599 ** contents of the file up to this point and set each bit in the
600 ** jt_file.pWritable bitvec of the main database file associated with
601 ** this journal file.
603 pMain
= locateDatabaseHandle(p
->zName
);
606 /* Set the bitvec values */
607 if( pMain
->pWritable
){
609 rc
= readJournalFile(p
, pMain
);
616 return sqlite3OsSync(p
->pReal
, flags
);
620 ** Return the current file-size of an jt-file.
622 static int jtFileSize(sqlite3_file
*pFile
, sqlite_int64
*pSize
){
623 jt_file
*p
= (jt_file
*)pFile
;
624 return sqlite3OsFileSize(p
->pReal
, pSize
);
630 static int jtLock(sqlite3_file
*pFile
, int eLock
){
632 jt_file
*p
= (jt_file
*)pFile
;
633 rc
= sqlite3OsLock(p
->pReal
, eLock
);
634 if( rc
==SQLITE_OK
&& eLock
>p
->eLock
){
641 ** Unlock an jt-file.
643 static int jtUnlock(sqlite3_file
*pFile
, int eLock
){
645 jt_file
*p
= (jt_file
*)pFile
;
646 rc
= sqlite3OsUnlock(p
->pReal
, eLock
);
647 if( rc
==SQLITE_OK
&& eLock
<p
->eLock
){
654 ** Check if another file-handle holds a RESERVED lock on an jt-file.
656 static int jtCheckReservedLock(sqlite3_file
*pFile
, int *pResOut
){
657 jt_file
*p
= (jt_file
*)pFile
;
658 return sqlite3OsCheckReservedLock(p
->pReal
, pResOut
);
662 ** File control method. For custom operations on an jt-file.
664 static int jtFileControl(sqlite3_file
*pFile
, int op
, void *pArg
){
665 jt_file
*p
= (jt_file
*)pFile
;
666 return p
->pReal
->pMethods
->xFileControl(p
->pReal
, op
, pArg
);
670 ** Return the sector-size in bytes for an jt-file.
672 static int jtSectorSize(sqlite3_file
*pFile
){
673 jt_file
*p
= (jt_file
*)pFile
;
674 return sqlite3OsSectorSize(p
->pReal
);
678 ** Return the device characteristic flags supported by an jt-file.
680 static int jtDeviceCharacteristics(sqlite3_file
*pFile
){
681 jt_file
*p
= (jt_file
*)pFile
;
682 return sqlite3OsDeviceCharacteristics(p
->pReal
);
686 ** Open an jt file handle.
696 jt_file
*p
= (jt_file
*)pFile
;
698 p
->pReal
= (sqlite3_file
*)&p
[1];
699 p
->pReal
->pMethods
= 0;
700 rc
= sqlite3OsOpen(g
.pVfs
, zName
, p
->pReal
, flags
, pOutFlags
);
701 assert( rc
==SQLITE_OK
|| p
->pReal
->pMethods
==0 );
703 pFile
->pMethods
= &jt_io_methods
;
721 ** Delete the file located at zPath. If the dirSync argument is true,
722 ** ensure the file-system modifications are synced to disk before
725 static int jtDelete(sqlite3_vfs
*pVfs
, const char *zPath
, int dirSync
){
726 int nPath
= (int)strlen(zPath
);
727 if( nPath
>8 && 0==strcmp("-journal", &zPath
[nPath
-8]) ){
728 /* Deleting a journal file. The end of a transaction. */
729 jt_file
*pMain
= locateDatabaseHandle(zPath
);
731 closeTransaction(pMain
);
735 return sqlite3OsDelete(g
.pVfs
, zPath
, dirSync
);
739 ** Test for access permissions. Return true if the requested permission
740 ** is available, or false otherwise.
748 return sqlite3OsAccess(g
.pVfs
, zPath
, flags
, pResOut
);
752 ** Populate buffer zOut with the full canonical pathname corresponding
753 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
754 ** of at least (JT_MAX_PATHNAME+1) bytes.
756 static int jtFullPathname(
762 return sqlite3OsFullPathname(g
.pVfs
, zPath
, nOut
, zOut
);
766 ** Open the dynamic library located at zPath and return a handle.
768 static void *jtDlOpen(sqlite3_vfs
*pVfs
, const char *zPath
){
769 return g
.pVfs
->xDlOpen(g
.pVfs
, zPath
);
773 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
774 ** utf-8 string describing the most recent error encountered associated
775 ** with dynamic libraries.
777 static void jtDlError(sqlite3_vfs
*pVfs
, int nByte
, char *zErrMsg
){
778 g
.pVfs
->xDlError(g
.pVfs
, nByte
, zErrMsg
);
782 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
784 static void (*jtDlSym(sqlite3_vfs
*pVfs
, void *p
, const char *zSym
))(void){
785 return g
.pVfs
->xDlSym(g
.pVfs
, p
, zSym
);
789 ** Close the dynamic library handle pHandle.
791 static void jtDlClose(sqlite3_vfs
*pVfs
, void *pHandle
){
792 g
.pVfs
->xDlClose(g
.pVfs
, pHandle
);
796 ** Populate the buffer pointed to by zBufOut with nByte bytes of
799 static int jtRandomness(sqlite3_vfs
*pVfs
, int nByte
, char *zBufOut
){
800 return sqlite3OsRandomness(g
.pVfs
, nByte
, zBufOut
);
804 ** Sleep for nMicro microseconds. Return the number of microseconds
807 static int jtSleep(sqlite3_vfs
*pVfs
, int nMicro
){
808 return sqlite3OsSleep(g
.pVfs
, nMicro
);
812 ** Return the current time as a Julian Day number in *pTimeOut.
814 static int jtCurrentTime(sqlite3_vfs
*pVfs
, double *pTimeOut
){
815 return g
.pVfs
->xCurrentTime(g
.pVfs
, pTimeOut
);
818 ** Return the current time as a Julian Day number in *pTimeOut.
820 static int jtCurrentTimeInt64(sqlite3_vfs
*pVfs
, sqlite3_int64
*pTimeOut
){
821 return g
.pVfs
->xCurrentTimeInt64(g
.pVfs
, pTimeOut
);
824 /**************************************************************************
825 ** Start of public API.
829 ** Configure the jt VFS as a wrapper around the VFS named by parameter
830 ** zWrap. If the isDefault parameter is true, then the jt VFS is installed
831 ** as the new default VFS for SQLite connections. If isDefault is not
832 ** true, then the jt VFS is installed as non-default. In this case it
833 ** is available via its name, "jt".
835 int jt_register(char *zWrap
, int isDefault
){
836 g
.pVfs
= sqlite3_vfs_find(zWrap
);
840 jt_vfs
.szOsFile
= sizeof(jt_file
) + g
.pVfs
->szOsFile
;
841 if( g
.pVfs
->iVersion
==1 ){
843 }else if( g
.pVfs
->xCurrentTimeInt64
==0 ){
844 jt_vfs
.xCurrentTimeInt64
= 0;
846 sqlite3_vfs_register(&jt_vfs
, isDefault
);
851 ** Uninstall the jt VFS, if it is installed.
853 void jt_unregister(void){
854 sqlite3_vfs_unregister(&jt_vfs
);