xref: /sqlite-3.40.0/ext/misc/appendvfs.c (revision a959bf53)
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.
10 **
11 ******************************************************************************
12 **
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.
15 **
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.
21 **
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:
26 **
27 **  (1)  An empty file is an ordinary database.
28 **
29 **  (2)  If the file ends with the appendvfs trailer string
30 **       "Start-Of-SQLite3-NNNNNNNN" that file is an appended database.
31 **
32 **  (3)  If the file begins with the standard SQLite prefix string
33 **       "SQLite format 3", that file is an ordinary database.
34 **
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.
37 **
38 **  (5)  Otherwise, SQLITE_CANTOPEN is returned.
39 **
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.
45 **
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>
53 
54 /* The append mark at the end of the database is:
55 **
56 **     Start-Of-SQLite3-NNNNNNNN
57 **     123456789 123456789 12345
58 **
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.
61 */
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)
66 
67 /*
68 ** Maximum size of the combined prefix + database + append-mark.  This
69 ** must be less than 0x40000000 to avoid locking issues on Windows.
70 */
71 #define APND_MAX_SIZE  (0x40000000)
72 
73 /*
74 ** Try to align the database to an even multiple of APND_ROUNDUP bytes.
75 */
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)
81 
82 /*
83 ** Forward declaration of objects used by this utility
84 */
85 typedef struct sqlite3_vfs ApndVfs;
86 typedef struct ApndFile ApndFile;
87 
88 /* Access to a lower-level VFS that (might) implement dynamic loading,
89 ** access to randomness, etc.
90 */
91 #define ORIGVFS(p)  ((sqlite3_vfs*)((p)->pAppData))
92 #define ORIGFILE(p) ((sqlite3_file*)(((ApndFile*)(p))+1))
93 
94 /* An open appendvfs file
95 **
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.
101 **
102 ** The structure of an AppendVFS database is like this:
103 **
104 **   +-------------+---------+----------+-------------+
105 **   | prefix-file | padding | database | append-mark |
106 **   +-------------+---------+----------+-------------+
107 **                           ^          ^
108 **                           |          |
109 **                         iPgOne      iMark
110 **
111 **
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".
119 **
120 ** The size of the database is iMark - iPgOne.
121 **
122 ** The NNNNNNNN in the "Start-Of-SQLite3-NNNNNNNN" suffix is the value
123 ** of iPgOne stored as a big-ending 64-bit integer.
124 **
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.
127 */
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 */
133 };
134 
135 /*
136 ** Methods for ApndFile
137 */
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);
156 
157 /*
158 ** Methods for ApndVfs
159 */
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);
176 
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 */
200 };
201 
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 */
222 };
223 
224 /*
225 ** Close an apnd-file.
226 */
apndClose(sqlite3_file * pFile)227 static int apndClose(sqlite3_file *pFile){
228   pFile = ORIGFILE(pFile);
229   return pFile->pMethods->xClose(pFile);
230 }
231 
232 /*
233 ** Read data from an apnd-file.
234 */
apndRead(sqlite3_file * pFile,void * zBuf,int iAmt,sqlite_int64 iOfst)235 static int apndRead(
236   sqlite3_file *pFile,
237   void *zBuf,
238   int iAmt,
239   sqlite_int64 iOfst
240 ){
241   ApndFile *paf = (ApndFile *)pFile;
242   pFile = ORIGFILE(pFile);
243   return pFile->pMethods->xRead(pFile, zBuf, iAmt, paf->iPgOne+iOfst);
244 }
245 
246 /*
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.
250 */
apndWriteMark(ApndFile * paf,sqlite3_file * pFile,sqlite_int64 iWriteEnd)251 static int apndWriteMark(
252   ApndFile *paf,
253   sqlite3_file *pFile,
254   sqlite_int64 iWriteEnd
255 ){
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;
265   }
266   iWriteEnd += paf->iPgOne;
267   if( SQLITE_OK==(rc = pFile->pMethods->xWrite
268                   (pFile, a, APND_MARK_SIZE, iWriteEnd)) ){
269     paf->iMark = iWriteEnd;
270   }
271   return rc;
272 }
273 
274 /*
275 ** Write data to an apnd-file.
276 */
apndWrite(sqlite3_file * pFile,const void * zBuf,int iAmt,sqlite_int64 iOfst)277 static int apndWrite(
278   sqlite3_file *pFile,
279   const void *zBuf,
280   int iAmt,
281   sqlite_int64 iOfst
282 ){
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;
291   }
292   return pFile->pMethods->xWrite(pFile, zBuf, iAmt, paf->iPgOne+iOfst);
293 }
294 
295 /*
296 ** Truncate an apnd-file.
297 */
apndTruncate(sqlite3_file * pFile,sqlite_int64 size)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);
305 }
306 
307 /*
308 ** Sync an apnd-file.
309 */
apndSync(sqlite3_file * pFile,int flags)310 static int apndSync(sqlite3_file *pFile, int flags){
311   pFile = ORIGFILE(pFile);
312   return pFile->pMethods->xSync(pFile, flags);
313 }
314 
315 /*
316 ** Return the current file-size of an apnd-file.
317 ** If the append mark is not yet there, the file-size is 0.
318 */
apndFileSize(sqlite3_file * pFile,sqlite_int64 * pSize)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;
323 }
324 
325 /*
326 ** Lock an apnd-file.
327 */
apndLock(sqlite3_file * pFile,int eLock)328 static int apndLock(sqlite3_file *pFile, int eLock){
329   pFile = ORIGFILE(pFile);
330   return pFile->pMethods->xLock(pFile, eLock);
331 }
332 
333 /*
334 ** Unlock an apnd-file.
335 */
apndUnlock(sqlite3_file * pFile,int eLock)336 static int apndUnlock(sqlite3_file *pFile, int eLock){
337   pFile = ORIGFILE(pFile);
338   return pFile->pMethods->xUnlock(pFile, eLock);
339 }
340 
341 /*
342 ** Check if another file-handle holds a RESERVED lock on an apnd-file.
343 */
apndCheckReservedLock(sqlite3_file * pFile,int * pResOut)344 static int apndCheckReservedLock(sqlite3_file *pFile, int *pResOut){
345   pFile = ORIGFILE(pFile);
346   return pFile->pMethods->xCheckReservedLock(pFile, pResOut);
347 }
348 
349 /*
350 ** File control method. For custom operations on an apnd-file.
351 */
apndFileControl(sqlite3_file * pFile,int op,void * pArg)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);
360   }
361   return rc;
362 }
363 
364 /*
365 ** Return the sector-size in bytes for an apnd-file.
366 */
apndSectorSize(sqlite3_file * pFile)367 static int apndSectorSize(sqlite3_file *pFile){
368   pFile = ORIGFILE(pFile);
369   return pFile->pMethods->xSectorSize(pFile);
370 }
371 
372 /*
373 ** Return the device characteristic flags supported by an apnd-file.
374 */
apndDeviceCharacteristics(sqlite3_file * pFile)375 static int apndDeviceCharacteristics(sqlite3_file *pFile){
376   pFile = ORIGFILE(pFile);
377   return pFile->pMethods->xDeviceCharacteristics(pFile);
378 }
379 
380 /* Create a shared memory file mapping */
apndShmMap(sqlite3_file * pFile,int iPg,int pgsz,int bExtend,void volatile ** pp)381 static int apndShmMap(
382   sqlite3_file *pFile,
383   int iPg,
384   int pgsz,
385   int bExtend,
386   void volatile **pp
387 ){
388   pFile = ORIGFILE(pFile);
389   return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp);
390 }
391 
392 /* Perform locking on a shared-memory segment */
apndShmLock(sqlite3_file * pFile,int offset,int n,int flags)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);
396 }
397 
398 /* Memory barrier operation on shared memory */
apndShmBarrier(sqlite3_file * pFile)399 static void apndShmBarrier(sqlite3_file *pFile){
400   pFile = ORIGFILE(pFile);
401   pFile->pMethods->xShmBarrier(pFile);
402 }
403 
404 /* Unmap a shared memory segment */
apndShmUnmap(sqlite3_file * pFile,int deleteFlag)405 static int apndShmUnmap(sqlite3_file *pFile, int deleteFlag){
406   pFile = ORIGFILE(pFile);
407   return pFile->pMethods->xShmUnmap(pFile,deleteFlag);
408 }
409 
410 /* Fetch a page of a memory-mapped file */
apndFetch(sqlite3_file * pFile,sqlite3_int64 iOfst,int iAmt,void ** pp)411 static int apndFetch(
412   sqlite3_file *pFile,
413   sqlite3_int64 iOfst,
414   int iAmt,
415   void **pp
416 ){
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. */
420   }
421   pFile = ORIGFILE(pFile);
422   return pFile->pMethods->xFetch(pFile, iOfst+p->iPgOne, iAmt, pp);
423 }
424 
425 /* Release a memory-mapped page */
apndUnfetch(sqlite3_file * pFile,sqlite3_int64 iOfst,void * pPage)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);
430 }
431 
432 /*
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;
436 **
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.
440 */
apndReadMark(sqlite3_int64 sz,sqlite3_file * pFile)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];
446 
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;
455   }
456   if( iMark > (sz - APND_MARK_SIZE - 512) ) return -1;
457   if( iMark & 0x1ff ) return -1;
458   return iMark;
459 }
460 
461 static const char apvfsSqliteHdr[] = "SQLite format 3";
462 /*
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.
465 */
apndIsAppendvfsDatabase(sqlite3_int64 sz,sqlite3_file * pFile)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.
474     */
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
480     ){
481       return 1; /* It's an appendvfs database */
482     }
483   }
484   return 0;
485 }
486 
487 /*
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.
490 */
apndIsOrdinaryDatabaseFile(sqlite3_int64 sz,sqlite3_file * pFile)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
497   ){
498     return 0;
499   }else{
500     return 1;
501   }
502 }
503 
504 /*
505 ** Open an apnd file handle.
506 */
apndOpen(sqlite3_vfs * pApndVfs,const char * zName,sqlite3_file * pFile,int flags,int * pOutFlags)507 static int apndOpen(
508   sqlite3_vfs *pApndVfs,
509   const char *zName,
510   sqlite3_file *pFile,
511   int flags,
512   int *pOutFlags
513 ){
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.)
523     */
524     return pBaseVfs->xOpen(pBaseVfs, zName, pFile, flags, pOutFlags);
525   }
526   memset(pApndFile, 0, sizeof(ApndFile));
527   pFile->pMethods = &apnd_io_methods;
528   pApndFile->iMark = -1;    /* Append mark not yet written */
529 
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);
535     }
536   }
537   if( rc ){
538     pFile->pMethods = 0;
539     return rc;
540   }
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.
544     */
545     memmove(pApndFile, pBaseFile, pBaseVfs->szOsFile);
546     return SQLITE_OK;
547   }
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;
552   }
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.
562     */
563     pApndFile->iPgOne = APND_START_ROUNDUP(sz);
564   }
565   return rc;
566 }
567 
568 /*
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.
573 */
apndDelete(sqlite3_vfs * pVfs,const char * zPath,int dirSync)574 static int apndDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
575   return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync);
576 }
577 
578 /*
579 ** All other VFS methods are pass-thrus.
580 */
apndAccess(sqlite3_vfs * pVfs,const char * zPath,int flags,int * pResOut)581 static int apndAccess(
582   sqlite3_vfs *pVfs,
583   const char *zPath,
584   int flags,
585   int *pResOut
586 ){
587   return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut);
588 }
apndFullPathname(sqlite3_vfs * pVfs,const char * zPath,int nOut,char * zOut)589 static int apndFullPathname(
590   sqlite3_vfs *pVfs,
591   const char *zPath,
592   int nOut,
593   char *zOut
594 ){
595   return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut);
596 }
apndDlOpen(sqlite3_vfs * pVfs,const char * zPath)597 static void *apndDlOpen(sqlite3_vfs *pVfs, const char *zPath){
598   return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath);
599 }
apndDlError(sqlite3_vfs * pVfs,int nByte,char * zErrMsg)600 static void apndDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
601   ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg);
602 }
apndDlSym(sqlite3_vfs * pVfs,void * p,const char * zSym)603 static void (*apndDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
604   return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym);
605 }
apndDlClose(sqlite3_vfs * pVfs,void * pHandle)606 static void apndDlClose(sqlite3_vfs *pVfs, void *pHandle){
607   ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle);
608 }
apndRandomness(sqlite3_vfs * pVfs,int nByte,char * zBufOut)609 static int apndRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
610   return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut);
611 }
apndSleep(sqlite3_vfs * pVfs,int nMicro)612 static int apndSleep(sqlite3_vfs *pVfs, int nMicro){
613   return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro);
614 }
apndCurrentTime(sqlite3_vfs * pVfs,double * pTimeOut)615 static int apndCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
616   return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut);
617 }
apndGetLastError(sqlite3_vfs * pVfs,int a,char * b)618 static int apndGetLastError(sqlite3_vfs *pVfs, int a, char *b){
619   return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b);
620 }
apndCurrentTimeInt64(sqlite3_vfs * pVfs,sqlite3_int64 * p)621 static int apndCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){
622   return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p);
623 }
apndSetSystemCall(sqlite3_vfs * pVfs,const char * zName,sqlite3_syscall_ptr pCall)624 static int apndSetSystemCall(
625   sqlite3_vfs *pVfs,
626   const char *zName,
627   sqlite3_syscall_ptr pCall
628 ){
629   return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall);
630 }
apndGetSystemCall(sqlite3_vfs * pVfs,const char * zName)631 static sqlite3_syscall_ptr apndGetSystemCall(
632   sqlite3_vfs *pVfs,
633   const char *zName
634 ){
635   return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName);
636 }
apndNextSystemCall(sqlite3_vfs * pVfs,const char * zName)637 static const char *apndNextSystemCall(sqlite3_vfs *pVfs, const char *zName){
638   return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName);
639 }
640 
641 
642 #ifdef _WIN32
643 __declspec(dllexport)
644 #endif
645 /*
646 ** This routine is called when the extension is loaded.
647 ** Register the new VFS.
648 */
sqlite3_appendvfs_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)649 int sqlite3_appendvfs_init(
650   sqlite3 *db,
651   char **pzErrMsg,
652   const sqlite3_api_routines *pApi
653 ){
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);
668   }
669 #endif
670   if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY;
671   return rc;
672 }
673