aboutsummaryrefslogtreecommitdiff
path: root/ext/misc/appendvfs.c
diff options
context:
space:
mode:
authorlarrybr <larrybr@noemail.net>2021-03-16 06:41:51 +0000
committerlarrybr <larrybr@noemail.net>2021-03-16 06:41:51 +0000
commit5cad178b86f5ec6e8c29fff70b0392a274d81ebc (patch)
treef259a67129795349e3aa356fba11430357b6196b /ext/misc/appendvfs.c
parent21f0f694ff32954a43a4518401ad3905bcbe32f9 (diff)
downloadsqlite-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.c58
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;