1: /*
2: ** 2008 Jan 22
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 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.
17: **
18: ** INTERFACE
19: **
20: ** The public interface to this wrapper VFS is two functions:
21: **
22: ** jt_register()
23: ** jt_unregister()
24: **
25: ** See header comments associated with those two functions below for
26: ** details.
27: **
28: ** LIMITATIONS
29: **
30: ** This wrapper will not work if "PRAGMA synchronous = off" is used.
31: **
32: ** OPERATION
33: **
34: ** Starting a Transaction:
35: **
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):
39: **
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.
44: **
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
47: ** file.
48: **
49: ** Syncing the Journal File:
50: **
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.
58: **
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.
64: **
65: ** Writing to the Database File:
66: **
67: ** When a block of data is written to a database file, the following
68: ** invariants are asserted:
69: **
70: ** a) That the block of data is an aligned block of page-size bytes.
71: **
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.
76: **
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.
81: **
82: ** Closing a Transaction:
83: **
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:
88: **
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.
91: **
92: ** b) A journal file is truncated to zero bytes in size using xTruncate.
93: **
94: ** c) The journal file is deleted using xDelete.
95: */
96: #if SQLITE_TEST /* This file is used for testing only */
97:
98: #include "sqlite3.h"
99: #include "sqliteInt.h"
100:
101: /*
102: ** Maximum pathname length supported by the jt backend.
103: */
104: #define JT_MAX_PATHNAME 512
105:
106: /*
107: ** Name used to identify this VFS.
108: */
109: #define JT_VFS_NAME "jt"
110:
111: typedef struct jt_file jt_file;
112: struct jt_file {
113: sqlite3_file base;
114: const char *zName; /* Name of open file */
115: int flags; /* Flags the file was opened with */
116:
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 */
124:
125: /* Only used by journal file-handles */
126: sqlite3_int64 iMaxOff; /* Maximum offset written to this transaction */
127:
128: jt_file *pNext; /* All files are stored in a linked list */
129: sqlite3_file *pReal; /* The file handle for the underlying vfs */
130: };
131:
132: /*
133: ** Method declarations for jt_file.
134: */
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*);
147:
148: /*
149: ** Method declarations for jt_vfs.
150: */
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:
164: static sqlite3_vfs jt_vfs = {
165: 2, /* iVersion */
166: sizeof(jt_file), /* szOsFile */
167: JT_MAX_PATHNAME, /* mxPathname */
168: 0, /* pNext */
169: JT_VFS_NAME, /* zName */
170: 0, /* pAppData */
171: jtOpen, /* xOpen */
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 */
184: };
185:
186: static sqlite3_io_methods jt_io_methods = {
187: 1, /* iVersion */
188: jtClose, /* xClose */
189: jtRead, /* xRead */
190: jtWrite, /* xWrite */
191: jtTruncate, /* xTruncate */
192: jtSync, /* xSync */
193: jtFileSize, /* xFileSize */
194: jtLock, /* xLock */
195: jtUnlock, /* xUnlock */
196: jtCheckReservedLock, /* xCheckReservedLock */
197: jtFileControl, /* xFileControl */
198: jtSectorSize, /* xSectorSize */
199: jtDeviceCharacteristics /* xDeviceCharacteristics */
200: };
201:
202: struct JtGlobal {
203: sqlite3_vfs *pVfs; /* Parent VFS */
204: jt_file *pList; /* List of all open files */
205: };
206: static struct JtGlobal g = {0, 0};
207:
208: /*
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.
211: */
212: static void enterJtMutex(void){
213: sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG));
214: }
215: static void leaveJtMutex(void){
216: sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG));
217: }
218:
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;
226: }
227: static void start_ioerr_simulation(int iSave, int iSave2){
228: sqlite3_io_error_pending = iSave;
229: sqlite3_io_error_hit = iSave2;
230: }
231:
232: /*
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.
236: */
237: static void closeTransaction(jt_file *p){
238: sqlite3BitvecDestroy(p->pWritable);
239: sqlite3_free(p->aCksum);
240: p->pWritable = 0;
241: p->aCksum = 0;
242: p->nSync = 0;
243: }
244:
245: /*
246: ** Close an jt-file.
247: */
248: static int jtClose(sqlite3_file *pFile){
249: jt_file **pp;
250: jt_file *p = (jt_file *)pFile;
251:
252: closeTransaction(p);
253: enterJtMutex();
254: if( p->zName ){
255: for(pp=&g.pList; *pp!=p; pp=&(*pp)->pNext);
256: *pp = p->pNext;
257: }
258: leaveJtMutex();
259: return sqlite3OsClose(p->pReal);
260: }
261:
262: /*
263: ** Read data from an jt-file.
264: */
265: static int jtRead(
266: sqlite3_file *pFile,
267: void *zBuf,
268: int iAmt,
269: sqlite_int64 iOfst
270: ){
271: jt_file *p = (jt_file *)pFile;
272: return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
273: }
274:
275: /*
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:
281: **
282: ** a) SQLITE_OPEN_MAIN_DB was specified when the file was opened.
283: **
284: ** b) The file-name specified when the file was opened matches
285: ** all but the final 8 characters of the journal file name.
286: **
287: ** c) There is currently a reserved lock on the file.
288: **/
289: static jt_file *locateDatabaseHandle(const char *zJournal){
290: jt_file *pMain = 0;
291: enterJtMutex();
292: for(pMain=g.pList; pMain; pMain=pMain->pNext){
293: int nName = strlen(zJournal) - strlen("-journal");
294: if( (pMain->flags&SQLITE_OPEN_MAIN_DB)
295: && (strlen(pMain->zName)==nName)
296: && 0==memcmp(pMain->zName, zJournal, nName)
297: && (pMain->eLock>=SQLITE_LOCK_RESERVED)
298: ){
299: break;
300: }
301: }
302: leaveJtMutex();
303: return pMain;
304: }
305:
306: /*
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.
310: */
311: static u32 decodeUint32(const unsigned char *z){
312: return (z[0]<<24) + (z[1]<<16) + (z[2]<<8) + z[3];
313: }
314:
315: /*
316: ** Calculate a checksum from the buffer of length n bytes pointed to
317: ** by parameter z.
318: */
319: static u32 genCksum(const unsigned char *z, int n){
320: int i;
321: u32 cksum = 0;
322: for(i=0; i<n; i++){
323: cksum = cksum + z[i] + (cksum<<3);
324: }
325: return cksum;
326: }
327:
328: /*
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.
333: **
334: ** SQLITE_OK is returned if the journal-header is successfully
335: ** decoded. Otherwise, SQLITE_ERROR.
336: */
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 */
343: ){
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]);
350: return SQLITE_OK;
351: }
352:
353: /*
354: ** This function is called when a new transaction is opened, just after
355: ** the first journal-header is written to the journal file.
356: */
357: static int openTransaction(jt_file *pMain, jt_file *pJournal){
358: unsigned char *aData;
359: sqlite3_file *p = pMain->pReal;
360: int rc = SQLITE_OK;
361:
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;
367:
368: if( !pMain->pWritable || !pMain->aCksum || !aData ){
369: rc = SQLITE_IOERR_NOMEM;
370: }else if( pMain->nPage>0 ){
371: u32 iTrunk;
372: int iSave;
373: int iSave2;
374:
375: stop_ioerr_simulation(&iSave, &iSave2);
376:
377: /* Read the database free-list. Add the page-number for each free-list
378: ** leaf to the jt_file.pWritable bitvec.
379: */
380: rc = sqlite3OsRead(p, aData, pMain->nPagesize, 0);
381: if( rc==SQLITE_OK ){
382: u32 nDbsize = decodeUint32(&aData[28]);
383: if( nDbsize>0 && memcmp(&aData[24], &aData[92], 4)==0 ){
384: u32 iPg;
385: for(iPg=nDbsize+1; iPg<=pMain->nPage; iPg++){
386: sqlite3BitvecSet(pMain->pWritable, iPg);
387: }
388: }
389: }
390: iTrunk = decodeUint32(&aData[32]);
391: while( rc==SQLITE_OK && iTrunk>0 ){
392: u32 nLeaf;
393: u32 iLeaf;
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);
400: }
401: iTrunk = decodeUint32(aData);
402: }
403:
404: /* Calculate and store a checksum for each page in the database file. */
405: if( rc==SQLITE_OK ){
406: int ii;
407: for(ii=0; rc==SQLITE_OK && ii<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;
413: }
414: }
415:
416: start_ioerr_simulation(iSave, iSave2);
417: }
418:
419: sqlite3_free(aData);
420: return rc;
421: }
422:
423: /*
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.
427: */
428: static int readJournalFile(jt_file *p, jt_file *pMain){
429: int rc = SQLITE_OK;
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;
435: int iSave;
436: int iSave2;
437:
438: aPage = sqlite3_malloc(pMain->nPagesize);
439: if( !aPage ){
440: return SQLITE_IOERR_NOMEM;
441: }
442:
443: stop_ioerr_simulation(&iSave, &iSave2);
444:
445: while( rc==SQLITE_OK && iOff<iSize ){
446: u32 nRec, nPage, nSector, nPagesize;
447: u32 ii;
448:
449: /* Read and decode the next journal-header from the journal file. */
450: rc = sqlite3OsRead(pReal, zBuf, 28, iOff);
451: if( rc!=SQLITE_OK
452: || decodeJournalHdr(zBuf, &nRec, &nPage, &nSector, &nPagesize)
453: ){
454: goto finish_rjf;
455: }
456: iOff += nSector;
457:
458: if( nRec==0 ){
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.
462: */
463: if( iSize>=(iOff+nSector) ){
464: rc = sqlite3OsRead(pReal, zBuf, 28, iOff);
465: if( rc!=SQLITE_OK || 0==decodeJournalHdr(zBuf, 0, 0, 0, 0) ){
466: continue;
467: }
468: }
469: nRec = (iSize-iOff) / (pMain->nPagesize+8);
470: }
471:
472: /* Read all the records that follow the journal-header just read. */
473: for(ii=0; rc==SQLITE_OK && ii<nRec && iOff<iSize; ii++){
474: u32 pgno;
475: rc = sqlite3OsRead(pReal, zBuf, 4, iOff);
476: if( rc==SQLITE_OK ){
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);
481: if( rc==SQLITE_OK ){
482: u32 cksum = genCksum(aPage, pMain->nPagesize);
483: assert( cksum==pMain->aCksum[pgno-1] );
484: }
485: }
486: sqlite3BitvecSet(pMain->pWritable, pgno);
487: }
488: iOff += (8 + pMain->nPagesize);
489: }
490: }
491:
492: iOff = ((iOff + (nSector-1)) / nSector) * nSector;
493: }
494:
495: finish_rjf:
496: start_ioerr_simulation(iSave, iSave2);
497: sqlite3_free(aPage);
498: if( rc==SQLITE_IOERR_SHORT_READ ){
499: rc = SQLITE_OK;
500: }
501: return rc;
502: }
503:
504: /*
505: ** Write data to an jt-file.
506: */
507: static int jtWrite(
508: sqlite3_file *pFile,
509: const void *zBuf,
510: int iAmt,
511: sqlite_int64 iOfst
512: ){
513: int rc;
514: jt_file *p = (jt_file *)pFile;
515: if( p->flags&SQLITE_OPEN_MAIN_JOURNAL ){
516: if( iOfst==0 ){
517: jt_file *pMain = locateDatabaseHandle(p->zName);
518: assert( pMain );
519:
520: if( iAmt==28 ){
521: /* Zeroing the first journal-file header. This is the end of a
522: ** transaction. */
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. */
527: u8 *z = (u8 *)zBuf;
528: pMain->nPage = decodeUint32(&z[16]);
529: pMain->nPagesize = decodeUint32(&z[24]);
530: if( SQLITE_OK!=(rc=openTransaction(pMain, p)) ){
531: return rc;
532: }
533: }
534: }
535: if( p->iMaxOff<(iOfst + iAmt) ){
536: p->iMaxOff = iOfst + iAmt;
537: }
538: }
539:
540: if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){
541: if( iAmt<p->nPagesize
542: && p->nPagesize%iAmt==0
543: && iOfst>=(PENDING_BYTE+512)
544: && iOfst+iAmt<=PENDING_BYTE+p->nPagesize
545: ){
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.
550: */
551: }else{
552: u32 pgno = 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) );
556: }
557: }
558:
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;
564: }
565: return rc;
566: }
567:
568: /*
569: ** Truncate an jt-file.
570: */
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);
577: }
578: if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){
579: u32 pgno;
580: u32 locking_page = (u32)(PENDING_BYTE/p->nPagesize+1);
581: for(pgno=size/p->nPagesize+1; pgno<=p->nPage; pgno++){
582: assert( pgno==locking_page || sqlite3BitvecTest(p->pWritable, pgno) );
583: }
584: }
585: return sqlite3OsTruncate(p->pReal, size);
586: }
587:
588: /*
589: ** Sync an jt-file.
590: */
591: static int jtSync(sqlite3_file *pFile, int flags){
592: jt_file *p = (jt_file *)pFile;
593:
594: if( p->flags&SQLITE_OPEN_MAIN_JOURNAL ){
595: int rc;
596: jt_file *pMain; /* The associated database file */
597:
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.
602: */
603: pMain = locateDatabaseHandle(p->zName);
604: assert(pMain);
605:
606: /* Set the bitvec values */
607: if( pMain->pWritable ){
608: pMain->nSync++;
609: rc = readJournalFile(p, pMain);
610: if( rc!=SQLITE_OK ){
611: return rc;
612: }
613: }
614: }
615:
616: return sqlite3OsSync(p->pReal, flags);
617: }
618:
619: /*
620: ** Return the current file-size of an jt-file.
621: */
622: static int jtFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
623: jt_file *p = (jt_file *)pFile;
624: return sqlite3OsFileSize(p->pReal, pSize);
625: }
626:
627: /*
628: ** Lock an jt-file.
629: */
630: static int jtLock(sqlite3_file *pFile, int eLock){
631: int rc;
632: jt_file *p = (jt_file *)pFile;
633: rc = sqlite3OsLock(p->pReal, eLock);
634: if( rc==SQLITE_OK && eLock>p->eLock ){
635: p->eLock = eLock;
636: }
637: return rc;
638: }
639:
640: /*
641: ** Unlock an jt-file.
642: */
643: static int jtUnlock(sqlite3_file *pFile, int eLock){
644: int rc;
645: jt_file *p = (jt_file *)pFile;
646: rc = sqlite3OsUnlock(p->pReal, eLock);
647: if( rc==SQLITE_OK && eLock<p->eLock ){
648: p->eLock = eLock;
649: }
650: return rc;
651: }
652:
653: /*
654: ** Check if another file-handle holds a RESERVED lock on an jt-file.
655: */
656: static int jtCheckReservedLock(sqlite3_file *pFile, int *pResOut){
657: jt_file *p = (jt_file *)pFile;
658: return sqlite3OsCheckReservedLock(p->pReal, pResOut);
659: }
660:
661: /*
662: ** File control method. For custom operations on an jt-file.
663: */
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);
667: }
668:
669: /*
670: ** Return the sector-size in bytes for an jt-file.
671: */
672: static int jtSectorSize(sqlite3_file *pFile){
673: jt_file *p = (jt_file *)pFile;
674: return sqlite3OsSectorSize(p->pReal);
675: }
676:
677: /*
678: ** Return the device characteristic flags supported by an jt-file.
679: */
680: static int jtDeviceCharacteristics(sqlite3_file *pFile){
681: jt_file *p = (jt_file *)pFile;
682: return sqlite3OsDeviceCharacteristics(p->pReal);
683: }
684:
685: /*
686: ** Open an jt file handle.
687: */
688: static int jtOpen(
689: sqlite3_vfs *pVfs,
690: const char *zName,
691: sqlite3_file *pFile,
692: int flags,
693: int *pOutFlags
694: ){
695: int rc;
696: jt_file *p = (jt_file *)pFile;
697: pFile->pMethods = 0;
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 );
702: if( rc==SQLITE_OK ){
703: pFile->pMethods = &jt_io_methods;
704: p->eLock = 0;
705: p->zName = zName;
706: p->flags = flags;
707: p->pNext = 0;
708: p->pWritable = 0;
709: p->aCksum = 0;
710: enterJtMutex();
711: if( zName ){
712: p->pNext = g.pList;
713: g.pList = p;
714: }
715: leaveJtMutex();
716: }
717: return rc;
718: }
719:
720: /*
721: ** Delete the file located at zPath. If the dirSync argument is true,
722: ** ensure the file-system modifications are synced to disk before
723: ** returning.
724: */
725: static int jtDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
726: int nPath = 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);
730: if( pMain ){
731: closeTransaction(pMain);
732: }
733: }
734:
735: return sqlite3OsDelete(g.pVfs, zPath, dirSync);
736: }
737:
738: /*
739: ** Test for access permissions. Return true if the requested permission
740: ** is available, or false otherwise.
741: */
742: static int jtAccess(
743: sqlite3_vfs *pVfs,
744: const char *zPath,
745: int flags,
746: int *pResOut
747: ){
748: return sqlite3OsAccess(g.pVfs, zPath, flags, pResOut);
749: }
750:
751: /*
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.
755: */
756: static int jtFullPathname(
757: sqlite3_vfs *pVfs,
758: const char *zPath,
759: int nOut,
760: char *zOut
761: ){
762: return sqlite3OsFullPathname(g.pVfs, zPath, nOut, zOut);
763: }
764:
765: /*
766: ** Open the dynamic library located at zPath and return a handle.
767: */
768: static void *jtDlOpen(sqlite3_vfs *pVfs, const char *zPath){
769: return g.pVfs->xDlOpen(g.pVfs, zPath);
770: }
771:
772: /*
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.
776: */
777: static void jtDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
778: g.pVfs->xDlError(g.pVfs, nByte, zErrMsg);
779: }
780:
781: /*
782: ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
783: */
784: static void (*jtDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
785: return g.pVfs->xDlSym(g.pVfs, p, zSym);
786: }
787:
788: /*
789: ** Close the dynamic library handle pHandle.
790: */
791: static void jtDlClose(sqlite3_vfs *pVfs, void *pHandle){
792: g.pVfs->xDlClose(g.pVfs, pHandle);
793: }
794:
795: /*
796: ** Populate the buffer pointed to by zBufOut with nByte bytes of
797: ** random data.
798: */
799: static int jtRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
800: return sqlite3OsRandomness(g.pVfs, nByte, zBufOut);
801: }
802:
803: /*
804: ** Sleep for nMicro microseconds. Return the number of microseconds
805: ** actually slept.
806: */
807: static int jtSleep(sqlite3_vfs *pVfs, int nMicro){
808: return sqlite3OsSleep(g.pVfs, nMicro);
809: }
810:
811: /*
812: ** Return the current time as a Julian Day number in *pTimeOut.
813: */
814: static int jtCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
815: return g.pVfs->xCurrentTime(g.pVfs, pTimeOut);
816: }
817: /*
818: ** Return the current time as a Julian Day number in *pTimeOut.
819: */
820: static int jtCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
821: return g.pVfs->xCurrentTimeInt64(g.pVfs, pTimeOut);
822: }
823:
824: /**************************************************************************
825: ** Start of public API.
826: */
827:
828: /*
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".
834: */
835: int jt_register(char *zWrap, int isDefault){
836: g.pVfs = sqlite3_vfs_find(zWrap);
837: if( g.pVfs==0 ){
838: return SQLITE_ERROR;
839: }
840: jt_vfs.szOsFile = sizeof(jt_file) + g.pVfs->szOsFile;
841: if( g.pVfs->iVersion==1 ){
842: jt_vfs.iVersion = 1;
843: }else if( g.pVfs->xCurrentTimeInt64==0 ){
844: jt_vfs.xCurrentTimeInt64 = 0;
845: }
846: sqlite3_vfs_register(&jt_vfs, isDefault);
847: return SQLITE_OK;
848: }
849:
850: /*
851: ** Uninstall the jt VFS, if it is installed.
852: */
853: void jt_unregister(void){
854: sqlite3_vfs_unregister(&jt_vfs);
855: }
856:
857: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>