Fixes default log output to console for macOS
[sqlcipher.git] / ext / misc / appendvfs.c
blobeb9ed01f62e38d725f7fc56d4eda4a047044f0d2
1 /*
2 ** 2017-10-20
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.
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)
48 **/
49 #include "sqlite3ext.h"
50 SQLITE_EXTENSION_INIT1
51 #include <string.h>
52 #include <assert.h>
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.
76 #ifndef APND_ROUNDUP
77 #define APND_ROUNDUP 4096
78 #endif
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
100 ** append-mark.
102 ** The structure of an AppendVFS database is like this:
104 ** +-------------+---------+----------+-------------+
105 ** | prefix-file | padding | database | append-mark |
106 ** +-------------+---------+----------+-------------+
107 ** ^ ^
108 ** | |
109 ** iPgOne iMark
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
118 ** of "database".
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.
128 struct ApndFile {
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 */
181 0, /* pNext */
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 = {
203 3, /* iVersion */
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.
235 static int apndRead(
236 sqlite3_file *pFile,
237 void *zBuf,
238 int iAmt,
239 sqlite_int64 iOfst
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(
252 ApndFile *paf,
253 sqlite3_file *pFile,
254 sqlite_int64 iWriteEnd
256 sqlite_int64 iPgOne = paf->iPgOne;
257 unsigned char a[APND_MARK_SIZE];
258 int i = APND_MARK_FOS_SZ;
259 int rc;
260 assert(pFile == ORIGFILE(paf));
261 memcpy(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ);
262 while( --i >= 0 ){
263 a[APND_MARK_PREFIX_SZ+i] = (unsigned char)(iPgOne & 0xff);
264 iPgOne >>= 8;
266 iWriteEnd += paf->iPgOne;
267 if( SQLITE_OK==(rc = pFile->pMethods->xWrite
268 (pFile, a, APND_MARK_SIZE, iWriteEnd)) ){
269 paf->iMark = iWriteEnd;
271 return rc;
275 ** Write data to an apnd-file.
277 static int apndWrite(
278 sqlite3_file *pFile,
279 const void *zBuf,
280 int iAmt,
281 sqlite_int64 iOfst
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;
322 return SQLITE_OK;
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;
354 int rc;
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);
361 return rc;
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(
382 sqlite3_file *pFile,
383 int iPg,
384 int pgsz,
385 int bExtend,
386 void volatile **pp
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(
412 sqlite3_file *pFile,
413 sqlite3_int64 iOfst,
414 int iAmt,
415 void **pp
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){
442 int rc, i;
443 sqlite3_int64 iMark;
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);
449 if( rc ) return -1;
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;
452 for(i=1; i<8; i++){
453 msbs -= 8;
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;
458 return iMark;
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){
467 int rc;
468 char zHdr[16];
469 sqlite3_int64 iMark = apndReadMark(sz, pFile);
470 if( iMark>=0 ){
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);
476 if( SQLITE_OK==rc
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 */
484 return 0;
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){
492 char zHdr[16];
493 if( apndIsAppendvfsDatabase(sz, pFile) /* rule 2 */
494 || (sz & 0x1ff) != 0
495 || SQLITE_OK!=pFile->pMethods->xRead(pFile, zHdr, sizeof(zHdr), 0)
496 || memcmp(zHdr, apvfsSqliteHdr, sizeof(zHdr))!=0
498 return 0;
499 }else{
500 return 1;
505 ** Open an apnd file handle.
507 static int apndOpen(
508 sqlite3_vfs *pApndVfs,
509 const char *zName,
510 sqlite3_file *pFile,
511 int flags,
512 int *pOutFlags
514 ApndFile *pApndFile = (ApndFile*)pFile;
515 sqlite3_file *pBaseFile = ORIGFILE(pFile);
516 sqlite3_vfs *pBaseVfs = ORIGVFS(pApndVfs);
517 int rc;
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);
531 if( rc==SQLITE_OK ){
532 rc = pBaseFile->pMethods->xFileSize(pBaseFile, &sz);
533 if( rc ){
534 pBaseFile->pMethods->xClose(pBaseFile);
537 if( rc ){
538 pFile->pMethods = 0;
539 return rc;
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);
546 return SQLITE_OK;
548 pApndFile->iPgOne = apndReadMark(sz, pFile);
549 if( pApndFile->iPgOne>=0 ){
550 pApndFile->iMark = sz - APND_MARK_SIZE; /* Append mark found */
551 return SQLITE_OK;
553 if( (flags & SQLITE_OPEN_CREATE)==0 ){
554 pBaseFile->pMethods->xClose(pBaseFile);
555 rc = SQLITE_CANTOPEN;
556 pFile->pMethods = 0;
557 }else{
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);
565 return rc;
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(
582 sqlite3_vfs *pVfs,
583 const char *zPath,
584 int flags,
585 int *pResOut
587 return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut);
589 static int apndFullPathname(
590 sqlite3_vfs *pVfs,
591 const char *zPath,
592 int nOut,
593 char *zOut
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(
625 sqlite3_vfs *pVfs,
626 const char *zName,
627 sqlite3_syscall_ptr pCall
629 return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall);
631 static sqlite3_syscall_ptr apndGetSystemCall(
632 sqlite3_vfs *pVfs,
633 const char *zName
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);
642 #ifdef _WIN32
643 __declspec(dllexport)
644 #endif
646 ** This routine is called when the extension is loaded.
647 ** Register the new VFS.
649 int sqlite3_appendvfs_init(
650 sqlite3 *db,
651 char **pzErrMsg,
652 const sqlite3_api_routines *pApi
654 int rc = SQLITE_OK;
655 sqlite3_vfs *pOrig;
656 SQLITE_EXTENSION_INIT2(pApi);
657 (void)pzErrMsg;
658 (void)db;
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
666 if( rc==SQLITE_OK ){
667 rc = sqlite3_auto_extension((void(*)(void))apndvfsRegister);
669 #endif
670 if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
671 return rc;