diff options
author | larrybr <larrybr@noemail.net> | 2021-03-16 06:41:51 +0000 |
---|---|---|
committer | larrybr <larrybr@noemail.net> | 2021-03-16 06:41:51 +0000 |
commit | 5cad178b86f5ec6e8c29fff70b0392a274d81ebc (patch) | |
tree | f259a67129795349e3aa356fba11430357b6196b /ext/misc/appendvfs.c | |
parent | 21f0f694ff32954a43a4518401ad3905bcbe32f9 (diff) | |
download | sqlite-5cad178b86f5ec6e8c29fff70b0392a274d81ebc.tar.gz sqlite-5cad178b86f5ec6e8c29fff70b0392a274d81ebc.zip |
Fix appendvfs bug exposed with bigger files, and add tests for such conditions.
FossilOrigin-Name: 19b1f53a1c0a14440ae8ac71660a2595d37a4a5b201055c19366c7dca75d6660
Diffstat (limited to 'ext/misc/appendvfs.c')
-rw-r--r-- | ext/misc/appendvfs.c | 58 |
1 files changed, 35 insertions, 23 deletions
diff --git a/ext/misc/appendvfs.c b/ext/misc/appendvfs.c index 3fff9a10f..970bb282c 100644 --- a/ext/misc/appendvfs.c +++ b/ext/misc/appendvfs.c @@ -122,6 +122,10 @@ struct ApndFile { sqlite3_int64 iPgOne; /* File offset of written append-mark, or -1 if unwritten */ sqlite3_int64 iMark; + /* Whenever file is open and .iMark >= 0, and file size changes are + * not in progress, .iMark + sizeof(append mark) == base file size, + * and append file size == .iMark - .iPgOne . + */ }; /* @@ -217,6 +221,7 @@ static const sqlite3_io_methods apnd_io_methods = { ** Close an apnd-file. */ static int apndClose(sqlite3_file *pFile){ + assert((ApndFile *pFile)pFile == ORIGFILE(pFile)); pFile = ORIGFILE(pFile); return pFile->pMethods->xClose(pFile); } @@ -250,6 +255,7 @@ static int apndWriteMark( int i = APND_MARK_FOS_SZ; int rc; assert(pFile == ORIGFILE(paf)); + /* assert(pFile == paf->base); */ memcpy(a, APND_MARK_PREFIX, APND_MARK_PREFIX_SZ); while (--i >= 0) { a[APND_MARK_PREFIX_SZ+i] = (unsigned char)(iPgOne & 0xff); @@ -276,6 +282,7 @@ static int apndWrite( sqlite_int64 iWriteEnd = iOfst + iAmt; if( iWriteEnd>=APND_MAX_SIZE ) return SQLITE_FULL; pFile = ORIGFILE(pFile); + /* assert(pFile == paf->base); */ /* If append-mark is absent or will be overwritten, write it. */ if( paf->iMark < 0 || paf->iPgOne + iWriteEnd > paf->iMark ){ int rc = apndWriteMark(paf, pFile, iWriteEnd); @@ -499,55 +506,60 @@ static int apndIsOrdinaryDatabaseFile(sqlite3_int64 sz, sqlite3_file *pFile){ ** Open an apnd file handle. */ static int apndOpen( - sqlite3_vfs *pVfs, + sqlite3_vfs *pApndVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags ){ - ApndFile *p; - sqlite3_file *pSubFile; - sqlite3_vfs *pSubVfs; + ApndFile *pApndFile = (ApndFile*)pFile; + sqlite3_file *pBaseFile = ORIGFILE(pFile); + sqlite3_vfs *pBaseVfs = ORIGVFS(pApndVfs); int rc; sqlite3_int64 sz; - pSubVfs = ORIGVFS(pVfs); if( (flags & SQLITE_OPEN_MAIN_DB)==0 ){ - /* The appendvfs is not to be used for transient or temporary databases. */ - return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags); + /* The appendvfs is not to be used for transient or temporary databases. + * Just use the base VFS open to initialize the given file object and + * open the underlying file. (Appendvfs is then unused for this file.) + */ + return pBaseVfs->xOpen(pBaseVfs, zName, pFile, flags, pOutFlags); } - p = (ApndFile*)pFile; - memset(p, 0, sizeof(*p)); - pSubFile = ORIGFILE(pFile); + memset(pApndFile, 0, sizeof(ApndFile)); pFile->pMethods = &apnd_io_methods; - rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags); + /* Record that append mark has not been written until seen otherwise. */ + pApndFile->iMark = -1; + + rc = pBaseVfs->xOpen(pBaseVfs, zName, pBaseFile, flags, pOutFlags); if( rc ) goto apnd_open_done; - rc = pSubFile->pMethods->xFileSize(pSubFile, &sz); + rc = pBaseFile->pMethods->xFileSize(pBaseFile, &sz); if( rc ){ - pSubFile->pMethods->xClose(pSubFile); + pBaseFile->pMethods->xClose(pBaseFile); goto apnd_open_done; } - if( apndIsOrdinaryDatabaseFile(sz, pSubFile) ){ - memmove(pFile, pSubFile, pSubVfs->szOsFile); + if( apndIsOrdinaryDatabaseFile(sz, pBaseFile) ){ + /* The file being opened appears to be just an ordinary DB. Copy + * the base dispatch-table so this instance mimics the base VFS. + */ + memmove(pApndFile, pBaseFile, pBaseVfs->szOsFile); return SQLITE_OK; } - /* Record that append mark has not been written until seen otherwise. */ - p->iMark = -1; - p->iPgOne = apndReadMark(sz, pFile); - if( p->iPgOne>=0 ){ + pApndFile->iPgOne = apndReadMark(sz, pFile); + if( pApndFile->iPgOne>=0 ){ /* Append mark was found, infer its offset */ - p->iMark = sz - p->iPgOne - APND_MARK_SIZE; + pApndFile->iMark = sz - APND_MARK_SIZE; + /* pApndFile->base = pBaseFile; */ return SQLITE_OK; } if( (flags & SQLITE_OPEN_CREATE)==0 ){ - pSubFile->pMethods->xClose(pSubFile); + pBaseFile->pMethods->xClose(pBaseFile); rc = SQLITE_CANTOPEN; } /* Round newly added appendvfs location to #define'd page boundary. * Note that nothing has yet been written to the underlying file. * The append mark will be written along with first content write. - * Until then, the p->iMark value indicates it is not yet written. + * Until then, paf->iMark value indicates it is not yet written. */ - p->iPgOne = APND_START_ROUNDUP(sz, APND_ROUNDUP_BITS); + pApndFile->iPgOne = APND_START_ROUNDUP(sz, APND_ROUNDUP_BITS); apnd_open_done: if( rc ) pFile->pMethods = 0; return rc; |