/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BaseVFS.h"
#include <string.h>
#include "sqlite3.h"
namespace {
// The last VFS version for which this file has been updated.
constexpr
int kLastKnowVfsVersion = 3;
// The last io_methods version for which this file has been updated.
constexpr
int kLastKnownIOMethodsVersion = 3;
using namespace mozilla;
struct BaseFile {
// Base class. Must be first
sqlite3_file base;
// This points to the underlying sqlite3_file
sqlite3_file pReal[1];
};
int BaseClose(sqlite3_file* pFile) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xClose(p->pReal);
}
int BaseRead(sqlite3_file* pFile,
void* zBuf,
int iAmt, sqlite_int64 iOfst) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst);
}
int BaseWrite(sqlite3_file* pFile,
const void* zBuf,
int iAmt,
sqlite_int64 iOfst) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst);
}
int BaseTruncate(sqlite3_file* pFile, sqlite_int64 size) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xTruncate(p->pReal, size);
}
int BaseSync(sqlite3_file* pFile,
int flags) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xSync(p->pReal, flags);
}
int BaseFileSize(sqlite3_file* pFile, sqlite_int64* pSize) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xFileSize(p->pReal, pSize);
}
int BaseLock(sqlite3_file* pFile,
int eLock) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xLock(p->pReal, eLock);
}
int BaseUnlock(sqlite3_file* pFile,
int eLock) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xUnlock(p->pReal, eLock);
}
int BaseCheckReservedLock(sqlite3_file* pFile,
int* pResOut) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut);
}
int BaseFileControl(sqlite3_file* pFile,
int op,
void* pArg) {
#if defined(MOZ_SQLITE_PERSIST_AUXILIARY_FILES)
// Persist auxiliary files (-shm and -wal) on disk, because creating and
// deleting them may be expensive on slow storage.
// Only do this when there is a journal size limit, so the journal is
// truncated instead of deleted on shutdown, that feels safer if the user
// moves a database file around without its auxiliary files.
MOZ_ASSERT(
::sqlite3_compileoption_used(
"DEFAULT_JOURNAL_SIZE_LIMIT"),
"A journal size limit ensures the journal is truncated on shutdown");
if (op == SQLITE_FCNTL_PERSIST_WAL) {
*
static_cast<
int*>(pArg) = 1;
return SQLITE_OK;
}
#endif
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xFileControl(p->pReal, op, pArg);
}
int BaseSectorSize(sqlite3_file* pFile) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xSectorSize(p->pReal);
}
int BaseDeviceCharacteristics(sqlite3_file* pFile) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xDeviceCharacteristics(p->pReal);
}
int BaseShmMap(sqlite3_file* pFile,
int iPg,
int pgsz,
int bExtend,
void volatile** pp) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xShmMap(p->pReal, iPg, pgsz, bExtend, pp);
}
int BaseShmLock(sqlite3_file* pFile,
int offset,
int n,
int flags) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xShmLock(p->pReal, offset, n, flags);
}
void BaseShmBarrier(sqlite3_file* pFile) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xShmBarrier(p->pReal);
}
int BaseShmUnmap(sqlite3_file* pFile,
int deleteFlag) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag);
}
int BaseFetch(sqlite3_file* pFile, sqlite3_int64 iOfst,
int iAmt,
void** pp) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xFetch(p->pReal, iOfst, iAmt, pp);
}
int BaseUnfetch(sqlite3_file* pFile, sqlite3_int64 iOfst,
void* pPage) {
BaseFile* p = (BaseFile*)pFile;
return p->pReal->pMethods->xUnfetch(p->pReal, iOfst, pPage);
}
int BaseOpen(sqlite3_vfs* vfs,
const char* zName, sqlite3_file* pFile,
int flags,
int* pOutFlags) {
BaseFile* p = (BaseFile*)pFile;
sqlite3_vfs* origVfs = (sqlite3_vfs*)(vfs->pAppData);
int rc = origVfs->xOpen(origVfs, zName, p->pReal, flags, pOutFlags);
if (rc) {
return rc;
}
if (p->pReal->pMethods) {
// If the io_methods version is higher than the last known one, you should
// update this VFS adding appropriate IO methods for any methods added in
// the version change.
MOZ_ASSERT(p->pReal->pMethods->iVersion == kLastKnownIOMethodsVersion);
static const sqlite3_io_methods IOmethods = {
kLastKnownIOMethodsVersion,
/* iVersion */
BaseClose,
/* xClose */
BaseRead,
/* xRead */
BaseWrite,
/* xWrite */
BaseTruncate,
/* xTruncate */
BaseSync,
/* xSync */
BaseFileSize,
/* xFileSize */
BaseLock,
/* xLock */
BaseUnlock,
/* xUnlock */
BaseCheckReservedLock,
/* xCheckReservedLock */
BaseFileControl,
/* xFileControl */
BaseSectorSize,
/* xSectorSize */
BaseDeviceCharacteristics,
/* xDeviceCharacteristics */
BaseShmMap,
/* xShmMap */
BaseShmLock,
/* xShmLock */
BaseShmBarrier,
/* xShmBarrier */
BaseShmUnmap,
/* xShmUnmap */
BaseFetch,
/* xFetch */
BaseUnfetch
/* xUnfetch */
};
pFile->pMethods = &IOmethods;
}
return SQLITE_OK;
}
}
// namespace
namespace mozilla::storage::basevfs {
const char* GetVFSName(
bool exclusive) {
return exclusive ?
"base-vfs-excl" :
"base-vfs";
}
UniquePtr<sqlite3_vfs> ConstructVFS(
bool exclusive) {
#if defined(XP_WIN)
# define EXPECTED_VFS
"win32"
# define EXPECTED_VFS_EXCL
"win32"
#else
# define EXPECTED_VFS
"unix"
# define EXPECTED_VFS_EXCL
"unix-excl"
#endif
if (sqlite3_vfs_find(GetVFSName(exclusive))) {
return nullptr;
}
bool found;
sqlite3_vfs* origVfs;
if (!exclusive) {
// Use the non-exclusive VFS.
origVfs = sqlite3_vfs_find(nullptr);
found = origVfs && origVfs->zName && !strcmp(origVfs->zName, EXPECTED_VFS);
}
else {
origVfs = sqlite3_vfs_find(EXPECTED_VFS_EXCL);
found = (origVfs != nullptr);
}
if (!found) {
return nullptr;
}
// If the VFS version is higher than the last known one, you should update
// this VFS adding appropriate methods for any methods added in the version
// change.
MOZ_ASSERT(origVfs->iVersion == kLastKnowVfsVersion);
sqlite3_vfs vfs = {
kLastKnowVfsVersion,
/* iVersion */
origVfs->szOsFile +
static_cast<
int>(
sizeof(BaseFile)),
/* szOsFile */
origVfs->mxPathname,
/* mxPathname */
nullptr,
/* pNext */
GetVFSName(exclusive),
/* zName */
origVfs,
/* pAppData */
BaseOpen,
/* xOpen */
origVfs->xDelete,
/* xDelete */
origVfs->xAccess,
/* xAccess */
origVfs->xFullPathname,
/* xFullPathname */
origVfs->xDlOpen,
/* xDlOpen */
origVfs->xDlError,
/* xDlError */
origVfs->xDlSym,
/* xDlSym */
origVfs->xDlClose,
/* xDlClose */
origVfs->xRandomness,
/* xRandomness */
origVfs->xSleep,
/* xSleep */
origVfs->xCurrentTime,
/* xCurrentTime */
origVfs->xGetLastError,
/* xGetLastError */
origVfs->xCurrentTimeInt64,
/* xCurrentTimeInt64 */
origVfs->xSetSystemCall,
/* xSetSystemCall */
origVfs->xGetSystemCall,
/* xGetSystemCall */
origVfs->xNextSystemCall
/* xNextSystemCall */
};
return MakeUnique<sqlite3_vfs>(vfs);
}
}
// namespace mozilla::storage::basevfs