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 implements a VFS shim that allows an SQLite database to be
14 ** appended onto the end of some other file, such as an executable.
16 ** A special record must appear at the end of the file that identifies the
17 ** file as an appended database and provides the offset to the first page
18 ** of the exposed content. (Or, it is the length of the content prefix.)
19 ** For best performance page 1 should be located at a disk page boundary,
20 ** though that is not required.
22 ** When opening a database using this VFS, the connection might treat
23 ** the file as an ordinary SQLite database, or it might treat it as a
24 ** database appended onto some other file. The decision is made by
25 ** applying the following rules in order:
27 ** (1) An empty file is an ordinary database.
29 ** (2) If the file ends with the appendvfs trailer string
30 ** "Start-Of-SQLite3-NNNNNNNN" that file is an appended database.
32 ** (3) If the file begins with the standard SQLite prefix string
33 ** "SQLite format 3", that file is an ordinary database.
35 ** (4) If none of the above apply and the SQLITE_OPEN_CREATE flag is
36 ** set, then a new database is appended to the already existing file.
38 ** (5) Otherwise, SQLITE_CANTOPEN is returned.
40 ** To avoid unnecessary complications with the PENDING_BYTE, the size of
41 ** the file containing the database is limited to 1GiB. (1073741824 bytes)
42 ** This VFS will not read or write past the 1GiB mark. This restriction
43 ** might be lifted in future versions. For now, if you need a larger
44 ** database, then keep it in a separate file.
46 ** If the file being opened is a plain database (not an appended one), then
47 ** this shim is a pass-through into the default underlying VFS. (rule 3)
49 #include "sqlite3ext.h"
50 SQLITE_EXTENSION_INIT1
54 /* The append mark at the end of the database is:
56 ** Start-Of-SQLite3-NNNNNNNN
57 ** 123456789 123456789 12345
59 ** The NNNNNNNN represents a 64-bit big-endian unsigned integer which is
60 ** the offset to page 1, and also the length of the prefix content.
62 #define APND_MARK_PREFIX "Start-Of-SQLite3-"
63 #define APND_MARK_PREFIX_SZ 17
64 #define APND_MARK_FOS_SZ 8
65 #define APND_MARK_SIZE (APND_MARK_PREFIX_SZ+APND_MARK_FOS_SZ)
68 ** Maximum size of the combined prefix + database + append-mark. This
69 ** must be less than 0x40000000 to avoid locking issues on Windows.
71 #define APND_MAX_SIZE (0x40000000)
74 ** Try to align the database to an even multiple of APND_ROUNDUP bytes.
77 #define APND_ROUNDUP 4096
79 #define APND_ALIGN_MASK ((sqlite3_int64)(APND_ROUNDUP-1))
80 #define APND_START_ROUNDUP(fsz) (((fsz)+APND_ALIGN_MASK) & ~APND_ALIGN_MASK)
83 ** Forward declaration of objects used by this utility
85 typedef struct sqlite3_vfs ApndVfs
;
86 typedef struct ApndFile ApndFile
;
88 /* Access to a lower-level VFS that (might) implement dynamic loading,
89 ** access to randomness, etc.
91 #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
92 #define ORIGFILE(p) ((sqlite3_file*)(((ApndFile*)(p))+1))
94 /* An open appendvfs file
96 ** An instance of this structure describes the appended database file.
97 ** A separate sqlite3_file object is always appended. The appended
98 ** sqlite3_file object (which can be accessed using ORIGFILE()) describes
99 ** the entire file, including the prefix, the database, and the
102 ** The structure of an AppendVFS database is like this:
104 ** +-------------+---------+----------+-------------+
105 ** | prefix-file | padding | database | append-mark |
106 ** +-------------+---------+----------+-------------+
112 ** "prefix file" - file onto which the database has been appended.
113 ** "padding" - zero or more bytes inserted so that "database"
114 ** starts on an APND_ROUNDUP boundary
115 ** "database" - The SQLite database file
116 ** "append-mark" - The 25-byte "Start-Of-SQLite3-NNNNNNNN" that indicates
117 ** the offset from the start of prefix-file to the start
120 ** The size of the database is iMark - iPgOne.
122 ** The NNNNNNNN in the "Start-Of-SQLite3-NNNNNNNN" suffix is the value
123 ** of iPgOne stored as a big-ending 64-bit integer.
125 ** iMark will be the size of the underlying file minus 25 (APND_MARKSIZE).
126 ** Or, iMark is -1 to indicate that it has not yet been written.
129 sqlite3_file base
; /* Subclass. MUST BE FIRST! */
130 sqlite3_int64 iPgOne
; /* Offset to the start of the database */
131 sqlite3_int64 iMark
; /* Offset of the append mark. -1 if unwritten */
132 /* Always followed by another sqlite3_file that describes the whole file */
136 ** Methods for ApndFile
138 static int apndClose(sqlite3_file
*);
139 static int apndRead(sqlite3_file
*, void*, int iAmt
, sqlite3_int64 iOfst
);
140 static int apndWrite(sqlite3_file
*,const void*,int iAmt
, sqlite3_int64 iOfst
);
141 static int apndTruncate(sqlite3_file
*, sqlite3_int64 size
);
142 static int apndSync(sqlite3_file
*, int flags
);
143 static int apndFileSize(sqlite3_file
*, sqlite3_int64
*pSize
);
144 static int apndLock(sqlite3_file
*, int);
145 static int apndUnlock(sqlite3_file
*, int);
146 static int apndCheckReservedLock(sqlite3_file
*, int *pResOut
);
147 static int apndFileControl(sqlite3_file
*, int op
, void *pArg
);
148 static int apndSectorSize(sqlite3_file
*);
149 static int apndDeviceCharacteristics(sqlite3_file
*);
150 static int apndShmMap(sqlite3_file
*, int iPg
, int pgsz
, int, void volatile**);
151 static int apndShmLock(sqlite3_file
*, int offset
, int n
, int flags
);
152 static void apndShmBarrier(sqlite3_file
*);
153 static int apndShmUnmap(sqlite3_file
*, int deleteFlag
);
154 static int apndFetch(sqlite3_file
*, sqlite3_int64 iOfst
, int iAmt
, void **pp
);
155 static int apndUnfetch(sqlite3_file
*, sqlite3_int64 iOfst
, void *p
);
158 ** Methods for ApndVfs
160 static int apndOpen(sqlite3_vfs
*, const char *, sqlite3_file
*, int , int *);
161 static int apndDelete(sqlite3_vfs
*, const char *zName
, int syncDir
);
162 static int apndAccess(sqlite3_vfs
*, const char *zName
, int flags
, int *);
163 static int apndFullPathname(sqlite3_vfs
*, const char *zName
, int, char *zOut
);
164 static void *apndDlOpen(sqlite3_vfs
*, const char *zFilename
);
165 static void apndDlError(sqlite3_vfs
*, int nByte
, char *zErrMsg
);
166 static void (*apndDlSym(sqlite3_vfs
*pVfs
, void *p
, const char*zSym
))(void);
167 static void apndDlClose(sqlite3_vfs
*, void*);
168 static int apndRandomness(sqlite3_vfs
*, int nByte
, char *zOut
);
169 static int apndSleep(sqlite3_vfs
*, int microseconds
);
170 static int apndCurrentTime(sqlite3_vfs
*, double*);
171 static int apndGetLastError(sqlite3_vfs
*, int, char *);
172 static int apndCurrentTimeInt64(sqlite3_vfs
*, sqlite3_int64
*);
173 static int apndSetSystemCall(sqlite3_vfs
*, const char*,sqlite3_syscall_ptr
);
174 static sqlite3_syscall_ptr
apndGetSystemCall(sqlite3_vfs
*, const char *z
);
175 static const char *apndNextSystemCall(sqlite3_vfs
*, const char *zName
);
177 static sqlite3_vfs apnd_vfs
= {
178 3, /* iVersion (set when registered) */
179 0, /* szOsFile (set when registered) */
180 1024, /* mxPathname */
182 "apndvfs", /* zName */
183 0, /* pAppData (set when registered) */
184 apndOpen
, /* xOpen */
185 apndDelete
, /* xDelete */
186 apndAccess
, /* xAccess */
187 apndFullPathname
, /* xFullPathname */
188 apndDlOpen
, /* xDlOpen */
189 apndDlError
, /* xDlError */
190 apndDlSym
, /* xDlSym */
191 apndDlClose
, /* xDlClose */
192 apndRandomness
, /* xRandomness */
193 apndSleep
, /* xSleep */
194 apndCurrentTime
, /* xCurrentTime */
195 apndGetLastError
, /* xGetLastError */
196 apndCurrentTimeInt64
, /* xCurrentTimeInt64 */
197 apndSetSystemCall
, /* xSetSystemCall */
198 apndGetSystemCall
, /* xGetSystemCall */
199 apndNextSystemCall
/* xNextSystemCall */
202 static const sqlite3_io_methods apnd_io_methods
= {
204 apndClose
, /* xClose */
205 apndRead
, /* xRead */
206 apndWrite
, /* xWrite */
207 apndTruncate
, /* xTruncate */
208 apndSync
, /* xSync */
209 apndFileSize
, /* xFileSize */
210 apndLock
, /* xLock */
211 apndUnlock
, /* xUnlock */
212 apndCheckReservedLock
, /* xCheckReservedLock */
213 apndFileControl
, /* xFileControl */
214 apndSectorSize
, /* xSectorSize */
215 apndDeviceCharacteristics
, /* xDeviceCharacteristics */
216 apndShmMap
, /* xShmMap */
217 apndShmLock
, /* xShmLock */
218 apndShmBarrier
, /* xShmBarrier */
219 apndShmUnmap
, /* xShmUnmap */
220 apndFetch
, /* xFetch */
221 apndUnfetch
/* xUnfetch */
225 ** Close an apnd-file.
227 static int apndClose(sqlite3_file
*pFile
){
228 pFile
= ORIGFILE(pFile
);
229 return pFile
->pMethods
->xClose(pFile
);
233 ** Read data from an apnd-file.
241 ApndFile
*paf
= (ApndFile
*)pFile
;
242 pFile
= ORIGFILE(pFile
);
243 return pFile
->pMethods
->xRead(pFile
, zBuf
, iAmt
, paf
->iPgOne
+iOfst
);
247 ** Add the append-mark onto what should become the end of the file.
248 * If and only if this succeeds, internal ApndFile.iMark is updated.
249 * Parameter iWriteEnd is the appendvfs-relative offset of the new mark.
251 static int apndWriteMark(
254 sqlite_int64 iWriteEnd
256 sqlite_int64 iPgOne
= paf
->iPgOne
;
257 unsigned char a
[APND_MARK_SIZE
];
258 int i
= APND_MARK_FOS_SZ
;
260 assert(pFile
== ORIGFILE(paf
));
261 memcpy(a
, APND_MARK_PREFIX
, APND_MARK_PREFIX_SZ
);
263 a
[APND_MARK_PREFIX_SZ
+i
] = (unsigned char)(iPgOne
& 0xff);
266 iWriteEnd
+= paf
->iPgOne
;
267 if( SQLITE_OK
==(rc
= pFile
->pMethods
->xWrite
268 (pFile
, a
, APND_MARK_SIZE
, iWriteEnd
)) ){
269 paf
->iMark
= iWriteEnd
;
275 ** Write data to an apnd-file.
277 static int apndWrite(
283 ApndFile
*paf
= (ApndFile
*)pFile
;
284 sqlite_int64 iWriteEnd
= iOfst
+ iAmt
;
285 if( iWriteEnd
>=APND_MAX_SIZE
) return SQLITE_FULL
;
286 pFile
= ORIGFILE(pFile
);
287 /* If append-mark is absent or will be overwritten, write it. */
288 if( paf
->iMark
< 0 || paf
->iPgOne
+ iWriteEnd
> paf
->iMark
){
289 int rc
= apndWriteMark(paf
, pFile
, iWriteEnd
);
290 if( SQLITE_OK
!=rc
) return rc
;
292 return pFile
->pMethods
->xWrite(pFile
, zBuf
, iAmt
, paf
->iPgOne
+iOfst
);
296 ** Truncate an apnd-file.
298 static int apndTruncate(sqlite3_file
*pFile
, sqlite_int64 size
){
299 ApndFile
*paf
= (ApndFile
*)pFile
;
300 pFile
= ORIGFILE(pFile
);
301 /* The append mark goes out first so truncate failure does not lose it. */
302 if( SQLITE_OK
!=apndWriteMark(paf
, pFile
, size
) ) return SQLITE_IOERR
;
303 /* Truncate underlying file just past append mark */
304 return pFile
->pMethods
->xTruncate(pFile
, paf
->iMark
+APND_MARK_SIZE
);
308 ** Sync an apnd-file.
310 static int apndSync(sqlite3_file
*pFile
, int flags
){
311 pFile
= ORIGFILE(pFile
);
312 return pFile
->pMethods
->xSync(pFile
, flags
);
316 ** Return the current file-size of an apnd-file.
317 ** If the append mark is not yet there, the file-size is 0.
319 static int apndFileSize(sqlite3_file
*pFile
, sqlite_int64
*pSize
){
320 ApndFile
*paf
= (ApndFile
*)pFile
;
321 *pSize
= ( paf
->iMark
>= 0 )? (paf
->iMark
- paf
->iPgOne
) : 0;
326 ** Lock an apnd-file.
328 static int apndLock(sqlite3_file
*pFile
, int eLock
){
329 pFile
= ORIGFILE(pFile
);
330 return pFile
->pMethods
->xLock(pFile
, eLock
);
334 ** Unlock an apnd-file.
336 static int apndUnlock(sqlite3_file
*pFile
, int eLock
){
337 pFile
= ORIGFILE(pFile
);
338 return pFile
->pMethods
->xUnlock(pFile
, eLock
);
342 ** Check if another file-handle holds a RESERVED lock on an apnd-file.
344 static int apndCheckReservedLock(sqlite3_file
*pFile
, int *pResOut
){
345 pFile
= ORIGFILE(pFile
);
346 return pFile
->pMethods
->xCheckReservedLock(pFile
, pResOut
);
350 ** File control method. For custom operations on an apnd-file.
352 static int apndFileControl(sqlite3_file
*pFile
, int op
, void *pArg
){
353 ApndFile
*paf
= (ApndFile
*)pFile
;
355 pFile
= ORIGFILE(pFile
);
356 if( op
==SQLITE_FCNTL_SIZE_HINT
) *(sqlite3_int64
*)pArg
+= paf
->iPgOne
;
357 rc
= pFile
->pMethods
->xFileControl(pFile
, op
, pArg
);
358 if( rc
==SQLITE_OK
&& op
==SQLITE_FCNTL_VFSNAME
){
359 *(char**)pArg
= sqlite3_mprintf("apnd(%lld)/%z", paf
->iPgOne
,*(char**)pArg
);
365 ** Return the sector-size in bytes for an apnd-file.
367 static int apndSectorSize(sqlite3_file
*pFile
){
368 pFile
= ORIGFILE(pFile
);
369 return pFile
->pMethods
->xSectorSize(pFile
);
373 ** Return the device characteristic flags supported by an apnd-file.
375 static int apndDeviceCharacteristics(sqlite3_file
*pFile
){
376 pFile
= ORIGFILE(pFile
);
377 return pFile
->pMethods
->xDeviceCharacteristics(pFile
);
380 /* Create a shared memory file mapping */
381 static int apndShmMap(
388 pFile
= ORIGFILE(pFile
);
389 return pFile
->pMethods
->xShmMap(pFile
,iPg
,pgsz
,bExtend
,pp
);
392 /* Perform locking on a shared-memory segment */
393 static int apndShmLock(sqlite3_file
*pFile
, int offset
, int n
, int flags
){
394 pFile
= ORIGFILE(pFile
);
395 return pFile
->pMethods
->xShmLock(pFile
,offset
,n
,flags
);
398 /* Memory barrier operation on shared memory */
399 static void apndShmBarrier(sqlite3_file
*pFile
){
400 pFile
= ORIGFILE(pFile
);
401 pFile
->pMethods
->xShmBarrier(pFile
);
404 /* Unmap a shared memory segment */
405 static int apndShmUnmap(sqlite3_file
*pFile
, int deleteFlag
){
406 pFile
= ORIGFILE(pFile
);
407 return pFile
->pMethods
->xShmUnmap(pFile
,deleteFlag
);
410 /* Fetch a page of a memory-mapped file */
411 static int apndFetch(
417 ApndFile
*p
= (ApndFile
*)pFile
;
418 if( p
->iMark
< 0 || iOfst
+iAmt
> p
->iMark
){
419 return SQLITE_IOERR
; /* Cannot read what is not yet there. */
421 pFile
= ORIGFILE(pFile
);
422 return pFile
->pMethods
->xFetch(pFile
, iOfst
+p
->iPgOne
, iAmt
, pp
);
425 /* Release a memory-mapped page */
426 static int apndUnfetch(sqlite3_file
*pFile
, sqlite3_int64 iOfst
, void *pPage
){
427 ApndFile
*p
= (ApndFile
*)pFile
;
428 pFile
= ORIGFILE(pFile
);
429 return pFile
->pMethods
->xUnfetch(pFile
, iOfst
+p
->iPgOne
, pPage
);
433 ** Try to read the append-mark off the end of a file. Return the
434 ** start of the appended database if the append-mark is present.
435 ** If there is no valid append-mark, return -1;
437 ** An append-mark is only valid if the NNNNNNNN start-of-database offset
438 ** indicates that the appended database contains at least one page. The
439 ** start-of-database value must be a multiple of 512.
441 static sqlite3_int64
apndReadMark(sqlite3_int64 sz
, sqlite3_file
*pFile
){
444 int msbs
= 8 * (APND_MARK_FOS_SZ
-1);
445 unsigned char a
[APND_MARK_SIZE
];
447 if( APND_MARK_SIZE
!=(sz
& 0x1ff) ) return -1;
448 rc
= pFile
->pMethods
->xRead(pFile
, a
, APND_MARK_SIZE
, sz
-APND_MARK_SIZE
);
450 if( memcmp(a
, APND_MARK_PREFIX
, APND_MARK_PREFIX_SZ
)!=0 ) return -1;
451 iMark
= ((sqlite3_int64
)(a
[APND_MARK_PREFIX_SZ
] & 0x7f)) << msbs
;
454 iMark
|= (sqlite3_int64
)a
[APND_MARK_PREFIX_SZ
+i
]<<msbs
;
456 if( iMark
> (sz
- APND_MARK_SIZE
- 512) ) return -1;
457 if( iMark
& 0x1ff ) return -1;
461 static const char apvfsSqliteHdr
[] = "SQLite format 3";
463 ** Check to see if the file is an appendvfs SQLite database file.
464 ** Return true iff it is such. Parameter sz is the file's size.
466 static int apndIsAppendvfsDatabase(sqlite3_int64 sz
, sqlite3_file
*pFile
){
469 sqlite3_int64 iMark
= apndReadMark(sz
, pFile
);
471 /* If file has the correct end-marker, the expected odd size, and the
472 ** SQLite DB type marker where the end-marker puts it, then it
473 ** is an appendvfs database.
475 rc
= pFile
->pMethods
->xRead(pFile
, zHdr
, sizeof(zHdr
), iMark
);
477 && memcmp(zHdr
, apvfsSqliteHdr
, sizeof(zHdr
))==0
478 && (sz
& 0x1ff) == APND_MARK_SIZE
479 && sz
>=512+APND_MARK_SIZE
481 return 1; /* It's an appendvfs database */
488 ** Check to see if the file is an ordinary SQLite database file.
489 ** Return true iff so. Parameter sz is the file's size.
491 static int apndIsOrdinaryDatabaseFile(sqlite3_int64 sz
, sqlite3_file
*pFile
){
493 if( apndIsAppendvfsDatabase(sz
, pFile
) /* rule 2 */
495 || SQLITE_OK
!=pFile
->pMethods
->xRead(pFile
, zHdr
, sizeof(zHdr
), 0)
496 || memcmp(zHdr
, apvfsSqliteHdr
, sizeof(zHdr
))!=0
505 ** Open an apnd file handle.
508 sqlite3_vfs
*pApndVfs
,
514 ApndFile
*pApndFile
= (ApndFile
*)pFile
;
515 sqlite3_file
*pBaseFile
= ORIGFILE(pFile
);
516 sqlite3_vfs
*pBaseVfs
= ORIGVFS(pApndVfs
);
518 sqlite3_int64 sz
= 0;
519 if( (flags
& SQLITE_OPEN_MAIN_DB
)==0 ){
520 /* The appendvfs is not to be used for transient or temporary databases.
521 ** Just use the base VFS open to initialize the given file object and
522 ** open the underlying file. (Appendvfs is then unused for this file.)
524 return pBaseVfs
->xOpen(pBaseVfs
, zName
, pFile
, flags
, pOutFlags
);
526 memset(pApndFile
, 0, sizeof(ApndFile
));
527 pFile
->pMethods
= &apnd_io_methods
;
528 pApndFile
->iMark
= -1; /* Append mark not yet written */
530 rc
= pBaseVfs
->xOpen(pBaseVfs
, zName
, pBaseFile
, flags
, pOutFlags
);
532 rc
= pBaseFile
->pMethods
->xFileSize(pBaseFile
, &sz
);
534 pBaseFile
->pMethods
->xClose(pBaseFile
);
541 if( apndIsOrdinaryDatabaseFile(sz
, pBaseFile
) ){
542 /* The file being opened appears to be just an ordinary DB. Copy
543 ** the base dispatch-table so this instance mimics the base VFS.
545 memmove(pApndFile
, pBaseFile
, pBaseVfs
->szOsFile
);
548 pApndFile
->iPgOne
= apndReadMark(sz
, pFile
);
549 if( pApndFile
->iPgOne
>=0 ){
550 pApndFile
->iMark
= sz
- APND_MARK_SIZE
; /* Append mark found */
553 if( (flags
& SQLITE_OPEN_CREATE
)==0 ){
554 pBaseFile
->pMethods
->xClose(pBaseFile
);
555 rc
= SQLITE_CANTOPEN
;
558 /* Round newly added appendvfs location to #define'd page boundary.
559 ** Note that nothing has yet been written to the underlying file.
560 ** The append mark will be written along with first content write.
561 ** Until then, paf->iMark value indicates it is not yet written.
563 pApndFile
->iPgOne
= APND_START_ROUNDUP(sz
);
569 ** Delete an apnd file.
570 ** For an appendvfs, this could mean delete the appendvfs portion,
571 ** leaving the appendee as it was before it gained an appendvfs.
572 ** For now, this code deletes the underlying file too.
574 static int apndDelete(sqlite3_vfs
*pVfs
, const char *zPath
, int dirSync
){
575 return ORIGVFS(pVfs
)->xDelete(ORIGVFS(pVfs
), zPath
, dirSync
);
579 ** All other VFS methods are pass-thrus.
581 static int apndAccess(
587 return ORIGVFS(pVfs
)->xAccess(ORIGVFS(pVfs
), zPath
, flags
, pResOut
);
589 static int apndFullPathname(
595 return ORIGVFS(pVfs
)->xFullPathname(ORIGVFS(pVfs
),zPath
,nOut
,zOut
);
597 static void *apndDlOpen(sqlite3_vfs
*pVfs
, const char *zPath
){
598 return ORIGVFS(pVfs
)->xDlOpen(ORIGVFS(pVfs
), zPath
);
600 static void apndDlError(sqlite3_vfs
*pVfs
, int nByte
, char *zErrMsg
){
601 ORIGVFS(pVfs
)->xDlError(ORIGVFS(pVfs
), nByte
, zErrMsg
);
603 static void (*apndDlSym(sqlite3_vfs
*pVfs
, void *p
, const char *zSym
))(void){
604 return ORIGVFS(pVfs
)->xDlSym(ORIGVFS(pVfs
), p
, zSym
);
606 static void apndDlClose(sqlite3_vfs
*pVfs
, void *pHandle
){
607 ORIGVFS(pVfs
)->xDlClose(ORIGVFS(pVfs
), pHandle
);
609 static int apndRandomness(sqlite3_vfs
*pVfs
, int nByte
, char *zBufOut
){
610 return ORIGVFS(pVfs
)->xRandomness(ORIGVFS(pVfs
), nByte
, zBufOut
);
612 static int apndSleep(sqlite3_vfs
*pVfs
, int nMicro
){
613 return ORIGVFS(pVfs
)->xSleep(ORIGVFS(pVfs
), nMicro
);
615 static int apndCurrentTime(sqlite3_vfs
*pVfs
, double *pTimeOut
){
616 return ORIGVFS(pVfs
)->xCurrentTime(ORIGVFS(pVfs
), pTimeOut
);
618 static int apndGetLastError(sqlite3_vfs
*pVfs
, int a
, char *b
){
619 return ORIGVFS(pVfs
)->xGetLastError(ORIGVFS(pVfs
), a
, b
);
621 static int apndCurrentTimeInt64(sqlite3_vfs
*pVfs
, sqlite3_int64
*p
){
622 return ORIGVFS(pVfs
)->xCurrentTimeInt64(ORIGVFS(pVfs
), p
);
624 static int apndSetSystemCall(
627 sqlite3_syscall_ptr pCall
629 return ORIGVFS(pVfs
)->xSetSystemCall(ORIGVFS(pVfs
),zName
,pCall
);
631 static sqlite3_syscall_ptr
apndGetSystemCall(
635 return ORIGVFS(pVfs
)->xGetSystemCall(ORIGVFS(pVfs
),zName
);
637 static const char *apndNextSystemCall(sqlite3_vfs
*pVfs
, const char *zName
){
638 return ORIGVFS(pVfs
)->xNextSystemCall(ORIGVFS(pVfs
), zName
);
643 __declspec(dllexport
)
646 ** This routine is called when the extension is loaded.
647 ** Register the new VFS.
649 int sqlite3_appendvfs_init(
652 const sqlite3_api_routines
*pApi
656 SQLITE_EXTENSION_INIT2(pApi
);
659 pOrig
= sqlite3_vfs_find(0);
660 if( pOrig
==0 ) return SQLITE_ERROR
;
661 apnd_vfs
.iVersion
= pOrig
->iVersion
;
662 apnd_vfs
.pAppData
= pOrig
;
663 apnd_vfs
.szOsFile
= pOrig
->szOsFile
+ sizeof(ApndFile
);
664 rc
= sqlite3_vfs_register(&apnd_vfs
, 0);
665 #ifdef APPENDVFS_TEST
667 rc
= sqlite3_auto_extension((void(*)(void))apndvfsRegister
);
670 if( rc
==SQLITE_OK
) rc
= SQLITE_OK_LOAD_PERMANENTLY
;