mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-01 08:42:13 +00:00
b2cc4c68f4
Differential Revision: https://phabricator.services.mozilla.com/D187992
266 lines
8.9 KiB
C++
266 lines
8.9 KiB
C++
/* -*- 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
|