BaseVFS.cpp (8550B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "BaseVFS.h" 8 9 #include <string.h> 10 #include "sqlite3.h" 11 12 #include "mozilla/Assertions.h" 13 14 namespace { 15 16 // The last VFS version for which this file has been updated. 17 constexpr int kLastKnowVfsVersion = 3; 18 19 // The last io_methods version for which this file has been updated. 20 constexpr int kLastKnownIOMethodsVersion = 3; 21 22 using namespace mozilla; 23 24 struct BaseFile { 25 // Base class. Must be first 26 sqlite3_file base; 27 // This points to the underlying sqlite3_file 28 sqlite3_file pReal[1]; 29 }; 30 31 int BaseClose(sqlite3_file* pFile) { 32 BaseFile* p = (BaseFile*)pFile; 33 return p->pReal->pMethods->xClose(p->pReal); 34 } 35 36 int BaseRead(sqlite3_file* pFile, void* zBuf, int iAmt, sqlite_int64 iOfst) { 37 BaseFile* p = (BaseFile*)pFile; 38 return p->pReal->pMethods->xRead(p->pReal, zBuf, iAmt, iOfst); 39 } 40 41 int BaseWrite(sqlite3_file* pFile, const void* zBuf, int iAmt, 42 sqlite_int64 iOfst) { 43 BaseFile* p = (BaseFile*)pFile; 44 return p->pReal->pMethods->xWrite(p->pReal, zBuf, iAmt, iOfst); 45 } 46 47 int BaseTruncate(sqlite3_file* pFile, sqlite_int64 size) { 48 BaseFile* p = (BaseFile*)pFile; 49 return p->pReal->pMethods->xTruncate(p->pReal, size); 50 } 51 52 int BaseSync(sqlite3_file* pFile, int flags) { 53 BaseFile* p = (BaseFile*)pFile; 54 return p->pReal->pMethods->xSync(p->pReal, flags); 55 } 56 57 int BaseFileSize(sqlite3_file* pFile, sqlite_int64* pSize) { 58 BaseFile* p = (BaseFile*)pFile; 59 return p->pReal->pMethods->xFileSize(p->pReal, pSize); 60 } 61 62 int BaseLock(sqlite3_file* pFile, int eLock) { 63 BaseFile* p = (BaseFile*)pFile; 64 return p->pReal->pMethods->xLock(p->pReal, eLock); 65 } 66 67 int BaseUnlock(sqlite3_file* pFile, int eLock) { 68 BaseFile* p = (BaseFile*)pFile; 69 return p->pReal->pMethods->xUnlock(p->pReal, eLock); 70 } 71 72 int BaseCheckReservedLock(sqlite3_file* pFile, int* pResOut) { 73 BaseFile* p = (BaseFile*)pFile; 74 return p->pReal->pMethods->xCheckReservedLock(p->pReal, pResOut); 75 } 76 77 int BaseFileControl(sqlite3_file* pFile, int op, void* pArg) { 78 #if defined(MOZ_SQLITE_PERSIST_AUXILIARY_FILES) 79 // Persist auxiliary files (-shm and -wal) on disk, because creating and 80 // deleting them may be expensive on slow storage. 81 // Only do this when there is a journal size limit, so the journal is 82 // truncated instead of deleted on shutdown, that feels safer if the user 83 // moves a database file around without its auxiliary files. 84 MOZ_ASSERT( 85 ::sqlite3_compileoption_used("DEFAULT_JOURNAL_SIZE_LIMIT"), 86 "A journal size limit ensures the journal is truncated on shutdown"); 87 if (op == SQLITE_FCNTL_PERSIST_WAL) { 88 *static_cast<int*>(pArg) = 1; 89 return SQLITE_OK; 90 } 91 #endif 92 BaseFile* p = (BaseFile*)pFile; 93 return p->pReal->pMethods->xFileControl(p->pReal, op, pArg); 94 } 95 96 int BaseSectorSize(sqlite3_file* pFile) { 97 BaseFile* p = (BaseFile*)pFile; 98 return p->pReal->pMethods->xSectorSize(p->pReal); 99 } 100 101 int BaseDeviceCharacteristics(sqlite3_file* pFile) { 102 BaseFile* p = (BaseFile*)pFile; 103 return p->pReal->pMethods->xDeviceCharacteristics(p->pReal); 104 } 105 106 int BaseShmMap(sqlite3_file* pFile, int iPg, int pgsz, int bExtend, 107 void volatile** pp) { 108 BaseFile* p = (BaseFile*)pFile; 109 return p->pReal->pMethods->xShmMap(p->pReal, iPg, pgsz, bExtend, pp); 110 } 111 112 int BaseShmLock(sqlite3_file* pFile, int offset, int n, int flags) { 113 BaseFile* p = (BaseFile*)pFile; 114 return p->pReal->pMethods->xShmLock(p->pReal, offset, n, flags); 115 } 116 117 void BaseShmBarrier(sqlite3_file* pFile) { 118 BaseFile* p = (BaseFile*)pFile; 119 return p->pReal->pMethods->xShmBarrier(p->pReal); 120 } 121 122 int BaseShmUnmap(sqlite3_file* pFile, int deleteFlag) { 123 BaseFile* p = (BaseFile*)pFile; 124 return p->pReal->pMethods->xShmUnmap(p->pReal, deleteFlag); 125 } 126 127 int BaseFetch(sqlite3_file* pFile, sqlite3_int64 iOfst, int iAmt, void** pp) { 128 BaseFile* p = (BaseFile*)pFile; 129 return p->pReal->pMethods->xFetch(p->pReal, iOfst, iAmt, pp); 130 } 131 132 int BaseUnfetch(sqlite3_file* pFile, sqlite3_int64 iOfst, void* pPage) { 133 BaseFile* p = (BaseFile*)pFile; 134 return p->pReal->pMethods->xUnfetch(p->pReal, iOfst, pPage); 135 } 136 137 int BaseOpen(sqlite3_vfs* vfs, const char* zName, sqlite3_file* pFile, 138 int flags, int* pOutFlags) { 139 BaseFile* p = (BaseFile*)pFile; 140 sqlite3_vfs* origVfs = (sqlite3_vfs*)(vfs->pAppData); 141 int rc = origVfs->xOpen(origVfs, zName, p->pReal, flags, pOutFlags); 142 if (rc) { 143 return rc; 144 } 145 if (p->pReal->pMethods) { 146 // If the io_methods version is higher than the last known one, you should 147 // update this VFS adding appropriate IO methods for any methods added in 148 // the version change. 149 MOZ_ASSERT(p->pReal->pMethods->iVersion == kLastKnownIOMethodsVersion); 150 static const sqlite3_io_methods IOmethods = { 151 kLastKnownIOMethodsVersion, /* iVersion */ 152 BaseClose, /* xClose */ 153 BaseRead, /* xRead */ 154 BaseWrite, /* xWrite */ 155 BaseTruncate, /* xTruncate */ 156 BaseSync, /* xSync */ 157 BaseFileSize, /* xFileSize */ 158 BaseLock, /* xLock */ 159 BaseUnlock, /* xUnlock */ 160 BaseCheckReservedLock, /* xCheckReservedLock */ 161 BaseFileControl, /* xFileControl */ 162 BaseSectorSize, /* xSectorSize */ 163 BaseDeviceCharacteristics, /* xDeviceCharacteristics */ 164 BaseShmMap, /* xShmMap */ 165 BaseShmLock, /* xShmLock */ 166 BaseShmBarrier, /* xShmBarrier */ 167 BaseShmUnmap, /* xShmUnmap */ 168 BaseFetch, /* xFetch */ 169 BaseUnfetch /* xUnfetch */ 170 }; 171 pFile->pMethods = &IOmethods; 172 } 173 174 return SQLITE_OK; 175 } 176 177 } // namespace 178 179 namespace mozilla::storage::basevfs { 180 181 const char* GetVFSName(bool exclusive) { 182 return exclusive ? "base-vfs-excl" : "base-vfs"; 183 } 184 185 UniquePtr<sqlite3_vfs> ConstructVFS(bool exclusive) { 186 #if defined(XP_WIN) 187 # define EXPECTED_VFS "win32" 188 # define EXPECTED_VFS_EXCL "win32" 189 #else 190 # define EXPECTED_VFS "unix" 191 # define EXPECTED_VFS_EXCL "unix-excl" 192 #endif 193 194 if (sqlite3_vfs_find(GetVFSName(exclusive))) { 195 return nullptr; 196 } 197 198 bool found; 199 sqlite3_vfs* origVfs; 200 if (!exclusive) { 201 // Use the non-exclusive VFS. 202 origVfs = sqlite3_vfs_find(nullptr); 203 found = origVfs && origVfs->zName && !strcmp(origVfs->zName, EXPECTED_VFS); 204 } else { 205 origVfs = sqlite3_vfs_find(EXPECTED_VFS_EXCL); 206 found = (origVfs != nullptr); 207 } 208 if (!found) { 209 return nullptr; 210 } 211 212 // If the VFS version is higher than the last known one, you should update 213 // this VFS adding appropriate methods for any methods added in the version 214 // change. 215 MOZ_ASSERT(origVfs->iVersion == kLastKnowVfsVersion); 216 217 sqlite3_vfs vfs = { 218 kLastKnowVfsVersion, /* iVersion */ 219 origVfs->szOsFile + static_cast<int>(sizeof(BaseFile)), /* szOsFile */ 220 origVfs->mxPathname, /* mxPathname */ 221 nullptr, /* pNext */ 222 GetVFSName(exclusive), /* zName */ 223 origVfs, /* pAppData */ 224 BaseOpen, /* xOpen */ 225 origVfs->xDelete, /* xDelete */ 226 origVfs->xAccess, /* xAccess */ 227 origVfs->xFullPathname, /* xFullPathname */ 228 origVfs->xDlOpen, /* xDlOpen */ 229 origVfs->xDlError, /* xDlError */ 230 origVfs->xDlSym, /* xDlSym */ 231 origVfs->xDlClose, /* xDlClose */ 232 origVfs->xRandomness, /* xRandomness */ 233 origVfs->xSleep, /* xSleep */ 234 origVfs->xCurrentTime, /* xCurrentTime */ 235 origVfs->xGetLastError, /* xGetLastError */ 236 origVfs->xCurrentTimeInt64, /* xCurrentTimeInt64 */ 237 origVfs->xSetSystemCall, /* xSetSystemCall */ 238 origVfs->xGetSystemCall, /* xGetSystemCall */ 239 origVfs->xNextSystemCall /* xNextSystemCall */ 240 }; 241 242 return MakeUnique<sqlite3_vfs>(vfs); 243 } 244 245 } // namespace mozilla::storage::basevfs