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 *************************************************************************
15 ** This file contains some example code demonstrating how the SQLite
16 ** vfs feature can be used to have SQLite operate directly on an
17 ** embedded media, without using an intermediate file system.
19 ** Because this is only a demo designed to run on a workstation, the
20 ** underlying media is simulated using a regular file-system file. The
21 ** size of the file is fixed when it is first created (default size 10 MB).
22 ** From SQLite's point of view, this space is used to store a single
23 ** database file and the journal file.
25 ** Any statement journal created is stored in volatile memory obtained
26 ** from sqlite3_malloc(). Any attempt to create a temporary database file
27 ** will fail (SQLITE_IOERR). To prevent SQLite from attempting this,
28 ** it should be configured to store all temporary database files in
29 ** main memory (see pragma "temp_store" or the SQLITE_TEMP_STORE compile
34 ** After it has been created, the blob file is accessed using the
35 ** following three functions only:
37 ** mediaRead(); - Read a 512 byte block from the file.
38 ** mediaWrite(); - Write a 512 byte block to the file.
39 ** mediaSync(); - Tell the media hardware to sync.
41 ** It is assumed that these can be easily implemented by any "real"
42 ** media vfs driver adapting this code.
46 ** The basic principle is that the "database file" is stored at the
47 ** beginning of the 10 MB blob and grows in a forward direction. The
48 ** "journal file" is stored at the end of the 10MB blob and grows
49 ** in the reverse direction. If, during a transaction, insufficient
50 ** space is available to expand either the journal or database file,
51 ** an SQLITE_FULL error is returned. The database file is never allowed
52 ** to consume more than 90% of the blob space. If SQLite tries to
53 ** create a file larger than this, SQLITE_FULL is returned.
55 ** No allowance is made for "wear-leveling", as is required by.
56 ** embedded devices in the absence of equivalent hardware features.
58 ** The first 512 block byte of the file is reserved for storing the
59 ** size of the "database file". It is updated as part of the sync()
60 ** operation. On startup, it can only be trusted if no journal file
61 ** exists. If a journal-file does exist, then it stores the real size
62 ** of the database region. The second and subsequent blocks store the
63 ** actual database content.
65 ** The size of the "journal file" is not stored persistently in the
66 ** file. When the system is running, the size of the journal file is
67 ** stored in volatile memory. When recovering from a crash, this vfs
68 ** reports a very large size for the journal file. The normal journal
69 ** header and checksum mechanisms serve to prevent SQLite from
70 ** processing any data that lies past the logical end of the journal.
72 ** When SQLite calls OsDelete() to delete the journal file, the final
73 ** 512 bytes of the blob (the area containing the first journal header)
78 ** File locking is a no-op. Only one connection may be open at any one
79 ** time using this demo vfs.
87 ** Maximum pathname length supported by the fs backend.
90 #define BLOBSIZE 10485760
93 ** Name used to identify this VFS.
95 #define FS_VFS_NAME "fs"
97 typedef struct fs_real_file fs_real_file
;
101 int nDatabase
; /* Current size of database region */
102 int nJournal
; /* Current size of journal region */
103 int nBlob
; /* Total size of allocated blob */
104 int nRef
; /* Number of pointers to this structure */
106 fs_real_file
**ppThis
;
109 typedef struct fs_file fs_file
;
116 typedef struct tmp_file tmp_file
;
124 /* Values for fs_file.eType. */
125 #define DATABASE_FILE 1
126 #define JOURNAL_FILE 2
129 ** Method declarations for fs_file.
131 static int fsClose(sqlite3_file
*);
132 static int fsRead(sqlite3_file
*, void*, int iAmt
, sqlite3_int64 iOfst
);
133 static int fsWrite(sqlite3_file
*, const void*, int iAmt
, sqlite3_int64 iOfst
);
134 static int fsTruncate(sqlite3_file
*, sqlite3_int64 size
);
135 static int fsSync(sqlite3_file
*, int flags
);
136 static int fsFileSize(sqlite3_file
*, sqlite3_int64
*pSize
);
137 static int fsLock(sqlite3_file
*, int);
138 static int fsUnlock(sqlite3_file
*, int);
139 static int fsCheckReservedLock(sqlite3_file
*, int *pResOut
);
140 static int fsFileControl(sqlite3_file
*, int op
, void *pArg
);
141 static int fsSectorSize(sqlite3_file
*);
142 static int fsDeviceCharacteristics(sqlite3_file
*);
145 ** Method declarations for tmp_file.
147 static int tmpClose(sqlite3_file
*);
148 static int tmpRead(sqlite3_file
*, void*, int iAmt
, sqlite3_int64 iOfst
);
149 static int tmpWrite(sqlite3_file
*, const void*, int iAmt
, sqlite3_int64 iOfst
);
150 static int tmpTruncate(sqlite3_file
*, sqlite3_int64 size
);
151 static int tmpSync(sqlite3_file
*, int flags
);
152 static int tmpFileSize(sqlite3_file
*, sqlite3_int64
*pSize
);
153 static int tmpLock(sqlite3_file
*, int);
154 static int tmpUnlock(sqlite3_file
*, int);
155 static int tmpCheckReservedLock(sqlite3_file
*, int *pResOut
);
156 static int tmpFileControl(sqlite3_file
*, int op
, void *pArg
);
157 static int tmpSectorSize(sqlite3_file
*);
158 static int tmpDeviceCharacteristics(sqlite3_file
*);
161 ** Method declarations for fs_vfs.
163 static int fsOpen(sqlite3_vfs
*, const char *, sqlite3_file
*, int , int *);
164 static int fsDelete(sqlite3_vfs
*, const char *zName
, int syncDir
);
165 static int fsAccess(sqlite3_vfs
*, const char *zName
, int flags
, int *);
166 static int fsFullPathname(sqlite3_vfs
*, const char *zName
, int nOut
,char *zOut
);
167 static void *fsDlOpen(sqlite3_vfs
*, const char *zFilename
);
168 static void fsDlError(sqlite3_vfs
*, int nByte
, char *zErrMsg
);
169 static void (*fsDlSym(sqlite3_vfs
*,void*, const char *zSymbol
))(void);
170 static void fsDlClose(sqlite3_vfs
*, void*);
171 static int fsRandomness(sqlite3_vfs
*, int nByte
, char *zOut
);
172 static int fsSleep(sqlite3_vfs
*, int microseconds
);
173 static int fsCurrentTime(sqlite3_vfs
*, double*);
176 typedef struct fs_vfs_t fs_vfs_t
;
179 fs_real_file
*pFileList
;
180 sqlite3_vfs
*pParent
;
183 static fs_vfs_t fs_vfs
= {
189 FS_VFS_NAME
, /* zName */
192 fsDelete
, /* xDelete */
193 fsAccess
, /* xAccess */
194 fsFullPathname
, /* xFullPathname */
195 fsDlOpen
, /* xDlOpen */
196 fsDlError
, /* xDlError */
197 fsDlSym
, /* xDlSym */
198 fsDlClose
, /* xDlClose */
199 fsRandomness
, /* xRandomness */
200 fsSleep
, /* xSleep */
201 fsCurrentTime
, /* xCurrentTime */
202 0 /* xCurrentTimeInt64 */
208 static sqlite3_io_methods fs_io_methods
= {
210 fsClose
, /* xClose */
212 fsWrite
, /* xWrite */
213 fsTruncate
, /* xTruncate */
215 fsFileSize
, /* xFileSize */
217 fsUnlock
, /* xUnlock */
218 fsCheckReservedLock
, /* xCheckReservedLock */
219 fsFileControl
, /* xFileControl */
220 fsSectorSize
, /* xSectorSize */
221 fsDeviceCharacteristics
, /* xDeviceCharacteristics */
229 static sqlite3_io_methods tmp_io_methods
= {
231 tmpClose
, /* xClose */
233 tmpWrite
, /* xWrite */
234 tmpTruncate
, /* xTruncate */
236 tmpFileSize
, /* xFileSize */
238 tmpUnlock
, /* xUnlock */
239 tmpCheckReservedLock
, /* xCheckReservedLock */
240 tmpFileControl
, /* xFileControl */
241 tmpSectorSize
, /* xSectorSize */
242 tmpDeviceCharacteristics
, /* xDeviceCharacteristics */
249 /* Useful macros used in several places */
250 #define MIN(x,y) ((x)<(y)?(x):(y))
251 #define MAX(x,y) ((x)>(y)?(x):(y))
257 static int tmpClose(sqlite3_file
*pFile
){
258 tmp_file
*pTmp
= (tmp_file
*)pFile
;
259 sqlite3_free(pTmp
->zAlloc
);
264 ** Read data from a tmp-file.
272 tmp_file
*pTmp
= (tmp_file
*)pFile
;
273 if( (iAmt
+iOfst
)>pTmp
->nSize
){
274 return SQLITE_IOERR_SHORT_READ
;
276 memcpy(zBuf
, &pTmp
->zAlloc
[iOfst
], iAmt
);
281 ** Write data to a tmp-file.
289 tmp_file
*pTmp
= (tmp_file
*)pFile
;
290 if( (iAmt
+iOfst
)>pTmp
->nAlloc
){
291 int nNew
= (int)(2*(iAmt
+iOfst
+pTmp
->nAlloc
));
292 char *zNew
= sqlite3_realloc(pTmp
->zAlloc
, nNew
);
299 memcpy(&pTmp
->zAlloc
[iOfst
], zBuf
, iAmt
);
300 pTmp
->nSize
= (int)MAX(pTmp
->nSize
, iOfst
+iAmt
);
305 ** Truncate a tmp-file.
307 static int tmpTruncate(sqlite3_file
*pFile
, sqlite_int64 size
){
308 tmp_file
*pTmp
= (tmp_file
*)pFile
;
309 pTmp
->nSize
= (int)MIN(pTmp
->nSize
, size
);
316 static int tmpSync(sqlite3_file
*pFile
, int flags
){
321 ** Return the current file-size of a tmp-file.
323 static int tmpFileSize(sqlite3_file
*pFile
, sqlite_int64
*pSize
){
324 tmp_file
*pTmp
= (tmp_file
*)pFile
;
325 *pSize
= pTmp
->nSize
;
332 static int tmpLock(sqlite3_file
*pFile
, int eLock
){
337 ** Unlock a tmp-file.
339 static int tmpUnlock(sqlite3_file
*pFile
, int eLock
){
344 ** Check if another file-handle holds a RESERVED lock on a tmp-file.
346 static int tmpCheckReservedLock(sqlite3_file
*pFile
, int *pResOut
){
352 ** File control method. For custom operations on a tmp-file.
354 static int tmpFileControl(sqlite3_file
*pFile
, int op
, void *pArg
){
359 ** Return the sector-size in bytes for a tmp-file.
361 static int tmpSectorSize(sqlite3_file
*pFile
){
366 ** Return the device characteristic flags supported by a tmp-file.
368 static int tmpDeviceCharacteristics(sqlite3_file
*pFile
){
375 static int fsClose(sqlite3_file
*pFile
){
377 fs_file
*p
= (fs_file
*)pFile
;
378 fs_real_file
*pReal
= p
->pReal
;
380 /* Decrement the real_file ref-count. */
382 assert(pReal
->nRef
>=0);
384 /* When the ref-count reaches 0, destroy the structure */
385 if( pReal
->nRef
==0 ){
386 *pReal
->ppThis
= pReal
->pNext
;
388 pReal
->pNext
->ppThis
= pReal
->ppThis
;
390 rc
= pReal
->pFile
->pMethods
->xClose(pReal
->pFile
);
398 ** Read data from an fs-file.
407 fs_file
*p
= (fs_file
*)pFile
;
408 fs_real_file
*pReal
= p
->pReal
;
409 sqlite3_file
*pF
= pReal
->pFile
;
411 if( (p
->eType
==DATABASE_FILE
&& (iAmt
+iOfst
)>pReal
->nDatabase
)
412 || (p
->eType
==JOURNAL_FILE
&& (iAmt
+iOfst
)>pReal
->nJournal
)
414 rc
= SQLITE_IOERR_SHORT_READ
;
415 }else if( p
->eType
==DATABASE_FILE
){
416 rc
= pF
->pMethods
->xRead(pF
, zBuf
, iAmt
, iOfst
+BLOCKSIZE
);
422 while( iRem
>0 && rc
==SQLITE_OK
){
423 int iRealOff
= pReal
->nBlob
- BLOCKSIZE
*((ii
/BLOCKSIZE
)+1) + ii
%BLOCKSIZE
;
424 int iRealAmt
= MIN(iRem
, BLOCKSIZE
- (iRealOff
%BLOCKSIZE
));
426 rc
= pF
->pMethods
->xRead(pF
, &((char *)zBuf
)[iBuf
], iRealAmt
, iRealOff
);
437 ** Write data to an fs-file.
446 fs_file
*p
= (fs_file
*)pFile
;
447 fs_real_file
*pReal
= p
->pReal
;
448 sqlite3_file
*pF
= pReal
->pFile
;
450 if( p
->eType
==DATABASE_FILE
){
451 if( (iAmt
+iOfst
+BLOCKSIZE
)>(pReal
->nBlob
-pReal
->nJournal
) ){
454 rc
= pF
->pMethods
->xWrite(pF
, zBuf
, iAmt
, iOfst
+BLOCKSIZE
);
456 pReal
->nDatabase
= (int)MAX(pReal
->nDatabase
, iAmt
+iOfst
);
464 while( iRem
>0 && rc
==SQLITE_OK
){
465 int iRealOff
= pReal
->nBlob
- BLOCKSIZE
*((ii
/BLOCKSIZE
)+1) + ii
%BLOCKSIZE
;
466 int iRealAmt
= MIN(iRem
, BLOCKSIZE
- (iRealOff
%BLOCKSIZE
));
468 if( iRealOff
<(pReal
->nDatabase
+BLOCKSIZE
) ){
471 rc
= pF
->pMethods
->xWrite(pF
, &((char *)zBuf
)[iBuf
], iRealAmt
,iRealOff
);
478 pReal
->nJournal
= (int)MAX(pReal
->nJournal
, iAmt
+iOfst
);
486 ** Truncate an fs-file.
488 static int fsTruncate(sqlite3_file
*pFile
, sqlite_int64 size
){
489 fs_file
*p
= (fs_file
*)pFile
;
490 fs_real_file
*pReal
= p
->pReal
;
491 if( p
->eType
==DATABASE_FILE
){
492 pReal
->nDatabase
= (int)MIN(pReal
->nDatabase
, size
);
494 pReal
->nJournal
= (int)MIN(pReal
->nJournal
, size
);
502 static int fsSync(sqlite3_file
*pFile
, int flags
){
503 fs_file
*p
= (fs_file
*)pFile
;
504 fs_real_file
*pReal
= p
->pReal
;
505 sqlite3_file
*pRealFile
= pReal
->pFile
;
508 if( p
->eType
==DATABASE_FILE
){
509 unsigned char zSize
[4];
510 zSize
[0] = (pReal
->nDatabase
&0xFF000000)>>24;
511 zSize
[1] = (unsigned char)((pReal
->nDatabase
&0x00FF0000)>>16);
512 zSize
[2] = (pReal
->nDatabase
&0x0000FF00)>>8;
513 zSize
[3] = (pReal
->nDatabase
&0x000000FF);
514 rc
= pRealFile
->pMethods
->xWrite(pRealFile
, zSize
, 4, 0);
517 rc
= pRealFile
->pMethods
->xSync(pRealFile
, flags
&(~SQLITE_SYNC_DATAONLY
));
524 ** Return the current file-size of an fs-file.
526 static int fsFileSize(sqlite3_file
*pFile
, sqlite_int64
*pSize
){
527 fs_file
*p
= (fs_file
*)pFile
;
528 fs_real_file
*pReal
= p
->pReal
;
529 if( p
->eType
==DATABASE_FILE
){
530 *pSize
= pReal
->nDatabase
;
532 *pSize
= pReal
->nJournal
;
540 static int fsLock(sqlite3_file
*pFile
, int eLock
){
545 ** Unlock an fs-file.
547 static int fsUnlock(sqlite3_file
*pFile
, int eLock
){
552 ** Check if another file-handle holds a RESERVED lock on an fs-file.
554 static int fsCheckReservedLock(sqlite3_file
*pFile
, int *pResOut
){
560 ** File control method. For custom operations on an fs-file.
562 static int fsFileControl(sqlite3_file
*pFile
, int op
, void *pArg
){
563 if( op
==SQLITE_FCNTL_PRAGMA
) return SQLITE_NOTFOUND
;
568 ** Return the sector-size in bytes for an fs-file.
570 static int fsSectorSize(sqlite3_file
*pFile
){
575 ** Return the device characteristic flags supported by an fs-file.
577 static int fsDeviceCharacteristics(sqlite3_file
*pFile
){
582 ** Open an fs file handle.
591 fs_vfs_t
*pFsVfs
= (fs_vfs_t
*)pVfs
;
592 fs_file
*p
= (fs_file
*)pFile
;
593 fs_real_file
*pReal
= 0;
598 if( 0==(flags
&(SQLITE_OPEN_MAIN_DB
|SQLITE_OPEN_MAIN_JOURNAL
)) ){
599 tmp_file
*p2
= (tmp_file
*)pFile
;
600 memset(p2
, 0, sizeof(*p2
));
601 p2
->base
.pMethods
= &tmp_io_methods
;
605 eType
= ((flags
&(SQLITE_OPEN_MAIN_DB
))?DATABASE_FILE
:JOURNAL_FILE
);
606 p
->base
.pMethods
= &fs_io_methods
;
609 assert(strlen("-journal")==8);
610 nName
= (int)strlen(zName
)-((eType
==JOURNAL_FILE
)?8:0);
611 pReal
=pFsVfs
->pFileList
;
612 for(; pReal
&& strncmp(pReal
->zName
, zName
, nName
); pReal
=pReal
->pNext
);
615 int real_flags
= (flags
&~(SQLITE_OPEN_MAIN_DB
))|SQLITE_OPEN_TEMP_DB
;
617 sqlite3_file
*pRealFile
;
618 sqlite3_vfs
*pParent
= pFsVfs
->pParent
;
619 assert(eType
==DATABASE_FILE
);
621 pReal
= (fs_real_file
*)sqlite3_malloc(sizeof(*pReal
)+pParent
->szOsFile
);
626 memset(pReal
, 0, sizeof(*pReal
)+pParent
->szOsFile
);
627 pReal
->zName
= zName
;
628 pReal
->pFile
= (sqlite3_file
*)(&pReal
[1]);
630 rc
= pParent
->xOpen(pParent
, zName
, pReal
->pFile
, real_flags
, pOutFlags
);
634 pRealFile
= pReal
->pFile
;
636 rc
= pRealFile
->pMethods
->xFileSize(pRealFile
, &size
);
641 rc
= pRealFile
->pMethods
->xWrite(pRealFile
, "\0", 1, BLOBSIZE
-1);
642 pReal
->nBlob
= BLOBSIZE
;
645 pReal
->nBlob
= (int)size
;
646 rc
= pRealFile
->pMethods
->xRead(pRealFile
, zS
, 4, 0);
647 pReal
->nDatabase
= (zS
[0]<<24)+(zS
[1]<<16)+(zS
[2]<<8)+zS
[3];
649 rc
= pRealFile
->pMethods
->xRead(pRealFile
, zS
, 4, pReal
->nBlob
-4);
650 if( zS
[0] || zS
[1] || zS
[2] || zS
[3] ){
651 pReal
->nJournal
= pReal
->nBlob
;
657 pReal
->pNext
= pFsVfs
->pFileList
;
659 pReal
->pNext
->ppThis
= &pReal
->pNext
;
661 pReal
->ppThis
= &pFsVfs
->pFileList
;
662 pFsVfs
->pFileList
= pReal
;
672 if( pReal
->pFile
->pMethods
){
673 pReal
->pFile
->pMethods
->xClose(pReal
->pFile
);
682 ** Delete the file located at zPath. If the dirSync argument is true,
683 ** ensure the file-system modifications are synced to disk before
686 static int fsDelete(sqlite3_vfs
*pVfs
, const char *zPath
, int dirSync
){
688 fs_vfs_t
*pFsVfs
= (fs_vfs_t
*)pVfs
;
691 int nName
= (int)strlen(zPath
) - 8;
693 assert(strlen("-journal")==8);
694 assert(strcmp("-journal", &zPath
[nName
])==0);
696 pReal
= pFsVfs
->pFileList
;
697 for(; pReal
&& strncmp(pReal
->zName
, zPath
, nName
); pReal
=pReal
->pNext
);
700 rc
= pF
->pMethods
->xWrite(pF
, "\0\0\0\0", 4, pReal
->nBlob
-BLOCKSIZE
);
709 ** Test for access permissions. Return true if the requested permission
710 ** is available, or false otherwise.
718 fs_vfs_t
*pFsVfs
= (fs_vfs_t
*)pVfs
;
721 int nName
= (int)strlen(zPath
);
723 if( flags
!=SQLITE_ACCESS_EXISTS
){
724 sqlite3_vfs
*pParent
= ((fs_vfs_t
*)pVfs
)->pParent
;
725 return pParent
->xAccess(pParent
, zPath
, flags
, pResOut
);
728 assert(strlen("-journal")==8);
729 if( nName
>8 && strcmp("-journal", &zPath
[nName
-8])==0 ){
734 pReal
= pFsVfs
->pFileList
;
735 for(; pReal
&& strncmp(pReal
->zName
, zPath
, nName
); pReal
=pReal
->pNext
);
737 *pResOut
= (pReal
&& (!isJournal
|| pReal
->nJournal
>0));
742 ** Populate buffer zOut with the full canonical pathname corresponding
743 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
744 ** of at least (FS_MAX_PATHNAME+1) bytes.
746 static int fsFullPathname(
747 sqlite3_vfs
*pVfs
, /* Pointer to vfs object */
748 const char *zPath
, /* Possibly relative input path */
749 int nOut
, /* Size of output buffer in bytes */
750 char *zOut
/* Output buffer */
752 sqlite3_vfs
*pParent
= ((fs_vfs_t
*)pVfs
)->pParent
;
753 return pParent
->xFullPathname(pParent
, zPath
, nOut
, zOut
);
757 ** Open the dynamic library located at zPath and return a handle.
759 static void *fsDlOpen(sqlite3_vfs
*pVfs
, const char *zPath
){
760 sqlite3_vfs
*pParent
= ((fs_vfs_t
*)pVfs
)->pParent
;
761 return pParent
->xDlOpen(pParent
, zPath
);
765 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
766 ** utf-8 string describing the most recent error encountered associated
767 ** with dynamic libraries.
769 static void fsDlError(sqlite3_vfs
*pVfs
, int nByte
, char *zErrMsg
){
770 sqlite3_vfs
*pParent
= ((fs_vfs_t
*)pVfs
)->pParent
;
771 pParent
->xDlError(pParent
, nByte
, zErrMsg
);
775 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
777 static void (*fsDlSym(sqlite3_vfs
*pVfs
, void *pH
, const char *zSym
))(void){
778 sqlite3_vfs
*pParent
= ((fs_vfs_t
*)pVfs
)->pParent
;
779 return pParent
->xDlSym(pParent
, pH
, zSym
);
783 ** Close the dynamic library handle pHandle.
785 static void fsDlClose(sqlite3_vfs
*pVfs
, void *pHandle
){
786 sqlite3_vfs
*pParent
= ((fs_vfs_t
*)pVfs
)->pParent
;
787 pParent
->xDlClose(pParent
, pHandle
);
791 ** Populate the buffer pointed to by zBufOut with nByte bytes of
794 static int fsRandomness(sqlite3_vfs
*pVfs
, int nByte
, char *zBufOut
){
795 sqlite3_vfs
*pParent
= ((fs_vfs_t
*)pVfs
)->pParent
;
796 return pParent
->xRandomness(pParent
, nByte
, zBufOut
);
800 ** Sleep for nMicro microseconds. Return the number of microseconds
803 static int fsSleep(sqlite3_vfs
*pVfs
, int nMicro
){
804 sqlite3_vfs
*pParent
= ((fs_vfs_t
*)pVfs
)->pParent
;
805 return pParent
->xSleep(pParent
, nMicro
);
809 ** Return the current time as a Julian Day number in *pTimeOut.
811 static int fsCurrentTime(sqlite3_vfs
*pVfs
, double *pTimeOut
){
812 sqlite3_vfs
*pParent
= ((fs_vfs_t
*)pVfs
)->pParent
;
813 return pParent
->xCurrentTime(pParent
, pTimeOut
);
817 ** This procedure registers the fs vfs with SQLite. If the argument is
818 ** true, the fs vfs becomes the new default vfs. It is the only publicly
819 ** available function in this file.
821 int fs_register(void){
822 if( fs_vfs
.pParent
) return SQLITE_OK
;
823 fs_vfs
.pParent
= sqlite3_vfs_find(0);
824 fs_vfs
.base
.mxPathname
= fs_vfs
.pParent
->mxPathname
;
825 fs_vfs
.base
.szOsFile
= MAX(sizeof(tmp_file
), sizeof(fs_file
));
826 return sqlite3_vfs_register(&fs_vfs
.base
, 0);
830 int SqlitetestOnefile_Init() {return fs_register();}