/* -*- 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 #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) { #ifdef EARLY_BETA_OR_EARLIER // 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(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 { const char* GetBaseVFSName(bool exclusive) { return exclusive ? "base-vfs-excl" : "base-vfs"; } UniquePtr ConstructBaseVFS(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(GetBaseVFSName(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(sizeof(BaseFile)), /* szOsFile */ origVfs->mxPathname, /* mxPathname */ nullptr, /* pNext */ GetBaseVFSName(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(vfs); } } // namespace mozilla::storage