xtool/contrib/mORMot/SQLite3/amalgamation/sqlite3mc_vfs.c

1003 lines
28 KiB
C

/*
** Name: sqlite3mc_vfs.c
** Purpose: Implementation of SQLite VFS for Multiple Ciphers
** Author: Ulrich Telle
** Created: 2020-02-28
** Copyright: (c) 2020 Ulrich Telle
** License: MIT
** Patched by: Arnaud Bouchez for BCC32 proper compilation
*/
#include "sqlite3mc_vfs.h"
#include "sqlite3.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
/*
** Type definitions
*/
typedef struct sqlite3mc_db sqlite3mc_db;
typedef struct sqlite3mc_file sqlite3mc_file;
typedef struct sqlite3mc_vfs sqlite3mc_vfs;
/*
** MultiCipher file structure
*/
struct sqlite3mc_db
{
sqlite3mc_db* dbNext; /* Pointer to next entry in list */
sqlite3* db; /* Database connection */
int dbIndex; /* Database index (0 for main database, >= 2 for attached databases) */
};
struct sqlite3mc_file
{
sqlite3_file base; /* sqlite3_file I/O methods */
sqlite3_file* pFile; /* Real underlying OS file */
const char* zFileName; /* File name */
int openFlags; /* Open flags */
sqlite3mc_file* pMainNext; /* Next main db file */
sqlite3mc_file* pMainDb; /* Main database to which this one is attached */
sqlite3mc_db* pDb; /* Head of list of database connections */
Codec* codec; /* Codec if encrypted */
int pageNo; /* Page number (in case of journal files) */
};
/*
** MultiCipher VFS structure
*/
struct sqlite3mc_vfs
{
sqlite3_vfs base; /* MultiCipher VFS shim methods */
sqlite3_vfs* pVfs; /* Underlying VFS */
sqlite3_mutex* mutex; /* Mutex to protect pMain */
sqlite3mc_file* pMain; /* List of main database files */
};
#define REALVFS(p) (((sqlite3mc_vfs*)(p))->pVfs)
#define REALFILE(p) (((sqlite3mc_file*)(p))->pFile)
/*
** Prototypes for VFS methods
*/
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);
/*
** Prototypes for IO methods
*/
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 ("multicipher")
static const int walFrameHeaderSize = 24;
static const int walFileHeaderSize = 32;
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 */
mcIoClose, /* xClose */
mcIoRead, /* xRead */
mcIoWrite, /* xWrite */
mcIoTruncate, /* xTruncate */
mcIoSync, /* xSync */
mcIoFileSize, /* xFileSize */
mcIoLock, /* xLock */
mcIoUnlock, /* xUnlock */
mcIoCheckReservedLock, /* xCheckReservedLock */
mcIoFileControl, /* xFileControl */
mcIoSectorSize, /* xSectorSize */
mcIoDeviceCharacteristics, /* xDeviceCharacteristics */
mcIoShmMap, /* xShmMap */
mcIoShmLock, /* xShmLock */
mcIoShmBarrier, /* xShmBarrier */
mcIoShmUnmap, /* xShmUnmap */
mcIoFetch, /* xFetch */
mcIoUnfetch, /* xUnfetch */
};
/*
** Internal functions
*/
/*
** Add an item to the list of main database files, if it is not already present.
*/
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);
}
/*
** Remove an item from the list of main database files.
*/
static void mcMainListRemove(sqlite3mc_file* pFile)
{
sqlite3mc_file** pMainPrev;
sqlite3_mutex_enter(mcVfsGlobal.mutex);
for (pMainPrev = &mcVfsGlobal.pMain; *pMainPrev && *pMainPrev != pFile; pMainPrev = &((*pMainPrev)->pMainNext)){}
if (*pMainPrev) *pMainPrev = pFile->pMainNext;
pFile->pMainNext = 0;
sqlite3_mutex_leave(mcVfsGlobal.mutex);
}
/*
** Given that zFileName points to a buffer containing a database file name passed to
** either the xOpen() or xAccess() VFS method, search the list of main database files
** for a file handle opened by the same database connection on the corresponding
** database file.
*/
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;
}
#if 0
/*
** Given that dbIndex is the index of a main database or attached database within a
** database connection, search the list of main database files for the file handle
** of the corresponding database file.
*/
static sqlite3mc_file* mcFindDbMainFile(sqlite3mc_vfs* mcVfs, sqlite3* db, int dbIndex)
{
sqlite3mc_file* pDbMain;
sqlite3_mutex_enter(mcVfs->mutex);
for (pDbMain = mcVfs->pMain; pDbMain && mcDbListFind(pDbMain, db, dbIndex) == NULL; pDbMain = pDbMain->pMainNext) {}
sqlite3_mutex_leave(mcVfs->mutex);
return pDbMain;
}
#endif
/*
** Find the codec of the database file
** corresponding to the database index.
*/
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)
{
codec = pDbMain->codec;
}
return codec;
}
/*
** Find the codec of the main database file.
*/
SQLITE_PRIVATE Codec* sqlite3mcGetMainCodec(sqlite3* db)
{
return sqlite3mcGetCodec(db, "main");
}
/*
** Set the codec of the database file with the given database index.
*/
SQLITE_PRIVATE void sqlite3mcSetCodec(sqlite3* db, const char* zFileName, Codec* codec)
{
sqlite3mc_file* pDbMain = mcFindDbMainFileName(&mcVfsGlobal, zFileName);
//fprintf(stdout,"sqlite3mcSetCodec %s as %x\n", zFileName, pDbMain);
if (pDbMain)
{
if (pDbMain->codec)
{
sqlite3mcCodecFree(pDbMain->codec);
}
pDbMain->codec = codec;
}
else
{
/*
** No main database file handle found (e.g. vaccum or attached
** from memory db): free codec
*/
sqlite3mcCodecFree(codec);
}
}
/*
** Implementation of VFS methods
*/
static int mcVfsOpen(sqlite3_vfs* pVfs, const char* zName, sqlite3_file* pFile, int flags, int* pOutFlags)
{
int rc;
const char* dbFileName;
sqlite3mc_vfs* mcVfs = (sqlite3mc_vfs*) pVfs;
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
mcFile->pFile = (sqlite3_file*) &mcFile[1];
mcFile->openFlags = flags;
mcFile->zFileName = zName;
mcFile->pDb = NULL;
mcFile->codec = 0;
mcFile->pMainDb = 0;
mcFile->pMainNext = 0;
mcFile->pageNo = 0;
//fprintf(stdout,"mcVfsOpen %s %x\n", zName, flags);
if (zName)
{
if (flags & SQLITE_OPEN_MAIN_DB)
{
/* A main database has just been opened.
*/
mcFile->zFileName = zName;
}
#if 1
else if (flags & SQLITE_OPEN_TEMP_DB)
{
mcFile->zFileName = zName;
}
#endif
#if 0
else if (flags & SQLITE_OPEN_TRANSIENT_DB)
{
}
#endif
else if (flags & SQLITE_OPEN_MAIN_JOURNAL)
{
mcFile->zFileName = zName;
dbFileName = sqlite3_filename_database(zName);
mcFile->pMainDb = mcFindDbMainFileName(&mcVfsGlobal, dbFileName);
}
#if 0
else if (flags & SQLITE_OPEN_TEMP_JOURNAL)
{
}
#endif
else if (flags & SQLITE_OPEN_SUBJOURNAL)
{
mcFile->zFileName = zName;
dbFileName = sqlite3_filename_database(zName);
mcFile->pMainDb = mcFindDbMainFileName(&mcVfsGlobal, dbFileName);
}
#if 0
else if (flags & SQLITE_OPEN_MASTER_JOURNAL)
{
}
#endif
else if (flags & SQLITE_OPEN_WAL)
{
mcFile->zFileName = zName;
dbFileName = sqlite3_filename_database(zName);
mcFile->pMainDb = mcFindDbMainFileName(&mcVfsGlobal, dbFileName);
}
}
rc = REALVFS(pVfs)->xOpen(REALVFS(pVfs), zName, mcFile->pFile, flags, pOutFlags);
if (rc == SQLITE_OK)
{
pFile->pMethods = &mcIoMethodsGlobal;
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);
}
/*
** IO methods
*/
static int mcIoClose(sqlite3_file* pFile)
{
sqlite3mc_file* p = (sqlite3mc_file*) pFile;
int rc;
if (p->openFlags & SQLITE_OPEN_MAIN_DB)
{
mcMainListRemove(p);
}
if (p->codec)
{
sqlite3mcCodecFree(p->codec);
p->codec = 0;
}
assert(p->pMainNext == 0 && mcVfsGlobal.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;
int pageNo;
void* bufferDecrypted;
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
/*
** Special case: read 16 bytes salt from beginning of database file without decrypting
*/
if (offset == 0 && count == 16)
{
return rc;
}
if (mcFile->codec != 0 && CodecIsEncrypted(mcFile->codec))
{
const int pageSize = sqlite3mcGetPageSize(mcFile->codec);
const int deltaOffset = offset % pageSize;
const int deltaCount = count % pageSize;
if (deltaOffset || deltaCount)
{
const sqlite3_int64 prevOffset = offset - deltaOffset;
unsigned char* pageBuffer = CodecGetPageBuffer(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 && CodecIsEncrypted(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 && CodecIsEncrypted(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 && CodecIsEncrypted(codec))
{
const int pageSize = sqlite3mcGetPageSize(codec);
if (count == pageSize)
{
int pageNo = 0;
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);
}
}
}
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
else if (mcFile->openFlags & SQLITE_OPEN_TEMP_DB)
{
}
#endif
#if 0
else if (mcFile->openFlags & SQLITE_OPEN_TRANSIENT_DB)
{
}
#endif
else if (mcFile->openFlags & SQLITE_OPEN_MAIN_JOURNAL)
{
rc = mcReadMainJournal(pFile, buffer, count, offset);
}
#if 0
else if (mcFile->openFlags & SQLITE_OPEN_TEMP_JOURNAL)
{
}
#endif
else if (mcFile->openFlags & SQLITE_OPEN_SUBJOURNAL)
{
rc = mcReadSubJournal(pFile, buffer, count, offset);
}
#if 0
else if (mcFile->openFlags & SQLITE_OPEN_MASTER_JOURNAL)
{
}
#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 && CodecIsEncrypted(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 && CodecIsEncrypted(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 && CodecIsEncrypted(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 && CodecIsEncrypted(codec))
{
const int pageSize = sqlite3mcGetPageSize(codec);
if (count == pageSize)
{
int pageNo = 0;
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
{
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
else if (mcFile->openFlags & SQLITE_OPEN_TEMP_DB)
{
}
#endif
#if 0
else if (mcFile->openFlags & SQLITE_OPEN_TRANSIENT_DB)
{
}
#endif
else if (mcFile->openFlags & SQLITE_OPEN_MAIN_JOURNAL)
{
rc = mcWriteMainJournal(pFile, buffer, count, offset);
}
#if 0
else if (mcFile->openFlags & SQLITE_OPEN_TEMP_JOURNAL)
{
}
#endif
else if (mcFile->openFlags & SQLITE_OPEN_SUBJOURNAL)
{
rc = mcWriteSubJournal(pFile, buffer, count, offset);
}
#if 0
else if (mcFile->openFlags & SQLITE_OPEN_MASTER_JOURNAL)
{
}
#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;
/*
** TODO: Handle pragmas
*/
switch (op)
{
case SQLITE_FCNTL_PDB:
{
#if 0
/* pArg points to the sqlite3* handle for which the database file was opened */
/* In shared cache mode this function is invoked for every use of the database file in a connection */
/* Unfortunately there is no notification, when a database file is no longer used by a connection (close in normal mode) */
sqlite3* db = *((sqlite3**) pArg);
#endif
}
break;
case SQLITE_FCNTL_PRAGMA:
{
#if 0
/* Handle database file specific pragmas */
char* pragmaName = ((char**) pArg)[1];
char* pragmaValue = ((char**) pArg)[2];
if (sqlite3StrICmp(pragmaName, "...") == 0)
{
/* Action */
/* ((char**) pArg)[0] = sqlite3_mprintf("error msg.");*/
doReal = 0;
}
#endif
}
break;
default:
break;
}
if (doReal)
{
rc = REALFILE(pFile)->pMethods->xFileControl(REALFILE(pFile), op, pArg);
}
return rc;
}
static int mcIoSectorSize(sqlite3_file* pFile)
{
return REALFILE(pFile)->pMethods->xSectorSize(REALFILE(pFile));
}
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);
}
/*
** MultiCipher external API functions
*/
SQLITE_API const char* sqlite3mc_vfs_name()
{
return SQLITE3MC_VFS_NAME;
}
/*
** Terminate and unregister the SQLite3 Multi Cipher VFS
*/
SQLITE_API void sqlite3mc_vfs_terminate()
{
if (mcVfsGlobal.pMain == 0)
{
sqlite3_mutex_free(mcVfsGlobal.mutex);
sqlite3_vfs_unregister(&mcVfsGlobal.base);
}
}
/*
** Initialize SQLite3 Multi Cipher VFS that accesses the underlying file-system
** via the current default VFS.
*/
SQLITE_API int sqlite3mc_vfs_initialize(sqlite3_vfs* vfsDefault, int makeDefault)
{
int rc = SQLITE_OK;
if (!vfsDefault)
{
return SQLITE_NOTFOUND;
}
mcVfsGlobal.base.szOsFile = sizeof(sqlite3mc_file) + vfsDefault->szOsFile;
mcVfsGlobal.base.mxPathname = vfsDefault->mxPathname;
mcVfsGlobal.pVfs = vfsDefault;
mcVfsGlobal.mutex = 0;
mcVfsGlobal.pMain = 0;
mcVfsGlobal.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE);
if (mcVfsGlobal.mutex == 0)
{
rc = SQLITE_NOMEM;
}
else
{
rc = sqlite3_vfs_register(&mcVfsGlobal.base, makeDefault);
if (rc != SQLITE_OK)
{
sqlite3_mutex_free(mcVfsGlobal.mutex);
mcVfsGlobal.mutex = 0;
}
}
//fprintf(stdout,"sqlite3mc_vfs_initialize returned %d\n", rc);
return rc;
}