Skip to content

Commit

Permalink
Remove global VFS management structure
Browse files Browse the repository at this point in the history
Attempt to solve issue #73: global VFS management structure did not work properly in multi-threaded environment.
  • Loading branch information
utelle committed Apr 14, 2022
1 parent 2249ca3 commit 9fd21f4
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 60 deletions.
14 changes: 7 additions & 7 deletions src/codecext.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
** Purpose: Implementation of SQLite codec API
** Author: Ulrich Telle
** Created: 2006-12-06
** Copyright: (c) 2006-2021 Ulrich Telle
** Copyright: (c) 2006-2022 Ulrich Telle
** License: MIT
*/

Expand Down Expand Up @@ -167,7 +167,7 @@ SQLITE_PRIVATE Codec*
sqlite3mcGetMainCodec(sqlite3* db);

SQLITE_PRIVATE void
sqlite3mcSetCodec(sqlite3* db, const char* zFileName, Codec* codec);
sqlite3mcSetCodec(sqlite3* db, const char* zDbName, const char* zFileName, Codec* codec);

static int
mcAdjustBtree(Btree* pBt, int nPageSize, int nReserved, int isLegacy)
Expand Down Expand Up @@ -229,7 +229,7 @@ sqlite3mcCodecAttach(sqlite3* db, int nDb, const char* zPath, const void* zKey,
sqlite3mcSetBtree(codec, db->aDb[nDb].pBt);
mcAdjustBtree(db->aDb[nDb].pBt, pageSize, reserved, sqlite3mcGetLegacyWriteCipher(codec));
sqlite3mcCodecSizeChange(codec, pageSize, reserved);
sqlite3mcSetCodec(db, dbFileName, codec);
sqlite3mcSetCodec(db, zDbName, dbFileName, codec);
}
else
{
Expand All @@ -250,7 +250,7 @@ sqlite3mcCodecAttach(sqlite3* db, int nDb, const char* zPath, const void* zKey,
/* Remove codec for main database */
if (nDb == 0 && nKey == 0)
{
sqlite3mcSetCodec(db, dbFileName, NULL);
sqlite3mcSetCodec(db, zDbName, dbFileName, NULL);
}
}
}
Expand Down Expand Up @@ -285,7 +285,7 @@ sqlite3mcCodecAttach(sqlite3* db, int nDb, const char* zPath, const void* zKey,
int reserved = sqlite3mcGetReservedWriteCipher(codec);
mcAdjustBtree(db->aDb[nDb].pBt, pageSize, reserved, sqlite3mcGetLegacyWriteCipher(codec));
sqlite3mcCodecSizeChange(codec, pageSize, reserved);
sqlite3mcSetCodec(db, dbFileName, codec);
sqlite3mcSetCodec(db, zDbName, dbFileName, codec);
}
else
{
Expand Down Expand Up @@ -432,7 +432,7 @@ sqlite3_rekey_v2(sqlite3* db, const char* zDbName, const void* zKey, int nKey)
int nReservedWriteCipher;
sqlite3mcSetHasReadCipher(codec, 0); /* Original database is not encrypted */
mcAdjustBtree(pBt, sqlite3mcGetPageSizeWriteCipher(codec), sqlite3mcGetReservedWriteCipher(codec), sqlite3mcGetLegacyWriteCipher(codec));
sqlite3mcSetCodec(db, dbFileName, codec);
sqlite3mcSetCodec(db, zDbName, dbFileName, codec);
nReservedWriteCipher = sqlite3mcGetReservedWriteCipher(codec);
sqlite3mcCodecSizeChange(codec, nPagesize, nReservedWriteCipher);
if (nReserved != nReservedWriteCipher)
Expand Down Expand Up @@ -583,7 +583,7 @@ sqlite3_rekey_v2(sqlite3* db, const char* zDbName, const void* zKey, int nKey)
if (!sqlite3mcIsEncrypted(codec))
{
/* Remove codec for unencrypted database */
sqlite3mcSetCodec(db, dbFileName, NULL);
sqlite3mcSetCodec(db, zDbName, dbFileName, NULL);
}
return rc;
}
Expand Down
6 changes: 3 additions & 3 deletions src/sqlite3mc_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
#define SQLITE3MC_VERSION_H_

#define SQLITE3MC_VERSION_MAJOR 1
#define SQLITE3MC_VERSION_MINOR 3
#define SQLITE3MC_VERSION_RELEASE 10
#define SQLITE3MC_VERSION_MINOR 4
#define SQLITE3MC_VERSION_RELEASE 0
#define SQLITE3MC_VERSION_SUBRELEASE 0
#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 1.3.10"
#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 1.4.0"

#endif /* SQLITE3MC_VERSION_H_ */
133 changes: 83 additions & 50 deletions src/sqlite3mc_vfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
** Purpose: Implementation of SQLite VFS for Multiple Ciphers
** Author: Ulrich Telle
** Created: 2020-02-28
** Copyright: (c) 2020-2021 Ulrich Telle
** Copyright: (c) 2020-2022 Ulrich Telle
** License: MIT
*/

Expand All @@ -29,6 +29,7 @@ struct sqlite3mc_file
{
sqlite3_file base; /* sqlite3_file I/O methods */
sqlite3_file* pFile; /* Real underlying OS file */
sqlite3mc_vfs* pVfsMC; /* Pointer to the sqlite3mc_vfs object */
const char* zFileName; /* File name */
int openFlags; /* Open flags */
sqlite3mc_file* pMainNext; /* Next main db file */
Expand All @@ -51,9 +52,6 @@ struct sqlite3mc_vfs
#define REALVFS(p) ((sqlite3_vfs*)(((sqlite3mc_vfs*)(p))->base.pAppData))
#define REALFILE(p) (((sqlite3mc_file*)(p))->pFile)

#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
#define ORIGFILE(p) ((sqlite3_file*)(((CksmFile*)(p))+1))

/*
** Prototypes for VFS methods
*/
Expand Down Expand Up @@ -107,37 +105,8 @@ static const int walFrameHeaderSize = 24;
static const int walFileHeaderSize = 32;

/*
** Global VFS structure of SQLite3 Multiple Ciphers VFS
** Global I/O method structure of SQLite3 Multiple Ciphers VFS
*/
static sqlite3mc_vfs mcVfsGlobal =
{
{
3, /* iVersion */
0, /* szOsFile */
1024, /* mxPathname */
0, /* pNext */
SQLITE3MC_VFS_NAME, /* zName */
0, /* pAppData */
mcVfsOpen, /* xOpen */
mcVfsDelete, /* xDelete */
mcVfsAccess, /* xAccess */
mcVfsFullPathname, /* xFullPathname */
mcVfsDlOpen, /* xDlOpen */
mcVfsDlError, /* xDlError */
mcVfsDlSym, /* xDlSym */
mcVfsDlClose, /* xDlClose */
mcVfsRandomness, /* xRandomness */
mcVfsSleep, /* xSleep */
mcVfsCurrentTime, /* xCurrentTime */
mcVfsGetLastError, /* xGetLastError */
mcVfsCurrentTimeInt64, /* xCurrentTimeInt64 */
mcVfsSetSystemCall, /* xSetSystemCall */
mcVfsGetSystemCall, /* xGetSystemCall */
mcVfsNextSystemCall /* xNextSystemCall */
},
NULL
};

static sqlite3_io_methods mcIoMethodsGlobal =
{
3, /* iVersion */
Expand Down Expand Up @@ -171,10 +140,10 @@ static sqlite3_io_methods mcIoMethodsGlobal =
static void mcMainListAdd(sqlite3mc_file* pFile)
{
assert( (pFile->openFlags & SQLITE_OPEN_MAIN_DB) );
sqlite3_mutex_enter(mcVfsGlobal.mutex);
pFile->pMainNext = mcVfsGlobal.pMain;
mcVfsGlobal.pMain = pFile;
sqlite3_mutex_leave(mcVfsGlobal.mutex);
sqlite3_mutex_enter(pFile->pVfsMC->mutex);
pFile->pMainNext = pFile->pVfsMC->pMain;
pFile->pVfsMC->pMain = pFile;
sqlite3_mutex_leave(pFile->pVfsMC->mutex);
}

/*
Expand All @@ -183,11 +152,11 @@ static void mcMainListAdd(sqlite3mc_file* pFile)
static void mcMainListRemove(sqlite3mc_file* pFile)
{
sqlite3mc_file** pMainPrev;
sqlite3_mutex_enter(mcVfsGlobal.mutex);
for (pMainPrev = &mcVfsGlobal.pMain; *pMainPrev && *pMainPrev != pFile; pMainPrev = &((*pMainPrev)->pMainNext)){}
sqlite3_mutex_enter(pFile->pVfsMC->mutex);
for (pMainPrev = &pFile->pVfsMC->pMain; *pMainPrev && *pMainPrev != pFile; pMainPrev = &((*pMainPrev)->pMainNext)){}
if (*pMainPrev) *pMainPrev = pFile->pMainNext;
pFile->pMainNext = 0;
sqlite3_mutex_leave(mcVfsGlobal.mutex);
sqlite3_mutex_leave(pFile->pVfsMC->mutex);
}

/*
Expand All @@ -205,18 +174,68 @@ static sqlite3mc_file* mcFindDbMainFileName(sqlite3mc_vfs* mcVfs, const char* zF
return pDb;
}

/*
** Find a pointer to the Multiple Ciphers VFS in use for a database connection.
*/
static sqlite3mc_vfs* mcFindVfs(sqlite3* db, const char* zDbName)
{
sqlite3mc_vfs* pVfsMC = NULL;
if (db->pVfs && db->pVfs->xOpen == mcVfsOpen)
{
/* The top level VFS is a Multiple Ciphers VFS */
pVfsMC = (sqlite3mc_vfs*)(db->pVfs);
}
else
{
/*
** The top level VFS is not a Multiple Ciphers VFS.
** Retrieve the VFS names stack.
*/
char* zVfsNameStack = 0;
if ((sqlite3_file_control(db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsNameStack) == SQLITE_OK) && (zVfsNameStack != NULL))
{
/* Search for the name prefix of a Multiple Ciphers VFS. */
char* zVfsName = strstr(zVfsNameStack, SQLITE3MC_VFS_NAME);
if (zVfsName != NULL)
{
/* The prefix was found, now determine the full VFS name. */
char* zVfsNameEnd = zVfsName + strlen(SQLITE3MC_VFS_NAME);
if (*zVfsNameEnd == '-')
{
for (++zVfsNameEnd; *zVfsNameEnd != '/' && *zVfsNameEnd != 0; ++zVfsNameEnd);
if (*zVfsNameEnd == '/') *zVfsNameEnd = 0;

/* Find a pointer to the VFS with the determined name. */
sqlite3_vfs* pVfs = sqlite3_vfs_find(zVfsName);
if (pVfs && pVfs->xOpen == mcVfsOpen)
{
pVfsMC = (sqlite3mc_vfs*) pVfs;
}
}
}
sqlite3_free(zVfsNameStack);
}
}
return pVfsMC;
}

/*
** Find the codec of the database file
** corresponding to the database schema name.
*/
SQLITE_PRIVATE Codec* sqlite3mcGetCodec(sqlite3* db, const char* zDbName)
{
Codec* codec = NULL;
const char* dbFileName = sqlite3_db_filename(db, zDbName);
sqlite3mc_file* pDbMain = mcFindDbMainFileName(&mcVfsGlobal, dbFileName);
if (pDbMain)
sqlite3mc_vfs* pVfsMC = mcFindVfs(db, zDbName);

if (pVfsMC)
{
codec = pDbMain->codec;
const char* dbFileName = sqlite3_db_filename(db, zDbName);
sqlite3mc_file* pDbMain = mcFindDbMainFileName(pVfsMC, dbFileName);
if (pDbMain)
{
codec = pDbMain->codec;
}
}
return codec;
}
Expand All @@ -239,9 +258,14 @@ SQLITE_PRIVATE Codec* sqlite3mcGetMainCodec(sqlite3* db)
** connection handle is actually valid, because the association between
** connection handles and database file handles is not maintained properly.
*/
SQLITE_PRIVATE void sqlite3mcSetCodec(sqlite3* db, const char* zFileName, Codec* codec)
SQLITE_PRIVATE void sqlite3mcSetCodec(sqlite3* db, const char* zDbName, const char* zFileName, Codec* codec)
{
sqlite3mc_file* pDbMain = mcFindDbMainFileName(&mcVfsGlobal, zFileName);
sqlite3mc_file* pDbMain = NULL;
sqlite3mc_vfs* pVfsMC = mcFindVfs(db, zDbName);
if (pVfsMC)
{
pDbMain = mcFindDbMainFileName((sqlite3mc_vfs*)(db->pVfs), zFileName);
}
if (pDbMain)
{
Codec* prevCodec = pDbMain->codec;
Expand Down Expand Up @@ -310,6 +334,7 @@ static int mcVfsOpen(sqlite3_vfs* pVfs, const char* zName, sqlite3_file* pFile,
sqlite3mc_vfs* mcVfs = (sqlite3mc_vfs*) pVfs;
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
mcFile->pFile = (sqlite3_file*) &mcFile[1];
mcFile->pVfsMC = mcVfs;
mcFile->openFlags = flags;
mcFile->zFileName = zName;
mcFile->codec = 0;
Expand Down Expand Up @@ -340,7 +365,7 @@ static int mcVfsOpen(sqlite3_vfs* pVfs, const char* zName, sqlite3_file* pFile,
else if (flags & SQLITE_OPEN_MAIN_JOURNAL)
{
const char* dbFileName = sqlite3_filename_database(zName);
mcFile->pMainDb = mcFindDbMainFileName(&mcVfsGlobal, dbFileName);
mcFile->pMainDb = mcFindDbMainFileName(mcFile->pVfsMC, dbFileName);
mcFile->zFileName = zName;
SQLITE3MC_DEBUG_LOG("mcVfsOpen MAIN Journal: mcFile=%p fileName=%s dbFileName=%s\n", mcFile, mcFile->zFileName, dbFileName);
}
Expand All @@ -355,7 +380,7 @@ static int mcVfsOpen(sqlite3_vfs* pVfs, const char* zName, sqlite3_file* pFile,
else if (flags & SQLITE_OPEN_SUBJOURNAL)
{
const char* dbFileName = sqlite3_filename_database(zName);
mcFile->pMainDb = mcFindDbMainFileName(&mcVfsGlobal, dbFileName);
mcFile->pMainDb = mcFindDbMainFileName(mcFile->pVfsMC, dbFileName);
mcFile->zFileName = zName;
SQLITE3MC_DEBUG_LOG("mcVfsOpen SUB Journal: mcFile=%p fileName=%s dbFileName=%s\n", mcFile, mcFile->zFileName, dbFileName);
}
Expand All @@ -371,7 +396,7 @@ static int mcVfsOpen(sqlite3_vfs* pVfs, const char* zName, sqlite3_file* pFile,
else if (flags & SQLITE_OPEN_WAL)
{
const char* dbFileName = sqlite3_filename_database(zName);
mcFile->pMainDb = mcFindDbMainFileName(&mcVfsGlobal, dbFileName);
mcFile->pMainDb = mcFindDbMainFileName(mcFile->pVfsMC, dbFileName);
mcFile->zFileName = zName;
SQLITE3MC_DEBUG_LOG("mcVfsOpen WAL Journal: mcFile=%p fileName=%s dbFileName=%s\n", mcFile, mcFile->zFileName, dbFileName);
}
Expand Down Expand Up @@ -1155,6 +1180,14 @@ static int mcIoFileControl(sqlite3_file* pFile, int op, void* pArg)
if (doReal)
{
rc = REALFILE(pFile)->pMethods->xFileControl(REALFILE(pFile), op, pArg);
if (rc == SQLITE_OK && op == SQLITE_FCNTL_VFSNAME)
{
sqlite3mc_vfs* pVfsMC = p->pVfsMC;
char* zIn = *(char**)pArg;
char* zOut = sqlite3_mprintf("%s/%z", pVfsMC->base.zName, zIn);
*(char**)pArg = zOut;
if (zOut == 0) rc = SQLITE_NOMEM;
}
}
return rc;
}
Expand Down

0 comments on commit 9fd21f4

Please sign in to comment.