#include "sqlite3mc_vfs.h"
#include "sqlite3.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "mystdint.h"
typedef struct sqlite3mc_file sqlite3mc_file;
typedef struct sqlite3mc_vfs sqlite3mc_vfs;
struct sqlite3mc_file
{
sqlite3_file base;
sqlite3_file* pFile;
sqlite3mc_vfs* pVfsMC;
const char* zFileName;
int openFlags;
sqlite3mc_file* pMainNext;
sqlite3mc_file* pMainDb;
Codec* codec;
int pageNo;
};
struct sqlite3mc_vfs
{
sqlite3_vfs base;
sqlite3_mutex* mutex;
sqlite3mc_file* pMain;
};
#define REALVFS(p) ((sqlite3_vfs*)(((sqlite3mc_vfs*)(p))->base.pAppData))
#define REALFILE(p) (((sqlite3mc_file*)(p))->pFile)
static int mcVfsOpen(sqlite3_vfs* pVfs, const char* zName, sqlite3_file* pFile, int flags, int* pOutFlags);
static int mcVfsDelete(sqlite3_vfs* pVfs, const char* zName, int syncDir);
static int mcVfsAccess(sqlite3_vfs* pVfs, const char* zName, int flags, int* pResOut);
static int mcVfsFullPathname(sqlite3_vfs* pVfs, const char* zName, int nOut, char* zOut);
static void* mcVfsDlOpen(sqlite3_vfs* pVfs, const char* zFilename);
static void mcVfsDlError(sqlite3_vfs* pVfs, int nByte, char* zErrMsg);
static void (*mcVfsDlSym(sqlite3_vfs* pVfs, void* p, const char* zSymbol))(void);
static void mcVfsDlClose(sqlite3_vfs* pVfs, void* p);
static int mcVfsRandomness(sqlite3_vfs* pVfs, int nByte, char* zOut);
static int mcVfsSleep(sqlite3_vfs* pVfs, int microseconds);
static int mcVfsCurrentTime(sqlite3_vfs* pVfs, double* pOut);
static int mcVfsGetLastError(sqlite3_vfs* pVfs, int nErr, char* zOut);
static int mcVfsCurrentTimeInt64(sqlite3_vfs* pVfs, sqlite3_int64* pOut);
static int mcVfsSetSystemCall(sqlite3_vfs* pVfs, const char* zName, sqlite3_syscall_ptr pNewFunc);
static sqlite3_syscall_ptr mcVfsGetSystemCall(sqlite3_vfs* pVfs, const char* zName);
static const char* mcVfsNextSystemCall(sqlite3_vfs* pVfs, const char* zName);
static int mcIoClose(sqlite3_file* pFile);
static int mcIoRead(sqlite3_file* pFile, void*, int iAmt, sqlite3_int64 iOfst);
static int mcIoWrite(sqlite3_file* pFile,const void*,int iAmt, sqlite3_int64 iOfst);
static int mcIoTruncate(sqlite3_file* pFile, sqlite3_int64 size);
static int mcIoSync(sqlite3_file* pFile, int flags);
static int mcIoFileSize(sqlite3_file* pFile, sqlite3_int64* pSize);
static int mcIoLock(sqlite3_file* pFile, int lock);
static int mcIoUnlock(sqlite3_file* pFile, int lock);
static int mcIoCheckReservedLock(sqlite3_file* pFile, int *pResOut);
static int mcIoFileControl(sqlite3_file* pFile, int op, void *pArg);
static int mcIoSectorSize(sqlite3_file* pFile);
static int mcIoDeviceCharacteristics(sqlite3_file* pFile);
static int mcIoShmMap(sqlite3_file* pFile, int iPg, int pgsz, int map, void volatile** p);
static int mcIoShmLock(sqlite3_file* pFile, int offset, int n, int flags);
static void mcIoShmBarrier(sqlite3_file* pFile);
static int mcIoShmUnmap(sqlite3_file* pFile, int deleteFlag);
static int mcIoFetch(sqlite3_file* pFile, sqlite3_int64 iOfst, int iAmt, void** pp);
static int mcIoUnfetch(sqlite3_file* pFile, sqlite3_int64 iOfst, void* p);
#define SQLITE3MC_VFS_NAME ("multipleciphers")
static const int walFrameHeaderSize = 24;
static const int walFileHeaderSize = 32;
#define IOMETHODS_VERSION_MIN 1
#define IOMETHODS_VERSION_MAX 3
static sqlite3_io_methods mcIoMethodsGlobal1 =
{
1,
mcIoClose,
mcIoRead,
mcIoWrite,
mcIoTruncate,
mcIoSync,
mcIoFileSize,
mcIoLock,
mcIoUnlock,
mcIoCheckReservedLock,
mcIoFileControl,
mcIoSectorSize,
mcIoDeviceCharacteristics,
0,
0,
0,
0,
0,
0,
};
static sqlite3_io_methods mcIoMethodsGlobal2 =
{
2,
mcIoClose,
mcIoRead,
mcIoWrite,
mcIoTruncate,
mcIoSync,
mcIoFileSize,
mcIoLock,
mcIoUnlock,
mcIoCheckReservedLock,
mcIoFileControl,
mcIoSectorSize,
mcIoDeviceCharacteristics,
mcIoShmMap,
mcIoShmLock,
mcIoShmBarrier,
mcIoShmUnmap,
0,
0,
};
static sqlite3_io_methods mcIoMethodsGlobal3 =
{
3,
mcIoClose,
mcIoRead,
mcIoWrite,
mcIoTruncate,
mcIoSync,
mcIoFileSize,
mcIoLock,
mcIoUnlock,
mcIoCheckReservedLock,
mcIoFileControl,
mcIoSectorSize,
mcIoDeviceCharacteristics,
mcIoShmMap,
mcIoShmLock,
mcIoShmBarrier,
mcIoShmUnmap,
mcIoFetch,
mcIoUnfetch,
};
static sqlite3_io_methods* mcIoMethodsGlobal[] =
{ 0, &mcIoMethodsGlobal1 , &mcIoMethodsGlobal2 , &mcIoMethodsGlobal3 };
static void mcMainListAdd(sqlite3mc_file* pFile)
{
assert( (pFile->openFlags & SQLITE_OPEN_MAIN_DB) );
sqlite3_mutex_enter(pFile->pVfsMC->mutex);
pFile->pMainNext = pFile->pVfsMC->pMain;
pFile->pVfsMC->pMain = pFile;
sqlite3_mutex_leave(pFile->pVfsMC->mutex);
}
static void mcMainListRemove(sqlite3mc_file* pFile)
{
sqlite3mc_file** pMainPrev;
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(pFile->pVfsMC->mutex);
}
static sqlite3mc_file* mcFindDbMainFileName(sqlite3mc_vfs* mcVfs, const char* zFileName)
{
sqlite3mc_file* pDb;
sqlite3_mutex_enter(mcVfs->mutex);
for (pDb = mcVfs->pMain; pDb && pDb->zFileName != zFileName; pDb = pDb->pMainNext){}
sqlite3_mutex_leave(mcVfs->mutex);
return pDb;
}
static sqlite3mc_vfs* mcFindVfs(sqlite3* db, const char* zDbName)
{
sqlite3mc_vfs* pVfsMC = NULL;
if (db->pVfs && db->pVfs->xOpen == mcVfsOpen)
{
pVfsMC = (sqlite3mc_vfs*)(db->pVfs);
}
else
{
char* zVfsNameStack = 0;
if ((sqlite3_file_control(db, zDbName, SQLITE_FCNTL_VFSNAME, &zVfsNameStack) == SQLITE_OK) && (zVfsNameStack != NULL))
{
char* zVfsName = strstr(zVfsNameStack, SQLITE3MC_VFS_NAME);
if (zVfsName != NULL)
{
char* zVfsNameEnd = zVfsName + strlen(SQLITE3MC_VFS_NAME);
if (*zVfsNameEnd == '-')
{
for (++zVfsNameEnd; *zVfsNameEnd != '/' && *zVfsNameEnd != 0; ++zVfsNameEnd);
if (*zVfsNameEnd == '/') *zVfsNameEnd = 0;
sqlite3_vfs* pVfs = sqlite3_vfs_find(zVfsName);
if (pVfs && pVfs->xOpen == mcVfsOpen)
{
pVfsMC = (sqlite3mc_vfs*) pVfs;
}
}
}
sqlite3_free(zVfsNameStack);
}
}
return pVfsMC;
}
SQLITE_PRIVATE Codec* sqlite3mcGetCodec(sqlite3* db, const char* zDbName)
{
Codec* codec = NULL;
sqlite3mc_vfs* pVfsMC = mcFindVfs(db, zDbName);
if (pVfsMC)
{
const char* dbFileName = sqlite3_db_filename(db, zDbName);
sqlite3mc_file* pDbMain = mcFindDbMainFileName(pVfsMC, dbFileName);
if (pDbMain)
{
codec = pDbMain->codec;
}
}
return codec;
}
SQLITE_PRIVATE Codec* sqlite3mcGetMainCodec(sqlite3* db)
{
return sqlite3mcGetCodec(db, "main");
}
SQLITE_PRIVATE void sqlite3mcSetCodec(sqlite3* db, const char* zDbName, const char* zFileName, Codec* codec)
{
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;
Codec* msgCodec = (codec) ? codec : prevCodec;
if (msgCodec)
{
mcReportCodecError(sqlite3mcGetBtShared(msgCodec), SQLITE_OK);
}
if (prevCodec)
{
sqlite3mcCodecFree(prevCodec);
}
pDbMain->codec = codec;
}
else
{
sqlite3mcCodecFree(codec);
}
}
int libsql_pager_codec_impl(libsql_pghdr* pPg, void **ret)
{
int rc = SQLITE_NOMEM;
if (!pPg || !pPg->pPager) {
return SQLITE_MISUSE_BKPT;
}
sqlite3_file* pFile = sqlite3PagerFile(pPg->pPager);
void* aData = 0;
if (pFile->pMethods == &mcIoMethodsGlobal1 ||
pFile->pMethods == &mcIoMethodsGlobal2 ||
pFile->pMethods == &mcIoMethodsGlobal3)
{
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
Codec* codec = mcFile->codec;
if (codec != 0 && codec->m_walLegacy == 0 && sqlite3mcIsEncrypted(codec))
{
aData = sqlite3mcCodec(codec, pPg->pData, pPg->pgno, 6);
}
else
{
aData = (char*) pPg->pData;
}
}
else
{
aData = (char*) pPg->pData;
}
if (aData) {
*ret = aData;
rc = SQLITE_OK;
}
return rc;
}
static int mcVfsOpen(sqlite3_vfs* pVfs, const char* zName, sqlite3_file* pFile, int flags, int* pOutFlags)
{
int rc;
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;
mcFile->pMainDb = 0;
mcFile->pMainNext = 0;
mcFile->pageNo = 0;
if (zName)
{
if (flags & SQLITE_OPEN_MAIN_DB)
{
mcFile->zFileName = zName;
SQLITE3MC_DEBUG_LOG("mcVfsOpen MAIN: mcFile=%p fileName=%s\n", mcFile, mcFile->zFileName);
}
else if (flags & SQLITE_OPEN_TEMP_DB)
{
mcFile->zFileName = zName;
SQLITE3MC_DEBUG_LOG("mcVfsOpen TEMP: mcFile=%p fileName=%s\n", mcFile, mcFile->zFileName);
}
#if 0#endif
else if (flags & SQLITE_OPEN_MAIN_JOURNAL)
{
const char* dbFileName = sqlite3_filename_database(zName);
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);
}
#if 0#endif
else if (flags & SQLITE_OPEN_SUBJOURNAL)
{
const char* dbFileName = sqlite3_filename_database(zName);
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);
}
#if 0#endif
else if (flags & SQLITE_OPEN_WAL)
{
const char* dbFileName = sqlite3_filename_database(zName);
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);
}
}
rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, mcFile->pFile, flags, pOutFlags);
if (rc == SQLITE_OK)
{
int ioMethodsVersion = mcFile->pFile->pMethods->iVersion;
if (ioMethodsVersion < IOMETHODS_VERSION_MIN ||
ioMethodsVersion > IOMETHODS_VERSION_MAX)
{
ioMethodsVersion = IOMETHODS_VERSION_MAX;
}
pFile->pMethods = mcIoMethodsGlobal[ioMethodsVersion];
if (flags & SQLITE_OPEN_MAIN_DB)
{
mcMainListAdd(mcFile);
}
}
return rc;
}
static int mcVfsDelete(sqlite3_vfs* pVfs, const char* zName, int syncDir)
{
return REALVFS(pVfs)->xDelete(REALVFS(pVfs), zName, syncDir);
}
static int mcVfsAccess(sqlite3_vfs* pVfs, const char* zName, int flags, int* pResOut)
{
return REALVFS(pVfs)->xAccess(REALVFS(pVfs), zName, flags, pResOut);
}
static int mcVfsFullPathname(sqlite3_vfs* pVfs, const char* zName, int nOut, char* zOut)
{
return REALVFS(pVfs)->xFullPathname(REALVFS(pVfs), zName, nOut, zOut);
}
static void* mcVfsDlOpen(sqlite3_vfs* pVfs, const char* zFilename)
{
return REALVFS(pVfs)->xDlOpen(REALVFS(pVfs), zFilename);
}
static void mcVfsDlError(sqlite3_vfs* pVfs, int nByte, char* zErrMsg)
{
REALVFS(pVfs)->xDlError(REALVFS(pVfs), nByte, zErrMsg);
}
static void (*mcVfsDlSym(sqlite3_vfs* pVfs, void* p, const char* zSymbol))(void)
{
return REALVFS(pVfs)->xDlSym(REALVFS(pVfs), p, zSymbol);
}
static void mcVfsDlClose(sqlite3_vfs* pVfs, void* p)
{
REALVFS(pVfs)->xDlClose(REALVFS(pVfs), p);
}
static int mcVfsRandomness(sqlite3_vfs* pVfs, int nByte, char* zOut)
{
return REALVFS(pVfs)->xRandomness(REALVFS(pVfs), nByte, zOut);
}
static int mcVfsSleep(sqlite3_vfs* pVfs, int microseconds)
{
return REALVFS(pVfs)->xSleep(REALVFS(pVfs), microseconds);
}
static int mcVfsCurrentTime(sqlite3_vfs* pVfs, double* pOut)
{
return REALVFS(pVfs)->xCurrentTime(REALVFS(pVfs), pOut);
}
static int mcVfsGetLastError(sqlite3_vfs* pVfs, int code, char* pOut)
{
return REALVFS(pVfs)->xGetLastError(REALVFS(pVfs), code, pOut);
}
static int mcVfsCurrentTimeInt64(sqlite3_vfs* pVfs, sqlite3_int64* pOut)
{
return REALVFS(pVfs)->xCurrentTimeInt64(REALVFS(pVfs), pOut);
}
static int mcVfsSetSystemCall(sqlite3_vfs* pVfs, const char* zName, sqlite3_syscall_ptr pNewFunc)
{
return REALVFS(pVfs)->xSetSystemCall(REALVFS(pVfs), zName, pNewFunc);
}
static sqlite3_syscall_ptr mcVfsGetSystemCall(sqlite3_vfs* pVfs, const char* zName)
{
return REALVFS(pVfs)->xGetSystemCall(REALVFS(pVfs), zName);
}
static const char* mcVfsNextSystemCall(sqlite3_vfs* pVfs, const char* zName)
{
return REALVFS(pVfs)->xNextSystemCall(REALVFS(pVfs), zName);
}
static int mcIoClose(sqlite3_file* pFile)
{
int rc;
sqlite3mc_file* p = (sqlite3mc_file*) pFile;
if (p->openFlags & SQLITE_OPEN_MAIN_DB)
{
mcMainListRemove(p);
}
if (p->codec)
{
sqlite3mcCodecFree(p->codec);
p->codec = 0;
}
assert(p->pMainNext == 0 && p->pVfsMC->pMain != p);
rc = REALFILE(pFile)->pMethods->xClose(REALFILE(pFile));
return rc;
}
static int mcReadMainDb(sqlite3_file* pFile, void* buffer, int count, sqlite3_int64 offset)
{
int rc = SQLITE_OK;
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
if (offset == 0 && count == 16)
{
return rc;
}
if (mcFile->codec != 0 && sqlite3mcIsEncrypted(mcFile->codec))
{
const int pageSize = sqlite3mcGetPageSize(mcFile->codec);
const int deltaOffset = offset % pageSize;
const int deltaCount = count % pageSize;
if (deltaOffset || deltaCount)
{
int pageNo = 0;
void* bufferDecrypted = 0;
const sqlite3_int64 prevOffset = offset - deltaOffset;
unsigned char* pageBuffer = sqlite3mcGetPageBuffer(mcFile->codec);
rc = REALFILE(pFile)->pMethods->xRead(REALFILE(pFile), pageBuffer, pageSize, prevOffset);
if (rc == SQLITE_IOERR_SHORT_READ)
{
return rc;
}
pageNo = prevOffset / pageSize + 1;
bufferDecrypted = sqlite3mcCodec(mcFile->codec, pageBuffer, pageNo, 3);
if (deltaOffset)
{
memcpy(buffer, pageBuffer + deltaOffset, count);
}
else
{
memcpy(buffer, pageBuffer, count);
}
}
else
{
unsigned char* data = (unsigned char*) buffer;
int pageNo = offset / pageSize + 1;
int nPages = count / pageSize;
int iPage;
for (iPage = 0; iPage < nPages; ++iPage)
{
void* bufferDecrypted = sqlite3mcCodec(mcFile->codec, data, pageNo, 3);
data += pageSize;
offset += pageSize;
++pageNo;
}
}
}
return rc;
}
static int mcReadMainJournal(sqlite3_file* pFile, const void* buffer, int count, sqlite3_int64 offset)
{
int rc = SQLITE_OK;
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
Codec* codec = (mcFile->pMainDb) ? mcFile->pMainDb->codec : 0;
if (codec != 0 && sqlite3mcIsEncrypted(codec))
{
const int pageSize = sqlite3mcGetPageSize(codec);
if (count == pageSize && mcFile->pageNo != 0)
{
void* bufferDecrypted = sqlite3mcCodec(codec, (char*) buffer, mcFile->pageNo, 3);
mcFile->pageNo = 0;
}
else if (count == 4)
{
mcFile->pageNo = sqlite3Get4byte(buffer);
}
}
return rc;
}
static int mcReadSubJournal(sqlite3_file* pFile, const void* buffer, int count, sqlite3_int64 offset)
{
int rc = SQLITE_OK;
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
Codec* codec = (mcFile->pMainDb) ? mcFile->pMainDb->codec : 0;
if (codec != 0 && sqlite3mcIsEncrypted(codec))
{
const int pageSize = sqlite3mcGetPageSize(codec);
if (count == pageSize && mcFile->pageNo != 0)
{
void* bufferDecrypted = sqlite3mcCodec(codec, (char*) buffer, mcFile->pageNo, 3);
}
else if (count == 4)
{
mcFile->pageNo = sqlite3Get4byte(buffer);
}
}
return rc;
}
static int mcReadWal(sqlite3_file* pFile, const void* buffer, int count, sqlite3_int64 offset)
{
int rc = SQLITE_OK;
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
Codec* codec = (mcFile->pMainDb) ? mcFile->pMainDb->codec : 0;
if (codec != 0 && sqlite3mcIsEncrypted(codec))
{
const int pageSize = sqlite3mcGetPageSize(codec);
if (count == pageSize)
{
int pageNo = 0;
unsigned char ac[4];
rc = REALFILE(pFile)->pMethods->xRead(REALFILE(pFile), ac, 4, offset - walFrameHeaderSize);
if (rc == SQLITE_OK)
{
pageNo = sqlite3Get4byte(ac);
}
if (pageNo != 0)
{
void* bufferDecrypted = sqlite3mcCodec(codec, (char*)buffer, pageNo, 3);
}
}
else if (codec->m_walLegacy != 0 && count == pageSize + walFrameHeaderSize)
{
int pageNo = sqlite3Get4byte(buffer);
if (pageNo != 0)
{
void* bufferDecrypted = sqlite3mcCodec(codec, (char*)buffer+walFrameHeaderSize, pageNo, 3);
}
}
}
return rc;
}
static int mcIoRead(sqlite3_file* pFile, void* buffer, int count, sqlite3_int64 offset)
{
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
int rc = REALFILE(pFile)->pMethods->xRead(REALFILE(pFile), buffer, count, offset);
if (rc == SQLITE_IOERR_SHORT_READ)
{
return rc;
}
if (mcFile->openFlags & SQLITE_OPEN_MAIN_DB)
{
rc = mcReadMainDb(pFile, buffer, count, offset);
}
#if 0#endif
#if 0#endif
else if (mcFile->openFlags & SQLITE_OPEN_MAIN_JOURNAL)
{
rc = mcReadMainJournal(pFile, buffer, count, offset);
}
#if 0#endif
else if (mcFile->openFlags & SQLITE_OPEN_SUBJOURNAL)
{
rc = mcReadSubJournal(pFile, buffer, count, offset);
}
#if 0#endif
else if (mcFile->openFlags & SQLITE_OPEN_WAL)
{
rc = mcReadWal(pFile, buffer, count, offset);
}
return rc;
}
static int mcWriteMainDb(sqlite3_file* pFile, const void* buffer, int count, sqlite3_int64 offset)
{
int rc = SQLITE_OK;
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
if (mcFile->codec != 0 && sqlite3mcIsEncrypted(mcFile->codec))
{
const int pageSize = sqlite3mcGetPageSize(mcFile->codec);
const int deltaOffset = offset % pageSize;
const int deltaCount = count % pageSize;
if (deltaOffset || deltaCount)
{
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
}
else
{
char* data = (char*) buffer;
int pageNo = offset / pageSize + 1;
int nPages = count / pageSize;
int iPage;
for (iPage = 0; iPage < nPages; ++iPage)
{
void* bufferEncrypted = sqlite3mcCodec(mcFile->codec, data, pageNo, 6);
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), bufferEncrypted, pageSize, offset);
data += pageSize;
offset += pageSize;
++pageNo;
}
}
}
else
{
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
}
return rc;
}
static int mcWriteMainJournal(sqlite3_file* pFile, const void* buffer, int count, sqlite3_int64 offset)
{
int rc = SQLITE_OK;
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
Codec* codec = (mcFile->pMainDb) ? mcFile->pMainDb->codec : 0;
if (codec != 0 && sqlite3mcIsEncrypted(codec))
{
const int pageSize = sqlite3mcGetPageSize(codec);
const int frameSize = pageSize + 4 + 4;
if (count == pageSize && mcFile->pageNo != 0)
{
void* bufferEncrypted = sqlite3mcCodec(codec, (char*) buffer, mcFile->pageNo, 7);
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), bufferEncrypted, pageSize, offset);
}
else
{
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
if (count == 4)
{
mcFile->pageNo = (rc == SQLITE_OK) ? sqlite3Get4byte(buffer) : 0;
}
}
}
else
{
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
}
return rc;
}
static int mcWriteSubJournal(sqlite3_file* pFile, const void* buffer, int count, sqlite3_int64 offset)
{
int rc = SQLITE_OK;
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
Codec* codec = (mcFile->pMainDb) ? mcFile->pMainDb->codec : 0;
if (codec != 0 && sqlite3mcIsEncrypted(codec))
{
const int pageSize = sqlite3mcGetPageSize(codec);
const int frameSize = pageSize + 4;
if (count == pageSize && mcFile->pageNo != 0)
{
void* bufferEncrypted = sqlite3mcCodec(codec, (char*) buffer, mcFile->pageNo, 7);
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), bufferEncrypted, pageSize, offset);
}
else
{
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
if (count == 4)
{
mcFile->pageNo = (rc == SQLITE_OK) ? sqlite3Get4byte(buffer) : 0;
}
}
}
else
{
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
}
return rc;
}
static int mcWriteWal(sqlite3_file* pFile, const void* buffer, int count, sqlite3_int64 offset)
{
int rc = SQLITE_OK;
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
Codec* codec = (mcFile->pMainDb) ? mcFile->pMainDb->codec : 0;
if (codec != 0 && codec->m_walLegacy != 0 && sqlite3mcIsEncrypted(codec))
{
const int pageSize = sqlite3mcGetPageSize(codec);
if (count == pageSize)
{
int pageNo = 0;
unsigned char ac[4];
rc = REALFILE(pFile)->pMethods->xRead(REALFILE(pFile), ac, 4, offset - walFrameHeaderSize);
if (rc == SQLITE_OK)
{
pageNo = sqlite3Get4byte(ac);
}
if (pageNo != 0)
{
void* bufferEncrypted = sqlite3mcCodec(codec, (char*) buffer, pageNo, 7);
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), bufferEncrypted, pageSize, offset);
}
else
{
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
}
}
else if (count == pageSize + walFrameHeaderSize)
{
int pageNo = sqlite3Get4byte(buffer);
if (pageNo != 0)
{
void* bufferEncrypted = sqlite3mcCodec(codec, (char*)buffer+walFrameHeaderSize, pageNo, 7);
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, walFrameHeaderSize, offset);
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), bufferEncrypted, pageSize, offset+walFrameHeaderSize);
}
else
{
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
}
}
else
{
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
}
}
else
{
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
}
return rc;
}
static int mcIoWrite(sqlite3_file* pFile, const void* buffer, int count, sqlite3_int64 offset)
{
int rc = SQLITE_OK;
int doDefault = 1;
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
if (mcFile->openFlags & SQLITE_OPEN_MAIN_DB)
{
rc = mcWriteMainDb(pFile, buffer, count, offset);
}
#if 0#endif
#if 0#endif
else if (mcFile->openFlags & SQLITE_OPEN_MAIN_JOURNAL)
{
rc = mcWriteMainJournal(pFile, buffer, count, offset);
}
#if 0#endif
else if (mcFile->openFlags & SQLITE_OPEN_SUBJOURNAL)
{
rc = mcWriteSubJournal(pFile, buffer, count, offset);
}
#if 0#endif
else if (mcFile->openFlags & SQLITE_OPEN_WAL)
{
rc = mcWriteWal(pFile, buffer, count, offset);
}
else
{
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
}
return rc;
}
static int mcIoTruncate(sqlite3_file* pFile, sqlite3_int64 size)
{
return REALFILE(pFile)->pMethods->xTruncate(REALFILE(pFile), size);
}
static int mcIoSync(sqlite3_file* pFile, int flags)
{
return REALFILE(pFile)->pMethods->xSync(REALFILE(pFile), flags);
}
static int mcIoFileSize(sqlite3_file* pFile, sqlite3_int64* pSize)
{
return REALFILE(pFile)->pMethods->xFileSize(REALFILE(pFile), pSize);
}
static int mcIoLock(sqlite3_file* pFile, int lock)
{
return REALFILE(pFile)->pMethods->xLock(REALFILE(pFile), lock);
}
static int mcIoUnlock(sqlite3_file* pFile, int lock)
{
return REALFILE(pFile)->pMethods->xUnlock(REALFILE(pFile), lock);
}
static int mcIoCheckReservedLock(sqlite3_file* pFile, int* pResOut)
{
return REALFILE(pFile)->pMethods->xCheckReservedLock(REALFILE(pFile), pResOut);
}
static int mcIoFileControl(sqlite3_file* pFile, int op, void* pArg)
{
int rc = SQLITE_OK;
int doReal = 1;
sqlite3mc_file* p = (sqlite3mc_file*) pFile;
switch (op)
{
case SQLITE_FCNTL_PDB:
{
#if 0#endif
}
break;
case SQLITE_FCNTL_PRAGMA:
{
#if 0#endif
}
break;
default:
break;
}
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;
}
static int mcIoSectorSize(sqlite3_file* pFile)
{
if (REALFILE(pFile)->pMethods->xSectorSize)
return REALFILE(pFile)->pMethods->xSectorSize(REALFILE(pFile));
else
return SQLITE_DEFAULT_SECTOR_SIZE;
}
static int mcIoDeviceCharacteristics(sqlite3_file* pFile)
{
return REALFILE(pFile)->pMethods->xDeviceCharacteristics(REALFILE(pFile));
}
static int mcIoShmMap(sqlite3_file* pFile, int iPg, int pgsz, int map, void volatile** p)
{
return REALFILE(pFile)->pMethods->xShmMap(REALFILE(pFile), iPg, pgsz, map, p);
}
static int mcIoShmLock(sqlite3_file* pFile, int offset, int n, int flags)
{
return REALFILE(pFile)->pMethods->xShmLock(REALFILE(pFile), offset, n, flags);
}
static void mcIoShmBarrier(sqlite3_file* pFile)
{
REALFILE(pFile)->pMethods->xShmBarrier(REALFILE(pFile));
}
static int mcIoShmUnmap(sqlite3_file* pFile, int deleteFlag)
{
return REALFILE(pFile)->pMethods->xShmUnmap(REALFILE(pFile), deleteFlag);
}
static int mcIoFetch(sqlite3_file* pFile, sqlite3_int64 iOfst, int iAmt, void** pp)
{
return REALFILE(pFile)->pMethods->xFetch(REALFILE(pFile), iOfst, iAmt, pp);
}
static int mcIoUnfetch( sqlite3_file* pFile, sqlite3_int64 iOfst, void* p)
{
return REALFILE(pFile)->pMethods->xUnfetch(REALFILE(pFile), iOfst, p);
}
SQLITE_PRIVATE int
sqlite3mcCheckVfs(const char* zVfs)
{
int rc = SQLITE_OK;
sqlite3_vfs* pVfs = sqlite3_vfs_find(zVfs);
if (pVfs == NULL)
{
int prefixLen = (int) strlen(SQLITE3MC_VFS_NAME);
if (strncmp(zVfs, SQLITE3MC_VFS_NAME, prefixLen) == 0)
{
const char* zVfsNameEnd = zVfs + strlen(SQLITE3MC_VFS_NAME);
if (*zVfsNameEnd == '-')
{
const char* zVfsReal = zVfsNameEnd + 1;
pVfs = sqlite3_vfs_find(zVfsReal);
if (pVfs != NULL)
{
rc = sqlite3mc_vfs_create(zVfsReal, 0);
}
}
}
}
return rc;
}
int libsql_pager_has_codec_impl(struct Pager* pPager)
{
int hasCodec = 0;
sqlite3mc_vfs* pVfsMC = NULL;
sqlite3_vfs* pVfs = pPager->pVfs;
for (; pVfs; pVfs = pVfs->pNext)
{
if (pVfs && pVfs->xOpen == mcVfsOpen)
{
pVfsMC = (sqlite3mc_vfs*)(pVfs);
break;
}
}
if (pVfsMC)
{
sqlite3mc_file* mcFile = mcFindDbMainFileName(pVfsMC, pPager->zFilename);
if (mcFile)
{
Codec* codec = mcFile->codec;
hasCodec = (codec != 0 && sqlite3mcIsEncrypted(codec));
}
}
return hasCodec;
}
static void mcVfsDestroy(sqlite3_vfs* pVfs)
{
if (pVfs && pVfs->xOpen == mcVfsOpen)
{
if (((sqlite3mc_vfs*) pVfs)->pMain == 0)
{
sqlite3_mutex_free(((sqlite3mc_vfs*)pVfs)->mutex);
sqlite3_vfs_unregister(pVfs);
sqlite3_free(pVfs);
}
}
}
SQLITE_API void sqlite3mc_vfs_destroy(const char* zName)
{
mcVfsDestroy(sqlite3_vfs_find(zName));
}
SQLITE_API int sqlite3mc_vfs_create(const char* zVfsReal, int makeDefault)
{
static sqlite3_vfs mcVfsTemplate =
{
3,
0,
1024,
0,
0,
0,
mcVfsOpen,
mcVfsDelete,
mcVfsAccess,
mcVfsFullPathname,
#ifndef SQLITE_OMIT_LOAD_EXTENSION
mcVfsDlOpen,
mcVfsDlError,
mcVfsDlSym,
mcVfsDlClose,
#else
0, 0, 0, 0,
#endif
mcVfsRandomness,
mcVfsSleep,
mcVfsCurrentTime,
mcVfsGetLastError,
mcVfsCurrentTimeInt64,
mcVfsSetSystemCall,
mcVfsGetSystemCall,
mcVfsNextSystemCall
};
sqlite3mc_vfs* pVfsNew = 0;
sqlite3_vfs* pVfsReal = sqlite3_vfs_find(zVfsReal);
int rc;
if (pVfsReal)
{
size_t nPrefix = strlen(SQLITE3MC_VFS_NAME);
size_t nRealName = strlen(pVfsReal->zName);
size_t nName = nPrefix + nRealName + 1;
size_t nByte = sizeof(sqlite3mc_vfs) + nName + 1;
pVfsNew = (sqlite3mc_vfs*) sqlite3_malloc64(nByte);
if (pVfsNew)
{
char* zSpace = (char*) &pVfsNew[1];
memset(pVfsNew, 0, nByte);
memcpy(&pVfsNew->base, &mcVfsTemplate, sizeof(sqlite3_vfs));
pVfsNew->base.iVersion = pVfsReal->iVersion;
pVfsNew->base.pAppData = pVfsReal;
pVfsNew->base.mxPathname = pVfsReal->mxPathname;
pVfsNew->base.szOsFile = sizeof(sqlite3mc_file) + pVfsReal->szOsFile;
pVfsNew->base.zName = (const char*) zSpace;
memcpy(zSpace, SQLITE3MC_VFS_NAME, nPrefix);
memcpy(zSpace + nPrefix, "-", 1);
memcpy(zSpace + nPrefix + 1, pVfsReal->zName, nRealName);
pVfsNew->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE);
if (pVfsNew->mutex)
{
rc = sqlite3_vfs_register(&pVfsNew->base, makeDefault);
if (rc != SQLITE_OK)
{
sqlite3_mutex_free(pVfsNew->mutex);
}
}
else
{
rc = SQLITE_NOMEM;
}
if (rc != SQLITE_OK)
{
sqlite3_free(pVfsNew);
}
}
else
{
rc = SQLITE_NOMEM;
}
}
else
{
rc = SQLITE_NOTFOUND;
}
return rc;
}
SQLITE_API void sqlite3mc_vfs_shutdown()
{
sqlite3_vfs* pVfs;
sqlite3_vfs* pVfsNext;
for (pVfs = sqlite3_vfs_find(0); pVfs; pVfs = pVfsNext)
{
pVfsNext = pVfs->pNext;
mcVfsDestroy(pVfs);
}
}