summaryrefslogtreecommitdiffstats
path: root/storage/BaseVFS.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/BaseVFS.cpp')
-rw-r--r--storage/BaseVFS.cpp265
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