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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 399 static void apndShmBarrier(sqlite3_file *pFile){ 400 pFile = ORIGFILE(pFile); 401 pFile->pMethods->xShmBarrier(pFile); 402 } 403 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); 408 } 409 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 } 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 } 597 static void *apndDlOpen(sqlite3_vfs *pVfs, const char *zPath){ 598 return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath); 599 } 600 static void apndDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ 601 ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg); 602 } 603 static void (*apndDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ 604 return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym); 605 } 606 static void apndDlClose(sqlite3_vfs *pVfs, void *pHandle){ 607 ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle); 608 } 609 static int apndRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ 610 return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut); 611 } 612 static int apndSleep(sqlite3_vfs *pVfs, int nMicro){ 613 return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro); 614 } 615 static int apndCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ 616 return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut); 617 } 618 static int apndGetLastError(sqlite3_vfs *pVfs, int a, char *b){ 619 return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b); 620 } 621 static int apndCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){ 622 return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p); 623 } 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 } 631 static sqlite3_syscall_ptr apndGetSystemCall( 632 sqlite3_vfs *pVfs, 633 const char *zName 634 ){ 635 return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName); 636 } 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 */ 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