diff options
Diffstat (limited to 'storage/BaseVFS.cpp')
-rw-r--r-- | storage/BaseVFS.cpp | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/storage/BaseVFS.cpp b/storage/BaseVFS.cpp new file mode 100644 index 0000000000..f6090bf008 --- /dev/null +++ b/storage/BaseVFS.cpp @@ -0,0 +1,265 @@ +/* -*- 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" +#include "mozilla/net/IOActivityMonitor.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; +using namespace mozilla::net; + +struct BaseFile { + // Base class. Must be first + sqlite3_file base; + // The filename + char* location; + // This points to the underlying sqlite3_file + sqlite3_file pReal[1]; +}; + +int BaseClose(sqlite3_file* pFile) { + BaseFile* p = (BaseFile*)pFile; + delete[] p->location; + return p->pReal->pMethods->xClose(p->pReal); +} + +int BaseRead(sqlite3_file* pFile, void* zBuf, int iAmt, sqlite_int64 iOfst) { + BaseFile* p = (BaseFile*)pFile; + int rc = p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst); + if (rc == SQLITE_OK && IOActivityMonitor::IsActive()) { + IOActivityMonitor::Read(nsDependentCString(p->location), iAmt); + } + return rc; +} + +int BaseWrite(sqlite3_file* pFile, const void* zBuf, int iAmt, + sqlite_int64 iOfst) { + BaseFile* p = (BaseFile*)pFile; + int rc = p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst); + if (rc == SQLITE_OK && IOActivityMonitor::IsActive()) { + IOActivityMonitor::Write(nsDependentCString(p->location), iAmt); + } + return rc; +} + +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; + if (zName) { + p->location = new char[7 + strlen(zName) + 1]; + strcpy(p->location, "file://"); + strcpy(p->location + 7, zName); + } else { + p->location = new char[8]; + strcpy(p->location, "file://"); + } + + 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 |